@astryxdesign/cli 0.4.6 → 0.4.7-canary.29be96d
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 +4 -0
- package/README.md +1 -0
- package/api/index.d.mts +1 -1
- package/api/index.mjs +1 -1
- package/api/theme/build/build.mjs +8 -38
- package/api/theme/targets/targets.d.mts +18 -0
- package/api/theme/targets/targets.mjs +87 -0
- package/api/theme/targets/targets.test.mjs +65 -0
- package/api/theme/theme.d.mts +1 -0
- package/api/theme/theme.mjs +3 -1
- package/api/theme/theme.type.d.mts +23 -0
- package/api/theme/theme.type.mjs +21 -1
- package/api/theme/themeTargets.doc.d.mts +11 -0
- package/api/theme/themeTargets.doc.mjs +58 -0
- package/assets/docs/README.md +50 -0
- package/assets/docs/cli-integrations.doc.mjs +4 -4
- package/assets/docs/theme.doc.dense.mjs +1 -1
- package/assets/docs/theme.doc.mjs +1 -1
- package/assets/templates/blocks/components/Dialog/DialogAdaptivePresentation.doc.mjs +25 -0
- package/assets/templates/blocks/components/Dialog/DialogAdaptivePresentation.tsx +167 -0
- package/assets/templates/blocks/components/Dialog/DialogScrollingContent.tsx +1 -1
- package/assets/templates/blocks/components/Step/StepContent.doc.mjs +14 -0
- package/assets/templates/blocks/components/Step/StepContent.tsx +32 -0
- package/assets/templates/blocks/components/Step/StepIndicator.doc.mjs +14 -0
- package/assets/templates/blocks/components/Step/StepIndicator.tsx +60 -0
- package/assets/templates/blocks/components/Step/StepShowcase.doc.mjs +15 -0
- package/assets/templates/blocks/components/Step/StepShowcase.tsx +26 -0
- package/assets/templates/blocks/components/Step/StepStates.doc.mjs +14 -0
- package/assets/templates/blocks/components/Step/StepStates.tsx +46 -0
- package/assets/templates/blocks/components/Stepper/StepperCustomContent.doc.mjs +22 -0
- package/assets/templates/blocks/components/Stepper/StepperCustomContent.tsx +126 -0
- package/assets/templates/blocks/components/Stepper/StepperIndicatorModes.doc.mjs +1 -1
- package/assets/templates/blocks/components/Stepper/StepperIndicatorModes.tsx +17 -5
- package/assets/templates/blocks/components/Stepper/StepperOnTrackHorizontal.doc.mjs +14 -0
- package/assets/templates/blocks/components/Stepper/StepperOnTrackHorizontal.tsx +25 -0
- package/assets/templates/blocks/components/Stepper/StepperOnTrackVertical.doc.mjs +2 -2
- package/assets/templates/blocks/components/Stepper/StepperOnTrackVertical.tsx +1 -1
- package/assets/templates/blocks/components/Stepper/StepperShowcase.doc.mjs +1 -1
- package/assets/templates/blocks/components/Stepper/StepperShowcase.tsx +6 -7
- package/assets/templates/blocks/components/Stepper/StepperStatus.tsx +1 -1
- package/assets/templates/themes/neutral/neutralTheme.ts +13 -8
- package/clients/cli/commands/build-theme.mjs +85 -0
- package/clients/cli/commands/dialog-adaptive-template.test.mjs +24 -0
- package/clients/cli/commands/theme-targets.behavior.test.mjs +64 -0
- package/clients/cli/commands/theme-targets.doc.mjs +38 -0
- package/clients/cli/commands/theme.doc.mjs +4 -2
- package/clients/cli/index.mjs +1 -0
- package/clients/cli/lib/manifest.mjs +2 -0
- package/foundation/discovery/theming-targets.d.mts +48 -0
- package/foundation/discovery/theming-targets.mjs +135 -0
- package/foundation/discovery/theming-targets.test.mjs +127 -0
- package/foundation/response/response-types.doc.mjs +5 -0
- package/package.json +9 -9
- package/assets/templates/blocks/components/Stepper/StepperHorizontal.doc.mjs +0 -14
- package/assets/templates/blocks/components/Stepper/StepperHorizontal.tsx +0 -24
- package/assets/templates/blocks/components/Stepper/StepperMultiStepForm.doc.mjs +0 -14
- package/assets/templates/blocks/components/Stepper/StepperMultiStepForm.tsx +0 -92
- package/assets/templates/blocks/components/Stepper/StepperVerticalOnboarding.doc.mjs +0 -14
- package/assets/templates/blocks/components/Stepper/StepperVerticalOnboarding.tsx +0 -40
|
@@ -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
|
+
});
|
|
@@ -199,6 +199,11 @@ export const doc = {
|
|
|
199
199
|
description:
|
|
200
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
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.',
|
|
206
|
+
},
|
|
202
207
|
|
|
203
208
|
// upgrade
|
|
204
209
|
{
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/cli",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.7-canary.29be96d",
|
|
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.29be96d",
|
|
91
|
+
"@astryxdesign/core": "0.4.7-canary.29be96d",
|
|
92
|
+
"@astryxdesign/lab": "0.4.7-canary.29be96d",
|
|
93
|
+
"@astryxdesign/theme-neutral": "0.4.7-canary.29be96d",
|
|
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.29be96d",
|
|
112
|
+
"@astryxdesign/core": "0.4.7-canary.29be96d",
|
|
113
|
+
"@astryxdesign/lab": "0.4.7-canary.29be96d",
|
|
114
|
+
"@astryxdesign/theme-neutral": "0.4.7-canary.29be96d",
|
|
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
|
-
}
|