@astryxdesign/core 0.6.2 → 0.6.3-canary.01fa439
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 +81 -0
- package/dist/BottomSheet/BottomSheet.d.ts +1 -1
- package/dist/BottomSheet/BottomSheet.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheet.js +3 -1
- package/dist/BottomSheet/BottomSheetPanel.d.ts +7 -5
- package/dist/BottomSheet/BottomSheetPanel.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetPanel.js +56 -19
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +10 -5
- package/dist/Chat/ChatComposerDrawer.d.ts +19 -5
- package/dist/Chat/ChatComposerDrawer.d.ts.map +1 -1
- package/dist/Chat/ChatComposerDrawer.js +48 -23
- package/dist/Chat/ChatComposerInput.d.ts +11 -3
- package/dist/Chat/ChatComposerInput.d.ts.map +1 -1
- package/dist/Chat/ChatComposerInput.js +63 -16
- package/dist/Chat/ChatDictationButton.d.ts +3 -2
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +6 -4
- package/dist/Chat/ChatSendButton.js +1 -1
- package/dist/Chat/index.d.ts +1 -1
- package/dist/Chat/index.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +12 -2
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +6 -1
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +1 -1
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +1 -1
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +4 -4
- package/dist/DateInput/NativeDateField.d.ts.map +1 -1
- package/dist/DateInput/NativeDateField.js +16 -16
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +2 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +4 -4
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +8 -8
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +9 -3
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -1
- package/dist/DateTimeInput/nativePickerSegmentStyles.js +3 -3
- package/dist/Dialog/DialogHeader.d.ts +8 -1
- package/dist/Dialog/DialogHeader.d.ts.map +1 -1
- package/dist/Dialog/DialogHeader.js +10 -1
- package/dist/Field/InputClearButton.d.ts +4 -2
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +4 -2
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +1 -1
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +7 -7
- package/dist/Kbd/Kbd.d.ts +5 -3
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +36 -42
- package/dist/Link/Link.d.ts.map +1 -1
- package/dist/Link/Link.js +6 -2
- package/dist/Markdown/Markdown.d.ts +8 -2
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.fr23.bench.d.ts +2 -0
- package/dist/Markdown/Markdown.fr23.bench.d.ts.map +1 -0
- package/dist/Markdown/Markdown.fr23.bench.js +150 -0
- package/dist/Markdown/Markdown.fr23.sampling.d.ts +2 -0
- package/dist/Markdown/Markdown.fr23.sampling.d.ts.map +1 -0
- package/dist/Markdown/Markdown.fr23.sampling.js +43 -0
- package/dist/Markdown/Markdown.js +262 -109
- package/dist/Markdown/ast.d.ts +162 -0
- package/dist/Markdown/ast.d.ts.map +1 -0
- package/dist/Markdown/ast.js +74 -0
- package/dist/Markdown/index.d.ts +5 -3
- package/dist/Markdown/index.d.ts.map +1 -1
- package/dist/Markdown/index.js +3 -2
- package/dist/Markdown/parser/index.d.ts +10 -0
- package/dist/Markdown/parser/index.d.ts.map +1 -0
- package/dist/Markdown/parser/index.js +10 -0
- package/dist/Markdown/parser.d.ts +126 -58
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +716 -167
- package/dist/Markdown/plugins/frontmatter.d.ts +32 -0
- package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -0
- package/dist/Markdown/plugins/frontmatter.js +132 -0
- package/dist/Markdown/plugins/index.d.ts +16 -0
- package/dist/Markdown/plugins/index.d.ts.map +1 -0
- package/dist/Markdown/plugins/index.js +13 -0
- package/dist/Markdown/plugins/protocol.d.ts +191 -0
- package/dist/Markdown/plugins/protocol.d.ts.map +1 -0
- package/dist/Markdown/plugins/protocol.js +957 -0
- package/dist/Markdown/plugins/semanticFence.d.ts +36 -0
- package/dist/Markdown/plugins/semanticFence.d.ts.map +1 -0
- package/dist/Markdown/plugins/semanticFence.js +213 -0
- package/dist/Markdown/plugins/sourceDecoration.d.ts +76 -0
- package/dist/Markdown/plugins/sourceDecoration.d.ts.map +1 -0
- package/dist/Markdown/plugins/sourceDecoration.js +393 -0
- package/dist/Markdown/plugins/textTransform.d.ts +30 -0
- package/dist/Markdown/plugins/textTransform.d.ts.map +1 -0
- package/dist/Markdown/plugins/textTransform.js +374 -0
- package/dist/Markdown/remark.d.ts +196 -0
- package/dist/Markdown/remark.d.ts.map +1 -0
- package/dist/Markdown/remark.js +1062 -0
- package/dist/Markdown/url.d.ts +4 -0
- package/dist/Markdown/url.d.ts.map +1 -0
- package/dist/Markdown/url.js +25 -0
- package/dist/Markdown/utils.d.ts +4 -2
- package/dist/Markdown/utils.d.ts.map +1 -1
- package/dist/Markdown/utils.js +2 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +4 -4
- package/dist/Outline/index.d.ts +1 -0
- package/dist/Outline/index.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.d.ts +7 -1
- package/dist/Outline/parseOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/parseOutlineFromMarkdown.js +14 -8
- package/dist/Outline/useOutlineFromMarkdown.d.ts +3 -1
- package/dist/Outline/useOutlineFromMarkdown.d.ts.map +1 -1
- package/dist/Outline/useOutlineFromMarkdown.js +8 -3
- package/dist/PowerSearch/PowerSearchEditPopover.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchEditPopover.js +46 -30
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +36 -31
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +13 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +5 -5
- package/dist/Selector/Selector.d.ts +9 -7
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +7 -5
- package/dist/SideNav/SideNav.d.ts +2 -1
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +9 -3
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +28 -12
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +23 -7
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +11 -0
- package/dist/TabList/Tab.d.ts +1 -1
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +20 -7
- package/dist/Table/Table.d.ts +1 -0
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +29 -13
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +1 -1
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +2 -2
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +4 -4
- package/dist/ToggleButton/ToggleButton.d.ts +9 -6
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +15 -27
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +3 -0
- package/dist/TreeList/TreeListItem.d.ts +6 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +12 -2
- package/dist/TreeList/TreeListTypes.d.ts +8 -1
- package/dist/TreeList/TreeListTypes.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +16 -7
- package/dist/astryx.css +18 -7
- package/dist/hooks/scrollKeyboardDelegation.d.ts +3 -0
- package/dist/hooks/scrollKeyboardDelegation.d.ts.map +1 -0
- package/dist/hooks/scrollKeyboardDelegation.js +146 -0
- package/dist/hooks/useScrollableArea.d.ts +6 -2
- package/dist/hooks/useScrollableArea.d.ts.map +1 -1
- package/dist/hooks/useScrollableArea.js +17 -5
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +10 -0
- package/dist/utils/interactionOverlay.stylex.d.ts +8 -0
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -1
- package/dist/utils/interactionOverlay.stylex.js +9 -0
- package/locales/af-ZA.json +530 -1
- package/locales/ar-SA.json +490 -1
- package/locales/ca-ES.json +514 -1
- package/locales/cs-CZ.json +498 -1
- package/locales/da-DK.json +522 -1
- package/locales/de-DE.json +522 -1
- package/locales/el-GR.json +498 -1
- package/locales/es-ES.json +510 -1
- package/locales/fi-FI.json +498 -1
- package/locales/fr-FR.json +534 -1
- package/locales/he-IL.json +498 -1
- package/locales/hu-HU.json +498 -1
- package/locales/it-IT.json +510 -1
- package/locales/ja-JP.json +490 -1
- package/locales/ko-KR.json +498 -1
- package/locales/nl-NL.json +534 -1
- package/locales/no-NO.json +510 -1
- package/locales/pl-PL.json +506 -1
- package/locales/pt-BR.json +506 -1
- package/locales/pt-PT.json +506 -1
- package/locales/ro-RO.json +506 -1
- package/locales/ru-RU.json +498 -1
- package/locales/sr-SP.json +498 -1
- package/locales/sv-SE.json +502 -1
- package/locales/tr-TR.json +498 -1
- package/locales/uk-UA.json +498 -1
- package/locales/vi-VN.json +502 -1
- package/locales/zh-CN.json +490 -1
- package/locales/zh-TW.json +490 -1
- package/package.json +19 -4
- package/src/BottomSheet/BottomSheet.doc.mjs +8 -1
- package/src/BottomSheet/BottomSheet.spec.md +46 -20
- package/src/BottomSheet/BottomSheet.test.tsx +6 -3
- package/src/BottomSheet/BottomSheet.tsx +3 -1
- package/src/BottomSheet/BottomSheetKeyboard.test.tsx +195 -0
- package/src/BottomSheet/BottomSheetPanel.test.tsx +11 -1
- package/src/BottomSheet/BottomSheetPanel.tsx +49 -16
- package/src/BottomSheet/__tests__/BottomSheetKeyboard.a11y.browser.spec.ts +344 -0
- package/src/Button/__tests__/Button.a11y.chromium.spec.ts +17 -1
- package/src/Button/__tests__/Button.a11y.known-failures.ts +0 -29
- package/src/Button/__tests__/Button.a11y.renders.tsx +9 -2
- package/src/Button/__tests__/Button.a11y.states.ts +9 -0
- package/src/Chat/ChatComposer.doc.mjs +14 -0
- package/src/Chat/ChatComposer.spec.md +230 -0
- package/src/Chat/ChatComposer.test.tsx +57 -0
- package/src/Chat/ChatComposer.tsx +21 -9
- package/src/Chat/ChatComposerDrawer.doc.mjs +63 -5
- package/src/Chat/ChatComposerDrawer.spec.md +267 -0
- package/src/Chat/ChatComposerDrawer.test.tsx +81 -12
- package/src/Chat/ChatComposerDrawer.tsx +38 -9
- package/src/Chat/ChatComposerInput.doc.mjs +114 -26
- package/src/Chat/ChatComposerInput.spec.md +185 -0
- package/src/Chat/ChatComposerInput.test.tsx +113 -3
- package/src/Chat/ChatComposerInput.tsx +78 -13
- package/src/Chat/ChatComposerTokenElement.spec.md +152 -0
- package/src/Chat/ChatComposerTokenElement.test.tsx +85 -0
- package/src/Chat/ChatDictationButton.doc.mjs +3 -3
- package/src/Chat/ChatDictationButton.spec.md +160 -0
- package/src/Chat/ChatDictationButton.test.tsx +92 -27
- package/src/Chat/ChatDictationButton.tsx +8 -6
- package/src/Chat/ChatSendButton.test.tsx +1 -4
- package/src/Chat/ChatSendButton.tsx +1 -1
- package/src/Chat/index.ts +1 -0
- package/src/CheckboxInput/CheckboxInput.doc.mjs +11 -0
- package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
- package/src/CheckboxInput/CheckboxInput.tsx +21 -1
- package/src/ClickableCard/ClickableCard.test.tsx +102 -5
- package/src/Collapsible/Collapsible.doc.mjs +11 -0
- package/src/Collapsible/Collapsible.test.tsx +21 -0
- package/src/Collapsible/Collapsible.tsx +5 -0
- package/src/CommandPalette/CommandPaletteInput.tsx +6 -1
- package/src/ComplexSelector/ComplexSelector.tsx +6 -1
- package/src/DateInput/DateInput.tsx +6 -1
- package/src/DateInput/NativeDateField.tsx +24 -8
- package/src/DateInput/TouchDateField.tsx +6 -2
- package/src/DateRangeInput/DateRangeInput.tsx +6 -1
- package/src/DateTimeInput/DateTimeInput.tsx +6 -1
- package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
- package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
- package/src/Dialog/DialogHeader.doc.mjs +12 -0
- package/src/Dialog/DialogHeader.test.tsx +97 -0
- package/src/Dialog/DialogHeader.tsx +25 -3
- package/src/Dialog/modules/DialogHeader.spec.md +75 -38
- package/src/Field/InputClearButton.test.tsx +17 -3
- package/src/Field/InputClearButton.tsx +5 -2
- package/src/Field/PanelSearchInput.tsx +5 -2
- package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +1 -1
- package/src/FileInput/FileInput.tsx +11 -2
- package/src/Kbd/Kbd.doc.mjs +3 -3
- package/src/Kbd/Kbd.test.tsx +57 -1
- package/src/Kbd/Kbd.tsx +57 -37
- package/src/Layout/LayoutFooter.doc.mjs +17 -0
- package/src/Link/Link.doc.mjs +11 -0
- package/src/Link/Link.test.tsx +24 -0
- package/src/Link/Link.tsx +5 -0
- package/src/List/List.spec.md +200 -0
- package/src/Markdown/Markdown.doc.mjs +272 -0
- package/src/Markdown/Markdown.fr23.bench.ts +174 -0
- package/src/Markdown/Markdown.fr23.perf.test.ts +249 -0
- package/src/Markdown/Markdown.fr23.sampling.ts +49 -0
- package/src/Markdown/Markdown.helpers.perf.test.ts +489 -0
- package/src/Markdown/Markdown.public.test.ts +126 -3
- package/src/Markdown/Markdown.spec.md +197 -44
- package/src/Markdown/Markdown.test.tsx +11 -0
- package/src/Markdown/Markdown.tsx +414 -135
- package/src/Markdown/ast.test.ts +307 -0
- package/src/Markdown/ast.ts +337 -0
- package/src/Markdown/incremental.test.ts +12 -0
- package/src/Markdown/index.ts +37 -1
- package/src/Markdown/modules/remark.spec.md +269 -0
- package/src/Markdown/parser/index.ts +64 -0
- package/src/Markdown/parser.public.test.ts +103 -0
- package/src/Markdown/parser.ts +1180 -235
- package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
- package/src/Markdown/plugins/frontmatter.ts +198 -0
- package/src/Markdown/plugins/index.ts +53 -0
- package/src/Markdown/plugins/protocol.test.tsx +1022 -0
- package/src/Markdown/plugins/protocol.ts +1618 -0
- package/src/Markdown/plugins/semanticFence.test.tsx +546 -0
- package/src/Markdown/plugins/semanticFence.ts +424 -0
- package/src/Markdown/plugins/sourceDecoration.test.tsx +799 -0
- package/src/Markdown/plugins/sourceDecoration.ts +539 -0
- package/src/Markdown/plugins/textTransform.test.ts +467 -0
- package/src/Markdown/plugins/textTransform.ts +554 -0
- package/src/Markdown/remark.test.tsx +1877 -0
- package/src/Markdown/remark.ts +1574 -0
- package/src/Markdown/url.ts +30 -0
- package/src/Markdown/utils.ts +13 -1
- package/src/MultiSelector/MultiSelector.test.tsx +1 -35
- package/src/MultiSelector/__tests__/MultiSelector.listbox.a11y.test.tsx +128 -0
- package/src/NumberInput/NumberInput.tsx +6 -1
- package/src/Outline/Outline.doc.mjs +7 -5
- package/src/Outline/Outline.spec.md +1 -1
- package/src/Outline/index.ts +1 -0
- package/src/Outline/modules/parseOutlineFromMarkdown.spec.md +142 -0
- package/src/Outline/parseOutlineFromMarkdown.ts +40 -10
- package/src/Outline/useOutlineFromMarkdown.ts +15 -3
- package/src/PowerSearch/PowerSearch.doc.mjs +2 -2
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +150 -1
- package/src/PowerSearch/PowerSearchEditPopover.tsx +51 -28
- package/src/ProgressBar/ProgressBar.test.tsx +29 -11
- package/src/ProgressBar/ProgressBar.tsx +59 -72
- package/src/RadioList/RadioList.doc.mjs +11 -0
- package/src/RadioList/RadioList.test.tsx +32 -0
- package/src/RadioList/RadioListItem.tsx +25 -1
- package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
- package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
- package/src/SegmentedControl/SegmentedControl.test.tsx +31 -0
- package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
- package/src/Selector/Selector.doc.mjs +2 -2
- package/src/Selector/Selector.spec.md +51 -49
- package/src/Selector/Selector.test.tsx +61 -55
- package/src/Selector/Selector.tsx +23 -14
- package/src/Selector/__tests__/Listbox.a11y.chromium.spec.ts +130 -0
- package/src/Selector/__tests__/Listbox.a11y.dom.ts +38 -0
- package/src/Selector/__tests__/Listbox.a11y.inventory.test.ts +63 -0
- package/src/Selector/__tests__/Listbox.a11y.known-failures.ts +37 -0
- package/src/Selector/__tests__/Listbox.a11y.states.ts +232 -0
- package/src/Selector/__tests__/Selector.listbox.a11y.test.tsx +121 -0
- package/src/SideNav/SideNav.doc.mjs +1 -1
- package/src/SideNav/SideNav.test.tsx +10 -0
- package/src/SideNav/SideNav.tsx +14 -2
- package/src/Slider/Slider.doc.mjs +17 -3
- package/src/Slider/Slider.test.tsx +221 -0
- package/src/Slider/Slider.tsx +40 -9
- package/src/Spinner/Spinner.test.tsx +4 -0
- package/src/Spinner/Spinner.tsx +31 -18
- package/src/Switch/Switch.doc.mjs +11 -0
- package/src/Switch/Switch.test.tsx +16 -0
- package/src/Switch/Switch.tsx +28 -0
- package/src/TabList/Tab.tsx +35 -7
- package/src/TabList/TabList.doc.mjs +11 -0
- package/src/TabList/TabList.spec.md +204 -0
- package/src/TabList/TabList.test.tsx +66 -0
- package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +1 -34
- package/src/Table/Table.doc.mjs +1 -1
- package/src/Table/Table.spec.md +54 -40
- package/src/Table/Table.test.tsx +83 -10
- package/src/Table/Table.tsx +30 -22
- package/src/Table/__tests__/TableScroll.a11y.chromium.spec.ts +137 -0
- package/src/TextArea/TextArea.tsx +6 -1
- package/src/TextInput/TextInput.test.tsx +20 -1
- package/src/TextInput/TextInput.tsx +6 -1
- package/src/TimeInput/TimeInput.tsx +6 -1
- package/src/ToggleButton/ToggleButton.doc.mjs +3 -3
- package/src/ToggleButton/ToggleButton.test.tsx +299 -4
- package/src/ToggleButton/ToggleButton.tsx +26 -33
- package/src/ToggleButton/ToggleButtonGroup.doc.mjs +3 -3
- package/src/ToggleButton/__tests__/ToggleButton.a11y.chromium.spec.ts +209 -0
- package/src/Tokenizer/Tokenizer.spec.md +142 -75
- package/src/TreeList/TreeList.doc.mjs +3 -3
- package/src/TreeList/TreeList.spec.md +123 -75
- package/src/TreeList/TreeList.test.tsx +29 -0
- package/src/TreeList/TreeList.tsx +3 -0
- package/src/TreeList/TreeListItem.tsx +15 -1
- package/src/TreeList/TreeListTypes.ts +11 -1
- package/src/Typeahead/BaseTypeahead.spec.md +4 -3
- package/src/Typeahead/BaseTypeahead.tsx +21 -7
- package/src/Typeahead/Typeahead.test.tsx +53 -0
- package/src/__tests__/PressedState.a11y.chromium.spec.ts +813 -0
- package/src/__tests__/pressState.ts +93 -0
- package/src/hooks/scrollKeyboardDelegation.test.ts +155 -0
- package/src/hooks/scrollKeyboardDelegation.ts +233 -0
- package/src/hooks/useScrollableArea.doc.mjs +15 -3
- package/src/hooks/useScrollableArea.test.tsx +59 -1
- package/src/hooks/useScrollableArea.ts +34 -10
- package/src/inputFontFloor.test.ts +106 -0
- package/src/tailwind-theme.css +0 -6
- package/src/theme/generateThemeRules.test.ts +30 -0
- package/src/theme/generateThemeRules.ts +10 -0
- package/src/utils/interactionOverlay.stylex.ts +20 -0
|
@@ -92,9 +92,14 @@ const styles = stylex.create({
|
|
|
92
92
|
borderStyle: 'none',
|
|
93
93
|
padding: 0,
|
|
94
94
|
fontFamily: typographyVars['--font-family-body'],
|
|
95
|
+
// The 16px floor is iOS-only: iOS Safari zooms the page when a focused
|
|
96
|
+
// control sits under 16px, and only iOS WebKit implements
|
|
97
|
+
// -webkit-touch-callout to key the coarse-pointer floor to it.
|
|
95
98
|
fontSize: {
|
|
96
99
|
default: typeScaleVars['--text-body-size'],
|
|
97
|
-
'@media (pointer: coarse)':
|
|
100
|
+
'@media (pointer: coarse)': {
|
|
101
|
+
'@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
|
|
102
|
+
},
|
|
98
103
|
},
|
|
99
104
|
lineHeight: typeScaleVars['--text-body-leading'],
|
|
100
105
|
color: colorVars['--color-text-primary'],
|
|
@@ -173,9 +173,14 @@ const styles = stylex.create({
|
|
|
173
173
|
borderStyle: 'none',
|
|
174
174
|
padding: 0,
|
|
175
175
|
fontFamily: typographyVars['--font-family-body'],
|
|
176
|
+
// The 16px floor is iOS-only: iOS Safari zooms the page when a focused
|
|
177
|
+
// control sits under 16px, and only iOS WebKit implements
|
|
178
|
+
// -webkit-touch-callout to key the coarse-pointer floor to it.
|
|
176
179
|
fontSize: {
|
|
177
180
|
default: typeScaleVars['--text-body-size'],
|
|
178
|
-
'@media (pointer: coarse)':
|
|
181
|
+
'@media (pointer: coarse)': {
|
|
182
|
+
'@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
|
|
183
|
+
},
|
|
179
184
|
},
|
|
180
185
|
lineHeight: typeScaleVars['--text-body-leading'],
|
|
181
186
|
color: colorVars['--color-text-primary'],
|
|
@@ -182,9 +182,14 @@ const styles = stylex.create({
|
|
|
182
182
|
borderStyle: 'none',
|
|
183
183
|
padding: 0,
|
|
184
184
|
fontFamily: typographyVars['--font-family-body'],
|
|
185
|
+
// The 16px floor is iOS-only: iOS Safari zooms the page when a focused
|
|
186
|
+
// control sits under 16px, and only iOS WebKit implements
|
|
187
|
+
// -webkit-touch-callout to key the coarse-pointer floor to it.
|
|
185
188
|
fontSize: {
|
|
186
189
|
default: typeScaleVars['--text-body-size'],
|
|
187
|
-
'@media (pointer: coarse)':
|
|
190
|
+
'@media (pointer: coarse)': {
|
|
191
|
+
'@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
|
|
192
|
+
},
|
|
188
193
|
},
|
|
189
194
|
lineHeight: typeScaleVars['--text-body-leading'],
|
|
190
195
|
color: colorVars['--color-text-primary'],
|
|
@@ -42,21 +42,34 @@ export const nativePickerSegmentStyles = stylex.create({
|
|
|
42
42
|
borderStyle: 'none',
|
|
43
43
|
padding: 0,
|
|
44
44
|
fontFamily: typographyVars['--font-family-body'],
|
|
45
|
-
// Below 16px iOS zooms the page when the field takes focus.
|
|
45
|
+
// Below 16px iOS zooms the page when the field takes focus. Only iOS
|
|
46
|
+
// WebKit implements -webkit-touch-callout, so the coarse-pointer floor is
|
|
47
|
+
// keyed to iOS alone.
|
|
46
48
|
fontSize: {
|
|
47
49
|
default: typeScaleVars['--text-body-size'],
|
|
48
|
-
'@media (pointer: coarse)':
|
|
50
|
+
'@media (pointer: coarse)': {
|
|
51
|
+
'@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
|
|
52
|
+
},
|
|
49
53
|
},
|
|
50
54
|
lineHeight: typeScaleVars['--text-body-leading'],
|
|
51
55
|
color: colorVars['--color-text-primary'],
|
|
52
56
|
backgroundColor: 'transparent',
|
|
53
57
|
outline: 'none',
|
|
54
58
|
// Native date/time controls size from their internal edit fields. Pin the
|
|
55
|
-
// box to one text line so both segments stay aligned.
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
59
|
+
// box to one text line so both segments stay aligned. The calc fallback
|
|
60
|
+
// mirrors the iOS-only floor above; browsers with `1lh` track it for free.
|
|
61
|
+
height: {
|
|
62
|
+
default: stylex.firstThatWorks(
|
|
63
|
+
'1lh',
|
|
64
|
+
`calc(${typeScaleVars['--text-body-size']} * ${typeScaleVars['--text-body-leading']})`,
|
|
65
|
+
),
|
|
66
|
+
'@media (pointer: coarse)': {
|
|
67
|
+
'@supports (-webkit-touch-callout: none)': stylex.firstThatWorks(
|
|
68
|
+
'1lh',
|
|
69
|
+
`calc(max(1rem, ${typeScaleVars['--text-body-size']}) * ${typeScaleVars['--text-body-leading']})`,
|
|
70
|
+
),
|
|
71
|
+
},
|
|
72
|
+
},
|
|
60
73
|
WebkitAppearance: 'none',
|
|
61
74
|
appearance: 'none',
|
|
62
75
|
// DateTimeInput renders its own calendar/clock affordances.
|
|
@@ -101,9 +114,12 @@ export const nativePickerSegmentStyles = stylex.create({
|
|
|
101
114
|
insetInlineEnd: 0,
|
|
102
115
|
insetBlock: 0,
|
|
103
116
|
display: 'block',
|
|
117
|
+
// The same iOS-only floor as the input it covers, shared baselines.
|
|
104
118
|
fontSize: {
|
|
105
119
|
default: typeScaleVars['--text-body-size'],
|
|
106
|
-
'@media (pointer: coarse)':
|
|
120
|
+
'@media (pointer: coarse)': {
|
|
121
|
+
'@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
|
|
122
|
+
},
|
|
107
123
|
},
|
|
108
124
|
lineHeight: typeScaleVars['--text-body-leading'],
|
|
109
125
|
pointerEvents: 'none',
|
|
@@ -66,6 +66,11 @@ export const docs = {
|
|
|
66
66
|
},
|
|
67
67
|
],
|
|
68
68
|
},
|
|
69
|
+
{
|
|
70
|
+
name: 'endContentEdgeCompensation',
|
|
71
|
+
type: "'inline' | 'block' | 'all'",
|
|
72
|
+
description: 'Selects compensation axes for the end-content slot. Omit to preserve automatic close-action compensation.',
|
|
73
|
+
},
|
|
69
74
|
{
|
|
70
75
|
name: 'hasDivider',
|
|
71
76
|
type: 'boolean',
|
|
@@ -166,6 +171,11 @@ export const docsZh = {
|
|
|
166
171
|
type: 'ReactNode',
|
|
167
172
|
description: '标题之后、关闭按钮之前的内容。',
|
|
168
173
|
},
|
|
174
|
+
{
|
|
175
|
+
name: 'endContentEdgeCompensation',
|
|
176
|
+
type: "'inline' | 'block' | 'all'",
|
|
177
|
+
description: '选择尾部内容插槽的补偿轴;省略时保留关闭操作的自动补偿。',
|
|
178
|
+
},
|
|
169
179
|
{
|
|
170
180
|
name: 'hasDivider',
|
|
171
181
|
type: 'boolean',
|
|
@@ -201,6 +211,8 @@ export const docsDense = {
|
|
|
201
211
|
onOpenChange: 'close button callback (omit=no button)',
|
|
202
212
|
startContent: 'content before title (e.g. back button)',
|
|
203
213
|
endContent: 'content after title, before close button',
|
|
214
|
+
endContentEdgeCompensation:
|
|
215
|
+
'end-content slot axes: inline | block | all; omit=automatic close-action compensation',
|
|
204
216
|
hasDivider: 'bottom border',
|
|
205
217
|
},
|
|
206
218
|
};
|
|
@@ -22,6 +22,17 @@ function generateThemeTestCSS(theme: Parameters<typeof generateThemeCSS>[0]) {
|
|
|
22
22
|
return [prose, component].filter(Boolean).join('\n\n');
|
|
23
23
|
}
|
|
24
24
|
|
|
25
|
+
function getEndSlot(): HTMLElement {
|
|
26
|
+
const child =
|
|
27
|
+
screen.queryByRole('button', {name: 'Action'}) ??
|
|
28
|
+
screen.getByRole('button', {name: /close/i});
|
|
29
|
+
const slot = child.parentElement;
|
|
30
|
+
if (slot == null) {
|
|
31
|
+
throw new Error('Expected DialogHeader end slot');
|
|
32
|
+
}
|
|
33
|
+
return slot;
|
|
34
|
+
}
|
|
35
|
+
|
|
25
36
|
describe('DialogHeader', () => {
|
|
26
37
|
it('renders the title', () => {
|
|
27
38
|
render(<DialogHeader title="My Dialog Title" />);
|
|
@@ -63,6 +74,92 @@ describe('DialogHeader', () => {
|
|
|
63
74
|
expect(screen.getByRole('button', {name: /close/i})).toBeInTheDocument();
|
|
64
75
|
});
|
|
65
76
|
|
|
77
|
+
it('preserves automatic end-slot compensation when the close action renders', () => {
|
|
78
|
+
const {rerender} = render(
|
|
79
|
+
<DialogHeader title="Title" onOpenChange={() => {}} />,
|
|
80
|
+
);
|
|
81
|
+
const automaticClassName = getEndSlot().className;
|
|
82
|
+
|
|
83
|
+
rerender(
|
|
84
|
+
<DialogHeader
|
|
85
|
+
title="Title"
|
|
86
|
+
endContent={<button type="button">Action</button>}
|
|
87
|
+
onOpenChange={() => {}}
|
|
88
|
+
/>,
|
|
89
|
+
);
|
|
90
|
+
expect(getEndSlot().className).toBe(automaticClassName);
|
|
91
|
+
|
|
92
|
+
rerender(
|
|
93
|
+
<DialogHeader
|
|
94
|
+
title="Title"
|
|
95
|
+
endContent={<button type="button">Action</button>}
|
|
96
|
+
/>,
|
|
97
|
+
);
|
|
98
|
+
expect(getEndSlot().className).not.toBe(automaticClassName);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('lets endContentEdgeCompensation select inline, block, or all', () => {
|
|
102
|
+
const {rerender} = render(
|
|
103
|
+
<DialogHeader
|
|
104
|
+
title="Title"
|
|
105
|
+
endContent={<button type="button">Action</button>}
|
|
106
|
+
/>,
|
|
107
|
+
);
|
|
108
|
+
const noCompensationClassName = getEndSlot().className;
|
|
109
|
+
|
|
110
|
+
rerender(
|
|
111
|
+
<DialogHeader
|
|
112
|
+
title="Title"
|
|
113
|
+
endContent={<button type="button">Action</button>}
|
|
114
|
+
endContentEdgeCompensation="inline"
|
|
115
|
+
/>,
|
|
116
|
+
);
|
|
117
|
+
const inlineClassName = getEndSlot().className;
|
|
118
|
+
|
|
119
|
+
rerender(
|
|
120
|
+
<DialogHeader
|
|
121
|
+
title="Title"
|
|
122
|
+
endContent={<button type="button">Action</button>}
|
|
123
|
+
endContentEdgeCompensation="block"
|
|
124
|
+
/>,
|
|
125
|
+
);
|
|
126
|
+
const blockClassName = getEndSlot().className;
|
|
127
|
+
|
|
128
|
+
rerender(
|
|
129
|
+
<DialogHeader
|
|
130
|
+
title="Title"
|
|
131
|
+
endContent={<button type="button">Action</button>}
|
|
132
|
+
endContentEdgeCompensation="all"
|
|
133
|
+
/>,
|
|
134
|
+
);
|
|
135
|
+
const allClassName = getEndSlot().className;
|
|
136
|
+
|
|
137
|
+
expect(inlineClassName).not.toBe(noCompensationClassName);
|
|
138
|
+
expect(blockClassName).not.toBe(noCompensationClassName);
|
|
139
|
+
expect(inlineClassName).not.toBe(blockClassName);
|
|
140
|
+
expect(allClassName).not.toBe(inlineClassName);
|
|
141
|
+
expect(allClassName).not.toBe(blockClassName);
|
|
142
|
+
|
|
143
|
+
rerender(
|
|
144
|
+
<DialogHeader
|
|
145
|
+
title="Title"
|
|
146
|
+
endContent={<button type="button">Action</button>}
|
|
147
|
+
onOpenChange={() => {}}
|
|
148
|
+
/>,
|
|
149
|
+
);
|
|
150
|
+
expect(getEndSlot().className).toBe(allClassName);
|
|
151
|
+
|
|
152
|
+
rerender(
|
|
153
|
+
<DialogHeader
|
|
154
|
+
title="Title"
|
|
155
|
+
endContent={<button type="button">Action</button>}
|
|
156
|
+
endContentEdgeCompensation="inline"
|
|
157
|
+
onOpenChange={() => {}}
|
|
158
|
+
/>,
|
|
159
|
+
);
|
|
160
|
+
expect(getEndSlot().className).toBe(inlineClassName);
|
|
161
|
+
});
|
|
162
|
+
|
|
66
163
|
it('exposes theme targets for the header row, title block, and close icon', () => {
|
|
67
164
|
const {container} = render(
|
|
68
165
|
<DialogHeader
|
|
@@ -37,9 +37,11 @@ const styles = stylex.create({
|
|
|
37
37
|
justifyContent: 'space-between',
|
|
38
38
|
gap: spacingVars['--spacing-3'],
|
|
39
39
|
},
|
|
40
|
-
// Compensate for the icon button's visual padding on the
|
|
41
|
-
|
|
40
|
+
// Compensate for the medium icon button's visual padding on the end slot.
|
|
41
|
+
endBlockEdgeCompensation: {
|
|
42
42
|
marginBlock: `calc(-1 * ${spacingVars['--spacing-2']})`,
|
|
43
|
+
},
|
|
44
|
+
endInlineEdgeCompensation: {
|
|
43
45
|
marginInlineEnd: `calc(-1 * ${spacingVars['--spacing-2']})`,
|
|
44
46
|
},
|
|
45
47
|
titleWrapper: {
|
|
@@ -98,6 +100,14 @@ export interface DialogHeaderProps extends BaseProps<HTMLDivElement> {
|
|
|
98
100
|
*/
|
|
99
101
|
endContent?: ReactNode;
|
|
100
102
|
|
|
103
|
+
/**
|
|
104
|
+
* Overrides automatic end-slot compensation. When omitted, the slot keeps its
|
|
105
|
+
* existing behavior: rendering the close action applies block and logical
|
|
106
|
+
* inline-end compensation. Use `inline`, `block`, or `all` to select the axes
|
|
107
|
+
* explicitly.
|
|
108
|
+
*/
|
|
109
|
+
endContentEdgeCompensation?: 'inline' | 'block' | 'all';
|
|
110
|
+
|
|
101
111
|
/**
|
|
102
112
|
* Adds a themed border at the bottom edge.
|
|
103
113
|
* When false, spacing collapse is applied automatically for seamless visual flow.
|
|
@@ -134,6 +144,7 @@ export function DialogHeader({
|
|
|
134
144
|
onOpenChange,
|
|
135
145
|
startContent,
|
|
136
146
|
endContent,
|
|
147
|
+
endContentEdgeCompensation,
|
|
137
148
|
hasDivider,
|
|
138
149
|
xstyle,
|
|
139
150
|
className,
|
|
@@ -146,6 +157,16 @@ export function DialogHeader({
|
|
|
146
157
|
const dialogContext = useDialogContext();
|
|
147
158
|
const shouldAutoFocus = dialogContext?.isInline !== true;
|
|
148
159
|
const titleId = dialogContext?.titleId;
|
|
160
|
+
const shouldCompensateEndBlock =
|
|
161
|
+
endContentEdgeCompensation == null
|
|
162
|
+
? onOpenChange != null
|
|
163
|
+
: endContentEdgeCompensation === 'block' ||
|
|
164
|
+
endContentEdgeCompensation === 'all';
|
|
165
|
+
const shouldCompensateEndInline =
|
|
166
|
+
endContentEdgeCompensation == null
|
|
167
|
+
? onOpenChange != null
|
|
168
|
+
: endContentEdgeCompensation === 'inline' ||
|
|
169
|
+
endContentEdgeCompensation === 'all';
|
|
149
170
|
|
|
150
171
|
// Auto-focus the title when mounted for screen reader accessibility.
|
|
151
172
|
// Inline dialogs are documentation/showcase previews, so suppress focus to
|
|
@@ -197,7 +218,8 @@ export function DialogHeader({
|
|
|
197
218
|
<div
|
|
198
219
|
{...stylex.props(
|
|
199
220
|
styles.actions,
|
|
200
|
-
|
|
221
|
+
shouldCompensateEndBlock && styles.endBlockEdgeCompensation,
|
|
222
|
+
shouldCompensateEndInline && styles.endInlineEdgeCompensation,
|
|
201
223
|
)}>
|
|
202
224
|
{endContent}
|
|
203
225
|
{onOpenChange && (
|
|
@@ -7,9 +7,9 @@ authority: current
|
|
|
7
7
|
archive_reason: null
|
|
8
8
|
superseded_by: null
|
|
9
9
|
approved_by: cixzhang
|
|
10
|
-
approved_at: 2026-09-
|
|
10
|
+
approved_at: 2026-09-22
|
|
11
11
|
owners: [cixzhang, imdreamrunner]
|
|
12
|
-
review_triggers: [theming, layout]
|
|
12
|
+
review_triggers: [theming, layout, public-api]
|
|
13
13
|
verified_by:
|
|
14
14
|
[
|
|
15
15
|
packages/core/src/Dialog/DialogHeader.test.tsx,
|
|
@@ -17,7 +17,8 @@ verified_by:
|
|
|
17
17
|
scripts/check-knowledge.mjs,
|
|
18
18
|
]
|
|
19
19
|
parent_component: component:Dialog
|
|
20
|
-
references:
|
|
20
|
+
references:
|
|
21
|
+
[architecture:component-theming-surface, architecture:container-padding]
|
|
21
22
|
---
|
|
22
23
|
|
|
23
24
|
# DialogHeader module contract
|
|
@@ -26,13 +27,14 @@ references: [architecture:component-theming-surface]
|
|
|
26
27
|
|
|
27
28
|
`DialogHeader` presents the title region of a Dialog and its optional close
|
|
28
29
|
control. This record owns the stable header-row, title-block, and close-icon
|
|
29
|
-
anatomy
|
|
30
|
+
anatomy, their public theming targets, and the fixed compensation applied to the
|
|
31
|
+
existing end-content slot.
|
|
30
32
|
|
|
31
33
|
## Compatibility and migration
|
|
32
34
|
|
|
33
35
|
- Released default preserved: `yes`
|
|
34
|
-
- Compatibility class: additive
|
|
35
|
-
|
|
36
|
+
- Compatibility class: one additive prop; omitted layout, paint, interaction,
|
|
37
|
+
accessibility, and theming remain unchanged
|
|
36
38
|
- Migration decision: none
|
|
37
39
|
|
|
38
40
|
Consumer migration instructions belong in consumer docs and release notes.
|
|
@@ -43,6 +45,10 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
43
45
|
|
|
44
46
|
- The header row that arranges title content and trailing controls.
|
|
45
47
|
- The title block that groups the title and optional subtitle.
|
|
48
|
+
- The existing end-content wrapper that groups optional trailing content with
|
|
49
|
+
the close action.
|
|
50
|
+
- The fixed end-slot compensation derived from the medium close action's
|
|
51
|
+
transparent inset.
|
|
46
52
|
- The close icon rendered for the optional close action.
|
|
47
53
|
- The `dialog-header`, `dialog-header-title-block`, and
|
|
48
54
|
`dialog-header-close-icon` targets.
|
|
@@ -53,50 +59,65 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
53
59
|
`component:Dialog` and its linked system records.
|
|
54
60
|
- Generic Button or Icon presentation outside this module — owned by those
|
|
55
61
|
components.
|
|
56
|
-
-
|
|
62
|
+
- List-style inherited container-padding compensation, caller-supplied margin
|
|
63
|
+
values, or a general alignment primitive.
|
|
57
64
|
|
|
58
65
|
## Public API and concepts
|
|
59
66
|
|
|
60
|
-
|
|
61
|
-
|
|
67
|
+
This contract preserves the three existing theming surfaces and adds one
|
|
68
|
+
slot-targeted compensation override.
|
|
62
69
|
|
|
63
|
-
| Concept
|
|
64
|
-
|
|
|
65
|
-
| Header row target
|
|
66
|
-
| Title block target
|
|
67
|
-
| Close icon target
|
|
70
|
+
| Concept | Closed values or states | Meaning | Default | Owner | Stability |
|
|
71
|
+
| ---------------------------- | --------------------------------- | ------------------------------------------------------------------------------------- | ----------------------------------------------------- | ---------------------------- | --------- |
|
|
72
|
+
| Header row target | present | Styles the row that arranges title content and controls | Existing row visuals | `module:Dialog/DialogHeader` | stable |
|
|
73
|
+
| Title block target | present | Styles the title/subtitle grouping element | Existing title stack visuals | `module:Dialog/DialogHeader` | stable |
|
|
74
|
+
| Close icon target | present when close action renders | Styles the close glyph itself | Existing medium Icon visuals | `module:Dialog/DialogHeader` | stable |
|
|
75
|
+
| `endContentEdgeCompensation` | `inline`, `block`, `all` | Selects which axes of the existing end-content wrapper receive its fixed compensation | omitted; preserve automatic close-action compensation | `module:Dialog/DialogHeader` | stable |
|
|
76
|
+
|
|
77
|
+
For this slot-targeted prop, `inline` means the slot's logical inline-end edge,
|
|
78
|
+
`block` means both block edges, and `all` combines them.
|
|
68
79
|
|
|
69
80
|
## Behavioral contract
|
|
70
81
|
|
|
71
|
-
| ID
|
|
72
|
-
| --- |
|
|
73
|
-
| FR1 | The header row MUST carry `dialog-header` on the element that applies its row layout and gap.
|
|
74
|
-
| FR2 | The title block MUST carry `dialog-header-title-block` on the element that applies its title/subtitle layout and gap.
|
|
75
|
-
| FR3 | The rendered close Icon MUST carry `dialog-header-close-icon` on the glyph element that applies icon presentation.
|
|
76
|
-
| FR4 | Omitting `onOpenChange` MUST continue to omit the close action and its optional close-icon anatomy.
|
|
82
|
+
| ID | Invariant | Basis | Review state |
|
|
83
|
+
| --- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------ | ------------ |
|
|
84
|
+
| FR1 | The header row MUST carry `dialog-header` on the element that applies its row layout and gap. | Current implementation and owner decision | settled |
|
|
85
|
+
| FR2 | The title block MUST carry `dialog-header-title-block` on the element that applies its title/subtitle layout and gap. | Current implementation and owner decision | settled |
|
|
86
|
+
| FR3 | The rendered close Icon MUST carry `dialog-header-close-icon` on the glyph element that applies icon presentation. | Current implementation and owner decision | settled |
|
|
87
|
+
| FR4 | Omitting `onOpenChange` MUST continue to omit the close action and its optional close-icon anatomy. | Released behavior | settled |
|
|
88
|
+
| FR5 | The existing end wrapper MUST continue to group optional `endContent` with the optional close action; this change MUST NOT add another wrapper. | Current implementation | settled |
|
|
89
|
+
| FR6 | When `endContentEdgeCompensation` is omitted, rendering the close action MUST preserve the released fixed negative block and logical inline-end inset, whether or not `endContent` is present. Without the close action, no automatic compensation applies. | Released behavior and owner decision | settled |
|
|
90
|
+
| FR7 | Explicit `inline` MUST apply only logical inline-end compensation; `block` MUST apply only both block edges; `all` MUST apply both. The explicit value overrides the automatic close-action selection. | `module:Dialog/DialogHeader/DEC-2` | settled |
|
|
91
|
+
| FR8 | Compensation MUST use logical inline properties, preserve title, slot, and close-action semantics and hit targets, and expose no caller-controlled margin amount. | `architecture:container-padding`; owner decision | settled |
|
|
77
92
|
|
|
78
93
|
### Transformation and precedence order
|
|
79
94
|
|
|
80
|
-
|
|
81
|
-
|
|
95
|
+
1. If `endContentEdgeCompensation` is present, its closed value selects the
|
|
96
|
+
compensated axes.
|
|
97
|
+
2. Otherwise, a rendered close action selects `all`; omission of the close
|
|
98
|
+
action selects no compensation.
|
|
99
|
+
3. The module applies each existing theme target to its owning element before
|
|
100
|
+
normal theme CSS resolves through the shared theming pipeline.
|
|
82
101
|
|
|
83
102
|
### Performance and resources
|
|
84
103
|
|
|
85
|
-
- The additive
|
|
86
|
-
measurement, or asynchronous resource.
|
|
104
|
+
- The additive closed-value branch and class selection introduce no listener,
|
|
105
|
+
observer, timer, measurement, or asynchronous resource.
|
|
87
106
|
|
|
88
107
|
## Accessibility contract
|
|
89
108
|
|
|
90
|
-
-
|
|
91
|
-
|
|
109
|
+
- Compensation MUST NOT change the title's role, focus behavior, dialog naming,
|
|
110
|
+
the close button's accessible name and operation, or any slot child's hit
|
|
111
|
+
target.
|
|
92
112
|
|
|
93
113
|
## Design relationships
|
|
94
114
|
|
|
95
|
-
| Anatomy or state | Design requirement
|
|
96
|
-
|
|
|
97
|
-
| Header row
|
|
98
|
-
| Title block
|
|
99
|
-
|
|
|
115
|
+
| Anatomy or state | Design requirement | Representation authority | Module contract |
|
|
116
|
+
| ---------------- | ---------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------- | --------------- |
|
|
117
|
+
| Header row | Owns arrangement and spacing among title content and controls. | This module | FR1 |
|
|
118
|
+
| Title block | Owns title/subtitle grouping and spacing. | This module | FR2 |
|
|
119
|
+
| End content | Owns the existing trailing wrapper containing optional end content and the close action, including its fixed slot-targeted compensation. | This module | FR4–FR8 |
|
|
120
|
+
| Close icon | Owns the close glyph's visual box inside the Button-owned action. | This module with Icon rendering | FR3, FR4 |
|
|
100
121
|
|
|
101
122
|
### Theming anatomy
|
|
102
123
|
|
|
@@ -115,20 +136,25 @@ existing anatomy.
|
|
|
115
136
|
- `component:Dialog` owns modal behavior and the aggregate Dialog contract.
|
|
116
137
|
- `component:Layout` owns the composed LayoutHeader region outside the three
|
|
117
138
|
module-owned inner parts.
|
|
118
|
-
- `component:Button` owns the close action's control behavior
|
|
119
|
-
presentation.
|
|
139
|
+
- `component:Button` owns the close action's control behavior, hit target, and
|
|
140
|
+
outer presentation.
|
|
120
141
|
- `component:Icon` renders the glyph; this module guarantees a distinct target
|
|
121
142
|
for the close icon's DialogHeader-specific visual contract.
|
|
122
143
|
- `architecture:component-theming-surface` owns target qualification, anatomy
|
|
123
144
|
mapping, and the requirement that each target sits on its painter.
|
|
145
|
+
- `architecture:container-padding` defines the retained-inset edge-compensation
|
|
146
|
+
intent and distinguishes this slot-targeted projection from List-style
|
|
147
|
+
inherited-inset self-compensation and full bleed.
|
|
124
148
|
|
|
125
149
|
## Verification map
|
|
126
150
|
|
|
127
|
-
| Contract
|
|
128
|
-
|
|
|
129
|
-
| FR1–FR3
|
|
130
|
-
| FR4
|
|
131
|
-
|
|
|
151
|
+
| Contract | Verification | Representative states | Mutation or failure expectation |
|
|
152
|
+
| ------------------- | ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------- |
|
|
153
|
+
| FR1–FR3 | Existing target tests, target inventory, generated probe theme, and source inspection | title only, title/subtitle, close action | An existing target is removed or moved away from its owning painter. |
|
|
154
|
+
| FR4–FR5 | Existing content and close-button tests | end content only; close only; both | The close action or slot content disappears, reorders, or gains another wrapper. |
|
|
155
|
+
| FR6–FR7 | Focused end-slot class-selection assertions | close only; end content only; both; explicit `inline`, `block`, and `all` | An omitted prop changes released geometry, or an explicit value selects the wrong axes. |
|
|
156
|
+
| FR8 | Source inspection, RTL CI, interaction tests, and focused real-browser geometry | LTR and RTL; custom end control; close action | Physical margins, caller-controlled amounts, or hit-target changes enter the implementation. |
|
|
157
|
+
| Theming anatomy map | `scripts/check-knowledge.mjs` | all three module anatomy entries and targets | Anatomy, docs, runtime targets, and the module map drift. |
|
|
132
158
|
|
|
133
159
|
## Decision log
|
|
134
160
|
|
|
@@ -141,6 +167,17 @@ Each public target represents documented anatomy and is applied to the element
|
|
|
141
167
|
that owns the corresponding visuals. The header row, title block, and close icon
|
|
142
168
|
meet that admission rule and are approved as additive targets.
|
|
143
169
|
|
|
170
|
+
### DEC-2 — End-content compensation is slot-targeted and explicit
|
|
171
|
+
|
|
172
|
+
**Reference:** `module:Dialog/DialogHeader/DEC-2`
|
|
173
|
+
**Decider:** cixzhang, 2026-09-22
|
|
174
|
+
|
|
175
|
+
DialogHeader preserves its released automatic compensation whenever the close
|
|
176
|
+
action renders. `endContentEdgeCompensation` targets the existing end-content
|
|
177
|
+
slot and selects `inline`, `block`, or `all` without exposing a margin amount.
|
|
178
|
+
This is a slot-targeted projection of the retained-inset edge-compensation
|
|
179
|
+
intent; it does not make DialogHeader a List-style inherited-padding consumer.
|
|
180
|
+
|
|
144
181
|
## Open questions
|
|
145
182
|
|
|
146
183
|
None.
|
|
@@ -8,8 +8,8 @@
|
|
|
8
8
|
* @output Unit tests for the shared clear-button primitive
|
|
9
9
|
* @position Testing; validates InputClearButton.tsx — the single home for the
|
|
10
10
|
* clearable input family's clear (✕) affordance and its theme target. Covers
|
|
11
|
-
* the accessible name,
|
|
12
|
-
* both theme targets,
|
|
11
|
+
* the accessible name, contextual hover tooltip, click callback, decorative
|
|
12
|
+
* registry glyph, both theme targets, touch hit area, and xstyle forwarding.
|
|
13
13
|
*
|
|
14
14
|
* SYNC: When InputClearButton.tsx changes, update tests to match new behavior.
|
|
15
15
|
*/
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
import {readFileSync} from 'node:fs';
|
|
18
18
|
import path from 'node:path';
|
|
19
19
|
import {describe, it, expect, vi, afterEach} from 'vitest';
|
|
20
|
-
import {render, screen, fireEvent} from '@testing-library/react';
|
|
20
|
+
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
21
21
|
import * as stylex from '@stylexjs/stylex';
|
|
22
22
|
import {
|
|
23
23
|
InputClearButton,
|
|
@@ -95,6 +95,20 @@ describe('InputClearButton public props', () => {
|
|
|
95
95
|
});
|
|
96
96
|
|
|
97
97
|
describe('InputClearButton', () => {
|
|
98
|
+
it('uses the contextual label for the tooltip and accessible name', async () => {
|
|
99
|
+
const showPopover = vi.spyOn(HTMLElement.prototype, 'showPopover');
|
|
100
|
+
render(<InputClearButton label="Clear Search" onClick={() => {}} />);
|
|
101
|
+
|
|
102
|
+
const button = screen.getByRole('button', {name: 'Clear Search'});
|
|
103
|
+
const tooltip = screen.getByRole('tooltip', {hidden: true});
|
|
104
|
+
expect(tooltip).toHaveTextContent(/^Clear Search$/);
|
|
105
|
+
expect(button.getAttribute('aria-describedby')).toBe(tooltip.id);
|
|
106
|
+
|
|
107
|
+
fireEvent.mouseEnter(button);
|
|
108
|
+
await waitFor(() => expect(showPopover).toHaveBeenCalled());
|
|
109
|
+
showPopover.mockRestore();
|
|
110
|
+
});
|
|
111
|
+
|
|
98
112
|
it('renders a real button with the given accessible label', () => {
|
|
99
113
|
render(<InputClearButton label="Clear" onClick={() => {}} />);
|
|
100
114
|
const button = screen.getByRole('button', {name: 'Clear'});
|
|
@@ -4,8 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* @file InputClearButton.tsx
|
|
7
|
-
* @input Uses React, Button, Icon
|
|
8
|
-
* @output Exports the public InputClearButton and an internal popup-aware variant
|
|
7
|
+
* @input Uses React, Button, and Icon
|
|
8
|
+
* @output Exports the public InputClearButton and an internal popup-aware variant,
|
|
9
|
+
* both with a contextual tooltip matching their required label.
|
|
9
10
|
* @position Shared primitive. Every input that renders a clear affordance —
|
|
10
11
|
* TextInput, NumberInput, TimeInput, DateInput, DateTimeInput,
|
|
11
12
|
* DateRangeInput, Selector, MultiSelector, Typeahead, Tokenizer, FileInput —
|
|
@@ -66,6 +67,7 @@ const styles = stylex.create({
|
|
|
66
67
|
});
|
|
67
68
|
|
|
68
69
|
export interface InputClearButtonProps {
|
|
70
|
+
/** Contextual accessible name for the button, such as "Clear Search". */
|
|
69
71
|
label: string;
|
|
70
72
|
onClick: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
|
71
73
|
xstyle?: stylex.StyleXStyles;
|
|
@@ -104,6 +106,7 @@ function renderInputClearButton({
|
|
|
104
106
|
variant="ghost"
|
|
105
107
|
size="sm"
|
|
106
108
|
label={label}
|
|
109
|
+
tooltip={label}
|
|
107
110
|
className={buttonTargetClassName}
|
|
108
111
|
icon={
|
|
109
112
|
<Icon
|
|
@@ -119,10 +119,13 @@ const styles = stylex.create({
|
|
|
119
119
|
color: colorVars['--color-text-primary'],
|
|
120
120
|
fontFamily: typographyVars['--font-family-body'],
|
|
121
121
|
// Matches the option rows below it, so the query reads as the first line of
|
|
122
|
-
// the list. The
|
|
122
|
+
// the list. The floor keeps iOS from zooming on focus — keyed to iOS
|
|
123
|
+
// alone, since only iOS WebKit implements -webkit-touch-callout.
|
|
123
124
|
fontSize: {
|
|
124
125
|
default: typeScaleVars['--text-label-size'],
|
|
125
|
-
'@media (pointer: coarse)':
|
|
126
|
+
'@media (pointer: coarse)': {
|
|
127
|
+
'@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-label-size']})`,
|
|
128
|
+
},
|
|
126
129
|
},
|
|
127
130
|
lineHeight: typeScaleVars['--text-label-leading'],
|
|
128
131
|
// The field draws the focus ring (see `field`), so the bare input must not
|
|
@@ -256,7 +256,7 @@ export const CORE_STATUS_MESSAGE_BINDING_STATES = [
|
|
|
256
256
|
minValue: 0,
|
|
257
257
|
maxValue: 100,
|
|
258
258
|
},
|
|
259
|
-
focusSelector: '[
|
|
259
|
+
focusSelector: '[tabindex="0"]',
|
|
260
260
|
storyId: 'a11y-status-message-pattern--progress-mark-focused-update',
|
|
261
261
|
},
|
|
262
262
|
] as const satisfies ReadonlyArray<CoreStatusMessageBindingDefinition>;
|
|
@@ -231,9 +231,14 @@ const styles = stylex.create({
|
|
|
231
231
|
},
|
|
232
232
|
placeholderText: {
|
|
233
233
|
fontFamily: typographyVars['--font-family-body'],
|
|
234
|
+
// The 16px floor is iOS-only: iOS Safari zooms the page when a focused
|
|
235
|
+
// control sits under 16px, and only iOS WebKit implements
|
|
236
|
+
// -webkit-touch-callout to key the coarse-pointer floor to it.
|
|
234
237
|
fontSize: {
|
|
235
238
|
default: typeScaleVars['--text-body-size'],
|
|
236
|
-
'@media (pointer: coarse)':
|
|
239
|
+
'@media (pointer: coarse)': {
|
|
240
|
+
'@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
|
|
241
|
+
},
|
|
237
242
|
},
|
|
238
243
|
lineHeight: typeScaleVars['--text-body-leading'],
|
|
239
244
|
color: colorVars['--color-text-secondary'],
|
|
@@ -242,9 +247,13 @@ const styles = stylex.create({
|
|
|
242
247
|
},
|
|
243
248
|
fileNameText: {
|
|
244
249
|
fontFamily: typographyVars['--font-family-body'],
|
|
250
|
+
// ...and the filename beside it keeps the same floor, so both lines the
|
|
251
|
+
// control shows stay the same size.
|
|
245
252
|
fontSize: {
|
|
246
253
|
default: typeScaleVars['--text-body-size'],
|
|
247
|
-
'@media (pointer: coarse)':
|
|
254
|
+
'@media (pointer: coarse)': {
|
|
255
|
+
'@supports (-webkit-touch-callout: none)': `max(1rem, ${typeScaleVars['--text-body-size']})`,
|
|
256
|
+
},
|
|
248
257
|
},
|
|
249
258
|
lineHeight: typeScaleVars['--text-body-leading'],
|
|
250
259
|
color: colorVars['--color-text-primary'],
|