@astryxdesign/core 0.1.9-canary.d2d84f8 → 0.1.9-canary.e00a241
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/dist/Avatar/Avatar.d.ts +6 -1
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +46 -12
- package/dist/Avatar/AvatarStatusDot.d.ts +6 -4
- package/dist/Avatar/AvatarStatusDot.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +11 -4
- package/dist/Breadcrumbs/index.d.ts +1 -0
- package/dist/Breadcrumbs/index.d.ts.map +1 -1
- package/dist/Breadcrumbs/index.js +2 -1
- package/dist/Calendar/Calendar.d.ts.map +1 -1
- package/dist/Calendar/Calendar.js +50 -9
- package/dist/Calendar/dayCellUtils.d.ts +4 -4
- package/dist/Calendar/dayCellUtils.js +2 -2
- package/dist/Calendar/styles.d.ts +30 -31
- package/dist/Calendar/styles.d.ts.map +1 -1
- package/dist/Calendar/styles.js +30 -31
- package/dist/Card/Card.js +1 -1
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +22 -12
- package/dist/Chat/ChatDictationButton.d.ts.map +1 -1
- package/dist/Chat/ChatDictationButton.js +3 -1
- package/dist/Chat/ChatMessageBubble.d.ts.map +1 -1
- package/dist/Chat/ChatMessageBubble.js +8 -8
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +10 -3
- package/dist/CheckboxInput/CheckboxInput.js +4 -4
- package/dist/Citation/Citation.d.ts +22 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +20 -6
- package/dist/CodeBlock/CodeBlock.d.ts.map +1 -1
- package/dist/CodeBlock/CodeBlock.js +13 -7
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +3 -1
- package/dist/CommandPalette/CommandPalette.d.ts +1 -1
- package/dist/CommandPalette/CommandPalette.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPalette.js +42 -3
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +14 -5
- package/dist/ContextMenu/index.d.ts +1 -0
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +3 -1
- package/dist/DateInput/DateInput.d.ts +1 -0
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +31 -19
- package/dist/DateRangeInput/DateRangeInput.d.ts +1 -0
- package/dist/DateRangeInput/DateRangeInput.d.ts.map +1 -1
- package/dist/DateRangeInput/DateRangeInput.js +20 -19
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +23 -18
- package/dist/Divider/Divider.d.ts +2 -2
- package/dist/Divider/Divider.d.ts.map +1 -1
- package/dist/Divider/Divider.js +13 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +6 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +22 -5
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +4 -1
- package/dist/DropdownMenu/DropdownMenuItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuItem.js +4 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +4 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts +104 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +427 -0
- package/dist/DropdownMenu/index.d.ts +10 -0
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +13 -0
- package/dist/DropdownMenu/menuItemHover.d.ts +23 -0
- package/dist/DropdownMenu/menuItemHover.d.ts.map +1 -0
- package/dist/DropdownMenu/menuItemHover.js +33 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts +8 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -1
- package/dist/DropdownMenu/menuItemRoles.js +10 -1
- package/dist/DropdownMenu/renderDropdownItems.d.ts.map +1 -1
- package/dist/DropdownMenu/renderDropdownItems.js +21 -6
- package/dist/Field/Field.d.ts +3 -1
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +4 -1
- package/dist/Field/inputStyles.stylex.d.ts +1 -0
- package/dist/Field/inputStyles.stylex.d.ts.map +1 -1
- package/dist/Field/inputStyles.stylex.js +1 -0
- package/dist/FieldStatus/FieldStatus.d.ts +4 -1
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +4 -2
- package/dist/FileInput/FileInput.d.ts +1 -0
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +91 -65
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +10 -4
- package/dist/Icon/Icon.d.ts +15 -1
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +19 -3
- package/dist/Lightbox/Lightbox.d.ts.map +1 -1
- package/dist/Lightbox/Lightbox.js +15 -9
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +6 -3
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +7 -0
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +65 -40
- package/dist/NumberInput/NumberInput.d.ts +1 -0
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +20 -17
- package/dist/Outline/Outline.js +2 -2
- package/dist/RadioList/RadioList.d.ts +2 -2
- package/dist/RadioList/RadioListItem.js +4 -4
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +49 -19
- package/dist/SegmentedControl/SegmentedControlItem.d.ts +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.d.ts.map +1 -1
- package/dist/SegmentedControl/SegmentedControlItem.js +2 -1
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +58 -16
- package/dist/SideNav/SideNav.d.ts.map +1 -1
- package/dist/SideNav/SideNav.js +5 -5
- package/dist/SideNav/SideNavCollapseButton.d.ts.map +1 -1
- package/dist/SideNav/SideNavCollapseButton.js +13 -10
- package/dist/SideNav/SideNavItem.d.ts +1 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +12 -10
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +87 -34
- package/dist/Spinner/Spinner.d.ts +3 -2
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +11 -2
- package/dist/Switch/Switch.d.ts +8 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +160 -91
- package/dist/TabList/TabList.d.ts +2 -11
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +5 -9
- package/dist/TabList/TabListContext.d.ts +0 -5
- package/dist/TabList/TabListContext.d.ts.map +1 -1
- package/dist/TabList/TabListContext.js +0 -5
- package/dist/Table/BaseTable.d.ts.map +1 -1
- package/dist/Table/BaseTable.js +30 -4
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.d.ts.map +1 -1
- package/dist/Table/plugins/groupedRows/useTableGroupedRows.js +15 -11
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +36 -26
- package/dist/Table/plugins/selection/useTableSelection.d.ts.map +1 -1
- package/dist/Table/plugins/selection/useTableSelection.js +3 -0
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.d.ts.map +1 -1
- package/dist/Table/plugins/stickyColumns/useTableStickyColumns.js +14 -6
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -1
- package/dist/Table/plugins/tree/useTableTreeData.js +29 -23
- package/dist/Table/types.d.ts +32 -0
- package/dist/Table/types.d.ts.map +1 -1
- package/dist/TextArea/TextArea.d.ts +1 -0
- package/dist/TextArea/TextArea.d.ts.map +1 -1
- package/dist/TextArea/TextArea.js +16 -19
- package/dist/TextInput/TextInput.d.ts +1 -0
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +18 -17
- package/dist/TimeInput/TimeInput.d.ts +1 -0
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +15 -17
- package/dist/Timestamp/Timestamp.d.ts +31 -3
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +47 -76
- package/dist/Timestamp/formatInstant.d.ts +41 -0
- package/dist/Timestamp/formatInstant.d.ts.map +1 -0
- package/dist/Timestamp/formatInstant.js +177 -0
- package/dist/Timestamp/index.d.ts +1 -0
- package/dist/Timestamp/index.d.ts.map +1 -1
- package/dist/Timestamp/tooltipEntries.d.ts +56 -0
- package/dist/Timestamp/tooltipEntries.d.ts.map +1 -0
- package/dist/Timestamp/tooltipEntries.js +163 -0
- package/dist/Token/Token.d.ts +30 -3
- package/dist/Token/Token.d.ts.map +1 -1
- package/dist/Token/Token.js +17 -2
- package/dist/Token/index.d.ts +1 -1
- package/dist/Token/index.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +2 -2
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +17 -1
- package/dist/TopNav/TopNavItem.d.ts +3 -1
- package/dist/TopNav/TopNavItem.d.ts.map +1 -1
- package/dist/TopNav/TopNavItem.js +30 -3
- package/dist/TreeList/TreeList.d.ts.map +1 -1
- package/dist/TreeList/TreeList.js +1 -0
- package/dist/TreeList/TreeListBranches.d.ts.map +1 -1
- package/dist/TreeList/TreeListBranches.js +8 -6
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +32 -14
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +19 -10
- package/dist/Typeahead/Typeahead.js +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts +1 -1
- package/dist/Typeahead/TypeaheadItem.d.ts.map +1 -1
- package/dist/Typeahead/TypeaheadItem.js +20 -10
- package/dist/astryx.css +38 -14
- package/dist/astryx.umd.js +52 -52
- package/dist/astryx.umd.js.map +4 -4
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/isRtlElement.d.ts +18 -0
- package/dist/hooks/isRtlElement.d.ts.map +1 -0
- package/dist/hooks/isRtlElement.js +27 -0
- package/dist/hooks/useAnnounce.d.ts +3 -0
- package/dist/hooks/useAnnounce.d.ts.map +1 -1
- package/dist/hooks/useAnnounce.js +39 -1
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +52 -11
- package/dist/hooks/useGridFocus.d.ts +6 -1
- package/dist/hooks/useGridFocus.d.ts.map +1 -1
- package/dist/hooks/useGridFocus.js +12 -9
- package/dist/hooks/useHotkeys.d.ts +9 -0
- package/dist/hooks/useHotkeys.d.ts.map +1 -1
- package/dist/hooks/useHotkeys.js +9 -0
- package/dist/hooks/useInputStatusIcon.d.ts +38 -0
- package/dist/hooks/useInputStatusIcon.d.ts.map +1 -0
- package/dist/hooks/useInputStatusIcon.js +158 -0
- package/dist/hooks/useListFocus.d.ts +39 -1
- package/dist/hooks/useListFocus.d.ts.map +1 -1
- package/dist/hooks/useListFocus.js +54 -9
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +13 -0
- package/dist/utils/index.d.ts +1 -0
- package/dist/utils/index.d.ts.map +1 -1
- package/dist/utils/index.js +2 -1
- package/dist/utils/plainDate.d.ts +17 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +23 -4
- package/dist/utils/rtlStyles.d.ts +24 -0
- package/dist/utils/rtlStyles.d.ts.map +1 -0
- package/dist/utils/rtlStyles.js +27 -0
- package/locales/en.json +76 -0
- package/locales/pseudo.json +57 -0
- package/package.json +6 -1
- package/src/Avatar/Avatar.doc.mjs +18 -4
- package/src/Avatar/Avatar.test.tsx +106 -0
- package/src/Avatar/Avatar.tsx +62 -10
- package/src/Avatar/AvatarStatusDot.doc.mjs +4 -4
- package/src/Avatar/AvatarStatusDot.tsx +6 -4
- package/src/AvatarGroup/AvatarGroup.test.tsx +16 -1
- package/src/Breadcrumbs/BreadcrumbItem.tsx +10 -10
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +51 -0
- package/src/Breadcrumbs/index.ts +4 -0
- package/src/Button/Button.doc.mjs +0 -4
- package/src/Calendar/Calendar.test.tsx +170 -20
- package/src/Calendar/Calendar.tsx +73 -16
- package/src/Calendar/dayCellUtils.test.ts +18 -18
- package/src/Calendar/dayCellUtils.ts +2 -2
- package/src/Calendar/styles.ts +33 -39
- package/src/Card/Card.tsx +1 -1
- package/src/Carousel/Carousel.tsx +25 -6
- package/src/Chat/ChatComposer.doc.mjs +2 -2
- package/src/Chat/ChatComposerInput.doc.mjs +1 -1
- package/src/Chat/ChatDictationButton.tsx +7 -1
- package/src/Chat/ChatMessageBubble.tsx +15 -10
- package/src/Chat/ChatSystemMessage.test.tsx +5 -0
- package/src/Chat/ChatToolCalls.tsx +9 -2
- package/src/CheckboxInput/CheckboxInput.doc.mjs +6 -0
- package/src/CheckboxInput/CheckboxInput.tsx +4 -4
- package/src/CheckboxList/CheckboxList.doc.mjs +6 -0
- package/src/Citation/Citation.doc.mjs +4 -3
- package/src/Citation/Citation.test.tsx +97 -0
- package/src/Citation/Citation.tsx +43 -11
- package/src/CodeBlock/CodeBlock.tsx +35 -8
- package/src/Collapsible/Collapsible.doc.mjs +1 -0
- package/src/Collapsible/Collapsible.test.tsx +7 -0
- package/src/Collapsible/Collapsible.tsx +16 -6
- package/src/CommandPalette/CommandPalette.test.tsx +95 -1
- package/src/CommandPalette/CommandPalette.tsx +41 -2
- package/src/ContextMenu/ContextMenu.test.tsx +42 -0
- package/src/ContextMenu/ContextMenu.tsx +13 -11
- package/src/ContextMenu/index.ts +5 -0
- package/src/DateInput/DateInput.doc.mjs +15 -5
- package/src/DateInput/DateInput.test.tsx +210 -3
- package/src/DateInput/DateInput.tsx +41 -29
- package/src/DateRangeInput/DateRangeInput.doc.mjs +11 -3
- package/src/DateRangeInput/DateRangeInput.test.tsx +120 -3
- package/src/DateRangeInput/DateRangeInput.tsx +29 -27
- package/src/DateTimeInput/DateTimeInput.doc.mjs +22 -1
- package/src/DateTimeInput/DateTimeInput.test.tsx +112 -0
- package/src/DateTimeInput/DateTimeInput.tsx +44 -39
- package/src/Divider/Divider.test.tsx +32 -8
- package/src/Divider/Divider.tsx +14 -1
- package/src/DropdownMenu/DropdownMenu.test.tsx +60 -0
- package/src/DropdownMenu/DropdownMenu.tsx +31 -12
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +8 -2
- package/src/DropdownMenu/DropdownMenuItem.tsx +8 -2
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +8 -2
- package/src/DropdownMenu/DropdownMenuSubMenu.doc.mjs +88 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +635 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +553 -0
- package/src/DropdownMenu/index.ts +16 -0
- package/src/DropdownMenu/menuItemHover.ts +39 -0
- package/src/DropdownMenu/menuItemRoles.ts +9 -0
- package/src/DropdownMenu/renderDropdownItems.tsx +29 -15
- package/src/Field/Field.tsx +14 -9
- package/src/Field/inputStyles.stylex.ts +2 -0
- package/src/FieldStatus/FieldStatus.tsx +10 -4
- package/src/FileInput/FileInput.doc.mjs +13 -7
- package/src/FileInput/FileInput.test.tsx +84 -16
- package/src/FileInput/FileInput.tsx +96 -79
- package/src/HoverCard/useHoverCard.tsx +15 -3
- package/src/Icon/Icon.doc.mjs +13 -0
- package/src/Icon/Icon.test.tsx +89 -0
- package/src/Icon/Icon.tsx +51 -3
- package/src/Lightbox/Lightbox.tsx +11 -3
- package/src/List/List.test.tsx +17 -29
- package/src/List/List.tsx +6 -1
- package/src/Markdown/Markdown.test.tsx +21 -0
- package/src/Markdown/Markdown.tsx +4 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +11 -0
- package/src/MultiSelector/MultiSelector.test.tsx +306 -3
- package/src/MultiSelector/MultiSelector.tsx +88 -57
- package/src/NumberInput/NumberInput.doc.mjs +11 -5
- package/src/NumberInput/NumberInput.test.tsx +48 -0
- package/src/NumberInput/NumberInput.tsx +25 -26
- package/src/Outline/Outline.test.tsx +12 -12
- package/src/Outline/Outline.tsx +2 -2
- package/src/RadioList/RadioList.doc.mjs +6 -0
- package/src/RadioList/RadioList.tsx +2 -2
- package/src/RadioList/RadioListItem.tsx +4 -4
- package/src/Resizable/ResizeHandle.test.tsx +94 -0
- package/src/Resizable/ResizeHandle.tsx +70 -20
- package/src/SegmentedControl/SegmentedControlItem.tsx +2 -0
- package/src/Selector/Selector.doc.mjs +8 -0
- package/src/Selector/Selector.test.tsx +328 -3
- package/src/Selector/Selector.tsx +70 -19
- package/src/SideNav/SideNav.tsx +1 -8
- package/src/SideNav/SideNavCollapseButton.tsx +9 -7
- package/src/SideNav/SideNavItem.tsx +5 -3
- package/src/Slider/Slider.doc.mjs +6 -0
- package/src/Slider/Slider.test.tsx +240 -12
- package/src/Slider/Slider.tsx +96 -23
- package/src/Spinner/Spinner.test.tsx +10 -8
- package/src/Spinner/Spinner.tsx +15 -5
- package/src/Switch/Switch.doc.mjs +142 -42
- package/src/Switch/Switch.test.tsx +22 -0
- package/src/Switch/Switch.tsx +90 -33
- package/src/TabList/TabList.doc.mjs +0 -6
- package/src/TabList/TabList.test.tsx +3 -15
- package/src/TabList/TabList.tsx +6 -17
- package/src/TabList/TabListContext.ts +0 -6
- package/src/Table/BaseTable.tsx +34 -2
- package/src/Table/Table.doc.mjs +11 -0
- package/src/Table/Table.test.tsx +85 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.tsx +9 -6
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +24 -17
- package/src/Table/plugins/selection/useTableSelection.test.tsx +61 -3
- package/src/Table/plugins/selection/useTableSelection.tsx +3 -0
- package/src/Table/plugins/stickyColumns/useTableStickyColumns.tsx +37 -8
- package/src/Table/plugins/tree/useTableTreeData.tsx +17 -13
- package/src/Table/types.ts +33 -0
- package/src/Table/useTableRowStatus.doc.mjs +1 -1
- package/src/TextArea/TextArea.doc.mjs +11 -5
- package/src/TextArea/TextArea.tsx +17 -26
- package/src/TextInput/TextInput.doc.mjs +11 -5
- package/src/TextInput/TextInput.test.tsx +130 -3
- package/src/TextInput/TextInput.tsx +18 -25
- package/src/Thumbnail/Thumbnail.doc.mjs +1 -1
- package/src/TimeInput/TimeInput.doc.mjs +11 -5
- package/src/TimeInput/TimeInput.tsx +14 -25
- package/src/Timestamp/Timestamp.doc.mjs +32 -6
- package/src/Timestamp/Timestamp.test.tsx +371 -0
- package/src/Timestamp/Timestamp.tsx +96 -93
- package/src/Timestamp/formatInstant.ts +218 -0
- package/src/Timestamp/index.ts +4 -0
- package/src/Timestamp/tooltipEntries.test.ts +552 -0
- package/src/Timestamp/tooltipEntries.ts +210 -0
- package/src/Token/Token.test.tsx +21 -15
- package/src/Token/Token.tsx +31 -14
- package/src/Token/index.ts +1 -1
- package/src/Tokenizer/Tokenizer.doc.mjs +8 -1
- package/src/Tokenizer/Tokenizer.tsx +4 -2
- package/src/Tooltip/Tooltip.test.tsx +46 -0
- package/src/Tooltip/useTooltip.tsx +20 -0
- package/src/TopNav/TopNav.test.tsx +93 -2
- package/src/TopNav/TopNavItem.doc.mjs +3 -3
- package/src/TopNav/TopNavItem.tsx +35 -6
- package/src/TopNav/TopNavMegaMenuFeaturedCard.doc.mjs +1 -1
- package/src/TreeList/TreeList.doc.mjs +6 -0
- package/src/TreeList/TreeList.test.tsx +50 -10
- package/src/TreeList/TreeList.tsx +5 -0
- package/src/TreeList/TreeListBranches.tsx +8 -6
- package/src/TreeList/TreeListItem.tsx +33 -11
- package/src/Typeahead/BaseTypeahead.tsx +29 -14
- package/src/Typeahead/Typeahead.doc.mjs +6 -0
- package/src/Typeahead/Typeahead.test.tsx +27 -0
- package/src/Typeahead/Typeahead.tsx +1 -1
- package/src/Typeahead/TypeaheadItem.tsx +2 -1
- package/src/__tests__/inputWidthContract.test.tsx +62 -0
- package/src/doc-mjs.d.ts +19 -0
- package/src/hooks/index.ts +6 -0
- package/src/hooks/isRtlElement.ts +27 -0
- package/src/hooks/useAnnounce.test.tsx +75 -2
- package/src/hooks/useAnnounce.ts +47 -1
- package/src/hooks/useFocusTrap.test.tsx +104 -0
- package/src/hooks/useFocusTrap.ts +61 -12
- package/src/hooks/useGridFocus.doc.mjs +3 -3
- package/src/hooks/useGridFocus.test.tsx +41 -0
- package/src/hooks/useGridFocus.ts +21 -10
- package/src/hooks/useHotkeys.ts +9 -0
- package/src/hooks/useInputStatusIcon.test.tsx +162 -0
- package/src/hooks/useInputStatusIcon.tsx +224 -0
- package/src/hooks/useListFocus.doc.mjs +25 -3
- package/src/hooks/useListFocus.test.tsx +153 -1
- package/src/hooks/useListFocus.ts +102 -9
- package/src/reset.css +0 -26
- package/src/reset.test.ts +60 -0
- package/src/theme/derivedVarRegistry.test.ts +1 -0
- package/src/theme/derivedVarRegistry.ts +6 -0
- package/src/theme/generateThemeRules.test.ts +42 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/plainDate.test.ts +24 -6
- package/src/utils/plainDate.ts +18 -4
- package/src/utils/rtlStyles.ts +27 -0
|
@@ -41,8 +41,9 @@ import {Button} from '../Button';
|
|
|
41
41
|
import {Icon} from '../Icon';
|
|
42
42
|
import {useLayer} from '../Layer';
|
|
43
43
|
import {useScrollOverflow} from '../hooks/useScrollOverflow';
|
|
44
|
+
import {isRtlElement} from '../hooks/isRtlElement';
|
|
44
45
|
import type {BaseProps} from '../BaseProps';
|
|
45
|
-
import {mergeProps, mergeRefs} from '../utils';
|
|
46
|
+
import {mergeProps, mergeRefs, rtlStyles} from '../utils';
|
|
46
47
|
import type {SpacingStep} from '../utils/types';
|
|
47
48
|
import {themeProps} from '../utils/themeProps';
|
|
48
49
|
import {useTranslator} from '../i18n';
|
|
@@ -166,10 +167,16 @@ const styles = stylex.create({
|
|
|
166
167
|
transitionTimingFunction: easeVars['--ease-standard'],
|
|
167
168
|
},
|
|
168
169
|
buttonPillStart: {
|
|
169
|
-
transform:
|
|
170
|
+
transform: {
|
|
171
|
+
default: 'translateX(-50%)',
|
|
172
|
+
':is([dir="rtl"] *)': 'translateX(50%)',
|
|
173
|
+
},
|
|
170
174
|
},
|
|
171
175
|
buttonPillEnd: {
|
|
172
|
-
transform:
|
|
176
|
+
transform: {
|
|
177
|
+
default: 'translateX(50%)',
|
|
178
|
+
':is([dir="rtl"] *)': 'translateX(-50%)',
|
|
179
|
+
},
|
|
173
180
|
},
|
|
174
181
|
buttonHidden: {
|
|
175
182
|
opacity: 0,
|
|
@@ -347,7 +354,11 @@ export function Carousel({
|
|
|
347
354
|
typeof window.matchMedia === 'function' &&
|
|
348
355
|
window.matchMedia('(prefers-reduced-motion: reduce)').matches;
|
|
349
356
|
el.scrollBy({
|
|
350
|
-
|
|
357
|
+
// `direction` is the logical intent (-1 = toward content start, +1 =
|
|
358
|
+
// toward content end). Under RTL the scroll axis is inverted (start is
|
|
359
|
+
// scrollLeft 0, the end is negative), so flip the physical delta sign.
|
|
360
|
+
left:
|
|
361
|
+
(isRtlElement(el) ? -1 : 1) * direction * Math.max(amount, itemWidth),
|
|
351
362
|
behavior: prefersReducedMotion ? 'auto' : 'smooth',
|
|
352
363
|
});
|
|
353
364
|
}, []);
|
|
@@ -425,7 +436,11 @@ export function Carousel({
|
|
|
425
436
|
!overflowStart && styles.buttonHidden,
|
|
426
437
|
)}>
|
|
427
438
|
<Button
|
|
428
|
-
icon={
|
|
439
|
+
icon={
|
|
440
|
+
<span {...stylex.props(rtlStyles.mirror)}>
|
|
441
|
+
<Icon icon="chevronLeft" size="xsm" />
|
|
442
|
+
</span>
|
|
443
|
+
}
|
|
429
444
|
label={t('@astryx.carousel.scrollLeft')}
|
|
430
445
|
variant="ghost"
|
|
431
446
|
size="sm"
|
|
@@ -446,7 +461,11 @@ export function Carousel({
|
|
|
446
461
|
!overflowEnd && styles.buttonHidden,
|
|
447
462
|
)}>
|
|
448
463
|
<Button
|
|
449
|
-
icon={
|
|
464
|
+
icon={
|
|
465
|
+
<span {...stylex.props(rtlStyles.mirror)}>
|
|
466
|
+
<Icon icon="chevronRight" size="xsm" />
|
|
467
|
+
</span>
|
|
468
|
+
}
|
|
450
469
|
label={t('@astryx.carousel.scrollRight')}
|
|
451
470
|
variant="ghost"
|
|
452
471
|
size="sm"
|
|
@@ -60,7 +60,7 @@ export const docs = {
|
|
|
60
60
|
name: 'elevation',
|
|
61
61
|
type: "'none' | 'low'",
|
|
62
62
|
description:
|
|
63
|
-
"Resting elevation of the composer body. `low` (the default) keeps today's raised look
|
|
63
|
+
"Resting elevation of the composer body. `low` (the default) keeps today's raised look: low at rest, bumping to med on hover / focus. `none` flattens it and draws a border with the same rest / hover / focus treatment as a text input (emphasized border → accent on focus, matching inset rings).",
|
|
64
64
|
default: "'low'",
|
|
65
65
|
},
|
|
66
66
|
{
|
|
@@ -109,7 +109,7 @@ export const docs = {
|
|
|
109
109
|
{
|
|
110
110
|
name: 'input',
|
|
111
111
|
type: 'ReactNode',
|
|
112
|
-
description: 'Slot: custom input element. Replaces the default input. Use ChatComposerInput for trigger menus/tokens, or wire any input (plain textarea, rich editor) to the composition contract via useChatComposerContext()
|
|
112
|
+
description: 'Slot: custom input element. Replaces the default input. Use ChatComposerInput for trigger menus/tokens, or wire any input (plain textarea, rich editor) to the composition contract via useChatComposerContext(): read value/onChange/onSubmit/canSend and register a focus control on inputControlRef so body-click-to-focus works.',
|
|
113
113
|
slotElements: [
|
|
114
114
|
{
|
|
115
115
|
__element: 'TextInput',
|
|
@@ -83,7 +83,7 @@ export const docs = {
|
|
|
83
83
|
{
|
|
84
84
|
name: 'onKeyDown',
|
|
85
85
|
type: '(event) => void',
|
|
86
|
-
description: 'Key-down handler invoked before the built-in Enter/history behavior (after any open trigger menu). The seam for platform-specific keys: call event.preventDefault() to suppress the default submit (e.g. newline on a touch keyboard), or act on the event yourself to add behavior (e.g. submit on Cmd/Ctrl+Enter). IME composition is always respected
|
|
86
|
+
description: 'Key-down handler invoked before the built-in Enter/history behavior (after any open trigger menu). The seam for platform-specific keys: call event.preventDefault() to suppress the default submit (e.g. newline on a touch keyboard), or act on the event yourself to add behavior (e.g. submit on Cmd/Ctrl+Enter). IME composition is always respected; Enter never submits mid-composition.',
|
|
87
87
|
},
|
|
88
88
|
],
|
|
89
89
|
};
|
|
@@ -26,6 +26,7 @@ import {Button} from '../Button';
|
|
|
26
26
|
import {Icon} from '../Icon';
|
|
27
27
|
import {mergeProps} from '../utils';
|
|
28
28
|
import type {BaseProps} from '../BaseProps';
|
|
29
|
+
import {useTranslator} from '../i18n';
|
|
29
30
|
|
|
30
31
|
// =============================================================================
|
|
31
32
|
// Types
|
|
@@ -110,13 +111,18 @@ export function ChatDictationButton({
|
|
|
110
111
|
style,
|
|
111
112
|
...rest
|
|
112
113
|
}: ChatDictationButtonProps) {
|
|
114
|
+
const t = useTranslator();
|
|
115
|
+
|
|
113
116
|
if (isHiddenWhenUnsupported && !dictation.isSupported) {
|
|
114
117
|
return null;
|
|
115
118
|
}
|
|
116
119
|
|
|
117
120
|
const {isListening, bands, volume: rawVolume} = dictation;
|
|
118
121
|
const accessibleLabel =
|
|
119
|
-
label ??
|
|
122
|
+
label ??
|
|
123
|
+
(isListening
|
|
124
|
+
? t('@astryx.chatDictationButton.stopDictation')
|
|
125
|
+
: t('@astryx.chatDictationButton.startDictation'));
|
|
120
126
|
|
|
121
127
|
// Boost each band for visibility — quiet speech (0-10%) maps to full visual range
|
|
122
128
|
const boostedBands = bands.map(b => Math.min(Math.pow(b / 0.2, 0.5), 1));
|
|
@@ -160,27 +160,32 @@ const styles = stylex.create({
|
|
|
160
160
|
backgroundColor: 'transparent',
|
|
161
161
|
color: colorVars['--color-text-primary'],
|
|
162
162
|
},
|
|
163
|
-
// Grouped bubble corners — assistant (
|
|
163
|
+
// Grouped bubble corners — assistant (inline-start side tight).
|
|
164
|
+
// Logical radii so the tail follows reading direction: inline-start is the
|
|
165
|
+
// left edge under LTR and the right edge under RTL (assistant tucks toward
|
|
166
|
+
// the start of the line in both directions).
|
|
164
167
|
groupFirstAssistant: {
|
|
165
|
-
|
|
168
|
+
borderEndStartRadius: radiusVars['--radius-inner'],
|
|
166
169
|
},
|
|
167
170
|
groupMiddleAssistant: {
|
|
168
|
-
|
|
169
|
-
|
|
171
|
+
borderStartStartRadius: radiusVars['--radius-inner'],
|
|
172
|
+
borderEndStartRadius: radiusVars['--radius-inner'],
|
|
170
173
|
},
|
|
171
174
|
groupLastAssistant: {
|
|
172
|
-
|
|
175
|
+
borderStartStartRadius: radiusVars['--radius-inner'],
|
|
173
176
|
},
|
|
174
|
-
// Grouped bubble corners — user (
|
|
177
|
+
// Grouped bubble corners — user (inline-end side tight).
|
|
178
|
+
// Logical radii: inline-end is the right edge under LTR and the left edge
|
|
179
|
+
// under RTL (user tucks toward the end of the line in both directions).
|
|
175
180
|
groupFirstUser: {
|
|
176
|
-
|
|
181
|
+
borderEndEndRadius: radiusVars['--radius-inner'],
|
|
177
182
|
},
|
|
178
183
|
groupMiddleUser: {
|
|
179
|
-
|
|
180
|
-
|
|
184
|
+
borderStartEndRadius: radiusVars['--radius-inner'],
|
|
185
|
+
borderEndEndRadius: radiusVars['--radius-inner'],
|
|
181
186
|
},
|
|
182
187
|
groupLastUser: {
|
|
183
|
-
|
|
188
|
+
borderStartEndRadius: radiusVars['--radius-inner'],
|
|
184
189
|
},
|
|
185
190
|
});
|
|
186
191
|
|
|
@@ -28,6 +28,11 @@ describe('ChatSystemMessage', () => {
|
|
|
28
28
|
expect(screen.getByText('Today')).toBeTruthy();
|
|
29
29
|
});
|
|
30
30
|
|
|
31
|
+
it('exposes the divider variant label as the separator accessible name', () => {
|
|
32
|
+
render(<ChatSystemMessage variant="divider">Today</ChatSystemMessage>);
|
|
33
|
+
expect(screen.getByRole('separator')).toHaveAccessibleName('Today');
|
|
34
|
+
});
|
|
35
|
+
|
|
31
36
|
it('renders icon', () => {
|
|
32
37
|
render(
|
|
33
38
|
<ChatSystemMessage icon={<span data-testid="icon">*</span>}>
|
|
@@ -37,6 +37,7 @@ import {Icon, type IconName} from '../Icon';
|
|
|
37
37
|
import {Spinner} from '../Spinner';
|
|
38
38
|
import {VisuallyHidden} from '../VisuallyHidden';
|
|
39
39
|
import {themeProps} from '../utils/themeProps';
|
|
40
|
+
import {useTranslator} from '../i18n';
|
|
40
41
|
|
|
41
42
|
// =============================================================================
|
|
42
43
|
// Types
|
|
@@ -363,6 +364,7 @@ function getToolCallKey(call: ChatToolCallItem): string {
|
|
|
363
364
|
// =============================================================================
|
|
364
365
|
|
|
365
366
|
function CallRow({call}: {call: ChatToolCallItem}) {
|
|
367
|
+
const t = useTranslator();
|
|
366
368
|
const status = call.status ?? 'complete';
|
|
367
369
|
const hasDetail = call.resultDetail != null;
|
|
368
370
|
const [isDetailOpen, setIsDetailOpen] = useState(false);
|
|
@@ -414,7 +416,11 @@ function CallRow({call}: {call: ChatToolCallItem}) {
|
|
|
414
416
|
// as real text so it reaches screen readers, keyboard, and touch
|
|
415
417
|
// users. Rendering it inside the row also folds it into the
|
|
416
418
|
// accessible name of expandable (role="button") rows.
|
|
417
|
-
<VisuallyHidden>
|
|
419
|
+
<VisuallyHidden>
|
|
420
|
+
{t('@astryx.chatToolCalls.error', {
|
|
421
|
+
message: call.errorMessage ?? '',
|
|
422
|
+
})}
|
|
423
|
+
</VisuallyHidden>
|
|
418
424
|
)}
|
|
419
425
|
</span>
|
|
420
426
|
<span {...stylex.props(styles.callName)}>{call.name}</span>
|
|
@@ -498,6 +504,7 @@ function CallRow({call}: {call: ChatToolCallItem}) {
|
|
|
498
504
|
* ```
|
|
499
505
|
*/
|
|
500
506
|
export function ChatToolCalls(props: ChatToolCallsProps) {
|
|
507
|
+
const t = useTranslator();
|
|
501
508
|
const {
|
|
502
509
|
calls,
|
|
503
510
|
label: _customLabel,
|
|
@@ -580,7 +587,7 @@ export function ChatToolCalls(props: ChatToolCallsProps) {
|
|
|
580
587
|
<Icon icon="wrench" size="sm" color="inherit" />
|
|
581
588
|
</span>
|
|
582
589
|
<span {...stylex.props(styles.groupLabel)}>
|
|
583
|
-
{calls.length}
|
|
590
|
+
{t('@astryx.chatToolCalls.groupLabel', {count: calls.length})}
|
|
584
591
|
</span>
|
|
585
592
|
</>
|
|
586
593
|
) : (
|
|
@@ -121,6 +121,12 @@ export const docs = {
|
|
|
121
121
|
description:
|
|
122
122
|
'Status indicator. Displays a colored message box below the checkbox and sets aria-invalid for errors.',
|
|
123
123
|
},
|
|
124
|
+
{
|
|
125
|
+
name: 'width',
|
|
126
|
+
type: 'SizeValue',
|
|
127
|
+
description:
|
|
128
|
+
'Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.',
|
|
129
|
+
},
|
|
124
130
|
],
|
|
125
131
|
theming: {
|
|
126
132
|
targets: [
|
|
@@ -198,12 +198,12 @@ const wrapperSizeStyles = stylex.create({
|
|
|
198
198
|
|
|
199
199
|
const checkboxSizeStyles = stylex.create({
|
|
200
200
|
sm: {
|
|
201
|
-
width:
|
|
202
|
-
height:
|
|
201
|
+
width: 20,
|
|
202
|
+
height: 20,
|
|
203
203
|
},
|
|
204
204
|
md: {
|
|
205
|
-
width:
|
|
206
|
-
height:
|
|
205
|
+
width: 24,
|
|
206
|
+
height: 24,
|
|
207
207
|
},
|
|
208
208
|
});
|
|
209
209
|
|
|
@@ -88,6 +88,12 @@ export const docs = {
|
|
|
88
88
|
type: "{type: 'warning' | 'error' | 'success', message?: string}",
|
|
89
89
|
description: 'Status indicator ({ type, message }).',
|
|
90
90
|
},
|
|
91
|
+
{
|
|
92
|
+
name: 'width',
|
|
93
|
+
type: 'SizeValue',
|
|
94
|
+
description:
|
|
95
|
+
'Width of the field (number = pixels, string used as-is, e.g. "100%"). Sizes the whole field (label, control, and status) so they stay aligned.',
|
|
96
|
+
},
|
|
91
97
|
{
|
|
92
98
|
name: 'xstyle',
|
|
93
99
|
type: 'StyleXStyles',
|
|
@@ -39,7 +39,7 @@ export const docs = {
|
|
|
39
39
|
name: 'Icon',
|
|
40
40
|
required: false,
|
|
41
41
|
description:
|
|
42
|
-
'An optional
|
|
42
|
+
'An optional source icon shown before the label text. Accepts a favicon/logo image URL (via source.src) or a React node such as an Astryx <Icon>. Only available in the label variant.',
|
|
43
43
|
},
|
|
44
44
|
{
|
|
45
45
|
name: 'Label text',
|
|
@@ -71,7 +71,7 @@ export const docs = {
|
|
|
71
71
|
name: 'source',
|
|
72
72
|
type: 'CitationSource',
|
|
73
73
|
description:
|
|
74
|
-
'The citation source object containing title, url, and optional icon.',
|
|
74
|
+
'The citation source object containing title, url, an optional image src, and an optional icon node.',
|
|
75
75
|
required: true,
|
|
76
76
|
},
|
|
77
77
|
{
|
|
@@ -121,7 +121,8 @@ export const docsDense = {
|
|
|
121
121
|
],
|
|
122
122
|
},
|
|
123
123
|
propDescriptions: {
|
|
124
|
-
source:
|
|
124
|
+
source:
|
|
125
|
+
'citation source object with title, url, optional image src, and optional icon node.',
|
|
125
126
|
number: 'display index for this citation.',
|
|
126
127
|
variant: 'display style: label chip with source title or compact numbered badge.',
|
|
127
128
|
},
|
|
@@ -169,4 +169,101 @@ describe('Citation', () => {
|
|
|
169
169
|
expect(el.classList.contains(cls)).toBe(true);
|
|
170
170
|
}
|
|
171
171
|
});
|
|
172
|
+
|
|
173
|
+
// --- Source icon: image URL (back-compat) vs ReactNode ---------------------
|
|
174
|
+
|
|
175
|
+
it('renders a legacy string icon as a decorative image (back-compat)', () => {
|
|
176
|
+
// Existing callers pass a favicon URL to `source.icon`. A bare string must
|
|
177
|
+
// still render as <img src>, unchanged from the original behavior.
|
|
178
|
+
const {container} = render(
|
|
179
|
+
<Citation
|
|
180
|
+
source={{
|
|
181
|
+
title: 'GitHub',
|
|
182
|
+
url: 'https://github.com',
|
|
183
|
+
icon: 'https://example.com/favicon.png',
|
|
184
|
+
}}
|
|
185
|
+
number={1}
|
|
186
|
+
data-testid="citation"
|
|
187
|
+
/>,
|
|
188
|
+
);
|
|
189
|
+
const img = container.querySelector('img');
|
|
190
|
+
expect(img).not.toBeNull();
|
|
191
|
+
expect(img).toHaveAttribute('src', 'https://example.com/favicon.png');
|
|
192
|
+
// Decorative: empty alt, and the wrapper is aria-hidden.
|
|
193
|
+
expect(img).toHaveAttribute('alt', '');
|
|
194
|
+
expect(container.querySelector('[aria-hidden="true"] img')).toBe(img);
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
it('renders source.src as a decorative image', () => {
|
|
198
|
+
const {container} = render(
|
|
199
|
+
<Citation
|
|
200
|
+
source={{
|
|
201
|
+
title: 'GitHub',
|
|
202
|
+
url: 'https://github.com',
|
|
203
|
+
src: 'https://example.com/logo.png',
|
|
204
|
+
}}
|
|
205
|
+
number={1}
|
|
206
|
+
data-testid="citation"
|
|
207
|
+
/>,
|
|
208
|
+
);
|
|
209
|
+
const img = container.querySelector('img');
|
|
210
|
+
expect(img).toHaveAttribute('src', 'https://example.com/logo.png');
|
|
211
|
+
expect(img).toHaveAttribute('alt', '');
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
it('renders a ReactNode icon as-is (not an <img>)', () => {
|
|
215
|
+
const {container} = render(
|
|
216
|
+
<Citation
|
|
217
|
+
source={{
|
|
218
|
+
title: 'GitHub',
|
|
219
|
+
url: 'https://github.com',
|
|
220
|
+
icon: <svg data-testid="custom-icon" />,
|
|
221
|
+
}}
|
|
222
|
+
number={1}
|
|
223
|
+
data-testid="citation"
|
|
224
|
+
/>,
|
|
225
|
+
);
|
|
226
|
+
// The node renders directly; no <img> is produced for a node icon.
|
|
227
|
+
expect(container.querySelector('img')).toBeNull();
|
|
228
|
+
expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
|
|
229
|
+
// Still decorative — wrapped in an aria-hidden container.
|
|
230
|
+
expect(
|
|
231
|
+
container.querySelector(
|
|
232
|
+
'[aria-hidden="true"] [data-testid="custom-icon"]',
|
|
233
|
+
),
|
|
234
|
+
).not.toBeNull();
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
it('prefers a node icon over src when both are provided', () => {
|
|
238
|
+
const {container} = render(
|
|
239
|
+
<Citation
|
|
240
|
+
source={{
|
|
241
|
+
title: 'GitHub',
|
|
242
|
+
url: 'https://github.com',
|
|
243
|
+
src: 'https://example.com/logo.png',
|
|
244
|
+
icon: <svg data-testid="custom-icon" />,
|
|
245
|
+
}}
|
|
246
|
+
number={1}
|
|
247
|
+
data-testid="citation"
|
|
248
|
+
/>,
|
|
249
|
+
);
|
|
250
|
+
expect(screen.getByTestId('custom-icon')).toBeInTheDocument();
|
|
251
|
+
expect(container.querySelector('img')).toBeNull();
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
it('keeps aria-label as the sole accessible name when an icon is present', () => {
|
|
255
|
+
render(
|
|
256
|
+
<Citation
|
|
257
|
+
source={{
|
|
258
|
+
title: 'GitHub',
|
|
259
|
+
url: 'https://github.com',
|
|
260
|
+
icon: 'https://example.com/favicon.png',
|
|
261
|
+
}}
|
|
262
|
+
number={2}
|
|
263
|
+
data-testid="citation"
|
|
264
|
+
/>,
|
|
265
|
+
);
|
|
266
|
+
const el = screen.getByTestId('citation');
|
|
267
|
+
expect(el).toHaveAttribute('aria-label', 'Citation 2: GitHub');
|
|
268
|
+
});
|
|
172
269
|
});
|
|
@@ -10,10 +10,14 @@
|
|
|
10
10
|
*
|
|
11
11
|
* SYNC: When modified, update these files to stay in sync:
|
|
12
12
|
* - /packages/core/src/Citation/index.ts (exports if types change)
|
|
13
|
+
* - /packages/core/src/Citation/Citation.doc.mjs (props table, features)
|
|
14
|
+
* - /packages/core/src/Citation/Citation.test.tsx (tests for new/changed behavior)
|
|
15
|
+
* - /apps/storybook/stories/Citation.stories.tsx (storybook stories)
|
|
13
16
|
* - /packages/cli/templates/blocks/components/Citation/ (showcase blocks)
|
|
14
17
|
*/
|
|
15
18
|
|
|
16
19
|
import type React from 'react';
|
|
20
|
+
import type {ReactNode} from 'react';
|
|
17
21
|
import * as stylex from '@stylexjs/stylex';
|
|
18
22
|
import {
|
|
19
23
|
colorVars,
|
|
@@ -29,11 +33,29 @@ import {mergeProps} from '../utils';
|
|
|
29
33
|
import type {BaseProps} from '../BaseProps';
|
|
30
34
|
import {themeProps} from '../utils/themeProps';
|
|
31
35
|
import {useTranslator} from '../i18n';
|
|
36
|
+
import {renderIconSlot} from '../Icon';
|
|
32
37
|
|
|
33
38
|
export interface CitationSource {
|
|
34
39
|
title?: string;
|
|
35
40
|
url?: string;
|
|
36
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Image URL for a favicon or source logo, rendered as `<img src>` inside the
|
|
43
|
+
* icon circle. This is the idiomatic field for image sources (mirrors
|
|
44
|
+
* `Avatar`/`Thumbnail` `src`). When both `src` and a non-string `icon` are
|
|
45
|
+
* provided, `icon` wins.
|
|
46
|
+
*/
|
|
47
|
+
src?: string;
|
|
48
|
+
/**
|
|
49
|
+
* Source icon shown before the label text (label variant only). Accepts:
|
|
50
|
+
* - a React node / Astryx `<Icon>` / SVG element — rendered as-is, or
|
|
51
|
+
* - a string image URL — rendered as `<img src>` for backward compatibility
|
|
52
|
+
* with callers that passed a favicon URL here.
|
|
53
|
+
*
|
|
54
|
+
* Note: unlike icon slots elsewhere in the system, a bare string is treated
|
|
55
|
+
* as an image URL (not a semantic icon name) to preserve the original
|
|
56
|
+
* favicon behavior. Pass an Astryx `<Icon>` (or other node) for a real icon.
|
|
57
|
+
*/
|
|
58
|
+
icon?: ReactNode;
|
|
37
59
|
}
|
|
38
60
|
|
|
39
61
|
export interface CitationProps extends BaseProps<HTMLElement> {
|
|
@@ -162,7 +184,18 @@ export function Citation({
|
|
|
162
184
|
const t = useTranslator();
|
|
163
185
|
const title = source.title ?? String(number);
|
|
164
186
|
const href = source.url;
|
|
165
|
-
|
|
187
|
+
|
|
188
|
+
// Resolve the source icon. A non-string `icon` node renders as-is (an Astryx
|
|
189
|
+
// <Icon>, SVG, avatar, etc.). Otherwise fall back to an image URL: `src`, or
|
|
190
|
+
// a legacy string passed to `icon` (back-compat — favicon URLs still render
|
|
191
|
+
// as <img>). The icon is decorative; the accessible name comes solely from
|
|
192
|
+
// the element's aria-label, so nothing is double-announced.
|
|
193
|
+
const iconNode =
|
|
194
|
+
source.icon != null && typeof source.icon !== 'string' ? source.icon : null;
|
|
195
|
+
const imageSrc =
|
|
196
|
+
source.src ?? (typeof source.icon === 'string' ? source.icon : undefined);
|
|
197
|
+
const hasIcon = iconNode != null || imageSrc != null;
|
|
198
|
+
|
|
166
199
|
const Tag = href ? 'a' : 'span';
|
|
167
200
|
// `doc-noteref` is a reference role — only appropriate on the interactive
|
|
168
201
|
// link form. On a plain (unlinked) span it is not a permitted role
|
|
@@ -218,7 +251,7 @@ export function Citation({
|
|
|
218
251
|
themeProps('citation', {variant}),
|
|
219
252
|
stylex.props(
|
|
220
253
|
styles.label,
|
|
221
|
-
|
|
254
|
+
hasIcon && styles.labelWithIcon,
|
|
222
255
|
href != null && styles.labelHover,
|
|
223
256
|
href != null && styles.labelInteractive,
|
|
224
257
|
xstyle,
|
|
@@ -226,14 +259,13 @@ export function Citation({
|
|
|
226
259
|
className,
|
|
227
260
|
style,
|
|
228
261
|
)}>
|
|
229
|
-
{
|
|
230
|
-
<span {...stylex.props(styles.iconWrap)}>
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
/>
|
|
262
|
+
{hasIcon && (
|
|
263
|
+
<span aria-hidden="true" {...stylex.props(styles.iconWrap)}>
|
|
264
|
+
{iconNode != null ? (
|
|
265
|
+
renderIconSlot(iconNode, {size: 'sm'})
|
|
266
|
+
) : (
|
|
267
|
+
<img src={imageSrc} alt="" {...stylex.props(styles.icon)} />
|
|
268
|
+
)}
|
|
237
269
|
</span>
|
|
238
270
|
)}
|
|
239
271
|
<span {...stylex.props(styles.labelText)}>{title}</span>
|
|
@@ -88,6 +88,23 @@ const dynamicStyles = stylex.create({
|
|
|
88
88
|
}),
|
|
89
89
|
});
|
|
90
90
|
|
|
91
|
+
// Light reveal so the leading chevron eases into view instead of popping in.
|
|
92
|
+
// Growing the chevron's own footprint (width + inline margin) from zero slides
|
|
93
|
+
// the title into place instead of snapping it over, and clipping keeps the
|
|
94
|
+
// glyph from spilling while it's mid-reveal.
|
|
95
|
+
const chevronReveal = stylex.keyframes({
|
|
96
|
+
from: {
|
|
97
|
+
width: 0,
|
|
98
|
+
marginInlineEnd: 0,
|
|
99
|
+
opacity: 0,
|
|
100
|
+
},
|
|
101
|
+
to: {
|
|
102
|
+
width: '14px',
|
|
103
|
+
marginInlineEnd: spacingVars['--spacing-1'],
|
|
104
|
+
opacity: 1,
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
|
|
91
108
|
const styles = stylex.create({
|
|
92
109
|
root: {
|
|
93
110
|
position: 'relative',
|
|
@@ -133,7 +150,6 @@ const styles = stylex.create({
|
|
|
133
150
|
headerTitle: {
|
|
134
151
|
display: 'flex',
|
|
135
152
|
alignItems: 'center',
|
|
136
|
-
gap: spacingVars['--spacing-1'],
|
|
137
153
|
fontSize: typeScaleVars['--text-supporting-size'],
|
|
138
154
|
fontFamily: typographyVars['--font-family-code'],
|
|
139
155
|
fontWeight: fontWeightVars['--font-weight-medium'],
|
|
@@ -173,13 +189,24 @@ const styles = stylex.create({
|
|
|
173
189
|
flexShrink: 0,
|
|
174
190
|
width: '14px',
|
|
175
191
|
height: '14px',
|
|
192
|
+
marginInlineEnd: spacingVars['--spacing-1'],
|
|
193
|
+
overflow: 'hidden',
|
|
176
194
|
color: 'var(--color-syntax-comment)',
|
|
195
|
+
animationName: {
|
|
196
|
+
default: chevronReveal,
|
|
197
|
+
'@media (prefers-reduced-motion: reduce)': 'none',
|
|
198
|
+
},
|
|
199
|
+
animationDuration: durationVars['--duration-medium'],
|
|
200
|
+
animationTimingFunction: easeVars['--ease-standard'],
|
|
177
201
|
transitionProperty: 'transform',
|
|
178
202
|
transitionDuration: durationVars['--duration-fast'],
|
|
179
203
|
transitionTimingFunction: easeVars['--ease-standard'],
|
|
180
204
|
},
|
|
181
|
-
|
|
182
|
-
|
|
205
|
+
collapseChevronExpanded: {
|
|
206
|
+
// Leading disclosure convention (matches TreeList/Table): the resting
|
|
207
|
+
// chevronRight points right (>) when collapsed; rotate it down (v) when
|
|
208
|
+
// expanded.
|
|
209
|
+
transform: 'rotate(90deg)',
|
|
183
210
|
},
|
|
184
211
|
headerCollapsible: {
|
|
185
212
|
cursor: 'pointer',
|
|
@@ -845,18 +872,18 @@ export function CodeBlock({
|
|
|
845
872
|
canCollapse && styles.headerCollapsible,
|
|
846
873
|
)}>
|
|
847
874
|
<span {...stylex.props(styles.headerTitle)}>
|
|
848
|
-
{title}
|
|
849
|
-
{title && languageLabel ? ' — ' : ''}
|
|
850
|
-
{languageLabel}
|
|
851
875
|
{canCollapse && (
|
|
852
876
|
<span
|
|
853
877
|
{...stylex.props(
|
|
854
878
|
styles.collapseChevron,
|
|
855
|
-
isCollapsed && styles.
|
|
879
|
+
!isCollapsed && styles.collapseChevronExpanded,
|
|
856
880
|
)}>
|
|
857
|
-
<Icon icon="
|
|
881
|
+
<Icon icon="chevronRight" size="xsm" color="inherit" />
|
|
858
882
|
</span>
|
|
859
883
|
)}
|
|
884
|
+
{title}
|
|
885
|
+
{title && languageLabel ? ' — ' : ''}
|
|
886
|
+
{languageLabel}
|
|
860
887
|
</span>
|
|
861
888
|
</div>
|
|
862
889
|
{copyButtonEl}
|
|
@@ -17,6 +17,7 @@ export const docs = {
|
|
|
17
17
|
theming: {
|
|
18
18
|
targets: [
|
|
19
19
|
{className: 'astryx-collapsible', visualProps: ['density']},
|
|
20
|
+
{className: 'astryx-collapsible-trigger', visualProps: ['density']},
|
|
20
21
|
{className: 'astryx-collapsible-content', visualProps: ['density']},
|
|
21
22
|
{className: 'astryx-collapsible-group', visualProps: ['density']},
|
|
22
23
|
],
|
|
@@ -72,6 +72,13 @@ describe('Collapsible', () => {
|
|
|
72
72
|
expect(screen.getByTestId('root')).toHaveClass('astryx-collapsible');
|
|
73
73
|
});
|
|
74
74
|
|
|
75
|
+
it('renders the stable astryx-collapsible-trigger class on the trigger button', () => {
|
|
76
|
+
render(<Collapsible trigger="T">c</Collapsible>);
|
|
77
|
+
expect(screen.getByRole('button')).toHaveClass(
|
|
78
|
+
'astryx-collapsible-trigger',
|
|
79
|
+
);
|
|
80
|
+
});
|
|
81
|
+
|
|
75
82
|
it('renders the stable astryx-collapsible-content class on the content area', () => {
|
|
76
83
|
render(<Collapsible trigger="T">c</Collapsible>);
|
|
77
84
|
const content = contentFor(screen.getByRole('button'));
|
|
@@ -51,7 +51,12 @@ const styles = stylex.create({
|
|
|
51
51
|
root: {
|
|
52
52
|
width: '100%',
|
|
53
53
|
},
|
|
54
|
-
// Trigger button — full width, flex row, no browser button styling
|
|
54
|
+
// Trigger button — full width, flex row, no browser button styling.
|
|
55
|
+
// Anchors heading-adjacent typography (body family, large size, semibold)
|
|
56
|
+
// so the label reads as a section header regardless of where the
|
|
57
|
+
// Collapsible is placed. External themes retarget it independently from the
|
|
58
|
+
// content via the `astryx-collapsible-trigger` target — e.g. a heading font
|
|
59
|
+
// on the trigger while the content stays on the body font.
|
|
55
60
|
trigger: {
|
|
56
61
|
all: 'unset',
|
|
57
62
|
boxSizing: 'border-box',
|
|
@@ -113,7 +118,7 @@ const styles = stylex.create({
|
|
|
113
118
|
// Anchors body typography so revealed text renders at the system's body
|
|
114
119
|
// scale (family/size/weight/leading) instead of inheriting from wherever
|
|
115
120
|
// the Collapsible is placed. External themes override via the
|
|
116
|
-
// `astryx-collapsible-content` target.
|
|
121
|
+
// `astryx-collapsible-content` target, independently from the trigger.
|
|
117
122
|
content: {
|
|
118
123
|
paddingBlockStart: spacingVars['--spacing-1'],
|
|
119
124
|
fontFamily: typographyVars['--font-family-body'],
|
|
@@ -318,10 +323,15 @@ export function Collapsible({
|
|
|
318
323
|
// the system-wide disabled convention (never native `disabled`, which
|
|
319
324
|
// would swallow events like a wrapping tooltip's hover).
|
|
320
325
|
tabIndex={isDisabled ? -1 : undefined}
|
|
321
|
-
{...
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
326
|
+
{...mergeProps(
|
|
327
|
+
themeProps('collapsible-trigger', {
|
|
328
|
+
density: density ?? undefined,
|
|
329
|
+
}),
|
|
330
|
+
stylex.props(
|
|
331
|
+
styles.trigger,
|
|
332
|
+
density != null && triggerDensity[density],
|
|
333
|
+
isDisabled && styles.triggerDisabled,
|
|
334
|
+
),
|
|
325
335
|
)}>
|
|
326
336
|
<span {...stylex.props(styles.triggerLabel)}>{trigger}</span>
|
|
327
337
|
<span
|