torch-glare 2.1.1 → 2.1.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/apps/lib/components/BadgeField.tsx +2 -2
- package/apps/lib/components/DataViews/ARCHITECTURE.md +439 -0
- package/apps/lib/components/DataViews/DataViewsConfigPanel.tsx +416 -0
- package/apps/lib/components/DataViews/DataViewsHeader.tsx +126 -0
- package/apps/lib/components/DataViews/DataViewsLayout.tsx +300 -0
- package/apps/lib/components/DataViews/FilterPanel.tsx +324 -0
- package/apps/lib/components/DataViews/InboxView.tsx +514 -0
- package/apps/lib/components/DataViews/KanbanView.tsx +242 -0
- package/apps/lib/components/DataViews/PanelControls.tsx +80 -0
- package/apps/lib/components/DataViews/SettingsPanel.tsx +285 -0
- package/apps/lib/components/DataViews/TableView.tsx +232 -0
- package/apps/lib/components/DataViews/TreeView.tsx +363 -0
- package/apps/lib/components/DataViews/badgeAdapter.ts +45 -0
- package/apps/lib/components/DataViews/fieldRenderers.tsx +334 -0
- package/apps/lib/components/DataViews/filters/DateRangePopover.tsx +113 -0
- package/apps/lib/components/DataViews/filters/PresetChips.tsx +45 -0
- package/apps/lib/components/DataViews/filters/RangeSliderWithInputs.tsx +154 -0
- package/apps/lib/components/DataViews/index.ts +30 -0
- package/apps/lib/components/DataViews/tree/TreeDrawer.tsx +54 -0
- package/apps/lib/components/DataViews/tree/TreeSidebar.tsx +77 -0
- package/apps/lib/components/DataViews/types.ts +177 -0
- package/apps/lib/components/TreeFolder/TreeFolder.tsx +387 -0
- package/apps/lib/components/TreeFolder/TreeFolderBreadcrumb.tsx +80 -0
- package/apps/lib/components/TreeFolder/TreeFolderRow.tsx +235 -0
- package/apps/lib/components/TreeFolder/TreeFolderStyles.tsx +60 -0
- package/apps/lib/components/TreeFolder/icons.tsx +63 -0
- package/apps/lib/components/TreeFolder/index.ts +17 -0
- package/apps/lib/components/TreeFolder/treeFolderUtils.ts +114 -0
- package/apps/lib/components/TreeFolder/types.ts +68 -0
- package/apps/lib/components/TreeFolder/useTreeFolderDnD.ts +261 -0
- package/apps/lib/hooks/useDataViewsState.ts +169 -0
- package/apps/lib/hooks/useIsMobile.ts +21 -0
- package/apps/lib/utils/dataViews/columnUtils.ts +130 -0
- package/apps/lib/utils/dataViews/fieldUtils.ts +198 -0
- package/apps/lib/utils/dataViews/nestedDataUtils.tsx +364 -0
- package/apps/lib/utils/dataViews/pathUtils.ts +132 -0
- package/apps/lib/utils/dataViews/rangeUtils.ts +225 -0
- package/apps/lib/utils/dataViews/treeUtils.ts +403 -0
- package/dist/bin/index.js +3 -3
- package/dist/bin/index.js.map +1 -1
- package/dist/src/commands/add.d.ts.map +1 -1
- package/dist/src/commands/add.js +29 -6
- package/dist/src/commands/add.js.map +1 -1
- package/dist/src/commands/utils.d.ts.map +1 -1
- package/dist/src/commands/utils.js +22 -2
- package/dist/src/commands/utils.js.map +1 -1
- package/dist/src/shared/copyComponentsRecursively.d.ts.map +1 -1
- package/dist/src/shared/copyComponentsRecursively.js +8 -1
- package/dist/src/shared/copyComponentsRecursively.js.map +1 -1
- package/dist/src/shared/getDependenciesAndInstallNestedComponents.d.ts +18 -4
- package/dist/src/shared/getDependenciesAndInstallNestedComponents.d.ts.map +1 -1
- package/dist/src/shared/getDependenciesAndInstallNestedComponents.js +110 -40
- package/dist/src/shared/getDependenciesAndInstallNestedComponents.js.map +1 -1
- package/docs/components/form-stepper.md +244 -0
- package/docs/components/stepper.md +215 -0
- package/docs/components/timeline.md +248 -0
- package/package.json +6 -6
- package/apps/lib/components/Charts-dev.tsx +0 -365
- package/apps/lib/components/Command-dev.tsx +0 -151
- package/apps/lib/components/IosDatePicker-dev.tsx +0 -341
- /package/docs/components/{labeled-checkbox.md → labeled-check-box.md} +0 -0
- /package/docs/components/{tree-dropdown.md → tree-drop-down.md} +0 -0
package/dist/src/commands/add.js
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import path from "path";
|
|
2
|
+
import fs from "fs";
|
|
2
3
|
import inquirer from "inquirer";
|
|
3
4
|
import { fileURLToPath } from "url";
|
|
4
5
|
import { ensureDirectoryExists } from "../shared/ensureDirectoryExists.js";
|
|
@@ -25,15 +26,16 @@ export async function add(component, replace = false) {
|
|
|
25
26
|
if (!component) {
|
|
26
27
|
component = await promptComponentSelection(availableComponents);
|
|
27
28
|
}
|
|
28
|
-
//
|
|
29
|
-
|
|
29
|
+
// Resolve user input to an actual entry — accepts "Button", "Button.tsx", or "DataViews" (folder).
|
|
30
|
+
const resolved = resolveComponentEntry(component, availableComponents, templatesDir);
|
|
31
|
+
if (!resolved) {
|
|
30
32
|
console.error(`❌ Component "${component}" not found.`);
|
|
31
33
|
return;
|
|
32
34
|
}
|
|
33
|
-
const { source, targetDir } = getInstallPaths(
|
|
35
|
+
const { source, targetDir } = getInstallPaths(resolved, targetFile, templatesDir, "components");
|
|
34
36
|
// Check if component already exists
|
|
35
|
-
if (isFileExists(targetDir,
|
|
36
|
-
console.log(`⚠️ Component "${
|
|
37
|
+
if (isFileExists(targetDir, resolved) && !replace) {
|
|
38
|
+
console.log(`⚠️ Component "${resolved}" already exists.`);
|
|
37
39
|
return;
|
|
38
40
|
}
|
|
39
41
|
// Ensure the target directory exists
|
|
@@ -41,7 +43,28 @@ export async function add(component, replace = false) {
|
|
|
41
43
|
ensureDirectoryExists(targetDir);
|
|
42
44
|
// Copy the component (directory or file) and install dependencies
|
|
43
45
|
copyComponentsRecursively(source, targetDir);
|
|
44
|
-
console.log(`✅ ${
|
|
46
|
+
console.log(`✅ ${resolved} has been added to ${targetFile.path}!`);
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Resolve a user-provided component name to an actual entry in the templates
|
|
50
|
+
* directory. Tries (in order):
|
|
51
|
+
* 1. exact match (e.g. "Button.tsx" or "DataViews")
|
|
52
|
+
* 2. with `.tsx` suffix (e.g. user typed "Button")
|
|
53
|
+
* 3. with `.ts` suffix (for non-JSX modules)
|
|
54
|
+
* Returns the matching entry name, or null if nothing matches.
|
|
55
|
+
*/
|
|
56
|
+
function resolveComponentEntry(input, available, dir) {
|
|
57
|
+
if (available.includes(input))
|
|
58
|
+
return input;
|
|
59
|
+
const candidates = [`${input}.tsx`, `${input}.ts`];
|
|
60
|
+
for (const c of candidates) {
|
|
61
|
+
if (available.includes(c))
|
|
62
|
+
return c;
|
|
63
|
+
}
|
|
64
|
+
// Last-ditch: see if it exists on disk even if `getAvailableFiles` missed it.
|
|
65
|
+
if (fs.existsSync(path.join(dir, input)))
|
|
66
|
+
return input;
|
|
67
|
+
return null;
|
|
45
68
|
}
|
|
46
69
|
/**
|
|
47
70
|
* Prompt the user to select a component from a list.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../cli/src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAE/D,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,iBAAiB,EAAE,MAAM,gCAAgC,CAAC;AACnE,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAElD,2CAA2C;AAC3C,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,6CAA6C;AAC7C,MAAM,YAAY,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,8BAA8B,CAAC,CAAC;AAI7E;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,SAAkB,EAAE,UAAmB,KAAK;IAClE,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,CAAW,CAAC;IACpD,MAAM,mBAAmB,GAAG,iBAAiB,CAAC,YAAY,CAAC,CAAC;IAE5D,6DAA6D;IAC7D,IAAI,CAAC,SAAS,EAAE,CAAC;QACb,SAAS,GAAG,MAAM,wBAAwB,CAAC,mBAAmB,CAAC,CAAC;IACpE,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"add.js","sourceRoot":"","sources":["../../../cli/src/commands/add.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../cli/src/commands/utils.ts"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../cli/src/commands/utils.ts"],"names":[],"mappings":"AAiBA;;;;GAIG;AACH,wBAAsB,OAAO,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,OAAO,GAAE,OAAe,GAAG,OAAO,CAAC,IAAI,CAAC,CAoCpF"}
|
|
@@ -24,11 +24,13 @@ export async function addUtil(util, replace = false) {
|
|
|
24
24
|
if (!util) {
|
|
25
25
|
util = await promptUtilSelection(availableUtils);
|
|
26
26
|
}
|
|
27
|
-
//
|
|
28
|
-
|
|
27
|
+
// Resolve user input — accepts "cn", "cn.ts", or a folder name like "dataViews".
|
|
28
|
+
const resolved = resolveUtilEntry(util, availableUtils, utilsTemplatesDir);
|
|
29
|
+
if (!resolved) {
|
|
29
30
|
console.error(`❌ Utility file "${util}" not found.`);
|
|
30
31
|
return;
|
|
31
32
|
}
|
|
33
|
+
util = resolved;
|
|
32
34
|
// get the path and create the create the target directory
|
|
33
35
|
const { source, targetDir } = getInstallPaths(util, targetFile, utilsTemplatesDir, "utils");
|
|
34
36
|
const target = path.join(targetDir, util);
|
|
@@ -52,6 +54,24 @@ export async function addUtil(util, replace = false) {
|
|
|
52
54
|
function getAvailableUtils(utilsTemplatesDir) {
|
|
53
55
|
return fs.readdirSync(utilsTemplatesDir).map((file) => path.basename(file));
|
|
54
56
|
}
|
|
57
|
+
/**
|
|
58
|
+
* Resolve a user-provided util name to an actual entry. Tries:
|
|
59
|
+
* 1. exact match (e.g. "cn.ts" or "dataViews")
|
|
60
|
+
* 2. with `.ts` suffix
|
|
61
|
+
* 3. with `.tsx` suffix
|
|
62
|
+
*/
|
|
63
|
+
function resolveUtilEntry(input, available, dir) {
|
|
64
|
+
if (available.includes(input))
|
|
65
|
+
return input;
|
|
66
|
+
const candidates = [`${input}.ts`, `${input}.tsx`];
|
|
67
|
+
for (const c of candidates) {
|
|
68
|
+
if (available.includes(c))
|
|
69
|
+
return c;
|
|
70
|
+
}
|
|
71
|
+
if (fs.existsSync(path.join(dir, input)))
|
|
72
|
+
return input;
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
55
75
|
/**
|
|
56
76
|
* Prompt the user to select a utility file from a list.
|
|
57
77
|
* @param {string[]} availableUtils - Array of available utility files.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../cli/src/commands/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,WAAW,EAAE,MAAM,WAAW,CAAC;AAExC,OAAO,EAAE,aAAa,EAAE,MAAM,KAAK,CAAC;AACpC,OAAO,EAAE,qBAAqB,EAAE,MAAM,oCAAoC,CAAC;AAC3E,OAAO,EAAE,eAAe,EAAE,MAAM,8BAA8B,CAAC;AAC/D,OAAO,QAAQ,MAAM,UAAU,CAAC;AAChC,OAAO,EAAE,yBAAyB,EAAE,MAAM,wCAAwC,CAAC;AACnF,OAAO,EAAE,YAAY,EAAE,MAAM,2BAA2B,CAAC;AACzD,MAAM,UAAU,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAClD,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;AAE3C,mDAAmD;AACnD,MAAM,iBAAiB,GAAW,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,yBAAyB,CAAC,CAAC;AAErF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAa,EAAE,UAAmB,KAAK;IACjE,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,CAAW,CAAC;IACpD,MAAM,cAAc,GAAa,iBAAiB,CAAC,iBAAiB,CAAC,CAAC;IAEtE,gEAAgE;IAChE,IAAI,CAAC,IAAI,EAAE,CAAC;QACR,IAAI,GAAG,MAAM,mBAAmB,CAAC,cAAc,CAAC,CAAC;IACrD,CAAC;IAED,
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../../../cli/src/commands/utils.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copyComponentsRecursively.d.ts","sourceRoot":"","sources":["../../../cli/src/shared/copyComponentsRecursively.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,
|
|
1
|
+
{"version":3,"file":"copyComponentsRecursively.d.ts","sourceRoot":"","sources":["../../../cli/src/shared/copyComponentsRecursively.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,CAqB9E;AACD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAC7B,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,GACf,IAAI,CAiBN"}
|
|
@@ -8,7 +8,14 @@ import path from "path";
|
|
|
8
8
|
*/
|
|
9
9
|
export function copyComponentsRecursively(source, target) {
|
|
10
10
|
if (fs.lstatSync(source).isDirectory()) {
|
|
11
|
-
|
|
11
|
+
// If target already exists as a directory, nest the source folder
|
|
12
|
+
// inside it (so `add DataViews` ends up at ./components/DataViews/,
|
|
13
|
+
// not flattened into ./components/). Otherwise the target IS the
|
|
14
|
+
// destination directory (legacy behavior).
|
|
15
|
+
const finalTarget = fs.existsSync(target) && fs.lstatSync(target).isDirectory()
|
|
16
|
+
? path.join(target, path.basename(source))
|
|
17
|
+
: target;
|
|
18
|
+
copyDirectorySync(source, finalTarget);
|
|
12
19
|
}
|
|
13
20
|
else {
|
|
14
21
|
let finalTarget = target;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"copyComponentsRecursively.js","sourceRoot":"","sources":["../../../cli/src/shared/copyComponentsRecursively.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAE,MAAc;IACpE,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACrC,
|
|
1
|
+
{"version":3,"file":"copyComponentsRecursively.js","sourceRoot":"","sources":["../../../cli/src/shared/copyComponentsRecursively.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAC/D,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AAExB;;;;GAIG;AACH,MAAM,UAAU,yBAAyB,CAAC,MAAc,EAAE,MAAc;IACpE,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;QACrC,kEAAkE;QAClE,oEAAoE;QACpE,iEAAiE;QACjE,2CAA2C;QAC3C,MAAM,WAAW,GACb,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE;YACvD,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC;YAC1C,CAAC,CAAC,MAAM,CAAC;QACjB,iBAAiB,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;IAC3C,CAAC;SAAM,CAAC;QACJ,IAAI,WAAW,GAAG,MAAM,CAAC;QAEzB,IAAI,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;YAC9D,WAAW,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QAC3D,CAAC;QAED,EAAE,CAAC,YAAY,CAAC,MAAM,EAAE,WAAW,CAAC,CAAC;QACrC,mBAAmB,CAAC,MAAM,CAAC,CAAC;IAChC,CAAC;AACL,CAAC;AACD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC7B,MAAc,EACd,MAAc;IAEd,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;QACzB,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,KAAK,GAAG,EAAE,CAAC,WAAW,CAAC,MAAM,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACvB,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAChD,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QAEhD,IAAI,IAAI,CAAC,WAAW,EAAE,EAAE,CAAC;YACrB,iBAAiB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;QAC9C,CAAC;aAAM,CAAC;YACJ,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;YACxC,mBAAmB,CAAC,UAAU,CAAC,CAAC;QACpC,CAAC;IACL,CAAC;AACL,CAAC"}
|
|
@@ -1,8 +1,22 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
2
|
+
* Walk a copied component file's imports and (a) collect 3rd-party deps to
|
|
3
|
+
* install, (b) recursively pull in any referenced glare components, hooks, or
|
|
4
|
+
* utils so the user gets a self-contained drop-in.
|
|
5
|
+
*
|
|
6
|
+
* Import-path forms understood:
|
|
7
|
+
* "lucide-react" → 3rd-party
|
|
8
|
+
* "./TableView" → sibling (already copied by folder copy)
|
|
9
|
+
* "../Button" → ../components/Button.tsx
|
|
10
|
+
* "../../components/Button" → same
|
|
11
|
+
* "../utils/cn" → util "cn"
|
|
12
|
+
* "../../utils/cn" → util "cn"
|
|
13
|
+
* "../../utils/dataViews/pathUtils" → util folder "dataViews" (whole folder)
|
|
14
|
+
* "../hooks/useIsMobile" → hook "useIsMobile.ts"
|
|
15
|
+
* "../../hooks/useIsMobile" → same
|
|
16
|
+
*
|
|
17
|
+
* @param componentPath - File whose imports we're walking.
|
|
18
|
+
* @param installedDependencies - Already-present 3rd-party packages.
|
|
19
|
+
* @returns Set of 3rd-party deps still to install.
|
|
6
20
|
*/
|
|
7
21
|
export declare function getDependenciesAndInstallNestedComponents(componentPath: string, installedDependencies: Set<string>): Set<string>;
|
|
8
22
|
//# sourceMappingURL=getDependenciesAndInstallNestedComponents.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDependenciesAndInstallNestedComponents.d.ts","sourceRoot":"","sources":["../../../cli/src/shared/getDependenciesAndInstallNestedComponents.ts"],"names":[],"mappings":"AAMA
|
|
1
|
+
{"version":3,"file":"getDependenciesAndInstallNestedComponents.d.ts","sourceRoot":"","sources":["../../../cli/src/shared/getDependenciesAndInstallNestedComponents.ts"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,yCAAyC,CACrD,aAAa,EAAE,MAAM,EACrB,qBAAqB,EAAE,GAAG,CAAC,MAAM,CAAC,GACnC,GAAG,CAAC,MAAM,CAAC,CAgEb"}
|
|
@@ -4,63 +4,133 @@ import { addUtil } from "../commands/utils.js";
|
|
|
4
4
|
import { addHook } from "../commands/hook.js";
|
|
5
5
|
import { add } from "../commands/add.js";
|
|
6
6
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
7
|
+
* Walk a copied component file's imports and (a) collect 3rd-party deps to
|
|
8
|
+
* install, (b) recursively pull in any referenced glare components, hooks, or
|
|
9
|
+
* utils so the user gets a self-contained drop-in.
|
|
10
|
+
*
|
|
11
|
+
* Import-path forms understood:
|
|
12
|
+
* "lucide-react" → 3rd-party
|
|
13
|
+
* "./TableView" → sibling (already copied by folder copy)
|
|
14
|
+
* "../Button" → ../components/Button.tsx
|
|
15
|
+
* "../../components/Button" → same
|
|
16
|
+
* "../utils/cn" → util "cn"
|
|
17
|
+
* "../../utils/cn" → util "cn"
|
|
18
|
+
* "../../utils/dataViews/pathUtils" → util folder "dataViews" (whole folder)
|
|
19
|
+
* "../hooks/useIsMobile" → hook "useIsMobile.ts"
|
|
20
|
+
* "../../hooks/useIsMobile" → same
|
|
21
|
+
*
|
|
22
|
+
* @param componentPath - File whose imports we're walking.
|
|
23
|
+
* @param installedDependencies - Already-present 3rd-party packages.
|
|
24
|
+
* @returns Set of 3rd-party deps still to install.
|
|
11
25
|
*/
|
|
12
26
|
export function getDependenciesAndInstallNestedComponents(componentPath, installedDependencies) {
|
|
13
27
|
const componentContent = fs.readFileSync(componentPath, "utf-8");
|
|
14
|
-
const importRegex = /import\s
|
|
28
|
+
const importRegex = /import\s+(?:[\s\S]*?from\s+)?['"]([^'"]+)['"]/g;
|
|
15
29
|
const dependenciesToInstall = new Set();
|
|
30
|
+
const dir = path.dirname(componentPath);
|
|
16
31
|
let match;
|
|
17
32
|
while ((match = importRegex.exec(componentContent)) !== null) {
|
|
18
33
|
const moduleName = match[1];
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
addUtil(moduleName.slice(9) + ".ts");
|
|
34
|
+
if (!moduleName)
|
|
35
|
+
continue;
|
|
36
|
+
// ----- 3rd-party packages (no relative prefix) -----
|
|
37
|
+
if (!moduleName.startsWith(".")) {
|
|
38
|
+
if (!installedDependencies.has(moduleName)) {
|
|
39
|
+
dependenciesToInstall.add(moduleName);
|
|
40
|
+
}
|
|
41
|
+
continue;
|
|
28
42
|
}
|
|
29
|
-
//
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
43
|
+
// ----- Relative imports -----
|
|
44
|
+
const segments = moduleName.split("/").filter(s => s && s !== ".");
|
|
45
|
+
const dotDots = segments.filter(s => s === "..").length;
|
|
46
|
+
const rest = segments.slice(dotDots);
|
|
47
|
+
// Sibling import (no ..): handled by directory copy, skip.
|
|
48
|
+
if (dotDots === 0)
|
|
49
|
+
continue;
|
|
50
|
+
const head = rest[0];
|
|
51
|
+
// Implicit-or-explicit segment header — handle both:
|
|
52
|
+
// "../utils/cn" (head = "utils")
|
|
53
|
+
// "../../utils/cn" (head = "utils")
|
|
54
|
+
// "../Button" (head = "Button") → component sibling
|
|
55
|
+
if (head === "utils") {
|
|
56
|
+
// utils/cn or utils/dataViews/pathUtils
|
|
57
|
+
const utilEntry = rest[1];
|
|
58
|
+
if (utilEntry) {
|
|
59
|
+
addUtil(utilEntry);
|
|
60
|
+
}
|
|
34
61
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
(
|
|
38
|
-
|
|
39
|
-
!installedDependencies.has(moduleName)) {
|
|
40
|
-
const baseName = moduleName.slice(2);
|
|
41
|
-
const dir = path.dirname(componentPath);
|
|
42
|
-
// Try .tsx first, fall back to .ts for non-JSX files
|
|
43
|
-
if (fs.existsSync(path.join(dir, baseName + ".tsx"))) {
|
|
44
|
-
add(baseName + ".tsx");
|
|
62
|
+
else if (head === "hooks") {
|
|
63
|
+
const hookEntry = rest[1];
|
|
64
|
+
if (hookEntry) {
|
|
65
|
+
addHook(`${hookEntry}.ts`);
|
|
45
66
|
}
|
|
46
|
-
|
|
47
|
-
|
|
67
|
+
}
|
|
68
|
+
else if (head === "components") {
|
|
69
|
+
const compEntry = rest[1];
|
|
70
|
+
if (compEntry) {
|
|
71
|
+
// Use bare name; the add() resolver figures out folder-vs-file.
|
|
72
|
+
add(compEntry);
|
|
48
73
|
}
|
|
49
74
|
}
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
if (fs.existsSync(path.join(componentsDir, baseName + ".tsx"))) {
|
|
57
|
-
add(baseName + ".tsx");
|
|
75
|
+
else {
|
|
76
|
+
// Bare relative — assume sibling component (e.g. "../Button" from a layout).
|
|
77
|
+
// Resolve against the file system to decide whether to call addUtil/addHook/add.
|
|
78
|
+
const resolved = resolveRelative(dir, moduleName);
|
|
79
|
+
if (resolved) {
|
|
80
|
+
routeByLocation(resolved);
|
|
58
81
|
}
|
|
59
82
|
else {
|
|
60
|
-
|
|
83
|
+
// Fallback: try as a sibling component.
|
|
84
|
+
add(head);
|
|
61
85
|
}
|
|
62
86
|
}
|
|
63
87
|
}
|
|
64
88
|
return dependenciesToInstall;
|
|
65
89
|
}
|
|
90
|
+
/**
|
|
91
|
+
* Resolve a relative import to an absolute file or folder path inside
|
|
92
|
+
* apps/lib (skipping extension guesses — caller knows what they want).
|
|
93
|
+
* Returns null when nothing exists.
|
|
94
|
+
*/
|
|
95
|
+
function resolveRelative(fromDir, moduleName) {
|
|
96
|
+
const base = path.resolve(fromDir, moduleName);
|
|
97
|
+
const candidates = [base, `${base}.tsx`, `${base}.ts`, path.join(base, "index.ts"), path.join(base, "index.tsx")];
|
|
98
|
+
for (const c of candidates) {
|
|
99
|
+
if (fs.existsSync(c))
|
|
100
|
+
return c;
|
|
101
|
+
}
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Given an absolute path inside apps/lib, route it to the right add* command
|
|
106
|
+
* by inspecting which top-level folder it lives in.
|
|
107
|
+
*/
|
|
108
|
+
function routeByLocation(absPath) {
|
|
109
|
+
const marker = `${path.sep}apps${path.sep}lib${path.sep}`;
|
|
110
|
+
const idx = absPath.indexOf(marker);
|
|
111
|
+
if (idx === -1)
|
|
112
|
+
return;
|
|
113
|
+
const after = absPath.slice(idx + marker.length);
|
|
114
|
+
const [folder, ...rest] = after.split(path.sep);
|
|
115
|
+
const entry = rest[0];
|
|
116
|
+
if (!entry)
|
|
117
|
+
return;
|
|
118
|
+
switch (folder) {
|
|
119
|
+
case "components":
|
|
120
|
+
add(stripExt(entry));
|
|
121
|
+
break;
|
|
122
|
+
case "hooks":
|
|
123
|
+
addHook(entry);
|
|
124
|
+
break;
|
|
125
|
+
case "utils":
|
|
126
|
+
addUtil(entry);
|
|
127
|
+
break;
|
|
128
|
+
case "layouts":
|
|
129
|
+
add(stripExt(entry));
|
|
130
|
+
break;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function stripExt(name) {
|
|
134
|
+
return name.replace(/\.(tsx?|jsx?)$/, "");
|
|
135
|
+
}
|
|
66
136
|
//# sourceMappingURL=getDependenciesAndInstallNestedComponents.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"getDependenciesAndInstallNestedComponents.js","sourceRoot":"","sources":["../../../cli/src/shared/getDependenciesAndInstallNestedComponents.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,IAAI,CAAC;AACzB,OAAO,KAAK,IAAI,MAAM,MAAM,CAAC;AAC7B,OAAO,EAAE,OAAO,EAAE,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AAC9C,OAAO,EAAE,GAAG,EAAE,MAAM,oBAAoB,CAAC;AAEzC
|
|
1
|
+
{"version":3,"file":"getDependenciesAndInstallNestedComponents.js","sourceRoot":"","sources":["../../../cli/src/shared/getDependenciesAndInstallNestedComponents.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: FormStepper
|
|
3
|
+
description: Pill-shaped multi-step indicator for forms and wizards. Three semantic step types (default, success, negative) with resting, hover, selected, and selected-hover states. Full LTR and RTL support.
|
|
4
|
+
component: true
|
|
5
|
+
group: Forms
|
|
6
|
+
keywords: [form-stepper, stepper, wizard, steps, pill, multi-step, form, indicator, RTL]
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
# FormStepper
|
|
10
|
+
|
|
11
|
+
A pill-shaped multi-step indicator for forms and wizards. Each step renders a circular indicator and a label inside a pill. Selection swaps the pill background to black with a white label; hover deepens the shadow on selected pills and grows the label gap on non-selected ones. The status badge on the indicator switches the visual to `success` (green check) or `negative` (red info).
|
|
12
|
+
|
|
13
|
+
The component is composed of `FormStepper`, `FormStep`, `FormStepIndicator`, and `FormStepLabel`.
|
|
14
|
+
|
|
15
|
+
## Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npx torch-glare@latest add FormStepper
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Imports
|
|
22
|
+
|
|
23
|
+
```typescript
|
|
24
|
+
import {
|
|
25
|
+
FormStepper,
|
|
26
|
+
FormStep,
|
|
27
|
+
FormStepIndicator,
|
|
28
|
+
FormStepLabel,
|
|
29
|
+
} from '@/components/FormStepper'
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
## Basic Usage
|
|
33
|
+
|
|
34
|
+
```tsx
|
|
35
|
+
import { useState } from 'react'
|
|
36
|
+
import {
|
|
37
|
+
FormStepper,
|
|
38
|
+
FormStep,
|
|
39
|
+
FormStepIndicator,
|
|
40
|
+
FormStepLabel,
|
|
41
|
+
} from '@/components/FormStepper'
|
|
42
|
+
|
|
43
|
+
export function BasicFormStepper() {
|
|
44
|
+
const [activeStep, setActiveStep] = useState(0)
|
|
45
|
+
|
|
46
|
+
return (
|
|
47
|
+
<FormStepper activeStep={activeStep}>
|
|
48
|
+
<FormStep index={0} type="success" onClick={() => setActiveStep(0)}>
|
|
49
|
+
<FormStepIndicator />
|
|
50
|
+
<FormStepLabel>Account</FormStepLabel>
|
|
51
|
+
</FormStep>
|
|
52
|
+
<FormStep index={1} type="default" onClick={() => setActiveStep(1)}>
|
|
53
|
+
<FormStepIndicator />
|
|
54
|
+
<FormStepLabel>Profile</FormStepLabel>
|
|
55
|
+
</FormStep>
|
|
56
|
+
<FormStep index={2} type="negative" onClick={() => setActiveStep(2)}>
|
|
57
|
+
<FormStepIndicator />
|
|
58
|
+
<FormStepLabel>Payment</FormStepLabel>
|
|
59
|
+
</FormStep>
|
|
60
|
+
<FormStep index={3} type="default" onClick={() => setActiveStep(3)}>
|
|
61
|
+
<FormStepIndicator />
|
|
62
|
+
<FormStepLabel>Confirm</FormStepLabel>
|
|
63
|
+
</FormStep>
|
|
64
|
+
</FormStepper>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
`FormStepper.activeStep` drives which pill renders selected — each `FormStep` auto-selects when its `index` matches. Pass `selected` on a step to override the match.
|
|
70
|
+
|
|
71
|
+
## Examples
|
|
72
|
+
|
|
73
|
+
### Step Types
|
|
74
|
+
|
|
75
|
+
Three semantic types. `success` and `negative` add a small status badge on the indicator (check / info icon) and use filled colors when selected. `default` uses a gray ring at rest, blue ring on hover, and a solid blue fill when selected.
|
|
76
|
+
|
|
77
|
+
```tsx
|
|
78
|
+
export function StepTypes() {
|
|
79
|
+
return (
|
|
80
|
+
<FormStepper>
|
|
81
|
+
<FormStep index={0} type="default" selected={false}>
|
|
82
|
+
<FormStepIndicator />
|
|
83
|
+
<FormStepLabel>Default</FormStepLabel>
|
|
84
|
+
</FormStep>
|
|
85
|
+
<FormStep index={1} type="success" selected={false}>
|
|
86
|
+
<FormStepIndicator />
|
|
87
|
+
<FormStepLabel>Success</FormStepLabel>
|
|
88
|
+
</FormStep>
|
|
89
|
+
<FormStep index={2} type="negative" selected={false}>
|
|
90
|
+
<FormStepIndicator />
|
|
91
|
+
<FormStepLabel>Negative</FormStepLabel>
|
|
92
|
+
</FormStep>
|
|
93
|
+
</FormStepper>
|
|
94
|
+
)
|
|
95
|
+
}
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Selected state
|
|
99
|
+
|
|
100
|
+
```tsx
|
|
101
|
+
export function SelectedSteps() {
|
|
102
|
+
return (
|
|
103
|
+
<FormStepper>
|
|
104
|
+
<FormStep index={0} type="default" selected>
|
|
105
|
+
<FormStepIndicator />
|
|
106
|
+
<FormStepLabel>Default</FormStepLabel>
|
|
107
|
+
</FormStep>
|
|
108
|
+
<FormStep index={1} type="success" selected>
|
|
109
|
+
<FormStepIndicator />
|
|
110
|
+
<FormStepLabel>Success</FormStepLabel>
|
|
111
|
+
</FormStep>
|
|
112
|
+
<FormStep index={2} type="negative" selected>
|
|
113
|
+
<FormStepIndicator />
|
|
114
|
+
<FormStepLabel>Negative</FormStepLabel>
|
|
115
|
+
</FormStep>
|
|
116
|
+
</FormStepper>
|
|
117
|
+
)
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### RTL direction
|
|
122
|
+
|
|
123
|
+
The pill, label spacing, and indicator badge all flip under `dir="rtl"`.
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
export function RTLFormStepper() {
|
|
127
|
+
return (
|
|
128
|
+
<div dir="rtl">
|
|
129
|
+
<FormStepper>
|
|
130
|
+
<FormStep index={0} type="default" selected>
|
|
131
|
+
<FormStepIndicator />
|
|
132
|
+
<FormStepLabel>افتراضي</FormStepLabel>
|
|
133
|
+
</FormStep>
|
|
134
|
+
<FormStep index={1} type="success">
|
|
135
|
+
<FormStepIndicator />
|
|
136
|
+
<FormStepLabel>نجاح</FormStepLabel>
|
|
137
|
+
</FormStep>
|
|
138
|
+
<FormStep index={2} type="negative">
|
|
139
|
+
<FormStepIndicator />
|
|
140
|
+
<FormStepLabel>خطأ</FormStepLabel>
|
|
141
|
+
</FormStep>
|
|
142
|
+
</FormStepper>
|
|
143
|
+
</div>
|
|
144
|
+
)
|
|
145
|
+
}
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Custom badge icon
|
|
149
|
+
|
|
150
|
+
`FormStepIndicator.badgeIcon` overrides the default check / info icon for `success` / `negative` types.
|
|
151
|
+
|
|
152
|
+
```tsx
|
|
153
|
+
<FormStep index={0} type="success" selected>
|
|
154
|
+
<FormStepIndicator badgeIcon={<i className="ri-shield-check-line" />} />
|
|
155
|
+
<FormStepLabel>Verified</FormStepLabel>
|
|
156
|
+
</FormStep>
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Custom indicator content
|
|
160
|
+
|
|
161
|
+
Children of `FormStepIndicator` replace the auto-rendered step number.
|
|
162
|
+
|
|
163
|
+
```tsx
|
|
164
|
+
<FormStep index={0} type="default" selected>
|
|
165
|
+
<FormStepIndicator>
|
|
166
|
+
<i className="ri-user-line" />
|
|
167
|
+
</FormStepIndicator>
|
|
168
|
+
<FormStepLabel>Account</FormStepLabel>
|
|
169
|
+
</FormStep>
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## API Reference
|
|
173
|
+
|
|
174
|
+
### FormStepper
|
|
175
|
+
|
|
176
|
+
| Prop | Type | Default | Description |
|
|
177
|
+
| ------------ | ------------------------------- | ------- | ----------------------------------------------------------------- |
|
|
178
|
+
| `activeStep` | `number` | `0` | Zero-based index of the currently selected step. |
|
|
179
|
+
| `theme` | `'dark' \| 'light' \| 'default'` | — | Theme override applied via `data-theme`. |
|
|
180
|
+
| `className` | `string` | — | Extra classes merged onto the root `<div>`. |
|
|
181
|
+
|
|
182
|
+
Standard `HTMLAttributes<HTMLDivElement>` are forwarded.
|
|
183
|
+
|
|
184
|
+
### FormStep
|
|
185
|
+
|
|
186
|
+
| Prop | Type | Default | Description |
|
|
187
|
+
| ----------- | --------------------------------------- | ----------- | -------------------------------------------------------------------------- |
|
|
188
|
+
| `index` | `number` | `0` | Zero-based step index. Matched against `FormStepper.activeStep`. |
|
|
189
|
+
| `type` | `'default' \| 'success' \| 'negative'` | `'default'` | Visual type. `success` and `negative` add a status badge on the indicator. |
|
|
190
|
+
| `selected` | `boolean` | — | Force the selected state, overriding the index/`activeStep` match. |
|
|
191
|
+
| `className` | `string` | — | Extra classes merged onto the pill root. |
|
|
192
|
+
|
|
193
|
+
Standard `HTMLAttributes<HTMLDivElement>` (minus `type`) are forwarded — typical use is `onClick` for navigation.
|
|
194
|
+
|
|
195
|
+
### FormStepIndicator
|
|
196
|
+
|
|
197
|
+
| Prop | Type | Default | Description |
|
|
198
|
+
| ----------- | ----------- | ------- | ----------------------------------------------------------------------------- |
|
|
199
|
+
| `badgeIcon` | `ReactNode` | — | Override the default badge icon (check for `success`, info for `negative`). |
|
|
200
|
+
| `children` | `ReactNode` | — | Replaces the auto-rendered step number. |
|
|
201
|
+
| `className` | `string` | — | Extra classes merged onto the indicator `<div>`. |
|
|
202
|
+
|
|
203
|
+
### FormStepLabel
|
|
204
|
+
|
|
205
|
+
Forwards `HTMLAttributes<HTMLDivElement>`. Color and label spacing follow the parent `FormStep` selection state.
|
|
206
|
+
|
|
207
|
+
## Styling
|
|
208
|
+
|
|
209
|
+
- Pill height: `28px`, fully rounded, `2px` inner padding.
|
|
210
|
+
- Indicator: `24×24px` circle, `border-[3px]` for `default`, solid fill for `success`/`negative`.
|
|
211
|
+
- Status badge: `15×15px` circle pinned to the top-right of the indicator (top-left under RTL), with `border` matching the page background.
|
|
212
|
+
- Selection: `bg-[#000000]` pill with `text-[#FFFFFF]` label and a `0 0 32px 2px rgba(0,0,0,0.05)` shadow that deepens on hover.
|
|
213
|
+
- Non-selected hover: `bg-[#FFFFFF]` pill, label gap grows from `6px` to `9px`, ring color flips to `#004699`.
|
|
214
|
+
|
|
215
|
+
## TypeScript Types
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
type FormStepperType = 'default' | 'success' | 'negative'
|
|
219
|
+
|
|
220
|
+
interface FormStepperProps extends React.HTMLAttributes<HTMLDivElement> {
|
|
221
|
+
activeStep?: number
|
|
222
|
+
theme?: 'dark' | 'light' | 'default'
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface FormStepProps
|
|
226
|
+
extends Omit<React.HTMLAttributes<HTMLDivElement>, 'type'> {
|
|
227
|
+
index?: number
|
|
228
|
+
type?: FormStepperType
|
|
229
|
+
selected?: boolean
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
## Accessibility
|
|
234
|
+
|
|
235
|
+
- Each `FormStep` is a focusable interactive surface — attach `onClick` and (if needed) `role="button"` plus `tabIndex={0}` for keyboard navigation.
|
|
236
|
+
- The status badge is `aria-hidden`; the meaning should be carried by the label text (e.g. `"Payment — error"`).
|
|
237
|
+
- Color is never the sole signal for `success`/`negative` — pair with text or an off-screen description.
|
|
238
|
+
|
|
239
|
+
## Best Practices
|
|
240
|
+
|
|
241
|
+
1. Drive selection with `activeStep` from the parent form state — avoid setting `selected` per step manually.
|
|
242
|
+
2. Use `success` only for *completed and validated* steps, `negative` only for *failed* steps. Default = pending or current.
|
|
243
|
+
3. Keep labels short — the pill grows by `~3px` on hover, and long labels make that animation jittery.
|
|
244
|
+
4. Wire `onClick` for non-linear navigation (jump-to-step). For strict wizards, omit `onClick` on future steps.
|