@astryxdesign/core 0.7.2-canary.fdd384f → 0.7.2
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 +156 -2
- package/README.md +4 -4
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +8 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +4 -1
- package/dist/Chat/ChatLayoutScrollButton.d.ts.map +1 -1
- package/dist/Chat/ChatLayoutScrollButton.js +1 -0
- package/dist/CheckboxList/CheckboxList.d.ts +1 -1
- package/dist/CheckboxList/CheckboxList.d.ts.map +1 -1
- package/dist/CheckboxList/CheckboxList.js +6 -2
- package/dist/DropdownMenu/DropdownMenu.d.ts +1 -1
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +38 -110
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +1 -1
- 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/DropdownMenuRadioItem.d.ts +1 -1
- 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/DropdownMenu/menuRegionStops.d.ts +38 -0
- package/dist/DropdownMenu/menuRegionStops.d.ts.map +1 -0
- package/dist/DropdownMenu/menuRegionStops.js +131 -0
- package/dist/FormLayout/FormLayout.d.ts +5 -4
- package/dist/FormLayout/FormLayout.d.ts.map +1 -1
- package/dist/FormLayout/FormLayout.js +1 -1
- package/dist/FormLayout/FormLayoutContext.d.ts +3 -3
- package/dist/FormLayout/FormLayoutContext.js +3 -3
- package/dist/Grid/Grid.d.ts +8 -7
- package/dist/Grid/Grid.d.ts.map +1 -1
- package/dist/Grid/Grid.js +5 -4
- package/dist/Grid/GridSpan.d.ts +1 -1
- package/dist/Markdown/parser.d.ts.map +1 -1
- package/dist/Markdown/parser.js +8 -2
- package/dist/Markdown/plugins/headingLinks.d.ts.map +1 -1
- package/dist/Markdown/plugins/headingLinks.js +9 -1
- package/dist/PowerSearch/PowerSearch.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearch.js +5 -0
- package/dist/PowerSearch/PowerSearchValueEditor.d.ts.map +1 -1
- package/dist/PowerSearch/PowerSearchValueEditor.js +45 -11
- package/dist/SideNav/SideNavItem.d.ts.map +1 -1
- package/dist/SideNav/SideNavItem.js +6 -2
- package/dist/Token/Token.js +1 -1
- package/dist/TopNav/TopNavMegaMenu.js +2 -0
- package/dist/TopNav/TopNavMenu.d.ts.map +1 -1
- package/dist/TopNav/TopNavMenu.js +2 -0
- package/dist/astryx.css +1 -1
- package/dist/reset.a11y.chromium.spec.js +50 -1
- package/docs.mjs +4 -4
- package/package.json +4 -4
- package/scripts/agent-doc-state.mjs +66 -6
- package/scripts/postinstall.mjs +44 -3
- package/src/Avatar/Avatar.tsx +11 -2
- package/src/AvatarGroup/AvatarGroupOverflow.test.tsx +24 -1
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +2 -0
- package/src/Chat/ChatLayoutScrollButton.test.tsx +13 -0
- package/src/Chat/ChatLayoutScrollButton.tsx +4 -2
- package/src/Chat/__tests__/ChatLayoutScrollButton.a11y.chromium.spec.ts +64 -19
- package/src/CheckboxList/CheckboxList.fr10.test.tsx +29 -2
- package/src/CheckboxList/CheckboxList.tsx +4 -1
- package/src/Code/Code.doc.mjs +1 -0
- package/src/CommandPalette/CommandPalette.doc.mjs +2 -0
- package/src/ContextMenu/ContextMenu.test.tsx +12 -2
- package/src/Drawer/Drawer.doc.mjs +1 -0
- package/src/DropdownMenu/DropdownMenu.ssr.test.tsx +57 -0
- package/src/DropdownMenu/DropdownMenu.test.tsx +17 -5
- package/src/DropdownMenu/DropdownMenu.tsx +43 -142
- package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +1 -1
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +1 -1
- 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/DropdownMenuRadioItem.doc.mjs +1 -1
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +1 -1
- package/src/DropdownMenu/__tests__/DropdownMenuGroupAudit.a11y.chromium.spec.ts +334 -0
- package/src/DropdownMenu/__tests__/warmMenuBottomSheet.tsx +43 -0
- package/src/DropdownMenu/lazyMenuBottomSheet.ts +71 -0
- package/src/DropdownMenu/menuRegionStops.ts +167 -0
- 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/FormLayout/FormLayout.doc.mjs +6 -3
- package/src/FormLayout/FormLayout.spec.md +192 -0
- package/src/FormLayout/FormLayout.test.tsx +15 -0
- package/src/FormLayout/FormLayout.tsx +7 -6
- package/src/FormLayout/FormLayoutContext.ts +3 -3
- package/src/Grid/Grid.doc.mjs +7 -1
- package/src/Grid/Grid.spec.md +93 -113
- package/src/Grid/Grid.test.tsx +22 -0
- package/src/Grid/Grid.tsx +10 -9
- package/src/Grid/GridSpan.doc.mjs +3 -3
- package/src/Grid/GridSpan.tsx +1 -1
- package/src/Icon/Icon.doc.mjs +36 -0
- package/src/Indicator/Indicator.doc.mjs +3 -3
- package/src/Layout/LayoutHeader.doc.mjs +5 -0
- package/src/Markdown/parser.ts +8 -2
- package/src/Markdown/plugins/headingLinks.ts +9 -1
- package/src/MetadataList/MetadataList.doc.mjs +1 -1
- package/src/MoreMenu/MoreMenu.test.tsx +5 -1
- package/src/PowerSearch/PowerSearch.test.tsx +62 -0
- package/src/PowerSearch/PowerSearch.tsx +9 -0
- package/src/PowerSearch/PowerSearchValueEditor.test.tsx +71 -0
- package/src/PowerSearch/PowerSearchValueEditor.tsx +45 -0
- package/src/ProgressBar/ProgressBar.doc.mjs +1 -0
- package/src/Resizable/useResizable.doc.mjs +2 -0
- package/src/ScrollableArea/ScrollableArea.doc.mjs +1 -1
- package/src/SideNav/SideNav.spec.md +227 -0
- package/src/SideNav/SideNav.test.tsx +41 -0
- package/src/SideNav/SideNavItem.tsx +5 -2
- package/src/Spinner/Spinner.doc.mjs +1 -1
- package/src/Table/Table.spec.md +6 -1
- package/src/Table/plugins/activation/useTableActivation.spec.md +254 -0
- package/src/Timestamp/Timestamp.doc.mjs +1 -1
- package/src/ToggleButton/ToggleButtonGroup.doc.mjs +4 -0
- package/src/Token/Token.tsx +1 -1
- package/src/Token/__tests__/TokenRemoveTarget.a11y.chromium.spec.ts +86 -0
- 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/TopNav/TopNavMegaMenu.test.tsx +25 -0
- package/src/TopNav/TopNavMegaMenu.tsx +2 -0
- package/src/TopNav/TopNavMenu.test.tsx +27 -1
- package/src/TopNav/TopNavMenu.tsx +2 -0
- package/src/postinstall.test.mjs +79 -0
- package/src/reset.a11y.chromium.spec.ts +52 -1
- package/src/reset.css +9 -0
- package/src/reset.test.ts +11 -0
- package/src/unicodePropertyEscapes.source-build.test.mjs +69 -0
package/src/Grid/Grid.spec.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
schema_version: 3
|
|
3
|
-
template_version:
|
|
3
|
+
template_version: 7
|
|
4
4
|
kind: component
|
|
5
5
|
id: component:Grid
|
|
6
6
|
authority: draft
|
|
@@ -9,10 +9,12 @@ superseded_by: null
|
|
|
9
9
|
approved_by: null
|
|
10
10
|
approved_at: null
|
|
11
11
|
owners: [cixzhang]
|
|
12
|
-
review_triggers: [layout, theming]
|
|
12
|
+
review_triggers: [public-api, behavior, layout, theming, accessibility]
|
|
13
13
|
verified_by:
|
|
14
14
|
[
|
|
15
15
|
packages/core/src/Grid/Grid.test.tsx,
|
|
16
|
+
apps/storybook/stories/Grid.stories.tsx,
|
|
17
|
+
.github/scripts/story-play-guard.js,
|
|
16
18
|
packages/core/src/theme/themingTargets.test.ts,
|
|
17
19
|
scripts/check-knowledge.mjs,
|
|
18
20
|
]
|
|
@@ -20,27 +22,41 @@ modules: []
|
|
|
20
22
|
families: [family:layout-primitives]
|
|
21
23
|
design_specs: []
|
|
22
24
|
architecture:
|
|
23
|
-
[
|
|
25
|
+
[
|
|
26
|
+
architecture:component-theming-surface,
|
|
27
|
+
architecture:public-component-api,
|
|
28
|
+
architecture:component-test-sufficiency,
|
|
29
|
+
]
|
|
24
30
|
contributing: []
|
|
25
31
|
system_specs: []
|
|
26
32
|
---
|
|
27
33
|
|
|
28
34
|
# Grid component contract
|
|
29
35
|
|
|
36
|
+
## Contract at a glance
|
|
37
|
+
|
|
38
|
+
| Area | Contract |
|
|
39
|
+
| ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
40
|
+
| Public contract | `Grid` owns fixed and intrinsic column-track construction; `GridSpan` changes one direct item's row or column participation. Both accept root `BaseProps`. |
|
|
41
|
+
| Behavior | A positive number creates exactly N `1fr` tracks without reflow; an object creates fill/fit tracks from a pixel minimum and optional count cap; axis gaps override uniform gap. |
|
|
42
|
+
| End-user impact | Content keeps DOM order and logical direction while responsive object-form grids reduce their count to fit. Fixed tracks may narrow or overflow when their content cannot shrink. |
|
|
43
|
+
| Builder impact | Builders choose fixed numeric tracks or responsive object tracks explicitly. `'full'` spans all explicit columns, not implicit tracks created by an oversized numeric span. |
|
|
44
|
+
| Compatibility/readiness | This draft records released behavior. It changes no public API, default, target, or runtime behavior. |
|
|
45
|
+
| Review checks | Reject automatic reflow for numeric columns, equal-width promises that ignore minimum content, lost gap precedence, raw inline track templates, caller-overridable owned metadata, or `'full'` as all implicit tracks. |
|
|
46
|
+
| Governing rules | `family:layout-primitives/FR1–FR7`; `architecture:public-component-api/INV5–INV9`; `architecture:component-theming-surface/INV2–INV6`. |
|
|
47
|
+
|
|
48
|
+
This table is a review projection; the body below is authoritative.
|
|
49
|
+
|
|
30
50
|
## Intent
|
|
31
51
|
|
|
32
|
-
Grid arranges caller-supplied items in two-dimensional tracks. GridSpan
|
|
33
|
-
optionally wraps one item to control its row or column participation. This draft
|
|
34
|
-
records the current consumer anatomy and theming ownership without changing
|
|
35
|
-
layout, targets, or public API.
|
|
52
|
+
Grid arranges caller-supplied items in two-dimensional tracks. GridSpan optionally wraps one item to control its row or column participation. Neither component owns the content, a surface, or structural page semantics.
|
|
36
53
|
|
|
37
54
|
## Compatibility and migration
|
|
38
55
|
|
|
39
|
-
- Released default preserved:
|
|
40
|
-
- Compatibility class:
|
|
41
|
-
|
|
42
|
-
-
|
|
43
|
-
- Migration decision: none
|
|
56
|
+
- Released default preserved: yes; omitted, zero, or negative numeric `columns` resolves to one track.
|
|
57
|
+
- Compatibility class: observational only; runtime, DOM, styling, targets, and public API remain unchanged.
|
|
58
|
+
- Controlled/uncontrolled behavior: not applicable.
|
|
59
|
+
- Migration decision: none.
|
|
44
60
|
|
|
45
61
|
Consumer migration instructions belong in consumer docs and release notes.
|
|
46
62
|
|
|
@@ -48,106 +64,82 @@ Consumer migration instructions belong in consumer docs and release notes.
|
|
|
48
64
|
|
|
49
65
|
**Owns**
|
|
50
66
|
|
|
51
|
-
-
|
|
52
|
-
-
|
|
53
|
-
-
|
|
67
|
+
- Grid's root container, current `grid` target, track construction, axis gaps, item alignment, and explicit box dimensions.
|
|
68
|
+
- GridSpan's optional wrapper, current `grid-span` target, and one item's row/column participation.
|
|
69
|
+
- Root prop and style composition on each owned element.
|
|
54
70
|
|
|
55
71
|
**Does not own / non-goals**
|
|
56
72
|
|
|
57
|
-
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
73
|
+
- Caller content, item semantics, surfaces, or interaction — owned by the product callsite or rendered child component.
|
|
74
|
+
- A shared breakpoint or automatic reflow for numeric columns — responsiveness is selected by Grid's object form.
|
|
75
|
+
- Implicit tracks created by CSS Grid when a numeric span exceeds the explicit grid.
|
|
60
76
|
|
|
61
77
|
## Public concepts
|
|
62
78
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
`
|
|
79
|
+
| Concept | Closed values or states | Meaning | Availability by variant/orientation/state | Default | Owner | Stability | Invalid-value behavior |
|
|
80
|
+
| -------------------- | ------------------------------------------ | ----------------------------------------------------------------------- | ----------------------------------------- | --------------------------- | -------------------------- | --------- | --------------------------------------------------------- |
|
|
81
|
+
| column shape | fixed number; responsive object; omitted | Selects fixed `1fr` tracks or intrinsic fill/fit tracks. | Every Grid | one track | `component:Grid` | released | zero/negative number falls back to one track |
|
|
82
|
+
| responsive repeat | `fill`; `fit` | Keeps empty tracks or collapses them so present items stretch. | Object-form columns | `fill` | `component:Grid` | released | Type-constrained |
|
|
83
|
+
| responsive count cap | absent; positive `max`; non-positive `max` | Caps the number of intrinsic tracks while allowing present tracks fill. | Object-form columns | absent | `component:Grid` | released | non-positive behaves as uncapped |
|
|
84
|
+
| spacing | shared `SpacingStep` values | Separates rows/columns; axis values override uniform gap. | Every Grid | browser grid gap default | `family:layout-primitives` | released | Type-constrained |
|
|
85
|
+
| item alignment | `start`; `center`; `end`; `stretch` | Sets `align-items` and `justify-items`. | Every Grid | `stretch` | `component:Grid` | released | Type-constrained |
|
|
86
|
+
| box size | number; CSS value string; absent | Sizes the Grid box; numbers become pixels. | Every Grid | caller/container-determined | `family:layout-primitives` | released | Browser validates strings |
|
|
87
|
+
| implicit row height | number; absent | Sets pixel height for implicit rows used by row spans. | Every Grid | browser `auto` | `component:Grid` | released | Browser validates the resulting CSS |
|
|
88
|
+
| column participation | number; `full`; absent | Spans N columns or every explicit column. | GridSpan under a grid | intrinsic item placement | `component:GridSpan` | released | Browser resolves numeric spans, including implicit tracks |
|
|
89
|
+
| row participation | number; absent | Spans N rows. | GridSpan under a grid | intrinsic item placement | `component:GridSpan` | released | Browser validates the resulting CSS |
|
|
66
90
|
|
|
67
91
|
## Behavioral and layout contract
|
|
68
92
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
|
72
|
-
|
|
|
73
|
-
|
|
|
93
|
+
Draft requirements identify their basis so observed code is not mistaken for an intentional decision.
|
|
94
|
+
|
|
95
|
+
| ID | Candidate invariant | Basis | Draft review state |
|
|
96
|
+
| --- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------- | ------------------- |
|
|
97
|
+
| FR1 | A positive numeric `columns={N}` creates exactly N `1fr` tracks at every width and never reflows; minimum content may widen one track and overflow a narrow container. | DEC-1; released docs, source, tests, and browser evidence | settled observation |
|
|
98
|
+
| FR2 | Object-form columns use auto-fill by default or auto-fit for `repeat: 'fit'`; `minWidth` is the track floor, while a positive `max` caps count and allows a lone track to shrink to the container. | Released docs, source, tests, and browser evidence | settled observation |
|
|
99
|
+
| FR3 | `rowGap` overrides `gap` only for rows, and `columnGap` overrides `gap` only for columns; the effective column gap participates in capped-track math. | `family:layout-primitives/FR4`; source and tests | settled observation |
|
|
100
|
+
| FR4 | Grid's dynamic track template uses CSS-variable-backed StyleX so caller `xstyle` and class rules, including media rules, can replace it. Caller `style` wins other inline declarations, including `gridTemplateColumns`; explicit `width`, `height`, `maxWidth`, and `minHeight` props override matching `style` keys. | `architecture:public-component-api/INV5–INV8`; source/tests | settled observation |
|
|
101
|
+
| FR5 | GridSpan changes only its wrapper's participation. `columns="full"` uses `1 / -1`, which covers explicit tracks; a wider numeric span may create implicit tracks that participate in later placement. | Released source, tests, and browser CSS Grid behavior | settled observation |
|
|
102
|
+
| FR6 | Root refs, DOM/data/ARIA/events, `xstyle`, class name, and inline style reach or compose on the owned root without replacing the canonical target or Grid's owned reflected metadata. | `architecture:public-component-api/INV5–INV8` | settled observation |
|
|
103
|
+
| FR7 | Grid and GridSpan preserve caller DOM order and use the document's logical inline direction; neither creates a separate keyboard order. | Platform layout behavior and browser evidence | settled observation |
|
|
74
104
|
|
|
75
105
|
### Allowed variation
|
|
76
106
|
|
|
77
|
-
-
|
|
78
|
-
|
|
79
|
-
- Caller
|
|
80
|
-
- A Spanning item may span columns, rows, both, or neither while retaining the
|
|
81
|
-
same target.
|
|
82
|
-
|
|
83
|
-
### Responsive contract
|
|
84
|
-
|
|
85
|
-
The `columns` prop decides how many column tracks Grid lays out and whether
|
|
86
|
-
that count changes with the container's width. Other inputs change the result
|
|
87
|
-
only by changing what `columns` has to fit: `width` and `maxWidth` set the
|
|
88
|
-
container width a reflowing shape measures against; an `xstyle`, `className`,
|
|
89
|
-
or `style` that sets the track template (including under a media query)
|
|
90
|
-
replaces the computed one; and a numeric GridSpan wider than the grid's tracks
|
|
91
|
-
makes the browser add implicit tracks to the whole grid, which later items flow
|
|
92
|
-
into. No other prop changes the count.
|
|
93
|
-
|
|
94
|
-
| `columns` | Behavior | Reflows |
|
|
95
|
-
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |
|
|
96
|
-
| `N` (number) | Exactly N tracks that share the row equally at every container width; a child wider than its share widens its track and can push the grid past a narrow container. | never |
|
|
97
|
-
| `{minWidth}` | As many tracks as fit while each stays at least `minWidth` px wide. A container narrower than `minWidth` keeps one `minWidth`-wide track that overflows it. Empty tracks keep their width. | yes |
|
|
98
|
-
| `{minWidth, repeat: 'fit'}` | As above, and empty tracks collapse so the present items stretch across the row. | yes |
|
|
99
|
-
| `{minWidth, max}` | Up to `max` tracks, each at least `minWidth` px and never narrower than an equal share of the row; fewer tracks as the container narrows, down to one track that shrinks to the container rather than overflowing it. `repeat: 'fit'` applies the same way. | yes |
|
|
100
|
-
| omitted, `0`, or negative | One track. | never |
|
|
101
|
-
|
|
102
|
-
- `gap` and `columnGap` count toward the width a reflowing shape has to fit, so
|
|
103
|
-
the full count is reached only when the container has room for the tracks and
|
|
104
|
-
the gaps between them. They never change the count of a numeric `columns`.
|
|
105
|
-
- `height`, `minHeight`, `rowHeight`, `align`, and `justify` size or place the
|
|
106
|
-
container and its items and do not change the column count.
|
|
107
|
-
- GridSpan spans `k` tracks, or the whole row for `'full'`. `'full'` never
|
|
108
|
-
adds tracks. A numeric span wider than the grid's current tracks makes the
|
|
109
|
-
browser add implicit tracks to the grid for the remainder; they persist for
|
|
110
|
-
every row, items placed before and after the span flow into them, and once
|
|
111
|
-
they exist `'full'` covers only the explicit tracks. In a reflowing grid keep
|
|
112
|
-
spans within the smallest count the grid can reach or use `'full'`.
|
|
113
|
-
- For columns that reflow on small screens, use `{minWidth, max}`: `max` is
|
|
114
|
-
what lets the last track shrink to a narrow container, so `{minWidth}` alone
|
|
115
|
-
still overflows a phone narrower than `minWidth`. A numeric `columns` never
|
|
116
|
-
reflows, so a four-up numeric row on a phone renders four narrow tracks, or
|
|
117
|
-
overflows when a child cannot shrink to its share; that is the fixed
|
|
118
|
-
contract, not a defect.
|
|
107
|
+
- **AV1 — Caller content.** Any caller-owned element may participate directly or inside GridSpan; Grid does not inspect or rewrite it.
|
|
108
|
+
- **AV2 — Track count.** Container width, minimum content, gaps, and object-form options may change the rendered responsive count within FR1–FR3.
|
|
109
|
+
- **AV3 — Root styling.** Caller styles may replace track templates or box presentation while preserving component-owned targets and metadata.
|
|
119
110
|
|
|
120
111
|
### Representative states
|
|
121
112
|
|
|
122
|
-
| State
|
|
123
|
-
|
|
|
124
|
-
|
|
|
125
|
-
|
|
|
126
|
-
|
|
|
127
|
-
|
|
|
113
|
+
| State | Required invariant | Allowed variation |
|
|
114
|
+
| --------------------- | ------------------------------------------------------------------------ | ----------------------------------------------------- |
|
|
115
|
+
| fixed Grid | Exactly N explicit `1fr` tracks; no component-owned reflow. | N, content minimums, gaps, and caller styling. |
|
|
116
|
+
| responsive fill | Empty tracks remain allocated while count responds to available width. | Minimum width, cap, content count, and effective gap. |
|
|
117
|
+
| responsive fit | Empty tracks collapse and present items stretch. | Minimum width, cap, content count, and effective gap. |
|
|
118
|
+
| capped narrow Grid | Count drops and one present track can fill a container below `minWidth`. | Container width and caller content. |
|
|
119
|
+
| direct item | Caller content participates without a Grid-owned wrapper. | Any caller-owned element and semantics. |
|
|
120
|
+
| numeric spanning item | The wrapper spans N rows/columns and may cause implicit tracks. | Positive browser-valid span counts. |
|
|
121
|
+
| full spanning item | The wrapper covers the explicit grid from line 1 to -1. | Explicit count and caller content. |
|
|
128
122
|
|
|
129
123
|
### Transformation and precedence order
|
|
130
124
|
|
|
131
|
-
-
|
|
132
|
-
|
|
125
|
+
- **ORD1 — Track shape.** Responsive object with positive `max` → capped fill/fit template; responsive object without positive `max` → uncapped fill/fit template; positive number → fixed `repeat(N, 1fr)`; otherwise → one `1fr` track.
|
|
126
|
+
- **ORD2 — Gap.** Axis gap → uniform gap → zero gap for capped-track arithmetic.
|
|
127
|
+
- **ORD3 — Root composition.** Neutral pass-throughs apply first; component-owned target/reflection and StyleX compose next; `xstyle`, class name, and caller inline style retain their documented styling precedence.
|
|
128
|
+
- **ORD4 — Span.** `'full'` becomes `1 / -1`; a number becomes `span N`; absence leaves browser placement intrinsic.
|
|
133
129
|
|
|
134
130
|
### Performance and resources
|
|
135
131
|
|
|
136
|
-
-
|
|
132
|
+
- **PR1 — CSS-owned layout.** Grid and GridSpan own no state, effect, observer, listener, timer, or JavaScript measurement loop; layout and reflow remain CSS-owned.
|
|
137
133
|
|
|
138
134
|
## Accessibility contract
|
|
139
135
|
|
|
140
|
-
|
|
141
|
-
|
|
136
|
+
- **AR1 — Layout remains nonsemantic.** Grid and GridSpan render `<div>` elements without inventing grid, list, group, or landmark semantics; callers provide semantics when their composition needs them.
|
|
137
|
+
- **AR2 — Order remains perceivable.** DOM order remains the reading and keyboard order in LTR and RTL; visual tracks do not create a second sequence.
|
|
138
|
+
- **AR3 — Content remains reachable.** GridSpan keeps a zero inline minimum so supported shrinkable descendants can remain inside their track; caller content that cannot shrink may still overflow under FR1.
|
|
142
139
|
|
|
143
140
|
## Design relationships
|
|
144
141
|
|
|
145
|
-
|
|
146
|
-
| ---------------- | ------------------------------------------------------------------ | ----------------------------------------- | -------------- | ------------------ |
|
|
147
|
-
| Grid container | Presents the current two-dimensional layout container. | Current source, docs, and family contract | Supporting | FR1 |
|
|
148
|
-
| Spanning item | Optionally changes one item's row or column participation in Grid. | Current source, docs, and family contract | Supporting | FR2, FR3 |
|
|
149
|
-
|
|
150
|
-
Direct caller content is not an additional Grid-owned anatomy part.
|
|
142
|
+
No current component-local or shared design record prescribes a Grid-specific visual representation. Grid and GridSpan own geometry only; caller content owns visible surfaces and states.
|
|
151
143
|
|
|
152
144
|
### Theming anatomy
|
|
153
145
|
|
|
@@ -162,42 +154,32 @@ Direct caller content is not an additional Grid-owned anatomy part.
|
|
|
162
154
|
|
|
163
155
|
## Family and system relationships
|
|
164
156
|
|
|
165
|
-
- `family:layout-primitives` owns
|
|
166
|
-
|
|
167
|
-
- `architecture:component-theming-surface` owns
|
|
168
|
-
|
|
169
|
-
- `architecture:public-component-api` owns the stable prop surface; this
|
|
170
|
-
documentation adds no API.
|
|
157
|
+
- `family:layout-primitives` owns shared spacing, sizing, alignment, and item-participation vocabulary; Grid owns the two-dimensional realization.
|
|
158
|
+
- `architecture:public-component-api` owns root prop, styling, event, ref, and released-type composition.
|
|
159
|
+
- `architecture:component-theming-surface` owns the two exact target mappings and Grid's reflected visual axes.
|
|
160
|
+
- `architecture:component-test-sufficiency` owns bounded, mutation-sensitive evidence selection.
|
|
171
161
|
|
|
172
162
|
## Verification map
|
|
173
163
|
|
|
174
|
-
| Contract
|
|
175
|
-
|
|
|
176
|
-
| FR1
|
|
177
|
-
|
|
|
178
|
-
|
|
|
179
|
-
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
They do not assert both target classes in focused component tests; target
|
|
183
|
-
placement is source-inspected and the global inventory checks the runtime/docs
|
|
184
|
-
relationship.
|
|
164
|
+
| Contract | Verification | Representative states | Mutation or failure expectation | Audit section |
|
|
165
|
+
| --------------- | ------------------------------------------------------------------------- | -------------------------------------------------------- | -------------------------------------------------------------------------------------------------- | ------------------------- |
|
|
166
|
+
| FR1–FR3, ORD1–2 | `Grid.test.tsx` exact track tests and exact-head AuditMatrix story guards | fixed; fill; fit; capped wide/narrow; uniform/axis gap | Track output, count, fill behavior, or gap precedence changes fail exact source or browser checks. | `audit:Grid/behavior` |
|
|
167
|
+
| FR4, FR6, ORD3 | root composition tests, BaseProps lint, theming target tests | DOM/data/ARIA/events; class/style/xstyle; reflected axes | A caller input drops, owned metadata is replaced, or a raw inline track defeats media xstyle. | `audit:Grid/api` |
|
|
168
|
+
| FR5, ORD4, AR3 | `Grid.test.tsx`, long-content play, and AuditMatrix full-span assertion | numeric/full/row/combined spans; long shrinkable child | Span CSS, explicit-grid coverage, target, or bounded shrink behavior changes. | `audit:GridSpan/behavior` |
|
|
169
|
+
| FR7, AR1–AR2 | DOM tests and exact-head LTR/RTL AuditMatrix guards | plain roots; fixed tracks in LTR/RTL | A semantic role appears, DOM order changes, or logical order stops mirroring. | `audit:Grid/a11y-rtl` |
|
|
170
|
+
| Theming anatomy | knowledge validation and `themingTargets.test.ts` | Grid and GridSpan targets | A target loses its semantic owner or the anatomy map drifts. | `audit:Grid/theming` |
|
|
171
|
+
| Documentation | docs typecheck, prop literal/reference tests, and Storybook typecheck | fixed/responsive columns; row height; spans | Docs claim equal widths, automatic numeric reflow, whole implicit rows, or omit public behavior. | `audit:Grid/docs` |
|
|
185
172
|
|
|
186
173
|
## Decision log
|
|
187
174
|
|
|
188
175
|
### DEC-1 — Numeric `columns` stays fixed; reflow uses the existing object form
|
|
189
176
|
|
|
177
|
+
**Reference:** `component:Grid/DEC-1`
|
|
190
178
|
**Decider:** `cixzhang`, `2026-10-11`
|
|
191
179
|
|
|
192
|
-
`columns={N}` means exactly N
|
|
193
|
-
reflows on small screens uses `{minWidth, max?, repeat?}`. Two shapes, one
|
|
194
|
-
responsibility each: the number is the fixed contract, the object form is the
|
|
195
|
-
responsive one, and the record and the docs say so where a caller first meets
|
|
196
|
-
`columns`.
|
|
180
|
+
`columns={N}` means exactly N `1fr` tracks at every width, and a grid that reflows on small screens uses `{minWidth, max?, repeat?}`. The number is the fixed contract; the object form is the responsive contract.
|
|
197
181
|
|
|
198
|
-
Rejected: redefining the number as "at most N"
|
|
199
|
-
grid and needs an opt-out shape); a `{count, isFixed}` shape (duplicates the
|
|
200
|
-
number and the `max` cap).
|
|
182
|
+
Rejected: redefining the number as "at most N" would break released numeric grids; a `{count, isFixed}` shape would duplicate the number and the `max` cap.
|
|
201
183
|
|
|
202
184
|
## Open questions
|
|
203
185
|
|
|
@@ -205,6 +187,4 @@ None.
|
|
|
205
187
|
|
|
206
188
|
## Content boundary
|
|
207
189
|
|
|
208
|
-
This file does not duplicate consumer prop tables
|
|
209
|
-
rules, track algorithms, implementation steps, or system rules. It links to
|
|
210
|
-
their owners.
|
|
190
|
+
This file records verified shipped behavior. It does not duplicate consumer prop tables or examples, prescribe caller content or visuals, approve a new API or target, or store audit scores and run evidence.
|
package/src/Grid/Grid.test.tsx
CHANGED
|
@@ -308,6 +308,28 @@ describe('Grid', () => {
|
|
|
308
308
|
expect(grid).toHaveAttribute('aria-label', 'Product grid');
|
|
309
309
|
});
|
|
310
310
|
|
|
311
|
+
it('keeps component-owned theme metadata over colliding pass-throughs', () => {
|
|
312
|
+
render(
|
|
313
|
+
<Grid
|
|
314
|
+
columns={3}
|
|
315
|
+
gap={4}
|
|
316
|
+
align="end"
|
|
317
|
+
justify="center"
|
|
318
|
+
data-columns="9"
|
|
319
|
+
data-gap="10"
|
|
320
|
+
data-align="start"
|
|
321
|
+
data-justify="stretch"
|
|
322
|
+
data-testid="grid">
|
|
323
|
+
<div>Item</div>
|
|
324
|
+
</Grid>,
|
|
325
|
+
);
|
|
326
|
+
const grid = screen.getByTestId('grid');
|
|
327
|
+
expect(grid).toHaveAttribute('data-columns', '3');
|
|
328
|
+
expect(grid).toHaveAttribute('data-gap', '4');
|
|
329
|
+
expect(grid).toHaveAttribute('data-align', 'end');
|
|
330
|
+
expect(grid).toHaveAttribute('data-justify', 'center');
|
|
331
|
+
});
|
|
332
|
+
|
|
311
333
|
it('renders children correctly', () => {
|
|
312
334
|
render(
|
|
313
335
|
<Grid columns={3} data-testid="grid">
|
package/src/Grid/Grid.tsx
CHANGED
|
@@ -31,13 +31,14 @@ export type GridAlignment = 'start' | 'center' | 'end' | 'stretch';
|
|
|
31
31
|
/**
|
|
32
32
|
* Column configuration for Grid.
|
|
33
33
|
*
|
|
34
|
-
* A number means exactly N
|
|
35
|
-
* `columns={4}` on a phone renders four narrow tracks.
|
|
34
|
+
* A number means exactly N `1fr` tracks at every width; it never reflows, so
|
|
35
|
+
* `columns={4}` on a phone renders four narrow tracks. A child's minimum
|
|
36
|
+
* content can widen its track beyond an equal fraction. For columns that reflow
|
|
36
37
|
* on small screens, use the object form: `{minWidth: 240, max: 4}` renders at
|
|
37
38
|
* most four columns, each at least 240px, and fewer when the container is
|
|
38
39
|
* narrower.
|
|
39
40
|
*
|
|
40
|
-
* - `number` — exactly N
|
|
41
|
+
* - `number` — exactly N `1fr` tracks (e.g. `columns={3}`); never reflows
|
|
41
42
|
* - `object` — responsive columns based on minimum child width:
|
|
42
43
|
* - `minWidth` — minimum width (px) for each column track
|
|
43
44
|
* - `repeat` — `'fill'` (default) preserves empty tracks for consistent widths;
|
|
@@ -59,10 +60,10 @@ export interface GridProps extends BaseProps<HTMLDivElement> {
|
|
|
59
60
|
/** Ref forwarded to the root element */
|
|
60
61
|
ref?: React.Ref<HTMLDivElement>;
|
|
61
62
|
/**
|
|
62
|
-
* Column configuration. A number
|
|
63
|
-
* reflows;
|
|
64
|
-
* `{minWidth, max}`.
|
|
65
|
-
* - `number` — exactly N
|
|
63
|
+
* Column configuration. A number creates exactly N `1fr` tracks and never
|
|
64
|
+
* reflows; a child's minimum content may widen its track. For columns that
|
|
65
|
+
* reflow on small screens, use `{minWidth, max}`.
|
|
66
|
+
* - `number` — exactly N `1fr` tracks at every width
|
|
66
67
|
* - `{minWidth, max?, repeat?}` — responsive columns with a px floor and an
|
|
67
68
|
* optional cap
|
|
68
69
|
*
|
|
@@ -455,6 +456,7 @@ export function Grid({
|
|
|
455
456
|
return (
|
|
456
457
|
<div
|
|
457
458
|
ref={ref}
|
|
459
|
+
{...props}
|
|
458
460
|
{...mergeProps(
|
|
459
461
|
themeProps('grid', {columns: columnsVariant, gap, align, justify}),
|
|
460
462
|
stylex.props(
|
|
@@ -470,8 +472,7 @@ export function Grid({
|
|
|
470
472
|
),
|
|
471
473
|
className,
|
|
472
474
|
{...style, ...inlineStyle},
|
|
473
|
-
)}
|
|
474
|
-
{...props}>
|
|
475
|
+
)}>
|
|
475
476
|
{children}
|
|
476
477
|
</div>
|
|
477
478
|
);
|
|
@@ -19,7 +19,7 @@ export const docs = {
|
|
|
19
19
|
{
|
|
20
20
|
name: 'columns',
|
|
21
21
|
type: "number | 'full'",
|
|
22
|
-
description: "Columns to span; use `'full'` to span
|
|
22
|
+
description: "Columns to span; use `'full'` to span all explicit columns.",
|
|
23
23
|
},
|
|
24
24
|
{
|
|
25
25
|
name: 'rows',
|
|
@@ -43,7 +43,7 @@ export const docsZh = {
|
|
|
43
43
|
{
|
|
44
44
|
name: 'columns',
|
|
45
45
|
type: "number | 'full'",
|
|
46
|
-
description: "要跨越的列数;使用 `'full'`
|
|
46
|
+
description: "要跨越的列数;使用 `'full'` 跨越所有显式列。",
|
|
47
47
|
},
|
|
48
48
|
{
|
|
49
49
|
name: 'rows',
|
|
@@ -64,7 +64,7 @@ export const docsDense = {
|
|
|
64
64
|
displayName: 'Grid Span',
|
|
65
65
|
description: 'Grid item spanning multiple columns/rows.',
|
|
66
66
|
propDescriptions: {
|
|
67
|
-
columns: "Columns to span; 'full' spans
|
|
67
|
+
columns: "Columns to span; 'full' spans all explicit columns.",
|
|
68
68
|
rows: 'Rows to span.',
|
|
69
69
|
children: 'Content.',
|
|
70
70
|
},
|
package/src/Grid/GridSpan.tsx
CHANGED
|
@@ -25,7 +25,7 @@ export interface GridSpanProps extends BaseProps<HTMLDivElement> {
|
|
|
25
25
|
/**
|
|
26
26
|
* Number of columns to span, or 'full' to span all columns.
|
|
27
27
|
* - Number: `grid-column: span N`
|
|
28
|
-
* - 'full': `grid-column: 1 / -1` (spans
|
|
28
|
+
* - 'full': `grid-column: 1 / -1` (spans all explicit columns)
|
|
29
29
|
*/
|
|
30
30
|
columns?: number | 'full';
|
|
31
31
|
|
package/src/Icon/Icon.doc.mjs
CHANGED
|
@@ -23,6 +23,42 @@ export const docs = {
|
|
|
23
23
|
'pictogram',
|
|
24
24
|
'graphic',
|
|
25
25
|
'vector',
|
|
26
|
+
'arrow',
|
|
27
|
+
'chevron',
|
|
28
|
+
'caret',
|
|
29
|
+
'checkmark',
|
|
30
|
+
'cross',
|
|
31
|
+
'gear',
|
|
32
|
+
'cog',
|
|
33
|
+
'broom',
|
|
34
|
+
'sparkle',
|
|
35
|
+
'sparkles',
|
|
36
|
+
'star',
|
|
37
|
+
'heart',
|
|
38
|
+
'bell',
|
|
39
|
+
'trash',
|
|
40
|
+
'pencil',
|
|
41
|
+
'magnifyingglass',
|
|
42
|
+
'paperclip',
|
|
43
|
+
'house',
|
|
44
|
+
'flame',
|
|
45
|
+
'rocket',
|
|
46
|
+
'lightning',
|
|
47
|
+
'bolt',
|
|
48
|
+
'globe',
|
|
49
|
+
'sun',
|
|
50
|
+
'moon',
|
|
51
|
+
'bookmark',
|
|
52
|
+
'thumbsup',
|
|
53
|
+
'smiley',
|
|
54
|
+
'emoji',
|
|
55
|
+
'lock',
|
|
56
|
+
'eye',
|
|
57
|
+
'cloud',
|
|
58
|
+
'hourglass',
|
|
59
|
+
'trophy',
|
|
60
|
+
'gift',
|
|
61
|
+
'camera',
|
|
26
62
|
],
|
|
27
63
|
playground: {
|
|
28
64
|
// `icon` is required and its type can't be auto-generated, so the
|
|
@@ -171,7 +171,7 @@ defineTheme({
|
|
|
171
171
|
code: `// When the shape itself is wrong, hand the theme a component. It receives
|
|
172
172
|
// {state, size, isDisabled, children} and nothing else.
|
|
173
173
|
//
|
|
174
|
-
// Use theme tokens, never raw values — run \`
|
|
174
|
+
// Use theme tokens, never raw values — run \`astryx docs tokens\` for the
|
|
175
175
|
// full set. Color: --color-accent, --color-on-accent, --color-border,
|
|
176
176
|
// --color-border-emphasized, --color-background-surface,
|
|
177
177
|
// --color-background-muted. Radius: --radius-inner, --radius-full.
|
|
@@ -236,7 +236,7 @@ defineTheme({name: 'brand', indicators: {check: RadioIndicator}});`,
|
|
|
236
236
|
{
|
|
237
237
|
guidance: true,
|
|
238
238
|
description:
|
|
239
|
-
'Use theme tokens for every color, radius, and border width in a replacement. Run `
|
|
239
|
+
'Use theme tokens for every color, radius, and border width in a replacement. Run `astryx docs tokens` for the set.',
|
|
240
240
|
},
|
|
241
241
|
{
|
|
242
242
|
guidance: true,
|
|
@@ -297,7 +297,7 @@ export const docsDense = {
|
|
|
297
297
|
{
|
|
298
298
|
guidance: true,
|
|
299
299
|
description:
|
|
300
|
-
'Use theme tokens for every color, radius, and border width in a replacement. Run `
|
|
300
|
+
'Use theme tokens for every color, radius, and border width in a replacement. Run `astryx docs tokens` for the set.',
|
|
301
301
|
},
|
|
302
302
|
{
|
|
303
303
|
guidance: true,
|
|
@@ -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: {
|
package/src/Markdown/parser.ts
CHANGED
|
@@ -1718,8 +1718,14 @@ interface DelimiterRun {
|
|
|
1718
1718
|
readonly canClose: boolean;
|
|
1719
1719
|
}
|
|
1720
1720
|
|
|
1721
|
-
|
|
1722
|
-
|
|
1721
|
+
// Built at runtime, not written as literals: for targets without property
|
|
1722
|
+
// escapes, or when no browserslist is set, Babel's
|
|
1723
|
+
// transform-unicode-property-regex rewrites a `\p{…}` literal, and the copy
|
|
1724
|
+
// bundled with Next.js lacks the Unicode data it needs, so a source build fails
|
|
1725
|
+
// with "Unknown property". Literals are safe once Next's bundled Babel ships
|
|
1726
|
+
// that data.
|
|
1727
|
+
const UNICODE_WHITESPACE = new RegExp('^[\\t\\n\\f\\r\\p{Zs}]$', 'u');
|
|
1728
|
+
const UNICODE_PUNCTUATION = new RegExp('^[\\p{P}\\p{S}]$', 'u');
|
|
1723
1729
|
|
|
1724
1730
|
/** The character before `index` (a whole code point), if any. */
|
|
1725
1731
|
function characterBefore(text: string, index: number): string | undefined {
|
|
@@ -59,13 +59,21 @@ function fail(message: string): never {
|
|
|
59
59
|
throw new TypeError(`Markdown heading links: ${message}`);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
// Built at runtime, not written as a literal: for targets without property
|
|
63
|
+
// escapes, or when no browserslist is set, Babel's
|
|
64
|
+
// transform-unicode-property-regex rewrites a `\p{…}` literal, and the copy
|
|
65
|
+
// bundled with Next.js lacks the Unicode data it needs, so a source build fails
|
|
66
|
+
// with "Unknown property". A literal is safe once Next's bundled Babel ships
|
|
67
|
+
// that data.
|
|
68
|
+
const NON_SLUG_CHARACTERS = new RegExp('[^\\p{Letter}\\p{Number}]+', 'gu');
|
|
69
|
+
|
|
62
70
|
function headingSlug(value: string): string {
|
|
63
71
|
return value
|
|
64
72
|
.normalize('NFKC')
|
|
65
73
|
.trim()
|
|
66
74
|
.toLowerCase()
|
|
67
75
|
.replace(/['"]/gu, '')
|
|
68
|
-
.replace(
|
|
76
|
+
.replace(NON_SLUG_CHARACTERS, '-')
|
|
69
77
|
.replace(/^-+|-+$/gu, '');
|
|
70
78
|
}
|
|
71
79
|
|
|
@@ -7,7 +7,7 @@ export const docs = {
|
|
|
7
7
|
displayName: 'Metadata List',
|
|
8
8
|
group: 'MetadataList',
|
|
9
9
|
category: 'Table & List',
|
|
10
|
-
keywords: ["metadata","description","definition","keyvalue","properties","details","attributes","summary"],
|
|
10
|
+
keywords: ["metadata","description","definition","keyvalue","properties","details","attributes","summary","descriptionlist","descriptions"],
|
|
11
11
|
theming: {
|
|
12
12
|
targets: [
|
|
13
13
|
{
|
|
@@ -9,11 +9,15 @@
|
|
|
9
9
|
* SYNC: When MoreMenu.tsx changes, update tests to match new behavior
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import {describe, it, expect, vi, beforeEach} from 'vitest';
|
|
12
|
+
import {describe, it, expect, vi, beforeAll, beforeEach} from 'vitest';
|
|
13
13
|
import {render, screen, fireEvent, waitFor} from '@testing-library/react';
|
|
14
14
|
import userEvent from '@testing-library/user-event';
|
|
15
15
|
import {MoreMenu} from './MoreMenu';
|
|
16
16
|
import {DropdownMenu} from '../DropdownMenu/DropdownMenu';
|
|
17
|
+
import {warmMenuBottomSheet} from '../DropdownMenu/__tests__/warmMenuBottomSheet';
|
|
18
|
+
|
|
19
|
+
// DropdownMenu's touch sheet is loaded lazily; resolve it once up front.
|
|
20
|
+
beforeAll(warmMenuBottomSheet, 20000);
|
|
17
21
|
|
|
18
22
|
// Mock showPopover and hidePopover methods since they're not implemented in jsdom
|
|
19
23
|
beforeEach(() => {
|