@nghitrum/dsforge 0.1.5-alpha.5 → 0.1.5-alpha.6

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.
@@ -0,0 +1,28 @@
1
+ // src/lib/license.ts
2
+ import { readFileSync } from "fs";
3
+ import { join } from "path";
4
+ function readKeyFromDotEnv() {
5
+ try {
6
+ const content = readFileSync(join(process.cwd(), ".env"), "utf8");
7
+ for (const raw of content.split("\n")) {
8
+ const line = raw.trim();
9
+ if (!line || line.startsWith("#")) continue;
10
+ const eq = line.indexOf("=");
11
+ if (eq === -1) continue;
12
+ const key = line.slice(0, eq).trim();
13
+ if (key !== "DSFORGE_KEY") continue;
14
+ const val = line.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
15
+ return val || void 0;
16
+ }
17
+ } catch {
18
+ }
19
+ return void 0;
20
+ }
21
+ function isProUnlocked() {
22
+ const key = process.env["DSFORGE_KEY"] ?? readKeyFromDotEnv();
23
+ return typeof key === "string" && key.length > 0;
24
+ }
25
+
26
+ export {
27
+ isProUnlocked
28
+ };
@@ -27,7 +27,7 @@ function generatePackageJson(config, componentNames) {
27
27
  componentNames.map((c) => [`./metadata/${c}`, `./metadata/${c}.json`])
28
28
  )
29
29
  },
30
- files: ["dist", "tokens", "metadata", "docs", "CHANGELOG.md"],
30
+ files: ["dist", "tokens", "metadata", "CHANGELOG.md"],
31
31
  scripts: {
32
32
  build: "tsc",
33
33
  prepublishOnly: "npm run build"
package/dist/cli/index.js CHANGED
@@ -3,7 +3,10 @@ import {
3
3
  generateChangelog,
4
4
  generatePackageJson,
5
5
  generateTsConfig
6
- } from "../chunk-RI3XDGKU.js";
6
+ } from "../chunk-QHE35QQQ.js";
7
+ import {
8
+ isProUnlocked
9
+ } from "../chunk-OAMEFG6Q.js";
7
10
 
8
11
  // src/cli/index.ts
9
12
  import { program } from "commander";
@@ -436,6 +439,32 @@ var RADIUS_PRESETS = {
436
439
  comfortable: { none: 0, sm: 2, md: 4, lg: 8, xl: 16, full: 9999 },
437
440
  spacious: { none: 0, sm: 3, md: 6, lg: 12, xl: 20, full: 9999 }
438
441
  };
