@astryxdesign/core 0.7.1 → 0.7.2-canary.020e1fe
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.map +1 -1
- package/dist/AppShell/AppShell.js +40 -1
- package/dist/AspectRatio/AspectRatio.d.ts +6 -8
- package/dist/AspectRatio/AspectRatio.d.ts.map +1 -1
- package/dist/AspectRatio/AspectRatio.js +44 -3
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +5 -2
- package/dist/Button/Button.d.ts.map +1 -1
- package/dist/Button/Button.js +38 -14
- package/dist/CheckboxInput/CheckboxInput.d.ts +1 -1
- package/dist/CheckboxInput/CheckboxInput.d.ts.map +1 -1
- package/dist/CheckboxInput/CheckboxInput.js +3 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts +9 -1
- package/dist/CheckboxList/CheckboxListItem.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxListItem.js +4 -2
- package/dist/CommandPalette/CommandPaletteInput.d.ts +1 -1
- package/dist/CommandPalette/CommandPaletteInput.d.ts.map +1 -1
- package/dist/CommandPalette/CommandPaletteInput.js +37 -5
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +5 -2
- package/dist/Dialog/Dialog.d.ts.map +1 -1
- package/dist/Dialog/Dialog.js +20 -8
- package/dist/Drawer/Drawer.d.ts +191 -0
- package/dist/Drawer/Drawer.d.ts.map +1 -0
- package/dist/Drawer/Drawer.js +382 -0
- package/dist/Drawer/DrawerHeader.d.ts +85 -0
- package/dist/Drawer/DrawerHeader.d.ts.map +1 -0
- package/dist/Drawer/DrawerHeader.js +134 -0
- package/dist/Drawer/index.d.ts +11 -0
- package/dist/Drawer/index.d.ts.map +1 -0
- package/dist/Drawer/index.js +11 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts +42 -0
- package/dist/Drawer/useDrawerDialogPresence.d.ts.map +1 -0
- package/dist/Drawer/useDrawerDialogPresence.js +236 -0
- package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +83 -11
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -0
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +21 -0
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts +5 -3
- package/dist/DropdownMenu/DropdownMenuDivider.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuDivider.js +7 -3
- package/dist/DropdownMenu/DropdownMenuGroup.d.ts +6 -4
- package/dist/DropdownMenu/DropdownMenuGroup.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuGroup.js +4 -3
- package/dist/DropdownMenu/DropdownMenuSubMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuSubMenu.js +19 -8
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts +24 -0
- package/dist/DropdownMenu/lazyMenuBottomSheet.d.ts.map +1 -0
- package/dist/DropdownMenu/lazyMenuBottomSheet.js +46 -0
- package/dist/EmptyState/EmptyState.d.ts.map +1 -1
- package/dist/EmptyState/EmptyState.js +4 -10
- package/dist/Field/Field.d.ts +1 -1
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +8 -4
- package/dist/Grid/GridSpan.d.ts.map +1 -1
- package/dist/Grid/GridSpan.js +1 -0
- package/dist/Heading/Heading.d.ts.map +1 -1
- package/dist/Heading/Heading.js +4 -2
- package/dist/HoverCard/useHoverCard.d.ts.map +1 -1
- package/dist/HoverCard/useHoverCard.js +10 -2
- package/dist/Item/Item.d.ts +6 -2
- package/dist/Item/Item.d.ts.map +1 -1
- package/dist/Item/Item.js +19 -4
- package/dist/Layer/layerViewportInset.stylex.d.ts +6 -2
- package/dist/Layer/layerViewportInset.stylex.d.ts.map +1 -1
- package/dist/Layer/layerViewportInset.stylex.js +6 -2
- package/dist/Layer/useLayer.d.ts.map +1 -1
- package/dist/Layer/useLayer.js +13 -7
- package/dist/Layer/useLayerDismissal.d.ts +1 -1
- package/dist/Layer/useLayerDismissal.js +1 -1
- package/dist/Layout/container.stylex.d.ts +5 -5
- package/dist/Layout/container.stylex.js +4 -4
- package/dist/List/List.d.ts +46 -19
- package/dist/List/List.d.ts.map +1 -1
- package/dist/List/List.js +28 -10
- package/dist/List/ListContext.d.ts +8 -3
- package/dist/List/ListContext.d.ts.map +1 -1
- package/dist/List/ListContext.js +7 -2
- package/dist/List/ListItem.d.ts +13 -5
- package/dist/List/ListItem.d.ts.map +1 -1
- package/dist/List/ListItem.js +21 -8
- package/dist/List/index.d.ts +1 -1
- package/dist/List/index.d.ts.map +1 -1
- package/dist/Markdown/Markdown.d.ts.map +1 -1
- package/dist/Markdown/Markdown.js +8 -1
- package/dist/Markdown/plugins/frontmatter.d.ts.map +1 -1
- package/dist/Markdown/plugins/frontmatter.js +7 -3
- package/dist/MetadataList/MetadataList.d.ts.map +1 -1
- package/dist/MetadataList/MetadataList.js +5 -1
- package/dist/MetadataList/MetadataListContext.d.ts +1 -1
- package/dist/MetadataList/MetadataListContext.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.d.ts +9 -0
- package/dist/MobileNav/MobileNav.d.ts.map +1 -1
- package/dist/MobileNav/MobileNav.js +30 -3
- package/dist/MultiSelector/MultiSelector.d.ts.map +1 -1
- package/dist/MultiSelector/MultiSelector.js +22 -8
- package/dist/MultiSelector/OptionActions.a11y.chromium.spec.js +100 -2
- package/dist/MultiSelector/hooks.d.ts.map +1 -1
- package/dist/MultiSelector/hooks.js +3 -1
- package/dist/Pagination/Pagination.d.ts +8 -5
- package/dist/Pagination/Pagination.d.ts.map +1 -1
- package/dist/Pagination/Pagination.js +21 -8
- package/dist/Popover/Popover.js +2 -2
- package/dist/PowerSearch/PowerSearch.js +1 -1
- package/dist/RadioList/RadioList.d.ts +1 -1
- package/dist/RadioList/RadioList.d.ts.map +1 -1
- package/dist/RadioList/RadioList.js +6 -2
- package/dist/RadioList/RadioListItem.d.ts +9 -1
- package/dist/RadioList/RadioListItem.d.ts.map +1 -1
- package/dist/RadioList/RadioListItem.js +2 -0
- package/dist/Selector/hooks.d.ts.map +1 -1
- package/dist/Selector/hooks.js +6 -2
- package/dist/SideNav/SideNavItem.d.ts +8 -1
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +71 -9
- package/dist/Switch/Switch.d.ts +1 -1
- package/dist/Switch/Switch.d.ts.map +1 -1
- package/dist/Switch/Switch.js +13 -1
- package/dist/TabList/TabMenu.d.ts +2 -2
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +6 -3
- package/dist/Text/Text.d.ts.map +1 -1
- package/dist/Text/Text.js +4 -2
- package/dist/Text/useTruncation.d.ts +7 -5
- package/dist/Text/useTruncation.d.ts.map +1 -1
- package/dist/Text/useTruncation.js +16 -5
- package/dist/ToggleButton/ToggleButton.d.ts +3 -2
- package/dist/ToggleButton/ToggleButton.d.ts.map +1 -1
- package/dist/ToggleButton/ToggleButton.js +12 -1
- package/dist/Tooltip/useTooltip.d.ts.map +1 -1
- package/dist/Tooltip/useTooltip.js +11 -0
- package/dist/TopNav/TopNavMegaMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +3 -3
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +3 -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 +2 -2
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +57 -9
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +26 -0
- package/dist/astryx.css +47 -13
- package/dist/hooks/useEntryAnimation.d.ts +2 -1
- package/dist/hooks/useEntryAnimation.d.ts.map +1 -1
- package/dist/hooks/useEntryAnimation.js +14 -12
- package/dist/hooks/useIsHydrating.d.ts +6 -0
- package/dist/hooks/useIsHydrating.d.ts.map +1 -0
- package/dist/hooks/useIsHydrating.js +30 -0
- package/dist/hooks/useMenuHover.d.ts.map +1 -1
- package/dist/hooks/useMenuHover.js +18 -13
- package/dist/i18n/generated-locales/en.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/en.generated.js +112 -1
- package/dist/i18n/generated-locales/pseudo.generated.d.ts.map +1 -1
- package/dist/i18n/generated-locales/pseudo.generated.js +112 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/derivedVarRegistry.d.ts.map +1 -1
- package/dist/theme/derivedVarRegistry.js +0 -3
- package/dist/utils/focusOutline.stylex.d.ts +4 -0
- package/dist/utils/focusOutline.stylex.d.ts.map +1 -1
- package/dist/utils/focusOutline.stylex.js +4 -0
- package/dist/utils/plainDate.d.ts.map +1 -1
- package/dist/utils/plainDate.js +15 -9
- package/dist/utils/sharedMutationObserver.d.ts +21 -0
- package/dist/utils/sharedMutationObserver.d.ts.map +1 -0
- package/dist/utils/sharedMutationObserver.js +69 -0
- package/locales/en.json +444 -0
- package/locales/pseudo.json +333 -0
- package/package.json +9 -4
- package/scripts/agent-doc-state.mjs +38 -0
- package/scripts/postinstall.mjs +1 -1
- package/src/AppShell/AppShell.tsx +45 -1
- package/src/AspectRatio/AspectRatio.test.tsx +44 -43
- package/src/AspectRatio/AspectRatio.tsx +38 -18
- package/src/AspectRatio/__tests__/AspectRatioFitLayers.a11y.browser.spec.ts +157 -0
- package/src/Avatar/Avatar.doc.mjs +5 -3
- package/src/AvatarGroup/AvatarGroup.doc.mjs +3 -2
- package/src/Breadcrumbs/BreadcrumbItem.tsx +4 -1
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +30 -1
- package/src/Button/Button.doc.mjs +2 -2
- package/src/Button/Button.test.tsx +155 -9
- package/src/Button/Button.tsx +39 -16
- package/src/Button/__tests__/Button.a11y.known-failures.ts +1 -62
- package/src/Button/__tests__/Button.a11y.states.ts +0 -10
- package/src/Card/Card.doc.mjs +1 -1
- package/src/Chat/__tests__/ChatMessageMetadata.a11y.chromium.spec.ts +3 -1
- package/src/CheckboxInput/CheckboxInput.test.tsx +34 -0
- package/src/CheckboxInput/CheckboxInput.tsx +3 -1
- package/src/CheckboxList/CheckboxList.test.tsx +22 -0
- package/src/CheckboxList/CheckboxListItem.doc.mjs +16 -0
- package/src/CheckboxList/CheckboxListItem.tsx +10 -0
- package/src/Code/Code.doc.mjs +1 -0
- package/src/CommandPalette/CommandPalette.doc.mjs +2 -0
- package/src/CommandPalette/CommandPaletteInput.test.tsx +53 -4
- package/src/CommandPalette/CommandPaletteInput.tsx +33 -3
- package/src/CommandPalette/__tests__/CommandPaletteInputAudit.a11y.chromium.spec.ts +335 -0
- package/src/CommandPalette/__tests__/CommandPaletteItemAudit.a11y.chromium.spec.ts +292 -0
- package/src/ContextMenu/ContextMenu.doc.mjs +2 -3
- package/src/ContextMenu/ContextMenu.tsx +4 -1
- package/src/ContextMenu/__tests__/ContextMenuAudit.a11y.chromium.spec.ts +438 -0
- package/src/Dialog/Dialog.test.tsx +46 -0
- package/src/Dialog/Dialog.tsx +20 -7
- package/src/Dialog/__tests__/Dialog.a11y.known-failures.ts +0 -14
- package/src/Drawer/Drawer.doc.mjs +473 -0
- package/src/Drawer/Drawer.spec.md +357 -0
- package/src/Drawer/Drawer.test.tsx +1300 -0
- package/src/Drawer/Drawer.tsx +613 -0
- package/src/Drawer/DrawerDirection.test.tsx +127 -0
- package/src/Drawer/DrawerHeader.doc.mjs +293 -0
- package/src/Drawer/DrawerHeader.test.tsx +102 -0
- package/src/Drawer/DrawerHeader.tsx +235 -0
- package/src/Drawer/__tests__/DrawerAudit.a11y.chromium.spec.ts +401 -0
- package/src/Drawer/__tests__/DrawerHeaderAudit.a11y.chromium.spec.ts +297 -0
- package/src/Drawer/index.ts +13 -0
- package/src/Drawer/useDrawerDialogPresence.ts +284 -0
- package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +57 -0
- package/src/DropdownMenu/DropdownMenu.test.tsx +79 -18
- package/src/DropdownMenu/DropdownMenu.tsx +83 -12
- package/src/DropdownMenu/DropdownMenuContext.tsx +24 -0
- package/src/DropdownMenu/DropdownMenuDivider.doc.mjs +2 -2
- package/src/DropdownMenu/DropdownMenuDivider.spec.md +192 -0
- package/src/DropdownMenu/DropdownMenuDivider.tsx +9 -5
- package/src/DropdownMenu/DropdownMenuGroup.doc.mjs +169 -10
- package/src/DropdownMenu/DropdownMenuGroup.tsx +6 -4
- package/src/DropdownMenu/DropdownMenuLazySheet.test.tsx +126 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.test.tsx +185 -0
- package/src/DropdownMenu/DropdownMenuSubMenu.tsx +19 -5
- package/src/DropdownMenu/__tests__/DropdownMenuDividerAudit.a11y.chromium.spec.ts +280 -0
- package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +334 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.chromium.spec.ts +145 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.known-failures.ts +26 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.renders.tsx +65 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.states.ts +138 -0
- package/src/DropdownMenu/__tests__/Menu.a11y.test.tsx +136 -0
- package/src/DropdownMenu/__tests__/warmMenuBottomSheet.tsx +43 -0
- package/src/DropdownMenu/lazyMenuBottomSheet.ts +71 -0
- package/src/EmptyState/EmptyState.doc.mjs +3 -2
- package/src/EmptyState/EmptyState.spec.md +189 -0
- package/src/EmptyState/EmptyState.test.tsx +74 -3
- package/src/EmptyState/EmptyState.tsx +4 -8
- package/src/Field/Field.doc.mjs +14 -8
- package/src/Field/Field.spec.md +217 -0
- package/src/Field/Field.test.tsx +60 -2
- package/src/Field/Field.tsx +17 -8
- package/src/Field/FieldLabel.doc.mjs +133 -26
- package/src/Field/FieldLabel.spec.md +172 -0
- package/src/Field/__tests__/FieldLabelAudit.a11y.chromium.spec.ts +296 -0
- package/src/Grid/GridSpan.tsx +3 -0
- package/src/Heading/Heading.test.tsx +57 -0
- package/src/Heading/Heading.tsx +6 -2
- package/src/HoverCard/HoverCard.test.tsx +58 -0
- package/src/HoverCard/useHoverCard.tsx +10 -2
- package/src/Icon/Icon.doc.mjs +36 -0
- package/src/IconButton/IconButton.doc.mjs +2 -2
- package/src/IconButton/IconButton.test.tsx +3 -1
- package/src/Item/Item.doc.mjs +12 -8
- package/src/Item/Item.spec.md +226 -0
- package/src/Item/Item.test.tsx +61 -0
- package/src/Item/Item.tsx +40 -4
- package/src/Layer/layerViewportInset.source-build.test.mjs +90 -0
- package/src/Layer/layerViewportInset.stylex.ts +6 -2
- package/src/Layer/layerViewportInset.test.ts +1 -0
- package/src/Layer/useLayer.tsx +24 -13
- package/src/Layer/useLayerDismissal.ts +1 -1
- package/src/Layout/LayoutHeader.doc.mjs +5 -0
- package/src/Layout/container.stylex.ts +6 -6
- package/src/List/List.doc.mjs +14 -1
- package/src/List/List.spec.md +129 -77
- package/src/List/List.test.tsx +163 -94
- package/src/List/List.tsx +74 -18
- package/src/List/ListContext.tsx +9 -3
- package/src/List/ListItem.doc.mjs +24 -5
- package/src/List/ListItem.tsx +56 -27
- package/src/List/index.ts +1 -1
- package/src/Markdown/Markdown.tsx +14 -1
- package/src/Markdown/plugins/frontmatter.test.tsx +25 -0
- package/src/Markdown/plugins/frontmatter.ts +7 -3
- package/src/MetadataList/MetadataList.doc.mjs +3 -3
- package/src/MetadataList/MetadataList.test.tsx +38 -0
- package/src/MetadataList/MetadataList.tsx +8 -1
- package/src/MetadataList/MetadataListContext.tsx +1 -1
- package/src/MobileNav/MobileNav.tsx +30 -3
- package/src/MobileNav/MobileNavCloseEdgeCases.test.tsx +173 -15
- package/src/MoreMenu/MoreMenu.test.tsx +5 -1
- package/src/MultiSelector/MultiSelector.test.tsx +159 -0
- package/src/MultiSelector/MultiSelector.tsx +40 -7
- package/src/MultiSelector/OptionActions.a11y.chromium.spec.ts +112 -2
- package/src/MultiSelector/hooks.ts +3 -1
- package/src/MultiSelector/useMultiCombobox.doc.mjs +267 -0
- package/src/Pagination/Pagination.doc.mjs +7 -7
- package/src/Pagination/Pagination.spec.md +9 -9
- package/src/Pagination/Pagination.test.tsx +242 -0
- package/src/Pagination/Pagination.tsx +27 -11
- package/src/Popover/Popover.test.tsx +2 -2
- package/src/Popover/Popover.tsx +4 -4
- package/src/PowerSearch/PowerSearch.test.tsx +85 -0
- package/src/PowerSearch/PowerSearch.tsx +2 -2
- package/src/ProgressBar/ProgressBar.doc.mjs +1 -0
- package/src/RadioList/RadioList.fr10.test.tsx +45 -2
- package/src/RadioList/RadioList.test.tsx +22 -0
- package/src/RadioList/RadioList.tsx +4 -1
- package/src/RadioList/RadioListItem.doc.mjs +16 -0
- package/src/RadioList/RadioListItem.tsx +10 -1
- package/src/Resizable/useResizable.doc.mjs +2 -0
- package/src/ScrollableArea/ScrollableArea.doc.mjs +1 -1
- package/src/Selector/hooks.ts +6 -2
- package/src/Selector/useCombobox.doc.mjs +237 -0
- package/src/SideNav/SideNav.spec.md +227 -0
- package/src/SideNav/SideNav.test.tsx +179 -0
- package/src/SideNav/SideNavItem.doc.mjs +2 -2
- package/src/SideNav/SideNavItem.tsx +96 -17
- package/src/Slider/Slider.spec.md +39 -18
- package/src/Spinner/Spinner.doc.mjs +1 -1
- package/src/Switch/Switch.test.tsx +49 -0
- package/src/Switch/Switch.tsx +11 -0
- package/src/TabList/TabList.spec.md +57 -44
- package/src/TabList/TabList.test.tsx +67 -0
- package/src/TabList/TabMenu.doc.mjs +4 -3
- package/src/TabList/TabMenu.tsx +7 -4
- package/src/Text/Text.test.tsx +57 -0
- package/src/Text/Text.tsx +6 -2
- package/src/Text/useTruncation.test.tsx +69 -0
- package/src/Text/useTruncation.ts +16 -5
- package/src/TimeInput/TimeInput.fr10.test.tsx +15 -0
- package/src/Timestamp/Timestamp.doc.mjs +1 -1
- package/src/ToggleButton/ToggleButton.test.tsx +95 -0
- package/src/ToggleButton/ToggleButton.tsx +12 -1
- package/src/ToggleButton/ToggleButtonGroup.doc.mjs +4 -0
- package/src/Tokenizer/Tokenizer.test.tsx +54 -1
- package/src/Toolbar/Toolbar.test.tsx +0 -8
- package/src/Toolbar/__tests__/Toolbar.a11y.chromium.spec.ts +163 -0
- package/src/Toolbar/__tests__/Toolbar.a11y.renders.tsx +63 -0
- package/src/Toolbar/__tests__/Toolbar.a11y.states.ts +142 -0
- package/src/Toolbar/__tests__/Toolbar.a11y.test.tsx +126 -0
- package/src/Tooltip/Tooltip.test.tsx +31 -0
- package/src/Tooltip/useTooltip.test.tsx +13 -0
- package/src/Tooltip/useTooltip.tsx +11 -0
- package/src/TopNav/TopNavMegaMenu.test.tsx +22 -0
- package/src/TopNav/TopNavMegaMenu.tsx +7 -3
- package/src/TopNav/TopNavMenu.test.tsx +19 -0
- package/src/TopNav/TopNavMenu.tsx +11 -3
- package/src/TreeList/TreeList.doc.mjs +1 -0
- package/src/TreeList/TreeList.spec.md +29 -17
- package/src/TreeList/TreeList.test.tsx +327 -6
- package/src/TreeList/TreeList.tsx +5 -1
- package/src/TreeList/TreeListBranches.tsx +6 -0
- package/src/TreeList/TreeListItem.tsx +88 -13
- package/src/Typeahead/BaseTypeahead.tsx +26 -0
- package/src/Typeahead/Typeahead.test.tsx +260 -2
- package/src/docPropLiterals.test.ts +36 -10
- package/src/hooks/useEntryAnimation.doc.mjs +4 -4
- package/src/hooks/useEntryAnimation.ssr.test.tsx +143 -0
- package/src/hooks/useEntryAnimation.ts +15 -16
- package/src/hooks/useIsHydrating.test.tsx +70 -0
- package/src/hooks/useIsHydrating.ts +31 -0
- package/src/hooks/useMenuHover.ts +18 -13
- package/src/i18n/InternationalizationProvider.doc.mjs +8 -0
- package/src/i18n/InternationalizationProvider.spec.md +252 -0
- package/src/i18n/__tests__/InternationalizationProvider.test.tsx +128 -0
- package/src/i18n/generated-locales/en.generated.ts +121 -0
- package/src/i18n/generated-locales/pseudo.generated.ts +121 -0
- package/src/i18n/useTranslator.test.tsx +37 -0
- package/src/index.ts +1 -0
- package/src/postinstall.test.mjs +46 -0
- package/src/reset.css +0 -29
- package/src/theme/derivedVarRegistry.test.ts +7 -3
- package/src/theme/derivedVarRegistry.ts +0 -3
- package/src/utils/focusOutline.stylex.ts +4 -0
- package/src/utils/plainDate.test.ts +37 -1
- package/src/utils/plainDate.ts +15 -5
- package/src/utils/sharedMutationObserver.test.ts +53 -0
- package/src/utils/sharedMutationObserver.ts +78 -0
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 3
|
|
3
|
+
template_version: 7
|
|
4
|
+
kind: component
|
|
5
|
+
id: component:Item
|
|
6
|
+
authority: current
|
|
7
|
+
archive_reason: null
|
|
8
|
+
superseded_by: null
|
|
9
|
+
approved_by: cixzhang
|
|
10
|
+
approved_at: 2026-10-16
|
|
11
|
+
owners: [cixzhang]
|
|
12
|
+
review_triggers: [public-api, layout, theming]
|
|
13
|
+
verified_by:
|
|
14
|
+
[
|
|
15
|
+
packages/core/src/Item/Item.test.tsx,
|
|
16
|
+
packages/core/src/List/List.test.tsx,
|
|
17
|
+
packages/core/src/RadioList/RadioList.test.tsx,
|
|
18
|
+
packages/core/src/CheckboxList/CheckboxList.test.tsx,
|
|
19
|
+
apps/storybook/stories/Item.stories.tsx,
|
|
20
|
+
scripts/check-knowledge.mjs,
|
|
21
|
+
]
|
|
22
|
+
modules: []
|
|
23
|
+
families: [family:navigation-destinations]
|
|
24
|
+
design_specs: []
|
|
25
|
+
architecture:
|
|
26
|
+
[
|
|
27
|
+
architecture:component-theming-surface,
|
|
28
|
+
architecture:public-component-api,
|
|
29
|
+
architecture:internationalization,
|
|
30
|
+
]
|
|
31
|
+
contributing: [contributing:api-conventions]
|
|
32
|
+
system_specs: [spec:AST-017/FR3, spec:AST-057]
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
# Item component contract
|
|
36
|
+
|
|
37
|
+
<!-- Describe the system, not the project: present tense, what it does. No proposals, history, pull requests, or research in the record; see docs/contributing/spec-writing.md and report its rubric results in the pull request. -->
|
|
38
|
+
|
|
39
|
+
This record governs how Item aligns its start and end content against the
|
|
40
|
+
label. Item's swipe actions are governed by `spec:AST-057`, and its link and
|
|
41
|
+
navigation semantics by `family:navigation-destinations`; other Item behavior
|
|
42
|
+
remains described by its source, tests, and `Item.doc.mjs` until a record
|
|
43
|
+
claims it.
|
|
44
|
+
|
|
45
|
+
## Contract at a glance
|
|
46
|
+
|
|
47
|
+
| Area | Contract |
|
|
48
|
+
| ----------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| Public contract | `align?: 'center' \| 'start' \| 'first-line'` on Item, ListItem, RadioListItem, and CheckboxListItem; default `center`. |
|
|
50
|
+
| Behavior | `first-line` centers each start and end slot on the label's first line, for any slot height; a slot taller than that line moves the text down rather than leaving the row. |
|
|
51
|
+
| End-user impact | A small status dot, radio, or age stays level with the first line of a wrapped label instead of drifting to the middle of the row (`center`) or riding above the line (`start`). |
|
|
52
|
+
| Builder impact | None by default. A builder opts in per row with `align="first-line"`; theme authors may style the `item` target's `first-line` alignment. |
|
|
53
|
+
| Compatibility/readiness | Additive: a new value on an existing closed axis and typed forwarding of an existing runtime pass-through. Rows that omit `align` are unchanged. |
|
|
54
|
+
| Review checks | Reject a changed default, changed `center`/`start` geometry, JavaScript measurement, a slot pushed outside the row, a second theme target, or a composing row that drops the value. |
|
|
55
|
+
| Governing rules | FR1–FR8 below; `architecture:component-theming-surface/INV6`; `spec:AST-017/FR3`. |
|
|
56
|
+
|
|
57
|
+
This table is a review projection; the body below is authoritative.
|
|
58
|
+
|
|
59
|
+
## Intent
|
|
60
|
+
|
|
61
|
+
Item is the shared row behind lists, menus, pickers, and option rows. Its label
|
|
62
|
+
can wrap, while its start and end content is often a single-line-sized mark: a
|
|
63
|
+
status dot, a radio or checkbox, an icon, a short timestamp. Those marks belong
|
|
64
|
+
to the first line of text they annotate. Item owns the alignment because only
|
|
65
|
+
Item knows where its label's first line sits; a caller cannot place a slot
|
|
66
|
+
against it without copying Item's typography.
|
|
67
|
+
|
|
68
|
+
## Compatibility and migration
|
|
69
|
+
|
|
70
|
+
- Released default preserved: `yes`; omitted `align` resolves to `center`.
|
|
71
|
+
- Compatibility class: additive closed-axis value; additive typed prop on three
|
|
72
|
+
composing rows that already forward unknown props to Item at runtime.
|
|
73
|
+
- Controlled/uncontrolled behavior: not applicable.
|
|
74
|
+
- Migration decision: `component:Item/DEC-1`.
|
|
75
|
+
|
|
76
|
+
Consumer migration instructions belong in consumer docs and release notes.
|
|
77
|
+
|
|
78
|
+
## Ownership boundary
|
|
79
|
+
|
|
80
|
+
**Owns**
|
|
81
|
+
|
|
82
|
+
- The `align` axis: its values, default, and the geometry of each value for
|
|
83
|
+
the start and end content slots.
|
|
84
|
+
- Reflecting the resolved alignment on the `item` theme target.
|
|
85
|
+
- The forwarding rule for rows that compose Item and expose `align`.
|
|
86
|
+
|
|
87
|
+
**Does not own / non-goals**
|
|
88
|
+
|
|
89
|
+
- The `marker` slot's alignment — owned by whoever renders the marker; ListItem
|
|
90
|
+
positions its own markers against the first line.
|
|
91
|
+
- Typography of caller content inside `label` — owned by the caller.
|
|
92
|
+
- A theme-wide default alignment — themes style values; they do not choose a
|
|
93
|
+
component's prop default (`architecture:component-theming-surface`).
|
|
94
|
+
- Alignment inside a slot's own content (for example, an avatar stack) — owned
|
|
95
|
+
by that content.
|
|
96
|
+
|
|
97
|
+
## Public concepts
|
|
98
|
+
|
|
99
|
+
| Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
|
|
100
|
+
| --------- | ------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | -------- | ---------------- | --------- | -------------------------------------------- |
|
|
101
|
+
| Alignment | `center`, `start`, `first-line` | `center`: slots centered on the whole text block. `start`: slot tops on the text block's top. `first-line`: slot centers on the first line's center. | Every density, layout, interaction mode, and direction; start and end slots | `center` | `component:Item` | stable | Other values are rejected by the public type |
|
|
102
|
+
|
|
103
|
+
## Behavioral and layout contract
|
|
104
|
+
|
|
105
|
+
| ID | Invariant | Basis | Draft review state |
|
|
106
|
+
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- | ------------------ |
|
|
107
|
+
| FR1 | Item MUST accept `align` with exactly `center`, `start`, and `first-line`, and MUST resolve an omitted value to `center`. The geometry of `center` and `start` MUST NOT change. | `component:Item/DEC-1` | settled |
|
|
108
|
+
| FR2 | Under `first-line`, the block-axis center of each rendered start-content and end-content slot MUST coincide with the block-axis center of the label's first line box, for every slot block size. | Owner direction | settled |
|
|
109
|
+
| FR3 | Under `first-line`, a slot taller than the label's first line MUST stay inside the row's content box: the label and description move down by the difference, and the row grows to fit. No slot is clipped or painted into the row's block padding. | Owner direction | settled |
|
|
110
|
+
| FR4 | A row whose label renders a single line and which has no description MUST render identically under `first-line` and `center`, for every slot block size. | Follows from FR2 and FR3 | settled |
|
|
111
|
+
| FR5 | The first line box is the label line as Item styles it, from the active theme's body text size and leading. A theme that changes those tokens moves the alignment with them. Caller content inside `label` that sets its own font size or line height is outside the FR2 guarantee. | Shared typography source | settled |
|
|
112
|
+
| FR6 | `first-line` MUST hold in every density, in `stacked` and `inline` layouts, with `labelLines` truncation, and in plain, button, link, link-root, delegated, and parent-role rows. In right-to-left text it MUST produce the same block-axis placement with the slots mirrored by logical order and no DOM reordering. | `architecture:internationalization` | settled |
|
|
113
|
+
| FR7 | The `item` theme target MUST reflect the resolved alignment as its existing `align` selector axis, including `first-line`, and Item's public theming metadata MUST list that value. No new target, state, or theme-level default is added. | `architecture:component-theming-surface/INV6`; `component:Item/DEC-2` | settled |
|
|
114
|
+
| FR8 | ListItem, RadioListItem, and CheckboxListItem MUST expose `align` with Item's values and default and forward it unchanged to the Item row they render. A composing row MUST NOT drop, remap, or narrow the value. | Owner direction | settled |
|
|
115
|
+
|
|
116
|
+
### Allowed variation
|
|
117
|
+
|
|
118
|
+
- **AV1 — Slot content.** Any slot content and size may appear; FR2 holds for
|
|
119
|
+
each slot independently, so a start slot and an end slot of different heights
|
|
120
|
+
each center on the first line.
|
|
121
|
+
- **AV2 — Theme typography.** Body text size and leading may vary by theme; the
|
|
122
|
+
first line box follows them (FR5).
|
|
123
|
+
- **AV3 — Row height.** Under `first-line` a row may be taller than the same
|
|
124
|
+
row under `center` when a slot is taller than the first line and a
|
|
125
|
+
description or second label line is present (FR3).
|
|
126
|
+
|
|
127
|
+
### Representative states
|
|
128
|
+
|
|
129
|
+
| State | Required invariant | Allowed variation |
|
|
130
|
+
| -------------------------------------------- | --------------------------------------------------------------------- | ------------------------------------- |
|
|
131
|
+
| Wrapped label, 6px dot start, short-text end | Both slot centers on the first line's center. | Density, theme typography, direction. |
|
|
132
|
+
| One-line label, no description, any slot | Identical to `center`. | Slot size. |
|
|
133
|
+
| Label and description, 40px avatar start | Avatar center on the first line's center; text moves down; row grows. | Avatar size. |
|
|
134
|
+
| Radio or checkbox row with a wrapped label | The control centers on the first line. | Control size by Field size. |
|
|
135
|
+
| Right-to-left | Same block-axis placement; slots mirrored by logical order. | Writing direction. |
|
|
136
|
+
| Omitted `align` | Identical to today's `center`. | None. |
|
|
137
|
+
|
|
138
|
+
### Transformation and precedence order
|
|
139
|
+
|
|
140
|
+
- **ORD1 — Resolution.** An explicit `align` on a composing row forwards to
|
|
141
|
+
Item unchanged; Item resolves an omitted value to `center`; the resolved value
|
|
142
|
+
drives both geometry and the `item` target's selector axis, so the two never
|
|
143
|
+
disagree.
|
|
144
|
+
|
|
145
|
+
### Performance and resources
|
|
146
|
+
|
|
147
|
+
- **PR1 — CSS geometry only.** Every alignment value MUST be achieved in CSS:
|
|
148
|
+
no measurement, observer, listener, state, Effect, or extra render pass.
|
|
149
|
+
|
|
150
|
+
## Accessibility contract
|
|
151
|
+
|
|
152
|
+
- **AR1 — Presentation only.** Alignment MUST NOT change the DOM order, role,
|
|
153
|
+
accessible name or description, focus target, tab order, or hit target of the
|
|
154
|
+
row or its slots.
|
|
155
|
+
- **AR2 — No exposed text.** Any construct that implements `first-line` MUST
|
|
156
|
+
contribute no text to the accessibility tree.
|
|
157
|
+
|
|
158
|
+
## Design relationships
|
|
159
|
+
|
|
160
|
+
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
161
|
+
| --------------------- | ----------------------------------------------------- | ------------------------ | -------------- | ------------------ |
|
|
162
|
+
| Start and end content | Annotates the first line of the label it sits beside. | Owner direction | Supporting | FR2–FR4 |
|
|
163
|
+
| Label first line | The reference line the slots align to. | Item typography | Prominent | FR5 |
|
|
164
|
+
|
|
165
|
+
## Family and system relationships
|
|
166
|
+
|
|
167
|
+
- `spec:AST-057` owns Item's swipe actions and their panels; alignment does
|
|
168
|
+
not change them, because the panels sit outside the row's flow.
|
|
169
|
+
- `family:navigation-destinations` owns Item's link and navigation semantics;
|
|
170
|
+
alignment does not change them.
|
|
171
|
+
- `architecture:component-theming-surface` owns how visual axes reach theme
|
|
172
|
+
targets; this record adds one value to Item's existing `align` axis.
|
|
173
|
+
- `architecture:public-component-api` owns prop admission; FR8 types an existing
|
|
174
|
+
runtime pass-through rather than adding a parallel concept.
|
|
175
|
+
- `architecture:internationalization` owns logical-direction behavior; FR6
|
|
176
|
+
applies it.
|
|
177
|
+
- `spec:AST-017/FR3` classifies this as a non-breaking feature: it adds a value
|
|
178
|
+
and a typed prop, narrows nothing, and a caller who never sets `align` sees no
|
|
179
|
+
change.
|
|
180
|
+
|
|
181
|
+
## Verification map
|
|
182
|
+
|
|
183
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
184
|
+
| -------- | ------------------------------------------------------------------------------- | ------------------------------------------------------------- | ------------------------------------------------------------------------------------- | ------------------- |
|
|
185
|
+
| FR1, FR7 | `Item.test.tsx` alignment and theme-reflection suites; public type test | Omitted, `center`, `start`, `first-line` | A changed default, a missing `data-align="first-line"`, or a widened type fails. | `audit:Item/api` |
|
|
186
|
+
| FR2–FR6 | Real-Chromium geometry assertions over the Item alignment stories | Wrapped label with dot and age; avatar; densities; RTL; theme | A slot center off the first line center by more than 0.5px, or a clipped slot, fails. | `audit:Item/layout` |
|
|
187
|
+
| FR8 | `List.test.tsx`, `RadioList.test.tsx`, `CheckboxList.test.tsx` forwarding cases | Each composing row with `align="first-line"` | A row whose Item root lacks `data-align="first-line"` fails. | `audit:Item/api` |
|
|
188
|
+
| AR1, AR2 | Accessibility-tree snapshot of a `first-line` row against a `center` row | Plain and option rows | Any difference in name, role, description, or order fails. | `audit:Item/a11y` |
|
|
189
|
+
| PR1 | Source review of Item's alignment styles | All values | A ref, observer, or Effect added for alignment fails review. | `audit:Item/layout` |
|
|
190
|
+
|
|
191
|
+
## Decision log
|
|
192
|
+
|
|
193
|
+
<!-- Record the boundary or requirement, not how it was reached. A rejected alternative is at most one line here, kept only when it is consequential and likely to recur. -->
|
|
194
|
+
|
|
195
|
+
### DEC-1 — `first-line` is an opt-in value; `center` stays the default
|
|
196
|
+
|
|
197
|
+
**Reference:** `component:Item/DEC-1`
|
|
198
|
+
**Decider:** cixzhang, 2026-10-16
|
|
199
|
+
|
|
200
|
+
A wrapped label with a single-line-sized mark needs the mark on its first line,
|
|
201
|
+
and neither existing value does that: `center` drops the mark to the middle of
|
|
202
|
+
the row and `start` pins its top, which leaves a small mark above the line's
|
|
203
|
+
center. A new value fixes those rows without moving any row that relies on
|
|
204
|
+
today's default.
|
|
205
|
+
|
|
206
|
+
Rejected: making `first-line` the default, because a slot sized to the whole
|
|
207
|
+
text block, such as an avatar beside a label and description, is correct under
|
|
208
|
+
`center`.
|
|
209
|
+
|
|
210
|
+
### DEC-2 — The theme setting is the `item` target's alignment axis
|
|
211
|
+
|
|
212
|
+
**Reference:** `component:Item/DEC-2`
|
|
213
|
+
**Decider:** cixzhang, 2026-10-16
|
|
214
|
+
|
|
215
|
+
Themes reach `first-line` rows through the `item` target's existing `align`
|
|
216
|
+
selector axis, the same way they reach `center` and `start`. A theme can style
|
|
217
|
+
those rows; it does not choose which value a row receives.
|
|
218
|
+
|
|
219
|
+
## Open questions
|
|
220
|
+
|
|
221
|
+
None.
|
|
222
|
+
|
|
223
|
+
## Content boundary
|
|
224
|
+
|
|
225
|
+
This file does not duplicate consumer prop tables/examples, current audit
|
|
226
|
+
results, implementation steps, or family/system rules. It links to their owners.
|
package/src/Item/Item.test.tsx
CHANGED
|
@@ -531,6 +531,67 @@ describe('Item', () => {
|
|
|
531
531
|
expect(screen.getByTestId('item')).toBeInTheDocument();
|
|
532
532
|
});
|
|
533
533
|
|
|
534
|
+
it('reflects the resolved alignment on the item theme target', () => {
|
|
535
|
+
const {rerender} = render(<Item label="Item" data-testid="item" />);
|
|
536
|
+
expect(screen.getByTestId('item')).toHaveAttribute('data-align', 'center');
|
|
537
|
+
for (const align of ['center', 'start', 'first-line'] as const) {
|
|
538
|
+
rerender(<Item label="Item" align={align} data-testid="item" />);
|
|
539
|
+
const item = screen.getByTestId('item');
|
|
540
|
+
expect(item).toHaveClass('astryx-item');
|
|
541
|
+
expect(item).toHaveAttribute('data-align', align);
|
|
542
|
+
}
|
|
543
|
+
});
|
|
544
|
+
|
|
545
|
+
it('aligns the row on first baselines only under first-line', () => {
|
|
546
|
+
const {rerender} = render(<Item label="Item" data-testid="item" />);
|
|
547
|
+
const declares = (value: string) =>
|
|
548
|
+
rulesDeclaredFor(screen.getByTestId('item')).some(rule =>
|
|
549
|
+
rule.includes(`align-items: ${value}`),
|
|
550
|
+
);
|
|
551
|
+
expect(declares('baseline')).toBe(false);
|
|
552
|
+
rerender(<Item label="Item" align="start" data-testid="item" />);
|
|
553
|
+
expect(declares('baseline')).toBe(false);
|
|
554
|
+
rerender(<Item label="Item" align="first-line" data-testid="item" />);
|
|
555
|
+
expect(declares('baseline')).toBe(true);
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
it('gives each first-line slot a strut with no accessible text', () => {
|
|
559
|
+
render(
|
|
560
|
+
<Item
|
|
561
|
+
label="Item"
|
|
562
|
+
align="first-line"
|
|
563
|
+
startContent={<span data-testid="start">S</span>}
|
|
564
|
+
endContent={<span data-testid="end">E</span>}
|
|
565
|
+
/>,
|
|
566
|
+
);
|
|
567
|
+
for (const id of ['start', 'end']) {
|
|
568
|
+
const slot = screen.getByTestId(id).parentElement!;
|
|
569
|
+
const before = rulesDeclaredFor(slot).filter(rule =>
|
|
570
|
+
rule.slice(0, rule.indexOf('{')).includes('::before'),
|
|
571
|
+
);
|
|
572
|
+
expect(before.some(rule => rule.includes('/ ""'))).toBe(true);
|
|
573
|
+
}
|
|
574
|
+
});
|
|
575
|
+
|
|
576
|
+
it('leaves center and start slots without a strut', () => {
|
|
577
|
+
const {rerender} = render(
|
|
578
|
+
<Item label="Item" startContent={<span data-testid="start">S</span>} />,
|
|
579
|
+
);
|
|
580
|
+
const hasStrut = () =>
|
|
581
|
+
rulesDeclaredFor(screen.getByTestId('start').parentElement!).some(rule =>
|
|
582
|
+
rule.slice(0, rule.indexOf('{')).includes('::before'),
|
|
583
|
+
);
|
|
584
|
+
expect(hasStrut()).toBe(false);
|
|
585
|
+
rerender(
|
|
586
|
+
<Item
|
|
587
|
+
label="Item"
|
|
588
|
+
align="start"
|
|
589
|
+
startContent={<span data-testid="start">S</span>}
|
|
590
|
+
/>,
|
|
591
|
+
);
|
|
592
|
+
expect(hasStrut()).toBe(false);
|
|
593
|
+
});
|
|
594
|
+
|
|
534
595
|
// ===========================================================================
|
|
535
596
|
// Description rendering
|
|
536
597
|
// ===========================================================================
|
package/src/Item/Item.tsx
CHANGED
|
@@ -67,7 +67,7 @@ const LazyItemSwipeLayer = lazy(async () => import('./ItemSwipeLayer'));
|
|
|
67
67
|
// Types
|
|
68
68
|
// =============================================================================
|
|
69
69
|
|
|
70
|
-
export type ItemAlign = 'center' | 'start';
|
|
70
|
+
export type ItemAlign = 'center' | 'start' | 'first-line';
|
|
71
71
|
export type ItemDensity = 'compact' | 'balanced' | 'spacious';
|
|
72
72
|
|
|
73
73
|
/**
|
|
@@ -168,7 +168,11 @@ export interface ItemProps extends BaseProps<HTMLElement> {
|
|
|
168
168
|
endContent?: ReactNode;
|
|
169
169
|
|
|
170
170
|
/**
|
|
171
|
-
* Vertical alignment of the start/end content slots.
|
|
171
|
+
* Vertical alignment of the start/end content slots. `center` centers each
|
|
172
|
+
* slot on the whole text block; `start` lines up slot tops with the text's
|
|
173
|
+
* top; `first-line` centers each slot on the label's first line, so a small
|
|
174
|
+
* mark (a status dot, a radio, a timestamp) stays level with the first line
|
|
175
|
+
* of a wrapped label. A slot taller than that line moves the text down.
|
|
172
176
|
* @default 'center'
|
|
173
177
|
*/
|
|
174
178
|
align?: ItemAlign;
|
|
@@ -338,7 +342,7 @@ const styles = stylex.create({
|
|
|
338
342
|
gap: spacingVars['--spacing-2'],
|
|
339
343
|
// The inline inset is published as --_item-inset-inline and the padding
|
|
340
344
|
// derives from it, so consumers that need to compensate for the inset
|
|
341
|
-
// (List's
|
|
345
|
+
// (List's edge treatments) read the var instead of mirroring the values.
|
|
342
346
|
// Themes that set paddingInline on `item` also feed this var via the
|
|
343
347
|
// derived var registry, keeping padding and compensation in sync.
|
|
344
348
|
'--_item-inset-inline': spacingVars['--spacing-2'],
|
|
@@ -351,6 +355,30 @@ const styles = stylex.create({
|
|
|
351
355
|
alignStart: {
|
|
352
356
|
alignItems: 'flex-start',
|
|
353
357
|
},
|
|
358
|
+
// `first-line`: the row aligns its children on their first baselines. The
|
|
359
|
+
// label's first baseline is its first line's; each slot gets the same
|
|
360
|
+
// baseline from its strut (below), which the slot centers against its
|
|
361
|
+
// content. So each slot's center lands on the first line's center for any
|
|
362
|
+
// slot height, and a taller slot pushes the text down instead of leaving
|
|
363
|
+
// the row. Pure CSS: no measurement.
|
|
364
|
+
alignFirstLine: {
|
|
365
|
+
alignItems: 'baseline',
|
|
366
|
+
},
|
|
367
|
+
// A zero-width line of label text inside the slot: same size and leading as
|
|
368
|
+
// the label, so its line box is the label's first line box. The slot centers
|
|
369
|
+
// it against the slot's content, and the row's baseline alignment puts it on
|
|
370
|
+
// the label's first line. Its content carries empty alternative text so
|
|
371
|
+
// assistive technology reads nothing from it.
|
|
372
|
+
firstLineSlot: {
|
|
373
|
+
alignItems: 'center',
|
|
374
|
+
'::before': {
|
|
375
|
+
content: stylex.firstThatWorks('"\\200B" / ""', '"\\200B"'),
|
|
376
|
+
inlineSize: 0,
|
|
377
|
+
overflow: 'hidden',
|
|
378
|
+
fontSize: typeScaleVars['--text-body-size'],
|
|
379
|
+
lineHeight: typeScaleVars['--text-body-leading'],
|
|
380
|
+
},
|
|
381
|
+
},
|
|
354
382
|
interactive: {
|
|
355
383
|
cursor: {
|
|
356
384
|
default: 'pointer',
|
|
@@ -712,7 +740,13 @@ export function Item({
|
|
|
712
740
|
<>
|
|
713
741
|
{marker}
|
|
714
742
|
{startContent != null && (
|
|
715
|
-
<span
|
|
743
|
+
<span
|
|
744
|
+
{...stylex.props(
|
|
745
|
+
styles.startContent,
|
|
746
|
+
align === 'first-line' && styles.firstLineSlot,
|
|
747
|
+
)}>
|
|
748
|
+
{startContent}
|
|
749
|
+
</span>
|
|
716
750
|
)}
|
|
717
751
|
|
|
718
752
|
{hasParentRole || isDelegate ? (
|
|
@@ -768,6 +802,7 @@ export function Item({
|
|
|
768
802
|
<span
|
|
769
803
|
{...stylex.props(
|
|
770
804
|
styles.endContent,
|
|
805
|
+
align === 'first-line' && styles.firstLineSlot,
|
|
771
806
|
isDisabled && styles.disabledContent,
|
|
772
807
|
)}>
|
|
773
808
|
{endContent}
|
|
@@ -846,6 +881,7 @@ export function Item({
|
|
|
846
881
|
styles.root,
|
|
847
882
|
densityStyles[density],
|
|
848
883
|
align === 'start' && styles.alignStart,
|
|
884
|
+
align === 'first-line' && styles.alignFirstLine,
|
|
849
885
|
isInteractive && styles.interactive,
|
|
850
886
|
isInteractive && interactionOverlayStyles.backgroundColor,
|
|
851
887
|
isLinkRoot && styles.linkRoot,
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* @file layerViewportInset.source-build.test.mjs
|
|
5
|
+
* @input Uses Babel, the core StyleX build config, the StyleX rule processor,
|
|
6
|
+
* and the sources that cap or inset anchored layers
|
|
7
|
+
* @output Verifies the shipped stylesheet carries the dynamic-viewport,
|
|
8
|
+
* safe-area gutter and caps (spec:AST-059 FR1–FR3), not only the fallbacks
|
|
9
|
+
* @position Regression test for the compiled layer viewport inset
|
|
10
|
+
*
|
|
11
|
+
* `stylex.firstThatWorks(a, b)` turns two `var()` arguments into one nested
|
|
12
|
+
* `var(a, b)`. A `defineConsts` reference compiles to such a `var()`, and the
|
|
13
|
+
* rule processor inlines a constant only where its `var()` stands alone, so a
|
|
14
|
+
* pair of bare constant references shipped as `var(--<hash>, <fallback>)`
|
|
15
|
+
* with `--<hash>` defined nowhere: every engine took the fallback.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import fs from 'node:fs/promises';
|
|
19
|
+
import path from 'node:path';
|
|
20
|
+
import {fileURLToPath} from 'node:url';
|
|
21
|
+
import {transformAsync} from '@babel/core';
|
|
22
|
+
import stylexBabelPlugin from '@stylexjs/babel-plugin';
|
|
23
|
+
import {describe, expect, it} from 'vitest';
|
|
24
|
+
|
|
25
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
26
|
+
const SRC = path.resolve(__dirname, '..');
|
|
27
|
+
const CORE_ROOT = path.resolve(SRC, '..');
|
|
28
|
+
|
|
29
|
+
const SOURCES = [
|
|
30
|
+
'Layer/layerViewportInset.stylex.ts',
|
|
31
|
+
'Layer/useLayer.tsx',
|
|
32
|
+
'Popover/Popover.tsx',
|
|
33
|
+
'DropdownMenu/DropdownMenu.tsx',
|
|
34
|
+
'DropdownMenu/DropdownMenuSubMenu.tsx',
|
|
35
|
+
];
|
|
36
|
+
|
|
37
|
+
async function compileStylesheet() {
|
|
38
|
+
const rules = [];
|
|
39
|
+
for (const relative of SOURCES) {
|
|
40
|
+
const filename = path.join(SRC, relative);
|
|
41
|
+
const result = await transformAsync(await fs.readFile(filename, 'utf8'), {
|
|
42
|
+
babelrc: false,
|
|
43
|
+
configFile: path.join(CORE_ROOT, 'babel.config.json'),
|
|
44
|
+
filename,
|
|
45
|
+
});
|
|
46
|
+
rules.push(...(result?.metadata?.stylex ?? []));
|
|
47
|
+
}
|
|
48
|
+
return stylexBabelPlugin.processStylexRules(rules, false);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Every declaration of `property` in the compiled sheet. */
|
|
52
|
+
function declarations(css, property) {
|
|
53
|
+
return [...css.matchAll(new RegExp(`[{;]${property}:([^;}]+)`, 'g'))].map(
|
|
54
|
+
match => match[1],
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe('layer viewport inset stylesheet (spec:AST-059)', () => {
|
|
59
|
+
it('leaves no constant reference unresolved behind a fallback', async () => {
|
|
60
|
+
const css = await compileStylesheet();
|
|
61
|
+
const defined = new Set(
|
|
62
|
+
[...css.matchAll(/(--[\w-]+)\s*:/g)].map(match => match[1]),
|
|
63
|
+
);
|
|
64
|
+
const undefinedReferences = [
|
|
65
|
+
...css.matchAll(/var\((--x[a-z0-9]+),/g),
|
|
66
|
+
].flatMap(match => (defined.has(match[1]) ? [] : [match[0]]));
|
|
67
|
+
// Covers the caps and the four alignment-axis gutter margins.
|
|
68
|
+
expect(undefinedReferences).toEqual([]);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('caps both axes against the dynamic viewport and the safe-area gutters', async () => {
|
|
72
|
+
const css = await compileStylesheet();
|
|
73
|
+
const blockCaps = declarations(css, 'max-height');
|
|
74
|
+
const inlineCaps = declarations(css, 'max-width');
|
|
75
|
+
|
|
76
|
+
expect(blockCaps).toContainEqual(
|
|
77
|
+
expect.stringMatching(/^calc\(calc\(100dvb - .*safe-area-inset-top/),
|
|
78
|
+
);
|
|
79
|
+
expect(inlineCaps).toContainEqual(
|
|
80
|
+
expect.stringMatching(/^calc\(calc\(100vi - .*safe-area-inset-left/),
|
|
81
|
+
);
|
|
82
|
+
// The older-engine fallbacks still ship, ahead of the preferred value.
|
|
83
|
+
expect(blockCaps).toContainEqual(
|
|
84
|
+
expect.stringMatching(/^calc\(calc\(100vh - /),
|
|
85
|
+
);
|
|
86
|
+
expect(inlineCaps).toContainEqual(
|
|
87
|
+
expect.stringMatching(/^calc\(calc\(100vw - /),
|
|
88
|
+
);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
@@ -56,8 +56,12 @@ const GUTTER_BLOCK = `calc(max(${SPACING}, env(safe-area-inset-top, 0px), env(sa
|
|
|
56
56
|
|
|
57
57
|
/**
|
|
58
58
|
* The viewport gutter and the caps derived from it. Every value has an
|
|
59
|
-
* `env()`-less fallback for engines without safe-area support; pair them
|
|
60
|
-
* `stylex.firstThatWorks(cap
|
|
59
|
+
* `env()`-less fallback for engines without safe-area support; pair them as
|
|
60
|
+
* `stylex.firstThatWorks(`calc(${cap})`, `calc(${capFallback})`)`. Pass
|
|
61
|
+
* each inside a `calc()` (or another function), never as a bare reference: a
|
|
62
|
+
* constant reference compiles to a `var()`, and `firstThatWorks` folds two
|
|
63
|
+
* `var()` arguments into one `var(cap, capFallback)` whose constant is never
|
|
64
|
+
* inlined, so every engine would take the fallback.
|
|
61
65
|
*/
|
|
62
66
|
export const layerViewportInset = stylex.defineConsts({
|
|
63
67
|
/** Gutter from the block-start viewport edge. */
|
package/src/Layer/useLayer.tsx
CHANGED
|
@@ -102,15 +102,17 @@ const styles = stylex.create({
|
|
|
102
102
|
// The cap is on the layer box itself: content wider than the viewport
|
|
103
103
|
// overflows inside the layer, where the composing component decides
|
|
104
104
|
// whether it scrolls or clips; the box never leaves the viewport.
|
|
105
|
+
// Each constant is wrapped in `calc()` so both declarations ship (see
|
|
106
|
+
// layerViewportInset).
|
|
105
107
|
viewportFit: {
|
|
106
108
|
boxSizing: 'border-box',
|
|
107
109
|
maxInlineSize: stylex.firstThatWorks(
|
|
108
|
-
layerViewportInset.maxInlineSize
|
|
109
|
-
layerViewportInset.maxInlineSizeFallback
|
|
110
|
+
`calc(${layerViewportInset.maxInlineSize})`,
|
|
111
|
+
`calc(${layerViewportInset.maxInlineSizeFallback})`,
|
|
110
112
|
),
|
|
111
113
|
maxBlockSize: stylex.firstThatWorks(
|
|
112
|
-
layerViewportInset.maxBlockSize
|
|
113
|
-
layerViewportInset.maxBlockSizeFallback
|
|
114
|
+
`calc(${layerViewportInset.maxBlockSize})`,
|
|
115
|
+
`calc(${layerViewportInset.maxBlockSizeFallback})`,
|
|
114
116
|
),
|
|
115
117
|
},
|
|
116
118
|
// Alignment-axis gutter (spec:AST-059 FR1): a margin on the far viewport
|
|
@@ -120,26 +122,26 @@ const styles = stylex.create({
|
|
|
120
122
|
// (see layerSlideRules.ts).
|
|
121
123
|
gutterInlineEnd: {
|
|
122
124
|
marginInlineEnd: stylex.firstThatWorks(
|
|
123
|
-
layerViewportInset.gutterInline
|
|
124
|
-
layerViewportInset.gutterInlineFallback
|
|
125
|
+
`calc(${layerViewportInset.gutterInline})`,
|
|
126
|
+
`calc(${layerViewportInset.gutterInlineFallback})`,
|
|
125
127
|
),
|
|
126
128
|
},
|
|
127
129
|
gutterInlineStart: {
|
|
128
130
|
marginInlineStart: stylex.firstThatWorks(
|
|
129
|
-
layerViewportInset.gutterInline
|
|
130
|
-
layerViewportInset.gutterInlineFallback
|
|
131
|
+
`calc(${layerViewportInset.gutterInline})`,
|
|
132
|
+
`calc(${layerViewportInset.gutterInlineFallback})`,
|
|
131
133
|
),
|
|
132
134
|
},
|
|
133
135
|
gutterBlockEnd: {
|
|
134
136
|
marginBlockEnd: stylex.firstThatWorks(
|
|
135
|
-
layerViewportInset.gutterBlock
|
|
136
|
-
layerViewportInset.gutterBlockFallback
|
|
137
|
+
`calc(${layerViewportInset.gutterBlock})`,
|
|
138
|
+
`calc(${layerViewportInset.gutterBlockFallback})`,
|
|
137
139
|
),
|
|
138
140
|
},
|
|
139
141
|
gutterBlockStart: {
|
|
140
142
|
marginBlockStart: stylex.firstThatWorks(
|
|
141
|
-
layerViewportInset.gutterBlock
|
|
142
|
-
layerViewportInset.gutterBlockFallback
|
|
143
|
+
`calc(${layerViewportInset.gutterBlock})`,
|
|
144
|
+
`calc(${layerViewportInset.gutterBlockFallback})`,
|
|
143
145
|
),
|
|
144
146
|
},
|
|
145
147
|
});
|
|
@@ -760,7 +762,16 @@ function useLayerImplementation(
|
|
|
760
762
|
// hosted away from its trigger then still takes its sequential focus
|
|
761
763
|
// order (and its popover nesting) from the trigger rather than from
|
|
762
764
|
// its own DOM position. Browsers without the option ignore it.
|
|
763
|
-
|
|
765
|
+
// `source` is declared as an `HTMLElement`. A caller-rendered icon
|
|
766
|
+
// trigger is an `SVGElement`, whose dictionary conversion throws
|
|
767
|
+
// before the popover opens. Omitting the option for it still anchors
|
|
768
|
+
// the layer, because positioning reads the anchor-name pair, and only
|
|
769
|
+
// gives up the invoker's focus order.
|
|
770
|
+
const trigger =
|
|
771
|
+
triggerRef.current instanceof HTMLElement
|
|
772
|
+
? triggerRef.current
|
|
773
|
+
: undefined;
|
|
774
|
+
popover.showPopover({source: trigger});
|
|
764
775
|
});
|
|
765
776
|
} else {
|
|
766
777
|
popover.style.display = 'block';
|
|
@@ -98,7 +98,7 @@ export interface UseLayerDismissalReturn {
|
|
|
98
98
|
* routes each Escape press to the top-most REGISTERED layer, so one press
|
|
99
99
|
* dismisses exactly one of them. Dialog (and what is built on it, including
|
|
100
100
|
* CommandPalette), Popover and the menus built on it, ContextMenu, Tooltip,
|
|
101
|
-
* HoverCard, Lightbox, MobileNav, BottomSheet, BottomSheetSwitcher and
|
|
101
|
+
* HoverCard, Lightbox, MobileNav, BottomSheet, BottomSheetSwitcher and
|
|
102
102
|
* `Drawer` register today.
|
|
103
103
|
*
|
|
104
104
|
* `DropdownMenuSubMenu` and `PowerSearchEditPopover` still run their own Escape
|
|
@@ -6,6 +6,11 @@ export const docs = {
|
|
|
6
6
|
name: 'LayoutHeader',
|
|
7
7
|
subComponentOf: 'Layout',
|
|
8
8
|
displayName: 'Layout Header',
|
|
9
|
+
keywords: [
|
|
10
|
+
'pageheader',
|
|
11
|
+
'appheader',
|
|
12
|
+
'header',
|
|
13
|
+
],
|
|
9
14
|
isHiddenFromOverview: true,
|
|
10
15
|
description: 'Top bar for page titles, app bars, and toolbars.',
|
|
11
16
|
playground: {
|
|
@@ -4,8 +4,8 @@
|
|
|
4
4
|
* @file container.stylex.ts
|
|
5
5
|
* @input Uses @stylexjs/stylex, spacing from theme
|
|
6
6
|
* @output StyleX utility for layout container styling
|
|
7
|
-
* @position Layout utility; used by Card, Section, Dialog, BottomSheet, and
|
|
8
|
-
*
|
|
7
|
+
* @position Layout utility; used by Card, Section, Dialog, BottomSheet, and
|
|
8
|
+
* Drawer
|
|
9
9
|
*
|
|
10
10
|
* ## Public API for themes
|
|
11
11
|
*
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
* --astryx-card-padding-block-end
|
|
20
20
|
*
|
|
21
21
|
* Read order per level: `var(--astryx-…, <next level>)`, terminating at
|
|
22
|
-
* `--spacing-4`. Same pattern for section, dialog, bottom-sheet, and
|
|
22
|
+
* `--spacing-4`. Same pattern for section, dialog, bottom-sheet, and
|
|
23
23
|
* drawer.
|
|
24
24
|
*
|
|
25
25
|
* ```ts
|
|
@@ -150,7 +150,7 @@ const bottomSheetInlineEnd = `var(--astryx-bottom-sheet-padding-inline-end, ${bo
|
|
|
150
150
|
const bottomSheetBlockStart = `var(--astryx-bottom-sheet-padding-block-start, ${bottomSheetShorthand})`;
|
|
151
151
|
const bottomSheetBlockEnd = `var(--astryx-bottom-sheet-padding-block-end, ${bottomSheetShorthand})`;
|
|
152
152
|
|
|
153
|
-
// Drawer
|
|
153
|
+
// Drawer padding chains: --astryx-* then the next specificity level,
|
|
154
154
|
// terminating at --spacing-4 like Dialog. Built as chained const strings (no
|
|
155
155
|
// function calls) so StyleX can statically analyze them; see naming.ts for the
|
|
156
156
|
// prefix policy.
|
|
@@ -522,8 +522,8 @@ export interface ContainerOptions {
|
|
|
522
522
|
* This allows themes to override container padding via component-specific
|
|
523
523
|
* public CSS custom properties without touching internal vars.
|
|
524
524
|
*
|
|
525
|
-
* Used by Card, Section, Dialog, BottomSheet, and
|
|
526
|
-
*
|
|
525
|
+
* Used by Card, Section, Dialog, BottomSheet, and Drawer when no explicit
|
|
526
|
+
* padding prop is provided.
|
|
527
527
|
* @default undefined (uses explicit spacing token values)
|
|
528
528
|
*/
|
|
529
529
|
useThemeDefault?: ContainerComponent;
|