@fragments-sdk/cli 0.15.2 → 0.15.4

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/dist/bin.js CHANGED
@@ -7050,7 +7050,7 @@ program.command("add").argument("[name]", 'Component name (e.g., "Button", "Text
7050
7050
  });
7051
7051
  program.command("create").argument("[name]", "Project name").description("Create a new project with Fragments UI and your custom theme").option("-t, --template <template>", "Framework template (nextjs, vite)", "nextjs").option("--pm <manager>", "Package manager (npm, pnpm, yarn, bun)").option("--theme <encoded>", "Encoded theme string").option("--preset <id>", "Theme preset ID from usefragments.com/create").option("--brand <color>", "Brand color hex (e.g., #6366f1)").option("--scss", "Use SCSS output (installs sass)").option("--mcp", "Configure MCP server for AI tooling").option("-y, --yes", "Skip interactive prompts").option("--no-git", "Skip git initialization").action(async (name, options) => {
7052
7052
  try {
7053
- const { create } = await import("./create-JVAU3YKN.js");
7053
+ const { create } = await import("./create-LA4J2HHQ.js");
7054
7054
  const result = await create({
7055
7055
  name,
7056
7056
  template: options.template,
@@ -7394,7 +7394,7 @@ governCmd.command("connect").description("Connect your project to the Fragments
7394
7394
  });
7395
7395
  governCmd.command("scan").description("Scan JSX/TSX codebase for governance violations").option("-d, --dir <path>", "Root directory (default: auto-detect)").option("-c, --config <path>", "Path to govern.config.ts").option("-f, --format <format>", "Output format: summary, json, sarif", "summary").option("-q, --quiet", "Suppress non-error output").action(async (options) => {
7396
7396
  try {
7397
- const { governScan } = await import("./govern-scan-OYFZYOQW.js");
7397
+ const { governScan } = await import("./govern-scan-DW4QUAYD.js");
7398
7398
  const { exitCode } = await governScan({
7399
7399
  dir: options.dir,
7400
7400
  config: options.config,
@@ -7409,7 +7409,7 @@ governCmd.command("scan").description("Scan JSX/TSX codebase for governance viol
7409
7409
  });
7410
7410
  governCmd.command("watch").description("Watch JSX/TSX files and re-check on changes").option("-d, --dir <path>", "Root directory (default: auto-detect)").option("-c, --config <path>", "Path to govern.config.ts").option("-q, --quiet", "Suppress non-error output").option("--debounce <ms>", "Debounce interval in ms", "300").action(async (options) => {
7411
7411
  try {
7412
- const { governWatch } = await import("./govern-scan-OYFZYOQW.js");
7412
+ const { governWatch } = await import("./govern-scan-DW4QUAYD.js");
7413
7413
  await governWatch({
7414
7414
  dir: options.dir,
7415
7415
  config: options.config,
@@ -298,72 +298,6 @@ function generateDarkTokens(config, format) {
298
298
  }
299
299
  return tokens;
300
300
  }
301
- function generateScssTokens(config) {
302
- const lines = [];
303
- lines.push("// Auto-generated by @fragments-sdk/cli");
304
- lines.push(`// Theme: ${config.name}`);
305
- if (config.version) {
306
- lines.push(`// Version: ${config.version}`);
307
- }
308
- lines.push("");
309
- const colorTokens = generateCategoryTokens(config, "colors", "scss");
310
- if (colorTokens.length > 0) {
311
- lines.push("// Colors");
312
- lines.push(...colorTokens);
313
- lines.push("");
314
- }
315
- const surfaceTokens = generateCategoryTokens(config, "surfaces", "scss");
316
- if (surfaceTokens.length > 0) {
317
- lines.push("// Surfaces");
318
- lines.push(...surfaceTokens);
319
- lines.push("");
320
- }
321
- const textTokens = generateCategoryTokens(config, "text", "scss");
322
- if (textTokens.length > 0) {
323
- lines.push("// Text");
324
- lines.push(...textTokens);
325
- lines.push("");
326
- }
327
- const borderTokens = generateCategoryTokens(config, "borders", "scss");
328
- if (borderTokens.length > 0) {
329
- lines.push("// Borders");
330
- lines.push(...borderTokens);
331
- if (config.borders?.default) {
332
- lines.push(`$fui-border-default: ${config.borders.default} !default;`);
333
- }
334
- lines.push("");
335
- }
336
- const typographyTokens = generateCategoryTokens(config, "typography", "scss");
337
- if (typographyTokens.length > 0) {
338
- lines.push("// Typography");
339
- lines.push(...typographyTokens);
340
- lines.push("");
341
- }
342
- const radiusTokens = generateCategoryTokens(config, "radius", "scss");
343
- if (radiusTokens.length > 0) {
344
- lines.push("// Border Radius");
345
- lines.push(...radiusTokens);
346
- lines.push("");
347
- }
348
- const shadowTokens = generateCategoryTokens(config, "shadows", "scss");
349
- if (shadowTokens.length > 0) {
350
- lines.push("// Shadows");
351
- lines.push(...shadowTokens);
352
- lines.push("");
353
- }
354
- if (config.density) {
355
- lines.push("// Density");
356
- lines.push(`$fui-density: "${config.density}" !default;`);
357
- lines.push("");
358
- }
359
- const darkTokens = generateDarkTokens(config, "scss");
360
- if (darkTokens.length > 0) {
361
- lines.push("// Dark Mode");
362
- lines.push(...darkTokens);
363
- lines.push("");
364
- }
365
- return lines.join("\n");
366
- }
367
301
  function generateCssTokens(config) {
368
302
  const lines = [];
369
303
  lines.push("/* Auto-generated by @fragments-sdk/cli */");
@@ -536,31 +470,244 @@ export function Providers({ children }: { children: ReactNode }) {
536
470
  function generateNextjsPage() {
537
471
  return `'use client';
538
472
 
539
- import { Button, Card, Stack, Text, Input } from '@fragments-sdk/ui';
473
+ import { useState } from 'react';
474
+ import {
475
+ Avatar,
476
+ Badge,
477
+ Button,
478
+ Card,
479
+ Checkbox,
480
+ Input,
481
+ Progress,
482
+ Separator,
483
+ Stack,
484
+ Switch,
485
+ Tabs,
486
+ Text,
487
+ Tooltip,
488
+ } from '@fragments-sdk/ui';
489
+ import styles from './page.module.css';
490
+
491
+ function StatCard({ label, value, change }: { label: string; value: string; change: string }) {
492
+ const isPositive = change.startsWith('+');
493
+ return (
494
+ <Card>
495
+ <Card.Body>
496
+ <Stack gap="xs">
497
+ <Text size="sm" color="secondary">{label}</Text>
498
+ <Text size="2xl" weight="semibold">{value}</Text>
499
+ <Badge variant={isPositive ? 'success' : 'error'} size="sm">{change}</Badge>
500
+ </Stack>
501
+ </Card.Body>
502
+ </Card>
503
+ );
504
+ }
505
+
506
+ function TaskItem({ title, done }: { title: string; done?: boolean }) {
507
+ const [checked, setChecked] = useState(done ?? false);
508
+ return (
509
+ <Stack direction="row" align="center" gap="sm">
510
+ <Checkbox checked={checked} onChange={() => setChecked(!checked)} />
511
+ <Text size="sm" className={checked ? styles.done : undefined}>{title}</Text>
512
+ </Stack>
513
+ );
514
+ }
540
515
 
541
516
  export default function Home() {
517
+ const [notifications, setNotifications] = useState(true);
518
+
542
519
  return (
543
- <main style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
544
- <Card style={{ maxWidth: 480, width: '100%' }}>
545
- <Card.Header>
546
- <Card.Title>Welcome to Fragments</Card.Title>
547
- <Card.Description>Your app is ready. Start building something great.</Card.Description>
548
- </Card.Header>
549
- <Card.Body>
550
- <Stack gap={3}>
551
- <Input placeholder="Enter something..." />
552
- <Stack direction="row" gap={2}>
553
- <Button>Get Started</Button>
554
- <Button variant="secondary">Learn More</Button>
520
+ <main className={styles.page}>
521
+ {/* Hero */}
522
+ <Stack align="center" gap="md" className={styles.hero}>
523
+ <Badge variant="info">Powered by Fragments UI</Badge>
524
+ <Text as="h1" size="2xl" weight="bold">Your app is ready</Text>
525
+ <Text size="lg" color="secondary" className={styles.heroDescription}>
526
+ This page showcases your custom theme and components.
527
+ Edit <code>src/app/page.tsx</code> to start building.
528
+ </Text>
529
+ <Stack direction="row" gap="sm">
530
+ <Button size="lg">Start building</Button>
531
+ <Button size="lg" variant="secondary">Read the docs</Button>
532
+ </Stack>
533
+ </Stack>
534
+
535
+ <Separator />
536
+
537
+ {/* Stats */}
538
+ <div className={styles.statsGrid}>
539
+ <StatCard label="Components" value="66" change="+12 this month" />
540
+ <StatCard label="Design tokens" value="80" change="+5 new" />
541
+ <StatCard label="Accessibility" value="98%" change="+2.4%" />
542
+ </div>
543
+
544
+ {/* Content */}
545
+ <div className={styles.contentGrid}>
546
+ <Card>
547
+ <Card.Header>
548
+ <Card.Title>Getting started</Card.Title>
549
+ <Card.Description>Pick up where you left off</Card.Description>
550
+ </Card.Header>
551
+ <Card.Body>
552
+ <Tabs defaultValue="tasks">
553
+ <Tabs.List>
554
+ <Tabs.Tab value="tasks">Tasks</Tabs.Tab>
555
+ <Tabs.Tab value="progress">Progress</Tabs.Tab>
556
+ </Tabs.List>
557
+ <Tabs.Panel value="tasks">
558
+ <Stack gap="sm" className={styles.tabContent}>
559
+ <TaskItem title="Install Fragments UI" done />
560
+ <TaskItem title="Configure your theme" done />
561
+ <TaskItem title="Build your first page" />
562
+ <TaskItem title="Set up MCP for AI tooling" />
563
+ <TaskItem title="Deploy to production" />
564
+ </Stack>
565
+ </Tabs.Panel>
566
+ <Tabs.Panel value="progress">
567
+ <Stack gap="md" className={styles.tabContent}>
568
+ <Stack gap="xs">
569
+ <Stack direction="row" justify="between">
570
+ <Text size="sm">Setup</Text>
571
+ <Text size="sm" color="secondary">2 of 5</Text>
572
+ </Stack>
573
+ <Progress value={40} />
574
+ </Stack>
575
+ <Text size="sm" color="secondary">
576
+ Complete the remaining tasks to finish setting up your project.
577
+ </Text>
578
+ </Stack>
579
+ </Tabs.Panel>
580
+ </Tabs>
581
+ </Card.Body>
582
+ </Card>
583
+
584
+ <Card>
585
+ <Card.Header>
586
+ <Card.Title>Settings</Card.Title>
587
+ <Card.Description>Manage your preferences</Card.Description>
588
+ </Card.Header>
589
+ <Card.Body>
590
+ <Stack gap="md">
591
+ <Input placeholder="Search settings..." />
592
+ <Stack direction="row" align="center" justify="between">
593
+ <Stack gap="xs">
594
+ <Text size="sm" weight="medium">Notifications</Text>
595
+ <Text size="xs" color="secondary">Receive alerts for updates</Text>
596
+ </Stack>
597
+ <Switch checked={notifications} onChange={() => setNotifications(!notifications)} />
598
+ </Stack>
599
+ <Separator />
600
+ <Stack direction="row" align="center" justify="between">
601
+ <Stack gap="xs">
602
+ <Text size="sm" weight="medium">Theme</Text>
603
+ <Text size="xs" color="secondary">System preference detected</Text>
604
+ </Stack>
605
+ <Badge variant="default" size="sm">Auto</Badge>
606
+ </Stack>
607
+ <Separator />
608
+ <Stack direction="row" gap="sm" align="center">
609
+ <Avatar name="You" size="sm" />
610
+ <Stack gap="xs" className={styles.flex1}>
611
+ <Text size="sm" weight="medium">Your account</Text>
612
+ <Text size="xs" color="secondary">Manage profile and billing</Text>
613
+ </Stack>
614
+ <Tooltip content="Go to account settings">
615
+ <Button variant="ghost" size="sm">Manage</Button>
616
+ </Tooltip>
617
+ </Stack>
555
618
  </Stack>
556
- </Stack>
557
- </Card.Body>
558
- </Card>
619
+ </Card.Body>
620
+ </Card>
621
+ </div>
622
+
623
+ {/* Footer */}
624
+ <Text size="sm" color="secondary" className={styles.footer}>
625
+ Built with{' '}
626
+ <a href="https://usefragments.com" className={styles.link}>Fragments UI</a>
627
+ {' '}&mdash; 66 components, 80 design tokens, accessible by default.
628
+ </Text>
559
629
  </main>
560
630
  );
561
631
  }
562
632
  `;
563
633
  }
634
+ function generatePageCssModule() {
635
+ return `.page {
636
+ min-height: 100vh;
637
+ display: flex;
638
+ flex-direction: column;
639
+ align-items: center;
640
+ padding: var(--fui-space-6, 3rem) var(--fui-space-3, 1.5rem);
641
+ gap: var(--fui-space-4, 2rem);
642
+ max-width: 960px;
643
+ margin: 0 auto;
644
+ }
645
+
646
+ .hero {
647
+ text-align: center;
648
+ padding-top: var(--fui-space-4, 2rem);
649
+ padding-bottom: var(--fui-space-2, 1rem);
650
+ }
651
+
652
+ .heroDescription {
653
+ max-width: 480px;
654
+ }
655
+
656
+ .heroDescription code {
657
+ font-size: 0.875em;
658
+ font-family: var(--fui-font-mono, monospace);
659
+ background: var(--fui-bg-secondary);
660
+ padding: 0.125em 0.375em;
661
+ border-radius: var(--fui-radius-sm, 0.25rem);
662
+ }
663
+
664
+ .statsGrid {
665
+ display: grid;
666
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
667
+ gap: var(--fui-space-2, 1rem);
668
+ width: 100%;
669
+ }
670
+
671
+ .contentGrid {
672
+ display: grid;
673
+ grid-template-columns: 1fr 1fr;
674
+ gap: var(--fui-space-3, 1.5rem);
675
+ width: 100%;
676
+ }
677
+
678
+ @media (max-width: 768px) {
679
+ .contentGrid {
680
+ grid-template-columns: 1fr;
681
+ }
682
+ }
683
+
684
+ .tabContent {
685
+ padding-top: var(--fui-space-1, 0.75rem);
686
+ }
687
+
688
+ .done {
689
+ text-decoration: line-through;
690
+ opacity: 0.5;
691
+ }
692
+
693
+ .flex1 {
694
+ flex: 1;
695
+ }
696
+
697
+ .footer {
698
+ padding-top: var(--fui-space-2, 1rem);
699
+ }
700
+
701
+ .link {
702
+ color: inherit;
703
+ text-decoration: underline;
704
+ }
705
+
706
+ .link:hover {
707
+ color: var(--fui-color-accent);
708
+ }
709
+ `;
710
+ }
564
711
  function generateViteMain(themePath) {
565
712
  return `import { StrictMode } from 'react';
566
713
  import { createRoot } from 'react-dom/client';
@@ -583,32 +730,7 @@ createRoot(document.getElementById('root')!).render(
583
730
  `;
584
731
  }
585
732
  function generateViteApp() {
586
- return `import { Button, Card, Stack, Text, Input } from '@fragments-sdk/ui';
587
-
588
- function App() {
589
- return (
590
- <main style={{ minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
591
- <Card style={{ maxWidth: 480, width: '100%' }}>
592
- <Card.Header>
593
- <Card.Title>Welcome to Fragments</Card.Title>
594
- <Card.Description>Your app is ready. Start building something great.</Card.Description>
595
- </Card.Header>
596
- <Card.Body>
597
- <Stack gap={3}>
598
- <Input placeholder="Enter something..." />
599
- <Stack direction="row" gap={2}>
600
- <Button>Get Started</Button>
601
- <Button variant="secondary">Learn More</Button>
602
- </Stack>
603
- </Stack>
604
- </Card.Body>
605
- </Card>
606
- </main>
607
- );
608
- }
609
-
610
- export default App;
611
- `;
733
+ return generateNextjsPage().replace("'use client';\n\n", "").replace("import styles from './page.module.css';", "import styles from './App.module.css';").replace("src/app/page.tsx", "src/App.tsx").replace("export default function Home()", "function App()") + "\nexport default App;\n";
612
734
  }
613
735
  function injectFontIntoViteHtml(projectDir, theme) {
614
736
  const fontName = theme.typography?.fontSans ? extractFontFamily(theme.typography.fontSans) : null;
@@ -677,26 +799,28 @@ Scaffolding ${template === "nextjs" ? "Next.js" : "Vite + React"} project...
677
799
  }
678
800
  }
679
801
  }
680
- function installDeps(projectDir, pm, scss) {
802
+ function installDeps(projectDir, pm) {
681
803
  console.log(pc.cyan("\nInstalling Fragments UI...\n"));
682
804
  const install = getInstallCommand(pm);
805
+ const devInstall = getDevInstallCommand(pm);
683
806
  execSync(`${install} @fragments-sdk/ui`, { cwd: projectDir, stdio: "inherit" });
684
- if (scss) {
685
- const devInstall = getDevInstallCommand(pm);
686
- execSync(`${devInstall} sass`, { cwd: projectDir, stdio: "inherit" });
687
- }
807
+ execSync(`${devInstall} sass`, { cwd: projectDir, stdio: "inherit" });
688
808
  }
689
- function writeThemeFile(projectDir, theme, scss, template) {
809
+ function writeThemeFile(projectDir, theme, template) {
690
810
  const stylesDir = join2(projectDir, "src", "styles");
691
811
  mkdirSync(stylesDir, { recursive: true });
692
- const ext = scss ? "scss" : "css";
693
- const content = scss ? generateScssTokens(theme) : generateCssTokens(theme);
694
- const filePath = join2(stylesDir, `theme.${ext}`);
812
+ const cssContent = generateCssTokens(theme);
813
+ const content = `// Fragments UI \u2014 tokens, resets, dark mode
814
+ @use '@fragments-sdk/ui/styles';
815
+
816
+ // Theme overrides (generated from your preset)
817
+ ${cssContent}`;
818
+ const filePath = join2(stylesDir, "theme.scss");
695
819
  writeFileSync(filePath, content, "utf-8");
696
820
  if (template === "nextjs") {
697
- return `../styles/theme.${ext}`;
821
+ return "../styles/theme.scss";
698
822
  }
699
- return `./styles/theme.${ext}`;
823
+ return "./styles/theme.scss";
700
824
  }
701
825
  function addNextTranspilePackages(projectDir) {
702
826
  const configCandidates = ["next.config.ts", "next.config.mjs", "next.config.js"];
@@ -747,11 +871,8 @@ function rewriteAppFiles(projectDir, template, themePath, theme) {
747
871
  writeFileSync(providersPath, generateNextjsProviders(), "utf-8");
748
872
  const pagePath = join2(projectDir, "src", "app", "page.tsx");
749
873
  writeFileSync(pagePath, generateNextjsPage(), "utf-8");
750
- const moduleCssPath = join2(projectDir, "src", "app", "page.module.css");
751
- try {
752
- unlinkSync(moduleCssPath);
753
- } catch {
754
- }
874
+ const pageCssPath = join2(projectDir, "src", "app", "page.module.css");
875
+ writeFileSync(pageCssPath, generatePageCssModule(), "utf-8");
755
876
  const globalsCssPath = join2(projectDir, "src", "app", "globals.css");
756
877
  try {
757
878
  unlinkSync(globalsCssPath);
@@ -763,6 +884,8 @@ function rewriteAppFiles(projectDir, template, themePath, theme) {
763
884
  writeFileSync(mainPath, generateViteMain(themePath), "utf-8");
764
885
  const appPath = join2(projectDir, "src", "App.tsx");
765
886
  writeFileSync(appPath, generateViteApp(), "utf-8");
887
+ const appCssModulePath = join2(projectDir, "src", "App.module.css");
888
+ writeFileSync(appCssModulePath, generatePageCssModule(), "utf-8");
766
889
  for (const file of ["src/App.css", "src/index.css"]) {
767
890
  try {
768
891
  unlinkSync(join2(projectDir, file));
@@ -818,8 +941,8 @@ ${BRAND.name} Create
818
941
  if (!existsSync(projectDir)) {
819
942
  return { success: false, error: "Framework scaffolding failed \u2014 project directory was not created." };
820
943
  }
821
- installDeps(projectDir, pm, !!resolved.scss);
822
- const themePath = writeThemeFile(projectDir, theme, !!resolved.scss, template);
944
+ installDeps(projectDir, pm);
945
+ const themePath = writeThemeFile(projectDir, theme, template);
823
946
  rewriteAppFiles(projectDir, template, themePath, theme);
824
947
  if (resolved.mcp) {
825
948
  configureMcp(projectDir);
@@ -837,7 +960,7 @@ ${BRAND.name} Create
837
960
  console.log("");
838
961
  if (theme.name !== "default") {
839
962
  console.log(pc.dim(` Theme "${theme.name}" applied with full token set.`));
840
- console.log(pc.dim(` Edit src/styles/theme.${resolved.scss ? "scss" : "css"} to customize.
963
+ console.log(pc.dim(` Edit src/styles/theme.scss to customize.
841
964
  `));
842
965
  }
843
966
  return { success: true, projectDir };
@@ -847,6 +970,7 @@ export {
847
970
  create,
848
971
  generateNextjsLayout,
849
972
  generateNextjsPage,
850
- generateNextjsProviders
973
+ generateNextjsProviders,
974
+ generatePageCssModule
851
975
  };
852
- //# sourceMappingURL=create-JVAU3YKN.js.map
976
+ //# sourceMappingURL=create-LA4J2HHQ.js.map