@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
|
@@ -46,7 +46,11 @@ import {
|
|
|
46
46
|
} from '../theme/tokens.stylex';
|
|
47
47
|
import {focusOutlineProps} from '../utils/focusOutline.stylex';
|
|
48
48
|
import {mergeProps, rtlStyles} from '../utils';
|
|
49
|
-
import
|
|
49
|
+
import {
|
|
50
|
+
getCollapseControls,
|
|
51
|
+
getEffectiveMaxPx,
|
|
52
|
+
type ResizableProps,
|
|
53
|
+
} from './useResizable';
|
|
50
54
|
import {themeProps} from '../utils/themeProps';
|
|
51
55
|
import {useTranslator} from '../i18n';
|
|
52
56
|
|
|
@@ -360,6 +364,60 @@ export interface ResizeHandleProps extends Omit<
|
|
|
360
364
|
children?: ReactNode;
|
|
361
365
|
}
|
|
362
366
|
|
|
367
|
+
/**
|
|
368
|
+
* The snap point `count` points away from the region's current size in
|
|
369
|
+
* `direction` (+1 grows, -1 shrinks). A point beyond `minSize` or `maxSize`
|
|
370
|
+
* counts as that bound; the nearest end point serves when fewer remain, and
|
|
371
|
+
* the current size when it is already there.
|
|
372
|
+
*/
|
|
373
|
+
function adjacentSnapPoint(
|
|
374
|
+
resizable: ResizableProps,
|
|
375
|
+
direction: 1 | -1,
|
|
376
|
+
count: number,
|
|
377
|
+
): number {
|
|
378
|
+
const points = [
|
|
379
|
+
...new Set(
|
|
380
|
+
resizable._snaps.map(p =>
|
|
381
|
+
Math.min(resizable._maxSizePx, Math.max(resizable._minSizePx, p)),
|
|
382
|
+
),
|
|
383
|
+
),
|
|
384
|
+
].sort((a, b) => a - b);
|
|
385
|
+
const size = resizable._size;
|
|
386
|
+
const ahead =
|
|
387
|
+
direction > 0
|
|
388
|
+
? points.filter(p => p > size)
|
|
389
|
+
: points.filter(p => p < size).reverse();
|
|
390
|
+
if (ahead.length === 0) {
|
|
391
|
+
return size;
|
|
392
|
+
}
|
|
393
|
+
return ahead[Math.min(count, ahead.length) - 1];
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
/**
|
|
397
|
+
* Collapse an open pane, or restore a collapsed one to the size it had before
|
|
398
|
+
* it collapsed (APG window splitter: Enter "restores the splitter to its
|
|
399
|
+
* previous position"). The hook's own collapse/expand do exactly that; a
|
|
400
|
+
* hand-built `ResizableProps` (no registered controls) falls back to a resize
|
|
401
|
+
* gesture to the minimum, which also cannot reopen a pane whose minimum sits below its
|
|
402
|
+
* collapse threshold.
|
|
403
|
+
*/
|
|
404
|
+
function toggleCollapse(resizable: ResizableProps): void {
|
|
405
|
+
const controls = getCollapseControls(resizable);
|
|
406
|
+
if (controls) {
|
|
407
|
+
if (resizable._isCollapsed) {
|
|
408
|
+
controls.expand();
|
|
409
|
+
} else {
|
|
410
|
+
controls.collapse();
|
|
411
|
+
}
|
|
412
|
+
return;
|
|
413
|
+
}
|
|
414
|
+
resizable._onResizeStart();
|
|
415
|
+
resizable._onResizeMove(
|
|
416
|
+
resizable._isCollapsed ? resizable._minSizePx : -resizable._size,
|
|
417
|
+
);
|
|
418
|
+
resizable._onResizeEnd();
|
|
419
|
+
}
|
|
420
|
+
|
|
363
421
|
/**
|
|
364
422
|
* Draggable resize handle placed between resizable panels. Renders as a thin
|
|
365
423
|
* divider line with a wider invisible hit area and optional pill grip indicator.
|
|
@@ -375,6 +433,7 @@ export interface ResizeHandleProps extends Omit<
|
|
|
375
433
|
* hasDivider />
|
|
376
434
|
* ```
|
|
377
435
|
*/
|
|
436
|
+
|
|
378
437
|
export function ResizeHandle({
|
|
379
438
|
direction = 'horizontal',
|
|
380
439
|
position: positionMode = 'inline',
|
|
@@ -528,20 +587,64 @@ export function ResizeHandle({
|
|
|
528
587
|
const step = e.shiftKey ? KEYBOARD_LARGE_STEP : KEYBOARD_STEP;
|
|
529
588
|
const rtl = isHorizontal ? getRTLMultiplier() : 1;
|
|
530
589
|
|
|
590
|
+
// The pane's grow direction on this key: ArrowRight/Down grow unless the
|
|
591
|
+
// layout is reversed or, on the inline axis, right-to-left.
|
|
592
|
+
const grows = (key: string) =>
|
|
593
|
+
(key === 'ArrowRight' || key === 'ArrowDown'
|
|
594
|
+
? 1
|
|
595
|
+
: key === 'ArrowLeft' || key === 'ArrowUp'
|
|
596
|
+
? -1
|
|
597
|
+
: 0) *
|
|
598
|
+
(isHorizontal ? rtl : 1) *
|
|
599
|
+
sign >
|
|
600
|
+
0;
|
|
601
|
+
|
|
531
602
|
switch (e.key) {
|
|
532
603
|
case 'ArrowRight':
|
|
533
|
-
case 'ArrowDown':
|
|
534
|
-
e.preventDefault();
|
|
535
|
-
resizable._onResizeStart();
|
|
536
|
-
resizable._onResizeMove(step * (isHorizontal ? rtl : 1) * sign);
|
|
537
|
-
resizable._onResizeEnd();
|
|
538
|
-
break;
|
|
539
|
-
}
|
|
604
|
+
case 'ArrowDown':
|
|
540
605
|
case 'ArrowLeft':
|
|
541
606
|
case 'ArrowUp': {
|
|
542
607
|
e.preventDefault();
|
|
608
|
+
if (resizable._isCollapsed) {
|
|
609
|
+
// A collapsed pane answers only the grow arrow: it opens one step
|
|
610
|
+
// above its minimum, the value the separator announces while
|
|
611
|
+
// collapsed, or at the collapse threshold when that is larger (APG
|
|
612
|
+
// window splitter: the arrow moves the separator from where it is;
|
|
613
|
+
// a bare step would stay below the threshold and leave it in
|
|
614
|
+
// place). The shrink arrow is a no-op.
|
|
615
|
+
if (grows(e.key)) {
|
|
616
|
+
resizable._onResizeStart();
|
|
617
|
+
// At least the collapse threshold, or the move would stay
|
|
618
|
+
// collapsed when the minimum sits below it.
|
|
619
|
+
resizable._onResizeMove(
|
|
620
|
+
Math.max(resizable._minSizePx + step, resizable._collapsedSize),
|
|
621
|
+
);
|
|
622
|
+
resizable._onResizeEnd();
|
|
623
|
+
}
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
if (resizable._snaps.length > 0) {
|
|
627
|
+
// With snap points the region can rest only on a point, so a
|
|
628
|
+
// pixel step would snap straight back; the arrow moves to the
|
|
629
|
+
// adjacent point in its direction instead (Shift, two points),
|
|
630
|
+
// staying within the bounds.
|
|
631
|
+
resizable._onResizeStart();
|
|
632
|
+
resizable._onResizeMove(
|
|
633
|
+
adjacentSnapPoint(
|
|
634
|
+
resizable,
|
|
635
|
+
grows(e.key) ? 1 : -1,
|
|
636
|
+
e.shiftKey ? 2 : 1,
|
|
637
|
+
) - resizable._size,
|
|
638
|
+
);
|
|
639
|
+
resizable._onResizeEnd();
|
|
640
|
+
break;
|
|
641
|
+
}
|
|
642
|
+
const direction =
|
|
643
|
+
e.key === 'ArrowRight' || e.key === 'ArrowDown' ? 1 : -1;
|
|
543
644
|
resizable._onResizeStart();
|
|
544
|
-
resizable._onResizeMove(
|
|
645
|
+
resizable._onResizeMove(
|
|
646
|
+
direction * step * (isHorizontal ? rtl : 1) * sign,
|
|
647
|
+
);
|
|
545
648
|
resizable._onResizeEnd();
|
|
546
649
|
break;
|
|
547
650
|
}
|
|
@@ -554,6 +657,9 @@ export function ResizeHandle({
|
|
|
554
657
|
}
|
|
555
658
|
case 'End': {
|
|
556
659
|
e.preventDefault();
|
|
660
|
+
// Only a configured maximum is the region's own limit; the reported
|
|
661
|
+
// stand-in for an unbounded region is where the pane *could* reach,
|
|
662
|
+
// not where End may safely move it (a recorded gap).
|
|
557
663
|
if (resizable._maxSizePx !== Infinity) {
|
|
558
664
|
resizable._onResizeStart();
|
|
559
665
|
resizable._onResizeMove(resizable._maxSizePx - resizable._size);
|
|
@@ -564,11 +670,7 @@ export function ResizeHandle({
|
|
|
564
670
|
case 'Enter': {
|
|
565
671
|
e.preventDefault();
|
|
566
672
|
if (resizable._collapsible) {
|
|
567
|
-
resizable
|
|
568
|
-
resizable._onResizeMove(
|
|
569
|
-
resizable._isCollapsed ? resizable._minSizePx : -resizable._size,
|
|
570
|
-
);
|
|
571
|
-
resizable._onResizeEnd();
|
|
673
|
+
toggleCollapse(resizable);
|
|
572
674
|
}
|
|
573
675
|
break;
|
|
574
676
|
}
|
|
@@ -582,11 +684,7 @@ export function ResizeHandle({
|
|
|
582
684
|
if (isDisabled || !resizable || !resizable._collapsible) {
|
|
583
685
|
return;
|
|
584
686
|
}
|
|
585
|
-
resizable
|
|
586
|
-
resizable._onResizeMove(
|
|
587
|
-
resizable._isCollapsed ? resizable._minSizePx : -resizable._size,
|
|
588
|
-
);
|
|
589
|
-
resizable._onResizeEnd();
|
|
687
|
+
toggleCollapse(resizable);
|
|
590
688
|
}, [isDisabled, resizable]);
|
|
591
689
|
|
|
592
690
|
// --- Cleanup on unmount ---
|
|
@@ -620,9 +718,16 @@ export function ResizeHandle({
|
|
|
620
718
|
: resizable._size
|
|
621
719
|
: undefined;
|
|
622
720
|
const ariaValueMin = resizable ? resizable._minSizePx : undefined;
|
|
721
|
+
// A separator with a value needs a maximum (WAI-ARIA, APG window splitter).
|
|
722
|
+
// Unbounded regions report the basis they can fill; a hand-built props
|
|
723
|
+
// object without it reports only a configured maximum.
|
|
724
|
+
const effectiveMax = resizable
|
|
725
|
+
? (getEffectiveMaxPx(resizable) ??
|
|
726
|
+
(resizable._maxSizePx !== Infinity ? resizable._maxSizePx : undefined))
|
|
727
|
+
: undefined;
|
|
623
728
|
const ariaValueMax =
|
|
624
|
-
|
|
625
|
-
?
|
|
729
|
+
effectiveMax != null && Number.isFinite(effectiveMax)
|
|
730
|
+
? effectiveMax
|
|
626
731
|
: undefined;
|
|
627
732
|
const ariaValueText =
|
|
628
733
|
resizable && isCollapsed ? t('@astryx.resizable.collapsed') : undefined;
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ResizeHandle.a11y.chromium.spec.ts
|
|
5
|
+
* @input Built ResizeHandle stories and WINDOW_SPLITTER_PATTERN in real Chromium
|
|
6
|
+
* @output Browser evidence for every window-splitter expectation across the binding's states, reconciled against the exact known failures
|
|
7
|
+
* @position Chromium lane of the ResizeHandle binding (component:Resizable AR1)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import {
|
|
11
|
+
expect,
|
|
12
|
+
test,
|
|
13
|
+
type CDPSession,
|
|
14
|
+
type Locator,
|
|
15
|
+
type Page,
|
|
16
|
+
} from '@playwright/test';
|
|
17
|
+
import {
|
|
18
|
+
WINDOW_SPLITTER_PATTERN,
|
|
19
|
+
blockingResults,
|
|
20
|
+
checkAccessibilitySpec,
|
|
21
|
+
formatFailures,
|
|
22
|
+
neverExercised,
|
|
23
|
+
summarize,
|
|
24
|
+
unmatchedKnownFailures,
|
|
25
|
+
type BindingResult,
|
|
26
|
+
} from '@astryxdesign/a11y-spec';
|
|
27
|
+
import {
|
|
28
|
+
createChromiumHarness,
|
|
29
|
+
holdMotionStill,
|
|
30
|
+
} from '@astryxdesign/a11y-spec/chromium';
|
|
31
|
+
import {
|
|
32
|
+
DEFAULT_STORYBOOK_DIR,
|
|
33
|
+
serveStorybook,
|
|
34
|
+
type StaticServer,
|
|
35
|
+
} from '@astryxdesign/a11y-spec/storybook';
|
|
36
|
+
import {RESIZE_HANDLE_KNOWN_FAILURES} from './ResizeHandle.a11y.known-failures';
|
|
37
|
+
import {
|
|
38
|
+
RESIZE_HANDLE_BINDING_STATES,
|
|
39
|
+
type ResizeHandleBindingState,
|
|
40
|
+
} from './ResizeHandle.a11y.states';
|
|
41
|
+
|
|
42
|
+
let storybook: StaticServer;
|
|
43
|
+
|
|
44
|
+
test.beforeAll(async () => {
|
|
45
|
+
storybook = await serveStorybook(
|
|
46
|
+
process.env.ASTRYX_STORYBOOK_DIR ?? DEFAULT_STORYBOOK_DIR,
|
|
47
|
+
);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
test.afterAll(async () => {
|
|
51
|
+
await storybook?.close();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
function storyUrl(storyId: string): string {
|
|
55
|
+
return `${storybook.origin}/iframe.html?id=${storyId}&viewMode=story`;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
async function mountState(
|
|
59
|
+
page: Page,
|
|
60
|
+
state: ResizeHandleBindingState,
|
|
61
|
+
): Promise<{subject: Locator; related: Record<string, Locator>}> {
|
|
62
|
+
await page.goto(storyUrl(state.storyId), {waitUntil: 'load'});
|
|
63
|
+
await holdMotionStill(page);
|
|
64
|
+
const root = page.locator('#storybook-root');
|
|
65
|
+
const subject = root.getByRole('separator', {name: state.label});
|
|
66
|
+
await subject.waitFor({state: 'attached'});
|
|
67
|
+
const pane = root.locator('#a11y-splitter-pane');
|
|
68
|
+
return {subject, related: {pane}};
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async function runState(
|
|
72
|
+
page: Page,
|
|
73
|
+
cdp: CDPSession,
|
|
74
|
+
state: ResizeHandleBindingState,
|
|
75
|
+
): Promise<BindingResult> {
|
|
76
|
+
return checkAccessibilitySpec({
|
|
77
|
+
spec: WINDOW_SPLITTER_PATTERN,
|
|
78
|
+
binding: 'ResizeHandle',
|
|
79
|
+
state: state.id,
|
|
80
|
+
facts: state.facts,
|
|
81
|
+
knownFailures: RESIZE_HANDLE_KNOWN_FAILURES,
|
|
82
|
+
mount: async () => {
|
|
83
|
+
const {subject, related} = await mountState(page, state);
|
|
84
|
+
return createChromiumHarness({page, cdp, subject, related});
|
|
85
|
+
},
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
test('every window-splitter expectation is exercised by a ResizeHandle state', async ({
|
|
90
|
+
page,
|
|
91
|
+
}) => {
|
|
92
|
+
// One test mounts and checks every binding state in turn: about 20s on an
|
|
93
|
+
// idle machine, three times that when the contract run shares a runner's
|
|
94
|
+
// cores, so the default 60s ran out mid-loop on whichever state it reached.
|
|
95
|
+
// Budget it like the other whole-inventory sweeps (Button, Checkbox).
|
|
96
|
+
test.setTimeout(3 * 60 * 1000);
|
|
97
|
+
const cdp = await page.context().newCDPSession(page);
|
|
98
|
+
const results: BindingResult[] = [];
|
|
99
|
+
for (const state of RESIZE_HANDLE_BINDING_STATES) {
|
|
100
|
+
results.push(await runState(page, cdp, state));
|
|
101
|
+
}
|
|
102
|
+
expect(neverExercised(results)).toEqual([]);
|
|
103
|
+
expect(unmatchedKnownFailures(RESIZE_HANDLE_KNOWN_FAILURES, results)).toEqual(
|
|
104
|
+
[],
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
for (const state of RESIZE_HANDLE_BINDING_STATES) {
|
|
109
|
+
test(`ResizeHandle [${state.id}] — ${state.summary}`, async ({page}) => {
|
|
110
|
+
const cdp = await page.context().newCDPSession(page);
|
|
111
|
+
const result = await runState(page, cdp, state);
|
|
112
|
+
const report = summarize(WINDOW_SPLITTER_PATTERN, [result]);
|
|
113
|
+
// Required rows block (AST-020 FR9); advisory rows and exact known
|
|
114
|
+
// failures report.
|
|
115
|
+
expect(formatFailures(blockingResults([result]))).toBe('');
|
|
116
|
+
expect(report.unrunLayers).toEqual([]);
|
|
117
|
+
expect(report.counts.unexpectedPass).toBe(0);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ResizeHandle.a11y.known-failures.ts
|
|
5
|
+
* @input The exact window-splitter failures the shipped ResizeHandle produces today
|
|
6
|
+
* @output RESIZE_HANDLE_KNOWN_FAILURES — records both lanes reconcile against, so a fix shows up as an unexpected pass and any other failure stays a failure
|
|
7
|
+
* @position Known-failure ledger for the ResizeHandle binding
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {KnownFailure} from '@astryxdesign/a11y-spec';
|
|
11
|
+
|
|
12
|
+
export const RESIZE_HANDLE_KNOWN_FAILURES: ReadonlyArray<KnownFailure> = [
|
|
13
|
+
{
|
|
14
|
+
expectation: 'windowsplitter.separator.maximum',
|
|
15
|
+
binding: 'ResizeHandle',
|
|
16
|
+
state: 'bare-unbounded-in-container',
|
|
17
|
+
evidenceLayer: 'dom',
|
|
18
|
+
failureEquals: 'the splitter exposes no aria-valuemax',
|
|
19
|
+
standardsReference:
|
|
20
|
+
'WAI-ARIA separator (focusable): aria-valuemax; APG Window Splitter states and properties; Astryx component:Resizable AR1 (an unbounded Handle in a container that no percentage bound observes carries no aria-valuemax, because measuring that container would add an observer to a region whose bounds are all in pixels).',
|
|
21
|
+
userImpact:
|
|
22
|
+
'A screen-reader user on a handle whose pixel-only region sits in a container and sets no maximum hears a value and a minimum but no maximum.',
|
|
23
|
+
reason:
|
|
24
|
+
'A recorded gap with a reason the record owns (Performance and resources: atomic pixel paths add no observer); it closes only with a record decision, not a fix.',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
expectation: 'windowsplitter.separator.controls-pane',
|
|
28
|
+
binding: 'ResizeHandle',
|
|
29
|
+
state: 'bare-documented-usage',
|
|
30
|
+
evidenceLayer: 'dom',
|
|
31
|
+
failureEquals: 'the splitter carries no aria-controls',
|
|
32
|
+
standardsReference:
|
|
33
|
+
'APG Window Splitter states and properties: the separator has aria-controls set to the id of the primary pane; Astryx component:Resizable AR1 (the Handle names the pane it resizes with aria-controls only when its caller passes one).',
|
|
34
|
+
userImpact:
|
|
35
|
+
'A screen-reader user on a handle rendered the documented minimal way hears a separator with no named pane; the relationship exists only when the caller wires it (SideNav does).',
|
|
36
|
+
reason:
|
|
37
|
+
'A recorded gap the record owns: whether the Handle should derive the pane relationship itself is a component decision for its own spec-backed patch.',
|
|
38
|
+
},
|
|
39
|
+
];
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file ResizeHandle.a11y.renders.tsx
|
|
7
|
+
* @input One ResizeHandle binding state
|
|
8
|
+
* @output The React tree every lane renders for that state (the jsdom test directly, the story through Storybook)
|
|
9
|
+
* @position Shared fixture for the ResizeHandle binding
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import {useRef, type ReactElement} from 'react';
|
|
13
|
+
import {ResizeHandle} from '../ResizeHandle';
|
|
14
|
+
import {useResizable} from '../useResizable';
|
|
15
|
+
import type {ResizeHandleBindingState} from './ResizeHandle.a11y.states';
|
|
16
|
+
|
|
17
|
+
/** The id the binding gives the pane the bare handle controls. */
|
|
18
|
+
export const BARE_PANE_ID = 'a11y-splitter-pane';
|
|
19
|
+
|
|
20
|
+
function BareSplitter({state}: {state: ResizeHandleBindingState}) {
|
|
21
|
+
const direction = state.direction ?? 'horizontal';
|
|
22
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
23
|
+
const region = useResizable({
|
|
24
|
+
containerRef: state.inContainer ? containerRef : undefined,
|
|
25
|
+
defaultSize: state.facts.valueNow,
|
|
26
|
+
minSize: state.facts.valueMin,
|
|
27
|
+
maxSize: state.maxSize === null ? undefined : (state.facts.valueMax ?? 400),
|
|
28
|
+
direction,
|
|
29
|
+
collapsible: state.facts.collapsible,
|
|
30
|
+
collapsedSize: state.collapsedSize,
|
|
31
|
+
defaultIsCollapsed: state.startsCollapsed,
|
|
32
|
+
snaps: state.snaps ? [...state.snaps] : undefined,
|
|
33
|
+
});
|
|
34
|
+
const isHorizontal = direction === 'horizontal';
|
|
35
|
+
const pane = (
|
|
36
|
+
<div
|
|
37
|
+
id={BARE_PANE_ID}
|
|
38
|
+
style={{
|
|
39
|
+
...(isHorizontal ? {width: region.size} : {height: region.size}),
|
|
40
|
+
background: 'var(--astryx-bg-surface, #f2f2f2)',
|
|
41
|
+
padding: 12,
|
|
42
|
+
}}>
|
|
43
|
+
Details
|
|
44
|
+
</div>
|
|
45
|
+
);
|
|
46
|
+
const handle = (
|
|
47
|
+
<ResizeHandle
|
|
48
|
+
resizable={region.props}
|
|
49
|
+
label={state.label}
|
|
50
|
+
direction={direction}
|
|
51
|
+
isReversed={state.isReversed}
|
|
52
|
+
isDisabled={state.disabled}
|
|
53
|
+
aria-controls={state.withoutControls ? undefined : BARE_PANE_ID}
|
|
54
|
+
/>
|
|
55
|
+
);
|
|
56
|
+
return (
|
|
57
|
+
<div
|
|
58
|
+
ref={containerRef}
|
|
59
|
+
style={{
|
|
60
|
+
display: 'flex',
|
|
61
|
+
flexDirection: isHorizontal ? 'row' : 'column',
|
|
62
|
+
width: 600,
|
|
63
|
+
height: 320,
|
|
64
|
+
}}>
|
|
65
|
+
{state.isReversed ? handle : pane}
|
|
66
|
+
{state.isReversed ? pane : handle}
|
|
67
|
+
<div style={{flex: 1, padding: 12}}>Main content</div>
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
export function renderResizeHandleState(
|
|
73
|
+
state: ResizeHandleBindingState,
|
|
74
|
+
): ReactElement {
|
|
75
|
+
return (
|
|
76
|
+
<div dir={state.rtl ? 'rtl' : 'ltr'} style={{padding: 16}}>
|
|
77
|
+
<BareSplitter state={state} />
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file ResizeHandle.a11y.states.ts
|
|
5
|
+
* @input ResizeHandle's representative splitter states and the facts WINDOW_SPLITTER_PATTERN reads
|
|
6
|
+
* @output RESIZE_HANDLE_BINDING_STATES and the explicit ownership exclusions for this binding
|
|
7
|
+
* @position Binding inventory shared by the jsdom test, the Chromium spec, and the story (component:Resizable AR1)
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {WindowSplitterStateFacts} from '@astryxdesign/a11y-spec';
|
|
11
|
+
|
|
12
|
+
export interface ResizeHandleBindingState {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly summary: string;
|
|
15
|
+
readonly storyId: string;
|
|
16
|
+
/** Which composition renders the handle; SideNav's binding follows separately. */
|
|
17
|
+
readonly component: 'ResizeHandle';
|
|
18
|
+
/** The separator's accessible name. */
|
|
19
|
+
readonly label: string;
|
|
20
|
+
readonly facts: WindowSplitterStateFacts;
|
|
21
|
+
/** Bare-handle configuration. */
|
|
22
|
+
readonly direction?: 'horizontal' | 'vertical';
|
|
23
|
+
readonly isReversed?: boolean;
|
|
24
|
+
readonly rtl?: boolean;
|
|
25
|
+
readonly maxSize?: number | null;
|
|
26
|
+
/** The hook's collapse threshold, when the state sets one. */
|
|
27
|
+
readonly collapsedSize?: number;
|
|
28
|
+
/** Start the pane collapsed (`defaultIsCollapsed`). */
|
|
29
|
+
readonly startsCollapsed?: boolean;
|
|
30
|
+
/** Pass a `containerRef` (a pixel-only region inside a container). */
|
|
31
|
+
readonly inContainer?: boolean;
|
|
32
|
+
/** Snap points for the region (`snaps`). */
|
|
33
|
+
readonly snaps?: ReadonlyArray<number>;
|
|
34
|
+
/** Render the documented minimal usage: no `aria-controls` passed. */
|
|
35
|
+
readonly withoutControls?: boolean;
|
|
36
|
+
readonly disabled?: boolean;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function facts(
|
|
40
|
+
overrides: Partial<WindowSplitterStateFacts> = {},
|
|
41
|
+
): WindowSplitterStateFacts {
|
|
42
|
+
return {
|
|
43
|
+
valueNow: 200,
|
|
44
|
+
valueMin: 100,
|
|
45
|
+
valueMax: 400,
|
|
46
|
+
orientation: 'vertical',
|
|
47
|
+
increaseKey: 'ArrowRight',
|
|
48
|
+
step: 10,
|
|
49
|
+
operable: true,
|
|
50
|
+
collapsible: false,
|
|
51
|
+
...overrides,
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const story = (id: string) => `a11y-windowsplitter--${id}`;
|
|
56
|
+
|
|
57
|
+
export const RESIZE_HANDLE_BINDING_STATES = [
|
|
58
|
+
{
|
|
59
|
+
id: 'bare-horizontal',
|
|
60
|
+
summary: 'a bare ResizeHandle on the end side of a 200px pane (100–400)',
|
|
61
|
+
storyId: story('bare-horizontal'),
|
|
62
|
+
component: 'ResizeHandle',
|
|
63
|
+
label: 'Resize details pane',
|
|
64
|
+
facts: facts(),
|
|
65
|
+
},
|
|
66
|
+
{
|
|
67
|
+
id: 'bare-vertical',
|
|
68
|
+
summary: 'a bare ResizeHandle below a 200px pane: ArrowDown grows it',
|
|
69
|
+
storyId: story('bare-vertical'),
|
|
70
|
+
component: 'ResizeHandle',
|
|
71
|
+
label: 'Resize log pane',
|
|
72
|
+
facts: facts({orientation: 'horizontal', increaseKey: 'ArrowDown'}),
|
|
73
|
+
direction: 'vertical',
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
id: 'bare-reversed',
|
|
77
|
+
summary:
|
|
78
|
+
'a bare ResizeHandle on the start side of its pane: ArrowLeft grows it',
|
|
79
|
+
storyId: story('bare-reversed'),
|
|
80
|
+
component: 'ResizeHandle',
|
|
81
|
+
label: 'Resize details pane',
|
|
82
|
+
facts: facts({increaseKey: 'ArrowLeft'}),
|
|
83
|
+
isReversed: true,
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
id: 'bare-rtl',
|
|
87
|
+
summary:
|
|
88
|
+
'a bare ResizeHandle on a right-to-left page: the inline arrows follow the reading direction',
|
|
89
|
+
storyId: story('bare-rtl'),
|
|
90
|
+
component: 'ResizeHandle',
|
|
91
|
+
label: 'Resize details pane',
|
|
92
|
+
facts: facts({increaseKey: 'ArrowLeft'}),
|
|
93
|
+
rtl: true,
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
id: 'bare-collapsible',
|
|
97
|
+
summary:
|
|
98
|
+
'a bare ResizeHandle on a collapsible pane: Enter collapses and restores',
|
|
99
|
+
storyId: story('bare-collapsible'),
|
|
100
|
+
component: 'ResizeHandle',
|
|
101
|
+
label: 'Resize details pane',
|
|
102
|
+
facts: facts({collapsible: true}),
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
id: 'bare-small-min',
|
|
106
|
+
summary:
|
|
107
|
+
'a bare ResizeHandle on a collapsible pane whose minimum sits below the collapse threshold',
|
|
108
|
+
storyId: story('bare-small-min'),
|
|
109
|
+
component: 'ResizeHandle',
|
|
110
|
+
label: 'Resize details pane',
|
|
111
|
+
facts: facts({collapsible: true, valueMin: 20}),
|
|
112
|
+
collapsedSize: 50,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
id: 'bare-start-collapsed',
|
|
116
|
+
summary:
|
|
117
|
+
'a bare ResizeHandle on a pane that starts collapsed: it announces the minimum as its value',
|
|
118
|
+
storyId: story('bare-start-collapsed'),
|
|
119
|
+
component: 'ResizeHandle',
|
|
120
|
+
label: 'Resize details pane',
|
|
121
|
+
// Collapsed, the handle announces the minimum (100) as its value.
|
|
122
|
+
facts: facts({collapsible: true, startsCollapsed: true, valueNow: 100}),
|
|
123
|
+
startsCollapsed: true,
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
id: 'bare-unbounded',
|
|
127
|
+
summary: 'a bare ResizeHandle whose region sets no maximum',
|
|
128
|
+
storyId: story('bare-unbounded'),
|
|
129
|
+
component: 'ResizeHandle',
|
|
130
|
+
label: 'Resize details pane',
|
|
131
|
+
facts: facts({valueMax: null}),
|
|
132
|
+
maxSize: null,
|
|
133
|
+
},
|
|
134
|
+
{
|
|
135
|
+
id: 'bare-unbounded-in-container',
|
|
136
|
+
summary:
|
|
137
|
+
'a bare ResizeHandle whose pixel-only region sets no maximum and passes a containerRef: the first useResizable example',
|
|
138
|
+
storyId: story('bare-unbounded-in-container'),
|
|
139
|
+
component: 'ResizeHandle',
|
|
140
|
+
label: 'Resize details pane',
|
|
141
|
+
facts: facts({valueMax: null}),
|
|
142
|
+
maxSize: null,
|
|
143
|
+
inContainer: true,
|
|
144
|
+
},
|
|
145
|
+
{
|
|
146
|
+
id: 'bare-snapped',
|
|
147
|
+
summary:
|
|
148
|
+
'a bare ResizeHandle whose region sets snap points [100, 200, 300, 400]: an arrow moves to the adjacent point',
|
|
149
|
+
storyId: story('bare-snapped'),
|
|
150
|
+
component: 'ResizeHandle',
|
|
151
|
+
label: 'Resize details pane',
|
|
152
|
+
// One arrow moves to the adjacent point: 100px apart here.
|
|
153
|
+
facts: facts({step: 100}),
|
|
154
|
+
snaps: [100, 200, 300, 400],
|
|
155
|
+
},
|
|
156
|
+
{
|
|
157
|
+
id: 'bare-documented-usage',
|
|
158
|
+
summary:
|
|
159
|
+
'the documented minimal usage — <ResizeHandle direction resizable={region.props} /> with no aria-controls passed',
|
|
160
|
+
storyId: story('bare-documented-usage'),
|
|
161
|
+
component: 'ResizeHandle',
|
|
162
|
+
label: 'Resize details pane',
|
|
163
|
+
facts: facts(),
|
|
164
|
+
withoutControls: true,
|
|
165
|
+
},
|
|
166
|
+
{
|
|
167
|
+
id: 'bare-disabled',
|
|
168
|
+
summary: 'a disabled ResizeHandle: out of the Tab order and unmoving',
|
|
169
|
+
storyId: story('bare-disabled'),
|
|
170
|
+
component: 'ResizeHandle',
|
|
171
|
+
label: 'Resize details pane',
|
|
172
|
+
facts: facts({operable: false}),
|
|
173
|
+
disabled: true,
|
|
174
|
+
},
|
|
175
|
+
] as const satisfies ReadonlyArray<ResizeHandleBindingState>;
|
|
176
|
+
|
|
177
|
+
export const RESIZE_HANDLE_EXCLUSIONS = [
|
|
178
|
+
{
|
|
179
|
+
id: 'sidenav-binding',
|
|
180
|
+
owner:
|
|
181
|
+
'SideNav.test.tsx until SideNav binds this contract in its own change',
|
|
182
|
+
reason:
|
|
183
|
+
'SideNav renders ResizeHandle in overlay position with its own collapse coupling and translated label, and hides the handle entirely while the nav is collapsed, so the collapse-and-restore row cannot run against it as written; SideNav binds separately with states shaped for that.',
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
id: 'pointer-drag-model',
|
|
187
|
+
owner: 'ResizeHandle.test.tsx pointer suites',
|
|
188
|
+
reason:
|
|
189
|
+
"Dragging (pointer capture on the grab zone, ignoring a pointer that does not own the drag, ending on pointercancel or lost capture), double-click collapse and restore, and the grab-zone geometry are pointer behavior outside the keyboard-and-semantics pattern; the component's own jsdom pointer suites prove them. ResizeHandle has no Escape cancel and no Chromium pointer suite.",
|
|
190
|
+
},
|
|
191
|
+
{
|
|
192
|
+
id: 'pane-cycling',
|
|
193
|
+
owner: 'component:Resizable AR1 (not adopted) and the composing page',
|
|
194
|
+
reason:
|
|
195
|
+
"F6 pane cycling is an optional part of the APG pattern that the record does not adopt; which panes exist and how focus cycles among them is the composing page's decision.",
|
|
196
|
+
},
|
|
197
|
+
] as const;
|