@astryxdesign/cli 0.3.0-canary.e9fc2bb → 0.3.0-canary.ee705d8

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.
Files changed (30) hide show
  1. package/api/template/template.test.mjs +26 -0
  2. package/assets/codemods/transforms/next/__tests__/next-codemods.test.mjs +92 -0
  3. package/assets/codemods/transforms/next/index.mjs +11 -1
  4. package/assets/codemods/transforms/next/rename-dropdown-menu-radio-dot-target.mjs +152 -0
  5. package/assets/codemods/transforms/v0.3.0/__tests__/migrate-table-rowexpansion-to-tree.test.mjs +201 -0
  6. package/assets/codemods/transforms/v0.3.0/index.mjs +8 -0
  7. package/assets/codemods/transforms/v0.3.0/migrate-table-rowexpansion-to-tree.mjs +214 -0
  8. package/assets/docs/getting-started.doc.mjs +3 -3
  9. package/assets/templates/blocks/components/Stepper/StepperHorizontal.doc.mjs +14 -0
  10. package/assets/templates/blocks/components/Stepper/StepperHorizontal.tsx +24 -0
  11. package/assets/templates/blocks/components/Stepper/StepperIndicatorModes.doc.mjs +14 -0
  12. package/assets/templates/blocks/components/Stepper/StepperIndicatorModes.tsx +68 -0
  13. package/assets/templates/blocks/components/Stepper/StepperMultiStepForm.doc.mjs +14 -0
  14. package/assets/templates/blocks/components/Stepper/StepperMultiStepForm.tsx +92 -0
  15. package/assets/templates/blocks/components/Stepper/StepperOnTrackVertical.doc.mjs +14 -0
  16. package/assets/templates/blocks/components/Stepper/StepperOnTrackVertical.tsx +41 -0
  17. package/assets/templates/blocks/components/Stepper/StepperShowcase.doc.mjs +15 -0
  18. package/assets/templates/blocks/components/Stepper/StepperShowcase.tsx +25 -0
  19. package/assets/templates/blocks/components/Stepper/StepperStatus.doc.mjs +14 -0
  20. package/assets/templates/blocks/components/Stepper/StepperStatus.tsx +50 -0
  21. package/assets/templates/blocks/components/Stepper/StepperVerticalOnboarding.doc.mjs +14 -0
  22. package/assets/templates/blocks/components/Stepper/StepperVerticalOnboarding.tsx +40 -0
  23. package/assets/templates/blocks/components/Table/TableRowExpansionTable.tsx +61 -58
  24. package/assets/templates/blocks/components/TextArea/TextAreaStates.tsx +1 -1
  25. package/assets/templates/themes/neutral/neutralTheme.ts +4 -1
  26. package/authoring/doctypes/base/type.ts +15 -0
  27. package/clients/cli/commands/build-theme.registry.test.mjs +14 -1
  28. package/foundation/discovery/template-adapter.d.mts +6 -3
  29. package/foundation/discovery/template-adapter.mjs +30 -14
  30. package/package.json +9 -9
