pixelize-native-library 1.2.0 → 1.2.1
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/lib/module/core/MODULE.md +2 -1
- package/lib/module/core/gradient/AccentGradientFill.js +80 -0
- package/lib/module/core/gradient/darkenHex.js +13 -0
- package/lib/module/core/gradient/gradientStops.js +27 -0
- package/lib/module/core/gradient/index.js +7 -0
- package/lib/module/core/gradient/withAlpha.js +19 -0
- package/lib/module/core/haptics/MODULE.md +4 -0
- package/lib/module/core/haptics/context.js +7 -0
- package/lib/module/core/haptics/haptics.js +17 -0
- package/lib/module/core/haptics/index.js +6 -0
- package/lib/module/core/haptics/useHaptics.js +73 -0
- package/lib/module/core/icon/MODULE.md +16 -9
- package/lib/module/core/icon/icons/trending-up.js +10 -0
- package/lib/module/core/icon/resolve.js +2 -0
- package/lib/module/core/media/expoImage.js +6 -0
- package/lib/module/core/motion/MODULE.md +12 -12
- package/lib/module/core/motion/config.js +4 -1
- package/lib/module/core/motion/index.js +2 -1
- package/lib/module/core/motion/usePressState.js +145 -0
- package/lib/module/core/style/index.js +1 -0
- package/lib/module/core/style/radius.js +4 -0
- package/lib/module/index.js +1 -0
- package/lib/module/modules/accordion/Accordion.js +69 -49
- package/lib/module/modules/accordion/Accordion.variants.js +4 -3
- package/lib/module/modules/accordion/MODULE.md +2 -1
- package/lib/module/modules/alert-dialog/AlertDialog.js +6 -5
- package/lib/module/modules/alert-dialog/AlertDialog.variants.js +4 -0
- package/lib/module/modules/app-bar/AppBar.js +6 -4
- package/lib/module/modules/app-bar/AppBar.variants.js +1 -2
- package/lib/module/modules/avatar/Avatar.js +7 -1
- package/lib/module/modules/avatar/Avatar.variants.js +1 -1
- package/lib/module/modules/avatar/MODULE.md +2 -2
- package/lib/module/modules/avatar-group/AvatarGroup.js +10 -6
- package/lib/module/modules/avatar-group/AvatarGroup.variants.js +23 -0
- package/lib/module/modules/avatar-group/MODULE.md +16 -0
- package/lib/module/modules/badge/Badge.js +11 -5
- package/lib/module/modules/badge/Badge.variants.js +2 -1
- package/lib/module/modules/badge/MODULE.md +5 -5
- package/lib/module/modules/banner/Banner.js +106 -60
- package/lib/module/modules/banner/Banner.variants.js +2 -2
- package/lib/module/modules/banner/MODULE.md +7 -2
- package/lib/module/modules/bottom-nav/BottomNav.js +6 -3
- package/lib/module/modules/bottom-nav/BottomNav.variants.js +9 -10
- package/lib/module/modules/bottom-nav/BottomNavOverflowSheet.js +28 -4
- package/lib/module/modules/bottom-nav/BottomNavTab.js +28 -4
- package/lib/module/modules/bottom-nav/MODULE.md +10 -1
- package/lib/module/modules/bottom-sheet/BottomSheet.js +20 -7
- package/lib/module/modules/bottom-sheet/BottomSheet.variants.js +15 -5
- package/lib/module/modules/bottom-sheet/MODULE.md +13 -2
- package/lib/module/modules/button/Button.js +87 -101
- package/lib/module/modules/button/Button.variants.js +8 -7
- package/lib/module/modules/button/MODULE.md +6 -0
- package/lib/module/modules/button-group/ButtonGroup.js +36 -37
- package/lib/module/modules/button-group/ButtonGroup.variants.js +21 -46
- package/lib/module/modules/button-group/MODULE.md +25 -30
- package/lib/module/modules/card/Card.js +117 -19
- package/lib/module/modules/card/Card.variants.js +1 -0
- package/lib/module/modules/card/MODULE.md +13 -10
- package/lib/module/modules/charts/BarChart.js +29 -14
- package/lib/module/modules/charts/BarList.js +31 -18
- package/lib/module/modules/charts/Charts.variants.js +66 -2
- package/lib/module/modules/charts/DonutChart.js +9 -4
- package/lib/module/modules/charts/LineChart.js +5 -3
- package/lib/module/modules/charts/MODULE.md +24 -11
- package/lib/module/modules/charts/PieChart.js +13 -4
- package/lib/module/modules/charts/Sparkline.js +4 -2
- package/lib/module/modules/checkbox/Checkbox.js +10 -2
- package/lib/module/modules/checkbox/MODULE.md +5 -0
- package/lib/module/modules/chip/Chip.js +83 -38
- package/lib/module/modules/chip/Chip.variants.js +15 -3
- package/lib/module/modules/chip/MODULE.md +6 -4
- package/lib/module/modules/combobox/Combobox.js +93 -57
- package/lib/module/modules/combobox/Combobox.variants.js +22 -7
- package/lib/module/modules/combobox/MODULE.md +14 -4
- package/lib/module/modules/composer/Composer.js +9 -2
- package/lib/module/modules/composer/Composer.variants.js +2 -0
- package/lib/module/modules/composer/MODULE.md +5 -0
- package/lib/module/modules/copy-button/CopyButton.js +22 -4
- package/lib/module/modules/copy-button/CopyButton.variants.js +4 -2
- package/lib/module/modules/copy-button/MODULE.md +5 -0
- package/lib/module/modules/data-table/DataTable.js +28 -9
- package/lib/module/modules/data-table/DataTable.variants.js +3 -2
- package/lib/module/modules/data-table/MODULE.md +1 -0
- package/lib/module/modules/date-picker/Calendar.js +75 -29
- package/lib/module/modules/date-picker/DatePicker.variants.js +24 -9
- package/lib/module/modules/date-picker/MODULE.md +25 -4
- package/lib/module/modules/date-picker/PickerField.js +13 -4
- package/lib/module/modules/date-picker/PickerShell.js +2 -0
- package/lib/module/modules/date-picker/TimePicker.js +13 -18
- package/lib/module/modules/divider/Divider.variants.js +6 -5
- package/lib/module/modules/divider/MODULE.md +2 -0
- package/lib/module/modules/drawer/Drawer.js +20 -8
- package/lib/module/modules/drawer/Drawer.variants.js +4 -4
- package/lib/module/modules/drawer/MODULE.md +3 -0
- package/lib/module/modules/empty-state/EmptyState.js +18 -29
- package/lib/module/modules/empty-state/EmptyState.variants.js +7 -0
- package/lib/module/modules/empty-state/MODULE.md +1 -0
- package/lib/module/modules/fab/Fab.js +41 -61
- package/lib/module/modules/fab/Fab.variants.js +15 -1
- package/lib/module/modules/fab/FabGroup.js +84 -57
- package/lib/module/modules/fab/MODULE.md +19 -6
- package/lib/module/modules/file-grid/FileGrid.js +30 -16
- package/lib/module/modules/file-grid/FileGrid.variants.js +2 -2
- package/lib/module/modules/file-grid/MODULE.md +3 -1
- package/lib/module/modules/file-upload/FileUpload.variants.js +3 -1
- package/lib/module/modules/file-upload/MODULE.md +2 -0
- package/lib/module/modules/filter-sheet/FilterChip.js +11 -3
- package/lib/module/modules/filter-sheet/FilterSheetBody.js +15 -3
- package/lib/module/modules/filter-sheet/MODULE.md +9 -0
- package/lib/module/modules/folder-row/FolderRow.js +29 -17
- package/lib/module/modules/folder-row/FolderRow.variants.js +4 -2
- package/lib/module/modules/folder-row/MODULE.md +2 -1
- package/lib/module/modules/gantt/Gantt.js +30 -9
- package/lib/module/modules/gantt/Gantt.variants.js +36 -0
- package/lib/module/modules/gantt/MODULE.md +11 -1
- package/lib/module/modules/image-viewer/ImageViewer.js +35 -5
- package/lib/module/modules/image-viewer/MODULE.md +6 -0
- package/lib/module/modules/input/Input.js +20 -7
- package/lib/module/modules/input/Input.variants.js +8 -7
- package/lib/module/modules/input/MODULE.md +2 -0
- package/lib/module/modules/list-item/ListItem.js +48 -26
- package/lib/module/modules/list-item/ListItem.variants.js +11 -2
- package/lib/module/modules/list-item/MODULE.md +2 -3
- package/lib/module/modules/markdown/MODULE.md +8 -1
- package/lib/module/modules/markdown/Markdown.js +57 -22
- package/lib/module/modules/markdown/Markdown.variants.js +2 -1
- package/lib/module/modules/menu/MODULE.md +11 -0
- package/lib/module/modules/menu/Menu.js +99 -40
- package/lib/module/modules/menu/Menu.variants.js +3 -3
- package/lib/module/modules/message-bubble/MODULE.md +4 -1
- package/lib/module/modules/message-bubble/MessageBubble.js +4 -5
- package/lib/module/modules/message-bubble/MessageBubble.variants.js +5 -5
- package/lib/module/modules/modal/MODULE.md +11 -0
- package/lib/module/modules/modal/Modal.js +87 -35
- package/lib/module/modules/modal/Modal.variants.js +2 -2
- package/lib/module/modules/more-items/MODULE.md +5 -0
- package/lib/module/modules/more-items/MoreItems.js +7 -1
- package/lib/module/modules/more-items/MoreItems.variants.js +4 -1
- package/lib/module/modules/multi-select/MODULE.md +5 -0
- package/lib/module/modules/multi-select/MultiSelect.js +23 -1
- package/lib/module/modules/multi-select/MultiSelect.variants.js +4 -2
- package/lib/module/modules/number-input/MODULE.md +2 -1
- package/lib/module/modules/number-input/NumberInput.js +97 -84
- package/lib/module/modules/number-input/NumberInput.variants.js +9 -6
- package/lib/module/modules/org-switcher/MODULE.md +13 -1
- package/lib/module/modules/org-switcher/OrgSwitcher.js +13 -2
- package/lib/module/modules/org-switcher/OrgSwitcher.variants.js +4 -2
- package/lib/module/modules/pagination/MODULE.md +2 -2
- package/lib/module/modules/pagination/Pagination.js +76 -37
- package/lib/module/modules/pagination/Pagination.variants.js +4 -2
- package/lib/module/modules/pagination/PaginationControls.js +55 -35
- package/lib/module/modules/pin-input/MODULE.md +5 -1
- package/lib/module/modules/pin-input/PinInput.js +9 -2
- package/lib/module/modules/pin-input/PinInput.variants.js +2 -1
- package/lib/module/modules/radio-group/MODULE.md +2 -2
- package/lib/module/modules/radio-group/RadioGroup.js +122 -63
- package/lib/module/modules/radio-group/RadioGroup.variants.js +2 -1
- package/lib/module/modules/reorder/MODULE.md +2 -0
- package/lib/module/modules/reorder/Reorder.js +4 -3
- package/lib/module/modules/reorder/Reorder.variants.js +4 -2
- package/lib/module/modules/rich-text/MODULE.md +3 -1
- package/lib/module/modules/rich-text/RichText.js +42 -22
- package/lib/module/modules/rich-text-editor/MODULE.md +4 -1
- package/lib/module/modules/rich-text-editor/RichTextEditor.js +8 -1
- package/lib/module/modules/rich-text-editor/RichTextEditor.variants.js +9 -6
- package/lib/module/modules/screen/MODULE.md +7 -0
- package/lib/module/modules/screen/Screen.js +50 -17
- package/lib/module/modules/screen/Screen.variants.js +18 -0
- package/lib/module/modules/search-bar/MODULE.md +1 -0
- package/lib/module/modules/search-bar/SearchBar.js +46 -26
- package/lib/module/modules/search-bar/SearchBar.variants.js +11 -8
- package/lib/module/modules/section/MODULE.md +2 -0
- package/lib/module/modules/section/Section.js +8 -15
- package/lib/module/modules/section/Section.variants.js +1 -6
- package/lib/module/modules/segmented-control/MODULE.md +3 -1
- package/lib/module/modules/segmented-control/SegmentedControl.js +110 -46
- package/lib/module/modules/segmented-control/SegmentedControl.variants.js +3 -2
- package/lib/module/modules/select/MODULE.md +26 -5
- package/lib/module/modules/select/Select.js +39 -12
- package/lib/module/modules/select/Select.variants.js +36 -12
- package/lib/module/modules/skeleton/MODULE.md +23 -27
- package/lib/module/modules/skeleton/Skeleton.js +46 -51
- package/lib/module/modules/skeleton/Skeleton.variants.js +17 -75
- package/lib/module/modules/slider/MODULE.md +2 -0
- package/lib/module/modules/slider/Slider.js +2 -1
- package/lib/module/modules/stage-progress/MODULE.md +12 -8
- package/lib/module/modules/stage-progress/StageProgress.js +94 -47
- package/lib/module/modules/stage-progress/StageProgress.variants.js +17 -12
- package/lib/module/modules/stat-tile/MODULE.md +2 -0
- package/lib/module/modules/stat-tile/StatTile.js +15 -10
- package/lib/module/modules/stat-tile/StatTile.variants.js +2 -0
- package/lib/module/modules/state-block/MODULE.md +3 -0
- package/lib/module/modules/state-block/StateBlock.js +11 -6
- package/lib/module/modules/state-block/StateBlock.variants.js +7 -0
- package/lib/module/modules/surface/MODULE.md +59 -0
- package/lib/module/modules/surface/Surface.js +42 -0
- package/lib/module/modules/surface/Surface.variants.js +33 -0
- package/lib/module/modules/surface/index.js +4 -0
- package/lib/module/modules/swipeable-row/MODULE.md +9 -0
- package/lib/module/modules/swipeable-row/SwipeableRow.js +28 -7
- package/lib/module/modules/switch/MODULE.md +2 -0
- package/lib/module/modules/switch/Switch.js +8 -2
- package/lib/module/modules/tabs/MODULE.md +2 -1
- package/lib/module/modules/tabs/Tabs.js +37 -18
- package/lib/module/modules/tabs/Tabs.variants.js +4 -2
- package/lib/module/modules/text/MODULE.md +5 -2
- package/lib/module/modules/text/Text.js +18 -6
- package/lib/module/modules/text/Text.variants.js +108 -44
- package/lib/module/modules/textarea/MODULE.md +2 -0
- package/lib/module/modules/textarea/Textarea.js +3 -2
- package/lib/module/modules/textarea/Textarea.variants.js +2 -1
- package/lib/module/modules/toast/MODULE.md +8 -4
- package/lib/module/modules/toast/Toast.js +31 -13
- package/lib/module/modules/toast/Toast.variants.js +5 -0
- package/lib/module/modules/tooltip/MODULE.md +15 -11
- package/lib/module/modules/tooltip/Tooltip.js +41 -9
- package/lib/module/modules/tooltip/Tooltip.variants.js +8 -1
- package/lib/module/theme/MODULE.md +3 -1
- package/lib/module/theme/platform/MODULE.md +14 -2
- package/lib/module/theme/platform/elevation.native.js +0 -44
- package/lib/module/theme/platform/floatingSurface.native.js +75 -0
- package/lib/module/theme/platform/highlight.native.js +59 -0
- package/lib/module/theme/platform/index.js +5 -0
- package/lib/module/theme/platform/motion.native.js +31 -11
- package/lib/module/theme/platform/stateLayer.native.js +14 -0
- package/lib/module/theme/platform/surfaces.native.js +11 -0
- package/lib/module/theme/provider/PixelizeProvider.js +12 -5
- package/lib/module/theme/tokens/MODULE.md +32 -28
- package/lib/module/theme/tokens/THEME-CONTRACT.md +137 -0
- package/lib/module/theme/tokens/assertPalette.js +29 -0
- package/lib/module/theme/tokens/brands/emerald/palette.light.js +7 -6
- package/lib/module/theme/tokens/brands/lavender/palette.light.js +3 -2
- package/lib/module/theme/tokens/brands/meadow/palette.light.js +7 -6
- package/lib/module/theme/tokens/brands/radiant/palette.light.js +7 -6
- package/lib/module/theme/tokens/brands/rosewood/palette.light.js +7 -6
- package/lib/module/theme/tokens/brands/skyline/palette.light.js +7 -6
- package/lib/module/theme/tokens/brands/slate/palette.light.js +8 -10
- package/lib/module/theme/tokens/brands/storefront/palette.light.js +7 -6
- package/lib/module/theme/tokens/brands/zinc/palette.dark.js +3 -2
- package/lib/module/theme/tokens/brands/zinc/palette.light.js +3 -2
- package/lib/module/theme/tokens/builders/buildDarkPalette.js +3 -2
- package/lib/module/theme/tokens/builders/finalizePalette.js +34 -0
- package/lib/module/theme/tokens/builders/liftToContrast.js +44 -0
- package/lib/module/theme/tokens/builders/placeholderInk.js +22 -0
- package/lib/module/theme/tokens/builders/semanticText.js +14 -0
- package/lib/module/theme/tokens/builders/surfaceRungs.js +44 -0
- package/lib/module/theme/tokens/index.js +5 -0
- package/lib/module/theme/tokens/roles/index.js +5 -0
- package/lib/typescript/core/gradient/AccentGradientFill.d.ts +7 -0
- package/lib/typescript/core/gradient/darkenHex.d.ts +2 -0
- package/lib/typescript/core/gradient/gradientStops.d.ts +10 -0
- package/lib/typescript/core/gradient/index.d.ts +5 -0
- package/lib/typescript/core/gradient/withAlpha.d.ts +2 -0
- package/lib/typescript/core/haptics/context.d.ts +3 -0
- package/lib/typescript/core/haptics/haptics.d.ts +33 -0
- package/lib/typescript/core/haptics/index.d.ts +6 -0
- package/lib/typescript/core/haptics/useHaptics.d.ts +12 -0
- package/lib/typescript/core/icon/icons/trending-up.d.ts +3 -0
- package/lib/typescript/core/icon/names.d.ts +1 -1
- package/lib/typescript/core/media/expoImage.d.ts +15 -6
- package/lib/typescript/core/media/pickers.d.ts +5 -5
- package/lib/typescript/core/motion/config.d.ts +2 -1
- package/lib/typescript/core/motion/index.d.ts +3 -1
- package/lib/typescript/core/motion/usePressState.d.ts +21 -0
- package/lib/typescript/core/style/index.d.ts +1 -0
- package/lib/typescript/core/style/radius.d.ts +2 -0
- package/lib/typescript/index.d.ts +4 -2
- package/lib/typescript/modules/accordion/Accordion.variants.d.ts +2 -2
- package/lib/typescript/modules/alert-dialog/AlertDialog.variants.d.ts +1 -0
- package/lib/typescript/modules/avatar/Avatar.variants.d.ts +1 -1
- package/lib/typescript/modules/avatar-group/AvatarGroup.d.ts +4 -2
- package/lib/typescript/modules/avatar-group/AvatarGroup.variants.d.ts +19 -0
- package/lib/typescript/modules/banner/Banner.d.ts +2 -0
- package/lib/typescript/modules/bottom-nav/BottomNav.variants.d.ts +1 -3
- package/lib/typescript/modules/bottom-sheet/BottomSheet.variants.d.ts +3 -1
- package/lib/typescript/modules/button/Button.d.ts +0 -25
- package/lib/typescript/modules/button/Button.variants.d.ts +6 -6
- package/lib/typescript/modules/button-group/ButtonGroup.d.ts +0 -19
- package/lib/typescript/modules/button-group/ButtonGroup.variants.d.ts +22 -56
- package/lib/typescript/modules/card/Card.d.ts +7 -5
- package/lib/typescript/modules/charts/Charts.variants.d.ts +29 -1
- package/lib/typescript/modules/chip/Chip.d.ts +3 -1
- package/lib/typescript/modules/chip/Chip.variants.d.ts +6 -2
- package/lib/typescript/modules/chip/index.d.ts +1 -1
- package/lib/typescript/modules/combobox/Combobox.variants.d.ts +17 -4
- package/lib/typescript/modules/data-table/DataTable.variants.d.ts +1 -1
- package/lib/typescript/modules/date-picker/DatePicker.variants.d.ts +15 -3
- package/lib/typescript/modules/date-picker/TimePicker.d.ts +1 -7
- package/lib/typescript/modules/divider/Divider.variants.d.ts +4 -4
- package/lib/typescript/modules/empty-state/EmptyState.d.ts +2 -0
- package/lib/typescript/modules/empty-state/EmptyState.variants.d.ts +1 -0
- package/lib/typescript/modules/fab/Fab.variants.d.ts +2 -0
- package/lib/typescript/modules/folder-row/FolderRow.d.ts +0 -8
- package/lib/typescript/modules/gantt/Gantt.variants.d.ts +21 -0
- package/lib/typescript/modules/input/Input.variants.d.ts +6 -6
- package/lib/typescript/modules/list-item/ListItem.d.ts +1 -5
- package/lib/typescript/modules/list-item/ListItem.variants.d.ts +137 -1
- package/lib/typescript/modules/markdown/Markdown.d.ts +7 -0
- package/lib/typescript/modules/message-bubble/MessageBubble.d.ts +2 -2
- package/lib/typescript/modules/message-bubble/MessageBubble.variants.d.ts +1 -2
- package/lib/typescript/modules/number-input/NumberInput.variants.d.ts +7 -5
- package/lib/typescript/modules/pagination/PaginationControls.d.ts +1 -4
- package/lib/typescript/modules/reorder/Reorder.d.ts +1 -1
- package/lib/typescript/modules/screen/Screen.d.ts +3 -9
- package/lib/typescript/modules/screen/Screen.variants.d.ts +4 -0
- package/lib/typescript/modules/search-bar/SearchBar.variants.d.ts +6 -6
- package/lib/typescript/modules/section/Section.variants.d.ts +0 -3
- package/lib/typescript/modules/segmented-control/SegmentedControl.variants.d.ts +1 -1
- package/lib/typescript/modules/select/Select.d.ts +4 -1
- package/lib/typescript/modules/select/Select.variants.d.ts +22 -8
- package/lib/typescript/modules/select/index.d.ts +1 -1
- package/lib/typescript/modules/skeleton/Skeleton.d.ts +3 -18
- package/lib/typescript/modules/skeleton/Skeleton.variants.d.ts +12 -68
- package/lib/typescript/modules/stage-progress/StageProgress.variants.d.ts +15 -6
- package/lib/typescript/modules/state-block/StateBlock.d.ts +4 -0
- package/lib/typescript/modules/state-block/StateBlock.variants.d.ts +1 -0
- package/lib/typescript/modules/surface/Surface.d.ts +19 -0
- package/lib/typescript/modules/surface/Surface.variants.d.ts +15 -0
- package/lib/typescript/modules/surface/index.d.ts +4 -0
- package/lib/typescript/modules/text/Text.d.ts +8 -4
- package/lib/typescript/modules/text/Text.variants.d.ts +14 -11
- package/lib/typescript/modules/toast/Toast.variants.d.ts +2 -0
- package/lib/typescript/modules/tooltip/Tooltip.variants.d.ts +7 -0
- package/lib/typescript/theme/index.d.ts +1 -1
- package/lib/typescript/theme/platform/elevation.native.d.ts +0 -30
- package/lib/typescript/theme/platform/floatingSurface.native.d.ts +10 -0
- package/lib/typescript/theme/platform/highlight.native.d.ts +17 -0
- package/lib/typescript/theme/platform/index.d.ts +9 -0
- package/lib/typescript/theme/platform/motion.native.d.ts +33 -13
- package/lib/typescript/theme/platform/stateLayer.native.d.ts +11 -0
- package/lib/typescript/theme/platform/surfaces.native.d.ts +8 -0
- package/lib/typescript/theme/provider/PixelizeProvider.d.ts +1 -1
- package/lib/typescript/theme/provider/types.d.ts +8 -0
- package/lib/typescript/theme/tokens/assertPalette.d.ts +10 -0
- package/lib/typescript/theme/tokens/brands/emerald/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/brands/lavender/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/brands/meadow/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/brands/radiant/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/brands/rosewood/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/brands/skyline/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/brands/slate/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/brands/storefront/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/brands/zinc/palette.light.d.ts +4 -3
- package/lib/typescript/theme/tokens/builders/finalizePalette.d.ts +4 -0
- package/lib/typescript/theme/tokens/builders/liftToContrast.d.ts +9 -0
- package/lib/typescript/theme/tokens/builders/placeholderInk.d.ts +13 -0
- package/lib/typescript/theme/tokens/builders/semanticText.d.ts +4 -0
- package/lib/typescript/theme/tokens/builders/surfaceRungs.d.ts +12 -0
- package/lib/typescript/theme/tokens/index.d.ts +5 -0
- package/lib/typescript/theme/tokens/roles/index.d.ts +1 -0
- package/lib/typescript/theme/tokens/types.d.ts +8 -7
- package/package.json +10 -2
- package/registry.json +5 -0
|
@@ -15,28 +15,36 @@
|
|
|
15
15
|
|
|
16
16
|
import { cloneElement, memo, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
17
17
|
import { Animated, Modal, Platform, Pressable, ScrollView, StyleSheet, Text, View } from "react-native";
|
|
18
|
+
import Reanimated from "react-native-reanimated";
|
|
18
19
|
import { focusItemProps, useDismissOnEscape, useFocusTrap, useRovingKeys, useSpaceActivation } from "../../core/a11y/keyboard";
|
|
19
|
-
import { useMotion } from "../../core/motion/index.js";
|
|
20
|
+
import { MOTION_TRANSFORM, useAnimatedValue, useMotion } from "../../core/motion/index.js";
|
|
21
|
+
import { usePressState } from "../../core/motion/usePressState.js";
|
|
22
|
+
import { withAlpha } from "../../core/gradient/index.js";
|
|
20
23
|
import { Icon } from "../../core/icon/index.js";
|
|
21
24
|
import { VirtualList } from "../../core/list/index.js";
|
|
25
|
+
import { concentric } from "../../core/style/index.js";
|
|
26
|
+
import { elevation, floatingBackground, floatingSurfaceStyle, highlight } from "../../theme/platform/index.js";
|
|
27
|
+
import { elevation as elevationTokens } from "../../theme/tokens/primitives/index.js";
|
|
22
28
|
import { useTheme } from "../../theme/hooks.js";
|
|
23
29
|
import { ModalPortalContext } from "../modal/ModalPortalContext.js";
|
|
24
30
|
import { renderWebPortal } from "../modal/renderWebPortal";
|
|
25
|
-
import { MENU_ROW_ICON_SIZE, MENU_ROW_MIN_HEIGHT, menuOverlayStructure, menuRowStructure, menuSheetStructure, resolveMenuItemColor
|
|
31
|
+
import { MENU_ROW_ICON_SIZE, MENU_ROW_MIN_HEIGHT, menuOverlayStructure, menuRowStructure, menuSheetStructure, resolveMenuItemColor } from "./Menu.variants.js";
|
|
26
32
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
27
33
|
const VIRTUALIZE_THRESHOLD = 15;
|
|
28
34
|
const ICON_STROKE = 2;
|
|
29
|
-
|
|
35
|
+
// Opacity is the shared `scrimOpacity` knob, not a locally-guessed hex — matches Modal/Drawer/BottomSheet.
|
|
36
|
+
const BACKDROP_SCRIM = withAlpha("#000000", MOTION_TRANSFORM.scrimOpacity);
|
|
37
|
+
const AnimatedPressable = Reanimated.createAnimatedComponent(Pressable);
|
|
30
38
|
const MenuRow = /*#__PURE__*/memo(function MenuRow({
|
|
31
39
|
item,
|
|
32
40
|
index,
|
|
33
41
|
tabIndex,
|
|
34
42
|
theme,
|
|
35
|
-
pressedRowBg,
|
|
36
43
|
onSelect,
|
|
37
44
|
testID
|
|
38
45
|
}) {
|
|
39
46
|
const color = resolveMenuItemColor(theme.colors, item.tone ?? "default");
|
|
47
|
+
const press = usePressState(false);
|
|
40
48
|
const handlePress = useCallback(() => onSelect(item), [onSelect, item]);
|
|
41
49
|
const rowRef = useRef(null);
|
|
42
50
|
const active = tabIndex === 0;
|
|
@@ -50,24 +58,33 @@ const MenuRow = /*#__PURE__*/memo(function MenuRow({
|
|
|
50
58
|
|
|
51
59
|
// `menuitem` is not `button`, so RNW never presses on Space — see `core/a11y/keyboard.web.ts`.
|
|
52
60
|
useSpaceActivation(rowRef, handlePress);
|
|
53
|
-
const rowStyle =
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
|
|
61
|
+
const rowStyle = useMemo(() => [menuRowStructure(theme), {
|
|
62
|
+
overflow: "hidden"
|
|
63
|
+
}, press.animatedStyle], [theme, press.animatedStyle]);
|
|
64
|
+
const overlayStaticStyle = useMemo(() => ({
|
|
65
|
+
backgroundColor: theme.mode === "dark" ? "#ffffff" : "#000000",
|
|
66
|
+
borderRadius: concentric(theme.radii.lg, theme.space[4]),
|
|
67
|
+
borderCurve: "continuous"
|
|
68
|
+
}), [theme.mode, theme.radii.lg, theme.space]);
|
|
58
69
|
const labelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.regular), {
|
|
59
70
|
flex: 1,
|
|
60
71
|
fontSize: theme.fontSizes.md,
|
|
61
72
|
color
|
|
62
73
|
}], [theme, color]);
|
|
63
|
-
return /*#__PURE__*/_jsxs(
|
|
74
|
+
return /*#__PURE__*/_jsxs(AnimatedPressable, {
|
|
64
75
|
ref: rowRef,
|
|
65
76
|
testID: testID ? `${testID}-item-${index}` : undefined,
|
|
66
77
|
accessibilityRole: "menuitem",
|
|
67
78
|
tabIndex: tabIndex,
|
|
68
79
|
onPress: handlePress,
|
|
80
|
+
onPressIn: press.handlers.onPressIn,
|
|
81
|
+
onPressOut: press.handlers.onPressOut,
|
|
82
|
+
onLayout: press.onLayout,
|
|
69
83
|
style: rowStyle,
|
|
70
|
-
children: [
|
|
84
|
+
children: [/*#__PURE__*/_jsx(Reanimated.View, {
|
|
85
|
+
pointerEvents: "none",
|
|
86
|
+
style: [StyleSheet.absoluteFill, overlayStaticStyle, press.overlayStyle]
|
|
87
|
+
}), item.icon !== undefined && /*#__PURE__*/_jsx(Icon, {
|
|
71
88
|
name: item.icon,
|
|
72
89
|
size: MENU_ROW_ICON_SIZE,
|
|
73
90
|
color: color,
|
|
@@ -89,28 +106,59 @@ export const Menu = /*#__PURE__*/memo(function Menu({
|
|
|
89
106
|
const motion = useMotion();
|
|
90
107
|
const portalContainer = useContext(ModalPortalContext);
|
|
91
108
|
const [open, setOpen] = useState(false);
|
|
109
|
+
const [mounted, setMounted] = useState(false);
|
|
110
|
+
const mountedRef = useRef(mounted);
|
|
111
|
+
mountedRef.current = mounted;
|
|
92
112
|
const [activeIndex, setActiveIndex] = useState(0);
|
|
93
113
|
const sheetRef = useRef(null);
|
|
94
|
-
const enter =
|
|
95
|
-
const
|
|
114
|
+
const enter = useAnimatedValue(0);
|
|
115
|
+
const running = useRef(null);
|
|
116
|
+
const unmountTimer = useRef(null);
|
|
96
117
|
useEffect(() => {
|
|
97
|
-
|
|
98
|
-
|
|
118
|
+
const clearUnmount = () => {
|
|
119
|
+
if (unmountTimer.current !== null) {
|
|
120
|
+
clearTimeout(unmountTimer.current);
|
|
121
|
+
unmountTimer.current = null;
|
|
122
|
+
}
|
|
123
|
+
};
|
|
124
|
+
running.current?.stop();
|
|
125
|
+
clearUnmount();
|
|
126
|
+
if (open) {
|
|
127
|
+
setMounted(true);
|
|
128
|
+
if (!motion.enabled) {
|
|
129
|
+
enter.setValue(1);
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
99
132
|
enter.setValue(0);
|
|
133
|
+
running.current = motion.timing(enter, 1, {
|
|
134
|
+
duration: "fast",
|
|
135
|
+
easing: "decelerate"
|
|
136
|
+
});
|
|
137
|
+
running.current.start();
|
|
100
138
|
return;
|
|
101
139
|
}
|
|
102
|
-
if (!
|
|
103
|
-
|
|
140
|
+
if (!mountedRef.current) return;
|
|
141
|
+
const exitMs = motion.duration("fast");
|
|
142
|
+
if (!motion.enabled || exitMs === 0) {
|
|
143
|
+
enter.setValue(0);
|
|
144
|
+
setMounted(false);
|
|
104
145
|
return;
|
|
105
146
|
}
|
|
106
|
-
|
|
107
|
-
entering.current = motion.timing(enter, 1, {
|
|
147
|
+
running.current = motion.timing(enter, 0, {
|
|
108
148
|
duration: "fast",
|
|
109
|
-
easing: "
|
|
149
|
+
easing: "accelerate"
|
|
110
150
|
});
|
|
111
|
-
|
|
151
|
+
running.current.start();
|
|
152
|
+
unmountTimer.current = setTimeout(() => {
|
|
153
|
+
unmountTimer.current = null;
|
|
154
|
+
setMounted(false);
|
|
155
|
+
}, exitMs);
|
|
156
|
+
return clearUnmount;
|
|
112
157
|
}, [open, motion, enter]);
|
|
113
|
-
useEffect(() => () =>
|
|
158
|
+
useEffect(() => () => {
|
|
159
|
+
running.current?.stop();
|
|
160
|
+
if (unmountTimer.current !== null) clearTimeout(unmountTimer.current);
|
|
161
|
+
}, []);
|
|
114
162
|
const openMenu = useCallback(() => {
|
|
115
163
|
if (disabled) return;
|
|
116
164
|
setActiveIndex(0);
|
|
@@ -141,7 +189,6 @@ export const Menu = /*#__PURE__*/memo(function Menu({
|
|
|
141
189
|
const clonedTrigger = /*#__PURE__*/cloneElement(trigger, {
|
|
142
190
|
onPress: handleTriggerPress
|
|
143
191
|
});
|
|
144
|
-
const pressedRowBg = useMemo(() => resolveMenuRowPressedBackground(theme.colors), [theme.colors]);
|
|
145
192
|
const keyExtractor = useCallback((item, index) => `${item.label}-${index}`, []);
|
|
146
193
|
const renderItem = useCallback(({
|
|
147
194
|
item,
|
|
@@ -151,12 +198,20 @@ export const Menu = /*#__PURE__*/memo(function Menu({
|
|
|
151
198
|
index: index,
|
|
152
199
|
tabIndex: focusItemProps(index, activeIndex).tabIndex,
|
|
153
200
|
theme: theme,
|
|
154
|
-
pressedRowBg: pressedRowBg,
|
|
155
201
|
onSelect: selectItem,
|
|
156
202
|
testID: testID
|
|
157
|
-
}), [activeIndex, theme,
|
|
158
|
-
const
|
|
159
|
-
|
|
203
|
+
}), [activeIndex, theme, selectItem, testID]);
|
|
204
|
+
const floatingStyle = useMemo(() => {
|
|
205
|
+
highlight("subtle", theme.mode);
|
|
206
|
+
elevation(elevationTokens.md);
|
|
207
|
+
void theme.elevatedSurfaces;
|
|
208
|
+
return {
|
|
209
|
+
backgroundColor: floatingBackground(theme, "md"),
|
|
210
|
+
...floatingSurfaceStyle(theme, "md")
|
|
211
|
+
};
|
|
212
|
+
}, [theme]);
|
|
213
|
+
const sheetStyle = useMemo(() => [menuSheetStructure(theme), floatingStyle, {
|
|
214
|
+
opacity: enter,
|
|
160
215
|
transform: [{
|
|
161
216
|
scale: enter.interpolate({
|
|
162
217
|
inputRange: [0, 1],
|
|
@@ -168,27 +223,30 @@ export const Menu = /*#__PURE__*/memo(function Menu({
|
|
|
168
223
|
outputRange: [motion.transform.offsetY, 0]
|
|
169
224
|
})
|
|
170
225
|
}]
|
|
171
|
-
}], [theme, enter, motion.transform.pressScale, motion.transform.offsetY]);
|
|
226
|
+
}], [theme, floatingStyle, enter, motion.transform.pressScale, motion.transform.offsetY]);
|
|
227
|
+
const backdropStyle = useMemo(() => [styles.backdrop, {
|
|
228
|
+
opacity: enter
|
|
229
|
+
}], [enter]);
|
|
172
230
|
|
|
173
|
-
// Built only while
|
|
174
|
-
// of the screen that hosts it.
|
|
175
|
-
const sheet =
|
|
231
|
+
// Built only while mounted: a closed, settled Menu must not materialize one element per item on
|
|
232
|
+
// every render of the screen that hosts it.
|
|
233
|
+
const sheet = mounted ? /*#__PURE__*/_jsxs(_Fragment, {
|
|
176
234
|
children: [/*#__PURE__*/_jsx(Pressable, {
|
|
177
235
|
testID: testID ? `${testID}-backdrop` : undefined,
|
|
178
236
|
accessible: false,
|
|
179
237
|
tabIndex: -1,
|
|
180
|
-
style:
|
|
181
|
-
onPress: closeMenu
|
|
238
|
+
style: StyleSheet.absoluteFill,
|
|
239
|
+
onPress: closeMenu,
|
|
240
|
+
children: /*#__PURE__*/_jsx(Animated.View, {
|
|
241
|
+
pointerEvents: "none",
|
|
242
|
+
style: backdropStyle
|
|
243
|
+
})
|
|
182
244
|
}), /*#__PURE__*/_jsx(View, {
|
|
183
245
|
style: menuOverlayStructure(theme),
|
|
184
246
|
pointerEvents: "box-none",
|
|
185
247
|
children: /*#__PURE__*/_jsx(Animated.View, {
|
|
186
248
|
ref: sheetRef,
|
|
187
|
-
testID: testID ? `${testID}-sheet` : undefined
|
|
188
|
-
// The container role the `menuitem` rows below need, plus the modal semantics every other
|
|
189
|
-
// overlay in this library gives its panel. Declared HERE, before the portal branch, so the
|
|
190
|
-
// web-portal path — which renders no RN `<Modal>` at all — inherits them too.
|
|
191
|
-
,
|
|
249
|
+
testID: testID ? `${testID}-sheet` : undefined,
|
|
192
250
|
accessibilityRole: "menu",
|
|
193
251
|
accessibilityViewIsModal: true,
|
|
194
252
|
onAccessibilityEscape: closeMenu,
|
|
@@ -205,7 +263,6 @@ export const Menu = /*#__PURE__*/memo(function Menu({
|
|
|
205
263
|
index: index,
|
|
206
264
|
tabIndex: focusItemProps(index, activeIndex).tabIndex,
|
|
207
265
|
theme: theme,
|
|
208
|
-
pressedRowBg: pressedRowBg,
|
|
209
266
|
onSelect: selectItem,
|
|
210
267
|
testID: testID
|
|
211
268
|
}, `${item.label}-${index}`))
|
|
@@ -213,13 +270,15 @@ export const Menu = /*#__PURE__*/memo(function Menu({
|
|
|
213
270
|
})
|
|
214
271
|
})]
|
|
215
272
|
}) : null;
|
|
216
|
-
const menu = Platform.OS === "web" && portalContainer != null ?
|
|
273
|
+
const menu = Platform.OS === "web" && portalContainer != null ? mounted ? renderWebPortal(/*#__PURE__*/_jsx(View, {
|
|
217
274
|
style: StyleSheet.absoluteFill,
|
|
218
275
|
pointerEvents: "box-none",
|
|
219
276
|
children: sheet
|
|
220
277
|
}), portalContainer) : null : /*#__PURE__*/_jsx(Modal, {
|
|
221
278
|
visible: open,
|
|
222
279
|
transparent: true,
|
|
280
|
+
statusBarTranslucent: true,
|
|
281
|
+
navigationBarTranslucent: true,
|
|
223
282
|
animationType: motion.enabled ? "fade" : "none",
|
|
224
283
|
onRequestClose: closeMenu,
|
|
225
284
|
children: sheet
|
|
@@ -67,10 +67,10 @@ export const menuOverlayStructure = createThemedVariants(theme => ({
|
|
|
67
67
|
}));
|
|
68
68
|
export const menuSheetStructure = createThemedVariants(theme => ({
|
|
69
69
|
base: {
|
|
70
|
-
borderRadius: theme.radii.
|
|
70
|
+
borderRadius: theme.radii.lg,
|
|
71
|
+
borderCurve: "continuous",
|
|
71
72
|
paddingVertical: theme.space[2],
|
|
72
|
-
maxHeight: 320
|
|
73
|
-
...theme.elevation.lg
|
|
73
|
+
maxHeight: 320
|
|
74
74
|
}
|
|
75
75
|
}));
|
|
76
76
|
export const menuRowStructure = createThemedVariants(theme => ({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# message-bubble/
|
|
2
2
|
|
|
3
|
-
Single chat bubble — `user` (accent) or `assistant` (surface
|
|
3
|
+
Single chat bubble — `user` (accent) or `assistant` (tonal surface). Plain `content` string.
|
|
4
4
|
|
|
5
5
|
## Motion contract
|
|
6
6
|
|
|
@@ -36,3 +36,6 @@ mean a new prop — not added speculatively.
|
|
|
36
36
|
| `content` | `string` | — |
|
|
37
37
|
| `style` | `LayoutStyle` | — |
|
|
38
38
|
| `testID` | `string` | — |
|
|
39
|
+
|
|
40
|
+
- **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
|
|
41
|
+
- **Round 5 tonal** — assistant's `borderWidth.thin` hairline dropped; `bg.surface` alone now separates the bubble from its parent by tone, matching `Card`'s borderless-flat precedent.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* MessageBubble — a single chat turn bubble. User variant uses accent fill; assistant uses
|
|
5
|
-
*
|
|
4
|
+
* MessageBubble — a single chat turn bubble. User variant uses accent fill; assistant uses a tonal
|
|
5
|
+
* surface fill, no border. Plain-text `content` only (rich assistant replies compose Markdown/RichText
|
|
6
6
|
* upstream).
|
|
7
7
|
*
|
|
8
8
|
* The accessible label names the sender ("You" / "Assistant") ahead of the content: alignment and
|
|
@@ -32,9 +32,8 @@ export const MessageBubble = /*#__PURE__*/memo(function MessageBubble({
|
|
|
32
32
|
const bubbleStyle = useMemo(() => [messageBubbleStructure(theme, {
|
|
33
33
|
variant
|
|
34
34
|
}), {
|
|
35
|
-
backgroundColor: colors.background
|
|
36
|
-
|
|
37
|
-
}, style], [theme, variant, colors.background, colors.border, style]);
|
|
35
|
+
backgroundColor: colors.background
|
|
36
|
+
}, style], [theme, variant, colors.background, style]);
|
|
38
37
|
const textStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.regular), {
|
|
39
38
|
fontSize: theme.fontSizes.md,
|
|
40
39
|
lineHeight: theme.fontSizes.md * 1.45,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
import { createThemedVariants } from "../../core/style/index.js";
|
|
4
|
+
/** Assistant separates from the canvas by tone (`bg.surface`) alone now — no hairline border. */
|
|
4
5
|
export function resolveMessageBubbleColors(colors, variant) {
|
|
5
6
|
if (variant === "user") {
|
|
6
7
|
return {
|
|
@@ -10,8 +11,7 @@ export function resolveMessageBubbleColors(colors, variant) {
|
|
|
10
11
|
}
|
|
11
12
|
return {
|
|
12
13
|
background: colors.bg.surface,
|
|
13
|
-
text: colors.fg.default
|
|
14
|
-
border: colors.border.default
|
|
14
|
+
text: colors.fg.default
|
|
15
15
|
};
|
|
16
16
|
}
|
|
17
17
|
export const messageBubbleStructure = createThemedVariants(theme => ({
|
|
@@ -19,7 +19,8 @@ export const messageBubbleStructure = createThemedVariants(theme => ({
|
|
|
19
19
|
maxWidth: "85%",
|
|
20
20
|
paddingHorizontal: theme.space[3],
|
|
21
21
|
paddingVertical: theme.space[2],
|
|
22
|
-
borderRadius: theme.radii.lg
|
|
22
|
+
borderRadius: theme.radii.lg,
|
|
23
|
+
borderCurve: "continuous"
|
|
23
24
|
},
|
|
24
25
|
variants: {
|
|
25
26
|
variant: {
|
|
@@ -29,8 +30,7 @@ export const messageBubbleStructure = createThemedVariants(theme => ({
|
|
|
29
30
|
},
|
|
30
31
|
assistant: {
|
|
31
32
|
alignSelf: "flex-start",
|
|
32
|
-
borderBottomLeftRadius: theme.radii.sm
|
|
33
|
-
borderWidth: theme.borderWidths.thin
|
|
33
|
+
borderBottomLeftRadius: theme.radii.sm
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
},
|
|
@@ -135,6 +135,14 @@ none of them contains keyboard code, and each has a test asserting the inheritan
|
|
|
135
135
|
4. **Closed `size` union** reusing the shared `sizes` primitive (384/448/512dp) instead of
|
|
136
136
|
Modal-local numbers — `theme/tokens/primitives/sizes.ts` is documented for exactly this case.
|
|
137
137
|
|
|
138
|
+
## Android edge-to-edge
|
|
139
|
+
|
|
140
|
+
Every RN `<Modal transparent>` in this library (`Modal`, `Select`, `MultiSelect`, `Combobox`,
|
|
141
|
+
`Menu`, `OrgSwitcher`, `PickerShell`, `Drawer`) also sets `statusBarTranslucent` and
|
|
142
|
+
`navigationBarTranslucent`, both `true`. Without them, Android edge-to-edge (Expo default since
|
|
143
|
+
SDK 53) paints the modal's backing window opaque instead of transparent — the whole screen goes
|
|
144
|
+
solid white on open. Add both any time a new module renders its own RN `<Modal transparent>`.
|
|
145
|
+
|
|
138
146
|
## Known gaps
|
|
139
147
|
|
|
140
148
|
- **No full SCREEN-READER trap.** iOS gets `accessibilityViewIsModal` (constrains VoiceOver to the
|
|
@@ -162,3 +170,6 @@ Both `Modal` and `ModalPortalProvider` are wrapped in `React.memo` (repo-wide re
|
|
|
162
170
|
- Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
|
|
163
171
|
- List-heavy surfaces use `VirtualList` with device-tier window sizing where applicable.
|
|
164
172
|
- `React.memo` + stable callbacks retained; render-item/key-extractor hoisted per ESLint perf rules.
|
|
173
|
+
|
|
174
|
+
- **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
|
|
175
|
+
- **Round 5 motion** — dropped the ad hoc reanimated `FadeInDown`/`FadeOut` layer; the panel's own `enter` value now drives backdrop opacity too, so scrim fade and panel slide+fade are one gesture on both the RNModal and web-portal paths. The portal branch now tracks `mounted` through a real timed exit instead of unmounting instantly. `MODAL_BACKDROP`'s opacity comes from `MOTION_TRANSFORM.scrimOpacity`.
|
|
@@ -33,19 +33,22 @@
|
|
|
33
33
|
* which is where all three silently went missing.
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
|
-
import { memo, useContext, useEffect, useMemo, useRef } from "react";
|
|
37
|
-
import { Animated, Modal as RNModal, Platform, Pressable, StyleSheet,
|
|
36
|
+
import { memo, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
37
|
+
import { Animated, Modal as RNModal, Platform, Pressable, StyleSheet, View } from "react-native";
|
|
38
38
|
import { useDismissOnEscape, useFocusTrap } from "../../core/a11y/keyboard";
|
|
39
|
-
import { useAnimatedValue, useMotion } from "../../core/motion/index.js";
|
|
39
|
+
import { MOTION_TRANSFORM, useAnimatedValue, useMotion } from "../../core/motion/index.js";
|
|
40
|
+
import { withAlpha } from "../../core/gradient/index.js";
|
|
41
|
+
import { elevation, floatingBackground, floatingSurfaceStyle, highlight } from "../../theme/platform/index.js";
|
|
42
|
+
import { elevation as elevationTokens } from "../../theme/tokens/primitives/index.js";
|
|
40
43
|
import { useTheme } from "../../theme/hooks.js";
|
|
44
|
+
import { Heading } from "../text/index.js";
|
|
41
45
|
import { ModalPortalContext } from "./ModalPortalContext.js";
|
|
42
46
|
import { renderWebPortal } from "./renderWebPortal";
|
|
43
|
-
import { modalOverlayStructure, modalPanelStructure, resolveModalAnimationType
|
|
47
|
+
import { modalOverlayStructure, modalPanelStructure, resolveModalAnimationType } from "./Modal.variants.js";
|
|
44
48
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
45
|
-
// Decorative dismiss scrim
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
const MODAL_BACKDROP = "#00000080";
|
|
49
|
+
// Decorative dismiss scrim, not a role token — same reasoning Button's PRESS_SCRIM and Select's
|
|
50
|
+
// BACKDROP_SCRIM record. Opacity is the shared `scrimOpacity` knob, not a locally-guessed hex.
|
|
51
|
+
const MODAL_BACKDROP = withAlpha("#000000", MOTION_TRANSFORM.scrimOpacity);
|
|
49
52
|
export const Modal = /*#__PURE__*/memo(function Modal({
|
|
50
53
|
visible,
|
|
51
54
|
onRequestClose,
|
|
@@ -56,54 +59,105 @@ export const Modal = /*#__PURE__*/memo(function Modal({
|
|
|
56
59
|
}) {
|
|
57
60
|
const theme = useTheme();
|
|
58
61
|
const motion = useMotion();
|
|
59
|
-
const panelColors = useMemo(() => resolveModalPanelColors(theme.colors), [theme.colors]);
|
|
60
62
|
const portalContainer = useContext(ModalPortalContext);
|
|
61
63
|
const panelRef = useRef(null);
|
|
62
64
|
const portalled = Platform.OS === "web" && portalContainer != null;
|
|
63
65
|
useDismissOnEscape(portalled && visible, onRequestClose);
|
|
64
66
|
useFocusTrap(panelRef, portalled && visible);
|
|
67
|
+
|
|
68
|
+
// `mounted` only gates the web-portal render below — the RNModal branch keeps handing `visible`
|
|
69
|
+
// straight to RN's own <Modal>, which still owns that surface's native fade in and out.
|
|
70
|
+
const [mounted, setMounted] = useState(visible);
|
|
71
|
+
const mountedRef = useRef(mounted);
|
|
72
|
+
mountedRef.current = mounted;
|
|
65
73
|
const enter = useAnimatedValue(visible ? 1 : 0);
|
|
66
|
-
const
|
|
74
|
+
const running = useRef(null);
|
|
75
|
+
const unmountTimer = useRef(null);
|
|
67
76
|
useEffect(() => {
|
|
68
|
-
|
|
69
|
-
|
|
77
|
+
const clearUnmount = () => {
|
|
78
|
+
if (unmountTimer.current !== null) {
|
|
79
|
+
clearTimeout(unmountTimer.current);
|
|
80
|
+
unmountTimer.current = null;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
running.current?.stop();
|
|
84
|
+
clearUnmount();
|
|
85
|
+
if (visible) {
|
|
86
|
+
setMounted(true);
|
|
87
|
+
if (!motion.enabled) {
|
|
88
|
+
enter.setValue(1);
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
70
91
|
enter.setValue(0);
|
|
92
|
+
running.current = motion.timing(enter, 1, {
|
|
93
|
+
easing: "decelerate"
|
|
94
|
+
});
|
|
95
|
+
running.current.start();
|
|
71
96
|
return;
|
|
72
97
|
}
|
|
73
|
-
if (!
|
|
74
|
-
|
|
98
|
+
if (!mountedRef.current) return;
|
|
99
|
+
const exitMs = motion.duration("fast");
|
|
100
|
+
if (!motion.enabled || exitMs === 0) {
|
|
101
|
+
enter.setValue(0);
|
|
102
|
+
setMounted(false);
|
|
75
103
|
return;
|
|
76
104
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
easing: "
|
|
105
|
+
running.current = motion.timing(enter, 0, {
|
|
106
|
+
duration: "fast",
|
|
107
|
+
easing: "accelerate"
|
|
80
108
|
});
|
|
81
|
-
|
|
109
|
+
running.current.start();
|
|
110
|
+
unmountTimer.current = setTimeout(() => {
|
|
111
|
+
unmountTimer.current = null;
|
|
112
|
+
setMounted(false);
|
|
113
|
+
}, exitMs);
|
|
114
|
+
return clearUnmount;
|
|
82
115
|
}, [visible, motion, enter]);
|
|
83
|
-
useEffect(() => () =>
|
|
116
|
+
useEffect(() => () => {
|
|
117
|
+
running.current?.stop();
|
|
118
|
+
if (unmountTimer.current !== null) clearTimeout(unmountTimer.current);
|
|
119
|
+
}, []);
|
|
120
|
+
const floatingStyle = useMemo(() => {
|
|
121
|
+
highlight("subtle", theme.mode);
|
|
122
|
+
elevation(elevationTokens.lg);
|
|
123
|
+
void theme.elevatedSurfaces;
|
|
124
|
+
return {
|
|
125
|
+
backgroundColor: floatingBackground(theme, "lg"),
|
|
126
|
+
...floatingSurfaceStyle(theme, "lg")
|
|
127
|
+
};
|
|
128
|
+
}, [theme]);
|
|
84
129
|
const panelStyle = useMemo(() => [modalPanelStructure(theme, {
|
|
85
130
|
size
|
|
86
|
-
}), {
|
|
87
|
-
|
|
131
|
+
}), floatingStyle, {
|
|
132
|
+
opacity: enter,
|
|
88
133
|
transform: [{
|
|
89
134
|
translateY: enter.interpolate({
|
|
90
135
|
inputRange: [0, 1],
|
|
91
136
|
outputRange: [motion.transform.offsetY, 0]
|
|
92
137
|
})
|
|
93
138
|
}]
|
|
94
|
-
}], [theme, size,
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
139
|
+
}], [theme, size, floatingStyle, enter, motion.transform.offsetY]);
|
|
140
|
+
const backdropStyle = useMemo(() => [styles.backdrop, {
|
|
141
|
+
opacity: enter
|
|
142
|
+
}], [enter]);
|
|
143
|
+
const titleBlock = title !== undefined ? /*#__PURE__*/_jsx(Heading, {
|
|
144
|
+
variant: "h3",
|
|
145
|
+
style: {
|
|
146
|
+
marginBottom: theme.space[3]
|
|
147
|
+
},
|
|
148
|
+
children: title
|
|
149
|
+
}) : null;
|
|
100
150
|
const overlay = /*#__PURE__*/_jsxs(_Fragment, {
|
|
101
151
|
children: [/*#__PURE__*/_jsx(Pressable, {
|
|
102
152
|
testID: testID ? `${testID}-backdrop` : undefined,
|
|
103
153
|
accessible: false,
|
|
104
154
|
tabIndex: -1,
|
|
105
|
-
style:
|
|
106
|
-
onPress: onRequestClose
|
|
155
|
+
style: StyleSheet.absoluteFill,
|
|
156
|
+
onPress: onRequestClose,
|
|
157
|
+
children: /*#__PURE__*/_jsx(Animated.View, {
|
|
158
|
+
pointerEvents: "none",
|
|
159
|
+
style: backdropStyle
|
|
160
|
+
})
|
|
107
161
|
}), /*#__PURE__*/_jsx(View, {
|
|
108
162
|
style: modalOverlayStructure(theme),
|
|
109
163
|
pointerEvents: "box-none",
|
|
@@ -113,16 +167,12 @@ export const Modal = /*#__PURE__*/memo(function Modal({
|
|
|
113
167
|
accessibilityViewIsModal: true,
|
|
114
168
|
onAccessibilityEscape: onRequestClose,
|
|
115
169
|
style: panelStyle,
|
|
116
|
-
children: [
|
|
117
|
-
accessibilityRole: "header",
|
|
118
|
-
style: titleStyle,
|
|
119
|
-
children: title
|
|
120
|
-
}), children]
|
|
170
|
+
children: [titleBlock, children]
|
|
121
171
|
})
|
|
122
172
|
})]
|
|
123
173
|
});
|
|
124
174
|
if (portalled) {
|
|
125
|
-
if (!
|
|
175
|
+
if (!mounted) return null;
|
|
126
176
|
// RN's own <Modal> supplies a `position: fixed`/full-screen ancestor for `overlay`'s children
|
|
127
177
|
// to size against (see ModalPortalContext.ts) — reproduce just that sizing here (never touching
|
|
128
178
|
// the shared `modalOverlayStructure`/`modalPanelStructure` resolvers the RNModal path below
|
|
@@ -137,6 +187,8 @@ export const Modal = /*#__PURE__*/memo(function Modal({
|
|
|
137
187
|
return /*#__PURE__*/_jsx(RNModal, {
|
|
138
188
|
visible: visible,
|
|
139
189
|
transparent: true,
|
|
190
|
+
statusBarTranslucent: true,
|
|
191
|
+
navigationBarTranslucent: true,
|
|
140
192
|
animationType: resolveModalAnimationType(!motion.enabled),
|
|
141
193
|
onRequestClose: onRequestClose,
|
|
142
194
|
children: overlay
|
|
@@ -69,8 +69,8 @@ export const modalPanelStructure = createThemedVariants(theme => ({
|
|
|
69
69
|
width: "100%",
|
|
70
70
|
maxHeight: "92%",
|
|
71
71
|
borderRadius: theme.radii.lg,
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
borderCurve: "continuous",
|
|
73
|
+
padding: theme.space[5]
|
|
74
74
|
},
|
|
75
75
|
variants: {
|
|
76
76
|
size: {
|
|
@@ -34,6 +34,9 @@ Renders `null` when the count is ≤0 and there is no `triggerText` — nothing
|
|
|
34
34
|
- **Touch target (WCAG 2.5.5 / 2.5.8)** — the trigger carries `minHeight: 44` (this library's
|
|
35
35
|
floor). It is a standalone node with no neighbouring target to overlap, so the floor is real
|
|
36
36
|
height via `minHeight`, not `hitSlop` expansion the way `Button`'s shorter sizes reach it.
|
|
37
|
+
- **Android touch feedback** — the trigger carries `android_ripple` (`rippleColor(theme.mode)`,
|
|
38
|
+
`borderless: false`), gated on `Platform.OS === "android"`. The scrim `Pressable` gets none — it is
|
|
39
|
+
the same `accessible={false}` decoy described under Modal semantics below, not a real press target.
|
|
37
40
|
- **Label in Name (WCAG 2.5.3)** — the accessible name is built to CONTAIN the visible text
|
|
38
41
|
(`"${triggerText} +${count} more"`, or just `"+${count} more"` with no leading text), not a
|
|
39
42
|
separately-worded `"${count} more items"`. Voice control says what it reads; the old name shared no
|
|
@@ -70,3 +73,5 @@ Renders `null` when the count is ≤0 and there is no `triggerText` — nothing
|
|
|
70
73
|
|
|
71
74
|
- Rows are display-only — no press/selection. A selectable overflow list would be a different
|
|
72
75
|
component (`Select`/`Menu`), not a prop added here.
|
|
76
|
+
|
|
77
|
+
- **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
|
|
@@ -5,10 +5,11 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import { memo, useCallback, useMemo, useState } from "react";
|
|
8
|
-
import { Animated, Modal, Pressable, StyleSheet, Text, View } from "react-native";
|
|
8
|
+
import { Animated, Modal, Platform, Pressable, StyleSheet, Text, View } from "react-native";
|
|
9
9
|
import { VirtualList } from "../../core/list/index.js";
|
|
10
10
|
import { useEnterExit, usePressMotion } from "../../core/motion/index.js";
|
|
11
11
|
import { useTheme } from "../../theme/hooks.js";
|
|
12
|
+
import { rippleColor } from "../../theme/platform/stateLayer.native.js";
|
|
12
13
|
import { moreItemsBadgeStructure, moreItemsDotStructure, moreItemsOverlayStructure, moreItemsRowStructure, moreItemsSheetStructure, moreItemsTriggerContentStructure, moreItemsTriggerStructure, resolveMoreItemsCount, resolveMoreItemsDotColor } from "./MoreItems.variants.js";
|
|
13
14
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
14
15
|
const BACKDROP = "#00000080";
|
|
@@ -72,6 +73,10 @@ export const MoreItems = /*#__PURE__*/memo(function MoreItems({
|
|
|
72
73
|
backgroundColor: theme.colors.accent.subtle
|
|
73
74
|
}], [theme]);
|
|
74
75
|
const overlayStructure = useMemo(() => moreItemsOverlayStructure(theme), [theme]);
|
|
76
|
+
const androidRipple = useMemo(() => Platform.OS === "android" ? {
|
|
77
|
+
color: rippleColor(theme.mode),
|
|
78
|
+
borderless: false
|
|
79
|
+
} : undefined, [theme.mode]);
|
|
75
80
|
const sheetStyle = useMemo(() => [moreItemsSheetStructure(theme), {
|
|
76
81
|
backgroundColor: theme.colors.bg.surface
|
|
77
82
|
}], [theme]);
|
|
@@ -102,6 +107,7 @@ export const MoreItems = /*#__PURE__*/memo(function MoreItems({
|
|
|
102
107
|
onPress: openSheet,
|
|
103
108
|
onPressIn: press.onPressIn,
|
|
104
109
|
onPressOut: press.onPressOut,
|
|
110
|
+
android_ripple: androidRipple,
|
|
105
111
|
style: triggerStyle,
|
|
106
112
|
children: /*#__PURE__*/_jsxs(Animated.View, {
|
|
107
113
|
style: [triggerContentStructure, press.style],
|
|
@@ -48,7 +48,8 @@ export const moreItemsDotStructure = createThemedVariants(theme => ({
|
|
|
48
48
|
base: {
|
|
49
49
|
width: MORE_ITEMS_DOT_SIZE,
|
|
50
50
|
height: MORE_ITEMS_DOT_SIZE,
|
|
51
|
-
borderRadius: theme.radii.full
|
|
51
|
+
borderRadius: theme.radii.full,
|
|
52
|
+
borderCurve: "continuous"
|
|
52
53
|
}
|
|
53
54
|
}));
|
|
54
55
|
export const moreItemsOverlayStructure = createThemedVariants(theme => ({
|
|
@@ -61,6 +62,7 @@ export const moreItemsOverlayStructure = createThemedVariants(theme => ({
|
|
|
61
62
|
export const moreItemsSheetStructure = createThemedVariants(theme => ({
|
|
62
63
|
base: {
|
|
63
64
|
borderRadius: theme.radii.lg,
|
|
65
|
+
borderCurve: "continuous",
|
|
64
66
|
padding: theme.space[3],
|
|
65
67
|
maxHeight: MORE_ITEMS_SHEET_MAX_HEIGHT
|
|
66
68
|
}
|
|
@@ -71,6 +73,7 @@ export const moreItemsBadgeStructure = createThemedVariants(theme => ({
|
|
|
71
73
|
paddingHorizontal: theme.space[2],
|
|
72
74
|
paddingVertical: 2,
|
|
73
75
|
borderRadius: theme.radii.full,
|
|
76
|
+
borderCurve: "continuous",
|
|
74
77
|
fontSize: theme.fontSizes.xs
|
|
75
78
|
}
|
|
76
79
|
}));
|
|
@@ -164,3 +164,8 @@ Via `core/motion` only — `opacity`/`transform`, native driver, all reduce-moti
|
|
|
164
164
|
|
|
165
165
|
- Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
|
|
166
166
|
- List-heavy surfaces use `VirtualList` with device-tier window sizing where applicable.
|
|
167
|
+
|
|
168
|
+
- **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
|
|
169
|
+
- **Round 5 (Android parity)** — `android_ripple` (`borderless: false`) added to the trigger (gated
|
|
170
|
+
`!disabled`), the header close button, and each option row. The trigger and close button also
|
|
171
|
+
gained `overflow: "hidden"` so their ripple clips to their shape.
|