@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
|
@@ -1,9 +1,34 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
import {createElement, createRef, Fragment, type ReactNode} from 'react';
|
|
3
4
|
import {describe, it, expect} from 'vitest';
|
|
4
5
|
import {render, screen} from '@testing-library/react';
|
|
5
6
|
import {ChatMessage} from './ChatMessage';
|
|
6
7
|
import {ChatMessageBubble} from './ChatMessageBubble';
|
|
8
|
+
import {ChatMessageList} from './ChatMessageList';
|
|
9
|
+
|
|
10
|
+
// Content that renders nothing but is not a skipped scalar: its wrapper
|
|
11
|
+
// renders and collapses through CSS instead of the content being inspected.
|
|
12
|
+
const contentThatRendersNothing: [string, () => ReactNode][] = [
|
|
13
|
+
['an empty array', () => []],
|
|
14
|
+
['an array of non-rendering values', () => [null, false, '']],
|
|
15
|
+
['an empty Fragment', () => createElement(Fragment)],
|
|
16
|
+
['a component that returns null', () => <RendersNothing />],
|
|
17
|
+
];
|
|
18
|
+
|
|
19
|
+
function RendersNothing() {
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function OpaqueName() {
|
|
24
|
+
return <span>Navi</span>;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** The name wrapper the article's aria-labelledby points at. */
|
|
28
|
+
function labelTarget(article: HTMLElement): HTMLElement | null {
|
|
29
|
+
const id = article.getAttribute('aria-labelledby');
|
|
30
|
+
return id == null ? null : article.ownerDocument.getElementById(id);
|
|
31
|
+
}
|
|
7
32
|
|
|
8
33
|
describe('ChatMessage', () => {
|
|
9
34
|
it('renders children', () => {
|
|
@@ -33,6 +58,60 @@ describe('ChatMessage', () => {
|
|
|
33
58
|
expect(screen.queryByText('System')).toBeNull();
|
|
34
59
|
});
|
|
35
60
|
|
|
61
|
+
it.each([false, true, ''])('does not render a name wrapper for %j', name => {
|
|
62
|
+
render(
|
|
63
|
+
<ChatMessage sender="assistant" name={name}>
|
|
64
|
+
<span>Summary</span>
|
|
65
|
+
</ChatMessage>,
|
|
66
|
+
);
|
|
67
|
+
const article = screen.getByRole('article');
|
|
68
|
+
expect(article).toHaveAccessibleName('Message from assistant');
|
|
69
|
+
expect(article).not.toHaveAttribute('aria-labelledby');
|
|
70
|
+
expect(article.querySelector('div:empty')).toBeNull();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('preserves a numeric name', () => {
|
|
74
|
+
render(
|
|
75
|
+
<ChatMessage sender="assistant" name={0}>
|
|
76
|
+
<span>Summary</span>
|
|
77
|
+
</ChatMessage>,
|
|
78
|
+
);
|
|
79
|
+
expect(screen.getByRole('article')).toHaveAccessibleName('0');
|
|
80
|
+
expect(screen.getByText('0')).toBeInTheDocument();
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it.each(contentThatRendersNothing)(
|
|
84
|
+
'collapses the name wrapper and keeps the fallback label for %s',
|
|
85
|
+
(_label, createName) => {
|
|
86
|
+
render(
|
|
87
|
+
<ChatMessage sender="assistant" name={createName()}>
|
|
88
|
+
<span>Summary</span>
|
|
89
|
+
</ChatMessage>,
|
|
90
|
+
);
|
|
91
|
+
const article = screen.getByRole('article');
|
|
92
|
+
const target = labelTarget(article);
|
|
93
|
+
// The label reference resolves to no text, so the accessible name falls
|
|
94
|
+
// back to aria-label; real Chromium computes "Message from assistant".
|
|
95
|
+
expect(target).not.toBeNull();
|
|
96
|
+
expect(target).toBeEmptyDOMElement();
|
|
97
|
+
expect(getComputedStyle(target as HTMLElement).display).toBe('none');
|
|
98
|
+
expect(article).toHaveAttribute('aria-label', 'Message from assistant');
|
|
99
|
+
},
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
it('labels the article by a name that renders text', () => {
|
|
103
|
+
render(
|
|
104
|
+
<ChatMessage sender="assistant" name={<OpaqueName />}>
|
|
105
|
+
<span>Summary</span>
|
|
106
|
+
</ChatMessage>,
|
|
107
|
+
);
|
|
108
|
+
const article = screen.getByRole('article');
|
|
109
|
+
expect(article).toHaveAccessibleName('Navi');
|
|
110
|
+
expect(
|
|
111
|
+
getComputedStyle(labelTarget(article) as HTMLElement).display,
|
|
112
|
+
).not.toBe('none');
|
|
113
|
+
});
|
|
114
|
+
|
|
36
115
|
it('renders avatar for assistant', () => {
|
|
37
116
|
render(
|
|
38
117
|
<ChatMessage
|
|
@@ -53,6 +132,53 @@ describe('ChatMessage', () => {
|
|
|
53
132
|
expect(screen.queryByTestId('avatar')).toBeNull();
|
|
54
133
|
});
|
|
55
134
|
|
|
135
|
+
it.each([false, true, ''])(
|
|
136
|
+
'does not render an avatar wrapper for %j',
|
|
137
|
+
avatar => {
|
|
138
|
+
render(
|
|
139
|
+
<ChatMessage sender="assistant" avatar={avatar}>
|
|
140
|
+
<span>Summary</span>
|
|
141
|
+
</ChatMessage>,
|
|
142
|
+
);
|
|
143
|
+
expect(screen.getByRole('article').querySelector('div:empty')).toBeNull();
|
|
144
|
+
},
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
it('preserves a numeric avatar', () => {
|
|
148
|
+
render(
|
|
149
|
+
<ChatMessage sender="assistant" avatar={0}>
|
|
150
|
+
<span>Summary</span>
|
|
151
|
+
</ChatMessage>,
|
|
152
|
+
);
|
|
153
|
+
expect(screen.getByText('0')).toBeInTheDocument();
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
it.each(contentThatRendersNothing)(
|
|
157
|
+
'collapses the avatar wrapper for %s',
|
|
158
|
+
(_label, createAvatar) => {
|
|
159
|
+
render(
|
|
160
|
+
<ChatMessage sender="assistant" avatar={createAvatar()}>
|
|
161
|
+
<span>Summary</span>
|
|
162
|
+
</ChatMessage>,
|
|
163
|
+
);
|
|
164
|
+
const wrapper = screen.getByRole('article').firstElementChild;
|
|
165
|
+
expect(wrapper).toBeEmptyDOMElement();
|
|
166
|
+
expect(getComputedStyle(wrapper as HTMLElement).display).toBe('none');
|
|
167
|
+
},
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
it('keeps an avatar wrapper that renders content visible', () => {
|
|
171
|
+
render(
|
|
172
|
+
<ChatMessage
|
|
173
|
+
sender="assistant"
|
|
174
|
+
avatar={<span data-testid="avatar">N</span>}>
|
|
175
|
+
<span>Summary</span>
|
|
176
|
+
</ChatMessage>,
|
|
177
|
+
);
|
|
178
|
+
const wrapper = screen.getByTestId('avatar').parentElement;
|
|
179
|
+
expect(getComputedStyle(wrapper as HTMLElement).display).not.toBe('none');
|
|
180
|
+
});
|
|
181
|
+
|
|
56
182
|
it('applies sender class', () => {
|
|
57
183
|
render(
|
|
58
184
|
<ChatMessage sender="user" data-testid="msg">
|
|
@@ -95,4 +221,124 @@ describe('ChatMessage', () => {
|
|
|
95
221
|
);
|
|
96
222
|
expect(screen.getByTestId('custom-content')).toBeTruthy();
|
|
97
223
|
});
|
|
224
|
+
|
|
225
|
+
it('renders metadata for a non-system sender', () => {
|
|
226
|
+
render(
|
|
227
|
+
<ChatMessage sender="assistant" metadata={<span>Updated just now</span>}>
|
|
228
|
+
<span>Summary</span>
|
|
229
|
+
</ChatMessage>,
|
|
230
|
+
);
|
|
231
|
+
expect(screen.getByText('Updated just now')).toBeInTheDocument();
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
it('hides metadata for a system sender', () => {
|
|
235
|
+
render(
|
|
236
|
+
<ChatMessage sender="system" metadata={<span>Hidden metadata</span>}>
|
|
237
|
+
<span>Maintenance complete</span>
|
|
238
|
+
</ChatMessage>,
|
|
239
|
+
);
|
|
240
|
+
expect(screen.queryByText('Hidden metadata')).not.toBeInTheDocument();
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
it.each([false, true, ''])(
|
|
244
|
+
'does not render an empty metadata wrapper for %j',
|
|
245
|
+
metadata => {
|
|
246
|
+
render(
|
|
247
|
+
<ChatMessage sender="assistant" metadata={metadata}>
|
|
248
|
+
<span>Summary</span>
|
|
249
|
+
</ChatMessage>,
|
|
250
|
+
);
|
|
251
|
+
expect(screen.getByRole('article').querySelector('div:empty')).toBeNull();
|
|
252
|
+
},
|
|
253
|
+
);
|
|
254
|
+
|
|
255
|
+
it('preserves numeric metadata', () => {
|
|
256
|
+
render(
|
|
257
|
+
<ChatMessage sender="assistant" metadata={0}>
|
|
258
|
+
<span>Summary</span>
|
|
259
|
+
</ChatMessage>,
|
|
260
|
+
);
|
|
261
|
+
expect(screen.getByText('0')).toBeInTheDocument();
|
|
262
|
+
});
|
|
263
|
+
|
|
264
|
+
it.each(contentThatRendersNothing)(
|
|
265
|
+
'collapses the metadata wrapper for %s',
|
|
266
|
+
(_label, createMetadata) => {
|
|
267
|
+
render(
|
|
268
|
+
<ChatMessage sender="assistant" metadata={createMetadata()}>
|
|
269
|
+
<span>Summary</span>
|
|
270
|
+
</ChatMessage>,
|
|
271
|
+
);
|
|
272
|
+
const column = screen.getByText('Summary').parentElement?.parentElement;
|
|
273
|
+
const wrapper = column?.lastElementChild;
|
|
274
|
+
expect(wrapper).toBeEmptyDOMElement();
|
|
275
|
+
expect(getComputedStyle(wrapper as HTMLElement).display).toBe('none');
|
|
276
|
+
},
|
|
277
|
+
);
|
|
278
|
+
|
|
279
|
+
it('keeps metadata that renders content visible', () => {
|
|
280
|
+
render(
|
|
281
|
+
<ChatMessage sender="assistant" metadata={<span>Updated</span>}>
|
|
282
|
+
<span>Summary</span>
|
|
283
|
+
</ChatMessage>,
|
|
284
|
+
);
|
|
285
|
+
const wrapper = screen.getByText('Updated').parentElement;
|
|
286
|
+
expect(getComputedStyle(wrapper as HTMLElement).display).not.toBe('none');
|
|
287
|
+
});
|
|
288
|
+
|
|
289
|
+
it('uses balanced density without list context', () => {
|
|
290
|
+
render(
|
|
291
|
+
<ChatMessage sender="assistant" data-testid="message">
|
|
292
|
+
<span>Summary</span>
|
|
293
|
+
</ChatMessage>,
|
|
294
|
+
);
|
|
295
|
+
expect(screen.getByTestId('message')).toHaveAttribute(
|
|
296
|
+
'data-density',
|
|
297
|
+
'balanced',
|
|
298
|
+
);
|
|
299
|
+
});
|
|
300
|
+
|
|
301
|
+
it('inherits list density and lets an explicit prop override it', () => {
|
|
302
|
+
render(
|
|
303
|
+
<ChatMessageList density="spacious">
|
|
304
|
+
<ChatMessage sender="assistant" data-testid="inherited">
|
|
305
|
+
<span>Inherited</span>
|
|
306
|
+
</ChatMessage>
|
|
307
|
+
<ChatMessage
|
|
308
|
+
sender="assistant"
|
|
309
|
+
density="compact"
|
|
310
|
+
data-testid="explicit">
|
|
311
|
+
<span>Explicit</span>
|
|
312
|
+
</ChatMessage>
|
|
313
|
+
</ChatMessageList>,
|
|
314
|
+
);
|
|
315
|
+
expect(screen.getByTestId('inherited')).toHaveAttribute(
|
|
316
|
+
'data-density',
|
|
317
|
+
'spacious',
|
|
318
|
+
);
|
|
319
|
+
expect(screen.getByTestId('explicit')).toHaveAttribute(
|
|
320
|
+
'data-density',
|
|
321
|
+
'compact',
|
|
322
|
+
);
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
it('forwards root props and ref while preserving the theme target', () => {
|
|
326
|
+
const ref = createRef<HTMLElement>();
|
|
327
|
+
render(
|
|
328
|
+
<ChatMessage
|
|
329
|
+
ref={ref}
|
|
330
|
+
sender="assistant"
|
|
331
|
+
data-testid="message"
|
|
332
|
+
data-purpose="summary"
|
|
333
|
+
className="consumer-message"
|
|
334
|
+
style={{order: 2}}>
|
|
335
|
+
<span>Summary</span>
|
|
336
|
+
</ChatMessage>,
|
|
337
|
+
);
|
|
338
|
+
const message = screen.getByTestId('message');
|
|
339
|
+
expect(ref.current).toBe(message);
|
|
340
|
+
expect(message).toHaveAttribute('data-purpose', 'summary');
|
|
341
|
+
expect(message).toHaveClass('astryx-chat-message', 'consumer-message');
|
|
342
|
+
expect(message.style.order).toBe('2');
|
|
343
|
+
});
|
|
98
344
|
});
|
package/src/Chat/ChatMessage.tsx
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
* SYNC: When modified, update these files to stay in sync:
|
|
17
17
|
* - /packages/core/src/Chat/index.ts (exports)
|
|
18
18
|
* - /apps/storybook/stories/Chat.stories.tsx
|
|
19
|
+
* - /apps/storybook/stories/ChatMessage.stories.tsx
|
|
19
20
|
* - /packages/cli/assets/templates/blocks/components/ChatMessage/ (block examples)
|
|
20
21
|
*/
|
|
21
22
|
|
|
@@ -33,7 +34,7 @@ import {
|
|
|
33
34
|
type ChatMessageSender,
|
|
34
35
|
type ChatDensity,
|
|
35
36
|
} from './ChatContext';
|
|
36
|
-
import {mergeProps} from '../utils';
|
|
37
|
+
import {isRenderable, mergeProps} from '../utils';
|
|
37
38
|
import type {BaseProps} from '../BaseProps';
|
|
38
39
|
import {themeProps} from '../utils/themeProps';
|
|
39
40
|
import {useTranslator} from '../i18n';
|
|
@@ -49,9 +50,17 @@ export interface ChatMessageProps extends BaseProps<HTMLElement> {
|
|
|
49
50
|
* should span the full message column.
|
|
50
51
|
*/
|
|
51
52
|
children: ReactNode;
|
|
53
|
+
/**
|
|
54
|
+
* Avatar content rendered beside a non-system message.
|
|
55
|
+
* `null`, booleans, and empty strings create no slot; any other content that
|
|
56
|
+
* renders nothing collapses its slot.
|
|
57
|
+
*/
|
|
52
58
|
avatar?: ReactNode;
|
|
53
59
|
/**
|
|
54
60
|
* Sender name rendered above the message body.
|
|
61
|
+
* `null`, booleans, and empty strings create no slot, and the message is
|
|
62
|
+
* labelled by the translated sender fallback; any other content that renders
|
|
63
|
+
* nothing collapses its slot and falls back to the same label.
|
|
55
64
|
* Use when the first child is raw content (not a bubble).
|
|
56
65
|
* If the first child is a ChatMessageBubble, put the name on the
|
|
57
66
|
* bubble's `name` prop instead — it aligns with the bubble's padding.
|
|
@@ -59,6 +68,8 @@ export interface ChatMessageProps extends BaseProps<HTMLElement> {
|
|
|
59
68
|
name?: ReactNode;
|
|
60
69
|
/**
|
|
61
70
|
* Metadata rendered below the message body.
|
|
71
|
+
* `null`, booleans, and empty strings create no slot; any other content that
|
|
72
|
+
* renders nothing collapses its slot.
|
|
62
73
|
* Use when the last child is raw content (not a bubble).
|
|
63
74
|
* If the last child is a ChatMessageBubble, put metadata on the
|
|
64
75
|
* bubble's `metadata` prop instead — it aligns with the bubble's padding.
|
|
@@ -94,7 +105,11 @@ const styles = stylex.create({
|
|
|
94
105
|
flexDirection: 'row',
|
|
95
106
|
justifyContent: 'center',
|
|
96
107
|
},
|
|
108
|
+
// Slot wrappers collapse when the caller's content renders nothing, so an
|
|
109
|
+
// empty Fragment or a component that returns null leaves no gap. Content is
|
|
110
|
+
// never inspected to decide this.
|
|
97
111
|
avatarWrap: {
|
|
112
|
+
display: {default: null, ':empty': 'none'},
|
|
98
113
|
flexShrink: 0,
|
|
99
114
|
':has(~ * [data-chat-name])': {
|
|
100
115
|
marginBlockStart: spacingVars['--spacing-5'],
|
|
@@ -117,12 +132,16 @@ const styles = stylex.create({
|
|
|
117
132
|
alignItems: 'flex-end',
|
|
118
133
|
},
|
|
119
134
|
name: {
|
|
135
|
+
display: {default: null, ':empty': 'none'},
|
|
120
136
|
fontSize: typeScaleVars['--text-supporting-size'],
|
|
121
137
|
fontWeight: fontWeightVars['--font-weight-semibold'],
|
|
122
138
|
color: colorVars['--color-text-secondary'],
|
|
123
139
|
lineHeight: typeScaleVars['--text-supporting-leading'],
|
|
124
140
|
marginBlockEnd: spacingVars['--spacing-1'],
|
|
125
141
|
},
|
|
142
|
+
metadata: {
|
|
143
|
+
display: {default: null, ':empty': 'none'},
|
|
144
|
+
},
|
|
126
145
|
childrenWrap: {
|
|
127
146
|
display: 'flex',
|
|
128
147
|
flexDirection: 'column',
|
|
@@ -219,8 +238,9 @@ export function ChatMessage({
|
|
|
219
238
|
: styles.childrenAssistant;
|
|
220
239
|
|
|
221
240
|
const isSystem = sender === 'system';
|
|
222
|
-
const hasAvatar =
|
|
223
|
-
const hasName =
|
|
241
|
+
const hasAvatar = !isSystem && isRenderable(avatar);
|
|
242
|
+
const hasName = !isSystem && isRenderable(name);
|
|
243
|
+
const hasMetadata = !isSystem && isRenderable(metadata);
|
|
224
244
|
const nameId = useId();
|
|
225
245
|
|
|
226
246
|
return (
|
|
@@ -229,9 +249,10 @@ export function ChatMessage({
|
|
|
229
249
|
{...rest}
|
|
230
250
|
ref={ref}
|
|
231
251
|
data-testid={testId}
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
252
|
+
// The visible name labels the article. When it renders no text, the
|
|
253
|
+
// label reference resolves to nothing and the accessible name falls
|
|
254
|
+
// back to aria-label (accessible name computation 1.2, step 2B).
|
|
255
|
+
aria-label={t('@astryx.chatMessage.messageFrom', {sender})}
|
|
235
256
|
aria-labelledby={hasName ? nameId : undefined}
|
|
236
257
|
{...mergeProps(
|
|
237
258
|
themeProps('chat-message', {sender, density}),
|
|
@@ -262,7 +283,9 @@ export function ChatMessage({
|
|
|
262
283
|
{children}
|
|
263
284
|
</div>
|
|
264
285
|
|
|
265
|
-
{
|
|
286
|
+
{hasMetadata && (
|
|
287
|
+
<div {...stylex.props(styles.metadata)}>{metadata}</div>
|
|
288
|
+
)}
|
|
266
289
|
</div>
|
|
267
290
|
</article>
|
|
268
291
|
</ChatMessageContext>
|
|
@@ -80,7 +80,7 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
80
80
|
- Sender identity, avatar, bubble, transcript ordering, or scrolling.
|
|
81
81
|
- Divider rule paint, label placement, separator role, or separator naming, which are delegated to `component:Divider`.
|
|
82
82
|
- Long Divider-label overflow and forced-colors rule paint, which remain shared `component:Divider` advisories rather than ChatSystemMessage-owned defects.
|
|
83
|
-
- Divider's
|
|
83
|
+
- Divider's skipped-label rendering. Empty strings and empty Fragments leave the separator without a visible label or accessible name; numeric zero renders one visible `0` and names the separator `0`. These partitions remain owned by `component:Divider`.
|
|
84
84
|
- The semantic or directional meaning of caller-provided content or icon artwork.
|
|
85
85
|
- Announcement timing or spoken output; claims at that layer require `spec:AST-009` evidence.
|
|
86
86
|
|
|
@@ -99,14 +99,14 @@ observable public surface without deciding the unresolved divider/icon contract.
|
|
|
99
99
|
|
|
100
100
|
## Behavioral and layout contract
|
|
101
101
|
|
|
102
|
-
| ID | Candidate invariant
|
|
103
|
-
| --- |
|
|
104
|
-
| FR1 | The default branch MUST render the required content in a centered, noninteractive status row, allow long content to wrap within the available inline space, and preserve optional icon geometry.
|
|
105
|
-
| FR2 |
|
|
106
|
-
| FR3 | The divider branch currently ignores `icon`; this draft MUST NOT convert that observation into a stable restriction, a requirement to render the icon, or a warning policy.
|
|
107
|
-
| FR4 | Supported root DOM, data, ARIA, className, style, xstyle, and ref inputs MUST reach or compose on the root while component-owned `role="status"` and reflected `variant` remain intact.
|
|
108
|
-
| FR5 | The component MUST use semantic color, spacing, and typography tokens and logical layout; the `variant` state remains reflected on the single `chat-system-message` target.
|
|
109
|
-
| FR6 | The component remains render-only: props determine output without Effects, state mirrors, observers, listeners, timers, or owned async resources.
|
|
102
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
103
|
+
| --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
|
|
104
|
+
| FR1 | The default branch MUST render the required content in a centered, noninteractive status row, allow long content to wrap within the available inline space, and preserve optional icon geometry. | Current source, released docs, tests, and examples | Verified current behavior |
|
|
105
|
+
| FR2 | The divider branch MUST render renderable content through Divider as a labelled horizontal separator inside the component's status root. Skipped content follows Divider's delegated label contract. | Current source, released docs, Divider implementation, tests, and examples | Verified current behavior; delegated Divider partitions |
|
|
106
|
+
| FR3 | The divider branch currently ignores `icon`; this draft MUST NOT convert that observation into a stable restriction, a requirement to render the icon, or a warning policy. | `architecture:public-component-api/INV3`, `architecture:public-component-api/INV5`, and `spec:AST-002/FR15` | Human API decision required; see OQ1 |
|
|
107
|
+
| FR4 | Supported root DOM, data, ARIA, className, style, xstyle, and ref inputs MUST reach or compose on the root while component-owned `role="status"` and reflected `variant` remain intact. | Current source plus `architecture:public-component-api/INV5-INV8` | Verified current behavior and existing focused evidence |
|
|
108
|
+
| FR5 | The component MUST use semantic color, spacing, and typography tokens and logical layout; the `variant` state remains reflected on the single `chat-system-message` target. | Current source, `architecture:theme-tokens`, and theming architecture | Verified current behavior |
|
|
109
|
+
| FR6 | The component remains render-only: props determine output without Effects, state mirrors, observers, listeners, timers, or owned async resources. | Current source and `architecture:react-component-runtime/INV1-INV8` | Verified current behavior |
|
|
110
110
|
|
|
111
111
|
### Allowed variation
|
|
112
112
|
|
|
@@ -116,9 +116,8 @@ observable public surface without deciding the unresolved divider/icon contract.
|
|
|
116
116
|
content unchanged: empty string and empty Fragment content remain empty, while
|
|
117
117
|
numeric zero renders one `0`. In the divider variant, the status root and separator
|
|
118
118
|
remain; empty string and empty Fragment content produce no visible label or
|
|
119
|
-
accessible name, while numeric zero
|
|
120
|
-
|
|
121
|
-
to `component:Divider`.
|
|
119
|
+
accessible name, while numeric zero renders one visible `0` and names the
|
|
120
|
+
separator `0`. Divider owns those label partitions.
|
|
122
121
|
- **AV2 - Caller styling.** Supported root styling inputs may extend the component
|
|
123
122
|
without replacing owned status semantics or variant reflection.
|
|
124
123
|
- **AV3 - Delegated Divider paint.** Divider owns its rule and label paint and may
|
|
@@ -126,15 +125,15 @@ observable public surface without deciding the unresolved divider/icon contract.
|
|
|
126
125
|
|
|
127
126
|
### Representative states
|
|
128
127
|
|
|
129
|
-
| State | Required invariant
|
|
130
|
-
| --------------------- |
|
|
131
|
-
| Default | Centered status content is present.
|
|
132
|
-
| Default with icon | Optional icon content and visible content render together.
|
|
133
|
-
| Default long content | Content wraps without crossing either inline edge or creating page overflow.
|
|
134
|
-
| Divider | A labelled horizontal separator presents the supplied content.
|
|
135
|
-
| Divider with icon | Current output is measured without deciding the ignored-input contract.
|
|
136
|
-
| Empty ReactNode | The default variant keeps `role="status"` and renders content unchanged (empty or one `0`). In the divider variant, the status root and separator remain; empty content has no label/name, while numeric zero
|
|
137
|
-
| Narrow/coarse pointer | The noninteractive row remains visible without horizontal page overflow.
|
|
128
|
+
| State | Required invariant | Allowed variation |
|
|
129
|
+
| --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
|
130
|
+
| Default | Centered status content is present. | Content, theme, and root styling. |
|
|
131
|
+
| Default with icon | Optional icon content and visible content render together. | Caller-provided artwork and content. |
|
|
132
|
+
| Default long content | Content wraps without crossing either inline edge or creating page overflow. | Theme and localized content. |
|
|
133
|
+
| Divider | A labelled horizontal separator presents the supplied content. | Label content, theme, and root styling. |
|
|
134
|
+
| Divider with icon | Current output is measured without deciding the ignored-input contract. | No behavior change until OQ1 is resolved. |
|
|
135
|
+
| Empty ReactNode | The default variant keeps `role="status"` and renders content unchanged (empty or one `0`). In the divider variant, the status root and separator remain; empty content has no label/name, while numeric zero renders and names one `0`. | Empty string, numeric zero, empty Fragment. |
|
|
136
|
+
| Narrow/coarse pointer | The noninteractive row remains visible without horizontal page overflow. | Theme and supported content. |
|
|
138
137
|
|
|
139
138
|
### Transformation and precedence order
|
|
140
139
|
|
|
@@ -156,10 +155,10 @@ observable public surface without deciding the unresolved divider/icon contract.
|
|
|
156
155
|
- **AR1 - Status exposure.** The root currently exposes `role="status"` for both
|
|
157
156
|
variants. Browser evidence may prove role exposure; spoken announcement timing is
|
|
158
157
|
outside this draft and requires `spec:AST-009` evidence.
|
|
159
|
-
- **AR2 - Divider relationship.**
|
|
158
|
+
- **AR2 - Divider relationship.** Renderable content in the divider branch delegates a
|
|
160
159
|
horizontal `separator` whose labelled target contains the visible label; focused DOM
|
|
161
|
-
tests verify the computed accessible name.
|
|
162
|
-
|
|
160
|
+
tests verify the computed accessible name. Skipped content follows Divider's
|
|
161
|
+
delegated label contract.
|
|
163
162
|
- **AR3 - Caller content.** Visible content remains the self-contained message.
|
|
164
163
|
Caller-provided icon content does not replace that text.
|
|
165
164
|
- **AR4 - Noninteractive surface.** The component introduces no focus target,
|
|
@@ -180,8 +179,8 @@ icon artwork, live-region timing, or divider/icon behavior.
|
|
|
180
179
|
## Family and system relationships
|
|
181
180
|
|
|
182
181
|
- `component:Divider` owns the delegated separator structure, role, name,
|
|
183
|
-
paint, long-label overflow, and
|
|
184
|
-
|
|
182
|
+
paint, long-label overflow, and label partitions. Numeric zero renders as one
|
|
183
|
+
visible label and names the separator `0`; skipped content remains unlabelled.
|
|
185
184
|
- `architecture:public-component-api` owns released exports, BaseProps reachability,
|
|
186
185
|
styling composition, and the ref contract.
|
|
187
186
|
- `architecture:component-theming-surface` owns the target/anatomy mapping and
|
|
@@ -197,17 +196,17 @@ icon artwork, live-region timing, or divider/icon behavior.
|
|
|
197
196
|
|
|
198
197
|
## Verification map
|
|
199
198
|
|
|
200
|
-
| Contract | Verification | Representative states | Mutation or failure expectation
|
|
201
|
-
| ------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
|
202
|
-
| FR1, AR1, AR3 | `ChatSystemMessage.test.tsx`, scoped axe, and exact-head Chromium receipts | Default, default with icon, long content, nested live log, neutral light/dark | Missing content, status role, icon content, wrapping, or browser-visible subject fails focused or browser evidence.
|
|
203
|
-
| FR2, AR2 | `ChatSystemMessage.test.tsx`, Divider tests, scoped axe, and exact-head Chromium receipts |
|
|
204
|
-
| FR3 | Closed audit inventory and exact-head observation of the divider/icon partition | Divider with supplied icon | The audit must expose, not silently omit, the unresolved branch; implementation remains unchanged until owner decision.
|
|
205
|
-
| FR4 | Mutation-sensitive root-passthrough tests, source inspection, type checks, and target reflection | Default and divider roots | Removing ref, className, style, xstyle, ARIA forwarding, or owned role precedence fails focused tests.
|
|
206
|
-
| FR5 | `themingTargets.test.ts`, source inspection, generated build, and exact-head computed paint | Both variants and color modes | Target/state metadata drift, raw styling, physical layout, or unresolved mode paint fails checks or browser evidence.
|
|
207
|
-
| FR6 | Source inspection, strict lint, and component test suite | Every render | Adding hidden state or an owned external resource triggers runtime review and corresponding evidence.
|
|
208
|
-
| RTL relation | Source-hashed verified-N/A record | Both variants and caller-owned icon content | Directional component-owned content, physical positioning, ordering, scroll/drag, overlay, or horizontal keyboard behavior invalidates the record.
|
|
209
|
-
| Browser matrix | `ChatSystemMessage.a11y.chromium.spec.ts` exact-head 10-sensor receipts | Default, icon, wrapped long content, divider, unresolved divider/icon, nested live log, 320px/coarse pointer, light/dark, D7 pairs | Stale build, wrong story, incorrect mode, missing semantics, default overflow, failed contrast, blank crop, or page error fails closed.
|
|
210
|
-
| Documentation and surface | Consumer docs, published declarations, block metadata, explicit story ownership, exports, and `check:knowledge` | Props, `./Chat` subpath, four blocks, draft record | Missing or stale public docs, export, owner route, target map, or knowledge shape fails validation or review.
|
|
199
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
200
|
+
| ------------------------- | --------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------- |
|
|
201
|
+
| FR1, AR1, AR3 | `ChatSystemMessage.test.tsx`, scoped axe, and exact-head Chromium receipts | Default, default with icon, long content, nested live log, neutral light/dark | Missing content, status role, icon content, wrapping, or browser-visible subject fails focused or browser evidence. | `audit:ChatSystemMessage/accessibility` |
|
|
202
|
+
| FR2, AR2 | `ChatSystemMessage.test.tsx`, Divider tests, scoped axe, and exact-head Chromium receipts | Labelled divider content plus empty string, numeric zero, and empty Fragment observations | Lost separator role, label association, orientation, content, or paint fails focused or browser evidence; skipped partitions stay delegated to Divider. | `audit:ChatSystemMessage/behavior` |
|
|
203
|
+
| FR3 | Closed audit inventory and exact-head observation of the divider/icon partition | Divider with supplied icon | The audit must expose, not silently omit, the unresolved branch; implementation remains unchanged until owner decision. | `audit:ChatSystemMessage/public-api` |
|
|
204
|
+
| FR4 | Mutation-sensitive root-passthrough tests, source inspection, type checks, and target reflection | Default and divider roots | Removing ref, className, style, xstyle, ARIA forwarding, or owned role precedence fails focused tests. | `audit:ChatSystemMessage/public-api` |
|
|
205
|
+
| FR5 | `themingTargets.test.ts`, source inspection, generated build, and exact-head computed paint | Both variants and color modes | Target/state metadata drift, raw styling, physical layout, or unresolved mode paint fails checks or browser evidence. | `audit:ChatSystemMessage/theming` |
|
|
206
|
+
| FR6 | Source inspection, strict lint, and component test suite | Every render | Adding hidden state or an owned external resource triggers runtime review and corresponding evidence. | `audit:ChatSystemMessage/code-health` |
|
|
207
|
+
| RTL relation | Source-hashed verified-N/A record | Both variants and caller-owned icon content | Directional component-owned content, physical positioning, ordering, scroll/drag, overlay, or horizontal keyboard behavior invalidates the record. | `audit:ChatSystemMessage/i18n-rtl` |
|
|
208
|
+
| Browser matrix | `ChatSystemMessage.a11y.chromium.spec.ts` exact-head 10-sensor receipts | Default, icon, wrapped long content, divider, unresolved divider/icon, nested live log, 320px/coarse pointer, light/dark, D7 pairs | Stale build, wrong story, incorrect mode, missing semantics, default overflow, failed contrast, blank crop, or page error fails closed. | `audit:ChatSystemMessage/visual` |
|
|
209
|
+
| Documentation and surface | Consumer docs, published declarations, block metadata, explicit story ownership, exports, and `check:knowledge` | Props, `./Chat` subpath, four blocks, draft record | Missing or stale public docs, export, owner route, target map, or knowledge shape fails validation or review. | `audit:ChatSystemMessage/docs` |
|
|
211
210
|
|
|
212
211
|
## Decision log
|
|
213
212
|
|
|
@@ -152,7 +152,7 @@ describe('ChatSystemMessage', () => {
|
|
|
152
152
|
expect(root).toContainElement(screen.getByRole('separator'));
|
|
153
153
|
});
|
|
154
154
|
|
|
155
|
-
it('
|
|
155
|
+
it('keeps the numeric-zero label visible and names the shared divider', () => {
|
|
156
156
|
render(
|
|
157
157
|
<ChatSystemMessage variant="divider" data-testid="divider-zero">
|
|
158
158
|
{0}
|
|
@@ -160,8 +160,8 @@ describe('ChatSystemMessage', () => {
|
|
|
160
160
|
);
|
|
161
161
|
const root = screen.getByTestId('divider-zero');
|
|
162
162
|
const separator = screen.getByRole('separator');
|
|
163
|
-
expect(root).toHaveTextContent(
|
|
164
|
-
expect(separator).
|
|
165
|
-
expect(separator).
|
|
163
|
+
expect(root).toHaveTextContent(/^0$/);
|
|
164
|
+
expect(separator).toHaveAccessibleName('0');
|
|
165
|
+
expect(separator).toHaveAttribute('aria-labelledby');
|
|
166
166
|
});
|
|
167
167
|
});
|