@@ -0,0 +1,214 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file Codemod: Migrate tree-mode useTableRowExpansion to the tree plugin
5
+ *
6
+ * useTableRowExpansion is now a detail-panel plugin (renderExpanded). Its old
7
+ * tree mode (child rows that reuse the parent columns) moved to
8
+ * useTableTreeData + useTableTreeState, and useTableRowExpansionState was
9
+ * removed. This codemod rewrites the standard tree pattern:
10
+ *
11
+ * const {data, expansionConfig} = useTableRowExpansionState({
12
+ * baseData, getChildren, getRowKey, expandedKeys, setExpandedKeys,
13
+ * });
14
+ * const expansion = useTableRowExpansion(expansionConfig);
15
+ *
16
+ * into:
17
+ *
18
+ * const {visibleData: data, treeConfig} = useTableTreeState({
19
+ * data: baseData, childrenKey: 'children', idKey: getRowKey, ...
20
+ * });
21
+ * const expansion = useTableTreeData(treeConfig);
22
+ *
23
+ * Files that use the new detail-panel API (renderExpanded, no
24
+ * useTableRowExpansionState import) are left untouched.
25
+ */
26
+
27
+ export const meta = {
28
+ title: 'Migrate tree-mode useTableRowExpansion to the tree plugin',
29
+ description:
30
+ 'Rewrites the removed useTableRowExpansionState tree pattern to useTableTreeState + useTableTreeData. Detail-panel usage (renderExpanded) is left untouched.',
31
+ pr: '#4612',
32
+ };
33
+
34
+ const IMPORT_SOURCES = new Set([
35
+ '@astryxdesign/core',
36
+ '@astryxdesign/core/Table',
37
+ '@xds/core',
38
+ '@xds/core/Table',
39
+ ]);
40
+
41
+ /**
42
+ * @param {import('../../../../authoring/codemod/type').AstryxCodemodFile} file
43
+ * @param {import('../../../../authoring/codemod/type').CodemodTransformApi} api
44
+ * @returns {string | null | undefined}
45
+ */
46
+ export default function transformer(file, api) {
47
+ const j = api.jscodeshift;
48
+ const root = j(file.source);
49
+
50
+ // Only act on files importing the removed state hook. Detail-panel-only
51
+ // usage (useTableRowExpansion alone) is the new API and must be left alone.
52
+ let stateLocal = null;
53
+ let pluginLocal = null;
54
+ /** @type {any[]} */
55
+ const importPaths = [];
56
+ root.find(j.ImportDeclaration).forEach((/** @type {any} */ path) => {
57
+ if (!IMPORT_SOURCES.has(path.node.source.value)) return;
58
+ for (const spec of path.node.specifiers ?? []) {
59
+ if (spec.type !== 'ImportSpecifier') continue;
60
+ if (spec.imported.name === 'useTableRowExpansionState') {
61
+ stateLocal = spec.local?.name ?? spec.imported.name;
62
+ importPaths.push(path);
63
+ }
64
+ if (spec.imported.name === 'useTableRowExpansion') {
65
+ pluginLocal = spec.local?.name ?? spec.imported.name;
66
+ }
67
+ }
68
+ });
69
+ if (!stateLocal) return undefined;
70
+
71
+ let hasChanges = false;
72
+
73
+ // --- 1. Rewrite the state hook call + its config object ---
74
+ root
75
+ .find(j.CallExpression, {callee: {name: stateLocal}})
76
+ .forEach((/** @type {any} */ path) => {
77
+ const arg = path.node.arguments[0];
78
+ if (!arg || arg.type !== 'ObjectExpression') return;
79
+
80
+ /** @type {any} */
81
+ let getChildrenValue = null;
82
+ const nextProps = [];
83
+ for (const prop of arg.properties) {
84
+ const key =
85
+ prop.key?.name ?? (prop.key?.value ? String(prop.key.value) : null);
86
+ if (key === 'baseData') {
87
+ nextProps.push(j.property('init', j.identifier('data'), prop.value));
88
+ } else if (key === 'getChildren') {
89
+ getChildrenValue = prop.value;
90
+ // childrenKey is emitted below (default 'children').
91
+ } else if (key === 'getRowKey') {
92
+ nextProps.push(j.property('init', j.identifier('idKey'), prop.value));
93
+ } else if (key === 'getIsItemExpandable') {
94
+ nextProps.push(
95
+ j.property('init', j.identifier('isItemExpandable'), prop.value),
96
+ );
97
+ } else if (key === 'expandedKeys' || key === 'setExpandedKeys') {
98
+ // The tree state hook owns expansion internally (uncontrolled) or
99
+ // via expandedIds/onExpandedIdsChange (controlled). The 1:1
100
+ // controlled mapping is not mechanical, so these are dropped and a
101
+ // guidance comment is attached below.
102
+ continue;
103
+ } else {
104
+ nextProps.push(prop);
105
+ }
106
+ }
107
+
108
+ // childrenKey: derive the literal when getChildren is the canonical
109
+ // `item => item.children` / `item.children ?? []`; otherwise keep the
110
+ // default and let the guidance comment flag it.
111
+ nextProps.splice(
112
+ 1,
113
+ 0,
114
+ j.property('init', j.identifier('childrenKey'), j.literal('children')),
115
+ );
116
+
117
+ arg.properties = nextProps;
118
+ path.node.callee = j.identifier('useTableTreeState');
119
+ hasChanges = true;
120
+
121
+ // Rename the destructured result: data -> visibleData (aliased back to
122
+ // the local name), expansionConfig -> treeConfig.
123
+ const declarator = path.parent.node;
124
+ if (
125
+ declarator.type === 'VariableDeclarator' &&
126
+ declarator.id.type === 'ObjectPattern'
127
+ ) {
128
+ for (const p of declarator.id.properties) {
129
+ if (p.type !== 'ObjectProperty' && p.type !== 'Property') continue;
130
+ const kName = p.key?.name;
131
+ if (kName === 'data') {
132
+ // {data} -> {visibleData: data}
133
+ p.key = j.identifier('visibleData');
134
+ if (p.shorthand) {
135
+ p.shorthand = false;
136
+ p.value = j.identifier('data');
137
+ }
138
+ } else if (kName === 'expansionConfig') {
139
+ // {expansionConfig} -> {treeConfig} (keep it shorthand).
140
+ p.key = j.identifier('treeConfig');
141
+ if (p.value?.type === 'Identifier') {
142
+ p.value = j.identifier('treeConfig');
143
+ p.shorthand = true;
144
+ }
145
+ }
146
+ }
147
+ }
148
+
149
+ // Attach a one-line migration note as a leading comment on the
150
+ // statement, so a human confirms the expansion-state wiring.
151
+ const stmt = path.parent.parent.node;
152
+ if (stmt && !stmt.comments) {
153
+ stmt.comments = [
154
+ j.commentLine(
155
+ ' astryx-migration: verify tree expansion state. useTableTreeState',
156
+ true,
157
+ false,
158
+ ),
159
+ j.commentLine(
160
+ ' is uncontrolled by default; pass defaultExpandedIds, or',
161
+ true,
162
+ false,
163
+ ),
164
+ j.commentLine(
165
+ ' expandedIds + onExpandedIdsChange for the old controlled set.',
166
+ true,
167
+ false,
168
+ ),
169
+ ];
170
+ }
171
+ void getChildrenValue;
172
+ });
173
+
174
+ // --- 2. Swap the plugin call: useTableRowExpansion(cfg) -> useTableTreeData(cfg) ---
175
+ if (pluginLocal) {
176
+ root
177
+ .find(j.CallExpression, {callee: {name: pluginLocal}})
178
+ .forEach((/** @type {any} */ path) => {
179
+ // Rename the argument identifier expansionConfig -> treeConfig.
180
+ const a = path.node.arguments[0];
181
+ if (a && a.type === 'Identifier' && a.name === 'expansionConfig') {
182
+ path.node.arguments[0] = j.identifier('treeConfig');
183
+ }
184
+ path.node.callee = j.identifier('useTableTreeData');
185
+ hasChanges = true;
186
+ });
187
+ }
188
+
189
+ if (!hasChanges) return undefined;
190
+
191
+ // --- 3. Fix imports: drop the removed hooks, add the tree hooks ---
192
+ for (const path of importPaths) {
193
+ const specs = path.node.specifiers.filter(
194
+ (/** @type {any} */ s) =>
195
+ !(
196
+ s.type === 'ImportSpecifier' &&
197
+ (s.imported.name === 'useTableRowExpansionState' ||
198
+ s.imported.name === 'useTableRowExpansion')
199
+ ),
200
+ );
201
+ const existing = new Set(
202
+ specs.map((/** @type {any} */ s) => s.imported?.name),
203
+ );
204
+ if (!existing.has('useTableTreeState')) {
205
+ specs.push(j.importSpecifier(j.identifier('useTableTreeState')));
206
+ }
207
+ if (!existing.has('useTableTreeData')) {
208
+ specs.push(j.importSpecifier(j.identifier('useTableTreeData')));
209
+ }
210
+ path.node.specifiers = specs;
211
+ }
212
+
213
+ return root.toSource({quote: 'single'});
214
+ }
@@ -21,7 +21,7 @@ export const docs = {
21
21
  type: 'code',
22
22
  lang: 'text',
23
23
  label: 'Paste this into your AI',
24
- code: 'Install @astryxdesign/core, @astryxdesign/theme-neutral, and @astryxdesign/cli in this project, then run `npx @astryxdesign/cli init` to set up agent docs. Read the generated files to learn the conventions.',
24
+ code: 'Install @astryxdesign/core, @stylexjs/stylex, @astryxdesign/theme-neutral, and @astryxdesign/cli in this project, then run `npx @astryxdesign/cli init` to set up agent docs. Read the generated files to learn the conventions.',
25
25
  },
