@duro-app/ui 5.11.0 → 5.13.0
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/dist/Table-Bms2ftt3.js +1694 -0
- package/dist/Table-Bms2ftt3.js.map +1 -0
- package/dist/compiler-runtime-BuugS4D0.js.map +1 -1
- package/dist/components/Alert/Alert.d.ts.map +1 -1
- package/dist/components/AppShell/native.css.d.ts +53 -0
- package/dist/components/AppShell/native.css.d.ts.map +1 -0
- package/dist/components/Button/Button.d.ts +2 -1
- package/dist/components/Button/Button.d.ts.map +1 -1
- package/dist/components/Button/styles.css.d.ts +1 -0
- package/dist/components/Button/styles.css.d.ts.map +1 -1
- package/dist/components/Callout/Callout.d.ts.map +1 -1
- package/dist/components/Callout/styles.css.d.ts +3 -0
- package/dist/components/Callout/styles.css.d.ts.map +1 -1
- package/dist/components/Checkbox/Checkbox.d.ts.map +1 -1
- package/dist/components/ConfirmDialog/ConfirmDialog.d.ts.map +1 -1
- package/dist/components/DetailPanel/DetailPanel.d.ts.map +1 -1
- package/dist/components/Dialog/Dialog.d.ts +2 -17
- package/dist/components/Dialog/Dialog.d.ts.map +1 -1
- package/dist/components/Dialog/Dialog.stories.d.ts +4 -0
- package/dist/components/Dialog/Dialog.stories.d.ts.map +1 -1
- package/dist/components/Dialog/native.css.d.ts +82 -0
- package/dist/components/Dialog/native.css.d.ts.map +1 -0
- package/dist/components/Dialog/parts.css.d.ts +82 -0
- package/dist/components/Dialog/parts.css.d.ts.map +1 -0
- package/dist/components/Dialog/parts.d.ts +35 -0
- package/dist/components/Dialog/parts.d.ts.map +1 -0
- package/dist/components/Dialog/styles.css.d.ts +1 -74
- package/dist/components/Dialog/styles.css.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.d.ts +7 -35
- package/dist/components/Drawer/Drawer.d.ts.map +1 -1
- package/dist/components/Drawer/Drawer.meta.d.ts.map +1 -1
- package/dist/components/Drawer/DrawerScroll.stories.d.ts.map +1 -1
- package/dist/components/Drawer/DrawerSnap.stories.d.ts +20 -0
- package/dist/components/Drawer/DrawerSnap.stories.d.ts.map +1 -0
- package/dist/components/Drawer/native.css.d.ts +55 -0
- package/dist/components/Drawer/native.css.d.ts.map +1 -0
- package/dist/components/Drawer/parts.css.d.ts +96 -0
- package/dist/components/Drawer/parts.css.d.ts.map +1 -0
- package/dist/components/Drawer/parts.d.ts +56 -0
- package/dist/components/Drawer/parts.d.ts.map +1 -0
- package/dist/components/Drawer/sheetPhysics.d.ts +56 -0
- package/dist/components/Drawer/sheetPhysics.d.ts.map +1 -0
- package/dist/components/Drawer/styles.css.d.ts +15 -58
- package/dist/components/Drawer/styles.css.d.ts.map +1 -1
- package/dist/components/Drawer/touchInput.d.ts +35 -0
- package/dist/components/Drawer/touchInput.d.ts.map +1 -0
- package/dist/components/Drawer/useDrawerRoot.d.ts +33 -0
- package/dist/components/Drawer/useDrawerRoot.d.ts.map +1 -0
- package/dist/components/Drawer/useSheetHeights.d.ts +7 -0
- package/dist/components/Drawer/useSheetHeights.d.ts.map +1 -0
- package/dist/components/Drawer/useSwipeDismiss.d.ts +13 -2
- package/dist/components/Drawer/useSwipeDismiss.d.ts.map +1 -1
- package/dist/components/Grid/styles.css.d.ts +1 -0
- package/dist/components/Grid/styles.css.d.ts.map +1 -1
- package/dist/components/Icon/Icon.d.ts +3 -9
- package/dist/components/Icon/Icon.d.ts.map +1 -1
- package/dist/components/Icon/geometry.d.ts +60 -0
- package/dist/components/Icon/geometry.d.ts.map +1 -0
- package/dist/components/Icon/types.d.ts +15 -0
- package/dist/components/Icon/types.d.ts.map +1 -0
- package/dist/components/Input/Input.d.ts +5 -1
- package/dist/components/Input/Input.d.ts.map +1 -1
- package/dist/components/Input/styles.css.d.ts +1 -0
- package/dist/components/Input/styles.css.d.ts.map +1 -1
- package/dist/components/LinkButton/styles.css.d.ts +1 -0
- package/dist/components/LinkButton/styles.css.d.ts.map +1 -1
- package/dist/components/Menu/Menu.d.ts +7 -1
- package/dist/components/Menu/Menu.d.ts.map +1 -1
- package/dist/components/Menu/native.css.d.ts +14 -0
- package/dist/components/Menu/native.css.d.ts.map +1 -0
- package/dist/components/Menu/useMenuOpen.d.ts +16 -0
- package/dist/components/Menu/useMenuOpen.d.ts.map +1 -0
- package/dist/components/Menu/useMenuRoot.d.ts +3 -6
- package/dist/components/Menu/useMenuRoot.d.ts.map +1 -1
- package/dist/components/Meter/styles.css.d.ts +1 -0
- package/dist/components/Meter/styles.css.d.ts.map +1 -1
- package/dist/components/PageShell/styles.css.d.ts +2 -0
- package/dist/components/PageShell/styles.css.d.ts.map +1 -1
- package/dist/components/Popover/native.css.d.ts +11 -0
- package/dist/components/Popover/native.css.d.ts.map +1 -0
- package/dist/components/RadioGroup/RadioGroup.d.ts +1 -17
- package/dist/components/RadioGroup/RadioGroup.d.ts.map +1 -1
- package/dist/components/RadioGroup/RadioGroup.stories.d.ts +3 -0
- package/dist/components/RadioGroup/RadioGroup.stories.d.ts.map +1 -1
- package/dist/components/RadioGroup/group.d.ts +31 -0
- package/dist/components/RadioGroup/group.d.ts.map +1 -0
- package/dist/components/RadioGroup/styles.css.d.ts +10 -0
- package/dist/components/RadioGroup/styles.css.d.ts.map +1 -1
- package/dist/components/ScrollArea/styles.css.d.ts +1 -0
- package/dist/components/ScrollArea/styles.css.d.ts.map +1 -1
- package/dist/components/SideNav/Chevron.d.ts +4 -0
- package/dist/components/SideNav/Chevron.d.ts.map +1 -0
- package/dist/components/SideNav/SideNav.d.ts.map +1 -1
- package/dist/components/SideNav/styles.css.d.ts +6 -0
- package/dist/components/SideNav/styles.css.d.ts.map +1 -1
- package/dist/components/SideNav/types.d.ts +6 -0
- package/dist/components/SideNav/types.d.ts.map +1 -0
- package/dist/components/Spinner/Spinner.d.ts +2 -6
- package/dist/components/Spinner/Spinner.d.ts.map +1 -1
- package/dist/components/Spinner/Spinner.types.d.ts +6 -0
- package/dist/components/Spinner/Spinner.types.d.ts.map +1 -0
- package/dist/components/Spinner/ring.css.d.ts +39 -0
- package/dist/components/Spinner/ring.css.d.ts.map +1 -0
- package/dist/components/Spinner/styles.css.d.ts +1 -28
- package/dist/components/Spinner/styles.css.d.ts.map +1 -1
- package/dist/components/SplitPane/SplitPane.d.ts +38 -0
- package/dist/components/SplitPane/SplitPane.d.ts.map +1 -0
- package/dist/components/SplitPane/SplitPane.meta.d.ts +3 -0
- package/dist/components/SplitPane/SplitPane.meta.d.ts.map +1 -0
- package/dist/components/SplitPane/SplitPane.stories.d.ts +17 -0
- package/dist/components/SplitPane/SplitPane.stories.d.ts.map +1 -0
- package/dist/components/SplitPane/styles.css.d.ts +78 -0
- package/dist/components/SplitPane/styles.css.d.ts.map +1 -0
- package/dist/components/StatusIcon/StatusIcon.d.ts.map +1 -1
- package/dist/components/StatusIcon/styles.css.d.ts +3 -0
- package/dist/components/StatusIcon/styles.css.d.ts.map +1 -1
- package/dist/components/Switch/Switch.d.ts +2 -18
- package/dist/components/Switch/Switch.d.ts.map +1 -1
- package/dist/components/Switch/Switch.types.d.ts +18 -0
- package/dist/components/Switch/Switch.types.d.ts.map +1 -0
- package/dist/components/TableOfContents/styles.css.d.ts +1 -0
- package/dist/components/TableOfContents/styles.css.d.ts.map +1 -1
- package/dist/components/Tabs/TabLayout.d.ts +7 -0
- package/dist/components/Tabs/TabLayout.d.ts.map +1 -0
- package/dist/components/Tabs/Tabs.d.ts.map +1 -1
- package/dist/components/Tabs/indicator.d.ts +28 -0
- package/dist/components/Tabs/indicator.d.ts.map +1 -0
- package/dist/components/Tabs/styles.css.d.ts +4 -0
- package/dist/components/Tabs/styles.css.d.ts.map +1 -1
- package/dist/components/Tabs/useTabIndicator.d.ts +4 -0
- package/dist/components/Tabs/useTabIndicator.d.ts.map +1 -0
- package/dist/components/Tabs/useTabKeys.d.ts +13 -0
- package/dist/components/Tabs/useTabKeys.d.ts.map +1 -0
- package/dist/components/Tag/RemoveGlyph.d.ts +4 -0
- package/dist/components/Tag/RemoveGlyph.d.ts.map +1 -0
- package/dist/components/Tag/Tag.d.ts +2 -24
- package/dist/components/Tag/Tag.d.ts.map +1 -1
- package/dist/components/Tag/styles.css.d.ts +8 -0
- package/dist/components/Tag/styles.css.d.ts.map +1 -1
- package/dist/components/Tag/types.d.ts +39 -0
- package/dist/components/Tag/types.d.ts.map +1 -0
- package/dist/components/Textarea/styles.css.d.ts +1 -0
- package/dist/components/Textarea/styles.css.d.ts.map +1 -1
- package/dist/components/Toast/ToastProvider.d.ts +2 -21
- package/dist/components/Toast/ToastProvider.d.ts.map +1 -1
- package/dist/components/Toast/native.css.d.ts +81 -0
- package/dist/components/Toast/native.css.d.ts.map +1 -0
- package/dist/components/Toast/store.d.ts +47 -0
- package/dist/components/Toast/store.d.ts.map +1 -0
- package/dist/components/Toggle/Toggle.d.ts.map +1 -1
- package/dist/components/Toggle/styles.css.d.ts +11 -2
- package/dist/components/Toggle/styles.css.d.ts.map +1 -1
- package/dist/components/Tooltip/TooltipHint.d.ts +9 -0
- package/dist/components/Tooltip/TooltipHint.d.ts.map +1 -0
- package/dist/components/Tree/Tree.d.ts.map +1 -1
- package/dist/components/Tree/styles.css.d.ts +6 -0
- package/dist/components/Tree/styles.css.d.ts.map +1 -1
- package/dist/components/Tree/useTreeKeyboard.d.ts +19 -0
- package/dist/components/Tree/useTreeKeyboard.d.ts.map +1 -0
- package/dist/components/VirtualList/VirtualList.d.ts +33 -0
- package/dist/components/VirtualList/VirtualList.d.ts.map +1 -0
- package/dist/components/VirtualList/VirtualList.meta.d.ts +3 -0
- package/dist/components/VirtualList/VirtualList.meta.d.ts.map +1 -0
- package/dist/components/VirtualList/VirtualList.stories.d.ts +15 -0
- package/dist/components/VirtualList/VirtualList.stories.d.ts.map +1 -0
- package/dist/components/VirtualList/styles.css.d.ts +28 -0
- package/dist/components/VirtualList/styles.css.d.ts.map +1 -0
- package/dist/components/VirtualTable/styles.css.d.ts +6 -0
- package/dist/components/VirtualTable/styles.css.d.ts.map +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6202 -4794
- package/dist/index.js.map +1 -1
- package/dist/shared/ButtonHost.d.ts +11 -0
- package/dist/shared/ButtonHost.d.ts.map +1 -0
- package/dist/shared/portal/hostRegistry.d.ts +33 -0
- package/dist/shared/portal/hostRegistry.d.ts.map +1 -0
- package/dist/shared/pressableChild.d.ts +14 -0
- package/dist/shared/pressableChild.d.ts.map +1 -0
- package/dist/shared/useOverlayOpenState.d.ts +40 -0
- package/dist/shared/useOverlayOpenState.d.ts.map +1 -0
- package/dist/table.js +141 -135
- package/dist/table.js.map +1 -1
- package/package.json +34 -4
- package/src/components/Alert/Alert.tsx +14 -2
- package/src/components/AppShell/AppShell.meta.ts +1 -1
- package/src/components/AppShell/AppShell.native.tsx +174 -0
- package/src/components/AppShell/native.css.ts +56 -0
- package/src/components/Button/Button.tsx +6 -5
- package/src/components/Button/styles.css.ts +2 -0
- package/src/components/Callout/Callout.tsx +17 -3
- package/src/components/Callout/styles.css.ts +5 -0
- package/src/components/Checkbox/Checkbox.native.tsx +67 -0
- package/src/components/Checkbox/Checkbox.tsx +1 -50
- package/src/components/ConfirmDialog/ConfirmDialog.tsx +3 -0
- package/src/components/DetailPanel/DetailPanel.tsx +9 -45
- package/src/components/Dialog/Dialog.native.tsx +296 -0
- package/src/components/Dialog/Dialog.stories.tsx +71 -0
- package/src/components/Dialog/Dialog.tsx +41 -130
- package/src/components/Dialog/native.css.ts +78 -0
- package/src/components/Dialog/parts.css.ts +101 -0
- package/src/components/Dialog/parts.tsx +61 -0
- package/src/components/Dialog/styles.css.ts +2 -89
- package/src/components/Drawer/Drawer.meta.ts +2 -1
- package/src/components/Drawer/Drawer.native.tsx +469 -0
- package/src/components/Drawer/Drawer.tsx +63 -179
- package/src/components/Drawer/DrawerScroll.stories.tsx +4 -54
- package/src/components/Drawer/DrawerSnap.stories.tsx +205 -0
- package/src/components/Drawer/native.css.ts +58 -0
- package/src/components/Drawer/parts.css.ts +125 -0
- package/src/components/Drawer/parts.tsx +110 -0
- package/src/components/Drawer/sheetPhysics.ts +103 -0
- package/src/components/Drawer/styles.css.ts +19 -74
- package/src/components/Drawer/touchInput.ts +81 -0
- package/src/components/Drawer/useDrawerRoot.ts +90 -0
- package/src/components/Drawer/useSheetHeights.ts +42 -0
- package/src/components/Drawer/useSwipeDismiss.ts +146 -23
- package/src/components/Grid/styles.css.ts +2 -0
- package/src/components/Icon/Icon.native.tsx +54 -0
- package/src/components/Icon/Icon.tsx +19 -430
- package/src/components/Icon/geometry.ts +456 -0
- package/src/components/Icon/types.ts +74 -0
- package/src/components/Input/Input.tsx +8 -0
- package/src/components/Input/styles.css.ts +2 -0
- package/src/components/LinkButton/styles.css.ts +2 -0
- package/src/components/Menu/Menu.meta.ts +1 -1
- package/src/components/Menu/Menu.native.tsx +268 -0
- package/src/components/Menu/Menu.tsx +11 -2
- package/src/components/Menu/native.css.ts +18 -0
- package/src/components/Menu/useMenuOpen.ts +33 -0
- package/src/components/Menu/useMenuRoot.ts +7 -26
- package/src/components/Meter/styles.css.ts +2 -0
- package/src/components/PageShell/styles.css.ts +4 -0
- package/src/components/Popover/Popover.meta.ts +1 -1
- package/src/components/Popover/Popover.native.tsx +205 -0
- package/src/components/Popover/native.css.ts +13 -0
- package/src/components/RadioGroup/RadioGroup.meta.ts +1 -1
- package/src/components/RadioGroup/RadioGroup.native.tsx +48 -0
- package/src/components/RadioGroup/RadioGroup.stories.tsx +64 -1
- package/src/components/RadioGroup/RadioGroup.tsx +8 -83
- package/src/components/RadioGroup/group.tsx +85 -0
- package/src/components/RadioGroup/styles.css.ts +13 -0
- package/src/components/ScrollArea/styles.css.ts +2 -0
- package/src/components/SideNav/Chevron.native.tsx +20 -0
- package/src/components/SideNav/Chevron.tsx +20 -0
- package/src/components/SideNav/SideNav.meta.ts +1 -1
- package/src/components/SideNav/SideNav.tsx +57 -41
- package/src/components/SideNav/styles.css.ts +8 -0
- package/src/components/SideNav/types.ts +6 -0
- package/src/components/Spinner/Spinner.native.tsx +37 -0
- package/src/components/Spinner/Spinner.tsx +6 -15
- package/src/components/Spinner/Spinner.types.ts +6 -0
- package/src/components/Spinner/ring.css.ts +45 -0
- package/src/components/Spinner/styles.css.ts +2 -32
- package/src/components/SplitPane/SplitPane.meta.ts +40 -0
- package/src/components/SplitPane/SplitPane.native.tsx +47 -0
- package/src/components/SplitPane/SplitPane.stories.tsx +148 -0
- package/src/components/SplitPane/SplitPane.tsx +218 -0
- package/src/components/SplitPane/styles.css.ts +81 -0
- package/src/components/StatusIcon/StatusIcon.tsx +13 -2
- package/src/components/StatusIcon/styles.css.ts +5 -0
- package/src/components/Switch/Switch.native.tsx +45 -0
- package/src/components/Switch/Switch.tsx +22 -44
- package/src/components/Switch/Switch.types.ts +18 -0
- package/src/components/TableOfContents/styles.css.ts +2 -0
- package/src/components/Tabs/TabLayout.native.tsx +9 -0
- package/src/components/Tabs/TabLayout.tsx +6 -0
- package/src/components/Tabs/Tabs.meta.ts +1 -1
- package/src/components/Tabs/Tabs.tsx +38 -136
- package/src/components/Tabs/indicator.ts +36 -0
- package/src/components/Tabs/styles.css.ts +7 -0
- package/src/components/Tabs/useTabIndicator.native.ts +35 -0
- package/src/components/Tabs/useTabIndicator.ts +49 -0
- package/src/components/Tabs/useTabKeys.native.ts +2 -0
- package/src/components/Tabs/useTabKeys.ts +99 -0
- package/src/components/Tag/RemoveGlyph.native.tsx +17 -0
- package/src/components/Tag/RemoveGlyph.tsx +10 -0
- package/src/components/Tag/Tag.meta.ts +1 -1
- package/src/components/Tag/Tag.native.tsx +70 -0
- package/src/components/Tag/Tag.tsx +9 -37
- package/src/components/Tag/styles.css.ts +9 -0
- package/src/components/Tag/types.ts +43 -0
- package/src/components/Textarea/styles.css.ts +2 -0
- package/src/components/ThemeProvider/ThemeProvider.native.tsx +70 -10
- package/src/components/Toast/Toast.meta.ts +1 -1
- package/src/components/Toast/ToastProvider.native.tsx +226 -0
- package/src/components/Toast/ToastProvider.tsx +22 -84
- package/src/components/Toast/native.css.ts +78 -0
- package/src/components/Toast/store.ts +96 -0
- package/src/components/Toggle/Toggle.tsx +5 -3
- package/src/components/Toggle/styles.css.ts +14 -2
- package/src/components/Tooltip/Tooltip.meta.ts +1 -1
- package/src/components/Tooltip/Tooltip.native.tsx +36 -0
- package/src/components/Tooltip/TooltipHint.ts +13 -0
- package/src/components/Tree/Tree.meta.ts +1 -1
- package/src/components/Tree/Tree.tsx +23 -135
- package/src/components/Tree/styles.css.ts +6 -0
- package/src/components/Tree/useTreeKeyboard.native.ts +5 -0
- package/src/components/Tree/useTreeKeyboard.ts +152 -0
- package/src/components/VirtualList/VirtualList.meta.ts +39 -0
- package/src/components/VirtualList/VirtualList.stories.tsx +95 -0
- package/src/components/VirtualList/VirtualList.tsx +103 -0
- package/src/components/VirtualList/styles.css.ts +31 -0
- package/src/components/VirtualTable/styles.css.ts +12 -0
- package/src/hooks/useContainerBelow.native.ts +30 -0
- package/src/index.native.ts +61 -1
- package/src/index.ts +8 -1
- package/src/native-guard/globals.d.ts +10 -0
- package/src/native-guard/react-dom.d.ts +3 -0
- package/src/shared/ButtonHost.native.tsx +70 -0
- package/src/shared/ButtonHost.tsx +12 -0
- package/src/shared/accessibilityFocus.native.ts +23 -0
- package/src/shared/portal/AnchoredOverlay.native.tsx +117 -0
- package/src/shared/portal/OverlayModal.native.tsx +51 -0
- package/src/shared/portal/PortalHost.native.tsx +102 -0
- package/src/shared/portal/hostRegistry.ts +76 -0
- package/src/shared/portal/themeScope.native.ts +18 -0
- package/src/shared/pressableChild.ts +33 -0
- package/src/shared/safeArea.native.ts +22 -0
- package/src/shared/useKeyboardHeight.native.ts +18 -0
- package/src/shared/useOverlayOpenState.ts +128 -0
- package/src/shared/useScreenReaderEnabled.native.ts +19 -0
- package/dist/Table-ColfpgKV.js +0 -1552
- package/dist/Table-ColfpgKV.js.map +0 -1
- package/dist/components/ThemeProvider/ThemeProvider.native.d.ts +0 -10
- package/dist/components/ThemeProvider/ThemeProvider.native.d.ts.map +0 -1
- package/dist/index.native.d.ts +0 -33
- package/dist/index.native.d.ts.map +0 -1
- package/dist/platform.native.d.ts +0 -2
- package/dist/platform.native.d.ts.map +0 -1
|
@@ -1,10 +1,8 @@
|
|
|
1
1
|
import {css} from 'react-strict-dom'
|
|
2
2
|
import {colors} from '@duro-app/tokens/tokens/colors.css'
|
|
3
3
|
import {spacing, radii} from '@duro-app/tokens/tokens/spacing.css'
|
|
4
|
-
import {typography} from '@duro-app/tokens/tokens/typography.css'
|
|
5
4
|
import {shadows} from '@duro-app/tokens/tokens/shadows.css'
|
|
6
5
|
import {duration, easing} from '@duro-app/tokens/tokens/motion.css'
|
|
7
|
-
import {sizes} from '@duro-app/tokens/tokens/sizes.css'
|
|
8
6
|
import {borders} from '@duro-app/tokens/tokens/borders.css'
|
|
9
7
|
import {layers} from '@duro-app/tokens/tokens/layers.css'
|
|
10
8
|
|
|
@@ -60,6 +58,8 @@ export const styles = css.create({
|
|
|
60
58
|
borderRadius: radii.lg,
|
|
61
59
|
boxShadow: shadows.lg,
|
|
62
60
|
width: '100%',
|
|
61
|
+
// Native has no border-box reset (the web's global-reset.css); declare it.
|
|
62
|
+
boxSizing: 'border-box',
|
|
63
63
|
maxHeight: '85vh',
|
|
64
64
|
display: 'flex',
|
|
65
65
|
flexDirection: 'column',
|
|
@@ -115,93 +115,6 @@ export const styles = css.create({
|
|
|
115
115
|
closeDurationBase: {animationDuration: duration.base},
|
|
116
116
|
closeDurationSlow: {animationDuration: duration.slow},
|
|
117
117
|
|
|
118
|
-
// --- Sizes ---
|
|
119
|
-
sm: {maxWidth: sizes.dialogSm},
|
|
120
|
-
md: {maxWidth: sizes.dialogMd},
|
|
121
|
-
lg: {maxWidth: sizes.dialogLg},
|
|
122
|
-
|
|
123
|
-
// --- Header ---
|
|
124
|
-
header: {
|
|
125
|
-
display: 'flex',
|
|
126
|
-
alignItems: 'flex-start',
|
|
127
|
-
justifyContent: 'space-between',
|
|
128
|
-
paddingTop: spacing.lg,
|
|
129
|
-
paddingLeft: spacing.lg,
|
|
130
|
-
paddingRight: spacing.lg,
|
|
131
|
-
paddingBottom: spacing.md,
|
|
132
|
-
gap: spacing.md,
|
|
133
|
-
},
|
|
134
|
-
|
|
135
|
-
// --- Title ---
|
|
136
|
-
title: {
|
|
137
|
-
fontSize: typography.fontSizeLg,
|
|
138
|
-
fontWeight: typography.fontWeightSemibold,
|
|
139
|
-
lineHeight: typography.lineHeight,
|
|
140
|
-
color: colors.text,
|
|
141
|
-
margin: 0,
|
|
142
|
-
},
|
|
143
|
-
|
|
144
|
-
// --- Description ---
|
|
145
|
-
description: {
|
|
146
|
-
fontSize: typography.fontSizeSm,
|
|
147
|
-
lineHeight: typography.lineHeight,
|
|
148
|
-
color: colors.textMuted,
|
|
149
|
-
margin: 0,
|
|
150
|
-
paddingLeft: spacing.lg,
|
|
151
|
-
paddingRight: spacing.lg,
|
|
152
|
-
paddingBottom: spacing.md,
|
|
153
|
-
},
|
|
154
|
-
|
|
155
|
-
// --- Body ---
|
|
156
|
-
body: {
|
|
157
|
-
paddingLeft: spacing.lg,
|
|
158
|
-
paddingRight: spacing.lg,
|
|
159
|
-
paddingBottom: spacing.lg,
|
|
160
|
-
overflowY: 'auto',
|
|
161
|
-
flex: 1,
|
|
162
|
-
},
|
|
163
|
-
|
|
164
|
-
// --- Footer ---
|
|
165
|
-
footer: {
|
|
166
|
-
display: 'flex',
|
|
167
|
-
alignItems: 'center',
|
|
168
|
-
justifyContent: 'flex-end',
|
|
169
|
-
gap: spacing.sm,
|
|
170
|
-
paddingTop: spacing.md,
|
|
171
|
-
paddingLeft: spacing.lg,
|
|
172
|
-
paddingRight: spacing.lg,
|
|
173
|
-
paddingBottom: spacing.lg,
|
|
174
|
-
borderTopWidth: borders.hairline,
|
|
175
|
-
borderTopStyle: 'solid',
|
|
176
|
-
borderTopColor: colors.border,
|
|
177
|
-
},
|
|
178
|
-
|
|
179
|
-
// --- Close button ---
|
|
180
|
-
closeButton: {
|
|
181
|
-
display: 'flex',
|
|
182
|
-
alignItems: 'center',
|
|
183
|
-
justifyContent: 'center',
|
|
184
|
-
width: sizes.iconButton,
|
|
185
|
-
height: sizes.iconButton,
|
|
186
|
-
borderRadius: radii.sm,
|
|
187
|
-
borderWidth: 0,
|
|
188
|
-
backgroundColor: {
|
|
189
|
-
default: 'transparent',
|
|
190
|
-
':hover': colors.bgCardHover,
|
|
191
|
-
},
|
|
192
|
-
color: colors.textMuted,
|
|
193
|
-
cursor: 'pointer',
|
|
194
|
-
padding: 0,
|
|
195
|
-
flexShrink: 0,
|
|
196
|
-
transitionProperty: 'background-color',
|
|
197
|
-
transitionDuration: duration.fast,
|
|
198
|
-
},
|
|
199
|
-
|
|
200
|
-
// --- Inline wrapper (for Trigger / Close children) ---
|
|
201
|
-
inlineWrapper: {
|
|
202
|
-
display: 'inline-flex',
|
|
203
|
-
},
|
|
204
|
-
|
|
205
118
|
// --- Reduced motion ---
|
|
206
119
|
reducedMotion: {
|
|
207
120
|
animationDuration: duration.minimal,
|
|
@@ -2,10 +2,11 @@ import type {ComponentMeta} from '../component-meta'
|
|
|
2
2
|
|
|
3
3
|
export const meta: ComponentMeta = {
|
|
4
4
|
description:
|
|
5
|
-
'Modal sliding panel from a screen edge (right, left, or bottom). Slides in with backdrop overlay. Supports swipe-to-dismiss gestures on mobile, backdrop click dismiss, and Escape key. Swipe yields to an inner Duro ScrollArea: a drag there scrolls it, and dismisses only toward the edge from the scroll start (a native overflow:auto child is not covered — use ScrollArea). Use for secondary workflows, settings panels, or mobile-friendly detail views.',
|
|
5
|
+
'Modal sliding panel from a screen edge (right, left, or bottom). Slides in with backdrop overlay. Supports swipe-to-dismiss gestures on mobile, backdrop click dismiss, and Escape key. Swipe yields to an inner Duro ScrollArea: a drag there scrolls it, and dismisses only toward the edge from the scroll start (a native overflow:auto child is not covered — use ScrollArea). A bottom drawer with snapPoints (medium and large) is a phone sheet: it rests at its detents, a grabber steps through them on a tap, a drag moves between them and dismisses below the lowest; its Body is the scroll the drag defers to. Header titleAlign="center" centres the title with a text close at the end. Use for secondary workflows, settings panels, or mobile-friendly detail views.',
|
|
6
6
|
whenToUse: [
|
|
7
7
|
'Settings or configuration panels that slide in from the side',
|
|
8
8
|
'Mobile-friendly detail views (bottom sheet pattern)',
|
|
9
|
+
'Phone pickers and lists that need more room on demand (snapPoints)',
|
|
9
10
|
'Secondary workflows that need more space than a dialog',
|
|
10
11
|
'Filters, navigation drawers, or form panels',
|
|
11
12
|
],
|
|
@@ -0,0 +1,469 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
type ReactNode,
|
|
4
|
+
type RefObject,
|
|
5
|
+
useContext,
|
|
6
|
+
useEffect,
|
|
7
|
+
useMemo,
|
|
8
|
+
useRef,
|
|
9
|
+
} from 'react'
|
|
10
|
+
import {
|
|
11
|
+
type AccessibilityActionEvent,
|
|
12
|
+
type LayoutChangeEvent,
|
|
13
|
+
Pressable,
|
|
14
|
+
StyleSheet,
|
|
15
|
+
useWindowDimensions,
|
|
16
|
+
type View,
|
|
17
|
+
} from 'react-native'
|
|
18
|
+
import {Gesture, GestureDetector, type GestureType} from 'react-native-gesture-handler'
|
|
19
|
+
import Animated, {
|
|
20
|
+
type AnimatedRef,
|
|
21
|
+
Easing,
|
|
22
|
+
scrollTo,
|
|
23
|
+
useAnimatedRef,
|
|
24
|
+
useAnimatedScrollHandler,
|
|
25
|
+
useAnimatedStyle,
|
|
26
|
+
useSharedValue,
|
|
27
|
+
withTiming,
|
|
28
|
+
} from 'react-native-reanimated'
|
|
29
|
+
import {scheduleOnRN} from 'react-native-worklets'
|
|
30
|
+
import {html} from 'react-strict-dom'
|
|
31
|
+
import {DURATION_MS, SIZES_PX} from '@duro-app/tokens/keys'
|
|
32
|
+
import {ModalContext} from '../../shared/ModalContext'
|
|
33
|
+
import {OverlayModal} from '../../shared/portal/OverlayModal'
|
|
34
|
+
import {focusForAccessibility} from '../../shared/accessibilityFocus'
|
|
35
|
+
import {useSafeAreaInsets} from '../../shared/safeArea'
|
|
36
|
+
import {withPress} from '../../shared/pressableChild'
|
|
37
|
+
import {ControlContextBoundary} from '../Toolbar/ControlContextBoundary'
|
|
38
|
+
import {Icon} from '../Icon/Icon'
|
|
39
|
+
import {nativeStyles} from './native.css'
|
|
40
|
+
import {partStyles} from './parts.css'
|
|
41
|
+
import {
|
|
42
|
+
DEFAULT_GRABBER_LABELS,
|
|
43
|
+
Description,
|
|
44
|
+
DrawerContext,
|
|
45
|
+
Footer,
|
|
46
|
+
Header,
|
|
47
|
+
Title,
|
|
48
|
+
useDrawer,
|
|
49
|
+
type DrawerSize,
|
|
50
|
+
type GrabberLabels,
|
|
51
|
+
} from './parts'
|
|
52
|
+
import {
|
|
53
|
+
CROSS_SLOP,
|
|
54
|
+
DISMISS_DURATION,
|
|
55
|
+
DRAG_SLOP,
|
|
56
|
+
SNAP_DURATION,
|
|
57
|
+
SNAP_MAX_OVERSHOOT,
|
|
58
|
+
cycleDetent,
|
|
59
|
+
detentHeight,
|
|
60
|
+
rubberBand,
|
|
61
|
+
settleDetent,
|
|
62
|
+
shouldDismissEdge,
|
|
63
|
+
} from './sheetPhysics'
|
|
64
|
+
import {useDrawerRoot, type DrawerRootProps} from './useDrawerRoot'
|
|
65
|
+
|
|
66
|
+
export type {DrawerAnchor, DrawerSize, SnapPoint} from './parts'
|
|
67
|
+
|
|
68
|
+
/** Native-only wiring: where accessibility focus returns on close. */
|
|
69
|
+
const TriggerRefContext = createContext<RefObject<unknown> | null>(null)
|
|
70
|
+
|
|
71
|
+
/** What Drawer.Body needs from its sheet: the scroll the drag defers to. */
|
|
72
|
+
interface SheetScroll {
|
|
73
|
+
scrollRef: AnimatedRef<Animated.ScrollView>
|
|
74
|
+
scrollGesture: GestureType
|
|
75
|
+
onScroll: ReturnType<typeof useAnimatedScrollHandler>
|
|
76
|
+
/** px of a snap sheet below the screen's bottom edge at its detent */
|
|
77
|
+
hiddenBelow: number
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const SheetScrollContext = createContext<SheetScroll | null>(null)
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Native Drawer (plan N0, Slice B): the same compound API, in an
|
|
84
|
+
* OverlayModal. The panel follows the finger on the UI thread (Gesture
|
|
85
|
+
* Handler + Reanimated); a bottom drawer with `snapPoints` rests at its
|
|
86
|
+
* detents and dismisses below the lowest. The backdrop press and Android's
|
|
87
|
+
* back button close it; the screen reader's focus moves into the panel on
|
|
88
|
+
* open and back to the trigger on close.
|
|
89
|
+
*/
|
|
90
|
+
function Root({children, ...props}: DrawerRootProps) {
|
|
91
|
+
const ctx = useDrawerRoot(props)
|
|
92
|
+
const triggerRef = useRef<unknown>(null)
|
|
93
|
+
|
|
94
|
+
// Back to the trigger once the drawer is gone.
|
|
95
|
+
const wasOpen = useRef(ctx.open)
|
|
96
|
+
useEffect(() => {
|
|
97
|
+
if (wasOpen.current && !ctx.open) focusForAccessibility(triggerRef.current, 'Drawer')
|
|
98
|
+
wasOpen.current = ctx.open
|
|
99
|
+
}, [ctx.open])
|
|
100
|
+
|
|
101
|
+
return (
|
|
102
|
+
<DrawerContext.Provider value={ctx}>
|
|
103
|
+
<TriggerRefContext.Provider value={triggerRef}>{children}</TriggerRefContext.Provider>
|
|
104
|
+
</DrawerContext.Provider>
|
|
105
|
+
)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** Opens the drawer from its one child (a Button), whose host gets focus back on close. */
|
|
109
|
+
function Trigger({children}: {children: ReactNode}) {
|
|
110
|
+
const {requestOpen} = useDrawer()
|
|
111
|
+
const triggerRef = useContext(TriggerRefContext)
|
|
112
|
+
return withPress(children, requestOpen, triggerRef ?? undefined)
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
interface PortalProps {
|
|
116
|
+
children: ReactNode
|
|
117
|
+
size?: DrawerSize
|
|
118
|
+
/** The grabber's accessible names, by what a press does next. Snap sheets only */
|
|
119
|
+
grabberLabels?: GrabberLabels
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const PANEL_WIDTH = {sm: SIZES_PX.panelSm, md: SIZES_PX.panelMd, lg: SIZES_PX.panelLg} as const
|
|
123
|
+
|
|
124
|
+
/** A content-height bottom drawer is capped at 85% of the window, as the web caps it at 85vh. */
|
|
125
|
+
const CONTENT_SHEET_CAP = 0.85
|
|
126
|
+
|
|
127
|
+
const easeOut = Easing.out(Easing.cubic)
|
|
128
|
+
const easeIn = Easing.in(Easing.cubic)
|
|
129
|
+
|
|
130
|
+
function Portal({children, size = 'md', grabberLabels = DEFAULT_GRABBER_LABELS}: PortalProps) {
|
|
131
|
+
const {
|
|
132
|
+
open,
|
|
133
|
+
closing,
|
|
134
|
+
closeDuration,
|
|
135
|
+
anchor,
|
|
136
|
+
dismissable,
|
|
137
|
+
swipeDismiss,
|
|
138
|
+
requestClose,
|
|
139
|
+
requestCloseImmediate,
|
|
140
|
+
titleId,
|
|
141
|
+
panelRef,
|
|
142
|
+
snapPoints,
|
|
143
|
+
snapIndex,
|
|
144
|
+
setSnapIndex,
|
|
145
|
+
} = useDrawer()
|
|
146
|
+
const window = useWindowDimensions()
|
|
147
|
+
const insets = useSafeAreaInsets()
|
|
148
|
+
const bottom = anchor === 'bottom'
|
|
149
|
+
const snapping = snapPoints.length > 0
|
|
150
|
+
|
|
151
|
+
const heights = useMemo(
|
|
152
|
+
() => snapPoints.map((p) => detentHeight(p, window.height, insets.top)),
|
|
153
|
+
[snapPoints, window.height, insets.top],
|
|
154
|
+
)
|
|
155
|
+
const high = heights.length > 0 ? heights[heights.length - 1] : 0
|
|
156
|
+
// Where the panel rests at its detent: its offset below its own full height.
|
|
157
|
+
const rest = snapping ? high - heights[snapIndex] : 0
|
|
158
|
+
// Off screen: the whole panel past its edge (a snap sheet's overshoot skirt included).
|
|
159
|
+
const hidden = snapping ? high + SNAP_MAX_OVERSHOOT : bottom ? window.height : window.width
|
|
160
|
+
|
|
161
|
+
// The panel's displacement toward its edge, in px: 0 shows it whole; a
|
|
162
|
+
// snap sheet rests at restOf(detent); negative only while pulled past its
|
|
163
|
+
// largest detent.
|
|
164
|
+
const offset = useSharedValue(hidden)
|
|
165
|
+
const start = useSharedValue(0)
|
|
166
|
+
const extent = useSharedValue(bottom ? window.height : window.width)
|
|
167
|
+
const index = useSharedValue(snapIndex)
|
|
168
|
+
const owns = useSharedValue(false)
|
|
169
|
+
const inBody = useSharedValue(false)
|
|
170
|
+
const scrollY = useSharedValue(0)
|
|
171
|
+
const scrollRef = useAnimatedRef<Animated.ScrollView>()
|
|
172
|
+
|
|
173
|
+
// Enter, exit, and a detent chosen from React (the grabber): animate there.
|
|
174
|
+
useEffect(() => {
|
|
175
|
+
if (!open) {
|
|
176
|
+
offset.value = hidden
|
|
177
|
+
return
|
|
178
|
+
}
|
|
179
|
+
if (closing) {
|
|
180
|
+
offset.value = withTiming(hidden, {duration: DURATION_MS[closeDuration], easing: easeIn})
|
|
181
|
+
return
|
|
182
|
+
}
|
|
183
|
+
index.value = snapIndex
|
|
184
|
+
offset.value = withTiming(rest, {duration: DURATION_MS.base, easing: easeOut})
|
|
185
|
+
// `rest` and `hidden` follow the window: a rotation re-seats the panel too.
|
|
186
|
+
}, [open, closing, closeDuration, snapIndex, rest, hidden, index, offset])
|
|
187
|
+
|
|
188
|
+
const heightsShared = useSharedValue(heights)
|
|
189
|
+
useEffect(() => {
|
|
190
|
+
heightsShared.value = heights
|
|
191
|
+
}, [heights, heightsShared])
|
|
192
|
+
|
|
193
|
+
const scrollGesture = useMemo(
|
|
194
|
+
() =>
|
|
195
|
+
Gesture.Native().onBegin(() => {
|
|
196
|
+
inBody.value = true
|
|
197
|
+
}),
|
|
198
|
+
[inBody],
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
const onScroll = useAnimatedScrollHandler((e) => {
|
|
202
|
+
scrollY.value = e.contentOffset.y
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
const horizontalSign = anchor === 'left' ? -1 : 1
|
|
206
|
+
const canDismiss = swipeDismiss && dismissable
|
|
207
|
+
const pan = useMemo(() => {
|
|
208
|
+
const toEdge = (x: number, y: number) => {
|
|
209
|
+
'worklet'
|
|
210
|
+
return bottom ? y : x * horizontalSign
|
|
211
|
+
}
|
|
212
|
+
const settleTo = (target: number) => {
|
|
213
|
+
'worklet'
|
|
214
|
+
offset.value = withTiming(target, {duration: SNAP_DURATION, easing: easeOut})
|
|
215
|
+
}
|
|
216
|
+
const dismiss = () => {
|
|
217
|
+
'worklet'
|
|
218
|
+
offset.value = withTiming(hidden, {duration: DISMISS_DURATION, easing: easeIn}, (done) => {
|
|
219
|
+
if (done) scheduleOnRN(requestCloseImmediate)
|
|
220
|
+
})
|
|
221
|
+
}
|
|
222
|
+
const gesture = Gesture.Pan()
|
|
223
|
+
.enabled(swipeDismiss || snapping)
|
|
224
|
+
.onStart((e) => {
|
|
225
|
+
start.value = offset.value
|
|
226
|
+
const t = toEdge(e.translationX, e.translationY)
|
|
227
|
+
// From the content, the sheet takes the drag only with the list at its
|
|
228
|
+
// top: toward the edge, or upward while a larger detent remains.
|
|
229
|
+
owns.value =
|
|
230
|
+
!bottom || !inBody.value
|
|
231
|
+
? true
|
|
232
|
+
: scrollY.value <= 0 &&
|
|
233
|
+
(t > 0 || (snapping && index.value < heightsShared.value.length - 1))
|
|
234
|
+
})
|
|
235
|
+
.onUpdate((e) => {
|
|
236
|
+
if (!owns.value) return
|
|
237
|
+
if (inBody.value) scrollTo(scrollRef, 0, 0, false)
|
|
238
|
+
const next = start.value + toEdge(e.translationX, e.translationY)
|
|
239
|
+
if (snapping) offset.value = next < 0 ? -rubberBand(-next, SNAP_MAX_OVERSHOOT) : next
|
|
240
|
+
else offset.value = Math.max(0, next)
|
|
241
|
+
})
|
|
242
|
+
.onEnd((e) => {
|
|
243
|
+
if (!owns.value) return
|
|
244
|
+
const velocity = toEdge(e.velocityX, e.velocityY) / 1000
|
|
245
|
+
if (snapping) {
|
|
246
|
+
const hs = heightsShared.value
|
|
247
|
+
const top = hs[hs.length - 1]
|
|
248
|
+
const settled = settleDetent({
|
|
249
|
+
heights: hs,
|
|
250
|
+
from: index.value,
|
|
251
|
+
height: top - offset.value,
|
|
252
|
+
velocity,
|
|
253
|
+
})
|
|
254
|
+
if (settled === 'dismiss') {
|
|
255
|
+
if (canDismiss) dismiss()
|
|
256
|
+
else settleTo(top - hs[0])
|
|
257
|
+
return
|
|
258
|
+
}
|
|
259
|
+
settleTo(top - hs[settled])
|
|
260
|
+
if (settled !== index.value) {
|
|
261
|
+
index.value = settled
|
|
262
|
+
scheduleOnRN(setSnapIndex, settled)
|
|
263
|
+
}
|
|
264
|
+
return
|
|
265
|
+
}
|
|
266
|
+
if (canDismiss && shouldDismissEdge(offset.value, extent.value, velocity)) dismiss()
|
|
267
|
+
else settleTo(0)
|
|
268
|
+
})
|
|
269
|
+
.onFinalize(() => {
|
|
270
|
+
inBody.value = false
|
|
271
|
+
owns.value = false
|
|
272
|
+
})
|
|
273
|
+
.simultaneousWithExternalGesture(scrollGesture)
|
|
274
|
+
return bottom
|
|
275
|
+
? gesture.activeOffsetY([-DRAG_SLOP, DRAG_SLOP]).failOffsetX([-CROSS_SLOP, CROSS_SLOP])
|
|
276
|
+
: gesture.activeOffsetX([-DRAG_SLOP, DRAG_SLOP]).failOffsetY([-CROSS_SLOP, CROSS_SLOP])
|
|
277
|
+
}, [
|
|
278
|
+
bottom,
|
|
279
|
+
horizontalSign,
|
|
280
|
+
snapping,
|
|
281
|
+
swipeDismiss,
|
|
282
|
+
canDismiss,
|
|
283
|
+
hidden,
|
|
284
|
+
requestCloseImmediate,
|
|
285
|
+
setSnapIndex,
|
|
286
|
+
scrollGesture,
|
|
287
|
+
offset,
|
|
288
|
+
start,
|
|
289
|
+
extent,
|
|
290
|
+
index,
|
|
291
|
+
owns,
|
|
292
|
+
inBody,
|
|
293
|
+
scrollY,
|
|
294
|
+
scrollRef,
|
|
295
|
+
heightsShared,
|
|
296
|
+
])
|
|
297
|
+
|
|
298
|
+
const panelMotion = useAnimatedStyle(() =>
|
|
299
|
+
bottom
|
|
300
|
+
? {transform: [{translateY: offset.value}]}
|
|
301
|
+
: {transform: [{translateX: offset.value * horizontalSign}]},
|
|
302
|
+
)
|
|
303
|
+
const backdropMotion = useAnimatedStyle(() => {
|
|
304
|
+
if (snapping) {
|
|
305
|
+
const hs = heightsShared.value
|
|
306
|
+
const visible = hs[hs.length - 1] - offset.value
|
|
307
|
+
return {opacity: Math.min(1, Math.max(0, visible / hs[0]))}
|
|
308
|
+
}
|
|
309
|
+
return {opacity: Math.min(1, Math.max(0, 1 - offset.value / extent.value))}
|
|
310
|
+
})
|
|
311
|
+
|
|
312
|
+
const onPanelLayout = (e: LayoutChangeEvent) => {
|
|
313
|
+
const {width, height} = e.nativeEvent.layout
|
|
314
|
+
extent.value = bottom ? height : width
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
const placement = bottom
|
|
318
|
+
? snapping
|
|
319
|
+
? [layout.bottom, {height: high + SNAP_MAX_OVERSHOOT, bottom: -SNAP_MAX_OVERSHOOT}]
|
|
320
|
+
: [layout.bottom, {maxHeight: window.height * CONTENT_SHEET_CAP}]
|
|
321
|
+
: [layout.side, anchor === 'left' ? layout.left : layout.right, {maxWidth: PANEL_WIDTH[size]}]
|
|
322
|
+
const padTop = bottom ? 0 : insets.top
|
|
323
|
+
const padBottom = insets.bottom + (snapping ? SNAP_MAX_OVERSHOOT : 0)
|
|
324
|
+
|
|
325
|
+
const nextIndex = cycleDetent(snapIndex, snapPoints.length)
|
|
326
|
+
const onGrabberAction = (e: AccessibilityActionEvent) => {
|
|
327
|
+
if (e.nativeEvent.actionName === 'increment') {
|
|
328
|
+
setSnapIndex(Math.min(snapIndex + 1, snapPoints.length - 1))
|
|
329
|
+
} else if (e.nativeEvent.actionName === 'decrement') {
|
|
330
|
+
setSnapIndex(Math.max(snapIndex - 1, 0))
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
const sheetScroll: SheetScroll = {
|
|
335
|
+
scrollRef,
|
|
336
|
+
scrollGesture,
|
|
337
|
+
onScroll,
|
|
338
|
+
hiddenBelow: snapping ? high - heights[snapIndex] : 0,
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return (
|
|
342
|
+
<OverlayModal
|
|
343
|
+
visible={open}
|
|
344
|
+
onRequestClose={() => {
|
|
345
|
+
if (dismissable) requestClose()
|
|
346
|
+
}}
|
|
347
|
+
onShow={() => focusForAccessibility(panelRef.current, 'Drawer')}
|
|
348
|
+
>
|
|
349
|
+
<Animated.View style={[StyleSheet.absoluteFill, backdropMotion]}>
|
|
350
|
+
<Pressable
|
|
351
|
+
style={StyleSheet.absoluteFill}
|
|
352
|
+
onPress={dismissable ? requestClose : undefined}
|
|
353
|
+
accessible={false}
|
|
354
|
+
importantForAccessibility="no"
|
|
355
|
+
>
|
|
356
|
+
<html.div aria-hidden style={[nativeStyles.fill, nativeStyles.scrim]} />
|
|
357
|
+
</Pressable>
|
|
358
|
+
</Animated.View>
|
|
359
|
+
<GestureDetector gesture={pan}>
|
|
360
|
+
<Animated.View
|
|
361
|
+
ref={panelRef as RefObject<View | null>}
|
|
362
|
+
accessibilityViewIsModal
|
|
363
|
+
onLayout={onPanelLayout}
|
|
364
|
+
style={[placement, panelMotion]}
|
|
365
|
+
>
|
|
366
|
+
<html.div
|
|
367
|
+
role="dialog"
|
|
368
|
+
aria-modal
|
|
369
|
+
aria-labelledby={titleId}
|
|
370
|
+
style={[
|
|
371
|
+
nativeStyles.panel,
|
|
372
|
+
bottom && nativeStyles.panelBottom,
|
|
373
|
+
anchor === 'right' && nativeStyles.panelRight,
|
|
374
|
+
anchor === 'left' && nativeStyles.panelLeft,
|
|
375
|
+
nativeStyles.insets(padTop, padBottom),
|
|
376
|
+
]}
|
|
377
|
+
>
|
|
378
|
+
{snapping && (
|
|
379
|
+
<Pressable
|
|
380
|
+
accessibilityRole="adjustable"
|
|
381
|
+
accessibilityLabel={
|
|
382
|
+
nextIndex > snapIndex ? grabberLabels.expand : grabberLabels.collapse
|
|
383
|
+
}
|
|
384
|
+
accessibilityValue={{text: snapPoints[snapIndex]}}
|
|
385
|
+
accessibilityActions={[{name: 'increment'}, {name: 'decrement'}]}
|
|
386
|
+
onAccessibilityAction={onGrabberAction}
|
|
387
|
+
onPress={() => setSnapIndex(nextIndex)}
|
|
388
|
+
>
|
|
389
|
+
<html.div style={partStyles.grabberHit}>
|
|
390
|
+
<html.div style={partStyles.grabber} />
|
|
391
|
+
</html.div>
|
|
392
|
+
</Pressable>
|
|
393
|
+
)}
|
|
394
|
+
<ModalContext.Provider value={true}>
|
|
395
|
+
<ControlContextBoundary>
|
|
396
|
+
<SheetScrollContext.Provider value={sheetScroll}>
|
|
397
|
+
{children}
|
|
398
|
+
</SheetScrollContext.Provider>
|
|
399
|
+
</ControlContextBoundary>
|
|
400
|
+
</ModalContext.Provider>
|
|
401
|
+
</html.div>
|
|
402
|
+
</Animated.View>
|
|
403
|
+
</GestureDetector>
|
|
404
|
+
</OverlayModal>
|
|
405
|
+
)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// Layout-only RN styles: where the moving panel sits before it moves.
|
|
409
|
+
const layout = StyleSheet.create({
|
|
410
|
+
bottom: {position: 'absolute', left: 0, right: 0, bottom: 0},
|
|
411
|
+
side: {position: 'absolute', top: 0, bottom: 0, width: '100%'},
|
|
412
|
+
left: {left: 0},
|
|
413
|
+
right: {right: 0},
|
|
414
|
+
body: {flexGrow: 0, flexShrink: 1},
|
|
415
|
+
bodyFill: {flex: 1},
|
|
416
|
+
})
|
|
417
|
+
|
|
418
|
+
/**
|
|
419
|
+
* Native Body: a ScrollView, since a native div does not scroll its
|
|
420
|
+
* overflow. In a bottom sheet the drag defers to it: the list scrolls, and
|
|
421
|
+
* moves the sheet only from its top.
|
|
422
|
+
*/
|
|
423
|
+
function Body({children}: {children: ReactNode}) {
|
|
424
|
+
const sheet = useContext(SheetScrollContext)
|
|
425
|
+
const {snapPoints} = useDrawer()
|
|
426
|
+
if (!sheet) return null
|
|
427
|
+
return (
|
|
428
|
+
<GestureDetector gesture={sheet.scrollGesture}>
|
|
429
|
+
<Animated.ScrollView
|
|
430
|
+
ref={sheet.scrollRef}
|
|
431
|
+
onScroll={sheet.onScroll}
|
|
432
|
+
scrollEventThrottle={16}
|
|
433
|
+
bounces={false}
|
|
434
|
+
style={snapPoints.length > 0 ? layout.bodyFill : layout.body}
|
|
435
|
+
>
|
|
436
|
+
<html.div style={[nativeStyles.bodyContent, nativeStyles.hiddenBelow(sheet.hiddenBelow)]}>
|
|
437
|
+
{children}
|
|
438
|
+
</html.div>
|
|
439
|
+
</Animated.ScrollView>
|
|
440
|
+
</GestureDetector>
|
|
441
|
+
)
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
interface CloseProps {
|
|
445
|
+
children?: ReactNode
|
|
446
|
+
'aria-label'?: string
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function Close({children, 'aria-label': ariaLabel = 'Close'}: CloseProps) {
|
|
450
|
+
const {requestClose} = useDrawer()
|
|
451
|
+
if (children) return withPress(children, requestClose)
|
|
452
|
+
return (
|
|
453
|
+
<html.button onClick={requestClose} aria-label={ariaLabel} style={partStyles.closeButton}>
|
|
454
|
+
<Icon name="x" size="sm" color="textMuted" />
|
|
455
|
+
</html.button>
|
|
456
|
+
)
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
export const Drawer = {
|
|
460
|
+
Root,
|
|
461
|
+
Trigger,
|
|
462
|
+
Portal,
|
|
463
|
+
Header,
|
|
464
|
+
Title,
|
|
465
|
+
Description,
|
|
466
|
+
Body,
|
|
467
|
+
Footer,
|
|
468
|
+
Close,
|
|
469
|
+
}
|