@astryxdesign/cli 0.4.6 → 0.4.7-canary.20bae6c

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 (65) hide show
  1. package/CHANGELOG.md +4 -0
  2. package/README.md +53 -51
  3. package/api/docs/docs.doc.mjs +2 -2
  4. package/api/index.d.mts +1 -1
  5. package/api/index.mjs +1 -1
  6. package/api/template/template.doc.mjs +2 -2
  7. package/api/theme/build/build.mjs +8 -38
  8. package/api/theme/targets/targets.d.mts +18 -0
  9. package/api/theme/targets/targets.mjs +87 -0
  10. package/api/theme/targets/targets.test.mjs +65 -0
  11. package/api/theme/theme.d.mts +1 -0
  12. package/api/theme/theme.mjs +3 -1
  13. package/api/theme/theme.type.d.mts +23 -0
  14. package/api/theme/theme.type.mjs +21 -1
  15. package/api/theme/themeTargets.doc.d.mts +11 -0
  16. package/api/theme/themeTargets.doc.mjs +58 -0
  17. package/api/theme/themeTemplate.doc.mjs +3 -3
  18. package/assets/docs/README.md +50 -0
  19. package/assets/docs/cli-integrations.doc.mjs +4 -4
  20. package/assets/docs/theme.doc.dense.mjs +1 -1
  21. package/assets/docs/theme.doc.mjs +1 -1
  22. package/assets/docs/typography.doc.mjs +2 -2
  23. package/assets/templates/blocks/components/Dialog/DialogAdaptivePresentation.doc.mjs +25 -0
  24. package/assets/templates/blocks/components/Dialog/DialogAdaptivePresentation.tsx +167 -0
  25. package/assets/templates/blocks/components/Dialog/DialogScrollingContent.tsx +1 -1
  26. package/assets/templates/blocks/components/Step/StepContent.doc.mjs +14 -0
  27. package/assets/templates/blocks/components/Step/StepContent.tsx +32 -0
  28. package/assets/templates/blocks/components/Step/StepIndicator.doc.mjs +14 -0
  29. package/assets/templates/blocks/components/Step/StepIndicator.tsx +60 -0
  30. package/assets/templates/blocks/components/Step/StepShowcase.doc.mjs +15 -0
  31. package/assets/templates/blocks/components/Step/StepShowcase.tsx +26 -0
  32. package/assets/templates/blocks/components/Step/StepStates.doc.mjs +14 -0
  33. package/assets/templates/blocks/components/Step/StepStates.tsx +46 -0
  34. package/assets/templates/blocks/components/Stepper/StepperCustomContent.doc.mjs +22 -0
  35. package/assets/templates/blocks/components/Stepper/StepperCustomContent.tsx +126 -0
  36. package/assets/templates/blocks/components/Stepper/StepperIndicatorModes.doc.mjs +1 -1
  37. package/assets/templates/blocks/components/Stepper/StepperIndicatorModes.tsx +17 -5
  38. package/assets/templates/blocks/components/Stepper/StepperOnTrackHorizontal.doc.mjs +14 -0
  39. package/assets/templates/blocks/components/Stepper/StepperOnTrackHorizontal.tsx +25 -0
  40. package/assets/templates/blocks/components/Stepper/StepperOnTrackVertical.doc.mjs +2 -2
  41. package/assets/templates/blocks/components/Stepper/StepperOnTrackVertical.tsx +1 -1
  42. package/assets/templates/blocks/components/Stepper/StepperShowcase.doc.mjs +1 -1
  43. package/assets/templates/blocks/components/Stepper/StepperShowcase.tsx +6 -7
  44. package/assets/templates/blocks/components/Stepper/StepperStatus.tsx +1 -1
  45. package/assets/templates/pages/mixed-gallery/page.tsx +12 -3
  46. package/assets/templates/themes/neutral/neutralTheme.ts +13 -8
  47. package/clients/cli/commands/build-theme.mjs +85 -0
  48. package/clients/cli/commands/dialog-adaptive-template.test.mjs +24 -0
  49. package/clients/cli/commands/theme-targets.behavior.test.mjs +64 -0
  50. package/clients/cli/commands/theme-targets.doc.mjs +38 -0
  51. package/clients/cli/commands/theme-template.doc.mjs +2 -2
  52. package/clients/cli/commands/theme.doc.mjs +4 -2
  53. package/clients/cli/index.mjs +1 -0
  54. package/clients/cli/lib/manifest.mjs +2 -0
  55. package/foundation/discovery/theming-targets.d.mts +48 -0
  56. package/foundation/discovery/theming-targets.mjs +135 -0
  57. package/foundation/discovery/theming-targets.test.mjs +127 -0
  58. package/foundation/response/response-types.doc.mjs +7 -2
  59. package/package.json +9 -9
  60. package/assets/templates/blocks/components/Stepper/StepperHorizontal.doc.mjs +0 -14
  61. package/assets/templates/blocks/components/Stepper/StepperHorizontal.tsx +0 -24
  62. package/assets/templates/blocks/components/Stepper/StepperMultiStepForm.doc.mjs +0 -14
  63. package/assets/templates/blocks/components/Stepper/StepperMultiStepForm.tsx +0 -92
  64. package/assets/templates/blocks/components/Stepper/StepperVerticalOnboarding.doc.mjs +0 -14
  65. package/assets/templates/blocks/components/Stepper/StepperVerticalOnboarding.tsx +0 -40
