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
|
@@ -25,16 +25,16 @@ const slopFor = height => Math.max(0, Math.ceil((MIN_TOUCH_TARGET - height) / 2)
|
|
|
25
25
|
*/
|
|
26
26
|
export const SEARCH_BAR_SIZES = {
|
|
27
27
|
sm: {
|
|
28
|
-
height:
|
|
28
|
+
height: 44,
|
|
29
29
|
fontSize: 14,
|
|
30
30
|
iconSize: 16,
|
|
31
|
-
hitSlop: slopFor(
|
|
31
|
+
hitSlop: slopFor(44)
|
|
32
32
|
},
|
|
33
33
|
md: {
|
|
34
|
-
height:
|
|
34
|
+
height: 52,
|
|
35
35
|
fontSize: 16,
|
|
36
36
|
iconSize: 18,
|
|
37
|
-
hitSlop: slopFor(
|
|
37
|
+
hitSlop: slopFor(52)
|
|
38
38
|
}
|
|
39
39
|
};
|
|
40
40
|
|
|
@@ -59,7 +59,7 @@ export const CLEAR_BUTTON_WIDTH = MIN_TOUCH_TARGET;
|
|
|
59
59
|
export function resolveSearchBarColors(colors) {
|
|
60
60
|
return {
|
|
61
61
|
text: colors.fg.default,
|
|
62
|
-
placeholder: colors.fg.
|
|
62
|
+
placeholder: colors.fg.placeholder,
|
|
63
63
|
icon: colors.fg.muted,
|
|
64
64
|
border: colors.border.interactive,
|
|
65
65
|
focusBorder: colors.border.focus,
|
|
@@ -141,7 +141,8 @@ export const searchBarFieldStructure = createThemedVariants(theme => ({
|
|
|
141
141
|
alignItems: "center",
|
|
142
142
|
columnGap: theme.space[2],
|
|
143
143
|
borderWidth: theme.borderWidths.thin,
|
|
144
|
-
borderRadius: theme.radii.
|
|
144
|
+
borderRadius: theme.radii.md,
|
|
145
|
+
borderCurve: "continuous"
|
|
145
146
|
},
|
|
146
147
|
variants: {
|
|
147
148
|
size: {
|
|
@@ -171,7 +172,8 @@ export const searchBarClearStructure = createThemedVariants(theme => ({
|
|
|
171
172
|
alignSelf: "stretch",
|
|
172
173
|
alignItems: "center",
|
|
173
174
|
justifyContent: "center",
|
|
174
|
-
borderRadius: theme.radii.
|
|
175
|
+
borderRadius: theme.radii.md,
|
|
176
|
+
borderCurve: "continuous"
|
|
175
177
|
}
|
|
176
178
|
}));
|
|
177
179
|
|
|
@@ -186,7 +188,8 @@ export const searchBarCancelStructure = createThemedVariants(theme => ({
|
|
|
186
188
|
alignItems: "center",
|
|
187
189
|
justifyContent: "center",
|
|
188
190
|
paddingHorizontal: theme.space[2],
|
|
189
|
-
borderRadius: theme.radii.
|
|
191
|
+
borderRadius: theme.radii.md,
|
|
192
|
+
borderCurve: "continuous"
|
|
190
193
|
},
|
|
191
194
|
variants: {
|
|
192
195
|
size: {
|
|
@@ -37,3 +37,5 @@ the settings-section pattern re-declared across consumer apps.
|
|
|
37
37
|
## Performance
|
|
38
38
|
|
|
39
39
|
Wrapped in `React.memo`.
|
|
40
|
+
|
|
41
|
+
- **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
|
|
@@ -9,10 +9,10 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { memo, useMemo } from "react";
|
|
12
|
-
import {
|
|
13
|
-
import { HEADING_LEVEL, HeadingText } from "../../core/heading/index.js";
|
|
12
|
+
import Reanimated, { FadeInDown, ReduceMotion } from "react-native-reanimated";
|
|
14
13
|
import { useTheme } from "../../theme/hooks.js";
|
|
15
|
-
import {
|
|
14
|
+
import { Text } from "../text/index.js";
|
|
15
|
+
import { sectionContainerStructure } from "./Section.variants.js";
|
|
16
16
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
17
17
|
export const Section = /*#__PURE__*/memo(function Section({
|
|
18
18
|
label,
|
|
@@ -21,20 +21,13 @@ export const Section = /*#__PURE__*/memo(function Section({
|
|
|
21
21
|
testID
|
|
22
22
|
}) {
|
|
23
23
|
const theme = useTheme();
|
|
24
|
-
const
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}, style], [theme, colors, style]);
|
|
28
|
-
const labelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.bold), sectionLabelStructure(theme), {
|
|
29
|
-
color: colors.label
|
|
30
|
-
}], [theme, colors]);
|
|
31
|
-
return /*#__PURE__*/_jsxs(View, {
|
|
24
|
+
const rootStyle = useMemo(() => [sectionContainerStructure(theme), style], [theme, style]);
|
|
25
|
+
return /*#__PURE__*/_jsxs(Reanimated.View, {
|
|
26
|
+
entering: FadeInDown.springify().reduceMotion(ReduceMotion.System),
|
|
32
27
|
testID: testID,
|
|
33
28
|
style: rootStyle,
|
|
34
|
-
children: [/*#__PURE__*/_jsx(
|
|
35
|
-
|
|
36
|
-
"aria-level": HEADING_LEVEL.section,
|
|
37
|
-
style: labelStyle,
|
|
29
|
+
children: [/*#__PURE__*/_jsx(Text, {
|
|
30
|
+
variant: "overline",
|
|
38
31
|
children: label
|
|
39
32
|
}), children]
|
|
40
33
|
});
|
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
/**
|
|
4
|
-
* Section's style resolution — same split as `Divider.variants` / `Card.variants`.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
3
|
import { createThemedTextVariants, createThemedVariants } from "../../core/style/index.js";
|
|
8
4
|
export function resolveSectionColors(colors) {
|
|
9
5
|
return {
|
|
@@ -13,8 +9,7 @@ export function resolveSectionColors(colors) {
|
|
|
13
9
|
}
|
|
14
10
|
export const sectionContainerStructure = createThemedVariants(theme => ({
|
|
15
11
|
base: {
|
|
16
|
-
|
|
17
|
-
paddingTop: theme.space[2],
|
|
12
|
+
paddingTop: theme.space[4],
|
|
18
13
|
paddingBottom: theme.space[2],
|
|
19
14
|
rowGap: theme.space[2]
|
|
20
15
|
}
|
|
@@ -74,7 +74,7 @@ The slide goes through **`useMotion()`**, not a direct `MOTION_DURATION` import:
|
|
|
74
74
|
configured constant straight to `Animated.timing` read the CONFIGURED duration, never the one
|
|
75
75
|
resolved against the device tier, so `MOTION_TIER[tier].durationScale` never reached the pill.
|
|
76
76
|
Reduce-motion is `motion.enabled` — no second `useReducedMotion()` call (`core/motion/MODULE.md`
|
|
77
|
-
rule 6). The in-flight slide is stopped on effect cleanup and on unmount.
|
|
77
|
+
rule 6). Segment presses use `usePressState` (scale + state-layer overlay). The in-flight slide is stopped on effect cleanup and on unmount.
|
|
78
78
|
|
|
79
79
|
## Patterns copied from Tabs / ButtonGroup / Card
|
|
80
80
|
|
|
@@ -122,3 +122,5 @@ Wrapped in `React.memo`. `handleSegmentLayout` is `useCallback`'d (mirroring `Ta
|
|
|
122
122
|
- Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
|
|
123
123
|
- List-heavy surfaces use `VirtualList` with device-tier window sizing where applicable.
|
|
124
124
|
- `React.memo` + stable callbacks retained; render-item/key-extractor hoisted per ESLint perf rules.
|
|
125
|
+
- **Round 5 (Android parity)** — segments were missing `android_ripple` entirely; added, bounded
|
|
126
|
+
(`borderless: false`), gated off while a segment is disabled.
|
|
@@ -17,14 +17,102 @@
|
|
|
17
17
|
* the focused segment (WCAG 2.4.7), the same treatment `BottomNavTab` uses.
|
|
18
18
|
*/
|
|
19
19
|
|
|
20
|
-
import { memo, useCallback, useEffect, useRef, useState } from "react";
|
|
21
|
-
import { Animated, Pressable, StyleSheet, Text, View } from "react-native";
|
|
20
|
+
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
21
|
+
import { Animated, Platform, Pressable, StyleSheet, Text, View } from "react-native";
|
|
22
|
+
import Reanimated from "react-native-reanimated";
|
|
22
23
|
import { useAnimatedValue, useMotion } from "../../core/motion/index.js";
|
|
24
|
+
import { useHaptics } from "../../core/haptics/index.js";
|
|
25
|
+
import { usePressState } from "../../core/motion/usePressState.js";
|
|
23
26
|
import { Icon } from "../../core/icon/index.js";
|
|
27
|
+
import { rippleColor, stateLayerScrim } from "../../theme/platform/stateLayer.native.js";
|
|
24
28
|
import { useTheme } from "../../theme/hooks.js";
|
|
29
|
+
import { floatingBackground, floatingSurfaceStyle } from "../../theme/platform/index.js";
|
|
25
30
|
import { resolveSegmentedControlColors, resolveSegmentedControlSegmentAccessibility, resolveSegmentedControlSegmentHitSlop, SEGMENTED_CONTROL_SIZES, segmentedControlFocusRingStructure, segmentedControlPillStructure, segmentedControlSegmentStructure, segmentedControlTrackStructure } from "./SegmentedControl.variants.js";
|
|
26
31
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
27
32
|
const ICON_STROKE = 2;
|
|
33
|
+
const AnimatedPressable = Reanimated.createAnimatedComponent(Pressable);
|
|
34
|
+
const SegmentButton = /*#__PURE__*/memo(function SegmentButton({
|
|
35
|
+
option,
|
|
36
|
+
selected,
|
|
37
|
+
segmentDisabled,
|
|
38
|
+
size,
|
|
39
|
+
fullWidth,
|
|
40
|
+
labelColor,
|
|
41
|
+
hitSlop,
|
|
42
|
+
focused,
|
|
43
|
+
onChange,
|
|
44
|
+
onLayout,
|
|
45
|
+
onFocus,
|
|
46
|
+
onBlur,
|
|
47
|
+
testID
|
|
48
|
+
}) {
|
|
49
|
+
const theme = useTheme();
|
|
50
|
+
const press = usePressState(segmentDisabled);
|
|
51
|
+
const a11y = resolveSegmentedControlSegmentAccessibility({
|
|
52
|
+
selected,
|
|
53
|
+
disabled: segmentDisabled
|
|
54
|
+
});
|
|
55
|
+
const spec = SEGMENTED_CONTROL_SIZES[size];
|
|
56
|
+
const overlayStaticStyle = useMemo(() => ({
|
|
57
|
+
backgroundColor: stateLayerScrim(theme.mode),
|
|
58
|
+
borderRadius: theme.radii.md,
|
|
59
|
+
borderCurve: "continuous"
|
|
60
|
+
}), [theme.mode, theme.radii.md]);
|
|
61
|
+
const androidRipple = useMemo(() => {
|
|
62
|
+
if (Platform.OS !== "android" || segmentDisabled) return undefined;
|
|
63
|
+
return {
|
|
64
|
+
color: rippleColor(theme.mode),
|
|
65
|
+
borderless: false
|
|
66
|
+
};
|
|
67
|
+
}, [segmentDisabled, theme.mode]);
|
|
68
|
+
return /*#__PURE__*/_jsxs(AnimatedPressable, {
|
|
69
|
+
testID: testID,
|
|
70
|
+
accessibilityRole: a11y.accessibilityRole,
|
|
71
|
+
"aria-selected": a11y["aria-selected"],
|
|
72
|
+
"aria-disabled": a11y["aria-disabled"],
|
|
73
|
+
accessibilityLabel: option.label,
|
|
74
|
+
disabled: a11y.disabled,
|
|
75
|
+
onPress: segmentDisabled ? undefined : () => onChange(option.value),
|
|
76
|
+
onLayout: event => {
|
|
77
|
+
press.onLayout(event);
|
|
78
|
+
onLayout(option.value, event);
|
|
79
|
+
},
|
|
80
|
+
onFocus: () => onFocus(option.value),
|
|
81
|
+
onBlur: () => onBlur(option.value),
|
|
82
|
+
onPressIn: press.handlers.onPressIn,
|
|
83
|
+
onPressOut: press.handlers.onPressOut,
|
|
84
|
+
hitSlop: hitSlop,
|
|
85
|
+
android_ripple: androidRipple,
|
|
86
|
+
style: [segmentedControlSegmentStructure(theme, {
|
|
87
|
+
size,
|
|
88
|
+
fullWidth: fullWidth ? "on" : "off"
|
|
89
|
+
}), {
|
|
90
|
+
overflow: "hidden"
|
|
91
|
+
}, press.animatedStyle, option.disabled === true && !segmentDisabled && styles.dimmed],
|
|
92
|
+
children: [/*#__PURE__*/_jsx(Reanimated.View, {
|
|
93
|
+
pointerEvents: "none",
|
|
94
|
+
style: [StyleSheet.absoluteFill, overlayStaticStyle, press.overlayStyle]
|
|
95
|
+
}), focused && /*#__PURE__*/_jsx(View, {
|
|
96
|
+
pointerEvents: "none",
|
|
97
|
+
testID: testID ? `${testID}-focus-ring` : undefined,
|
|
98
|
+
style: [segmentedControlFocusRingStructure(theme), {
|
|
99
|
+
borderColor: theme.colors.border.focus
|
|
100
|
+
}]
|
|
101
|
+
}), option.icon !== undefined && /*#__PURE__*/_jsx(Icon, {
|
|
102
|
+
name: option.icon,
|
|
103
|
+
size: spec.iconSize,
|
|
104
|
+
color: labelColor,
|
|
105
|
+
strokeWidth: ICON_STROKE
|
|
106
|
+
}), /*#__PURE__*/_jsx(Text, {
|
|
107
|
+
numberOfLines: 1,
|
|
108
|
+
style: [theme.fontStyleForWeight(theme.fontWeights.medium), {
|
|
109
|
+
fontSize: spec.fontSize,
|
|
110
|
+
color: labelColor
|
|
111
|
+
}],
|
|
112
|
+
children: option.label
|
|
113
|
+
})]
|
|
114
|
+
});
|
|
115
|
+
});
|
|
28
116
|
function SegmentedControlImpl({
|
|
29
117
|
options,
|
|
30
118
|
value,
|
|
@@ -37,8 +125,8 @@ function SegmentedControlImpl({
|
|
|
37
125
|
}) {
|
|
38
126
|
const theme = useTheme();
|
|
39
127
|
const motion = useMotion();
|
|
128
|
+
const haptics = useHaptics();
|
|
40
129
|
const colors = resolveSegmentedControlColors(theme.colors);
|
|
41
|
-
const spec = SEGMENTED_CONTROL_SIZES[size];
|
|
42
130
|
const hitSlop = resolveSegmentedControlSegmentHitSlop(size);
|
|
43
131
|
const [layouts, setLayouts] = useState({});
|
|
44
132
|
// Which segment holds keyboard/AT focus. One value rather than per-segment state: only one segment
|
|
@@ -78,11 +166,16 @@ function SegmentedControlImpl({
|
|
|
78
166
|
return () => running.current?.stop();
|
|
79
167
|
}, [activeLayout, motion, pillX]);
|
|
80
168
|
useEffect(() => () => running.current?.stop(), []);
|
|
169
|
+
const handleChange = useCallback(optionValue => {
|
|
170
|
+
haptics.selection();
|
|
171
|
+
onChange(optionValue);
|
|
172
|
+
}, [haptics, onChange]);
|
|
81
173
|
return /*#__PURE__*/_jsxs(View, {
|
|
82
174
|
testID: testID,
|
|
83
175
|
accessibilityRole: "tablist",
|
|
84
176
|
style: [segmentedControlTrackStructure(theme), {
|
|
85
|
-
backgroundColor:
|
|
177
|
+
backgroundColor: floatingBackground(theme, "sm"),
|
|
178
|
+
...floatingSurfaceStyle(theme, "sm")
|
|
86
179
|
}, disabled && styles.dimmed, style],
|
|
87
180
|
children: [/*#__PURE__*/_jsx(Animated.View, {
|
|
88
181
|
pointerEvents: "none",
|
|
@@ -97,50 +190,21 @@ function SegmentedControlImpl({
|
|
|
97
190
|
}), options.map(option => {
|
|
98
191
|
const selected = option.value === value;
|
|
99
192
|
const segmentDisabled = disabled || option.disabled === true;
|
|
100
|
-
const a11y = resolveSegmentedControlSegmentAccessibility({
|
|
101
|
-
selected,
|
|
102
|
-
disabled: segmentDisabled
|
|
103
|
-
});
|
|
104
193
|
const labelColor = selected ? colors.activeLabel : colors.inactiveLabel;
|
|
105
|
-
return /*#__PURE__*/
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
onPress: segmentDisabled ? undefined : () => onChange(option.value),
|
|
113
|
-
onLayout: event => handleSegmentLayout(option.value, event),
|
|
114
|
-
onFocus: () => setFocusedValue(option.value),
|
|
115
|
-
onBlur: () => setFocusedValue(current => current === option.value ? null : current),
|
|
194
|
+
return /*#__PURE__*/_jsx(SegmentButton, {
|
|
195
|
+
option: option,
|
|
196
|
+
selected: selected,
|
|
197
|
+
segmentDisabled: segmentDisabled,
|
|
198
|
+
size: size,
|
|
199
|
+
fullWidth: fullWidth,
|
|
200
|
+
labelColor: labelColor,
|
|
116
201
|
hitSlop: hitSlop,
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
backgroundColor: colors.pressedSegment
|
|
124
|
-
}, option.disabled === true && !disabled && styles.dimmed],
|
|
125
|
-
children: [focusedValue === option.value && /*#__PURE__*/_jsx(View, {
|
|
126
|
-
pointerEvents: "none",
|
|
127
|
-
testID: testID ? `${testID}-${option.value}-focus-ring` : undefined,
|
|
128
|
-
style: [segmentedControlFocusRingStructure(theme), {
|
|
129
|
-
borderColor: theme.colors.border.focus
|
|
130
|
-
}]
|
|
131
|
-
}), option.icon !== undefined && /*#__PURE__*/_jsx(Icon, {
|
|
132
|
-
name: option.icon,
|
|
133
|
-
size: spec.iconSize,
|
|
134
|
-
color: labelColor,
|
|
135
|
-
strokeWidth: ICON_STROKE
|
|
136
|
-
}), /*#__PURE__*/_jsx(Text, {
|
|
137
|
-
numberOfLines: 1,
|
|
138
|
-
style: [theme.fontStyleForWeight(theme.fontWeights.medium), {
|
|
139
|
-
fontSize: spec.fontSize,
|
|
140
|
-
color: labelColor
|
|
141
|
-
}],
|
|
142
|
-
children: option.label
|
|
143
|
-
})]
|
|
202
|
+
focused: focusedValue === option.value,
|
|
203
|
+
onChange: handleChange,
|
|
204
|
+
onLayout: handleSegmentLayout,
|
|
205
|
+
onFocus: setFocusedValue,
|
|
206
|
+
onBlur: v => setFocusedValue(current => current === v ? null : current),
|
|
207
|
+
testID: testID ? `${testID}-${option.value}` : undefined
|
|
144
208
|
}, option.value);
|
|
145
209
|
})]
|
|
146
210
|
});
|
|
@@ -86,13 +86,14 @@ export const segmentedControlTrackStructure = createThemedVariants(theme => ({
|
|
|
86
86
|
base: {
|
|
87
87
|
flexDirection: "row",
|
|
88
88
|
position: "relative",
|
|
89
|
-
borderRadius: theme.radii.
|
|
89
|
+
borderRadius: theme.radii.md,
|
|
90
|
+
borderCurve: "continuous",
|
|
90
91
|
padding: theme.space[1]
|
|
91
92
|
}
|
|
92
93
|
}));
|
|
93
94
|
|
|
94
95
|
/**
|
|
95
|
-
* The pill. `theme.radii.sm` — one step down from the track's `theme.radii.
|
|
96
|
+
* The pill. `theme.radii.sm` — one step down from the track's `theme.radii.md` — nests cleanly
|
|
96
97
|
* inside the track's own `space[1]` inset, the same "inner radius ≈ outer radius − inset" geometry
|
|
97
98
|
* a nested rounded rect needs to read as concentric rather than mismatched. `top`/`bottom` pin it to
|
|
98
99
|
* the row's own height (set by the segments, its flow siblings); `left`/`width` are driven by
|
|
@@ -27,7 +27,7 @@ context + a stateless helper with no React-tree footprint of its own, not a depe
|
|
|
27
27
|
|
|
28
28
|
| Prop | Type | Default | Notes |
|
|
29
29
|
|------|------|---------|-------|
|
|
30
|
-
| `options` | `
|
|
30
|
+
| `options` | `SelectOption[]` | — | Required. Each option may set `tone` / `customColors` (same `custom` escape hatch as `Badge`). |
|
|
31
31
|
| `value` | `string` | — | The currently selected option's `value`. |
|
|
32
32
|
| `onValueChange` | `(value: string) => void` | — | Required. Fired on row press; the menu closes right after. |
|
|
33
33
|
| `placeholder` | `string` | — | Shown when `value` matches no option. |
|
|
@@ -40,6 +40,16 @@ context + a stateless helper with no React-tree footprint of its own, not a depe
|
|
|
40
40
|
No `icon` prop — the chevron/check glyphs are fixed to the component's own semantics, not
|
|
41
41
|
caller-configurable.
|
|
42
42
|
|
|
43
|
+
### `SelectOption`
|
|
44
|
+
|
|
45
|
+
| Field | Type | Notes |
|
|
46
|
+
|-------|------|-------|
|
|
47
|
+
| `label` | `string` | Row label (required). |
|
|
48
|
+
| `value` | `string` | Stable id (required). |
|
|
49
|
+
| `leading` | `ReactNode` | Optional fixed-size adornment on the row and trigger. |
|
|
50
|
+
| `tone` | `SelectOptionTone` | Optional label colour from role tokens, or `"custom"`. |
|
|
51
|
+
| `customColors` | `{ bg, fg }` | Required when `tone="custom"`. Label reads `fg`. |
|
|
52
|
+
|
|
43
53
|
## Accessibility contract (WCAG)
|
|
44
54
|
|
|
45
55
|
- **2.5.x target size** — every trigger size reaches ≥ 44dp via `hitSlop`; option rows have a
|
|
@@ -56,14 +66,25 @@ caller-configurable.
|
|
|
56
66
|
`bg.selected` isn't proven ≥ 4.5:1 against `fg.default` on every brand (measured: fails on
|
|
57
67
|
radiant/rosewood light), so `resolveSelectRowColors` keeps the row fill at `bg.surface` for every
|
|
58
68
|
row, selected or not.
|
|
59
|
-
- Each option row is `accessibilityRole="
|
|
60
|
-
the sighted echo of the same state, never the only signal.
|
|
69
|
+
- Each option row is `accessibilityRole="option"` with flat `aria-selected`; the "check" icon is
|
|
70
|
+
the sighted echo of the same state, never the only signal. **2026-08 sweep:** rows were
|
|
71
|
+
`accessibilityRole="menuitem"`, which made `aria-selected` invalid ARIA (only valid on
|
|
72
|
+
`option`/`row`/`tab`/`gridcell`/`treeitem`). Unlike `OrgSwitcher`'s identical bug — fixed to
|
|
73
|
+
`role="radio"` + `aria-checked` because that sheet's row list carries no `listbox` role — Select's
|
|
74
|
+
rows sit inside a `SELECT_LISTBOX_ROLE` (`"listbox"`) container, so `option` + `aria-selected` is
|
|
75
|
+
the textbook-correct ARIA listbox pattern; only the row's `accessibilityRole` changed, `aria-selected`
|
|
76
|
+
was already the right prop.
|
|
61
77
|
- **2.3.3** — RN's `Modal animationType` is always `"none"`; the reveal is `core/motion`'s
|
|
62
78
|
`useReveal`, which snaps to the final state (no tween) under reduce-motion. Row press feedback
|
|
63
79
|
and the check fade go through the same `motion.enabled` gate. Covered by
|
|
64
80
|
`__tests__/Select.motion.test.tsx`.
|
|
65
81
|
- Disabled is exempt from the contrast minimum (WCAG 1.4.3) — like Button, it's signalled by a
|
|
66
82
|
uniform `opacity: 0.5` dim rather than a separate, still-must-pass colour pair.
|
|
83
|
+
- **Android touch feedback** — the trigger and every option row carry `android_ripple`
|
|
84
|
+
(`rippleColor(theme.mode)`, `borderless: false`), gated on `Platform.OS === "android"`. The trigger
|
|
85
|
+
and the sheet container both gained `overflow: "hidden"` so the ripple clips to their rounded
|
|
86
|
+
bounds — rows have no radius of their own, the sheet does. The backdrop carries no ripple; it is
|
|
87
|
+
`accessible={false}` and not a real press target.
|
|
67
88
|
|
|
68
89
|
## Patterns copied from Button (the reference module)
|
|
69
90
|
|
|
@@ -86,9 +107,9 @@ the tab stop, and `useFocusTrap` needs the focused node to still be tabbable or
|
|
|
86
107
|
sheet. `useFocusTrap` also restores focus to the trigger on close; `useDismissOnEscape` closes on
|
|
87
108
|
Escape.
|
|
88
109
|
|
|
89
|
-
**`useRovingKeys` gets no `onActivate`.** RNW already presses
|
|
110
|
+
**`useRovingKeys` gets no `onActivate`.** RNW already presses on Enter regardless of role, and Space is
|
|
90
111
|
supplied per row by `useSpaceActivation` (RNW's `isValidKeyPress` needs a `button` tag/role, which
|
|
91
|
-
`
|
|
112
|
+
`option` deliberately is not) — passing `onActivate` too would select twice.
|
|
92
113
|
|
|
93
114
|
The list container is `SELECT_LISTBOX_ROLE`: RN 0.86's role unions have no `listbox`, so the
|
|
94
115
|
widening is one audited cast in `Select.variants.ts` rather than a cast at the call site.
|
|
@@ -10,10 +10,14 @@ import { focusItemProps, useDismissOnEscape, useFocusTrap, useRovingKeys, useSpa
|
|
|
10
10
|
import { Icon } from "../../core/icon/index.js";
|
|
11
11
|
import { VirtualList } from "../../core/list/index.js";
|
|
12
12
|
import { useMotion, usePressMotion, useReveal } from "../../core/motion/index.js";
|
|
13
|
+
import { elevation, floatingBackground, floatingSurfaceStyle, highlight } from "../../theme/platform/index.js";
|
|
14
|
+
import { rippleColor } from "../../theme/platform/stateLayer.native.js";
|
|
15
|
+
import { elevation as elevationTokens } from "../../theme/tokens/primitives/index.js";
|
|
16
|
+
import { withAlpha } from "../../core/gradient/index.js";
|
|
13
17
|
import { useTheme } from "../../theme/hooks.js";
|
|
14
18
|
import { ModalPortalContext } from "../modal/ModalPortalContext.js";
|
|
15
19
|
import { renderWebPortal } from "../modal/renderWebPortal";
|
|
16
|
-
import { resolveSelectAccessibility, resolveSelectRowColors, resolveSelectTriggerColors, SELECT_LISTBOX_ROLE, SELECT_ROW_ICON_SIZE, SELECT_ROW_MIN_HEIGHT, SELECT_SIZES, selectOverlayStructure, selectRowLeadingStructure, selectRowStructure, selectSheetStructure, selectTriggerStructure, selectTriggerValueStructure } from "./Select.variants.js";
|
|
20
|
+
import { resolveSelectAccessibility, resolveSelectOptionLabelColor, resolveSelectRowColors, resolveSelectTriggerColors, SELECT_LISTBOX_ROLE, SELECT_OPTION_ROLE, SELECT_ROW_ICON_SIZE, SELECT_ROW_MIN_HEIGHT, SELECT_SIZES, selectOverlayStructure, selectRowLeadingStructure, selectRowStructure, selectSheetStructure, selectTriggerStructure, selectTriggerValueStructure } from "./Select.variants.js";
|
|
17
21
|
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
18
22
|
const ICON_STROKE = 2;
|
|
19
23
|
const BACKDROP_SCRIM = "#00000099";
|
|
@@ -29,6 +33,10 @@ const SelectOptionRow = /*#__PURE__*/memo(function SelectOptionRow({
|
|
|
29
33
|
const motion = useMotion();
|
|
30
34
|
const press = usePressMotion();
|
|
31
35
|
const handlePress = useCallback(() => onSelect(option), [onSelect, option]);
|
|
36
|
+
const androidRipple = useMemo(() => Platform.OS === "android" ? {
|
|
37
|
+
color: rippleColor(theme.mode),
|
|
38
|
+
borderless: false
|
|
39
|
+
} : undefined, [theme.mode]);
|
|
32
40
|
const rowRef = useRef(null);
|
|
33
41
|
const active = tabIndex === 0;
|
|
34
42
|
|
|
@@ -39,7 +47,7 @@ const SelectOptionRow = /*#__PURE__*/memo(function SelectOptionRow({
|
|
|
39
47
|
rowRef.current?.focus();
|
|
40
48
|
}, [active]);
|
|
41
49
|
|
|
42
|
-
// `
|
|
50
|
+
// `option` is not `button`, so RNW never presses on Space — see `core/a11y/keyboard.web.ts`.
|
|
43
51
|
useSpaceActivation(rowRef, handlePress);
|
|
44
52
|
const checkOpacity = useRef(new Animated.Value(selected ? 1 : 0)).current;
|
|
45
53
|
const skipFirst = useRef(true);
|
|
@@ -73,17 +81,18 @@ const SelectOptionRow = /*#__PURE__*/memo(function SelectOptionRow({
|
|
|
73
81
|
const labelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.regular), {
|
|
74
82
|
flex: 1,
|
|
75
83
|
fontSize: theme.fontSizes.md,
|
|
76
|
-
color:
|
|
77
|
-
}], [theme,
|
|
84
|
+
color: resolveSelectOptionLabelColor(theme.colors, option.tone, option.customColors)
|
|
85
|
+
}], [theme, option.tone, option.customColors]);
|
|
78
86
|
return /*#__PURE__*/_jsx(Pressable, {
|
|
79
87
|
ref: rowRef,
|
|
80
88
|
testID: testID ? `${testID}-option-${option.value}` : undefined,
|
|
81
|
-
accessibilityRole:
|
|
89
|
+
accessibilityRole: SELECT_OPTION_ROLE,
|
|
82
90
|
"aria-selected": selected,
|
|
83
91
|
tabIndex: tabIndex,
|
|
84
92
|
onPress: handlePress,
|
|
85
93
|
onPressIn: press.onPressIn,
|
|
86
94
|
onPressOut: press.onPressOut,
|
|
95
|
+
android_ripple: androidRipple,
|
|
87
96
|
style: rowStyle,
|
|
88
97
|
children: /*#__PURE__*/_jsxs(Animated.View, {
|
|
89
98
|
testID: testID ? `${testID}-option-${option.value}-content` : undefined,
|
|
@@ -156,7 +165,7 @@ export const Select = /*#__PURE__*/memo(function Select({
|
|
|
156
165
|
const typeaheadLabels = useMemo(() => options.map(option => option.label), [options]);
|
|
157
166
|
|
|
158
167
|
// Keyboard (web only — every hook below is a no-op on native, see `core/a11y/keyboard.ts`).
|
|
159
|
-
// No `onActivate`: RNW already presses
|
|
168
|
+
// No `onActivate`: RNW already presses on Enter regardless of role, and each row's own
|
|
160
169
|
// `useSpaceActivation` owns Space — passing it here would select twice.
|
|
161
170
|
useDismissOnEscape(open, closeMenu);
|
|
162
171
|
useFocusTrap(sheetRef, open);
|
|
@@ -183,14 +192,29 @@ export const Select = /*#__PURE__*/memo(function Select({
|
|
|
183
192
|
const triggerStyle = useMemo(() => [selectTriggerStructure(theme, {
|
|
184
193
|
size
|
|
185
194
|
}), {
|
|
186
|
-
backgroundColor: triggerColors.background,
|
|
187
|
-
borderColor: triggerColors.border
|
|
188
|
-
|
|
195
|
+
backgroundColor: focused || open ? withAlpha(theme.colors.accent.solid, 0.04) : triggerColors.background,
|
|
196
|
+
borderColor: triggerColors.border,
|
|
197
|
+
borderWidth: focused || open ? 2 : theme.borderWidths.thin,
|
|
198
|
+
overflow: "hidden"
|
|
199
|
+
}, disabled && styles.dimmed], [theme, size, triggerColors, disabled, focused, open]);
|
|
189
200
|
const valueStructure = useMemo(() => selectTriggerValueStructure(theme), [theme]);
|
|
190
201
|
const overlayStructure = useMemo(() => selectOverlayStructure(theme), [theme]);
|
|
191
|
-
const
|
|
192
|
-
|
|
193
|
-
|
|
202
|
+
const floatingStyle = useMemo(() => {
|
|
203
|
+
highlight("subtle", theme.mode);
|
|
204
|
+
elevation(elevationTokens.md);
|
|
205
|
+
void theme.elevatedSurfaces;
|
|
206
|
+
return {
|
|
207
|
+
backgroundColor: floatingBackground(theme, "md"),
|
|
208
|
+
...floatingSurfaceStyle(theme, "md")
|
|
209
|
+
};
|
|
210
|
+
}, [theme]);
|
|
211
|
+
const sheetStyle = useMemo(() => [selectSheetStructure(theme), floatingStyle, {
|
|
212
|
+
overflow: "hidden"
|
|
213
|
+
}], [theme, floatingStyle]);
|
|
214
|
+
const androidRipple = useMemo(() => Platform.OS === "android" ? {
|
|
215
|
+
color: rippleColor(theme.mode),
|
|
216
|
+
borderless: false
|
|
217
|
+
} : undefined, [theme.mode]);
|
|
194
218
|
const fieldLabelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.medium), {
|
|
195
219
|
fontSize: theme.fontSizes.sm,
|
|
196
220
|
color: theme.colors.fg.muted,
|
|
@@ -231,6 +255,8 @@ export const Select = /*#__PURE__*/memo(function Select({
|
|
|
231
255
|
}), portalContainer) : null : /*#__PURE__*/_jsx(Modal, {
|
|
232
256
|
visible: open,
|
|
233
257
|
transparent: true,
|
|
258
|
+
statusBarTranslucent: true,
|
|
259
|
+
navigationBarTranslucent: true,
|
|
234
260
|
animationType: "none",
|
|
235
261
|
onRequestClose: closeMenu,
|
|
236
262
|
children: sheet
|
|
@@ -251,6 +277,7 @@ export const Select = /*#__PURE__*/memo(function Select({
|
|
|
251
277
|
onFocus: handleFocus,
|
|
252
278
|
onBlur: handleBlur,
|
|
253
279
|
hitSlop: spec.hitSlop,
|
|
280
|
+
android_ripple: androidRipple,
|
|
254
281
|
style: triggerStyle,
|
|
255
282
|
children: [/*#__PURE__*/_jsxs(View, {
|
|
256
283
|
style: valueStructure,
|
|
@@ -22,32 +22,41 @@ import { createThemedVariants } from "../../core/style/index.js";
|
|
|
22
22
|
*/
|
|
23
23
|
export const SELECT_LISTBOX_ROLE = "listbox";
|
|
24
24
|
|
|
25
|
+
/**
|
|
26
|
+
* Each option row's role. `aria-selected` is only valid ARIA on `option`/`row`/`tab`/`gridcell`/
|
|
27
|
+
* `treeitem` — the row sits inside a `SELECT_LISTBOX_ROLE` container, so `option` is the
|
|
28
|
+
* textbook-correct pairing (2026-08 sweep fixed the row from the invalid `menuitem`+`aria-selected`
|
|
29
|
+
* combination). Same type gap as `SELECT_LISTBOX_ROLE`: RN 0.86's `AccessibilityRole` union has no
|
|
30
|
+
* `option` either.
|
|
31
|
+
*/
|
|
32
|
+
export const SELECT_OPTION_ROLE = "option";
|
|
33
|
+
|
|
25
34
|
/** Same touch-target floor as Button (44dp — Apple HIG minimum, WCAG 2.5.5 AAA). */
|
|
26
35
|
export const MIN_TOUCH_TARGET = 44;
|
|
27
36
|
const slopFor = height => Math.max(0, Math.ceil((MIN_TOUCH_TARGET - height) / 2));
|
|
28
37
|
export const SELECT_SIZES = {
|
|
29
38
|
sm: {
|
|
30
|
-
height:
|
|
39
|
+
height: 44,
|
|
31
40
|
fontSize: 14,
|
|
32
41
|
iconSize: 16,
|
|
33
|
-
hitSlop: slopFor(
|
|
42
|
+
hitSlop: slopFor(44)
|
|
34
43
|
},
|
|
35
44
|
md: {
|
|
36
|
-
height:
|
|
45
|
+
height: 52,
|
|
37
46
|
fontSize: 16,
|
|
38
47
|
iconSize: 18,
|
|
39
|
-
hitSlop: slopFor(
|
|
48
|
+
hitSlop: slopFor(52)
|
|
40
49
|
},
|
|
41
50
|
lg: {
|
|
42
|
-
height:
|
|
51
|
+
height: 56,
|
|
43
52
|
fontSize: 18,
|
|
44
53
|
iconSize: 20,
|
|
45
|
-
hitSlop: slopFor(
|
|
54
|
+
hitSlop: slopFor(56)
|
|
46
55
|
}
|
|
47
56
|
};
|
|
48
57
|
|
|
49
58
|
/** Minimum height for an option row — a list item is still an interactive target (WCAG 2.5.8). */
|
|
50
|
-
export const SELECT_ROW_MIN_HEIGHT =
|
|
59
|
+
export const SELECT_ROW_MIN_HEIGHT = 48;
|
|
51
60
|
|
|
52
61
|
/** The "check" glyph beside the active row. Fixed — independent of the trigger's own `size`. */
|
|
53
62
|
export const SELECT_ROW_ICON_SIZE = 18;
|
|
@@ -60,7 +69,7 @@ export const SELECT_ROW_ICON_SIZE = 18;
|
|
|
60
69
|
export function resolveSelectTriggerColors(colors, focused) {
|
|
61
70
|
return {
|
|
62
71
|
background: colors.bg.surface,
|
|
63
|
-
border: focused ? colors.
|
|
72
|
+
border: focused ? colors.accent.solid : colors.border.interactive,
|
|
64
73
|
text: colors.fg.default,
|
|
65
74
|
placeholder: colors.fg.muted,
|
|
66
75
|
icon: colors.fg.muted
|
|
@@ -74,6 +83,20 @@ export function resolveSelectRowColors(colors) {
|
|
|
74
83
|
pressedRow: colors.bg.sunken
|
|
75
84
|
};
|
|
76
85
|
}
|
|
86
|
+
export function resolveSelectOptionLabelColor(colors, tone, customColors) {
|
|
87
|
+
if (tone === undefined) {
|
|
88
|
+
return colors.fg.default;
|
|
89
|
+
}
|
|
90
|
+
if (tone === "custom") {
|
|
91
|
+
if (!customColors) {
|
|
92
|
+
throw new Error('SelectOption tone="custom" requires customColors={{ bg, fg }}.');
|
|
93
|
+
}
|
|
94
|
+
return customColors.fg;
|
|
95
|
+
}
|
|
96
|
+
if (tone === "accent") return colors.accent.text;
|
|
97
|
+
if (tone === "neutral") return colors.fg.default;
|
|
98
|
+
return colors.status[tone].text;
|
|
99
|
+
}
|
|
77
100
|
/**
|
|
78
101
|
* Derives the trigger's accessibility surface once, purely: `expanded` tracks whether the option
|
|
79
102
|
* list is showing (WCAG 4.1.2 — a collapsible control must expose its expanded/collapsed state),
|
|
@@ -99,7 +122,8 @@ export const selectTriggerStructure = createThemedVariants(theme => ({
|
|
|
99
122
|
alignItems: "center",
|
|
100
123
|
justifyContent: "space-between",
|
|
101
124
|
columnGap: theme.space[2],
|
|
102
|
-
borderRadius: theme.radii.
|
|
125
|
+
borderRadius: theme.radii.md,
|
|
126
|
+
borderCurve: "continuous",
|
|
103
127
|
borderWidth: theme.borderWidths.thin
|
|
104
128
|
},
|
|
105
129
|
variants: {
|
|
@@ -145,10 +169,10 @@ export const selectOverlayStructure = createThemedVariants(theme => ({
|
|
|
145
169
|
}));
|
|
146
170
|
export const selectSheetStructure = createThemedVariants(theme => ({
|
|
147
171
|
base: {
|
|
148
|
-
borderRadius: theme.radii.
|
|
172
|
+
borderRadius: theme.radii.lg,
|
|
173
|
+
borderCurve: "continuous",
|
|
149
174
|
paddingVertical: theme.space[2],
|
|
150
|
-
maxHeight: 320
|
|
151
|
-
...theme.elevation.lg
|
|
175
|
+
maxHeight: 320
|
|
152
176
|
}
|
|
153
177
|
}));
|
|
154
178
|
export const selectRowStructure = createThemedVariants(theme => ({
|