442
+ function applyPreset(config, preset) {
443
+ const spacing = SPACING_PRESETS[preset];
444
+ const radius = RADIUS_PRESETS[preset];
445
+ const baseUnit = preset === "compact" ? 2 : preset === "spacious" ? 6 : 4;
446
+ config.spacing = {
447
+ ...config.spacing,
448
+ baseUnit,
449
+ scale: spacing,
450
+ semantic: {
451
+ "component-padding-xs": `${spacing["1"]}`,
452
+ "component-padding-sm": `${spacing["2"]}`,
453
+ "component-padding-md": `${spacing["4"]}`,
454
+ "component-padding-lg": `${spacing["5"]}`,
455
+ "layout-gap-xs": `${spacing["2"]}`,
456
+ "layout-gap-sm": `${spacing["3"]}`,
457
+ "layout-gap-md": `${spacing["5"]}`,
458
+ "layout-gap-lg": `${spacing["6"]}`,
459
+ "layout-section": `${spacing["7"]}`
460
+ }
461
+ };
462
+ config.radius = { ...config.radius, ...radius };
463
+ config.philosophy = {
464
+ ...config.philosophy,
465
+ density: preset
466
+ };
467
+ }
439
468
  function buildInitialConfig(name, preset = "comfortable") {
440
469
  const spacing = SPACING_PRESETS[preset];
441
470
  const radius = RADIUS_PRESETS[preset];
@@ -775,7 +804,15 @@ async function runInit(cwd, options) {
775
804
  }
776
805
  const name = rawName.replace(/\s+/g, "-").toLowerCase();
777
806
  let preset;
778
- if (options.preset && VALID_PRESETS.includes(options.preset)) {
807
+ if (!isProUnlocked()) {
808
+ if (options.preset && options.preset !== "comfortable") {
809
+ logger.hint(
810
+ `Preset "${options.preset}" requires dsforge Pro`,
811
+ `Set DSFORGE_KEY to unlock compact and spacious. Using comfortable.`
812
+ );
813
+ }
814
+ preset = "comfortable";
815
+ } else if (options.preset && VALID_PRESETS.includes(options.preset)) {
779
816
  preset = options.preset;
780
817
  } else {
781
818
  const answer = await ask(
@@ -4761,6 +4798,10 @@ async function runGenerate(cwd, options) {
4761
4798
  options.debug ?? false
4762
4799
  );
4763
4800
  }
4801
+ const presetValue = config.meta.preset;
4802
+ if (presetValue === "compact" || presetValue === "comfortable" || presetValue === "spacious") {
4803
+ applyPreset(config, presetValue);
4804
+ }
4764
4805
  const fullRules = Object.fromEntries(
4765
4806
  REACT_COMPONENTS.map((name) => [name, rules[name] ?? {}])
4766
4807
  );
@@ -4855,7 +4896,7 @@ async function runGenerate(cwd, options) {
4855
4896
  logger.dim(` \u2192 src/${idxFile}`);
4856
4897
  logger.success(`${generatedNames.length} components generated`);
4857
4898
  }
4858
- if (!only || only === "metadata") {
4899
+ if (isProUnlocked() && (!only || only === "metadata")) {
4859
4900
  logger.step("Writing AI metadata...");
4860
4901
  const metaDir = path3.join(outRoot, "metadata");
4861
4902
  await ensureDir(metaDir);
@@ -4866,27 +4907,6 @@ async function runGenerate(cwd, options) {
4866
4907
  }
4867
4908
  logger.success(`Metadata written (${metaFiles.length} files)`);
4868
4909
  }
4869
- if (!only || only === "docs") {
4870
- logger.step("Generating docs...");
4871
- const docsDir = path3.join(outRoot, "docs");
4872
- await ensureDir(docsDir);
4873
- const metadataFiles = generateMetadata(config, fullRules, tokenCount);
4874
- const metadataMap = {};
4875
- for (const { filename, content } of metadataFiles) {
4876
- const name = filename.replace(".json", "");
4877
- if (name !== "index") {
4878
- metadataMap[name] = JSON.parse(
4879
- content
4880
- );
4881
- }
4882
- }
4883
- const docFiles = reactAdapter.generateDocs(config, fullRules, metadataMap);
4884
- for (const { filename, content } of docFiles) {
4885
- await writeFile(path3.join(docsDir, filename), content);
4886
- logger.dim(` \u2192 docs/${filename}`);
4887
- }
4888
- logger.success(`Docs written (${docFiles.length} files)`);
4889
- }
4890
4910
  if (!only) {
4891
4911
  logger.step("Writing package files...");
4892
4912
  const componentNames = Object.keys(fullRules);
@@ -4896,7 +4916,7 @@ async function runGenerate(cwd, options) {
4896
4916
  const tsConfig = generateTsConfig();
4897
4917
  await writeFile(path3.join(outRoot, "tsconfig.json"), tsConfig);
4898
4918
  logger.dim(` \u2192 tsconfig.json`);
4899
- const { generateReadme } = await import("../emitter-ZNRPJ4D6.js");
4919
+ const { generateReadme } = await import("../emitter-KNYIQTS5.js");
4900
4920
  await writeFile(
4901
4921
  path3.join(outRoot, "README.md"),
4902
4922
  generateReadme(config, componentNames)
@@ -4912,7 +4932,7 @@ async function runGenerate(cwd, options) {
4912
4932
  logger.success(`Package files written`);
4913
4933
  }
4914
4934
  logger.step("Generating showcase...");
4915
- const { generateShowcase } = await import("../html-6SIG34W5.js");
4935
+ const { generateShowcase } = await import("../html-BJBKRTSX.js");
4916
4936
  const showcaseHtml = generateShowcase(config, resolution);
4917
4937
  await writeFile(path3.join(outRoot, "showcase.html"), showcaseHtml);
4918
4938
  logger.dim(` \u2192 showcase.html`);
@@ -5299,7 +5319,7 @@ async function runMenu() {
5299
5319
  // package.json
5300
5320
  var package_default = {
5301
5321
  name: "@nghitrum/dsforge",
5302
- version: "0.1.5-alpha.5",
5322
+ version: "0.1.5-alpha.6",
5303
5323
  description: "AI-native design system generator \u2014 tokens \u2192 components \u2192 docs \u2192 npm",
5304
5324
  keywords: [
5305
5325
  "design-system",
@@ -3,7 +3,7 @@ import {
3
3
  generatePackageJson,
4
4
  generateReadme,
5
5
  generateTsConfig
6
- } from "./chunk-RI3XDGKU.js";
6
+ } from "./chunk-QHE35QQQ.js";
7
7
  export {
8
8
  generateChangelog,
9
9
  generatePackageJson,
@@ -1,3 +1,7 @@
1
+ import {
2
+ isProUnlocked
3
+ } from "./chunk-OAMEFG6Q.js";
4
+
1
5
  // src/generators/showcase/types.ts
2
6
  function esc(s) {
3
7
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
@@ -32,31 +36,6 @@ function componentTokens(config, tokens) {
32
36
  };
33
37
  }
34
38
 
35
- // src/lib/license.ts
36
- import { readFileSync } from "fs";
37
- import { join } from "path";
38
- function readKeyFromDotEnv() {
39
- try {
40
- const content = readFileSync(join(process.cwd(), ".env"), "utf8");
41
- for (const raw of content.split("\n")) {
42
- const line = raw.trim();
43
- if (!line || line.startsWith("#")) continue;
44
- const eq = line.indexOf("=");
45
- if (eq === -1) continue;
46
- const key = line.slice(0, eq).trim();
47
- if (key !== "DSFORGE_KEY") continue;
48
- const val = line.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
49
- return val || void 0;
50
- }
51
- } catch {
52
- }
53
- return void 0;
54
- }
55
- function isProUnlocked() {
56
- const key = process.env["DSFORGE_KEY"] ?? readKeyFromDotEnv();
57
- return typeof key === "string" && key.length > 0;
58
- }
59
-
60
39
  // src/generators/showcase/foundations.ts
61
40
  function buildColorSection(config, tokens) {
62
41
  const groups = [];
@@ -231,7 +210,9 @@ var lockedPanel = (label) => `
231
210
  function buildComponentPage(def, isPro) {
232
211
  const tabId = (tab) => `${def.id}-tab-${tab}`;
233
212
  const panelId = (tab) => `${def.id}-panel-${tab}`;
234
- const overviewHtml = `<div class="comp-overview">${def.overviewHtml}</div>`;
213
+ const overviewHtml = `
214
+ <div class="comp-overview">${def.overviewHtml}</div>
215
+ <p class="component-description">${esc(def.description)}</p>`;
235
216
  const propsTable = `
236
217
  <table class="props-table">
237
218
  <thead>
@@ -366,6 +347,9 @@ function buttonDef(config, tokens) {
366
347
  id: "button",
367
348
  label: "Button",
368
349
  description: "Triggers an action or event. Use for form submissions, dialogs, and in-page actions.",
350
+ usageExample: `<Button variant="primary" size="md" onClick={() => {}}>
351
+ Save changes
352
+ </Button>`,
369
353
  overviewHtml: `
370
354
  <div class="comp-overview-section">
371
355
  <div class="comp-overview-label">Variants</div>
@@ -552,6 +536,13 @@ function inputDef(config, tokens) {
552
536
  id: "input",
553
537
  label: "Input",
554
538
  description: "Single-line text field. Covers all standard input types with label, helper text, and validation states.",
539
+ usageExample: `<Input
540
+ label="Email"
541
+ placeholder="you@example.com"
542
+ value={email}
543
+ onChange={(e) => setEmail(e.target.value)}
544
+ error={emailError}
545
+ />`,
555
546
  overviewHtml: `
556
547
  <div class="comp-overview-section">
557
548
  <div class="comp-overview-label">States</div>
@@ -757,6 +748,10 @@ function cardDef(config, tokens) {
757
748
  id: "card",
758
749
  label: "Card",
759
750
  description: "A surface that groups related content. Supports header, body, and optional footer slots.",
751
+ usageExample: `<Card padding="lg">
752
+ <h2>Card title</h2>
753
+ <p>Card content goes here.</p>
754
+ </Card>`,
760
755
  overviewHtml: `
761
756
  <div class="comp-overview-section">
762
757
  <div class="comp-overview-label">Variants</div>
@@ -913,6 +908,8 @@ function badgeDef(config, tokens) {
913
908
  id: "badge",
914
909
  label: "Badge",
915
910
  description: "Compact label for status, categories, or counts. Display-only \u2014 not interactive.",
911
+ usageExample: `<Badge variant="success">Active</Badge>
912
+ <Badge variant="warning">Pending</Badge>`,
916
913
  overviewHtml: `
917
914
  <div class="comp-overview-section">
918
915
  <div class="comp-overview-label">Variants</div>
@@ -1057,6 +1054,11 @@ function checkboxDef(config, tokens) {
1057
1054
  id: "checkbox",
1058
1055
  label: "Checkbox",
1059
1056
  description: "Binary toggle for boolean values. Supports indeterminate state for partial selections.",
1057
+ usageExample: `<Checkbox
1058
+ label="Accept terms"
1059
+ checked={accepted}
1060
+ onChange={(e) => setAccepted(e.target.checked)}
1061
+ />`,
1060
1062
  overviewHtml: `
1061
1063
  <div class="comp-overview-section">
1062
1064
  <div class="comp-overview-label">States</div>
@@ -1239,6 +1241,8 @@ function radioDef(config, tokens) {
1239
1241
  id: "radio",
1240
1242
  label: "Radio",
1241
1243
  description: "Single selection within a mutually exclusive group. Always pair Radio with RadioGroup.",
1244
+ usageExample: `<Radio label="Option A" name="choice" value="a" checked={choice === 'a'} onChange={() => setChoice('a')} />
1245
+ <Radio label="Option B" name="choice" value="b" checked={choice === 'b'} onChange={() => setChoice('b')} />`,
1242
1246
  overviewHtml: `
1243
1247
  <div class="comp-overview-section">
1244
1248
  <div class="comp-overview-label">RadioGroup (vertical)</div>
@@ -1425,6 +1429,12 @@ function selectDef(config, tokens) {
1425
1429
  id: "select",
1426
1430
  label: "Select",
1427
1431
  description: "Dropdown picker for selecting from a list of options. Wraps native <select> for full accessibility.",
1432
+ usageExample: `<Select
1433
+ label="Country"
1434
+ options={[{ label: 'Norway', value: 'no' }, { label: 'Sweden', value: 'se' }]}
1435
+ value={country}
1436
+ onChange={(e) => setCountry(e.target.value)}
1437
+ />`,
1428
1438
  overviewHtml: `
1429
1439
  <div class="comp-overview-section">
1430
1440
  <div class="comp-overview-label">States</div>
@@ -1610,6 +1620,12 @@ function toastDef(config, tokens) {
1610
1620
  id: "toast",
1611
1621
  label: "Toast / Alert",
1612
1622
  description: "Feedback for user actions. Alert is inline and static; Toast is an overlay with auto-dismiss and a useToast() hook.",
1623
+ usageExample: `<Toast
1624
+ message="Changes saved successfully"
1625
+ variant="success"
1626
+ duration={3000}
1627
+ onDismiss={() => setToast(null)}
1628
+ />`,
1613
1629
  overviewHtml: `
1614
1630
  <div class="comp-overview-section">
1615
1631
  <div class="comp-overview-label">Alert \u2014 inline variants</div>
@@ -1791,6 +1807,7 @@ function spinnerDef(config, tokens) {
1791
1807
  id: "spinner",
1792
1808
  label: "Spinner",
1793
1809
  description: "Loading indicator for async operations. Includes a visually hidden status label for screen readers.",
1810
+ usageExample: `<Spinner size="lg" label="Saving your changes" />`,
1794
1811
  overviewHtml: `
1795
1812
  <div class="comp-overview-section">
1796
1813
  <div class="comp-overview-label">Sizes</div>
@@ -2301,6 +2318,27 @@ ${themeCssDark}
2301
2318
  .ds-card-body { padding: 12px 14px; }
2302
2319
  .ds-card-footer { padding: 10px 14px; display: flex; justify-content: flex-end; }
2303
2320
 
2321
+ /* \u2500\u2500 Component docs \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
2322
+ .component-docs { margin-top: 36px; }
2323
+ .component-description {
2324
+ font-size: 14px; color: var(--color-text-secondary, #64748b);
2325
+ line-height: 1.65; margin-bottom: 24px; max-width: 640px;
2326
+ }
2327
+ .component-docs h4 {
2328
+ font-size: 11px; font-weight: 600; text-transform: uppercase;
2329
+ letter-spacing: 0.07em; color: var(--color-text-secondary, #64748b);
2330
+ margin-bottom: 12px; padding-bottom: 8px;
2331
+ border-bottom: 1px solid var(--color-border-default, #e2e8f0);
2332
+ }
2333
+ .usage-example {
2334
+ margin: 0; padding: 16px 18px;
2335
+ background: var(--color-bg-default, #fff);
2336
+ color: var(--color-text-primary, #0f172a);
2337
+ border: 1px solid var(--color-border-default, #e2e8f0); border-radius: 8px;
2338
+ font-family: "SF Mono", "Fira Code", "Cascadia Code", monospace;
2339
+ font-size: 12.5px; line-height: 1.65; overflow-x: auto; white-space: pre;
2340
+ }
2341
+
2304
2342
  /* \u2500\u2500 Spinner animation \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */
2305
2343
  @keyframes dsforge-spin { to { transform: rotate(360deg); } }
2306
2344
  @media (prefers-reduced-motion: reduce) { @keyframes dsforge-spin { to { transform: none; } } }
package/dist/index.js CHANGED
@@ -1143,6 +1143,10 @@ var rl = readline.createInterface({
1143
1143
  output: process.stdout
1144
1144
  });
1145
1145
 
1146
+ // src/lib/license.ts
1147
+ import { readFileSync } from "fs";
1148
+ import { join } from "path";
1149
+
1146
1150
  // src/cli/commands/init.ts
1147
1151
  var SPACING_PRESETS = {
1148
1152
  compact: {
@@ -3062,7 +3066,7 @@ function generatePackageJson(config, componentNames) {
3062
3066
  componentNames.map((c) => [`./metadata/${c}`, `./metadata/${c}.json`])
3063
3067
  )
3064
3068
  },
3065
- files: ["dist", "tokens", "metadata", "docs", "CHANGELOG.md"],
3069
+ files: ["dist", "tokens", "metadata", "CHANGELOG.md"],
3066
3070
  scripts: {
3067
3071
  build: "tsc",
3068
3072
  prepublishOnly: "npm run build"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nghitrum/dsforge",
3
- "version": "0.1.5-alpha.5",
3
+ "version": "0.1.5-alpha.6",
4
4
  "description": "AI-native design system generator — tokens → components → docs → npm",
5
5
  "keywords": [
6
6
  "design-system",