Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(widget): make only one flat set of params #3318

Merged
merged 13 commits into from
Nov 3, 2023
Merged
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { useEffect, useMemo } from 'react'
import { useEffect } from 'react'

import {
Dimensions,
Expand Down Expand Up @@ -76,10 +76,7 @@ export function useAnalyticsReporter() {

const walletName = _walletName || getConnectionName(connection.type, isMetaMask)

const injectedWidgetAppId = useMemo(
() => (injectedWidgetMetaData ? `${injectedWidgetMetaData.appKey}:${injectedWidgetMetaData.url}` : ''),
[injectedWidgetMetaData]
)
const injectedWidgetAppId = `${injectedWidgetMetaData.appKey}:${injectedWidgetMetaData.email}`
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved

useEffect(() => {
// Custom dimension 2 - walletname
Expand Down
2 changes: 1 addition & 1 deletion apps/cowswap-frontend/src/modules/appData/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export function useAppCode(): string | null {

return useMemo(() => {
if (isInjectedWidget()) {
return injectedWidgetMetaData?.appKey || null
return injectedWidgetMetaData.appKey
}

if (APP_CODE) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { useAtomValue } from 'jotai'

import { InjectedWidgetMetaData, injectedWidgetMetaDataAtom } from '../state/injectedWidgetMetaDataAtom'
import type { CowSwapWidgetMetaData } from '@cowprotocol/widget-lib'

export function useInjectedWidgetMetaData(): InjectedWidgetMetaData | null {
import { injectedWidgetMetaDataAtom } from '../state/injectedWidgetMetaDataAtom'

export function useInjectedWidgetMetaData(): CowSwapWidgetMetaData {
return useAtomValue(injectedWidgetMetaDataAtom)
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { atom } from 'jotai'

export interface InjectedWidgetMetaData {
appKey: string
url: string
import type { CowSwapWidgetMetaData } from '@cowprotocol/widget-lib'

const DEFAULT_INJECTED_WIDGET_META_DATA: CowSwapWidgetMetaData = {
appKey: 'DEFAULT_INJECTED_WIDGET',
}

export const injectedWidgetMetaDataAtom = atom<InjectedWidgetMetaData | null>(null)
export const injectedWidgetMetaDataAtom = atom<CowSwapWidgetMetaData>(DEFAULT_INJECTED_WIDGET_META_DATA)
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ export function InjectedWidgetUpdater() {
navigate(data.urlParams)
}

if (method === 'metaData') {
if (method === 'metaData' && data.metaData) {
updateMetaData(data.metaData)
}
},
Expand Down
12 changes: 5 additions & 7 deletions apps/widget-configurator/src/app/configurator/embedDialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,9 @@ import { nightOwl } from 'react-syntax-highlighter/dist/esm/styles/hljs'

export interface EmbedDialogProps {
params: CowSwapWidgetProps['params']
settings: CowSwapWidgetProps['settings']
}

export function EmbedDialog({ params, settings }: EmbedDialogProps) {
export function EmbedDialog({ params }: EmbedDialogProps) {
const [open, setOpen] = useState(false)
const [scroll, setScroll] = useState<DialogProps['scroll']>('paper')

Expand All @@ -42,18 +41,17 @@ export function EmbedDialog({ params, settings }: EmbedDialogProps) {

const paramsSanitized = {
...params,
container: `<YOUR_CONTAINER>`,
provider: `<eip-1193 provider>`,
}

const code = `
import { CowSwapWidgetParams, CowSwapWidgetSettings, cowSwapWidget } from '@cowprotocol/widget-lib'
import { CowSwapWidgetParams, cowSwapWidget } from '@cowprotocol/widget-lib'

const params: CowSwapWidgetParams = ${JSON.stringify(paramsSanitized, null, 4)}
const container = document.getElementById('<YOUR_CONTAINER>')

const settings: CowSwapWidgetSettings = ${JSON.stringify(settings, null, 4)}
const params: CowSwapWidgetParams = ${JSON.stringify(paramsSanitized, null, 4)}

const updateWidget = cowSwapWidget(params, settings)
const updateWidget = cowSwapWidget(container, params)
`

const handleCopy = () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,13 +32,10 @@ export function useWidgetParamsAndSettings(
} = configuratorState

const params: CowSwapWidgetProps['params'] = {
metaData: { appKey: '<YOUR_APP_ID>', url: '<https://YOUR_APP_URL>' },
metaData: { appKey: '<YOUR_APP_ID>' },
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
width: 400,
height: 640,
provider,
}

const settings: CowSwapWidgetProps['settings'] = {
theme,
chainId,
env: getEnv(),
Expand All @@ -51,12 +48,12 @@ export function useWidgetParamsAndSettings(
enabledTradeTypes,
// palette: {
// primaryColor: '#d9258e',
// screenBackground: '#c7860f',
// widgetBackground: '#eed4a7',
// textColor: '#413931',
// screenBackground: '#ee00cd',
// widgetBackground: '#b900ff',
// textColor: '#b348cc',
// },
}

return { params, settings }
return params
}, [provider, configuratorState])
}
9 changes: 4 additions & 5 deletions apps/widget-configurator/src/app/configurator/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,7 @@ export function Configurator({ title }: { title: string }) {
dynamicHeightEnabled: true,
}

const paramsAndSettings = useWidgetParamsAndSettings(provider, state)
const { params, settings } = paramsAndSettings || {}
const params = useWidgetParamsAndSettings(provider, state)

useEffect(() => {
web3Modal.setThemeMode(mode)
Expand Down Expand Up @@ -117,11 +116,11 @@ export function Configurator({ title }: { title: string }) {
</Drawer>

<Box sx={ContentStyled}>
{params && settings && (
{params && (
<>
<EmbedDialog params={params} settings={settings} />
<EmbedDialog params={params} />
<br />
<CowSwapWidget provider={provider} settings={settings} params={params} />
<CowSwapWidget provider={provider} params={params} />
</>
)}
</Box>
Expand Down
19 changes: 10 additions & 9 deletions libs/widget-lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,29 +31,30 @@ Create a container somewhere in your website, the widget will be rendered inside
Import the widget and initialise it:

```js
import { cowSwapWidget } from '@cowprotocol/widget-lib'
import { cowSwapWidget, CowSwapWidgetParams } from '@cowprotocol/widget-lib'

// Initialise the widget
const widgetContainer = document.getElementById('cowswap-widget')

const updateWidget = cowSwapWidget({
container: widgetContainer,
width: 600,
height: 640,
const params: CowSwapWidgetParams = {
metaData: {
appKey: '<YOUR_APP_KEY>', // Just an unique identifier for your app,
appUrl: '<YOUR_APP_URL>'
},
// Optionally, you can provide some additional params to customise your widget
}, {
sell: { asset: 'DAI' },
buy: { asset: 'USDC', amount: '0.1' },
// instantiate your own web3 provider
provider: window.ethereum
})
}

const updateWidget = cowSwapWidget(
widgetContainer,
// Optionally, you can provide some additional params to customise your widget
params
)

// You also can change widget configuration on the fly
updateWidget({ tradeType: 'limit' })
updateWidget({ ...params, tradeType: 'limit' })
```

## Developers
Expand Down
14 changes: 2 additions & 12 deletions libs/widget-lib/demo/vanilla.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,12 @@
<head>
<meta charset="UTF-8">
<title>CoWSwap Widget demo</title>
<script src="https://cdn.jsdelivr.net/npm/@cowprotocol/[email protected].2/index.iife.js"></script>
<script src="https://cdn.jsdelivr.net/npm/@cowprotocol/[email protected].3/index.iife.js"></script>
</head>
<body>
<div id="app"></div>
<script>
cowSwapWidget.cowSwapWidget({
container: document.getElementById("app"),
width: 400,
height: 600,
metaData: {
appKey: 'test',
appUrl: 'test',
}
}, {
env: 'dev'
})
cowSwapWidget.cowSwapWidget(document.getElementById("app"))
</script>
</body>
</html>
121 changes: 39 additions & 82 deletions libs/widget-lib/docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,30 +21,29 @@ npm install @cowprotocol/widget-lib
## Quick start

```typescript
import {cowSwapWidget, CowSwapWidgetParams, CowSwapWidgetSettings} from '@cowprotocol/widget-lib'
import {cowSwapWidget, CowSwapWidgetParams} from '@cowprotocol/widget-lib'

// Initialise the widget
// HTML element where the widget will be rendered
const widgetContainer = document.getElementById('cowswap-widget')

const params: CowSwapWidgetParams = {
container: widgetContainer,
metaData: {appKey: 'YOUR_APP_ID', url: 'https://YOUR_APP_URL'},
width: 600,
height: 640,
}

const settings: CowSwapWidgetSettings = {
sell: {asset: 'DAI'},
buy: {asset: 'USDC', amount: '0.1'}
}

cowSwapWidget(params, settings)
cowSwapWidget(widgetContainer, params)
```

## App key
You must specify the `appKey` parameter when initializing the widget. This parameter is used to identify the source of orders.

You must specify the `appKey` parameter when initializing the widget. This parameter is used to identify the source of
orders.
The key must be a UTF8 string of up to 50 chars.
It will be a part of orders meta-data, see more in the [CoW Protocol Docs](https://docs.cow.fi/front-end/creating-app-ids/create-the-order-meta-data-file/appcode).
It will be a part of orders meta-data, see more in
the [CoW Protocol Docs](https://docs.cow.fi/front-end/creating-app-ids/create-the-order-meta-data-file/appcode).

## Wallet provider

Expand Down Expand Up @@ -75,99 +74,57 @@ An example of connecting a widget to Metamask:
```typescript
import {cowSwapWidget, CowSwapWidgetParams} from '@cowprotocol/widget-lib'

const params: CowSwapWidgetParams = {
container: document.getElementById('cowswap-widget'),
metaData: {appKey: 'YOUR_APP_ID', url: 'https://YOUR_APP_URL'},
width: 600,
height: 640,
provider: window.ethereum // <-------
}

cowSwapWidget(params, {})
cowSwapWidget(
document.getElementById('cowswap-widget'),
{
provider: window.ethereum // <-------
}
)
```

## Configuration

### `CowSwapWidgetParams`

| Parameter | Type | Description |
|-------------|-------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------|
| `width` | `number` | The width of the widget in pixels. |
| `height` | `number` | The height of the widget in pixels. |
| `container` | `HTMLElement` | The container in which the widget will be displayed. |
| `metaData` | `CowSwapWidgetMetaData` | Information about the application in which the widget is embedded. This information will help identify the source of orders and requests from users. |
| `provider` | `EthereumProvider` | (Optional) The Ethereum provider to be used for interacting with a wallet. |

### `CowSwapWidgetSettings`

| Parameter | Type | Description |
|------------------------|------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `chainId` | `number` | The blockchain ID on which the trade will take place. |
| `tradeType` | `string` | The type of trade. Can be `swap` or `limit-orders`. |
| `env` | `CowSwapWidgetEnv` | The environment of the widget (`'local'` or `'prod'`). |
| `tradeAssets` | `TradeAssets` | (Optional) An object containing information about the selling and buying assets. |
| `theme` | `CowSwapTheme` | (Optional) The theme of the widget (`'dark'` for dark theme or `'light'` for light theme). |
| `logoUrl` | `boolean` | (Optional) The width of the widget in pixels. |
| `hideLogo` | `boolean` | (Optional) The height of the widget in pixels. |
| `hideNetworkSelector` | `boolean` | (Optional) Disables an opportunity to change the network from the widget UI. |
| `dynamicHeightEnabled` | `boolean` | (Optional) Dynamically changes the height of the iframe depending on the content. |
| `enabledTradeTypes` | `Array<TradeType>` | (Optional) CowSwap provides three trading widgets: swap, limit and twap orders. Using this option you can narrow down the list of available trading widgets. |
| `palette` | `CowSwapWidgetPalette` | (Optional) Using the palette you can customize the appearance of the widget. For example, you can change the main color of the background and text. |

```typescript
export interface CowSwapWidgetMetaData {
appKey: string
url: string
}

interface TradeAsset {
asset: string
amount?: string
}

export interface TradeAssets {
sell: TradeAsset
buy: TradeAsset
}

export enum TradeType {
SWAP = 'swap',
LIMIT = 'limit',
ADVANCED = 'advanced',
}

export interface CowSwapWidgetPalette {
primaryColor: string
screenBackground: string
widgetBackground: string
textColor: string
}
```
>All params are optional

| Parameter | Type | Description |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
|------------------------|-------------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `width` | `number` | The width of the widget in pixels. Default: 400px |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `height` | `number` | The height of the widget in pixels. Default: 600px |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `metaData` | `CowSwapWidgetMetaData` | Information about the application in which the widget is embedded. This information will help identify the source of orders and requests from users. |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `provider` | `EthereumProvider` | The Ethereum provider to be used for interacting with a wallet. |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `chainId` | `number` | The blockchain ID on which the trade will take place. |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `tradeType` | `string` | The type of trade. Can be `swap` or `limit-orders`. |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `env` | `CowSwapWidgetEnv` | The environment of the widget (`'local'` or `'prod'`). |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: I would write environment, however i think is more versatile to pass the cowSwapBaseUrl defaulting to https://swap.cow.fi. As an interface for clients makes more sense to me. Also, local may be different for different people, maybe I have in another port for example.

Also this gives the flexibility to point the widget to IPFS or any other web

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a link to COWSWAP_URLS.
About IPFS, I think we can easily add an opportiunity for it just when we have a case for it

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This property actually is mostly for us (developers). Partners always should use prod. I can delete it from the docs to avoid confusion

| `tradeAssets` | `TradeAssets` | An object containing information about the selling and buying assets. |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `theme` | `CowSwapTheme` | The theme of the widget (`'dark'` for dark theme or `'light'` for light theme). |
| `logoUrl` | `boolean` | The width of the widget in pixels. |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `hideLogo` | `boolean` | The height of the widget in pixels. |
| `hideNetworkSelector` | `boolean` | Disables an opportunity to change the network from the widget UI. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Allow users to change network from the Widget. Missing defaults

I assume is mandatory if we run it in standalone and there's more than one network?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since an integrator can preselect a network (by passing chainId parameter) they might want to disable the opportunity. For example, some of integrators supports only Gnosis chain, they wouldn't like their users to switch to Mainnet.
And yes, this option works only in standalone mode.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image

@fairlighteth looks like we never show the network selector in the widget mode. Could you please help with that?

| `dynamicHeightEnabled` | `boolean` | Dynamically changes the height of the iframe depending on the content. |
shoom3301 marked this conversation as resolved.
Show resolved Hide resolved
| `enabledTradeTypes` | `Array<TradeType>` | CowSwap provides three trading widgets: swap, limit and twap orders. Using this option you can narrow down the list of available trading widgets. |
| `palette` | `CowSwapWidgetPalette` | Using the palette you can customize the appearance of the widget. For example, you can change the main color of the background and text. |
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We have theme, and palette. Should we make the names closer:

theme: 'dark' | 'light' themePalette: 'dark' | CowSwapWidgetPalette

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm afraid we need both.
them sets a general subset of colors.
palette only overrides some of them

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep, but i could see that in the future palette has more and more options.

BEcause both are part of theming, as a dev i find it easier to find if they show close to each other so their names are similar.

So i was suggesting leaving both: theme & themePallete

However, there's another alternative, since apps will likely setup this once.

What about defining it like this?

type ThemeBase = 'light' | 'dark' | 'auto'

export interface CowSwapTheme {
  baseTheme: ThemeBase
  primaryColor: string
  screenBackground: string
  widgetBackground: string
  textColor: string
}

Then, the theme type would be

{
    theme: ThemeBase | CowSwapTheme
    ...
}

// so users can do:
theme = 'light'
theme = 'dark'
theme = {
   baseTheme: 'light,
   primaryColor: '#fff'
   ...
}

Alternatively:

type ThemeBase = 'light' | 'dark' | 'auto'

export interface CowSwapTheme {
  baseTheme?: ThemeBase
  primaryColor?: string
  screenBackground?: string
  widgetBackground?: string
  textColor?: string
}

{
    theme?: CowSwapTheme // defaults to "{ baseTheme: 'auto' }" which uses the OS
    ...
}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got your point.
Don't you mind if I will implement this in the next PR?
Anyway, currently the palette just randomly bound to colors. It needs and input from Michel


## Widget updating

You can change all possible widget options on the fly:

```typescript
import { cowSwapWidget, CowSwapWidgetParams, CowSwapWidgetSettings } from '@cowprotocol/widget-lib'

const params: CowSwapWidgetParams = {
container: document.getElementById('cowswap-widget'),
metaData: { appKey: 'YOUR_APP_ID', url: 'https://YOUR_APP_URL' },
width: 600,
height: 640,
}
import {cowSwapWidget, CowSwapWidgetParams} from '@cowprotocol/widget-lib'

const container = document.getElementById('cowswap-widget')

const settings: CowSwapWidgetSettings = {
const params: CowSwapWidgetParams = {
metaData: {appKey: 'YOUR_APP_ID', url: 'https://YOUR_APP_URL'},
logoUrl: 'YOUR_LOGO_URL'
}

const updateWidget = cowSwapWidget(params, settings)
const updateWidget = cowSwapWidget(container, params)

// Update the widget
updateWidget({
...settings,
...params,
theme: 'dark', // <- Change theme to dark
hideNetworkSelector: true // <- Hide the network selector
})
Expand Down
Loading