@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
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file Carousel.a11y.states.ts
|
|
5
|
+
* @input Uses CarouselStateFacts from @astryxdesign/a11y-spec
|
|
6
|
+
* @output The AST-021 binding inventory for Carousel semantic parts
|
|
7
|
+
* @position Data-only inventory shared by jsdom, Storybook, and Chromium bindings.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type {CarouselStateFacts} from '@astryxdesign/a11y-spec';
|
|
11
|
+
|
|
12
|
+
export interface CarouselBindingState {
|
|
13
|
+
readonly id: string;
|
|
14
|
+
readonly summary: string;
|
|
15
|
+
readonly facts: CarouselStateFacts;
|
|
16
|
+
readonly subject:
|
|
17
|
+
| {readonly role: 'region' | 'group' | 'button'; readonly name: string}
|
|
18
|
+
| {readonly selector: string};
|
|
19
|
+
readonly relations?: Readonly<Record<string, {readonly selector: string}>>;
|
|
20
|
+
readonly storyId: string;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export type CarouselBindingRow = CarouselBindingState;
|
|
24
|
+
|
|
25
|
+
const story = (id: string) => `a11y-carousel-pattern--${id}`;
|
|
26
|
+
const slideRelations = {
|
|
27
|
+
'slide-1': {selector: '[role="group"][aria-label="Slide 1 of 4"]'},
|
|
28
|
+
'slide-2': {selector: '[role="group"][aria-label="Slide 2 of 4"]'},
|
|
29
|
+
'slide-3': {selector: '[role="group"][aria-label="Slide 3 of 4"]'},
|
|
30
|
+
'slide-4': {selector: '[role="group"][aria-label="Slide 4 of 4"]'},
|
|
31
|
+
} as const;
|
|
32
|
+
|
|
33
|
+
export const CAROUSEL_BINDING_STATES = [
|
|
34
|
+
{
|
|
35
|
+
id: 'container-labelled',
|
|
36
|
+
summary: 'the labelled Carousel region and all four slides',
|
|
37
|
+
facts: {
|
|
38
|
+
part: 'container',
|
|
39
|
+
expectedName: 'Featured work',
|
|
40
|
+
slideRelations: Object.keys(slideRelations),
|
|
41
|
+
offscreen: false,
|
|
42
|
+
scrollable: false,
|
|
43
|
+
focusable: false,
|
|
44
|
+
preservesControlFocus: false,
|
|
45
|
+
},
|
|
46
|
+
subject: {role: 'region', name: 'Featured work'},
|
|
47
|
+
relations: slideRelations,
|
|
48
|
+
storyId: story('container-labelled'),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'slide-visible',
|
|
52
|
+
summary: 'the first visible positional slide',
|
|
53
|
+
facts: {
|
|
54
|
+
part: 'slide',
|
|
55
|
+
expectedName: 'Slide 1 of 4',
|
|
56
|
+
slideRelations: [],
|
|
57
|
+
offscreen: false,
|
|
58
|
+
scrollable: false,
|
|
59
|
+
focusable: false,
|
|
60
|
+
preservesControlFocus: false,
|
|
61
|
+
},
|
|
62
|
+
subject: {role: 'group', name: 'Slide 1 of 4'},
|
|
63
|
+
storyId: story('slide-visible'),
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
id: 'slide-offscreen',
|
|
67
|
+
summary: 'the fourth off-screen slide that remains exposed',
|
|
68
|
+
facts: {
|
|
69
|
+
part: 'slide',
|
|
70
|
+
expectedName: 'Slide 4 of 4',
|
|
71
|
+
slideRelations: [],
|
|
72
|
+
offscreen: true,
|
|
73
|
+
scrollable: false,
|
|
74
|
+
focusable: false,
|
|
75
|
+
preservesControlFocus: false,
|
|
76
|
+
},
|
|
77
|
+
subject: {role: 'group', name: 'Slide 4 of 4'},
|
|
78
|
+
storyId: story('slide-offscreen'),
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
id: 'scroller-keyboard',
|
|
82
|
+
summary: 'the native horizontal scroll container in the tab sequence',
|
|
83
|
+
facts: {
|
|
84
|
+
part: 'scroller',
|
|
85
|
+
expectedName: '',
|
|
86
|
+
slideRelations: [],
|
|
87
|
+
offscreen: false,
|
|
88
|
+
scrollable: true,
|
|
89
|
+
focusable: true,
|
|
90
|
+
preservesControlFocus: false,
|
|
91
|
+
},
|
|
92
|
+
subject: {
|
|
93
|
+
selector: '[data-testid="carousel-a11y"] > .astryx-carousel-scroller',
|
|
94
|
+
},
|
|
95
|
+
storyId: story('scroller-keyboard'),
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
id: 'next-control-focus',
|
|
99
|
+
summary: 'the looping next control, which stays enabled and keeps focus',
|
|
100
|
+
facts: {
|
|
101
|
+
part: 'control',
|
|
102
|
+
expectedName: 'Scroll right',
|
|
103
|
+
slideRelations: [],
|
|
104
|
+
offscreen: false,
|
|
105
|
+
scrollable: false,
|
|
106
|
+
focusable: true,
|
|
107
|
+
preservesControlFocus: true,
|
|
108
|
+
},
|
|
109
|
+
subject: {role: 'button', name: 'Scroll right'},
|
|
110
|
+
storyId: story('next-control-focus'),
|
|
111
|
+
},
|
|
112
|
+
] as const satisfies ReadonlyArray<CarouselBindingState>;
|
|
113
|
+
|
|
114
|
+
export const CAROUSEL_EXCLUSIONS = [
|
|
115
|
+
{
|
|
116
|
+
owner: 'Button pattern',
|
|
117
|
+
classification: 'preserved',
|
|
118
|
+
reason:
|
|
119
|
+
'Navigation-control role, name, activation, unavailable state, and pointer cancellation remain owned by the shared Button contract.',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
owner: 'Carousel implementation and visual gate',
|
|
123
|
+
classification: 'preserved',
|
|
124
|
+
reason:
|
|
125
|
+
'Scroll distance, snapping, looping, edge fades, focus-ring paint, target geometry, and reduced-motion behavior remain component-owned browser and visual evidence.',
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
owner: 'Caller content',
|
|
129
|
+
classification: 'out-of-scope',
|
|
130
|
+
reason:
|
|
131
|
+
'Slide descendants keep their own image, link, control, reading-order, and language obligations.',
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
owner: 'Automatic rotation',
|
|
135
|
+
classification: 'out-of-scope',
|
|
136
|
+
reason:
|
|
137
|
+
'Carousel does not auto-advance; the public docs explicitly tell consumers not to auto-advance items.',
|
|
138
|
+
},
|
|
139
|
+
] as const;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
/** @vitest-environment jsdom */
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* @file Carousel.a11y.test.tsx
|
|
6
|
+
* @input Uses the shared Carousel contract and complete Carousel binding inventory
|
|
7
|
+
* @output DOM-layer binding evidence; browser-owned outcomes remain explicitly unrun
|
|
8
|
+
* @position Fast migration lane for Carousel container, slides, scroller, and control.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import {cleanup, render, screen} from '@testing-library/react';
|
|
12
|
+
import {describe, expect, it} from 'vitest';
|
|
13
|
+
import {
|
|
14
|
+
CAROUSEL_PATTERN,
|
|
15
|
+
checkAccessibilitySpec,
|
|
16
|
+
createJsdomHarness,
|
|
17
|
+
expectAccessibilitySpec,
|
|
18
|
+
summarize,
|
|
19
|
+
type BindingResult,
|
|
20
|
+
} from '@astryxdesign/a11y-spec';
|
|
21
|
+
import {CAROUSEL_KNOWN_FAILURES} from './Carousel.a11y.known-failures';
|
|
22
|
+
import {CAROUSEL_STATE_RENDERS} from './Carousel.a11y.renders';
|
|
23
|
+
import {
|
|
24
|
+
CAROUSEL_BINDING_STATES,
|
|
25
|
+
CAROUSEL_EXCLUSIONS,
|
|
26
|
+
type CarouselBindingRow,
|
|
27
|
+
} from './Carousel.a11y.states';
|
|
28
|
+
|
|
29
|
+
function subjectFor(state: CarouselBindingRow): Element {
|
|
30
|
+
if ('selector' in state.subject) {
|
|
31
|
+
const element = document.querySelector(state.subject.selector);
|
|
32
|
+
if (element == null) {
|
|
33
|
+
throw new Error(`no subject for ${state.id}`);
|
|
34
|
+
}
|
|
35
|
+
return element;
|
|
36
|
+
}
|
|
37
|
+
return screen.getByRole(state.subject.role, {
|
|
38
|
+
name: state.subject.name,
|
|
39
|
+
hidden: true,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function relatedFor(
|
|
44
|
+
state: CarouselBindingRow,
|
|
45
|
+
): Readonly<Record<string, Element>> {
|
|
46
|
+
return Object.fromEntries(
|
|
47
|
+
Object.entries(state.relations ?? {}).map(([name, relation]) => {
|
|
48
|
+
const element = document.querySelector(relation.selector);
|
|
49
|
+
if (element == null) {
|
|
50
|
+
throw new Error(`no related subject "${name}" for ${state.id}`);
|
|
51
|
+
}
|
|
52
|
+
return [name, element];
|
|
53
|
+
}),
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async function checkState(state: CarouselBindingRow): Promise<BindingResult> {
|
|
58
|
+
return checkAccessibilitySpec({
|
|
59
|
+
spec: CAROUSEL_PATTERN,
|
|
60
|
+
binding: 'Carousel',
|
|
61
|
+
state: state.id,
|
|
62
|
+
facts: state.facts,
|
|
63
|
+
knownFailures: CAROUSEL_KNOWN_FAILURES,
|
|
64
|
+
mount: async () => {
|
|
65
|
+
render(CAROUSEL_STATE_RENDERS[state.id]());
|
|
66
|
+
return createJsdomHarness({
|
|
67
|
+
subject: subjectFor(state),
|
|
68
|
+
related: relatedFor(state),
|
|
69
|
+
});
|
|
70
|
+
},
|
|
71
|
+
unmount: cleanup,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
describe('the shared Carousel pattern, jsdom lane', () => {
|
|
76
|
+
it.each(
|
|
77
|
+
CAROUSEL_BINDING_STATES.map(
|
|
78
|
+
state => [`Carousel [${state.id}]`, state.summary, state] as const,
|
|
79
|
+
),
|
|
80
|
+
)('%s — %s', async (_id, _summary, state) => {
|
|
81
|
+
await expectAccessibilitySpec({
|
|
82
|
+
spec: CAROUSEL_PATTERN,
|
|
83
|
+
binding: 'Carousel',
|
|
84
|
+
state: state.id,
|
|
85
|
+
facts: state.facts,
|
|
86
|
+
knownFailures: CAROUSEL_KNOWN_FAILURES,
|
|
87
|
+
render: () => {
|
|
88
|
+
render(CAROUSEL_STATE_RENDERS[state.id]());
|
|
89
|
+
},
|
|
90
|
+
subject: () => subjectFor(state),
|
|
91
|
+
related: () => relatedFor(state),
|
|
92
|
+
cleanup,
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it('runs DOM expectations and reports higher layers as unrun', async () => {
|
|
97
|
+
const results: BindingResult[] = [];
|
|
98
|
+
for (const state of CAROUSEL_BINDING_STATES) {
|
|
99
|
+
results.push(await checkState(state));
|
|
100
|
+
}
|
|
101
|
+
const report = summarize(CAROUSEL_PATTERN, results);
|
|
102
|
+
expect(report.counts.pass).toBeGreaterThan(0);
|
|
103
|
+
expect(report.unrunLayers).toEqual(['accessibility-tree', 'real-browser']);
|
|
104
|
+
expect(report.counts.unexpectedPass).toBe(0);
|
|
105
|
+
});
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
describe('the Carousel binding inventory', () => {
|
|
109
|
+
it('names a distinct checked-in story for every state', () => {
|
|
110
|
+
const ids = CAROUSEL_BINDING_STATES.map(state => state.storyId);
|
|
111
|
+
expect(new Set(ids).size).toBe(ids.length);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('records every excluded owner explicitly', () => {
|
|
115
|
+
expect(CAROUSEL_EXCLUSIONS.every(row => row.owner && row.reason)).toBe(
|
|
116
|
+
true,
|
|
117
|
+
);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
it('renders exactly one subject for every state', () => {
|
|
121
|
+
for (const state of CAROUSEL_BINDING_STATES) {
|
|
122
|
+
render(CAROUSEL_STATE_RENDERS[state.id]());
|
|
123
|
+
expect(subjectFor(state), state.id).toBeTruthy();
|
|
124
|
+
cleanup();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -98,7 +98,7 @@ export const docs = {
|
|
|
98
98
|
name: 'triggers',
|
|
99
99
|
type: 'ChatComposerTrigger[]',
|
|
100
100
|
description:
|
|
101
|
-
'Trigger definitions for typeahead menus. Each trigger specifies a character (@ or /), a search source, and an onSelect handler that returns the token to insert. Per-trigger emptySearchText (ReactNode) is the message when the query matched nothing.',
|
|
101
|
+
'Trigger definitions for typeahead menus. Each trigger specifies a character (@ or /), a search source, and an onSelect handler that returns the token to insert. Set hasMultiWordQuery: true when suggestions contain spaces (people, topics): the query then runs to a line break or about 64 characters instead of ending at the first space. Per-trigger emptySearchText (ReactNode) is the message when the query matched nothing.',
|
|
102
102
|
},
|
|
103
103
|
{
|
|
104
104
|
name: 'debounceMs',
|
|
@@ -3,11 +3,11 @@ schema_version: 3
|
|
|
3
3
|
template_version: 5
|
|
4
4
|
kind: component
|
|
5
5
|
id: component:ChatComposerInput
|
|
6
|
-
authority:
|
|
6
|
+
authority: current
|
|
7
7
|
archive_reason: null
|
|
8
8
|
superseded_by: null
|
|
9
|
-
approved_by:
|
|
10
|
-
approved_at:
|
|
9
|
+
approved_by: cixzhang
|
|
10
|
+
approved_at: 2026-10-14
|
|
11
11
|
owners: [cixzhang]
|
|
12
12
|
review_triggers: [public-api, behavior, accessibility, interaction, theming]
|
|
13
13
|
verified_by:
|
|
@@ -33,15 +33,15 @@ system_specs: [spec:AST-002, spec:AST-029]
|
|
|
33
33
|
|
|
34
34
|
## Contract at a glance
|
|
35
35
|
|
|
36
|
-
| Area | Contract
|
|
37
|
-
| ----------------------- |
|
|
38
|
-
| Public contract |
|
|
39
|
-
| Behavior | Every edit path keeps the serialized draft observable. Files pasted or dropped reach `onFiles`; consumer `onPaste` receives first refusal over plain text before optional paste-as-token conversion.
|
|
40
|
-
| End-user impact | Dictated or otherwise programmatically inserted text
|
|
41
|
-
| Builder impact | Existing props, callback signatures, defaults, exports, and token serialization
|
|
42
|
-
| Compatibility/readiness | Patch-compatible
|
|
43
|
-
| Review checks | Reject an edit path that mutates the DOM without updating the serialized draft, a file drop that can navigate away or bypass `onFiles`, a text paste that bypasses consumer interception,
|
|
44
|
-
| Governing rules | `architecture:public-component-api/INV1`; `architecture:interaction-modality/INV1–INV4`; `architecture:knowledge-contracts/INV11, INV16`; `spec:AST-002`; `spec:AST-029`; rubric B15.
|
|
36
|
+
| Area | Contract |
|
|
37
|
+
| ----------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
38
|
+
| Public contract | ChatComposerInput remains the optional rich editing surface for ChatComposer, with controlled draft, trigger, history, paste, file, and imperative seams. Each trigger definition may opt into multi-word queries with `hasMultiWordQuery`, default `false`. |
|
|
39
|
+
| Behavior | Every edit path keeps the serialized draft observable. Files pasted or dropped reach `onFiles`; consumer `onPaste` receives first refusal over plain text before optional paste-as-token conversion. |
|
|
40
|
+
| End-user impact | Dictated or otherwise programmatically inserted text is sendable and never hidden behind the empty placeholder; dropped files reach the product attachment flow. |
|
|
41
|
+
| Builder impact | Existing props, callback signatures, prop defaults, exports, and token serialization are unchanged. Builders relying on the documented `onPaste` and `onFiles` paths receive those callbacks except where FR5 and FR6 record implementation gaps; `hasMultiWordQuery` is the one added optional trigger field. Every trigger receives the trigger-key corrections listed under Compatibility and migration (FR10, FR13, FR15, FR16). |
|
|
42
|
+
| Compatibility/readiness | Patch-compatible. One additive optional trigger field (DEC-1) plus trigger-key corrections that apply to every trigger (FR10, FR13, FR15, FR16); no visual decision. Implementation gaps are recorded inline on FR1, FR5, FR6, FR10, and PR2. |
|
|
43
|
+
| Review checks | Reject an edit path that mutates the DOM without updating the serialized draft, a file drop that can navigate away or bypass `onFiles`, a text paste that bypasses consumer interception, changed submit/token semantics, a trigger query that alters typed text, a key that picks a row from an earlier trigger query, or a menu that reopens after a send. |
|
|
44
|
+
| Governing rules | `architecture:public-component-api/INV1`; `architecture:interaction-modality/INV1–INV4`; `architecture:knowledge-contracts/INV11, INV16`; `spec:AST-002`; `spec:AST-029`; rubric B15. |
|
|
45
45
|
|
|
46
46
|
This table is a review projection; the body below is authoritative.
|
|
47
47
|
|
|
@@ -55,9 +55,15 @@ imperative editing handle.
|
|
|
55
55
|
## Compatibility and migration
|
|
56
56
|
|
|
57
57
|
- Released default preserved: yes
|
|
58
|
-
- Compatibility class: patch-compatible
|
|
58
|
+
- Compatibility class: patch-compatible; one additive optional trigger field, no prop default changes, and trigger-key corrections for every trigger
|
|
59
59
|
- Controlled and composition behavior: unchanged
|
|
60
60
|
- Migration decision: none
|
|
61
|
+
- Trigger query shape: `hasMultiWordQuery` is an additive optional trigger field; omitting it keeps single-token queries
|
|
62
|
+
- Every trigger, opted in or not, also receives these patch-compatible corrections:
|
|
63
|
+
- FR13, correction: a key never picks a row returned for an earlier query, and a result arriving after a send, clear, pick, or dismissal is discarded instead of reopening the menu.
|
|
64
|
+
- FR15, correction: IME composition keys never pick a row or move the highlighted row.
|
|
65
|
+
- FR16, correction: after Escape, the menu stays hidden while the same query keeps growing instead of reopening on the next keystroke.
|
|
66
|
+
- FR10, correction: a tab before the trigger character is a boundary, like a space or line break.
|
|
61
67
|
|
|
62
68
|
## Ownership boundary
|
|
63
69
|
|
|
@@ -82,6 +88,7 @@ imperative editing handle.
|
|
|
82
88
|
| draft storage | DOM-owned; `value` controlled; ChatComposer context controlled | Selects the serialized draft source and observable change channel. | every editor | context or empty DOM | `component:ChatComposerInput` | stable | Explicit `value` wins; unsupported values are rejected by TypeScript. |
|
|
83
89
|
| submission | Enter; Shift+Enter; IME Enter; consumer-cancelled Enter | Submits one trimmed non-empty draft only on uncancelled Enter without Shift or composition. | enabled editor | Enter submits | `component:ChatComposerInput` | stable | Empty or composing submission is ignored. |
|
|
84
90
|
| trigger menu | omitted; one or more trigger definitions | Opens suggestions at a configured character and inserts text or a serialized token. | when triggers are configured | omitted | `component:ChatComposerInput` | stable | Unknown trigger characters remain ordinary text. |
|
|
91
|
+
| trigger query | single-token; multi-word | Sets where an active trigger query ends, as FR10 and FR11 state. | while a trigger is active | single-token | `component:ChatComposerInput` | stable | Omitting `hasMultiWordQuery` keeps single-token queries. |
|
|
85
92
|
| history | enabled; disabled | Recalls submitted drafts at text boundaries with ArrowUp and ArrowDown. | when enabled and history exists | enabled | `component:ChatComposerInput` | stable | Mid-text arrow keys retain native caret behavior. |
|
|
86
93
|
| text paste | consumer-handled; paste-as-token; plain text | Gives `onPaste` first refusal, then optional token conversion, then inserts plain text. | enabled editor | long-paste token conversion | `component:ChatComposerInput` | stable | A handled callback stops later insertion paths. |
|
|
87
94
|
| file intake | pasted; dropped | Prevents browser navigation and passes the files to `onFiles`. | when files are supplied | no callback | `component:ChatComposerInput` | stable | Empty drops do nothing; disabled input does not emit files. |
|
|
@@ -89,17 +96,24 @@ imperative editing handle.
|
|
|
89
96
|
|
|
90
97
|
## Behavioral and layout contract
|
|
91
98
|
|
|
92
|
-
| ID
|
|
93
|
-
|
|
|
94
|
-
| FR1
|
|
95
|
-
| FR2
|
|
96
|
-
| FR3
|
|
97
|
-
| FR4
|
|
98
|
-
| FR5
|
|
99
|
-
| FR6
|
|
100
|
-
| FR7
|
|
101
|
-
| FR8
|
|
102
|
-
| FR9
|
|
99
|
+
| ID | Invariant | Basis |
|
|
100
|
+
| ---- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- |
|
|
101
|
+
| FR1 | Every user or imperative edit that changes serialized content MUST update empty state and emit the effective value through the active `onChange` channel. Implementation gap: `handleRef.insertToken` inserts the token without emitting the value through `onChange` or updating empty state, so the placeholder stays visible. | Shipped `onChange` contract, imperative handle, and ChatDictation callsite. |
|
|
102
|
+
| FR2 | Enter without Shift MUST submit one trimmed non-empty draft and clear it unless the event is composing, the trigger menu consumes it, or a consumer prevents default. | Shipped implementation and consumer docs. |
|
|
103
|
+
| FR3 | Shift+Enter and mid-text history arrows MUST retain native multiline editing behavior. | Shipped implementation and focused tests. |
|
|
104
|
+
| FR4 | `value` supplied directly on ChatComposerInput MUST win over ChatComposer context, while an emitted echo MUST NOT rebuild the DOM or move the caret. | Shipped controlled precedence and regression tests. |
|
|
105
|
+
| FR5 | Plain-text paste precedence MUST be consumer `onPaste` → configured/default paste-as-token → plain insertion. Implementation gap: a paste whose selection starts inside a token inserts the text after that token without calling `onPaste`. | Public callback meaning and objective callback composition. |
|
|
106
|
+
| FR6 | File paste and file drop MUST prevent native insertion/navigation and deliver the same ordered `File[]` to `onFiles`; disabled editors MUST NOT emit file callbacks. Implementation gap: a file paste whose selection starts inside a token never reaches `onFiles`. | Shipped public `onFiles` contract and consumer docs. |
|
|
107
|
+
| FR7 | Trigger-menu keyboard handling MUST run before consumer and built-in editor handling; IME composition MUST never submit. | Shipped interaction contract and tests. |
|
|
108
|
+
| FR8 | History recall MUST operate only at the draft boundaries and MUST restore the pending draft after stepping past the newest item. | Shipped behavior and tests. |
|
|
109
|
+
| FR9 | The root MUST keep forwarding its ref, BaseProps attributes, and styling seams; the imperative handle remains separate in `handleRef`. | Released public API and `architecture:public-component-api`. |
|
|
110
|
+
| FR10 | A trigger activates when its character starts the text or follows a space, a tab, or a line break, and its query runs from after that character to the caret. Inside an active multi-word query, FR11 limits which characters activate. A no-break space, such as the one after an inserted token, is not a boundary. A single-token query ends at a space, a tab, or a line break. Implementation gap: a trigger character that begins a text node activates whatever precedes it, such as an `@` typed directly after an inserted token and before its trailing no-break space. | Shipped trigger detection; DEC-1. |
|
|
111
|
+
| FR11 | A trigger with `hasMultiWordQuery: true` keeps its query through spaces and punctuation. The query ends only at a line break, past an implementation-owned length bound of at least 64 characters, or where the same trigger's character after a space, a tab, or a line break starts a new query; no word count, punctuation list, or termination callback applies. Inside an active multi-word query, another trigger's character does not activate under FR10, so the query continues through it. | DEC-1. |
|
|
112
|
+
| FR12 | Ending a trigger query MUST leave the typed text unchanged. Only an explicit pick of a current row replaces the range from the trigger character to the caret. | DEC-1. |
|
|
113
|
+
| FR13 | While a newer search for the active query is pending, Enter without Shift submits the draft as typed and MUST NOT pick a row; no key picks a row returned for an earlier query. Results for a superseded query, or arriving after a pick, dismissal, submission, or the query ending, are discarded, so the menu never reopens over a sent or cleared draft. This applies to every trigger. | DEC-1; reference chat composer behavior. |
|
|
114
|
+
| FR14 | When a multi-word query settles with no matches, the menu is hidden unless the trigger supplies `emptySearchText`. A single-token query with no matches shows the empty message. | DEC-1. |
|
|
115
|
+
| FR15 | Keys pressed during IME composition MUST NOT pick a row or move the highlighted row. | DEC-1; FR7. |
|
|
116
|
+
| FR16 | Escape on a visible menu dismisses it, and the menu stays hidden while the same query keeps growing from the same trigger. | DEC-1. |
|
|
103
117
|
|
|
104
118
|
### Allowed variation
|
|
105
119
|
|
|
@@ -109,27 +123,29 @@ imperative editing handle.
|
|
|
109
123
|
|
|
110
124
|
### Representative states
|
|
111
125
|
|
|
112
|
-
| State | Required invariant
|
|
113
|
-
| ----------------------------------- |
|
|
114
|
-
| empty | Placeholder is visible and the serialized value is empty.
|
|
115
|
-
| typed or imperatively inserted text | Placeholder is absent and the same serialized value is observable to ChatComposer and callbacks.
|
|
116
|
-
| controlled update | External value is reflected without corrupting a live caret or treating a stale echo as authoritative.
|
|
117
|
-
| trigger menu open | Combobox semantics and active option wiring are exposed; menu interaction owns its keys.
|
|
118
|
-
|
|
|
119
|
-
|
|
|
126
|
+
| State | Required invariant | Allowed variation |
|
|
127
|
+
| ----------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------- |
|
|
128
|
+
| empty | Placeholder is visible and the serialized value is empty. | Placeholder copy. |
|
|
129
|
+
| typed or imperatively inserted text | Placeholder is absent and the same serialized value is observable to ChatComposer and callbacks (FR1 records an implementation gap). | Draft content. |
|
|
130
|
+
| controlled update | External value is reflected without corrupting a live caret or treating a stale echo as authoritative. | Parent update timing. |
|
|
131
|
+
| trigger menu open | Combobox semantics and active option wiring are exposed; menu interaction owns its keys. | Search source and item rendering. |
|
|
132
|
+
| trigger search pending | Enter submits the draft as typed; no earlier query's row can be picked. | Loading copy and source latency. |
|
|
133
|
+
| trigger menu hidden | The editor reports a collapsed combobox and the menu consumes no keys. | Why the menu is hidden. |
|
|
134
|
+
| file paste or drop | Native insertion/navigation is prevented and files reach `onFiles` once (FR6 records an implementation gap). | File types and product handling. |
|
|
135
|
+
| disabled | Editing and file callbacks are unavailable and disabled state is exposed. | Product reason and surrounding status. |
|
|
120
136
|
|
|
121
137
|
### Transformation and precedence order
|
|
122
138
|
|
|
123
139
|
- **ORD1 — Draft source.** Explicit `value` → ChatComposer context value → editor DOM.
|
|
124
140
|
- **ORD2 — Change channel.** Explicit controlled input callback when `value` is explicit → ChatComposer context callback → distinct local callback.
|
|
125
141
|
- **ORD3 — Key handling.** Trigger menu → consumer `onKeyDown` → IME/submit/history behavior.
|
|
126
|
-
- **ORD4 — Plain paste.** Consumer `onPaste` → paste-as-token behavior → plain insertion.
|
|
127
|
-
- **ORD5 — File intake.** Files on clipboard or data transfer → prevent native behavior → emit `onFiles` when enabled.
|
|
142
|
+
- **ORD4 — Plain paste.** Consumer `onPaste` → paste-as-token behavior → plain insertion (FR5 records an implementation gap).
|
|
143
|
+
- **ORD5 — File intake.** Files on clipboard or data transfer → prevent native behavior → emit `onFiles` when enabled (FR6 records an implementation gap).
|
|
128
144
|
|
|
129
145
|
### Performance and resources
|
|
130
146
|
|
|
131
147
|
- **PR1 — Selection work.** Selection reads and writes are scoped to the mounted editable and run only for direct editing actions or controlled synchronization.
|
|
132
|
-
- **PR2 — Async trigger work.** Search cancellation and
|
|
148
|
+
- **PR2 — Async trigger work.** Search cancellation goes through the supplied `SearchSource` and its optional `cancel`, and `debounceMs` sets the delay before an async search starts. Implementation gap: each keystroke that changes the query also calls `search('')` at once to detect whether the source is async, so an async source receives an undelayed search.
|
|
133
149
|
- **PR3 — Portal cleanup.** Token portals are cleaned through the existing token hook when content changes or unmounts.
|
|
134
150
|
|
|
135
151
|
## Accessibility contract
|
|
@@ -138,19 +154,20 @@ imperative editing handle.
|
|
|
138
154
|
- **AR2 — Disabled state.** Disabled editing is exposed with `aria-disabled` and cannot accept content or file callbacks.
|
|
139
155
|
- **AR3 — Keyboard ownership.** IME, trigger-menu keys, consumer cancellation, Enter submission, and boundary-only history do not steal one another's keys.
|
|
140
156
|
- **AR4 — Focus visibility.** When composed in ChatComposer, the semantic editor focus owner drives the shell's shared keyboard focus indicator.
|
|
157
|
+
- **AR5 — Collapsed suggestions.** While the menu is hidden, the editor reports `aria-expanded="false"`, exposes no active descendant, and arrow keys, Enter, and Escape reach the editor and its surroundings.
|
|
141
158
|
|
|
142
159
|
## Design relationships
|
|
143
160
|
|
|
144
|
-
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract
|
|
145
|
-
| ---------------- | ---------------------------------- | ------------------------ | -------------- |
|
|
146
|
-
| input root | existing themed target | observed implementation | supporting | FR9
|
|
147
|
-
| editable surface | ordinary composer editing surface | ChatComposer family | prominent | FR1–FR4, AR1–AR4
|
|
148
|
-
| placeholder | secondary text while empty | current token role | supporting | FR1
|
|
149
|
-
| trigger menu | delegated Typeahead behavior | Typeahead owner | floating | FR7
|
|
150
|
-
| inline token | structured Badge or caller content | Badge or caller owner | supporting | AV2
|
|
161
|
+
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
162
|
+
| ---------------- | ---------------------------------- | ------------------------ | -------------- | ------------------- |
|
|
163
|
+
| input root | existing themed target | observed implementation | supporting | FR9 |
|
|
164
|
+
| editable surface | ordinary composer editing surface | ChatComposer family | prominent | FR1–FR4, AR1–AR4 |
|
|
165
|
+
| placeholder | secondary text while empty | current token role | supporting | FR1 |
|
|
166
|
+
| trigger menu | delegated Typeahead behavior | Typeahead owner | floating | FR7, FR10–FR16, AR5 |
|
|
167
|
+
| inline token | structured Badge or caller content | Badge or caller owner | supporting | AV2 |
|
|
151
168
|
|
|
152
|
-
The existing `chat-composer-input` target remains on the root. This
|
|
153
|
-
|
|
169
|
+
The existing `chat-composer-input` target remains on the root. This record does not
|
|
170
|
+
add a theming target or decide a new visual state.
|
|
154
171
|
|
|
155
172
|
## Family and system relationships
|
|
156
173
|
|
|
@@ -161,18 +178,40 @@ draft does not add a theming target or decide a new visual state.
|
|
|
161
178
|
|
|
162
179
|
## Verification map
|
|
163
180
|
|
|
164
|
-
| Contract | Verification | Representative states
|
|
165
|
-
| --------------------- | ---------------------------------------------------------------------------------- |
|
|
166
|
-
| FR1, ORD1–ORD2 | focused imperative insertion and controlled-sync tests; `ImperativeInsertion` play | empty → inserted text; controlled echo; external override
|
|
167
|
-
| FR2–FR3, FR7–FR8, AR3 | focused keyboard, IME, trigger, and history tests | Enter; Shift+Enter; composition; cancelled key; boundary and mid-text arrows
|
|
168
|
-
|
|
|
169
|
-
|
|
|
170
|
-
|
|
|
171
|
-
|
|
|
181
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
182
|
+
| --------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------- |
|
|
183
|
+
| FR1, ORD1–ORD2 | focused imperative insertion and controlled-sync tests; `ImperativeInsertion` play | empty → inserted text; controlled echo; external override | Text appears only in the DOM, placeholder remains, callback is stale, or the caret jumps. | `audit:ChatComposerInput/behavior` |
|
|
184
|
+
| FR2–FR3, FR7–FR8, AR3 | focused keyboard, IME, trigger, and history tests | Enter; Shift+Enter; composition; cancelled key; boundary and mid-text arrows | A key submits twice, submits during composition, or steals native editing. | `audit:ChatComposerInput/interaction` |
|
|
185
|
+
| FR10–FR16, AR5 | focused trigger-query and trigger keyboard tests | single-token; multi-word; line break; length bound; pending search; no matches; IME; Escape | A query ends early or alters text, Enter picks an earlier query's row or fails to submit while a search is pending, a late result reopens the menu after a send, or a hidden menu consumes keys. | `audit:ChatComposerInput/interaction` |
|
|
186
|
+
| FR5, ORD4 | focused long-paste interception tests | consumer handled; token conversion; plain insertion | Consumer interception is skipped or multiple insertion paths run. | `audit:ChatComposerInput/behavior` |
|
|
187
|
+
| FR6, ORD5, AR2 | focused paste/drop tests and `FileDrop` play | paste; drop; disabled | Files navigate away, insert into the editor, bypass `onFiles`, or emit while disabled. | `audit:ChatComposerInput/behavior` |
|
|
188
|
+
| AR1, AR4 | role/name/ARIA tests plus exact-head accessibility and visual gates | textbox; combobox; disabled; keyboard focus | Name, role, multiline, expanded, disabled, or visible focus semantics regress. | `audit:ChatComposerInput/accessibility` |
|
|
189
|
+
| FR9 | ref, target, package, and repository checks | ref; BaseProps; xstyle; className; style | Root ownership or a styling seam moves or disappears. | `audit:ChatComposerInput/api` |
|
|
172
190
|
|
|
173
191
|
## Decision log
|
|
174
192
|
|
|
175
|
-
|
|
193
|
+
### DEC-1 — Trigger queries are non-destructive and act only on current results
|
|
194
|
+
|
|
195
|
+
**Reference:** `component:ChatComposerInput/DEC-1`
|
|
196
|
+
**Decider:** `cixzhang`, `2026-10-06`; pending-search Enter, `2026-10-14`; cross-trigger continuation applies the same reference-composer direction, `2026-10-14`
|
|
197
|
+
|
|
198
|
+
Only the caller knows whether its suggestions contain spaces, so multi-word
|
|
199
|
+
queries are a per-trigger opt-in and single-token triggers such as commands keep
|
|
200
|
+
ending at whitespace. A multi-word query never changes what the person typed: it
|
|
201
|
+
ends as FR11 states, and only an explicit pick replaces text. Suggestions act
|
|
202
|
+
only on the current query: while a search is pending, Enter sends the message as
|
|
203
|
+
typed and never picks a row from an earlier query, and results that arrive after
|
|
204
|
+
the send are dropped so the menu never reopens over the cleared composer. This
|
|
205
|
+
matches the reference chat composer, where a message may simply start with a
|
|
206
|
+
trigger. An unmatched multi-word phrase hides the menu instead of covering prose
|
|
207
|
+
with an empty panel. Inside an active multi-word query another trigger's
|
|
208
|
+
character does not start a query, so `@Jordan /` keeps the mention query, while
|
|
209
|
+
the same trigger's character starts a new query as FR11 states; both match the
|
|
210
|
+
reference chat composer.
|
|
211
|
+
|
|
212
|
+
Rejected: word caps, punctuation terminators, or a termination callback; they cut off real names and depend on language.
|
|
213
|
+
|
|
214
|
+
Rejected: holding Enter until a pending search settles; it blocks sending a message that only starts with a trigger.
|
|
176
215
|
|
|
177
216
|
## Open questions
|
|
178
217
|
|
|
@@ -181,5 +220,5 @@ None.
|
|
|
181
220
|
## Content boundary
|
|
182
221
|
|
|
183
222
|
This file does not duplicate consumer prop tables, examples, current audit scores,
|
|
184
|
-
or visual design rationale. It records shipped behavior
|
|
185
|
-
|
|
223
|
+
or visual design rationale. It records shipped behavior, objective corrections, and
|
|
224
|
+
the trigger-query contract in DEC-1, without deciding a new visual representation.
|