@astryxdesign/core 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +41 -3
- package/dist/AppShell/AppShell.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts +12 -1
- package/dist/BottomSheet/BottomSheetSwitcher.d.ts.map +1 -1
- package/dist/BottomSheet/BottomSheetSwitcher.js +44 -15
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts +3 -2
- package/dist/Breadcrumbs/BreadcrumbItem.d.ts.map +1 -1
- package/dist/Breadcrumbs/BreadcrumbItem.js +3 -7
- package/dist/Center/Center.d.ts +23 -16
- package/dist/Center/Center.d.ts.map +1 -1
- package/dist/Center/Center.js +7 -5
- package/dist/CodeBlock/CodeBlock.js +2 -2
- package/dist/DateInput/DateInput.d.ts.map +1 -1
- package/dist/DateInput/DateInput.js +12 -2
- package/dist/DateTimeInput/DateTimeInput.d.ts.map +1 -1
- package/dist/DateTimeInput/DateTimeInput.js +12 -2
- package/dist/Field/Field.d.ts.map +1 -1
- package/dist/Field/Field.js +1 -0
- package/dist/Field/InputClearButton.d.ts +2 -2
- package/dist/Field/InputClearButton.d.ts.map +1 -1
- package/dist/Field/InputClearButton.js +5 -1
- package/dist/Field/PanelSearchInput.d.ts.map +1 -1
- package/dist/Field/PanelSearchInput.js +16 -4
- package/dist/FileInput/FileInput.d.ts.map +1 -1
- package/dist/FileInput/FileInput.js +12 -1
- package/dist/HoverCard/useHoverCard.js +2 -2
- package/dist/Indicator/CheckboxIndicator.js +2 -2
- package/dist/Indicator/RadioIndicator.js +2 -2
- package/dist/Layer/layerStack.d.ts +10 -0
- package/dist/Layer/layerStack.d.ts.map +1 -1
- package/dist/Layer/layerStack.js +21 -9
- package/dist/Layer/useLayerDismissal.d.ts +2 -3
- package/dist/Layer/useLayerDismissal.d.ts.map +1 -1
- package/dist/Layer/useLayerDismissal.js +2 -3
- package/dist/NavIcon/NavIcon.js +2 -2
- package/dist/NumberInput/NumberInput.d.ts.map +1 -1
- package/dist/NumberInput/NumberInput.js +12 -2
- package/dist/Popover/usePopover.d.ts +3 -2
- package/dist/Popover/usePopover.d.ts.map +1 -1
- package/dist/Popover/usePopover.js +4 -2
- package/dist/ProgressBar/ProgressBar.js +2 -2
- package/dist/ScrollableArea/ScrollableArea.d.ts +79 -0
- package/dist/ScrollableArea/ScrollableArea.d.ts.map +1 -0
- package/dist/ScrollableArea/ScrollableArea.js +144 -0
- package/dist/ScrollableArea/index.d.ts +11 -0
- package/dist/ScrollableArea/index.d.ts.map +1 -0
- package/dist/ScrollableArea/index.js +11 -0
- package/dist/StatusDot/StatusDot.js +2 -2
- package/dist/TextArea/TextArea.js +2 -2
- package/dist/TextInput/TextInput.d.ts.map +1 -1
- package/dist/TextInput/TextInput.js +19 -4
- package/dist/TimeInput/TimeInput.d.ts.map +1 -1
- package/dist/TimeInput/TimeInput.js +12 -2
- package/dist/Typeahead/BaseTypeahead.d.ts +21 -14
- package/dist/Typeahead/BaseTypeahead.d.ts.map +1 -1
- package/dist/Typeahead/BaseTypeahead.js +56 -20
- package/dist/astryx.css +15 -0
- package/dist/hooks/index.d.ts +2 -0
- package/dist/hooks/index.d.ts.map +1 -1
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/scrollGeometry.d.ts +24 -0
- package/dist/hooks/scrollGeometry.d.ts.map +1 -0
- package/dist/hooks/scrollGeometry.js +86 -0
- package/dist/hooks/scrollOwnerRegistry.d.ts +15 -0
- package/dist/hooks/scrollOwnerRegistry.d.ts.map +1 -0
- package/dist/hooks/scrollOwnerRegistry.js +24 -0
- package/dist/hooks/useFocusTrap.d.ts +8 -0
- package/dist/hooks/useFocusTrap.d.ts.map +1 -1
- package/dist/hooks/useFocusTrap.js +22 -11
- package/dist/hooks/useScrollableArea.d.ts +51 -0
- package/dist/hooks/useScrollableArea.d.ts.map +1 -0
- package/dist/hooks/useScrollableArea.js +287 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -0
- package/dist/theme/defineTheme.d.ts +2 -6
- package/dist/theme/defineTheme.d.ts.map +1 -1
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/derivedVarRegistry.js +1 -1
- package/dist/theme/localTokens.d.ts +8 -11
- package/dist/theme/localTokens.d.ts.map +1 -1
- package/dist/theme/localTokens.js +17 -71
- package/dist/theme/themeAdaptations.d.ts.map +1 -1
- package/dist/theme/themeAdaptations.js +4 -4
- package/dist/utils/themeProps.d.ts +10 -10
- package/dist/utils/themeProps.d.ts.map +1 -1
- package/dist/utils/themeProps.js +27 -10
- package/locales/en.json +16 -0
- package/locales/pseudo.json +12 -0
- package/package.json +7 -2
- package/src/AppShell/AppShell.test.tsx +36 -0
- package/src/AppShell/AppShell.tsx +4 -1
- package/src/AspectRatio/AspectRatio.doc.mjs +3 -3
- package/src/Banner/Banner.test.tsx +3 -1
- package/src/BottomSheet/BottomSheetSwitcher.doc.mjs +56 -1
- package/src/BottomSheet/BottomSheetSwitcher.spec.md +211 -0
- package/src/BottomSheet/BottomSheetSwitcher.test.tsx +134 -2
- package/src/BottomSheet/BottomSheetSwitcher.tsx +43 -20
- package/src/Breadcrumbs/BreadcrumbItem.doc.mjs +10 -5
- package/src/Breadcrumbs/BreadcrumbItem.spec.md +225 -0
- package/src/Breadcrumbs/BreadcrumbItem.tsx +8 -13
- package/src/Breadcrumbs/Breadcrumbs.doc.mjs +2 -2
- package/src/Breadcrumbs/Breadcrumbs.test.tsx +49 -2
- package/src/Center/Center.doc.mjs +32 -28
- package/src/Center/Center.spec.md +225 -0
- package/src/Center/Center.test.tsx +42 -4
- package/src/Center/Center.tsx +24 -17
- package/src/Chat/ChatSystemMessage.test.tsx +2 -9
- package/src/CodeBlock/CodeBlock.doc.mjs +2 -2
- package/src/CodeBlock/CodeBlock.tsx +2 -2
- package/src/DateInput/DateInput.test.tsx +4 -4
- package/src/DateInput/DateInput.tsx +15 -4
- package/src/DateRangeInput/DateRangeInput.test.tsx +2 -2
- package/src/DateTimeInput/DateTimeInput.test.tsx +6 -4
- package/src/DateTimeInput/DateTimeInput.tsx +18 -7
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +4 -77
- package/src/Field/Field.test.tsx +42 -0
- package/src/Field/Field.tsx +6 -0
- package/src/Field/InputClearButton.test.tsx +35 -1
- package/src/Field/InputClearButton.tsx +7 -3
- package/src/Field/PanelSearchInput.tsx +21 -8
- package/src/FieldStatus/FieldStatus.spec.md +27 -17
- package/src/FieldStatus/FieldStatus.test.tsx +7 -5
- package/src/FieldStatus/__tests__/StatusMessage.a11y.chromium.spec.ts +198 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.known-failures.ts +13 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.renders.tsx +305 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.states.ts +317 -0
- package/src/FieldStatus/__tests__/StatusMessage.a11y.test.tsx +155 -0
- package/src/FileInput/FileInput.tsx +10 -1
- package/src/FormLayout/__snapshots__/FormLayout.test.tsx.snap +3 -3
- package/src/HoverCard/HoverCard.doc.mjs +4 -4
- package/src/HoverCard/useHoverCard.tsx +2 -2
- package/src/Indicator/CheckboxIndicator.tsx +2 -2
- package/src/Indicator/Indicator.doc.mjs +2 -2
- package/src/Indicator/Indicator.test.tsx +1 -1
- package/src/Indicator/RadioIndicator.tsx +2 -2
- package/src/Layer/layerStack.ts +20 -9
- package/src/Layer/useLayerDismissal.ts +2 -3
- package/src/MultiSelector/MultiSelector.test.tsx +4 -4
- package/src/NavIcon/NavIcon.doc.mjs +4 -4
- package/src/NavIcon/NavIcon.tsx +2 -2
- package/src/NumberInput/NumberInput.tsx +18 -7
- package/src/Popover/Popover.doc.mjs +10 -10
- package/src/Popover/Popover.spec.md +55 -65
- package/src/Popover/Popover.test.tsx +29 -0
- package/src/Popover/usePopover.doc.mjs +4 -4
- package/src/Popover/usePopover.tsx +7 -4
- package/src/ProgressBar/ProgressBar.doc.mjs +4 -4
- package/src/ProgressBar/ProgressBar.test.tsx +1 -31
- package/src/ProgressBar/ProgressBar.tsx +2 -2
- package/src/RadioList/RadioList.test.tsx +5 -144
- package/src/RadioList/__tests__/RadioGroup.a11y.chromium.spec.ts +255 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.known-failures.ts +12 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.renders.tsx +232 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.states.ts +503 -0
- package/src/RadioList/__tests__/RadioGroup.a11y.test.tsx +217 -0
- package/src/ScrollableArea/ScrollableArea.doc.mjs +100 -0
- package/src/ScrollableArea/ScrollableArea.spec.md +189 -0
- package/src/ScrollableArea/ScrollableArea.test.tsx +299 -0
- package/src/ScrollableArea/ScrollableArea.tsx +259 -0
- package/src/ScrollableArea/index.ts +26 -0
- package/src/ScrollableArea/modules/useScrollableArea.spec.md +121 -0
- package/src/SegmentedControl/SegmentedControl.test.tsx +5 -172
- package/src/Selector/Selector.test.tsx +4 -4
- package/src/Spinner/Spinner.test.tsx +0 -18
- package/src/StatusDot/StatusDot.doc.mjs +4 -4
- package/src/StatusDot/StatusDot.tsx +2 -2
- package/src/TabList/TabList.test.tsx +5 -9
- package/src/TabList/__tests__/Tabs.a11y.chromium.spec.ts +191 -0
- package/src/TabList/__tests__/Tabs.a11y.known-failures.ts +45 -0
- package/src/TabList/__tests__/Tabs.a11y.renders.tsx +92 -0
- package/src/TabList/__tests__/Tabs.a11y.states.ts +247 -0
- package/src/TabList/__tests__/Tabs.a11y.test.tsx +153 -0
- package/src/Table/Table.doc.mjs +2 -2
- package/src/TextArea/TextArea.doc.mjs +4 -4
- package/src/TextArea/TextArea.tsx +2 -2
- package/src/TextInput/TextInput.doc.mjs +2 -1
- package/src/TextInput/TextInput.test.tsx +94 -0
- package/src/TextInput/TextInput.tsx +22 -6
- package/src/TimeInput/TimeInput.tsx +18 -7
- package/src/Toast/ToastViewport.test.tsx +1 -39
- package/src/Typeahead/BaseTypeahead.doc.mjs +229 -33
- package/src/Typeahead/BaseTypeahead.spec.md +269 -0
- package/src/Typeahead/BaseTypeahead.test.tsx +200 -0
- package/src/Typeahead/BaseTypeahead.tsx +99 -30
- package/src/hooks/index.ts +13 -0
- package/src/hooks/scrollGeometry.ts +155 -0
- package/src/hooks/scrollOwnerRegistry.ts +47 -0
- package/src/hooks/useFocusTrap.ts +22 -11
- package/src/hooks/useFocusTrapEscapeShim.test.tsx +4 -3
- package/src/hooks/useScrollableArea.doc.mjs +108 -0
- package/src/hooks/useScrollableArea.test.tsx +437 -0
- package/src/hooks/useScrollableArea.ts +469 -0
- package/src/index.ts +1 -0
- package/src/theme/defineTheme.test.ts +65 -105
- package/src/theme/defineTheme.ts +3 -9
- package/src/theme/derivedVarRegistry.ts +1 -1
- package/src/theme/localTokens.ts +25 -96
- package/src/theme/publicThemeHelperContract.test.ts +2 -2
- package/src/theme/themeAdaptations.test.ts +16 -42
- package/src/theme/themeAdaptations.ts +6 -9
- package/src/utils/themeProps.test.ts +29 -10
- package/src/utils/themeProps.ts +36 -17
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 3
|
|
3
|
+
template_version: 4
|
|
4
|
+
kind: component
|
|
5
|
+
id: component:BreadcrumbItem
|
|
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: [public-api, behavior, layout, theming, accessibility]
|
|
13
|
+
verified_by:
|
|
14
|
+
[
|
|
15
|
+
packages/core/src/Breadcrumbs/Breadcrumbs.test.tsx,
|
|
16
|
+
apps/storybook/stories/BreadcrumbItem.stories.tsx,
|
|
17
|
+
packages/core/src/theme/themingTargets.test.ts,
|
|
18
|
+
scripts/check-knowledge.mjs,
|
|
19
|
+
]
|
|
20
|
+
modules: []
|
|
21
|
+
families: [family:navigation-destinations, family:overlay-dismissal]
|
|
22
|
+
design_specs: []
|
|
23
|
+
architecture:
|
|
24
|
+
[
|
|
25
|
+
architecture:component-style-authoring,
|
|
26
|
+
architecture:component-test-sufficiency,
|
|
27
|
+
architecture:component-theming-surface,
|
|
28
|
+
architecture:interaction-modality,
|
|
29
|
+
architecture:layer-runtime,
|
|
30
|
+
architecture:public-component-api,
|
|
31
|
+
architecture:react-component-runtime,
|
|
32
|
+
]
|
|
33
|
+
contributing: [contributing:api-conventions]
|
|
34
|
+
system_specs: [spec:AST-002, spec:AST-005, spec:AST-029]
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
# BreadcrumbItem component contract
|
|
38
|
+
|
|
39
|
+
## Intent
|
|
40
|
+
|
|
41
|
+
BreadcrumbItem presents one destination, action, current location, or sibling-menu
|
|
42
|
+
trigger inside a Breadcrumbs trail. This observational draft records verified
|
|
43
|
+
released behavior and current shared obligations without changing public API,
|
|
44
|
+
defaults, or the component's visual design.
|
|
45
|
+
|
|
46
|
+
## Compatibility and migration
|
|
47
|
+
|
|
48
|
+
- Released default preserved: `yes`
|
|
49
|
+
- Compatibility class: additive observational documentation plus bug fixes that
|
|
50
|
+
preserve the released public surface
|
|
51
|
+
- Controlled/uncontrolled behavior: not applicable
|
|
52
|
+
- Migration decision: none
|
|
53
|
+
|
|
54
|
+
Consumer migration instructions belong in consumer docs and release notes.
|
|
55
|
+
|
|
56
|
+
## Ownership boundary
|
|
57
|
+
|
|
58
|
+
**Owns**
|
|
59
|
+
|
|
60
|
+
- The list-item root, the item-content branch selected from current public inputs,
|
|
61
|
+
and forwarding the documented item ref and `BaseProps` surface to that root.
|
|
62
|
+
- The decorative separator container rendered for its position in the trail.
|
|
63
|
+
- The link-styled action or menu trigger and BreadcrumbItem-specific menu surface,
|
|
64
|
+
including their current theme targets.
|
|
65
|
+
- Deriving the menu-item size from the parent Breadcrumbs variant when no explicit
|
|
66
|
+
menu size is supplied.
|
|
67
|
+
|
|
68
|
+
**Does not own / non-goals**
|
|
69
|
+
|
|
70
|
+
- The navigation landmark, ordered list, trail label, separator value, or visual
|
|
71
|
+
variant — owned by `component:Breadcrumbs` through the public parent component.
|
|
72
|
+
- Destination acceptance and custom-router handoff — owned by
|
|
73
|
+
`family:navigation-destinations` and the shared link owner.
|
|
74
|
+
- Generic top-layer hosting, focus containment, positioning, and light dismissal —
|
|
75
|
+
owned by `component:Popover` and `architecture:layer-runtime`.
|
|
76
|
+
- Shared Escape/platform-close ordering — owned by
|
|
77
|
+
`family:overlay-dismissal`.
|
|
78
|
+
- Menu-item data, row semantics, selection, or submenu behavior — delegated to the
|
|
79
|
+
DropdownMenu item pipeline.
|
|
80
|
+
- Caller-provided icon artwork or arbitrary child content.
|
|
81
|
+
|
|
82
|
+
## Public concepts
|
|
83
|
+
|
|
84
|
+
| Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
|
|
85
|
+
| ------------- | -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | ----------------------------------------------- | ---------------------------------------------- | ----------------------------------------------- | ------------------------------------------------------------------------------------------ |
|
|
86
|
+
| Item content | required `ReactNode` | Supplies the visible item label and may contain caller-owned content. | Every item branch | Required | `component:BreadcrumbItem` | Released | React renders the supplied node. |
|
|
87
|
+
| Destination | supplied or absent `href` | Selects the shared link path when the item is not explicitly current and has no menu. | Default and supporting variants | Absent | `family:navigation-destinations` | Released | Shared link handling decides accepted destinations. |
|
|
88
|
+
| Action | supplied or absent `onClick` | Selects a native link-styled button when no destination or menu is supplied, or augments the link path when `href` is supplied. | Non-current items | Absent | `component:BreadcrumbItem` | Released | `menu` currently suppresses this input and warns in development. |
|
|
89
|
+
| Current page | `true`, `false`, or omitted | `true` explicitly marks the item current; `false` opts it out; omission makes the item an auto-current candidate. | Every branch, including a menu trigger | Omitted | `component:BreadcrumbItem` | Released observation; intent review pending | When no item is explicitly current, the omitted final item receives `aria-current="page"`. |
|
|
90
|
+
| Link renderer | per-item `as`, provider renderer, or native anchor | Selects the component that receives an accepted destination. | Non-current link path | Provider renderer, then native anchor | `family:navigation-destinations` | Released | Explicitly current and menu paths do not use it. |
|
|
91
|
+
| Start content | supplied or absent `startIcon` | Renders caller content before the item label. | Every item branch | Absent | Caller | Released | Caller content remains caller-owned. |
|
|
92
|
+
| Sibling menu | data array, composed menu content, or absent | Replaces the link/action content branch with a menu button and menu surface. | Current or non-current item | Absent | `component:BreadcrumbItem`; menu rows delegate | Released observation; precedence review pending | Currently suppresses `href` or `onClick` and warns in development. |
|
|
93
|
+
| Menu size | `sm`, `md`, or `lg` | Selects the delegated menu-row size. | Menu branch | `sm` for supporting Breadcrumbs; otherwise `md` | `component:BreadcrumbItem` | Released | TypeScript rejects unsupported values. |
|
|
94
|
+
|
|
95
|
+
## Behavioral and layout contract
|
|
96
|
+
|
|
97
|
+
Draft requirements identify their basis so observed code is not mistaken for an
|
|
98
|
+
intentional decision.
|
|
99
|
+
|
|
100
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
101
|
+
| --- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
|
|
102
|
+
| FR1 | The item root MUST remain one `<li>` carrying the public ref, item theme target, variant reflection, styling escape hatches, and neutral DOM pass-throughs. | Released types, source, docs, and tests; `architecture:public-component-api` | Verified current behavior; no API change proposed |
|
|
103
|
+
| FR2 | A non-current item with `href` and no menu MUST use the shared link renderer; an item with only `onClick` MUST use a native button; an item with neither MUST render text content. | Released source, docs, and tests | Verified current behavior |
|
|
104
|
+
| FR3 | Explicit `isCurrent=true` MUST expose `aria-current="page"`; explicit `false` MUST opt out; when every item omits the prop, the final item MUST receive the same current-page state. | Released source, docs, and tests | Verified current behavior; whether auto-detection remains the intended long-term default needs owner review |
|
|
105
|
+
| FR4 | Every item MUST render one decorative separator container; the first item hides it. The built-in slash mirrors exactly once in RTL, while caller-provided separators remain caller-owned. | Source, focused tests, and objective bidi behavior | Verified current behavior |
|
|
106
|
+
| FR5 | A menu item MUST expose one named menu button, current expanded state, control relationship, and one named `role="menu"` surface. Click, Enter, Space, and ArrowDown open it and focus its first item; Escape and selection close it. | APG Menu Button pattern, current Popover contract, source, tests, and browser evidence | Settled objective behavior |
|
|
107
|
+
| FR6 | Closing the menu MUST preserve a newly focused outside control. Focus returns to the trigger only when the closing surface would otherwise strand focus. | `component:Popover/AR4` and browser focus behavior | Settled objective behavior |
|
|
108
|
+
| FR7 | The menu branch MUST delegate item rendering, selection, typeahead, row focus, and submenu content to the shared DropdownMenu pipeline. | Released source and focused tests | Verified current behavior; DropdownMenu's draft contract remains context only |
|
|
109
|
+
| FR8 | Omitted `menuSize` MUST resolve from the parent variant before entering DropdownMenu context. | Released source and consumer docs | Verified current behavior |
|
|
110
|
+
| FR9 | The current local targets MUST remain `breadcrumb-item`, `breadcrumb-item-menu-trigger`, and `breadcrumb-menu`, each on its current visible style owner with `variant` reflected where applicable. | Released docs, source, and theming tests | Verified current inventory; no target change proposed |
|
|
111
|
+
|
|
112
|
+
### Allowed variation
|
|
113
|
+
|
|
114
|
+
- **AV1 — Link renderer.** Native anchors and custom router components may differ in
|
|
115
|
+
DOM implementation while preserving the shared destination contract.
|
|
116
|
+
- **AV2 — Caller content.** Labels and start content may be any renderable React
|
|
117
|
+
content; the item owns surrounding semantics, not caller artwork or markup.
|
|
118
|
+
- **AV3 — Menu content.** Data-driven and composed content may produce actions,
|
|
119
|
+
sections, dividers, selectable items, or submenus through the delegated pipeline.
|
|
120
|
+
- **AV4 — Theme.** Current targets and semantic tokens may change paint while item
|
|
121
|
+
roles, focus ownership, and branch behavior remain stable.
|
|
122
|
+
|
|
123
|
+
### Representative states
|
|
124
|
+
|
|
125
|
+
| State | Required invariant | Allowed variation |
|
|
126
|
+
| ---------------- | ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
|
|
127
|
+
| Destination link | Shared link path, visible keyboard focus, and accepted destination behavior remain available. | Native or custom router renderer; optional start content. |
|
|
128
|
+
| Action button | Native button semantics and supplied click handling remain available. | Default or supporting typography. |
|
|
129
|
+
| Explicit current | Current-page state is exposed on the rendered content owner. | Plain content or menu trigger. |
|
|
130
|
+
| Auto-current | The final omitted item receives current-page state only when no explicit current item exists. | Link or text content remains in its released branch. |
|
|
131
|
+
| Closed menu | Trigger exposes `aria-haspopup="menu"`, controls the menu, and reports collapsed state. | Data-driven or composed rows; current or non-current trigger. |
|
|
132
|
+
| Open menu | Named menu is top-layer reachable and focus enters its first eligible row. | Row kinds, submenu content, and explicit menu size. |
|
|
133
|
+
| Dismissed menu | One dismissal closes the surface; valid outside focus is preserved and stranded focus returns to the trigger. | Escape, selection, Tab, or native light dismiss. |
|
|
134
|
+
|
|
135
|
+
### Transformation and precedence order
|
|
136
|
+
|
|
137
|
+
- **ORD1 — Content branch.** Explicit current is evaluated first; within either
|
|
138
|
+
current or non-current state, `menu` selects the menu branch. Otherwise `href`
|
|
139
|
+
selects the link branch, then `onClick` selects the action branch, then plain
|
|
140
|
+
content remains.
|
|
141
|
+
- **ORD2 — Link renderer.** Per-item `as` wins over LinkProvider, which wins over
|
|
142
|
+
the native anchor.
|
|
143
|
+
- **ORD3 — Menu size.** Explicit `menuSize` wins; otherwise supporting resolves to
|
|
144
|
+
`sm` and every other parent variant resolves to `md`.
|
|
145
|
+
|
|
146
|
+
### Performance and resources
|
|
147
|
+
|
|
148
|
+
- **PR1 — Delegated layer resources.** BreadcrumbItem creates no independent global
|
|
149
|
+
listeners or observers; menu lifecycle and focus resources remain delegated to
|
|
150
|
+
Popover and shared menu hooks.
|
|
151
|
+
- **PR2 — Auto-current reconciliation.** Current source reconciles omitted current
|
|
152
|
+
state by inspecting the rendered sibling list after render. This is a known
|
|
153
|
+
runtime-authority gap under `architecture:react-component-runtime`, not an
|
|
154
|
+
approved implementation requirement.
|
|
155
|
+
|
|
156
|
+
## Accessibility contract
|
|
157
|
+
|
|
158
|
+
- **AR1 — Trail semantics.** The parent Breadcrumbs landmark and ordered list own
|
|
159
|
+
aggregate breadcrumb semantics; each item remains one list item.
|
|
160
|
+
- **AR2 — Current state.** The content owner for a current item exposes
|
|
161
|
+
`aria-current="page"`; the list-item wrapper does not duplicate it.
|
|
162
|
+
- **AR3 — Native interaction.** Links use link semantics, action-only items use a
|
|
163
|
+
native button, and menu items use the APG Menu Button relationship.
|
|
164
|
+
- **AR4 — Menu name.** The menu surface is labelled by its trigger, including when
|
|
165
|
+
the visible item content is a non-string React node.
|
|
166
|
+
- **AR5 — Focus.** Keyboard focus is visible on links and menu/action buttons. Menu
|
|
167
|
+
entry, containment, Escape return, and outside-focus preservation follow FR5–FR6.
|
|
168
|
+
- **AR6 — Separator.** Separator content is hidden from assistive technology while
|
|
169
|
+
remaining directionally correct for sighted readers.
|
|
170
|
+
|
|
171
|
+
## Design relationships
|
|
172
|
+
|
|
173
|
+
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
174
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------ | ---------------------------------------------------------------- | ----------------- | ------------------ |
|
|
175
|
+
| Item root | Carries current typography and the `breadcrumb-item` target. | Current source and public docs | Supporting | FR1, FR9 |
|
|
176
|
+
| Link or action content | Uses native semantics and the shared focus indicator without introducing another content target. | Current source; `architecture:interaction-modality` | Supporting | FR2, AR3, AR5 |
|
|
177
|
+
| Current content | Uses the released non-color text emphasis alongside current-page semantics. | Current source and objective non-color communication | Prominent | FR3, AR2 |
|
|
178
|
+
| Separator | Remains decorative to assistive technology and mirrors by contextual bidi role. | Objective bidi behavior | Supporting | FR4, AR6 |
|
|
179
|
+
| Menu trigger | Paints the menu-trigger target on the native focus owner. | Current source and public docs | Supporting | FR5, FR9, AR3–AR5 |
|
|
180
|
+
| Menu surface | Paints the `breadcrumb-menu` refinement inside Popover's shared layer surface. | `component:Popover` plus current BreadcrumbItem target inventory | Prominent | FR5–FR9 |
|
|
181
|
+
| Start content | Renders caller content without claiming its artwork or semantics. | Caller content; `component:Icon` when composed | Context-dependent | AV2 |
|
|
182
|
+
|
|
183
|
+
## Family and system relationships
|
|
184
|
+
|
|
185
|
+
- `family:navigation-destinations` owns destination inspection and handoff for
|
|
186
|
+
native and custom link paths. BreadcrumbItem composes the shared link owner.
|
|
187
|
+
- `family:overlay-dismissal` owns topmost Escape/platform-close routing.
|
|
188
|
+
BreadcrumbItem participates through Popover.
|
|
189
|
+
- `component:Popover` owns generic menu-surface hosting, focus containment, and
|
|
190
|
+
stranded-focus return; BreadcrumbItem owns its trigger and refinement target.
|
|
191
|
+
- `architecture:component-theming-surface` owns target qualification, placement,
|
|
192
|
+
and state reflection.
|
|
193
|
+
- `architecture:public-component-api` and `spec:AST-002` own released API,
|
|
194
|
+
precedence, invalid-state prevention, and compatibility review.
|
|
195
|
+
|
|
196
|
+
## Verification map
|
|
197
|
+
|
|
198
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
199
|
+
| ---------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------- | --------------------------------------------- |
|
|
200
|
+
| FR1–FR3, AR1–AR3 | `Breadcrumbs.test.tsx` branch, ref, pass-through, and current-state suites | Link, action, explicit current, omitted final, explicit false | A branch changes semantic element, loses current state, or moves the public root contract. | `audit:BreadcrumbItem/api-behavior` |
|
|
201
|
+
| FR4, AR6 | `Breadcrumbs.test.tsx`, `BreadcrumbItem.stories.tsx`, and RTL audit | Built-in slash, bidi-mirrored glyph, explicit icon mirror, LTR and RTL | A contextual separator fails to mirror exactly once or becomes exposed to AT. | `audit:BreadcrumbItem/rtl` |
|
|
202
|
+
| FR5–FR8, AR3–AR5 | `Breadcrumbs.test.tsx` plus real-browser story evidence | String and ReactNode labels, click/keyboard open, rows, selection, Escape, outside dismiss | A menu loses its name/state, focus enters the wrong owner, or dismissal steals valid outside focus. | `audit:BreadcrumbItem/accessibility-behavior` |
|
|
203
|
+
| FR9 | `themingTargets.test.ts`, source inspection, and rendered theme evidence | Item, menu trigger, menu surface; default/supporting | A target disappears, moves to non-painting plumbing, or loses variant reflection. | `audit:BreadcrumbItem/theming` |
|
|
204
|
+
| Draft structure | `scripts/check-knowledge.mjs` | Required schema and current relationship links | Missing sections, stale links, or accidental current authority fail validation. | `audit:BreadcrumbItem/knowledge` |
|
|
205
|
+
|
|
206
|
+
## Decision log
|
|
207
|
+
|
|
208
|
+
None. This draft records observed released behavior and objective shared
|
|
209
|
+
requirements; it makes no component-local API, default, compatibility, ownership,
|
|
210
|
+
or visual-design decision.
|
|
211
|
+
|
|
212
|
+
## Open questions
|
|
213
|
+
|
|
214
|
+
- **OQ1 — Conflicting interaction props.** Should the released `menu` + `href` or
|
|
215
|
+
`menu` + `onClick` combinations remain warning-based precedence, or should a
|
|
216
|
+
compatibility plan make them unrepresentable? (`human-api`)
|
|
217
|
+
- **OQ2 — Auto-current ownership.** Should omitted `isCurrent` remain an
|
|
218
|
+
auto-detected current candidate, and if so which React-owned mechanism should
|
|
219
|
+
replace post-render DOM reconciliation? (`human-api`)
|
|
220
|
+
|
|
221
|
+
## Content boundary
|
|
222
|
+
|
|
223
|
+
This file does not duplicate the consumer prop table, menu-item API, audit scores,
|
|
224
|
+
run evidence, screenshots, implementation steps, or shared navigation, layer,
|
|
225
|
+
dismissal, and theming rules. It links to their owners.
|
|
@@ -96,8 +96,9 @@ export interface BreadcrumbItemProps extends Omit<
|
|
|
96
96
|
onClick?: (e: MouseEvent<HTMLElement>) => void;
|
|
97
97
|
/**
|
|
98
98
|
* Marks this item as the current page. Renders as a span with aria-current="page".
|
|
99
|
-
*
|
|
100
|
-
*
|
|
99
|
+
* When omitted, the last item is auto-detected as current if no item is
|
|
100
|
+
* explicitly current. Pass `false` to opt this item out of auto-detection.
|
|
101
|
+
* @default undefined
|
|
101
102
|
*/
|
|
102
103
|
isCurrent?: boolean;
|
|
103
104
|
/**
|
|
@@ -395,8 +396,7 @@ export function BreadcrumbItem({
|
|
|
395
396
|
menu={menu}
|
|
396
397
|
menuSize={resolvedMenuSize}
|
|
397
398
|
variant={ctx.variant}
|
|
398
|
-
isCurrent
|
|
399
|
-
label={children}>
|
|
399
|
+
isCurrent>
|
|
400
400
|
{content}
|
|
401
401
|
</BreadcrumbMenuTrigger>
|
|
402
402
|
) : (
|
|
@@ -439,8 +439,7 @@ export function BreadcrumbItem({
|
|
|
439
439
|
ref={contentRef}
|
|
440
440
|
menu={menu}
|
|
441
441
|
menuSize={resolvedMenuSize}
|
|
442
|
-
variant={ctx.variant}
|
|
443
|
-
label={children}>
|
|
442
|
+
variant={ctx.variant}>
|
|
444
443
|
{content}
|
|
445
444
|
</BreadcrumbMenuTrigger>
|
|
446
445
|
) : href != null ? (
|
|
@@ -493,8 +492,6 @@ interface BreadcrumbMenuTriggerProps {
|
|
|
493
492
|
ref: React.Ref<HTMLElement>;
|
|
494
493
|
/** The link-styled label content rendered inside the trigger button. */
|
|
495
494
|
children: ReactNode;
|
|
496
|
-
/** Accessible name for the menu surface (the crumb's label). */
|
|
497
|
-
label: ReactNode;
|
|
498
495
|
menu: DropdownMenuOption[] | ReactNode;
|
|
499
496
|
menuSize: DropdownMenuSize;
|
|
500
497
|
variant: BreadcrumbsVariant;
|
|
@@ -511,20 +508,17 @@ interface BreadcrumbMenuTriggerProps {
|
|
|
511
508
|
function BreadcrumbMenuTrigger({
|
|
512
509
|
ref,
|
|
513
510
|
children,
|
|
514
|
-
label,
|
|
515
511
|
menu,
|
|
516
512
|
menuSize,
|
|
517
513
|
variant,
|
|
518
514
|
isCurrent = false,
|
|
519
515
|
}: BreadcrumbMenuTriggerProps) {
|
|
520
516
|
const menuId = useId();
|
|
517
|
+
const triggerId = useId();
|
|
521
518
|
const buttonRef = useRef<HTMLButtonElement>(null);
|
|
522
519
|
const isSupporting = variant === 'supporting';
|
|
523
520
|
|
|
524
521
|
const popover = usePopover({
|
|
525
|
-
onHide: useCallback(() => {
|
|
526
|
-
buttonRef.current?.focus();
|
|
527
|
-
}, []),
|
|
528
522
|
hasLightDismiss: true,
|
|
529
523
|
hasCloseButton: false,
|
|
530
524
|
hasAutoFocus: false,
|
|
@@ -637,6 +631,7 @@ function BreadcrumbMenuTrigger({
|
|
|
637
631
|
onClick={handleClick}
|
|
638
632
|
onKeyDown={handleKeyDown}
|
|
639
633
|
{...popover.triggerProps}
|
|
634
|
+
id={triggerId}
|
|
640
635
|
aria-haspopup="menu"
|
|
641
636
|
aria-controls={menuId}
|
|
642
637
|
aria-current={isCurrent ? 'page' : undefined}
|
|
@@ -670,7 +665,7 @@ function BreadcrumbMenuTrigger({
|
|
|
670
665
|
ref={listRef}
|
|
671
666
|
id={menuId}
|
|
672
667
|
role="menu"
|
|
673
|
-
aria-
|
|
668
|
+
aria-labelledby={triggerId}
|
|
674
669
|
onKeyDown={listKeyDown}
|
|
675
670
|
{...mergeProps(
|
|
676
671
|
themeProps('breadcrumb-menu'),
|
|
@@ -117,8 +117,8 @@ export const docs = {
|
|
|
117
117
|
{
|
|
118
118
|
name: 'isCurrent',
|
|
119
119
|
type: 'boolean',
|
|
120
|
-
description:
|
|
121
|
-
|
|
120
|
+
description:
|
|
121
|
+
'Marks this item as the current page, applying aria-current="page". When omitted, the last item is auto-detected if no item is explicitly current; pass false to opt out.',
|
|
122
122
|
},
|
|
123
123
|
{
|
|
124
124
|
name: 'startIcon',
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
3
|
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
4
|
-
import {render, screen, waitFor, fireEvent} from '@testing-library/react';
|
|
4
|
+
import {render, screen, waitFor, fireEvent, act} from '@testing-library/react';
|
|
5
5
|
import userEvent from '@testing-library/user-event';
|
|
6
6
|
import {Breadcrumbs} from './Breadcrumbs';
|
|
7
7
|
import {BreadcrumbItem} from './BreadcrumbItem';
|
|
@@ -427,6 +427,24 @@ describe('BreadcrumbItem menu', () => {
|
|
|
427
427
|
expect(trigger).toHaveAttribute('aria-expanded', 'false');
|
|
428
428
|
});
|
|
429
429
|
|
|
430
|
+
it('labels the menu from non-string trigger content', async () => {
|
|
431
|
+
const user = userEvent.setup();
|
|
432
|
+
render(
|
|
433
|
+
<Breadcrumbs>
|
|
434
|
+
<BreadcrumbItem menu={items}>
|
|
435
|
+
<span>Teams</span>
|
|
436
|
+
</BreadcrumbItem>
|
|
437
|
+
<BreadcrumbItem isCurrent>Overview</BreadcrumbItem>
|
|
438
|
+
</Breadcrumbs>,
|
|
439
|
+
);
|
|
440
|
+
|
|
441
|
+
await user.click(screen.getByRole('button', {name: 'Teams'}));
|
|
442
|
+
|
|
443
|
+
expect(screen.getByRole('menu', {hidden: true})).toHaveAccessibleName(
|
|
444
|
+
'Teams',
|
|
445
|
+
);
|
|
446
|
+
});
|
|
447
|
+
|
|
430
448
|
it('portability: a DropdownMenuOption[] renders its items on open', async () => {
|
|
431
449
|
const user = userEvent.setup();
|
|
432
450
|
render(
|
|
@@ -437,7 +455,7 @@ describe('BreadcrumbItem menu', () => {
|
|
|
437
455
|
);
|
|
438
456
|
await user.click(screen.getByRole('button', {name: 'Teams'}));
|
|
439
457
|
const menu = screen.getByRole('menu', {hidden: true});
|
|
440
|
-
expect(menu).
|
|
458
|
+
expect(menu).toHaveAccessibleName('Teams');
|
|
441
459
|
expect(
|
|
442
460
|
screen.getByRole('menuitem', {name: 'Design', hidden: true}),
|
|
443
461
|
).toBeInTheDocument();
|
|
@@ -579,6 +597,35 @@ describe('BreadcrumbItem menu', () => {
|
|
|
579
597
|
});
|
|
580
598
|
});
|
|
581
599
|
|
|
600
|
+
it('preserves outside focus after a browser light dismiss', async () => {
|
|
601
|
+
const user = userEvent.setup();
|
|
602
|
+
render(
|
|
603
|
+
<>
|
|
604
|
+
<Breadcrumbs>
|
|
605
|
+
<BreadcrumbItem menu={items}>Teams</BreadcrumbItem>
|
|
606
|
+
<BreadcrumbItem isCurrent>Overview</BreadcrumbItem>
|
|
607
|
+
</Breadcrumbs>
|
|
608
|
+
<button type="button">Outside action</button>
|
|
609
|
+
</>,
|
|
610
|
+
);
|
|
611
|
+
const trigger = screen.getByRole('button', {name: 'Teams'});
|
|
612
|
+
await user.click(trigger);
|
|
613
|
+
const menu = screen.getByRole('menu', {hidden: true});
|
|
614
|
+
const outside = screen.getByRole('button', {name: 'Outside action'});
|
|
615
|
+
|
|
616
|
+
outside.focus();
|
|
617
|
+
expect(outside).toHaveFocus();
|
|
618
|
+
const popover = menu.closest('[popover]');
|
|
619
|
+
expect(popover).not.toBeNull();
|
|
620
|
+
await act(async () => {
|
|
621
|
+
(popover as HTMLElement).hidePopover();
|
|
622
|
+
});
|
|
623
|
+
|
|
624
|
+
await waitFor(() => {
|
|
625
|
+
expect(outside).toHaveFocus();
|
|
626
|
+
});
|
|
627
|
+
});
|
|
628
|
+
|
|
582
629
|
it('roves focus with ArrowDown across items', async () => {
|
|
583
630
|
render(
|
|
584
631
|
<Breadcrumbs>
|
|
@@ -20,7 +20,8 @@ export const docs = {
|
|
|
20
20
|
{
|
|
21
21
|
name: 'axis',
|
|
22
22
|
type: "'both' | 'horizontal' | 'vertical'",
|
|
23
|
-
description:
|
|
23
|
+
description:
|
|
24
|
+
'Which Center mode to use. In horizontal writing, "horizontal" centers the flex main/inline axis and "vertical" centers the cross/block axis. In vertical writing, current single-axis behavior follows those logical flex axes rather than the physical names; "both" still centers both axes.',
|
|
24
25
|
default: "'both'",
|
|
25
26
|
},
|
|
26
27
|
{
|
|
@@ -53,37 +54,37 @@ export const docs = {
|
|
|
53
54
|
name: 'paddingInline',
|
|
54
55
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
55
56
|
description:
|
|
56
|
-
'
|
|
57
|
+
'Logical inline-axis padding, using the spacing scale. Overrides padding on the inline axis when both are set.',
|
|
57
58
|
},
|
|
58
59
|
{
|
|
59
60
|
name: 'paddingInlineStart',
|
|
60
61
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
61
62
|
description:
|
|
62
|
-
'
|
|
63
|
+
'Logical inline-start padding, using the spacing scale. Its resolved physical edge depends on writing mode and direction. Overrides paddingInline and padding on that edge only.',
|
|
63
64
|
},
|
|
64
65
|
{
|
|
65
66
|
name: 'paddingInlineEnd',
|
|
66
67
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
67
68
|
description:
|
|
68
|
-
'
|
|
69
|
+
'Logical inline-end padding, using the spacing scale. Its resolved physical edge depends on writing mode and direction. Overrides paddingInline and padding on that edge only.',
|
|
69
70
|
},
|
|
70
71
|
{
|
|
71
72
|
name: 'paddingBlock',
|
|
72
73
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
73
74
|
description:
|
|
74
|
-
'
|
|
75
|
+
'Logical block-axis padding, using the spacing scale. Overrides padding on the block axis when both are set.',
|
|
75
76
|
},
|
|
76
77
|
{
|
|
77
78
|
name: 'paddingBlockStart',
|
|
78
79
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
79
80
|
description:
|
|
80
|
-
'
|
|
81
|
+
'Logical block-start padding, using the spacing scale. Its resolved physical edge depends on writing mode. Overrides paddingBlock and padding on that edge only.',
|
|
81
82
|
},
|
|
82
83
|
{
|
|
83
84
|
name: 'paddingBlockEnd',
|
|
84
85
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
85
86
|
description:
|
|
86
|
-
'
|
|
87
|
+
'Logical block-end padding, using the spacing scale. Its resolved physical edge depends on writing mode. Overrides paddingBlock and padding on that edge only.',
|
|
87
88
|
},
|
|
88
89
|
{
|
|
89
90
|
name: 'isInline',
|
|
@@ -112,9 +113,10 @@ export const docs = {
|
|
|
112
113
|
description:
|
|
113
114
|
'Center aligns content to the middle of its container. Use it for empty states, loading screens, login forms, or any content that should sit in the center of the available space.',
|
|
114
115
|
bestPractices: [
|
|
115
|
-
{guidance: true, description: 'Use axis
|
|
116
|
-
{guidance: true, description: '
|
|
116
|
+
{guidance: true, description: 'Use a single-axis value only in horizontal writing, or after verifying the active writing mode. In vertical writing, the current implementation follows flex main/cross axes rather than the physical prop names.'},
|
|
117
|
+
{guidance: true, description: 'In horizontal writing, give Center height when using axis="vertical"; centering needs available space on the selected flex axis.'},
|
|
117
118
|
{guidance: true, description: 'Use isInline to center small elements like icons or badges within a line of text without breaking the text flow.'},
|
|
119
|
+
{guidance: true, description: 'Keep semantic structure and accessible names on the content. Center is a layout-only container and does not add a role or label.'},
|
|
118
120
|
{guidance: false, description: 'Wrap large page sections in Center. Use Layout or AppShell for page-level structure.'},
|
|
119
121
|
{guidance: false, description: 'Use Center for horizontal lists of items. Use Stack with hAlign="center" instead.'},
|
|
120
122
|
],
|
|
@@ -133,15 +135,16 @@ export const docsZh = {
|
|
|
133
135
|
description:
|
|
134
136
|
'Center aligns content to the middle of its container. Use it for empty states, loading screens, login forms, or any content that should sit in the center of the available space.',
|
|
135
137
|
bestPractices: [
|
|
136
|
-
{guidance: true, description: 'Use axis
|
|
137
|
-
{guidance: true, description: '
|
|
138
|
+
{guidance: true, description: 'Use a single-axis value only in horizontal writing, or after verifying the active writing mode. In vertical writing, the current implementation follows flex main/cross axes rather than the physical prop names.'},
|
|
139
|
+
{guidance: true, description: 'In horizontal writing, give Center height when using axis="vertical"; centering needs available space on the selected flex axis.'},
|
|
138
140
|
{guidance: true, description: 'Use isInline to center small elements like icons or badges within a line of text without breaking the text flow.'},
|
|
141
|
+
{guidance: true, description: 'Keep semantic structure and accessible names on the content. Center is a layout-only container and does not add a role or label.'},
|
|
139
142
|
{guidance: false, description: 'Wrap large page sections in Center. Use Layout or AppShell for page-level structure.'},
|
|
140
143
|
{guidance: false, description: 'Use Center for horizontal lists of items. Use Stack with hAlign="center" instead.'},
|
|
141
144
|
],
|
|
142
145
|
},
|
|
143
146
|
props: [
|
|
144
|
-
{name: 'axis', type: "'both' | 'horizontal' | 'vertical'", description: '
|
|
147
|
+
{name: 'axis', type: "'both' | 'horizontal' | 'vertical'", description: '选择 Center 模式。横向书写时,horizontal 对应 flex 主轴/行内轴,vertical 对应交叉轴/块轴;纵向书写时,当前单轴行为仍跟随这些逻辑 flex 轴,而不是属性名暗示的物理轴。', default: "'both'"},
|
|
145
148
|
{name: 'width', type: 'number | string', description: '容器宽度(px 或 CSS 值)。'},
|
|
146
149
|
{name: 'height', type: 'number | string', description: '容器高度(px 或 CSS 值)。'},
|
|
147
150
|
{
|
|
@@ -153,32 +156,32 @@ export const docsZh = {
|
|
|
153
156
|
{
|
|
154
157
|
name: 'paddingInline',
|
|
155
158
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
156
|
-
description: '
|
|
159
|
+
description: '逻辑行内轴内边距,使用间距刻度。两者同时设置时在行内轴上覆盖 padding。',
|
|
157
160
|
},
|
|
158
161
|
{
|
|
159
162
|
name: 'paddingInlineStart',
|
|
160
163
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
161
|
-
description: '
|
|
164
|
+
description: '逻辑行内起始内边距,使用间距刻度。解析后的物理边取决于书写模式和方向。仅在该边上覆盖 paddingInline 和 padding。',
|
|
162
165
|
},
|
|
163
166
|
{
|
|
164
167
|
name: 'paddingInlineEnd',
|
|
165
168
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
166
|
-
description: '
|
|
169
|
+
description: '逻辑行内结束内边距,使用间距刻度。解析后的物理边取决于书写模式和方向。仅在该边上覆盖 paddingInline 和 padding。',
|
|
167
170
|
},
|
|
168
171
|
{
|
|
169
172
|
name: 'paddingBlock',
|
|
170
173
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
171
|
-
description: '
|
|
174
|
+
description: '逻辑块轴内边距,使用间距刻度。两者同时设置时在块轴上覆盖 padding。',
|
|
172
175
|
},
|
|
173
176
|
{
|
|
174
177
|
name: 'paddingBlockStart',
|
|
175
178
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
176
|
-
description: '
|
|
179
|
+
description: '逻辑块起始内边距,使用间距刻度。解析后的物理边取决于书写模式。仅在该边上覆盖 paddingBlock 和 padding。',
|
|
177
180
|
},
|
|
178
181
|
{
|
|
179
182
|
name: 'paddingBlockEnd',
|
|
180
183
|
type: '0 | 0.5 | 1 | 1.5 | 2 | 3 | 4 | 5 | 6 | 8 | 10',
|
|
181
|
-
description: '
|
|
184
|
+
description: '逻辑块结束内边距,使用间距刻度。解析后的物理边取决于书写模式。仅在该边上覆盖 paddingBlock 和 padding。',
|
|
182
185
|
},
|
|
183
186
|
{name: 'isInline', type: 'boolean', description: '使用 inline-flex(适用于文本/图标)。', default: 'false'},
|
|
184
187
|
{name: 'children', type: 'ReactNode', description: '要居中的内容。'},
|
|
@@ -203,30 +206,31 @@ export const docsZh = {
|
|
|
203
206
|
|
|
204
207
|
/** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
|
|
205
208
|
export const docsDense = {
|
|
206
|
-
description: 'centers content
|
|
209
|
+
description: 'centers content on one or both flex axes; single-axis names match physical axes only in horizontal writing',
|
|
207
210
|
usage: {
|
|
208
211
|
description:
|
|
209
212
|
'Center aligns content to the middle of its container. Use for empty states, loading screens, login forms.',
|
|
210
213
|
bestPractices: [
|
|
211
|
-
{guidance: true, description: 'Use axis
|
|
212
|
-
{guidance: true, description: '
|
|
214
|
+
{guidance: true, description: 'Use a single-axis value only in horizontal writing, or after verifying the active writing mode. In vertical writing, the current implementation follows flex main/cross axes rather than the physical prop names.'},
|
|
215
|
+
{guidance: true, description: 'In horizontal writing, give Center height when using axis="vertical"; centering needs available space on the selected flex axis.'},
|
|
213
216
|
{guidance: true, description: 'Use isInline to center small elements (icons, badges) within a line of text without breaking text flow.'},
|
|
217
|
+
{guidance: true, description: 'Keep semantic structure and accessible names on the content; Center adds no role or label.'},
|
|
214
218
|
{guidance: false, description: 'Wrap large page sections in Center. Use Layout or AppShell for page-level structure.'},
|
|
215
219
|
{guidance: false, description: 'Use Center for horizontal lists of items. Use Stack with hAlign="center" instead.'},
|
|
216
220
|
],
|
|
217
221
|
},
|
|
218
222
|
propDescriptions: {
|
|
219
|
-
axis: 'centering
|
|
223
|
+
axis: 'centering mode; outside horizontal writing, single-axis values follow flex main/cross axes',
|
|
220
224
|
width: 'container width (px or CSS)',
|
|
221
225
|
height: 'container height (px or CSS)',
|
|
222
226
|
padding:
|
|
223
227
|
'inner padding on all sides (spacing step: 0, 0.5, 1, 1.5, 2, 3, 4, 5, 6, 8, 10)',
|
|
224
|
-
paddingInline: 'inline
|
|
225
|
-
paddingInlineStart: 'inline-start padding
|
|
226
|
-
paddingInlineEnd: 'inline-end padding
|
|
227
|
-
paddingBlock: 'block
|
|
228
|
-
paddingBlockStart: 'block-start
|
|
229
|
-
paddingBlockEnd: 'block-end
|
|
228
|
+
paddingInline: 'logical inline-axis padding; overrides padding on that axis',
|
|
229
|
+
paddingInlineStart: 'logical inline-start padding; physical edge depends on writing mode and direction',
|
|
230
|
+
paddingInlineEnd: 'logical inline-end padding; physical edge depends on writing mode and direction',
|
|
231
|
+
paddingBlock: 'logical block-axis padding; overrides padding on that axis',
|
|
232
|
+
paddingBlockStart: 'logical block-start padding; physical edge depends on writing mode',
|
|
233
|
+
paddingBlockEnd: 'logical block-end padding; physical edge depends on writing mode',
|
|
230
234
|
isInline: 'use inline-flex for text/icons',
|
|
231
235
|
children: 'content to center',
|
|
232
236
|
xstyle: 'StyleX styles for layout (margins, positioning, sizing); must be stylex.create() value',
|