@astryxdesign/core 0.6.2 → 0.6.3-canary.039a67e
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/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +33 -12
- 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/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +13 -28
- 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/ChatLayout.d.ts +19 -0
- package/dist/Chat/ChatLayout.d.ts.map +1 -1
- package/dist/Chat/ChatLayout.js +19 -0
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +44 -34
- package/dist/Chat/ChatMessageBubble.d.ts +2 -0
- package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.js +5 -3
- package/dist/Chat/ChatMessageList.d.ts +2 -1
- package/dist/Chat/ChatMessageList.d.ts.map +1 -1
- package/dist/Chat/ChatMessageList.js +4 -3
- package/dist/Chat/ChatMessageMetadata.d.ts +5 -4
- package/dist/Chat/ChatMessageMetadata.d.ts.map +1 -1
- package/dist/Chat/ChatMessageMetadata.js +12 -9
- package/dist/Chat/ChatSendButton.d.ts +2 -1
- package/dist/Chat/ChatSendButton.d.ts.map +1 -1
- package/dist/Chat/ChatSendButton.js +6 -4
- package/dist/Chat/ChatSystemMessage.d.ts +3 -3
- package/dist/Chat/ChatSystemMessage.d.ts.map +1 -1
- package/dist/Chat/ChatSystemMessage.js +2 -2
- package/dist/Chat/ChatTokenizedText.d.ts +6 -6
- package/dist/Chat/ChatTokenizedText.js +10 -6
- package/dist/Chat/ChatToolCalls.d.ts +7 -9
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +43 -26
- 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/Citation/Citation.d.ts +1 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +3 -2
- package/dist/CodeBlock/highlightRanges.d.ts.map +1 -1
- package/dist/CodeBlock/highlightRanges.js +14 -3
- 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 +25 -5
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +29 -17
- 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/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +4 -4
- package/dist/DateTimeInput/DateTimeInput.d.ts +32 -15
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +55 -30
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -1
- package/dist/DateTimeInput/TouchDateTimeField.js +4 -4
- package/dist/DateTimeInput/index.d.ts +1 -1
- package/dist/DateTimeInput/index.d.ts.map +1 -1
- 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 +13 -4
- 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/Icon/Icon.d.ts +6 -31
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +8 -71
- package/dist/Icon/IconDefaultSizeContext.d.ts +4 -0
- package/dist/Icon/IconDefaultSizeContext.d.ts.map +1 -0
- package/dist/Icon/IconDefaultSizeContext.js +18 -0
- package/dist/Icon/IconSize.stylex.d.ts +65 -0
- package/dist/Icon/IconSize.stylex.d.ts.map +1 -0
- package/dist/Icon/IconSize.stylex.js +75 -0
- package/dist/Item/Item.d.ts +1 -1
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +4 -3
- 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/Link/useLinkComponent.d.ts +5 -15
- package/dist/Link/useLinkComponent.d.ts.map +1 -1
- package/dist/Link/useLinkComponent.js +34 -51
- package/dist/List/List.d.ts +19 -1
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +9 -2
- package/dist/List/ListContext.d.ts +1 -0
- package/dist/List/ListContext.d.ts.map +1 -1
- package/dist/List/ListContext.js +2 -1
- package/dist/List/ListItem.d.ts +1 -1
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +9 -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 +726 -177
- 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 +17 -0
- package/dist/Markdown/plugins/index.d.ts.map +1 -0
- package/dist/Markdown/plugins/index.js +14 -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/softBreaks.d.ts +3 -0
- package/dist/Markdown/plugins/softBreaks.d.ts.map +1 -0
- package/dist/Markdown/plugins/softBreaks.js +172 -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 +6 -0
- package/dist/Markdown/url.d.ts.map +1 -0
- package/dist/Markdown/url.js +31 -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/MetadataList/MetadataList.js +3 -3
- 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/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +5 -0
- 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/ScrollableArea/ScrollableArea.d.ts +1 -0
- package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -1
- package/dist/ScrollableArea/ScrollableArea.js +1 -0
- package/dist/SegmentedControl/SegmentedControl.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControl.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControl.js +1 -0
- 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 +16 -7
- 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 +30 -14
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +61 -13
- package/dist/TimeInput/TouchTimeField.d.ts +11 -0
- package/dist/TimeInput/TouchTimeField.d.ts.map +1 -0
- package/dist/TimeInput/TouchTimeField.js +417 -0
- package/dist/TimeInput/index.d.ts +1 -1
- package/dist/TimeInput/index.d.ts.map +1 -1
- package/dist/Timer/Timer.d.ts +49 -0
- package/dist/Timer/Timer.d.ts.map +1 -0
- package/dist/Timer/Timer.js +158 -0
- package/dist/Timer/index.d.ts +9 -0
- package/dist/Timer/index.d.ts.map +1 -0
- package/dist/Timer/index.js +10 -0
- 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/TopNav/TopNavMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +3 -2
- 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 +27 -11
- 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/useClickableContainer.d.ts +10 -1
- package/dist/hooks/useClickableContainer.d.ts.map +1 -1
- package/dist/hooks/useClickableContainer.js +15 -4
- 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/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -0
- package/dist/theme/declarationBoundary.d.ts +17 -0
- package/dist/theme/declarationBoundary.d.ts.map +1 -0
- package/dist/theme/declarationBoundary.js +343 -0
- package/dist/theme/defineTheme.d.ts +3 -0
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +4 -1
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +4 -0
- package/dist/theme/generateThemeRules.d.ts +15 -7
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +143 -35
- package/dist/theme/themeAdaptations.d.ts +5 -3
- package/dist/theme/themeAdaptations.d.ts.map +1 -1
- package/dist/theme/themeAdaptations.js +33 -5
- package/dist/utils/inputPresentation.d.ts +55 -0
- package/dist/utils/inputPresentation.d.ts.map +1 -0
- package/dist/utils/inputPresentation.js +108 -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/dist/utils/safeUrl.d.ts +11 -0
- package/dist/utils/safeUrl.d.ts.map +1 -0
- package/dist/utils/safeUrl.js +78 -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 +24 -4
- package/src/Avatar/Avatar.doc.mjs +1 -1
- package/src/Avatar/Avatar.test.tsx +30 -0
- package/src/Avatar/Avatar.tsx +38 -14
- 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/Button.doc.mjs +5 -5
- package/src/Button/Button.tsx +15 -13
- 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/ChatLayout.doc.mjs +12 -4
- package/src/Chat/ChatLayout.spec.md +271 -0
- package/src/Chat/ChatLayout.test.tsx +28 -0
- package/src/Chat/ChatLayout.tsx +19 -0
- package/src/Chat/ChatLayoutScrollButton.spec.md +338 -0
- package/src/Chat/ChatLayoutScrollButton.test.tsx +31 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +31 -14
- package/src/Chat/ChatMessageBubble.doc.mjs +28 -15
- package/src/Chat/ChatMessageBubble.spec.md +263 -0
- package/src/Chat/ChatMessageBubble.test.tsx +93 -0
- package/src/Chat/ChatMessageBubble.tsx +8 -3
- package/src/Chat/ChatMessageList.spec.md +222 -0
- package/src/Chat/ChatMessageList.test.tsx +64 -2
- package/src/Chat/ChatMessageList.tsx +4 -3
- package/src/Chat/ChatMessageMetadata.doc.mjs +57 -3
- package/src/Chat/ChatMessageMetadata.spec.md +220 -0
- package/src/Chat/ChatMessageMetadata.test.tsx +34 -0
- package/src/Chat/ChatMessageMetadata.tsx +13 -13
- package/src/Chat/ChatSendButton.doc.mjs +32 -0
- package/src/Chat/ChatSendButton.spec.md +227 -0
- package/src/Chat/ChatSendButton.test.tsx +128 -8
- package/src/Chat/ChatSendButton.tsx +6 -4
- package/src/Chat/ChatSystemMessage.doc.mjs +115 -12
- package/src/Chat/ChatSystemMessage.spec.md +225 -0
- package/src/Chat/ChatSystemMessage.test.tsx +112 -20
- package/src/Chat/ChatSystemMessage.tsx +4 -6
- package/src/Chat/ChatTokenizedText.doc.mjs +96 -9
- package/src/Chat/ChatTokenizedText.spec.md +190 -0
- package/src/Chat/ChatTokenizedText.test.tsx +60 -1
- package/src/Chat/ChatTokenizedText.tsx +14 -8
- package/src/Chat/ChatToolCalls.doc.mjs +4 -1
- package/src/Chat/ChatToolCalls.spec.md +194 -0
- package/src/Chat/ChatToolCalls.test.tsx +83 -0
- package/src/Chat/ChatToolCalls.tsx +46 -21
- package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +514 -0
- package/src/Chat/__tests__/ChatLayoutScrollButtonSurface.a11y.chromium.spec.ts +740 -0
- package/src/Chat/__tests__/ChatMessageBubble.a11y.chromium.spec.ts +457 -0
- package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.test.ts +91 -0
- package/src/Chat/__tests__/ChatMessageBubble.auditProvenance.ts +91 -0
- package/src/Chat/__tests__/ChatMessageList.a11y.chromium.spec.ts +456 -0
- package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +413 -0
- package/src/Chat/__tests__/ChatSendButton.a11y.chromium.spec.ts +1522 -0
- package/src/Chat/__tests__/ChatSystemMessage.a11y.chromium.spec.ts +1004 -0
- package/src/Chat/__tests__/ChatTokenizedText.a11y.chromium.spec.ts +573 -0
- 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/Citation/Citation.doc.mjs +2 -2
- package/src/Citation/Citation.test.tsx +17 -0
- package/src/Citation/Citation.tsx +4 -2
- package/src/ClickableCard/ClickableCard.doc.mjs +2 -2
- package/src/ClickableCard/ClickableCard.test.tsx +102 -5
- package/src/CodeBlock/highlightRanges.test.ts +143 -1
- package/src/CodeBlock/highlightRanges.ts +15 -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.doc.mjs +38 -9
- package/src/DateInput/DateInput.tsx +59 -17
- package/src/DateInput/NativeDateField.tsx +24 -8
- package/src/DateInput/Presentation.test.tsx +121 -0
- package/src/DateInput/TouchDateField.tsx +6 -2
- package/src/DateInput/index.ts +1 -0
- package/src/DateRangeInput/DateRangeInput.tsx +6 -1
- package/src/DateTimeInput/DateTimeInput.doc.mjs +28 -12
- package/src/DateTimeInput/DateTimeInput.tsx +93 -37
- package/src/DateTimeInput/Presentation.test.tsx +89 -0
- package/src/DateTimeInput/TouchDateTimeField.tsx +6 -1
- package/src/DateTimeInput/index.ts +1 -0
- package/src/DateTimeInput/nativePickerSegmentStyles.ts +24 -8
- package/src/Dialog/Dialog.doc.mjs +2 -0
- package/src/Dialog/DialogHeader.doc.mjs +22 -0
- package/src/Dialog/DialogHeader.test.tsx +167 -3
- package/src/Dialog/DialogHeader.tsx +37 -6
- package/src/Dialog/modules/DialogHeader.spec.md +101 -42
- package/src/DropdownMenu/DropdownMenu.test.tsx +5 -2
- 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/Icon/Icon.doc.mjs +7 -5
- package/src/Icon/Icon.spec.md +81 -40
- package/src/Icon/Icon.test.tsx +6 -3
- package/src/Icon/Icon.tsx +20 -68
- package/src/Icon/IconDefaultSizeContext.ts +23 -0
- package/src/Icon/IconSize.stylex.ts +70 -0
- package/src/IconButton/IconButton.doc.mjs +3 -3
- package/src/IconButton/IconButton.test.tsx +40 -0
- package/src/Item/Item.doc.mjs +6 -2
- package/src/Item/Item.tsx +9 -3
- 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 +17 -4
- package/src/Link/Link.test.tsx +24 -0
- package/src/Link/Link.tsx +5 -0
- package/src/Link/LinkProvider.doc.mjs +2 -2
- package/src/Link/__tests__/Link.navigation.a11y.chromium.spec.ts +261 -0
- package/src/Link/useLinkComponent.test.tsx +333 -0
- package/src/Link/useLinkComponent.ts +29 -57
- package/src/List/List.doc.mjs +6 -0
- package/src/List/List.spec.md +200 -0
- package/src/List/List.test.tsx +117 -1
- package/src/List/List.tsx +22 -2
- package/src/List/ListContext.tsx +3 -1
- package/src/List/ListItem.doc.mjs +2 -2
- package/src/List/ListItem.source-build.test.mjs +41 -0
- package/src/List/ListItem.tsx +26 -2
- package/src/Markdown/Markdown.doc.mjs +300 -2
- 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 +130 -3
- package/src/Markdown/Markdown.renderBoundary.test.tsx +72 -0
- package/src/Markdown/Markdown.spec.md +210 -45
- package/src/Markdown/Markdown.test.tsx +87 -3
- 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 +43 -0
- package/src/Markdown/index.ts +37 -1
- package/src/Markdown/modules/remark.spec.md +269 -0
- package/src/Markdown/modules/softBreaks.spec.md +137 -0
- package/src/Markdown/parser/index.ts +64 -0
- package/src/Markdown/parser.public.test.ts +103 -0
- package/src/Markdown/parser.test.ts +38 -6
- package/src/Markdown/parser.ts +1221 -242
- package/src/Markdown/plugins/frontmatter.test.tsx +125 -0
- package/src/Markdown/plugins/frontmatter.ts +198 -0
- package/src/Markdown/plugins/index.ts +54 -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/softBreaks.test.tsx +172 -0
- package/src/Markdown/plugins/softBreaks.ts +169 -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 +36 -0
- package/src/Markdown/utils.ts +13 -1
- package/src/MetadataList/MetadataList.test.tsx +4 -2
- package/src/MetadataList/MetadataList.tsx +3 -3
- 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/PowerSearch/PowerSearchValueEditor.test.tsx +51 -0
- package/src/PowerSearch/PowerSearchValueEditor.tsx +4 -0
- 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/ScrollableArea.tsx +1 -0
- package/src/ScrollableArea/modules/useScrollableArea.spec.md +50 -22
- package/src/SegmentedControl/SegmentedControl.doc.mjs +2 -2
- package/src/SegmentedControl/SegmentedControl.test.tsx +61 -0
- package/src/SegmentedControl/SegmentedControl.tsx +2 -1
- package/src/SegmentedControl/SegmentedControlItem.tsx +6 -9
- package/src/Selector/Selector.doc.mjs +3 -3
- package/src/Selector/Selector.spec.md +51 -49
- package/src/Selector/Selector.test.tsx +61 -55
- package/src/Selector/Selector.tsx +34 -15
- 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.a11y.chromium.spec.ts +45 -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/NativeTimeInput.test.tsx +36 -3
- package/src/TimeInput/Presentation.test.tsx +148 -0
- package/src/TimeInput/TimeInput.doc.mjs +21 -5
- package/src/TimeInput/TimeInput.tsx +102 -11
- package/src/TimeInput/TouchTimeField.tsx +572 -0
- package/src/TimeInput/index.ts +1 -0
- package/src/Timer/Timer.doc.mjs +183 -0
- package/src/Timer/Timer.spec.md +215 -0
- package/src/Timer/Timer.test.tsx +302 -0
- package/src/Timer/Timer.tsx +258 -0
- package/src/Timer/index.ts +11 -0
- 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/Token/Token.doc.mjs +2 -2
- package/src/Tokenizer/Tokenizer.spec.md +142 -75
- package/src/TopNav/TopNavMenu.doc.mjs +2 -2
- package/src/TopNav/TopNavMenu.test.tsx +30 -0
- package/src/TopNav/TopNavMenu.tsx +7 -2
- 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/useClickableContainer.test.tsx +236 -0
- package/src/hooks/useClickableContainer.ts +20 -4
- 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/index.ts +3 -0
- package/src/inputFontFloor.test.ts +106 -0
- package/src/tailwind-theme.css +0 -6
- package/src/theme/Theme.test.tsx +32 -0
- package/src/theme/declarationBoundary.test.ts +126 -0
- package/src/theme/declarationBoundary.ts +347 -0
- package/src/theme/defineTheme.ts +4 -0
- package/src/theme/derivedVarRegistry.test.ts +7 -0
- package/src/theme/derivedVarRegistry.ts +1 -0
- package/src/theme/generateThemeRules.test.ts +526 -1
- package/src/theme/generateThemeRules.ts +231 -50
- package/src/theme/themeAdaptations.test.ts +211 -1
- package/src/theme/themeAdaptations.ts +50 -4
- package/src/theme/tokenValueCompat.test.ts +4 -1
- package/src/utils/inputPresentation.ts +143 -0
- package/src/utils/interactionOverlay.stylex.ts +20 -0
- package/src/utils/safeUrl.test.ts +88 -0
- package/src/utils/safeUrl.ts +85 -0
|
@@ -13,6 +13,10 @@ import {useState} from 'react';
|
|
|
13
13
|
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
14
14
|
import {render, screen, act, fireEvent, waitFor} from '@testing-library/react';
|
|
15
15
|
import userEvent from '@testing-library/user-event';
|
|
16
|
+
import {
|
|
17
|
+
declaresPressedOverlay,
|
|
18
|
+
rulesDeclaredFor,
|
|
19
|
+
} from '../__tests__/pressState';
|
|
16
20
|
import * as stylex from '@stylexjs/stylex';
|
|
17
21
|
import {Slider} from './Slider';
|
|
18
22
|
import {focusOutlineStyles} from '../utils/focusOutline.stylex';
|
|
@@ -727,6 +731,96 @@ describe('Slider', () => {
|
|
|
727
731
|
expect(handleChange).toHaveBeenCalledWith(100);
|
|
728
732
|
});
|
|
729
733
|
|
|
734
|
+
// --- Marks color ---
|
|
735
|
+
|
|
736
|
+
/** Whether the element has an unconditional rule painting a token. */
|
|
737
|
+
function declaresColorToken(el: Element, token: string): boolean {
|
|
738
|
+
return rulesDeclaredFor(el).some(rule => {
|
|
739
|
+
const selector = rule
|
|
740
|
+
.slice(0, rule.indexOf('{'))
|
|
741
|
+
.replaceAll(':not(#\\#)', '');
|
|
742
|
+
return !selector.includes(':') && rule.includes(`var(${token})`);
|
|
743
|
+
});
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
it('uses the track color for unfilled marks and the accent for filled marks', () => {
|
|
747
|
+
render(
|
|
748
|
+
<Slider
|
|
749
|
+
label="Volume"
|
|
750
|
+
value={50}
|
|
751
|
+
min={0}
|
|
752
|
+
max={100}
|
|
753
|
+
marks={[{value: 25}, {value: 75}]}
|
|
754
|
+
/>,
|
|
755
|
+
);
|
|
756
|
+
const marks = screen.getAllByTestId('slider-mark');
|
|
757
|
+
|
|
758
|
+
expect(marks).toHaveLength(2);
|
|
759
|
+
expect(declaresColorToken(marks[0], '--color-track')).toBe(false);
|
|
760
|
+
expect(declaresColorToken(marks[0], '--color-accent')).toBe(true);
|
|
761
|
+
expect(declaresColorToken(marks[1], '--color-track')).toBe(true);
|
|
762
|
+
expect(declaresColorToken(marks[1], '--color-accent')).toBe(false);
|
|
763
|
+
});
|
|
764
|
+
|
|
765
|
+
function declaresFillColor(el: Element): boolean {
|
|
766
|
+
return declaresColorToken(el, '--color-accent');
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
it('colors marks at or behind the thumb with the fill color', () => {
|
|
770
|
+
render(
|
|
771
|
+
<Slider
|
|
772
|
+
label="Volume"
|
|
773
|
+
value={50}
|
|
774
|
+
min={0}
|
|
775
|
+
max={100}
|
|
776
|
+
marks={[
|
|
777
|
+
{value: 0},
|
|
778
|
+
{value: 25},
|
|
779
|
+
{value: 50},
|
|
780
|
+
{value: 75},
|
|
781
|
+
{value: 100},
|
|
782
|
+
]}
|
|
783
|
+
/>,
|
|
784
|
+
);
|
|
785
|
+
const marks = screen.getAllByTestId('slider-mark');
|
|
786
|
+
expect(marks).toHaveLength(5);
|
|
787
|
+
// Marks at 0, 25, and 50 sit at or behind the thumb: fill color.
|
|
788
|
+
expect(declaresFillColor(marks[0])).toBe(true);
|
|
789
|
+
expect(declaresFillColor(marks[1])).toBe(true);
|
|
790
|
+
expect(declaresFillColor(marks[2])).toBe(true);
|
|
791
|
+
// Marks at 75 and 100 sit ahead of the thumb: default mark color.
|
|
792
|
+
expect(declaresFillColor(marks[3])).toBe(false);
|
|
793
|
+
expect(declaresFillColor(marks[4])).toBe(false);
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
it('colors marks between the thumbs with the fill color in range mode', () => {
|
|
797
|
+
render(
|
|
798
|
+
<Slider
|
|
799
|
+
label="Price range"
|
|
800
|
+
value={[20, 80] as [number, number]}
|
|
801
|
+
min={0}
|
|
802
|
+
max={100}
|
|
803
|
+
marks={[
|
|
804
|
+
{value: 0},
|
|
805
|
+
{value: 20},
|
|
806
|
+
{value: 50},
|
|
807
|
+
{value: 80},
|
|
808
|
+
{value: 100},
|
|
809
|
+
]}
|
|
810
|
+
/>,
|
|
811
|
+
);
|
|
812
|
+
const marks = screen.getAllByTestId('slider-mark');
|
|
813
|
+
expect(marks).toHaveLength(5);
|
|
814
|
+
// The mark at 0 sits before the range: default mark color.
|
|
815
|
+
expect(declaresFillColor(marks[0])).toBe(false);
|
|
816
|
+
// Marks at 20, 50, and 80 sit between (or at) the thumbs: fill color.
|
|
817
|
+
expect(declaresFillColor(marks[1])).toBe(true);
|
|
818
|
+
expect(declaresFillColor(marks[2])).toBe(true);
|
|
819
|
+
expect(declaresFillColor(marks[3])).toBe(true);
|
|
820
|
+
// The mark at 100 sits after the range: default mark color.
|
|
821
|
+
expect(declaresFillColor(marks[4])).toBe(false);
|
|
822
|
+
});
|
|
823
|
+
|
|
730
824
|
// --- Boundary clamping ---
|
|
731
825
|
|
|
732
826
|
it('clamps value at max boundary', async () => {
|
|
@@ -1101,3 +1195,130 @@ describe('Slider', () => {
|
|
|
1101
1195
|
});
|
|
1102
1196
|
});
|
|
1103
1197
|
});
|
|
1198
|
+
|
|
1199
|
+
describe('pressed state', () => {
|
|
1200
|
+
it('paints the pressed overlay on the thumb for as long as it is dragged, from wherever the press lands', () => {
|
|
1201
|
+
render(
|
|
1202
|
+
<Slider label="Volume" value={50} min={0} max={100} onChange={vi.fn()} />,
|
|
1203
|
+
);
|
|
1204
|
+
const thumb = screen.getByRole('slider');
|
|
1205
|
+
const trackContainer = thumb.parentElement!;
|
|
1206
|
+
trackContainer.getBoundingClientRect = () => ({
|
|
1207
|
+
left: 0,
|
|
1208
|
+
top: 0,
|
|
1209
|
+
right: 200,
|
|
1210
|
+
bottom: 20,
|
|
1211
|
+
width: 200,
|
|
1212
|
+
height: 20,
|
|
1213
|
+
x: 0,
|
|
1214
|
+
y: 0,
|
|
1215
|
+
toJSON: () => {},
|
|
1216
|
+
});
|
|
1217
|
+
|
|
1218
|
+
expect(declaresPressedOverlay(thumb)).toBe(false);
|
|
1219
|
+
// A slider is a drag: the press lands on the track, not the thumb, and
|
|
1220
|
+
// the thumb follows it. The pressed paint follows the drag.
|
|
1221
|
+
fireEvent.pointerDown(trackContainer, {
|
|
1222
|
+
clientX: 20,
|
|
1223
|
+
clientY: 10,
|
|
1224
|
+
pointerId: 1,
|
|
1225
|
+
});
|
|
1226
|
+
expect(declaresPressedOverlay(thumb)).toBe(true);
|
|
1227
|
+
fireEvent.pointerMove(trackContainer, {
|
|
1228
|
+
clientX: 120,
|
|
1229
|
+
clientY: 10,
|
|
1230
|
+
pointerId: 1,
|
|
1231
|
+
});
|
|
1232
|
+
expect(declaresPressedOverlay(thumb)).toBe(true);
|
|
1233
|
+
fireEvent.pointerUp(trackContainer, {
|
|
1234
|
+
clientX: 120,
|
|
1235
|
+
clientY: 10,
|
|
1236
|
+
pointerId: 1,
|
|
1237
|
+
});
|
|
1238
|
+
expect(declaresPressedOverlay(thumb)).toBe(false);
|
|
1239
|
+
});
|
|
1240
|
+
|
|
1241
|
+
it('paints only the thumb being dragged in a range slider', () => {
|
|
1242
|
+
render(
|
|
1243
|
+
<Slider
|
|
1244
|
+
label="Price"
|
|
1245
|
+
value={[20, 80] as [number, number]}
|
|
1246
|
+
min={0}
|
|
1247
|
+
max={100}
|
|
1248
|
+
onChange={vi.fn()}
|
|
1249
|
+
/>,
|
|
1250
|
+
);
|
|
1251
|
+
const [start, end] = screen.getAllByRole('slider');
|
|
1252
|
+
// In range mode the control is the group; each thumb sits in its own
|
|
1253
|
+
// value-tooltip wrapper.
|
|
1254
|
+
const trackContainer = screen.getByRole('group');
|
|
1255
|
+
trackContainer.getBoundingClientRect = () => ({
|
|
1256
|
+
left: 0,
|
|
1257
|
+
top: 0,
|
|
1258
|
+
right: 200,
|
|
1259
|
+
bottom: 20,
|
|
1260
|
+
width: 200,
|
|
1261
|
+
height: 20,
|
|
1262
|
+
x: 0,
|
|
1263
|
+
y: 0,
|
|
1264
|
+
toJSON: () => {},
|
|
1265
|
+
});
|
|
1266
|
+
fireEvent.pointerDown(trackContainer, {
|
|
1267
|
+
clientX: 170,
|
|
1268
|
+
clientY: 10,
|
|
1269
|
+
pointerId: 1,
|
|
1270
|
+
});
|
|
1271
|
+
expect(declaresPressedOverlay(end)).toBe(true);
|
|
1272
|
+
expect(declaresPressedOverlay(start)).toBe(false);
|
|
1273
|
+
fireEvent.pointerUp(trackContainer, {
|
|
1274
|
+
clientX: 170,
|
|
1275
|
+
clientY: 10,
|
|
1276
|
+
pointerId: 1,
|
|
1277
|
+
});
|
|
1278
|
+
expect(declaresPressedOverlay(end)).toBe(false);
|
|
1279
|
+
});
|
|
1280
|
+
|
|
1281
|
+
it('keeps a direct press on the visible upper thumb when range values coincide', () => {
|
|
1282
|
+
render(
|
|
1283
|
+
<Slider
|
|
1284
|
+
label="Price"
|
|
1285
|
+
value={[50, 50] as [number, number]}
|
|
1286
|
+
min={0}
|
|
1287
|
+
max={100}
|
|
1288
|
+
onChange={vi.fn()}
|
|
1289
|
+
/>,
|
|
1290
|
+
);
|
|
1291
|
+
const [start, end] = screen.getAllByRole('slider');
|
|
1292
|
+
const trackContainer = screen.getByRole('group');
|
|
1293
|
+
trackContainer.getBoundingClientRect = () => ({
|
|
1294
|
+
left: 0,
|
|
1295
|
+
top: 0,
|
|
1296
|
+
right: 200,
|
|
1297
|
+
bottom: 20,
|
|
1298
|
+
width: 200,
|
|
1299
|
+
height: 20,
|
|
1300
|
+
x: 0,
|
|
1301
|
+
y: 0,
|
|
1302
|
+
toJSON: () => {},
|
|
1303
|
+
});
|
|
1304
|
+
|
|
1305
|
+
fireEvent.pointerDown(end, {
|
|
1306
|
+
clientX: 100,
|
|
1307
|
+
clientY: 10,
|
|
1308
|
+
pointerId: 1,
|
|
1309
|
+
});
|
|
1310
|
+
expect(declaresPressedOverlay(end)).toBe(true);
|
|
1311
|
+
expect(declaresPressedOverlay(start)).toBe(false);
|
|
1312
|
+
});
|
|
1313
|
+
|
|
1314
|
+
it('does not press a disabled slider', () => {
|
|
1315
|
+
render(<Slider label="Volume" value={50} isDisabled onChange={vi.fn()} />);
|
|
1316
|
+
const thumb = screen.getByRole('slider');
|
|
1317
|
+
fireEvent.pointerDown(thumb.parentElement!, {
|
|
1318
|
+
clientX: 20,
|
|
1319
|
+
clientY: 10,
|
|
1320
|
+
pointerId: 1,
|
|
1321
|
+
});
|
|
1322
|
+
expect(declaresPressedOverlay(thumb)).toBe(false);
|
|
1323
|
+
});
|
|
1324
|
+
});
|
package/src/Slider/Slider.tsx
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
/**
|
|
6
6
|
* @file Slider.tsx
|
|
7
7
|
* @input Uses React, useId, useRef, useCallback, Field, Tooltip, useTooltip, VisuallyHidden
|
|
8
|
-
* @output Exports Slider and its props; modifier-only key presses do not restore the thumb focus ring
|
|
8
|
+
* @output Exports Slider and its props; unfilled marks share the track token; modifier-only key presses do not restore the thumb focus ring
|
|
9
9
|
* @position Core implementation; consumed by index.ts, tested by Slider.test.tsx
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update these files to stay in sync:
|
|
@@ -288,6 +288,15 @@ const styles = stylex.create({
|
|
|
288
288
|
},
|
|
289
289
|
},
|
|
290
290
|
},
|
|
291
|
+
// Pressed: the system's pressed overlay over the thumb's fill for as long
|
|
292
|
+
// as the thumb is being dragged. A slider is a drag, not a tap — the finger
|
|
293
|
+
// lands anywhere on the track and the thumb follows it — so the pressed
|
|
294
|
+
// paint follows the drag state the pointer handlers already keep, on a
|
|
295
|
+
// mouse and on a finger alike, rather than `:active` on the thumb itself
|
|
296
|
+
// (which a press on the track never activates).
|
|
297
|
+
thumbPressed: {
|
|
298
|
+
backgroundImage: `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`,
|
|
299
|
+
},
|
|
291
300
|
thumbDisabled: {
|
|
292
301
|
backgroundColor: colorVars['--color-background-muted'],
|
|
293
302
|
cursor: 'default',
|
|
@@ -314,9 +323,15 @@ const styles = stylex.create({
|
|
|
314
323
|
},
|
|
315
324
|
mark: {
|
|
316
325
|
position: 'absolute',
|
|
317
|
-
backgroundColor: colorVars['--color-
|
|
326
|
+
backgroundColor: colorVars['--color-track'],
|
|
318
327
|
borderRadius: radiusVars['--radius-full'],
|
|
319
328
|
},
|
|
329
|
+
// Marks over the filled region (at or behind the thumb in single mode,
|
|
330
|
+
// between the thumbs in range mode) take the fill color so they read as
|
|
331
|
+
// part of the filled track rather than the unfilled rail.
|
|
332
|
+
markFilled: {
|
|
333
|
+
backgroundColor: colorVars['--color-accent'],
|
|
334
|
+
},
|
|
320
335
|
markHorizontal: {
|
|
321
336
|
width: 2,
|
|
322
337
|
height: 8,
|
|
@@ -701,17 +716,25 @@ export function Slider({ref, ...props}: SliderProps) {
|
|
|
701
716
|
const newVal = markEl
|
|
702
717
|
? Number(markEl.dataset.markValue)
|
|
703
718
|
: getValueFromPosition(e.clientX, e.clientY);
|
|
704
|
-
const
|
|
719
|
+
const track = trackRef.current;
|
|
720
|
+
const thumbs = track?.querySelectorAll<HTMLElement>('[role="slider"]');
|
|
721
|
+
const pressedThumb = (e.target as Element).closest<HTMLElement>(
|
|
722
|
+
'[role="slider"]',
|
|
723
|
+
);
|
|
724
|
+
const pressedThumbIndex =
|
|
725
|
+
pressedThumb == null || thumbs == null
|
|
726
|
+
? -1
|
|
727
|
+
: Array.from(thumbs).indexOf(pressedThumb);
|
|
728
|
+
// A direct thumb press owns that thumb even when range values coincide.
|
|
729
|
+
// Track and mark presses still choose the nearest value.
|
|
730
|
+
const thumbIndex =
|
|
731
|
+
pressedThumbIndex >= 0 ? pressedThumbIndex : getClosestThumb(newVal);
|
|
705
732
|
draggingThumbRef.current = thumbIndex;
|
|
706
733
|
setDraggingThumb(thumbIndex);
|
|
707
734
|
updateValue(thumbIndex, newVal);
|
|
708
735
|
|
|
709
|
-
// Focus the
|
|
710
|
-
|
|
711
|
-
if (track) {
|
|
712
|
-
const thumbs = track.querySelectorAll<HTMLElement>('[role="slider"]');
|
|
713
|
-
thumbs[thumbIndex]?.focus();
|
|
714
|
-
}
|
|
736
|
+
// Focus the thumb that owns this drag.
|
|
737
|
+
thumbs?.[thumbIndex]?.focus();
|
|
715
738
|
// Also clear it explicitly: focusing an already-focused thumb fires no
|
|
716
739
|
// focus event, so a thumb the user had tabbed to would keep its ring
|
|
717
740
|
// through the drag.
|
|
@@ -908,6 +931,7 @@ export function Slider({ref, ...props}: SliderProps) {
|
|
|
908
931
|
? styles.thumbHorizontal
|
|
909
932
|
: rtlStyles.centerInline('50%'),
|
|
910
933
|
!isDisabled && styles.thumbHover,
|
|
934
|
+
!isDisabled && draggingThumb === thumbIndex && styles.thumbPressed,
|
|
911
935
|
!isDisabled &&
|
|
912
936
|
keyboardFocusThumb === thumbIndex &&
|
|
913
937
|
focusOutlineStyles.focusVisible,
|
|
@@ -1085,6 +1109,12 @@ export function Slider({ref, ...props}: SliderProps) {
|
|
|
1085
1109
|
const markPos = isHorizontal
|
|
1086
1110
|
? {insetInlineStart: insetPosition(percent)}
|
|
1087
1111
|
: {bottom: insetPosition(percent)};
|
|
1112
|
+
// Marks at or inside the filled region take the fill color:
|
|
1113
|
+
// at or behind the thumb in single mode, between the thumbs
|
|
1114
|
+
// in range mode.
|
|
1115
|
+
const isFilled = isRange
|
|
1116
|
+
? mark.value >= values[0] && mark.value <= values[1]
|
|
1117
|
+
: mark.value <= values[0];
|
|
1088
1118
|
return (
|
|
1089
1119
|
<div key={mark.value}>
|
|
1090
1120
|
<div
|
|
@@ -1096,6 +1126,7 @@ export function Slider({ref, ...props}: SliderProps) {
|
|
|
1096
1126
|
isHorizontal
|
|
1097
1127
|
? styles.markHorizontal
|
|
1098
1128
|
: styles.markVertical,
|
|
1129
|
+
isFilled && styles.markFilled,
|
|
1099
1130
|
),
|
|
1100
1131
|
{style: markPos},
|
|
1101
1132
|
)}
|
|
@@ -404,6 +404,10 @@ describe('Spinner ring', () => {
|
|
|
404
404
|
frames.forEach(cb => cb(0));
|
|
405
405
|
expect(animations).toHaveLength(5);
|
|
406
406
|
expect(animations.every(a => a.startTime === 0)).toBe(true);
|
|
407
|
+
// The dash animation lives on the arc <circle>, a descendant of the
|
|
408
|
+
// <svg> this ref sits on, not the <svg> itself (#6253) — subtree:true
|
|
409
|
+
// is what lets getAnimations() find it from here.
|
|
410
|
+
expect(getAnimations).toHaveBeenCalledWith({subtree: true});
|
|
407
411
|
// The pin runs on the branch the other shade cases cannot reach, so the
|
|
408
412
|
// no-read assertion is made here too.
|
|
409
413
|
expect(
|
package/src/Spinner/Spinner.tsx
CHANGED
|
@@ -147,13 +147,14 @@ function registerSpinnerVars(): void {
|
|
|
147
147
|
registerSpinnerVars();
|
|
148
148
|
|
|
149
149
|
/**
|
|
150
|
-
* Pin every ring's
|
|
151
|
-
* own start time, so spinners mounted seconds apart
|
|
150
|
+
* Pin every ring's dash motion to the document timeline's origin instead of
|
|
151
|
+
* its own start time, so spinners mounted seconds apart stay in phase.
|
|
152
152
|
*
|
|
153
153
|
* Setting `startTime` is exact where arithmetic on a clock read is not: a
|
|
154
154
|
* negative `animation-delay` computed at mount is only as good as the gap
|
|
155
155
|
* between reading the clock and the frame the animation starts in, which at
|
|
156
|
-
* 10x CPU throttling measured 116deg of drift
|
|
156
|
+
* 10x CPU throttling measured 116deg of drift (from when this animated a
|
|
157
|
+
* literal rotation; the same drift risk applies to the dash offset now).
|
|
157
158
|
*
|
|
158
159
|
* Rings are collected and pinned in one frame because `getAnimations()`
|
|
159
160
|
* resolves style and `startTime` dirties it again, so pinning them one at a
|
|
@@ -167,7 +168,9 @@ function pinRingsToTimelineOrigin(): void {
|
|
|
167
168
|
flushScheduled = false;
|
|
168
169
|
const animations: Animation[] = [];
|
|
169
170
|
for (const svg of pendingRings) {
|
|
170
|
-
|
|
171
|
+
// The animation now runs on the arc <circle>, a descendant of the ring
|
|
172
|
+
// this ref sits on (#6253), so it needs subtree:true to be found here.
|
|
173
|
+
animations.push(...svg.getAnimations({subtree: true}));
|
|
171
174
|
}
|
|
172
175
|
pendingRings.clear();
|
|
173
176
|
for (const animation of animations) {
|
|
@@ -205,9 +208,20 @@ function syncRotationPhase(
|
|
|
205
208
|
// Animation
|
|
206
209
|
// =============================================================================
|
|
207
210
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
+
/**
|
|
212
|
+
* Moves the dash around a stationary circle instead of rotating the whole
|
|
213
|
+
* ring. WebKit re-antialiases a rotating stroked shape's rounded cap
|
|
214
|
+
* (`strokeLinecap: 'round'`, below) slightly differently at each intermediate
|
|
215
|
+
* angle, which reads as a visible wobble on iOS Safari independent of
|
|
216
|
+
* compositing (#6253) — confirmed by a real-device test against this exact
|
|
217
|
+
* fix, since `willChange`/layer promotion alone (the earlier fix for #3617)
|
|
218
|
+
* only smooths the rotation's motion, not the per-frame stroke rasterization.
|
|
219
|
+
* A static circle with an animated `stroke-dashoffset` never rotates, so
|
|
220
|
+
* WebKit never re-rasterizes the cap at an intermediate angle at all.
|
|
221
|
+
*/
|
|
222
|
+
const dashMotion = stylex.keyframes({
|
|
223
|
+
'0%': {strokeDashoffset: '0px'},
|
|
224
|
+
'100%': {strokeDashoffset: `calc(var(${RESOLVED_DIAMETER}) * -${PI})`},
|
|
211
225
|
});
|
|
212
226
|
|
|
213
227
|
// =============================================================================
|
|
@@ -271,7 +285,6 @@ const styles = stylex.create({
|
|
|
271
285
|
// One expression, one source of truth, resolves in any layout.
|
|
272
286
|
width: `var(${BOX_SIZE})`,
|
|
273
287
|
height: `var(${BOX_SIZE})`,
|
|
274
|
-
willChange: 'transform',
|
|
275
288
|
// The svg is sized in CSS (100% of the span) rather than from the size
|
|
276
289
|
// constant, so one user unit is one CSS pixel AND the frame follows a
|
|
277
290
|
// themed diameter: the span's box is `diameter + 2 x stroke`, both public
|
|
@@ -280,16 +293,6 @@ const styles = stylex.create({
|
|
|
280
293
|
// diameter — an overflowing grid item aligns to start rather than centre,
|
|
281
294
|
// which put the ring 1.5-3.3px off across the four sizes.
|
|
282
295
|
overflow: 'visible',
|
|
283
|
-
// Slow the rotation dramatically under reduced-motion rather than freezing
|
|
284
|
-
// it (a frozen spinner reads as broken), matching ProgressBar's approach.
|
|
285
|
-
// The role="status" + "Loading" label still convey busy state (obs-6).
|
|
286
|
-
animationDuration: {
|
|
287
|
-
default: durationVars['--duration-slow-min'],
|
|
288
|
-
'@media (prefers-reduced-motion: reduce)': '3s',
|
|
289
|
-
},
|
|
290
|
-
animationIterationCount: 'infinite',
|
|
291
|
-
animationName: rotation,
|
|
292
|
-
animationTimingFunction: 'linear',
|
|
293
296
|
},
|
|
294
297
|
circle: {
|
|
295
298
|
fill: 'none',
|
|
@@ -327,6 +330,16 @@ const styles = stylex.create({
|
|
|
327
330
|
// `0` the way the registered length pair guards against, so it needs no
|
|
328
331
|
// registration.
|
|
329
332
|
arc: {
|
|
333
|
+
// Slow the motion dramatically under reduced-motion rather than freezing
|
|
334
|
+
// it (a frozen spinner reads as broken), matching ProgressBar's approach.
|
|
335
|
+
// The role="status" + "Loading" label still convey busy state (obs-6).
|
|
336
|
+
animationDuration: {
|
|
337
|
+
default: durationVars['--duration-slow-min'],
|
|
338
|
+
'@media (prefers-reduced-motion: reduce)': '3s',
|
|
339
|
+
},
|
|
340
|
+
animationIterationCount: 'infinite',
|
|
341
|
+
animationName: dashMotion,
|
|
342
|
+
animationTimingFunction: 'linear',
|
|
330
343
|
stroke: 'var(--spinner-color)',
|
|
331
344
|
transform: 'rotate(-90deg)',
|
|
332
345
|
strokeDasharray: `calc(var(${RESOLVED_DIAMETER}) * ${PI} * var(--spinner-arc-fraction)) calc(var(${RESOLVED_DIAMETER}) * ${PI} * (1 - var(--spinner-arc-fraction)))`,
|
|
@@ -210,6 +210,17 @@ export const docs = {
|
|
|
210
210
|
],
|
|
211
211
|
},
|
|
212
212
|
usage: {
|
|
213
|
+
accessibility: [
|
|
214
|
+
{
|
|
215
|
+
name: 'Track and thumb',
|
|
216
|
+
category: 'Color contrast',
|
|
217
|
+
criterion: '1.4.11 Non-text Contrast',
|
|
218
|
+
requirement: '3:1',
|
|
219
|
+
states: ['Rest', 'Hover', 'Pointer down'],
|
|
220
|
+
description:
|
|
221
|
+
'The on and off tracks must each have at least 3:1 contrast with the surface behind them, and the thumb with its track. For Hover and Pointer down, measure the final colors after the tint and the pressed overlay are applied.',
|
|
222
|
+
},
|
|
223
|
+
],
|
|
213
224
|
anatomy,
|
|
214
225
|
description:
|
|
215
226
|
'A toggle control for on/off states that take effect immediately. Supports labels, descriptions, loading states, and validation. Use it for settings or preferences that apply instantly. For changes requiring a form submission, use a checkbox instead.',
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
getAllInjectedCss,
|
|
31
31
|
getForcedColorsRules,
|
|
32
32
|
} from '../__tests__/forcedColors';
|
|
33
|
+
import {hasPressedArm} from '../__tests__/pressState';
|
|
33
34
|
import {__resetLiveRegionsForTest} from '../hooks/useAnnounce';
|
|
34
35
|
|
|
35
36
|
afterEach(() => {
|
|
@@ -755,6 +756,21 @@ describe('Switch', () => {
|
|
|
755
756
|
});
|
|
756
757
|
});
|
|
757
758
|
|
|
759
|
+
describe('pressed state', () => {
|
|
760
|
+
it('paints the pressed overlay on the track and the thumb while the row is pressed', () => {
|
|
761
|
+
const {container} = render(
|
|
762
|
+
<Switch label="Notifications" value={false} onChange={() => {}} />,
|
|
763
|
+
);
|
|
764
|
+
const track = container.querySelector('.astryx-switch');
|
|
765
|
+
const thumb = container.querySelector('.astryx-switch-thumb');
|
|
766
|
+
if (track == null || thumb == null) {
|
|
767
|
+
throw new Error('the switch has no track or thumb to press');
|
|
768
|
+
}
|
|
769
|
+
expect(hasPressedArm(track)).toBe(true);
|
|
770
|
+
expect(hasPressedArm(thumb)).toBe(true);
|
|
771
|
+
});
|
|
772
|
+
});
|
|
773
|
+
|
|
758
774
|
describe('coarse pointer and RTL hit-target positioning', () => {
|
|
759
775
|
it.each([
|
|
760
776
|
['sm', 'ltr'],
|
package/src/Switch/Switch.tsx
CHANGED
|
@@ -122,6 +122,15 @@ const thumbOnSizeStyles = stylex.create({
|
|
|
122
122
|
},
|
|
123
123
|
});
|
|
124
124
|
|
|
125
|
+
// The pressed overlay, painted as a gradient layer OVER the track's and
|
|
126
|
+
// thumb's own fills so it composes with the on/off colors and the hover tint
|
|
127
|
+
// instead of replacing them. Same token Button's overlay paints with. The
|
|
128
|
+
// switch is a two-part control whose focusable input sits beside the track,
|
|
129
|
+
// so the press is read off the shared scope marker (the row), the way the
|
|
130
|
+
// hover tint already is: pressing the input, the track or the label all
|
|
131
|
+
// activate the row.
|
|
132
|
+
const pressedImage = `linear-gradient(${colorVars['--color-overlay-pressed']}, ${colorVars['--color-overlay-pressed']})`;
|
|
133
|
+
|
|
125
134
|
const labelWrapperSizeStyles = stylex.create({
|
|
126
135
|
sm: {
|
|
127
136
|
minHeight: 20,
|
|
@@ -207,6 +216,15 @@ const styles = stylex.create({
|
|
|
207
216
|
default: null,
|
|
208
217
|
'@media (forced-colors: active)': 'CanvasText',
|
|
209
218
|
},
|
|
219
|
+
// Pressed: the overlay rides on top of the on/off fill. Gated like the
|
|
220
|
+
// hover tint so forced colors keeps its system-color track.
|
|
221
|
+
backgroundImage: {
|
|
222
|
+
default: null,
|
|
223
|
+
[stylex.when.ancestor(':active', switchScope)]: {
|
|
224
|
+
default: null,
|
|
225
|
+
'@media (forced-colors: none)': pressedImage,
|
|
226
|
+
},
|
|
227
|
+
},
|
|
210
228
|
},
|
|
211
229
|
// The one ring in the system not drawn by focusOutlineStyles. The focusable
|
|
212
230
|
// input is a sibling of the track, so the condition has to reach the shared
|
|
@@ -278,6 +296,16 @@ const styles = stylex.create({
|
|
|
278
296
|
'@media (prefers-reduced-motion: reduce)': '0s',
|
|
279
297
|
},
|
|
280
298
|
transitionTimingFunction: easeVars['--ease-standard'],
|
|
299
|
+
// Pressed: the same overlay as the track, so the whole control darkens
|
|
300
|
+
// under the finger rather than the thumb standing out against a darker
|
|
301
|
+
// track.
|
|
302
|
+
backgroundImage: {
|
|
303
|
+
default: null,
|
|
304
|
+
[stylex.when.ancestor(':active', switchScope)]: {
|
|
305
|
+
default: null,
|
|
306
|
+
'@media (forced-colors: none)': pressedImage,
|
|
307
|
+
},
|
|
308
|
+
},
|
|
281
309
|
},
|
|
282
310
|
// The thumb fill lives on the on/off styles (not the shared thumb style)
|
|
283
311
|
// because forced colors needs a per-state system color: CanvasText on the
|
package/src/TabList/Tab.tsx
CHANGED
|
@@ -137,6 +137,15 @@ const styles = stylex.create({
|
|
|
137
137
|
[stylex.when.ancestor(':hover', tabScope)]: {
|
|
138
138
|
'@media (hover: hover)': colorVars['--color-overlay-hover'],
|
|
139
139
|
},
|
|
140
|
+
// Pressed: the same layer steps up to the pressed overlay, read off the
|
|
141
|
+
// tab the way the hover is, so a press paints on a finger too. Repeated
|
|
142
|
+
// inside the hover-capable branch so it outranks the hover rule there
|
|
143
|
+
// (a media-nested rule carries extra generated priority; see
|
|
144
|
+
// interactionOverlay.stylex.ts).
|
|
145
|
+
[stylex.when.ancestor(':active', tabScope)]: {
|
|
146
|
+
default: colorVars['--color-overlay-pressed'],
|
|
147
|
+
'@media (hover: hover)': colorVars['--color-overlay-pressed'],
|
|
148
|
+
},
|
|
140
149
|
},
|
|
141
150
|
transitionProperty: 'background-color',
|
|
142
151
|
transitionDuration: durationVars['--duration-fast'],
|
|
@@ -249,6 +258,7 @@ export function Tab({
|
|
|
249
258
|
xstyle,
|
|
250
259
|
className,
|
|
251
260
|
style,
|
|
261
|
+
onClick,
|
|
252
262
|
...restProps
|
|
253
263
|
}: TabProps) {
|
|
254
264
|
const tabListCtx = useTabListContext();
|
|
@@ -263,9 +273,23 @@ export function Tab({
|
|
|
263
273
|
const displayIcon = isSelected && selectedIcon ? selectedIcon : icon;
|
|
264
274
|
const hasVisibleLabel = !isLabelHidden && label !== '';
|
|
265
275
|
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
|
|
276
|
+
const isDisabled =
|
|
277
|
+
restProps['aria-disabled'] === true ||
|
|
278
|
+
restProps['aria-disabled'] === 'true';
|
|
279
|
+
|
|
280
|
+
const handleSelect = useCallback(
|
|
281
|
+
(event: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => {
|
|
282
|
+
if (isDisabled) {
|
|
283
|
+
event.preventDefault();
|
|
284
|
+
return;
|
|
285
|
+
}
|
|
286
|
+
onClick?.(event as React.MouseEvent<HTMLButtonElement>);
|
|
287
|
+
if (!event.defaultPrevented) {
|
|
288
|
+
tabListCtx.onChange(value);
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
[isDisabled, onClick, tabListCtx, value],
|
|
292
|
+
);
|
|
269
293
|
|
|
270
294
|
useDevWarning(
|
|
271
295
|
'Tab',
|
|
@@ -339,7 +363,7 @@ export function Tab({
|
|
|
339
363
|
sizeStyles[size],
|
|
340
364
|
isSelected && styles.selected,
|
|
341
365
|
isFill && layoutStyles.fill,
|
|
342
|
-
tabScope,
|
|
366
|
+
!isDisabled && tabScope,
|
|
343
367
|
xstyle,
|
|
344
368
|
),
|
|
345
369
|
className,
|
|
@@ -382,10 +406,14 @@ export function Tab({
|
|
|
382
406
|
) : null;
|
|
383
407
|
|
|
384
408
|
if (isLink) {
|
|
409
|
+
// A disabled link tab must not reach a router component: some routers reject
|
|
410
|
+
// a missing destination, while others treat it as the current route. A
|
|
411
|
+
// plain anchor without href preserves the element shape but cannot navigate.
|
|
412
|
+
const LinkRoot = isDisabled ? 'a' : LinkComponent;
|
|
385
413
|
return (
|
|
386
|
-
<
|
|
414
|
+
<LinkRoot
|
|
387
415
|
ref={ref}
|
|
388
|
-
href={href}
|
|
416
|
+
href={isDisabled ? undefined : href}
|
|
389
417
|
onClick={handleSelect}
|
|
390
418
|
{...sharedProps}>
|
|
391
419
|
{hoverBgElement}
|
|
@@ -393,7 +421,7 @@ export function Tab({
|
|
|
393
421
|
{labelElement}
|
|
394
422
|
{endContentElement}
|
|
395
423
|
{indicatorElement}
|
|
396
|
-
</
|
|
424
|
+
</LinkRoot>
|
|
397
425
|
);
|
|
398
426
|
}
|
|
399
427
|
|
|
@@ -103,6 +103,17 @@ export const docs = {
|
|
|
103
103
|
{name: 'TabMenu'},
|
|
104
104
|
],
|
|
105
105
|
usage: {
|
|
106
|
+
accessibility: [
|
|
107
|
+
{
|
|
108
|
+
name: 'Tab label',
|
|
109
|
+
category: 'Color contrast',
|
|
110
|
+
criterion: '1.4.3 Contrast (Minimum)',
|
|
111
|
+
requirement: '4.5:1',
|
|
112
|
+
states: ['Rest', 'Hover', 'Pointer down', 'Selected'],
|
|
113
|
+
description:
|
|
114
|
+
'Each label must have at least 4.5:1 contrast with the tab surface behind it. For Hover and Pointer down, measure the final background after the overlay layer is applied.',
|
|
115
|
+
},
|
|
116
|
+
],
|
|
106
117
|
description:
|
|
107
118
|
'TabList provides tab-style navigation for organizing content into categorized sections. Use it to let users switch between related views without leaving the page, with overflow items handled by a built-in "more" menu.',
|
|
108
119
|
bestPractices: [
|