26
26
  ],
27
27
  },
@@ -34,13 +34,13 @@ export const docs = {
34
34
  },
35
35
  {
36
36
  type: 'prose',
37
- text: 'Add the core package, a theme, and the CLI to your existing project.',
37
+ text: 'Add the core package and its `@stylexjs/stylex` peer dependency, plus a theme and the CLI.',
38
38
  },
39
39
  {
40
40
  type: 'code',
41
41
  lang: 'bash',
42
42
  label: 'Terminal',
43
- code: `npm install @astryxdesign/core @astryxdesign/theme-neutral @astryxdesign/cli`,
43
+ code: `npm install @astryxdesign/core @stylexjs/stylex @astryxdesign/theme-neutral @astryxdesign/cli`,
44
44
  },
45
45
  {
46
46
  type: 'prose',
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Stepper',
7
+ name: 'Stepper — Horizontal Progress',
8
+ displayName: 'Stepper — Horizontal Progress',
9
+ description:
10
+ 'A horizontal separated stepper: each step owns a segment of the progress bar above its label. Filled segments track how far the flow has progressed.',
11
+ isReady: true,
12
+ aspectRatio: 16 / 9,
13
+ componentsUsed: ['Stepper'],
14
+ };
@@ -0,0 +1,24 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {Stepper, Step} from '@astryxdesign/lab';
7
+
8
+ export default function StepperHorizontal() {
9
+ const [active, setActive] = useState(1);
10
+ return (
11
+ <div style={{width: '100%', maxWidth: 600}}>
12
+ <Stepper
13
+ activeStep={active}
14
+ orientation="horizontal"
15
+ onStepClick={setActive}>
16
+ <Step step={0} label="Workspace" />
17
+ <Step step={1} label="Team" />
18
+ <Step step={2} label="Integrations" />
19
+ <Step step={3} label="Import" />
20
+ <Step step={4} label="Launch" />
21
+ </Stepper>
22
+ </div>
23
+ );
24
+ }
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Stepper',
7
+ name: 'Stepper — Indicator Modes',
8
+ displayName: 'Stepper — Indicator Modes',
9
+ description:
10
+ 'The indicator prop side by side: auto (check when done, ring when current, number ahead), always-number, and a custom icon per step.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['Stepper', 'Text', 'Icon'],
14
+ };
@@ -0,0 +1,68 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {Stepper, Step} from '@astryxdesign/lab';
7
+ import {Text} from '@astryxdesign/core/Text';
8
+ import {Icon} from '@astryxdesign/core/Icon';
9
+
10
+ export default function StepperIndicatorModes() {
11
+ const [active, setActive] = useState(2);
12
+ return (
13
+ <div style={{display: 'flex', gap: 48, flexWrap: 'wrap'}}>
14
+ <div style={{maxWidth: 220}}>
15
+ <Text type="label">Auto</Text>
16
+ <Stepper
17
+ activeStep={active}
18
+ orientation="vertical"
19
+ onStepClick={setActive}>
20
+ <Step step={0} label="Account" />
21
+ <Step step={1} label="Profile" />
22
+ <Step step={2} label="Settings" />
23
+ <Step step={3} label="Review" />
24
+ </Stepper>
25
+ </div>
26
+ <div style={{maxWidth: 220}}>
27
+ <Text type="label">Number</Text>
28
+ <Stepper
29
+ activeStep={active}
30
+ orientation="vertical"
31
+ onStepClick={setActive}>
32
+ <Step step={0} label="Account" indicator="number" />
33
+ <Step step={1} label="Profile" indicator="number" />
34
+ <Step step={2} label="Settings" indicator="number" />
35
+ <Step step={3} label="Review" indicator="number" />
36
+ </Stepper>
37
+ </div>
38
+ <div style={{maxWidth: 220}}>
39
+ <Text type="label">Custom icon</Text>
40
+ <Stepper
41
+ activeStep={active}
42
+ orientation="vertical"
43
+ onStepClick={setActive}>
44
+ <Step
45
+ step={0}
46
+ label="Account"
47
+ icon={<Icon icon="info" size="sm" />}
48
+ />
49
+ <Step
50
+ step={1}
51
+ label="Profile"
52
+ icon={<Icon icon="search" size="sm" />}
53
+ />
54
+ <Step
55
+ step={2}
56
+ label="Settings"
57
+ icon={<Icon icon="wrench" size="sm" />}
58
+ />
59
+ <Step
60
+ step={3}
61
+ label="Review"
62
+ icon={<Icon icon="check" size="sm" />}
63
+ />
64
+ </Stepper>
65
+ </div>
66
+ </div>
67
+ );
68
+ }
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Stepper',
7
+ name: 'Stepper — Multi-Step Form',
8
+ displayName: 'Stepper — Multi-Step Form',
9
+ description:
10
+ 'A vertical stepper driving a multi-step form. Each step renders its own fields in the content slot for the active step, with Back/Continue buttons advancing activeStep.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['Stepper', 'TextInput', 'Button', 'Text'],
14
+ };
@@ -0,0 +1,92 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {Stepper, Step} from '@astryxdesign/lab';
7
+ import {TextInput} from '@astryxdesign/core/TextInput';
8
+ import {Button} from '@astryxdesign/core/Button';
9
+ import {Text} from '@astryxdesign/core/Text';
10
+
11
+ export default function StepperMultiStepForm() {
12
+ const [active, setActive] = useState(0);
13
+ return (
14
+ <div style={{width: '100%', maxWidth: 480}}>
15
+ <Stepper
16
+ activeStep={active}
17
+ orientation="vertical"
18
+ onStepClick={setActive}>
19
+ <Step step={0} label="Project details" indicator="number">
20
+ {active === 0 && (
21
+ <div style={{display: 'flex', flexDirection: 'column', gap: 12}}>
22
+ <TextInput
23
+ label="Project name"
24
+ placeholder="My awesome project"
25
+ value=""
26
+ />
27
+ <TextInput
28
+ label="Repository URL"
29
+ placeholder="https://github.com/..."
30
+ value=""
31
+ />
32
+ <div>
33
+ <Button
34
+ label="Continue"
35
+ variant="primary"
36
+ onClick={() => setActive(1)}
37
+ />
38
+ </div>
39
+ </div>
40
+ )}
41
+ </Step>
42
+ <Step step={1} label="Environment" indicator="number">
43
+ {active === 1 && (
44
+ <div style={{display: 'flex', flexDirection: 'column', gap: 12}}>
45
+ <TextInput label="Node version" placeholder="20" value="" />
46
+ <TextInput
47
+ label="Build command"
48
+ placeholder="npm run build"
49
+ value=""
50
+ />
51
+ <div style={{display: 'flex', gap: 8}}>
52
+ <Button
53
+ label="Back"
54
+ variant="secondary"
55
+ onClick={() => setActive(0)}
56
+ />
57
+ <Button
58
+ label="Continue"
59
+ variant="primary"
60
+ onClick={() => setActive(2)}
61
+ />
62
+ </div>
63
+ </div>
64
+ )}
65
+ </Step>
66
+ <Step step={2} label="Deploy" indicator="number">
67
+ {active === 2 && (
68
+ <div style={{display: 'flex', flexDirection: 'column', gap: 12}}>
69
+ <Text type="body">
70
+ Ready to deploy. This creates a production build and pushes to
71
+ your configured hosting.
72
+ </Text>
73
+ <div style={{display: 'flex', gap: 8}}>
74
+ <Button
75
+ label="Back"
76
+ variant="secondary"
77
+ onClick={() => setActive(1)}
78
+ />
79
+ <Button
80
+ label="Deploy now"
81
+ variant="primary"
82
+ onClick={() => setActive(3)}
83
+ />
84
+ </div>
85
+ </div>
86
+ )}
87
+ </Step>
88
+ <Step step={3} label="Done" indicator="number" />
89
+ </Stepper>
90
+ </div>
91
+ );
92
+ }
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Stepper',
7
+ name: 'Stepper — On-Track Vertical',
8
+ displayName: 'Stepper — On-Track Vertical',
9
+ description:
10
+ 'The on-track layout in vertical orientation: indicators sit inline on a continuous connector rail, with each label and description beside its node.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['Stepper'],
14
+ };
@@ -0,0 +1,41 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {Stepper, Step} from '@astryxdesign/lab';
7
+
8
+ export default function StepperOnTrackVertical() {
9
+ const [active, setActive] = useState(2);
10
+ return (
11
+ <div style={{width: '100%', maxWidth: 400}}>
12
+ <Stepper
13
+ activeStep={active}
14
+ orientation="vertical"
15
+ indicatorPosition="on-track"
16
+ onStepClick={setActive}>
17
+ <Step
18
+ step={0}
19
+ label="Create workspace"
20
+ description="Name and configure your workspace"
21
+ />
22
+ <Step
23
+ step={1}
24
+ label="Invite team members"
25
+ description="Add collaborators by email"
26
+ />
27
+ <Step
28
+ step={2}
29
+ label="Set up integrations"
30
+ description="Connect Slack, GitHub, Jira"
31
+ />
32
+ <Step
33
+ step={3}
34
+ label="Import data"
35
+ description="Bring in existing projects"
36
+ />
37
+ <Step step={4} label="Launch" description="Go live with your team" />
38
+ </Stepper>
39
+ </div>
40
+ );
41
+ }
@@ -0,0 +1,15 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Stepper',
7
+ name: 'Stepper — Checkout Progress',
8
+ displayName: 'Stepper — Checkout Progress',
9
+ description:
10
+ 'A horizontal on-track stepper for a checkout flow: numbered nodes sit on a continuous connector, with completed and current steps filled. Click any step to jump.',
11
+ isReady: true,
12
+ isShowcase: true,
13
+ aspectRatio: 16 / 9,
14
+ componentsUsed: ['Stepper'],
15
+ };
@@ -0,0 +1,25 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {Stepper, Step} from '@astryxdesign/lab';
7
+
8
+ export default function StepperShowcase() {
9
+ const [active, setActive] = useState(2);
10
+ return (
11
+ <div style={{width: '100%', maxWidth: 640}}>
12
+ <Stepper
13
+ activeStep={active}
14
+ orientation="horizontal"
15
+ indicatorPosition="on-track"
16
+ onStepClick={setActive}>
17
+ <Step step={0} label="Cart" indicator="number" />
18
+ <Step step={1} label="Shipping" indicator="number" />
19
+ <Step step={2} label="Payment" indicator="number" />
20
+ <Step step={3} label="Review" indicator="number" />
21
+ <Step step={4} label="Confirm" indicator="number" />
22
+ </Stepper>
23
+ </div>
24
+ );
25
+ }
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Stepper',
7
+ name: 'Stepper — Validation Status',
8
+ displayName: 'Stepper — Validation Status',
9
+ description:
10
+ 'Semantic status per step in a verification flow: success shows a green check, error a red glyph, accent the in-progress step. Status sets the indicator color and glyph only — never the connector — and is announced to assistive tech as text.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['Stepper'],
14
+ };
@@ -0,0 +1,50 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ 'use client';
4
+
5
+ import {useState} from 'react';
6
+ import {Stepper, Step} from '@astryxdesign/lab';
7
+
8
+ export default function StepperStatus() {
9
+ const [active, setActive] = useState(3);
10
+ return (
11
+ <div style={{width: '100%', maxWidth: 400}}>
12
+ <Stepper
13
+ activeStep={active}
14
+ orientation="vertical"
15
+ onStepClick={setActive}>
16
+ <Step
17
+ step={0}
18
+ label="Email verified"
19
+ description="you@example.com"
20
+ status="success"
21
+ />
22
+ <Step
23
+ step={1}
24
+ label="Phone verified"
25
+ description="+1 (555) 012-3456"
26
+ status="success"
27
+ />
28
+ <Step
29
+ step={2}
30
+ label="Identity document"
31
+ description="Passport upload failed"
32
+ status="error"
33
+ />
34
+ <Step
35
+ step={3}
36
+ label="Address verification"
37
+ description="Pending review"
38
+ status="accent"
39
+ />
40
+ <Step
41
+ step={4}
42
+ label="Background check"
43
+ isOptional
44
+ description="Skipped"
45
+ />
46
+ <Step step={5} label="Account activated" />
47
+ </Stepper>
48
+ </div>
49
+ );
50
+ }
@@ -0,0 +1,14 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /** @type {import('@astryxdesign/cli/authoring').TemplateDoc} */
4
+ export const doc = {
5
+ type: 'block',
6
+ exampleFor: 'Stepper',
7
+ name: 'Stepper — Vertical Onboarding',
8
+ displayName: 'Stepper — Vertical Onboarding',
9
+ description:
10
+ 'A vertical stepper for an onboarding flow, with a label and description per step. The auto indicator shows a check for completed steps, a ring for the current step, and a number for upcoming ones.',
11
+ isReady: true,
12
+ aspectRatio: 4 / 3,
13
+ componentsUsed: ['Stepper'],
14
+ };