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
|
@@ -1,48 +1,23 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import { memo, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
11
|
-
import { ActivityIndicator, Animated, Pressable, StyleSheet, Text, View } from "react-native";
|
|
12
|
-
import { useAnimatedValue, useMotion } from "../../core/motion/index.js";
|
|
3
|
+
import { memo, useCallback, useMemo, useState } from "react";
|
|
4
|
+
import { ActivityIndicator, Platform, Pressable, StyleSheet, Text } from "react-native";
|
|
5
|
+
import Animated from "react-native-reanimated";
|
|
6
|
+
import { AccentGradientFill } from "../../core/gradient/index.js";
|
|
7
|
+
import { useFocusRing, usePressState } from "../../core/motion/usePressState.js";
|
|
8
|
+
import { useHaptics } from "../../core/haptics/index.js";
|
|
13
9
|
import { Icon } from "../../core/icon/index.js";
|
|
14
|
-
import {
|
|
10
|
+
import { composeBoxShadow, highlight } from "../../theme/platform/highlight.native.js";
|
|
11
|
+
import { tokenBoxShadow } from "../../theme/platform/floatingSurface.native.js";
|
|
12
|
+
import { elevation as elevationTokens } from "../../theme/tokens/primitives/index.js";
|
|
13
|
+
import { rippleColor, stateLayerScrim } from "../../theme/platform/stateLayer.native.js";
|
|
14
|
+
import { useTheme, useThemeColors } from "../../theme/hooks.js";
|
|
15
15
|
import { BUTTON_SIZES, buttonStructure, resolveButtonAccessibility, resolveButtonTone } from "./Button.variants.js";
|
|
16
|
-
|
|
17
|
-
/** A button with a visible text label. `accessibilityLabel` defaults to `label`. */
|
|
18
|
-
|
|
19
|
-
/**
|
|
20
|
-
* An icon-only button. It has no visible text, so `accessibilityLabel` is REQUIRED at the type level
|
|
21
|
-
* — the single worst a11y trap on web (its tooltip was the only label on icon-only buttons in 22
|
|
22
|
-
* files, and tooltips do not exist on touch). `label?: never` makes the two shapes mutually exclusive.
|
|
23
|
-
*/
|
|
24
16
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
25
17
|
const ICON_STROKE = 2;
|
|
26
|
-
|
|
27
|
-
// label on press — its contrast can only rise. 8-digit hex carries the alpha (~15%) directly.
|
|
28
|
-
const PRESS_SCRIM_DARK = "#00000026";
|
|
29
|
-
const PRESS_SCRIM_LIGHT = "#ffffff26";
|
|
30
|
-
// The focus ring sits a small gap OUTSIDE the control, on the canvas, because `border.focus` is the
|
|
31
|
-
// role token proven ≥ 3:1 against the canvas (WCAG 2.4.11) — drawn over a solid fill it could fail.
|
|
32
|
-
const FOCUS_RING_WIDTH = 2;
|
|
18
|
+
const FOCUS_RING_WIDTH = 3;
|
|
33
19
|
const FOCUS_RING_GAP = 2;
|
|
34
|
-
|
|
35
|
-
// The press scale has to sit on the same node `style` lands on, so the contract's "style last" holds.
|
|
36
20
|
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
37
|
-
|
|
38
|
-
/** Cheap perceived-brightness split; `onFill` is only ever a near-white or near-black role value. */
|
|
39
|
-
function isLight(hex) {
|
|
40
|
-
const n = parseInt(hex.slice(1, 7), 16);
|
|
41
|
-
const r = n >> 16 & 0xff;
|
|
42
|
-
const g = n >> 8 & 0xff;
|
|
43
|
-
const b = n & 0xff;
|
|
44
|
-
return r * 0.299 + g * 0.587 + b * 0.114 > 140;
|
|
45
|
-
}
|
|
46
21
|
function ButtonImpl(props) {
|
|
47
22
|
const {
|
|
48
23
|
variant = "solid",
|
|
@@ -68,45 +43,35 @@ function ButtonImpl(props) {
|
|
|
68
43
|
accessibilityHint
|
|
69
44
|
} = props;
|
|
70
45
|
const theme = useTheme();
|
|
71
|
-
const
|
|
72
|
-
const
|
|
73
|
-
const
|
|
74
|
-
|
|
46
|
+
const colors = useThemeColors();
|
|
47
|
+
const haptics = useHaptics();
|
|
48
|
+
const blocked = disabled || loading;
|
|
49
|
+
const press = usePressState(blocked);
|
|
75
50
|
const [focused, setFocused] = useState(false);
|
|
51
|
+
const {
|
|
52
|
+
focusRingStyle
|
|
53
|
+
} = useFocusRing(focused, blocked);
|
|
76
54
|
const spec = BUTTON_SIZES[size];
|
|
77
55
|
const toneColors = useMemo(() => resolveButtonTone(theme.colors, tone), [theme.colors, tone]);
|
|
78
56
|
const iconOnly = label === undefined;
|
|
79
57
|
const foreground = variant === "solid" ? toneColors.onFill : toneColors.text;
|
|
80
|
-
const overlayColor =
|
|
58
|
+
const overlayColor = stateLayerScrim(theme.mode);
|
|
59
|
+
const handlePress = useCallback(() => {
|
|
60
|
+
haptics.selection();
|
|
61
|
+
onPress?.();
|
|
62
|
+
}, [haptics, onPress]);
|
|
81
63
|
const a11y = useMemo(() => resolveButtonAccessibility({
|
|
82
64
|
label,
|
|
83
65
|
accessibilityLabel,
|
|
84
66
|
disabled,
|
|
85
67
|
loading,
|
|
86
68
|
selected,
|
|
87
|
-
onPress
|
|
88
|
-
}), [label, accessibilityLabel, disabled, loading, selected, onPress]);
|
|
89
|
-
const setPressed = useCallback(isPressed => {
|
|
90
|
-
running.current?.stop();
|
|
91
|
-
const toValue = isPressed ? 1 : 0;
|
|
92
|
-
if (!motion.enabled) {
|
|
93
|
-
pressed.setValue(toValue);
|
|
94
|
-
return;
|
|
95
|
-
}
|
|
96
|
-
running.current = motion.timing(pressed, toValue, {
|
|
97
|
-
duration: "fast"
|
|
98
|
-
});
|
|
99
|
-
running.current.start();
|
|
100
|
-
}, [motion, pressed]);
|
|
101
|
-
useEffect(() => () => running.current?.stop(), []);
|
|
102
|
-
|
|
103
|
-
// Own state first, then the incoming handler — an outer handler that throws can never strand the
|
|
104
|
-
// press/focus ring in its active state.
|
|
105
|
-
const handlePressIn = useCallback(() => setPressed(true), [setPressed]);
|
|
69
|
+
onPress: onPress === undefined ? undefined : handlePress
|
|
70
|
+
}), [label, accessibilityLabel, disabled, loading, selected, onPress, handlePress]);
|
|
106
71
|
const handlePressOut = useCallback(event => {
|
|
107
|
-
|
|
72
|
+
press.handlers.onPressOut();
|
|
108
73
|
onPressOut?.(event);
|
|
109
|
-
}, [
|
|
74
|
+
}, [press.handlers, onPressOut]);
|
|
110
75
|
const handleFocus = useCallback(event => {
|
|
111
76
|
setFocused(true);
|
|
112
77
|
onFocus?.(event);
|
|
@@ -115,42 +80,55 @@ function ButtonImpl(props) {
|
|
|
115
80
|
setFocused(false);
|
|
116
81
|
onBlur?.(event);
|
|
117
82
|
}, [onBlur]);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
}
|
|
127
|
-
|
|
128
|
-
|
|
83
|
+
const radius = theme.radii.md;
|
|
84
|
+
const solidToken = elevationTokens.sm;
|
|
85
|
+
const solidElevation = theme.elevation.sm;
|
|
86
|
+
const highlightLayers = highlight("subtle", theme.mode);
|
|
87
|
+
const surfaceStyle = useMemo(() => {
|
|
88
|
+
const base = {
|
|
89
|
+
borderRadius: radius,
|
|
90
|
+
borderCurve: "continuous"
|
|
91
|
+
};
|
|
92
|
+
if (variant === "solid") {
|
|
93
|
+
base.boxShadow = composeBoxShadow(tokenBoxShadow(solidToken), highlightLayers);
|
|
94
|
+
base.elevation = solidElevation.elevation;
|
|
95
|
+
Object.assign(base, solidElevation);
|
|
96
|
+
}
|
|
97
|
+
return base;
|
|
98
|
+
}, [variant, radius, solidToken, solidElevation, highlightLayers]);
|
|
99
|
+
const androidRipple = useMemo(() => {
|
|
100
|
+
if (Platform.OS !== "android") return undefined;
|
|
101
|
+
return {
|
|
102
|
+
color: rippleColor(theme.mode),
|
|
103
|
+
borderless: false
|
|
104
|
+
};
|
|
105
|
+
}, [theme.mode]);
|
|
106
|
+
const overlayStaticStyle = useMemo(() => ({
|
|
129
107
|
backgroundColor: overlayColor,
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
pointerEvents: "none",
|
|
108
|
+
borderRadius: radius
|
|
109
|
+
}), [overlayColor, radius]);
|
|
110
|
+
const focusRingStaticStyle = useMemo(() => ({
|
|
111
|
+
borderWidth: FOCUS_RING_WIDTH,
|
|
112
|
+
borderColor: colors.border.focus,
|
|
113
|
+
borderRadius: radius + FOCUS_RING_GAP + FOCUS_RING_WIDTH,
|
|
137
114
|
top: -(FOCUS_RING_GAP + FOCUS_RING_WIDTH),
|
|
138
115
|
left: -(FOCUS_RING_GAP + FOCUS_RING_WIDTH),
|
|
139
116
|
right: -(FOCUS_RING_GAP + FOCUS_RING_WIDTH),
|
|
140
|
-
bottom: -(FOCUS_RING_GAP + FOCUS_RING_WIDTH)
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
117
|
+
bottom: -(FOCUS_RING_GAP + FOCUS_RING_WIDTH)
|
|
118
|
+
}), [colors.border.focus, radius]);
|
|
119
|
+
const focusOutlineStyle = useMemo(() => ({
|
|
120
|
+
outlineWidth: FOCUS_RING_WIDTH,
|
|
121
|
+
outlineOffset: FOCUS_RING_GAP,
|
|
122
|
+
outlineColor: colors.border.focus,
|
|
123
|
+
outlineStyle: "solid",
|
|
124
|
+
borderRadius: radius
|
|
125
|
+
}), [colors.border.focus, radius]);
|
|
145
126
|
const glyph = useCallback(name => /*#__PURE__*/_jsx(Icon, {
|
|
146
127
|
name: name,
|
|
147
128
|
size: spec.iconSize,
|
|
148
129
|
color: foreground,
|
|
149
130
|
strokeWidth: ICON_STROKE
|
|
150
131
|
}), [spec.iconSize, foreground]);
|
|
151
|
-
|
|
152
|
-
// The spinner is never the sole loading signal — `accessibilityState.busy` announces it, and the
|
|
153
|
-
// label (when present) stays visible. Hidden from AT so it isn't read as a separate element.
|
|
154
132
|
const spinner = useMemo(() => /*#__PURE__*/_jsx(ActivityIndicator, {
|
|
155
133
|
size: "small",
|
|
156
134
|
color: foreground,
|
|
@@ -171,30 +149,38 @@ function ButtonImpl(props) {
|
|
|
171
149
|
disabled: a11y.disabled,
|
|
172
150
|
onPress: a11y.onPress,
|
|
173
151
|
onLongPress: onLongPress,
|
|
174
|
-
onPressIn:
|
|
152
|
+
onPressIn: press.handlers.onPressIn,
|
|
175
153
|
onPressOut: handlePressOut,
|
|
176
154
|
onHoverIn: onHoverIn,
|
|
177
155
|
onHoverOut: onHoverOut,
|
|
178
156
|
onFocus: handleFocus,
|
|
179
157
|
onBlur: handleBlur,
|
|
158
|
+
onLayout: press.onLayout,
|
|
180
159
|
hitSlop: spec.hitSlop,
|
|
160
|
+
android_ripple: androidRipple,
|
|
181
161
|
style: [buttonStructure(theme, {
|
|
182
162
|
variant,
|
|
183
163
|
size
|
|
184
|
-
}),
|
|
164
|
+
}), surfaceStyle, {
|
|
165
|
+
overflow: "hidden"
|
|
166
|
+
}, variant === "solid" && {
|
|
185
167
|
backgroundColor: toneColors.fill
|
|
186
168
|
}, variant === "outline" && {
|
|
187
169
|
borderColor: toneColors.border
|
|
188
170
|
}, iconOnly && {
|
|
189
171
|
paddingHorizontal: 0,
|
|
190
172
|
minWidth: spec.height
|
|
191
|
-
}, fullWidth && styles.fullWidth,
|
|
192
|
-
children: [/*#__PURE__*/_jsx(
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
173
|
+
}, fullWidth && styles.fullWidth, press.animatedStyle, focused && focusOutlineStyle, (disabled || loading) && styles.dimmed, style],
|
|
174
|
+
children: [variant === "solid" && /*#__PURE__*/_jsx(AccentGradientFill, {
|
|
175
|
+
color: toneColors.fill
|
|
176
|
+
}), focused && /*#__PURE__*/_jsx(Animated.View, {
|
|
177
|
+
pointerEvents: "none",
|
|
196
178
|
testID: "button-focus-ring",
|
|
197
|
-
style: focusRingStyle
|
|
179
|
+
style: [styles.focusRingHost, focusRingStaticStyle, focusRingStyle]
|
|
180
|
+
}), /*#__PURE__*/_jsx(Animated.View, {
|
|
181
|
+
pointerEvents: "none",
|
|
182
|
+
testID: "button-press-overlay",
|
|
183
|
+
style: [StyleSheet.absoluteFill, overlayStaticStyle, press.overlayStyle]
|
|
198
184
|
}), leading, label !== undefined && /*#__PURE__*/_jsx(Text, {
|
|
199
185
|
numberOfLines: 1,
|
|
200
186
|
style: [theme.fontStyleForWeight(theme.fontWeights.semibold), {
|
|
@@ -209,16 +195,16 @@ const styles = StyleSheet.create({
|
|
|
209
195
|
fullWidth: {
|
|
210
196
|
alignSelf: "stretch"
|
|
211
197
|
},
|
|
212
|
-
// A disabled control is exempt from the contrast minimum (WCAG 1.4.3), so a uniform dim is correct.
|
|
213
198
|
dimmed: {
|
|
214
199
|
opacity: 0.5
|
|
215
200
|
},
|
|
216
201
|
linkText: {
|
|
217
202
|
textDecorationLine: "underline"
|
|
203
|
+
},
|
|
204
|
+
focusRingHost: {
|
|
205
|
+
position: "absolute",
|
|
206
|
+
pointerEvents: "none"
|
|
218
207
|
}
|
|
219
208
|
});
|
|
220
|
-
|
|
221
|
-
// A consumer's screen re-renders far more often than Button's own props change — memo is near-free
|
|
222
|
-
// insurance for a design-system primitive (see CLAUDE.md "Performance — no unnecessary re-renders").
|
|
223
209
|
export const Button = /*#__PURE__*/memo(ButtonImpl);
|
|
224
210
|
//# sourceMappingURL=Button.js.map
|
|
@@ -31,22 +31,22 @@ const slopFor = height => Math.max(0, Math.ceil((MIN_TOUCH_TARGET - height) / 2)
|
|
|
31
31
|
*/
|
|
32
32
|
export const BUTTON_SIZES = {
|
|
33
33
|
sm: {
|
|
34
|
-
height:
|
|
34
|
+
height: 44,
|
|
35
35
|
fontSize: 14,
|
|
36
36
|
iconSize: 16,
|
|
37
|
-
hitSlop: slopFor(
|
|
37
|
+
hitSlop: slopFor(44)
|
|
38
38
|
},
|
|
39
39
|
md: {
|
|
40
|
-
height:
|
|
40
|
+
height: 52,
|
|
41
41
|
fontSize: 16,
|
|
42
42
|
iconSize: 18,
|
|
43
|
-
hitSlop: slopFor(
|
|
43
|
+
hitSlop: slopFor(52)
|
|
44
44
|
},
|
|
45
45
|
lg: {
|
|
46
|
-
height:
|
|
46
|
+
height: 56,
|
|
47
47
|
fontSize: 18,
|
|
48
48
|
iconSize: 20,
|
|
49
|
-
hitSlop: slopFor(
|
|
49
|
+
hitSlop: slopFor(56)
|
|
50
50
|
}
|
|
51
51
|
};
|
|
52
52
|
/**
|
|
@@ -136,7 +136,8 @@ export const buttonStructure = createThemedVariants(theme => ({
|
|
|
136
136
|
alignItems: "center",
|
|
137
137
|
justifyContent: "center",
|
|
138
138
|
columnGap: theme.space[2],
|
|
139
|
-
borderRadius: theme.radii.
|
|
139
|
+
borderRadius: theme.radii.md,
|
|
140
|
+
borderCurve: "continuous"
|
|
140
141
|
},
|
|
141
142
|
variants: {
|
|
142
143
|
size: {
|
|
@@ -98,6 +98,10 @@ label); `accent`/`danger` map to the accent and danger roles.
|
|
|
98
98
|
as optional peers); `Button.tsx` and `index.ts` import from there.
|
|
99
99
|
- `useReducedMotion` hoisted to `src/core/a11y/`.
|
|
100
100
|
|
|
101
|
+
Press feedback uses `usePressState` (Reanimated scale + state-layer overlay, width-aware).
|
|
102
|
+
Focus ring uses native `outline*` props animated via `useFocusRing`. Solid variant gets
|
|
103
|
+
`elevation.sm` + inset highlight; Android `android_ripple` on a clipped pressable.
|
|
104
|
+
|
|
101
105
|
## Performance
|
|
102
106
|
|
|
103
107
|
Wrapped in `React.memo` (repo-wide re-render audit, 2026-07-17 — see root `CLAUDE.md`) — renamed to `ButtonImpl` internally, exported as `Button = memo(ButtonImpl)`. Its one child, `Icon`, only ever receives primitives — nothing to memoize.
|
|
@@ -107,3 +111,5 @@ Wrapped in `React.memo` (repo-wide re-render audit, 2026-07-17 — see root `CLA
|
|
|
107
111
|
- Theme imports decoupled to `theme/hooks`; optional peers (reanimated, gesture-handler, flash-list) load at runtime.
|
|
108
112
|
- List-heavy surfaces use `VirtualList` with device-tier window sizing where applicable.
|
|
109
113
|
- `React.memo` + stable callbacks retained; render-item/key-extractor hoisted per ESLint perf rules.
|
|
114
|
+
|
|
115
|
+
- **Round 2 visual** — radii retarget (`radii.md`/`lg`/`xl`/`full`), `borderCurve: continuous` on md+ corners; floating surfaces wire platform elevation/highlight where applicable.
|
|
@@ -1,27 +1,14 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
* connected/segmented treatment is a different structural shape than Button's own pill/rect
|
|
7
|
-
* variants, so this is a standalone sibling (it never imports `../button`). The border/divider is
|
|
8
|
-
* drawn PER SEGMENT, not once on the container: every edge that touches the selected segment omits
|
|
9
|
-
* the stroke (see `resolveButtonGroupSegmentEdgeColors` — WCAG 1.4.11) and relies on the selected
|
|
10
|
-
* fill's own contrast against the canvas instead.
|
|
11
|
-
*
|
|
12
|
-
* One component owns the whole group, same as `RadioGroup`: each segment carries its own
|
|
13
|
-
* `accessibilityRole="radio"` + `accessibilityState.checked`, and the container carries
|
|
14
|
-
* `accessibilityRole="radiogroup"` so assistive tech announces the grouping without collapsing the
|
|
15
|
-
* individually-focusable segments into one.
|
|
16
|
-
*
|
|
17
|
-
* No animation anywhere, deliberately: selection is a conditional fill, and the segments share one
|
|
18
|
-
* continuous border, so a per-segment press scale (Button's affordance) would visibly detach a
|
|
19
|
-
* segment from the control it is part of. The `pressed` fill swap is the affordance instead. Nothing
|
|
20
|
-
* animates, so — like `RadioGroup` — there is nothing here for reduce motion (WCAG 2.3.3) to gate.
|
|
21
|
-
*/
|
|
3
|
+
// Segmented single-choice control: segments share one tonal container fill, not a bordered frame.
|
|
4
|
+
// A hairline divider sits between adjacent unselected segments, omitted at the selected edge (WCAG
|
|
5
|
+
// 1.4.11) — see `resolveButtonGroupSegmentEdgeColors`. Never imports `../button`; a different shape.
|
|
22
6
|
|
|
23
7
|
import { memo, useCallback, useMemo, useRef, useState } from "react";
|
|
24
|
-
import { Pressable, StyleSheet, Text, View } from "react-native";
|
|
8
|
+
import { Platform, Pressable, StyleSheet, Text, View } from "react-native";
|
|
9
|
+
import Animated from "react-native-reanimated";
|
|
10
|
+
import { usePressState } from "../../core/motion/usePressState.js";
|
|
11
|
+
import { rippleColor, stateLayerScrim } from "../../theme/platform/stateLayer.native.js";
|
|
25
12
|
import { useTheme } from "../../theme/hooks.js";
|
|
26
13
|
import { BUTTON_GROUP_SIZES, buttonGroupSegmentStructure, buttonGroupStructure, resolveButtonGroupColors, resolveButtonGroupKeyIndex, resolveButtonGroupSegmentAccessibility, resolveButtonGroupSegmentEdgeColors, resolveButtonGroupSegmentHitSlop } from "./ButtonGroup.variants.js";
|
|
27
14
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
@@ -38,6 +25,7 @@ const KeyboardView = View;
|
|
|
38
25
|
*/
|
|
39
26
|
const FOCUS_RING_WIDTH = 2;
|
|
40
27
|
const FOCUS_RING_INSET = 2;
|
|
28
|
+
const AnimatedPressable = Animated.createAnimatedComponent(Pressable);
|
|
41
29
|
function ButtonGroupSegmentImpl({
|
|
42
30
|
label,
|
|
43
31
|
value,
|
|
@@ -56,6 +44,7 @@ function ButtonGroupSegmentImpl({
|
|
|
56
44
|
testID
|
|
57
45
|
}) {
|
|
58
46
|
const theme = useTheme();
|
|
47
|
+
const press = usePressState(disabled || selected);
|
|
59
48
|
const [focused, setFocused] = useState(false);
|
|
60
49
|
const a11y = useMemo(() => resolveButtonGroupSegmentAccessibility({
|
|
61
50
|
selected,
|
|
@@ -69,6 +58,13 @@ function ButtonGroupSegmentImpl({
|
|
|
69
58
|
isFirst,
|
|
70
59
|
isLast
|
|
71
60
|
}), [size, isFirst, isLast]);
|
|
61
|
+
const androidRipple = useMemo(() => {
|
|
62
|
+
if (Platform.OS !== "android" || disabled || selected) return undefined;
|
|
63
|
+
return {
|
|
64
|
+
color: rippleColor(theme.mode),
|
|
65
|
+
borderless: false
|
|
66
|
+
};
|
|
67
|
+
}, [theme.mode, disabled, selected]);
|
|
72
68
|
const handlePress = useCallback(() => onValueChange(value), [onValueChange, value]);
|
|
73
69
|
const handleFocus = useCallback(() => setFocused(true), []);
|
|
74
70
|
const handleBlur = useCallback(() => setFocused(false), []);
|
|
@@ -84,29 +80,28 @@ function ButtonGroupSegmentImpl({
|
|
|
84
80
|
bottom: FOCUS_RING_INSET,
|
|
85
81
|
borderWidth: FOCUS_RING_WIDTH,
|
|
86
82
|
borderColor: theme.colors.border.focus,
|
|
87
|
-
borderRadius: Math.max(0, theme.radii.
|
|
88
|
-
}), [theme.colors.border.focus, theme.radii.
|
|
89
|
-
const segmentStyle =
|
|
90
|
-
pressed
|
|
91
|
-
}) => [buttonGroupSegmentStructure(theme, {
|
|
83
|
+
borderRadius: Math.max(0, theme.radii.md - FOCUS_RING_INSET)
|
|
84
|
+
}), [theme.colors.border.focus, theme.radii.md]);
|
|
85
|
+
const segmentStyle = useMemo(() => [buttonGroupSegmentStructure(theme, {
|
|
92
86
|
size,
|
|
93
87
|
first: isFirst ? "on" : "off",
|
|
94
88
|
last: isLast ? "on" : "off"
|
|
95
89
|
}), {
|
|
96
|
-
borderTopColor: edges.top,
|
|
97
|
-
borderBottomColor: edges.bottom,
|
|
98
|
-
borderLeftColor: edges.left,
|
|
99
90
|
borderRightColor: edges.right
|
|
100
91
|
}, selected ? {
|
|
101
92
|
backgroundColor: colors.selectedFill
|
|
102
|
-
} :
|
|
103
|
-
|
|
104
|
-
}, disabled && styles.dimmed], [theme, size, isFirst, isLast, edges, selected, disabled, colors]);
|
|
93
|
+
} : null, {
|
|
94
|
+
overflow: "hidden"
|
|
95
|
+
}, press.animatedStyle, disabled && styles.dimmed], [theme, size, isFirst, isLast, edges, selected, disabled, colors, press.animatedStyle]);
|
|
96
|
+
const overlayStaticStyle = useMemo(() => ({
|
|
97
|
+
backgroundColor: stateLayerScrim(theme.mode),
|
|
98
|
+
borderRadius: Math.max(0, theme.radii.md - FOCUS_RING_INSET)
|
|
99
|
+
}), [theme.mode, theme.radii.md]);
|
|
105
100
|
const labelStyle = useMemo(() => [theme.fontStyleForWeight(theme.fontWeights.medium), {
|
|
106
101
|
fontSize,
|
|
107
102
|
color: selected ? colors.onSelectedFill : colors.label
|
|
108
103
|
}], [theme, fontSize, selected, colors]);
|
|
109
|
-
return /*#__PURE__*/_jsxs(
|
|
104
|
+
return /*#__PURE__*/_jsxs(AnimatedPressable, {
|
|
110
105
|
ref: setRef,
|
|
111
106
|
testID: testID,
|
|
112
107
|
accessibilityRole: a11y.accessibilityRole,
|
|
@@ -114,17 +109,21 @@ function ButtonGroupSegmentImpl({
|
|
|
114
109
|
"aria-disabled": a11y["aria-disabled"],
|
|
115
110
|
accessibilityLabel: label,
|
|
116
111
|
disabled: a11y.disabled,
|
|
117
|
-
tabIndex: active && !disabled ? 0 : -1
|
|
118
|
-
// RN's Pressable stays `focusable` when disabled, so a TV remote could otherwise land on a
|
|
119
|
-
// segment that renders no ring (WCAG 2.4.7) — the same fix NumberInput's steppers use.
|
|
120
|
-
,
|
|
112
|
+
tabIndex: active && !disabled ? 0 : -1,
|
|
121
113
|
focusable: !disabled,
|
|
122
114
|
onFocus: handleFocus,
|
|
123
115
|
onBlur: handleBlur,
|
|
124
116
|
onPress: disabled ? undefined : handlePress,
|
|
117
|
+
onPressIn: press.handlers.onPressIn,
|
|
118
|
+
onPressOut: press.handlers.onPressOut,
|
|
119
|
+
onLayout: press.onLayout,
|
|
125
120
|
hitSlop: hitSlop,
|
|
121
|
+
android_ripple: androidRipple,
|
|
126
122
|
style: segmentStyle,
|
|
127
|
-
children: [
|
|
123
|
+
children: [!selected && /*#__PURE__*/_jsx(Animated.View, {
|
|
124
|
+
pointerEvents: "none",
|
|
125
|
+
style: [StyleSheet.absoluteFill, overlayStaticStyle, press.overlayStyle]
|
|
126
|
+
}), focused && !disabled && /*#__PURE__*/_jsx(View, {
|
|
128
127
|
testID: testID === undefined ? undefined : `${testID}-focus-ring`,
|
|
129
128
|
style: focusRingStyle
|
|
130
129
|
}), /*#__PURE__*/_jsx(Text, {
|
|
@@ -65,12 +65,7 @@ export function resolveButtonGroupColors(colors) {
|
|
|
65
65
|
selectedFill: colors.accent.solid,
|
|
66
66
|
onSelectedFill: colors.accent.onSolid,
|
|
67
67
|
label: colors.fg.default,
|
|
68
|
-
|
|
69
|
-
// drops the brand-tinted `fg.default` label below 4.5:1 on several brands — same class of bug
|
|
70
|
-
// Button's "neutral" tone and RadioGroup's pressed row document fixing the same way. Composited
|
|
71
|
-
// with a small `bg.canvas` overlay (see `PRESSED_FILL_OVERLAY_ALPHA_HEX` above) so it also clears
|
|
72
|
-
// 3:1 against `selectedFill` — the boundary a segment adjacent to the selected one actually draws
|
|
73
|
-
// while being pressed.
|
|
68
|
+
containerFill: colors.bg.raised,
|
|
74
69
|
pressedFill: compositeOver(`${colors.bg.canvas}${PRESSED_FILL_OVERLAY_ALPHA_HEX}`, colors.bg.sunken),
|
|
75
70
|
outline: colors.border.interactive
|
|
76
71
|
};
|
|
@@ -80,19 +75,9 @@ export function resolveButtonGroupColors(colors) {
|
|
|
80
75
|
* the WIDTH constant (see `buttonGroupSegmentStructure`) and only swapping the COLOUR avoids a
|
|
81
76
|
* layout shift when a segment's selection changes. */
|
|
82
77
|
const OMITTED_EDGE = "transparent";
|
|
83
|
-
/**
|
|
84
|
-
* Per-edge, per-segment outline colour — the WCAG 1.4.11 fix. An edge draws the shared `outline`
|
|
85
|
-
* colour only when BOTH sides of it are unselected; any edge touching the selected segment is
|
|
86
|
-
* `transparent` instead, so the selected fill's own contrast against the canvas (or, for the
|
|
87
|
-
* divider case, against the neighbour's transparent/canvas background) is what marks the boundary.
|
|
88
|
-
*/
|
|
89
78
|
export function resolveButtonGroupSegmentEdgeColors(colors, input) {
|
|
90
|
-
const own = input.selected ? OMITTED_EDGE : colors.outline;
|
|
91
79
|
const right = input.selected || input.nextSelected ? OMITTED_EDGE : colors.outline;
|
|
92
80
|
return {
|
|
93
|
-
top: own,
|
|
94
|
-
bottom: own,
|
|
95
|
-
left: own,
|
|
96
81
|
right
|
|
97
82
|
};
|
|
98
83
|
}
|
|
@@ -166,37 +151,29 @@ export function resolveButtonGroupKeyIndex(input) {
|
|
|
166
151
|
}
|
|
167
152
|
|
|
168
153
|
/**
|
|
169
|
-
* The container
|
|
170
|
-
*
|
|
171
|
-
*
|
|
172
|
-
*
|
|
173
|
-
* own: the outer border is drawn by the first/last segments themselves (see
|
|
174
|
-
* `buttonGroupSegmentStructure`), because only a per-segment border can be selectively omitted where
|
|
175
|
-
* it touches the selected segment (WCAG 1.4.11) — a single container-wide border is one colour for
|
|
176
|
-
* its entire perimeter and cannot vary by which segment it runs along.
|
|
154
|
+
* The container. `overflow: hidden` + `borderRadius` clips every segment's fill (and the outer
|
|
155
|
+
* segments' square corners) to one rounded shape, so the selected segment never pokes a corner past
|
|
156
|
+
* it. `backgroundColor: bg.raised` is the group's tonal frame — it replaces the old outer hairline,
|
|
157
|
+
* so unselected segments (transparent) read as sitting on one continuous raised surface.
|
|
177
158
|
*/
|
|
178
159
|
export const buttonGroupStructure = createThemedVariants(theme => ({
|
|
179
160
|
base: {
|
|
180
161
|
flexDirection: "row",
|
|
181
|
-
borderRadius: theme.radii.
|
|
182
|
-
|
|
162
|
+
borderRadius: theme.radii.md,
|
|
163
|
+
borderCurve: "continuous",
|
|
164
|
+
overflow: "hidden",
|
|
165
|
+
backgroundColor: theme.colors.bg.raised
|
|
183
166
|
}
|
|
184
167
|
}));
|
|
185
168
|
|
|
186
169
|
/**
|
|
187
170
|
* One segment's layout. `minWidth: MIN_TOUCH_TARGET` is the real ≥44dp touch-target floor for the
|
|
188
|
-
* WIDTH axis
|
|
189
|
-
* `resolveButtonGroupSegmentHitSlop`), so the rendered node itself must never shrink narrower than
|
|
190
|
-
* 44dp, for a realistic 2–4 option row at either size. `height` is fixed (not a minimum) so the
|
|
171
|
+
* WIDTH axis (see `resolveButtonGroupSegmentHitSlop`). `height` is fixed (not a minimum) so the
|
|
191
172
|
* vertical hitSlop math holds against what actually renders.
|
|
192
173
|
*
|
|
193
|
-
*
|
|
194
|
-
*
|
|
195
|
-
*
|
|
196
|
-
* edge); only the LAST segment gets right-corner radii (matching the container's own `borderRadius`,
|
|
197
|
-
* so that segment's own border curves rather than being clipped into an L by the container). Border
|
|
198
|
-
* WIDTHS are structural and constant; COLOURS (drawn vs `transparent`) are resolved per render by
|
|
199
|
-
* `resolveButtonGroupSegmentEdgeColors` and applied inline over this.
|
|
174
|
+
* Only a right border remains, structural on every segment but the last — the internal divider
|
|
175
|
+
* between two adjacent unselected segments (see `resolveButtonGroupSegmentEdgeColors`). There is no
|
|
176
|
+
* more top/bottom/left border: the container's own tonal fill carries the group's outer shape now.
|
|
200
177
|
*/
|
|
201
178
|
export const buttonGroupSegmentStructure = createThemedVariants(theme => ({
|
|
202
179
|
base: {
|
|
@@ -204,8 +181,6 @@ export const buttonGroupSegmentStructure = createThemedVariants(theme => ({
|
|
|
204
181
|
minWidth: MIN_TOUCH_TARGET,
|
|
205
182
|
alignItems: "center",
|
|
206
183
|
justifyContent: "center",
|
|
207
|
-
borderTopWidth: theme.borderWidths.thin,
|
|
208
|
-
borderBottomWidth: theme.borderWidths.thin,
|
|
209
184
|
borderRightWidth: theme.borderWidths.thin
|
|
210
185
|
},
|
|
211
186
|
variants: {
|
|
@@ -221,18 +196,18 @@ export const buttonGroupSegmentStructure = createThemedVariants(theme => ({
|
|
|
221
196
|
},
|
|
222
197
|
first: {
|
|
223
198
|
on: {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
199
|
+
borderTopLeftRadius: theme.radii.md,
|
|
200
|
+
borderBottomLeftRadius: theme.radii.md,
|
|
201
|
+
borderCurve: "continuous"
|
|
227
202
|
},
|
|
228
|
-
off: {
|
|
229
|
-
borderLeftWidth: 0
|
|
230
|
-
}
|
|
203
|
+
off: {}
|
|
231
204
|
},
|
|
232
205
|
last: {
|
|
233
206
|
on: {
|
|
234
|
-
borderTopRightRadius: theme.radii.
|
|
235
|
-
borderBottomRightRadius: theme.radii.
|
|
207
|
+
borderTopRightRadius: theme.radii.md,
|
|
208
|
+
borderBottomRightRadius: theme.radii.md,
|
|
209
|
+
borderCurve: "continuous",
|
|
210
|
+
borderRightWidth: 0
|
|
236
211
|
},
|
|
237
212
|
off: {}
|
|
238
213
|
}
|