From 40fecdda86dd757844148604ad5faedc40a2f98f Mon Sep 17 00:00:00 2001 From: Pedro Ladaria Date: Fri, 27 Sep 2024 14:45:16 +0200 Subject: [PATCH] feat(Sheet): lazy load sheet implementations (#1250) * `sheet-root` now has the bare minimum to work, it lazy loads everything when needed, including the native implementation. * Web implementations of native sheets (defined by the bridge) have been deprecated. The recommended way to use that predefined sheets is using the `showSheet` function. ## Pending tasks * [x] Update documentation * [x] Verify in webapp * https://webapp-sheet.movistar-es-dev.svc.dev.tuenti.io/pages/example-bottom-sheet * [x] web * [x] android native * [x] ios native ## Before Bundles from the webview entrypoint ![image](https://github.com/user-attachments/assets/4a2cb8d3-3524-4bbf-8d26-8fccc632e34a) ## After The arrow points to the sheet-root module ![image](https://github.com/user-attachments/assets/f094f693-0cec-4813-b8ee-ad5f1f1f8ec2) ![image](https://github.com/user-attachments/assets/639a4d1d-c56c-4fc4-b3fb-7b006bee58d2) --------- Co-authored-by: Pedro Ladaria --- doc/sheet.md | 134 ++-- doc/texts.md | 51 +- doc/theme-config.md | 4 +- package.json | 2 +- .../sheet-presets-story.tsx | 389 +++++++++ ...st-tsx-actions-sheet-in-desktop-1-snap.png | Bin 19052 -> 18911 bytes ...-actions-sheet-in-large-desktop-1-snap.png | Bin 23757 -> 23620 bytes ...tsx-actions-sheet-in-mobile-ios-1-snap.png | Bin 29105 -> 28955 bytes ...t-with-safe-inset-at-the-bottom-1-snap.png | Bin 29158 -> 28957 bytes .../sheet-screenshot-test.tsx | 12 +- src/__stories__/sheet-story.tsx | 376 +-------- src/__tests__/sheet-test.tsx | 42 +- src/index.tsx | 23 +- src/sheet-action-row.css.ts | 33 + src/sheet-actions-list.tsx | 113 +++ src/sheet-actions.tsx | 95 +++ src/{sheet.css.ts => sheet-common.css.ts} | 35 - src/sheet-common.tsx | 396 +++++++++ src/sheet-info.css.ts | 7 + src/sheet-info.tsx | 102 +++ src/sheet-native.tsx | 178 +++++ src/sheet-radio-list.tsx | 107 +++ src/sheet-root.tsx | 404 ++-------- src/sheet-types.tsx | 86 ++ src/sheet-web.tsx | 140 ++++ src/sheet.tsx | 755 ------------------ 26 files changed, 1832 insertions(+), 1652 deletions(-) create mode 100644 src/__private_stories__/sheet-presets-story.tsx create mode 100644 src/sheet-action-row.css.ts create mode 100644 src/sheet-actions-list.tsx create mode 100644 src/sheet-actions.tsx rename src/{sheet.css.ts => sheet-common.css.ts} (87%) create mode 100644 src/sheet-common.tsx create mode 100644 src/sheet-info.css.ts create mode 100644 src/sheet-info.tsx create mode 100644 src/sheet-native.tsx create mode 100644 src/sheet-radio-list.tsx create mode 100644 src/sheet-types.tsx create mode 100644 src/sheet-web.tsx delete mode 100644 src/sheet.tsx diff --git a/doc/sheet.md b/doc/sheet.md index 5ed178c21b..bab2f443ef 100644 --- a/doc/sheet.md +++ b/doc/sheet.md @@ -3,78 +3,21 @@ Mística provides a sheet component that can be used to display a modal-like content from over the main content of the screen. -## Basic usage +## Predefined sheets -You can show any content you want inside the sheet by passing it as a child of the component. - -```jsx -import {Sheet} from 'mistica'; - -const MyComponent = () => { - const [showSheet, setShowSheet] = useState(false); - return ( - <> - setShowSheet(true)}>show sheet - {showSheet && ( - setShowSheet(false)}> - - - )} - - ); -}; -``` - -The sheet will close when the user does the swipe down gesture or when the background overlay is touched. The -`onClose` callback is called when the closing animation finishes, that's the right place to unmount the sheet -as shown in the example above. - -You can also close the sheet programmatically using the render prop: - -```jsx -import {Sheet} from 'mistica'; - -const MyComponent = () => { - const [showSheet, setShowSheet] = useState(false); - return ( - <> - setShowSheet(true)}>show sheet - {showSheet && ( - setShowSheet(false)}> - {({closeModal, modalTitleId}) => ( - <> - My sheet - - Close - - )} - - )} - - ); -}; -``` - -## Sheet with predefined content - -Mística predefines some common sheet patterns for you to use: `RadioListSheet`, `ActionsListSheet`, -`InfoSheet` and `ActionsSheet`. You can see examples in the storybook. - -## `showSheet` imperative api +Some predefined sheets are available: `RadioListSheet`, `ActionsListSheet`, `InfoSheet` and `ActionsSheet`. +You can see examples in Storybook. -Instead of using React components, there is an alternative way to show a sheet: using the `showSheet` -function. For this to work, you need to render a `` somewhere in your app, typically where you -render the mistica ``, but it could be anywhere. +To use them, first you must configure the `SheetRoot` component in your app: ```jsx import {SheetRoot} from '@telefonica/mistica'; export const App = () => { return ( - <> - - - + + + ); }; ``` @@ -112,22 +55,67 @@ const MyComponent = () => { ### Native implementation -If you are using mistica inside Novum app, you can configure `showSheet` to use the native sheet -implementation with the webview bridge. +If your app is served inside a webview and uses the `webview-bridge` library, the native implementation of the +predefined sheets will be used. -```jsx -import {SheetRoot} from '@telefonica/mistica'; +```tsx import {bottomSheet, isWebViewBridgeAvailable} from '@tef-novum/webview-bridge'; -export const App = () => { +// ... + + +``` + +When possible, always use the native implementation, as it provides a better user experience. + +## Custom sheets + +You can show any content you want inside the sheet by passing it as a child of the component. + +```jsx +import {Sheet} from 'mistica'; + +const MyComponent = () => { + const [showSheet, setShowSheet] = useState(false); return ( <> - - + setShowSheet(true)}>show sheet + {showSheet && ( + setShowSheet(false)}> + + + )} ); }; ``` -Then when you call `showSheet`, if the code is running inside a webview, it will use the native implementation -instead of the web one. +The sheet will close when the user does the swipe down gesture or when the background overlay is touched. The +`onClose` callback is called when the closing animation finishes, that's the right place to unmount the sheet +as shown in the example above. + +You can also close the sheet programmatically using the render prop: + +```jsx +import {Sheet} from 'mistica'; + +const MyComponent = () => { + const [showSheet, setShowSheet] = useState(false); + return ( + <> + setShowSheet(true)}>show sheet + {showSheet && ( + setShowSheet(false)}> + {({closeModal, modalTitleId}) => ( + <> + My sheet + + Close + + )} + + )} + + ); +}; +``` diff --git a/doc/texts.md b/doc/texts.md index fe5f4632c2..baa79c7e08 100644 --- a/doc/texts.md +++ b/doc/texts.md @@ -2,39 +2,9 @@ Some components use some default texts that you can customize using [`theme` prop](./theme-config.md) -These are the customizable texts and their default values: - -- `expirationDatePlaceholder`: `'MM/AA'` -- `enablePasswordVisibility`: `'Mostrar contraseña'`, -- `disablePasswordVisibility`: `'Ocultar contraseña'`, -- `loading`: `'Cargando'` -- `linkOpensInNewTab`: `'Se abre en ventana nueva'` -- `modalClose`: `'Cerrar'` -- `dialogCancelButton`: `'Cancelar'` -- `dialogAcceptButton`: `'Aceptar'` -- `formFieldOptionalLabelSuffix`: `'opcional'` -- `formFieldErrorIsMandatory`: `'Este campo es obligatorio'` -- `formCreditCardNumberLabel`: `'Número de tarjeta'` -- `formCreditCardExpirationLabel`: `'Caducidad'` -- `formCreditCardCvvLabel`: `'CVV'` -- `formCreditCardCvvError`: `'CVV incorrecto'` -- `formCreditCardCvvTooltipVisaMcButton`: `'Mostrar ayuda CVV'` -- `formCreditCardCvvTooltipVisaMc`: `'El CVV son los 3 últimos dígitos del reverso de tu tarjeta'` -- `formCreditCardCvvTooltipAmex`: `'Si es American Express, añade los 4 dígitos del anverso'` -- `formCreditCardExpirationError`: `'Fecha no válida'` -- `formCreditCardNumberError`: `'No es un número de tarjeta válido'` -- `formDateOutOfRangeError`: `'Fecha no permitida'` -- `formEmailError`: `'Email incorrecto'` -- `formIbanError`: `'IBAN incorrecto'` -- `closeButtonLabel`: `'Cerrar'` -- `formSearchClear`: `'Borrar búsqueda'` -- `menuLabelSuffix`: `'menú'` -- `openNavigationMenu`: `'Abrir menú de navegación'` -- `closeNavigationMenu`: `'Cerrar menú de navegación'` - You can customize them in your page. For example: -```js +```tsx ``` +See the `Dictionary` type to known all the available texts. + If your application supports multi language, you may need to override all the texts and use localized translation tokens depending on your user preferred language. + +## Using Mística text tokens + +You can use Mística tokens in your texts. The translate function `t` will translate the token using the +configured locale in the `ThemeContextProvider`. + +Example: + +```tsx +import {textTokens} from '@telefonica/mistica'; + +const MyComponent = () => { + const {t} = useTheme(); + + return
{t(textTokens.formCreditCardExpirationError)}
; +}; +``` diff --git a/doc/theme-config.md b/doc/theme-config.md index 3349e047cf..48a329d429 100644 --- a/doc/theme-config.md +++ b/doc/theme-config.md @@ -49,7 +49,9 @@ Here is a description of every attribute: - `userAgent:` **IMPORTANT** In case you are using SSR, you should set this value with the user-agent header you receive on every request to your server, otherwise the server-side render won't take the user agent into account. -- `texts?`: some copies you can customize. See [customizable texts doc](./texts.md). +- `texts?`: some copies you can customize. See [texts doc](./texts.md). +- `t`: this is the translate funtion. It accepts a token as exported by `textTokens`. See + [texts doc](./texts.md). - `analytics?`: see [analytics docs](./analytics.md). - `Link?`: the `Link` component you want to use by Touchables that use the prop `to`. By default, the lib uses an anchor tag (``). Use this prop to use the Link component from ReactRouter, Next.js or any other diff --git a/package.json b/package.json index adc78ec4fd..e8cd864282 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "ts-check": "tsc --project tsconfig.json --noEmit", "build": "yarn clean && node scripts/build.js", "compile": "node scripts/compile.js", - "clean": "rimraf dist && rimraf dist-es && rimraf dist-ts && rimraf css/mistica.css && rimraf community.d.ts && rimraf community.js && rimraf node_modules/.cache", + "clean": "rimraf dist && rimraf dist-es && rimraf dist-ts && rimraf css/mistica.css && rimraf community.d.ts && rimraf community.js && rimraf node_modules/.cache && bash -c 'yarn jest --clearCache > /dev/null 2>&1'", "prepublishOnly": "node scripts/prepublish-only.js", "prepack": "yarn build", "storybook": "storybook dev -p 6006", diff --git a/src/__private_stories__/sheet-presets-story.tsx b/src/__private_stories__/sheet-presets-story.tsx new file mode 100644 index 0000000000..1aa0eaab0f --- /dev/null +++ b/src/__private_stories__/sheet-presets-story.tsx @@ -0,0 +1,389 @@ +import * as React from 'react'; +import { + Box, + ButtonPrimary, + Circle, + IconCheckRegular, + IconCocktailRegular, + IconLightningRegular, + IconMobileDeviceRegular, + IconTrashCanRegular, + SheetRoot, + skinVars, + Stack, + Text3, +} from '..'; +import RadioListSheet from '../sheet-radio-list'; +import InfoSheet from '../sheet-info'; +import ActionsSheet from '../sheet-actions'; +import ActionsListSheet from '../sheet-actions-list'; + +export default { + title: 'Private/Sheet Presets', + component: SheetRoot, + parameters: { + fullScreen: true, + }, +}; + +type SheetArgs = { + title: string; + subtitle: string; + description: string; + multiparagraphDescription: boolean; +}; + +type RadioListSheetArgs = SheetArgs & { + selectedId: string; +}; + +export const RadioList: StoryComponent = ({ + title, + subtitle, + description, + multiparagraphDescription, + selectedId, +}) => { + const [open, setOpen] = React.useState(false); + const [selected, setSelected] = React.useState(null); + + return ( + + + { + setOpen(true); + setSelected(null); + }} + > + Open + + {selected && ( + + selectedId: {selected} + + )} + + + {open && ( + { + setOpen(false); + }} + onSelect={(item) => { + setSelected(item); + }} + title={title} + subtitle={subtitle} + description={ + description && multiparagraphDescription ? [description, description] : description + } + selectedId={selectedId === 'none' ? undefined : selectedId} + items={[ + 'Apple', + 'Banana', + 'Pineapple', + 'Mango', + 'Peach', + 'Pear', + 'Strawberry', + 'Watermelon', + 'Kiwi', + 'Cherry', + 'Grape', + 'Lemon', + 'Lime', + ].map((fruit, idx) => ({ + id: String(idx), + title: fruit, + description: 'Description', + asset: ( + + + + ), + }))} + /> + )} + + ); +}; + +RadioList.storyName = 'RadioListSheet'; +RadioList.args = { + title: 'Select a fruit', + subtitle: 'Subtitle', + description: 'Description', + multiparagraphDescription: false, + selectedId: 'none', +}; +RadioList.argTypes = { + selectedId: { + control: {type: 'select'}, + options: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', 'none'], + }, + multiparagraphDescription: { + if: {arg: 'description'}, + }, +}; + +export const ActionsList: StoryComponent = ({ + title, + subtitle, + description, + multiparagraphDescription, +}) => { + const [open, setOpen] = React.useState(false); + const [selected, setSelected] = React.useState(null); + + return ( + + + { + setOpen(true); + setSelected(null); + }} + > + Open + + {selected && ( + + selectedId: {selected} + + )} + + + {open && ( + { + setOpen(false); + }} + onSelect={(item) => { + setSelected(item); + }} + title={title} + subtitle={subtitle} + description={ + description && multiparagraphDescription ? [description, description] : description + } + items={[ + { + id: '1', + title: 'Action with icon', + icon: { + Icon: IconLightningRegular, + }, + }, + { + id: '2', + title: 'Action without icon', + }, + { + id: '3', + title: 'Destructive action', + style: 'destructive', + icon: { + Icon: IconTrashCanRegular, + }, + }, + ]} + /> + )} + + ); +}; + +ActionsList.storyName = 'ActionsListSheet'; +ActionsList.args = { + title: 'Title', + subtitle: 'Subtitle', + description: 'Description', + multiparagraphDescription: false, +}; +ActionsList.argTypes = { + multiparagraphDescription: { + if: {arg: 'description'}, + }, +}; + +type InfoSheetArgs = SheetArgs & { + numItems: number; + iconType: 'bullet' | 'regular' | 'small'; +}; + +export const Info: StoryComponent = ({ + title, + subtitle, + description, + multiparagraphDescription, + numItems, + iconType, +}) => { + const [open, setOpen] = React.useState(false); + + return ( + + { + setOpen(true); + }} + > + Open + + + {open && ( + { + setOpen(false); + }} + title={title} + subtitle={subtitle} + description={ + description && multiparagraphDescription ? [description, description] : description + } + items={Array.from({length: numItems}, (_, idx) => ({ + id: String(idx), + title: 'Item ' + idx, + description: 'Description', + icon: + iconType === 'bullet' + ? {type: 'bullet'} + : { + type: iconType, + Icon: { + regular: IconCocktailRegular, + small: IconCheckRegular, + }[iconType], + }, + }))} + /> + )} + + ); +}; + +Info.storyName = 'InfoSheet'; +Info.args = { + title: 'Title', + subtitle: 'Subtitle', + description: 'Description', + numItems: 5, + iconType: 'bullet', + multiparagraphDescription: false, +}; +Info.argTypes = { + iconType: { + control: {type: 'select'}, + options: ['bullet', 'regular', 'small'], + }, + multiparagraphDescription: { + if: {arg: 'description'}, + }, +}; + +type ActionsSheetArgs = SheetArgs & { + buttonText: string; + secondaryButtonText: string; + buttonLinkText: string; + chevron: boolean; +}; + +export const Actions: StoryComponent = ({ + title, + subtitle, + description, + multiparagraphDescription, + buttonText, + secondaryButtonText, + buttonLinkText, + chevron, +}) => { + const [open, setOpen] = React.useState(false); + const [pressedButton, setPressedButton] = React.useState(null); + + return ( + + + { + setOpen(true); + setPressedButton(null); + }} + > + Open + + {pressedButton && ( + + pressedButton: {pressedButton} + + )} + + + {open && ( + { + setOpen(false); + }} + onPressButton={setPressedButton} + title={title} + subtitle={subtitle} + description={ + description && multiparagraphDescription ? [description, description] : description + } + button={{ + text: buttonText, + }} + secondaryButton={ + secondaryButtonText + ? { + text: secondaryButtonText, + } + : undefined + } + buttonLink={ + buttonLinkText + ? { + text: buttonLinkText, + withChevron: chevron, + } + : undefined + } + /> + )} + + ); +}; + +Actions.storyName = 'ActionsSheet'; +Actions.args = { + title: 'Title', + subtitle: 'Subtitle', + description: 'Description', + multiparagraphDescription: false, + buttonText: 'Button', + secondaryButtonText: 'Secondary button', + buttonLinkText: 'Link', + chevron: false, +}; +Actions.argTypes = { + chevron: { + control: {type: 'boolean'}, + if: {arg: 'buttonLinkText'}, + }, + multiparagraphDescription: { + if: {arg: 'description'}, + }, +}; diff --git a/src/__screenshot_tests__/__image_snapshots__/sheet-screenshot-test-tsx-actions-sheet-in-desktop-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/sheet-screenshot-test-tsx-actions-sheet-in-desktop-1-snap.png index 187d4ddbbb3852657b99c7d890a389591f987005..8949944421967850ecfb4e03c938537d2ee7b957 100644 GIT binary patch literal 18911 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 literal 19052 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 MV*6wD4>y1LZ-<^)vH$=8 diff --git a/src/__screenshot_tests__/__image_snapshots__/sheet-screenshot-test-tsx-actions-sheet-in-large-desktop-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/sheet-screenshot-test-tsx-actions-sheet-in-large-desktop-1-snap.png index e483971e0ce5eee6e4800171d12487194f7ee136..0b43c8e0c33ca0a8a18dc4567e135ac4db02e49e 100644 GIT binary patch literal 23620 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 literal 23757 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 L_@m@^mp}gpm0Djm diff --git a/src/__screenshot_tests__/__image_snapshots__/sheet-screenshot-test-tsx-actions-sheet-in-mobile-ios-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/sheet-screenshot-test-tsx-actions-sheet-in-mobile-ios-1-snap.png index bfb45878824b295da0fbdb0acead9d444eab62aa..95273298e8232f410d7f1e61870623ad19544640 100644 GIT binary patch literal 28955 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

A=|(~a8Mpe}_dmD4tmd3D8-;&tm%P+9|dJ}a^U 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 C%F%oP literal 29105 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 diff --git a/src/__screenshot_tests__/__image_snapshots__/sheet-screenshot-test-tsx-actions-sheet-with-safe-inset-at-the-bottom-1-snap.png b/src/__screenshot_tests__/__image_snapshots__/sheet-screenshot-test-tsx-actions-sheet-with-safe-inset-at-the-bottom-1-snap.png index 14a8f09dd15153e3bf044a0a016a19784c658d07..7da4392f811a0bf8d228c96fdec5fc26790f772f 100644 GIT binary patch literal 28957 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 { test.each(TESTABLE_DEVICES)('ActionsListSheet in %s', async (device) => { const page = await openStoryPage({ - id: 'components-modals-sheet--actions-list', + id: 'private-sheet-presets--actions-list', device, }); @@ -37,7 +37,7 @@ test.each(TESTABLE_DEVICES)('ActionsListSheet in %s', async (device) => { test.each(TESTABLE_DEVICES)('RadioListSheet in %s', async (device) => { const page = await openStoryPage({ - id: 'components-modals-sheet--radio-list', + id: 'private-sheet-presets--radio-list', device, }); @@ -53,7 +53,7 @@ test.each(TESTABLE_DEVICES)('RadioListSheet in %s', async (device) => { test.each(TESTABLE_DEVICES)('InfoSheet in %s', async (device) => { const page = await openStoryPage({ - id: 'components-modals-sheet--info', + id: 'private-sheet-presets--info', device, }); @@ -69,7 +69,7 @@ test.each(TESTABLE_DEVICES)('InfoSheet in %s', async (device) => { test('InfoSheet with multiple description paragraphs', async () => { const page = await openStoryPage({ - id: 'components-modals-sheet--info', + id: 'private-sheet-presets--info', device: 'MOBILE_IOS', args: { description: 'Description paragraph', @@ -89,7 +89,7 @@ test('InfoSheet with multiple description paragraphs', async () => { test.each(TESTABLE_DEVICES_WITH_LARGE_DESKTOP)('ActionsSheet in %s', async (device) => { const page = await openStoryPage({ - id: 'components-modals-sheet--actions', + id: 'private-sheet-presets--actions', device, }); @@ -105,7 +105,7 @@ test.each(TESTABLE_DEVICES_WITH_LARGE_DESKTOP)('ActionsSheet in %s', async (devi test('ActionsSheet with safe inset at the bottom', async () => { const page = await openStoryPage({ - id: 'components-modals-sheet--actions', + id: 'private-sheet-presets--actions', device: 'MOBILE_IOS_INSET', }); diff --git a/src/__stories__/sheet-story.tsx b/src/__stories__/sheet-story.tsx index 7916a7e0d9..69e1ab37ab 100644 --- a/src/__stories__/sheet-story.tsx +++ b/src/__stories__/sheet-story.tsx @@ -4,26 +4,17 @@ import { SheetRoot, Box, ButtonPrimary, - Circle, - IconCheckRegular, - IconCocktailRegular, - IconLightningRegular, - IconMobileDeviceRegular, - IconTrashCanRegular, Inline, Placeholder, ResponsiveLayout, showSheet, - skinVars, Stack, Text2, - Text3, Title1, Callout, IconInformationRegular, ButtonLink, } from '..'; -import {ActionsSheet, ActionsListSheet, InfoSheet, RadioListSheet} from '../sheet'; import avatarImg from './images/avatar.jpg'; export default { @@ -80,376 +71,19 @@ export const Default: StoryComponent = () => { Default.storyName = 'Sheet'; -type SheetArgs = { +type ShowSheetArgs = { title: string; subtitle: string; description: string; multiparagraphDescription: boolean; }; -type RadioListSheetArgs = SheetArgs & { - selectedId: string; -}; - -export const RadioList: StoryComponent = ({ - title, - subtitle, - description, - multiparagraphDescription, - selectedId, -}) => { - const [open, setOpen] = React.useState(false); - const [selected, setSelected] = React.useState(null); - - return ( - - - { - setOpen(true); - setSelected(null); - }} - > - Open - - {selected && ( - - selectedId: {selected} - - )} - - - {open && ( - { - setOpen(false); - }} - onSelect={(item) => { - setSelected(item); - }} - title={title} - subtitle={subtitle} - description={ - description && multiparagraphDescription ? [description, description] : description - } - selectedId={selectedId === 'none' ? undefined : selectedId} - items={[ - 'Apple', - 'Banana', - 'Pineapple', - 'Mango', - 'Peach', - 'Pear', - 'Strawberry', - 'Watermelon', - 'Kiwi', - 'Cherry', - 'Grape', - 'Lemon', - 'Lime', - ].map((fruit, idx) => ({ - id: String(idx), - title: fruit, - description: 'Description', - asset: ( - - - - ), - }))} - /> - )} - - ); -}; - -RadioList.storyName = 'RadioListSheet'; -RadioList.args = { - title: 'Select a fruit', - subtitle: 'Subtitle', - description: 'Description', - multiparagraphDescription: false, - selectedId: 'none', -}; -RadioList.argTypes = { - selectedId: { - control: {type: 'select'}, - options: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', 'none'], - }, - multiparagraphDescription: { - if: {arg: 'description'}, - }, -}; - -export const ActionsList: StoryComponent = ({ +export const ShowSheet: StoryComponent = ({ title, subtitle, description, multiparagraphDescription, }) => { - const [open, setOpen] = React.useState(false); - const [selected, setSelected] = React.useState(null); - - return ( - - - { - setOpen(true); - setSelected(null); - }} - > - Open - - {selected && ( - - selectedId: {selected} - - )} - - - {open && ( - { - setOpen(false); - }} - onSelect={(item) => { - setSelected(item); - }} - title={title} - subtitle={subtitle} - description={ - description && multiparagraphDescription ? [description, description] : description - } - items={[ - { - id: '1', - title: 'Action with icon', - icon: { - Icon: IconLightningRegular, - }, - }, - { - id: '2', - title: 'Action without icon', - }, - { - id: '3', - title: 'Destructive action', - style: 'destructive', - icon: { - Icon: IconTrashCanRegular, - }, - }, - ]} - /> - )} - - ); -}; - -ActionsList.storyName = 'ActionsListSheet'; -ActionsList.args = { - title: 'Title', - subtitle: 'Subtitle', - description: 'Description', - multiparagraphDescription: false, -}; -ActionsList.argTypes = { - multiparagraphDescription: { - if: {arg: 'description'}, - }, -}; - -type InfoSheetArgs = SheetArgs & { - numItems: number; - iconType: 'bullet' | 'regular' | 'small'; -}; - -export const Info: StoryComponent = ({ - title, - subtitle, - description, - multiparagraphDescription, - numItems, - iconType, -}) => { - const [open, setOpen] = React.useState(false); - - return ( - - { - setOpen(true); - }} - > - Open - - - {open && ( - { - setOpen(false); - }} - title={title} - subtitle={subtitle} - description={ - description && multiparagraphDescription ? [description, description] : description - } - items={Array.from({length: numItems}, (_, idx) => ({ - id: String(idx), - title: 'Item ' + idx, - description: 'Description', - icon: - iconType === 'bullet' - ? {type: 'bullet'} - : { - type: iconType, - Icon: { - regular: IconCocktailRegular, - small: IconCheckRegular, - }[iconType], - }, - }))} - /> - )} - - ); -}; - -Info.storyName = 'InfoSheet'; -Info.args = { - title: 'Title', - subtitle: 'Subtitle', - description: 'Description', - numItems: 5, - iconType: 'bullet', - multiparagraphDescription: false, -}; -Info.argTypes = { - iconType: { - control: {type: 'select'}, - options: ['bullet', 'regular', 'small'], - }, - multiparagraphDescription: { - if: {arg: 'description'}, - }, -}; - -type ActionsSheetArgs = SheetArgs & { - buttonText: string; - secondaryButtonText: string; - buttonLinkText: string; - chevron: boolean; -}; - -export const Actions: StoryComponent = ({ - title, - subtitle, - description, - multiparagraphDescription, - buttonText, - secondaryButtonText, - buttonLinkText, - chevron, -}) => { - const [open, setOpen] = React.useState(false); - const [pressedButton, setPressedButton] = React.useState(null); - - return ( - - - { - setOpen(true); - setPressedButton(null); - }} - > - Open - - {pressedButton && ( - - pressedButton: {pressedButton} - - )} - - - {open && ( - { - setOpen(false); - }} - onPressButton={setPressedButton} - title={title} - subtitle={subtitle} - description={ - description && multiparagraphDescription ? [description, description] : description - } - button={{ - text: buttonText, - }} - secondaryButton={ - secondaryButtonText - ? { - text: secondaryButtonText, - } - : undefined - } - buttonLink={ - buttonLinkText - ? { - text: buttonLinkText, - withChevron: chevron, - } - : undefined - } - /> - )} - - ); -}; - -Actions.storyName = 'ActionsSheet'; -Actions.args = { - title: 'Title', - subtitle: 'Subtitle', - description: 'Description', - multiparagraphDescription: false, - buttonText: 'Button', - secondaryButtonText: 'Secondary button', - buttonLinkText: 'Link', - chevron: false, -}; -Actions.argTypes = { - chevron: { - control: {type: 'boolean'}, - if: {arg: 'buttonLinkText'}, - }, - multiparagraphDescription: { - if: {arg: 'description'}, - }, -}; - -type RootArgs = { - title: string; - subtitle: string; - description: string; - multiparagraphDescription: boolean; -}; - -export const Root: StoryComponent = ({title, subtitle, description, multiparagraphDescription}) => { const [response, setResponse] = React.useState(); const [openDialogType, setOpenDialogType] = React.useState(); return ( @@ -621,14 +255,14 @@ export const Root: StoryComponent = ({title, subtitle, description, mu ); }; -Root.storyName = 'SheetRoot'; -Root.args = { +ShowSheet.storyName = 'showSheet'; +ShowSheet.args = { title: 'Title', subtitle: 'Subtitle', description: 'Description', multiparagraphDescription: false, }; -Root.argTypes = { +ShowSheet.argTypes = { multiparagraphDescription: { if: {arg: 'description'}, }, diff --git a/src/__tests__/sheet-test.tsx b/src/__tests__/sheet-test.tsx index 5b86734ecb..123edc5de3 100644 --- a/src/__tests__/sheet-test.tsx +++ b/src/__tests__/sheet-test.tsx @@ -1,9 +1,13 @@ import * as React from 'react'; -import Sheet, {ActionsSheet, ActionsListSheet, InfoSheet, RadioListSheet} from '../sheet'; -import {act, render, screen, waitFor, waitForElementToBeRemoved, within} from '@testing-library/react'; +import Sheet from '../sheet-common'; +import {act, render, screen, waitFor, within} from '@testing-library/react'; import {SheetRoot, ButtonPrimary, showSheet, ThemeContextProvider, Title1} from '..'; import {makeTheme} from './test-utils'; import userEvent from '@testing-library/user-event'; +import RadioListSheet from '../sheet-radio-list'; +import ActionsListSheet from '../sheet-actions-list'; +import InfoSheet from '../sheet-info'; +import ActionsSheet from '../sheet-actions'; test('Sheet', async () => { const TestComponent = () => { @@ -43,9 +47,9 @@ test('Sheet', async () => { const closeButton = await within(sheet).findByRole('button', {name: 'Close'}); - await act(() => userEvent.click(closeButton)); + await userEvent.click(closeButton); - await waitForElementToBeRemoved(sheet, {timeout: 5000}); + await waitFor(() => expect(sheet).not.toBeInTheDocument()); }, 30000); test('RadioListSheet', async () => { @@ -92,9 +96,9 @@ test('RadioListSheet', async () => { expect(item2).toBeChecked(); await userEvent.click(item1); - await act(() => userEvent.click(continueButton)); + await userEvent.click(continueButton); - await waitForElementToBeRemoved(sheet, {timeout: 5000}); + await waitFor(() => expect(sheet).not.toBeInTheDocument()); expect(selectSpy).toHaveBeenCalledWith('1'); }, 30000); @@ -272,7 +276,7 @@ test('showSheet INFO', async () => { ); - act(() => { + await act(async () => { showSheet({ type: 'INFO', props: { @@ -306,7 +310,7 @@ test('showSheet ACTIONS_LIST', async () => { ); - act(() => { + await act(async () => { showSheet({ type: 'ACTIONS_LIST', props: { @@ -344,7 +348,7 @@ test('showSheet ACTIONS_LIST dismiss', async () => { ); - act(() => { + await act(async () => { showSheet({ type: 'ACTIONS_LIST', props: { @@ -381,7 +385,7 @@ test('showSheet RADIO_LIST', async () => { ); - act(() => { + await act(async () => { showSheet({ type: 'RADIO_LIST', props: { @@ -421,7 +425,7 @@ test('showSheet RADIO_LIST dismiss', async () => { ); - act(() => { + await act(async () => { showSheet({ type: 'RADIO_LIST', props: { @@ -458,7 +462,7 @@ test('showSheet ACTIONS', async () => { ); - act(() => { + await act(async () => { showSheet({ type: 'ACTIONS', props: { @@ -503,7 +507,7 @@ test('showSheet ACTIONS dismiss', async () => { ); - act(() => { + await act(async () => { showSheet({ type: 'ACTIONS', props: { @@ -552,7 +556,7 @@ test('showSheet fails if there is already a sheet open', async () => { ); - act(() => { + await act(async () => { showSheet({ type: 'INFO', props: { @@ -596,7 +600,7 @@ test('showSheet with native implementation INFO', async () => { ); - await act(() => + await act(async () => showSheet({ type: 'INFO', props: { @@ -638,7 +642,7 @@ test('showSheet with native implementation ACTIONS_LIST', async () => { ); - await act(() => + await act(async () => showSheet({ type: 'ACTIONS_LIST', props: { @@ -686,7 +690,7 @@ test('showSheet with native implementation RADIO_LIST', async () => { ); - await act(() => + await act(async () => showSheet({ type: 'RADIO_LIST', props: { @@ -735,7 +739,7 @@ test('showSheet with native implementation ACTIONS', async () => { ); - await act(() => + await act(async () => showSheet({ type: 'ACTIONS', props: { @@ -781,7 +785,7 @@ test('showSheet with native implementation fallbacks to web if native fails', as ); - act(() => { + await act(async () => { showSheet({ type: 'ACTIONS', props: { diff --git a/src/index.tsx b/src/index.tsx index 598a3c423e..c647373aee 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -78,6 +78,7 @@ export { CardActionSpinner, CardActionIconButton, } from './card'; +export {default as StackingGroup} from './stacking-group'; export {default as Hero} from './hero'; export {default as CoverHero} from './cover-hero'; export {Table} from './table'; @@ -111,17 +112,19 @@ export { CarouselContextConsumer, } from './carousel'; export {Grid, GridItem} from './grid'; -export { - default as Sheet, - ActionsSheet, - InfoSheet, - ActionsListSheet, - RadioListSheet, - SheetBody, -} from './sheet'; + +// Sheets export {default as SheetRoot, showSheet} from './sheet-root'; -export type {NativeSheetImplementation} from './sheet-root'; -export {default as StackingGroup} from './stacking-group'; +export type {NativeSheetImplementation} from './sheet-types'; +export {default as Sheet, SheetBody} from './sheet-common'; +/** @deprecated use showSheet. It is easier to use and uses the app native implementation if available */ +export {default as ActionsSheet} from './sheet-actions'; +/** @deprecated use showSheet. It is easier to use and uses the app native implementation if available */ +export {default as InfoSheet} from './sheet-info'; +/** @deprecated use showSheet. It is easier to use and uses the app native implementation if available */ +export {default as ActionsListSheet} from './sheet-actions-list'; +/** @deprecated use showSheet. It is easier to use and uses the app native implementation if available */ +export {default as RadioListSheet} from './sheet-radio-list'; // Forms export {default as Form} from './form'; diff --git a/src/sheet-action-row.css.ts b/src/sheet-action-row.css.ts new file mode 100644 index 0000000000..34dd959309 --- /dev/null +++ b/src/sheet-action-row.css.ts @@ -0,0 +1,33 @@ +import {style} from '@vanilla-extract/css'; +import * as mq from './media-queries.css'; +import {vars as skinVars} from './skins/skin-contract.css'; +import {sprinkles} from './sprinkles.css'; + +export const sheetActionRow = style([ + sprinkles({ + display: 'flex', + padding: 16, + minHeight: 72, + alignItems: 'center', + }), + { + transition: 'background-color 0.1s ease-in-out', + ':active': { + background: skinVars.colors.backgroundContainerPressed, + }, + '@media': { + [mq.supportsHover]: { + ':hover': { + background: skinVars.colors.backgroundContainerHover, + }, + // need to repeat this inside of @media to avoid :hover background to take precedence over :active + ':active': { + background: skinVars.colors.backgroundContainerPressed, + }, + }, + [mq.touchableOnly]: { + transition: 'none', + }, + }, + }, +]); diff --git a/src/sheet-actions-list.tsx b/src/sheet-actions-list.tsx new file mode 100644 index 0000000000..04a60e9a08 --- /dev/null +++ b/src/sheet-actions-list.tsx @@ -0,0 +1,113 @@ +'use client'; +import * as React from 'react'; +import Sheet, {SheetBody} from './sheet-common'; +import {useTheme} from './hooks'; +import Box from './box'; +import {Text3} from './text'; +import {vars as skinVars} from './skins/skin-contract.css'; +import * as styles from './sheet-action-row.css'; +import Image from './image'; +import NegativeBox from './negative-box'; +import Touchable from './touchable'; + +import type {ExclusifyUnion} from './utils/utility-types'; +import type {DataAttributes, IconProps} from './utils/types'; + +type ActionsListSheetProps = { + title?: string; + subtitle?: string; + description?: string | ReadonlyArray; + items: ReadonlyArray<{ + id: string; + title: string; + /** "normal" by default */ + style?: 'normal' | 'destructive'; + icon?: ExclusifyUnion< + | { + /** @deprecated - use url instead */ + Icon: React.ComponentType; + } + | { + url: string; + urlDark?: string; + } + >; + }>; + onClose?: () => void; + onSelect?: (id: string) => void; + dataAttributes?: DataAttributes; +}; + +const ActionsListSheet = React.forwardRef( + ({title, subtitle, description, items, onClose, onSelect, dataAttributes}, ref) => { + const {isDarkMode} = useTheme(); + + return ( + + {({closeModal, modalTitleId}) => ( + + + {items.map(({id, style, title, icon}) => ( + { + onSelect?.(id); + closeModal(); + }} + > +

+ + ))} + + + )} + + ); + } +); + +export default ActionsListSheet; diff --git a/src/sheet-actions.tsx b/src/sheet-actions.tsx new file mode 100644 index 0000000000..946041fb97 --- /dev/null +++ b/src/sheet-actions.tsx @@ -0,0 +1,95 @@ +'use client'; +import * as React from 'react'; +import Sheet, {SheetBody} from './sheet-common'; +import {ButtonLink, ButtonPrimary, ButtonSecondary} from './button'; + +import type {DataAttributes, TrackingEvent} from './utils/types'; + +type PressedButton = 'PRIMARY' | 'SECONDARY' | 'LINK'; + +type ButtonProps = { + text: string; + trackingEvent?: TrackingEvent | ReadonlyArray; + trackEvent?: boolean; +}; + +type ActionsSheetProps = { + title?: string; + subtitle?: string; + description?: string | ReadonlyArray; + button: ButtonProps; + secondaryButton?: ButtonProps; + buttonLink?: ButtonProps & {withChevron?: boolean}; + onClose?: () => void; + onPressButton?: (pressedButton: PressedButton) => void; + dataAttributes?: DataAttributes; +}; + +const ActionsSheet = React.forwardRef( + ( + { + title, + subtitle, + description, + button, + secondaryButton, + buttonLink, + onClose, + dataAttributes, + onPressButton, + }, + ref + ) => { + const createPressHandler = (closeModal: () => void, pressedButton: PressedButton) => () => { + onPressButton?.(pressedButton); + closeModal(); + }; + + const getButtonProps = ({text, ...otherProps}: T) => ({ + children: text, + ...otherProps, + }); + + return ( + + {({modalTitleId, closeModal}) => ( + + } + secondaryButton={ + secondaryButton ? ( + + ) : undefined + } + link={ + buttonLink ? ( + + ) : undefined + } + /> + )} + + ); + } +); + +export default ActionsSheet; diff --git a/src/sheet.css.ts b/src/sheet-common.css.ts similarity index 87% rename from src/sheet.css.ts rename to src/sheet-common.css.ts index b86debdf48..a89076167f 100644 --- a/src/sheet.css.ts +++ b/src/sheet-common.css.ts @@ -256,38 +256,3 @@ export const bodyContent = style({ }, }, }); - -export const sheetActionRow = style([ - sprinkles({ - display: 'flex', - padding: 16, - minHeight: 72, - alignItems: 'center', - }), - { - transition: 'background-color 0.1s ease-in-out', - ':active': { - background: skinVars.colors.backgroundContainerPressed, - }, - '@media': { - [mq.supportsHover]: { - ':hover': { - background: skinVars.colors.backgroundContainerHover, - }, - // need to repeat this inside of @media to avoid :hover background to take precedence over :active - ':active': { - background: skinVars.colors.backgroundContainerPressed, - }, - }, - [mq.touchableOnly]: { - transition: 'none', - }, - }, - }, -]); - -export const infoItemIcon = sprinkles({ - display: 'flex', - alignItems: 'center', - height: 24, -}); diff --git a/src/sheet-common.tsx b/src/sheet-common.tsx new file mode 100644 index 0000000000..8ff8e43286 --- /dev/null +++ b/src/sheet-common.tsx @@ -0,0 +1,396 @@ +'use client'; +/* + * IMPORTANT: Do NOT import anything from here into `sheet-root.tsx` + + * The idea is to keep the SheetRoot component as small as possible (to keep the initial load time low) + * and lazy load the implementations when needed. + * + * This file contains code that is shared between different sheet implementations. + */ +import classnames from 'classnames'; +import * as React from 'react'; +import * as styles from './sheet-common.css'; +import FocusTrap from './focus-trap'; +import {useDisableBodyScroll, useIsInViewport, useScreenSize, useTheme} from './hooks'; +import {useSetModalStateEffect} from './modal-context-provider'; +import {Portal} from './portal'; +import {Text2, Text3, Text5} from './text'; +import {vars as skinVars} from './skins/skin-contract.css'; +import Stack from './stack'; +import Box from './box'; +import Divider from './divider'; +import {getPrefixedDataAttributes, getScrollableParentElement} from './utils/dom'; +import IconCloseRegular from './generated/mistica-icons/icon-close-regular'; +import {InternalIconButton} from './icon-button'; +import ButtonLayout from './button-layout'; +import {safeAreaInsetBottom} from './utils/css'; +import {MOBILE_SIDE_MARGIN, SMALL_DESKTOP_SIDE_MARGIN, TABLET_SIDE_MARGIN} from './responsive-layout.css'; +import * as tokens from './text-tokens'; + +import type {DataAttributes, RendersNullableElement} from './utils/types'; +import type {ButtonLink, ButtonPrimary, ButtonSecondary} from './button'; + +const transitionDuration = process.env.NODE_ENV === 'test' ? 0 : styles.transitionDuration; + +const getClientY = (ev: TouchEvent | MouseEvent | React.TouchEvent | React.MouseEvent) => { + if ('touches' in ev) { + return ev.touches[0].clientY; + } + return ev.clientY; +}; + +const useDraggableSheetProps = ({closeModal}: {closeModal: () => void}) => { + const [dragDistance, setDragDistance] = React.useState(0); + const isDraggingRef = React.useRef(false); + const initialMoveEventsCount = React.useRef(0); + const dragInitTimeRef = React.useRef(0); + const initialYRef = React.useRef(0); + const currentYRef = React.useRef(0); + + const {isDesktopOrBigger} = useScreenSize(); + + const handleTouchStart = React.useCallback((ev: React.TouchEvent | React.MouseEvent) => { + isDraggingRef.current = true; + initialMoveEventsCount.current = 0; + dragInitTimeRef.current = Date.now(); + initialYRef.current = getClientY(ev); + }, []); + + const handleScroll = React.useCallback(() => { + isDraggingRef.current = false; + setDragDistance(0); + }, []); + + React.useEffect(() => { + if (isDesktopOrBigger) { + return; + } + + const handleTouchMove = (ev: TouchEvent | MouseEvent) => { + if (!isDraggingRef.current) { + return; + } + + // we discard the first move events to allow scroll events to have priority. When the first + // scroll event is fired, dragging is disabled. If no scroll event is fired, we continue + // handling the dragging. After doing some tests in Android/iOS, 3 seems like a good number + if (initialMoveEventsCount.current < 3) { + initialMoveEventsCount.current++; + return; + } + + currentYRef.current = getClientY(ev); + + setDragDistance(currentYRef.current - initialYRef.current); + }; + + const handleTouchEnd = () => { + if (!isDraggingRef.current) { + return; + } + const dragTime = Date.now() - dragInitTimeRef.current; + const dragDistance = currentYRef.current - initialYRef.current; + const dragSpeed = dragDistance / dragTime; + + isDraggingRef.current = false; + setDragDistance(0); + if (dragDistance > 50 && (currentYRef.current > window.innerHeight * 0.75 || dragSpeed > 0.5)) { + closeModal(); + } + }; + + document.addEventListener('touchmove', handleTouchMove); + document.addEventListener('touchend', handleTouchEnd); + document.addEventListener('mousemove', handleTouchMove); + document.addEventListener('mouseup', handleTouchEnd); + + return () => { + document.removeEventListener('touchmove', handleTouchMove); + document.removeEventListener('touchend', handleTouchEnd); + document.removeEventListener('mousemove', handleTouchMove); + document.removeEventListener('mouseup', handleTouchEnd); + }; + }, [closeModal, isDesktopOrBigger]); + + if (isDesktopOrBigger) { + return {}; + } + + return { + onTouchStart: handleTouchStart, + onMouseDown: handleTouchStart, + style: dragDistance + ? { + transform: `translateY(${dragDistance}px)`, + transition: 'none', + } + : undefined, + onScroll: handleScroll, + overlayStyle: dragDistance + ? { + // decrease opacity when dragging down the sheet + opacity: 0.25 + 1 - dragDistance / (window.innerHeight - initialYRef.current), + transition: 'none', + } + : undefined, + }; +}; + +type ModalState = 'closed' | 'opening' | 'open' | 'closing' | 'closed'; +type ModalAction = 'close' | 'open' | 'transitionEnd'; + +const transitions: Record>> = { + closed: { + open: 'opening', + }, + opening: { + close: 'closed', + transitionEnd: 'open', + }, + open: { + close: 'closing', + }, + closing: { + transitionEnd: 'closed', + }, +}; + +const modalReducer = (state: ModalState, action: ModalAction): ModalState => + transitions[state][action] || state; + +type SheetProps = { + onClose?: () => void; + dataAttributes?: DataAttributes; + children: + | React.ReactNode + | ((renderParams: {closeModal: () => void; modalTitleId: string}) => React.ReactNode); +}; + +const Sheet = React.forwardRef(({onClose, children, dataAttributes}, ref) => { + const {texts, t} = useTheme(); + const [modalState, dispatch] = React.useReducer(modalReducer, 'closed'); + const initRef = React.useRef(false); + const modalTitleId = React.useId(); + + const handleTransitionEnd = React.useCallback((ev: React.AnimationEvent | React.TransitionEvent) => { + // Don't trigger transitionEnd if the event is not triggered by the sheet element. + if (ev.target === ev.currentTarget) { + dispatch('transitionEnd'); + } + }, []); + + const closeModal = () => { + if (modalState === 'open') { + dispatch('close'); + } + }; + + // transitionEnd/animationEnd dom events may not trigger in some cases, so we use a timeout as fallback + React.useEffect(() => { + if (modalState === 'opening' || modalState === 'closing') { + const tid = setTimeout(() => { + dispatch('transitionEnd'); + }, transitionDuration); + + return () => clearTimeout(tid); + } + }, [modalState]); + + React.useEffect(() => { + if (modalState === 'closed') { + if (initRef.current) { + onClose?.(); + } else { + dispatch('open'); + } + } else { + initRef.current = true; + } + }, [modalState, onClose]); + + const {onScroll, overlayStyle, ...dragableSheetProps} = useDraggableSheetProps({closeModal}); + + useSetModalStateEffect(); + useDisableBodyScroll(modalState !== 'closed'); + + if (modalState === 'closed') { + return null; + } + + return ( + + + {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */} +
+
+
+
+
+
+
+
+ {typeof children === 'function' + ? children({closeModal, modalTitleId}) + : children} +
+ +
+
+
+
+
+ + + ); +}); + +const paddingX = { + mobile: MOBILE_SIDE_MARGIN, + tablet: TABLET_SIDE_MARGIN, + desktop: SMALL_DESKTOP_SIDE_MARGIN, +} as const; + +type SheetBodyProps = { + title?: string; + subtitle?: string; + description?: string | ReadonlyArray; + button?: RendersNullableElement; + secondaryButton?: RendersNullableElement; + link?: RendersNullableElement; + modalTitleId: string; + children?: React.ReactNode; +}; + +export const SheetBody = ({ + title, + subtitle, + description, + modalTitleId, + button, + secondaryButton, + link, + children, +}: SheetBodyProps): JSX.Element => { + const topScrollSignalRef = React.useRef(null); + const bottomScrollSignalRef = React.useRef(null); + const scrollableParentRef = React.useRef(null); + + React.useEffect(() => { + if (bottomScrollSignalRef.current) { + scrollableParentRef.current = getScrollableParentElement(bottomScrollSignalRef.current); + } + }, []); + + const showTitleDivider = !useIsInViewport(topScrollSignalRef, true, { + root: scrollableParentRef.current, + }); + const showButtonsDivider = !useIsInViewport(bottomScrollSignalRef, true, { + rootMargin: '1px', // bottomScrollSignal div has 0px height so we need a 1px margin to trigger the intersection observer + root: scrollableParentRef.current, + }); + + const hasButtons = !!button || !!secondaryButton || !!link; + return ( + <> +
+
+ {title ? ( + + + {title} + + + ) : ( + + )} + {showTitleDivider && } +
+
+ + + {subtitle || description ? ( + + {subtitle && ( + + {subtitle} + + )} + {description && + (Array.isArray(description) ? ( + + {description.map((text, index) => ( +

+ {text} +

+ ))} +
+ ) : ( + + {description} + + ))} +
+ ) : null} + {children} +
+
+
+ {hasButtons && ( +
+ {showButtonsDivider && } + + + +
+ )} +
+ + ); +}; + +export default Sheet; diff --git a/src/sheet-info.css.ts b/src/sheet-info.css.ts new file mode 100644 index 0000000000..1a78b8229e --- /dev/null +++ b/src/sheet-info.css.ts @@ -0,0 +1,7 @@ +import {sprinkles} from './sprinkles.css'; + +export const infoItemIcon = sprinkles({ + display: 'flex', + alignItems: 'center', + height: 24, +}); diff --git a/src/sheet-info.tsx b/src/sheet-info.tsx new file mode 100644 index 0000000000..c5199e8c36 --- /dev/null +++ b/src/sheet-info.tsx @@ -0,0 +1,102 @@ +'use client'; +import * as React from 'react'; +import Inline from './inline'; +import Circle from './circle'; +import Sheet, {SheetBody} from './sheet-common'; +import {useTheme} from './hooks'; +import Box from './box'; +import Stack from './stack'; +import {Text3, Text2} from './text'; +import {vars as skinVars} from './skins/skin-contract.css'; +import * as styles from './sheet-info.css'; +import Image from './image'; + +import type {ExclusifyUnion} from './utils/utility-types'; +import type {DataAttributes, IconProps} from './utils/types'; + +type InfoSheetProps = { + title?: string; + subtitle?: string; + description?: string | ReadonlyArray; + items: ReadonlyArray<{ + id?: string; + title: string; + description?: string; + icon: ExclusifyUnion< + | { + type: 'regular' | 'small'; + /** @deprecated use url instead */ + Icon: React.ComponentType; + } + | { + type: 'regular' | 'small'; + url: string; + urlDark?: string; + } + | {type: 'bullet'} + >; + }>; + onClose?: () => void; + dataAttributes?: DataAttributes; +}; + +const InfoSheet = React.forwardRef( + ({title, subtitle, description, items, onClose, dataAttributes}, ref) => { + const {isDarkMode} = useTheme(); + return ( + + {({modalTitleId}) => ( + + + + {items.map((item, idx) => ( + +
+ {item.icon.type === 'bullet' ? ( + + ) : item.icon.Icon ? ( + + ) : ( + + )} +
+ + {item.title} + {item.description && ( + + {item.description} + + )} + +
+ ))} +
+
+
+ )} +
+ ); + } +); + +export default InfoSheet; diff --git a/src/sheet-native.tsx b/src/sheet-native.tsx new file mode 100644 index 0000000000..d587d903bc --- /dev/null +++ b/src/sheet-native.tsx @@ -0,0 +1,178 @@ +import type { + NativeSheetImplementation, + SheetPropsByType, + SheetResultByType, + SheetType, + SheetTypeWithProps, + SheetTypeWithPropsUnion, +} from './sheet-types'; + +const normalizeDescriptionForNative = (description?: string | Array): string | undefined => { + if (Array.isArray(description)) { + if (description.length) { + return description.join('\n\n'); + } else { + return undefined; + } + } + return description; +}; + +const showRadioListNativeSheet = ( + nativeSheetImplementation: NativeSheetImplementation, + {title, subtitle, description, selectedId, items}: SheetPropsByType['RADIO_LIST'] +): Promise => { + return (nativeSheetImplementation as NativeSheetImplementation)({ + title, + subtitle, + // TODO: add multiline support to native sheet + description: normalizeDescriptionForNative(description), + content: [ + { + type: 'LIST', + id: 'list-0', + listType: 'SINGLE_SELECTION', + autoSubmit: true, + selectedIds: typeof selectedId === 'string' ? [selectedId] : [], + items, + }, + ], + }).then(({action, result}) => { + if (action === 'SUBMIT') { + return { + action, + selectedId: result[0].selectedIds[0], + }; + } else { + return { + action, + selectedId: null, + }; + } + }); +}; + +const showActionsListNativeSheet = ( + nativeSheetImplementation: NativeSheetImplementation, + {title, subtitle, description, items}: SheetPropsByType['ACTIONS_LIST'] +): Promise => { + return (nativeSheetImplementation as NativeSheetImplementation)({ + title, + subtitle, + // TODO: add multiline support to native sheet + description: normalizeDescriptionForNative(description), + content: [ + { + type: 'LIST', + id: 'list-0', + listType: 'ACTIONS', + autoSubmit: true, + selectedIds: [], + items, + }, + ], + }).then(({action, result}) => { + if (action === 'SUBMIT') { + return { + action, + selectedId: result[0].selectedIds[0], + }; + } else { + return { + action, + selectedId: null, + }; + } + }); +}; + +const showInfoNativeSheet = async ( + nativeSheetImplementation: NativeSheetImplementation, + {title, subtitle, description, items}: SheetPropsByType['INFO'] +): Promise => { + // nothing to return, this is an informative sheet + await (nativeSheetImplementation as NativeSheetImplementation)({ + title, + subtitle, + // TODO: add multiline support to native sheet + description: normalizeDescriptionForNative(description), + content: [ + { + type: 'LIST', + id: 'list-0', + listType: 'INFORMATIVE', + autoSubmit: false, + selectedIds: [], + items, + }, + ], + }); +}; + +const showActionsNativeSheet = ( + nativeSheetImplementation: NativeSheetImplementation, + {title, subtitle, description, button, secondaryButton, link}: SheetPropsByType['ACTIONS'] +): Promise => { + return (nativeSheetImplementation as NativeSheetImplementation)({ + title, + subtitle, + // TODO: add multiline support to native sheet + description: normalizeDescriptionForNative(description), + content: [ + { + type: 'BOTTOM_ACTIONS', + id: 'bottom-actions-0', + button, + secondaryButton, + link, + }, + ], + }).then(({action, result}) => { + if (action === 'SUBMIT') { + const bottomActionsResult = result.find(({id}) => id === 'bottom-actions-0'); + const pressedAction = bottomActionsResult?.selectedIds[0]; + if (pressedAction === 'PRIMARY' || pressedAction === 'SECONDARY' || pressedAction === 'LINK') { + return { + action: pressedAction, + }; + } + } + return { + action: 'DISMISS', + }; + }); +}; + +export const showNativeSheet = ( + nativeSheetImplementation: NativeSheetImplementation, + sheetProps: SheetTypeWithProps +): Promise => { + let nativeResponse: Promise; + const {type, props} = sheetProps as SheetTypeWithPropsUnion; + switch (type) { + case 'INFO': + nativeResponse = showInfoNativeSheet(nativeSheetImplementation, props) as Promise< + SheetResultByType[T] + >; + break; + case 'ACTIONS_LIST': + nativeResponse = showActionsListNativeSheet(nativeSheetImplementation, props) as Promise< + SheetResultByType[T] + >; + break; + case 'RADIO_LIST': + nativeResponse = showRadioListNativeSheet(nativeSheetImplementation, props) as Promise< + SheetResultByType[T] + >; + break; + case 'ACTIONS': + nativeResponse = showActionsNativeSheet(nativeSheetImplementation, props) as Promise< + SheetResultByType[T] + >; + break; + default: + const unknownType: never = type; + throw new Error(`Unknown sheet type: ${unknownType}`); + } + return nativeResponse; +}; diff --git a/src/sheet-radio-list.tsx b/src/sheet-radio-list.tsx new file mode 100644 index 0000000000..b8b8a2ac57 --- /dev/null +++ b/src/sheet-radio-list.tsx @@ -0,0 +1,107 @@ +'use client'; +import * as React from 'react'; +import Sheet, {SheetBody} from './sheet-common'; +import {useScreenSize, useTheme} from './hooks'; +import NegativeBox from './negative-box'; +import {ButtonPrimary} from './button'; +import {RadioGroup} from './radio-button'; +import {Row, RowList} from './list'; +import * as tokens from './text-tokens'; + +import type {DataAttributes} from './utils/types'; + +type RadioListSheetProps = { + title?: string; + subtitle?: string; + description?: string | ReadonlyArray; + items: ReadonlyArray<{ + id: string; + title?: string; + description?: string; + asset?: React.ReactNode; + }>; + selectedId?: string; + onClose?: () => void; + onSelect?: (id: string) => void; + dataAttributes?: DataAttributes; + button?: { + text: string; + }; +}; + +const RadioListSheet = React.forwardRef( + ({title, subtitle, description, items, selectedId, onClose, onSelect, button, dataAttributes}, ref) => { + const [selectedItemId, setSelectedItemId] = React.useState(selectedId); + const hasSelectedRef = React.useRef(false); + const {isDesktopOrBigger} = useScreenSize(); + const {texts, t} = useTheme(); + + return ( + + {({closeModal, modalTitleId}) => ( + { + if (hasSelectedRef.current) { + onSelect?.(selectedItemId || ''); + } + closeModal(); + }} + > + {button?.text || texts.sheetConfirmButton || t(tokens.sheetConfirmButton)} + + ) : undefined + } + > + + { + setSelectedItemId(value); + hasSelectedRef.current = true; + + // In desktop, the modal is closed with the ButtonPrimary + if (isDesktopOrBigger) { + return; + } + + onSelect?.(value); + // Wait for radio animation to finish before closing the modal + setTimeout(() => { + closeModal(); + }, 200); + }} + > + + {items.map((item) => ( + + ))} + + + + + )} + + ); + } +); + +export default RadioListSheet; diff --git a/src/sheet-root.tsx b/src/sheet-root.tsx index a014bdebd6..8653a3f4b1 100644 --- a/src/sheet-root.tsx +++ b/src/sheet-root.tsx @@ -1,246 +1,34 @@ 'use client'; import * as React from 'react'; -import {ActionsSheet, ActionsListSheet, InfoSheet, RadioListSheet} from './sheet'; -import Image from './image'; -import {useTheme} from './hooks'; -import type {ExclusifyUnion, Id} from './utils/utility-types'; +import type { + NativeSheetImplementation, + SheetPromiseResolve, + SheetResultByType, + SheetType, + SheetTypeWithProps, + SheetTypeWithPropsUnion, +} from './sheet-types'; + +const SheetWeb = React.lazy( + () => + import( + /* webpackChunkName: "sheet-web" */ + './sheet-web' + ) +); -type InfoIcon = ExclusifyUnion< - | { - type: 'small' | 'regular'; - url: string; - urlDark?: string; - } - | {type: 'bullet'} ->; - -type SheetProps = Id< - { - title?: string; - subtitle?: string; - description?: string | Array; - } & T ->; - -type SheetPropsByType = { - RADIO_LIST: SheetProps<{ - selectedId?: string; - items: Array<{ - id: string; - title?: string; - description?: string; - icon?: { - size?: 'small' | 'large'; - url: string; - urlDark?: string; - }; - }>; - }>; - ACTIONS_LIST: SheetProps<{ - items: Array<{ - id: string; - title: string; - style?: 'normal' | 'destructive'; - icon?: { - url: string; - urlDark?: string; - }; - }>; - }>; - INFO: SheetProps<{ - items: Array<{ - id: string; - title: string; - description?: string; - icon: InfoIcon; - }>; - }>; - ACTIONS: SheetProps<{ - button: { - text: string; - }; - secondaryButton?: { - text: string; - }; - link?: { - text: string; - withChevron?: boolean; - }; - }>; -}; - -type SheetResultByType = { - RADIO_LIST: {action: 'SUBMIT'; selectedId: string} | {action: 'DISMISS'}; - ACTIONS_LIST: {action: 'SUBMIT'; selectedId: string} | {action: 'DISMISS'}; - INFO: void; - ACTIONS: {action: 'PRIMARY' | 'SECONDARY' | 'LINK' | 'DISMISS'}; -}; - -type SheetType = keyof SheetPropsByType; - -type SheetTypeWithProps = Id<{type: T; props: SheetPropsByType[T]}>; - -type SheetTypeWithPropsUnion = { - [T in SheetType]: SheetTypeWithProps; -}[SheetType]; - -export type NativeSheetImplementation = (typeof import('@tef-novum/webview-bridge'))['bottomSheet']; - -type SheetPropsListener = (sheetProps: SheetTypeWithPropsUnion) => void; -type SheetPromiseResolve = ( - value: T extends SheetType ? SheetResultByType[T] : 'You must provide a type parameter' -) => void; - -let listener: SheetPropsListener | null = null; -let sheetPromiseResolve: SheetPromiseResolve | null = null; let nativeSheetImplementation: NativeSheetImplementation | null = null; -const normalizeDescriptionForNative = (description?: string | Array): string | undefined => { - if (Array.isArray(description)) { - if (description.length) { - return description.join('\n\n'); - } else { - return undefined; - } - } - return description; -}; - -const showRadioListNativeSheet = ({ - title, - subtitle, - description, - selectedId, - items, -}: SheetPropsByType['RADIO_LIST']) => - (nativeSheetImplementation as NativeSheetImplementation)({ - title, - subtitle, - // TODO: add multiline support to native sheet - description: normalizeDescriptionForNative(description), - content: [ - { - type: 'LIST', - id: 'list-0', - listType: 'SINGLE_SELECTION', - autoSubmit: true, - selectedIds: typeof selectedId === 'string' ? [selectedId] : [], - items, - }, - ], - }).then(({action, result}) => { - if (action === 'SUBMIT') { - return { - action, - selectedId: result[0].selectedIds[0], - }; - } else { - return { - action, - selectedId: null, - }; - } - }); - -const showActionsListNativeSheet = ({ - title, - subtitle, - description, - items, -}: SheetPropsByType['ACTIONS_LIST']) => - (nativeSheetImplementation as NativeSheetImplementation)({ - title, - subtitle, - // TODO: add multiline support to native sheet - description: normalizeDescriptionForNative(description), - content: [ - { - type: 'LIST', - id: 'list-0', - listType: 'ACTIONS', - autoSubmit: true, - selectedIds: [], - items, - }, - ], - }).then(({action, result}) => { - if (action === 'SUBMIT') { - return { - action, - selectedId: result[0].selectedIds[0], - }; - } else { - return { - action, - selectedId: null, - }; - } - }); - -const showInfoNativeSheet = async ({title, subtitle, description, items}: SheetPropsByType['INFO']) => { - await (nativeSheetImplementation as NativeSheetImplementation)({ - title, - subtitle, - // TODO: add multiline support to native sheet - description: normalizeDescriptionForNative(description), - content: [ - { - type: 'LIST', - id: 'list-0', - listType: 'INFORMATIVE', - autoSubmit: false, - selectedIds: [], - items, - }, - ], - }); -}; - -const showActionsNativeSheet = async ({ - title, - subtitle, - description, - button, - secondaryButton, - link, -}: SheetPropsByType['ACTIONS']) => { - return (nativeSheetImplementation as NativeSheetImplementation)({ - title, - subtitle, - // TODO: add multiline support to native sheet - description: normalizeDescriptionForNative(description), - content: [ - { - type: 'BOTTOM_ACTIONS', - id: 'bottom-actions-0', - button, - secondaryButton, - link, - }, - ], - }).then(({action, result}) => { - if (action === 'SUBMIT') { - const bottomActionsResult = result.find(({id}) => id === 'bottom-actions-0'); - const pressedAction = bottomActionsResult?.selectedIds[0]; - if (pressedAction === 'PRIMARY' || pressedAction === 'SECONDARY' || pressedAction === 'LINK') { - return { - action: pressedAction, - }; - } - } - return { - action: 'DISMISS', - }; - }); -}; +let configureSheet: ((sheetProps: SheetTypeWithPropsUnion) => void) | null = null; +let resolveSheetPromise: SheetPromiseResolve | null = null; let isSheetOpen = false; export const showSheet = ( sheetProps: SheetTypeWithProps ): Promise => { const webImplementation = () => { - if (!listener) { + if (!configureSheet) { return Promise.reject( new Error('Tried to show a Sheet but the SheetRoot component was not mounted') ); @@ -251,10 +39,10 @@ export const showSheet = ( } isSheetOpen = true; - listener(sheetProps as SheetTypeWithPropsUnion); + configureSheet(sheetProps as SheetTypeWithPropsUnion); const sheetPromise = new Promise((resolve) => { - sheetPromiseResolve = resolve; + resolveSheetPromise = resolve; }); sheetPromise.finally(() => { @@ -265,33 +53,19 @@ export const showSheet = ( }; if (nativeSheetImplementation) { - let nativeResponse: Promise; - const {type, props} = sheetProps as SheetTypeWithPropsUnion; - switch (type) { - case 'INFO': - nativeResponse = showInfoNativeSheet(props) as Promise; - break; - case 'ACTIONS_LIST': - nativeResponse = showActionsListNativeSheet(props) as Promise; - break; - case 'RADIO_LIST': - nativeResponse = showRadioListNativeSheet(props) as Promise; - break; - case 'ACTIONS': - nativeResponse = showActionsNativeSheet(props) as Promise; - break; - default: - const unknownType: never = type; - throw new Error(`Unknown sheet type: ${unknownType}`); - } - return nativeResponse.catch((error) => { - if (error.code === '400') { - // fallback to web implementation if native implementation doesn't support the sheet type - return webImplementation(); - } else { - throw error; - } - }); + const impl = nativeSheetImplementation; + return import(/* webpackChunkName: "sheet-native" */ './sheet-native') + .then(({showNativeSheet}) => { + return showNativeSheet(impl, sheetProps); + }) + .catch((error) => { + if (error.code === '400') { + // fallback to web implementation if native implementation doesn't support the sheet type + return webImplementation(); + } else { + throw error; + } + }); } else { return webImplementation(); } @@ -299,12 +73,11 @@ export const showSheet = ( type Props = { nativeImplementation?: NativeSheetImplementation; + children?: React.ReactNode; }; -export const SheetRoot = (props: Props): React.ReactElement | null => { - const {isDarkMode} = useTheme(); +export const SheetRoot = (props: Props): JSX.Element => { const [sheetProps, setSheetProps] = React.useState(null); - const selectionRef = React.useRef(null); React.useEffect(() => { if (props.nativeImplementation) { @@ -316,99 +89,30 @@ export const SheetRoot = (props: Props): React.ReactElement | null => { }, [props.nativeImplementation]); React.useEffect(() => { - listener = (newSheetProps: SheetTypeWithProps) => { - selectionRef.current = null; + configureSheet = (newSheetProps: SheetTypeWithProps) => { setSheetProps(newSheetProps as SheetTypeWithPropsUnion); }; return () => { - listener = null; + configureSheet = null; }; }, []); - if (!sheetProps) { - return null; - } - - const handleClose = () => { - setSheetProps(null); - switch (sheetProps.type) { - case 'INFO': - sheetPromiseResolve?.<'INFO'>(undefined); - break; - case 'ACTIONS_LIST': - if (selectionRef.current) { - sheetPromiseResolve?.<'ACTIONS_LIST'>({ - action: 'SUBMIT', - selectedId: selectionRef.current, - }); - } else { - sheetPromiseResolve?.<'ACTIONS_LIST'>({action: 'DISMISS'}); - } - break; - case 'RADIO_LIST': - if (selectionRef.current) { - sheetPromiseResolve?.<'RADIO_LIST'>({action: 'SUBMIT', selectedId: selectionRef.current}); - } else { - sheetPromiseResolve?.<'RADIO_LIST'>({action: 'DISMISS'}); - } - break; - case 'ACTIONS': - if ( - selectionRef.current === 'PRIMARY' || - selectionRef.current === 'SECONDARY' || - selectionRef.current === 'LINK' - ) { - sheetPromiseResolve?.<'ACTIONS'>({action: selectionRef.current}); - } else { - sheetPromiseResolve?.<'ACTIONS'>({action: 'DISMISS'}); - } - break; - default: - // @ts-expect-error sheetProps is never - throw new Error(`Unknown sheet type: ${sheetProps.type}`); - } - }; - - const handleSelect = (id: string) => { - selectionRef.current = id; - }; - - switch (sheetProps.type) { - case 'INFO': - return ; - case 'ACTIONS_LIST': - return ; - case 'RADIO_LIST': - return ( - ({ - ...item, - asset: item.icon && ( - - ), - }))} - onClose={handleClose} - onSelect={handleSelect} - /> - ); - case 'ACTIONS': - return ( - - ); - default: - // @ts-expect-error sheetProps is never. This switch is exhaustive. - throw new Error(`Unknown sheet type: ${sheetProps.type}`); - } + return ( + <> + {props.children} + {sheetProps && ( + + { + setSheetProps(null); + resolveSheetPromise?.(result); + }} + /> + + )} + + ); }; export default SheetRoot; diff --git a/src/sheet-types.tsx b/src/sheet-types.tsx new file mode 100644 index 0000000000..a03f3c070f --- /dev/null +++ b/src/sheet-types.tsx @@ -0,0 +1,86 @@ +export type NativeSheetImplementation = (typeof import('@tef-novum/webview-bridge'))['bottomSheet']; + +import type {ExclusifyUnion, Id} from './utils/utility-types'; + +type InfoIcon = ExclusifyUnion< + | { + type: 'small' | 'regular'; + url: string; + urlDark?: string; + } + | {type: 'bullet'} +>; + +type SheetProps = Id< + { + title?: string; + subtitle?: string; + description?: string | Array; + } & T +>; + +export type SheetPropsByType = { + RADIO_LIST: SheetProps<{ + selectedId?: string; + items: Array<{ + id: string; + title?: string; + description?: string; + icon?: { + size?: 'small' | 'large'; + url: string; + urlDark?: string; + }; + }>; + }>; + ACTIONS_LIST: SheetProps<{ + items: Array<{ + id: string; + title: string; + style?: 'normal' | 'destructive'; + icon?: { + url: string; + urlDark?: string; + }; + }>; + }>; + INFO: SheetProps<{ + items: Array<{ + id: string; + title: string; + description?: string; + icon: InfoIcon; + }>; + }>; + ACTIONS: SheetProps<{ + button: { + text: string; + }; + secondaryButton?: { + text: string; + }; + link?: { + text: string; + withChevron?: boolean; + }; + }>; +}; + +export type SheetType = keyof SheetPropsByType; + +export type SheetResultByType = { + RADIO_LIST: {action: 'SUBMIT'; selectedId: string} | {action: 'DISMISS'}; + ACTIONS_LIST: {action: 'SUBMIT'; selectedId: string} | {action: 'DISMISS'}; + INFO: void; + ACTIONS: {action: 'PRIMARY' | 'SECONDARY' | 'LINK' | 'DISMISS'}; +}; + +export type SheetTypeWithProps = Id<{type: T; props: SheetPropsByType[T]}>; + +export type SheetTypeWithPropsUnion = { + [T in SheetType]: SheetTypeWithProps; +}[SheetType]; + +export type SheetPromiseResolve = ( + value: T extends SheetType ? SheetResultByType[T] : 'You must provide a type parameter' +) => void; diff --git a/src/sheet-web.tsx b/src/sheet-web.tsx new file mode 100644 index 0000000000..2370ffe158 --- /dev/null +++ b/src/sheet-web.tsx @@ -0,0 +1,140 @@ +'use client'; +import * as React from 'react'; +import {useTheme} from './hooks'; +import Image from './image'; + +import type {SheetPromiseResolve, SheetTypeWithPropsUnion} from './sheet-types'; + +const ActionsSheet = React.lazy( + () => + import( + /* webpackChunkName: "sheet-actions" */ + './sheet-actions' + ) +); + +const InfoSheet = React.lazy( + () => + import( + /* webpackChunkName: "sheet-info" */ + './sheet-info' + ) +); +const ActionsListSheet = React.lazy( + () => + import( + /* webpackChunkName: "sheet-action-list" */ + './sheet-actions-list' + ) +); + +const RadioListSheet = React.lazy( + () => + import( + /* webpackChunkName: "sheet-radio-list" */ + './sheet-radio-list' + ) +); + +type SheetWebProps = { + sheetProps: SheetTypeWithPropsUnion; + onResolve: SheetPromiseResolve; +}; + +const SheetWeb = ({sheetProps, onResolve}: SheetWebProps): JSX.Element => { + const {isDarkMode} = useTheme(); + const selectionRef = React.useRef(null); + + const handleSelect = (id: string): void => { + selectionRef.current = id; + }; + + const handleClose = () => { + if (!onResolve) { + throw new Error('onResolve handler is not set'); + } + switch (sheetProps.type) { + case 'INFO': + onResolve<'INFO'>(undefined); + break; + case 'ACTIONS_LIST': + if (selectionRef.current) { + onResolve<'ACTIONS_LIST'>({ + action: 'SUBMIT', + selectedId: selectionRef.current, + }); + } else { + onResolve<'ACTIONS_LIST'>({action: 'DISMISS'}); + } + break; + case 'RADIO_LIST': + if (selectionRef.current) { + onResolve<'RADIO_LIST'>({ + action: 'SUBMIT', + selectedId: selectionRef.current, + }); + } else { + onResolve<'RADIO_LIST'>({action: 'DISMISS'}); + } + break; + case 'ACTIONS': + if ( + selectionRef.current === 'PRIMARY' || + selectionRef.current === 'SECONDARY' || + selectionRef.current === 'LINK' + ) { + onResolve<'ACTIONS'>({action: selectionRef.current}); + } else { + onResolve<'ACTIONS'>({action: 'DISMISS'}); + } + break; + default: + // @ts-expect-error sheetProps is never + throw new Error(`Unknown sheet type: ${sheetProps.type}`); + } + selectionRef.current = null; + }; + + switch (sheetProps.type) { + case 'INFO': + return ; + + case 'ACTIONS_LIST': + return ; + + case 'RADIO_LIST': + return ( + ({ + ...item, + asset: item.icon && ( + + ), + }))} + onClose={handleClose} + onSelect={handleSelect} + /> + ); + + case 'ACTIONS': + return ( + + ); + + default: + // @ts-expect-error sheetProps is never. This switch is exhaustive. + throw new Error(`Unknown sheet type: ${sheetProps.type}`); + } +}; + +export default SheetWeb; diff --git a/src/sheet.tsx b/src/sheet.tsx deleted file mode 100644 index 843a73801a..0000000000 --- a/src/sheet.tsx +++ /dev/null @@ -1,755 +0,0 @@ -'use client'; -import classnames from 'classnames'; -import * as React from 'react'; -import * as styles from './sheet.css'; -import FocusTrap from './focus-trap'; -import {useDisableBodyScroll, useIsInViewport, useScreenSize, useTheme} from './hooks'; -import {useSetModalStateEffect} from './modal-context-provider'; -import {Portal} from './portal'; -import {Text2, Text3, Text5} from './text'; -import {vars as skinVars} from './skins/skin-contract.css'; -import {RadioGroup} from './radio-button'; -import {Row, RowList} from './list'; -import NegativeBox from './negative-box'; -import Stack from './stack'; -import Box from './box'; -import Touchable from './touchable'; -import Inline from './inline'; -import Circle from './circle'; -import Divider from './divider'; -import {getPrefixedDataAttributes, getScrollableParentElement} from './utils/dom'; -import {ButtonLink, ButtonPrimary, ButtonSecondary} from './button'; -import IconCloseRegular from './generated/mistica-icons/icon-close-regular'; -import {InternalIconButton} from './icon-button'; -import ButtonLayout from './button-layout'; -import Image from './image'; -import {safeAreaInsetBottom} from './utils/css'; -import {MOBILE_SIDE_MARGIN, SMALL_DESKTOP_SIDE_MARGIN, TABLET_SIDE_MARGIN} from './responsive-layout.css'; -import * as tokens from './text-tokens'; - -import type {ExclusifyUnion} from './utils/utility-types'; -import type {DataAttributes, IconProps, RendersNullableElement, TrackingEvent} from './utils/types'; - -const transitionDuration = process.env.NODE_ENV === 'test' ? 0 : styles.transitionDuration; - -const getClientY = (ev: TouchEvent | MouseEvent | React.TouchEvent | React.MouseEvent) => { - if ('touches' in ev) { - return ev.touches[0].clientY; - } - return ev.clientY; -}; - -const useDraggableSheetProps = ({closeModal}: {closeModal: () => void}) => { - const [dragDistance, setDragDistance] = React.useState(0); - const isDraggingRef = React.useRef(false); - const initialMoveEventsCount = React.useRef(0); - const dragInitTimeRef = React.useRef(0); - const initialYRef = React.useRef(0); - const currentYRef = React.useRef(0); - - const {isDesktopOrBigger} = useScreenSize(); - - const handleTouchStart = React.useCallback((ev: React.TouchEvent | React.MouseEvent) => { - isDraggingRef.current = true; - initialMoveEventsCount.current = 0; - dragInitTimeRef.current = Date.now(); - initialYRef.current = getClientY(ev); - }, []); - - const handleScroll = React.useCallback(() => { - isDraggingRef.current = false; - setDragDistance(0); - }, []); - - React.useEffect(() => { - if (isDesktopOrBigger) { - return; - } - - const handleTouchMove = (ev: TouchEvent | MouseEvent) => { - if (!isDraggingRef.current) { - return; - } - - // we discard the first move events to allow scroll events to have priority. When the first - // scroll event is fired, dragging is disabled. If no scroll event is fired, we continue - // handling the dragging. After doing some tests in Android/iOS, 3 seems like a good number - if (initialMoveEventsCount.current < 3) { - initialMoveEventsCount.current++; - return; - } - - currentYRef.current = getClientY(ev); - - setDragDistance(currentYRef.current - initialYRef.current); - }; - - const handleTouchEnd = () => { - if (!isDraggingRef.current) { - return; - } - const dragTime = Date.now() - dragInitTimeRef.current; - const dragDistance = currentYRef.current - initialYRef.current; - const dragSpeed = dragDistance / dragTime; - - isDraggingRef.current = false; - setDragDistance(0); - if (dragDistance > 50 && (currentYRef.current > window.innerHeight * 0.75 || dragSpeed > 0.5)) { - closeModal(); - } - }; - - document.addEventListener('touchmove', handleTouchMove); - document.addEventListener('touchend', handleTouchEnd); - document.addEventListener('mousemove', handleTouchMove); - document.addEventListener('mouseup', handleTouchEnd); - - return () => { - document.removeEventListener('touchmove', handleTouchMove); - document.removeEventListener('touchend', handleTouchEnd); - document.removeEventListener('mousemove', handleTouchMove); - document.removeEventListener('mouseup', handleTouchEnd); - }; - }, [closeModal, isDesktopOrBigger]); - - if (isDesktopOrBigger) { - return {}; - } - - return { - onTouchStart: handleTouchStart, - onMouseDown: handleTouchStart, - style: dragDistance - ? { - transform: `translateY(${dragDistance}px)`, - transition: 'none', - } - : undefined, - onScroll: handleScroll, - overlayStyle: dragDistance - ? { - // decrease opacity when dragging down the sheet - opacity: 0.25 + 1 - dragDistance / (window.innerHeight - initialYRef.current), - transition: 'none', - } - : undefined, - }; -}; - -type ModalState = 'closed' | 'opening' | 'open' | 'closing' | 'closed'; -type ModalAction = 'close' | 'open' | 'transitionEnd'; - -const transitions: Record>> = { - closed: { - open: 'opening', - }, - opening: { - close: 'closed', - transitionEnd: 'open', - }, - open: { - close: 'closing', - }, - closing: { - transitionEnd: 'closed', - }, -}; - -const modalReducer = (state: ModalState, action: ModalAction): ModalState => - transitions[state][action] || state; - -type SheetProps = { - onClose?: () => void; - dataAttributes?: DataAttributes; - children: - | React.ReactNode - | ((renderParams: {closeModal: () => void; modalTitleId: string}) => React.ReactNode); -}; - -const Sheet = React.forwardRef(({onClose, children, dataAttributes}, ref) => { - const {texts, t} = useTheme(); - const [modalState, dispatch] = React.useReducer(modalReducer, 'closed'); - const initRef = React.useRef(false); - const modalTitleId = React.useId(); - - const handleTransitionEnd = React.useCallback((ev: React.AnimationEvent | React.TransitionEvent) => { - // Don't trigger transitionEnd if the event is not triggered by the sheet element. - if (ev.target === ev.currentTarget) { - dispatch('transitionEnd'); - } - }, []); - - const closeModal = () => { - if (modalState === 'open') { - dispatch('close'); - } - }; - - // transitionEnd/animationEnd dom events may not trigger in some cases, so we use a timeout as fallback - React.useEffect(() => { - if (modalState === 'opening' || modalState === 'closing') { - const tid = setTimeout(() => { - dispatch('transitionEnd'); - }, transitionDuration); - - return () => clearTimeout(tid); - } - }, [modalState]); - - React.useEffect(() => { - if (modalState === 'closed') { - if (initRef.current) { - onClose?.(); - } else { - dispatch('open'); - } - } else { - initRef.current = true; - } - }, [modalState, onClose]); - - const {onScroll, overlayStyle, ...dragableSheetProps} = useDraggableSheetProps({closeModal}); - - useSetModalStateEffect(); - useDisableBodyScroll(modalState !== 'closed'); - - if (modalState === 'closed') { - return null; - } - - return ( - - - {/* eslint-disable-next-line jsx-a11y/no-static-element-interactions */} -
-
-
-
-
-
-
-
- {typeof children === 'function' - ? children({closeModal, modalTitleId}) - : children} -
- -
-
-
-
-
- - - ); -}); - -const paddingX = { - mobile: MOBILE_SIDE_MARGIN, - tablet: TABLET_SIDE_MARGIN, - desktop: SMALL_DESKTOP_SIDE_MARGIN, -} as const; - -type SheetBodyProps = { - title?: string; - subtitle?: string; - description?: string | ReadonlyArray; - button?: RendersNullableElement; - secondaryButton?: RendersNullableElement; - link?: RendersNullableElement; - modalTitleId: string; - children?: React.ReactNode; -}; - -export const SheetBody = ({ - title, - subtitle, - description, - modalTitleId, - button, - secondaryButton, - link, - children, -}: SheetBodyProps): JSX.Element => { - const topScrollSignalRef = React.useRef(null); - const bottomScrollSignalRef = React.useRef(null); - const scrollableParentRef = React.useRef(null); - - React.useEffect(() => { - if (bottomScrollSignalRef.current) { - scrollableParentRef.current = getScrollableParentElement(bottomScrollSignalRef.current); - } - }, []); - - const showTitleDivider = !useIsInViewport(topScrollSignalRef, true, { - root: scrollableParentRef.current, - }); - const showButtonsDivider = !useIsInViewport(bottomScrollSignalRef, true, { - rootMargin: '1px', // bottomScrollSignal div has 0px height so we need a 1px margin to trigger the intersection observer - root: scrollableParentRef.current, - }); - - const hasButtons = !!button || !!secondaryButton || !!link; - return ( - <> -
-
- {title ? ( - - - {title} - - - ) : ( - - )} - {showTitleDivider && } -
-
- - - {subtitle || description ? ( - - {subtitle && ( - - {subtitle} - - )} - {description && - (Array.isArray(description) ? ( - - {description.map((text, index) => ( -

- {text} -

- ))} -
- ) : ( - - {description} - - ))} -
- ) : null} - {children} -
-
-
- {hasButtons && ( -
- {showButtonsDivider && } - - - -
- )} -
- - ); -}; - -type RadioListSheetProps = { - title?: string; - subtitle?: string; - description?: string | ReadonlyArray; - items: ReadonlyArray<{ - id: string; - title?: string; - description?: string; - asset?: React.ReactNode; - }>; - selectedId?: string; - onClose?: () => void; - onSelect?: (id: string) => void; - dataAttributes?: DataAttributes; - button?: { - text: string; - }; -}; - -export const RadioListSheet = React.forwardRef( - ({title, subtitle, description, items, selectedId, onClose, onSelect, button, dataAttributes}, ref) => { - const [selectedItemId, setSelectedItemId] = React.useState(selectedId); - const hasSelectedRef = React.useRef(false); - const {isDesktopOrBigger} = useScreenSize(); - const {texts, t} = useTheme(); - - return ( - - {({closeModal, modalTitleId}) => ( - { - if (hasSelectedRef.current) { - onSelect?.(selectedItemId || ''); - } - closeModal(); - }} - > - {button?.text || texts.sheetConfirmButton || t(tokens.sheetConfirmButton)} - - ) : undefined - } - > - - { - setSelectedItemId(value); - hasSelectedRef.current = true; - - // In desktop, the modal is closed with the ButtonPrimary - if (isDesktopOrBigger) { - return; - } - - onSelect?.(value); - // Wait for radio animation to finish before closing the modal - setTimeout(() => { - closeModal(); - }, 200); - }} - > - - {items.map((item) => ( - - ))} - - - - - )} - - ); - } -); - -type ActionsListSheetProps = { - title?: string; - subtitle?: string; - description?: string | ReadonlyArray; - items: ReadonlyArray<{ - id: string; - title: string; - style?: 'normal' | 'destructive'; // "normal" by default - icon?: ExclusifyUnion< - | { - Icon: React.ComponentType; - } - | { - url: string; - urlDark?: string; - } - >; - }>; - onClose?: () => void; - onSelect?: (id: string) => void; - dataAttributes?: DataAttributes; -}; - -export const ActionsListSheet = React.forwardRef( - ({title, subtitle, description, items, onClose, onSelect, dataAttributes}, ref) => { - const {isDarkMode} = useTheme(); - - return ( - - {({closeModal, modalTitleId}) => ( - - - {items.map(({id, style, title, icon}) => ( - { - onSelect?.(id); - closeModal(); - }} - > -
- {icon && ( - - {icon.Icon ? ( - - ) : ( - - )} - - )} - - {title} - -
-
- ))} -
-
- )} -
- ); - } -); - -type InfoSheetProps = { - title?: string; - subtitle?: string; - description?: string | ReadonlyArray; - items: ReadonlyArray<{ - id?: string; - title: string; - description?: string; - icon: ExclusifyUnion< - | { - type: 'regular' | 'small'; - Icon: React.ComponentType; - } - | { - type: 'regular' | 'small'; - url: string; - urlDark?: string; - } - | {type: 'bullet'} - >; - }>; - onClose?: () => void; - dataAttributes?: DataAttributes; -}; - -export const InfoSheet = React.forwardRef( - ({title, subtitle, description, items, onClose, dataAttributes}, ref) => { - const {isDarkMode} = useTheme(); - return ( - - {({modalTitleId}) => ( - - - - {items.map((item, idx) => ( - -
- {item.icon.type === 'bullet' ? ( - - ) : item.icon.Icon ? ( - - ) : ( - - )} -
- - {item.title} - {item.description && ( - - {item.description} - - )} - -
- ))} -
-
-
- )} -
- ); - } -); - -type PressedButton = 'PRIMARY' | 'SECONDARY' | 'LINK'; - -type ButtonProps = { - text: string; - trackingEvent?: TrackingEvent | ReadonlyArray; - trackEvent?: boolean; -}; - -type ActionsSheetProps = { - title?: string; - subtitle?: string; - description?: string | ReadonlyArray; - button: ButtonProps; - secondaryButton?: ButtonProps; - buttonLink?: ButtonProps & {withChevron?: boolean}; - onClose?: () => void; - onPressButton?: (pressedButton: PressedButton) => void; - dataAttributes?: DataAttributes; -}; - -export const ActionsSheet = React.forwardRef( - ( - { - title, - subtitle, - description, - button, - secondaryButton, - buttonLink, - onClose, - dataAttributes, - onPressButton, - }, - ref - ) => { - const createPressHandler = (closeModal: () => void, pressedButton: PressedButton) => () => { - onPressButton?.(pressedButton); - closeModal(); - }; - - const getButtonProps = ({text, ...otherProps}: T) => ({ - children: text, - ...otherProps, - }); - - return ( - - {({modalTitleId, closeModal}) => ( - - } - secondaryButton={ - secondaryButton ? ( - - ) : undefined - } - link={ - buttonLink ? ( - - ) : undefined - } - /> - )} - - ); - } -); - -export default Sheet;