@astryxdesign/core 0.5.2-canary.005d975 → 0.5.2-canary.05994f8
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/package.json +2 -2
- package/src/CommandPalette/CommandPalette.doc.mjs +72 -0
- package/src/CommandPalette/CommandPalette.spec.md +223 -0
- package/src/Layout/Layout.doc.mjs +32 -0
- package/src/Layout/Layout.spec.md +199 -0
- package/src/Lightbox/Lightbox.doc.mjs +149 -33
- package/src/Lightbox/Lightbox.spec.md +197 -0
- package/src/MobileNav/MobileNav.doc.mjs +140 -32
- package/src/MobileNav/MobileNav.spec.md +208 -0
- package/src/NavIcon/NavIcon.doc.mjs +17 -0
- package/src/NavIcon/NavIcon.spec.md +133 -0
- package/src/OverflowList/OverflowList.doc.mjs +24 -0
- package/src/OverflowList/OverflowList.spec.md +156 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +198 -38
- package/src/ProgressBar/ProgressBar.spec.md +77 -25
- package/src/Resizable/Resizable.doc.mjs +59 -16
- package/src/Resizable/Resizable.spec.md +194 -0
- package/src/Section/Section.doc.mjs +17 -0
- package/src/Section/Section.spec.md +138 -0
- package/src/SegmentedControl/SegmentedControl.doc.mjs +27 -0
- package/src/SegmentedControl/SegmentedControl.spec.md +151 -0
- package/src/Skeleton/Skeleton.doc.mjs +12 -0
- package/src/Skeleton/Skeleton.spec.md +126 -0
- package/src/Slider/Slider.doc.mjs +184 -30
- package/src/Slider/Slider.spec.md +223 -0
- package/src/Stack/Stack.doc.mjs +22 -0
- package/src/Stack/Stack.spec.md +154 -0
- package/src/StatusDot/StatusDot.doc.mjs +17 -0
- package/src/StatusDot/StatusDot.spec.md +137 -0
- package/src/Text/Text.doc.mjs +190 -43
- package/src/Text/Text.spec.md +205 -0
- package/src/Tooltip/Tooltip.doc.mjs +17 -0
- package/src/Tooltip/Tooltip.spec.md +141 -0
- package/src/TreeList/TreeList.doc.mjs +58 -0
- package/src/TreeList/TreeList.spec.md +220 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/core",
|
|
3
|
-
"version": "0.5.2-canary.
|
|
3
|
+
"version": "0.5.2-canary.05994f8",
|
|
4
4
|
"displayName": "Astryx Core",
|
|
5
5
|
"description": "The component library. Accessible, themeable React components with built-in spacing, dark mode, and StyleX styling.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -661,7 +661,7 @@
|
|
|
661
661
|
"react-dom": ">=19.0.0"
|
|
662
662
|
},
|
|
663
663
|
"devDependencies": {
|
|
664
|
-
"@astryxdesign/cli": "0.5.2-canary.
|
|
664
|
+
"@astryxdesign/cli": "0.5.2-canary.05994f8",
|
|
665
665
|
"@babel/cli": "^8.0.4",
|
|
666
666
|
"@babel/core": "^7.29.7",
|
|
667
667
|
"@babel/preset-react": "^8.0.1",
|
|
@@ -1,5 +1,74 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
|
|
4
|
+
const anatomy = [
|
|
5
|
+
{
|
|
6
|
+
name: 'Dialog',
|
|
7
|
+
required: true,
|
|
8
|
+
description: 'Modal surface that contains the command palette.',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'Input',
|
|
12
|
+
required: true,
|
|
13
|
+
description:
|
|
14
|
+
'Search region containing the query field and its supporting visuals.',
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
name: 'Search glyph',
|
|
18
|
+
required: true,
|
|
19
|
+
description: 'Search symbol rendered by Icon in the default Input.',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'Query field',
|
|
23
|
+
required: true,
|
|
24
|
+
description: 'Native text field used to enter a search query.',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'Loading spinner',
|
|
28
|
+
required: false,
|
|
29
|
+
description:
|
|
30
|
+
'Spinner shown in the default Input while a search is pending.',
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
name: 'List',
|
|
34
|
+
required: true,
|
|
35
|
+
description:
|
|
36
|
+
'Scrollable listbox containing the current results or Empty state.',
|
|
37
|
+
},
|
|
38
|
+
{
|
|
39
|
+
name: 'Item',
|
|
40
|
+
required: false,
|
|
41
|
+
description: 'Selectable command result rendered inside the List.',
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
name: 'Group',
|
|
45
|
+
required: false,
|
|
46
|
+
description: 'Optional collection of Items that share a heading.',
|
|
47
|
+
},
|
|
48
|
+
{
|
|
49
|
+
name: 'Group heading',
|
|
50
|
+
required: false,
|
|
51
|
+
description: 'Visible heading rendered for a Group.',
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
name: 'Empty',
|
|
55
|
+
required: false,
|
|
56
|
+
description: 'Message shown when the current result set is empty.',
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
name: 'Footer',
|
|
60
|
+
required: false,
|
|
61
|
+
description:
|
|
62
|
+
'Footer region for default keyboard guidance or caller-provided content.',
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
name: 'Keyboard shortcut',
|
|
66
|
+
required: false,
|
|
67
|
+
description:
|
|
68
|
+
'Painted key badges rendered by Kbd in the default Footer guidance.',
|
|
69
|
+
},
|
|
70
|
+
];
|
|
71
|
+
|
|
3
72
|
/** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
|
|
4
73
|
export const docs = {
|
|
5
74
|
name: 'CommandPalette',
|
|
@@ -152,6 +221,7 @@ export const docs = {
|
|
|
152
221
|
],
|
|
153
222
|
},
|
|
154
223
|
usage: {
|
|
224
|
+
anatomy,
|
|
155
225
|
description: 'CommandPalette is a searchable dialog for quick access to commands, navigation, and actions. Use it as a keyboard-driven launcher powered by SearchSource for filtering and selection.',
|
|
156
226
|
bestPractices: [
|
|
157
227
|
{ guidance: true, description: 'Provide a searchSource with bootstrap results so users see useful options before typing.' },
|
|
@@ -165,6 +235,7 @@ export const docs = {
|
|
|
165
235
|
/** @type {import('@astryxdesign/cli/authoring').ComponentTranslationDoc} */
|
|
166
236
|
export const docsZh = {
|
|
167
237
|
usage: {
|
|
238
|
+
anatomy,
|
|
168
239
|
description: 'CommandPalette is a searchable dialog for quick access to commands, navigation, and actions. Use it as a keyboard-driven launcher powered by SearchSource for filtering and selection.',
|
|
169
240
|
bestPractices: [
|
|
170
241
|
{ guidance: true, description: 'Provide a searchSource with bootstrap results so users see useful options before typing.' },
|
|
@@ -180,6 +251,7 @@ export const docsDense = {
|
|
|
180
251
|
description:
|
|
181
252
|
'searchSource-driven command palette dialog; filtering, keyboard nav, grouping, selection; same SearchSource interface as Typeahead',
|
|
182
253
|
usage: {
|
|
254
|
+
anatomy,
|
|
183
255
|
description: 'CommandPalette is a searchable dialog for quick access to commands, navigation, and actions. Use it as a keyboard-driven launcher powered by SearchSource for filtering and selection.',
|
|
184
256
|
bestPractices: [
|
|
185
257
|
{ guidance: true, description: 'Provide a searchSource with bootstrap results so users see useful options before typing.' },
|
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
template_version: 3
|
|
4
|
+
kind: component
|
|
5
|
+
id: component:CommandPalette
|
|
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: [behavior, theming, accessibility]
|
|
13
|
+
verified_by:
|
|
14
|
+
[
|
|
15
|
+
packages/core/src/CommandPalette/CommandPalette.test.tsx,
|
|
16
|
+
packages/core/src/CommandPalette/CommandPaletteInput.test.tsx,
|
|
17
|
+
packages/core/src/CommandPalette/CommandPaletteList.test.tsx,
|
|
18
|
+
packages/core/src/CommandPalette/CommandPaletteItem.test.tsx,
|
|
19
|
+
packages/core/src/CommandPalette/CommandPaletteGroup.test.tsx,
|
|
20
|
+
packages/core/src/CommandPalette/CommandPaletteFooter.test.tsx,
|
|
21
|
+
packages/core/src/theme/themingTargets.test.ts,
|
|
22
|
+
scripts/check-knowledge.mjs,
|
|
23
|
+
]
|
|
24
|
+
families: [family:overlay-dismissal]
|
|
25
|
+
design_specs: []
|
|
26
|
+
architecture:
|
|
27
|
+
[
|
|
28
|
+
architecture:component-theming-surface,
|
|
29
|
+
architecture:interaction-modality,
|
|
30
|
+
architecture:public-component-api,
|
|
31
|
+
]
|
|
32
|
+
contributing: []
|
|
33
|
+
system_specs: []
|
|
34
|
+
---
|
|
35
|
+
|
|
36
|
+
# CommandPalette component contract
|
|
37
|
+
|
|
38
|
+
## Intent
|
|
39
|
+
|
|
40
|
+
CommandPalette presents searchable commands inside a Dialog. This draft records
|
|
41
|
+
its current aggregate consumer anatomy, target ownership, and delegated stable
|
|
42
|
+
parts without changing runtime behavior, styling, targets, or public API.
|
|
43
|
+
|
|
44
|
+
## Compatibility and migration
|
|
45
|
+
|
|
46
|
+
- Released default preserved: `yes`
|
|
47
|
+
- Compatibility class: additive documentation only; runtime, DOM, styling,
|
|
48
|
+
targets, aliases, and public API remain unchanged
|
|
49
|
+
- Controlled/uncontrolled behavior: unchanged
|
|
50
|
+
- Migration decision: none
|
|
51
|
+
|
|
52
|
+
Consumer migration instructions belong in consumer docs and release notes.
|
|
53
|
+
|
|
54
|
+
## Ownership boundary
|
|
55
|
+
|
|
56
|
+
**Owns**
|
|
57
|
+
|
|
58
|
+
- Search orchestration and the current Input, List, Item, Group, Group heading,
|
|
59
|
+
Empty, and Footer parts and targets.
|
|
60
|
+
- The native Query field rendered inside the default Input.
|
|
61
|
+
|
|
62
|
+
**Does not own / non-goals**
|
|
63
|
+
|
|
64
|
+
- Dialog's surface, Icon's glyph, Spinner's loading indicator, or Kbd's shortcut
|
|
65
|
+
badges — owned by their respective components.
|
|
66
|
+
- Caller-provided replacement Input, Footer, item content, or trailing input
|
|
67
|
+
content — owned by the product callsite.
|
|
68
|
+
- A `command-palette` root target — no such current target exists, and this
|
|
69
|
+
factual backfill does not invent one.
|
|
70
|
+
- Shared layer hosting, positioning, or lifecycle rules beyond the current
|
|
71
|
+
records linked below.
|
|
72
|
+
|
|
73
|
+
## Public concepts
|
|
74
|
+
|
|
75
|
+
No new public concept is introduced. Consumer props, slots, and usage remain
|
|
76
|
+
documented in `CommandPalette.doc.mjs` and its subcomponent docs.
|
|
77
|
+
|
|
78
|
+
## Behavioral and layout contract
|
|
79
|
+
|
|
80
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
81
|
+
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------- | ------------------------------------------------------------------------- |
|
|
82
|
+
| FR1 | The current default render places Input and Footer around a List inside a delegated Dialog; the List contains Items, optional Groups and Group headings, or Empty according to the current results. | Current source, docs, and tests | Verified current behavior; no new behavior decided |
|
|
83
|
+
| FR2 | Input, List, Item, Group, Group heading, Empty, and Footer carry the seven current `command-palette-*` targets documented below; no `command-palette` root target exists. | Current source and target docs | Verified current inventory; focused placement coverage is partial |
|
|
84
|
+
| FR3 | The default Input delegates its Search glyph to Icon and pending Loading spinner to Spinner; the default Footer delegates keyboard shortcuts to Kbd; the containing surface delegates to Dialog. | Current source and component docs | Verified current composition; no ownership change |
|
|
85
|
+
| FR4 | Query field is a distinct native text field inside Input and currently has no separate public target. The `command-palette-input` target is on the surrounding search region, not the native field. | Current source and target docs | Verified current reachability; long-term theming intent remains unsettled |
|
|
86
|
+
|
|
87
|
+
### Allowed variation
|
|
88
|
+
|
|
89
|
+
- **AV1 — Results.** Item count, grouping, selected content, and empty state may
|
|
90
|
+
vary without changing the aggregate anatomy.
|
|
91
|
+
- **AV2 — Slots.** Caller-provided Input and Footer content may replace the
|
|
92
|
+
defaults without becoming CommandPalette-owned subparts.
|
|
93
|
+
- **AV3 — Delegated rendering.** Dialog, Icon, Spinner, and Kbd may change their
|
|
94
|
+
internal element shape while preserving their own public contracts.
|
|
95
|
+
|
|
96
|
+
### Representative states
|
|
97
|
+
|
|
98
|
+
| State | Required invariant | Allowed variation |
|
|
99
|
+
| ---------------------- | ------------------------------------------------------- | ----------------------------------------------- |
|
|
100
|
+
| Ungrouped results | List contains Item instances. | Item count and caller-rendered content. |
|
|
101
|
+
| Grouped results | List contains Group, Group heading, and Item instances. | Group names, count, ordering, and item content. |
|
|
102
|
+
| Empty bootstrap/search | List contains Empty instead of Items. | Caller-provided empty content. |
|
|
103
|
+
| Pending search | Default Input may contain Loading spinner. | Spinner is absent when no search is pending. |
|
|
104
|
+
| Default slots | Input and Footer render their documented defaults. | Footer shortcut text and translated labels. |
|
|
105
|
+
| Caller-replaced slots | The slot content replaces the corresponding default. | Replacement structure remains caller-owned. |
|
|
106
|
+
|
|
107
|
+
### Transformation and precedence order
|
|
108
|
+
|
|
109
|
+
- No new search, selection, layout, or styling precedence rule is introduced.
|
|
110
|
+
|
|
111
|
+
### Performance and resources
|
|
112
|
+
|
|
113
|
+
- No new performance or resource rule is introduced.
|
|
114
|
+
|
|
115
|
+
## Accessibility contract
|
|
116
|
+
|
|
117
|
+
This draft does not change or extend CommandPalette's current Dialog, combobox,
|
|
118
|
+
listbox, option, announcement, or keyboard behavior.
|
|
119
|
+
|
|
120
|
+
## Design relationships
|
|
121
|
+
|
|
122
|
+
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
123
|
+
| ----------------- | ----------------------------------------------------------------------- | ------------------------------ | -------------- | ------------------ |
|
|
124
|
+
| Dialog | Presents the containing modal surface. | `component:Dialog` | Supporting | FR1, FR3 |
|
|
125
|
+
| Input | Paints the search region around the query field and supporting visuals. | Current source and public docs | Prominent | FR1, FR2, FR4 |
|
|
126
|
+
| Search glyph | Presents the search symbol in the default Input. | `component:Icon` | Supporting | FR3 |
|
|
127
|
+
| Query field | Accepts the native text query inside Input. | Current source and public docs | Prominent | FR1, FR4 |
|
|
128
|
+
| Loading spinner | Indicates a pending search in the default Input. | `component:Spinner` | Supporting | FR3 |
|
|
129
|
+
| List | Presents the current result collection or Empty state. | Current source and public docs | Supporting | FR1, FR2 |
|
|
130
|
+
| Item | Presents one selectable command result. | Current source and public docs | Prominent | FR1, FR2 |
|
|
131
|
+
| Group | Arranges related Items together. | Current source and public docs | Supporting | FR1, FR2 |
|
|
132
|
+
| Group heading | Labels one Group visually. | Current source and public docs | Supporting | FR1, FR2 |
|
|
133
|
+
| Empty | Presents the no-results or no-query message. | Current source and public docs | Prominent | FR1, FR2 |
|
|
134
|
+
| Footer | Presents default guidance or caller-provided footer content. | Current source and public docs | Supporting | FR1, FR2 |
|
|
135
|
+
| Keyboard shortcut | Presents one shortcut as painted key badges in the default Footer. | `component:Kbd` | Supporting | FR3 |
|
|
136
|
+
|
|
137
|
+
The native Query field is separate from the Input region that carries
|
|
138
|
+
`command-palette-input`. Its current lack of a direct target is observed
|
|
139
|
+
reachability, not a decision that it must remain unthemeable.
|
|
140
|
+
|
|
141
|
+
### Theming anatomy
|
|
142
|
+
|
|
143
|
+
<!-- anatomy-theming:v1 -->
|
|
144
|
+
|
|
145
|
+
```json
|
|
146
|
+
{
|
|
147
|
+
"Dialog": {
|
|
148
|
+
"delegatesTo": {"owner": "component:Dialog", "target": "dialog"}
|
|
149
|
+
},
|
|
150
|
+
"Input": {"target": "command-palette-input"},
|
|
151
|
+
"Search glyph": {
|
|
152
|
+
"delegatesTo": {"owner": "component:Icon", "target": "icon"}
|
|
153
|
+
},
|
|
154
|
+
"Query field": {
|
|
155
|
+
"none": {
|
|
156
|
+
"reason": "unsettled: No current public target is applied directly to the native query field; future exposure still needs an owner decision"
|
|
157
|
+
}
|
|
158
|
+
},
|
|
159
|
+
"Loading spinner": {
|
|
160
|
+
"delegatesTo": {"owner": "component:Spinner", "target": "spinner"}
|
|
161
|
+
},
|
|
162
|
+
"List": {"target": "command-palette-list"},
|
|
163
|
+
"Item": {"target": "command-palette-item"},
|
|
164
|
+
"Group": {"target": "command-palette-group"},
|
|
165
|
+
"Group heading": {"target": "command-palette-group-heading"},
|
|
166
|
+
"Empty": {"target": "command-palette-empty"},
|
|
167
|
+
"Footer": {"target": "command-palette-footer"},
|
|
168
|
+
"Keyboard shortcut": {
|
|
169
|
+
"delegatesTo": {"owner": "component:Kbd", "target": "kbd"}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
The seven local targets are current public seams. The delegated parts retain
|
|
175
|
+
their existing component owners. The Query field `none` disposition records a
|
|
176
|
+
current audit gap and does not authorize a new target.
|
|
177
|
+
|
|
178
|
+
## Family and system relationships
|
|
179
|
+
|
|
180
|
+
- `architecture:component-theming-surface` owns anatomy qualification, target
|
|
181
|
+
mapping, delegation, and factual `none` dispositions.
|
|
182
|
+
- `architecture:public-component-api` owns the stable props and composition
|
|
183
|
+
surface; this documentation adds no API.
|
|
184
|
+
- `architecture:interaction-modality` owns shared keyboard and pointer modality;
|
|
185
|
+
this draft does not redefine focus ownership or input behavior.
|
|
186
|
+
- `family:overlay-dismissal` identifies CommandPalette as a current member and
|
|
187
|
+
records its component-local Escape handling as an adoption gap.
|
|
188
|
+
- No layer-runtime record is linked because no current record with that scope is
|
|
189
|
+
present in this checkout.
|
|
190
|
+
|
|
191
|
+
## Verification map
|
|
192
|
+
|
|
193
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
194
|
+
| ------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------ |
|
|
195
|
+
| FR1 | CommandPalette root and subcomponent render suites plus source inspection | Default, grouped, empty, pending, and replaced slots | Removing the asserted Dialog, Query field, List, Item, Group, Group heading, Empty, or Footer content fails existing role, content, or slot assertions; Search glyph, Loading spinner, and Keyboard shortcut presence remain source-inspected only. | `audit:CommandPalette/anatomy` |
|
|
196
|
+
| FR2 | Source inspection, `themingTargets.test.ts`, and `CommandPaletteGroup.test.tsx` | Seven local targets; Group and Group heading placement | Removing a current target fails the global inventory; moving Group or Group heading fails focused class assertions. | `audit:CommandPalette/theming` |
|
|
197
|
+
| FR3 | Source inspection plus Dialog, Icon, Spinner, and Kbd public target metadata | Default surface, Input visuals, and Footer shortcuts | Existing focused tests do not assert the composed Icon, Spinner, or Kbd instances; changing delegated ownership requires this map and the delegated component metadata to change. | `audit:CommandPalette/theming` |
|
|
198
|
+
| FR4 | `CommandPaletteInput.test.tsx` and source inspection | Native query field with idle and pending Input | Removing the field fails combobox tests; adding a field target requires an explicit map update. | `audit:CommandPalette/anatomy` |
|
|
199
|
+
| Theming anatomy map | `scripts/check-knowledge.mjs` | Canonical anatomy and seven current local targets | Missing, extra, prefixed, stale, or alias-backed mappings fail repository validation. | `audit:CommandPalette/theming` |
|
|
200
|
+
|
|
201
|
+
Focused target-placement assertions currently cover Group and Group heading.
|
|
202
|
+
Input, List, Item, Empty, and Footer placement rely on source inspection plus the
|
|
203
|
+
global target inventory. Existing tests assert default Footer text and pending
|
|
204
|
+
announcements, but do not assert that Icon, Spinner, or Kbd renders.
|
|
205
|
+
|
|
206
|
+
## Decision log
|
|
207
|
+
|
|
208
|
+
None. This draft records current facts and introduces no component-local design,
|
|
209
|
+
layer, API, or theming decision.
|
|
210
|
+
|
|
211
|
+
## Open questions
|
|
212
|
+
|
|
213
|
+
- **OQ1 — Should Query field gain a stable public theming target?** (`human-api`)
|
|
214
|
+
Its current lack of direct reachability is an audit gap, not settled intent.
|
|
215
|
+
- **OQ2 — Should focused tests pin the default Search glyph, pending Loading
|
|
216
|
+
spinner, and default Footer Keyboard shortcuts?** (`checkable`) Their presence
|
|
217
|
+
is currently source-inspected rather than asserted.
|
|
218
|
+
|
|
219
|
+
## Content boundary
|
|
220
|
+
|
|
221
|
+
This file does not duplicate consumer prop tables/examples, shared layer or
|
|
222
|
+
modality rules, current audit results, or implementation steps. It links to
|
|
223
|
+
their owners.
|
|
@@ -1,5 +1,35 @@
|
|
|
1
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
2
|
|
|
3
|
+
/** @type {import('@astryxdesign/cli/authoring').ComponentAnatomyElement[]} */
|
|
4
|
+
const anatomy = [
|
|
5
|
+
{
|
|
6
|
+
name: 'Page shell',
|
|
7
|
+
required: true,
|
|
8
|
+
description: 'Outer Layout container that arranges the named page regions.',
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
name: 'Header',
|
|
12
|
+
required: false,
|
|
13
|
+
description: 'Optional top region for page or application header content.',
|
|
14
|
+
},
|
|
15
|
+
{
|
|
16
|
+
name: 'Panel',
|
|
17
|
+
required: false,
|
|
18
|
+
description:
|
|
19
|
+
'Optional start or end side region; both positions use the same LayoutPanel part.',
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
name: 'Content area',
|
|
23
|
+
required: false,
|
|
24
|
+
description: 'Optional central region for the page content.',
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
name: 'Footer',
|
|
28
|
+
required: false,
|
|
29
|
+
description: 'Optional bottom region for page footer content.',
|
|
30
|
+
},
|
|
31
|
+
];
|
|
32
|
+
|
|
3
33
|
/** @type {import('@astryxdesign/cli/authoring').ComponentDoc} */
|
|
4
34
|
|
|
5
35
|
export const docs = {
|
|
@@ -129,6 +159,7 @@ export const docs = {
|
|
|
129
159
|
{ guidance: false, description: 'Use Layout for simple stacking layouts; use HStack or VStack instead.' },
|
|
130
160
|
{ guidance: false, description: 'Nest multiple Layout components; use one per page shell and compose content within its slots.' },
|
|
131
161
|
],
|
|
162
|
+
anatomy,
|
|
132
163
|
},
|
|
133
164
|
};
|
|
134
165
|
|
|
@@ -159,5 +190,6 @@ export const docsDense = {
|
|
|
159
190
|
{ guidance: false, description: 'Use Layout for simple stacking layouts; use HStack or VStack instead.' },
|
|
160
191
|
{ guidance: false, description: 'Nest multiple Layout components; use one per page shell and compose content within its slots.' },
|
|
161
192
|
],
|
|
193
|
+
anatomy,
|
|
162
194
|
},
|
|
163
195
|
};
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
---
|
|
2
|
+
schema_version: 1
|
|
3
|
+
template_version: 3
|
|
4
|
+
kind: component
|
|
5
|
+
id: component:Layout
|
|
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/Layout/Layout.test.tsx,
|
|
16
|
+
packages/core/src/Layout/LayoutSlots.test.tsx,
|
|
17
|
+
packages/core/src/Layout/__tests__/childrenAsContent.test.tsx,
|
|
18
|
+
packages/core/src/Layout/__tests__/contentWidth.test.tsx,
|
|
19
|
+
packages/core/src/theme/themingTargets.test.ts,
|
|
20
|
+
scripts/check-knowledge.mjs,
|
|
21
|
+
]
|
|
22
|
+
families: [family:layout-regions]
|
|
23
|
+
design_specs: []
|
|
24
|
+
architecture:
|
|
25
|
+
[
|
|
26
|
+
architecture:container-padding,
|
|
27
|
+
architecture:component-theming-surface,
|
|
28
|
+
architecture:public-component-api,
|
|
29
|
+
]
|
|
30
|
+
contributing: []
|
|
31
|
+
system_specs: []
|
|
32
|
+
---
|
|
33
|
+
|
|
34
|
+
# Layout component contract
|
|
35
|
+
|
|
36
|
+
## Intent
|
|
37
|
+
|
|
38
|
+
Layout provides the page shell that arranges optional Header, Panel, Content
|
|
39
|
+
area, and Footer regions. This draft records the current aggregate consumer
|
|
40
|
+
anatomy and theming ownership without changing runtime behavior, DOM, styling,
|
|
41
|
+
targets, or public API.
|
|
42
|
+
|
|
43
|
+
## Compatibility and migration
|
|
44
|
+
|
|
45
|
+
- Released default preserved: `yes`
|
|
46
|
+
- Compatibility class: additive documentation only; runtime, DOM, styling,
|
|
47
|
+
targets, aliases, and public API remain unchanged
|
|
48
|
+
- Controlled/uncontrolled behavior: not applicable
|
|
49
|
+
- Migration decision: none
|
|
50
|
+
|
|
51
|
+
Consumer migration instructions belong in consumer docs and release notes.
|
|
52
|
+
|
|
53
|
+
## Ownership boundary
|
|
54
|
+
|
|
55
|
+
**Owns**
|
|
56
|
+
|
|
57
|
+
- The Page shell and its current `layout` target.
|
|
58
|
+
- The aggregate Header, Panel, Content area, and Footer anatomy and their current
|
|
59
|
+
`layout-header`, `layout-panel`, `layout-content`, and `layout-footer` targets.
|
|
60
|
+
- One Panel concept for both logical start and end positions.
|
|
61
|
+
|
|
62
|
+
**Does not own / non-goals**
|
|
63
|
+
|
|
64
|
+
- Product meaning or content supplied to any region — owned by the caller.
|
|
65
|
+
- Automatic responsive substitution of regions — owned by the caller, AppShell,
|
|
66
|
+
or another higher-level composition.
|
|
67
|
+
- Resize interaction — owned by useResizable and ResizeHandle.
|
|
68
|
+
- Correcting current container-padding publication mismatches or preventing two
|
|
69
|
+
adjacent divider owners from both painting; those remain current gaps and
|
|
70
|
+
caller obligations recorded below.
|
|
71
|
+
- New runtime behavior, API, target, alias, or region wrapper.
|
|
72
|
+
|
|
73
|
+
## Public concepts
|
|
74
|
+
|
|
75
|
+
No new public concept is introduced. Consumer props, slots, defaults, and usage
|
|
76
|
+
remain documented in `Layout.doc.mjs` and the region subcomponent docs.
|
|
77
|
+
`family:layout-regions` owns the shared region vocabulary.
|
|
78
|
+
|
|
79
|
+
## Behavioral and layout contract
|
|
80
|
+
|
|
81
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
82
|
+
| --- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------- | -------------------------------------------------- |
|
|
83
|
+
| FR1 | Layout renders one Page shell carrying the current `layout` target and places each supplied named region according to the existing shell topology. | Current source, docs, tests, and family | Verified current behavior; no new behavior decided |
|
|
84
|
+
| FR2 | Header, Content area, and Footer use their current `layout-header`, `layout-content`, and `layout-footer` targets on the corresponding Layout region components. | Current source and target metadata | Verified current inventory; no target change |
|
|
85
|
+
| FR3 | A Panel in either logical start or end position is the same aggregate Panel part and uses the current `layout-panel` target; position does not create a second anatomy row or target. | Current source, docs, tests, and family | Verified current ownership; no API change |
|
|
86
|
+
| FR4 | `Layout.doc.mjs` is the canonical aggregate consumer document for all five current `layout*` targets; region subcomponent docs continue to document their own props and usage without duplicating the aggregate target inventory. | Current documentation organization | Verified current ownership |
|
|
87
|
+
| FR5 | LayoutContent and LayoutPanel retain their shipped automatic container-padding publication behavior, including the mismatches recorded by `architecture:container-padding`; this documentation does not claim exact parity. | Current source and architecture record | Current conformance gap; not fixed here |
|
|
88
|
+
| FR6 | When an adjacent ResizeHandle owns a panel divider, the caller must keep `LayoutPanel hasDivider={false}`; current composition does not prevent both components from painting the same boundary. | Current source, docs, and family contract | Current caller obligation; not fixed here |
|
|
89
|
+
|
|
90
|
+
### Current evidence and gaps
|
|
91
|
+
|
|
92
|
+
- LayoutContent does not republish a matching inline-end container-padding value
|
|
93
|
+
on its automatic no-end path, and its no-start path writes the outer inline
|
|
94
|
+
value to both inline geometry variables. LayoutPanel applies automatic outer
|
|
95
|
+
shell-edge padding while retaining baseline inner geometry variables. A
|
|
96
|
+
full-bleed descendant can therefore compensate against a published value that
|
|
97
|
+
differs from the region's applied padding. This is shipped evidence and a
|
|
98
|
+
runtime conformance gap, not behavior corrected or approved by this draft.
|
|
99
|
+
- LayoutPanel and an adjacent ResizeHandle can both draw the same content-facing
|
|
100
|
+
divider. The current caller obligation is to set
|
|
101
|
+
`LayoutPanel hasDivider={false}` when ResizeHandle owns that line. This draft
|
|
102
|
+
does not add coordination or duplicate-divider prevention.
|
|
103
|
+
|
|
104
|
+
### Allowed variation
|
|
105
|
+
|
|
106
|
+
- **AV1 — Slot presence.** Header, start Panel, Content area, end Panel, and Footer
|
|
107
|
+
may be independently present or absent within the existing shell topology.
|
|
108
|
+
- **AV2 — Panel position.** A Panel may occupy logical start or end, or Panels may
|
|
109
|
+
occupy both positions; all use the same conceptual part and target owner.
|
|
110
|
+
- **AV3 — Region content.** Caller-provided region content retains its own
|
|
111
|
+
semantics and theming ownership.
|
|
112
|
+
|
|
113
|
+
### Representative states
|
|
114
|
+
|
|
115
|
+
| State | Required invariant | Allowed variation |
|
|
116
|
+
| --------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------ |
|
|
117
|
+
| Content-only shell | Page shell and Content area use their current targets. | Caller content and current height/width configuration. |
|
|
118
|
+
| Header/content/footer | Each supplied region uses its corresponding aggregate part and target. | Divider selection, size, padding, and caller content. |
|
|
119
|
+
| Start or end Panel | Either logical position uses the one Panel part and `layout-panel` target. | Position, width, scrolling, padding, and caller role. |
|
|
120
|
+
| Two Panels | Both instances remain one repeated conceptual Panel part. | Independent content, width, and local configuration. |
|
|
121
|
+
| ResizeHandle-adjacent | Divider ownership follows the current caller obligation in FR6. | Resize state remains owned by the resize components. |
|
|
122
|
+
|
|
123
|
+
### Transformation and precedence order
|
|
124
|
+
|
|
125
|
+
- No new slot, padding, content-width, divider, scrolling, sizing, or styling
|
|
126
|
+
precedence rule is introduced.
|
|
127
|
+
|
|
128
|
+
### Performance and resources
|
|
129
|
+
|
|
130
|
+
- No new performance or resource rule is introduced.
|
|
131
|
+
|
|
132
|
+
## Accessibility contract
|
|
133
|
+
|
|
134
|
+
This draft does not add inferred landmark semantics. LayoutHeader,
|
|
135
|
+
LayoutContent, LayoutFooter, and LayoutPanel retain their current explicit
|
|
136
|
+
caller-supplied role and label behavior.
|
|
137
|
+
|
|
138
|
+
## Design relationships
|
|
139
|
+
|
|
140
|
+
| Anatomy or state | Design requirement | Representation authority | Hierarchy role | Component contract |
|
|
141
|
+
| ---------------- | -------------------------------------------------------------- | ----------------------------------------- | -------------- | ------------------ |
|
|
142
|
+
| Page shell | Arranges the named page regions. | Current source, docs, and family contract | Supporting | FR1 |
|
|
143
|
+
| Header | Presents optional top-region content. | Current source, docs, and family contract | Supporting | FR1, FR2 |
|
|
144
|
+
| Panel | Presents optional side-region content at logical start or end. | Current source, docs, and family contract | Supporting | FR1, FR3, FR6 |
|
|
145
|
+
| Content area | Presents optional central page content. | Current source, docs, and family contract | Prominent | FR1, FR2, FR5 |
|
|
146
|
+
| Footer | Presents optional bottom-region content. | Current source, docs, and family contract | Supporting | FR1, FR2 |
|
|
147
|
+
|
|
148
|
+
### Theming anatomy
|
|
149
|
+
|
|
150
|
+
<!-- anatomy-theming:v1 -->
|
|
151
|
+
|
|
152
|
+
```json
|
|
153
|
+
{
|
|
154
|
+
"Page shell": {"target": "layout"},
|
|
155
|
+
"Header": {"target": "layout-header"},
|
|
156
|
+
"Panel": {"target": "layout-panel"},
|
|
157
|
+
"Content area": {"target": "layout-content"},
|
|
158
|
+
"Footer": {"target": "layout-footer"}
|
|
159
|
+
}
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
The exact map records the five current public targets. Start and end Panels are
|
|
163
|
+
instances of the same stable conceptual part and therefore share one map row.
|
|
164
|
+
|
|
165
|
+
## Family and system relationships
|
|
166
|
+
|
|
167
|
+
- `family:layout-regions` owns the shared shell-region topology, logical
|
|
168
|
+
direction, boundaries, scrolling, and component ownership.
|
|
169
|
+
- `architecture:container-padding` owns Layout inset publication and the current
|
|
170
|
+
LayoutContent/LayoutPanel conformance gap.
|
|
171
|
+
- `architecture:component-theming-surface` owns anatomy qualification and exact
|
|
172
|
+
target mapping rules.
|
|
173
|
+
- `architecture:public-component-api` owns the stable slots, props, exports, and
|
|
174
|
+
compatibility boundary; this documentation adds no API.
|
|
175
|
+
|
|
176
|
+
## Verification map
|
|
177
|
+
|
|
178
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
179
|
+
| ------------- | ----------------------------------------------------------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------- | ---------------------------- |
|
|
180
|
+
| FR1–FR3 | Layout render, slot, children-as-content, and target inventory tests | Content-only, all regions, logical start/end Panels | Removing a region or target fails existing structure, context, or target inventory assertions. | `audit:Layout/anatomy` |
|
|
181
|
+
| FR4 | `scripts/check-knowledge.mjs` | Canonical aggregate doc and exact five-target map | Duplicated, missing, extra, prefixed, or stale target mappings fail repository validation. | `audit:Layout/theming` |
|
|
182
|
+
| FR5 | Source inspection plus `architecture:container-padding` verification evidence | Automatic outer-edge Content area and Panel paths | This draft adds no parity assertion; a runtime correction requires separate compatibility evidence. | `audit:Layout/layout` |
|
|
183
|
+
| FR6 | LayoutPanel source/docs plus `family:layout-regions` verification evidence | Panel beside a divider-owning ResizeHandle | This draft adds no prevention assertion; changing ownership requires separate runtime coverage. | `audit:Layout/layout` |
|
|
184
|
+
| Accessibility | `LayoutSlots.test.tsx` landmark assertions | Header, Content area, Footer, and Panel roles | Supplied role or label no longer reaches the region element. | `audit:Layout/accessibility` |
|
|
185
|
+
|
|
186
|
+
## Decision log
|
|
187
|
+
|
|
188
|
+
None. This draft records current facts and introduces no component-local design,
|
|
189
|
+
layout, API, target, or behavior decision.
|
|
190
|
+
|
|
191
|
+
## Open questions
|
|
192
|
+
|
|
193
|
+
None.
|
|
194
|
+
|
|
195
|
+
## Content boundary
|
|
196
|
+
|
|
197
|
+
This file does not duplicate consumer prop tables or examples, family region
|
|
198
|
+
rules, container-padding mechanics, resize interaction, implementation steps,
|
|
199
|
+
or system rules. It links to their owners.
|