@astryxdesign/core 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +156 -0
- package/dist/AlertDialog/AlertDialog.d.ts +10 -2
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +22 -3
- package/dist/AppShell/AppShell.d.ts +2 -2
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +40 -9
- package/dist/AspectRatio/AspectRatio.d.ts +13 -0
- package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
- package/dist/AspectRatio/AspectRatio.js +9 -0
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +33 -20
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +2 -3
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +15 -14
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +21 -8
- package/dist/Breadcrumbs/index.d.ts +2 -1
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +1 -0
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +11 -15
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +2 -1
- package/dist/Calendar/styles.d.ts +0 -2
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +0 -2
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +8 -12
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +2 -1
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +3 -1
- package/dist/Chat/ChatSendButton.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.js +4 -3
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +17 -17
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +2 -6
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +36 -125
- package/dist/ClickableCard/ClickableCard.d.ts.map +1 -1
- package/dist/ClickableCard/ClickableCard.js +3 -11
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +84 -67
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +35 -15
- package/dist/CommandPalette/CommandPaletteItem.d.ts +1 -1
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +6 -3
- package/dist/CommandPalette/CommandPaletteList.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +35 -33
- package/dist/ContextMenu/ContextMenu.d.ts +2 -2
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +1 -1
- package/dist/ContextMenu/index.d.ts +2 -1
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +1 -0
- package/dist/DateInput/DateInput.d.ts +9 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +24 -23
- package/dist/DateRangeInput/DateRangeInput.d.ts +9 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +11 -16
- package/dist/DateTimeInput/DateTimeInput.d.ts +9 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +22 -17
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +4 -4
- package/dist/DropdownMenu/DropdownMenu.d.ts +33 -8
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +62 -20
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +8 -11
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +32 -31
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts +25 -0
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuDivider.js +66 -0
- package/dist/DropdownMenu/DropdownMenuItem.d.ts +15 -2
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +20 -8
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +5 -5
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +24 -67
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +2 -8
- package/dist/DropdownMenu/index.d.ts +2 -1
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +4 -0
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +35 -27
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +9 -5
- package/dist/Field/InputClearButton.d.ts +16 -3
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +15 -4
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +3 -19
- package/dist/Indicator/CheckIndicator.d.ts +25 -0
- package/dist/Indicator/CheckIndicator.d.ts.map +1 -0
- package/dist/Indicator/CheckIndicator.js +155 -0
- package/dist/Indicator/CheckboxIndicator.d.ts +22 -0
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -0
- package/dist/Indicator/CheckboxIndicator.js +173 -0
- package/dist/Indicator/RadioIndicator.d.ts +23 -0
- package/dist/Indicator/RadioIndicator.d.ts.map +1 -0
- package/dist/Indicator/RadioIndicator.js +137 -0
- package/dist/Indicator/index.d.ts +24 -0
- package/dist/Indicator/index.d.ts.map +1 -0
- package/dist/Indicator/index.js +26 -0
- package/dist/Indicator/indicator.markers.stylex.d.ts +16 -0
- package/dist/Indicator/indicator.markers.stylex.d.ts.map +1 -0
- package/dist/Indicator/indicator.markers.stylex.js +21 -0
- package/dist/Indicator/indicatorRegistry.d.ts +71 -0
- package/dist/Indicator/indicatorRegistry.d.ts.map +1 -0
- package/dist/Indicator/indicatorRegistry.js +93 -0
- package/dist/Indicator/types.d.ts +167 -0
- package/dist/Indicator/types.d.ts.map +1 -0
- package/dist/Indicator/types.js +1 -0
- package/dist/Indicator/useIndicator.d.ts +18 -0
- package/dist/Indicator/useIndicator.d.ts.map +1 -0
- package/dist/Indicator/useIndicator.js +30 -0
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +4 -8
- package/dist/Layer/useLayer.d.ts +14 -0
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +25 -2
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +56 -53
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +4 -5
- package/dist/MobileNav/MobileNav.js +8 -8
- package/dist/MoreMenu/MoreMenu.d.ts +14 -1
- package/dist/MoreMenu/MoreMenu.d.ts.map +1 -1
- package/dist/MoreMenu/MoreMenu.js +4 -0
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +78 -75
- package/dist/NumberInput/NumberInput.d.ts +27 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +230 -42
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +2 -3
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +61 -63
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +6 -8
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +7 -0
- package/dist/ProgressBar/ProgressBar.d.ts +11 -4
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +96 -6
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +29 -84
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +2 -3
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +2 -3
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +3 -11
- package/dist/Selector/Selector.d.ts +2 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +164 -94
- package/dist/Selector/hooks.d.ts +18 -6
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +57 -40
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +1 -1
- package/dist/SideNav/SideNavCollapseButton.d.ts +1 -1
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +29 -14
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +56 -20
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +28 -22
- package/dist/Stack/stack.stylex.d.ts +3 -3
- package/dist/Switch/Switch.js +11 -10
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +2 -3
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +41 -19
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +8 -0
- package/dist/Table/index.d.ts +1 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +22 -18
- package/dist/Table/plugins/rowExpansion/index.d.ts +1 -1
- package/dist/Table/plugins/rowExpansion/index.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/index.js +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts +41 -76
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +94 -345
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +23 -4
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +29 -33
- package/dist/Table/tableContextMenu.d.ts.map +1 -1
- package/dist/Table/tableContextMenu.js +2 -1
- package/dist/Table/types.d.ts +11 -0
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/TextArea/TextArea.d.ts +10 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +16 -6
- package/dist/TextInput/TextInput.d.ts +10 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +13 -19
- package/dist/Thumbnail/Thumbnail.d.ts.map +1 -1
- package/dist/Thumbnail/Thumbnail.js +32 -26
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +7 -15
- package/dist/Timestamp/TimestampHoverCard.d.ts.map +1 -1
- package/dist/Timestamp/TimestampHoverCard.js +16 -34
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +20 -11
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +4 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +3 -19
- package/dist/TopNav/TopNav.d.ts.map +1 -1
- package/dist/TopNav/TopNav.js +6 -5
- package/dist/TopNav/TopNavHeading.d.ts.map +1 -1
- package/dist/TopNav/TopNavHeading.js +54 -16
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -9
- package/dist/TopNav/TopNavMegaMenu.d.ts +7 -0
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +146 -60
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +22 -3
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +83 -38
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +13 -0
- package/dist/TreeList/TreeListBranches.d.ts +1 -1
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +14 -4
- package/dist/TreeList/TreeListItem.d.ts +11 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +57 -30
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +16 -8
- package/dist/astryx.css +74 -85
- package/dist/astryx.umd.js +56 -56
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/containerReveal.stylex.d.ts +61 -0
- package/dist/hooks/containerReveal.stylex.d.ts.map +1 -0
- package/dist/hooks/containerReveal.stylex.js +63 -0
- package/dist/hooks/index.d.ts +3 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +2 -0
- package/dist/hooks/useClipboard.d.ts +59 -0
- package/dist/hooks/useClipboard.d.ts.map +1 -0
- package/dist/hooks/useClipboard.js +106 -0
- package/dist/hooks/useContainerReveal.d.ts +14 -8
- package/dist/hooks/useContainerReveal.d.ts.map +1 -1
- package/dist/hooks/useContainerReveal.js +28 -69
- package/dist/hooks/useIndicatorFocusRing.d.ts +28 -0
- package/dist/hooks/useIndicatorFocusRing.d.ts.map +1 -0
- package/dist/hooks/useIndicatorFocusRing.js +96 -0
- package/dist/hooks/useLongPress.d.ts.map +1 -1
- package/dist/hooks/useLongPress.js +12 -2
- package/dist/hooks/useScrollLock.d.ts.map +1 -1
- package/dist/hooks/useScrollLock.js +33 -18
- package/dist/hooks/useStreamingText.d.ts +18 -3
- package/dist/hooks/useStreamingText.d.ts.map +1 -1
- package/dist/hooks/useStreamingText.js +47 -7
- package/dist/hooks/useTreeFocus.d.ts.map +1 -1
- package/dist/hooks/useTreeFocus.js +9 -3
- package/dist/hooks/useTypeahead.d.ts +3 -2
- package/dist/hooks/useTypeahead.d.ts.map +1 -1
- package/dist/hooks/useTypeahead.js +19 -7
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/defineTheme.d.ts +16 -0
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +8 -0
- package/dist/theme/derivedVarRegistry.d.ts +8 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +14 -13
- package/dist/theme/expandColorScale.d.ts +3 -1
- package/dist/theme/expandColorScale.d.ts.map +1 -1
- package/dist/theme/expandColorScale.js +17 -7
- package/dist/theme/expandTypeScale.d.ts.map +1 -1
- package/dist/theme/expandTypeScale.js +17 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +11 -0
- package/dist/theme/index.d.ts +1 -0
- package/dist/theme/index.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.d.ts +107 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -0
- package/dist/utils/focusOutline.stylex.js +130 -0
- package/dist/utils/focusReturn.d.ts +24 -0
- package/dist/utils/focusReturn.d.ts.map +1 -0
- package/dist/utils/focusReturn.js +29 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +1 -0
- package/dist/utils/mergeRefs.d.ts.map +1 -1
- package/dist/utils/mergeRefs.js +7 -5
- package/dist/utils/rtlStyles.d.ts +2 -2
- package/dist/utils/rtlStyles.js +2 -2
- package/dist/utils/themeProps.d.ts +20 -1
- package/dist/utils/themeProps.d.ts.map +1 -1
- package/dist/utils/themeProps.js +8 -2
- package/locales/en.json +12 -0
- package/locales/pseudo.json +9 -0
- package/package.json +7 -2
- package/src/AlertDialog/AlertDialog.doc.mjs +16 -3
- package/src/AlertDialog/AlertDialog.test.tsx +208 -1
- package/src/AlertDialog/AlertDialog.tsx +21 -3
- package/src/AppShell/AppShell.doc.mjs +11 -0
- package/src/AppShell/AppShell.test.tsx +139 -0
- package/src/AppShell/AppShell.tsx +32 -22
- package/src/AspectRatio/AspectRatio.doc.mjs +27 -3
- package/src/AspectRatio/AspectRatio.test.tsx +30 -0
- package/src/AspectRatio/AspectRatio.tsx +13 -0
- package/src/Avatar/Avatar.doc.mjs +2 -13
- package/src/Avatar/Avatar.test.tsx +33 -8
- package/src/Avatar/Avatar.tsx +52 -50
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -9
- package/src/Banner/Banner.tsx +9 -6
- package/src/Breadcrumbs/BreadcrumbItem.tsx +16 -6
- package/src/Breadcrumbs/index.ts +5 -1
- package/src/Button/Button.tsx +21 -41
- package/src/Calendar/Calendar.tsx +2 -1
- package/src/Calendar/styles.ts +0 -8
- package/src/Carousel/Carousel.doc.mjs +3 -0
- package/src/Carousel/Carousel.tsx +10 -6
- package/src/Chat/Chat.doc.mjs +2 -0
- package/src/Chat/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatLayoutScrollButton.test.tsx +22 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +8 -1
- package/src/Chat/ChatSendButton.tsx +2 -3
- package/src/Chat/ChatToolCalls.test.tsx +35 -0
- package/src/Chat/ChatToolCalls.tsx +36 -16
- package/src/Chat/useTriggerMenu.tsx +2 -5
- package/src/CheckboxInput/CheckboxInput.doc.mjs +4 -2
- package/src/CheckboxInput/CheckboxInput.test.tsx +115 -0
- package/src/CheckboxInput/CheckboxInput.tsx +45 -202
- package/src/ClickableCard/ClickableCard.tsx +6 -11
- package/src/CodeBlock/CodeBlock.doc.mjs +3 -0
- package/src/CodeBlock/CodeBlock.test.tsx +91 -0
- package/src/CodeBlock/CodeBlock.tsx +57 -80
- package/src/Collapsible/Collapsible.tsx +22 -18
- package/src/CommandPalette/CommandPalette.test.tsx +29 -0
- package/src/CommandPalette/CommandPaletteItem.tsx +7 -4
- package/src/CommandPalette/CommandPaletteList.tsx +2 -2
- package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
- package/src/ComplexSelector/ComplexSelector.test.tsx +64 -0
- package/src/ComplexSelector/ComplexSelector.tsx +46 -29
- package/src/ContextMenu/ContextMenu.doc.mjs +1 -1
- package/src/ContextMenu/ContextMenu.test.tsx +41 -0
- package/src/ContextMenu/ContextMenu.tsx +3 -3
- package/src/ContextMenu/index.ts +5 -1
- package/src/DateInput/DateInput.doc.mjs +18 -3
- package/src/DateInput/DateInput.test.tsx +93 -11
- package/src/DateInput/DateInput.tsx +41 -19
- package/src/DateRangeInput/DateRangeInput.doc.mjs +10 -2
- package/src/DateRangeInput/DateRangeInput.test.tsx +110 -14
- package/src/DateRangeInput/DateRangeInput.tsx +24 -12
- package/src/DateTimeInput/DateTimeInput.doc.mjs +16 -2
- package/src/DateTimeInput/DateTimeInput.test.tsx +75 -0
- package/src/DateTimeInput/DateTimeInput.tsx +35 -8
- package/src/Dialog/Dialog.tsx +2 -9
- package/src/DropdownMenu/DropdownMenu.doc.mjs +5 -9
- package/src/DropdownMenu/DropdownMenu.test.tsx +534 -4
- package/src/DropdownMenu/DropdownMenu.tsx +113 -52
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +27 -30
- package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +34 -0
- package/src/DropdownMenu/DropdownMenuDivider.tsx +81 -0
- package/src/DropdownMenu/DropdownMenuItem.doc.mjs +39 -4
- package/src/DropdownMenu/DropdownMenuItem.tsx +48 -10
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +30 -76
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +25 -19
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +44 -14
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +1 -5
- package/src/DropdownMenu/index.ts +8 -1
- package/src/DropdownMenu/renderDropdownItems.tsx +33 -34
- package/src/EmptyState/EmptyState.doc.mjs +4 -0
- package/src/EmptyState/EmptyState.test.tsx +62 -0
- package/src/EmptyState/EmptyState.tsx +16 -6
- package/src/Field/Field.doc.mjs +1 -0
- package/src/Field/InputClearButton.test.tsx +117 -0
- package/src/Field/InputClearButton.tsx +30 -3
- package/src/HoverCard/useHoverCard.tsx +2 -23
- package/src/Icon/Icon.doc.mjs +2 -1
- package/src/Indicator/CheckIndicator.tsx +174 -0
- package/src/Indicator/CheckboxIndicator.tsx +257 -0
- package/src/Indicator/Indicator.doc.mjs +344 -0
- package/src/Indicator/Indicator.test.tsx +393 -0
- package/src/Indicator/RadioIndicator.tsx +206 -0
- package/src/Indicator/index.ts +45 -0
- package/src/Indicator/indicator.markers.stylex.ts +19 -0
- package/src/Indicator/indicatorRegistry.test.tsx +106 -0
- package/src/Indicator/indicatorRegistry.ts +120 -0
- package/src/Indicator/types.ts +186 -0
- package/src/Indicator/useIndicator.ts +39 -0
- package/src/Item/Item.doc.mjs +1 -1
- package/src/Item/Item.tsx +7 -14
- package/src/Layer/useLayer.doc.mjs +2 -2
- package/src/Layer/useLayer.test.tsx +85 -0
- package/src/Layer/useLayer.tsx +39 -1
- package/src/Lightbox/Lightbox.doc.mjs +1 -1
- package/src/Lightbox/Lightbox.tsx +43 -38
- package/src/Link/Link.tsx +4 -11
- package/src/MobileNav/MobileNav.tsx +3 -3
- package/src/MoreMenu/MoreMenu.doc.mjs +31 -0
- package/src/MoreMenu/MoreMenu.test.tsx +68 -1
- package/src/MoreMenu/MoreMenu.tsx +19 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +9 -1
- package/src/MultiSelector/MultiSelector.test.tsx +255 -16
- package/src/MultiSelector/MultiSelector.tsx +103 -99
- package/src/NumberInput/NumberInput.doc.mjs +265 -50
- package/src/NumberInput/NumberInput.test.tsx +726 -21
- package/src/NumberInput/NumberInput.tsx +353 -59
- package/src/Outline/Outline.tsx +2 -5
- package/src/Pagination/Pagination.doc.mjs +1 -1
- package/src/Pagination/Pagination.test.tsx +22 -7
- package/src/Pagination/Pagination.tsx +38 -35
- package/src/Popover/Popover.tsx +6 -7
- package/src/PowerSearch/PowerSearch.tsx +1 -1
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +42 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +7 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +27 -5
- package/src/ProgressBar/ProgressBar.test.tsx +224 -1
- package/src/ProgressBar/ProgressBar.tsx +124 -22
- package/src/RadioList/RadioList.doc.mjs +4 -2
- package/src/RadioList/RadioListItem.tsx +31 -130
- package/src/Resizable/ResizeHandle.tsx +2 -9
- package/src/SegmentedControl/SegmentedControlItem.tsx +2 -9
- package/src/SelectableCard/SelectableCard.tsx +4 -9
- package/src/Selector/Selector.doc.mjs +7 -4
- package/src/Selector/Selector.test.tsx +935 -25
- package/src/Selector/Selector.tsx +189 -106
- package/src/Selector/hooks.ts +77 -50
- package/src/SideNav/SideNav.test.tsx +46 -0
- package/src/SideNav/SideNav.tsx +1 -0
- package/src/SideNav/SideNavCollapseButton.tsx +15 -10
- package/src/SideNav/SideNavHeading.tsx +48 -10
- package/src/SideNav/SideNavItem.tsx +20 -12
- package/src/Stack/Stack.doc.mjs +110 -0
- package/src/StatusDot/StatusDot.doc.mjs +12 -3
- package/src/Switch/Switch.test.tsx +32 -0
- package/src/Switch/Switch.tsx +8 -8
- package/src/TabList/Tab.tsx +2 -9
- package/src/TabList/TabMenu.tsx +14 -21
- package/src/Table/BaseTable.tsx +11 -0
- package/src/Table/index.ts +1 -4
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +30 -14
- package/src/Table/plugins/rowExpansion/index.ts +1 -4
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +125 -175
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +115 -458
- package/src/Table/plugins/sortable/useTableSortable.tsx +2 -6
- package/src/Table/plugins/tree/useTableTreeData.tsx +43 -24
- package/src/Table/tableContextMenu.test.tsx +27 -0
- package/src/Table/tableContextMenu.tsx +1 -0
- package/src/Table/types.ts +11 -0
- package/src/Table/useTableGroupedRows.doc.mjs +1 -1
- package/src/Table/useTableRowExpansion.doc.mjs +43 -66
- package/src/TextArea/TextArea.doc.mjs +42 -2
- package/src/TextArea/TextArea.test.tsx +219 -0
- package/src/TextArea/TextArea.tsx +34 -7
- package/src/TextInput/TextInput.doc.mjs +18 -2
- package/src/TextInput/TextInput.test.tsx +189 -0
- package/src/TextInput/TextInput.tsx +25 -31
- package/src/Thumbnail/Thumbnail.tsx +2 -9
- package/src/TimeInput/TimeInput.doc.mjs +2 -2
- package/src/TimeInput/TimeInput.test.tsx +30 -3
- package/src/TimeInput/TimeInput.tsx +9 -26
- package/src/Timestamp/Timestamp.doc.mjs +4 -3
- package/src/Timestamp/TimestampHoverCard.tsx +13 -35
- package/src/Token/Token.tsx +5 -28
- package/src/Tokenizer/Tokenizer.doc.mjs +2 -2
- package/src/Tokenizer/Tokenizer.test.tsx +45 -3
- package/src/Tokenizer/Tokenizer.tsx +10 -2
- package/src/Tooltip/useTooltip.tsx +2 -23
- package/src/TopNav/TopNav.tsx +1 -3
- package/src/TopNav/TopNavHeading.tsx +42 -13
- package/src/TopNav/TopNavItem.tsx +3 -21
- package/src/TopNav/TopNavMegaMenu.test.tsx +433 -33
- package/src/TopNav/TopNavMegaMenu.tsx +118 -53
- package/src/TopNav/TopNavMegaMenuItem.tsx +2 -9
- package/src/TopNav/TopNavMenu.tsx +34 -37
- package/src/TreeList/TreeList.doc.mjs +5 -0
- package/src/TreeList/TreeList.test.tsx +206 -7
- package/src/TreeList/TreeList.tsx +22 -0
- package/src/TreeList/TreeListBranches.tsx +25 -2
- package/src/TreeList/TreeListItem.tsx +89 -52
- package/src/Typeahead/BaseTypeahead.tsx +19 -6
- package/src/Typeahead/Typeahead.doc.mjs +1 -0
- package/src/Typeahead/Typeahead.test.tsx +76 -3
- package/src/hooks/containerReveal.stylex.ts +102 -0
- package/src/hooks/index.ts +4 -0
- package/src/hooks/useClipboard.doc.mjs +87 -0
- package/src/hooks/useClipboard.test.tsx +151 -0
- package/src/hooks/useClipboard.ts +135 -0
- package/src/hooks/useContainerReveal.doc.mjs +7 -7
- package/src/hooks/useContainerReveal.test.tsx +42 -62
- package/src/hooks/useContainerReveal.ts +36 -91
- package/src/hooks/useImageMode.test.ts +1 -1
- package/src/hooks/useIndicatorFocusRing.tsx +120 -0
- package/src/hooks/useLongPress.test.tsx +18 -0
- package/src/hooks/useLongPress.ts +12 -2
- package/src/hooks/useScrollLock.test.ts +72 -0
- package/src/hooks/useScrollLock.ts +51 -19
- package/src/hooks/useStreamingText.test.ts +46 -1
- package/src/hooks/useStreamingText.ts +49 -7
- package/src/hooks/useTreeFocus.test.tsx +50 -0
- package/src/hooks/useTreeFocus.ts +14 -3
- package/src/hooks/useTypeahead.test.tsx +150 -0
- package/src/hooks/useTypeahead.ts +24 -9
- package/src/i18n/InternationalizationProvider.doc.mjs +7 -2
- package/src/index.ts +1 -0
- package/src/theme/defineTheme.ts +24 -0
- package/src/theme/derivedVarRegistry.test.ts +21 -1
- package/src/theme/derivedVarRegistry.ts +19 -6
- package/src/theme/expandColorScale.test.ts +14 -0
- package/src/theme/expandColorScale.ts +24 -9
- package/src/theme/expandTypeScale.test.ts +43 -0
- package/src/theme/expandTypeScale.ts +17 -0
- package/src/theme/generateThemeRules.test.ts +61 -20
- package/src/theme/generateThemeRules.ts +11 -0
- package/src/theme/index.ts +13 -0
- package/src/utils/focusOutline.stylex.ts +163 -0
- package/src/utils/focusReturn.test.ts +42 -0
- package/src/utils/focusReturn.ts +31 -0
- package/src/utils/index.ts +1 -0
- package/src/utils/mergeRefs.test.ts +48 -0
- package/src/utils/mergeRefs.ts +12 -6
- package/src/utils/rtlStyles.ts +2 -2
- package/src/utils/themeProps.ts +26 -4
- package/dist/CheckboxInput/checkbox.markers.stylex.d.ts +0 -9
- package/dist/CheckboxInput/checkbox.markers.stylex.d.ts.map +0 -1
- package/dist/CheckboxInput/checkbox.markers.stylex.js +0 -14
- package/dist/RadioList/radio.markers.stylex.d.ts +0 -7
- package/dist/RadioList/radio.markers.stylex.d.ts.map +0 -1
- package/dist/RadioList/radio.markers.stylex.js +0 -12
- package/dist/hooks/containerReveal.pool.stylex.d.ts +0 -303
- package/dist/hooks/containerReveal.pool.stylex.d.ts.map +0 -1
- package/dist/hooks/containerReveal.pool.stylex.js +0 -292
- package/src/CheckboxInput/checkbox.markers.stylex.ts +0 -12
- package/src/RadioList/radio.markers.stylex.ts +0 -10
- package/src/hooks/containerReveal.pool.stylex.ts +0 -571
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
import {describe, it, expect, vi, beforeEach, afterEach} from 'vitest';
|
|
4
4
|
import {renderHook, act} from '@testing-library/react';
|
|
5
|
-
import {useStreamingText} from './useStreamingText';
|
|
5
|
+
import {snapToGraphemeBoundary, useStreamingText} from './useStreamingText';
|
|
6
6
|
|
|
7
7
|
describe('useStreamingText', () => {
|
|
8
8
|
let rafCallbacks: ((time: number) => void)[];
|
|
@@ -189,4 +189,49 @@ describe('useStreamingText', () => {
|
|
|
189
189
|
// (or close to it — the hook drains charsPerTick per tickMs)
|
|
190
190
|
expect(result.current.length).toBeGreaterThan(targetText.length * 0.5);
|
|
191
191
|
});
|
|
192
|
+
|
|
193
|
+
it('never reveals a tick boundary landing mid-surrogate-pair or mid-ZWJ-emoji-sequence (#4779)', () => {
|
|
194
|
+
// natural speed advances 10 UTF-16 code units per tick. 9 ASCII chars
|
|
195
|
+
// (indices 0-8) followed by a 4-person ZWJ family emoji (indices 9-19,
|
|
196
|
+
// one grapheme cluster, 11 code units) means the first tick's raw
|
|
197
|
+
// boundary (index 10) lands one code unit into the family emoji's first
|
|
198
|
+
// surrogate pair -- exactly the failure case from the issue.
|
|
199
|
+
const family = '\u{1F468}\u{1F469}\u{1F467}\u{1F466}';
|
|
200
|
+
const targetText = 'a'.repeat(9) + family + 'end';
|
|
201
|
+
const {result} = renderHook(() => useStreamingText(targetText, true));
|
|
202
|
+
|
|
203
|
+
expect(rafCallbacks.length).toBeGreaterThan(0);
|
|
204
|
+
const cb = rafCallbacks.pop()!;
|
|
205
|
+
act(() => cb(performance.now() + 20));
|
|
206
|
+
|
|
207
|
+
// Without the fix this would be 'a'.repeat(9) + a lone high surrogate
|
|
208
|
+
// (renders as U+FFFD). With the fix, the whole not-yet-complete family
|
|
209
|
+
// cluster is held back rather than rendering a broken glyph.
|
|
210
|
+
expect(result.current).toBe('a'.repeat(9));
|
|
211
|
+
});
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
describe('snapToGraphemeBoundary', () => {
|
|
215
|
+
it('does not split a surrogate pair', () => {
|
|
216
|
+
const text = 'a\u{1F389}b'; // 🎉 is a surrogate pair: indices 1 (high) and 2 (low)
|
|
217
|
+
expect(snapToGraphemeBoundary(text, 2)).toBe(1);
|
|
218
|
+
expect(snapToGraphemeBoundary(text, 1)).toBe(1);
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
it('does not split a ZWJ emoji sequence', () => {
|
|
222
|
+
const family = '\u{1F468}\u{1F469}\u{1F467}\u{1F466}';
|
|
223
|
+
const text = 'x' + family + 'y';
|
|
224
|
+
const familyStart = 1;
|
|
225
|
+
const familyEnd = 1 + family.length;
|
|
226
|
+
for (let offset = familyStart + 1; offset < familyEnd; offset++) {
|
|
227
|
+
expect(snapToGraphemeBoundary(text, offset)).toBe(familyStart);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
|
|
231
|
+
it('leaves boundary offsets (start, end, plain-ASCII midpoints) unchanged', () => {
|
|
232
|
+
const text = 'hello';
|
|
233
|
+
expect(snapToGraphemeBoundary(text, 0)).toBe(0);
|
|
234
|
+
expect(snapToGraphemeBoundary(text, 5)).toBe(5);
|
|
235
|
+
expect(snapToGraphemeBoundary(text, 3)).toBe(3);
|
|
236
|
+
});
|
|
192
237
|
});
|
|
@@ -9,9 +9,12 @@
|
|
|
9
9
|
* @position Core hook; smooths bursty streamed text into steady character reveal
|
|
10
10
|
*
|
|
11
11
|
* Decouples the arrival rate of streamed chunks from the display rate,
|
|
12
|
-
* draining characters at a steady pace using requestAnimationFrame.
|
|
13
|
-
*
|
|
14
|
-
*
|
|
12
|
+
* draining characters at a steady pace using requestAnimationFrame. The
|
|
13
|
+
* reveal cadence advances by a fixed number of UTF-16 code units per tick;
|
|
14
|
+
* the rendered slice is then snapped back to the nearest grapheme cluster
|
|
15
|
+
* boundary (see snapToGraphemeBoundary) so a tick landing inside a
|
|
16
|
+
* surrogate pair, flag sequence, or ZWJ emoji doesn't render a lone
|
|
17
|
+
* surrogate or a partial glyph for one frame.
|
|
15
18
|
*
|
|
16
19
|
* Animation timing derives from Astryx motion tokens (via useTheme) when
|
|
17
20
|
* an Theme provider is present. Falls back to sensible defaults when
|
|
@@ -68,6 +71,43 @@ const CHARS_PER_TICK = {
|
|
|
68
71
|
instant: Infinity,
|
|
69
72
|
} as const;
|
|
70
73
|
|
|
74
|
+
// Reuse a single segmenter when the runtime supports Intl.Segmenter.
|
|
75
|
+
// Granularity is fixed and locale doesn't affect grapheme-cluster
|
|
76
|
+
// boundaries, so one instance is safe to share across calls.
|
|
77
|
+
const graphemeSegmenter =
|
|
78
|
+
typeof Intl.Segmenter === 'function'
|
|
79
|
+
? new Intl.Segmenter(undefined, {granularity: 'grapheme'})
|
|
80
|
+
: null;
|
|
81
|
+
|
|
82
|
+
function isLowSurrogate(codeUnit: number): boolean {
|
|
83
|
+
return codeUnit >= 0xdc00 && codeUnit <= 0xdfff;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Snap a UTF-16 code-unit offset down to the start of the grapheme cluster
|
|
88
|
+
* it falls inside, so slicing `text` at the returned offset never splits a
|
|
89
|
+
* surrogate pair, flag sequence, or ZWJ emoji mid-glyph. Offsets at the
|
|
90
|
+
* start/end of the string are returned unchanged (nothing to snap).
|
|
91
|
+
*
|
|
92
|
+
* Falls back to snapping off a lone low surrogate when `Intl.Segmenter` is
|
|
93
|
+
* unavailable — narrower than full grapheme-cluster awareness (a ZWJ
|
|
94
|
+
* sequence or flag pair can still split in that path), but it's what's
|
|
95
|
+
* achievable without a full grapheme-aware dependency, and it's strictly
|
|
96
|
+
* better than the unguarded default of never checking at all.
|
|
97
|
+
*/
|
|
98
|
+
export function snapToGraphemeBoundary(text: string, offset: number): number {
|
|
99
|
+
if (offset <= 0 || offset >= text.length) {
|
|
100
|
+
return offset;
|
|
101
|
+
}
|
|
102
|
+
if (graphemeSegmenter) {
|
|
103
|
+
// `containing` only returns undefined for an out-of-range index; offset
|
|
104
|
+
// is already guarded to [1, text.length - 1] above, so this is always
|
|
105
|
+
// defined at runtime — the `??` is to satisfy the type, which is wider.
|
|
106
|
+
return graphemeSegmenter.segment(text).containing(offset)?.index ?? offset;
|
|
107
|
+
}
|
|
108
|
+
return isLowSurrogate(text.charCodeAt(offset)) ? offset - 1 : offset;
|
|
109
|
+
}
|
|
110
|
+
|
|
71
111
|
/**
|
|
72
112
|
* Smooths bursty streamed text into a steady character-by-character reveal.
|
|
73
113
|
*
|
|
@@ -76,9 +116,11 @@ const CHARS_PER_TICK = {
|
|
|
76
116
|
* reduced motion, the progressive reveal is skipped entirely and the full
|
|
77
117
|
* `targetText` is returned immediately.
|
|
78
118
|
*
|
|
79
|
-
* The
|
|
80
|
-
*
|
|
81
|
-
*
|
|
119
|
+
* The reveal cadence itself advances by a fixed number of UTF-16 code units
|
|
120
|
+
* per tick, not on word or markdown-syntax boundaries — but the rendered
|
|
121
|
+
* slice is always snapped back to the nearest grapheme cluster boundary, so
|
|
122
|
+
* a tick landing mid-surrogate-pair or mid-emoji-sequence never renders a
|
|
123
|
+
* broken glyph.
|
|
82
124
|
*
|
|
83
125
|
* @example
|
|
84
126
|
* ```
|
|
@@ -191,5 +233,5 @@ export function useStreamingText(
|
|
|
191
233
|
return targetText;
|
|
192
234
|
}
|
|
193
235
|
|
|
194
|
-
return targetText.slice(0, displayedLen);
|
|
236
|
+
return targetText.slice(0, snapToGraphemeBoundary(targetText, displayedLen));
|
|
195
237
|
}
|
|
@@ -261,4 +261,54 @@ describe('useTreeFocus activation + typeahead', () => {
|
|
|
261
261
|
fireEvent.keyDown(tree, {key: 'c'});
|
|
262
262
|
expect(screen.getByTestId('c')).toHaveFocus();
|
|
263
263
|
});
|
|
264
|
+
|
|
265
|
+
it('typeahead cycles through same-letter matches on repeated presses', () => {
|
|
266
|
+
const nodes: Node[] = [
|
|
267
|
+
{id: 'apple', label: 'Apple', level: 1},
|
|
268
|
+
{id: 'apricot', label: 'Apricot', level: 1},
|
|
269
|
+
{id: 'avocado', label: 'Avocado', level: 1},
|
|
270
|
+
];
|
|
271
|
+
render(<Tree collapsed={nodes} />);
|
|
272
|
+
const tree = screen.getByRole('tree');
|
|
273
|
+
screen.getByTestId('apple').focus();
|
|
274
|
+
|
|
275
|
+
fireEvent.keyDown(tree, {key: 'a'});
|
|
276
|
+
expect(screen.getByTestId('apricot')).toHaveFocus();
|
|
277
|
+
|
|
278
|
+
// A repeat must cycle, not extend the query to "aa" (as useTypeahead does).
|
|
279
|
+
fireEvent.keyDown(tree, {key: 'a'});
|
|
280
|
+
expect(screen.getByTestId('avocado')).toHaveFocus();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('typeahead searches from the top when no treeitem has focus', () => {
|
|
284
|
+
const nodes: Node[] = [
|
|
285
|
+
{id: 'apple', label: 'Apple', level: 1},
|
|
286
|
+
{id: 'banana', label: 'Banana', level: 1},
|
|
287
|
+
{id: 'avocado', label: 'Avocado', level: 1},
|
|
288
|
+
];
|
|
289
|
+
render(<Tree collapsed={nodes} />);
|
|
290
|
+
const tree = screen.getByRole('tree');
|
|
291
|
+
|
|
292
|
+
// No .focus() call: with no current item, the first match must win.
|
|
293
|
+
fireEvent.keyDown(tree, {key: 'a'});
|
|
294
|
+
expect(screen.getByTestId('apple')).toHaveFocus();
|
|
295
|
+
});
|
|
296
|
+
|
|
297
|
+
it('typeahead keeps focus on an item that still matches the refined buffer', () => {
|
|
298
|
+
const nodes: Node[] = [
|
|
299
|
+
{id: 'apple', label: 'Apple', level: 1},
|
|
300
|
+
{id: 'banana', label: 'Banana', level: 1},
|
|
301
|
+
{id: 'apricot', label: 'Apricot', level: 1},
|
|
302
|
+
];
|
|
303
|
+
render(<Tree collapsed={nodes} />);
|
|
304
|
+
const tree = screen.getByRole('tree');
|
|
305
|
+
screen.getByTestId('apple').focus();
|
|
306
|
+
|
|
307
|
+
fireEvent.keyDown(tree, {key: 'a'});
|
|
308
|
+
expect(screen.getByTestId('apricot')).toHaveFocus();
|
|
309
|
+
|
|
310
|
+
// "ap" refines the search; Apricot still matches, so focus holds.
|
|
311
|
+
fireEvent.keyDown(tree, {key: 'p'});
|
|
312
|
+
expect(screen.getByTestId('apricot')).toHaveFocus();
|
|
313
|
+
});
|
|
264
314
|
});
|
|
@@ -377,14 +377,25 @@ export function useTreeFocus<T extends HTMLElement = HTMLElement>(
|
|
|
377
377
|
if (state.timer != null) {
|
|
378
378
|
clearTimeout(state.timer);
|
|
379
379
|
}
|
|
380
|
-
|
|
380
|
+
// "aa" would match nothing; a repeat means "next match" (useTypeahead).
|
|
381
|
+
const char = e.key.toLowerCase();
|
|
382
|
+
const isRepeatSameChar =
|
|
383
|
+
state.buffer.length > 0 &&
|
|
384
|
+
state.buffer.split('').every(c => c === char);
|
|
385
|
+
state.buffer = isRepeatSameChar ? char : state.buffer + char;
|
|
381
386
|
state.timer = setTimeout(() => {
|
|
382
387
|
typeaheadRef.current.buffer = '';
|
|
383
388
|
}, typeaheadResetMs) as unknown as number;
|
|
384
389
|
|
|
385
390
|
const query = state.buffer;
|
|
386
|
-
|
|
387
|
-
const
|
|
391
|
+
// A longer query is refining, so the current item may still be the match.
|
|
392
|
+
const hasCurrent = currentIndex >= 0;
|
|
393
|
+
const start = hasCurrent ? currentIndex : 0;
|
|
394
|
+
const offset = hasCurrent && query.length === 1 ? 1 : 0;
|
|
395
|
+
const ordered = [
|
|
396
|
+
...items.slice(start + offset),
|
|
397
|
+
...items.slice(0, start + offset),
|
|
398
|
+
];
|
|
388
399
|
const match = ordered.find(
|
|
389
400
|
item =>
|
|
390
401
|
!itemDisabled(item) &&
|
|
@@ -106,4 +106,154 @@ describe('useTypeahead', () => {
|
|
|
106
106
|
expect(api.onKeyDown(key(' '))).toBe(false);
|
|
107
107
|
expect(onMatch).not.toHaveBeenCalled();
|
|
108
108
|
});
|
|
109
|
+
|
|
110
|
+
it('extends a live buffer with a space', () => {
|
|
111
|
+
const onMatch = vi.fn();
|
|
112
|
+
const {result} = renderHook(() =>
|
|
113
|
+
useTypeahead({
|
|
114
|
+
getItemLabels: () => ['Newark', 'New York'],
|
|
115
|
+
onMatch,
|
|
116
|
+
}),
|
|
117
|
+
);
|
|
118
|
+
for (const k of 'new ') {
|
|
119
|
+
result.current.onKeyDown(key(k));
|
|
120
|
+
}
|
|
121
|
+
result.current.onKeyDown(key('y'));
|
|
122
|
+
// "new y" reaches New York; a space that ended the buffer instead would
|
|
123
|
+
// leave "newy", which matches nothing.
|
|
124
|
+
expect(onMatch).toHaveBeenLastCalledWith(1);
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
it('ignores a Space chorded with ctrl or meta even mid-buffer', () => {
|
|
128
|
+
const onMatch = vi.fn();
|
|
129
|
+
const {result} = renderHook(() =>
|
|
130
|
+
useTypeahead({
|
|
131
|
+
getItemLabels: () => ['Melon', 'New York'],
|
|
132
|
+
onMatch,
|
|
133
|
+
}),
|
|
134
|
+
);
|
|
135
|
+
expect(result.current.onKeyDown(key('n'))).toBe(true);
|
|
136
|
+
expect(onMatch).toHaveBeenLastCalledWith(1);
|
|
137
|
+
|
|
138
|
+
// A chord is not typing. Consuming it would append a raw space and leave
|
|
139
|
+
// the buffer as "n ", poisoning every keystroke until the reset window.
|
|
140
|
+
expect(
|
|
141
|
+
result.current.onKeyDown(
|
|
142
|
+
new KeyboardEvent('keydown', {key: ' ', ctrlKey: true}),
|
|
143
|
+
),
|
|
144
|
+
).toBe(false);
|
|
145
|
+
expect(
|
|
146
|
+
result.current.onKeyDown(
|
|
147
|
+
new KeyboardEvent('keydown', {key: ' ', metaKey: true}),
|
|
148
|
+
),
|
|
149
|
+
).toBe(false);
|
|
150
|
+
|
|
151
|
+
result.current.onKeyDown(key('e'));
|
|
152
|
+
expect(onMatch).toHaveBeenCalledTimes(2);
|
|
153
|
+
expect(onMatch).toHaveBeenLastCalledWith(1);
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it('starts a fresh single-character search after the current item', () => {
|
|
157
|
+
const {onMatch, api} = setup({current: 0}); // Apple is current
|
|
158
|
+
api.onKeyDown(key('a'));
|
|
159
|
+
// A single-character search begins at current + 1, so pressing the current
|
|
160
|
+
// item's own initial advances instead of re-matching it into a dead key.
|
|
161
|
+
expect(onMatch).toHaveBeenCalledWith(1); // Apricot
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
it('searches from the top when there is no current item', () => {
|
|
165
|
+
// The last item also matches, so this distinguishes "from the top" from
|
|
166
|
+
// wrapping backwards off -1 and hitting the bottom of the list first.
|
|
167
|
+
const onMatch = vi.fn();
|
|
168
|
+
const {result} = renderHook(() =>
|
|
169
|
+
useTypeahead({
|
|
170
|
+
getItemLabels: () => ['Apple', 'Berry', 'Avocado'],
|
|
171
|
+
onMatch,
|
|
172
|
+
getCurrentIndex: () => -1,
|
|
173
|
+
}),
|
|
174
|
+
);
|
|
175
|
+
result.current.onKeyDown(key('a'));
|
|
176
|
+
expect(onMatch).toHaveBeenCalledWith(0); // Apple, not Avocado
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
it('keeps the current item in range once the buffer is multi-character', () => {
|
|
180
|
+
const {onMatch, api} = setup({current: 0});
|
|
181
|
+
api.onKeyDown(key('a')); // single char: advances to Apricot
|
|
182
|
+
expect(onMatch).toHaveBeenLastCalledWith(1);
|
|
183
|
+
api.onKeyDown(key('p')); // "ap" refines, so Apple is a candidate again
|
|
184
|
+
expect(onMatch).toHaveBeenLastCalledWith(0);
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
it('skips unmatchable label slots without shifting the reported index', () => {
|
|
188
|
+
// Callers may pass null/empty entries to keep the index mapping 1:1 with
|
|
189
|
+
// their own items — menus pass el.textContent, which can be null.
|
|
190
|
+
const onMatch = vi.fn();
|
|
191
|
+
const {result} = renderHook(() =>
|
|
192
|
+
useTypeahead({
|
|
193
|
+
getItemLabels: () => [null, '', ' ', undefined, 'Apple'],
|
|
194
|
+
onMatch,
|
|
195
|
+
}),
|
|
196
|
+
);
|
|
197
|
+
result.current.onKeyDown(key('a'));
|
|
198
|
+
expect(onMatch).toHaveBeenCalledWith(4);
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('treats any negative or stale current index safely', () => {
|
|
202
|
+
// A sentinel other than -1, and an index left over from a longer list:
|
|
203
|
+
// neither may search backwards or report an index outside the list.
|
|
204
|
+
const fromBelowZero = vi.fn();
|
|
205
|
+
const {result: below} = renderHook(() =>
|
|
206
|
+
useTypeahead({
|
|
207
|
+
getItemLabels: () => LABELS,
|
|
208
|
+
onMatch: fromBelowZero,
|
|
209
|
+
getCurrentIndex: () => -5,
|
|
210
|
+
}),
|
|
211
|
+
);
|
|
212
|
+
below.current.onKeyDown(key('a'));
|
|
213
|
+
expect(fromBelowZero).toHaveBeenCalledWith(0); // Apple, from the top
|
|
214
|
+
|
|
215
|
+
const fromStale = vi.fn();
|
|
216
|
+
const {result: stale} = renderHook(() =>
|
|
217
|
+
useTypeahead({
|
|
218
|
+
getItemLabels: () => LABELS,
|
|
219
|
+
onMatch: fromStale,
|
|
220
|
+
getCurrentIndex: () => 7,
|
|
221
|
+
}),
|
|
222
|
+
);
|
|
223
|
+
stale.current.onKeyDown(key('b'));
|
|
224
|
+
expect(fromStale).toHaveBeenCalledWith(2); // Banana, in range
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it('wraps onto the only item when the list has one entry', () => {
|
|
228
|
+
// "Advance past the current item" is about cycling; with one item the
|
|
229
|
+
// cycle is itself. The caller decides whether that is a no-op.
|
|
230
|
+
const onMatch = vi.fn();
|
|
231
|
+
const {result} = renderHook(() =>
|
|
232
|
+
useTypeahead({
|
|
233
|
+
getItemLabels: () => ['Apple'],
|
|
234
|
+
onMatch,
|
|
235
|
+
getCurrentIndex: () => 0,
|
|
236
|
+
}),
|
|
237
|
+
);
|
|
238
|
+
expect(result.current.onKeyDown(key('a'))).toBe(true);
|
|
239
|
+
expect(onMatch).toHaveBeenCalledWith(0);
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
it('matches characters composed with Option/Alt', () => {
|
|
243
|
+
const onMatch = vi.fn();
|
|
244
|
+
const {result} = renderHook(() =>
|
|
245
|
+
useTypeahead({
|
|
246
|
+
getItemLabels: () => ['Ångström', 'Berlin'],
|
|
247
|
+
onMatch,
|
|
248
|
+
getCurrentIndex: () => -1,
|
|
249
|
+
}),
|
|
250
|
+
);
|
|
251
|
+
// Option+a on macOS emits a printable 'å' with altKey set. Excluding it
|
|
252
|
+
// makes accented labels untypeable; real chords still carry ctrl/meta.
|
|
253
|
+
const handled = result.current.onKeyDown(
|
|
254
|
+
new KeyboardEvent('keydown', {key: 'å', altKey: true}),
|
|
255
|
+
);
|
|
256
|
+
expect(handled).toBe(true);
|
|
257
|
+
expect(onMatch).toHaveBeenCalledWith(0);
|
|
258
|
+
});
|
|
109
259
|
});
|
|
@@ -32,8 +32,9 @@ export interface UseTypeaheadOptions {
|
|
|
32
32
|
|
|
33
33
|
/**
|
|
34
34
|
* The index to start searching from — typically the currently focused item,
|
|
35
|
-
* so repeated presses of the same letter cycle through matches.
|
|
36
|
-
*
|
|
35
|
+
* so repeated presses of the same letter cycle through matches. Any negative
|
|
36
|
+
* value (the default) means nothing is current: the search runs from the top
|
|
37
|
+
* and never skips the first item.
|
|
37
38
|
*/
|
|
38
39
|
getCurrentIndex?: () => number;
|
|
39
40
|
|
|
@@ -67,9 +68,12 @@ export interface UseTypeaheadReturn {
|
|
|
67
68
|
function isPrintableCharacter(e: React.KeyboardEvent | KeyboardEvent): boolean {
|
|
68
69
|
return (
|
|
69
70
|
e.key.length === 1 &&
|
|
71
|
+
// Alt alone is not excluded: Option+letter on macOS composes a printable
|
|
72
|
+
// character (Option+a → "å"), and dropping those makes accented labels
|
|
73
|
+
// untypeable. Real chords still carry ctrl or meta — including AltGr,
|
|
74
|
+
// which sets ctrlKey on Windows and Linux.
|
|
70
75
|
!e.ctrlKey &&
|
|
71
76
|
!e.metaKey &&
|
|
72
|
-
!e.altKey &&
|
|
73
77
|
// A lone space is used for activation in menus, not typeahead-from-empty.
|
|
74
78
|
e.key !== ' '
|
|
75
79
|
);
|
|
@@ -133,8 +137,14 @@ export function useTypeahead(options: UseTypeaheadOptions): UseTypeaheadReturn {
|
|
|
133
137
|
const onKeyDown = useCallback(
|
|
134
138
|
(e: React.KeyboardEvent | KeyboardEvent): boolean => {
|
|
135
139
|
// A bare Space with no active buffer is not typeahead (menus activate on
|
|
136
|
-
// Space); once the user is mid-typing, Space extends the query.
|
|
137
|
-
|
|
140
|
+
// Space); once the user is mid-typing, Space extends the query. Chorded
|
|
141
|
+
// with ctrl or meta it is neither — that is an OS or IME shortcut, and
|
|
142
|
+
// consuming it would append a raw space that poisons the whole buffer.
|
|
143
|
+
const isSpaceMidType =
|
|
144
|
+
e.key === ' ' &&
|
|
145
|
+
!e.ctrlKey &&
|
|
146
|
+
!e.metaKey &&
|
|
147
|
+
bufferRef.current.length > 0;
|
|
138
148
|
if (!isPrintableCharacter(e) && !isSpaceMidType) {
|
|
139
149
|
return false;
|
|
140
150
|
}
|
|
@@ -154,11 +164,16 @@ export function useTypeahead(options: UseTypeaheadOptions): UseTypeaheadReturn {
|
|
|
154
164
|
bufferRef.current = nextBuffer;
|
|
155
165
|
scheduleReset();
|
|
156
166
|
|
|
157
|
-
const
|
|
167
|
+
const current = getCurrentIndex?.() ?? -1;
|
|
158
168
|
const count = labels.length;
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
169
|
+
const hasCurrent = current >= 0;
|
|
170
|
+
const start = hasCurrent ? current : 0;
|
|
171
|
+
// A single-character search starts AFTER the current item, so pressing a
|
|
172
|
+
// letter walks to the next item beginning with it instead of re-matching
|
|
173
|
+
// the one already selected (native <select> and APG getIndexByLetter).
|
|
174
|
+
// Once the buffer is longer it is refining a match, so the current item
|
|
175
|
+
// stays in range. With nothing current there is nothing to advance past.
|
|
176
|
+
const offset = hasCurrent && nextBuffer.length === 1 ? 1 : 0;
|
|
162
177
|
|
|
163
178
|
for (let i = 0; i < count; i++) {
|
|
164
179
|
const index = (start + offset + i + count) % count;
|
|
@@ -40,7 +40,7 @@ export const docs = {
|
|
|
40
40
|
{
|
|
41
41
|
guidance: true,
|
|
42
42
|
description:
|
|
43
|
-
'Set the `dir` attribute on `<html>` (or a wrapping element) yourself
|
|
43
|
+
'Set the `dir` attribute on `<html>` (or a wrapping element) yourself; the provider does not set it. Astryx components mirror layout and directional icons from the DOM `dir`, so an RTL locale won\'t visually mirror without it. Use `getLocaleDirection(locale)` to derive the value for both the provider and the DOM.',
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
46
|
guidance: false,
|
|
@@ -76,7 +76,7 @@ export const docs = {
|
|
|
76
76
|
type: "'ltr' | 'rtl'",
|
|
77
77
|
required: false,
|
|
78
78
|
description:
|
|
79
|
-
'Explicit text-direction override for the context. When omitted, direction is derived from `locale` via `Intl.Locale.getTextInfo()`. This sets the direction Astryx reads, but it does NOT set the DOM `dir` attribute
|
|
79
|
+
'Explicit text-direction override for the context. When omitted, direction is derived from `locale` via `Intl.Locale.getTextInfo()`. This sets the direction Astryx reads, but it does NOT set the DOM `dir` attribute; you must set `dir` on `<html>` (or a wrapping element) yourself, since Astryx components mirror layout and directional icons from the DOM `dir`, not from this prop. Set both to the same value and keep them in sync.',
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
name: 'children',
|
|
@@ -163,6 +163,11 @@ export const docsDense = {
|
|
|
163
163
|
description:
|
|
164
164
|
'Use real BCP 47 tags like `fr`, `pt-BR`, or `ar`; regional locales fall back to base language before English.',
|
|
165
165
|
},
|
|
166
|
+
{
|
|
167
|
+
guidance: true,
|
|
168
|
+
description:
|
|
169
|
+
'Set `dir` on `<html>` (or a wrapper) yourself; the provider does not. Astryx mirrors layout and directional icons from the DOM `dir`, so an RTL locale will not mirror without it. Use `getLocaleDirection(locale)` for both the provider and the DOM.',
|
|
170
|
+
},
|
|
166
171
|
{
|
|
167
172
|
guidance: false,
|
|
168
173
|
description:
|
package/src/index.ts
CHANGED
package/src/theme/defineTheme.ts
CHANGED
|
@@ -31,6 +31,7 @@
|
|
|
31
31
|
*/
|
|
32
32
|
|
|
33
33
|
import type {IconRegistry} from '../Icon/globalIconRegistry';
|
|
34
|
+
import type {IndicatorRegistry} from '../Indicator/types';
|
|
34
35
|
import type {TypographyConfig, FontWeight} from './types';
|
|
35
36
|
import {
|
|
36
37
|
resolveOnMedia,
|
|
@@ -280,6 +281,19 @@ export interface DefineThemeInput {
|
|
|
280
281
|
components?: ComponentStyleMap;
|
|
281
282
|
/** Icon registry — maps semantic icon names to React nodes */
|
|
282
283
|
icons?: Partial<IconRegistry>;
|
|
284
|
+
/**
|
|
285
|
+
* Indicator overrides — replaces the components that draw stateful control
|
|
286
|
+
* visuals with the theme's own, by name.
|
|
287
|
+
*
|
|
288
|
+
* Replacement is by indicator name, not per call site, so a single entry
|
|
289
|
+
* reaches every component that draws that indicator: mapping `check` to
|
|
290
|
+
* `RadioIndicator` gives radio visuals to every single-selection mark in the
|
|
291
|
+
* app.
|
|
292
|
+
*
|
|
293
|
+
* Each entry is checked against its indicator's family, so a replacement
|
|
294
|
+
* must accept the states that family passes.
|
|
295
|
+
*/
|
|
296
|
+
indicators?: IndicatorRegistry;
|
|
283
297
|
/**
|
|
284
298
|
* Default syntax highlighting theme for code components.
|
|
285
299
|
* Sets --color-syntax-* tokens at the theme root. Can be overridden
|
|
@@ -329,6 +343,8 @@ export interface DefinedTheme {
|
|
|
329
343
|
components?: ComponentStyleMap;
|
|
330
344
|
/** Icon registry */
|
|
331
345
|
icons?: Partial<IconRegistry>;
|
|
346
|
+
/** Indicator overrides for stateful control visuals, keyed by name */
|
|
347
|
+
indicators?: IndicatorRegistry;
|
|
332
348
|
/** Whether this theme has been pre-compiled by theme build CLI */
|
|
333
349
|
__built?: true;
|
|
334
350
|
/**
|
|
@@ -622,11 +638,19 @@ export function defineTheme(input: DefineThemeInput): DefinedTheme {
|
|
|
622
638
|
? {...base.icons, ...input.icons}
|
|
623
639
|
: (input.icons ?? base?.icons);
|
|
624
640
|
|
|
641
|
+
// Indicator overrides merge by name, like icons: a child theme replacing one
|
|
642
|
+
// indicator keeps the ones its base replaced.
|
|
643
|
+
const indicators =
|
|
644
|
+
input.indicators && base?.indicators
|
|
645
|
+
? {...base.indicators, ...input.indicators}
|
|
646
|
+
: (input.indicators ?? base?.indicators);
|
|
647
|
+
|
|
625
648
|
const theme: DefinedTheme = {
|
|
626
649
|
name: input.name,
|
|
627
650
|
tokens,
|
|
628
651
|
components,
|
|
629
652
|
icons,
|
|
653
|
+
indicators,
|
|
630
654
|
__inputTokens: input.tokens,
|
|
631
655
|
__onDark,
|
|
632
656
|
__onLight,
|
|
@@ -186,7 +186,6 @@ function discoverComponents(): ComponentInfo[] {
|
|
|
186
186
|
// ---------------------------------------------------------------------------
|
|
187
187
|
|
|
188
188
|
const DIR_TO_REGISTRY_KEY: Record<string, string> = {
|
|
189
|
-
Avatar: 'avatar',
|
|
190
189
|
Banner: 'banner',
|
|
191
190
|
Button: 'button',
|
|
192
191
|
Card: 'card',
|
|
@@ -196,8 +195,10 @@ const DIR_TO_REGISTRY_KEY: Record<string, string> = {
|
|
|
196
195
|
Field: 'field',
|
|
197
196
|
HoverCard: 'hovercard',
|
|
198
197
|
Popover: 'popover',
|
|
198
|
+
ProgressBar: 'progressbar-mark',
|
|
199
199
|
Section: 'section',
|
|
200
200
|
SegmentedControl: 'segmented-control',
|
|
201
|
+
TextArea: 'textarea',
|
|
201
202
|
};
|
|
202
203
|
|
|
203
204
|
/**
|
|
@@ -340,4 +341,23 @@ describe('getDerivedVars', () => {
|
|
|
340
341
|
it('returns empty for unregistered property', () => {
|
|
341
342
|
expect(getDerivedVars('card', 'color')).toEqual([]);
|
|
342
343
|
});
|
|
344
|
+
|
|
345
|
+
it('marks textarea paddingInline as replacing the source property', () => {
|
|
346
|
+
const result = getDerivedVars('textarea', 'paddingInline');
|
|
347
|
+
expect(result).toHaveLength(1);
|
|
348
|
+
expect(result[0].vars).toEqual(['--_textarea-inline-padding']);
|
|
349
|
+
expect(result[0].replaces).toBe(true);
|
|
350
|
+
});
|
|
351
|
+
|
|
352
|
+
it('marks progressbar-mark width and height as replacing the source property', () => {
|
|
353
|
+
for (const [property, varName] of [
|
|
354
|
+
['width', '--_progressbar-mark-width'],
|
|
355
|
+
['height', '--_progressbar-mark-height'],
|
|
356
|
+
]) {
|
|
357
|
+
const result = getDerivedVars('progressbar-mark', property);
|
|
358
|
+
expect(result).toHaveLength(1);
|
|
359
|
+
expect(result[0].vars).toEqual([varName]);
|
|
360
|
+
expect(result[0].replaces).toBe(true);
|
|
361
|
+
}
|
|
362
|
+
});
|
|
343
363
|
});
|
|
@@ -25,6 +25,14 @@ export interface DerivedVarEntry {
|
|
|
25
25
|
vars?: string[];
|
|
26
26
|
/** Named expansion strategy. 'container' expands padding to container tokens. */
|
|
27
27
|
expand?: 'container';
|
|
28
|
+
/**
|
|
29
|
+
* Emit only the internal `vars`, dropping the source property from the rule.
|
|
30
|
+
* Use when the class-carrying element must NOT receive the standard property
|
|
31
|
+
* itself — the value is consumed by a child through the var instead. Without
|
|
32
|
+
* this, the property is emitted alongside the var (correct when the same
|
|
33
|
+
* element both reads the var and applies the property, e.g. Chat/DropdownMenu).
|
|
34
|
+
*/
|
|
35
|
+
replaces?: boolean;
|
|
28
36
|
}
|
|
29
37
|
|
|
30
38
|
/**
|
|
@@ -35,12 +43,6 @@ export interface DerivedVarEntry {
|
|
|
35
43
|
* entries share the same property.
|
|
36
44
|
*/
|
|
37
45
|
export const derivedVarRegistry: Record<string, DerivedVarEntry[]> = {
|
|
38
|
-
avatar: [
|
|
39
|
-
{property: 'fontSize', vars: ['--_avatar-fallback-font-size']},
|
|
40
|
-
{property: 'fontWeight', vars: ['--_avatar-fallback-font-weight']},
|
|
41
|
-
{property: 'color', vars: ['--_avatar-fallback-color']},
|
|
42
|
-
{property: 'backgroundColor', vars: ['--_avatar-fallback-background']},
|
|
43
|
-
],
|
|
44
46
|
banner: [{property: 'borderRadius', vars: ['--_banner-radius']}],
|
|
45
47
|
button: [{property: 'borderRadius', vars: ['--_button-radius']}],
|
|
46
48
|
card: [
|
|
@@ -62,11 +64,22 @@ export const derivedVarRegistry: Record<string, DerivedVarEntry[]> = {
|
|
|
62
64
|
field: [{property: 'borderRadius', vars: ['--_field-radius']}],
|
|
63
65
|
hovercard: [{property: 'borderRadius', vars: ['--_hovercard-radius']}],
|
|
64
66
|
popover: [{property: 'borderRadius', vars: ['--_popover-radius']}],
|
|
67
|
+
'progressbar-mark': [
|
|
68
|
+
{property: 'width', vars: ['--_progressbar-mark-width'], replaces: true},
|
|
69
|
+
{property: 'height', vars: ['--_progressbar-mark-height'], replaces: true},
|
|
70
|
+
],
|
|
65
71
|
section: [{property: 'padding', expand: 'container'}],
|
|
66
72
|
'segmented-control': [
|
|
67
73
|
{property: 'borderRadius', vars: ['--_segmented-control-radius']},
|
|
68
74
|
{property: 'padding', vars: ['--_segmented-control-padding']},
|
|
69
75
|
],
|
|
76
|
+
textarea: [
|
|
77
|
+
{
|
|
78
|
+
property: 'paddingInline',
|
|
79
|
+
vars: ['--_textarea-inline-padding'],
|
|
80
|
+
replaces: true,
|
|
81
|
+
},
|
|
82
|
+
],
|
|
70
83
|
};
|
|
71
84
|
|
|
72
85
|
/**
|
|
@@ -100,6 +100,20 @@ describe('expandColorScale', () => {
|
|
|
100
100
|
standard['--color-text-primary'],
|
|
101
101
|
);
|
|
102
102
|
});
|
|
103
|
+
|
|
104
|
+
it('contrast high strengthens both border tokens', () => {
|
|
105
|
+
const standard = expandColorScale({
|
|
106
|
+
accent: '#0064E0',
|
|
107
|
+
contrast: 'standard',
|
|
108
|
+
});
|
|
109
|
+
const high = expandColorScale({accent: '#0064E0', contrast: 'high'});
|
|
110
|
+
// Both the subtle hairline and the emphasized border shift under high
|
|
111
|
+
// contrast, so structural boundaries stay perceivable.
|
|
112
|
+
expect(high['--color-border']).not.toBe(standard['--color-border']);
|
|
113
|
+
expect(high['--color-border-emphasized']).not.toBe(
|
|
114
|
+
standard['--color-border-emphasized'],
|
|
115
|
+
);
|
|
116
|
+
});
|
|
103
117
|
});
|
|
104
118
|
|
|
105
119
|
describe('expandColorScale — neutral-only themes (#2279)', () => {
|