@astryxdesign/core 0.5.2-canary.2da7a39 → 0.5.2-canary.2e51213
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/AppShell/AppShell.d.ts +2 -2
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/AppShell/AppShell.js +10 -7
- package/dist/Banner/Banner.d.ts +5 -0
- package/dist/Banner/Banner.d.ts.map +1 -1
- package/dist/Banner/Banner.js +7 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +3 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +22 -15
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +2 -2
- package/dist/Chat/ChatComposer.d.ts +2 -2
- package/dist/Chat/ChatComposer.d.ts.map +1 -1
- package/dist/Chat/ChatComposer.js +21 -2
- package/dist/Chat/ChatToolCalls.d.ts +1 -1
- package/dist/Chat/ChatToolCalls.d.ts.map +1 -1
- package/dist/Chat/ChatToolCalls.js +12 -34
- package/dist/Chat/useChatNewMessages.js +3 -3
- package/dist/CheckboxList/CheckboxListItem.d.ts +5 -3
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.d.ts +47 -13
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +269 -162
- package/dist/DateTimeInput/NativeDateSegment.d.ts +24 -0
- package/dist/DateTimeInput/NativeDateSegment.d.ts.map +1 -0
- package/dist/DateTimeInput/NativeDateSegment.js +235 -0
- package/dist/DateTimeInput/NativeTimeSegment.d.ts +30 -0
- package/dist/DateTimeInput/NativeTimeSegment.d.ts.map +1 -0
- package/dist/DateTimeInput/NativeTimeSegment.js +248 -0
- package/dist/DateTimeInput/index.d.ts +1 -1
- package/dist/DateTimeInput/index.d.ts.map +1 -1
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts +95 -0
- package/dist/DateTimeInput/nativePickerSegmentStyles.d.ts.map +1 -0
- package/dist/DateTimeInput/nativePickerSegmentStyles.js +103 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +2 -4
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +10 -4
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +3 -5
- package/dist/FieldStatus/FieldStatus.d.ts.map +1 -1
- package/dist/FieldStatus/FieldStatus.js +4 -2
- package/dist/Layer/useTouchTrigger.d.ts.map +1 -1
- package/dist/Layer/useTouchTrigger.js +2 -4
- package/dist/Layout/Layout.d.ts +7 -8
- package/dist/Layout/Layout.d.ts.map +1 -1
- package/dist/Layout/Layout.js +7 -8
- package/dist/MultiSelector/MultiSelector.d.ts +11 -1
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +89 -45
- package/dist/RadioList/RadioListItem.d.ts +30 -5
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +17 -4
- package/dist/Resizable/ResizeHandle.d.ts.map +1 -1
- package/dist/Resizable/ResizeHandle.js +102 -44
- package/dist/Resizable/index.d.ts +2 -0
- package/dist/Resizable/index.d.ts.map +1 -1
- package/dist/Resizable/index.js +1 -0
- package/dist/Resizable/useResizable.d.ts +89 -8
- package/dist/Resizable/useResizable.d.ts.map +1 -1
- package/dist/Resizable/useResizable.js +521 -38
- package/dist/Resizable/utils.d.ts +35 -0
- package/dist/Resizable/utils.d.ts.map +1 -0
- package/dist/Resizable/utils.js +27 -0
- package/dist/Selector/Selector.d.ts +10 -0
- package/dist/Selector/Selector.d.ts.map +1 -1
- package/dist/Selector/Selector.js +105 -57
- package/dist/Selector/useSelectorPresentation.d.ts +1 -0
- package/dist/Selector/useSelectorPresentation.d.ts.map +1 -1
- package/dist/Selector/useSelectorPresentation.js +17 -2
- package/dist/Slider/Slider.d.ts.map +1 -1
- package/dist/Slider/Slider.js +3 -5
- package/dist/Spinner/Spinner.d.ts.map +1 -1
- package/dist/Spinner/Spinner.js +9 -10
- package/dist/Stepper/Step.d.ts +2 -1
- package/dist/Stepper/Step.d.ts.map +1 -1
- package/dist/Stepper/Step.js +75 -11
- package/dist/Stepper/Stepper.d.ts.map +1 -1
- package/dist/Stepper/Stepper.js +1 -0
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +2 -3
- package/dist/Table/index.d.ts +16 -1
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +4 -0
- package/dist/Table/plugins/columnResize/useTableColumnResize.d.ts.map +1 -1
- package/dist/Table/plugins/columnResize/useTableColumnResize.js +8 -9
- package/dist/Table/plugins/rowStatus/index.d.ts +1 -1
- package/dist/Table/plugins/rowStatus/index.d.ts.map +1 -1
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts +11 -30
- package/dist/Table/plugins/rowStatus/useTableRowStatus.d.ts.map +1 -1
- package/dist/Table/plugins/rowStatus/useTableRowStatus.js +108 -62
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +9 -1
- package/dist/Text/useTruncation.d.ts +1 -1
- package/dist/Text/useTruncation.d.ts.map +1 -1
- package/dist/Text/useTruncation.js +8 -7
- package/dist/TimeInput/TimeInput.d.ts +16 -1
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +98 -60
- package/dist/TimeInput/index.d.ts +1 -1
- package/dist/TimeInput/index.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.d.ts +2 -2
- package/dist/Timestamp/Timestamp.d.ts.map +1 -1
- package/dist/Timestamp/Timestamp.js +4 -145
- package/dist/Timestamp/formatRelativeTime.d.ts +20 -0
- package/dist/Timestamp/formatRelativeTime.d.ts.map +1 -0
- package/dist/Timestamp/formatRelativeTime.js +81 -0
- package/dist/Toast/ToastViewport.d.ts.map +1 -1
- package/dist/Toast/ToastViewport.js +125 -77
- package/dist/Tokenizer/Tokenizer.d.ts +0 -38
- package/dist/Tokenizer/Tokenizer.d.ts.map +1 -1
- package/dist/Tokenizer/Tokenizer.js +94 -26
- package/dist/Tokenizer/useEndLaneReserve.d.ts +31 -0
- package/dist/Tokenizer/useEndLaneReserve.d.ts.map +1 -0
- package/dist/Tokenizer/useEndLaneReserve.js +136 -0
- package/dist/Tooltip/useTooltip.d.ts +1 -1
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +53 -42
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +85 -30
- package/dist/Typeahead/Typeahead.d.ts +0 -21
- package/dist/Typeahead/Typeahead.d.ts.map +1 -1
- package/dist/Typeahead/Typeahead.js +108 -67
- package/dist/Typeahead/busyIndicatorLane.d.ts +62 -0
- package/dist/Typeahead/busyIndicatorLane.d.ts.map +1 -0
- package/dist/Typeahead/busyIndicatorLane.js +98 -0
- package/dist/astryx.css +25 -7
- package/dist/hooks/useFocusReturnVisibility.d.ts.map +1 -1
- package/dist/hooks/useFocusReturnVisibility.js +3 -5
- package/dist/hooks/useIsomorphicLayoutEffect.d.ts +2 -2
- package/dist/hooks/useIsomorphicLayoutEffect.d.ts.map +1 -1
- package/dist/hooks/useOverflow.js +11 -11
- package/dist/hooks/useScrollOverflow.d.ts.map +1 -1
- package/dist/hooks/useScrollOverflow.js +7 -4
- package/dist/theme/defineTheme.d.ts +13 -0
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +7 -0
- package/dist/theme/generateThemeRules.d.ts.map +1 -1
- package/dist/theme/generateThemeRules.js +1 -1
- package/dist/theme/localTokens.d.ts +18 -0
- package/dist/theme/localTokens.d.ts.map +1 -0
- package/dist/theme/localTokens.js +162 -0
- package/dist/utils/interactionModality.d.ts +6 -28
- package/dist/utils/interactionModality.d.ts.map +1 -1
- package/dist/utils/interactionModality.js +72 -37
- package/dist/utils/sharedResizeObserver.d.ts +17 -9
- package/dist/utils/sharedResizeObserver.d.ts.map +1 -1
- package/dist/utils/sharedResizeObserver.js +54 -12
- package/locales/en.json +8 -0
- package/locales/pseudo.json +6 -0
- package/package.json +7 -2
- package/src/AlertDialog/useImperativeAlertDialog.test.tsx +163 -0
- package/src/AppShell/AppShell.doc.mjs +4 -3
- package/src/AppShell/AppShell.test.tsx +21 -0
- package/src/AppShell/AppShell.tsx +12 -7
- package/src/Banner/Banner.doc.mjs +5 -1
- package/src/Banner/Banner.tsx +12 -1
- package/src/BottomSheet/BottomSheet.doc.mjs +31 -0
- package/src/BottomSheet/BottomSheet.spec.md +178 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +18 -9
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +4 -1
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +12 -0
- package/src/Button/Button.doc.mjs +56 -0
- package/src/ButtonGroup/ButtonGroup.doc.mjs +47 -0
- package/src/Calendar/hooks/useCalendarConstraints.test.ts +153 -0
- package/src/Calendar/hooks/useCalendarDays.test.ts +265 -0
- package/src/Calendar/hooks/useCalendarNavigation.test.ts +252 -0
- package/src/Carousel/Carousel.test.tsx +83 -0
- package/src/Carousel/Carousel.tsx +8 -2
- package/src/Chat/ChatComposer.doc.mjs +7 -4
- package/src/Chat/ChatComposer.test.tsx +84 -2
- package/src/Chat/ChatComposer.tsx +45 -3
- package/src/Chat/ChatSendButton.test.tsx +189 -0
- package/src/Chat/ChatToolCalls.doc.mjs +1 -1
- package/src/Chat/ChatToolCalls.test.tsx +33 -1
- package/src/Chat/ChatToolCalls.tsx +13 -34
- package/src/Chat/useChatNewMessages.ts +3 -3
- package/src/Chat/useChatPasteAsToken.test.ts +191 -0
- package/src/CheckboxList/CheckboxList.doc.mjs +172 -31
- package/src/CheckboxList/CheckboxList.spec.md +215 -0
- package/src/CheckboxList/CheckboxList.test.tsx +45 -0
- package/src/CheckboxList/CheckboxListItem.doc.mjs +11 -9
- package/src/CheckboxList/CheckboxListItem.tsx +5 -3
- package/src/Collapsible/useCollapsible.test.tsx +236 -0
- package/src/CommandPalette/CommandPalette.doc.mjs +72 -0
- package/src/CommandPalette/CommandPalette.spec.md +224 -0
- package/src/CommandPalette/CommandPaletteEmpty.test.tsx +101 -0
- package/src/ComplexSelector/ComplexSelector.doc.mjs +42 -0
- package/src/ComplexSelector/ComplexSelector.spec.md +190 -0
- package/src/ContextMenu/ContextMenu.doc.mjs +48 -0
- package/src/ContextMenu/ContextMenu.spec.md +207 -0
- package/src/DateTimeInput/DateTimeInput.doc.mjs +43 -23
- package/src/DateTimeInput/DateTimeInput.tsx +388 -181
- package/src/DateTimeInput/DateTimeInputTouch.test.tsx +10 -2
- package/src/DateTimeInput/NativeDateSegment.tsx +308 -0
- package/src/DateTimeInput/NativePickerSegments.test.tsx +626 -0
- package/src/DateTimeInput/NativeTimeSegment.tsx +331 -0
- package/src/DateTimeInput/index.ts +1 -0
- package/src/DateTimeInput/nativePickerSegmentStyles.ts +120 -0
- package/src/Divider/Divider.doc.mjs +24 -0
- package/src/Divider/Divider.spec.md +157 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +104 -0
- package/src/DropdownMenu/DropdownMenu.spec.md +246 -0
- package/src/DropdownMenu/DropdownMenu.tsx +2 -4
- package/src/Field/Field.doc.mjs +1 -0
- package/src/Field/Field.test.tsx +39 -0
- package/src/Field/Field.tsx +18 -1
- package/src/Field/InputClearButton.test.tsx +68 -6
- package/src/Field/PanelSearchInput.tsx +3 -5
- package/src/FieldStatus/FieldStatus.doc.mjs +21 -0
- package/src/FieldStatus/FieldStatus.spec.md +213 -0
- package/src/FieldStatus/FieldStatus.test.tsx +17 -0
- package/src/FieldStatus/FieldStatus.tsx +7 -2
- package/src/Grid/Grid.doc.mjs +19 -0
- package/src/Grid/Grid.spec.md +162 -0
- package/src/Icon/Icon.doc.mjs +196 -48
- package/src/Icon/Icon.spec.md +192 -0
- package/src/IconButton/IconButton.doc.mjs +38 -0
- package/src/Kbd/Kbd.doc.mjs +18 -0
- package/src/Kbd/Kbd.spec.md +142 -0
- package/src/Layer/useTouchTrigger.ts +2 -4
- package/src/Layout/Layout.doc.mjs +57 -17
- package/src/Layout/Layout.spec.md +235 -0
- package/src/Layout/Layout.test.tsx +1 -1
- package/src/Layout/Layout.tsx +7 -8
- package/src/Layout/LayoutHeader.doc.mjs +9 -0
- package/src/Layout/LayoutPanel.doc.mjs +4 -3
- package/src/Lightbox/Lightbox.doc.mjs +149 -33
- package/src/Lightbox/Lightbox.spec.md +198 -0
- package/src/Lightbox/useLightbox.test.tsx +263 -0
- package/src/Markdown/Markdown.doc.mjs +60 -0
- package/src/Markdown/Markdown.spec.md +207 -0
- package/src/MobileNav/MobileNav.doc.mjs +140 -32
- package/src/MobileNav/MobileNav.spec.md +209 -0
- package/src/MoreMenu/MoreMenu.doc.mjs +42 -0
- package/src/MoreMenu/MoreMenu.spec.md +222 -0
- package/src/MultiSelector/MultiSelector.doc.mjs +124 -1
- package/src/MultiSelector/MultiSelector.spec.md +293 -0
- package/src/MultiSelector/MultiSelector.test.tsx +305 -2
- package/src/MultiSelector/MultiSelector.tsx +124 -55
- package/src/NavIcon/NavIcon.doc.mjs +17 -0
- package/src/NavIcon/NavIcon.spec.md +134 -0
- package/src/NavMenu/NavHeadingMenu.spec.md +210 -0
- package/src/NavMenu/NavMenu.doc.mjs +37 -0
- package/src/Outline/Outline.doc.mjs +35 -0
- package/src/Outline/Outline.spec.md +162 -0
- package/src/OverflowList/OverflowList.doc.mjs +24 -0
- package/src/OverflowList/OverflowList.spec.md +157 -0
- package/src/Pagination/Pagination.doc.mjs +74 -0
- package/src/Pagination/Pagination.spec.md +226 -0
- package/src/Popover/Popover.doc.mjs +264 -65
- package/src/Popover/Popover.spec.md +421 -0
- package/src/Popover/usePopover.doc.mjs +208 -33
- package/src/PowerSearch/PowerSearch.spec.md +291 -0
- package/src/PowerSearch/PowerSearchFilterEditor.test.tsx +253 -0
- package/src/PowerSearch/PowerSearchToken.test.tsx +228 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +198 -38
- package/src/ProgressBar/ProgressBar.spec.md +261 -0
- package/src/RadioList/RadioList.test.tsx +136 -2
- package/src/RadioList/RadioListItem.doc.mjs +30 -11
- package/src/RadioList/RadioListItem.tsx +44 -8
- package/src/Resizable/Resizable.doc.mjs +130 -24
- package/src/Resizable/Resizable.spec.md +246 -0
- package/src/Resizable/ResizeHandle.test.tsx +177 -56
- package/src/Resizable/ResizeHandle.tsx +128 -45
- package/src/Resizable/index.ts +2 -0
- package/src/Resizable/shippedDirections.test.ts +462 -0
- package/src/Resizable/useResizable.doc.mjs +124 -29
- package/src/Resizable/useResizable.test.ts +1277 -3
- package/src/Resizable/useResizable.ts +760 -48
- package/src/Resizable/utils.test.ts +74 -0
- package/src/Resizable/utils.ts +35 -0
- package/src/Section/Section.doc.mjs +17 -0
- package/src/Section/Section.spec.md +139 -0
- package/src/SegmentedControl/SegmentedControl.doc.mjs +83 -0
- package/src/SegmentedControl/SegmentedControl.spec.md +152 -0
- package/src/Selector/Selector.doc.mjs +133 -97
- package/src/Selector/Selector.spec.md +300 -0
- package/src/Selector/Selector.test.tsx +318 -1
- package/src/Selector/Selector.tsx +127 -60
- package/src/Selector/useSelectorPresentation.ts +24 -4
- package/src/SideNav/SideNav.test.tsx +3 -3
- package/src/SideNav/SideNavCollapseButton.doc.mjs +8 -0
- package/src/SideNav/SideNavItem.doc.mjs +1 -1
- package/src/Skeleton/Skeleton.doc.mjs +12 -0
- package/src/Skeleton/Skeleton.spec.md +127 -0
- package/src/Slider/Slider.doc.mjs +184 -30
- package/src/Slider/Slider.spec.md +224 -0
- package/src/Slider/Slider.tsx +2 -5
- package/src/Spinner/Spinner.doc.mjs +5 -5
- package/src/Spinner/Spinner.test.tsx +32 -7
- package/src/Spinner/Spinner.tsx +46 -14
- package/src/Stack/Stack.doc.mjs +22 -0
- package/src/Stack/Stack.spec.md +155 -0
- package/src/StatusDot/StatusDot.doc.mjs +17 -0
- package/src/StatusDot/StatusDot.spec.md +138 -0
- package/src/Stepper/Step.doc.mjs +1 -1
- package/src/Stepper/Step.tsx +118 -5
- package/src/Stepper/Stepper.doc.mjs +51 -1
- package/src/Stepper/Stepper.spec.md +245 -0
- package/src/Stepper/Stepper.test.tsx +315 -0
- package/src/Stepper/Stepper.tsx +8 -0
- package/src/Switch/Switch.doc.mjs +40 -0
- package/src/Switch/Switch.spec.md +175 -0
- package/src/TabList/TabList.tsx +2 -3
- package/src/Table/Table.doc.mjs +102 -24
- package/src/Table/Table.perf.test.tsx +51 -1
- package/src/Table/Table.spec.md +325 -0
- package/src/Table/TableHeaderCell.test.tsx +291 -0
- package/src/Table/index.ts +19 -4
- package/src/Table/plugins/columnResize/useTableColumnResize.tsx +8 -12
- package/src/Table/plugins/filtering/useTableFilterState.test.tsx +143 -0
- package/src/Table/plugins/groupedRows/useTableGroupedRows.test.tsx +2 -1
- package/src/Table/plugins/rowStatus/index.ts +1 -4
- package/src/Table/plugins/rowStatus/useTableRowStatus.public.test.ts +92 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.spec.md +354 -0
- package/src/Table/plugins/rowStatus/useTableRowStatus.test.tsx +431 -56
- package/src/Table/plugins/rowStatus/useTableRowStatus.tsx +155 -84
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +72 -0
- package/src/Table/plugins/sortable/useTableSortable.tsx +18 -1
- package/src/Table/useTableGroupedRows.doc.mjs +2 -2
- package/src/Table/useTableRowStatus.doc.mjs +5 -5
- package/src/Text/Text.doc.mjs +190 -43
- package/src/Text/Text.spec.md +206 -0
- package/src/Text/useTruncation.ts +8 -7
- package/src/TextArea/TextArea.doc.mjs +255 -45
- package/src/TextArea/TextArea.spec.md +205 -0
- package/src/TimeInput/NativeTimeInput.test.tsx +269 -0
- package/src/TimeInput/TimeInput.doc.mjs +47 -23
- package/src/TimeInput/TimeInput.tsx +109 -50
- package/src/TimeInput/index.ts +1 -0
- package/src/Timestamp/Timestamp.doc.mjs +2 -2
- package/src/Timestamp/Timestamp.test.tsx +75 -3
- package/src/Timestamp/Timestamp.tsx +7 -153
- package/src/Timestamp/formatRelativeTime.ts +96 -0
- package/src/Toast/ToastViewport.test.tsx +194 -0
- package/src/Toast/ToastViewport.tsx +136 -58
- package/src/ToggleButton/ToggleButton.doc.mjs +56 -0
- package/src/Tokenizer/Tokenizer.doc.mjs +2 -0
- package/src/Tokenizer/Tokenizer.spec.md +293 -0
- package/src/Tokenizer/Tokenizer.test.tsx +335 -1
- package/src/Tokenizer/Tokenizer.tsx +129 -46
- package/src/Tokenizer/useEndLaneReserve.ts +146 -0
- package/src/Toolbar/Toolbar.doc.mjs +19 -0
- package/src/Toolbar/Toolbar.spec.md +174 -0
- package/src/Tooltip/Tooltip.doc.mjs +17 -0
- package/src/Tooltip/Tooltip.spec.md +142 -0
- package/src/Tooltip/Tooltip.test.tsx +21 -1
- package/src/Tooltip/useTooltip.test.tsx +318 -0
- package/src/Tooltip/useTooltip.tsx +60 -39
- package/src/TreeList/TreeList.doc.mjs +58 -0
- package/src/TreeList/TreeList.spec.md +224 -0
- package/src/Typeahead/BaseTypeahead.tsx +96 -25
- package/src/Typeahead/Typeahead.doc.mjs +89 -1
- package/src/Typeahead/Typeahead.spec.md +257 -0
- package/src/Typeahead/Typeahead.test.tsx +502 -1
- package/src/Typeahead/Typeahead.tsx +187 -69
- package/src/Typeahead/TypeaheadItem.test.tsx +93 -2
- package/src/Typeahead/busyIndicatorLane.tsx +109 -0
- package/src/__tests__/stylexDeclarations.ts +51 -0
- package/src/hooks/useFocusReturnVisibility.ts +3 -5
- package/src/hooks/useOverflow.ts +11 -11
- package/src/hooks/useScrollLock.test.ts +103 -0
- package/src/hooks/useScrollOverflow.ts +7 -4
- package/src/i18n/useTranslator.test.tsx +197 -0
- package/src/theme/defineTheme.test.ts +227 -0
- package/src/theme/defineTheme.ts +30 -0
- package/src/theme/derivedVarRegistry.test.ts +6 -0
- package/src/theme/generateThemeRules.ts +4 -1
- package/src/theme/localTokens.ts +272 -0
- package/src/theme/themingTargets.test.ts +126 -28
- package/src/utils/interactionModality.test.ts +83 -0
- package/src/utils/interactionModality.ts +88 -36
- package/src/utils/sharedResizeObserver.test.ts +124 -5
- package/src/utils/sharedResizeObserver.ts +60 -14
|
@@ -25,6 +25,12 @@ import React, {
|
|
|
25
25
|
type ReactNode,
|
|
26
26
|
} from 'react';
|
|
27
27
|
import * as stylex from '@stylexjs/stylex';
|
|
28
|
+
import {
|
|
29
|
+
BusyIndicatorLaneProvider,
|
|
30
|
+
createBusyIndicatorLane,
|
|
31
|
+
useIsBusy,
|
|
32
|
+
type BusyIndicatorLane,
|
|
33
|
+
} from '../Typeahead/busyIndicatorLane';
|
|
28
34
|
import type {BaseProps} from '../BaseProps';
|
|
29
35
|
import type {SizeValue} from '../utils/types';
|
|
30
36
|
import {BaseTypeahead} from '../Typeahead/BaseTypeahead';
|
|
@@ -40,6 +46,8 @@ import {
|
|
|
40
46
|
type FieldStatusVariant,
|
|
41
47
|
} from '../Field';
|
|
42
48
|
import {Token} from '../Token';
|
|
49
|
+
import {Spinner} from '../Spinner';
|
|
50
|
+
import {useEndLaneReserve} from './useEndLaneReserve';
|
|
43
51
|
import {renderIconSlot, type IconType} from '../Icon';
|
|
44
52
|
import {OverflowList} from '../OverflowList';
|
|
45
53
|
import {useLayer} from '../Layer/useLayer';
|
|
@@ -232,6 +240,10 @@ export interface TokenizerProps<T extends SearchableItem> extends Omit<
|
|
|
232
240
|
// Styles
|
|
233
241
|
// =============================================================================
|
|
234
242
|
|
|
243
|
+
// How far the end lane sits from the field's inline-end border, named once
|
|
244
|
+
// because the input's reserve is derived from the same value.
|
|
245
|
+
const END_LANE_INSET = spacingVars['--spacing-2'];
|
|
246
|
+
|
|
235
247
|
const styles = stylex.create({
|
|
236
248
|
wrapper: {
|
|
237
249
|
position: 'relative',
|
|
@@ -267,7 +279,7 @@ const styles = stylex.create({
|
|
|
267
279
|
// Match the field's inline padding (inputWrapperStyles.base uses
|
|
268
280
|
// spacing-2) so end content (clear button, resultCount) lines up with
|
|
269
281
|
// the text/start-icon inset instead of hugging the border at ~3px.
|
|
270
|
-
insetInlineEnd:
|
|
282
|
+
insetInlineEnd: END_LANE_INSET,
|
|
271
283
|
display: 'flex',
|
|
272
284
|
alignItems: 'center',
|
|
273
285
|
gap: spacingVars['--spacing-2'],
|
|
@@ -387,6 +399,45 @@ const CREATABLE_ID_PREFIX = '__xds_create__';
|
|
|
387
399
|
* />
|
|
388
400
|
* ```
|
|
389
401
|
*/
|
|
402
|
+
/**
|
|
403
|
+
* The field's inline-end lane: the busy Spinner, then `endContent`, then the
|
|
404
|
+
* clear button — pinned to the field's first row while tokens wrap below it.
|
|
405
|
+
*
|
|
406
|
+
* A separate component so that subscribing to the busy state re-renders THIS
|
|
407
|
+
* and nothing else. Subscribed from `Tokenizer`, a search transition
|
|
408
|
+
* re-rendered every selected token twice — twenty tokens meant forty renders
|
|
409
|
+
* per search for one glyph none of them contain.
|
|
410
|
+
*
|
|
411
|
+
* Renders nothing when the lane would be empty, so `useEndLaneReserve` sees no
|
|
412
|
+
* element, publishes no width, and the input keeps its full content box.
|
|
413
|
+
*/
|
|
414
|
+
function EndLane({
|
|
415
|
+
lane,
|
|
416
|
+
laneRef,
|
|
417
|
+
laneXStyle,
|
|
418
|
+
loadingLabel,
|
|
419
|
+
hasStaticContent,
|
|
420
|
+
children,
|
|
421
|
+
}: {
|
|
422
|
+
lane: BusyIndicatorLane;
|
|
423
|
+
laneRef: (node: HTMLElement | null) => void;
|
|
424
|
+
laneXStyle: stylex.StyleXStyles[];
|
|
425
|
+
loadingLabel: string;
|
|
426
|
+
hasStaticContent: boolean;
|
|
427
|
+
children: ReactNode;
|
|
428
|
+
}) {
|
|
429
|
+
const isBusy = useIsBusy(lane);
|
|
430
|
+
if (!isBusy && !hasStaticContent) {
|
|
431
|
+
return null;
|
|
432
|
+
}
|
|
433
|
+
return (
|
|
434
|
+
<div ref={laneRef} {...stylex.props(laneXStyle)}>
|
|
435
|
+
{isBusy && <Spinner size="sm" aria-label={loadingLabel} />}
|
|
436
|
+
{children}
|
|
437
|
+
</div>
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
390
441
|
export function Tokenizer<T extends SearchableItem>({
|
|
391
442
|
label,
|
|
392
443
|
isLabelHidden = false,
|
|
@@ -461,6 +512,24 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
461
512
|
}));
|
|
462
513
|
|
|
463
514
|
// Focus-within state for overflow truncation
|
|
515
|
+
// Reported by BaseTypeahead so the indicator can live in this field's own
|
|
516
|
+
// end lane, beside endContent and the clear button.
|
|
517
|
+
// The base owns the busy state; this field only paints it. Held in a store
|
|
518
|
+
// rather than this component's state — held here, a search transition
|
|
519
|
+
// re-rendered every selected token twice, for a glyph no token contains.
|
|
520
|
+
// See busyIndicatorLane.tsx.
|
|
521
|
+
const busyLane = useMemo(() => createBusyIndicatorLane(), []);
|
|
522
|
+
// What sits in the end lane varies most here — a spinner, arbitrary
|
|
523
|
+
// `endContent`, a clear button, or all three — so its width is measured
|
|
524
|
+
// rather than assumed, and the input reserves it.
|
|
525
|
+
const [laneRef, laneReserve] = useEndLaneReserve(END_LANE_INSET);
|
|
526
|
+
// The half of the lane's contents this component knows about. The busy half
|
|
527
|
+
// is the leaf's own business — folding it in here would mean reading the
|
|
528
|
+
// busy state during this render, which is exactly the re-render the store
|
|
529
|
+
// exists to avoid.
|
|
530
|
+
const hasStaticEndLane = Boolean(
|
|
531
|
+
endContent || (hasClear && value.length > 0 && !isDisabled),
|
|
532
|
+
);
|
|
464
533
|
const [isFocusedWithin, setIsFocusedWithin] = useState(false);
|
|
465
534
|
const isTruncated =
|
|
466
535
|
!isFocusedWithin && tokenOverflowBehavior !== 'none' && value.length > 0;
|
|
@@ -795,37 +864,48 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
795
864
|
) : (
|
|
796
865
|
tokens
|
|
797
866
|
)}
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
867
|
+
{/* The base reports its busy state through this lane, so the
|
|
868
|
+
indicator lands in the end controls below beside the clear
|
|
869
|
+
button rather than as a second one inside the base. */}
|
|
870
|
+
<BusyIndicatorLaneProvider value={busyLane}>
|
|
871
|
+
<BaseTypeahead
|
|
872
|
+
ref={inputRef}
|
|
873
|
+
searchSource={isAtMax ? emptySource : filteredSource}
|
|
874
|
+
value={null}
|
|
875
|
+
onChange={handleAdd}
|
|
876
|
+
renderItem={renderItem}
|
|
877
|
+
placeholder={value.length === 0 ? placeholder : ''}
|
|
878
|
+
hasEntriesOnFocus={isAtMax ? false : hasEntriesOnFocus}
|
|
879
|
+
maxMenuItems={maxMenuItems}
|
|
880
|
+
menuWidth={menuWidth}
|
|
881
|
+
minQueryLength={minQueryLength}
|
|
882
|
+
emptySearchResultsText={emptySearchResultsText}
|
|
883
|
+
isDisabled={isDisabled}
|
|
884
|
+
isFocusableDisabled={showsDisabledMessage}
|
|
885
|
+
hasAutoFocus={hasAutoFocus}
|
|
886
|
+
inputId={inputId}
|
|
887
|
+
ariaDescribedBy={ariaDescribedBy}
|
|
888
|
+
onChangeQuery={onChangeQuery}
|
|
889
|
+
__queryEntries={createEntries}
|
|
890
|
+
debounceMs={debounceMs}
|
|
891
|
+
onKeyDown={handleKeyDown}
|
|
892
|
+
anchorRef={wrapperRef}
|
|
893
|
+
size={size}
|
|
894
|
+
inputXStyle={[
|
|
895
|
+
isAtMax || isTruncated
|
|
896
|
+
? styles.inputAtMax
|
|
897
|
+
: value.length > 0
|
|
898
|
+
? styles.inputCompact
|
|
899
|
+
: undefined,
|
|
900
|
+
// Not for the collapsed states above: those give the input no width
|
|
901
|
+
// to pad, and `inputAtMax` zeroes its padding outright.
|
|
902
|
+
// Applied whether or not a lane is up: the reserve resolves to
|
|
903
|
+
// zero until the lane publishes a width, so this does not need to
|
|
904
|
+
// know about the busy state.
|
|
905
|
+
!(isAtMax || isTruncated) && laneReserve,
|
|
906
|
+
]}
|
|
907
|
+
/>
|
|
908
|
+
</BusyIndicatorLaneProvider>
|
|
829
909
|
{htmlName != null &&
|
|
830
910
|
value.map(item => (
|
|
831
911
|
<input
|
|
@@ -838,20 +918,23 @@ export function Tokenizer<T extends SearchableItem>({
|
|
|
838
918
|
disabled={isDisabled}
|
|
839
919
|
/>
|
|
840
920
|
))}
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
921
|
+
<EndLane
|
|
922
|
+
lane={busyLane}
|
|
923
|
+
laneRef={laneRef}
|
|
924
|
+
laneXStyle={[styles.endSection, endSectionSizeStyles[size]]}
|
|
925
|
+
loadingLabel={t('@astryx.typeahead.loading')}
|
|
926
|
+
hasStaticContent={hasStaticEndLane}>
|
|
927
|
+
{endContent}
|
|
928
|
+
{hasClear && value.length > 0 && !isDisabled && (
|
|
929
|
+
<InputClearButton
|
|
930
|
+
label={t('@astryx.tokenizer.clearAll')}
|
|
931
|
+
onClick={e => {
|
|
932
|
+
e.stopPropagation();
|
|
933
|
+
handleClearAll();
|
|
934
|
+
}}
|
|
935
|
+
/>
|
|
936
|
+
)}
|
|
937
|
+
</EndLane>
|
|
855
938
|
</div>
|
|
856
939
|
);
|
|
857
940
|
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @file useEndLaneReserve.ts
|
|
7
|
+
* @input Uses React and the shared ResizeObserver
|
|
8
|
+
* @output Exports useEndLaneReserve, which keeps a field's input clear of the
|
|
9
|
+
* absolutely-positioned lane at its inline end
|
|
10
|
+
* @position Tokenizer internal. Tokenizer parks its clear button, end content
|
|
11
|
+
* and busy indicator in one absolutely-positioned lane at the field's
|
|
12
|
+
* inline end, and this keeps the input's text and caret clear of it.
|
|
13
|
+
*
|
|
14
|
+
* It lives here, beside its one caller, rather than in `Field/` with the
|
|
15
|
+
* shared field internals — deliberately. A measured reserve is Tokenizer's
|
|
16
|
+
* workaround for a constraint only Tokenizer has: its lane must stay pinned
|
|
17
|
+
* to the field's first row while tokens wrap below it, so it cannot be in
|
|
18
|
+
* flow, and an out-of-flow box reserves nothing. Every other field, this
|
|
19
|
+
* one's own Typeahead included, puts its end controls in flow as flex
|
|
20
|
+
* siblings the way TextInput does, which needs no measuring at all. Filed
|
|
21
|
+
* under `Field/` this read as shared infrastructure and invited the next
|
|
22
|
+
* field to reach for it; that is the wrong default.
|
|
23
|
+
*
|
|
24
|
+
* SYNC: When modified, update this header and the caller:
|
|
25
|
+
* - /packages/core/src/Tokenizer/Tokenizer.tsx
|
|
26
|
+
*/
|
|
27
|
+
|
|
28
|
+
import {useCallback} from 'react';
|
|
29
|
+
import * as stylex from '@stylexjs/stylex';
|
|
30
|
+
import {observeResize} from '../utils/sharedResizeObserver';
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* The measured lane width, published on the field wrapper and read by the
|
|
34
|
+
* input through inheritance. A custom property is the point of the design: it
|
|
35
|
+
* carries a measurement into CSS without carrying it through React, so a lane
|
|
36
|
+
* that grows or shrinks repaints without re-rendering the field.
|
|
37
|
+
*/
|
|
38
|
+
const LANE_RESERVE_VAR = '--_tokenizer-end-lane-reserve';
|
|
39
|
+
|
|
40
|
+
// Keep the input's text and caret out from under the lane.
|
|
41
|
+
//
|
|
42
|
+
// The input's content box already stops one wrapper padding short of the
|
|
43
|
+
// border, and the lane is inset from that same border — so what is left for
|
|
44
|
+
// the input to clear is the lane's inset plus its width, less the padding it
|
|
45
|
+
// already has, plus a padding's worth of gap so the text does not touch the
|
|
46
|
+
// glyph. The two paddings cancel, which is why this reads as inset + width.
|
|
47
|
+
//
|
|
48
|
+
// The variable carries the WHOLE reserve, not just the width, so its absence
|
|
49
|
+
// means "no lane" rather than "a lane of zero width": with no lane up, the
|
|
50
|
+
// fallback resolves the padding to 0 and the input keeps its full content box.
|
|
51
|
+
// That is what lets the caller apply this style unconditionally, which in turn
|
|
52
|
+
// is what keeps the field from having to know whether a search is running.
|
|
53
|
+
// The rule stays static either way — one class, generated once, never
|
|
54
|
+
// regenerated as the lane changes.
|
|
55
|
+
const reserveStyles = stylex.create({
|
|
56
|
+
reserve: {
|
|
57
|
+
paddingInlineEnd: `var(${LANE_RESERVE_VAR}, 0px)`,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Keep a field's input clear of the lane at its inline end.
|
|
63
|
+
*
|
|
64
|
+
* The lane is absolutely positioned — it has to be, because these wrappers
|
|
65
|
+
* wrap, and an in-flow sibling gets pushed onto a second row by a token — and
|
|
66
|
+
* an out-of-flow box reserves no space by definition. There is no CSS that
|
|
67
|
+
* makes one do so: the input cannot see a sibling's width. So the lane is
|
|
68
|
+
* measured, and the input spends the measurement as padding.
|
|
69
|
+
*
|
|
70
|
+
* What the lane holds is not a fixed set: a clear button that comes and goes
|
|
71
|
+
* with the value, a busy indicator that comes and goes with the search, and
|
|
72
|
+
* arbitrary `endContent`. Measuring covers all of it, including the
|
|
73
|
+
* combinations, and needs no constant kept in step with what renders.
|
|
74
|
+
*
|
|
75
|
+
* **The measurement never enters React state.** It is written to a custom
|
|
76
|
+
* property on the field wrapper and inherited by the input. Held in state, it
|
|
77
|
+
* cost the field a second commit every time the lane changed size — once when
|
|
78
|
+
* the spinner arrived and again when it left — doubling the field's renders
|
|
79
|
+
* across a search for a value no JavaScript ever reads. The observation is
|
|
80
|
+
* shared as well: `observeResize` batches every field on the page into one
|
|
81
|
+
* callback per frame instead of one observer each.
|
|
82
|
+
*
|
|
83
|
+
* Takes the lane's inset from the field's inline-end border, as the CSS
|
|
84
|
+
* expression that positions it. Returns a ref callback for the lane, and the
|
|
85
|
+
* style for the input — which the caller applies unconditionally: with no lane
|
|
86
|
+
* mounted the variable is absent and the padding resolves to zero, so the
|
|
87
|
+
* caller never has to know whether a search is running.
|
|
88
|
+
*/
|
|
89
|
+
export function useEndLaneReserve(
|
|
90
|
+
laneInset: string,
|
|
91
|
+
): [(node: HTMLElement | null) => void, stylex.StyleXStyles] {
|
|
92
|
+
const laneRef = useCallback(
|
|
93
|
+
(node: HTMLElement | null) => {
|
|
94
|
+
if (node == null) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
// The lane's parent: the field wrapper in both callers, and an ancestor
|
|
98
|
+
// of the input either way, which is what inheritance needs.
|
|
99
|
+
const host = node.parentElement;
|
|
100
|
+
|
|
101
|
+
const unobserve = observeResize(node, () => {
|
|
102
|
+
// `offsetWidth`, not `getBoundingClientRect().width`. The rect is in
|
|
103
|
+
// VIEWPORT space — it carries every CSS transform between this element
|
|
104
|
+
// and the root — while the padding it feeds is in the element's own
|
|
105
|
+
// LOCAL space. Under `scale(.5)` the rect reads half the lane's real
|
|
106
|
+
// width and the input reserves half of what it needs, so the query runs
|
|
107
|
+
// under the controls again; under `scale(2)` it reads double and the
|
|
108
|
+
// caret sits in a gap twice the lane's width. Measured in Chromium on a
|
|
109
|
+
// 123px lane in a 280px field: at `scale(.5)` the rect published 61.48px
|
|
110
|
+
// and the spinner covered 14px of the input's content box; at `scale(2)`
|
|
111
|
+
// it published 245.91px, leaving a 125.95px gap and growing the field
|
|
112
|
+
// from 32px to 55px tall. `offsetWidth` is the untransformed border-box
|
|
113
|
+
// width, so it reports 123 at every scale — the number this padding is
|
|
114
|
+
// actually denominated in.
|
|
115
|
+
//
|
|
116
|
+
// It is already an integer, which is the rounding the old `Math.ceil`
|
|
117
|
+
// was there for: a fractional width left as-is reserves a hair too
|
|
118
|
+
// little and the glyph's last subpixel column lands on the caret.
|
|
119
|
+
const width = node.offsetWidth;
|
|
120
|
+
if (width > 0) {
|
|
121
|
+
host?.style.setProperty(
|
|
122
|
+
LANE_RESERVE_VAR,
|
|
123
|
+
`calc(${laneInset} + ${width}px)`,
|
|
124
|
+
);
|
|
125
|
+
} else {
|
|
126
|
+
// A mounted but empty lane (no end content, no clear, not searching)
|
|
127
|
+
// claims nothing.
|
|
128
|
+
host?.style.removeProperty(LANE_RESERVE_VAR);
|
|
129
|
+
}
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
// React 19 runs a ref callback's return value as its cleanup, so the
|
|
133
|
+
// observer is released exactly when the lane unmounts.
|
|
134
|
+
return () => {
|
|
135
|
+
unobserve();
|
|
136
|
+
// The room the lane claimed goes back to the input. Removing beats
|
|
137
|
+
// setting 0px: the rule's fallback is already that, and this leaves no
|
|
138
|
+
// stale property behind on the DOM.
|
|
139
|
+
host?.style.removeProperty(LANE_RESERVE_VAR);
|
|
140
|
+
};
|
|
141
|
+
},
|
|
142
|
+
[laneInset],
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
return [laneRef, reserveStyles.reserve];
|
|
146
|
+
}
|
|
@@ -1,5 +1,21 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
|
|
4
|
+
const anatomy = [
|
|
5
|
+
{
|
|
6
|
+
name: 'Outer chrome',
|
|
7
|
+
required: true,
|
|
8
|
+
description:
|
|
9
|
+
'Section-owned container that supplies the toolbar surface, padding, and selected divider edges.',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
name: 'Toolbar',
|
|
13
|
+
required: true,
|
|
14
|
+
description:
|
|
15
|
+
'Named toolbar row that owns toolbar semantics and the start, optional center, and end layout.',
|
|
16
|
+
},
|
|
17
|
+
];
|
|
18
|
+
|
|
3
19
|
/** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
|
|
4
20
|
|
|
5
21
|
export const docs = {
|
|
@@ -147,6 +163,7 @@ export const docs = {
|
|
|
147
163
|
], },
|
|
148
164
|
],
|
|
149
165
|
usage: {
|
|
166
|
+
anatomy,
|
|
150
167
|
description:
|
|
151
168
|
'Toolbar is a horizontal bar with left, center, and right areas. Use it for contextual actions within a content area (above a table, inside a card, or in a panel), not as a page-level header. Set the size once on the toolbar and all buttons, inputs, and tabs inside it match automatically.',
|
|
152
169
|
bestPractices: [
|
|
@@ -182,6 +199,7 @@ export const docsZh = {
|
|
|
182
199
|
},
|
|
183
200
|
],
|
|
184
201
|
usage: {
|
|
202
|
+
anatomy,
|
|
185
203
|
description:
|
|
186
204
|
'Toolbar is a horizontal bar with left, center, and right areas. Use it for contextual actions within a content area (above a table, inside a card, or in a panel), not as a page-level header. Set the size once on the toolbar and all buttons, inputs, and tabs inside it match automatically.',
|
|
187
205
|
bestPractices: [
|
|
@@ -200,6 +218,7 @@ export const docsZh = {
|
|
|
200
218
|
export const docsDense = {
|
|
201
219
|
description: 'Horizontal bar w/ left, center, right areas. For contextual actions in content, not page headers. Size cascades to children.',
|
|
202
220
|
usage: {
|
|
221
|
+
anatomy,
|
|
203
222
|
description:
|
|
204
223
|
'Horizontal bar w/ left, optional center, right. For contextual actions within content (tables, cards, panels), not page-level headers. Size cascades to children.',
|
|
205
224
|
bestPractices: [
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 3
|
|
3
|
+
template_version: 3
|
|
4
|
+
kind: component
|
|
5
|
+
id: component:Toolbar
|
|
6
|
+
authority: draft
|
|
7
|
+
archive_reason: null
|
|
8
|
+
superseded_by: null
|
|
9
|
+
approved_by: null
|
|
10
|
+
approved_at: null
|
|
11
|
+
owners: [cixzhang]
|
|
12
|
+
review_triggers: [layout, theming, accessibility]
|
|
13
|
+
verified_by:
|
|
14
|
+
[
|
|
15
|
+
packages/core/src/Toolbar/Toolbar.test.tsx,
|
|
16
|
+
packages/core/src/Section/Section.test.tsx,
|
|
17
|
+
packages/core/src/theme/themingTargets.test.ts,
|
|
18
|
+
scripts/check-knowledge.mjs,
|
|
19
|
+
]
|
|
20
|
+
modules: []
|
|
21
|
+
families: [family:layout-regions]
|
|
22
|
+
design_specs: []
|
|
23
|
+
architecture:
|
|
24
|
+
[
|
|
25
|
+
architecture:component-theming-surface,
|
|
26
|
+
architecture:container-padding,
|
|
27
|
+
architecture:public-component-api,
|
|
28
|
+
]
|
|
29
|
+
contributing: []
|
|
30
|
+
system_specs: []
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
# Toolbar component contract
|
|
34
|
+
|
|
35
|
+
## Intent
|
|
36
|
+
|
|
37
|
+
Toolbar presents a named contextual action region with one semantic toolbar row
|
|
38
|
+
inside Section-owned outer chrome. This draft records the current consumer
|
|
39
|
+
anatomy and theming ownership without changing layout, keyboard behavior,
|
|
40
|
+
targets, or public API.
|
|
41
|
+
|
|
42
|
+
## Compatibility and migration
|
|
43
|
+
|
|
44
|
+
- Released default preserved: `yes`
|
|
45
|
+
- Compatibility class: additive documentation only; runtime, DOM, styling,
|
|
46
|
+
targets, and public API remain unchanged
|
|
47
|
+
- Controlled/uncontrolled behavior: not applicable
|
|
48
|
+
- Migration decision: none
|
|
49
|
+
|
|
50
|
+
Consumer migration instructions belong in consumer docs and release notes.
|
|
51
|
+
|
|
52
|
+
## Ownership boundary
|
|
53
|
+
|
|
54
|
+
**Owns**
|
|
55
|
+
|
|
56
|
+
- The named toolbar row, toolbar semantics, start/optional-center/end layout,
|
|
57
|
+
keyboard movement, size cascade, and current `toolbar` target.
|
|
58
|
+
|
|
59
|
+
**Does not own / non-goals**
|
|
60
|
+
|
|
61
|
+
- The painted outer chrome, variant, block padding, and selected divider edges —
|
|
62
|
+
delegated to `component:Section`.
|
|
63
|
+
- Content supplied through the three layout slots — owned by the caller or its
|
|
64
|
+
rendered components.
|
|
65
|
+
- A general arbitrary-child layout primitive contract.
|
|
66
|
+
- New runtime behavior, targets, props, or target placement.
|
|
67
|
+
|
|
68
|
+
## Public concepts
|
|
69
|
+
|
|
70
|
+
No new public concept is introduced. Consumer props, slots, and usage remain
|
|
71
|
+
documented in `Toolbar.doc.mjs`; `family:layout-regions` owns the shared
|
|
72
|
+
structural-region boundary.
|
|
73
|
+
|
|
74
|
+
## Behavioral and layout contract
|
|
75
|
+
|
|
76
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
77
|
+
| --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------ | -------------------------------------------------- |
|
|
78
|
+
| FR1 | The current render contains Section-owned Outer chrome around one named Toolbar carrying `role="toolbar"` and the current `toolbar` target. | Current source, docs, tests, and family | Verified current behavior; no new behavior decided |
|
|
79
|
+
| FR2 | The Toolbar uses its current two-lane layout without center content and its current three-lane layout when center content is supplied. | Current source and focused structure tests | Verified current behavior; no layout change |
|
|
80
|
+
| FR3 | Variant, selected divider edges, and outer padding remain delegated to Section, while Toolbar retains toolbar semantics, keyboard behavior, and internal layout. | Current source, docs, and family contract | Verified current ownership; no target change |
|
|
81
|
+
|
|
82
|
+
### Allowed variation
|
|
83
|
+
|
|
84
|
+
- Caller content may be absent or supplied in the start, center, and end slots
|
|
85
|
+
without changing Outer chrome or Toolbar ownership.
|
|
86
|
+
- Size and orientation may change the current row geometry and keyboard axis
|
|
87
|
+
without creating separate anatomy parts or targets.
|
|
88
|
+
|
|
89
|
+
### Representative states
|
|
90
|
+
|
|
91
|
+
| State | Required invariant | Allowed variation |
|
|
92
|
+
| ----------------- | ------------------------------------------------------- | --------------------------------------------------- |
|
|
93
|
+
| Empty toolbar | Outer chrome and named Toolbar remain rendered. | No caller slot content. |
|
|
94
|
+
| Two-lane layout | Start and/or end content use the current flex layout. | Either lane may be absent. |
|
|
95
|
+
| Three-lane layout | Center content selects the current three-column layout. | Start or end content may be absent. |
|
|
96
|
+
| Vertical toolbar | Toolbar semantics and target remain unchanged. | Layout and keyboard movement use the vertical axis. |
|
|
97
|
+
|
|
98
|
+
### Transformation and precedence order
|
|
99
|
+
|
|
100
|
+
- No new slot, layout, edge-compensation, padding, or event precedence rule is
|
|
101
|
+
introduced.
|
|
102
|
+
|
|
103
|
+
### Performance and resources
|
|
104
|
+
|
|
105
|
+
- No new performance or resource rule is introduced.
|
|
106
|
+
|
|
107
|
+
## Accessibility contract
|
|
108
|
+
|
|
109
|
+
This draft does not change or extend Toolbar's current accessible name,
|
|
110
|
+
orientation, roving-tabindex, keyboard-hint, caret-guard, or event-composition
|
|
111
|
+
behavior.
|
|
112
|
+
|
|
113
|
+
## Design relationships
|
|
114
|
+
|
|
115
|
+
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
116
|
+
| ---------------- | -------------------------------------------------------------------------------- | ----------------------------------------- | -------------- | ------------------ |
|
|
117
|
+
| Outer chrome | Supplies the painted surface, padding, and selected boundaries around the row. | `component:Section` | Supporting | FR1, FR3 |
|
|
118
|
+
| Toolbar | Presents the named toolbar semantics and current two- or three-lane arrangement. | Current source, docs, and family contract | Prominent | FR1, FR2, FR3 |
|
|
119
|
+
|
|
120
|
+
The slot contents are caller-owned content inside Toolbar's layout. They do not
|
|
121
|
+
become additional Toolbar-owned anatomy or targets.
|
|
122
|
+
|
|
123
|
+
### Theming anatomy
|
|
124
|
+
|
|
125
|
+
<!-- anatomy-theming:v1 -->
|
|
126
|
+
|
|
127
|
+
```json
|
|
128
|
+
{
|
|
129
|
+
"Outer chrome": {
|
|
130
|
+
"delegatesTo": {"owner": "component:Section", "target": "section"}
|
|
131
|
+
},
|
|
132
|
+
"Toolbar": {"target": "toolbar"}
|
|
133
|
+
}
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Family and system relationships
|
|
137
|
+
|
|
138
|
+
- `family:layout-regions` owns the structural-region vocabulary and records
|
|
139
|
+
Toolbar as a Section-backed contextual action region.
|
|
140
|
+
- `architecture:container-padding` owns the inherited inset and edge-compensation
|
|
141
|
+
geometry used by the composed Section and Toolbar.
|
|
142
|
+
- `architecture:component-theming-surface` owns anatomy qualification, local
|
|
143
|
+
target mapping, and component delegation.
|
|
144
|
+
- `architecture:public-component-api` owns the stable prop and slot surface; this
|
|
145
|
+
documentation adds no API.
|
|
146
|
+
|
|
147
|
+
## Verification map
|
|
148
|
+
|
|
149
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
150
|
+
| ------------------- | --------------------------------------------------------------- | ---------------------------------------------- | -------------------------------------------------------------------------------------------------------------------- | ----------------------- |
|
|
151
|
+
| FR1 | `Toolbar.test.tsx` role, name, pass-through, and Section suites | Empty and populated Toolbar | Removing the role/name, Toolbar target, Section composition, or delegated Section target fails current evidence. | `audit:Toolbar/anatomy` |
|
|
152
|
+
| FR2 | `Toolbar.test.tsx` slot and child-count suites | Start-only, end-only, two-lane, and three-lane | Changing current slot presence or two-/three-lane structure fails focused assertions. | `audit:Toolbar/layout` |
|
|
153
|
+
| FR3 | Toolbar and Section source plus their focused tests | Variant, divider, size, and orientation states | Moving outer chrome ownership into Toolbar or moving toolbar semantics onto Section contradicts source and coverage. | `audit:Toolbar/theming` |
|
|
154
|
+
| Target inventory | `packages/core/src/theme/themingTargets.test.ts` | Toolbar and delegated Section targets | Runtime and documented target metadata drift fails target validation. | `audit:Toolbar/theming` |
|
|
155
|
+
| Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical anatomy and current local target | Missing, extra, prefixed, or stale mappings fail repository validation. | `audit:Toolbar/theming` |
|
|
156
|
+
|
|
157
|
+
Existing tests assert the semantic row, slot structure, and Section composition.
|
|
158
|
+
They do not prove computed inset or edge-compensation geometry for every parent
|
|
159
|
+
padding state; this documentation does not claim that coverage.
|
|
160
|
+
|
|
161
|
+
## Decision log
|
|
162
|
+
|
|
163
|
+
None. This draft records current facts and introduces no component-local design,
|
|
164
|
+
layout, accessibility, or API decision.
|
|
165
|
+
|
|
166
|
+
## Open questions
|
|
167
|
+
|
|
168
|
+
None.
|
|
169
|
+
|
|
170
|
+
## Content boundary
|
|
171
|
+
|
|
172
|
+
This file does not duplicate consumer prop tables, examples, family layout
|
|
173
|
+
rules, container-padding mechanics, keyboard algorithms, implementation steps,
|
|
174
|
+
or system rules. It links to their owners.
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
|
|
4
|
+
const anatomy = [
|
|
5
|
+
{
|
|
6
|
+
name: 'Tooltip surface',
|
|
7
|
+
required: true,
|
|
8
|
+
description: 'Painted overlay surface that presents the tooltip.',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'Tooltip text',
|
|
12
|
+
required: true,
|
|
13
|
+
description: 'Tooltip content rendered within the surface.',
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
|
|
3
17
|
/** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
|
|
4
18
|
|
|
5
19
|
export const docs = {
|
|
@@ -110,6 +124,7 @@ export const docs = {
|
|
|
110
124
|
],
|
|
111
125
|
},
|
|
112
126
|
usage: {
|
|
127
|
+
anatomy,
|
|
113
128
|
description:
|
|
114
129
|
'A short text hint that appears on hover or focus, anchored to a trigger element. Use it to describe icon-only buttons, show the full text of truncated labels, or provide supplementary context without cluttering the UI.',
|
|
115
130
|
bestPractices: [
|
|
@@ -217,6 +232,7 @@ export const docsZh = {
|
|
|
217
232
|
],
|
|
218
233
|
},
|
|
219
234
|
usage: {
|
|
235
|
+
anatomy,
|
|
220
236
|
description:
|
|
221
237
|
'A short text hint that appears on hover or focus, anchored to a trigger element. Use it to describe icon-only buttons, show the full text of truncated labels, or provide supplementary context without cluttering the UI.',
|
|
222
238
|
bestPractices: [
|
|
@@ -233,6 +249,7 @@ export const docsZh = {
|
|
|
233
249
|
export const docsDense = {
|
|
234
250
|
description: 'Hover/focus triggered tooltip for displaying short, non-interactive text anchored to trigger element.',
|
|
235
251
|
usage: {
|
|
252
|
+
anatomy,
|
|
236
253
|
description:
|
|
237
254
|
'A short text hint that appears on hover or focus, anchored to a trigger element. Use it to describe icon-only buttons, show the full text of truncated labels, or provide supplementary context without cluttering the UI.',
|
|
238
255
|
bestPractices: [
|