@astryxdesign/cli 0.1.2-canary.a1dd3f9 → 0.1.2-canary.ae2d146
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/package.json +7 -7
- package/src/commands/build-theme.mjs +0 -117
- package/templates/blocks/components/DropdownMenu/DropdownMenuShowcase.tsx +6 -0
- package/templates/blocks/components/DropdownMenuItem/DropdownMenuItemShowcase.tsx +5 -1
- package/templates/blocks/components/Lightbox/LightboxShowcase.tsx +3 -4
- package/templates/blocks/components/MoreMenu/MoreMenuShowcase.tsx +6 -0
- package/templates/blocks/components/TreeListBranches/TreeListBranchesShowcase.doc.mjs +14 -0
- package/templates/blocks/components/TreeListBranches/TreeListBranchesShowcase.tsx +64 -0
- package/templates/blocks/components/TreeListItem/TreeListItemShowcase.doc.mjs +14 -0
- package/templates/blocks/components/TreeListItem/TreeListItemShowcase.tsx +60 -0
- package/templates/pages/shell-side-nav/page.tsx +1 -0
- package/src/commands/build-theme.watch.test.mjs +0 -157
- package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.doc.mjs +0 -14
- package/templates/blocks/components/AvatarStatusDot/AvatarStatusDotVariants.tsx +0 -28
- package/templates/blocks/components/Blockquote/BlockquoteTestimonials.doc.mjs +0 -14
- package/templates/blocks/components/Blockquote/BlockquoteTestimonials.tsx +0 -34
- package/templates/blocks/components/Blockquote/BlockquoteWithCite.doc.mjs +0 -14
- package/templates/blocks/components/Blockquote/BlockquoteWithCite.tsx +0 -21
- package/templates/blocks/components/BreadcrumbItem/BreadcrumbItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/BreadcrumbItem/BreadcrumbItemBasic.tsx +0 -15
- package/templates/blocks/components/ButtonGroup/ButtonGroupBasic.doc.mjs +0 -14
- package/templates/blocks/components/ButtonGroup/ButtonGroupBasic.tsx +0 -16
- package/templates/blocks/components/ChatDictationButton/ChatDictationButtonBasic.doc.mjs +0 -19
- package/templates/blocks/components/ChatDictationButton/ChatDictationButtonBasic.tsx +0 -34
- package/templates/blocks/components/CheckboxListItem/CheckboxListItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/CheckboxListItem/CheckboxListItemBasic.tsx +0 -30
- package/templates/blocks/components/CollapsibleGroup/CollapsibleGroupAccordion.doc.mjs +0 -14
- package/templates/blocks/components/CollapsibleGroup/CollapsibleGroupAccordion.tsx +0 -31
- package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyBasic.doc.mjs +0 -14
- package/templates/blocks/components/CommandPaletteEmpty/CommandPaletteEmptyBasic.tsx +0 -26
- package/templates/blocks/components/CommandPaletteFooter/CommandPaletteFooterBasic.doc.mjs +0 -14
- package/templates/blocks/components/CommandPaletteFooter/CommandPaletteFooterBasic.tsx +0 -32
- package/templates/blocks/components/CommandPaletteGroup/CommandPaletteGroupBasic.doc.mjs +0 -18
- package/templates/blocks/components/CommandPaletteGroup/CommandPaletteGroupBasic.tsx +0 -32
- package/templates/blocks/components/CommandPaletteItem/CommandPaletteItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/CommandPaletteItem/CommandPaletteItemBasic.tsx +0 -27
- package/templates/blocks/components/ContextMenu/ContextMenuBasic.doc.mjs +0 -14
- package/templates/blocks/components/ContextMenu/ContextMenuBasic.tsx +0 -32
- package/templates/blocks/components/DialogHeader/DialogHeaderBasic.doc.mjs +0 -14
- package/templates/blocks/components/DialogHeader/DialogHeaderBasic.tsx +0 -30
- package/templates/blocks/components/DropdownMenuItem/DropdownMenuItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/DropdownMenuItem/DropdownMenuItemBasic.tsx +0 -27
- package/templates/blocks/components/FieldLabel/FieldLabelBasic.doc.mjs +0 -14
- package/templates/blocks/components/FieldLabel/FieldLabelBasic.tsx +0 -20
- package/templates/blocks/components/FieldStatus/FieldStatusBasic.doc.mjs +0 -14
- package/templates/blocks/components/FieldStatus/FieldStatusBasic.tsx +0 -23
- package/templates/blocks/components/FileInput/FileInputBasic.doc.mjs +0 -14
- package/templates/blocks/components/FileInput/FileInputBasic.tsx +0 -22
- package/templates/blocks/components/GridSpan/GridSpanColumns.doc.mjs +0 -14
- package/templates/blocks/components/GridSpan/GridSpanColumns.tsx +0 -38
- package/templates/blocks/components/HStack/HStackBasic.doc.mjs +0 -14
- package/templates/blocks/components/HStack/HStackBasic.tsx +0 -16
- package/templates/blocks/components/Hooks/useKeyboardHintHookUsage.doc.mjs +0 -14
- package/templates/blocks/components/Hooks/useKeyboardHintHookUsage.tsx +0 -57
- package/templates/blocks/components/InputGroup/InputGroupBasic.doc.mjs +0 -14
- package/templates/blocks/components/InputGroup/InputGroupBasic.tsx +0 -27
- package/templates/blocks/components/LayoutContent/LayoutContentBasic.doc.mjs +0 -23
- package/templates/blocks/components/LayoutContent/LayoutContentBasic.tsx +0 -40
- package/templates/blocks/components/LayoutFooter/LayoutFooterActions.doc.mjs +0 -22
- package/templates/blocks/components/LayoutFooter/LayoutFooterActions.tsx +0 -41
- package/templates/blocks/components/LayoutHeader/LayoutHeaderWithActions.doc.mjs +0 -23
- package/templates/blocks/components/LayoutHeader/LayoutHeaderWithActions.tsx +0 -40
- package/templates/blocks/components/LayoutPanel/LayoutPanelNavigation.doc.mjs +0 -22
- package/templates/blocks/components/LayoutPanel/LayoutPanelNavigation.tsx +0 -37
- package/templates/blocks/components/Lightbox/LightboxGallery.doc.mjs +0 -14
- package/templates/blocks/components/Lightbox/LightboxGallery.tsx +0 -53
- package/templates/blocks/components/Lightbox/LightboxVideo.doc.mjs +0 -14
- package/templates/blocks/components/Lightbox/LightboxVideo.tsx +0 -27
- package/templates/blocks/components/Lightbox/LightboxZoom.doc.mjs +0 -14
- package/templates/blocks/components/Lightbox/LightboxZoom.tsx +0 -33
- package/templates/blocks/components/MetadataListItem/MetadataListItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/MetadataListItem/MetadataListItemBasic.tsx +0 -19
- package/templates/blocks/components/MobileNavToggle/MobileNavToggleBasic.doc.mjs +0 -23
- package/templates/blocks/components/MobileNavToggle/MobileNavToggleBasic.tsx +0 -42
- package/templates/blocks/components/NavIcon/NavIconBasic.doc.mjs +0 -14
- package/templates/blocks/components/NavIcon/NavIconBasic.tsx +0 -16
- package/templates/blocks/components/RadioListItem/RadioListItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/RadioListItem/RadioListItemBasic.tsx +0 -30
- package/templates/blocks/components/Resizable/ResizableSidebar.doc.mjs +0 -25
- package/templates/blocks/components/Resizable/ResizableSidebar.tsx +0 -67
- package/templates/blocks/components/SegmentedControlItem/SegmentedControlItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/SegmentedControlItem/SegmentedControlItemBasic.tsx +0 -21
- package/templates/blocks/components/SelectorOption/SelectorOptionBasic.doc.mjs +0 -14
- package/templates/blocks/components/SelectorOption/SelectorOptionBasic.tsx +0 -39
- package/templates/blocks/components/SideNavCollapseButton/SideNavCollapseButtonBasic.doc.mjs +0 -14
- package/templates/blocks/components/SideNavCollapseButton/SideNavCollapseButtonBasic.tsx +0 -55
- package/templates/blocks/components/SideNavHeading/SideNavHeadingBasic.doc.mjs +0 -14
- package/templates/blocks/components/SideNavHeading/SideNavHeadingBasic.tsx +0 -38
- package/templates/blocks/components/SideNavItem/SideNavItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/SideNavItem/SideNavItemBasic.tsx +0 -49
- package/templates/blocks/components/SideNavSection/SideNavSectionBasic.doc.mjs +0 -14
- package/templates/blocks/components/SideNavSection/SideNavSectionBasic.tsx +0 -71
- package/templates/blocks/components/StackItem/StackItemFill.doc.mjs +0 -14
- package/templates/blocks/components/StackItem/StackItemFill.tsx +0 -28
- package/templates/blocks/components/TabMenu/TabMenuBasic.doc.mjs +0 -14
- package/templates/blocks/components/TabMenu/TabMenuBasic.tsx +0 -23
- package/templates/blocks/components/ToggleButtonGroup/ToggleButtonGroupVertical.doc.mjs +0 -14
- package/templates/blocks/components/ToggleButtonGroup/ToggleButtonGroupVertical.tsx +0 -47
- package/templates/blocks/components/TopNavHeading/TopNavHeadingBasic.doc.mjs +0 -14
- package/templates/blocks/components/TopNavHeading/TopNavHeadingBasic.tsx +0 -22
- package/templates/blocks/components/TopNavItem/TopNavItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/TopNavItem/TopNavItemBasic.tsx +0 -21
- package/templates/blocks/components/TopNavMegaMenu/TopNavMegaMenuBasic.doc.mjs +0 -20
- package/templates/blocks/components/TopNavMegaMenu/TopNavMegaMenuBasic.tsx +0 -46
- package/templates/blocks/components/TopNavMegaMenuFeaturedCard/TopNavMegaMenuFeaturedCardBasic.doc.mjs +0 -14
- package/templates/blocks/components/TopNavMegaMenuFeaturedCard/TopNavMegaMenuFeaturedCardBasic.tsx +0 -16
- package/templates/blocks/components/TopNavMegaMenuItem/TopNavMegaMenuItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/TopNavMegaMenuItem/TopNavMegaMenuItemBasic.tsx +0 -26
- package/templates/blocks/components/TopNavMenu/TopNavMenuBasic.doc.mjs +0 -14
- package/templates/blocks/components/TopNavMenu/TopNavMenuBasic.tsx +0 -43
- package/templates/blocks/components/TypeaheadItem/TypeaheadItemBasic.doc.mjs +0 -14
- package/templates/blocks/components/TypeaheadItem/TypeaheadItemBasic.tsx +0 -43
- package/templates/blocks/components/VStack/VStackBasic.doc.mjs +0 -14
- package/templates/blocks/components/VStack/VStackBasic.tsx +0 -20
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astryxdesign/cli",
|
|
3
|
-
"version": "0.1.2-canary.
|
|
3
|
+
"version": "0.1.2-canary.ae2d146",
|
|
4
4
|
"displayName": "CLI",
|
|
5
5
|
"description": "Scaffold projects, browse templates, generate themes, and get agent-ready docs from the command line.",
|
|
6
6
|
"author": "Meta Open Source",
|
|
@@ -75,9 +75,9 @@
|
|
|
75
75
|
"zod": "^4.4.3"
|
|
76
76
|
},
|
|
77
77
|
"peerDependencies": {
|
|
78
|
-
"@astryxdesign/core": "0.1.2-canary.
|
|
79
|
-
"@astryxdesign/lab": "0.1.2-canary.
|
|
80
|
-
"@astryxdesign/theme-neutral": "0.1.2-canary.
|
|
78
|
+
"@astryxdesign/core": "0.1.2-canary.ae2d146",
|
|
79
|
+
"@astryxdesign/lab": "0.1.2-canary.ae2d146",
|
|
80
|
+
"@astryxdesign/theme-neutral": "0.1.2-canary.ae2d146",
|
|
81
81
|
"gpt-tokenizer": "^2.0.0"
|
|
82
82
|
},
|
|
83
83
|
"peerDependenciesMeta": {
|
|
@@ -92,9 +92,9 @@
|
|
|
92
92
|
}
|
|
93
93
|
},
|
|
94
94
|
"devDependencies": {
|
|
95
|
-
"@astryxdesign/core": "0.1.2-canary.
|
|
96
|
-
"@astryxdesign/lab": "0.1.2-canary.
|
|
97
|
-
"@astryxdesign/theme-neutral": "0.1.2-canary.
|
|
95
|
+
"@astryxdesign/core": "0.1.2-canary.ae2d146",
|
|
96
|
+
"@astryxdesign/lab": "0.1.2-canary.ae2d146",
|
|
97
|
+
"@astryxdesign/theme-neutral": "0.1.2-canary.ae2d146",
|
|
98
98
|
"gpt-tokenizer": "^2.0.0"
|
|
99
99
|
},
|
|
100
100
|
"scripts": {
|
|
@@ -15,7 +15,6 @@
|
|
|
15
15
|
import * as fs from 'node:fs';
|
|
16
16
|
import * as path from 'node:path';
|
|
17
17
|
import {pathToFileURL, fileURLToPath} from 'node:url';
|
|
18
|
-
import {spawn} from 'node:child_process';
|
|
19
18
|
import {createJiti} from 'jiti';
|
|
20
19
|
import {getRunPrefix} from '../utils/package-manager.mjs';
|
|
21
20
|
import {
|
|
@@ -598,104 +597,6 @@ function validatePrivateVars(themeDef) {
|
|
|
598
597
|
return errors;
|
|
599
598
|
}
|
|
600
599
|
|
|
601
|
-
/**
|
|
602
|
-
* Path to this CLI's real entry (bin/astryx.mjs), resolved from this module's
|
|
603
|
-
* location (src/commands/build-theme.mjs → ../../bin/astryx.mjs). Used to
|
|
604
|
-
* re-invoke `theme build` as a child process in watch mode.
|
|
605
|
-
*/
|
|
606
|
-
function resolveCliBin() {
|
|
607
|
-
const commandsDir = path.dirname(fileURLToPath(import.meta.url));
|
|
608
|
-
return path.resolve(commandsDir, '../../bin/astryx.mjs');
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
/**
|
|
612
|
-
* Run a single `theme build` as a child process, reusing the exact
|
|
613
|
-
* single-build code path (and its error handling) rather than duplicating it.
|
|
614
|
-
* Resolves with the child's exit code; never rejects.
|
|
615
|
-
*
|
|
616
|
-
* @param {string} file - The theme file argument, as the user passed it.
|
|
617
|
-
* @param {object} options - Parsed command options (only `out` is forwarded).
|
|
618
|
-
* @returns {Promise<number>}
|
|
619
|
-
*/
|
|
620
|
-
function runThemeBuildOnceChild(file, options) {
|
|
621
|
-
const cliBin = resolveCliBin();
|
|
622
|
-
const args = [cliBin, 'theme', 'build', file];
|
|
623
|
-
if (options.out) args.push('--out', options.out);
|
|
624
|
-
return new Promise(resolve => {
|
|
625
|
-
const child = spawn(process.execPath, args, {
|
|
626
|
-
stdio: 'inherit',
|
|
627
|
-
env: process.env,
|
|
628
|
-
});
|
|
629
|
-
child.on('close', code => resolve(code ?? 0));
|
|
630
|
-
child.on('error', () => resolve(1));
|
|
631
|
-
});
|
|
632
|
-
}
|
|
633
|
-
|
|
634
|
-
/**
|
|
635
|
-
* Watch a theme file and rebuild on change. Runs an initial build, then
|
|
636
|
-
* rebuilds (debounced) whenever the file changes, until interrupted with
|
|
637
|
-
* Ctrl-C. Each rebuild runs in a child process so a build error (which the
|
|
638
|
-
* single-build path reports via a hard exit) is contained and the watcher
|
|
639
|
-
* keeps running.
|
|
640
|
-
*
|
|
641
|
-
* @param {string} file - The theme file argument, as the user passed it.
|
|
642
|
-
* @param {string} filePath - Absolute path to the theme file.
|
|
643
|
-
* @param {object} options - Parsed command options.
|
|
644
|
-
* @returns {Promise<void>} Resolves when the watcher is stopped (Ctrl-C).
|
|
645
|
-
*/
|
|
646
|
-
async function runThemeBuildWatch(file, filePath, options) {
|
|
647
|
-
const rel = path.relative(process.cwd(), filePath);
|
|
648
|
-
|
|
649
|
-
// Initial build.
|
|
650
|
-
await runThemeBuildOnceChild(file, options);
|
|
651
|
-
|
|
652
|
-
humanLog(`\n👀 Watching ${rel} for changes — press Ctrl-C to stop.`);
|
|
653
|
-
|
|
654
|
-
let building = false;
|
|
655
|
-
let queued = false;
|
|
656
|
-
let debounce = null;
|
|
657
|
-
|
|
658
|
-
const rebuild = async () => {
|
|
659
|
-
if (building) {
|
|
660
|
-
// Coalesce changes that land mid-build into a single follow-up run.
|
|
661
|
-
queued = true;
|
|
662
|
-
return;
|
|
663
|
-
}
|
|
664
|
-
building = true;
|
|
665
|
-
humanLog(`\n♻️ Change detected — rebuilding ${rel}...`);
|
|
666
|
-
await runThemeBuildOnceChild(file, options);
|
|
667
|
-
building = false;
|
|
668
|
-
humanLog(`\n👀 Watching ${rel} for changes — press Ctrl-C to stop.`);
|
|
669
|
-
if (queued) {
|
|
670
|
-
queued = false;
|
|
671
|
-
rebuild();
|
|
672
|
-
}
|
|
673
|
-
};
|
|
674
|
-
|
|
675
|
-
// Some editors replace the file (rename) rather than writing in place, which
|
|
676
|
-
// can drop the watch. Watch the containing directory and filter to our file
|
|
677
|
-
// so edits survive atomic-save/rename.
|
|
678
|
-
const watchDir = path.dirname(filePath);
|
|
679
|
-
const baseName = path.basename(filePath);
|
|
680
|
-
const watcher = fs.watch(watchDir, (_eventType, changed) => {
|
|
681
|
-
if (changed && changed !== baseName) return;
|
|
682
|
-
clearTimeout(debounce);
|
|
683
|
-
// Debounce: editors often emit several events per save.
|
|
684
|
-
debounce = setTimeout(rebuild, 100);
|
|
685
|
-
});
|
|
686
|
-
|
|
687
|
-
await new Promise(resolve => {
|
|
688
|
-
const stop = () => {
|
|
689
|
-
clearTimeout(debounce);
|
|
690
|
-
watcher.close();
|
|
691
|
-
humanLog('\nStopped watching.');
|
|
692
|
-
resolve();
|
|
693
|
-
};
|
|
694
|
-
process.once('SIGINT', stop);
|
|
695
|
-
process.once('SIGTERM', stop);
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
|
|
699
600
|
export function registerTheme(program) {
|
|
700
601
|
const theme = program
|
|
701
602
|
.command('theme')
|
|
@@ -720,10 +621,6 @@ export function registerTheme(program) {
|
|
|
720
621
|
.command('build <file>')
|
|
721
622
|
.description('Compile a defineTheme file to CSS + JS')
|
|
722
623
|
.option('-o, --out <path>', 'Output CSS file path')
|
|
723
|
-
.option(
|
|
724
|
-
'-w, --watch',
|
|
725
|
-
'Rebuild automatically when the theme file changes (Ctrl-C to stop)',
|
|
726
|
-
)
|
|
727
624
|
.action(async (file, options) => {
|
|
728
625
|
const filePath = path.resolve(process.cwd(), file);
|
|
729
626
|
const json = program.opts().json || false;
|
|
@@ -733,20 +630,6 @@ export function registerTheme(program) {
|
|
|
733
630
|
return;
|
|
734
631
|
}
|
|
735
632
|
|
|
736
|
-
// Watch mode: run an initial build, then rebuild on every change to the
|
|
737
|
-
// theme file. Watch is a human-interactive, long-running mode — it is not
|
|
738
|
-
// supported in --json (machine) mode, which expects a single envelope.
|
|
739
|
-
if (options.watch) {
|
|
740
|
-
if (json) {
|
|
741
|
-
cliError('--watch is not supported with --json', {
|
|
742
|
-
code: ERROR_CODES.ERR_THEME_INVALID,
|
|
743
|
-
});
|
|
744
|
-
return;
|
|
745
|
-
}
|
|
746
|
-
await runThemeBuildWatch(file, filePath, options);
|
|
747
|
-
return;
|
|
748
|
-
}
|
|
749
|
-
|
|
750
633
|
if (!json) humanLog(`\nBuilding theme from ${path.relative(process.cwd(), filePath)}...`);
|
|
751
634
|
|
|
752
635
|
// Extract theme definition
|
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {DropdownMenu} from '@astryxdesign/core/DropdownMenu';
|
|
6
7
|
|
|
7
8
|
export default function DropdownMenuShowcase() {
|
|
9
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
10
|
+
|
|
8
11
|
return (
|
|
9
12
|
<DropdownMenu
|
|
13
|
+
isMenuOpen={isMenuOpen}
|
|
14
|
+
onOpenChange={setIsMenuOpen}
|
|
15
|
+
hasAutoFocus={false}
|
|
10
16
|
button={{label: 'Actions'}}
|
|
11
17
|
items={[
|
|
12
18
|
{label: 'Edit', onClick: () => {}},
|
|
@@ -65,7 +65,11 @@ const TrashIcon = (props: React.SVGProps<SVGSVGElement>) => (
|
|
|
65
65
|
|
|
66
66
|
export default function DropdownMenuItemShowcase() {
|
|
67
67
|
return (
|
|
68
|
-
<DropdownMenu
|
|
68
|
+
<DropdownMenu
|
|
69
|
+
button={{label: 'Actions'}}
|
|
70
|
+
isMenuOpen
|
|
71
|
+
hasAutoFocus={false}
|
|
72
|
+
onOpenChange={() => {}}>
|
|
69
73
|
<DropdownMenuItem
|
|
70
74
|
icon={PencilIcon}
|
|
71
75
|
label="Edit"
|
|
@@ -12,10 +12,9 @@ export default function LightboxShowcase() {
|
|
|
12
12
|
isOpen={isOpen}
|
|
13
13
|
onOpenChange={setIsOpen}
|
|
14
14
|
media={{
|
|
15
|
-
src: 'https://
|
|
16
|
-
alt: '
|
|
17
|
-
caption:
|
|
18
|
-
'A scenic coastline with waves rolling onto a sandy beach beneath a clear sky.',
|
|
15
|
+
src: 'https://picsum.photos/id/10/1200/800',
|
|
16
|
+
alt: 'Forest path',
|
|
17
|
+
caption: 'A winding path through the forest',
|
|
19
18
|
}}
|
|
20
19
|
/>
|
|
21
20
|
</>
|
|
@@ -2,11 +2,17 @@
|
|
|
2
2
|
|
|
3
3
|
'use client';
|
|
4
4
|
|
|
5
|
+
import {useState} from 'react';
|
|
5
6
|
import {MoreMenu} from '@astryxdesign/core/MoreMenu';
|
|
6
7
|
|
|
7
8
|
export default function MoreMenuShowcase() {
|
|
9
|
+
const [isMenuOpen, setIsMenuOpen] = useState(false);
|
|
10
|
+
|
|
8
11
|
return (
|
|
9
12
|
<MoreMenu
|
|
13
|
+
isMenuOpen={isMenuOpen}
|
|
14
|
+
onOpenChange={setIsMenuOpen}
|
|
15
|
+
hasAutoFocus={false}
|
|
10
16
|
items={[
|
|
11
17
|
{label: 'Edit', onClick: () => {}},
|
|
12
18
|
{label: 'Duplicate', onClick: () => {}},
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
exampleFor: 'TreeListBranches',
|
|
7
|
+
name: 'TreeListBranches',
|
|
8
|
+
displayName: 'Tree List Branches',
|
|
9
|
+
description: 'Tree with expandable branches at multiple nesting levels.',
|
|
10
|
+
isReady: true,
|
|
11
|
+
isShowcase: true,
|
|
12
|
+
aspectRatio: 4 / 3,
|
|
13
|
+
componentsUsed: ['TreeList'],
|
|
14
|
+
};
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {TreeList} from '@astryxdesign/core/TreeList';
|
|
6
|
+
|
|
7
|
+
const noop = () => {};
|
|
8
|
+
|
|
9
|
+
export default function TreeListBranchesShowcase() {
|
|
10
|
+
return (
|
|
11
|
+
<TreeList
|
|
12
|
+
items={[
|
|
13
|
+
{
|
|
14
|
+
id: 'design-system',
|
|
15
|
+
label: 'Design System',
|
|
16
|
+
isExpanded: true,
|
|
17
|
+
children: [
|
|
18
|
+
{
|
|
19
|
+
id: 'components',
|
|
20
|
+
label: 'Components',
|
|
21
|
+
isExpanded: true,
|
|
22
|
+
children: [
|
|
23
|
+
{
|
|
24
|
+
id: 'inputs',
|
|
25
|
+
label: 'Inputs',
|
|
26
|
+
children: [
|
|
27
|
+
{id: 'text-input', label: 'TextInput', onClick: noop},
|
|
28
|
+
{id: 'checkbox', label: 'Checkbox', onClick: noop},
|
|
29
|
+
{id: 'selector', label: 'Selector', onClick: noop},
|
|
30
|
+
],
|
|
31
|
+
},
|
|
32
|
+
{
|
|
33
|
+
id: 'layout',
|
|
34
|
+
label: 'Layout',
|
|
35
|
+
children: [
|
|
36
|
+
{id: 'stack', label: 'Stack', onClick: noop},
|
|
37
|
+
{id: 'grid', label: 'Grid', onClick: noop},
|
|
38
|
+
],
|
|
39
|
+
},
|
|
40
|
+
],
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
id: 'tokens',
|
|
44
|
+
label: 'Tokens',
|
|
45
|
+
children: [
|
|
46
|
+
{id: 'colors', label: 'Colors', onClick: noop},
|
|
47
|
+
{id: 'spacing', label: 'Spacing', onClick: noop},
|
|
48
|
+
{id: 'typography', label: 'Typography', onClick: noop},
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
],
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'utilities',
|
|
55
|
+
label: 'Utilities',
|
|
56
|
+
children: [
|
|
57
|
+
{id: 'hooks', label: 'Hooks', onClick: noop},
|
|
58
|
+
{id: 'helpers', label: 'Helpers', onClick: noop},
|
|
59
|
+
],
|
|
60
|
+
},
|
|
61
|
+
]}
|
|
62
|
+
/>
|
|
63
|
+
);
|
|
64
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
/** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
|
|
4
|
+
export const doc = {
|
|
5
|
+
type: 'block',
|
|
6
|
+
exampleFor: 'TreeListItem',
|
|
7
|
+
name: 'TreeListItem',
|
|
8
|
+
displayName: 'Tree List Item',
|
|
9
|
+
description: 'Tree items with descriptions, icons, badges, selection, disabled state, and nested expand/collapse. TreeList is data-driven: no composed children API.',
|
|
10
|
+
isReady: true,
|
|
11
|
+
isShowcase: true,
|
|
12
|
+
aspectRatio: 4 / 3,
|
|
13
|
+
componentsUsed: ['TreeList', 'Badge', 'Icon', 'Layout', 'Text'],
|
|
14
|
+
};
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
+
|
|
3
|
+
'use client';
|
|
4
|
+
|
|
5
|
+
import {TreeList} from '@astryxdesign/core/TreeList';
|
|
6
|
+
import {Badge} from '@astryxdesign/core/Badge';
|
|
7
|
+
import {Icon} from '@astryxdesign/core/Icon';
|
|
8
|
+
|
|
9
|
+
const noop = () => {};
|
|
10
|
+
|
|
11
|
+
export default function TreeListItemShowcase() {
|
|
12
|
+
return (
|
|
13
|
+
<TreeList
|
|
14
|
+
style={{width: 400}}
|
|
15
|
+
items={[
|
|
16
|
+
{
|
|
17
|
+
id: 'inbox',
|
|
18
|
+
label: 'Inbox',
|
|
19
|
+
description: '12 unread messages',
|
|
20
|
+
isExpanded: true,
|
|
21
|
+
startContent: <Icon icon="info" size="sm" />,
|
|
22
|
+
endContent: <Badge label="12" variant="info" />,
|
|
23
|
+
children: [
|
|
24
|
+
{
|
|
25
|
+
id: 'primary',
|
|
26
|
+
label: 'Primary',
|
|
27
|
+
isSelected: true,
|
|
28
|
+
startContent: <Icon icon="check" size="sm" />,
|
|
29
|
+
onClick: noop,
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
id: 'updates',
|
|
33
|
+
label: 'Updates',
|
|
34
|
+
endContent: <Badge label="4" variant="info" />,
|
|
35
|
+
onClick: noop,
|
|
36
|
+
},
|
|
37
|
+
],
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
id: 'drafts',
|
|
41
|
+
label: 'Drafts',
|
|
42
|
+
description: '3 draft messages',
|
|
43
|
+
startContent: <Icon icon="clock" size="sm" />,
|
|
44
|
+
onClick: noop,
|
|
45
|
+
},
|
|
46
|
+
{
|
|
47
|
+
id: 'archive',
|
|
48
|
+
label: 'Archive',
|
|
49
|
+
onClick: noop,
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
id: 'spam',
|
|
53
|
+
label: 'Spam',
|
|
54
|
+
isDisabled: true,
|
|
55
|
+
startContent: <Icon icon="warning" size="sm" />,
|
|
56
|
+
},
|
|
57
|
+
]}
|
|
58
|
+
/>
|
|
59
|
+
);
|
|
60
|
+
}
|
|
@@ -1,157 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* @file Tests for `astryx theme build --watch` (#3375).
|
|
5
|
-
*
|
|
6
|
-
* Watch mode runs an initial build, then rebuilds whenever the theme file
|
|
7
|
-
* changes, until interrupted. Each rebuild runs in a child process so a build
|
|
8
|
-
* error (reported by the single-build path via a hard exit) is contained and
|
|
9
|
-
* the watcher keeps running.
|
|
10
|
-
*
|
|
11
|
-
* Building `astryx theme build` requires a compiled @astryxdesign/core, so this
|
|
12
|
-
* suite builds core once in beforeAll (mirrors build-theme.prose.test.mjs).
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
import {describe, it, expect, beforeAll, beforeEach, afterEach} from 'vitest';
|
|
16
|
-
import {execFileSync, spawn} from 'node:child_process';
|
|
17
|
-
import * as fs from 'node:fs';
|
|
18
|
-
import * as path from 'node:path';
|
|
19
|
-
import * as os from 'node:os';
|
|
20
|
-
import {fileURLToPath} from 'node:url';
|
|
21
|
-
|
|
22
|
-
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
23
|
-
const CLI_BIN = path.resolve(__dirname, '../../bin/astryx.mjs');
|
|
24
|
-
const REPO_ROOT = path.resolve(__dirname, '../../../..');
|
|
25
|
-
const CORE_THEME_ENTRY = path.join(
|
|
26
|
-
REPO_ROOT,
|
|
27
|
-
'packages/core/dist/theme/index.js',
|
|
28
|
-
);
|
|
29
|
-
|
|
30
|
-
function runCli(args, cwd) {
|
|
31
|
-
try {
|
|
32
|
-
const out = execFileSync('node', [CLI_BIN, ...args], {
|
|
33
|
-
cwd,
|
|
34
|
-
encoding: 'utf-8',
|
|
35
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
36
|
-
env: {...process.env, FORCE_COLOR: '0'},
|
|
37
|
-
});
|
|
38
|
-
return {code: 0, stdout: out, stderr: ''};
|
|
39
|
-
} catch (e) {
|
|
40
|
-
return {
|
|
41
|
-
code: e.status ?? 1,
|
|
42
|
-
stdout: e.stdout?.toString() ?? '',
|
|
43
|
-
stderr: e.stderr?.toString() ?? '',
|
|
44
|
-
};
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Poll until `predicate()` is true or the timeout elapses. */
|
|
49
|
-
async function waitFor(predicate, {timeout = 8000, interval = 50} = {}) {
|
|
50
|
-
const start = Date.now();
|
|
51
|
-
for (;;) {
|
|
52
|
-
if (predicate()) return true;
|
|
53
|
-
if (Date.now() - start > timeout) return false;
|
|
54
|
-
await new Promise(r => setTimeout(r, interval));
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
beforeAll(() => {
|
|
59
|
-
if (!fs.existsSync(CORE_THEME_ENTRY)) {
|
|
60
|
-
execFileSync('pnpm', ['-F', '@astryxdesign/core', 'build'], {
|
|
61
|
-
cwd: REPO_ROOT,
|
|
62
|
-
stdio: 'pipe',
|
|
63
|
-
timeout: 180_000,
|
|
64
|
-
});
|
|
65
|
-
}
|
|
66
|
-
}, 200_000);
|
|
67
|
-
|
|
68
|
-
let tmpDir;
|
|
69
|
-
beforeEach(() => {
|
|
70
|
-
tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'astryx-build-theme-watch-'));
|
|
71
|
-
});
|
|
72
|
-
afterEach(() => {
|
|
73
|
-
fs.rmSync(tmpDir, {recursive: true, force: true});
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
describe('theme build --watch', () => {
|
|
77
|
-
it('advertises the flag in --help', () => {
|
|
78
|
-
const result = runCli(['theme', 'build', '--help'], process.cwd());
|
|
79
|
-
const out = result.stdout + result.stderr;
|
|
80
|
-
expect(out).toMatch(/--watch/);
|
|
81
|
-
});
|
|
82
|
-
|
|
83
|
-
it('rejects --watch together with --json (single-envelope contract)', () => {
|
|
84
|
-
const themeFile = path.join(tmpDir, 'wt.mjs');
|
|
85
|
-
fs.writeFileSync(
|
|
86
|
-
themeFile,
|
|
87
|
-
`export default { name: 'wt', tokens: { '--color-bg': '#fff' } };\n`,
|
|
88
|
-
);
|
|
89
|
-
const result = runCli(
|
|
90
|
-
['--json', 'theme', 'build', path.relative(tmpDir, themeFile), '--watch'],
|
|
91
|
-
tmpDir,
|
|
92
|
-
);
|
|
93
|
-
expect(result.code).not.toBe(0);
|
|
94
|
-
expect(result.stdout + result.stderr).toMatch(/watch/i);
|
|
95
|
-
});
|
|
96
|
-
|
|
97
|
-
it('builds initially, rebuilds on change, and stops cleanly on SIGINT', async () => {
|
|
98
|
-
const themeFile = path.join(tmpDir, 'wt.mjs');
|
|
99
|
-
const cssFile = path.join(tmpDir, 'wt.css');
|
|
100
|
-
fs.writeFileSync(
|
|
101
|
-
themeFile,
|
|
102
|
-
`export default { name: 'wt', tokens: { '--color-bg': '#ffffff' } };\n`,
|
|
103
|
-
);
|
|
104
|
-
|
|
105
|
-
const child = spawn(
|
|
106
|
-
process.execPath,
|
|
107
|
-
[CLI_BIN, 'theme', 'build', 'wt.mjs', '--watch'],
|
|
108
|
-
{cwd: tmpDir, env: {...process.env, FORCE_COLOR: '0'}},
|
|
109
|
-
);
|
|
110
|
-
let stdout = '';
|
|
111
|
-
child.stdout.on('data', d => (stdout += d.toString()));
|
|
112
|
-
child.stderr.on('data', d => (stdout += d.toString()));
|
|
113
|
-
|
|
114
|
-
try {
|
|
115
|
-
// Initial build produces the CSS.
|
|
116
|
-
const built = await waitFor(() => fs.existsSync(cssFile));
|
|
117
|
-
expect(built).toBe(true);
|
|
118
|
-
const firstCss = fs.readFileSync(cssFile, 'utf-8');
|
|
119
|
-
expect(firstCss).toMatch(/#ffffff/);
|
|
120
|
-
|
|
121
|
-
// Wait until the watcher is actually watching before editing, so the
|
|
122
|
-
// change isn't missed.
|
|
123
|
-
await waitFor(() => /Watching/i.test(stdout));
|
|
124
|
-
|
|
125
|
-
// Change the theme — the token value changes so the CSS must change.
|
|
126
|
-
fs.writeFileSync(
|
|
127
|
-
themeFile,
|
|
128
|
-
`export default { name: 'wt', tokens: { '--color-bg': '#010203' } };\n`,
|
|
129
|
-
);
|
|
130
|
-
|
|
131
|
-
// The rebuilt CSS should reflect the new value.
|
|
132
|
-
const rebuilt = await waitFor(() => {
|
|
133
|
-
try {
|
|
134
|
-
return fs.readFileSync(cssFile, 'utf-8').includes('#010203');
|
|
135
|
-
} catch {
|
|
136
|
-
return false;
|
|
137
|
-
}
|
|
138
|
-
});
|
|
139
|
-
expect(rebuilt).toBe(true);
|
|
140
|
-
expect(stdout).toMatch(/rebuild/i);
|
|
141
|
-
} finally {
|
|
142
|
-
// SIGINT must stop the watcher and exit cleanly.
|
|
143
|
-
child.kill('SIGINT');
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
const exited = await new Promise(resolve => {
|
|
147
|
-
let done = false;
|
|
148
|
-
child.on('exit', () => {
|
|
149
|
-
done = true;
|
|
150
|
-
resolve(true);
|
|
151
|
-
});
|
|
152
|
-
setTimeout(() => resolve(done), 4000);
|
|
153
|
-
});
|
|
154
|
-
expect(exited).toBe(true);
|
|
155
|
-
expect(stdout).toMatch(/Stopped watching/);
|
|
156
|
-
}, 30_000);
|
|
157
|
-
});
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'AvatarStatusDot',
|
|
7
|
-
name: 'AvatarStatusDot — Variants',
|
|
8
|
-
displayName: 'AvatarStatusDot — Variants',
|
|
9
|
-
description:
|
|
10
|
-
'Presence dots on Avatars using the success, neutral, and error variants. Pass an AvatarStatusDot to the Avatar status prop; the dot sizes itself to match the Avatar.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 16 / 9,
|
|
13
|
-
componentsUsed: ['Avatar', 'AvatarStatusDot', 'HStack'],
|
|
14
|
-
};
|
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import {Avatar, AvatarStatusDot} from '@astryxdesign/core/Avatar';
|
|
6
|
-
import {HStack} from '@astryxdesign/core/Layout';
|
|
7
|
-
|
|
8
|
-
export default function AvatarStatusDotVariants() {
|
|
9
|
-
return (
|
|
10
|
-
<HStack gap={4} vAlign="center">
|
|
11
|
-
<Avatar
|
|
12
|
-
name="Ana Silva"
|
|
13
|
-
size="large"
|
|
14
|
-
status={<AvatarStatusDot variant="success" label="Online" />}
|
|
15
|
-
/>
|
|
16
|
-
<Avatar
|
|
17
|
-
name="Ben Okafor"
|
|
18
|
-
size="large"
|
|
19
|
-
status={<AvatarStatusDot variant="neutral" label="Away" />}
|
|
20
|
-
/>
|
|
21
|
-
<Avatar
|
|
22
|
-
name="Cleo Marsh"
|
|
23
|
-
size="large"
|
|
24
|
-
status={<AvatarStatusDot variant="error" label="Do not disturb" />}
|
|
25
|
-
/>
|
|
26
|
-
</HStack>
|
|
27
|
-
);
|
|
28
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'Blockquote',
|
|
7
|
-
name: 'Blockquote — Testimonials',
|
|
8
|
-
displayName: 'Blockquote — Testimonials',
|
|
9
|
-
description:
|
|
10
|
-
'Multiple quotes arranged in a card grid for a testimonials section. Combine with Card and Grid to create social-proof layouts.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 4 / 3,
|
|
13
|
-
componentsUsed: ['Blockquote', 'Card', 'Grid', 'GridSpan'],
|
|
14
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
'use client';
|
|
4
|
-
|
|
5
|
-
import {Blockquote} from '@astryxdesign/core/Blockquote';
|
|
6
|
-
import {Grid, GridSpan} from '@astryxdesign/core/Grid';
|
|
7
|
-
import {Card} from '@astryxdesign/core/Card';
|
|
8
|
-
|
|
9
|
-
export default function BlockquoteTestimonials() {
|
|
10
|
-
return (
|
|
11
|
-
<Grid columns={2} gap={3} style={{maxWidth: 600}}>
|
|
12
|
-
<Card padding={4}>
|
|
13
|
-
<Blockquote cite="Sarah K., Lead Engineer">
|
|
14
|
-
Shipping UI has never been this fast. Our team went from design to
|
|
15
|
-
production in a single afternoon.
|
|
16
|
-
</Blockquote>
|
|
17
|
-
</Card>
|
|
18
|
-
<Card padding={4}>
|
|
19
|
-
<Blockquote cite="Marcus T., Product Designer">
|
|
20
|
-
The token system means every new screen just looks right — no manual
|
|
21
|
-
color or spacing decisions.
|
|
22
|
-
</Blockquote>
|
|
23
|
-
</Card>
|
|
24
|
-
<GridSpan columns={2}>
|
|
25
|
-
<Card padding={4}>
|
|
26
|
-
<Blockquote cite="Priya L., Engineering Manager">
|
|
27
|
-
Onboarding a new engineer used to take a week of design review. Now
|
|
28
|
-
they're shipping accessible, polished components on day one.
|
|
29
|
-
</Blockquote>
|
|
30
|
-
</Card>
|
|
31
|
-
</GridSpan>
|
|
32
|
-
</Grid>
|
|
33
|
-
);
|
|
34
|
-
}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
// Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
2
|
-
|
|
3
|
-
/** @type {import('../../../../../core/src/docs-types').TemplateDoc} */
|
|
4
|
-
export const doc = {
|
|
5
|
-
type: 'block',
|
|
6
|
-
exampleFor: 'Blockquote',
|
|
7
|
-
name: 'Blockquote — With Attribution',
|
|
8
|
-
displayName: 'Blockquote — With Attribution',
|
|
9
|
-
description:
|
|
10
|
-
'A plain quote and a quote with a cite attribution. Use cite to credit the original author or source.',
|
|
11
|
-
isReady: true,
|
|
12
|
-
aspectRatio: 4 / 3,
|
|
13
|
-
componentsUsed: ['Blockquote', 'Layout'],
|
|
14
|
-
};
|