@astryxdesign/core 0.7.1-canary.ff40b78 → 0.7.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/CHANGELOG.md +116 -0
- package/dist/Button/Button.d.ts +1 -1
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +5 -2
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +191 -32
- package/dist/Chat/ChatComposerInput.d.ts +9 -0
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +5 -0
- package/dist/Chat/ChatMessage.d.ts +11 -0
- package/dist/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/Chat/ChatMessage.js +18 -9
- package/dist/Chat/useTriggerMenu.d.ts +9 -2
- package/dist/Chat/useTriggerMenu.d.ts.map +1 -1
- package/dist/Chat/useTriggerMenu.js +222 -50
- package/dist/CodeBlock/CodeBlock.d.ts +10 -1
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +158 -38
- package/dist/CodeBlock/tokenizer.d.ts +39 -0
- package/dist/CodeBlock/tokenizer.d.ts.map +1 -1
- package/dist/CodeBlock/tokenizer.js +108 -0
- package/dist/CommandPalette/CommandPalette.d.ts +9 -5
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +38 -20
- package/dist/CommandPalette/CommandPaletteEmpty.d.ts +4 -3
- package/dist/CommandPalette/CommandPaletteEmpty.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteEmpty.js +4 -3
- package/dist/CommandPalette/CommandPaletteInput.d.ts +5 -4
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +35 -18
- package/dist/CommandPalette/CommandPaletteItem.d.ts +11 -6
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +8 -9
- package/dist/CommandPalette/CommandPaletteList.d.ts +4 -2
- package/dist/CommandPalette/CommandPaletteList.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteList.js +10 -5
- package/dist/ComplexSelector/ComplexSelector.d.ts +8 -5
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +12 -3
- package/dist/ContextMenu/ContextMenu.d.ts +3 -3
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +62 -48
- package/dist/DateInput/DateInput.js +1 -1
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +12 -4
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +12 -2
- package/dist/Dialog/Dialog.d.ts +1 -1
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +16 -5
- package/dist/Dialog/DialogHeader.d.ts +1 -1
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +7 -7
- package/dist/Divider/Divider.d.ts +1 -0
- package/dist/Divider/Divider.d.ts.map +1 -1
- package/dist/Divider/Divider.js +5 -4
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +161 -65
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +7 -5
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +12 -5
- package/dist/Field/InputClearButton.d.ts +8 -4
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +23 -7
- package/dist/FormLayout/FormLayout.d.ts.map +1 -1
- package/dist/FormLayout/FormLayout.js +1 -0
- package/dist/Grid/Grid.d.ts +13 -4
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +7 -1
- package/dist/HoverCard/useHoverCard.d.ts +1 -1
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +67 -49
- package/dist/InputGroup/InputGroup.d.ts +2 -4
- package/dist/InputGroup/InputGroup.d.ts.map +1 -1
- package/dist/InputGroup/InputGroup.js +2 -4
- package/dist/InputGroup/groupStyles.d.ts +10 -2
- package/dist/InputGroup/groupStyles.d.ts.map +1 -1
- package/dist/InputGroup/groupStyles.js +19 -2
- package/dist/Layer/useLayerDismissal.d.ts +9 -9
- package/dist/Layer/useLayerDismissal.js +9 -9
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +25 -4
- package/dist/MobileNav/MobileNav.d.ts +7 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +45 -2
- package/dist/MultiSelector/MultiSelector.d.ts +7 -4
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +24 -3
- package/dist/NumberInput/NumberInput.js +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +6 -0
- package/dist/Resizable/ResizeHandle.d.ts +1 -1
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +83 -15
- package/dist/Resizable/useResizable.d.ts +23 -0
- package/dist/Resizable/useResizable.d.ts.map +1 -1
- package/dist/Resizable/useResizable.js +78 -0
- package/dist/Selector/Selector.d.ts +6 -3
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +28 -6
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +10 -2
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +18 -7
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +16 -4
- package/dist/Toolbar/Toolbar.d.ts +2 -1
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +3 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +6 -3
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +7 -1
- package/dist/astryx.css +22 -0
- package/dist/hooks/useScrollOverflow.d.ts.map +1 -1
- package/dist/hooks/useScrollOverflow.js +55 -12
- package/dist/hooks/useTreeFocus.d.ts +21 -0
- package/dist/hooks/useTreeFocus.d.ts.map +1 -1
- package/dist/hooks/useTreeFocus.js +40 -2
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +3 -0
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +3 -0
- package/dist/reset.a11y.chromium.spec.js +6 -1
- package/dist/reset.until-found.a11y.browser.spec.d.ts +2 -0
- package/dist/reset.until-found.a11y.browser.spec.d.ts.map +1 -0
- package/dist/reset.until-found.a11y.browser.spec.js +71 -0
- package/dist/theme/syntax/SyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/SyntaxTheme.js +43 -2
- package/dist/theme/syntax/defineSyntaxTheme.d.ts +18 -5
- package/dist/theme/syntax/defineSyntaxTheme.d.ts.map +1 -1
- package/dist/theme/syntax/defineSyntaxTheme.js +38 -9
- package/dist/theme/syntax/index.d.ts +1 -1
- package/dist/theme/syntax/index.d.ts.map +1 -1
- package/dist/theme/syntax/tokens.d.ts +12 -2
- package/dist/theme/syntax/tokens.d.ts.map +1 -1
- package/dist/theme/syntax/tokens.js +25 -4
- package/dist/utils/plainDate.d.ts +12 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +63 -10
- package/locales/en.json +13 -1
- package/locales/pseudo.json +9 -0
- package/package.json +4 -4
- package/src/AlertDialog/AlertDialog.doc.mjs +6 -0
- package/src/AlertDialog/AlertDialog.spec.md +205 -0
- package/src/AlertDialog/AlertDialog.test.tsx +3 -14
- package/src/AlertDialog/__tests__/AlertDialog.a11y.chromium.spec.ts +115 -0
- package/src/AlertDialog/__tests__/AlertDialog.a11y.renders.tsx +52 -0
- package/src/AlertDialog/__tests__/AlertDialog.a11y.states.ts +68 -0
- package/src/AlertDialog/__tests__/AlertDialog.a11y.test.tsx +144 -0
- package/src/Button/Button.test.tsx +37 -0
- package/src/Button/Button.tsx +5 -1
- package/src/Calendar/Calendar.doc.mjs +234 -60
- package/src/Calendar/Calendar.spec.md +209 -0
- package/src/Calendar/Calendar.test.tsx +559 -20
- package/src/Calendar/Calendar.tsx +258 -41
- package/src/Calendar/__tests__/Calendar.a11y.chromium.spec.ts +126 -0
- package/src/Calendar/__tests__/Calendar.a11y.known-failures.ts +12 -0
- package/src/Calendar/__tests__/Calendar.a11y.renders.tsx +57 -0
- package/src/Calendar/__tests__/Calendar.a11y.states.ts +139 -0
- package/src/Calendar/__tests__/Calendar.a11y.test.tsx +137 -0
- package/src/Carousel/Carousel.test.tsx +54 -71
- package/src/Carousel/__tests__/Carousel.a11y.chromium.spec.ts +192 -0
- package/src/Carousel/__tests__/Carousel.a11y.known-failures.ts +27 -0
- package/src/Carousel/__tests__/Carousel.a11y.renders.tsx +39 -0
- package/src/Carousel/__tests__/Carousel.a11y.states.ts +139 -0
- package/src/Carousel/__tests__/Carousel.a11y.test.tsx +127 -0
- package/src/Chat/ChatComposerInput.doc.mjs +1 -1
- package/src/Chat/ChatComposerInput.spec.md +94 -55
- package/src/Chat/ChatComposerInput.test.tsx +202 -1
- package/src/Chat/ChatComposerInput.tsx +13 -0
- package/src/Chat/ChatMessage.doc.mjs +31 -16
- package/src/Chat/ChatMessage.spec.md +265 -0
- package/src/Chat/ChatMessage.test.tsx +246 -0
- package/src/Chat/ChatMessage.tsx +30 -7
- package/src/Chat/ChatSystemMessage.spec.md +36 -37
- package/src/Chat/ChatSystemMessage.test.tsx +4 -4
- package/src/Chat/useTriggerMenu.test.tsx +994 -0
- package/src/Chat/useTriggerMenu.tsx +278 -46
- package/src/CodeBlock/CodeBlock.doc.mjs +7 -0
- package/src/CodeBlock/CodeBlock.spec.md +40 -41
- package/src/CodeBlock/CodeBlock.test.tsx +89 -9
- package/src/CodeBlock/CodeBlock.tsx +205 -25
- package/src/CodeBlock/__tests__/CodeBlockOverflowStop.a11y.chromium.spec.ts +125 -0
- package/src/CodeBlock/__tests__/DiffRowPaint.a11y.chromium.spec.ts +93 -0
- package/src/CodeBlock/tokenizer.test.ts +112 -0
- package/src/CodeBlock/tokenizer.ts +106 -0
- package/src/Collapsible/CollapsibleGroup.spec.md +17 -8
- package/src/Collapsible/__tests__/CollapsibleGroup.a11y.renders.tsx +45 -0
- package/src/Collapsible/__tests__/CollapsibleGroup.a11y.states.ts +139 -0
- package/src/Collapsible/__tests__/CollapsibleGroup.a11y.test.tsx +135 -0
- package/src/Collapsible/__tests__/CollapsibleGroupAccordion.a11y.chromium.spec.ts +128 -0
- package/src/CommandPalette/CommandPalette.doc.mjs +126 -23
- package/src/CommandPalette/CommandPalette.spec.md +100 -49
- package/src/CommandPalette/CommandPalette.test.tsx +241 -2
- package/src/CommandPalette/CommandPalette.tsx +47 -21
- package/src/CommandPalette/CommandPaletteEmpty.tsx +4 -3
- package/src/CommandPalette/CommandPaletteInput.doc.mjs +61 -4
- package/src/CommandPalette/CommandPaletteInput.spec.md +215 -0
- package/src/CommandPalette/CommandPaletteInput.test.tsx +375 -51
- package/src/CommandPalette/CommandPaletteInput.tsx +74 -21
- package/src/CommandPalette/CommandPaletteItem.doc.mjs +73 -22
- package/src/CommandPalette/CommandPaletteItem.spec.md +223 -0
- package/src/CommandPalette/CommandPaletteItem.test.tsx +200 -5
- package/src/CommandPalette/CommandPaletteItem.tsx +16 -11
- package/src/CommandPalette/CommandPaletteList.doc.mjs +3 -3
- package/src/CommandPalette/CommandPaletteList.spec.md +41 -36
- package/src/CommandPalette/CommandPaletteList.test.tsx +80 -0
- package/src/CommandPalette/CommandPaletteList.tsx +10 -5
- package/src/CommandPalette/__tests__/CommandPalette.a11y.chromium.spec.ts +599 -0
- package/src/ComplexSelector/ComplexSelector.doc.mjs +10 -8
- package/src/ComplexSelector/ComplexSelector.spec.md +14 -9
- package/src/ComplexSelector/ComplexSelector.test.tsx +64 -16
- package/src/ComplexSelector/ComplexSelector.tsx +37 -8
- package/src/ContextMenu/ContextMenu.doc.mjs +6 -0
- package/src/ContextMenu/ContextMenu.spec.md +51 -53
- package/src/ContextMenu/ContextMenu.test.tsx +132 -1
- package/src/ContextMenu/ContextMenu.tsx +78 -48
- package/src/DateInput/DateInput.doc.mjs +52 -0
- package/src/DateInput/DateInput.spec.md +27 -15
- package/src/DateInput/DateInput.test.tsx +38 -0
- package/src/DateInput/DateInput.tsx +1 -1
- package/src/DateInput/DateInputTouch.test.tsx +22 -0
- package/src/DateInput/MonthScroller.tsx +12 -4
- package/src/DateRangeInput/DateRangeInput.test.tsx +49 -0
- package/src/DateRangeInput/DateRangeInput.tsx +20 -2
- package/src/Dialog/Dialog.test.tsx +27 -1
- package/src/Dialog/Dialog.tsx +16 -5
- package/src/Dialog/DialogHeader.test.tsx +27 -2
- package/src/Dialog/DialogHeader.tsx +7 -8
- package/src/Dialog/__tests__/Dialog.a11y.chromium.spec.ts +21 -14
- package/src/Divider/Divider.doc.mjs +5 -3
- package/src/Divider/Divider.spec.md +140 -54
- package/src/Divider/Divider.test.tsx +15 -0
- package/src/Divider/Divider.tsx +6 -4
- package/src/DropdownMenu/DropdownMenu.doc.mjs +2 -2
- package/src/DropdownMenu/DropdownMenu.spec.md +121 -45
- package/src/DropdownMenu/DropdownMenu.test.tsx +288 -23
- package/src/DropdownMenu/DropdownMenu.tsx +212 -81
- package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +38 -2
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +32 -18
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +146 -1
- package/src/DropdownMenu/__tests__/MenuButton.a11y.chromium.spec.ts +136 -0
- package/src/DropdownMenu/__tests__/MenuButton.a11y.known-failures.ts +12 -0
- package/src/DropdownMenu/__tests__/MenuButton.a11y.renders.tsx +67 -0
- package/src/DropdownMenu/__tests__/MenuButton.a11y.states.ts +141 -0
- package/src/DropdownMenu/__tests__/MenuButton.a11y.test.tsx +138 -0
- package/src/DropdownMenu/__tests__/MenuHeaderFooter.a11y.chromium.spec.ts +40 -5
- package/src/Field/InputClearButton.test.tsx +29 -4
- package/src/Field/InputClearButton.tsx +26 -8
- package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +21 -14
- package/src/FormLayout/FormLayout.tsx +1 -0
- package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +1 -1
- package/src/Grid/Grid.doc.mjs +14 -11
- package/src/Grid/Grid.spec.md +50 -32
- package/src/Grid/Grid.tsx +13 -4
- package/src/HoverCard/HoverCard.test.tsx +46 -1
- package/src/HoverCard/useHoverCard.tsx +68 -48
- package/src/InputGroup/InputGroup.doc.mjs +11 -1
- package/src/InputGroup/InputGroup.tsx +2 -4
- package/src/InputGroup/groupStyles.ts +40 -2
- package/src/Layer/useLayerDismissal.ts +9 -9
- package/src/Link/__tests__/Link.a11y.chromium.spec.ts +142 -0
- package/src/Link/__tests__/Link.a11y.renders.tsx +97 -0
- package/src/Link/__tests__/Link.a11y.states.ts +104 -0
- package/src/Link/__tests__/Link.a11y.test.tsx +127 -0
- package/src/Markdown/Markdown.doc.mjs +1 -1
- package/src/Markdown/Markdown.fr23.perf.test.ts +161 -40
- package/src/Markdown/Markdown.spec.md +45 -23
- package/src/Markdown/Markdown.test.tsx +38 -0
- package/src/Markdown/Markdown.tsx +24 -2
- package/src/Markdown/plugins/semanticFence.test.tsx +3 -2
- package/src/MobileNav/MobileNav.tsx +50 -2
- package/src/MobileNav/MobileNavFocus.test.tsx +553 -0
- package/src/MoreMenu/MoreMenu.spec.md +18 -7
- package/src/MoreMenu/MoreMenu.test.tsx +38 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +8 -8
- package/src/MultiSelector/MultiSelector.spec.md +1 -1
- package/src/MultiSelector/MultiSelector.test.tsx +188 -21
- package/src/MultiSelector/MultiSelector.tsx +50 -11
- package/src/NumberInput/NumberInput.test.tsx +24 -0
- package/src/NumberInput/NumberInput.tsx +1 -1
- package/src/NumberInput/__tests__/NumberInput.a11y.chromium.spec.ts +22 -15
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +78 -0
- package/src/PowerSearch/PowerSearchEditPopover.tsx +6 -0
- package/src/Resizable/Resizable.spec.md +41 -9
- package/src/Resizable/ResizeHandle.test.tsx +565 -2
- package/src/Resizable/ResizeHandle.tsx +126 -21
- package/src/Resizable/__tests__/ResizeHandle.a11y.chromium.spec.ts +119 -0
- package/src/Resizable/__tests__/ResizeHandle.a11y.known-failures.ts +39 -0
- package/src/Resizable/__tests__/ResizeHandle.a11y.renders.tsx +80 -0
- package/src/Resizable/__tests__/ResizeHandle.a11y.states.ts +197 -0
- package/src/Resizable/__tests__/ResizeHandle.a11y.test.tsx +123 -0
- package/src/Resizable/useResizable.ts +95 -0
- package/src/Selector/Selector.doc.mjs +7 -6
- package/src/Selector/Selector.spec.md +37 -24
- package/src/Selector/Selector.test.tsx +176 -10
- package/src/Selector/Selector.tsx +59 -14
- package/src/Selector/__tests__/Combobox.a11y.known-failures.ts +27 -0
- package/src/Selector/__tests__/Combobox.a11y.states.ts +145 -0
- package/src/Selector/__tests__/Selector.combobox.a11y.chromium.spec.ts +108 -0
- package/src/Selector/__tests__/Selector.combobox.a11y.test.tsx +126 -0
- package/src/SideNav/SideNav.test.tsx +35 -0
- package/src/SideNav/SideNav.tsx +16 -2
- package/src/Slider/Slider.spec.md +43 -17
- package/src/Slider/Slider.test.tsx +134 -0
- package/src/Slider/Slider.tsx +29 -6
- package/src/Slider/__tests__/Slider.a11y.chromium.spec.ts +112 -0
- package/src/Slider/__tests__/Slider.a11y.known-failures.ts +12 -0
- package/src/Slider/__tests__/Slider.a11y.renders.tsx +42 -0
- package/src/Slider/__tests__/Slider.a11y.states.ts +106 -0
- package/src/Slider/__tests__/Slider.a11y.test.tsx +105 -0
- package/src/Switch/__tests__/Switch.a11y.chromium.spec.ts +25 -18
- package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +19 -12
- package/src/TextInput/__tests__/TextInput.a11y.chromium.spec.ts +21 -14
- package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +18 -11
- package/src/Tokenizer/Tokenizer.test.tsx +87 -0
- package/src/Tokenizer/Tokenizer.tsx +31 -3
- package/src/Toolbar/Toolbar.test.tsx +131 -4
- package/src/Toolbar/Toolbar.tsx +3 -1
- package/src/TreeList/TreeList.spec.md +33 -8
- package/src/TreeList/TreeList.test.tsx +72 -0
- package/src/TreeList/TreeList.tsx +10 -6
- package/src/TreeList/TreeListItem.tsx +5 -0
- package/src/TreeList/__tests__/TreeList.a11y.chromium.spec.ts +125 -0
- package/src/TreeList/__tests__/TreeList.a11y.renders.tsx +44 -0
- package/src/TreeList/__tests__/TreeList.a11y.states.ts +164 -0
- package/src/TreeList/__tests__/TreeList.a11y.test.tsx +138 -0
- package/src/TreeList/__tests__/TreeListRowNames.a11y.chromium.spec.ts +82 -0
- package/src/hooks/useScrollOverflow.test.tsx +222 -0
- package/src/hooks/useScrollOverflow.ts +55 -13
- package/src/hooks/useTreeFocus.test.tsx +37 -0
- package/src/hooks/useTreeFocus.ts +55 -2
- package/src/i18n/generated-locales/en.generated.ts +3 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +3 -0
- package/src/reset.a11y.chromium.spec.ts +9 -1
- package/src/reset.css +8 -3
- package/src/reset.until-found.a11y.browser.spec.ts +75 -0
- package/src/reset.until-found.test.ts +32 -0
- package/src/stylexValidation.source-build.test.mjs +42 -0
- package/src/theme/syntax/SyntaxTheme.tsx +46 -5
- package/src/theme/syntax/defineSyntaxTheme.diff.test.ts +91 -0
- package/src/theme/syntax/defineSyntaxTheme.ts +75 -15
- package/src/theme/syntax/index.ts +5 -1
- package/src/theme/syntax/tokens.ts +32 -2
- package/src/theme/syntax/useSyntaxTheme.diff.test.tsx +40 -0
- package/src/utils/plainDate.test.ts +147 -0
- package/src/utils/plainDate.ts +75 -10
|
@@ -38,6 +38,7 @@ import {Theme} from '../theme/Theme';
|
|
|
38
38
|
import {generateThemeCSS} from '../theme/generateThemeRules';
|
|
39
39
|
import {spacingVars} from '../theme/tokens.stylex';
|
|
40
40
|
import {selectorPresentationStyles} from './selectorPresentation.stylex';
|
|
41
|
+
import {groupStyles} from '../InputGroup/groupStyles';
|
|
41
42
|
|
|
42
43
|
function generateThemeTestCSS(theme: Parameters<typeof generateThemeCSS>[0]) {
|
|
43
44
|
const {prose, component} = generateThemeCSS(theme);
|
|
@@ -605,7 +606,7 @@ describe('Selector', () => {
|
|
|
605
606
|
const inputDropdownClass = screen.getByRole('listbox', h).className;
|
|
606
607
|
unmount();
|
|
607
608
|
|
|
608
|
-
render(
|
|
609
|
+
const ghostRender = render(
|
|
609
610
|
<Selector
|
|
610
611
|
label="Ghost fruit"
|
|
611
612
|
options={OPTIONS}
|
|
@@ -616,10 +617,24 @@ describe('Selector', () => {
|
|
|
616
617
|
);
|
|
617
618
|
await user.click(screen.getByRole('combobox'));
|
|
618
619
|
const ghostDropdownClass = screen.getByRole('listbox', h).className;
|
|
620
|
+
ghostRender.unmount();
|
|
621
|
+
|
|
622
|
+
render(
|
|
623
|
+
<Selector
|
|
624
|
+
label="Secondary fruit"
|
|
625
|
+
options={OPTIONS}
|
|
626
|
+
value="Banana"
|
|
627
|
+
variant="secondary"
|
|
628
|
+
onChange={() => {}}
|
|
629
|
+
/>,
|
|
630
|
+
);
|
|
631
|
+
await user.click(screen.getByRole('combobox'));
|
|
632
|
+
const secondaryDropdownClass = screen.getByRole('listbox', h).className;
|
|
619
633
|
|
|
620
634
|
// The bordered input gets one extra StyleX rule for its border-width
|
|
621
|
-
// correction; the borderless ghost
|
|
635
|
+
// correction; the borderless secondary/ghost keep the base menu inset.
|
|
622
636
|
expect(inputDropdownClass).not.toBe(ghostDropdownClass);
|
|
637
|
+
expect(secondaryDropdownClass).toBe(ghostDropdownClass);
|
|
623
638
|
});
|
|
624
639
|
|
|
625
640
|
it('does not apply selected-item overlay offset when placement is explicit', async () => {
|
|
@@ -822,6 +837,58 @@ describe('Selector', () => {
|
|
|
822
837
|
expect(onChange).toHaveBeenCalledWith(null);
|
|
823
838
|
});
|
|
824
839
|
|
|
840
|
+
it('returns focus to the trigger when the clear button is activated by keyboard', async () => {
|
|
841
|
+
function Controlled() {
|
|
842
|
+
const [value, setValue] = useState<string | null>('Banana');
|
|
843
|
+
return (
|
|
844
|
+
<Selector
|
|
845
|
+
label="Fruit"
|
|
846
|
+
options={OPTIONS}
|
|
847
|
+
value={value}
|
|
848
|
+
onChange={setValue}
|
|
849
|
+
hasClear
|
|
850
|
+
/>
|
|
851
|
+
);
|
|
852
|
+
}
|
|
853
|
+
const user = userEvent.setup();
|
|
854
|
+
render(<Controlled />);
|
|
855
|
+
screen.getByRole('button', {name: 'Clear Fruit'}).focus();
|
|
856
|
+
await user.keyboard('{Enter}');
|
|
857
|
+
expect(
|
|
858
|
+
screen.queryByRole('button', {name: 'Clear Fruit'}),
|
|
859
|
+
).not.toBeInTheDocument();
|
|
860
|
+
expect(screen.getByRole('combobox')).toHaveFocus();
|
|
861
|
+
});
|
|
862
|
+
|
|
863
|
+
it('leaves focus in the search input when the clear button is clicked with the list open', async () => {
|
|
864
|
+
function Controlled() {
|
|
865
|
+
const [value, setValue] = useState<string | null>('Banana');
|
|
866
|
+
return (
|
|
867
|
+
<Selector
|
|
868
|
+
label="Fruit"
|
|
869
|
+
options={OPTIONS}
|
|
870
|
+
value={value}
|
|
871
|
+
onChange={setValue}
|
|
872
|
+
hasClear
|
|
873
|
+
hasSearch
|
|
874
|
+
/>
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
const user = userEvent.setup();
|
|
878
|
+
render(<Controlled />);
|
|
879
|
+
await user.click(screen.getByRole('button', {name: 'Fruit'}));
|
|
880
|
+
const search = screen.getByRole('combobox', {
|
|
881
|
+
name: 'Search options',
|
|
882
|
+
hidden: true,
|
|
883
|
+
});
|
|
884
|
+
search.focus();
|
|
885
|
+
await user.click(screen.getByRole('button', {name: 'Clear Fruit'}));
|
|
886
|
+
expect(
|
|
887
|
+
screen.queryByRole('button', {name: 'Clear Fruit'}),
|
|
888
|
+
).not.toBeInTheDocument();
|
|
889
|
+
expect(search).toHaveFocus();
|
|
890
|
+
});
|
|
891
|
+
|
|
825
892
|
it('clears the value via Delete on the focused trigger', async () => {
|
|
826
893
|
const user = userEvent.setup();
|
|
827
894
|
const onChange = vi.fn();
|
|
@@ -924,7 +991,10 @@ describe('Selector', () => {
|
|
|
924
991
|
expect(screen.getByRole('combobox', h)).toBeInTheDocument();
|
|
925
992
|
});
|
|
926
993
|
|
|
927
|
-
|
|
994
|
+
// The search input's expanded state, popup relationship, and active option
|
|
995
|
+
// are bound to the shared Combobox contract (Selector.combobox.a11y.test.tsx,
|
|
996
|
+
// search-active); this keeps only the Selector-specific wiring.
|
|
997
|
+
it('moves combobox semantics to the list-autocomplete search input (comboboxes-4)', async () => {
|
|
928
998
|
const user = userEvent.setup();
|
|
929
999
|
render(
|
|
930
1000
|
<Selector
|
|
@@ -941,12 +1011,6 @@ describe('Selector', () => {
|
|
|
941
1011
|
await user.click(triggerBtn);
|
|
942
1012
|
const search = screen.getByRole('combobox', h);
|
|
943
1013
|
expect(search).toHaveAttribute('aria-autocomplete', 'list');
|
|
944
|
-
expect(search).toHaveAttribute('aria-expanded', 'true');
|
|
945
|
-
expect(search).toHaveAttribute('aria-controls');
|
|
946
|
-
// ArrowDown moves the highlight; the search input reports it via
|
|
947
|
-
// aria-activedescendant (previously silent on the trigger).
|
|
948
|
-
await user.keyboard('{ArrowDown}');
|
|
949
|
-
expect(search).toHaveAttribute('aria-activedescendant');
|
|
950
1014
|
});
|
|
951
1015
|
|
|
952
1016
|
it('PageDown/PageUp jump the highlight to the last/first filtered option', async () => {
|
|
@@ -1285,7 +1349,6 @@ describe('Selector', () => {
|
|
|
1285
1349
|
<Selector label="Fruit" options={[]} onChange={() => {}} isLoading />,
|
|
1286
1350
|
);
|
|
1287
1351
|
const trigger = screen.getByRole('combobox', {name: 'Fruit'});
|
|
1288
|
-
expect(trigger).toHaveAttribute('aria-busy', 'true');
|
|
1289
1352
|
expect(screen.getByRole('status', {name: 'Loading'})).toBeInTheDocument();
|
|
1290
1353
|
|
|
1291
1354
|
await user.click(trigger);
|
|
@@ -2448,6 +2511,67 @@ describe('Selector', () => {
|
|
|
2448
2511
|
expect(screen.getByText('#')).toBeInTheDocument();
|
|
2449
2512
|
});
|
|
2450
2513
|
|
|
2514
|
+
it.each(['input', 'secondary'] as const)(
|
|
2515
|
+
'gives a grouped %s trigger the connected group geometry in every position',
|
|
2516
|
+
variant => {
|
|
2517
|
+
const groupClasses = stylex
|
|
2518
|
+
.props(groupStyles.inGroup)
|
|
2519
|
+
.className!.split(' ');
|
|
2520
|
+
const selector = (label: string) => (
|
|
2521
|
+
<Selector
|
|
2522
|
+
label={label}
|
|
2523
|
+
isLabelHidden
|
|
2524
|
+
variant={variant}
|
|
2525
|
+
options={OPTIONS}
|
|
2526
|
+
/>
|
|
2527
|
+
);
|
|
2528
|
+
render(
|
|
2529
|
+
<>
|
|
2530
|
+
<InputGroup label="First">
|
|
2531
|
+
{selector('Channel first')}
|
|
2532
|
+
<InputGroupText>#</InputGroupText>
|
|
2533
|
+
</InputGroup>
|
|
2534
|
+
<InputGroup label="Middle">
|
|
2535
|
+
<InputGroupText>#</InputGroupText>
|
|
2536
|
+
{selector('Channel middle')}
|
|
2537
|
+
<InputGroupText>@</InputGroupText>
|
|
2538
|
+
</InputGroup>
|
|
2539
|
+
<InputGroup label="Last">
|
|
2540
|
+
<InputGroupText>#</InputGroupText>
|
|
2541
|
+
{selector('Channel last')}
|
|
2542
|
+
</InputGroup>
|
|
2543
|
+
</>,
|
|
2544
|
+
);
|
|
2545
|
+
|
|
2546
|
+
// The group's row height, seam radii, and focus stacking all come from
|
|
2547
|
+
// these classes; their :first-child and last-item selectors resolve the
|
|
2548
|
+
// position. A secondary trigger keeps its fill but must not keep its
|
|
2549
|
+
// own standalone edges or width.
|
|
2550
|
+
for (const position of ['first', 'middle', 'last']) {
|
|
2551
|
+
const trigger = screen.getByRole('combobox', {
|
|
2552
|
+
name: new RegExp(`Channel ${position}`),
|
|
2553
|
+
});
|
|
2554
|
+
const box = trigger.closest('.astryx-selector') as HTMLElement;
|
|
2555
|
+
const classes = new Set(box.className.split(' '));
|
|
2556
|
+
expect(groupClasses.every(c => classes.has(c))).toBe(true);
|
|
2557
|
+
}
|
|
2558
|
+
},
|
|
2559
|
+
);
|
|
2560
|
+
|
|
2561
|
+
it('keeps a standalone secondary trigger out of the group geometry', () => {
|
|
2562
|
+
const groupClasses = stylex
|
|
2563
|
+
.props(groupStyles.inGroup)
|
|
2564
|
+
.className!.split(' ');
|
|
2565
|
+
render(
|
|
2566
|
+
<Selector label="Channel" variant="secondary" options={OPTIONS} />,
|
|
2567
|
+
);
|
|
2568
|
+
const box = screen
|
|
2569
|
+
.getByRole('combobox')
|
|
2570
|
+
.closest('.astryx-selector') as HTMLElement;
|
|
2571
|
+
const classes = new Set(box.className.split(' '));
|
|
2572
|
+
expect(groupClasses.some(c => classes.has(c))).toBe(false);
|
|
2573
|
+
});
|
|
2574
|
+
|
|
2451
2575
|
it('keeps disabled reasons described when grouped', () => {
|
|
2452
2576
|
render(
|
|
2453
2577
|
<InputGroup label="Destination">
|
|
@@ -3083,6 +3207,48 @@ describe('Selector statusVariant forwarding', () => {
|
|
|
3083
3207
|
);
|
|
3084
3208
|
});
|
|
3085
3209
|
|
|
3210
|
+
it('detaches attached status by default for the secondary variant', () => {
|
|
3211
|
+
const {container} = render(
|
|
3212
|
+
<Selector
|
|
3213
|
+
label="Fruit"
|
|
3214
|
+
options={['Apple', 'Banana']}
|
|
3215
|
+
variant="secondary"
|
|
3216
|
+
status={{type: 'error', message: 'Required'}}
|
|
3217
|
+
/>,
|
|
3218
|
+
);
|
|
3219
|
+
expect(container.querySelector('.astryx-selector')).toHaveAttribute(
|
|
3220
|
+
'data-variant',
|
|
3221
|
+
'secondary',
|
|
3222
|
+
);
|
|
3223
|
+
expect(container.querySelector('.astryx-field-status')).toHaveAttribute(
|
|
3224
|
+
'data-variant',
|
|
3225
|
+
'detached',
|
|
3226
|
+
);
|
|
3227
|
+
});
|
|
3228
|
+
|
|
3229
|
+
it('paints the secondary trigger with its own trigger style', () => {
|
|
3230
|
+
const inputRender = render(
|
|
3231
|
+
<Selector label="Fruit" options={['Apple', 'Banana']} value="Banana" />,
|
|
3232
|
+
);
|
|
3233
|
+
const inputTriggerClass =
|
|
3234
|
+
inputRender.container.querySelector('.astryx-selector')!.className;
|
|
3235
|
+
inputRender.unmount();
|
|
3236
|
+
|
|
3237
|
+
const secondaryRender = render(
|
|
3238
|
+
<Selector
|
|
3239
|
+
label="Fruit"
|
|
3240
|
+
options={['Apple', 'Banana']}
|
|
3241
|
+
value="Banana"
|
|
3242
|
+
variant="secondary"
|
|
3243
|
+
/>,
|
|
3244
|
+
);
|
|
3245
|
+
// The neutral-filled secondary trigger must not reuse the bordered
|
|
3246
|
+
// input trigger's classes; it carries the secondary trigger style.
|
|
3247
|
+
expect(
|
|
3248
|
+
secondaryRender.container.querySelector('.astryx-selector')!.className,
|
|
3249
|
+
).not.toBe(inputTriggerClass);
|
|
3250
|
+
});
|
|
3251
|
+
|
|
3086
3252
|
it('uses a status tooltip for ghost selectors when requested', () => {
|
|
3087
3253
|
const {container} = render(
|
|
3088
3254
|
<Selector
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* @file Selector.tsx
|
|
7
7
|
* @input Uses React, StyleX, adaptive selection surfaces, theme-resolved
|
|
8
8
|
* indicators, Field, and InputGroup context
|
|
9
|
-
* @output Exports Selector with content-derived option-mark layout and token-sized single-line triggers
|
|
9
|
+
* @output Exports Selector with input, secondary, and ghost trigger treatments, content-derived option-mark layout, and token-sized single-line triggers
|
|
10
10
|
* @position Core implementation; consumed by index.ts
|
|
11
11
|
*
|
|
12
12
|
* SYNC: When modified, update:
|
|
@@ -260,6 +260,37 @@ const styles = stylex.create({
|
|
|
260
260
|
'[data-astryx-press="on"]': 'scale(0.98)',
|
|
261
261
|
},
|
|
262
262
|
},
|
|
263
|
+
// Secondary is ghost's chrome with the resting fill of a secondary
|
|
264
|
+
// button (`--color-neutral`): no border, no shadow, content width, so a
|
|
265
|
+
// selector in a nav reads as the sibling of the secondary buttons and
|
|
266
|
+
// segmented controls beside it instead of as a form field. The hover and
|
|
267
|
+
// pressed answers still come from the shared interaction overlay, layered
|
|
268
|
+
// over the fill via backgroundImage.
|
|
269
|
+
triggerSecondary: {
|
|
270
|
+
width: 'auto',
|
|
271
|
+
borderWidth: 0,
|
|
272
|
+
lineHeight: `max(${spacingVars['--spacing-5']}, 20px, 1rem)`,
|
|
273
|
+
backgroundColor: colorVars['--color-neutral'],
|
|
274
|
+
boxShadow: {
|
|
275
|
+
default: 'none',
|
|
276
|
+
':hover:not(:focus-within):where(:not(:disabled,[aria-disabled="true"]))':
|
|
277
|
+
{
|
|
278
|
+
'@media (hover: hover)': 'none',
|
|
279
|
+
},
|
|
280
|
+
':focus-within': 'none',
|
|
281
|
+
},
|
|
282
|
+
fontWeight: fontWeightVars['--font-weight-medium'],
|
|
283
|
+
transitionProperty:
|
|
284
|
+
'background-image, background-color, color, opacity, transform',
|
|
285
|
+
transform: {
|
|
286
|
+
default: 'scale(1)',
|
|
287
|
+
':active': {
|
|
288
|
+
default: 'scale(0.98)',
|
|
289
|
+
'@media (pointer: coarse)': 'scale(1)',
|
|
290
|
+
},
|
|
291
|
+
'[data-astryx-press="on"]': 'scale(0.98)',
|
|
292
|
+
},
|
|
293
|
+
},
|
|
263
294
|
triggerGhostDisabled: {
|
|
264
295
|
backgroundImage: 'none',
|
|
265
296
|
transform: {
|
|
@@ -311,7 +342,7 @@ const styles = stylex.create({
|
|
|
311
342
|
},
|
|
312
343
|
dropdownInput: {
|
|
313
344
|
// The input trigger's text inset includes its border. Mirror that extra
|
|
314
|
-
// pixel in the menu; the borderless ghost
|
|
345
|
+
// pixel in the menu; the borderless secondary/ghost variants need no correction.
|
|
315
346
|
paddingInline: `calc(${spacingVars['--spacing-1']} + ${borderVars['--border-width']})`,
|
|
316
347
|
},
|
|
317
348
|
// Scroll ownership by the browser's own signal, as the menus declare it: a
|
|
@@ -512,7 +543,7 @@ const STATUS_BUTTON_LABEL_KEY: Record<SelectorStatusType, string> = {
|
|
|
512
543
|
|
|
513
544
|
export type SelectorSize = 'sm' | 'md' | 'lg';
|
|
514
545
|
|
|
515
|
-
export type SelectorVariant = 'input' | 'ghost';
|
|
546
|
+
export type SelectorVariant = 'input' | 'secondary' | 'ghost';
|
|
516
547
|
|
|
517
548
|
export type SelectorPresentation = AdaptivePresentation;
|
|
518
549
|
|
|
@@ -655,6 +686,9 @@ interface SelectorPropsBase<
|
|
|
655
686
|
/**
|
|
656
687
|
* Visual style of the selector trigger.
|
|
657
688
|
* - 'input': bordered input-style trigger for forms
|
|
689
|
+
* - 'secondary': matches the theme's secondary buttons (borderless and
|
|
690
|
+
* neutral-filled by default), for navs and toolbars where the selector
|
|
691
|
+
* sits beside secondary actions
|
|
658
692
|
* - 'ghost': borderless trigger matching ghost buttons, for toolbars
|
|
659
693
|
* @default 'input'
|
|
660
694
|
*/
|
|
@@ -671,7 +705,7 @@ interface SelectorPropsBase<
|
|
|
671
705
|
* - 'attached': message overlaps directly below the bordered input (input variant only)
|
|
672
706
|
* - 'detached': message floats below as a separate element with spacing
|
|
673
707
|
* - 'tooltip': message is exposed from the on-field status icon
|
|
674
|
-
* @default 'attached' for input selectors; 'detached' for ghost selectors
|
|
708
|
+
* @default 'attached' for input selectors; 'detached' for secondary/ghost selectors
|
|
675
709
|
*/
|
|
676
710
|
statusVariant?: FieldStatusVariant;
|
|
677
711
|
|
|
@@ -957,7 +991,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
957
991
|
const hasClear = hasClearProp === true;
|
|
958
992
|
const size = useSize(sizeProp, 'md');
|
|
959
993
|
const effectiveStatusVariant =
|
|
960
|
-
variant
|
|
994
|
+
variant !== 'input' && statusVariant === 'attached'
|
|
961
995
|
? 'detached'
|
|
962
996
|
: statusVariant;
|
|
963
997
|
const isEffectivelyReadOnly = isReadOnly && !isDisabled;
|
|
@@ -1381,6 +1415,14 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1381
1415
|
(e: React.MouseEvent) => {
|
|
1382
1416
|
e.stopPropagation(); // Don't open dropdown
|
|
1383
1417
|
clearValue();
|
|
1418
|
+
// A keyboard activation (detail 0) leaves focus on the clear button,
|
|
1419
|
+
// which unmounts once the value is null and would drop focus to <body>;
|
|
1420
|
+
// hand it to the trigger as `hasClear` documents. A pointer press never
|
|
1421
|
+
// focuses the button, so there is no focus to repair, and moving it
|
|
1422
|
+
// would pull it out of an open list's search input.
|
|
1423
|
+
if (e.detail === 0) {
|
|
1424
|
+
triggerRef.current?.focus();
|
|
1425
|
+
}
|
|
1384
1426
|
},
|
|
1385
1427
|
[clearValue],
|
|
1386
1428
|
);
|
|
@@ -1408,7 +1450,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1408
1450
|
{...themeProps('selector-search')}
|
|
1409
1451
|
xstyle={
|
|
1410
1452
|
surface.activePresentation === 'popover' &&
|
|
1411
|
-
variant
|
|
1453
|
+
variant === 'input' &&
|
|
1412
1454
|
styles.searchRowInput
|
|
1413
1455
|
}
|
|
1414
1456
|
// When hasSearch is set, focus moves into this input on open, so it —
|
|
@@ -1753,7 +1795,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1753
1795
|
? styles.touchPanYPinchZoom
|
|
1754
1796
|
: styles.touchPinchZoom,
|
|
1755
1797
|
surface.activePresentation === 'popover' &&
|
|
1756
|
-
variant
|
|
1798
|
+
variant === 'input' &&
|
|
1757
1799
|
styles.dropdownInput,
|
|
1758
1800
|
)}>
|
|
1759
1801
|
{renderOptions()}
|
|
@@ -1791,7 +1833,7 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1791
1833
|
styles.dropdown,
|
|
1792
1834
|
listboxHasOverflow ? styles.touchPanYPinchZoom : styles.touchPinchZoom,
|
|
1793
1835
|
surface.activePresentation === 'popover' &&
|
|
1794
|
-
variant
|
|
1836
|
+
variant === 'input' &&
|
|
1795
1837
|
styles.dropdownInput,
|
|
1796
1838
|
surface.activePresentation === 'popover' &&
|
|
1797
1839
|
!isPositioned &&
|
|
@@ -1884,24 +1926,27 @@ export function Selector<T extends SelectorOptionType>(
|
|
|
1884
1926
|
styles.triggerContainer,
|
|
1885
1927
|
sizeStyles[size],
|
|
1886
1928
|
variant === 'ghost' && styles.triggerGhost,
|
|
1887
|
-
variant === '
|
|
1888
|
-
variant
|
|
1929
|
+
variant === 'secondary' && styles.triggerSecondary,
|
|
1930
|
+
variant !== 'input' && interactionOverlayStyles.backgroundImage,
|
|
1931
|
+
variant !== 'input' && focusOutlineStyles.focusWithin,
|
|
1889
1932
|
surface.isTriggerFocusRingSuppressed &&
|
|
1890
1933
|
selectorPresentationStyles.pointerRestoredFocus,
|
|
1891
1934
|
isDisabled && inputWrapperStyles.disabled,
|
|
1892
1935
|
isEffectivelyReadOnly && styles.triggerReadOnly,
|
|
1893
|
-
variant
|
|
1894
|
-
variant
|
|
1936
|
+
variant !== 'input' && isDisabled && styles.triggerGhostDisabled,
|
|
1937
|
+
variant !== 'input' &&
|
|
1895
1938
|
isEffectivelyReadOnly &&
|
|
1896
1939
|
styles.triggerGhostReadOnly,
|
|
1897
1940
|
!selectedItem && styles.triggerPlaceholder,
|
|
1898
|
-
variant
|
|
1941
|
+
variant === 'input' &&
|
|
1899
1942
|
status &&
|
|
1900
1943
|
inputStatusBorderStyles[status.type],
|
|
1901
|
-
variant
|
|
1944
|
+
variant === 'input' &&
|
|
1902
1945
|
status &&
|
|
1903
1946
|
!isDisabled &&
|
|
1904
1947
|
inputStatusHoverShadowStyles[status.type],
|
|
1948
|
+
// Grouped secondary triggers keep their neutral fill but take the
|
|
1949
|
+
// group's row height, connected edge radii, and focus stacking.
|
|
1905
1950
|
variant !== 'ghost' && inputGroup && groupStyles.inGroup,
|
|
1906
1951
|
inputGroup && styles.triggerInGroup,
|
|
1907
1952
|
controlXstyle,
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Combobox.a11y.known-failures.ts
|
|
5
|
+
* @input Uses KnownFailure from @astryxdesign/a11y-spec
|
|
6
|
+
* @output Current public-safe Selector Combobox binding failures
|
|
7
|
+
* @position AST-021 debt records; operational ownership remains outside public source.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {KnownFailure} from '@astryxdesign/a11y-spec';
|
|
11
|
+
|
|
12
|
+
export const SELECTOR_COMBOBOX_KNOWN_FAILURES: ReadonlyArray<KnownFailure> = [
|
|
13
|
+
{
|
|
14
|
+
expectation: 'combobox.popup.relationship',
|
|
15
|
+
binding: 'Selector.trigger',
|
|
16
|
+
state: 'sheet-open',
|
|
17
|
+
evidenceLayer: 'dom',
|
|
18
|
+
failureEquals:
|
|
19
|
+
'aria-controls does not reference the rendered combobox popup',
|
|
20
|
+
standardsReference:
|
|
21
|
+
'WAI-ARIA 1.2 combobox: aria-controls refers to the displayed popup element; WCAG 2.2 1.3.1 Info and Relationships (Level A)',
|
|
22
|
+
userImpact:
|
|
23
|
+
'On touch screens the trigger announces that it opens a dialog, but its controls relationship points past that dialog to the list inside it, so assistive technology that follows the relationship reaches the list without the sheet that hosts it.',
|
|
24
|
+
reason:
|
|
25
|
+
'The trigger declares the sheet dialog as its popup kind while aria-controls names the inner listbox. Pointing both at one popup changes Selector runtime semantics under AR1, which needs its own decision; this test-only binding records the gap.',
|
|
26
|
+
},
|
|
27
|
+
];
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Explicit Selector states bound to the reusable Combobox contract, plus the
|
|
5
|
+
* states that stay out of it and why.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type {ComboboxStateFacts} from '@astryxdesign/a11y-spec';
|
|
9
|
+
|
|
10
|
+
export interface SelectorComboboxScenario {
|
|
11
|
+
readonly id:
|
|
12
|
+
'closed' | 'open' | 'read-only' | 'busy' | 'sheet-open' | 'search-active';
|
|
13
|
+
/** `trigger` is the Selector button; `search` is the popup's search input. */
|
|
14
|
+
readonly binding: 'Selector.trigger' | 'Selector.search';
|
|
15
|
+
readonly storyId: string;
|
|
16
|
+
readonly open: boolean;
|
|
17
|
+
/** Move the highlight to the first option from the search input. */
|
|
18
|
+
readonly highlightFirst?: boolean;
|
|
19
|
+
readonly props: {
|
|
20
|
+
readonly isReadOnly?: boolean;
|
|
21
|
+
readonly isLoading?: boolean;
|
|
22
|
+
readonly value?: string;
|
|
23
|
+
readonly presentation?: 'bottom-sheet';
|
|
24
|
+
readonly hasSearch?: boolean;
|
|
25
|
+
};
|
|
26
|
+
readonly facts: ComboboxStateFacts;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const baseFacts: ComboboxStateFacts = {
|
|
30
|
+
name: 'Fruit',
|
|
31
|
+
expanded: false,
|
|
32
|
+
popupRole: 'listbox',
|
|
33
|
+
popupVisible: false,
|
|
34
|
+
activeDescendant: false,
|
|
35
|
+
readOnly: false,
|
|
36
|
+
busy: false,
|
|
37
|
+
inertUnderOwnModal: false,
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
export const SELECTOR_COMBOBOX_SCENARIOS: ReadonlyArray<SelectorComboboxScenario> =
|
|
41
|
+
[
|
|
42
|
+
{
|
|
43
|
+
id: 'closed',
|
|
44
|
+
binding: 'Selector.trigger',
|
|
45
|
+
storyId: 'a11y-combobox-pattern--selector-closed',
|
|
46
|
+
open: false,
|
|
47
|
+
props: {},
|
|
48
|
+
facts: baseFacts,
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'open',
|
|
52
|
+
binding: 'Selector.trigger',
|
|
53
|
+
storyId: 'a11y-combobox-pattern--selector-open',
|
|
54
|
+
open: true,
|
|
55
|
+
props: {},
|
|
56
|
+
facts: {
|
|
57
|
+
...baseFacts,
|
|
58
|
+
expanded: true,
|
|
59
|
+
popupVisible: true,
|
|
60
|
+
activeDescendant: true,
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
id: 'read-only',
|
|
65
|
+
binding: 'Selector.trigger',
|
|
66
|
+
storyId: 'a11y-combobox-pattern--selector-read-only',
|
|
67
|
+
open: false,
|
|
68
|
+
props: {isReadOnly: true, value: 'apple'},
|
|
69
|
+
facts: {...baseFacts, readOnly: true},
|
|
70
|
+
},
|
|
71
|
+
{
|
|
72
|
+
id: 'busy',
|
|
73
|
+
binding: 'Selector.trigger',
|
|
74
|
+
storyId: 'a11y-combobox-pattern--selector-busy',
|
|
75
|
+
open: false,
|
|
76
|
+
props: {isLoading: true},
|
|
77
|
+
facts: {...baseFacts, busy: true},
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
// AR1: the touch presentation's popup is a modal dialog that contains
|
|
81
|
+
// the listbox, and the trigger declares aria-haspopup="dialog".
|
|
82
|
+
id: 'sheet-open',
|
|
83
|
+
binding: 'Selector.trigger',
|
|
84
|
+
storyId: 'a11y-combobox-pattern--selector-sheet-open',
|
|
85
|
+
open: true,
|
|
86
|
+
props: {presentation: 'bottom-sheet'},
|
|
87
|
+
facts: {
|
|
88
|
+
...baseFacts,
|
|
89
|
+
expanded: true,
|
|
90
|
+
popupRole: 'dialog',
|
|
91
|
+
popupVisible: true,
|
|
92
|
+
activeDescendant: true,
|
|
93
|
+
// The modal sheet makes the trigger inert, so the browser leaves it
|
|
94
|
+
// out of the accessibility tree until the sheet closes.
|
|
95
|
+
inertUnderOwnModal: true,
|
|
96
|
+
},
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
// With hasSearch, focus moves into the popup's search input, which owns
|
|
100
|
+
// the combobox role and reports the highlighted option.
|
|
101
|
+
id: 'search-active',
|
|
102
|
+
binding: 'Selector.search',
|
|
103
|
+
storyId: 'a11y-combobox-pattern--selector-search-active',
|
|
104
|
+
open: true,
|
|
105
|
+
highlightFirst: true,
|
|
106
|
+
props: {hasSearch: true},
|
|
107
|
+
facts: {
|
|
108
|
+
...baseFacts,
|
|
109
|
+
name: 'Search options',
|
|
110
|
+
expanded: true,
|
|
111
|
+
popupVisible: true,
|
|
112
|
+
activeDescendant: true,
|
|
113
|
+
},
|
|
114
|
+
},
|
|
115
|
+
];
|
|
116
|
+
|
|
117
|
+
/** Selector states that change a combobox outcome but are not bound here. */
|
|
118
|
+
export const SELECTOR_COMBOBOX_EXCLUSIONS = [
|
|
119
|
+
{
|
|
120
|
+
owner: 'Selector trigger with hasSearch',
|
|
121
|
+
reason:
|
|
122
|
+
'Editable search mode moves combobox semantics to the popup search input, bound as Selector.search; the trigger is not a combobox in that mode.',
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
owner: 'Selector search input inside the bottom sheet',
|
|
126
|
+
reason:
|
|
127
|
+
'The search input keeps the semantics bound in search-active; the sheet changes only its modal host, which the modal-dialog owner covers.',
|
|
128
|
+
},
|
|
129
|
+
{
|
|
130
|
+
owner: 'Selector interaction suites',
|
|
131
|
+
reason:
|
|
132
|
+
'Keyboard activation, arrow/Home/End/typeahead movement, Escape, Tab, and selection policy are verified by Selector.test.tsx (AR3); this contract encodes semantics only.',
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
owner: 'Disabled and disabledMessage triggers',
|
|
136
|
+
reason:
|
|
137
|
+
'Availability state belongs to the disabled-state owners; this contract has no disabled expectation.',
|
|
138
|
+
},
|
|
139
|
+
{
|
|
140
|
+
owner:
|
|
141
|
+
'MultiSelector, Typeahead, Tokenizer, PowerSearch, ComplexSelector, CommandPalette',
|
|
142
|
+
reason:
|
|
143
|
+
'Later bounded adopters; this first binding is limited to Selector.',
|
|
144
|
+
},
|
|
145
|
+
] as const;
|