@@ -17,11 +17,13 @@ export const doc = {
17
17
  description:
18
18
  'The theme command group. Running astryx theme with no subcommand prints the ' +
19
19
  'subcommand list; the work happens in the subcommands: compile a theme (build), ' +
20
- 'scaffold one into your project (add), start a custom one from the annotated template (template), or list the bundled themes (list).',
21
- subcommands: ['build', 'add', 'list', 'template'],
20
+ 'scaffold one into your project (add), start a custom one from the annotated template (template), ' +
21
+ 'list the bundled themes (list), or list the component theming targets a theme can override (targets).',
22
+ subcommands: ['build', 'add', 'list', 'template', 'targets'],
22
23
  examples: [
23
24
  {label: 'List bundled themes', cli: 'astryx theme list'},
24
25
  {label: 'Scaffold a theme', cli: 'astryx theme add matcha'},
26
+ {label: 'See what a theme can override', cli: 'astryx theme targets'},
25
27
  ],
26
28
  exitCodes: [
27
29
  {code: 0, when: 'success (help shown, or a subcommand succeeded)'},
@@ -70,6 +70,7 @@ export const JSON_SUPPORTED = new Set([
70
70
  'theme list',
71
71
  'theme add',
72
72
  'theme template',
73
+ 'theme targets',
73
74
  'upgrade',
74
75
  'manifest',
75
76
  'doctor',
@@ -77,6 +77,7 @@ export const RESPONSE_TYPES = {
77
77
  'theme list': ['theme.list'],
78
78
  'theme add': ['theme.list', 'theme.add'],
79
79
  'theme template': ['theme.template'],
80
+ 'theme targets': ['theme.targets'],
80
81
  upgrade: ['upgrade.list', 'upgrade.status', 'upgrade.run'],
81
82
  manifest: ['manifest'],
82
83
  doctor: ['doctor'],
@@ -116,6 +117,7 @@ const EXAMPLES = {
116
117
  'astryx theme add matcha ./src/themes/matcha',
117
118
  ],
118
119
  'theme template': ['astryx theme template', 'astryx theme template --json'],
120
+ 'theme targets': ['astryx theme targets Switch', 'astryx --json theme targets'],
119
121
  upgrade: ['astryx upgrade --json'],
120
122
  manifest: ['astryx manifest --json', 'astryx --json'],
121
123
  doctor: ['astryx doctor', 'astryx doctor --json'],
@@ -0,0 +1,48 @@
1
+ // @generated by scripts/sync-api-types.mjs from the JSDoc in foundation/**/*.mjs.
2
+ // DO NOT EDIT — run `pnpm sync:api-types` to regenerate.
3
+
4
+ /**
5
+ * Every theming target declared under a core `src` directory, sorted by key
6
+ * then component. A key can appear more than once: a shared sub-element (the
7
+ * radio indicator, say) is documented by every component that renders it.
8
+ *
9
+ * Unreadable docs are skipped rather than fatal — a single malformed doc must
10
+ * not take out theme validation or the listing.
11
+ *
12
+ * @param {string} coreSrc - absolute path to `<core>/src`
13
+ * @returns {Promise<ThemingTarget[]>}
14
+ */
15
+ export function collectThemingTargets(coreSrc: string): Promise<ThemingTarget[]>;
16
+ /**
17
+ * Collapse the enumeration into the `{key: [props and states]}` map theme
18
+ * validation checks override keys against — both are legal override keys, so
19
+ * they share one list.
20
+ * @param {ThemingTarget[]} targets
21
+ * @returns {Record<string, string[]>}
22
+ */
23
+ export function targetsByKey(targets: ThemingTarget[]): Record<string, string[]>;
24
+ /**
25
+ * One theming target, as a theme author has to write it.
26
+ */
27
+ export type ThemingTarget = {
28
+ /**
29
+ * - the `defineTheme` `components` key (class minus the `astryx-` prefix)
30
+ */
31
+ key: string;
32
+ /**
33
+ * - the stable class the component renders
34
+ */
35
+ className: string;
36
+ /**
37
+ * - the component whose doc declares it
38
+ */
39
+ component: string;
40
+ /**
41
+ * - visual props the target reflects (`variant:value` keys)
42
+ */
43
+ props: string[];
44
+ /**
45
+ * - runtime states the target reflects (bare-name keys)
46
+ */
47
+ states: string[];
48
+ };
@@ -0,0 +1,135 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file The one enumeration of component theming targets.
5
+ *
6
+ * @input a core `src` directory
7
+ * @output every `theming.targets` entry authored in a component `.doc.mjs`,
8
+ * flattened into the `defineTheme` component key a theme author writes
9
+ * @position packages/cli/foundation/discovery — shared by `theme targets` (the
10
+ * listing) and `theme build` (override validation). Both read the
11
+ * component docs, which are the source of truth `astryx component
12
+ * <Name>` prints; nothing here is a second registry, so the list a
13
+ * theme author can enumerate and the set the compiler accepts cannot
14
+ * drift from the components or from each other.
15
+ */
16
+
17
+ import * as fs from 'node:fs';
18
+ import * as path from 'node:path';
19
+ import {loadComponentDoc} from './component-loader.mjs';
20
+
21
+ const SKIP_DIRS = new Set(['node_modules', '__tests__']);
22
+
23
+ /**
24
+ * One theming target, as a theme author has to write it.
25
+ * @typedef {object} ThemingTarget
26
+ * @property {string} key - the `defineTheme` `components` key (class minus the `astryx-` prefix)
27
+ * @property {string} className - the stable class the component renders
28
+ * @property {string} component - the component whose doc declares it
29
+ * @property {string[]} props - visual props the target reflects (`variant:value` keys)
30
+ * @property {string[]} states - runtime states the target reflects (bare-name keys)
31
+ */
32
+
33
+ /**
34
+ * Strip the namespace prefix to get the `defineTheme` key for a class name.
35
+ *
36
+ * Keep the `astryx-` literal in sync with packages/core/src/naming.ts
37
+ * (NAMESPACE / classPrefix), the same way component-format.mjs does.
38
+ * <!-- SYNC: packages/core/src/naming.ts (namespace prefix source of truth) -->
39
+ * @param {string} className
40
+ * @returns {string}
41
+ */
42
+ function targetKey(className) {
43
+ return className.replace(/^astryx-/, '');
44
+ }
45
+
46
+ /**
47
+ * Every theming target declared under a core `src` directory, sorted by key
48
+ * then component. A key can appear more than once: a shared sub-element (the
49
+ * radio indicator, say) is documented by every component that renders it.
50
+ *
51
+ * Unreadable docs are skipped rather than fatal — a single malformed doc must
52
+ * not take out theme validation or the listing.
53
+ *
54
+ * @param {string} coreSrc - absolute path to `<core>/src`
55
+ * @returns {Promise<ThemingTarget[]>}
56
+ */
57
+ export async function collectThemingTargets(coreSrc) {
58
+ if (!coreSrc || !fs.existsSync(coreSrc)) return [];
59
+
60
+ /** @type {ThemingTarget[]} */
61
+ const targets = [];
62
+
63
+ /** @param {string} dir */
64
+ async function scan(dir) {
65
+ for (const entry of fs.readdirSync(dir, {withFileTypes: true})) {
66
+ const full = path.join(dir, entry.name);
67
+ if (entry.isDirectory()) {
68
+ if (SKIP_DIRS.has(entry.name)) continue;
69
+ await scan(full);
70
+ continue;
71
+ }
72
+ if (!entry.name.endsWith('.doc.mjs')) continue;
73
+
74
+ /** @type {any} */
75
+ let doc;
76
+ try {
77
+ doc = await loadComponentDoc(full);
78
+ } catch {
79
+ continue;
80
+ }
81
+
82
+ const component =
83
+ typeof doc?.name === 'string' && doc.name
84
+ ? doc.name
85
+ : path.basename(path.dirname(full));
86
+
87
+ for (const target of doc?.theming?.targets || []) {
88
+ const className = target?.className;
89
+ if (typeof className !== 'string') continue;
90
+ const key = targetKey(className);
91
+ if (!key) continue;
92
+ targets.push({
93
+ key,
94
+ className,
95
+ component,
96
+ props: stringList(target.visualProps),
97
+ states: stringList(target.states),
98
+ });
99
+ }
100
+ }
101
+ }
102
+
103
+ await scan(coreSrc);
104
+
105
+ targets.sort(
106
+ (a, b) => a.key.localeCompare(b.key) || a.component.localeCompare(b.component),
107
+ );
108
+ return targets;
109
+ }
110
+
111
+ /**
112
+ * Collapse the enumeration into the `{key: [props and states]}` map theme
113
+ * validation checks override keys against — both are legal override keys, so
114
+ * they share one list.
115
+ * @param {ThemingTarget[]} targets
116
+ * @returns {Record<string, string[]>}
117
+ */
118
+ export function targetsByKey(targets) {
119
+ /** @type {Record<string, string[]>} */
120
+ const byKey = {};
121
+ for (const t of targets) {
122
+ byKey[t.key] = [...new Set([...(byKey[t.key] || []), ...t.props, ...t.states])];
123
+ }
124
+ return byKey;
125
+ }
126
+
127
+ /**
128
+ * @param {unknown} value
129
+ * @returns {string[]}
130
+ */
131
+ function stringList(value) {
132
+ return Array.isArray(value)
133
+ ? value.filter((/** @type {unknown} */ v) => typeof v === 'string')
134
+ : [];
135
+ }
@@ -0,0 +1,127 @@
1
+ // Copyright (c) Meta Platforms, Inc. and affiliates.
2
+
3
+ /**
4
+ * @file The enumerability guard for component theming targets.
5
+ *
6
+ * A theming target is only useful if a theme author can find it. These tests
7
+ * run against the REAL core docs and fail if any component's targets stop
8
+ * being enumerable — a doc that moves out of the scanned tree, a target shape
9
+ * that stops being read, or a component whose Theming table says one thing
10
+ * while `theme targets` says another. That divergence is the failure the
11
+ * listing exists to prevent: a target list that can drift from the components
12
+ * is worse than no list.
13
+ */
14
+
15
+ import {describe, it, expect} from 'vitest';
16
+ import * as path from 'node:path';
17
+ import {findCoreDir} from '../fs/paths.mjs';
18
+ import {
19
+ discoverComponents,
20
+ findComponentReadme,
21
+ } from './component-discovery.mjs';
22
+ import {loadComponentDoc} from './component-loader.mjs';
23
+ import {collectThemingTargets, targetsByKey} from './theming-targets.mjs';
24
+
25
+ const coreDir = /** @type {string} */ (findCoreDir(process.cwd()));
26
+ const coreSrc = path.join(coreDir, 'src');
27
+
28
+ /** @type {Promise<import('./theming-targets.mjs').ThemingTarget[]>} */
29
+ const enumerated = collectThemingTargets(coreSrc);
30
+
31
+ describe('collectThemingTargets', () => {
32
+ it('enumerates the whole surface, not a handful', async () => {
33
+ const targets = await enumerated;
34
+ expect(targets.length).toBeGreaterThan(100);
35
+ expect(new Set(targets.map(t => t.component)).size).toBeGreaterThan(50);
36
+ });
37
+
38
+ it('drops the namespace prefix so each key is what defineTheme takes', async () => {
39
+ for (const t of await enumerated) {
40
+ expect(t.className).toBe(`astryx-${t.key}`);
41
+ expect(t.component).toBeTruthy();
42
+ }
43
+ });
44
+
45
+ it('carries the props and states a target reflects', async () => {
46
+ const targets = await enumerated;
47
+ expect(targets.find(t => t.key === 'switch-thumb')).toEqual({
48
+ key: 'switch-thumb',
49
+ className: 'astryx-switch-thumb',
50
+ component: 'Switch',
51
+ props: ['size'],
52
+ states: ['checked'],
53
+ });
54
+ });
55
+
56
+ it('is sorted by key, so a diff of two runs is readable', async () => {
57
+ const keys = (await enumerated).map(t => t.key);
58
+ expect(keys).toEqual([...keys].sort((a, b) => a.localeCompare(b)));
59
+ });
60
+
61
+ // The listing and `theme build`'s override validation read this one
62
+ // enumeration. `targetsByKey` is the shape validation wants: props and
63
+ // states merged, because both are legal override keys.
64
+ it('collapses to the override keys, merging the components that share one', async () => {
65
+ const byKey = targetsByKey(await enumerated);
66
+ expect(byKey['switch']).toEqual(['size', 'checked', 'disabled']);
67
+ // `radio` is documented by both Indicator and RadioList.
68
+ const radio = (await enumerated).filter(t => t.key === 'radio');
69
+ expect(radio.length).toBeGreaterThan(1);
70
+ for (const t of radio) {
71
+ for (const name of [...t.props, ...t.states]) {
72
+ expect(byKey['radio']).toContain(name);
73
+ }
74
+ }
75
+ });
76
+
77
+ it('every component doc that declares targets has them enumerated', async () => {
78
+ const targets = await enumerated;
79
+ /** @type {Map<string, Set<string>>} key -> props+states */
80
+ const byKey = new Map(
81
+ Object.entries(targetsByKey(targets)).map(([k, v]) => [k, new Set(v)]),
82
+ );
83
+
84
+ const names = Object.values(discoverComponents(coreDir)).flat();
85
+ /** @type {string[]} */
86
+ const missing = [];
87
+ /** @type {Set<string>} */
88
+ const seenDocs = new Set();
89
+ let checked = 0;
90
+
91
+ for (const name of names) {
92
+ const docPath = findComponentReadme(coreDir, name);
93
+ if (!docPath || seenDocs.has(docPath)) continue;
94
+ seenDocs.add(docPath);
95
+
96
+ /** @type {any} */
97
+ let doc;
98
+ try {
99
+ doc = await loadComponentDoc(docPath);
100
+ } catch {
101
+ continue;
102
+ }
103
+
104
+ for (const target of doc?.theming?.targets || []) {
105
+ if (typeof target?.className !== 'string') continue;
106
+ checked++;
107
+ const key = target.className.replace(/^astryx-/, '');
108
+ const known = byKey.get(key);
109
+ if (!known) {
110
+ missing.push(`${name}: ${target.className} is not enumerable`);
111
+ continue;
112
+ }
113
+ for (const prop of [
114
+ ...(target.visualProps || []),
115
+ ...(target.states || []),
116
+ ]) {
117
+ if (!known.has(prop)) {
118
+ missing.push(`${name}: ${target.className} lost "${prop}"`);
119
+ }
120
+ }
121
+ }
122
+ }
123
+
124
+ expect(checked).toBeGreaterThan(100);
125
+ expect(missing).toEqual([]);
126
+ }, 60_000);
127
+ });
@@ -153,7 +153,7 @@ export const doc = {
153
153
  {
154
154
  value: 'template.cdn',
155
155
  description:
156
- 'A write receipt for the no-build-step CDN starter page: the path (relative to cwd), the Astryx version every CDN URL was pinned to, whether it was written, and the reason it was not `exists` when a file was already there, which is a success.',
156
+ 'A write receipt for the no-build-step CDN starter page: the path (relative to cwd), the Astryx version every CDN URL was pinned to, whether it was written, and the reason it was not. `exists` when a file was already there, which is a success.',
157
157
  },
158
158
 
159
159
  // hook
@@ -197,7 +197,12 @@ export const doc = {
197
197
  {
198
198
  value: 'theme.template',
199
199
  description:
200
- 'A write receipt for the annotated theme template: the path (relative to cwd), whether it was written, and the reason it was not `exists` when a file was already there, which is a success.',
200
+ 'A write receipt for the annotated theme template: the path (relative to cwd), whether it was written, and the reason it was not. `exists` when a file was already there, which is a success.',
201
+ },
202
+ {
203
+ value: 'theme.targets',
204
+ description:
205
+ 'The whole themeable surface: the echoed filter, the component count, and one entry per theming target — {key, className, component, props, states}, where props and states are its legal override keys.',
201
206
  },
202
207
 
203
208
  // upgrade
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astryxdesign/cli",
3
- "version": "0.4.6",
3
+ "version": "0.4.7-canary.20bae6c",
4
4
  "displayName": "CLI",
5
5
  "description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
6
6
  "author": "Meta Open Source",
@@ -87,10 +87,10 @@
87
87
  "zod": "^4.4.3"
88
88
  },
89
89
  "peerDependencies": {
90
- "@astryxdesign/charts": "*",
91
- "@astryxdesign/core": "*",
92
- "@astryxdesign/lab": "*",
93
- "@astryxdesign/theme-neutral": "*",
90
+ "@astryxdesign/charts": "0.4.7-canary.20bae6c",
91
+ "@astryxdesign/core": "0.4.7-canary.20bae6c",
92
+ "@astryxdesign/lab": "0.4.7-canary.20bae6c",
93
+ "@astryxdesign/theme-neutral": "0.4.7-canary.20bae6c",
94
94
  "gpt-tokenizer": "^3.4.0"
95
95
  },
96
96
  "peerDependenciesMeta": {
@@ -108,10 +108,10 @@
108
108
  }
109
109
  },
110
110
  "devDependencies": {
111
- "@astryxdesign/charts": "*",
112
- "@astryxdesign/core": "*",
113
- "@astryxdesign/lab": "*",
114
- "@astryxdesign/theme-neutral": "*",
111
+ "@astryxdesign/charts": "0.4.7-canary.20bae6c",
112
+ "@astryxdesign/core": "0.4.7-canary.20bae6c",
113
+ "@astryxdesign/lab": "0.4.7-canary.20bae6c",
114
+ "@astryxdesign/theme-neutral": "0.4.7-canary.20bae6c",
115
115
  "gpt-tokenizer": "^3.4.0"
116
116
  },
117
117
  "scripts": {
@@ -1,14 +0,0 @@
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
- };
@@ -1,24 +0,0 @@
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
- }
@@ -1,14 +0,0 @@
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
- };
@@ -1,92 +0,0 @@
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
- }
@@ -1,14 +0,0 @@
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
- };
@@ -1,40 +0,0 @@
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 StepperVerticalOnboarding() {
9
- const [active, setActive] = useState(2);
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="Create workspace"
19
- description="Name and configure your workspace"
20
- />
21
- <Step
22
- step={1}
23
- label="Invite team members"
24
- description="Add collaborators by email"
25
- />
26
- <Step
27
- step={2}
28
- label="Set up integrations"
29
- description="Connect Slack, GitHub, Jira"
30
- />
31
- <Step
32
- step={3}
33
- label="Import data"
34
- description="Bring in existing projects"
35
- />
36
- <Step step={4} label="Launch" description="Go live with your team" />
37
- </Stepper>
38
- </div>
39
- );
40
- }