@astryxdesign/core 0.5.0 → 0.5.1-canary.046f6ea
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 +222 -0
- package/dist/AlertDialog/AlertDialog.d.ts +1 -1
- package/dist/AlertDialog/AlertDialog.d.ts.map +1 -1
- package/dist/AlertDialog/AlertDialog.js +45 -20
- package/dist/AspectRatio/AspectRatio.d.ts +6 -6
- package/dist/Avatar/Avatar.d.ts +25 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +43 -9
- package/dist/Avatar/index.d.ts +2 -2
- package/dist/Avatar/index.d.ts.map +1 -1
- package/dist/Avatar/index.js +1 -1
- package/dist/AvatarGroup/AvatarGroup.d.ts +9 -2
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +5 -2
- package/dist/AvatarGroup/AvatarGroupContext.d.ts +2 -1
- package/dist/AvatarGroup/AvatarGroupContext.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +11 -7
- package/dist/Badge/Badge.d.ts.map +1 -1
- package/dist/Badge/Badge.js +26 -2
- package/dist/Banner/Banner.d.ts +10 -1
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +11 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +8 -7
- package/dist/Calendar/Calendar.d.ts +4 -2
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +15 -21
- package/dist/Calendar/hooks/useCalendarDays.js +4 -6
- package/dist/Calendar/hooks/useCalendarNavigation.js +4 -6
- package/dist/Calendar/styles.d.ts +5 -20
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +15 -17
- package/dist/Card/Card.d.ts +12 -12
- package/dist/Card/Card.d.ts.map +1 -1
- package/dist/Card/Card.js +17 -9
- package/dist/Card/index.d.ts +35 -1
- package/dist/Card/index.d.ts.map +1 -1
- package/dist/Card/index.js +21 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +108 -7
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +7 -1
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +15 -4
- package/dist/CodeBlock/highlightRanges.js +1 -1
- package/dist/CodeBlock/highlightStyles.js +13 -13
- package/dist/CommandPalette/CommandPaletteItem.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteItem.js +2 -7
- package/dist/ComplexSelector/ComplexSelector.d.ts +10 -2
- package/dist/ComplexSelector/ComplexSelector.d.ts.map +1 -1
- package/dist/ComplexSelector/ComplexSelector.js +14 -7
- package/dist/DateInput/DateInput.d.ts +43 -0
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +22 -5
- package/dist/DateInput/MonthScroller.d.ts.map +1 -1
- package/dist/DateInput/MonthScroller.js +5 -3
- package/dist/DateInput/MonthYearWheels.d.ts.map +1 -1
- package/dist/DateInput/MonthYearWheels.js +6 -4
- package/dist/DateInput/NativeDateField.d.ts +10 -0
- package/dist/DateInput/NativeDateField.d.ts.map +1 -0
- package/dist/DateInput/NativeDateField.js +494 -0
- package/dist/DateInput/TouchDateField.d.ts.map +1 -1
- package/dist/DateInput/TouchDateField.js +52 -25
- package/dist/DateInput/Wheel.d.ts.map +1 -1
- package/dist/DateInput/Wheel.js +1 -0
- package/dist/DateInput/index.d.ts +1 -1
- package/dist/DateInput/index.d.ts.map +1 -1
- package/dist/DateInput/nativeDateSegments.d.ts +22 -0
- package/dist/DateInput/nativeDateSegments.d.ts.map +1 -0
- package/dist/DateInput/nativeDateSegments.js +111 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts +4 -2
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +3 -5
- package/dist/DateTimeInput/DateTimeInput.d.ts +23 -24
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +35 -10
- package/dist/DateTimeInput/TouchDateTimeField.d.ts +6 -0
- package/dist/DateTimeInput/TouchDateTimeField.d.ts.map +1 -0
- package/dist/DateTimeInput/TouchDateTimeField.js +1021 -0
- package/dist/Dialog/Dialog.d.ts +16 -2
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +28 -7
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +4 -13
- package/dist/Field/FieldLabel.d.ts.map +1 -1
- package/dist/Field/FieldLabel.js +9 -1
- package/dist/Field/InputClearButton.d.ts +9 -3
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +14 -3
- package/dist/Heading/Heading.d.ts.map +1 -1
- package/dist/Heading/Heading.js +0 -1
- package/dist/HoverCard/HoverCard.d.ts.map +1 -1
- package/dist/HoverCard/HoverCard.js +104 -3
- package/dist/HoverCard/useHoverCard.d.ts +14 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +7 -1
- package/dist/Icon/Icon.d.ts +4 -2
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/defaultIcons.d.ts +3 -2
- package/dist/Icon/defaultIcons.d.ts.map +1 -1
- package/dist/Icon/defaultIcons.js +7 -0
- package/dist/Icon/globalIconRegistry.d.ts +13 -0
- package/dist/Icon/globalIconRegistry.d.ts.map +1 -1
- package/dist/Icon/globalIconRegistry.js +34 -6
- package/dist/Icon/index.d.ts +1 -1
- package/dist/Icon/index.d.ts.map +1 -1
- package/dist/Icon/useIcon.d.ts +5 -2
- package/dist/Icon/useIcon.d.ts.map +1 -1
- package/dist/Icon/useIcon.js +3 -0
- package/dist/Indicator/CheckboxIndicator.d.ts.map +1 -1
- package/dist/Indicator/CheckboxIndicator.js +6 -2
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +2 -2
- package/dist/Kbd/Kbd.d.ts.map +1 -1
- package/dist/Kbd/Kbd.js +2 -26
- package/dist/Layer/gestureCounter.d.ts +8 -0
- package/dist/Layer/gestureCounter.d.ts.map +1 -0
- package/dist/Layer/gestureCounter.js +53 -0
- package/dist/Layer/useLayer.d.ts +23 -13
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +146 -24
- package/dist/List/List.d.ts +1 -1
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +15 -4
- package/dist/Markdown/Markdown.d.ts +1 -1
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +20 -7
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +5 -3
- package/dist/MetadataList/MetadataListItem.d.ts +1 -1
- package/dist/MetadataList/MetadataListItem.d.ts.map +1 -1
- package/dist/MetadataList/MetadataListItem.js +4 -1
- package/dist/MultiSelector/MultiSelector.d.ts +18 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +58 -11
- package/dist/MultiSelector/hooks.d.ts +7 -1
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +3 -2
- package/dist/NavIcon/NavIcon.d.ts.map +1 -1
- package/dist/NavIcon/NavIcon.js +5 -1
- package/dist/NavItem/navItemStyles.stylex.d.ts +0 -8
- package/dist/NavItem/navItemStyles.stylex.d.ts.map +1 -1
- package/dist/NavItem/navItemStyles.stylex.js +0 -2
- package/dist/NavMenu/NavHeadingMenu.d.ts +1 -1
- package/dist/NavMenu/NavHeadingMenu.d.ts.map +1 -1
- package/dist/NavMenu/NavHeadingMenu.js +7 -4
- package/dist/NumberInput/NumberInput.d.ts +6 -1
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +95 -126
- package/dist/NumberInput/numberInputCommit.d.ts +34 -0
- package/dist/NumberInput/numberInputCommit.d.ts.map +1 -0
- package/dist/NumberInput/numberInputCommit.js +71 -0
- package/dist/NumberInput/numberParser.d.ts +64 -0
- package/dist/NumberInput/numberParser.d.ts.map +1 -0
- package/dist/NumberInput/numberParser.js +350 -0
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +2 -3
- package/dist/OverflowList/OverflowList.d.ts +41 -1
- package/dist/OverflowList/OverflowList.d.ts.map +1 -1
- package/dist/OverflowList/OverflowList.js +43 -2
- package/dist/Popover/Popover.d.ts.map +1 -1
- package/dist/Popover/Popover.js +8 -14
- package/dist/Popover/usePopover.d.ts +15 -41
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +26 -7
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +91 -18
- package/dist/PowerSearch/formatFilterValue.d.ts.map +1 -1
- package/dist/PowerSearch/formatFilterValue.js +4 -2
- package/dist/ProgressBar/ProgressBar.d.ts.map +1 -1
- package/dist/ProgressBar/ProgressBar.js +18 -5
- package/dist/Resizable/useResizable.d.ts +19 -1
- package/dist/Resizable/useResizable.d.ts.map +1 -1
- package/dist/Resizable/useResizable.js +104 -38
- package/dist/SelectableCard/SelectableCard.d.ts.map +1 -1
- package/dist/SelectableCard/SelectableCard.js +9 -0
- package/dist/Selector/Selector.d.ts +18 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +92 -21
- package/dist/Selector/hooks.d.ts +7 -1
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +3 -2
- package/dist/SideNav/SideNav.d.ts +6 -1
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +57 -27
- package/dist/SideNav/SideNavHeading.d.ts.map +1 -1
- package/dist/SideNav/SideNavHeading.js +5 -4
- package/dist/SideNav/SideNavItem.d.ts +29 -4
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +75 -20
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +34 -2
- package/dist/Spinner/Spinner.d.ts +3 -1
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +199 -20
- package/dist/StatusDot/StatusDot.d.ts.map +1 -1
- package/dist/StatusDot/StatusDot.js +6 -1
- package/dist/Stepper/Step.d.ts.map +1 -1
- package/dist/Stepper/Step.js +7 -6
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +5 -1
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +6 -1
- package/dist/Table/Table.d.ts.map +1 -1
- package/dist/Table/Table.js +3 -6
- package/dist/Table/plugins/filtering/useTableFiltering.d.ts.map +1 -1
- package/dist/Table/plugins/filtering/useTableFiltering.js +73 -4
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts +26 -0
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +34 -3
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +25 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +3 -4
- package/dist/Text/Text.d.ts.map +1 -1
- package/dist/Text/Text.js +0 -1
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +13 -8
- package/dist/Timestamp/Timestamp.d.ts +1 -1
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +10 -18
- package/dist/Timestamp/formatInstant.d.ts.map +1 -1
- package/dist/Timestamp/formatInstant.js +10 -5
- package/dist/Toast/Toast.d.ts +17 -2
- package/dist/Toast/Toast.d.ts.map +1 -1
- package/dist/Toast/Toast.js +77 -11
- package/dist/Toast/ToastViewport.d.ts +1 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +76 -21
- package/dist/Toast/index.d.ts +1 -1
- package/dist/Toast/index.d.ts.map +1 -1
- package/dist/Toast/types.d.ts +38 -0
- package/dist/Toast/types.d.ts.map +1 -1
- package/dist/Toast/useToastGesture.d.ts +26 -0
- package/dist/Toast/useToastGesture.d.ts.map +1 -0
- package/dist/Toast/useToastGesture.js +223 -0
- package/dist/Token/Token.d.ts +1 -1
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +23 -12
- package/dist/Token/TokenLink.d.ts +1 -1
- package/dist/Token/TokenLink.d.ts.map +1 -1
- package/dist/Token/TokenLink.js +5 -2
- package/dist/Tokenizer/Tokenizer.d.ts +12 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +31 -21
- package/dist/TopNav/TopNavHeading.js +2 -2
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +3 -3
- package/dist/TopNav/TopNavMegaMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +30 -9
- package/dist/TopNav/TopNavMegaMenuItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenuItem.js +3 -3
- package/dist/TopNav/TopNavMenu.d.ts +1 -1
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +21 -6
- package/dist/TreeList/TreeList.d.ts +1 -1
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +7 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +2 -2
- package/dist/Typeahead/BaseTypeahead.d.ts +33 -0
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +51 -8
- package/dist/Typeahead/Typeahead.d.ts +8 -1
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +2 -0
- package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/Typeahead/TypeaheadItem.js +7 -2
- package/dist/astryx.css +87 -22
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +3 -25
- package/dist/hooks/useOverflow.d.ts.map +1 -1
- package/dist/hooks/useOverflow.js +14 -4
- package/dist/i18n/InternationalizationContext.d.ts +2 -0
- package/dist/i18n/InternationalizationContext.d.ts.map +1 -1
- package/dist/i18n/InternationalizationContext.js +3 -1
- package/dist/i18n/InternationalizationProvider.d.ts.map +1 -1
- package/dist/i18n/InternationalizationProvider.js +3 -1
- package/dist/i18n/resolve.d.ts +1 -1
- package/dist/i18n/resolve.d.ts.map +1 -1
- package/dist/i18n/resolve.js +37 -38
- package/dist/i18n/useTranslator.d.ts.map +1 -1
- package/dist/i18n/useTranslator.js +2 -3
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/theme/Theme.d.ts.map +1 -1
- package/dist/theme/Theme.js +46 -10
- package/dist/theme/defineTheme.d.ts +9 -3
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +5 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +24 -4
- package/dist/theme/generateThemeRules.d.ts +21 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +26 -0
- package/dist/theme/syntax/tokens.d.ts +1 -1
- package/dist/theme/syntax/tokens.d.ts.map +1 -1
- package/dist/theme/syntax/tokens.js +5 -2
- package/dist/theme/useTheme.d.ts.map +1 -1
- package/dist/theme/useTheme.js +6 -7
- package/dist/utils/dateParser.d.ts +5 -8
- package/dist/utils/dateParser.d.ts.map +1 -1
- package/dist/utils/dateParser.js +10 -11
- package/dist/utils/focusOutline.stylex.d.ts +25 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.js +15 -0
- package/dist/utils/interactionOverlay.stylex.d.ts +26 -0
- package/dist/utils/interactionOverlay.stylex.d.ts.map +1 -0
- package/dist/utils/interactionOverlay.stylex.js +42 -0
- package/dist/utils/isApplePlatform.d.ts +18 -0
- package/dist/utils/isApplePlatform.d.ts.map +1 -0
- package/dist/utils/isApplePlatform.js +37 -0
- package/dist/utils/plainDate.d.ts +11 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +20 -4
- package/locales/af-ZA.json +7 -7
- package/locales/ar-SA.json +7 -7
- package/locales/ca-ES.json +6 -6
- package/locales/cs-CZ.json +7 -7
- package/locales/da-DK.json +7 -7
- package/locales/de-DE.json +7 -7
- package/locales/el-GR.json +7 -7
- package/locales/en.json +178 -6
- package/locales/es-ES.json +6 -6
- package/locales/fi-FI.json +7 -7
- package/locales/fr-FR.json +7 -7
- package/locales/he-IL.json +7 -7
- package/locales/hu-HU.json +7 -7
- package/locales/it-IT.json +7 -7
- package/locales/ja-JP.json +7 -7
- package/locales/ko-KR.json +7 -7
- package/locales/nl-NL.json +7 -7
- package/locales/no-NO.json +7 -7
- package/locales/pl-PL.json +7 -7
- package/locales/pseudo.json +130 -1
- package/locales/pt-BR.json +7 -7
- package/locales/pt-PT.json +7 -7
- package/locales/ro-RO.json +7 -7
- package/locales/ru-RU.json +7 -7
- package/locales/sr-SP.json +7 -7
- package/locales/sv-SE.json +7 -7
- package/locales/tr-TR.json +7 -7
- package/locales/uk-UA.json +7 -7
- package/locales/vi-VN.json +7 -7
- package/locales/zh-CN.json +7 -7
- package/locales/zh-TW.json +7 -7
- package/package.json +4 -5
- package/src/AlertDialog/AlertDialog.doc.mjs +114 -30
- package/src/AlertDialog/AlertDialog.test.tsx +211 -2
- package/src/AlertDialog/AlertDialog.tsx +62 -20
- package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
- package/src/AspectRatio/AspectRatio.tsx +6 -6
- package/src/Avatar/Avatar.doc.mjs +12 -2
- package/src/Avatar/Avatar.test.tsx +80 -0
- package/src/Avatar/Avatar.tsx +64 -14
- package/src/Avatar/index.ts +2 -2
- package/src/AvatarGroup/AvatarGroup.doc.mjs +8 -2
- package/src/AvatarGroup/AvatarGroup.test.tsx +24 -0
- package/src/AvatarGroup/AvatarGroup.tsx +12 -4
- package/src/AvatarGroup/AvatarGroupContext.ts +5 -3
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +12 -12
- package/src/Badge/Badge.doc.mjs +3 -2
- package/src/Badge/Badge.test.tsx +32 -3
- package/src/Badge/Badge.tsx +42 -1
- package/src/Banner/Banner.doc.mjs +9 -0
- package/src/Banner/Banner.test.tsx +76 -11
- package/src/Banner/Banner.tsx +21 -2
- package/src/Button/Button.doc.mjs +2 -1
- package/src/Button/Button.test.tsx +19 -4
- package/src/Button/Button.tsx +9 -29
- package/src/ButtonGroup/ButtonGroup.doc.mjs +2 -2
- package/src/ButtonGroup/ButtonGroup.test.tsx +13 -0
- package/src/Calendar/Calendar.doc.mjs +4 -4
- package/src/Calendar/Calendar.test.tsx +112 -0
- package/src/Calendar/Calendar.tsx +18 -16
- package/src/Calendar/hooks/useCalendarDays.ts +4 -4
- package/src/Calendar/hooks/useCalendarNavigation.ts +4 -4
- package/src/Calendar/styles.ts +48 -42
- package/src/Card/Card.doc.mjs +10 -7
- package/src/Card/Card.test.tsx +113 -19
- package/src/Card/Card.tsx +67 -89
- package/src/Card/index.ts +36 -1
- package/src/Carousel/Carousel.doc.mjs +3 -0
- package/src/Carousel/Carousel.test.tsx +360 -0
- package/src/Carousel/Carousel.tsx +116 -15
- package/src/CheckboxInput/CheckboxInput.doc.mjs +3 -1
- package/src/CheckboxInput/CheckboxInput.test.tsx +15 -0
- package/src/CheckboxInput/CheckboxInput.tsx +5 -0
- package/src/CheckboxList/CheckboxList.doc.mjs +1 -1
- package/src/CodeBlock/CodeBlock.doc.mjs +10 -4
- package/src/CodeBlock/CodeBlock.test.tsx +37 -0
- package/src/CodeBlock/CodeBlock.tsx +20 -4
- package/src/CodeBlock/highlightRanges.ts +1 -1
- package/src/CodeBlock/highlightStyles.ts +13 -13
- package/src/CommandPalette/CommandPaletteItem.tsx +2 -12
- package/src/ComplexSelector/ComplexSelector.doc.mjs +9 -2
- package/src/ComplexSelector/ComplexSelector.test.tsx +183 -0
- package/src/ComplexSelector/ComplexSelector.tsx +22 -12
- package/src/DateInput/DateInput.doc.mjs +17 -1
- package/src/DateInput/DateInput.test.tsx +9 -4
- package/src/DateInput/DateInput.tsx +54 -3
- package/src/DateInput/DateInputTouch.test.tsx +146 -32
- package/src/DateInput/MonthScroller.tsx +5 -1
- package/src/DateInput/MonthYearWheels.tsx +7 -4
- package/src/DateInput/NativeDateField.test.tsx +635 -0
- package/src/DateInput/NativeDateField.tsx +641 -0
- package/src/DateInput/TouchDateField.tsx +83 -33
- package/src/DateInput/Wheel.tsx +1 -0
- package/src/DateInput/index.ts +1 -0
- package/src/DateInput/nativeDateSegments.ts +127 -0
- package/src/DateRangeInput/DateRangeInput.doc.mjs +3 -3
- package/src/DateRangeInput/DateRangeInput.test.tsx +46 -0
- package/src/DateRangeInput/DateRangeInput.tsx +8 -13
- package/src/DateTimeInput/DateTimeInput.doc.mjs +39 -22
- package/src/DateTimeInput/DateTimeInput.test.tsx +76 -0
- package/src/DateTimeInput/DateTimeInput.tsx +54 -20
- package/src/DateTimeInput/DateTimeInputTouch.test.tsx +980 -0
- package/src/DateTimeInput/TouchDateTimeField.tsx +1437 -0
- package/src/Dialog/Dialog.test.tsx +185 -18
- package/src/Dialog/Dialog.tsx +35 -11
- package/src/DropdownMenu/DropdownMenu.test.tsx +44 -10
- package/src/DropdownMenu/DropdownMenu.tsx +4 -13
- package/src/Field/Field.doc.mjs +1 -1
- package/src/Field/FieldLabel.test.tsx +29 -0
- package/src/Field/FieldLabel.tsx +7 -0
- package/src/Field/InputClearButton.test.tsx +15 -1
- package/src/Field/InputClearButton.tsx +28 -4
- package/src/FieldStatus/FieldStatus.doc.mjs +1 -1
- package/src/FileInput/FileInput.doc.mjs +1 -1
- package/src/Heading/Heading.tsx +0 -1
- package/src/HoverCard/HoverCard.doc.mjs +8 -2
- package/src/HoverCard/HoverCard.test.tsx +154 -4
- package/src/HoverCard/HoverCard.tsx +137 -3
- package/src/HoverCard/useHoverCard.tsx +23 -3
- package/src/Icon/Icon.test.tsx +55 -1
- package/src/Icon/Icon.tsx +5 -3
- package/src/Icon/defaultIcons.tsx +11 -2
- package/src/Icon/globalIconRegistry.test.tsx +16 -3
- package/src/Icon/globalIconRegistry.tsx +37 -6
- package/src/Icon/index.ts +1 -0
- package/src/Icon/useIcon.ts +9 -2
- package/src/Indicator/CheckboxIndicator.tsx +14 -8
- package/src/Indicator/Indicator.doc.mjs +3 -1
- package/src/InputGroup/InputGroup.doc.mjs +1 -1
- package/src/Item/Item.tsx +2 -7
- package/src/Kbd/Kbd.test.tsx +0 -17
- package/src/Kbd/Kbd.tsx +2 -26
- package/src/Layer/gestureCounter.ts +57 -0
- package/src/Layer/useLayer.test.tsx +368 -16
- package/src/Layer/useLayer.tsx +208 -35
- package/src/Layout/__tests__/edgeCompensation.test.tsx +1 -1
- package/src/List/List.test.tsx +38 -0
- package/src/List/List.tsx +8 -1
- package/src/Markdown/Markdown.test.tsx +37 -0
- package/src/Markdown/Markdown.tsx +16 -5
- package/src/Markdown/parser.test.ts +33 -0
- package/src/Markdown/parser.ts +9 -3
- package/src/MetadataList/MetadataList.test.tsx +75 -2
- package/src/MetadataList/MetadataListItem.tsx +5 -2
- package/src/MultiSelector/MultiSelector.doc.mjs +23 -2
- package/src/MultiSelector/MultiSelector.test.tsx +205 -0
- package/src/MultiSelector/MultiSelector.tsx +103 -16
- package/src/MultiSelector/hooks.ts +9 -2
- package/src/NavIcon/NavIcon.doc.mjs +8 -2
- package/src/NavIcon/NavIcon.test.tsx +9 -0
- package/src/NavIcon/NavIcon.tsx +5 -1
- package/src/NavItem/navItemStyles.stylex.ts +0 -8
- package/src/NavMenu/NavHeadingMenu.test.tsx +30 -0
- package/src/NavMenu/NavHeadingMenu.tsx +7 -4
- package/src/NumberInput/NumberInput.doc.mjs +27 -8
- package/src/NumberInput/NumberInput.test.tsx +563 -8
- package/src/NumberInput/NumberInput.tsx +77 -131
- package/src/NumberInput/numberInputCommit.test.ts +72 -0
- package/src/NumberInput/numberInputCommit.ts +103 -0
- package/src/NumberInput/numberParser.docblock.test.ts +234 -0
- package/src/NumberInput/numberParser.test.ts +222 -0
- package/src/NumberInput/numberParser.ts +403 -0
- package/src/Outline/Outline.tsx +2 -4
- package/src/OverflowList/OverflowList.doc.mjs +102 -21
- package/src/OverflowList/OverflowList.test.tsx +550 -4
- package/src/OverflowList/OverflowList.tsx +100 -2
- package/src/Pagination/Pagination.test.tsx +3 -2
- package/src/Popover/Popover.doc.mjs +2 -2
- package/src/Popover/Popover.test.tsx +38 -0
- package/src/Popover/Popover.tsx +28 -66
- package/src/Popover/usePopover.tsx +44 -5
- package/src/PowerSearch/PowerSearch.doc.mjs +1 -1
- package/src/PowerSearch/PowerSearchEditPopover.test.tsx +87 -0
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +64 -0
- package/src/PowerSearch/PowerSearchValueEditor.tsx +109 -10
- package/src/PowerSearch/formatFilterValue.test.ts +16 -1
- package/src/PowerSearch/formatFilterValue.ts +2 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +42 -6
- package/src/ProgressBar/ProgressBar.test.tsx +24 -0
- package/src/ProgressBar/ProgressBar.tsx +28 -8
- package/src/RadioList/RadioList.doc.mjs +1 -1
- package/src/Resizable/Resizable.doc.mjs +2 -2
- package/src/Resizable/useResizable.doc.mjs +21 -2
- package/src/Resizable/useResizable.test.ts +421 -0
- package/src/Resizable/useResizable.ts +133 -48
- package/src/SelectableCard/SelectableCard.doc.mjs +3 -0
- package/src/SelectableCard/SelectableCard.tsx +16 -0
- package/src/Selector/Selector.doc.mjs +15 -1
- package/src/Selector/Selector.source-build.test.mjs +65 -0
- package/src/Selector/Selector.test.tsx +301 -0
- package/src/Selector/Selector.tsx +145 -32
- package/src/Selector/hooks.ts +17 -2
- package/src/SideNav/SideNav.doc.mjs +2 -2
- package/src/SideNav/SideNav.test.tsx +1069 -6
- package/src/SideNav/SideNav.tsx +109 -38
- package/src/SideNav/SideNavHeading.tsx +5 -2
- package/src/SideNav/SideNavItem.doc.mjs +24 -3
- package/src/SideNav/SideNavItem.tsx +134 -44
- package/src/Slider/Slider.doc.mjs +2 -2
- package/src/Slider/Slider.test.tsx +106 -1
- package/src/Slider/Slider.tsx +52 -1
- package/src/Spinner/Spinner.doc.mjs +17 -5
- package/src/Spinner/Spinner.test.tsx +164 -0
- package/src/Spinner/Spinner.tsx +252 -22
- package/src/StatusDot/StatusDot.doc.mjs +8 -2
- package/src/StatusDot/StatusDot.test.tsx +9 -0
- package/src/StatusDot/StatusDot.tsx +7 -1
- package/src/Stepper/Step.doc.mjs +1 -1
- package/src/Stepper/Step.tsx +7 -14
- package/src/Switch/Switch.doc.mjs +3 -1
- package/src/Switch/Switch.test.tsx +10 -0
- package/src/Switch/Switch.tsx +3 -0
- package/src/Table/BaseTable.tsx +6 -1
- package/src/Table/Table.doc.mjs +5 -3
- package/src/Table/Table.tsx +3 -8
- package/src/Table/TableBody.doc.mjs +2 -2
- package/src/Table/TableFooter.doc.mjs +1 -1
- package/src/Table/TableHeader.doc.mjs +1 -1
- package/src/Table/plugins/filtering/useTableFiltering.test.tsx +44 -6
- package/src/Table/plugins/filtering/useTableFiltering.tsx +100 -4
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +50 -4
- package/src/Table/plugins/selection/useTableSelection.test.tsx +62 -0
- package/src/Table/plugins/selection/useTableSelection.tsx +25 -2
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +1 -2
- package/src/Table/useTableGroupedRows.doc.mjs +3 -3
- package/src/Table/useTablePagination.doc.mjs +1 -1
- package/src/Table/useTableSelection.doc.mjs +1 -1
- package/src/Text/Text.test.tsx +44 -0
- package/src/Text/Text.tsx +0 -1
- package/src/TextArea/TextArea.doc.mjs +13 -3
- package/src/TextArea/TextArea.test.tsx +11 -0
- package/src/TextArea/TextArea.tsx +34 -22
- package/src/TextInput/TextInput.doc.mjs +1 -1
- package/src/TimeInput/TimeInput.doc.mjs +1 -1
- package/src/Timestamp/Timestamp.test.tsx +89 -0
- package/src/Timestamp/Timestamp.tsx +8 -8
- package/src/Timestamp/formatInstant.ts +5 -0
- package/src/Toast/Toast.doc.mjs +213 -44
- package/src/Toast/Toast.tsx +118 -23
- package/src/Toast/ToastViewport.test.tsx +1434 -8
- package/src/Toast/ToastViewport.tsx +85 -14
- package/src/Toast/index.ts +2 -0
- package/src/Toast/types.ts +43 -5
- package/src/Toast/useToastGesture.ts +361 -0
- package/src/Token/Token.test.tsx +95 -0
- package/src/Token/Token.tsx +19 -17
- package/src/Token/TokenLink.tsx +12 -3
- package/src/Tokenizer/Tokenizer.doc.mjs +17 -4
- package/src/Tokenizer/Tokenizer.test.tsx +161 -0
- package/src/Tokenizer/Tokenizer.tsx +49 -24
- package/src/TopNav/TopNavHeading.tsx +2 -2
- package/src/TopNav/TopNavItem.tsx +3 -7
- package/src/TopNav/TopNavMegaMenu.test.tsx +104 -0
- package/src/TopNav/TopNavMegaMenu.tsx +47 -4
- package/src/TopNav/TopNavMegaMenuItem.tsx +10 -9
- package/src/TopNav/TopNavMenu.test.tsx +133 -1
- package/src/TopNav/TopNavMenu.tsx +38 -5
- package/src/TreeList/TreeList.test.tsx +49 -0
- package/src/TreeList/TreeList.tsx +7 -2
- package/src/TreeList/TreeListItem.tsx +2 -7
- package/src/Typeahead/BaseTypeahead.doc.mjs +13 -0
- package/src/Typeahead/BaseTypeahead.tsx +96 -6
- package/src/Typeahead/Typeahead.doc.mjs +7 -1
- package/src/Typeahead/Typeahead.test.tsx +154 -0
- package/src/Typeahead/Typeahead.tsx +9 -0
- package/src/Typeahead/TypeaheadItem.test.tsx +43 -0
- package/src/Typeahead/TypeaheadItem.tsx +8 -1
- package/src/hooks/useAnnounce.doc.mjs +96 -0
- package/src/hooks/useDevWarning.doc.mjs +96 -0
- package/src/hooks/useHotkeys.test.ts +0 -18
- package/src/hooks/useHotkeys.ts +3 -25
- package/src/hooks/useIndicatorFocusRing.doc.mjs +104 -0
- package/src/hooks/useInputStatusIcon.doc.mjs +142 -0
- package/src/hooks/useInteractiveRole.doc.mjs +119 -0
- package/src/hooks/useLongPress.doc.mjs +123 -0
- package/src/hooks/useOverflow.doc.mjs +58 -17
- package/src/hooks/useOverflow.ts +16 -4
- package/src/hooks/useTypeahead.doc.mjs +153 -0
- package/src/i18n/InternationalizationContext.ts +3 -0
- package/src/i18n/InternationalizationProvider.tsx +8 -1
- package/src/i18n/__tests__/resolve.test.ts +23 -1
- package/src/i18n/resolve.ts +46 -49
- package/src/i18n/useTranslator.ts +2 -7
- package/src/index.ts +2 -0
- package/src/raw-import.d.ts +14 -0
- package/src/theme/Theme.test.tsx +104 -2
- package/src/theme/Theme.tsx +49 -14
- package/src/theme/defineTheme.test.ts +23 -0
- package/src/theme/defineTheme.ts +12 -3
- package/src/theme/derivedVarRegistry.test.ts +87 -3
- package/src/theme/derivedVarRegistry.ts +23 -4
- package/src/theme/generateThemeRules.test.ts +99 -1
- package/src/theme/generateThemeRules.ts +28 -0
- package/src/theme/syntax/tokens.ts +5 -2
- package/src/theme/useTheme.test.tsx +10 -0
- package/src/theme/useTheme.ts +16 -10
- package/src/utils/dateParser.test.ts +34 -2
- package/src/utils/dateParser.ts +11 -14
- package/src/utils/focusOutline.stylex.ts +50 -0
- package/src/utils/interactionOverlay.stylex.ts +74 -0
- package/src/utils/isApplePlatform.test.ts +61 -0
- package/src/utils/isApplePlatform.ts +37 -0
- package/src/utils/plainDate.test.ts +46 -0
- package/src/utils/plainDate.ts +18 -3
|
@@ -365,7 +365,94 @@ describe('HoverCard', () => {
|
|
|
365
365
|
);
|
|
366
366
|
});
|
|
367
367
|
|
|
368
|
-
it('
|
|
368
|
+
it('advertises a dialog popup on the trigger when labelled', () => {
|
|
369
|
+
render(
|
|
370
|
+
<HoverCard content={<span>Card content</span>} label="Profile actions">
|
|
371
|
+
<button type="button">Trigger</button>
|
|
372
|
+
</HoverCard>,
|
|
373
|
+
);
|
|
374
|
+
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
375
|
+
expect(trigger).toHaveAttribute('aria-haspopup', 'dialog');
|
|
376
|
+
// While closed, the layer is not in the DOM, so aria-controls must not
|
|
377
|
+
// point at a missing id (see DateInput). It is set once the card opens.
|
|
378
|
+
expect(trigger).not.toHaveAttribute('aria-controls');
|
|
379
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
380
|
+
expect(trigger).not.toHaveAttribute('aria-describedby');
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
it('merges existing popup attributes on the trigger when labelled', () => {
|
|
384
|
+
render(
|
|
385
|
+
<HoverCard content={<span>Card content</span>} label="Profile actions">
|
|
386
|
+
<button
|
|
387
|
+
type="button"
|
|
388
|
+
aria-haspopup="menu"
|
|
389
|
+
aria-controls="menu-id"
|
|
390
|
+
aria-expanded="true">
|
|
391
|
+
Trigger
|
|
392
|
+
</button>
|
|
393
|
+
</HoverCard>,
|
|
394
|
+
);
|
|
395
|
+
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
396
|
+
// The hover card's dialog popup is advertised, but the trigger's own
|
|
397
|
+
// popup semantics are preserved rather than overwritten.
|
|
398
|
+
expect(trigger).toHaveAttribute('aria-haspopup', 'dialog');
|
|
399
|
+
expect(trigger.getAttribute('aria-controls')).toContain('menu-id');
|
|
400
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
it('omits aria-expanded on a trigger whose role does not support it', () => {
|
|
404
|
+
render(
|
|
405
|
+
<HoverCard content={<span>Card content</span>} label="Timestamp details">
|
|
406
|
+
<time dateTime="2026-08-25" tabIndex={0}>
|
|
407
|
+
2 hours ago
|
|
408
|
+
</time>
|
|
409
|
+
</HoverCard>,
|
|
410
|
+
);
|
|
411
|
+
const trigger = screen.getByText('2 hours ago');
|
|
412
|
+
expect(trigger.tagName).toBe('TIME');
|
|
413
|
+
// Global attributes are valid on any element, so the popup relationship is
|
|
414
|
+
// still advertised.
|
|
415
|
+
expect(trigger).toHaveAttribute('aria-haspopup', 'dialog');
|
|
416
|
+
// aria-expanded is not: <time> has no role that supports it, and emitting
|
|
417
|
+
// it is a critical axe aria-allowed-attr violation.
|
|
418
|
+
expect(trigger).not.toHaveAttribute('aria-expanded');
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('keeps aria-expanded on a role-less trigger that declares a supporting role', () => {
|
|
422
|
+
render(
|
|
423
|
+
<HoverCard content={<span>Card content</span>} label="Profile actions">
|
|
424
|
+
<span role="button" tabIndex={0}>
|
|
425
|
+
Trigger
|
|
426
|
+
</span>
|
|
427
|
+
</HoverCard>,
|
|
428
|
+
);
|
|
429
|
+
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
430
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
431
|
+
});
|
|
432
|
+
|
|
433
|
+
it('leaves a role-less trigger own aria-expanded untouched', () => {
|
|
434
|
+
render(
|
|
435
|
+
<HoverCard content={<span>Card content</span>} label="Profile actions">
|
|
436
|
+
<span aria-expanded="true">Trigger</span>
|
|
437
|
+
</HoverCard>,
|
|
438
|
+
);
|
|
439
|
+
const trigger = screen.getByText('Trigger');
|
|
440
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
441
|
+
});
|
|
442
|
+
|
|
443
|
+
it('keeps aria-expanded on triggers whose implicit role supports it', () => {
|
|
444
|
+
render(
|
|
445
|
+
<HoverCard content={<span>Card content</span>} label="Profile actions">
|
|
446
|
+
<input type="button" value="Trigger" />
|
|
447
|
+
</HoverCard>,
|
|
448
|
+
);
|
|
449
|
+
expect(screen.getByRole('button')).toHaveAttribute(
|
|
450
|
+
'aria-expanded',
|
|
451
|
+
'false',
|
|
452
|
+
);
|
|
453
|
+
});
|
|
454
|
+
|
|
455
|
+
it('keeps aria-describedby on the trigger when no label is provided', () => {
|
|
369
456
|
render(
|
|
370
457
|
<HoverCard content={<span>Card content</span>}>
|
|
371
458
|
<button type="button">Trigger</button>
|
|
@@ -373,9 +460,10 @@ describe('HoverCard', () => {
|
|
|
373
460
|
);
|
|
374
461
|
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
375
462
|
expect(trigger).toHaveAttribute('aria-describedby');
|
|
463
|
+
expect(trigger).not.toHaveAttribute('aria-haspopup');
|
|
376
464
|
});
|
|
377
465
|
|
|
378
|
-
it('
|
|
466
|
+
it('preserves existing aria-describedby when no label is provided', () => {
|
|
379
467
|
render(
|
|
380
468
|
<HoverCard content={<span>Card content</span>}>
|
|
381
469
|
<button type="button" aria-describedby="existing-id">
|
|
@@ -388,6 +476,34 @@ describe('HoverCard', () => {
|
|
|
388
476
|
expect(describedBy).toContain('existing-id');
|
|
389
477
|
});
|
|
390
478
|
|
|
479
|
+
it('updates aria-expanded when the labelled hover card opens and closes', async () => {
|
|
480
|
+
render(
|
|
481
|
+
<HoverCard
|
|
482
|
+
content={<span>Card content</span>}
|
|
483
|
+
label="Profile actions"
|
|
484
|
+
delay={0}>
|
|
485
|
+
<button type="button">Trigger</button>
|
|
486
|
+
</HoverCard>,
|
|
487
|
+
);
|
|
488
|
+
const trigger = screen.getByRole('button', {name: 'Trigger'});
|
|
489
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
490
|
+
expect(trigger).not.toHaveAttribute('aria-controls');
|
|
491
|
+
|
|
492
|
+
fireEvent.mouseEnter(trigger);
|
|
493
|
+
await waitFor(() => {
|
|
494
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'true');
|
|
495
|
+
// The layer is in the DOM now, so aria-controls points at it.
|
|
496
|
+
expect(trigger).toHaveAttribute('aria-controls');
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
fireEvent.mouseLeave(trigger);
|
|
500
|
+
await waitFor(() => {
|
|
501
|
+
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
502
|
+
// The layer is gone from the DOM, so aria-controls is cleared.
|
|
503
|
+
expect(trigger).not.toHaveAttribute('aria-controls');
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
|
|
391
507
|
it('calls onOpenChange(true) when shown', async () => {
|
|
392
508
|
const onOpenChange = vi.fn();
|
|
393
509
|
render(
|
|
@@ -429,16 +545,33 @@ describe('HoverCard', () => {
|
|
|
429
545
|
|
|
430
546
|
it('supports text-only children with inline wrapper', () => {
|
|
431
547
|
render(
|
|
432
|
-
<HoverCard content={<span>Card content</span>}>
|
|
548
|
+
<HoverCard content={<span>Card content</span>} label="Profile actions">
|
|
433
549
|
Just text, no element
|
|
434
550
|
</HoverCard>,
|
|
435
551
|
);
|
|
436
552
|
// Text should be rendered
|
|
437
553
|
expect(screen.getByText('Just text, no element')).toBeInTheDocument();
|
|
438
|
-
//
|
|
554
|
+
// When labelled, the wrapper advertises a dialog popup.
|
|
555
|
+
const wrapper = screen.getByText('Just text, no element');
|
|
556
|
+
expect(wrapper.tagName).toBe('SPAN');
|
|
557
|
+
expect(wrapper).toHaveAttribute('aria-haspopup', 'dialog');
|
|
558
|
+
// The wrapper is a role-less <span>; aria-expanded is invalid there.
|
|
559
|
+
expect(wrapper).not.toHaveAttribute('aria-expanded');
|
|
560
|
+
// While closed, the layer is not in the DOM, so aria-controls is unset.
|
|
561
|
+
expect(wrapper).not.toHaveAttribute('aria-controls');
|
|
562
|
+
expect(wrapper).not.toHaveAttribute('aria-describedby');
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
it('keeps aria-describedby on text-only children when no label is provided', () => {
|
|
566
|
+
render(
|
|
567
|
+
<HoverCard content={<span>Card content</span>}>
|
|
568
|
+
Just text, no element
|
|
569
|
+
</HoverCard>,
|
|
570
|
+
);
|
|
439
571
|
const wrapper = screen.getByText('Just text, no element');
|
|
440
572
|
expect(wrapper.tagName).toBe('SPAN');
|
|
441
573
|
expect(wrapper).toHaveAttribute('aria-describedby');
|
|
574
|
+
expect(wrapper).not.toHaveAttribute('aria-haspopup');
|
|
442
575
|
});
|
|
443
576
|
|
|
444
577
|
describe('isDefaultOpen', () => {
|
|
@@ -994,3 +1127,20 @@ describe('HoverCard', () => {
|
|
|
994
1127
|
});
|
|
995
1128
|
});
|
|
996
1129
|
});
|
|
1130
|
+
|
|
1131
|
+
describe('HoverCard theme target names', () => {
|
|
1132
|
+
it('renders the deprecated class beside the current one on the card surface', async () => {
|
|
1133
|
+
render(
|
|
1134
|
+
<HoverCard content={<span>Card content</span>} delay={0}>
|
|
1135
|
+
<button type="button">Trigger</button>
|
|
1136
|
+
</HoverCard>,
|
|
1137
|
+
);
|
|
1138
|
+
fireEvent.mouseEnter(screen.getByRole('button', {name: 'Trigger'}));
|
|
1139
|
+
|
|
1140
|
+
await waitFor(() => {
|
|
1141
|
+
const layer = screen.getByText('Card content').closest('[popover]');
|
|
1142
|
+
expect(layer).toHaveClass('astryx-hover-card');
|
|
1143
|
+
expect(layer).toHaveClass('astryx-hovercard');
|
|
1144
|
+
});
|
|
1145
|
+
});
|
|
1146
|
+
});
|
|
@@ -32,6 +32,66 @@ export type {
|
|
|
32
32
|
HoverCardTouchTrigger,
|
|
33
33
|
} from './useHoverCard';
|
|
34
34
|
|
|
35
|
+
// `aria-haspopup` and `aria-controls` are global, so any trigger may carry
|
|
36
|
+
// them. `aria-expanded` is not. This is the ARIA 1.2 "Supported States and
|
|
37
|
+
// Properties" list for it — deliberately the narrow reading: axe accepts the
|
|
38
|
+
// attribute on rather more roles, since it also allows every subclass of these,
|
|
39
|
+
// so a role outside this set is not necessarily a violation. Widening it is
|
|
40
|
+
// safe; the set is a floor, not the spec's ceiling. The same rule is applied in
|
|
41
|
+
// Chat/useTriggerMenu.tsx, which only emits the combobox attributes once the
|
|
42
|
+
// element is actually a combobox.
|
|
43
|
+
const EXPANDABLE_ROLES = new Set([
|
|
44
|
+
'application',
|
|
45
|
+
'button',
|
|
46
|
+
'checkbox',
|
|
47
|
+
'columnheader',
|
|
48
|
+
'combobox',
|
|
49
|
+
'gridcell',
|
|
50
|
+
'link',
|
|
51
|
+
'listbox',
|
|
52
|
+
'menuitem',
|
|
53
|
+
'menuitemcheckbox',
|
|
54
|
+
'menuitemradio',
|
|
55
|
+
'row',
|
|
56
|
+
'rowheader',
|
|
57
|
+
'switch',
|
|
58
|
+
'tab',
|
|
59
|
+
'treeitem',
|
|
60
|
+
]);
|
|
61
|
+
|
|
62
|
+
const BUTTON_INPUT_TYPES = new Set(['button', 'submit', 'reset', 'image']);
|
|
63
|
+
|
|
64
|
+
// Deliberately partial, and unlisted elements are read as role-less: dropping
|
|
65
|
+
// aria-expanded where it might have been legal costs an AT user a state they
|
|
66
|
+
// can still infer, whereas emitting it where it is illegal is a critical
|
|
67
|
+
// aria-allowed-attr defect.
|
|
68
|
+
function supportsAriaExpanded(el: HTMLElement): boolean {
|
|
69
|
+
const explicit = el.getAttribute('role')?.trim().split(/\s+/)[0];
|
|
70
|
+
if (explicit) {
|
|
71
|
+
return EXPANDABLE_ROLES.has(explicit);
|
|
72
|
+
}
|
|
73
|
+
switch (el.tagName) {
|
|
74
|
+
case 'BUTTON':
|
|
75
|
+
case 'SUMMARY':
|
|
76
|
+
return true;
|
|
77
|
+
case 'A':
|
|
78
|
+
case 'AREA':
|
|
79
|
+
return el.hasAttribute('href');
|
|
80
|
+
case 'INPUT':
|
|
81
|
+
// The button-flavoured input types map to role="button"; every other
|
|
82
|
+
// type maps to a textbox-family role, which does not take it.
|
|
83
|
+
return BUTTON_INPUT_TYPES.has(
|
|
84
|
+
(el as HTMLInputElement).type?.toLowerCase(),
|
|
85
|
+
);
|
|
86
|
+
case 'SELECT':
|
|
87
|
+
// combobox when it is a single-line picker, listbox otherwise; both
|
|
88
|
+
// support aria-expanded.
|
|
89
|
+
return true;
|
|
90
|
+
default:
|
|
91
|
+
return false;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
35
95
|
const styles = stylex.create({
|
|
36
96
|
wrapperContents: {
|
|
37
97
|
display: 'contents',
|
|
@@ -259,7 +319,70 @@ export function HoverCard({
|
|
|
259
319
|
// Use combined ref for position + interaction
|
|
260
320
|
hoverCard.ref(firstChild);
|
|
261
321
|
|
|
262
|
-
|
|
322
|
+
if (label) {
|
|
323
|
+
// When named, the hover card is a dialog. The trigger should advertise the
|
|
324
|
+
// popup relationship with aria-haspopup/aria-expanded, not describe the
|
|
325
|
+
// trigger with the dialog's content (aria-describedby is for plain-text
|
|
326
|
+
// descriptions, not navigable regions). See #5049.
|
|
327
|
+
//
|
|
328
|
+
// aria-expanded only goes on a trigger whose role permits it. A role-less
|
|
329
|
+
// trigger (Timestamp's <time>/<span>) gets haspopup + controls, which are
|
|
330
|
+
// global, and no expanded state.
|
|
331
|
+
//
|
|
332
|
+
// Merge rather than overwrite: the trigger may already carry its own
|
|
333
|
+
// popup semantics (e.g. a menu button wrapped in a labelled HoverCard),
|
|
334
|
+
// so preserve the existing values and restore them on cleanup.
|
|
335
|
+
const existingHaspopup = firstChild.getAttribute('aria-haspopup');
|
|
336
|
+
const existingControls = firstChild.getAttribute('aria-controls');
|
|
337
|
+
const existingExpanded = firstChild.getAttribute('aria-expanded');
|
|
338
|
+
const canExpand = supportsAriaExpanded(firstChild);
|
|
339
|
+
|
|
340
|
+
firstChild.setAttribute('aria-haspopup', 'dialog');
|
|
341
|
+
// Only point aria-controls at the layer while it is open and in the DOM.
|
|
342
|
+
// While closed, useLayer leaves only an inert <template> marker, so the
|
|
343
|
+
// id would reference nothing. DateInput gates it the same way. The
|
|
344
|
+
// trigger's own aria-controls (if any) is preserved either way.
|
|
345
|
+
if (hoverCard.isOpen) {
|
|
346
|
+
firstChild.setAttribute(
|
|
347
|
+
'aria-controls',
|
|
348
|
+
mergeIds(existingControls, hoverCard.id) ?? '',
|
|
349
|
+
);
|
|
350
|
+
} else if (existingControls) {
|
|
351
|
+
firstChild.setAttribute('aria-controls', existingControls);
|
|
352
|
+
} else {
|
|
353
|
+
firstChild.removeAttribute('aria-controls');
|
|
354
|
+
}
|
|
355
|
+
if (canExpand) {
|
|
356
|
+
firstChild.setAttribute('aria-expanded', String(hoverCard.isOpen));
|
|
357
|
+
} else if (existingExpanded) {
|
|
358
|
+
firstChild.setAttribute('aria-expanded', existingExpanded);
|
|
359
|
+
} else {
|
|
360
|
+
firstChild.removeAttribute('aria-expanded');
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return () => {
|
|
364
|
+
hoverCard.ref(null);
|
|
365
|
+
if (existingHaspopup) {
|
|
366
|
+
firstChild.setAttribute('aria-haspopup', existingHaspopup);
|
|
367
|
+
} else {
|
|
368
|
+
firstChild.removeAttribute('aria-haspopup');
|
|
369
|
+
}
|
|
370
|
+
if (existingControls) {
|
|
371
|
+
firstChild.setAttribute('aria-controls', existingControls);
|
|
372
|
+
} else {
|
|
373
|
+
firstChild.removeAttribute('aria-controls');
|
|
374
|
+
}
|
|
375
|
+
if (existingExpanded) {
|
|
376
|
+
firstChild.setAttribute('aria-expanded', existingExpanded);
|
|
377
|
+
} else {
|
|
378
|
+
firstChild.removeAttribute('aria-expanded');
|
|
379
|
+
}
|
|
380
|
+
};
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Unnamed fallback: the popup remains role="group", which is not a dialog,
|
|
384
|
+
// so keep the previous description relationship until a naming decision is
|
|
385
|
+
// made for the no-label case (tracked in #5049).
|
|
263
386
|
const existingDescribedBy = firstChild.getAttribute('aria-describedby');
|
|
264
387
|
firstChild.setAttribute(
|
|
265
388
|
'aria-describedby',
|
|
@@ -274,7 +397,14 @@ export function HoverCard({
|
|
|
274
397
|
firstChild.removeAttribute('aria-describedby');
|
|
275
398
|
}
|
|
276
399
|
};
|
|
277
|
-
}, [
|
|
400
|
+
}, [
|
|
401
|
+
textOnly,
|
|
402
|
+
label,
|
|
403
|
+
hoverCard.ref,
|
|
404
|
+
hoverCard.id,
|
|
405
|
+
hoverCard.isOpen,
|
|
406
|
+
hoverCard.describedBy,
|
|
407
|
+
]);
|
|
278
408
|
|
|
279
409
|
// While closed, useLayer leaves only an inert <template> marker at this JSX
|
|
280
410
|
// position. When the card needs to open, it uses that marker to keep the
|
|
@@ -293,7 +423,11 @@ export function HoverCard({
|
|
|
293
423
|
<span
|
|
294
424
|
ref={hoverCard.ref}
|
|
295
425
|
tabIndex={0}
|
|
296
|
-
aria-
|
|
426
|
+
aria-haspopup={label ? 'dialog' : undefined}
|
|
427
|
+
aria-controls={label && hoverCard.isOpen ? hoverCard.id : undefined}
|
|
428
|
+
// No aria-expanded: this wrapper is a role-less <span>, and
|
|
429
|
+
// aria-expanded is invalid on it (see EXPANDABLE_ROLES above).
|
|
430
|
+
aria-describedby={label ? undefined : hoverCard.describedBy}
|
|
297
431
|
{...stylex.props(
|
|
298
432
|
styles.wrapperInline,
|
|
299
433
|
showHoverIndication && styles.hoverIndication,
|
|
@@ -190,11 +190,25 @@ export interface HoverCardReturn {
|
|
|
190
190
|
anchorId: string;
|
|
191
191
|
|
|
192
192
|
/**
|
|
193
|
-
* ID for
|
|
194
|
-
*
|
|
193
|
+
* Unique ID for the hover card container.
|
|
194
|
+
* Useful for `aria-controls` or `aria-owns` on the trigger.
|
|
195
|
+
*/
|
|
196
|
+
id: string;
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Deprecated alias of `id`. Kept for backwards compatibility; prefer `id`.
|
|
195
200
|
*/
|
|
196
201
|
describedBy: string;
|
|
197
202
|
|
|
203
|
+
/**
|
|
204
|
+
* Whether the hover card is currently open.
|
|
205
|
+
* Useful for driving `aria-expanded` on the trigger — but only when the
|
|
206
|
+
* trigger's role permits it (`button`, `link`, `combobox`, …). On a role-less
|
|
207
|
+
* trigger `aria-expanded` is invalid; use `aria-haspopup`/`aria-controls`
|
|
208
|
+
* alone there.
|
|
209
|
+
*/
|
|
210
|
+
isOpen: boolean;
|
|
211
|
+
|
|
198
212
|
/**
|
|
199
213
|
* Render function for hover card content.
|
|
200
214
|
* Returns anchor-positioned popover element.
|
|
@@ -594,7 +608,11 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
594
608
|
props?: Omit<ContextRenderProps, 'positioning'>,
|
|
595
609
|
): ReactNode => {
|
|
596
610
|
const renderPlacement = props?.placement ?? placement;
|
|
597
|
-
const themeClassName = themeProps('
|
|
611
|
+
const themeClassName = themeProps('hover-card', undefined, {
|
|
612
|
+
// `hovercard` ran the compound name together; themes styling it keep
|
|
613
|
+
// working until the next major.
|
|
614
|
+
legacyNames: ['hovercard'],
|
|
615
|
+
}).className;
|
|
598
616
|
const renderProps = {
|
|
599
617
|
placement: renderPlacement,
|
|
600
618
|
alignment: props?.alignment ?? alignment,
|
|
@@ -681,7 +699,9 @@ export function useHoverCard(options: HoverCardOptions = {}): HoverCardReturn {
|
|
|
681
699
|
positionRef: layer.ref,
|
|
682
700
|
interactionRef,
|
|
683
701
|
anchorId: layer.anchorId,
|
|
702
|
+
id: layer.id,
|
|
684
703
|
describedBy: layer.id,
|
|
704
|
+
isOpen: layer.isOpen,
|
|
685
705
|
renderHoverCard,
|
|
686
706
|
show: layer.show,
|
|
687
707
|
hide: layer.hide,
|
package/src/Icon/Icon.test.tsx
CHANGED
|
@@ -17,7 +17,7 @@ import {Theme} from '../theme/Theme';
|
|
|
17
17
|
import {defineTheme} from '../theme/defineTheme';
|
|
18
18
|
import {resetThemes} from '../theme/themeRegistry';
|
|
19
19
|
import {Icon} from './Icon';
|
|
20
|
-
import {resetIcons} from './globalIconRegistry';
|
|
20
|
+
import {registerIcons, resetIcons} from './globalIconRegistry';
|
|
21
21
|
|
|
22
22
|
describe('Icon', () => {
|
|
23
23
|
it('renders the icon component', () => {
|
|
@@ -192,6 +192,60 @@ describe('Icon', () => {
|
|
|
192
192
|
expect(screen.getByTestId('inner')).toHaveTextContent('inner-check');
|
|
193
193
|
});
|
|
194
194
|
|
|
195
|
+
describe('namespaced extension keys', () => {
|
|
196
|
+
it('renders a theme-registered namespaced key with size and color applied', () => {
|
|
197
|
+
resetIcons();
|
|
198
|
+
resetThemes();
|
|
199
|
+
const theme = defineTheme({
|
|
200
|
+
name: 'ns-theme',
|
|
201
|
+
icons: {'numberInput:stepperDown': 'themed-stepper'},
|
|
202
|
+
});
|
|
203
|
+
|
|
204
|
+
render(
|
|
205
|
+
<Theme theme={theme}>
|
|
206
|
+
<Icon icon="numberInput:stepperDown" size="xsm" data-testid="icon" />
|
|
207
|
+
</Theme>,
|
|
208
|
+
);
|
|
209
|
+
|
|
210
|
+
const icon = screen.getByTestId('icon');
|
|
211
|
+
expect(icon).toHaveTextContent('themed-stepper');
|
|
212
|
+
expect(icon).toHaveAttribute('aria-hidden', 'true');
|
|
213
|
+
expect(icon.className).not.toBe('');
|
|
214
|
+
});
|
|
215
|
+
|
|
216
|
+
it('resolves a namespaced key registered globally', () => {
|
|
217
|
+
resetIcons();
|
|
218
|
+
resetThemes();
|
|
219
|
+
registerIcons({'numberInput:stepperDown': 'global-stepper'});
|
|
220
|
+
|
|
221
|
+
render(<Icon icon="numberInput:stepperDown" data-testid="icon" />);
|
|
222
|
+
|
|
223
|
+
expect(screen.getByTestId('icon')).toHaveTextContent('global-stepper');
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it('still rejects a misspelled built-in name', () => {
|
|
227
|
+
render(
|
|
228
|
+
// @ts-expect-error — the prop takes built-in names and namespaced
|
|
229
|
+
// keys, not any string, so a typo is still a compile error.
|
|
230
|
+
<Icon icon="chevrondown" data-testid="icon" />,
|
|
231
|
+
);
|
|
232
|
+
|
|
233
|
+
expect(screen.queryByTestId('icon')).not.toBeInTheDocument();
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('renders nothing when a namespaced key resolves to nothing', () => {
|
|
237
|
+
resetIcons();
|
|
238
|
+
resetThemes();
|
|
239
|
+
|
|
240
|
+
const {container} = render(
|
|
241
|
+
<Icon icon="numberInput:missing" data-testid="icon" />,
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
expect(screen.queryByTestId('icon')).not.toBeInTheDocument();
|
|
245
|
+
expect(container).toBeEmptyDOMElement();
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
|
|
195
249
|
it('lets a string-mode icon be made meaningful by overriding aria-hidden', () => {
|
|
196
250
|
render(
|
|
197
251
|
<Icon
|
package/src/Icon/Icon.tsx
CHANGED
|
@@ -28,7 +28,7 @@ import type {StyleXStyles} from '@stylexjs/stylex';
|
|
|
28
28
|
import {colorVars} from '../theme/tokens.stylex';
|
|
29
29
|
import {useThemeName} from '../theme/useTheme';
|
|
30
30
|
import {getIcon} from './globalIconRegistry';
|
|
31
|
-
import type {IconName} from './globalIconRegistry';
|
|
31
|
+
import type {IconName, NamespacedIconName} from './globalIconRegistry';
|
|
32
32
|
import {mergeProps} from '../utils';
|
|
33
33
|
import {themeProps} from '../utils/themeProps';
|
|
34
34
|
|
|
@@ -199,9 +199,11 @@ export interface IconProps extends Omit<
|
|
|
199
199
|
/**
|
|
200
200
|
* Icon to render. Can be:
|
|
201
201
|
* - A semantic name string (e.g. 'close', 'chevronDown') — resolved from theme or built-in fallback
|
|
202
|
+
* - A namespaced extension key (e.g. 'richtext:bold') for a glyph owned by
|
|
203
|
+
* one component or library — resolved the same way, themeable by key
|
|
202
204
|
* - An SVG icon component (e.g. from @heroicons/react) — rendered directly
|
|
203
205
|
*/
|
|
204
|
-
icon: IconType | IconName;
|
|
206
|
+
icon: IconType | IconName | NamespacedIconName;
|
|
205
207
|
/**
|
|
206
208
|
* The color variant of the icon.
|
|
207
209
|
* @default 'inherit'
|
|
@@ -371,7 +373,7 @@ function IconFromRegistry({
|
|
|
371
373
|
xstyle,
|
|
372
374
|
spanProps,
|
|
373
375
|
}: {
|
|
374
|
-
name: IconName;
|
|
376
|
+
name: IconName | NamespacedIconName;
|
|
375
377
|
color: IconColor;
|
|
376
378
|
size: IconSize;
|
|
377
379
|
a11yProps: {role: 'img'; 'aria-label': string} | {'aria-hidden': 'true'};
|
|
@@ -23,7 +23,8 @@
|
|
|
23
23
|
* - /packages/core/src/Icon/Icon.doc.mjs (fallback icon documentation)
|
|
24
24
|
*/
|
|
25
25
|
|
|
26
|
-
import type {
|
|
26
|
+
import type {ReactNode} from 'react';
|
|
27
|
+
import type {IconRegistry, NamespacedIconName} from './globalIconRegistry';
|
|
27
28
|
|
|
28
29
|
const svgProps = {
|
|
29
30
|
xmlns: 'http://www.w3.org/2000/svg',
|
|
@@ -53,7 +54,8 @@ const solidSvgProps = {
|
|
|
53
54
|
'aria-hidden': true as const,
|
|
54
55
|
};
|
|
55
56
|
|
|
56
|
-
export const defaultIcons: IconRegistry
|
|
57
|
+
export const defaultIcons: IconRegistry &
|
|
58
|
+
Partial<Record<NamespacedIconName, ReactNode>> = {
|
|
57
59
|
/** ✕ — two diagonal lines */
|
|
58
60
|
close: (
|
|
59
61
|
<svg {...svgProps}>
|
|
@@ -68,6 +70,13 @@ export const defaultIcons: IconRegistry = {
|
|
|
68
70
|
</svg>
|
|
69
71
|
),
|
|
70
72
|
|
|
73
|
+
/** ⌄ — compact NumberInput stepper chevron */
|
|
74
|
+
'numberInput:stepperDown': (
|
|
75
|
+
<svg {...svgProps}>
|
|
76
|
+
<path d="M7.5 9.75l4.5 4.5 4.5-4.5" />
|
|
77
|
+
</svg>
|
|
78
|
+
),
|
|
79
|
+
|
|
71
80
|
/** ‹ — left chevron */
|
|
72
81
|
chevronLeft: (
|
|
73
82
|
<svg {...svgProps}>
|
|
@@ -27,12 +27,22 @@ describe('iconRegistry (global, RSC-compatible)', () => {
|
|
|
27
27
|
|
|
28
28
|
it('returns a default icon registry snapshot', () => {
|
|
29
29
|
const registry = getIconRegistry();
|
|
30
|
+
const builtInDefaults = Object.fromEntries(
|
|
31
|
+
Object.entries(defaultIcons).filter(([name]) => !name.includes(':')),
|
|
32
|
+
);
|
|
30
33
|
|
|
31
|
-
expect(
|
|
32
|
-
expect(registry).toEqual(defaultIcons);
|
|
34
|
+
expect(registry).toEqual(builtInDefaults);
|
|
33
35
|
expect(registry).not.toBe(defaultIcons);
|
|
34
36
|
});
|
|
35
37
|
|
|
38
|
+
it('provides a distinct default for the NumberInput stepper icon', () => {
|
|
39
|
+
const icon = getIcon('numberInput:stepperDown');
|
|
40
|
+
|
|
41
|
+
expect(icon).toBe(defaultIcons['numberInput:stepperDown']);
|
|
42
|
+
expect(icon).toBeDefined();
|
|
43
|
+
expect(icon).not.toBe(defaultIcons.chevronDown);
|
|
44
|
+
});
|
|
45
|
+
|
|
36
46
|
it('returns default icons when nothing is registered', () => {
|
|
37
47
|
const icon = getIcon('close');
|
|
38
48
|
expect(icon).toBeDefined();
|
|
@@ -149,7 +159,10 @@ describe('iconRegistry (global, RSC-compatible)', () => {
|
|
|
149
159
|
registerIcons({'richtext:bold': 'my-bold'});
|
|
150
160
|
// getIconRegistry() is the built-in IconName snapshot; extension keys
|
|
151
161
|
// are resolved via getIcon/getExtendedIcon, not surfaced here.
|
|
152
|
-
expect(Object.keys(getIconRegistry())).
|
|
162
|
+
expect(Object.keys(getIconRegistry())).not.toContain('richtext:bold');
|
|
163
|
+
expect(Object.keys(getIconRegistry())).not.toContain(
|
|
164
|
+
'numberInput:stepperDown',
|
|
165
|
+
);
|
|
153
166
|
});
|
|
154
167
|
|
|
155
168
|
it('extension keys are cleared by resetIcons', () => {
|
|
@@ -57,6 +57,20 @@ export type IconName =
|
|
|
57
57
|
| 'stop'
|
|
58
58
|
| 'microphone';
|
|
59
59
|
|
|
60
|
+
/**
|
|
61
|
+
* A namespaced extension key, `'<namespace>:<name>'`.
|
|
62
|
+
*
|
|
63
|
+
* This is the tier for a glyph that belongs to one component or library rather
|
|
64
|
+
* than to the system: `'richtext:bold'`, `'numberInput:stepperDown'`. A theme
|
|
65
|
+
* overrides it by key through `registerIcons` or `defineTheme({icons})`,
|
|
66
|
+
* exactly as it overrides a built-in name, and the core {@link IconName} union
|
|
67
|
+
* stays reserved for glyphs the whole system shares.
|
|
68
|
+
*
|
|
69
|
+
* Accepted anywhere a built-in name is, including `<Icon icon>` — which is
|
|
70
|
+
* what lets a namespaced glyph keep `size`, `color` and `xstyle`.
|
|
71
|
+
*/
|
|
72
|
+
export type NamespacedIconName = `${string}:${string}`;
|
|
73
|
+
|
|
60
74
|
/**
|
|
61
75
|
* A semantic icon name — either one of the built-in {@link IconName}s or an
|
|
62
76
|
* arbitrary string key contributed by a library/app.
|
|
@@ -81,9 +95,19 @@ export type IconRegistrySource = DefinedTheme | string | null | undefined;
|
|
|
81
95
|
|
|
82
96
|
let globalRegistry: Record<string, ReactNode> = {};
|
|
83
97
|
|
|
98
|
+
/**
|
|
99
|
+
* A key is namespaced when it carries a `<namespace>:` prefix — the runtime
|
|
100
|
+
* form of {@link NamespacedIconName}, which is how the typed
|
|
101
|
+
* {@link getIconRegistry} snapshot tells a built-in name from a component- or
|
|
102
|
+
* library-owned one.
|
|
103
|
+
*/
|
|
104
|
+
function isNamespacedKey(name: string): boolean {
|
|
105
|
+
return name.includes(':');
|
|
106
|
+
}
|
|
107
|
+
|
|
84
108
|
function getThemeIconOverrides(
|
|
85
109
|
source: IconRegistrySource,
|
|
86
|
-
): Partial<
|
|
110
|
+
): Partial<Record<IconName | NamespacedIconName, ReactNode>> | null {
|
|
87
111
|
if (source == null) {
|
|
88
112
|
return null;
|
|
89
113
|
}
|
|
@@ -140,23 +164,30 @@ export function registerIcons(
|
|
|
140
164
|
export function getIconRegistry(
|
|
141
165
|
source?: IconRegistrySource,
|
|
142
166
|
): Readonly<IconRegistry> {
|
|
143
|
-
const registry = {
|
|
167
|
+
const registry: Record<string, ReactNode> = {};
|
|
144
168
|
|
|
145
|
-
// Only surface built-in IconName keys here —
|
|
146
|
-
//
|
|
147
|
-
// out of the
|
|
169
|
+
// Only surface built-in IconName keys here — namespaced keys, whether
|
|
170
|
+
// contributed by a library or shipped as a component's own default, are
|
|
171
|
+
// resolved via getIcon/getExtendedIcon and intentionally kept out of the
|
|
172
|
+
// typed IconRegistry snapshot.
|
|
148
173
|
for (const name of Object.keys(defaultIcons) as IconName[]) {
|
|
174
|
+
if (isNamespacedKey(name)) {
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
149
177
|
registry[name] = globalRegistry[name] ?? defaultIcons[name];
|
|
150
178
|
}
|
|
151
179
|
|
|
152
180
|
const themeIcons = getThemeIconOverrides(source);
|
|
153
181
|
if (themeIcons != null) {
|
|
154
182
|
for (const name of Object.keys(themeIcons) as IconName[]) {
|
|
183
|
+
if (isNamespacedKey(name)) {
|
|
184
|
+
continue;
|
|
185
|
+
}
|
|
155
186
|
registry[name] = themeIcons[name] ?? registry[name];
|
|
156
187
|
}
|
|
157
188
|
}
|
|
158
189
|
|
|
159
|
-
return registry;
|
|
190
|
+
return registry as IconRegistry;
|
|
160
191
|
}
|
|
161
192
|
|
|
162
193
|
/**
|