@antscorp/ui 0.1.2 → 0.1.3
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/README.md +1 -1
- package/dist/atoms/AddButton.d.ts +1 -1
- package/dist/atoms/AddButton.doc.d.ts +21 -0
- package/dist/atoms/AddGlyph.doc.d.ts +16 -0
- package/dist/atoms/Chip.doc.d.ts +29 -0
- package/dist/atoms/ChipSkeletons.doc.d.ts +21 -0
- package/dist/atoms/FieldHeading.doc.d.ts +15 -0
- package/dist/atoms/HoverSwap.doc.d.ts +25 -0
- package/dist/atoms/InfoTip.doc.d.ts +25 -0
- package/dist/atoms/InfoTip.js +2 -0
- package/dist/atoms/JointLabel.doc.d.ts +15 -0
- package/dist/atoms/LabeledDivider.d.ts +1 -1
- package/dist/atoms/LabeledDivider.doc.d.ts +21 -0
- package/dist/atoms/LogoImage.doc.d.ts +21 -0
- package/dist/atoms/PanelSearchInput.d.ts +1 -1
- package/dist/atoms/PanelSearchInput.doc.d.ts +25 -0
- package/dist/atoms/PathMark.doc.d.ts +16 -0
- package/dist/atoms/RemoveButton.doc.d.ts +16 -0
- package/dist/atoms/RowSkeletons.doc.d.ts +25 -0
- package/dist/atoms/TextAction.d.ts +3 -3
- package/dist/atoms/TextAction.doc.d.ts +25 -0
- package/dist/atoms/TruncatedOption.d.ts +1 -1
- package/dist/atoms/TruncatedOption.doc.d.ts +24 -0
- package/dist/atoms/TruncatedText.doc.d.ts +15 -0
- package/dist/cli.js +248 -0
- package/dist/doc/schema.d.ts +34 -0
- package/dist/doc/schema.js +33 -0
- package/dist/docs.json +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +53 -51
- package/dist/lib/useLoadingShown.d.ts +1 -1
- package/dist/molecules/AccentCard.d.ts +2 -3
- package/dist/molecules/AccentCard.doc.d.ts +25 -0
- package/dist/molecules/CheckGroup.doc.d.ts +25 -0
- package/dist/molecules/CheckRow.d.ts +1 -1
- package/dist/molecules/CheckRow.doc.d.ts +25 -0
- package/dist/molecules/ChoiceDialog.doc.d.ts +21 -0
- package/dist/molecules/ChoiceTiles.d.ts +1 -1
- package/dist/molecules/ChoiceTiles.doc.d.ts +21 -0
- package/dist/molecules/CommitTextField.doc.d.ts +29 -0
- package/dist/molecules/ConfirmDialog.doc.d.ts +21 -0
- package/dist/molecules/DateTimeInput.doc.d.ts +25 -0
- package/dist/molecules/DurationInput.doc.d.ts +25 -0
- package/dist/molecules/FieldGroup.d.ts +1 -1
- package/dist/molecules/FieldGroup.doc.d.ts +25 -0
- package/dist/molecules/FieldRow.d.ts +1 -1
- package/dist/molecules/FieldRow.doc.d.ts +24 -0
- package/dist/molecules/FieldSkeleton.doc.d.ts +25 -0
- package/dist/molecules/FrequencyLimitRow.doc.d.ts +25 -0
- package/dist/molecules/InlineEditableText.doc.d.ts +25 -0
- package/dist/molecules/LoadMoreRow.doc.d.ts +21 -0
- package/dist/molecules/LoadState.doc.d.ts +21 -0
- package/dist/molecules/MetaTable.d.ts +1 -1
- package/dist/molecules/MetaTable.doc.d.ts +25 -0
- package/dist/molecules/PercentRow.doc.d.ts +25 -0
- package/dist/molecules/PhoneFrame.d.ts +1 -1
- package/dist/molecules/PhoneFrame.doc.d.ts +21 -0
- package/dist/molecules/ProblemsButton.doc.d.ts +25 -0
- package/dist/molecules/RemovableRow.d.ts +1 -1
- package/dist/molecules/RemovableRow.doc.d.ts +25 -0
- package/dist/molecules/RevealRadioGroup.doc.d.ts +25 -0
- package/dist/molecules/RevealSwitch.doc.d.ts +25 -0
- package/dist/molecules/RuleRow.doc.d.ts +25 -0
- package/dist/molecules/Select.d.ts +2 -2
- package/dist/molecules/Select.doc.d.ts +30 -0
- package/dist/molecules/Select.js +27 -27
- package/dist/molecules/SideLabelRow.d.ts +1 -1
- package/dist/molecules/SideLabelRow.doc.d.ts +20 -0
- package/dist/molecules/SplitButton.d.ts +1 -1
- package/dist/molecules/SplitButton.doc.d.ts +25 -0
- package/dist/molecules/StatusButton.doc.d.ts +25 -0
- package/dist/molecules/TagSelect.d.ts +2 -2
- package/dist/molecules/TagSelect.doc.d.ts +25 -0
- package/dist/molecules/ToggleGrid.doc.d.ts +25 -0
- package/dist/molecules/TokenTextField.doc.d.ts +29 -0
- package/dist/molecules/TransferLayout.d.ts +1 -1
- package/dist/molecules/TransferLayout.doc.d.ts +25 -0
- package/dist/molecules/TreeOptions.d.ts +1 -1
- package/dist/molecules/TreeOptions.doc.d.ts +25 -0
- package/dist/organisms/ChipListAddPopover.doc.d.ts +25 -0
- package/dist/organisms/HourOfDayRow.doc.d.ts +25 -0
- package/dist/organisms/HourOfWeekGrid.doc.d.ts +25 -0
- package/dist/organisms/RepeatableList.doc.d.ts +21 -0
- package/dist/organisms/ResizableDrawer.doc.d.ts +25 -0
- package/dist/organisms/RuleGroups.d.ts +3 -3
- package/dist/organisms/RuleGroups.doc.d.ts +21 -0
- package/dist/organisms/RuleList.doc.d.ts +25 -0
- package/dist/organisms/SearchableGroupedList.d.ts +1 -1
- package/dist/organisms/SearchableGroupedList.doc.d.ts +25 -0
- package/dist/organisms/TokenPickerDialog.doc.d.ts +21 -0
- package/dist/organisms/TransferPicker.d.ts +1 -1
- package/dist/organisms/TransferPicker.doc.d.ts +29 -0
- package/dist/organisms/TreeSearchPanel.doc.d.ts +25 -0
- package/dist/organisms/TreeSelect.d.ts +3 -3
- package/dist/organisms/TreeSelect.doc.d.ts +29 -0
- package/dist/theme/AntsomiTheme.doc.d.ts +15 -0
- package/dist/theme/AntsomiTheme.doc.js +22 -0
- package/package.json +17 -6
- package/src/atoms/AddButton.doc.ts +36 -0
- package/src/atoms/AddButton.tsx +1 -1
- package/src/atoms/AddGlyph.doc.ts +26 -0
- package/src/atoms/Chip.doc.ts +45 -0
- package/src/atoms/Chip.tsx +2 -2
- package/src/atoms/ChipSkeletons.doc.ts +31 -0
- package/src/atoms/FieldHeading.doc.ts +22 -0
- package/src/atoms/HoverSwap.doc.ts +39 -0
- package/src/atoms/InfoTip.doc.ts +37 -0
- package/src/atoms/InfoTip.tsx +2 -2
- package/src/atoms/JointLabel.doc.ts +23 -0
- package/src/atoms/LabeledDivider.doc.ts +35 -0
- package/src/atoms/LabeledDivider.tsx +1 -1
- package/src/atoms/LogoImage.doc.ts +42 -0
- package/src/atoms/PanelSearchInput.doc.ts +41 -0
- package/src/atoms/PanelSearchInput.tsx +1 -1
- package/src/atoms/PathMark.doc.ts +25 -0
- package/src/atoms/RemoveButton.doc.ts +26 -0
- package/src/atoms/RowSkeletons.doc.ts +43 -0
- package/src/atoms/TextAction.doc.ts +40 -0
- package/src/atoms/TextAction.tsx +4 -4
- package/src/atoms/TruncatedOption.doc.ts +39 -0
- package/src/atoms/TruncatedOption.tsx +1 -1
- package/src/atoms/TruncatedText.doc.ts +22 -0
- package/src/doc/schema.ts +67 -0
- package/src/index.ts +2 -0
- package/src/lib/useLoadMore.ts +1 -2
- package/src/lib/useLoadingShown.ts +1 -1
- package/src/molecules/AccentCard.doc.ts +43 -0
- package/src/molecules/AccentCard.tsx +7 -8
- package/src/molecules/CheckGroup.doc.ts +40 -0
- package/src/molecules/CheckRow.doc.ts +43 -0
- package/src/molecules/CheckRow.tsx +1 -1
- package/src/molecules/ChoiceDialog.doc.ts +48 -0
- package/src/molecules/ChoiceTiles.doc.ts +42 -0
- package/src/molecules/ChoiceTiles.tsx +3 -3
- package/src/molecules/CommitTextField.doc.ts +41 -0
- package/src/molecules/ConfirmDialog.doc.ts +43 -0
- package/src/molecules/DateTimeInput.doc.ts +48 -0
- package/src/molecules/DurationInput.doc.ts +36 -0
- package/src/molecules/DurationInput.tsx +2 -2
- package/src/molecules/FieldGroup.doc.ts +41 -0
- package/src/molecules/FieldGroup.tsx +1 -1
- package/src/molecules/FieldRow.doc.ts +36 -0
- package/src/molecules/FieldRow.tsx +1 -1
- package/src/molecules/FieldSkeleton.doc.ts +38 -0
- package/src/molecules/FrequencyLimitRow.doc.ts +48 -0
- package/src/molecules/FrequencyLimitRow.tsx +1 -1
- package/src/molecules/InlineEditableText.doc.ts +41 -0
- package/src/molecules/LoadMoreRow.doc.ts +36 -0
- package/src/molecules/LoadState.doc.ts +42 -0
- package/src/molecules/MetaTable.doc.ts +46 -0
- package/src/molecules/MetaTable.tsx +1 -1
- package/src/molecules/PercentRow.doc.ts +48 -0
- package/src/molecules/PhoneFrame.doc.ts +46 -0
- package/src/molecules/PhoneFrame.tsx +2 -2
- package/src/molecules/ProblemsButton.doc.ts +41 -0
- package/src/molecules/RemovableRow.doc.ts +48 -0
- package/src/molecules/RemovableRow.tsx +2 -2
- package/src/molecules/RevealRadioGroup.doc.ts +41 -0
- package/src/molecules/RevealSwitch.doc.ts +38 -0
- package/src/molecules/RuleRow.doc.ts +43 -0
- package/src/molecules/Select.doc.ts +62 -0
- package/src/molecules/Select.tsx +2 -2
- package/src/molecules/SideLabelRow.doc.ts +35 -0
- package/src/molecules/SideLabelRow.tsx +2 -2
- package/src/molecules/SplitButton.doc.ts +41 -0
- package/src/molecules/SplitButton.tsx +1 -1
- package/src/molecules/StatusButton.doc.ts +39 -0
- package/src/molecules/TagSelect.doc.ts +41 -0
- package/src/molecules/TagSelect.tsx +5 -5
- package/src/molecules/ToggleGrid.doc.ts +43 -0
- package/src/molecules/TokenTextField.doc.ts +41 -0
- package/src/molecules/TransferLayout.doc.ts +42 -0
- package/src/molecules/TransferLayout.tsx +2 -3
- package/src/molecules/TreeOptions.doc.ts +38 -0
- package/src/molecules/TreeOptions.tsx +6 -6
- package/src/organisms/ChipListAddPopover.doc.ts +54 -0
- package/src/organisms/HourOfDayRow.doc.ts +43 -0
- package/src/organisms/HourOfDayRow.tsx +1 -1
- package/src/organisms/HourOfWeekGrid.doc.ts +48 -0
- package/src/organisms/HourOfWeekGrid.tsx +1 -1
- package/src/organisms/RepeatableList.doc.ts +49 -0
- package/src/organisms/ResizableDrawer.doc.ts +48 -0
- package/src/organisms/RuleGroups.doc.ts +49 -0
- package/src/organisms/RuleGroups.tsx +3 -3
- package/src/organisms/RuleList.doc.ts +43 -0
- package/src/organisms/SearchableGroupedList.doc.ts +49 -0
- package/src/organisms/SearchableGroupedList.tsx +2 -2
- package/src/organisms/TokenPickerDialog.doc.ts +54 -0
- package/src/organisms/TransferPicker.doc.ts +69 -0
- package/src/organisms/TransferPicker.tsx +3 -3
- package/src/organisms/TreeSearchPanel.doc.ts +43 -0
- package/src/organisms/TreeSearchPanel.tsx +1 -1
- package/src/organisms/TreeSelect.doc.ts +56 -0
- package/src/organisms/TreeSelect.tsx +4 -4
- package/src/theme/AntsomiTheme.doc.ts +23 -0
package/dist/cli.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/cli/main.ts
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
|
|
6
|
+
// src/cli/catalog.ts
|
|
7
|
+
var record = (value) => typeof value === "object" && value !== null;
|
|
8
|
+
var texts = (value) => Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
9
|
+
var objects = (value, check) => Array.isArray(value) && value.every((item) => record(item) && check(item));
|
|
10
|
+
var optional = (value, check) => value === undefined || check(value);
|
|
11
|
+
var text = (value) => typeof value === "string";
|
|
12
|
+
function component(value) {
|
|
13
|
+
return ["name", "level", "category", "import", "description", "usage", "primaryExample"].every((key) => text(value[key])) && texts(value["keywords"]) && objects(value["bestPractices"], (item) => typeof item["guidance"] === "boolean" && text(item["description"])) && optional(value["anatomy"], (items) => objects(items, (item) => text(item["name"]) && typeof item["required"] === "boolean" && text(item["description"]))) && optional(value["accessibility"], texts) && optional(value["related"], (items) => objects(items, (item) => text(item["name"]) && text(item["when"]))) && objects(value["props"], (item) => text(item["path"]) && text(item["type"]) && typeof item["required"] === "boolean" && optional(item["requiredWhenParent"], (flag) => flag === true) && optional(item["default"], text) && text(item["description"])) && objects(value["examples"], (item) => ["name", "description", "source", "file"].every((key) => text(item[key])));
|
|
14
|
+
}
|
|
15
|
+
function isCatalog(value) {
|
|
16
|
+
return record(value) && value["schemaVersion"] === 1 && text(value["package"]) && text(value["version"]) && objects(value["components"], component);
|
|
17
|
+
}
|
|
18
|
+
function parseCatalog(source) {
|
|
19
|
+
const value = JSON.parse(source);
|
|
20
|
+
if (!isCatalog(value))
|
|
21
|
+
throw new Error("Invalid component catalog (expected schemaVersion 1). Reinstall @antscorp/ui.");
|
|
22
|
+
return value;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
// src/cli/run.ts
|
|
26
|
+
import { parseArgs } from "node:util";
|
|
27
|
+
|
|
28
|
+
// src/cli/format.ts
|
|
29
|
+
var nextCommand = (name) => `bunx @antscorp/ui component ${name}`;
|
|
30
|
+
var line = (text) => text.replaceAll(/\s+/gu, " ").trim();
|
|
31
|
+
var propsFor = (view) => ({
|
|
32
|
+
requiredProps: view.props.filter((prop) => prop.required),
|
|
33
|
+
keyProps: view.props.filter((prop) => !prop.required && (!prop.path.includes(".") || prop.path.startsWith("labels.")))
|
|
34
|
+
});
|
|
35
|
+
var denseData = (catalog, view) => {
|
|
36
|
+
const props = propsFor(view);
|
|
37
|
+
const fact = (prop) => ({
|
|
38
|
+
path: prop.path,
|
|
39
|
+
type: prop.required ? prop.type : prop.type.replace(/ \| undefined$/u, ""),
|
|
40
|
+
description: line(prop.description),
|
|
41
|
+
default: prop.default,
|
|
42
|
+
requiredWhenParent: prop.requiredWhenParent
|
|
43
|
+
});
|
|
44
|
+
return {
|
|
45
|
+
name: view.name,
|
|
46
|
+
package: catalog.package,
|
|
47
|
+
version: catalog.version,
|
|
48
|
+
category: view.category,
|
|
49
|
+
import: view.import,
|
|
50
|
+
usage: line(view.usage),
|
|
51
|
+
related: view.related,
|
|
52
|
+
requiredProps: props.requiredProps.map(fact),
|
|
53
|
+
bestPractices: view.bestPractices,
|
|
54
|
+
keyProps: props.keyProps.map(fact),
|
|
55
|
+
primaryExample: view.primaryExample,
|
|
56
|
+
example: `${nextCommand(view.name)} --example ${view.primaryExample}`,
|
|
57
|
+
more: [
|
|
58
|
+
`${nextCommand(view.name)} --full`,
|
|
59
|
+
"bunx @antscorp/ui search <query>",
|
|
60
|
+
"bunx @antscorp/ui list"
|
|
61
|
+
]
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
function propLine(prop) {
|
|
65
|
+
const parent = prop.path.slice(0, prop.path.lastIndexOf("."));
|
|
66
|
+
const state = prop.required ? "required" : prop.requiredWhenParent === true ? `required when ${parent} is set` : "optional";
|
|
67
|
+
return `- ${prop.path}: ${line(prop.type)} (${state}${prop.default === undefined ? "" : `; default: ${prop.default}`}) — ${line(prop.description)}`;
|
|
68
|
+
}
|
|
69
|
+
function keyPropLines(props) {
|
|
70
|
+
return props.flatMap((prop, index) => {
|
|
71
|
+
if (!prop.path.startsWith("labels."))
|
|
72
|
+
return [propLine(prop)];
|
|
73
|
+
return [
|
|
74
|
+
...props[index - 1]?.path.startsWith("labels") === true ? [] : ["- labels fields (see required props):"],
|
|
75
|
+
` ${propLine(prop)}`
|
|
76
|
+
];
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function formatComponent(catalog, view, full) {
|
|
80
|
+
const { requiredProps: required, keyProps } = propsFor(view);
|
|
81
|
+
return [
|
|
82
|
+
`${view.name} — ${catalog.package} v${catalog.version} — ${view.category}`,
|
|
83
|
+
view.import,
|
|
84
|
+
`Use: ${line(view.usage)}`,
|
|
85
|
+
...view.related === undefined ? [] : ["Alternatives:", ...view.related.map((item) => `- ${item.name}: ${line(item.when)}`)],
|
|
86
|
+
"Required props:",
|
|
87
|
+
...required.length === 0 ? ["(none)"] : required.map(propLine),
|
|
88
|
+
"Rules:",
|
|
89
|
+
...view.bestPractices.map((item) => `- ${item.guidance ? "Do" : "Don't"}: ${line(item.description)}`),
|
|
90
|
+
full ? "All props:" : "Key props (nested labels follow their parent):",
|
|
91
|
+
...full ? view.props.map(propLine) : keyPropLines(keyProps),
|
|
92
|
+
...full && view.anatomy !== undefined ? [
|
|
93
|
+
"Anatomy:",
|
|
94
|
+
...view.anatomy.map((item) => `- ${item.name} (${item.required ? "required" : "optional"}): ${line(item.description)}`)
|
|
95
|
+
] : [],
|
|
96
|
+
...full && view.accessibility !== undefined ? ["Accessibility:", ...view.accessibility.map((item) => `- ${line(item)}`)] : [],
|
|
97
|
+
`Primary example: ${view.primaryExample}`,
|
|
98
|
+
`Example: ${nextCommand(view.name)} --example ${view.primaryExample}`,
|
|
99
|
+
...full ? ["Examples:", ...view.examples.map((item) => `- ${item.name}: ${line(item.description)}`)] : [],
|
|
100
|
+
`more: ${nextCommand(view.name)} --full`,
|
|
101
|
+
"more: bunx @antscorp/ui search <query> | bunx @antscorp/ui list"
|
|
102
|
+
].join(`
|
|
103
|
+
`);
|
|
104
|
+
}
|
|
105
|
+
function exampleData(view, name) {
|
|
106
|
+
const example = view.examples.find((item) => item.name.toLowerCase() === name.toLowerCase());
|
|
107
|
+
if (example === undefined)
|
|
108
|
+
throw new Error(`Unknown example ${name} for ${view.name}. Examples: ${view.examples.map((item) => item.name).join(", ")}`);
|
|
109
|
+
return {
|
|
110
|
+
...example,
|
|
111
|
+
notice: "Storybook source. This declaration requires the story module's imports, data and metadata; it is not a standalone consumer example."
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
function search(catalog, query) {
|
|
115
|
+
const needle = query.toLowerCase().trim();
|
|
116
|
+
const terms = needle.split(/\s+/u);
|
|
117
|
+
return catalog.components.map((view) => {
|
|
118
|
+
const name = view.name.toLowerCase();
|
|
119
|
+
const score = name === needle ? 1e5 : terms.reduce((total, term) => total + (name.includes(term) ? 1000 : view.keywords.some((word) => word.toLowerCase().includes(term)) ? 100 : view.category.toLowerCase().includes(term) ? 10 : view.usage.toLowerCase().includes(term) ? 1 : 0), 0);
|
|
120
|
+
return { view, score };
|
|
121
|
+
}).filter((item) => item.score > 0).toSorted((left, right) => right.score - left.score || left.view.name.localeCompare(right.view.name, "en")).slice(0, 5).map(({ view }) => ({
|
|
122
|
+
name: view.name,
|
|
123
|
+
category: view.category,
|
|
124
|
+
description: view.description,
|
|
125
|
+
next: nextCommand(view.name)
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
function suggestions(catalog, name) {
|
|
129
|
+
function distance(candidate) {
|
|
130
|
+
let row = Array.from({ length: candidate.length + 1 }, (_, index) => index);
|
|
131
|
+
for (const [i, char] of name.toLowerCase().split("").entries()) {
|
|
132
|
+
const next = [i + 1];
|
|
133
|
+
for (const [j, other] of candidate.toLowerCase().split("").entries())
|
|
134
|
+
next.push(Math.min((next[j] ?? 0) + 1, (row[j + 1] ?? 0) + 1, (row[j] ?? 0) + Number(char !== other)));
|
|
135
|
+
row = next;
|
|
136
|
+
}
|
|
137
|
+
return row.at(-1) ?? 0;
|
|
138
|
+
}
|
|
139
|
+
return catalog.components.map((view) => ({ name: view.name, distance: distance(view.name) })).toSorted((left, right) => left.distance - right.distance || left.name.localeCompare(right.name, "en")).slice(0, 3).map((view) => view.name);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// src/cli/run.ts
|
|
143
|
+
var USAGE = `Usage: bunx @antscorp/ui <command> [--json]
|
|
144
|
+
component <Name> [--full | --example <Story>]
|
|
145
|
+
search <query> Up to five ranked views, with the next command
|
|
146
|
+
list Every view: name | category | description
|
|
147
|
+
--help Show this help`;
|
|
148
|
+
function componentOutput(catalog, names, full, exampleName) {
|
|
149
|
+
const [name] = names;
|
|
150
|
+
if (name === undefined || names.length !== 1)
|
|
151
|
+
throw new Error("component requires one view name.");
|
|
152
|
+
if (full && exampleName !== undefined)
|
|
153
|
+
throw new Error("Choose --full or --example.");
|
|
154
|
+
const view = catalog.components.find((item) => item.name.toLowerCase() === name.toLowerCase());
|
|
155
|
+
if (view === undefined)
|
|
156
|
+
throw new Error(`Unknown view ${name}. Close names: ${suggestions(catalog, name).join(", ")}`);
|
|
157
|
+
if (exampleName === undefined)
|
|
158
|
+
return {
|
|
159
|
+
data: full ? { package: catalog.package, version: catalog.version, ...view } : denseData(catalog, view),
|
|
160
|
+
text: formatComponent(catalog, view, full)
|
|
161
|
+
};
|
|
162
|
+
const example = exampleData(view, exampleName);
|
|
163
|
+
return {
|
|
164
|
+
data: example,
|
|
165
|
+
text: `${view.name} — ${example.name}
|
|
166
|
+
${example.description}
|
|
167
|
+
${example.file}
|
|
168
|
+
${example.notice}
|
|
169
|
+
|
|
170
|
+
${example.source}`
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
function searchOutput(catalog, words) {
|
|
174
|
+
const query = words.join(" ").trim();
|
|
175
|
+
if (query.length === 0)
|
|
176
|
+
throw new Error("search requires a query.");
|
|
177
|
+
const results = search(catalog, query);
|
|
178
|
+
return {
|
|
179
|
+
data: results,
|
|
180
|
+
text: results.length === 0 ? `No matches for ${JSON.stringify(query)}.` : results.map((view) => `${view.name} | ${view.category} | ${view.description}
|
|
181
|
+
next: ${view.next}`).join(`
|
|
182
|
+
|
|
183
|
+
`)
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
function run(catalog, args) {
|
|
187
|
+
let json = false;
|
|
188
|
+
try {
|
|
189
|
+
const { values, positionals } = parseArgs({
|
|
190
|
+
args: [...args],
|
|
191
|
+
allowPositionals: true,
|
|
192
|
+
options: {
|
|
193
|
+
full: { type: "boolean" },
|
|
194
|
+
example: { type: "string" },
|
|
195
|
+
json: { type: "boolean" },
|
|
196
|
+
help: { type: "boolean", short: "h" }
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
json = values.json === true;
|
|
200
|
+
const [command, ...rest] = positionals;
|
|
201
|
+
const success = (data, formatted) => ({
|
|
202
|
+
code: 0,
|
|
203
|
+
stdout: json ? JSON.stringify(data) : formatted,
|
|
204
|
+
stderr: ""
|
|
205
|
+
});
|
|
206
|
+
if (values.help === true || command === undefined)
|
|
207
|
+
return success({ usage: USAGE }, USAGE);
|
|
208
|
+
if (command !== "component" && (values.full === true || values.example !== undefined))
|
|
209
|
+
throw new Error("--full and --example apply only to component.");
|
|
210
|
+
if (command === "list") {
|
|
211
|
+
if (rest.length > 0)
|
|
212
|
+
throw new Error("list takes no arguments.");
|
|
213
|
+
const views = catalog.components.map((view) => ({
|
|
214
|
+
name: view.name,
|
|
215
|
+
category: view.category,
|
|
216
|
+
description: view.description
|
|
217
|
+
}));
|
|
218
|
+
return success(views, views.map((view) => `${view.name} | ${view.category} | ${view.description}`).join(`
|
|
219
|
+
`));
|
|
220
|
+
}
|
|
221
|
+
if (command === "search") {
|
|
222
|
+
const output = searchOutput(catalog, rest);
|
|
223
|
+
return success(output.data, output.text);
|
|
224
|
+
}
|
|
225
|
+
if (command !== "component")
|
|
226
|
+
throw new Error(`Unknown command ${command}.
|
|
227
|
+
${USAGE}`);
|
|
228
|
+
const output = componentOutput(catalog, rest, values.full === true, values.example);
|
|
229
|
+
return success(output.data, output.text);
|
|
230
|
+
} catch (error) {
|
|
231
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
232
|
+
return { code: 1, stdout: "", stderr: json ? JSON.stringify({ error: message }) : message };
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// src/cli/main.ts
|
|
237
|
+
try {
|
|
238
|
+
const catalog = parseCatalog(readFileSync(new URL("./docs.json", import.meta.url), "utf8"));
|
|
239
|
+
const result = run(catalog, process.argv.slice(2));
|
|
240
|
+
if (result.stdout.length > 0)
|
|
241
|
+
console.log(result.stdout);
|
|
242
|
+
if (result.stderr.length > 0)
|
|
243
|
+
console.error(result.stderr);
|
|
244
|
+
process.exitCode = result.code;
|
|
245
|
+
} catch (error) {
|
|
246
|
+
console.error(`Cannot read component catalog: ${error instanceof Error ? error.message : String(error)}`);
|
|
247
|
+
process.exitCode = 1;
|
|
248
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
/** Structured guidance beside a view; its props and examples come from TypeScript and stories. */
|
|
3
|
+
export declare const componentDocSchema: z.ZodObject<{
|
|
4
|
+
category: z.ZodEnum<{
|
|
5
|
+
"Data display": "Data display";
|
|
6
|
+
Feedback: "Feedback";
|
|
7
|
+
Inputs: "Inputs";
|
|
8
|
+
Layout: "Layout";
|
|
9
|
+
Overlays: "Overlays";
|
|
10
|
+
Selection: "Selection";
|
|
11
|
+
Theme: "Theme";
|
|
12
|
+
}>;
|
|
13
|
+
keywords: z.ZodArray<z.ZodString>;
|
|
14
|
+
related: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
15
|
+
name: z.ZodString;
|
|
16
|
+
when: z.ZodString;
|
|
17
|
+
}, z.core.$strip>>>;
|
|
18
|
+
example: z.ZodOptional<z.ZodString>;
|
|
19
|
+
usage: z.ZodObject<{
|
|
20
|
+
description: z.ZodString;
|
|
21
|
+
bestPractices: z.ZodArray<z.ZodObject<{
|
|
22
|
+
guidance: z.ZodBoolean;
|
|
23
|
+
description: z.ZodString;
|
|
24
|
+
}, z.core.$strip>>;
|
|
25
|
+
anatomy: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
26
|
+
name: z.ZodString;
|
|
27
|
+
required: z.ZodBoolean;
|
|
28
|
+
description: z.ZodString;
|
|
29
|
+
}, z.core.$strip>>>;
|
|
30
|
+
}, z.core.$strip>;
|
|
31
|
+
accessibility: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
32
|
+
}, z.core.$strip>;
|
|
33
|
+
/** Authoring contract for a view's `<View>.doc.ts` export. */
|
|
34
|
+
export type ComponentDoc = z.input<typeof componentDocSchema>;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { z as e } from "zod";
|
|
2
|
+
// src/doc/schema.ts
|
|
3
|
+
var t = e.string().trim().min(1), n = e.object({
|
|
4
|
+
category: e.enum([
|
|
5
|
+
"Inputs",
|
|
6
|
+
"Selection",
|
|
7
|
+
"Feedback",
|
|
8
|
+
"Layout",
|
|
9
|
+
"Data display",
|
|
10
|
+
"Overlays",
|
|
11
|
+
"Theme"
|
|
12
|
+
]).describe("The view's purpose: Inputs edits values; Selection chooses options; Feedback communicates status; Layout arranges content; Data display presents values; Overlays shows dialogs or panels; Theme provides visual tokens and icons."),
|
|
13
|
+
keywords: e.array(t).min(3).describe("At least three search terms for the view."),
|
|
14
|
+
related: e.array(e.object({
|
|
15
|
+
name: t.describe("A kit view or Astryx facade module, such as astryx/Badge."),
|
|
16
|
+
when: t.describe("When to choose this alternative.")
|
|
17
|
+
})).min(1).optional().describe("Alternatives, validated against public views and facade modules during docs generation."),
|
|
18
|
+
example: t.optional().describe("The existing story export shown first, validated during docs generation."),
|
|
19
|
+
usage: e.object({
|
|
20
|
+
description: t.describe("When and how to use the view."),
|
|
21
|
+
bestPractices: e.array(e.object({
|
|
22
|
+
guidance: e.boolean().describe("True for a recommended practice; false for a practice to avoid."),
|
|
23
|
+
description: t.describe("The practice and its reason.")
|
|
24
|
+
})).min(2).refine((e) => e.some((e) => e.guidance) && e.some((e) => !e.guidance), "Include a recommended practice and a practice to avoid.").describe("Recommended practices and practices to avoid."),
|
|
25
|
+
anatomy: e.array(e.object({
|
|
26
|
+
name: t.describe("The part's name."),
|
|
27
|
+
required: e.boolean().describe("Whether this part is always present."),
|
|
28
|
+
description: t.describe("The part's purpose and the condition when it appears.")
|
|
29
|
+
})).min(1).optional().describe("The view's visible and interactive parts.")
|
|
30
|
+
}).describe("Usage, best practices and optional anatomy."),
|
|
31
|
+
accessibility: e.array(t).min(1).optional().describe("Accessible naming and interaction guidance.")
|
|
32
|
+
});
|
|
33
|
+
export { n as componentDocSchema };
|