@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,104 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** AST-021 state inventory for the Link binding of the shared Link contract. */
|
|
4
|
+
|
|
5
|
+
import type {LinkStateFacts} from '@astryxdesign/a11y-spec';
|
|
6
|
+
|
|
7
|
+
export interface LinkA11yState {
|
|
8
|
+
readonly id:
|
|
9
|
+
| 'text-native'
|
|
10
|
+
| 'icon-labelled'
|
|
11
|
+
| 'current-page'
|
|
12
|
+
| 'external-new-tab'
|
|
13
|
+
| 'provider-router'
|
|
14
|
+
| 'as-router';
|
|
15
|
+
readonly summary: string;
|
|
16
|
+
readonly facts: LinkStateFacts;
|
|
17
|
+
readonly storyId: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export type LinkA11yRow = (typeof LINK_A11Y_STATES)[number];
|
|
21
|
+
|
|
22
|
+
const story = (id: string) => `a11y-link-pattern--${id}`;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Every destination is a same-document fragment, so following a link keeps the
|
|
26
|
+
* story mounted. The router component records its own navigations; the browser
|
|
27
|
+
* records native ones.
|
|
28
|
+
*/
|
|
29
|
+
export const LINK_A11Y_DESTINATION = '#link-destination';
|
|
30
|
+
|
|
31
|
+
export const LINK_A11Y_STATES = [
|
|
32
|
+
{
|
|
33
|
+
id: 'text-native',
|
|
34
|
+
summary: 'a native anchor named by its visible text',
|
|
35
|
+
facts: {name: 'Documentation', current: null},
|
|
36
|
+
storyId: story('text-native'),
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
id: 'icon-labelled',
|
|
40
|
+
summary: 'an icon-only link named by its label prop',
|
|
41
|
+
facts: {name: 'Close dialog', current: null},
|
|
42
|
+
storyId: story('icon-labelled'),
|
|
43
|
+
},
|
|
44
|
+
{
|
|
45
|
+
id: 'current-page',
|
|
46
|
+
summary: 'a link the caller marks as the current page',
|
|
47
|
+
facts: {name: 'Overview', current: 'page'},
|
|
48
|
+
storyId: story('current-page'),
|
|
49
|
+
},
|
|
50
|
+
{
|
|
51
|
+
id: 'external-new-tab',
|
|
52
|
+
summary:
|
|
53
|
+
'an external link whose name carries the new-tab notice and which opens a new tab',
|
|
54
|
+
facts: {name: 'GitHub (opens in new tab)', current: null},
|
|
55
|
+
storyId: story('external-new-tab'),
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
id: 'provider-router',
|
|
59
|
+
summary:
|
|
60
|
+
'a link rendered by a router component supplied through LinkProvider',
|
|
61
|
+
facts: {name: 'Projects', current: null},
|
|
62
|
+
storyId: story('provider-router'),
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
id: 'as-router',
|
|
66
|
+
summary: 'a link rendered by a router component supplied through `as`',
|
|
67
|
+
facts: {name: 'Settings', current: null},
|
|
68
|
+
storyId: story('as-router'),
|
|
69
|
+
},
|
|
70
|
+
] as const satisfies ReadonlyArray<LinkA11yState>;
|
|
71
|
+
|
|
72
|
+
export const LINK_A11Y_EXCLUSIONS = [
|
|
73
|
+
{
|
|
74
|
+
owner: 'Link component tests and family:navigation-destinations FR7',
|
|
75
|
+
reason:
|
|
76
|
+
'A disabled Link renders an href-less anchor that is neither a link nor focusable. That disabled semantics is member-owned, so disabled states are not bound to this available-link contract.',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
owner: 'Link component tests (button rendering)',
|
|
80
|
+
reason:
|
|
81
|
+
'A Link without href renders a button for an action; the button contract, not this one, owns that role.',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
owner: 'family:navigation-destinations and its verification map',
|
|
85
|
+
reason:
|
|
86
|
+
'Which destinations are accepted or blocked, and how rejected destinations render, is navigation safety rather than an accessibility outcome.',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
owner:
|
|
90
|
+
'BreadcrumbItem, SideNavItem, TopNavItem, Citation, and ClickableCard',
|
|
91
|
+
reason:
|
|
92
|
+
'Links inside navigation aggregates and enlarged surfaces bind separately; this first binding covers the Link component and both custom-router seams.',
|
|
93
|
+
},
|
|
94
|
+
{
|
|
95
|
+
owner: 'Link visual and Tooltip evidence',
|
|
96
|
+
reason:
|
|
97
|
+
'Underline, hover color, focus ring paint, truncation, and tooltip presentation require rendered and component checks.',
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
owner: 'AST-009',
|
|
101
|
+
reason:
|
|
102
|
+
'This binding claims DOM, accessibility-tree, and real-browser behavior, not spoken wording, virtual-cursor, or assistive-technology activation.',
|
|
103
|
+
},
|
|
104
|
+
] as const;
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
/** @vitest-environment jsdom */
|
|
3
|
+
|
|
4
|
+
/** Fast DOM binding for Link against the shared Link contract. */
|
|
5
|
+
|
|
6
|
+
import {cleanup, render} from '@testing-library/react';
|
|
7
|
+
import {describe, expect, it} from 'vitest';
|
|
8
|
+
import {
|
|
9
|
+
LINK_PATTERN,
|
|
10
|
+
checkAccessibilitySpec,
|
|
11
|
+
createJsdomHarness,
|
|
12
|
+
expectAccessibilitySpec,
|
|
13
|
+
summarize,
|
|
14
|
+
type BindingResult,
|
|
15
|
+
} from '@astryxdesign/a11y-spec';
|
|
16
|
+
import {LINK_A11Y_RENDERS} from './Link.a11y.renders';
|
|
17
|
+
import {
|
|
18
|
+
LINK_A11Y_EXCLUSIONS,
|
|
19
|
+
LINK_A11Y_STATES,
|
|
20
|
+
type LinkA11yRow,
|
|
21
|
+
} from './Link.a11y.states';
|
|
22
|
+
|
|
23
|
+
const SUBJECT_SELECTOR = '[data-a11y-link]';
|
|
24
|
+
|
|
25
|
+
function subjectFor(): HTMLElement {
|
|
26
|
+
const subjects = document.querySelectorAll(SUBJECT_SELECTOR);
|
|
27
|
+
if (subjects.length !== 1 || !(subjects[0] instanceof HTMLElement)) {
|
|
28
|
+
throw new Error(
|
|
29
|
+
`binding rendered ${subjects.length} link subjects instead of one`,
|
|
30
|
+
);
|
|
31
|
+
}
|
|
32
|
+
return subjects[0];
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
async function checkState(state: LinkA11yRow): Promise<BindingResult> {
|
|
36
|
+
return checkAccessibilitySpec({
|
|
37
|
+
spec: LINK_PATTERN,
|
|
38
|
+
binding: 'Link',
|
|
39
|
+
state: state.id,
|
|
40
|
+
facts: state.facts,
|
|
41
|
+
mount: async () => {
|
|
42
|
+
render(LINK_A11Y_RENDERS[state.id]());
|
|
43
|
+
return createJsdomHarness({subject: subjectFor()});
|
|
44
|
+
},
|
|
45
|
+
unmount: cleanup,
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
describe('the shared Link pattern, jsdom lane', () => {
|
|
50
|
+
it.each(
|
|
51
|
+
LINK_A11Y_STATES.map(
|
|
52
|
+
state => [`Link [${state.id}]`, state.summary, state] as const,
|
|
53
|
+
),
|
|
54
|
+
)('%s — %s', async (_id, _summary, state) => {
|
|
55
|
+
await expectAccessibilitySpec({
|
|
56
|
+
spec: LINK_PATTERN,
|
|
57
|
+
binding: 'Link',
|
|
58
|
+
state: state.id,
|
|
59
|
+
facts: state.facts,
|
|
60
|
+
render: () => {
|
|
61
|
+
render(LINK_A11Y_RENDERS[state.id]());
|
|
62
|
+
},
|
|
63
|
+
subject: subjectFor,
|
|
64
|
+
cleanup,
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('runs DOM expectations and reports tree and browser outcomes as unrun', async () => {
|
|
69
|
+
const results: BindingResult[] = [];
|
|
70
|
+
for (const state of LINK_A11Y_STATES) {
|
|
71
|
+
results.push(await checkState(state));
|
|
72
|
+
}
|
|
73
|
+
const report = summarize(LINK_PATTERN, results);
|
|
74
|
+
expect(report.counts.pass).toBeGreaterThan(0);
|
|
75
|
+
expect([...report.unrunLayers].sort()).toEqual([
|
|
76
|
+
'accessibility-tree',
|
|
77
|
+
'real-browser',
|
|
78
|
+
]);
|
|
79
|
+
expect(report.counts.unexpectedPass).toBe(0);
|
|
80
|
+
});
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
describe('the Link binding inventory', () => {
|
|
84
|
+
it('names a distinct checked-in story for every state', () => {
|
|
85
|
+
const ids = LINK_A11Y_STATES.map(state => state.storyId);
|
|
86
|
+
expect(new Set(ids).size).toBe(ids.length);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('records every adjacent exclusion with an owner and reason', () => {
|
|
90
|
+
expect(LINK_A11Y_EXCLUSIONS.every(row => row.owner && row.reason)).toBe(
|
|
91
|
+
true,
|
|
92
|
+
);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
it('renders an anchor with a destination for every state', () => {
|
|
96
|
+
for (const state of LINK_A11Y_STATES) {
|
|
97
|
+
render(LINK_A11Y_RENDERS[state.id]());
|
|
98
|
+
const subject = subjectFor();
|
|
99
|
+
expect(subject.tagName, state.id).toBe('A');
|
|
100
|
+
expect(subject.getAttribute('href'), state.id).not.toBeNull();
|
|
101
|
+
cleanup();
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('renders both custom-router seams through the router component', () => {
|
|
106
|
+
for (const id of ['provider-router', 'as-router'] as const) {
|
|
107
|
+
render(LINK_A11Y_RENDERS[id]());
|
|
108
|
+
expect(subjectFor().hasAttribute('data-a11y-link-router'), id).toBe(true);
|
|
109
|
+
cleanup();
|
|
110
|
+
}
|
|
111
|
+
for (const state of LINK_A11Y_STATES.filter(
|
|
112
|
+
row => row.id !== 'provider-router' && row.id !== 'as-router',
|
|
113
|
+
)) {
|
|
114
|
+
render(LINK_A11Y_RENDERS[state.id]());
|
|
115
|
+
expect(subjectFor().hasAttribute('data-a11y-link-router'), state.id).toBe(
|
|
116
|
+
false,
|
|
117
|
+
);
|
|
118
|
+
cleanup();
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('opens the external state in a new tab', () => {
|
|
123
|
+
render(LINK_A11Y_RENDERS['external-new-tab']());
|
|
124
|
+
expect(subjectFor().getAttribute('target')).toBe('_blank');
|
|
125
|
+
cleanup();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -29,7 +29,7 @@ const anatomy = [
|
|
|
29
29
|
name: 'Code block',
|
|
30
30
|
required: false,
|
|
31
31
|
description:
|
|
32
|
-
'Fenced code block;
|
|
32
|
+
'Fenced code block; long lines wrap rather than scroll sideways. A custom code renderer replaces the default part.',
|
|
33
33
|
},
|
|
34
34
|
{
|
|
35
35
|
name: 'Blockquote',
|
|
@@ -19,8 +19,10 @@
|
|
|
19
19
|
* The timed region inside each process is the spec's protocol, unsmoothed:
|
|
20
20
|
* ten untimed warmups, then one median of nine alternating paired rounds,
|
|
21
21
|
* for a stable plugin list and a recreated equivalent one, against the
|
|
22
|
-
* omitted baseline.
|
|
23
|
-
*
|
|
22
|
+
* omitted baseline. A first attempt within budget on both paths certifies
|
|
23
|
+
* them. Otherwise up to nine fresh-process attempts decide each path on its
|
|
24
|
+
* own: a path fails the unchanged budget when a majority of the nine (five)
|
|
25
|
+
* exceed it, and collection stops as soon as both paths are decided.
|
|
24
26
|
*/
|
|
25
27
|
|
|
26
28
|
import {execFileSync} from 'node:child_process';
|
|
@@ -166,18 +168,64 @@ function logBenchmarkResult(result: BenchmarkResult, attempt: number): void {
|
|
|
166
168
|
);
|
|
167
169
|
}
|
|
168
170
|
|
|
171
|
+
/** The two paths FR23 measures; each is held to the budget on its own. */
|
|
172
|
+
const FR23_PATHS = ['stable', 'recreated'] as const;
|
|
173
|
+
type FR23Path = (typeof FR23_PATHS)[number];
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Fresh-process attempts that decide a path after a noisy first one. On CI a
|
|
177
|
+
* clean representative set measures about 1.19 at 500 sections with about
|
|
178
|
+
* ±0.04 of sample noise, so a single attempt lands over the budget roughly
|
|
179
|
+
* one time in ten; a majority of nine does so well under one time in a
|
|
180
|
+
* thousand, while a slowdown of 0.1 or more still exceeds it nearly always.
|
|
181
|
+
*/
|
|
182
|
+
const FR23_ATTEMPTS = 9;
|
|
183
|
+
const FR23_MAJORITY = Math.floor(FR23_ATTEMPTS / 2) + 1;
|
|
184
|
+
|
|
185
|
+
function attemptsOverBudget(
|
|
186
|
+
attempts: ReadonlyArray<BenchmarkResult>,
|
|
187
|
+
fr23Path: FR23Path,
|
|
188
|
+
): number {
|
|
189
|
+
return attempts.filter(result => result[fr23Path] > FR23_BUDGET).length;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Whether the remaining attempts can no longer change this path's verdict. */
|
|
193
|
+
function pathDecided(
|
|
194
|
+
attempts: ReadonlyArray<BenchmarkResult>,
|
|
195
|
+
fr23Path: FR23Path,
|
|
196
|
+
): boolean {
|
|
197
|
+
const over = attemptsOverBudget(attempts, fr23Path);
|
|
198
|
+
return over >= FR23_MAJORITY || attempts.length - over >= FR23_MAJORITY;
|
|
199
|
+
}
|
|
200
|
+
|
|
169
201
|
function collectFR23Attempts(
|
|
170
202
|
sections: number,
|
|
171
203
|
runAttempt: (sections: number) => BenchmarkResult = runSettledBenchmark,
|
|
172
204
|
): ReadonlyArray<BenchmarkResult> {
|
|
173
205
|
const attempts = [runAttempt(sections)];
|
|
174
|
-
if (exceedsFR23Budget(attempts[0])) {
|
|
175
|
-
attempts
|
|
206
|
+
if (!exceedsFR23Budget(attempts[0])) {
|
|
207
|
+
return attempts;
|
|
208
|
+
}
|
|
209
|
+
while (
|
|
210
|
+
attempts.length < FR23_ATTEMPTS &&
|
|
211
|
+
!FR23_PATHS.every(fr23Path => pathDecided(attempts, fr23Path))
|
|
212
|
+
) {
|
|
176
213
|
attempts.push(runAttempt(sections));
|
|
177
214
|
}
|
|
178
215
|
return attempts;
|
|
179
216
|
}
|
|
180
217
|
|
|
218
|
+
/** The paths whose attempts exceed the budget in a majority of nine. */
|
|
219
|
+
function pathsOverBudget(
|
|
220
|
+
attempts: ReadonlyArray<BenchmarkResult>,
|
|
221
|
+
): ReadonlyArray<FR23Path> {
|
|
222
|
+
return FR23_PATHS.filter(fr23Path =>
|
|
223
|
+
attempts.length > 1
|
|
224
|
+
? attemptsOverBudget(attempts, fr23Path) >= FR23_MAJORITY
|
|
225
|
+
: attemptsOverBudget(attempts, fr23Path) > 0,
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
|
|
181
229
|
describe('Markdown FR23 helper overhead', () => {
|
|
182
230
|
it('reports one nine-pair median without selecting the cheapest baseline', () => {
|
|
183
231
|
// Paired ratios: four 1.1s, one 1.2, four 10s. The median is 1.2,
|
|
@@ -218,35 +266,104 @@ describe('Markdown FR23 helper overhead', () => {
|
|
|
218
266
|
}
|
|
219
267
|
});
|
|
220
268
|
|
|
221
|
-
|
|
269
|
+
describe('deciding each path from fresh-process attempts', () => {
|
|
222
270
|
const result = (stable: number, recreated: number): BenchmarkResult => ({
|
|
223
|
-
sections:
|
|
271
|
+
sections: 500,
|
|
224
272
|
stable,
|
|
225
273
|
recreated,
|
|
226
274
|
control: 1,
|
|
227
275
|
});
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
result(1.
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
276
|
+
const run = (results: BenchmarkResult[]) => {
|
|
277
|
+
const queue = [...results];
|
|
278
|
+
let calls = 0;
|
|
279
|
+
const attempts = collectFR23Attempts(500, () => {
|
|
280
|
+
calls++;
|
|
281
|
+
const next = queue.shift();
|
|
282
|
+
if (next == null) {
|
|
283
|
+
throw new Error('asked for an unplanned attempt');
|
|
284
|
+
}
|
|
285
|
+
return next;
|
|
286
|
+
});
|
|
287
|
+
return {attempts, calls, failing: pathsOverBudget(attempts)};
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
it('certifies both paths from one attempt within budget', () => {
|
|
291
|
+
const {calls, failing} = run([result(1.2, 1.22)]);
|
|
292
|
+
expect(calls).toBe(1);
|
|
293
|
+
expect(failing).toEqual([]);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
it('fails a single attempt over budget only if no retry ran', () => {
|
|
297
|
+
expect(pathsOverBudget([result(1.26, 1.2)])).toEqual(['stable']);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('judges each path by its own majority, not either path per attempt', () => {
|
|
301
|
+
// Main run 38393555595: stable was over in attempt 1 and recreated in
|
|
302
|
+
// attempt 2, which the old either-path-per-attempt count read as a
|
|
303
|
+
// two-of-three failure although neither path was over in a majority.
|
|
304
|
+
const {attempts, failing} = run([
|
|
305
|
+
result(1.256, 1.201),
|
|
306
|
+
result(1.145, 1.275),
|
|
307
|
+
result(1.183, 1.187),
|
|
308
|
+
result(1.18, 1.2),
|
|
309
|
+
result(1.19, 1.21),
|
|
310
|
+
result(1.2, 1.22),
|
|
311
|
+
result(1.17, 1.19),
|
|
312
|
+
]);
|
|
313
|
+
// Each path needs five attempts within budget; each had one over.
|
|
314
|
+
expect(attempts).toHaveLength(6);
|
|
315
|
+
expect(failing).toEqual([]);
|
|
316
|
+
});
|
|
317
|
+
|
|
318
|
+
it('stops as soon as both paths are decided', () => {
|
|
319
|
+
// Recreated is decided after five passes, stable after one more.
|
|
320
|
+
const {calls} = run([
|
|
321
|
+
result(1.3, 1.2),
|
|
322
|
+
result(1.2, 1.2),
|
|
323
|
+
result(1.2, 1.2),
|
|
324
|
+
result(1.2, 1.2),
|
|
325
|
+
result(1.2, 1.2),
|
|
326
|
+
result(1.2, 1.2),
|
|
327
|
+
]);
|
|
328
|
+
expect(calls).toBe(6);
|
|
329
|
+
});
|
|
330
|
+
|
|
331
|
+
it('fails a path that is over budget in a majority of nine', () => {
|
|
332
|
+
const {attempts, failing} = run([
|
|
333
|
+
result(1.3, 1.2),
|
|
334
|
+
result(1.27, 1.2),
|
|
335
|
+
result(1.2, 1.2),
|
|
336
|
+
result(1.26, 1.21),
|
|
337
|
+
result(1.22, 1.2),
|
|
338
|
+
result(1.28, 1.19),
|
|
339
|
+
result(1.26, 1.2),
|
|
340
|
+
]);
|
|
341
|
+
expect(attempts).toHaveLength(7);
|
|
342
|
+
expect(failing).toEqual(['stable']);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
it('fails a consistent slowdown on both paths after five attempts', () => {
|
|
346
|
+
const {calls, failing} = run(
|
|
347
|
+
Array.from({length: 9}, () => result(1.4, 1.42)),
|
|
348
|
+
);
|
|
349
|
+
expect(calls).toBe(5);
|
|
350
|
+
expect(failing).toEqual(['stable', 'recreated']);
|
|
351
|
+
});
|
|
352
|
+
|
|
353
|
+
it('never runs more than nine attempts', () => {
|
|
354
|
+
const {calls} = run([
|
|
355
|
+
result(1.3, 1.3),
|
|
356
|
+
result(1.2, 1.2),
|
|
357
|
+
result(1.3, 1.3),
|
|
358
|
+
result(1.2, 1.2),
|
|
359
|
+
result(1.3, 1.3),
|
|
360
|
+
result(1.2, 1.2),
|
|
361
|
+
result(1.3, 1.3),
|
|
362
|
+
result(1.2, 1.2),
|
|
363
|
+
result(1.3, 1.3),
|
|
364
|
+
]);
|
|
365
|
+
expect(calls).toBe(9);
|
|
366
|
+
});
|
|
250
367
|
});
|
|
251
368
|
|
|
252
369
|
it.each([200, 500])(
|
|
@@ -257,28 +374,32 @@ describe('Markdown FR23 helper overhead', () => {
|
|
|
257
374
|
// attempt counts: a value over budget is machine noise, so that process
|
|
258
375
|
// is replaced before its A/B result can certify or fail the helpers.
|
|
259
376
|
//
|
|
260
|
-
// A single over-budget A/B is also noisy at this threshold.
|
|
261
|
-
//
|
|
262
|
-
//
|
|
263
|
-
// 1.25 budget.
|
|
377
|
+
// A single over-budget A/B is also noisy at this threshold. Each path
|
|
378
|
+
// is then decided by a majority of up to nine fresh-process attempts
|
|
379
|
+
// against the unchanged 1.25 budget.
|
|
264
380
|
const attempts = collectFR23Attempts(sections);
|
|
265
|
-
if (attempts.length
|
|
381
|
+
if (attempts.length > 1) {
|
|
266
382
|
console.log(
|
|
267
383
|
` ${sections} sections: first A/B exceeded ${FR23_BUDGET};` +
|
|
268
|
-
|
|
384
|
+
` decided each path from ${attempts.length} fresh processes`,
|
|
269
385
|
);
|
|
270
386
|
}
|
|
271
387
|
attempts.forEach((result, index) =>
|
|
272
388
|
logBenchmarkResult(result, index + 1),
|
|
273
389
|
);
|
|
274
|
-
const
|
|
390
|
+
const failing = pathsOverBudget(attempts);
|
|
275
391
|
expect(
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
392
|
+
failing,
|
|
393
|
+
failing
|
|
394
|
+
.map(
|
|
395
|
+
fr23Path =>
|
|
396
|
+
`${fr23Path}: ${attemptsOverBudget(attempts, fr23Path)} of ` +
|
|
397
|
+
`${attempts.length} fresh FR23 attempts exceeded the ${FR23_BUDGET} budget`,
|
|
398
|
+
)
|
|
399
|
+
.join('; '),
|
|
400
|
+
).toEqual([]);
|
|
280
401
|
},
|
|
281
|
-
|
|
402
|
+
600_000,
|
|
282
403
|
);
|
|
283
404
|
|
|
284
405
|
it('fails loudly when the benchmark process cannot produce a result', () => {
|
|
@@ -50,6 +50,7 @@ system_specs:
|
|
|
50
50
|
spec:AST-036/DEC-4,
|
|
51
51
|
spec:AST-061/DEC-5,
|
|
52
52
|
spec:AST-061/DEC-6,
|
|
53
|
+
spec:AST-061/DEC-9,
|
|
53
54
|
spec:AST-064/DEC-6,
|
|
54
55
|
spec:AST-036/DEC-12,
|
|
55
56
|
]
|
|
@@ -64,18 +65,37 @@ constrained renderer seams. Callers may opt into the canonical plugin protocol f
|
|
|
64
65
|
bounded source syntax, immutable document transformation, typed extension
|
|
65
66
|
rendering, and native typed document-start frontmatter. They may separately opt into dollar-delimited math by supplying one typed
|
|
66
67
|
renderer for both inline and display expressions. The parser accepts matching
|
|
67
|
-
explicit options.
|
|
68
|
-
|
|
68
|
+
explicit options. Plugins and math change nothing when absent; the default Code
|
|
69
|
+
block path renders `diff` and `diff-<language>` fences as CodeBlock's diff layer
|
|
70
|
+
(FR29) and wraps every fence's long lines (`spec:AST-061` FR5, DEC-9), and every
|
|
71
|
+
other parsing, rendering, styling, and streaming behavior is the released one.
|
|
69
72
|
|
|
70
73
|
## Compatibility and migration
|
|
71
74
|
|
|
72
|
-
- Released default preserved: `yes`
|
|
73
|
-
- Compatibility class: additive, opt-in public API
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
75
|
+
- Released default preserved: `yes`, except the default Code block path for `diff` fences (FR29, below) and its long-line wrap (below)
|
|
76
|
+
- Compatibility class: additive, opt-in public API, with two visible
|
|
77
|
+
default-path rendering changes (the FR29 diff layer and the fenced-code wrap,
|
|
78
|
+
below); existing parser nodes, DOM, styling, targets,
|
|
79
|
+
dollar-delimited text, `components`, and `inlinePlugins` remain unchanged unless
|
|
80
|
+
the caller supplies `plugins`, supplies `components.math`, or passes the matching
|
|
81
|
+
explicit parser option.
|
|
77
82
|
- Controlled/uncontrolled behavior: not applicable
|
|
78
83
|
- Migration decision: none
|
|
84
|
+
- Default-path rendering change for diff fences (FR29), a visible default change
|
|
85
|
+
and not a breaking one: a `diff` fence that rendered as plain text renders as CodeBlock's diff
|
|
86
|
+
layer over plaintext with a `diff` label, and a `diff-<language>` fence —
|
|
87
|
+
which rendered as plain text with a `diff` label and viewport name, its
|
|
88
|
+
leading word being all Markdown read — as the layer over that language with
|
|
89
|
+
a `<language> diff` label; the header, copy, disclosure, and viewport name
|
|
90
|
+
stay, and a supplied `code` renderer's contract is unchanged. The way back to
|
|
91
|
+
plain text is a `text` fence or a custom `code` renderer. Every other fence
|
|
92
|
+
is unchanged apart from the wrap below.
|
|
93
|
+
- Default-path wrap change (`spec:AST-061` FR5, DEC-9), visual and not breaking:
|
|
94
|
+
the default Code block wraps long lines instead of scrolling them sideways, so
|
|
95
|
+
a fence whose lines no longer overflow also no longer takes the conditional
|
|
96
|
+
scroll-region tab stop. Text, line numbers, syntax colours, copy output, and a
|
|
97
|
+
supplied `code` renderer's contract are unchanged. The way back to sideways
|
|
98
|
+
scrolling is a custom `code` renderer.
|
|
79
99
|
- Default-path layout change (FR26–FR28): a default table's columns may become
|
|
80
100
|
wider than the released fixed buckets, never narrower; header labels wrap
|
|
81
101
|
instead of truncating; a table that squashed its columns may now scroll.
|
|
@@ -228,6 +248,7 @@ unions. Enabled calls return the explicit `InlineNodeWithMath` and
|
|
|
228
248
|
| FR26 | On the default table path each column has a content-derived width floor: the larger of its own longest unbreakable token and a readable minimum derived from that column's content, bounded so a table of short columns still fits its container. The floor applies to the cell's text, not to its padded box, so it means the same amount of content at every density. A header label contributes its own readable minimum to that comparison. A table whose floors exceed the container grows and scrolls rather than dividing the container equally. |
|
|
229
249
|
| FR27 | Default table header cells never truncate: no ellipsis and no width clamp. A header reads in full, on one line up to a bounded width and wrapping past it. Inline code inside a default table cell keeps its token whole rather than breaking mid-token; a supplied `inlineCode` renderer owns its own wrapping. |
|
|
230
250
|
| FR28 | Markdown's Table block owns spacing, sizing, and alignment. The nested Table's own Scroll region remains the sole owner of the table's horizontal overflow, its accessible name, and its conditional keyboard focusability; Markdown adds no second scroll container, name, or tab stop of its own. |
|
|
251
|
+
| FR29 | On the default Code block path the fence's full first word selects CodeBlock's diff layer (`component:CodeBlock` FR9): `diff` renders the layer over plaintext, `diff-<language>` the layer over `<language>` (the language read by the same leading-word rule as any other fence); every other fence takes no diff layer. A supplied `code` renderer's contract is unchanged: it keeps receiving the leading word characters as `language` — `diff` for both `diff` and `diff-<language>` fences — and nothing new. |
|
|
231
252
|
|
|
232
253
|
FR23 includes CommonMark-compatible lazy paragraph continuation inside blockquotes
|
|
233
254
|
and ordered, unordered, or task-list items. Omitting a repeated quote marker or
|
|
@@ -421,22 +442,23 @@ and this change preserves the existing spelling exactly.
|
|
|
421
442
|
|
|
422
443
|
## Verification map
|
|
423
444
|
|
|
424
|
-
| Contract | Verification
|
|
425
|
-
| ---------------------- |
|
|
426
|
-
| FR1–FR5 | `Markdown.test.tsx`, theme-target tests, and `scripts/check-knowledge.mjs`
|
|
427
|
-
| FR6–FR10 | `parser.test.ts` and `Markdown.test.tsx`
|
|
428
|
-
| FR11 | `incremental.test.ts` and `Markdown.test.tsx`
|
|
429
|
-
| FR12–FR16 | plugin, transform, adapter, performance, and Outline parser tests
|
|
430
|
-
| FR17–FR18 | container parse/validation, ownership, and dependency tests
|
|
431
|
-
| FR19 | diagnostic-channel tests in development and production
|
|
432
|
-
| FR20–FR22 | canonical/server imports, inference, streaming, preparation, theming tests
|
|
433
|
-
| FR23 | parser, incremental, renderer, nesting, and public option tests
|
|
434
|
-
| FR24 | `plugins/frontmatter.test.tsx`, Storybook, and server rendering
|
|
435
|
-
| FR25 | `parser.public.test.ts`, plugin SSR tests, and package export checks
|
|
436
|
-
| FR26–FR28 | `Markdown.test.tsx` and a real-browser layer over checked-in narrow-width stories
|
|
437
|
-
|
|
|
438
|
-
|
|
|
439
|
-
|
|
|
445
|
+
| Contract | Verification | Representative states | Failure signal |
|
|
446
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
447
|
+
| FR1–FR5 | `Markdown.test.tsx`, theme-target tests, and `scripts/check-knowledge.mjs` | Default block/inline output and all current targets | Existing DOM, target, spacing, or renderer behavior changes. |
|
|
448
|
+
| FR6–FR10 | `parser.test.ts` and `Markdown.test.tsx` | Opt-out, inline/display math, escapes, currency, code, links, plugins | A delimiter is claimed without opt-in, TeX is formatted as Markdown, or opaque contexts leak. |
|
|
449
|
+
| FR11 | `incremental.test.ts` and `Markdown.test.tsx` | Every-character top-level/list/task-list/blockquote splits, CRLF, source ranges | Streaming diverges from a full parse, shows partial syntax, mistakes a nested closer for an opener, or crosses a closed container. |
|
|
450
|
+
| FR12–FR16 | plugin, transform, adapter, performance, and Outline parser tests | omitted/empty lists, immutable transforms, invalid outputs, live updates, one compatible Remark plugin, duplicate headings | Empty behavior forks, input mutates, invalid structure escapes, transforms reparse, adapter loses content, budgets fail, or heading targets diverge. |
|
|
451
|
+
| FR17–FR18 | container parse/validation, ownership, and dependency tests | leaf/container declarations, nested containers, foreign read/remove/mint/edit, unmet/misordered dependencies | Plugin-built parsed children, invalid content, lost fallback children, foreign mint/edit, or generic ownership codes. |
|
|
452
|
+
| FR19 | diagnostic-channel tests in development and production | every phase, advisory reports, rate suppression, no handler, malformed list, duplicate Core, version skew | A silent production failure, document content in a diagnostic, or one entrypoint throwing where another recovers. |
|
|
453
|
+
| FR20–FR22 | canonical/server imports, inference, streaming, preparation, theming tests | server imports, no explicit type args, chunk boundaries, recreated lists, themed/unthemed extensions | Client references, explicit-type workarounds, oscillation, per-render re-preparation, or unreachable opted-in output. |
|
|
454
|
+
| FR23 | parser, incremental, renderer, nesting, and public option tests | mixed lists; escaped prose/code table cells, nested inline code, full/streaming parity; autolink omitted/enabled | A mixed list splits or loses state, an escaped table pipe changes cells or exposes its backslash, or autolink changes other syntax. |
|
|
455
|
+
| FR24 | `plugins/frontmatter.test.tsx`, Storybook, and server rendering | complete, malformed, non-leading, LF/CRLF, unfinished streaming, full plugin stack | Metadata syntax renders after completion, unfinished syntax leaks while streaming, typing is lost, or later plugins stop composing. |
|
|
456
|
+
| FR25 | `parser.public.test.ts`, plugin SSR tests, and package export checks | server/RSC parsing with plugins, synchronous SSR, suspending renderer streaming boundary | A server import gains `use client`, plugin execution needs serialization, SSR loses fallback, or direct RSC rendering is misrepresented as supported. |
|
|
457
|
+
| FR26–FR28 | `Markdown.test.tsx` and a real-browser layer over checked-in narrow-width stories | short, prose, and token-heavy tables; header-only rows and empty cells; long headers over short bodies; reading columns from phone to document width | A column collapses below its content floor, cell padding eats the floor, a header truncates, an inline-code token breaks mid-token, or a second scroll viewport, name, or tab stop appears around a table. |
|
|
458
|
+
| FR29 | `Markdown.test.tsx` (a `diff` fence → plaintext + layer, a `diff-tsx` fence → tsx + layer, a plain fence unchanged, a custom `code` renderer receives `language="diff"` for both diff fences and nothing new) | default path and custom renderer, `diff` and `diff-<language>` fences | a fence word other than `diff`/`diff-<language>` reaching the layer, or a custom renderer receiving a new prop or a different `language` |
|
|
459
|
+
| Public syntax/types | `Markdown.public.test.ts`, core typecheck, and `Markdown.doc.mjs` | Legacy exhaustive switches, math opt-ins, inferred extension-node unions | A released union widens, an enabled union loses nodes, or docs drift from declarations. |
|
|
460
|
+
| Navigation contract | `parser.test.ts`, `Markdown.test.tsx`, and `Markdown.renderBoundary.test.tsx` | Parsed and rendered links, including transformed built-in links; accepted ordinary schemes; rejected destinations; links versus images | A blocked destination reaches navigation or a custom link renderer, or resource policy narrows accepted navigation. |
|
|
461
|
+
| Security/accessibility | `parser.test.ts`, `Markdown.test.tsx`, and renderer guidance | Inert expression strings and renderer-owned semantics | Astryx executes math as HTML or silently claims renderer-owned accessibility. |
|
|
440
462
|
|
|
441
463
|
Focused tests continue to pin all nine current target names and default block
|
|
442
464
|
placement. Math intentionally adds no target and no default anatomy.
|