@astryxdesign/core 0.1.7 → 0.1.8-canary.c5fa19b
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 +65 -0
- package/README.md +30 -19
- package/dist/Avatar/Avatar.d.ts +10 -5
- package/dist/Avatar/Avatar.d.ts.map +1 -1
- package/dist/Avatar/Avatar.js +12 -8
- package/dist/Avatar/AvatarSizeContext.d.ts +1 -1
- package/dist/Avatar/AvatarSizeContext.js +1 -1
- package/dist/Avatar/AvatarStatusDot.d.ts +2 -2
- package/dist/Avatar/AvatarStatusDot.js +2 -2
- package/dist/AvatarGroup/AvatarGroup.d.ts +2 -2
- package/dist/AvatarGroup/AvatarGroup.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroup.js +2 -2
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.d.ts.map +1 -1
- package/dist/AvatarGroup/AvatarGroupOverflow.js +16 -14
- package/dist/Carousel/Carousel.d.ts +3 -2
- package/dist/Carousel/Carousel.d.ts.map +1 -1
- package/dist/Carousel/Carousel.js +32 -2
- package/dist/Chat/ChatMessage.d.ts +1 -1
- package/dist/Chat/ChatMessage.d.ts.map +1 -1
- package/dist/Chat/ChatMessage.js +1 -1
- package/dist/Citation/Citation.d.ts.map +1 -1
- package/dist/Citation/Citation.js +10 -4
- package/dist/Collapsible/Collapsible.d.ts +11 -1
- package/dist/Collapsible/Collapsible.d.ts.map +1 -1
- package/dist/Collapsible/Collapsible.js +36 -4
- package/dist/ContextMenu/ContextMenu.d.ts.map +1 -1
- package/dist/ContextMenu/ContextMenu.js +4 -3
- package/dist/ContextMenu/index.d.ts +3 -0
- package/dist/ContextMenu/index.d.ts.map +1 -1
- package/dist/ContextMenu/index.js +7 -1
- package/dist/DropdownMenu/DropdownMenu.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenu.js +8 -4
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts +89 -0
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuCheckboxItem.js +170 -0
- package/dist/DropdownMenu/DropdownMenuContext.d.ts +17 -1
- package/dist/DropdownMenu/DropdownMenuContext.d.ts.map +1 -1
- package/dist/DropdownMenu/DropdownMenuContext.js +18 -0
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts +69 -0
- package/dist/DropdownMenu/DropdownMenuRadioGroup.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuRadioGroup.js +70 -0
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts +69 -0
- package/dist/DropdownMenu/DropdownMenuRadioItem.d.ts.map +1 -0
- package/dist/DropdownMenu/DropdownMenuRadioItem.js +178 -0
- package/dist/DropdownMenu/index.d.ts +5 -1
- package/dist/DropdownMenu/index.d.ts.map +1 -1
- package/dist/DropdownMenu/index.js +10 -1
- package/dist/DropdownMenu/menuItemRoles.d.ts +13 -0
- package/dist/DropdownMenu/menuItemRoles.d.ts.map +1 -0
- package/dist/DropdownMenu/menuItemRoles.js +15 -0
- package/dist/Icon/Icon.d.ts +43 -13
- package/dist/Icon/Icon.d.ts.map +1 -1
- package/dist/Icon/Icon.js +62 -27
- package/dist/Outline/Outline.d.ts +69 -3
- package/dist/Outline/Outline.d.ts.map +1 -1
- package/dist/Outline/Outline.js +129 -26
- package/dist/Outline/useScrollSpy.d.ts +27 -7
- package/dist/Outline/useScrollSpy.d.ts.map +1 -1
- package/dist/Outline/useScrollSpy.js +202 -70
- package/dist/TabList/Tab.d.ts.map +1 -1
- package/dist/TabList/Tab.js +2 -2
- package/dist/TabList/TabList.d.ts.map +1 -1
- package/dist/TabList/TabList.js +2 -0
- package/dist/TabList/TabMenu.d.ts.map +1 -1
- package/dist/TabList/TabMenu.js +1 -1
- package/dist/Table/Table.d.ts +1 -1
- package/dist/Table/Table.js +1 -1
- package/dist/Table/index.d.ts +2 -0
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +1 -0
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.d.ts.map +1 -1
- package/dist/Table/plugins/rowExpansion/useTableRowExpansion.js +24 -2
- package/dist/Table/plugins/sortable/useTableSortable.d.ts.map +1 -1
- package/dist/Table/plugins/sortable/useTableSortable.js +18 -7
- package/dist/Table/plugins/tree/index.d.ts +5 -0
- package/dist/Table/plugins/tree/index.d.ts.map +1 -0
- package/dist/Table/plugins/tree/index.js +4 -0
- package/dist/Table/plugins/tree/useTableTreeData.d.ts +38 -0
- package/dist/Table/plugins/tree/useTableTreeData.d.ts.map +1 -0
- package/dist/Table/plugins/tree/useTableTreeData.js +358 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts +51 -0
- package/dist/Table/plugins/tree/useTableTreeState.d.ts.map +1 -0
- package/dist/Table/plugins/tree/useTableTreeState.js +175 -0
- package/dist/Table/useBaseTablePlugins.d.ts.map +1 -1
- package/dist/Table/useBaseTablePlugins.js +6 -3
- package/dist/Toolbar/Toolbar.d.ts.map +1 -1
- package/dist/Toolbar/Toolbar.js +8 -1
- package/dist/TreeList/TreeListItem.d.ts.map +1 -1
- package/dist/TreeList/TreeListItem.js +5 -14
- package/dist/astryx.css +24 -4
- package/dist/astryx.umd.js +54 -54
- package/dist/astryx.umd.js.map +4 -4
- package/dist/theme/Theme.js +1 -1
- package/dist/theme/defineTheme.d.ts +1 -1
- package/dist/theme/defineTheme.js +1 -1
- package/dist/theme/hct.d.ts +0 -1
- package/dist/theme/hct.d.ts.map +1 -1
- package/dist/theme/hct.js +0 -3
- package/docs.mjs +32 -461
- package/locales/en.json +200 -172
- package/locales/pseudo.json +21 -0
- package/package.json +3 -1
- package/scripts/postinstall.mjs +93 -0
- package/src/Avatar/Avatar.doc.mjs +6 -6
- package/src/Avatar/Avatar.tsx +16 -11
- package/src/Avatar/AvatarSizeContext.ts +1 -1
- package/src/Avatar/AvatarStatusDot.tsx +2 -2
- package/src/AvatarGroup/AvatarGroup.doc.mjs +1 -1
- package/src/AvatarGroup/AvatarGroup.test.tsx +17 -3
- package/src/AvatarGroup/AvatarGroup.tsx +3 -3
- package/src/AvatarGroup/AvatarGroupOverflow.doc.mjs +4 -4
- package/src/AvatarGroup/AvatarGroupOverflow.tsx +21 -5
- package/src/Carousel/Carousel.doc.mjs +1 -0
- package/src/Carousel/Carousel.test.tsx +96 -1
- package/src/Carousel/Carousel.tsx +29 -2
- package/src/Chat/Chat.doc.mjs +1 -1
- package/src/Chat/ChatMessage.tsx +4 -2
- package/src/CheckboxInput/CheckboxInput.doc.mjs +1 -1
- package/src/Citation/Citation.test.tsx +51 -0
- package/src/Citation/Citation.tsx +8 -2
- package/src/Collapsible/Collapsible.doc.mjs +7 -0
- package/src/Collapsible/Collapsible.test.tsx +80 -0
- package/src/Collapsible/Collapsible.tsx +58 -5
- package/src/ContextMenu/ContextMenu.test.tsx +75 -1
- package/src/ContextMenu/ContextMenu.tsx +10 -5
- package/src/ContextMenu/index.ts +15 -0
- package/src/DropdownMenu/DropdownMenu.doc.mjs +23 -0
- package/src/DropdownMenu/DropdownMenu.tsx +11 -6
- package/src/DropdownMenu/DropdownMenuCheckboxItem.doc.mjs +95 -0
- package/src/DropdownMenu/DropdownMenuCheckboxItem.tsx +237 -0
- package/src/DropdownMenu/DropdownMenuContext.tsx +29 -1
- package/src/DropdownMenu/DropdownMenuItem.doc.mjs +7 -1
- package/src/DropdownMenu/DropdownMenuRadioGroup.doc.mjs +80 -0
- package/src/DropdownMenu/DropdownMenuRadioGroup.tsx +119 -0
- package/src/DropdownMenu/DropdownMenuRadioItem.doc.mjs +80 -0
- package/src/DropdownMenu/DropdownMenuRadioItem.tsx +232 -0
- package/src/DropdownMenu/DropdownMenuSelectable.test.tsx +163 -0
- package/src/DropdownMenu/index.ts +23 -3
- package/src/DropdownMenu/menuItemRoles.ts +22 -0
- package/src/Field/Field.doc.mjs +1 -1
- package/src/Field/FieldLabel.doc.mjs +1 -1
- package/src/Icon/Icon.doc.mjs +12 -0
- package/src/Icon/Icon.test.tsx +142 -0
- package/src/Icon/Icon.tsx +98 -30
- package/src/Item/Item.doc.mjs +1 -1
- package/src/NumberInput/NumberInput.doc.mjs +2 -2
- package/src/Outline/Outline.doc.mjs +123 -3
- package/src/Outline/Outline.test.tsx +735 -0
- package/src/Outline/Outline.tsx +184 -33
- package/src/Outline/useScrollSpy.ts +248 -72
- package/src/Selector/SelectorOption.doc.mjs +1 -1
- package/src/SideNav/SideNavItem.doc.mjs +2 -2
- package/src/Switch/Switch.doc.mjs +1 -1
- package/src/TabList/Tab.tsx +5 -1
- package/src/TabList/TabList.doc.mjs +3 -3
- package/src/TabList/TabList.test.tsx +66 -0
- package/src/TabList/TabList.tsx +8 -0
- package/src/TabList/TabMenu.tsx +4 -1
- package/src/Table/Table.doc.mjs +2 -0
- package/src/Table/Table.tsx +1 -1
- package/src/Table/index.ts +7 -0
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.test.tsx +90 -1
- package/src/Table/plugins/rowExpansion/useTableRowExpansion.tsx +37 -5
- package/src/Table/plugins/sortable/useTableSortable.test.tsx +95 -9
- package/src/Table/plugins/sortable/useTableSortable.tsx +23 -7
- package/src/Table/plugins/tree/index.ts +12 -0
- package/src/Table/plugins/tree/useTableTreeData-perf.test.tsx +163 -0
- package/src/Table/plugins/tree/useTableTreeData.test.tsx +594 -0
- package/src/Table/plugins/tree/useTableTreeData.tsx +495 -0
- package/src/Table/plugins/tree/useTableTreeState.test.tsx +636 -0
- package/src/Table/plugins/tree/useTableTreeState.tsx +253 -0
- package/src/Table/useBaseTablePlugins.ts +6 -2
- package/src/Table/useTableTreeData.doc.mjs +75 -0
- package/src/Table/useTableTreeState.doc.mjs +98 -0
- package/src/TextArea/TextArea.doc.mjs +1 -1
- package/src/TextInput/TextInput.doc.mjs +1 -1
- package/src/Toolbar/Toolbar.tsx +10 -3
- package/src/TreeList/TreeList.test.tsx +32 -1
- package/src/TreeList/TreeListItem.tsx +19 -10
- package/src/docs-script.test.mjs +18 -13
- package/src/postinstall.test.mjs +71 -0
- package/src/theme/Theme.doc.mjs +4 -4
- package/src/theme/Theme.tsx +1 -1
- package/src/theme/defineTheme.ts +1 -1
- package/src/theme/hct.ts +0 -4
- package/dist/TreeList/treeListItem.markers.stylex.d.ts +0 -16
- package/dist/TreeList/treeListItem.markers.stylex.d.ts.map +0 -1
- package/dist/TreeList/treeListItem.markers.stylex.js +0 -22
- package/src/TreeList/treeListItem.markers.stylex.ts +0 -20
package/dist/theme/Theme.js
CHANGED
|
@@ -115,7 +115,7 @@ function useThemeStyleInjection(theme) {
|
|
|
115
115
|
// One-time perf hint per theme
|
|
116
116
|
if (!warnedThemes.has(theme.name)) {
|
|
117
117
|
warnedThemes.add(theme.name);
|
|
118
|
-
console.warn(`[Astryx] Theme "${theme.name}" is using runtime style injection. ` + `For better performance, use the pre-built theme:\n\n` + ` import {${theme.name}Theme} from '@astryxdesign/theme-${theme.name}/built';\n` + ` import '@astryxdesign/theme-${theme.name}/theme.css';\n\n` + `For custom themes, run \`npx
|
|
118
|
+
console.warn(`[Astryx] Theme "${theme.name}" is using runtime style injection. ` + `For better performance, use the pre-built theme:\n\n` + ` import {${theme.name}Theme} from '@astryxdesign/theme-${theme.name}/built';\n` + ` import '@astryxdesign/theme-${theme.name}/theme.css';\n\n` + `For custom themes, run \`npx @astryxdesign/cli theme build <file>\` to generate ` + `the built artifacts.`);
|
|
119
119
|
}
|
|
120
120
|
const {
|
|
121
121
|
prose,
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Two distribution modes:
|
|
5
5
|
* - Unbuilt: Theme generates CSS and injects a <style> tag at runtime
|
|
6
|
-
* - Built: `
|
|
6
|
+
* - Built: `astryx theme build` pre-compiles to a CSS file; Theme just
|
|
7
7
|
* sets the data-astryx-theme attribute
|
|
8
8
|
*
|
|
9
9
|
* Token values can be:
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*
|
|
6
6
|
* Two distribution modes:
|
|
7
7
|
* - Unbuilt: Theme generates CSS and injects a <style> tag at runtime
|
|
8
|
-
* - Built: `
|
|
8
|
+
* - Built: `astryx theme build` pre-compiles to a CSS file; Theme just
|
|
9
9
|
* sets the data-astryx-theme attribute
|
|
10
10
|
*
|
|
11
11
|
* Token values can be:
|
package/dist/theme/hct.d.ts
CHANGED
package/dist/theme/hct.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"hct.d.ts","sourceRoot":"","sources":["../../src/theme/hct.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,GAAG;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAoFD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;
|
|
1
|
+
{"version":3,"file":"hct.d.ts","sourceRoot":"","sources":["../../src/theme/hct.ts"],"names":[],"mappings":"AAwBA,MAAM,WAAW,GAAG;IAClB,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;CACd;AAoFD,wBAAgB,OAAO,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAE5C;AAkBD;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAkBzC;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,GAAG,EAAE,GAAG,GAAG,MAAM,CA8BzC;AAkDD;;;GAGG;AACH,wBAAgB,YAAY,CAC1B,GAAG,EAAE,MAAM,EACX,MAAM,EAAE,MAAM,GACb,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAMxB;AAMD;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAM/D"}
|
package/dist/theme/hct.js
CHANGED
|
@@ -79,9 +79,6 @@ function labToXyz(L, a, b) {
|
|
|
79
79
|
export function toneToY(tone) {
|
|
80
80
|
return labFInv((tone + 16) / 116);
|
|
81
81
|
}
|
|
82
|
-
export function yToTone(y) {
|
|
83
|
-
return 116 * labF(y) - 16;
|
|
84
|
-
}
|
|
85
82
|
|
|
86
83
|
// =============================================================================
|
|
87
84
|
// Hex <-> RGB
|
package/docs.mjs
CHANGED
|
@@ -1,472 +1,43 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
1
|
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
|
-
* @file
|
|
4
|
+
* @file docs.mjs — Astryx component docs are served by the Astryx CLI.
|
|
6
5
|
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
6
|
+
* Component docs (props, variants, examples), page templates, design rules, and
|
|
7
|
+
* tokens are provided by the Astryx CLI — always current and richer than a
|
|
8
|
+
* bundled snapshot. This script intentionally redirects there instead of
|
|
9
|
+
* printing docs, so agents and humans converge on the CLI + `init` (which writes
|
|
10
|
+
* the full guide into AGENTS.md / CLAUDE.md) rather than treating a static doc
|
|
11
|
+
* dump as the whole story.
|
|
12
|
+
*
|
|
13
|
+
* ==========================================================================
|
|
14
|
+
* AI AGENT: do NOT guess component APIs or hand-write CSS. Run:
|
|
15
|
+
* npx @astryxdesign/cli init
|
|
16
|
+
* Use the SCOPED name `@astryxdesign/cli` — bare `npx astryx` resolves to an
|
|
17
|
+
* unrelated package until the CLI is a dependency. Then, per component:
|
|
18
|
+
* npx @astryxdesign/cli component <Name>
|
|
19
|
+
* npx @astryxdesign/cli component --list
|
|
20
|
+
* ==========================================================================
|
|
11
21
|
*/
|
|
12
22
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const coreDir = path.dirname(fileURLToPath(import.meta.url));
|
|
18
|
-
const srcDir = path.join(coreDir, 'src');
|
|
19
|
-
|
|
20
|
-
// ── Discovery ────────────────────────────────────────────────────────
|
|
21
|
-
|
|
22
|
-
const CATEGORY_MAP = {
|
|
23
|
-
AspectRatio: 'Layout', Center: 'Layout', CollapsibleGroup: 'Layout',
|
|
24
|
-
Grid: 'Layout', Layout: 'Layout', Stack: 'Layout',
|
|
25
|
-
Avatar: 'Display', Badge: 'Display', Divider: 'Display',
|
|
26
|
-
Icon: 'Display', Skeleton: 'Display', Table: 'Display', Text: 'Display',
|
|
27
|
-
CheckboxInput: 'Form', DateInput: 'Form', Field: 'Form',
|
|
28
|
-
NumberInput: 'Form', RadioList: 'Form', Selector: 'Form',
|
|
29
|
-
Slider: 'Form', Switch: 'Form', TextArea: 'Form', TextInput: 'Form',
|
|
30
|
-
TimeInput: 'Form',
|
|
31
|
-
Button: 'Action', CloseButton: 'Action', DropdownMenu: 'Action', Link: 'Action',
|
|
32
|
-
TabList: 'Navigation', TopNav: 'Navigation',
|
|
33
|
-
Calendar: 'Overlay', Dialog: 'Overlay', Layer: 'Overlay',
|
|
34
|
-
};
|
|
35
|
-
const CATEGORY_ORDER = ['Layout', 'Display', 'Form', 'Action', 'Navigation', 'Overlay', 'Other'];
|
|
36
|
-
const SKIP = new Set(['theme', 'hooks', 'utils', '__tests__', 'node_modules']);
|
|
37
|
-
|
|
38
|
-
function discoverDocs() {
|
|
39
|
-
const results = [];
|
|
40
|
-
if (!fs.existsSync(srcDir)) return results;
|
|
41
|
-
for (const entry of fs.readdirSync(srcDir, {withFileTypes: true})) {
|
|
42
|
-
if (!entry.isDirectory() || SKIP.has(entry.name)) continue;
|
|
43
|
-
const docPath = findDocFile(entry.name);
|
|
44
|
-
if (docPath) results.push({dir: entry.name, docPath});
|
|
45
|
-
}
|
|
46
|
-
return results;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
function findDocFile(name) {
|
|
50
|
-
const direct = path.join(srcDir, name, `${name}.doc.mjs`);
|
|
51
|
-
if (fs.existsSync(direct)) return direct;
|
|
52
|
-
const dir = path.join(srcDir, name);
|
|
53
|
-
if (!fs.existsSync(dir)) return null;
|
|
54
|
-
for (const sub of fs.readdirSync(dir, {withFileTypes: true})) {
|
|
55
|
-
if (sub.isDirectory()) {
|
|
56
|
-
const nested = path.join(dir, sub.name, `${sub.name}.doc.mjs`);
|
|
57
|
-
if (fs.existsSync(nested)) return nested;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
function findDocByComponent(name) {
|
|
64
|
-
let docPath = findDocFile(name);
|
|
65
|
-
if (docPath) return docPath;
|
|
66
|
-
for (const entry of fs.readdirSync(srcDir, {withFileTypes: true})) {
|
|
67
|
-
if (!entry.isDirectory() || SKIP.has(entry.name)) continue;
|
|
68
|
-
const nested = path.join(srcDir, entry.name, name, `${name}.doc.mjs`);
|
|
69
|
-
if (fs.existsSync(nested)) return nested;
|
|
70
|
-
}
|
|
71
|
-
// Fuzzy: find XDS{Name}.tsx and use parent doc
|
|
72
|
-
for (const entry of fs.readdirSync(srcDir, {withFileTypes: true})) {
|
|
73
|
-
if (!entry.isDirectory() || SKIP.has(entry.name)) continue;
|
|
74
|
-
const dir = path.join(srcDir, entry.name);
|
|
75
|
-
if (hasXDSFile(dir, name)) {
|
|
76
|
-
const doc = findDocInDir(dir);
|
|
77
|
-
if (doc) return doc;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return null;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function hasXDSFile(dir, name) {
|
|
84
|
-
// Match the current `XDS{Name}.tsx` convention and the post-migration bare
|
|
85
|
-
// `{Name}.tsx` form (XDS-prefix migration P2380608025, P4).
|
|
86
|
-
const targets = [`XDS${name}.tsx`, `${name}.tsx`];
|
|
87
|
-
try {
|
|
88
|
-
for (const f of fs.readdirSync(dir, {withFileTypes: true})) {
|
|
89
|
-
if (targets.includes(f.name)) return true;
|
|
90
|
-
if (f.isDirectory() && hasXDSFile(path.join(dir, f.name), name)) return true;
|
|
91
|
-
}
|
|
92
|
-
} catch {}
|
|
93
|
-
return false;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
function findDocInDir(dir) {
|
|
97
|
-
try {
|
|
98
|
-
for (const f of fs.readdirSync(dir)) {
|
|
99
|
-
if (f.endsWith('.doc.mjs')) return path.join(dir, f);
|
|
100
|
-
}
|
|
101
|
-
} catch {}
|
|
102
|
-
return null;
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
// ── Loading ──────────────────────────────────────────────────────────
|
|
106
|
-
|
|
107
|
-
async function loadDoc(docPath) {
|
|
108
|
-
const mod = await import(pathToFileURL(docPath).href);
|
|
109
|
-
return mod.docs;
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// ── Example extraction ───────────────────────────────────────────────
|
|
113
|
-
|
|
114
|
-
function extractExamples(docPath) {
|
|
115
|
-
const dir = path.dirname(docPath);
|
|
116
|
-
const examples = [];
|
|
117
|
-
try {
|
|
118
|
-
for (const file of fs.readdirSync(dir)) {
|
|
119
|
-
if (!file.endsWith('.tsx') || file.includes('.test')) continue;
|
|
120
|
-
const content = fs.readFileSync(path.join(dir, file), 'utf-8');
|
|
121
|
-
const regex = /@example\s*\n\s*\*\s*```[\w]*\n([\s\S]*?)```/g;
|
|
122
|
-
let match;
|
|
123
|
-
while ((match = regex.exec(content)) !== null) {
|
|
124
|
-
const code = match[1]
|
|
125
|
-
.split('\n')
|
|
126
|
-
.map(line => line.replace(/^\s*\*\s?/, ''))
|
|
127
|
-
.join('\n')
|
|
128
|
-
.trim();
|
|
129
|
-
if (code.includes('declare module')) continue;
|
|
130
|
-
if (code.includes('stylex.create') && !code.includes('XDS')) continue;
|
|
131
|
-
if (code.length > 0) examples.push(code);
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
} catch {}
|
|
135
|
-
return examples;
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
// ── Formatting ───────────────────────────────────────────────────────
|
|
139
|
-
|
|
140
|
-
function dataAttrForName(name) {
|
|
141
|
-
return `data-${name.replace(/([a-z0-9])([A-Z])/g, '$1-$2').toLowerCase()}`;
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
function getTargetDataAttributes(target) {
|
|
145
|
-
return [
|
|
146
|
-
...(target.visualProps || []).map(dataAttrForName),
|
|
147
|
-
...(target.states || []).map(dataAttrForName),
|
|
148
|
-
];
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function formatPropsTable(props) {
|
|
152
|
-
if (!props?.length) return '';
|
|
153
|
-
const lines = ['| Prop | Type | Default | Description |', '|------|------|---------|-------------|'];
|
|
154
|
-
for (const p of props) {
|
|
155
|
-
const def = p.default ? `\`${p.default}\`` : '—';
|
|
156
|
-
const req = p.required ? ' **(required)**' : '';
|
|
157
|
-
lines.push(`| \`${p.name}\` | \`${p.type}\` | ${def} | ${p.description}${req} |`);
|
|
158
|
-
}
|
|
159
|
-
return lines.join('\n');
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
function formatFull(docs, docPath) {
|
|
163
|
-
const s = [];
|
|
164
|
-
s.push(`# ${docs.name}\n`);
|
|
165
|
-
s.push((docs.usage?.description || '') + '\n');
|
|
166
|
-
|
|
167
|
-
// Examples from @example JSDoc blocks in component source
|
|
168
|
-
if (docPath) {
|
|
169
|
-
const examples = extractExamples(docPath);
|
|
170
|
-
if (examples.length) {
|
|
171
|
-
s.push('## Example\n');
|
|
172
|
-
s.push('```tsx');
|
|
173
|
-
s.push(examples.join('\n\n'));
|
|
174
|
-
s.push('```\n');
|
|
175
|
-
}
|
|
176
|
-
}
|
|
177
|
-
|
|
178
|
-
if (docs.usage?.anatomy?.length) {
|
|
179
|
-
s.push('## Anatomy\n');
|
|
180
|
-
s.push('| Element | Required | Description |');
|
|
181
|
-
s.push('|---------|----------|-------------|');
|
|
182
|
-
for (const el of docs.usage.anatomy)
|
|
183
|
-
s.push(`| ${el.name} | ${el.required ? 'Yes' : 'No'} | ${el.description} |`);
|
|
184
|
-
s.push('');
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
if (docs.usage?.bestPractices?.length) {
|
|
188
|
-
s.push('## Best Practices\n');
|
|
189
|
-
for (const bp of docs.usage.bestPractices)
|
|
190
|
-
s.push(`- ${bp.guidance ? '**Do:**' : "**Don't:**"} ${bp.description}`);
|
|
191
|
-
s.push('');
|
|
192
|
-
}
|
|
193
|
-
|
|
194
|
-
if ('props' in docs) {
|
|
195
|
-
s.push('## Props\n');
|
|
196
|
-
s.push(formatPropsTable(docs.props) + '\n');
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if ('components' in docs) {
|
|
200
|
-
s.push('## Components\n');
|
|
201
|
-
for (const comp of docs.components) {
|
|
202
|
-
s.push(`### ${comp.name}\n`);
|
|
203
|
-
s.push(comp.description + '\n');
|
|
204
|
-
s.push(formatPropsTable(comp.props) + '\n');
|
|
205
|
-
}
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
if (docs.theming?.targets?.length) {
|
|
209
|
-
s.push('## Theming\n');
|
|
210
|
-
s.push('| Component class | Preferred data attributes | Props | States |');
|
|
211
|
-
s.push('|-----------------|---------------------------|-------|--------|');
|
|
212
|
-
for (const t of docs.theming.targets) {
|
|
213
|
-
const dataAttrs = getTargetDataAttributes(t);
|
|
214
|
-
const attrs = dataAttrs.length ? dataAttrs.map(attr => `\`${attr}\``).join(', ') : '—';
|
|
215
|
-
const variants = t.visualProps?.join(', ') || '—';
|
|
216
|
-
const states = t.states?.join(', ') || '—';
|
|
217
|
-
s.push(`| \`${t.className}\` | ${attrs} | ${variants} | ${states} |`);
|
|
218
|
-
}
|
|
219
|
-
s.push('');
|
|
220
|
-
const publicVars = docs.theming.vars?.filter(v => !v.private && !v.derived) || [];
|
|
221
|
-
if (publicVars.length) {
|
|
222
|
-
s.push('| CSS Variable | Default | Description |');
|
|
223
|
-
s.push('|-------------|---------|-------------|');
|
|
224
|
-
for (const v of publicVars)
|
|
225
|
-
s.push(`| \`${v.name}\` | \`${v.default}\` | ${v.description} |`);
|
|
226
|
-
s.push('');
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
return s.join('\n');
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
function formatBrief(docs) {
|
|
234
|
-
const desc = docs.usage?.description || '';
|
|
235
|
-
const short = desc.length > 80 ? desc.slice(0, 77) + '...' : desc;
|
|
236
|
-
const props = docs.props || docs.components?.[0]?.props || [];
|
|
237
|
-
const sig = props
|
|
238
|
-
.filter(p => p.type.includes('|') && !p.type.includes('ReactNode'))
|
|
239
|
-
.map(p => `${p.name}: ${p.type.replace(/['"]/g, '').split('|').map(v => v.trim()).join('|')}`)
|
|
240
|
-
.join(', ');
|
|
241
|
-
return sig ? `${docs.name}(${sig}) ${short}` : `${docs.name} ${short}`;
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
// ── Main ─────────────────────────────────────────────────────────────
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
// ── Hook Support ─────────────────────────────────────────────────────
|
|
248
|
-
|
|
249
|
-
const HOOK_CATEGORY_MAP = {
|
|
250
|
-
useFocusTrap: 'Focus',
|
|
251
|
-
useGridFocus: 'Focus',
|
|
252
|
-
useListFocus: 'Focus',
|
|
253
|
-
useMediaQuery: 'Media',
|
|
254
|
-
useOverflow: 'Layout',
|
|
255
|
-
useScrollOverflow: 'Layout',
|
|
256
|
-
useScrollLock: 'Layout',
|
|
257
|
-
useEntryAnimation: 'Animation',
|
|
258
|
-
useStreamingText: 'Streaming',
|
|
259
|
-
useImageMode: 'Media',
|
|
260
|
-
useClickableContainer: 'Interaction',
|
|
261
|
-
useInputContainer: 'Interaction',
|
|
262
|
-
};
|
|
263
|
-
const HOOK_CATEGORY_ORDER = ['Focus', 'Layout', 'Animation', 'Interaction', 'Media', 'Streaming', 'Other'];
|
|
264
|
-
|
|
265
|
-
function discoverHookDocs() {
|
|
266
|
-
const results = [];
|
|
267
|
-
const hooksDir = path.join(srcDir, 'hooks');
|
|
268
|
-
if (fs.existsSync(hooksDir)) {
|
|
269
|
-
for (const file of fs.readdirSync(hooksDir)) {
|
|
270
|
-
if (file.endsWith('.doc.mjs')) {
|
|
271
|
-
results.push({name: file.replace('.doc.mjs', ''), docPath: path.join(hooksDir, file)});
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
// Also scan component directories for use*.doc.mjs
|
|
276
|
-
if (fs.existsSync(srcDir)) {
|
|
277
|
-
for (const entry of fs.readdirSync(srcDir, {withFileTypes: true})) {
|
|
278
|
-
if (!entry.isDirectory() || SKIP.has(entry.name)) continue;
|
|
279
|
-
const dir = path.join(srcDir, entry.name);
|
|
280
|
-
try {
|
|
281
|
-
for (const file of fs.readdirSync(dir)) {
|
|
282
|
-
if (file.startsWith('use') && file.endsWith('.doc.mjs')) {
|
|
283
|
-
results.push({name: file.replace('.doc.mjs', ''), docPath: path.join(dir, file)});
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
} catch {}
|
|
287
|
-
}
|
|
288
|
-
}
|
|
289
|
-
return results;
|
|
290
|
-
}
|
|
291
|
-
|
|
292
|
-
function findHookDocByName(hookName) {
|
|
293
|
-
const normalized = hookName.replace(/^use/i, '');
|
|
294
|
-
const hooksDir = path.join(srcDir, 'hooks');
|
|
295
|
-
|
|
296
|
-
// Direct match in hooks/
|
|
297
|
-
for (const variant of [hookName, `use${normalized}`, `useXDS${normalized}`]) {
|
|
298
|
-
const p = path.join(hooksDir, `${variant}.doc.mjs`);
|
|
299
|
-
if (fs.existsSync(p)) return p;
|
|
300
|
-
}
|
|
301
|
-
|
|
302
|
-
// Search component directories
|
|
303
|
-
if (fs.existsSync(srcDir)) {
|
|
304
|
-
for (const entry of fs.readdirSync(srcDir, {withFileTypes: true})) {
|
|
305
|
-
if (!entry.isDirectory() || SKIP.has(entry.name)) continue;
|
|
306
|
-
const dir = path.join(srcDir, entry.name);
|
|
307
|
-
for (const variant of [hookName, `use${normalized}`, `useXDS${normalized}`]) {
|
|
308
|
-
const p = path.join(dir, `${variant}.doc.mjs`);
|
|
309
|
-
if (fs.existsSync(p)) return p;
|
|
310
|
-
}
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
return null;
|
|
314
|
-
}
|
|
315
|
-
|
|
316
|
-
function formatHookParamsTable(params) {
|
|
317
|
-
if (!params?.length) return '';
|
|
318
|
-
const lines = ['| Param | Type | Default | Description |', '|-------|------|---------|-------------|'];
|
|
319
|
-
for (const p of params) {
|
|
320
|
-
const def = p.default ? `\`${p.default}\`` : '\u2014';
|
|
321
|
-
const req = p.required ? ' **(required)**' : '';
|
|
322
|
-
lines.push(`| \`${p.name}\` | \`${p.type}\` | ${def} | ${p.description}${req} |`);
|
|
323
|
-
}
|
|
324
|
-
return lines.join('\n');
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
function formatHookReturnsTable(returns) {
|
|
328
|
-
if (!returns?.length) return '';
|
|
329
|
-
const lines = ['| Field | Type | Description |', '|-------|------|-------------|'];
|
|
330
|
-
for (const r of returns) {
|
|
331
|
-
lines.push(`| \`${r.name}\` | \`${r.type}\` | ${r.description} |`);
|
|
332
|
-
}
|
|
333
|
-
return lines.join('\n');
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
function formatHookFull(docs) {
|
|
337
|
-
const s = [];
|
|
338
|
-
s.push(`# ${docs.name}\n`);
|
|
339
|
-
s.push((docs.usage?.description || '') + '\n');
|
|
340
|
-
|
|
341
|
-
if (docs.params?.length) {
|
|
342
|
-
s.push('## Parameters\n');
|
|
343
|
-
s.push(formatHookParamsTable(docs.params) + '\n');
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
if (docs.returns?.length) {
|
|
347
|
-
s.push('## Returns\n');
|
|
348
|
-
s.push(formatHookReturnsTable(docs.returns) + '\n');
|
|
349
|
-
}
|
|
350
|
-
|
|
351
|
-
if (docs.usage?.bestPractices?.length) {
|
|
352
|
-
s.push('## Best Practices\n');
|
|
353
|
-
for (const bp of docs.usage.bestPractices)
|
|
354
|
-
s.push(`- ${bp.guidance ? '**Do:**' : "**Don't:**"} ${bp.description}`);
|
|
355
|
-
s.push('');
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
const refs = [];
|
|
359
|
-
if (docs.relatedComponents?.length) refs.push(`Components: ${docs.relatedComponents.map(c => c).join(', ')}`);
|
|
360
|
-
if (docs.relatedHooks?.length) refs.push(`Hooks: ${docs.relatedHooks.join(', ')}`);
|
|
361
|
-
if (docs.importPath) refs.push(`Import: ${docs.importPath}`);
|
|
362
|
-
if (refs.length) {
|
|
363
|
-
s.push('## Related\n');
|
|
364
|
-
for (const r of refs) s.push(r);
|
|
365
|
-
s.push('');
|
|
366
|
-
}
|
|
23
|
+
const BANNER = `
|
|
24
|
+
==========================================================================
|
|
25
|
+
Astryx component docs are served by the Astryx CLI (accurate + current).
|
|
26
|
+
Do not guess component APIs or hand-write CSS — set up first (one time):
|
|
367
27
|
|
|
368
|
-
|
|
369
|
-
}
|
|
28
|
+
npx @astryxdesign/cli init
|
|
370
29
|
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
const short = desc.length > 80 ? desc.slice(0, 77) + '...' : desc;
|
|
374
|
-
const params = (docs.params || []).filter(p => p.required).map(p => `${p.name}: ${p.type}`).join(', ');
|
|
375
|
-
const ret = (docs.returns || []).map(r => r.type).join(' | ');
|
|
376
|
-
const sig = params ? `${docs.name}(${params})` : docs.name;
|
|
377
|
-
return ret ? `${sig}: ${ret} ${short}` : `${sig} ${short}`;
|
|
378
|
-
}
|
|
30
|
+
(Use the scoped name @astryxdesign/cli. Bare \`npx astryx\` resolves to an
|
|
31
|
+
unrelated package until the CLI is installed as a dependency.)
|
|
379
32
|
|
|
380
|
-
|
|
33
|
+
init writes the full component guide, page templates, design rules & tokens
|
|
34
|
+
into your AGENTS.md / CLAUDE.md. Then, for any component:
|
|
381
35
|
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
36
|
+
npx @astryxdesign/cli component <Name> # full props, variants, examples
|
|
37
|
+
npx @astryxdesign/cli component --list # every component
|
|
38
|
+
npx @astryxdesign/cli build "<what you're building>" # starter kit
|
|
39
|
+
==========================================================================
|
|
40
|
+
`;
|
|
387
41
|
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
const hookDocs = discoverHookDocs();
|
|
391
|
-
const grouped = {};
|
|
392
|
-
for (const {name: hookName, docPath} of hookDocs) {
|
|
393
|
-
const cat = HOOK_CATEGORY_MAP[hookName] || 'Other';
|
|
394
|
-
if (!grouped[cat]) grouped[cat] = [];
|
|
395
|
-
grouped[cat].push({name: hookName, docPath});
|
|
396
|
-
}
|
|
397
|
-
for (const cat of HOOK_CATEGORY_ORDER) {
|
|
398
|
-
if (!grouped[cat]) continue;
|
|
399
|
-
console.log(`\n${cat}:`);
|
|
400
|
-
for (const {name: hookName, docPath} of grouped[cat]) {
|
|
401
|
-
if (isBrief) {
|
|
402
|
-
try {
|
|
403
|
-
const d = await loadDoc(docPath);
|
|
404
|
-
console.log(' ' + formatHookBrief(d));
|
|
405
|
-
} catch {
|
|
406
|
-
console.log(` ${hookName} (error loading docs)`);
|
|
407
|
-
}
|
|
408
|
-
} else {
|
|
409
|
-
console.log(` ${hookName}`);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
}
|
|
413
|
-
} else if (isList) {
|
|
414
|
-
const docs = discoverDocs();
|
|
415
|
-
const grouped = {};
|
|
416
|
-
for (const {dir, docPath} of docs) {
|
|
417
|
-
const cat = CATEGORY_MAP[dir] || 'Other';
|
|
418
|
-
if (!grouped[cat]) grouped[cat] = [];
|
|
419
|
-
grouped[cat].push({dir, docPath});
|
|
420
|
-
}
|
|
421
|
-
for (const cat of CATEGORY_ORDER) {
|
|
422
|
-
if (!grouped[cat]) continue;
|
|
423
|
-
console.log(`\n${cat}:`);
|
|
424
|
-
for (const {dir, docPath} of grouped[cat]) {
|
|
425
|
-
if (isBrief) {
|
|
426
|
-
try {
|
|
427
|
-
const d = await loadDoc(docPath);
|
|
428
|
-
console.log(' ' + formatBrief(d));
|
|
429
|
-
} catch {
|
|
430
|
-
console.log(` ${dir} (error loading docs)`);
|
|
431
|
-
}
|
|
432
|
-
} else {
|
|
433
|
-
console.log(` ${dir}`);
|
|
434
|
-
}
|
|
435
|
-
}
|
|
436
|
-
}
|
|
437
|
-
} else if (name) {
|
|
438
|
-
// Try hook lookup first for names starting with 'use'
|
|
439
|
-
if (name.startsWith('use') || name.startsWith('Use')) {
|
|
440
|
-
const hookDocPath = findHookDocByName(name);
|
|
441
|
-
if (hookDocPath) {
|
|
442
|
-
const docs = await loadDoc(hookDocPath);
|
|
443
|
-
console.log(formatHookFull(docs));
|
|
444
|
-
} else {
|
|
445
|
-
// Fall through to component lookup
|
|
446
|
-
const docPath = findDocByComponent(name);
|
|
447
|
-
if (!docPath) {
|
|
448
|
-
console.error(`Hook or component "${name}" not found.`);
|
|
449
|
-
console.error('Run with --list to see components, or --hooks to see hooks.');
|
|
450
|
-
process.exit(1);
|
|
451
|
-
}
|
|
452
|
-
const docs = await loadDoc(docPath);
|
|
453
|
-
console.log(formatFull(docs, docPath));
|
|
454
|
-
}
|
|
455
|
-
} else {
|
|
456
|
-
const docPath = findDocByComponent(name);
|
|
457
|
-
if (!docPath) {
|
|
458
|
-
console.error(`Component "${name}" not found. Run with --list to see available components.`);
|
|
459
|
-
process.exit(1);
|
|
460
|
-
}
|
|
461
|
-
const docs = await loadDoc(docPath);
|
|
462
|
-
console.log(formatFull(docs, docPath));
|
|
463
|
-
}
|
|
464
|
-
} else {
|
|
465
|
-
console.log('Usage:');
|
|
466
|
-
console.log(' node docs.mjs <ComponentName> Show full component docs');
|
|
467
|
-
console.log(' node docs.mjs <hookName> Show full hook docs');
|
|
468
|
-
console.log(' node docs.mjs --list List all components');
|
|
469
|
-
console.log(' node docs.mjs --list --brief List with brief descriptions');
|
|
470
|
-
console.log(' node docs.mjs --hooks List all hooks');
|
|
471
|
-
console.log(' node docs.mjs --hooks --brief List hooks with brief descriptions');
|
|
472
|
-
}
|
|
42
|
+
console.log(BANNER);
|
|
43
|
+
process.exit(0);
|