@nghitrum/dsforge 0.1.5-alpha.8 → 0.1.5-alpha.9

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.
@@ -66,6 +66,11 @@ var RADIUS_PRESETS = {
66
66
  comfortable: { none: 0, sm: 2, md: 4, lg: 8, xl: 16, full: 9999 },
67
67
  spacious: { none: 0, sm: 3, md: 6, lg: 12, xl: 20, full: 9999 }
68
68
  };
69
+ var CONTROL_SIZE_PRESETS = {
70
+ compact: { sm: 12, md: 14, lg: 18 },
71
+ comfortable: { sm: 14, md: 16, lg: 20 },
72
+ spacious: { sm: 16, md: 18, lg: 24 }
73
+ };
69
74
  var PRESET_BASE_UNITS = {
70
75
  compact: 2,
71
76
  comfortable: 4,
@@ -106,6 +111,7 @@ export {
106
111
  PRESETS,
107
112
  SPACING_PRESETS,
108
113
  RADIUS_PRESETS,
114
+ CONTROL_SIZE_PRESETS,
109
115
  PRESET_BASE_UNITS,
110
116
  buildSemanticSpacing,
111
117
  applyPreset
package/dist/cli/index.js CHANGED
@@ -5,6 +5,7 @@ import {
5
5
  generateTsConfig
6
6
  } from "../chunk-QHE35QQQ.js";
7
7
  import {
8
+ CONTROL_SIZE_PRESETS,
8
9
  PRESETS,
9
10
  PRESET_BASE_UNITS,
10
11
  RADIUS_PRESETS,
@@ -12,7 +13,7 @@ import {
12
13
  applyPreset,
13
14
  buildSemanticSpacing,
14
15
  isProUnlocked
15
- } from "../chunk-JUMR3N5J.js";
16
+ } from "../chunk-YUPXTQZ5.js";
16
17
 
17
18
  // src/cli/index.ts
18
19
  import { program } from "commander";
@@ -1773,6 +1774,19 @@ function emitBaseCss(config, resolution) {
1773
1774
  if (typoEntries.length > 0) {
1774
1775
  sections.push(emitBlock(":root", typoEntries, "Typography"));
1775
1776
  }
1777
+ const currentPreset = config.philosophy?.density ?? "comfortable";
1778
+ const controlSizes = CONTROL_SIZE_PRESETS[currentPreset] ?? CONTROL_SIZE_PRESETS.comfortable;
1779
+ sections.push(
1780
+ emitBlock(
1781
+ ":root",
1782
+ [
1783
+ ["control-size-sm", `${controlSizes.sm}px`],
1784
+ ["control-size-md", `${controlSizes.md}px`],
1785
+ ["control-size-lg", `${controlSizes.lg}px`]
1786
+ ],
1787
+ "Control sizes"
1788
+ )
1789
+ );
1776
1790
  const radiusEntries = Object.entries(
1777
1791
  config.radius ?? {}
1778
1792
  ).filter(([, v]) => v !== void 0).map(([k, v]) => [`radius-${k}`, v === 9999 ? "9999px" : `${v}px`]);
@@ -1854,6 +1868,10 @@ function emitDensityCss(config) {
1854
1868
  for (const [key, value] of Object.entries(radius)) {
1855
1869
  entries.push([`radius-${key}`, value === 9999 ? "9999px" : `${value}px`]);
1856
1870
  }
1871
+ const controlSizes = CONTROL_SIZE_PRESETS[preset];
1872
+ entries.push(["control-size-sm", `${controlSizes.sm}px`]);
1873
+ entries.push(["control-size-md", `${controlSizes.md}px`]);
1874
+ entries.push(["control-size-lg", `${controlSizes.lg}px`]);
1857
1875
  lines.push(emitBlock(`[data-density="${preset}"]`, entries, `Preset: ${preset}`));
1858
1876
  lines.push("");
1859
1877
  }
@@ -2864,9 +2882,17 @@ export interface CheckboxProps
2864
2882
  // \u2500\u2500\u2500 Size map \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\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
2865
2883
 
2866
2884
  const SIZE_BOX: Record<"sm" | "md" | "lg", string> = {
2867
- sm: "14px",
2868
- md: "16px",
2869
- lg: "20px",
2885
+ sm: "var(--control-size-sm, 14px)",
2886
+ md: "var(--control-size-md, 16px)",
2887
+ lg: "var(--control-size-lg, 20px)",
2888
+ };
2889
+
2890
+ // SVG check/dash icon fits inside the box with a 6px inset, via calc() so it
2891
+ // tracks the CSS var when density changes at runtime.
2892
+ const SVG_SIZE: Record<"sm" | "md" | "lg", string> = {
2893
+ sm: "calc(var(--control-size-sm, 14px) - 6px)",
2894
+ md: "calc(var(--control-size-md, 16px) - 6px)",
2895
+ lg: "calc(var(--control-size-lg, 20px) - 6px)",
2870
2896
  };
2871
2897
 
2872
2898
  const SIZE_FONT: Record<"sm" | "md" | "lg", string> = {
@@ -3010,8 +3036,7 @@ export const Checkbox = React.forwardRef<HTMLInputElement, CheckboxProps>(
3010
3036
  <span style={boxStyle} aria-hidden="true">
3011
3037
  {isActive && (
3012
3038
  <svg
3013
- width={parseInt(boxSize) - 6}
3014
- height={parseInt(boxSize) - 6}
3039
+ style={{ width: SVG_SIZE[size], height: SVG_SIZE[size] }}
3015
3040
  viewBox="0 0 10 10"
3016
3041
  fill="none"
3017
3042
  stroke="#fff"
@@ -3113,9 +3138,9 @@ export interface RadioGroupProps {
3113
3138
  // \u2500\u2500\u2500 Size map \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\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
3114
3139
 
3115
3140
  const SIZE_BOX: Record<"sm" | "md" | "lg", string> = {
3116
- sm: "14px",
3117
- md: "16px",
3118
- lg: "20px",
3141
+ sm: "var(--control-size-sm, 14px)",
3142
+ md: "var(--control-size-md, 16px)",
3143
+ lg: "var(--control-size-lg, 20px)",
3119
3144
  };
3120
3145
 
3121
3146
  const SIZE_FONT: Record<"sm" | "md" | "lg", string> = {
@@ -4956,7 +4981,7 @@ async function runGenerate(cwd, options) {
4956
4981
  logger.success(`Package files written`);
4957
4982
  }
4958
4983
  logger.step("Generating showcase...");
4959
- const { generateShowcase } = await import("../html-LQHDCSG4.js");
4984
+ const { generateShowcase } = await import("../html-DJJSDXRX.js");
4960
4985
  const showcaseHtml = generateShowcase(config, resolution);
4961
4986
  await writeFile(path3.join(outRoot, "showcase.html"), showcaseHtml);
4962
4987
  logger.dim(` \u2192 showcase.html`);
@@ -5343,7 +5368,7 @@ async function runMenu() {
5343
5368
  // package.json
5344
5369
  var package_default = {
5345
5370
  name: "@nghitrum/dsforge",
5346
- version: "0.1.5-alpha.8",
5371
+ version: "0.1.5-alpha.9",
5347
5372
  description: "AI-native design system generator \u2014 tokens \u2192 components \u2192 docs \u2192 npm",
5348
5373
  keywords: [
5349
5374
  "design-system",
@@ -4,7 +4,7 @@ import {
4
4
  SPACING_PRESETS,
5
5
  buildSemanticSpacing,
6
6
  isProUnlocked
7
- } from "./chunk-JUMR3N5J.js";
7
+ } from "./chunk-YUPXTQZ5.js";
8
8
 
9
9
  // src/generators/showcase/types.ts
10
10
  function esc(s) {
@@ -907,7 +907,7 @@ function cardDef(config, tokens) {
907
907
  // src/generators/showcase/components/badge.ts
908
908
  function badgeDef(config, tokens) {
909
909
  const { ff } = componentTokens(config, tokens);
910
- const badgeHtml = (label, bg, color) => `<span style="display:inline-flex;align-items:center;font-family:${esc(ff)};font-size:12px;font-weight:500;padding:2px 8px;border-radius:9999px;background:${bg};color:${color};white-space:nowrap">${label}</span>`;
910
+ const badgeHtml = (label, bg, color) => `<span style="display:inline-flex;align-items:center;font-family:${esc(ff)};font-size:var(--font-size-caption,0.75rem);font-weight:500;padding:2px var(--spacing-2,8px);border-radius:var(--radius-full,9999px);background:${bg};color:${color};white-space:nowrap">${label}</span>`;
911
911
  const variants = [
912
912
  { label: "Default", bg: "#f1f5f9", color: "#6b7280" },
913
913
  { label: "Success", bg: "#dcfce7", color: "#16a34a" },
@@ -931,10 +931,10 @@ function badgeDef(config, tokens) {
931
931
  <div class="comp-overview-section">
932
932
  <div class="comp-overview-label">Sizes</div>
933
933
  <div class="comp-preview-row" style="align-items:center">
934
- <span style="display:inline-flex;align-items:center;font-family:${esc(ff)};font-size:11px;font-weight:500;padding:1px 6px;border-radius:9999px;background:#dbeafe;color:#2563eb">Small</span>
935
- <span style="display:inline-flex;align-items:center;font-family:${esc(ff)};font-size:12px;font-weight:500;padding:2px 8px;border-radius:9999px;background:#dbeafe;color:#2563eb">Medium</span>
936
- <span style="display:inline-flex;align-items:center;font-family:${esc(ff)};font-size:14px;font-weight:500;padding:4px 12px;border-radius:9999px;background:#dbeafe;color:#2563eb">Large</span>
937
- <span style="display:inline-flex;width:8px;height:8px;border-radius:50%;background:#16a34a" title="Dot mode"></span>
934
+ <span style="display:inline-flex;align-items:center;font-family:${esc(ff)};font-size:var(--font-size-caption,0.75rem);font-weight:500;padding:1px var(--spacing-1,4px);border-radius:var(--radius-full,9999px);background:#dbeafe;color:#2563eb">Small</span>
935
+ <span style="display:inline-flex;align-items:center;font-family:${esc(ff)};font-size:var(--font-size-caption,0.75rem);font-weight:500;padding:2px var(--spacing-2,8px);border-radius:var(--radius-full,9999px);background:#dbeafe;color:#2563eb">Medium</span>
936
+ <span style="display:inline-flex;align-items:center;font-family:${esc(ff)};font-size:var(--font-size-body,1rem);font-weight:500;padding:var(--spacing-1,4px) var(--spacing-3,12px);border-radius:var(--radius-full,9999px);background:#dbeafe;color:#2563eb">Large</span>
937
+ <span style="display:inline-flex;width:var(--spacing-2,8px);height:var(--spacing-2,8px);border-radius:50%;background:#16a34a" title="Dot mode"></span>
938
938
  </div>
939
939
  </div>`,
940
940
  props: [
@@ -1055,11 +1055,11 @@ function checkboxDef(config, tokens) {
1055
1055
  const fill = checked || indeterminate ? "#2563eb" : C.bg;
1056
1056
  const borderColor = checked || indeterminate ? "#2563eb" : C.border;
1057
1057
  const mark = checked ? `<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="1.5,5 4,7.5 8.5,2.5"/></svg>` : indeterminate ? `<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="#fff" stroke-width="2" stroke-linecap="round"><line x1="2" y1="5" x2="8" y2="5"/></svg>` : "";
1058
- return `<span style="display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:2px;border:2px solid ${borderColor};background:${fill};flex-shrink:0">${mark}</span>`;
1058
+ return `<span style="display:inline-flex;align-items:center;justify-content:center;width:var(--control-size-md,16px);height:var(--control-size-md,16px);border-radius:var(--radius-sm,2px);border:2px solid ${borderColor};background:${fill};flex-shrink:0">${mark}</span>`;
1059
1059
  };
1060
- const checkboxHtml = (label, checked, opts = "", helper = "") => `<label style="display:inline-flex;align-items:flex-start;gap:8px;cursor:pointer;font-family:${esc(ff)};${opts}">
1060
+ const checkboxHtml = (label, checked, opts = "", helper = "") => `<label style="display:inline-flex;align-items:flex-start;gap:var(--spacing-2,8px);cursor:pointer;font-family:${esc(ff)};${opts}">
1061
1061
  ${boxHtml(checked)}
1062
- <span style="font-size:14px;color:${C.text};line-height:1.4">${label}${helper ? `<br><span style="font-size:12px;color:${C.textSecondary}">${helper}</span>` : ""}</span>
1062
+ <span style="font-size:var(--font-size-small,0.875rem);color:${C.text};line-height:1.4">${label}${helper ? `<br><span style="font-size:var(--font-size-caption,0.75rem);color:${C.textSecondary}">${helper}</span>` : ""}</span>
1063
1063
  </label>`;
1064
1064
  return {
1065
1065
  id: "checkbox",
@@ -1076,9 +1076,9 @@ function checkboxDef(config, tokens) {
1076
1076
  <div class="comp-preview-col">
1077
1077
  ${checkboxHtml("Unchecked", false)}
1078
1078
  ${checkboxHtml("Checked", true)}
1079
- <label style="display:inline-flex;align-items:flex-start;gap:8px;cursor:pointer;font-family:${esc(ff)}">
1079
+ <label style="display:inline-flex;align-items:flex-start;gap:var(--spacing-2,8px);cursor:pointer;font-family:${esc(ff)}">
1080
1080
  ${boxHtml(false, true)}
1081
- <span style="font-size:14px;color:${C.text}">Indeterminate</span>
1081
+ <span style="font-size:var(--font-size-small,0.875rem);color:${C.text}">Indeterminate</span>
1082
1082
  </label>
1083
1083
  ${checkboxHtml("Disabled", false, "opacity:0.4;cursor:not-allowed")}
1084
1084
  </div>
@@ -1161,9 +1161,9 @@ function checkboxDef(config, tokens) {
1161
1161
  label="Select all (3 of 5)"
1162
1162
  indeterminate
1163
1163
  />`,
1164
- previewHtml: `<label style="display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-family:${esc(ff)}">
1164
+ previewHtml: `<label style="display:inline-flex;align-items:center;gap:var(--spacing-2,8px);cursor:pointer;font-family:${esc(ff)}">
1165
1165
  ${boxHtml(false, true)}
1166
- <span style="font-size:14px;color:${C.text}">Select all (3 of 5)</span>
1166
+ <span style="font-size:var(--font-size-small,0.875rem);color:${C.text}">Select all (3 of 5)</span>
1167
1167
  </label>`
1168
1168
  },
1169
1169
  {
@@ -1240,13 +1240,13 @@ function radioDef(config, tokens) {
1240
1240
  };
1241
1241
  const circleHtml = (selected) => {
1242
1242
  const borderColor = selected ? C.action : C.border;
1243
- return `<span style="display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;border-radius:50%;border:2px solid ${borderColor};background:${C.bg};flex-shrink:0">
1244
- ${selected ? `<span style="width:8px;height:8px;border-radius:50%;background:${C.action}"></span>` : ""}
1243
+ return `<span style="display:inline-flex;align-items:center;justify-content:center;width:var(--control-size-md,16px);height:var(--control-size-md,16px);border-radius:50%;border:2px solid ${borderColor};background:${C.bg};flex-shrink:0">
1244
+ ${selected ? `<span style="width:calc(var(--control-size-md,16px) / 2);height:calc(var(--control-size-md,16px) / 2);border-radius:50%;background:${C.action}"></span>` : ""}
1245
1245
  </span>`;
1246
1246
  };
1247
- const radioHtml = (label, selected, opts = "") => `<label style="display:inline-flex;align-items:center;gap:8px;cursor:pointer;font-family:${esc(ff)};${opts}">
1247
+ const radioHtml = (label, selected, opts = "") => `<label style="display:inline-flex;align-items:center;gap:var(--spacing-2,8px);cursor:pointer;font-family:${esc(ff)};${opts}">
1248
1248
  ${circleHtml(selected)}
1249
- <span style="font-size:14px;color:${C.text}">${label}</span>
1249
+ <span style="font-size:var(--font-size-small,0.875rem);color:${C.text}">${label}</span>
1250
1250
  </label>`;
1251
1251
  return {
1252
1252
  id: "radio",
@@ -1259,7 +1259,7 @@ function radioDef(config, tokens) {
1259
1259
  <div class="comp-overview-label">RadioGroup (vertical)</div>
1260
1260
  <div class="comp-preview-col">
1261
1261
  <fieldset style="border:none;padding:0;margin:0;font-family:${esc(ff)}">
1262
- <legend style="font-size:13px;font-weight:600;color:${C.text};margin-bottom:8px">Notification preference</legend>
1262
+ <legend style="font-size:var(--font-size-small,0.875rem);font-weight:600;color:${C.text};margin-bottom:var(--spacing-2,8px)">Notification preference</legend>
1263
1263
  <div class="comp-preview-col">
1264
1264
  ${radioHtml("Email", true)}
1265
1265
  ${radioHtml("SMS", false)}
@@ -1342,8 +1342,8 @@ function radioDef(config, tokens) {
1342
1342
  <Radio value="annual" label="Annual (save 20%)" />
1343
1343
  </RadioGroup>`,
1344
1344
  previewHtml: `<fieldset style="border:none;padding:0;margin:0;font-family:${esc(ff)}">
1345
- <legend style="font-size:13px;font-weight:600;color:${C.text};margin-bottom:8px">Billing cycle</legend>
1346
- <div style="display:flex;flex-direction:column;gap:8px">
1345
+ <legend style="font-size:var(--font-size-small,0.875rem);font-weight:600;color:${C.text};margin-bottom:var(--spacing-2,8px)">Billing cycle</legend>
1346
+ <div style="display:flex;flex-direction:column;gap:var(--spacing-2,8px)">
1347
1347
  ${radioHtml("Monthly", true)}
1348
1348
  ${radioHtml("Annual (save 20%)", false)}
1349
1349
  </div>
@@ -1358,8 +1358,8 @@ function radioDef(config, tokens) {
1358
1358
  <Radio value="lg" label="L" />
1359
1359
  </RadioGroup>`,
1360
1360
  previewHtml: `<fieldset style="border:none;padding:0;margin:0;font-family:${esc(ff)}">
1361
- <legend style="font-size:13px;font-weight:600;color:${C.text};margin-bottom:8px">Size</legend>
1362
- <div style="display:flex;gap:16px">
1361
+ <legend style="font-size:var(--font-size-small,0.875rem);font-weight:600;color:${C.text};margin-bottom:var(--spacing-2,8px)">Size</legend>
1362
+ <div style="display:flex;gap:var(--spacing-4,16px)">
1363
1363
  ${radioHtml("S", false)}
1364
1364
  ${radioHtml("M", true)}
1365
1365
  ${radioHtml("L", false)}
@@ -1620,11 +1620,11 @@ function toastDef(config, tokens) {
1620
1620
  danger: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="8" x2="12" y2="12"/><line x1="12" y1="16" x2="12.01" y2="16"/></svg>`,
1621
1621
  info: `<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>`
1622
1622
  };
1623
- const alertHtml = (v, title, body) => `<div role="alert" style="display:flex;gap:12px;padding:12px 16px;border-radius:${r};border:1px solid ${v.border};background:${v.bg};font-family:${esc(ff)};max-width:360px">
1623
+ const alertHtml = (v, title, body) => `<div role="alert" style="display:flex;gap:var(--spacing-3,12px);padding:var(--component-padding-sm,12px) var(--component-padding-md,16px);border-radius:${r};border:1px solid ${v.border};background:${v.bg};font-family:${esc(ff)};max-width:360px">
1624
1624
  <span style="color:${v.icon};flex-shrink:0;margin-top:1px">${icons[v.name]}</span>
1625
1625
  <div>
1626
- <p style="margin:0;font-size:13px;font-weight:600;color:${v.icon}">${title}</p>
1627
- <p style="margin:4px 0 0;font-size:13px;color:var(--color-text-secondary,#6b7280)">${body}</p>
1626
+ <p style="margin:0;font-size:var(--font-size-small,0.875rem);font-weight:600;color:${v.icon}">${title}</p>
1627
+ <p style="margin:var(--spacing-1,4px) 0 0;font-size:var(--font-size-small,0.875rem);color:var(--color-text-secondary,#6b7280)">${body}</p>
1628
1628
  </div>
1629
1629
  </div>`;
1630
1630
  return {
@@ -1712,11 +1712,11 @@ function toastDef(config, tokens) {
1712
1712
  >
1713
1713
  Upgrade to continue using all features.
1714
1714
  </Alert>`,
1715
- previewHtml: `<div role="alert" style="display:flex;gap:12px;padding:12px 16px;border-radius:${r};border:1px solid ${vWarning.border};background:${vWarning.bg};font-family:${esc(ff)};max-width:360px">
1715
+ previewHtml: `<div role="alert" style="display:flex;gap:var(--spacing-3,12px);padding:var(--component-padding-sm,12px) var(--component-padding-md,16px);border-radius:${r};border:1px solid ${vWarning.border};background:${vWarning.bg};font-family:${esc(ff)};max-width:360px">
1716
1716
  <span style="color:${vWarning.icon};flex-shrink:0;margin-top:1px">${icons["warning"]}</span>
1717
1717
  <div style="flex:1">
1718
- <p style="margin:0;font-size:13px;font-weight:600;color:${vWarning.icon}">Your trial expires in 3 days</p>
1719
- <p style="margin:4px 0 0;font-size:13px;color:var(--color-text-secondary,#6b7280)">Upgrade to continue using all features.</p>
1718
+ <p style="margin:0;font-size:var(--font-size-small,0.875rem);font-weight:600;color:${vWarning.icon}">Your trial expires in 3 days</p>
1719
+ <p style="margin:var(--spacing-1,4px) 0 0;font-size:var(--font-size-small,0.875rem);color:var(--color-text-secondary,#6b7280)">Upgrade to continue using all features.</p>
1720
1720
  </div>
1721
1721
  <button style="background:transparent;border:none;cursor:pointer;color:var(--color-text-secondary,#6b7280);padding:2px;flex-shrink:0" aria-label="Dismiss">\u2715</button>
1722
1722
  </div>`
@@ -1740,11 +1740,11 @@ toast.add({
1740
1740
  });`,
1741
1741
  previewHtml: `<div style="position:relative;background:var(--color-bg-subtle,#f8fafc);border:1px dashed var(--color-border-default,#e2e8f0);border-radius:${r};padding:20px;min-height:80px;font-family:${esc(ff)}">
1742
1742
  <p style="font-size:12px;color:var(--color-text-secondary,#6b7280);margin:0 0 12px">Bottom-right overlay (fixed position)</p>
1743
- <div style="display:flex;gap:12px;padding:12px 16px;border-radius:${r};border:1px solid var(--color-success-border,#86efac);background:var(--color-success-subtle,#dcfce7);box-shadow:0 4px 12px rgba(0,0,0,0.12)">
1743
+ <div style="display:flex;gap:var(--spacing-3,12px);padding:var(--component-padding-sm,12px) var(--component-padding-md,16px);border-radius:${r};border:1px solid var(--color-success-border,#86efac);background:var(--color-success-subtle,#dcfce7);box-shadow:0 4px 12px rgba(0,0,0,0.12)">
1744
1744
  <span style="color:var(--color-success,#16a34a)">${icons["success"]}</span>
1745
1745
  <div>
1746
- <p style="margin:0;font-size:13px;font-weight:600;color:var(--color-text-primary,#0f172a)">Saved</p>
1747
- <p style="margin:4px 0 0;font-size:13px;color:var(--color-text-secondary,#6b7280)">Your changes have been saved.</p>
1746
+ <p style="margin:0;font-size:var(--font-size-small,0.875rem);font-weight:600;color:var(--color-text-primary,#0f172a)">Saved</p>
1747
+ <p style="margin:var(--spacing-1,4px) 0 0;font-size:var(--font-size-small,0.875rem);color:var(--color-text-secondary,#6b7280)">Your changes have been saved.</p>
1748
1748
  </div>
1749
1749
  <button style="background:transparent;border:none;cursor:pointer;color:var(--color-text-secondary,#6b7280);padding:2px" aria-label="Dismiss">\u2715</button>
1750
1750
  </div>
package/dist/index.js CHANGED
@@ -1206,6 +1206,11 @@ var RADIUS_PRESETS = {
1206
1206
  comfortable: { none: 0, sm: 2, md: 4, lg: 8, xl: 16, full: 9999 },
1207
1207
  spacious: { none: 0, sm: 3, md: 6, lg: 12, xl: 20, full: 9999 }
1208
1208
  };
1209
+ var CONTROL_SIZE_PRESETS = {
1210
+ compact: { sm: 12, md: 14, lg: 18 },
1211
+ comfortable: { sm: 14, md: 16, lg: 20 },
1212
+ spacious: { sm: 16, md: 18, lg: 24 }
1213
+ };
1209
1214
  var PRESET_BASE_UNITS = {
1210
1215
  compact: 2,
1211
1216
  comfortable: 4,
@@ -1593,6 +1598,19 @@ function emitBaseCss(config, resolution) {
1593
1598
  if (typoEntries.length > 0) {
1594
1599
  sections.push(emitBlock(":root", typoEntries, "Typography"));
1595
1600
  }
1601
+ const currentPreset = config.philosophy?.density ?? "comfortable";
1602
+ const controlSizes = CONTROL_SIZE_PRESETS[currentPreset] ?? CONTROL_SIZE_PRESETS.comfortable;
1603
+ sections.push(
1604
+ emitBlock(
1605
+ ":root",
1606
+ [
1607
+ ["control-size-sm", `${controlSizes.sm}px`],
1608
+ ["control-size-md", `${controlSizes.md}px`],
1609
+ ["control-size-lg", `${controlSizes.lg}px`]
1610
+ ],
1611
+ "Control sizes"
1612
+ )
1613
+ );
1596
1614
  const radiusEntries = Object.entries(
1597
1615
  config.radius ?? {}
1598
1616
  ).filter(([, v]) => v !== void 0).map(([k, v]) => [`radius-${k}`, v === 9999 ? "9999px" : `${v}px`]);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nghitrum/dsforge",
3
- "version": "0.1.5-alpha.8",
3
+ "version": "0.1.5-alpha.9",
4
4
  "description": "AI-native design system generator — tokens → components → docs → npm",
5
5
  "keywords": [
6
6
  "design-system",