diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3fbbc91a..baf0af97 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,6 +7,8 @@ on: pull_request: branches: - master + - stable + - 'release/**' jobs: build: diff --git a/packages/example/package.json b/packages/example/package.json index 364c0134..85604c6c 100644 --- a/packages/example/package.json +++ b/packages/example/package.json @@ -1,6 +1,6 @@ { "name": "example", - "version": "4.0.0-dev", + "version": "4.0.1-dev", "private": true, "scripts": { "build": "next build", @@ -14,7 +14,7 @@ }, "license": "MIT", "dependencies": { - "@celo/react-celo": "4.0.0-dev", + "@celo/react-celo": "4.0.1-dev", "@celo/contractkit": "^2.0.0", "next": "^12.1.6", "postcss": "^8.4.5", diff --git a/packages/react-celo/__tests__/modals/connect.test.tsx b/packages/react-celo/__tests__/modals/connect.test.tsx new file mode 100644 index 00000000..fd601e0e --- /dev/null +++ b/packages/react-celo/__tests__/modals/connect.test.tsx @@ -0,0 +1,47 @@ +import '@testing-library/jest-dom'; + +import { RenderResult } from '@testing-library/react'; +import React from 'react'; + +import { ConnectModal } from '../../src/modals'; +import { renderComponentInCKProvider } from '../render-in-provider'; + +const theme = { + primary: '#eef2ff', + secondary: '#6366f1', + text: '#ffffff', + textSecondary: '#cbd5e1', + textTertiary: '#64748b', + muted: '#334155', + background: '#1e293b', + error: '#ef4444', +}; + +describe('ConnectModal', () => { + describe('when given reactModalProps', () => { + let dom: RenderResult; + describe('style.overlay', () => { + beforeEach(() => { + dom = renderComponentInCKProvider( + , + { providerProps: { theme } } + ); + }); + it('applies those styles while keeping original', async () => { + const modal = await dom.findByRole('dialog'); + expect(modal.parentElement).toHaveStyle( + 'z-index: 10; background: rgba(30, 41, 59, 0.75)' + ); + }); + it('still uses theme for background on content modal', async () => { + const modal = await dom.findByRole('dialog'); + expect(modal).toHaveStyle('background: rgba(30, 41, 59, 1)'); + }); + }); + }); +}); diff --git a/packages/react-celo/__tests__/react-celo-provider.test.tsx b/packages/react-celo/__tests__/react-celo-provider.test.tsx index 2ee1d445..e5575d39 100644 --- a/packages/react-celo/__tests__/react-celo-provider.test.tsx +++ b/packages/react-celo/__tests__/react-celo-provider.test.tsx @@ -1,51 +1,17 @@ import '@testing-library/jest-dom'; import { CeloContract } from '@celo/contractkit'; -import { act, fireEvent, render, renderHook } from '@testing-library/react'; -import React, { ReactElement } from 'react'; +import { act, fireEvent } from '@testing-library/react'; +import React from 'react'; -import { Mainnet } from '../src/constants'; -import { CeloProvider, CeloProviderProps } from '../src/react-celo-provider'; +import { Mainnet, SupportedProviders } from '../src/constants'; +import { CeloProviderProps } from '../src/react-celo-provider'; import { Maybe, Network, Theme } from '../src/types'; import { UseCelo, useCelo, useCeloInternal } from '../src/use-celo'; - -interface RenderArgs { - providerProps: Partial; -} - -const defaultProps: CeloProviderProps = { - dapp: { - name: 'Testing Celo React', - description: 'Test it well', - url: 'https://celo.developers', - icon: '', - }, - children: null, -}; - -function renderHookInCKProvider( - hook: (i: unknown) => R, - { providerProps }: RenderArgs -) { - return renderHook(hook, { - wrapper: ({ children }) => { - const props = { ...defaultProps, ...providerProps }; - return {children}; - }, - }); -} - -function renderComponentInCKProvider( - ui: ReactElement, - { providerProps }: RenderArgs -) { - return render(ui, { - wrapper: ({ children }) => { - const props = { ...defaultProps, ...providerProps }; - return {children}; - }, - }); -} +import { + renderComponentInCKProvider, + renderHookInCKProvider, +} from './render-in-provider'; describe('CeloProvider', () => { describe('user interface', () => { @@ -54,9 +20,9 @@ describe('CeloProvider', () => { return ; }; - async function stepsToOpenModal() { + async function stepsToOpenModal(props: Partial = {}) { const dom = renderComponentInCKProvider(, { - providerProps: {}, + providerProps: props, }); const button = await dom.findByText('Connect'); @@ -75,6 +41,62 @@ describe('CeloProvider', () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-call expect(modal).toBeVisible(); }); + it('shows default wallets', async () => { + const dom = await stepsToOpenModal(); + + Object.keys(SupportedProviders).map(async (key) => { + const walletName = { ...SupportedProviders }[ + key + ] as SupportedProviders; + + if (walletName === SupportedProviders.Injected) { + return; + } + + const walletEntry = await dom.findByText(walletName); + + expect(walletEntry).toBeVisible(); + }); + }); + }); + + describe('when hideFromModal option is given array', () => { + it('does not show those wallets in the UI', async () => { + const dom = await stepsToOpenModal({ + connectModal: { + providersOptions: { + hideFromDefaults: [ + SupportedProviders.CeloDance, + SupportedProviders.Ledger, + ], + }, + }, + }); + const valora = dom.queryByText('Valora'); + const ledger = dom.queryByText(SupportedProviders.Ledger); + expect(valora).toBeVisible(); + + expect(ledger).toBe(null); + }); + }); + describe('when hideFromModal option is given true', () => { + it('does not show any wallets in the UI', async () => { + const dom = await stepsToOpenModal({ + connectModal: { + providersOptions: { + hideFromDefaults: true, + }, + }, + }); + const valora = dom.queryByText('Valora'); + const ledger = dom.queryByText(SupportedProviders.Ledger); + const none = dom.queryByText('No matches'); + expect(valora).toBe(null); + + expect(ledger).toBe(null); + + expect(none).toBeVisible(); + }); }); }); diff --git a/packages/react-celo/__tests__/render-in-provider.tsx b/packages/react-celo/__tests__/render-in-provider.tsx new file mode 100644 index 00000000..9b9ebe10 --- /dev/null +++ b/packages/react-celo/__tests__/render-in-provider.tsx @@ -0,0 +1,42 @@ +import { render, renderHook } from '@testing-library/react'; +import React, { ReactElement } from 'react'; + +import { CeloProvider, CeloProviderProps } from '../src/react-celo-provider'; + +interface RenderArgs { + providerProps: Partial; +} + +const defaultProps: CeloProviderProps = { + dapp: { + name: 'Testing Celo React', + description: 'Test it well', + url: 'https://celo.developers', + icon: '', + }, + children: null, +}; + +export function renderComponentInCKProvider( + ui: ReactElement, + { providerProps }: RenderArgs +) { + return render(ui, { + wrapper: ({ children }) => { + const props = { ...defaultProps, ...providerProps }; + return {children}; + }, + }); +} + +export function renderHookInCKProvider( + hook: (i: unknown) => R, + { providerProps }: RenderArgs +) { + return renderHook(hook, { + wrapper: ({ children }) => { + const props = { ...defaultProps, ...providerProps }; + return {children}; + }, + }); +} diff --git a/packages/react-celo/package.json b/packages/react-celo/package.json index 27d5599f..6beb62aa 100644 --- a/packages/react-celo/package.json +++ b/packages/react-celo/package.json @@ -1,6 +1,6 @@ { "name": "@celo/react-celo", - "version": "4.0.0-dev", + "version": "4.0.1-dev", "private": false, "scripts": { "prebuild": "mkdir -p lib && node ./scripts/json-to-ts.js package.json lib", @@ -29,7 +29,7 @@ "@celo/wallet-ledger": "^2.0.0", "@celo/wallet-local": "^2.0.0", "@celo/wallet-remote": "^2.0.0", - "@celo/wallet-walletconnect-v1": "4.0.0-dev", + "@celo/wallet-walletconnect-v1": "4.0.1-dev", "@ethersproject/providers": "^5.5.2", "@ledgerhq/hw-transport-webusb": "^5.43.0", "isomorphic-fetch": "^3.0.0", diff --git a/packages/react-celo/src/modals/action.tsx b/packages/react-celo/src/modals/action.tsx index 96bd8e4a..289b6cc5 100644 --- a/packages/react-celo/src/modals/action.tsx +++ b/packages/react-celo/src/modals/action.tsx @@ -94,6 +94,8 @@ export const ActionModal: React.FC = ({ return ( 0} // isOpen ariaHideApp={false} diff --git a/packages/react-celo/src/modals/connect.tsx b/packages/react-celo/src/modals/connect.tsx index 449d8de0..7d605d96 100644 --- a/packages/react-celo/src/modals/connect.tsx +++ b/packages/react-celo/src/modals/connect.tsx @@ -57,6 +57,11 @@ export const styles = cls({ tw-overflow-hidden`, }); +type ReactModalProps = Omit< + ReactModal.Props, + 'onRequestClose' | 'htmlOpenClassName' | 'bodyOpenClassName' +>; + export interface ConnectModalProps { screens?: { [x in SupportedProviders]?: FunctionComponent<{ @@ -69,7 +74,7 @@ export interface ConnectModalProps { onClick: () => void; selected: boolean; }>; - reactModalProps?: Partial; + reactModalProps?: Partial; title?: string | React.ReactElement; providersOptions?: { hideFromDefaults?: true | SupportedProviders[]; @@ -132,8 +137,8 @@ export const ConnectModal: React.FC = ({ searchable = true, } = providersOptions; - const { wallets, allScreens } = useMemo(() => { - let _screens: Record>; + const { wallets, allScreens, includedDefaultProviders } = useMemo(() => { + let _screens: Partial>>; const _wallets = additionalWCWallets || []; if (hideFromDefaults) { @@ -155,15 +160,24 @@ export const ConnectModal: React.FC = ({ } return { + includedDefaultProviders: Object.keys(_screens) as SupportedProviders[], wallets: _wallets, - allScreens: _wallets.reduce((acc, wallet) => { - acc[wallet.id] = walletToScreen(wallet); - return acc; - }, _screens), + allScreens: _wallets.reduce( + (acc: Record>, wallet) => { + acc[wallet.id] = walletToScreen(wallet); + return acc; + }, + _screens + ), }; }, [screens, hideFromDefaults, additionalWCWallets]); - const providers = useProviders(wallets, sort, search); + const providers = useProviders( + wallets, + includedDefaultProviders, + sort, + search + ); const ProviderElement = adding && allScreens?.[adding]; const content = ProviderElement ? ( @@ -178,19 +192,22 @@ export const ConnectModal: React.FC = ({ return ( diff --git a/packages/react-celo/src/styles.css b/packages/react-celo/src/styles.css index 1de881aa..dd67c954 100644 --- a/packages/react-celo/src/styles.css +++ b/packages/react-celo/src/styles.css @@ -1,22 +1,11 @@ /*! tailwindcss v2.0.3 | MIT License | https://tailwindcss.com */ /*! modern-normalize v1.0.0 | MIT License | https://github.com/sindresorhus/modern-normalize */ - /* Document ======== */ -/** -Use a better box model (opinionated). -*/ - -.react-celo *, -.react-celo *::before, -.react-celo *::after { - box-sizing: border-box; -} - /** Use a more readable tab size (opinionated). */ @@ -79,15 +68,6 @@ Text-level semantics ==================== */ -/** -Add the correct text decoration in Chrome, Edge, and Safari. -*/ - -.react-celo abbr[title] { - -webkit-text-decoration: underline dotted; - text-decoration: underline dotted; -} - /** Add the correct font weight in Edge and Safari. */ @@ -97,20 +77,6 @@ Add the correct font weight in Edge and Safari. font-weight: bolder; } -/** -1. Improve consistency of default fonts in all browsers. (https://github.com/sindresorhus/modern-normalize/issues/3) -2. Correct the odd 'em' font sizing in all browsers. -*/ - -.react-celo code, -.react-celo kbd, -.react-celo samp, -.react-celo pre { - font-family: ui-monospace, SFMono-Regular, Consolas, 'Liberation Mono', Menlo, - monospace; /* 1 */ - font-size: 1em; /* 2 */ -} - /** Add the correct font size in all browsers. */ @@ -119,41 +85,6 @@ Add the correct font size in all browsers. font-size: 80%; } -/** -Prevent 'sub' and 'sup' elements from affecting the line height in all browsers. -*/ - -.react-celo sub, -.react-celo sup { - font-size: 75%; - line-height: 0; - position: relative; - vertical-align: baseline; -} - -.react-celo sub { - bottom: -0.25em; -} - -.react-celo sup { - top: -0.5em; -} - -/* -Tabular data -============ -*/ - -/** -1. Remove text indentation from table contents in Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=999088, https://bugs.webkit.org/show_bug.cgi?id=201297) -2. Correct table border color inheritance in all Chrome and Safari. (https://bugs.chromium.org/p/chromium/issues/detail?id=935729, https://bugs.webkit.org/show_bug.cgi?id=195016) -*/ - -.react-celo table { - text-indent: 0; /* 1 */ - border-color: inherit; /* 2 */ -} - /* Forms ===== @@ -223,14 +154,6 @@ See: https://github.com/mozilla/gecko-dev/blob/2f9eacd9d3d995c937b4251a5557d95d4 box-shadow: none; } -/** -Remove the padding so developers are not caught out when they zero out 'fieldset' elements in all browsers. -*/ - -.react-celo legend { - padding: 0; -} - /** Add the correct vertical alignment in Chrome and Firefox. */ @@ -266,29 +189,11 @@ Remove the inner padding in Chrome and Safari on macOS. -webkit-appearance: none; } -/** -1. Correct the inability to style clickable types in iOS and Safari. -2. Change font properties to 'inherit' in Safari. -*/ - -.react-celo ::-webkit-file-upload-button { - -webkit-appearance: button; /* 1 */ - font: inherit; /* 2 */ -} - /* Interactive =========== */ -/* -Add the correct display in Chrome and Safari. -*/ - -.react-celo summary { - display: list-item; -} - /** * Manually forked from SUIT CSS Base: https://github.com/suitcss/base * A thin layer on top of normalize.css that provides a starting point more @@ -299,9 +204,6 @@ Add the correct display in Chrome and Safari. * Removes the default spacing and border for appropriate elements. */ -.react-celo blockquote, -.react-celo dl, -.react-celo dd, .react-celo h1, .react-celo h2, .react-celo h3, @@ -330,71 +232,6 @@ Add the correct display in Chrome and Safari. outline: 5px auto -webkit-focus-ring-color; } -.react-celo fieldset { - margin: 0; - padding: 0; -} - -.react-celo ol, -.react-celo ul { - list-style: none; - margin: 0; - padding: 0; -} - -/** - * Tailwind custom reset styles - */ - -/** - * 1. Use the user's configured `sans` font-family (with Tailwind's default - * sans-serif font stack as a fallback) as a sane default. - * 2. Use Tailwind's default "normal" line-height so the user isn't forced - * to override it to ensure consistency even when using the default theme. - */ - -.react-celo { - font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, - 'Segoe UI', Roboto, 'Helvetica Neue', Arial, 'Noto Sans', sans-serif, - 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; /* 1 */ - line-height: 1.5; /* 2 */ -} - -/** - * Inherit font-family and line-height from `html` so users can set them as - * a class directly on the `html` element. - */ -/* .react-celo { - font-family: inherit; - line-height: inherit; -} */ - -/** - * 1. Prevent padding and border from affecting element width. - * - * We used to set this in the html element and inherit from - * the parent element for everything else. This caused issues - * in shadow-dom-enhanced elements like
where the content - * is wrapped by a div with box-sizing set to `content-box`. - * - * https://github.com/mozdevs/cssremedy/issues/4 - * - * - * 2. Allow adding a border to an element by just adding a border-width. - * - * By default, the way the browser specifies that an element should have no - * border is by setting it's border-style to `none` in the user-agent - * stylesheet. - * - * In order to easily add borders to elements by just setting the `border-width` - * property, we change the default border-style for all elements to `solid`, and - * use border-width to hide them instead. This way our `border` utilities only - * need to set the `border-width` property instead of the entire `border` - * shorthand, making our border utilities much more straightforward to compose. - * - * https://github.com/tailwindcss/tailwindcss/pull/116 - */ - .react-celo *, .react-celo ::before, .react-celo ::after { @@ -483,55 +320,16 @@ Add the correct display in Chrome and Safari. color: inherit; } -/** - * Use the configured 'mono' font family for elements that - * are expected to be rendered with a monospace font, falling - * back to the system monospace stack if there is no configured - * 'mono' font family. - */ - -.react-celo pre, -.react-celo code, -.react-celo kbd, -.react-celo samp { - font-family: ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, - 'Liberation Mono', 'Courier New', monospace; -} - -/** - * Make replaced elements `display: block` by default as that's - * the behavior you want almost all of the time. Inspired by - * CSS Remedy, with `svg` added as well. - * - * https://github.com/mozdevs/cssremedy/issues/14 - */ - .react-celo img, -.react-celo svg, -.react-celo video, -.react-celo canvas, -.react-celo audio, -.react-celo iframe, -.react-celo embed, -.react-celo object { +.react-celo video { display: block; - vertical-align: middle; -} -/** - * Constrain images and videos to the parent width and preserve - * their instrinsic aspect ratio. - * - * https://github.com/mozdevs/cssremedy/issues/14 - */ - -.react-celo img, -.react-celo video { max-width: 100%; height: auto; + vertical-align: middle; } -/* +/* Scrollbar overrides =================== */ @@ -595,6 +393,14 @@ Spinner animation: react-celo-spinner-dash 1.5s ease-in-out infinite; } +.react-celo .justify-center { + justify-content: center; +} + +.react-celo .justify-between { + justify-content: space-between; +} + @keyframes react-celo-spinner-rotate { 100% { transform: rotate(360deg); @@ -623,19 +429,28 @@ Spinner } } -@tailwind base; @tailwind components; @tailwind utilities; -body { +.react-celo-modal-open-body { min-height: 100vh; /* mobile viewport bug fix */ min-height: -webkit-fill-available; + overflow: hidden; +} + +@media (max-width: 900px) { + .react-celo-modal-open-html { + height: -webkit-fill-available; + } } -html { - height: -webkit-fill-available; +.tw-drop-shadow { + --tw-drop-shadow: drop-shadow(0 1px 2px rgba(0, 0, 0, 0.1)) + drop-shadow(0 1px 1px rgba(0, 0, 0, 0.06)) !important; + filter: var(--tw-drop-shadow); } +/* These are use by spinner */ * { --tw-translate-x: 0; diff --git a/packages/react-celo/src/utils/useProviders.ts b/packages/react-celo/src/utils/useProviders.ts index d7db6d91..be3874d0 100644 --- a/packages/react-celo/src/utils/useProviders.ts +++ b/packages/react-celo/src/utils/useProviders.ts @@ -5,6 +5,7 @@ import { localStorageKeys, Priorities, PROVIDERS, + SupportedProviders, WalletTypes, } from '../constants'; import { Maybe, Provider, WalletConnectProvider, WalletEntry } from '../types'; @@ -44,18 +45,22 @@ export function getRecent(): Maybe { export default function useProviders( wallets: WalletEntry[] = [], + includedDefaultProviders: SupportedProviders[], sort = defaultProviderSort, search?: string ) { const record: Record = useMemo( () => ({ - ...PROVIDERS, + ...includedDefaultProviders.reduce((all, current) => { + all[current] = PROVIDERS[current]; + return all; + }, {} as Record), ...wallets.reduce((acc, wallet) => { acc[wallet.id] = walletToProvider(wallet); return acc; }, {} as Record), }), - [wallets] + [wallets, includedDefaultProviders] ); const providers = useMemo<[providerKey: string, provider: Provider][]>(() => { diff --git a/packages/wallet-walletconnect/package.json b/packages/wallet-walletconnect/package.json index e60d006e..380ff9c6 100644 --- a/packages/wallet-walletconnect/package.json +++ b/packages/wallet-walletconnect/package.json @@ -1,6 +1,6 @@ { "name": "@celo/wallet-walletconnect", - "version": "4.0.0-dev", + "version": "4.0.1-dev", "description": "WalletConnect wallet implementation", "author": "Celo", "license": "Apache-2.0", diff --git a/packages/walletconnect-v1/package.json b/packages/walletconnect-v1/package.json index cf88a407..93a161f8 100644 --- a/packages/walletconnect-v1/package.json +++ b/packages/walletconnect-v1/package.json @@ -1,6 +1,6 @@ { "name": "@celo/wallet-walletconnect-v1", - "version": "4.0.0-dev", + "version": "4.0.1-dev", "description": "WalletConnect wallet legacy (v1) implementation", "author": "Celo", "license": "Apache-2.0",