@cdx-ui/components 0.2.2 → 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +24 -0
- package/README.md +6 -2
- package/coverage.svg +1 -1
- package/docs/components/accordion/content.md +538 -0
- package/docs/components/alert/content.md +203 -0
- package/docs/components/alert-dialog/content.md +319 -0
- package/docs/components/avatar/content.md +368 -0
- package/docs/components/avatar/design.md +202 -0
- package/docs/components/badge/content.md +235 -0
- package/docs/components/bottom-sheet/content.md +351 -0
- package/docs/components/bottom-sheet/design.md +249 -0
- package/docs/components/breadcrumbs/content.md +169 -0
- package/docs/components/button/content.md +398 -0
- package/docs/components/button/design.md +258 -0
- package/docs/components/calendar/content.md +137 -0
- package/docs/components/card/content.md +283 -0
- package/docs/components/carousel/content.md +416 -0
- package/docs/components/checkbox/content.md +236 -0
- package/docs/components/checkbox/design.md +214 -0
- package/docs/components/chip/content.md +439 -0
- package/docs/components/chip/design.md +418 -0
- package/docs/components/color-area/content.md +86 -0
- package/docs/components/color-field/content.md +134 -0
- package/docs/components/color-picker/content.md +208 -0
- package/docs/components/color-slider/content.md +120 -0
- package/docs/components/color-swatch/content.md +64 -0
- package/docs/components/color-swatch-picker/content.md +126 -0
- package/docs/components/content.md +97 -0
- package/docs/components/currency-input/content.md +205 -0
- package/docs/components/data-grid/content.md +522 -0
- package/docs/components/date-field/content.md +147 -0
- package/docs/components/date-picker/content.md +360 -0
- package/docs/components/date-range-picker/content.md +301 -0
- package/docs/components/date-time-field/content.md +157 -0
- package/docs/components/date-time-list/content.md +105 -0
- package/docs/components/date-time-picker/content.md +272 -0
- package/docs/components/dialog/content.md +436 -0
- package/docs/components/dialog/design.md +192 -0
- package/docs/components/divider/content.md +112 -0
- package/docs/components/drawer/content.md +436 -0
- package/docs/components/field/content.md +277 -0
- package/docs/components/form/content.md +62 -0
- package/docs/components/full-screen-dialog/content.md +881 -0
- package/docs/components/heading/content.md +55 -0
- package/docs/components/icon/content.md +190 -0
- package/docs/components/icon-button/content.md +200 -0
- package/docs/components/icon-button/design.md +165 -0
- package/docs/components/image/content.md +104 -0
- package/docs/components/input/content.md +281 -0
- package/docs/components/input/design.md +389 -0
- package/docs/components/insurance-disclosure/content.md +103 -0
- package/docs/components/link/content.md +180 -0
- package/docs/components/link/design.md +160 -0
- package/docs/components/list-item/content.md +695 -0
- package/docs/components/menu/content.md +1247 -0
- package/docs/components/month-calendar/content.md +84 -0
- package/docs/components/month-picker/content.md +273 -0
- package/docs/components/otp-input/content.md +327 -0
- package/docs/components/progress-bar/content.md +87 -0
- package/docs/components/progress-circle/content.md +176 -0
- package/docs/components/progress-segmented/content.md +119 -0
- package/docs/components/quick-action-button/content.md +154 -0
- package/docs/components/quick-action-button/design.md +170 -0
- package/docs/components/radio/content.md +224 -0
- package/docs/components/range-calendar/content.md +123 -0
- package/docs/components/reorderable-list/content.md +309 -0
- package/docs/components/scoped-theme/content.md +47 -0
- package/docs/components/scroll-shadow/content.md +686 -0
- package/docs/components/select/content.md +400 -0
- package/docs/components/select/design.md +301 -0
- package/docs/components/skeleton/content.md +103 -0
- package/docs/components/slider/content.md +423 -0
- package/docs/components/stack/content.md +161 -0
- package/docs/components/switch/content.md +150 -0
- package/docs/components/switch/design.md +208 -0
- package/docs/components/table/content.md +548 -0
- package/docs/components/table-pagination/content.md +177 -0
- package/docs/components/tabs/content.md +292 -0
- package/docs/components/text/content.md +142 -0
- package/docs/components/textarea/content.md +222 -0
- package/docs/components/tile/content.md +703 -0
- package/docs/components/toast/content.md +456 -0
- package/docs/components/toggle-button/content.md +505 -0
- package/docs/components/tooltip/content.md +350 -0
- package/docs/components/virtualized-list/content.md +250 -0
- package/docs/foundations/content.md +9 -0
- package/docs/foundations/expressions/icons/content.md +19 -0
- package/docs/foundations/styles/tokens/all-tokens/content.md +192 -0
- package/docs/foundations/styles/tokens/what-are-tokens/content.md +33 -0
- package/docs/foundations/styles/tokens/what-are-tokens/design.md +33 -0
- package/docs/getting-started/content.md +4 -0
- package/docs/getting-started/designers/content.md +13 -0
- package/docs/getting-started/designers/design.md +13 -0
- package/docs/getting-started/developers/accessibility/content.md +31 -0
- package/docs/getting-started/developers/content.md +612 -0
- package/docs/getting-started/developers/styling/content.md +193 -0
- package/docs/llms.txt +193 -0
- package/docs/patterns/account-management/content.md +75 -0
- package/docs/patterns/authentication/content.md +52 -0
- package/docs/patterns/content.md +10 -0
- package/docs/patterns/dashboard/content.md +39 -0
- package/docs/patterns/empty-states/content.md +31 -0
- package/docs/patterns/forms/content.md +109 -0
- package/docs/patterns/onboarding/content.md +69 -0
- package/docs/patterns/payments/content.md +35 -0
- package/docs/patterns/settings/content.md +72 -0
- package/docs/resources/content.md +9 -0
- package/docs/resources/figma-libraries/content.md +42 -0
- package/docs/resources/release-notes/0.0.1-beta.118/content.md +27 -0
- package/docs/resources/release-notes/0.0.1-beta.122/content.md +21 -0
- package/docs/resources/release-notes/0.0.1-beta.124/content.md +16 -0
- package/docs/resources/release-notes/0.0.1-beta.126/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.127/content.md +14 -0
- package/docs/resources/release-notes/0.0.1-beta.128/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.129/content.md +18 -0
- package/docs/resources/release-notes/0.0.1-beta.130/content.md +18 -0
- package/docs/resources/release-notes/0.0.1-beta.133/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.134/content.md +17 -0
- package/docs/resources/release-notes/0.0.1-beta.136/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.137/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.138/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.139/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.140/content.md +26 -0
- package/docs/resources/release-notes/0.0.1-beta.141/content.md +63 -0
- package/docs/resources/release-notes/0.0.1-beta.142/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.143/content.md +12 -0
- package/docs/resources/release-notes/0.0.1-beta.144/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.145/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.147/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.149/content.md +10 -0
- package/docs/resources/release-notes/0.0.1-beta.150/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.152/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.154/content.md +15 -0
- package/docs/resources/release-notes/0.0.1-beta.156/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.158/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.159/content.md +11 -0
- package/docs/resources/release-notes/0.0.1-beta.160/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.161/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.163/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.164/content.md +9 -0
- package/docs/resources/release-notes/0.0.1-beta.166/content.md +17 -0
- package/docs/resources/release-notes/0.0.1-beta.167/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.168/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.169/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.171/content.md +16 -0
- package/docs/resources/release-notes/0.0.1-beta.172/content.md +24 -0
- package/docs/resources/release-notes/0.0.1-beta.173/content.md +15 -0
- package/docs/resources/release-notes/0.0.1-beta.174/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.176/content.md +32 -0
- package/docs/resources/release-notes/0.0.1-beta.179/content.md +11 -0
- package/docs/resources/release-notes/0.0.1-beta.182/content.md +13 -0
- package/docs/resources/release-notes/0.0.1-beta.185/content.md +7 -0
- package/docs/resources/release-notes/0.0.1-beta.187/content.md +27 -0
- package/docs/resources/release-notes/0.1.1/content.md +23 -0
- package/docs/resources/release-notes/0.1.2/content.md +7 -0
- package/docs/resources/release-notes/0.1.4/content.md +19 -0
- package/docs/resources/release-notes/0.1.5/content.md +7 -0
- package/docs/resources/release-notes/0.1.6/content.md +7 -0
- package/docs/resources/release-notes/0.2.0/content.md +31 -0
- package/docs/resources/release-notes/0.2.1/content.md +17 -0
- package/docs/resources/release-notes/0.2.2/content.md +11 -0
- package/docs/resources/release-notes/0.2.3/content.md +15 -0
- package/docs/resources/release-notes/content.md +64 -0
- package/lib/commonjs/components/Checkbox/index.js.map +1 -1
- package/lib/commonjs/components/DateTimeList/index.js +11 -26
- package/lib/commonjs/components/DateTimeList/index.js.map +1 -1
- package/lib/commonjs/components/DateTimeList/styles.js +2 -12
- package/lib/commonjs/components/DateTimeList/styles.js.map +1 -1
- package/lib/commonjs/components/Heading/index.js.map +1 -1
- package/lib/commonjs/components/Icon/index.js.map +1 -1
- package/lib/commonjs/components/ListItem/index.js +170 -9
- package/lib/commonjs/components/ListItem/index.js.map +1 -1
- package/lib/commonjs/components/ListItem/styles.js +38 -2
- package/lib/commonjs/components/ListItem/styles.js.map +1 -1
- package/lib/commonjs/components/Menu/index.js +11 -5
- package/lib/commonjs/components/Menu/index.js.map +1 -1
- package/lib/commonjs/components/RangeCalendar/index.js.map +1 -1
- package/lib/commonjs/components/ReorderableList/ReorderableListShared.js +91 -0
- package/lib/commonjs/components/ReorderableList/ReorderableListShared.js.map +1 -0
- package/lib/commonjs/components/ReorderableList/index.js +135 -0
- package/lib/commonjs/components/ReorderableList/index.js.map +1 -0
- package/lib/commonjs/components/ReorderableList/index.web.js +233 -0
- package/lib/commonjs/components/ReorderableList/index.web.js.map +1 -0
- package/lib/commonjs/components/ReorderableList/labels.js +47 -0
- package/lib/commonjs/components/ReorderableList/labels.js.map +1 -0
- package/lib/commonjs/components/ReorderableList/reorderItems.js +16 -0
- package/lib/commonjs/components/ReorderableList/reorderItems.js.map +1 -0
- package/lib/commonjs/components/ReorderableList/rowContext.js +42 -0
- package/lib/commonjs/components/ReorderableList/rowContext.js.map +1 -0
- package/lib/commonjs/components/ReorderableList/types.js +6 -0
- package/lib/commonjs/components/ReorderableList/types.js.map +1 -0
- package/lib/commonjs/components/ReorderableList/useReorder.js +131 -0
- package/lib/commonjs/components/ReorderableList/useReorder.js.map +1 -0
- package/lib/commonjs/components/ReorderableList/webDnd.js +64 -0
- package/lib/commonjs/components/ReorderableList/webDnd.js.map +1 -0
- package/lib/commonjs/components/ScopedTheme/index.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/gradient.js +29 -0
- package/lib/commonjs/components/ScrollShadow/gradient.js.map +1 -0
- package/lib/commonjs/components/ScrollShadow/index.js +171 -44
- package/lib/commonjs/components/ScrollShadow/index.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/styles.js +58 -14
- package/lib/commonjs/components/ScrollShadow/styles.js.map +1 -1
- package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js +63 -0
- package/lib/commonjs/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
- package/lib/commonjs/components/ScrollShadow/useScrollShadow.js +48 -8
- package/lib/commonjs/components/ScrollShadow/useScrollShadow.js.map +1 -1
- package/lib/commonjs/components/Skeleton/index.js.map +1 -1
- package/lib/commonjs/components/TablePagination/index.js.map +1 -1
- package/lib/commonjs/components/Tabs/index.js +16 -23
- package/lib/commonjs/components/Tabs/index.js.map +1 -1
- package/lib/commonjs/components/Tabs/styles.js +1 -10
- package/lib/commonjs/components/Tabs/styles.js.map +1 -1
- package/lib/commonjs/components/Text/index.js.map +1 -1
- package/lib/commonjs/components/Tile/styles.js +1 -1
- package/lib/commonjs/components/Tile/styles.js.map +1 -1
- package/lib/commonjs/components/index.js.map +1 -1
- package/lib/commonjs/figma/ListItem.SectionHeader.figma.js +20 -5
- package/lib/commonjs/figma/ListItem.SectionHeader.figma.js.map +1 -1
- package/lib/commonjs/reorderable-list.js +17 -0
- package/lib/commonjs/reorderable-list.js.map +1 -0
- package/lib/module/components/Checkbox/index.js.map +1 -1
- package/lib/module/components/DateTimeList/index.js +12 -27
- package/lib/module/components/DateTimeList/index.js.map +1 -1
- package/lib/module/components/DateTimeList/styles.js +1 -11
- package/lib/module/components/DateTimeList/styles.js.map +1 -1
- package/lib/module/components/Heading/index.js.map +1 -1
- package/lib/module/components/Icon/index.js.map +1 -1
- package/lib/module/components/ListItem/index.js +163 -14
- package/lib/module/components/ListItem/index.js.map +1 -1
- package/lib/module/components/ListItem/styles.js +37 -1
- package/lib/module/components/ListItem/styles.js.map +1 -1
- package/lib/module/components/Menu/index.js +11 -5
- package/lib/module/components/Menu/index.js.map +1 -1
- package/lib/module/components/RangeCalendar/index.js.map +1 -1
- package/lib/module/components/ReorderableList/ReorderableListShared.js +86 -0
- package/lib/module/components/ReorderableList/ReorderableListShared.js.map +1 -0
- package/lib/module/components/ReorderableList/index.js +130 -0
- package/lib/module/components/ReorderableList/index.js.map +1 -0
- package/lib/module/components/ReorderableList/index.web.js +229 -0
- package/lib/module/components/ReorderableList/index.web.js.map +1 -0
- package/lib/module/components/ReorderableList/labels.js +41 -0
- package/lib/module/components/ReorderableList/labels.js.map +1 -0
- package/lib/module/components/ReorderableList/reorderItems.js +12 -0
- package/lib/module/components/ReorderableList/reorderItems.js.map +1 -0
- package/lib/module/components/ReorderableList/rowContext.js +38 -0
- package/lib/module/components/ReorderableList/rowContext.js.map +1 -0
- package/lib/module/components/ReorderableList/types.js +4 -0
- package/lib/module/components/ReorderableList/types.js.map +1 -0
- package/lib/module/components/ReorderableList/useReorder.js +123 -0
- package/lib/module/components/ReorderableList/useReorder.js.map +1 -0
- package/lib/module/components/ReorderableList/webDnd.js +59 -0
- package/lib/module/components/ReorderableList/webDnd.js.map +1 -0
- package/lib/module/components/ScopedTheme/index.js.map +1 -1
- package/lib/module/components/ScrollShadow/gradient.js +24 -0
- package/lib/module/components/ScrollShadow/gradient.js.map +1 -0
- package/lib/module/components/ScrollShadow/index.js +170 -48
- package/lib/module/components/ScrollShadow/index.js.map +1 -1
- package/lib/module/components/ScrollShadow/styles.js +57 -13
- package/lib/module/components/ScrollShadow/styles.js.map +1 -1
- package/lib/module/components/ScrollShadow/useComposedScrollHandler.js +57 -0
- package/lib/module/components/ScrollShadow/useComposedScrollHandler.js.map +1 -0
- package/lib/module/components/ScrollShadow/useScrollShadow.js +46 -8
- package/lib/module/components/ScrollShadow/useScrollShadow.js.map +1 -1
- package/lib/module/components/Skeleton/index.js.map +1 -1
- package/lib/module/components/TablePagination/index.js.map +1 -1
- package/lib/module/components/Tabs/index.js +17 -24
- package/lib/module/components/Tabs/index.js.map +1 -1
- package/lib/module/components/Tabs/styles.js +0 -9
- package/lib/module/components/Tabs/styles.js.map +1 -1
- package/lib/module/components/Text/index.js.map +1 -1
- package/lib/module/components/Tile/styles.js +1 -1
- package/lib/module/components/Tile/styles.js.map +1 -1
- package/lib/module/components/index.js.map +1 -1
- package/lib/module/figma/ListItem.SectionHeader.figma.js +20 -5
- package/lib/module/figma/ListItem.SectionHeader.figma.js.map +1 -1
- package/lib/module/reorderable-list.js +4 -0
- package/lib/module/reorderable-list.js.map +1 -0
- package/lib/typescript/components/Checkbox/index.d.ts +22 -0
- package/lib/typescript/components/Checkbox/index.d.ts.map +1 -1
- package/lib/typescript/components/DateTimeList/index.d.ts.map +1 -1
- package/lib/typescript/components/DateTimeList/styles.d.ts +1 -4
- package/lib/typescript/components/DateTimeList/styles.d.ts.map +1 -1
- package/lib/typescript/components/Heading/index.d.ts +20 -2
- package/lib/typescript/components/Heading/index.d.ts.map +1 -1
- package/lib/typescript/components/Icon/index.d.ts +2 -0
- package/lib/typescript/components/Icon/index.d.ts.map +1 -1
- package/lib/typescript/components/ListItem/index.d.ts +28 -5
- package/lib/typescript/components/ListItem/index.d.ts.map +1 -1
- package/lib/typescript/components/ListItem/styles.d.ts +6 -1
- package/lib/typescript/components/ListItem/styles.d.ts.map +1 -1
- package/lib/typescript/components/Menu/index.d.ts +116 -4
- package/lib/typescript/components/Menu/index.d.ts.map +1 -1
- package/lib/typescript/components/RangeCalendar/index.d.ts +2 -0
- package/lib/typescript/components/RangeCalendar/index.d.ts.map +1 -1
- package/lib/typescript/components/ReorderableList/ReorderableListShared.d.ts +31 -0
- package/lib/typescript/components/ReorderableList/ReorderableListShared.d.ts.map +1 -0
- package/lib/typescript/components/ReorderableList/index.d.ts +8 -0
- package/lib/typescript/components/ReorderableList/index.d.ts.map +1 -0
- package/lib/typescript/components/ReorderableList/index.web.d.ts +8 -0
- package/lib/typescript/components/ReorderableList/index.web.d.ts.map +1 -0
- package/lib/typescript/components/ReorderableList/labels.d.ts +16 -0
- package/lib/typescript/components/ReorderableList/labels.d.ts.map +1 -0
- package/lib/typescript/components/ReorderableList/reorderItems.d.ts +3 -0
- package/lib/typescript/components/ReorderableList/reorderItems.d.ts.map +1 -0
- package/lib/typescript/components/ReorderableList/rowContext.d.ts +57 -0
- package/lib/typescript/components/ReorderableList/rowContext.d.ts.map +1 -0
- package/lib/typescript/components/ReorderableList/types.d.ts +75 -0
- package/lib/typescript/components/ReorderableList/types.d.ts.map +1 -0
- package/lib/typescript/components/ReorderableList/useReorder.d.ts +31 -0
- package/lib/typescript/components/ReorderableList/useReorder.d.ts.map +1 -0
- package/lib/typescript/components/ReorderableList/webDnd.d.ts +27 -0
- package/lib/typescript/components/ReorderableList/webDnd.d.ts.map +1 -0
- package/lib/typescript/components/ScopedTheme/index.d.ts +6 -1
- package/lib/typescript/components/ScopedTheme/index.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/gradient.d.ts +7 -0
- package/lib/typescript/components/ScrollShadow/gradient.d.ts.map +1 -0
- package/lib/typescript/components/ScrollShadow/index.d.ts +57 -15
- package/lib/typescript/components/ScrollShadow/index.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/styles.d.ts +8 -2
- package/lib/typescript/components/ScrollShadow/styles.d.ts.map +1 -1
- package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts +13 -0
- package/lib/typescript/components/ScrollShadow/useComposedScrollHandler.d.ts.map +1 -0
- package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts +15 -2
- package/lib/typescript/components/ScrollShadow/useScrollShadow.d.ts.map +1 -1
- package/lib/typescript/components/Skeleton/index.d.ts +3 -0
- package/lib/typescript/components/Skeleton/index.d.ts.map +1 -1
- package/lib/typescript/components/TablePagination/index.d.ts +54 -0
- package/lib/typescript/components/TablePagination/index.d.ts.map +1 -1
- package/lib/typescript/components/Tabs/index.d.ts.map +1 -1
- package/lib/typescript/components/Tabs/styles.d.ts +0 -7
- package/lib/typescript/components/Tabs/styles.d.ts.map +1 -1
- package/lib/typescript/components/Text/index.d.ts +12 -2
- package/lib/typescript/components/Text/index.d.ts.map +1 -1
- package/lib/typescript/components/Tile/styles.d.ts.map +1 -1
- package/lib/typescript/components/ToggleButton/styles.d.ts +1 -1
- package/lib/typescript/components/index.d.ts +1 -0
- package/lib/typescript/components/index.d.ts.map +1 -1
- package/lib/typescript/figma/ListItem.SectionHeader.figma.d.ts.map +1 -1
- package/lib/typescript/reorderable-list.d.ts +2 -0
- package/lib/typescript/reorderable-list.d.ts.map +1 -0
- package/package.json +37 -8
- package/src/components/Checkbox/index.tsx +22 -0
- package/src/components/DateTimeList/index.tsx +13 -26
- package/src/components/DateTimeList/styles.ts +1 -10
- package/src/components/Heading/index.tsx +10 -1
- package/src/components/Icon/index.tsx +2 -0
- package/src/components/ListItem/index.tsx +232 -15
- package/src/components/ListItem/styles.ts +41 -0
- package/src/components/Menu/index.tsx +128 -12
- package/src/components/RangeCalendar/index.tsx +2 -0
- package/src/components/ReorderableList/ReorderableListShared.tsx +113 -0
- package/src/components/ReorderableList/index.tsx +162 -0
- package/src/components/ReorderableList/index.web.tsx +254 -0
- package/src/components/ReorderableList/labels.ts +52 -0
- package/src/components/ReorderableList/reorderItems.ts +16 -0
- package/src/components/ReorderableList/rowContext.tsx +72 -0
- package/src/components/ReorderableList/types.ts +80 -0
- package/src/components/ReorderableList/useReorder.ts +159 -0
- package/src/components/ReorderableList/webDnd.ts +60 -0
- package/src/components/ScopedTheme/index.tsx +6 -1
- package/src/components/ScrollShadow/gradient.ts +48 -0
- package/src/components/ScrollShadow/index.tsx +300 -69
- package/src/components/ScrollShadow/styles.ts +45 -28
- package/src/components/ScrollShadow/useComposedScrollHandler.ts +58 -0
- package/src/components/ScrollShadow/useScrollShadow.ts +72 -10
- package/src/components/Skeleton/index.tsx +3 -0
- package/src/components/TablePagination/index.tsx +54 -0
- package/src/components/Tabs/index.tsx +25 -35
- package/src/components/Tabs/styles.ts +0 -9
- package/src/components/Text/index.tsx +6 -1
- package/src/components/Tile/styles.ts +4 -1
- package/src/components/index.ts +5 -0
- package/src/reorderable-list.ts +1 -0
|
@@ -0,0 +1,881 @@
|
|
|
1
|
+
# Full Screen Dialog (https://design.candescent.com/docs/components/full-screen-dialog)
|
|
2
|
+
|
|
3
|
+
Resources: [Storybook](https://victorious-wave-0daadf00f.6.azurestaticapps.net/?path=/story/overlays-fullscreendialog--default)
|
|
4
|
+
|
|
5
|
+
A compound modal that presents a task as a full page. It shares the dialog's open state, focus trapping, and dismissal, and adds a back / title / close header. Bottom sheets, menus, selects, and picker popovers opened from it appear on top.
|
|
6
|
+
|
|
7
|
+
```tsx
|
|
8
|
+
import { Button, FullScreenDialog } from '@cdx-ui/components';
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
> [!NOTE]
|
|
12
|
+
>
|
|
13
|
+
> **Portal host**
|
|
14
|
+
>
|
|
15
|
+
> `ForgeDesignProvider` mounts the shared portal host automatically. If you do not use the
|
|
16
|
+
> provider, mount one `PortalHost` from `@cdx-ui/primitives` near your app root. On web, to keep
|
|
17
|
+
> the dialog inside an embedded surface such as a device preview, wrap that surface in
|
|
18
|
+
> `PortalProvider` and give its `PortalHost` a `container` element inside it; the fixed overlay
|
|
19
|
+
> stays inside only when an ancestor of the container sets a `transform`.
|
|
20
|
+
|
|
21
|
+
## Basic
|
|
22
|
+
|
|
23
|
+
Put a `ScrollView` inside `FullScreenDialog.Content` so the body scrolls under a fixed header. The header's close button closes the dialog unless you pass `onClose`. The popup always covers the viewport; on wide screens, add `w-full max-w-md self-center` to the header and content to keep the page at a phone reading width.
|
|
24
|
+
|
|
25
|
+
```tsx
|
|
26
|
+
import { useState } from 'react';
|
|
27
|
+
import { Box, Button, FullScreenDialog, ScrollView, Text } from '@cdx-ui/components';
|
|
28
|
+
|
|
29
|
+
const details = [
|
|
30
|
+
{ label: 'From', value: 'Everyday Checking •••• 4642' },
|
|
31
|
+
{ label: 'To', value: 'High-yield Savings •••• 5541' },
|
|
32
|
+
{ label: 'Amount', value: '$250.00' },
|
|
33
|
+
{ label: 'Frequency', value: 'Monthly on the 1st' },
|
|
34
|
+
];
|
|
35
|
+
|
|
36
|
+
export default function FullScreenDialogBasicDemo() {
|
|
37
|
+
const [open, setOpen] = useState(false);
|
|
38
|
+
|
|
39
|
+
return (
|
|
40
|
+
<FullScreenDialog isOpen={open} onOpenChange={setOpen}>
|
|
41
|
+
<FullScreenDialog.Trigger asChild>
|
|
42
|
+
<Button>
|
|
43
|
+
<Button.Label>View transfer</Button.Label>
|
|
44
|
+
</Button>
|
|
45
|
+
</FullScreenDialog.Trigger>
|
|
46
|
+
<FullScreenDialog.Popup>
|
|
47
|
+
<FullScreenDialog.Header
|
|
48
|
+
title="Scheduled transfer"
|
|
49
|
+
className="w-full max-w-md self-center"
|
|
50
|
+
/>
|
|
51
|
+
<FullScreenDialog.Content className="w-full max-w-md self-center">
|
|
52
|
+
<ScrollView className="flex-1" contentContainerClassName="gap-4 p-4">
|
|
53
|
+
{details.map((detail) => (
|
|
54
|
+
<Box key={detail.label} className="gap-1">
|
|
55
|
+
<Text color="secondary" size="sm">
|
|
56
|
+
{detail.label}
|
|
57
|
+
</Text>
|
|
58
|
+
<Text>{detail.value}</Text>
|
|
59
|
+
</Box>
|
|
60
|
+
))}
|
|
61
|
+
<Button onPress={() => setOpen(false)}>
|
|
62
|
+
<Button.Label>Done</Button.Label>
|
|
63
|
+
</Button>
|
|
64
|
+
</ScrollView>
|
|
65
|
+
</FullScreenDialog.Content>
|
|
66
|
+
</FullScreenDialog.Popup>
|
|
67
|
+
</FullScreenDialog>
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## With footer
|
|
73
|
+
|
|
74
|
+
`FullScreenDialog.Content` is a flex column, so actions placed after the `ScrollView` stay pinned above the bottom safe area while the body scrolls. Use `subtitle` for secondary context under the title, such as the payee.
|
|
75
|
+
|
|
76
|
+
```tsx
|
|
77
|
+
import { useState } from 'react';
|
|
78
|
+
import {
|
|
79
|
+
Avatar,
|
|
80
|
+
Box,
|
|
81
|
+
Button,
|
|
82
|
+
Chip,
|
|
83
|
+
Divider,
|
|
84
|
+
FullScreenDialog,
|
|
85
|
+
Heading,
|
|
86
|
+
ListItem,
|
|
87
|
+
ScrollView,
|
|
88
|
+
Text,
|
|
89
|
+
} from '@cdx-ui/components';
|
|
90
|
+
|
|
91
|
+
const details = [
|
|
92
|
+
{ label: 'From', value: 'Everyday Checking •••• 4642' },
|
|
93
|
+
{ label: 'Deliver by', value: 'Friday, October 9' },
|
|
94
|
+
{ label: 'Frequency', value: 'Monthly on the 9th' },
|
|
95
|
+
{ label: 'Memo', value: 'Account 0193 — October' },
|
|
96
|
+
];
|
|
97
|
+
|
|
98
|
+
export default function FullScreenDialogWithFooterDemo() {
|
|
99
|
+
const [open, setOpen] = useState(false);
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<FullScreenDialog isOpen={open} onOpenChange={setOpen}>
|
|
103
|
+
<FullScreenDialog.Trigger asChild>
|
|
104
|
+
<Button>
|
|
105
|
+
<Button.Label>Review payment</Button.Label>
|
|
106
|
+
</Button>
|
|
107
|
+
</FullScreenDialog.Trigger>
|
|
108
|
+
<FullScreenDialog.Popup>
|
|
109
|
+
<FullScreenDialog.Header
|
|
110
|
+
title="Review payment"
|
|
111
|
+
subtitle="Springfield Electric"
|
|
112
|
+
className="w-full max-w-md self-center"
|
|
113
|
+
/>
|
|
114
|
+
<FullScreenDialog.Content className="w-full max-w-md self-center">
|
|
115
|
+
<ScrollView className="flex-1" contentContainerClassName="gap-6 p-4">
|
|
116
|
+
<Box className="items-center gap-3 py-4">
|
|
117
|
+
<Avatar size="2xl" color="brand" accessibilityLabel="Springfield Electric">
|
|
118
|
+
<Avatar.Text>Springfield Electric</Avatar.Text>
|
|
119
|
+
</Avatar>
|
|
120
|
+
<Heading size="xl">$84.12</Heading>
|
|
121
|
+
<Chip color="warning" size="small">
|
|
122
|
+
<Chip.Label>Scheduled</Chip.Label>
|
|
123
|
+
</Chip>
|
|
124
|
+
</Box>
|
|
125
|
+
<Box>
|
|
126
|
+
{details.map((detail, index) => (
|
|
127
|
+
<ListItem key={detail.label} showSeparator={index < details.length - 1}>
|
|
128
|
+
<ListItem.Content>
|
|
129
|
+
<ListItem.Description>{detail.label}</ListItem.Description>
|
|
130
|
+
<ListItem.Title>{detail.value}</ListItem.Title>
|
|
131
|
+
</ListItem.Content>
|
|
132
|
+
</ListItem>
|
|
133
|
+
))}
|
|
134
|
+
</Box>
|
|
135
|
+
<Text color="secondary" size="sm">
|
|
136
|
+
Payments scheduled after 8 PM ET are processed the next business day. You can cancel
|
|
137
|
+
this payment until it starts processing.
|
|
138
|
+
</Text>
|
|
139
|
+
</ScrollView>
|
|
140
|
+
<Divider />
|
|
141
|
+
<Box className="gap-3 p-4">
|
|
142
|
+
<Button onPress={() => setOpen(false)}>
|
|
143
|
+
<Button.Label>Pay $84.12</Button.Label>
|
|
144
|
+
</Button>
|
|
145
|
+
<Button variant="ghost" onPress={() => setOpen(false)}>
|
|
146
|
+
<Button.Label>Edit payment</Button.Label>
|
|
147
|
+
</Button>
|
|
148
|
+
</Box>
|
|
149
|
+
</FullScreenDialog.Content>
|
|
150
|
+
</FullScreenDialog.Popup>
|
|
151
|
+
</FullScreenDialog>
|
|
152
|
+
);
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Custom triggers
|
|
157
|
+
|
|
158
|
+
Use `asChild` to open the dialog from any pressable, such as a list item or a quick action button. A dialog can have more than one trigger. To open it from a menu item, control `isOpen` and set it from the item's `onPress`.
|
|
159
|
+
|
|
160
|
+
```tsx
|
|
161
|
+
import { useState } from 'react';
|
|
162
|
+
import {
|
|
163
|
+
Box,
|
|
164
|
+
Button,
|
|
165
|
+
Card,
|
|
166
|
+
Chip,
|
|
167
|
+
FullScreenDialog,
|
|
168
|
+
Heading,
|
|
169
|
+
IconButton,
|
|
170
|
+
ListItem,
|
|
171
|
+
Menu,
|
|
172
|
+
QuickActionButton,
|
|
173
|
+
ScrollView,
|
|
174
|
+
Text,
|
|
175
|
+
} from '@cdx-ui/components';
|
|
176
|
+
import {
|
|
177
|
+
ChevronRight,
|
|
178
|
+
ContentCopy,
|
|
179
|
+
Download,
|
|
180
|
+
Info,
|
|
181
|
+
MoreHoriz,
|
|
182
|
+
Payments,
|
|
183
|
+
Send,
|
|
184
|
+
} from '@cdx-ui/icons';
|
|
185
|
+
|
|
186
|
+
const details = [
|
|
187
|
+
{ label: 'Account number', value: '•••• •••• 4642', copyable: true },
|
|
188
|
+
{ label: 'Routing number', value: '011000015', copyable: true },
|
|
189
|
+
{ label: 'Interest rate', value: '0.01% APY', copyable: false },
|
|
190
|
+
{ label: 'Opened', value: 'March 12, 2019', copyable: false },
|
|
191
|
+
];
|
|
192
|
+
|
|
193
|
+
export default function FullScreenDialogCustomTriggersDemo() {
|
|
194
|
+
const [open, setOpen] = useState(false);
|
|
195
|
+
|
|
196
|
+
return (
|
|
197
|
+
<FullScreenDialog isOpen={open} onOpenChange={setOpen} className="w-full max-w-md gap-4">
|
|
198
|
+
<Card fullBleed>
|
|
199
|
+
<Card.Header>
|
|
200
|
+
<Heading size="sm">Everyday Checking</Heading>
|
|
201
|
+
<Menu placement="bottom-end">
|
|
202
|
+
<Menu.Trigger asChild>
|
|
203
|
+
<IconButton
|
|
204
|
+
as={MoreHoriz}
|
|
205
|
+
variant="ghost"
|
|
206
|
+
size="small"
|
|
207
|
+
accessibilityLabel="Everyday Checking actions"
|
|
208
|
+
/>
|
|
209
|
+
</Menu.Trigger>
|
|
210
|
+
<Menu.Popup>
|
|
211
|
+
<Menu.Content accessibilityLabel="Everyday Checking actions">
|
|
212
|
+
<Menu.Item onPress={() => setOpen(true)}>
|
|
213
|
+
<Menu.ItemLabel>Account details</Menu.ItemLabel>
|
|
214
|
+
</Menu.Item>
|
|
215
|
+
<Menu.Item onPress={() => undefined}>
|
|
216
|
+
<Menu.ItemLabel>Manage alerts</Menu.ItemLabel>
|
|
217
|
+
</Menu.Item>
|
|
218
|
+
</Menu.Content>
|
|
219
|
+
</Menu.Popup>
|
|
220
|
+
</Menu>
|
|
221
|
+
</Card.Header>
|
|
222
|
+
<Card.Content>
|
|
223
|
+
<FullScreenDialog.Trigger asChild>
|
|
224
|
+
<ListItem showSeparator={false} accessibilityHint="Opens account details">
|
|
225
|
+
<ListItem.Content>
|
|
226
|
+
<ListItem.Description>Available balance</ListItem.Description>
|
|
227
|
+
<ListItem.Title>$2,418.07</ListItem.Title>
|
|
228
|
+
</ListItem.Content>
|
|
229
|
+
<ListItem.TrailingSlot>
|
|
230
|
+
<ChevronRight size={20} />
|
|
231
|
+
</ListItem.TrailingSlot>
|
|
232
|
+
</ListItem>
|
|
233
|
+
</FullScreenDialog.Trigger>
|
|
234
|
+
</Card.Content>
|
|
235
|
+
</Card>
|
|
236
|
+
|
|
237
|
+
<Box className="flex-row justify-center gap-4">
|
|
238
|
+
<QuickActionButton>
|
|
239
|
+
<QuickActionButton.Icon as={Send} />
|
|
240
|
+
<QuickActionButton.Label>Transfer</QuickActionButton.Label>
|
|
241
|
+
</QuickActionButton>
|
|
242
|
+
<QuickActionButton>
|
|
243
|
+
<QuickActionButton.Icon as={Payments} />
|
|
244
|
+
<QuickActionButton.Label>Pay</QuickActionButton.Label>
|
|
245
|
+
</QuickActionButton>
|
|
246
|
+
<FullScreenDialog.Trigger asChild>
|
|
247
|
+
<QuickActionButton>
|
|
248
|
+
<QuickActionButton.Icon as={Info} />
|
|
249
|
+
<QuickActionButton.Label>Details</QuickActionButton.Label>
|
|
250
|
+
</QuickActionButton>
|
|
251
|
+
</FullScreenDialog.Trigger>
|
|
252
|
+
</Box>
|
|
253
|
+
|
|
254
|
+
<FullScreenDialog.Popup>
|
|
255
|
+
<FullScreenDialog.Header
|
|
256
|
+
title="Account details"
|
|
257
|
+
subtitle="Everyday Checking •••• 4642"
|
|
258
|
+
className="w-full max-w-md self-center"
|
|
259
|
+
/>
|
|
260
|
+
<FullScreenDialog.Content className="w-full max-w-md self-center">
|
|
261
|
+
<ScrollView className="flex-1" contentContainerClassName="gap-6 p-4">
|
|
262
|
+
<Box className="items-center gap-2 py-4">
|
|
263
|
+
<Text color="secondary" size="sm">
|
|
264
|
+
Available balance
|
|
265
|
+
</Text>
|
|
266
|
+
<Heading size="xl">$2,418.07</Heading>
|
|
267
|
+
<Chip color="success" size="small">
|
|
268
|
+
<Chip.Label>Active</Chip.Label>
|
|
269
|
+
</Chip>
|
|
270
|
+
</Box>
|
|
271
|
+
<Box>
|
|
272
|
+
{details.map((detail, index) => (
|
|
273
|
+
<ListItem key={detail.label} showSeparator={index < details.length - 1}>
|
|
274
|
+
<ListItem.Content>
|
|
275
|
+
<ListItem.Description>{detail.label}</ListItem.Description>
|
|
276
|
+
<ListItem.Title>{detail.value}</ListItem.Title>
|
|
277
|
+
</ListItem.Content>
|
|
278
|
+
{detail.copyable ? (
|
|
279
|
+
<ListItem.TrailingSlot>
|
|
280
|
+
<IconButton
|
|
281
|
+
as={ContentCopy}
|
|
282
|
+
variant="ghost"
|
|
283
|
+
size="small"
|
|
284
|
+
accessibilityLabel={`Copy ${detail.label.toLowerCase()}`}
|
|
285
|
+
onPress={() => undefined}
|
|
286
|
+
/>
|
|
287
|
+
</ListItem.TrailingSlot>
|
|
288
|
+
) : null}
|
|
289
|
+
</ListItem>
|
|
290
|
+
))}
|
|
291
|
+
</Box>
|
|
292
|
+
<Button variant="outline">
|
|
293
|
+
<Button.Icon as={Download} position="leading" />
|
|
294
|
+
<Button.Label>Download statements</Button.Label>
|
|
295
|
+
</Button>
|
|
296
|
+
</ScrollView>
|
|
297
|
+
</FullScreenDialog.Content>
|
|
298
|
+
</FullScreenDialog.Popup>
|
|
299
|
+
</FullScreenDialog>
|
|
300
|
+
);
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
## Header content
|
|
305
|
+
|
|
306
|
+
Pass `children` to `FullScreenDialog.Header` to replace the title, for example with a search field. The back and close buttons stay in place. Without a title, the popup has no accessible name, so set `aria-label` on `FullScreenDialog.Popup`.
|
|
307
|
+
|
|
308
|
+
```tsx
|
|
309
|
+
import { useState } from 'react';
|
|
310
|
+
import {
|
|
311
|
+
Avatar,
|
|
312
|
+
Box,
|
|
313
|
+
FullScreenDialog,
|
|
314
|
+
Input,
|
|
315
|
+
ListItem,
|
|
316
|
+
ScrollView,
|
|
317
|
+
Text,
|
|
318
|
+
} from '@cdx-ui/components';
|
|
319
|
+
import { Check, ChevronRight, Search } from '@cdx-ui/icons';
|
|
320
|
+
|
|
321
|
+
const payees = [
|
|
322
|
+
{ id: 'electric', name: 'Springfield Electric', detail: 'Account •••• 0193' },
|
|
323
|
+
{ id: 'water', name: 'Shelbyville Water', detail: 'Account •••• 7720' },
|
|
324
|
+
{ id: 'mortgage', name: 'Evergreen Mortgage', detail: 'Loan •••• 4410' },
|
|
325
|
+
{ id: 'internet', name: 'Lakeside Fiber', detail: 'Account •••• 3358' },
|
|
326
|
+
{ id: 'insurance', name: 'Harbor Auto Insurance', detail: 'Policy •••• 9021' },
|
|
327
|
+
{ id: 'phone', name: 'Northwind Wireless', detail: 'Account •••• 6634' },
|
|
328
|
+
];
|
|
329
|
+
|
|
330
|
+
export default function FullScreenDialogHeaderContentDemo() {
|
|
331
|
+
const [open, setOpen] = useState(false);
|
|
332
|
+
const [query, setQuery] = useState('');
|
|
333
|
+
const [payeeId, setPayeeId] = useState('electric');
|
|
334
|
+
const payee = payees.find((item) => item.id === payeeId);
|
|
335
|
+
const matches = payees.filter((item) =>
|
|
336
|
+
item.name.toLowerCase().includes(query.trim().toLowerCase()),
|
|
337
|
+
);
|
|
338
|
+
|
|
339
|
+
const handleOpenChange = (next: boolean) => {
|
|
340
|
+
if (next) setQuery('');
|
|
341
|
+
setOpen(next);
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
return (
|
|
345
|
+
<FullScreenDialog isOpen={open} onOpenChange={handleOpenChange} className="w-full max-w-md">
|
|
346
|
+
<Text color="secondary" size="sm">
|
|
347
|
+
Pay to
|
|
348
|
+
</Text>
|
|
349
|
+
<FullScreenDialog.Trigger asChild>
|
|
350
|
+
<ListItem showSeparator={false} accessibilityHint="Opens a searchable list of payees">
|
|
351
|
+
<ListItem.LeadingSlot>
|
|
352
|
+
<Avatar size="lg" color="brand" accessibilityLabel={payee?.name ?? 'Payee'}>
|
|
353
|
+
<Avatar.Text>{payee?.name ?? ''}</Avatar.Text>
|
|
354
|
+
</Avatar>
|
|
355
|
+
</ListItem.LeadingSlot>
|
|
356
|
+
<ListItem.Content>
|
|
357
|
+
<ListItem.Title>{payee?.name ?? 'Choose a payee'}</ListItem.Title>
|
|
358
|
+
<ListItem.Description>{payee?.detail}</ListItem.Description>
|
|
359
|
+
</ListItem.Content>
|
|
360
|
+
<ListItem.TrailingSlot>
|
|
361
|
+
<ChevronRight size={20} />
|
|
362
|
+
</ListItem.TrailingSlot>
|
|
363
|
+
</ListItem>
|
|
364
|
+
</FullScreenDialog.Trigger>
|
|
365
|
+
|
|
366
|
+
<FullScreenDialog.Popup aria-label="Choose a payee">
|
|
367
|
+
<FullScreenDialog.Header
|
|
368
|
+
closeAccessibilityLabel="Cancel"
|
|
369
|
+
className="w-full max-w-md self-center"
|
|
370
|
+
>
|
|
371
|
+
<Box className="px-2">
|
|
372
|
+
<Input variant="outline">
|
|
373
|
+
<Input.Slot>
|
|
374
|
+
<Input.Icon as={Search} />
|
|
375
|
+
</Input.Slot>
|
|
376
|
+
<Input.Field
|
|
377
|
+
accessibilityLabel="Search payees"
|
|
378
|
+
placeholder="Search payees"
|
|
379
|
+
value={query}
|
|
380
|
+
onChangeText={setQuery}
|
|
381
|
+
autoCorrect={false}
|
|
382
|
+
returnKeyType="search"
|
|
383
|
+
/>
|
|
384
|
+
</Input>
|
|
385
|
+
</Box>
|
|
386
|
+
</FullScreenDialog.Header>
|
|
387
|
+
<FullScreenDialog.Content className="w-full max-w-md self-center">
|
|
388
|
+
<ScrollView
|
|
389
|
+
className="flex-1"
|
|
390
|
+
contentContainerClassName="p-4"
|
|
391
|
+
keyboardShouldPersistTaps="handled"
|
|
392
|
+
keyboardDismissMode="on-drag"
|
|
393
|
+
>
|
|
394
|
+
{matches.map((item, index) => (
|
|
395
|
+
<ListItem
|
|
396
|
+
key={item.id}
|
|
397
|
+
showSeparator={index < matches.length - 1}
|
|
398
|
+
accessibilityState={{ selected: item.id === payeeId }}
|
|
399
|
+
onPress={() => {
|
|
400
|
+
setPayeeId(item.id);
|
|
401
|
+
setOpen(false);
|
|
402
|
+
}}
|
|
403
|
+
>
|
|
404
|
+
<ListItem.LeadingSlot>
|
|
405
|
+
<Avatar size="lg" accessibilityLabel={item.name}>
|
|
406
|
+
<Avatar.Text>{item.name}</Avatar.Text>
|
|
407
|
+
</Avatar>
|
|
408
|
+
</ListItem.LeadingSlot>
|
|
409
|
+
<ListItem.Content>
|
|
410
|
+
<ListItem.Title>{item.name}</ListItem.Title>
|
|
411
|
+
<ListItem.Description>{item.detail}</ListItem.Description>
|
|
412
|
+
</ListItem.Content>
|
|
413
|
+
{item.id === payeeId ? (
|
|
414
|
+
<ListItem.TrailingSlot>
|
|
415
|
+
<Check size={20} />
|
|
416
|
+
</ListItem.TrailingSlot>
|
|
417
|
+
) : null}
|
|
418
|
+
</ListItem>
|
|
419
|
+
))}
|
|
420
|
+
{matches.length === 0 ? (
|
|
421
|
+
<Box className="items-center gap-1 py-8">
|
|
422
|
+
<Text>No payees found</Text>
|
|
423
|
+
<Text color="secondary" size="sm">
|
|
424
|
+
Try a different name, or add a new payee.
|
|
425
|
+
</Text>
|
|
426
|
+
</Box>
|
|
427
|
+
) : null}
|
|
428
|
+
</ScrollView>
|
|
429
|
+
</FullScreenDialog.Content>
|
|
430
|
+
</FullScreenDialog.Popup>
|
|
431
|
+
</FullScreenDialog>
|
|
432
|
+
);
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
## Multi-step flow
|
|
437
|
+
|
|
438
|
+
Keep the step index in your own state and render the current step. Set `onBack` on the header only after the first step: it shows the back button and also handles Android system back, so both go back one step. Steps that unmount lose their local state, so keep form values above the steps. A `ProgressSegmented` placed before the `ScrollView` stays fixed under the header.
|
|
439
|
+
|
|
440
|
+
```tsx
|
|
441
|
+
import { useState } from 'react';
|
|
442
|
+
import {
|
|
443
|
+
Box,
|
|
444
|
+
Button,
|
|
445
|
+
Field,
|
|
446
|
+
FullScreenDialog,
|
|
447
|
+
Input,
|
|
448
|
+
ListItem,
|
|
449
|
+
ProgressSegmented,
|
|
450
|
+
ScrollView,
|
|
451
|
+
Text,
|
|
452
|
+
} from '@cdx-ui/components';
|
|
453
|
+
|
|
454
|
+
const steps = ['Choose account', 'Enter amount', 'Review transfer'];
|
|
455
|
+
|
|
456
|
+
const accounts = [
|
|
457
|
+
{ id: 'checking', name: 'Everyday Checking •••• 4642', balance: '$2,418.07' },
|
|
458
|
+
{ id: 'savings', name: 'High-yield Savings •••• 5541', balance: '$16,163.04' },
|
|
459
|
+
{ id: 'money-market', name: 'Money Market •••• 2323', balance: '$55,847.23' },
|
|
460
|
+
];
|
|
461
|
+
|
|
462
|
+
export default function FullScreenDialogMultiStepDemo() {
|
|
463
|
+
const [open, setOpen] = useState(false);
|
|
464
|
+
const [step, setStep] = useState(0);
|
|
465
|
+
const [accountId, setAccountId] = useState<string | undefined>();
|
|
466
|
+
const [amount, setAmount] = useState('');
|
|
467
|
+
const account = accounts.find((item) => item.id === accountId);
|
|
468
|
+
|
|
469
|
+
const handleOpenChange = (next: boolean) => {
|
|
470
|
+
if (next) setStep(0);
|
|
471
|
+
setOpen(next);
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
return (
|
|
475
|
+
<FullScreenDialog isOpen={open} onOpenChange={handleOpenChange}>
|
|
476
|
+
<FullScreenDialog.Trigger asChild>
|
|
477
|
+
<Button>
|
|
478
|
+
<Button.Label>Start transfer</Button.Label>
|
|
479
|
+
</Button>
|
|
480
|
+
</FullScreenDialog.Trigger>
|
|
481
|
+
<FullScreenDialog.Popup>
|
|
482
|
+
<FullScreenDialog.Header
|
|
483
|
+
title={steps[step]}
|
|
484
|
+
subtitle={`Step ${step + 1} of ${steps.length}`}
|
|
485
|
+
onBack={step > 0 ? () => setStep((current) => current - 1) : undefined}
|
|
486
|
+
className="w-full max-w-md self-center"
|
|
487
|
+
/>
|
|
488
|
+
<FullScreenDialog.Content className="w-full max-w-md self-center">
|
|
489
|
+
<Box className="px-4 pt-2">
|
|
490
|
+
<ProgressSegmented
|
|
491
|
+
step={step + 1}
|
|
492
|
+
segments={steps.length}
|
|
493
|
+
accessibilityLabel="Transfer progress"
|
|
494
|
+
/>
|
|
495
|
+
</Box>
|
|
496
|
+
<ScrollView
|
|
497
|
+
className="flex-1"
|
|
498
|
+
contentContainerClassName="gap-4 p-4"
|
|
499
|
+
automaticallyAdjustKeyboardInsets
|
|
500
|
+
keyboardShouldPersistTaps="handled"
|
|
501
|
+
>
|
|
502
|
+
{step === 0 ? (
|
|
503
|
+
<Box>
|
|
504
|
+
{accounts.map((item, index) => (
|
|
505
|
+
<ListItem
|
|
506
|
+
key={item.id}
|
|
507
|
+
showSeparator={index < accounts.length - 1}
|
|
508
|
+
onPress={() => {
|
|
509
|
+
setAccountId(item.id);
|
|
510
|
+
setStep(1);
|
|
511
|
+
}}
|
|
512
|
+
>
|
|
513
|
+
<ListItem.Content>
|
|
514
|
+
<ListItem.Title>{item.name}</ListItem.Title>
|
|
515
|
+
<ListItem.Description>{`Available: ${item.balance}`}</ListItem.Description>
|
|
516
|
+
</ListItem.Content>
|
|
517
|
+
</ListItem>
|
|
518
|
+
))}
|
|
519
|
+
</Box>
|
|
520
|
+
) : null}
|
|
521
|
+
{step === 1 ? (
|
|
522
|
+
<>
|
|
523
|
+
<Field>
|
|
524
|
+
<Field.Label>Amount</Field.Label>
|
|
525
|
+
<Input variant="outline">
|
|
526
|
+
<Input.Field
|
|
527
|
+
placeholder="$0.00"
|
|
528
|
+
keyboardType="decimal-pad"
|
|
529
|
+
value={amount}
|
|
530
|
+
onChangeText={setAmount}
|
|
531
|
+
/>
|
|
532
|
+
</Input>
|
|
533
|
+
</Field>
|
|
534
|
+
<Button onPress={() => setStep(2)} isDisabled={amount === ''}>
|
|
535
|
+
<Button.Label>Continue</Button.Label>
|
|
536
|
+
</Button>
|
|
537
|
+
</>
|
|
538
|
+
) : null}
|
|
539
|
+
{step === 2 ? (
|
|
540
|
+
<>
|
|
541
|
+
<Box className="gap-1">
|
|
542
|
+
<Text color="secondary" size="sm">
|
|
543
|
+
From
|
|
544
|
+
</Text>
|
|
545
|
+
<Text>{account?.name ?? '—'}</Text>
|
|
546
|
+
</Box>
|
|
547
|
+
<Box className="gap-1">
|
|
548
|
+
<Text color="secondary" size="sm">
|
|
549
|
+
Amount
|
|
550
|
+
</Text>
|
|
551
|
+
<Text>{`$${amount}`}</Text>
|
|
552
|
+
</Box>
|
|
553
|
+
<Button onPress={() => setOpen(false)}>
|
|
554
|
+
<Button.Label>Submit transfer</Button.Label>
|
|
555
|
+
</Button>
|
|
556
|
+
</>
|
|
557
|
+
) : null}
|
|
558
|
+
</ScrollView>
|
|
559
|
+
</FullScreenDialog.Content>
|
|
560
|
+
</FullScreenDialog.Popup>
|
|
561
|
+
</FullScreenDialog>
|
|
562
|
+
);
|
|
563
|
+
}
|
|
564
|
+
```
|
|
565
|
+
|
|
566
|
+
## Discard confirmation
|
|
567
|
+
|
|
568
|
+
Control the dialog and intercept `onOpenChange(false)`, which fires for the close button, Escape, and Android back when the header has no `onBack`. When there are unsaved changes, open an `AlertDialog` instead of closing. Escape on the alert dialog is consumed by the alert dialog, so the full-screen dialog beneath stays open.
|
|
569
|
+
|
|
570
|
+
```tsx
|
|
571
|
+
import { useState } from 'react';
|
|
572
|
+
import {
|
|
573
|
+
AlertDialog,
|
|
574
|
+
Button,
|
|
575
|
+
Field,
|
|
576
|
+
FullScreenDialog,
|
|
577
|
+
Input,
|
|
578
|
+
ScrollView,
|
|
579
|
+
Text,
|
|
580
|
+
} from '@cdx-ui/components';
|
|
581
|
+
|
|
582
|
+
export default function FullScreenDialogDiscardConfirmationDemo() {
|
|
583
|
+
const [open, setOpen] = useState(false);
|
|
584
|
+
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
585
|
+
const [savedNickname, setSavedNickname] = useState('Everyday Checking');
|
|
586
|
+
const [nickname, setNickname] = useState(savedNickname);
|
|
587
|
+
const isDirty = nickname !== savedNickname;
|
|
588
|
+
|
|
589
|
+
const handleOpenChange = (next: boolean) => {
|
|
590
|
+
if (next) {
|
|
591
|
+
setNickname(savedNickname);
|
|
592
|
+
setOpen(true);
|
|
593
|
+
} else if (isDirty) {
|
|
594
|
+
setConfirmOpen(true);
|
|
595
|
+
} else {
|
|
596
|
+
setOpen(false);
|
|
597
|
+
}
|
|
598
|
+
};
|
|
599
|
+
|
|
600
|
+
return (
|
|
601
|
+
<>
|
|
602
|
+
<FullScreenDialog isOpen={open} onOpenChange={handleOpenChange}>
|
|
603
|
+
<FullScreenDialog.Trigger asChild>
|
|
604
|
+
<Button variant="outline">
|
|
605
|
+
<Button.Label>Rename account</Button.Label>
|
|
606
|
+
</Button>
|
|
607
|
+
</FullScreenDialog.Trigger>
|
|
608
|
+
<FullScreenDialog.Popup>
|
|
609
|
+
<FullScreenDialog.Header title="Rename account" className="w-full max-w-md self-center" />
|
|
610
|
+
<FullScreenDialog.Content className="w-full max-w-md self-center">
|
|
611
|
+
<ScrollView
|
|
612
|
+
className="flex-1"
|
|
613
|
+
contentContainerClassName="gap-4 p-4"
|
|
614
|
+
automaticallyAdjustKeyboardInsets
|
|
615
|
+
keyboardShouldPersistTaps="handled"
|
|
616
|
+
>
|
|
617
|
+
<Field>
|
|
618
|
+
<Field.Label>Account nickname</Field.Label>
|
|
619
|
+
<Input variant="outline">
|
|
620
|
+
<Input.Field value={nickname} onChangeText={setNickname} />
|
|
621
|
+
</Input>
|
|
622
|
+
</Field>
|
|
623
|
+
<Text color="secondary" size="sm">
|
|
624
|
+
{isDirty ? 'Unsaved changes' : 'No changes'}
|
|
625
|
+
</Text>
|
|
626
|
+
<Button
|
|
627
|
+
isDisabled={!isDirty}
|
|
628
|
+
onPress={() => {
|
|
629
|
+
setSavedNickname(nickname);
|
|
630
|
+
setOpen(false);
|
|
631
|
+
}}
|
|
632
|
+
>
|
|
633
|
+
<Button.Label>Save</Button.Label>
|
|
634
|
+
</Button>
|
|
635
|
+
</ScrollView>
|
|
636
|
+
</FullScreenDialog.Content>
|
|
637
|
+
</FullScreenDialog.Popup>
|
|
638
|
+
</FullScreenDialog>
|
|
639
|
+
|
|
640
|
+
<AlertDialog isOpen={confirmOpen} onOpenChange={setConfirmOpen}>
|
|
641
|
+
<AlertDialog.Popup>
|
|
642
|
+
<AlertDialog.Header>
|
|
643
|
+
<AlertDialog.Title severity="warning">Discard changes?</AlertDialog.Title>
|
|
644
|
+
</AlertDialog.Header>
|
|
645
|
+
<AlertDialog.Content>
|
|
646
|
+
<AlertDialog.Text>Your new account nickname won't be saved.</AlertDialog.Text>
|
|
647
|
+
</AlertDialog.Content>
|
|
648
|
+
<AlertDialog.Footer>
|
|
649
|
+
<AlertDialog.Cancel>Keep editing</AlertDialog.Cancel>
|
|
650
|
+
<AlertDialog.Action
|
|
651
|
+
color="danger"
|
|
652
|
+
onPress={() => {
|
|
653
|
+
setConfirmOpen(false);
|
|
654
|
+
setOpen(false);
|
|
655
|
+
}}
|
|
656
|
+
>
|
|
657
|
+
Discard
|
|
658
|
+
</AlertDialog.Action>
|
|
659
|
+
</AlertDialog.Footer>
|
|
660
|
+
</AlertDialog.Popup>
|
|
661
|
+
</AlertDialog>
|
|
662
|
+
</>
|
|
663
|
+
);
|
|
664
|
+
}
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
## With a bottom sheet
|
|
668
|
+
|
|
669
|
+
Declare the `BottomSheet.Modal` inside `FullScreenDialog.Popup`, which provides its own sheet host, so the sheet presents above the dialog. Android back and Escape close the sheet before the dialog.
|
|
670
|
+
|
|
671
|
+
```tsx
|
|
672
|
+
import { useState } from 'react';
|
|
673
|
+
import {
|
|
674
|
+
BottomSheet,
|
|
675
|
+
Box,
|
|
676
|
+
Button,
|
|
677
|
+
FullScreenDialog,
|
|
678
|
+
ListItem,
|
|
679
|
+
ScrollView,
|
|
680
|
+
Text,
|
|
681
|
+
useBottomSheet,
|
|
682
|
+
} from '@cdx-ui/components';
|
|
683
|
+
import { Check, ChevronRight } from '@cdx-ui/icons';
|
|
684
|
+
|
|
685
|
+
const accounts = [
|
|
686
|
+
{ id: 'checking', name: 'Everyday Checking •••• 4642', balance: '$2,418.07' },
|
|
687
|
+
{ id: 'savings', name: 'High-yield Savings •••• 5541', balance: '$16,163.04' },
|
|
688
|
+
{ id: 'money-market', name: 'Money Market •••• 2323', balance: '$55,847.23' },
|
|
689
|
+
];
|
|
690
|
+
|
|
691
|
+
export default function FullScreenDialogBottomSheetDemo() {
|
|
692
|
+
const [open, setOpen] = useState(false);
|
|
693
|
+
const [fromId, setFromId] = useState('checking');
|
|
694
|
+
const { ref, present, dismiss } = useBottomSheet();
|
|
695
|
+
const from = accounts.find((account) => account.id === fromId);
|
|
696
|
+
|
|
697
|
+
return (
|
|
698
|
+
<FullScreenDialog isOpen={open} onOpenChange={setOpen}>
|
|
699
|
+
<FullScreenDialog.Trigger asChild>
|
|
700
|
+
<Button>
|
|
701
|
+
<Button.Label>Edit transfer</Button.Label>
|
|
702
|
+
</Button>
|
|
703
|
+
</FullScreenDialog.Trigger>
|
|
704
|
+
<FullScreenDialog.Popup>
|
|
705
|
+
<FullScreenDialog.Header title="Edit transfer" className="w-full max-w-md self-center" />
|
|
706
|
+
<FullScreenDialog.Content className="w-full max-w-md self-center">
|
|
707
|
+
<ScrollView className="flex-1" contentContainerClassName="gap-4 p-4">
|
|
708
|
+
<Box>
|
|
709
|
+
<ListItem onPress={present} accessibilityHint="Opens a list of accounts">
|
|
710
|
+
<ListItem.Content>
|
|
711
|
+
<ListItem.Description>From</ListItem.Description>
|
|
712
|
+
<ListItem.Title>{from?.name ?? 'Choose an account'}</ListItem.Title>
|
|
713
|
+
</ListItem.Content>
|
|
714
|
+
<ListItem.TrailingSlot>
|
|
715
|
+
<ChevronRight size={20} />
|
|
716
|
+
</ListItem.TrailingSlot>
|
|
717
|
+
</ListItem>
|
|
718
|
+
<ListItem showSeparator={false}>
|
|
719
|
+
<ListItem.Content>
|
|
720
|
+
<ListItem.Description>To</ListItem.Description>
|
|
721
|
+
<ListItem.Title>Rent account •••• 8810</ListItem.Title>
|
|
722
|
+
</ListItem.Content>
|
|
723
|
+
</ListItem>
|
|
724
|
+
</Box>
|
|
725
|
+
<Text color="secondary" size="sm">
|
|
726
|
+
The account sheet is declared inside the popup, so it presents above the dialog.
|
|
727
|
+
</Text>
|
|
728
|
+
<Button onPress={() => setOpen(false)}>
|
|
729
|
+
<Button.Label>Save changes</Button.Label>
|
|
730
|
+
</Button>
|
|
731
|
+
</ScrollView>
|
|
732
|
+
</FullScreenDialog.Content>
|
|
733
|
+
|
|
734
|
+
<BottomSheet.Modal ref={ref}>
|
|
735
|
+
<BottomSheet.View>
|
|
736
|
+
<BottomSheet.Header title="Transfer from" onClose={dismiss} />
|
|
737
|
+
<BottomSheet.Content>
|
|
738
|
+
{accounts.map((account, index) => (
|
|
739
|
+
<ListItem
|
|
740
|
+
key={account.id}
|
|
741
|
+
showSeparator={index < accounts.length - 1}
|
|
742
|
+
accessibilityState={{ selected: account.id === fromId }}
|
|
743
|
+
onPress={() => {
|
|
744
|
+
setFromId(account.id);
|
|
745
|
+
dismiss();
|
|
746
|
+
}}
|
|
747
|
+
>
|
|
748
|
+
<ListItem.Content>
|
|
749
|
+
<ListItem.Title>{account.name}</ListItem.Title>
|
|
750
|
+
<ListItem.Description>{`Available: ${account.balance}`}</ListItem.Description>
|
|
751
|
+
</ListItem.Content>
|
|
752
|
+
{account.id === fromId ? (
|
|
753
|
+
<ListItem.TrailingSlot>
|
|
754
|
+
<Check size={20} />
|
|
755
|
+
</ListItem.TrailingSlot>
|
|
756
|
+
) : null}
|
|
757
|
+
</ListItem>
|
|
758
|
+
))}
|
|
759
|
+
</BottomSheet.Content>
|
|
760
|
+
</BottomSheet.View>
|
|
761
|
+
</BottomSheet.Modal>
|
|
762
|
+
</FullScreenDialog.Popup>
|
|
763
|
+
</FullScreenDialog>
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
## API
|
|
769
|
+
|
|
770
|
+
### FullScreenDialog
|
|
771
|
+
|
|
772
|
+
Controls open state and Escape dismissal. There is no backdrop to press, so `closeOnBackdropPress` is not available, and there is no `size`.
|
|
773
|
+
|
|
774
|
+
| Prop | Type | Default | Description |
|
|
775
|
+
| --- | --- | --- | --- |
|
|
776
|
+
| `className?` | `string` | — | Classes for the root wrapper around the trigger. |
|
|
777
|
+
| `children` | `ReactNode` | — | `FullScreenDialog.Trigger` and `FullScreenDialog.Popup`. |
|
|
778
|
+
| `onOpenChange?` | `((open: boolean) => void)` | — | Called with the next open state. Fires `false` for the header close button, Escape, and Android back while the header has no `onBack`. |
|
|
779
|
+
| `defaultOpen?` | `boolean` | `false` | Initial open state when uncontrolled. |
|
|
780
|
+
| `closeOnEscKey?` | `boolean` | `true` | Close when Escape is pressed. Web only. Escape never steps back; Android back is routed by the header's `onBack` independently of this prop. |
|
|
781
|
+
| `isOpen?` | `boolean` | — | Controlled open state. Use `defaultOpen` for the uncontrolled variant. |
|
|
782
|
+
| `animation?` | `'disable-all'` | — | Pass `'disable-all'` to turn off the popup's enter and exit motion. |
|
|
783
|
+
|
|
784
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props), except `children` and `role`.
|
|
785
|
+
|
|
786
|
+
## Sub-components
|
|
787
|
+
|
|
788
|
+
### FullScreenDialog.Trigger
|
|
789
|
+
|
|
790
|
+
Opens the dialog when pressed. Use `asChild` to merge trigger behavior onto a `Button` or another pressable element.
|
|
791
|
+
|
|
792
|
+
| Prop | Type | Default | Description |
|
|
793
|
+
| --- | --- | --- | --- |
|
|
794
|
+
| `className?` | `string` | — | Classes for the trigger. |
|
|
795
|
+
| `children?` | `ReactNode` | — | Content that opens the dialog when pressed. |
|
|
796
|
+
| `asChild?` | `boolean` | — | Render the single child as the trigger instead of a `Pressable`. |
|
|
797
|
+
|
|
798
|
+
Inherits all [`PressableProps`](https://reactnative.dev/docs/pressable#props).
|
|
799
|
+
|
|
800
|
+
### FullScreenDialog.Popup
|
|
801
|
+
|
|
802
|
+
The page surface. It covers the viewport with the primary surface color and has no backdrop, corner radius, swipe-to-dismiss, or keyboard-avoiding layer. Bottom sheets declared inside it present above it.
|
|
803
|
+
|
|
804
|
+
| Prop | Type | Default | Description |
|
|
805
|
+
| --- | --- | --- | --- |
|
|
806
|
+
| `className?` | `string` | — | Classes for the page surface, merged after the defaults. |
|
|
807
|
+
| `children?` | `ReactNode` | — | `FullScreenDialog.Header` and `FullScreenDialog.Content`. Bottom sheets declared here present above the page. |
|
|
808
|
+
|
|
809
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
810
|
+
|
|
811
|
+
| Attribute | Value | Description |
|
|
812
|
+
| ------------ | -------------------------------- | ---------------------------------------------- |
|
|
813
|
+
| `data-state` | `entering` \| `open` \| `closed` | Web only. Drives the enter and exit transition |
|
|
814
|
+
|
|
815
|
+
### FullScreenDialog.Header
|
|
816
|
+
|
|
817
|
+
Back / title / close row that clears the top safe-area inset. It takes the same props as [`BottomSheet.Header`](https://design.candescent.com/docs/components/bottom-sheet/content.md), except that the close button closes the dialog by default. The back button appears only while `onBack` is set. An unused back or close position keeps its space so the title stays centered, but it is not rendered as a button.
|
|
818
|
+
|
|
819
|
+
| Prop | Type | Default | Description |
|
|
820
|
+
| --- | --- | --- | --- |
|
|
821
|
+
| `title?` | `string` | — | Title text. Labels the dialog. Ignored when `children` is set. |
|
|
822
|
+
| `subtitle?` | `string` | — | Secondary line under the title. Has no effect without `title`, or when `children` is set. |
|
|
823
|
+
| `children?` | `ReactNode` | — | Custom header content. Replaces `title` and `subtitle`. The consumer then owns the dialog's accessible name and focus on step change: focus doesn't move to the header. |
|
|
824
|
+
| `className?` | `string` | — | Classes for the header region, which includes the top safe-area padding. |
|
|
825
|
+
| `onClose?` | `(() => void)` | `Closes the dialog (`onOpenChange(false)`).` | Called by the close button. |
|
|
826
|
+
| `closeAccessibilityLabel?` | `string` | `Close` | Accessible name for the close button. |
|
|
827
|
+
| `onBack?` | `(() => void)` | — | Shows the back button when set. Android system back calls it too, instead of closing the dialog. Escape on web always closes. |
|
|
828
|
+
| `backAccessibilityLabel?` | `string` | `Go back` | Accessible name for the back button. |
|
|
829
|
+
|
|
830
|
+
### FullScreenDialog.Content
|
|
831
|
+
|
|
832
|
+
Flex region under the header that clears the bottom safe-area inset. It does not scroll by itself; put a `ScrollView` inside it.
|
|
833
|
+
|
|
834
|
+
| Prop | Type | Default | Description |
|
|
835
|
+
| --- | --- | --- | --- |
|
|
836
|
+
| `className?` | `string` | — | Classes for the content region, merged after the defaults. |
|
|
837
|
+
| `children?` | `ReactNode` | — | Page body. Usually a `ScrollView`. |
|
|
838
|
+
| `asChild?` | `boolean` | — | Render the single child as the content region instead of a `View`. |
|
|
839
|
+
|
|
840
|
+
Inherits all [`ViewProps`](https://reactnative.dev/docs/view#props).
|
|
841
|
+
|
|
842
|
+
## Anatomy
|
|
843
|
+
|
|
844
|
+
| `data-slot` | Element |
|
|
845
|
+
| ---------------------------- | -------------------------------------------------- |
|
|
846
|
+
| `full-screen-dialog` | Root wrapper around the trigger |
|
|
847
|
+
| `full-screen-dialog-trigger` | Trigger |
|
|
848
|
+
| `full-screen-dialog-popup` | Page surface with `role="dialog"` |
|
|
849
|
+
| `full-screen-dialog-header` | Header region, including the top safe-area padding |
|
|
850
|
+
| `full-screen-dialog-content` | Body region under the header |
|
|
851
|
+
|
|
852
|
+
## Accessibility
|
|
853
|
+
|
|
854
|
+
- The popup receives `role="dialog"`, `aria-modal`, and `aria-labelledby` pointing at the header title.
|
|
855
|
+
- Focus moves into the popup, remains trapped while open, and returns to the trigger after close.
|
|
856
|
+
- When the header `title` changes, or `onBack` switches between set and unset, focus moves to the header title on web and screen-reader focus moves there on native, so the new step is announced. This does not happen when the dialog first opens.
|
|
857
|
+
- When you pass custom `children` to `FullScreenDialog.Header`, the title is not rendered, so you own the dialog's accessible name and moving focus on a step change. Set `aria-label` on `FullScreenDialog.Popup` to name the dialog.
|
|
858
|
+
- Android system back calls the header's `onBack` while it is set, and the dialog stays open. Without `onBack`, it closes the dialog.
|
|
859
|
+
- Escape closes the dialog on web when `closeOnEscKey` is enabled. It never steps back, even while `onBack` is set.
|
|
860
|
+
- Android back and Escape go to the topmost overlay first. A presented bottom sheet, or a dialog or select opened from the full-screen dialog, handles them before the full-screen dialog does.
|
|
861
|
+
- The back and close buttons default to the accessible names "Go back" and "Close".
|
|
862
|
+
|
|
863
|
+
## Constraints
|
|
864
|
+
|
|
865
|
+
- A shared `PortalHost` must be mounted once near the app root. `ForgeDesignProvider` includes one.
|
|
866
|
+
- Declare every `BottomSheet.Modal` you open from the dialog inside `FullScreenDialog.Popup`. The popup provides its own sheet host. A sheet declared outside the popup, for example as a sibling of `FullScreenDialog`, presents through the root host and stays beneath the dialog.
|
|
867
|
+
- Sheets opened from the dialog need a `GestureHandlerRootView` at the app root, wrapping `ForgeDesignProvider`. This is the same requirement as any other `BottomSheet`.
|
|
868
|
+
- Launching a full-screen dialog from a React Navigation native modal screen (`modal`, `formSheet`, `fullScreenModal`) is not supported in this version. On iOS the dialog renders underneath the presenting screen.
|
|
869
|
+
- There is no built-in keyboard avoidance. Make a `ScrollView` inside `FullScreenDialog.Content` the scroll container, and set `automaticallyAdjustKeyboardInsets` and `keyboardShouldPersistTaps="handled"` on it, as the multi-step and discard demos do. `automaticallyAdjustKeyboardInsets` applies on iOS. On Android, confirm the behavior on a device; it varies with edge-to-edge configuration. Do not wrap the dialog in a `KeyboardAvoidingView`.
|
|
870
|
+
- The dialog holds no step state and adds no browser history entry. It is a modal, not a navigator screen, so it does not get the iOS edge-swipe back gesture.
|
|
871
|
+
- Pass `animation="disable-all"` on `FullScreenDialog` to turn off the enter and exit motion. Reduced-motion settings are respected on every platform.
|
|
872
|
+
|
|
873
|
+
## When to use
|
|
874
|
+
|
|
875
|
+
| Component | Use for |
|
|
876
|
+
| ------------------ | ----------------------------------------------------------------------------------------------------------------------------- |
|
|
877
|
+
| `FullScreenDialog` | A task that needs the whole screen, such as editing a transfer or a multi-step setup, and returns to the same place when done |
|
|
878
|
+
| `Dialog` | A short confirmation or a small form on a centered card |
|
|
879
|
+
| `Drawer` | Filters, settings, or navigation on a panel attached to an edge of the viewport |
|
|
880
|
+
| `BottomSheet` | A secondary task at partial height that keeps the page behind it in view |
|
|
881
|
+
| A navigator screen | A page that needs its own URL or deep link, or a place in the navigation history |
|