@nghitrum/dsforge 0.1.5-alpha.0 → 0.1.5-alpha.10
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/README.md +22 -29
- package/dist/chunk-A7VW6SII.js +436 -0
- package/dist/chunk-YUPXTQZ5.js +118 -0
- package/dist/{chunk-RI3XDGKU.js → chunk-ZZRPNO6Z.js} +12 -17
- package/dist/cli/index.js +356 -310
- package/dist/componentDefinitions-5LFCNFQY.js +8 -0
- package/dist/{emitter-ZNRPJ4D6.js → emitter-IC77G4QF.js} +1 -1
- package/dist/generateAiFolder-3OOFWBH7.js +70 -0
- package/dist/generateComponentJson-XBEUWCW6.js +16 -0
- package/dist/generateComponentMetadata-2L5VNERD.js +13 -0
- package/dist/generateRegistry-3MEZDJAJ.js +19 -0
- package/dist/{html-6SIG34W5.js → html-XGJ22SXB.js} +385 -123
- package/dist/index.d.ts +12 -0
- package/dist/index.js +150 -46
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -381,7 +381,19 @@ declare function hasRefs(value: string): boolean;
|
|
|
381
381
|
|
|
382
382
|
declare function validateConfig(config: DesignSystemConfig, rules: RulesConfig): ValidationResult;
|
|
383
383
|
|
|
384
|
+
/**
|
|
385
|
+
* Density preset definitions.
|
|
386
|
+
*
|
|
387
|
+
* This is the single source of truth for compact / comfortable / spacious
|
|
388
|
+
* spacing and radius values. Imported by:
|
|
389
|
+
* - cli/commands/init.ts (initial config scaffolding)
|
|
390
|
+
* - cli/commands/generate.ts (re-applying preset on each generate run)
|
|
391
|
+
* - generators/tokens/css-vars.ts (emitting density.css for Pro)
|
|
392
|
+
* - generators/showcase/html.ts (embedding density CSS in showcase)
|
|
393
|
+
*/
|
|
394
|
+
|
|
384
395
|
type Preset = "compact" | "comfortable" | "spacious";
|
|
396
|
+
|
|
385
397
|
declare function buildInitialConfig(name: string, preset?: Preset): DesignSystemConfig;
|
|
386
398
|
declare function buildInitialRules(): RulesConfig;
|
|
387
399
|
|
package/dist/index.js
CHANGED
|
@@ -1143,7 +1143,32 @@ var rl = readline.createInterface({
|
|
|
1143
1143
|
output: process.stdout
|
|
1144
1144
|
});
|
|
1145
1145
|
|
|
1146
|
-
// src/
|
|
1146
|
+
// src/lib/license.ts
|
|
1147
|
+
import { readFileSync } from "fs";
|
|
1148
|
+
import { join } from "path";
|
|
1149
|
+
function readKeyFromDotEnv() {
|
|
1150
|
+
try {
|
|
1151
|
+
const content = readFileSync(join(process.cwd(), ".env"), "utf8");
|
|
1152
|
+
for (const raw of content.split("\n")) {
|
|
1153
|
+
const line = raw.trim();
|
|
1154
|
+
if (!line || line.startsWith("#")) continue;
|
|
1155
|
+
const eq = line.indexOf("=");
|
|
1156
|
+
if (eq === -1) continue;
|
|
1157
|
+
const key = line.slice(0, eq).trim();
|
|
1158
|
+
if (key !== "DSFORGE_KEY") continue;
|
|
1159
|
+
const val = line.slice(eq + 1).trim().replace(/^["']|["']$/g, "");
|
|
1160
|
+
return val || void 0;
|
|
1161
|
+
}
|
|
1162
|
+
} catch {
|
|
1163
|
+
}
|
|
1164
|
+
return void 0;
|
|
1165
|
+
}
|
|
1166
|
+
function isProUnlocked() {
|
|
1167
|
+
const key = process.env["DSFORGE_KEY"] ?? readKeyFromDotEnv();
|
|
1168
|
+
return typeof key === "string" && key.length > 0;
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
// src/presets/index.ts
|
|
1147
1172
|
var SPACING_PRESETS = {
|
|
1148
1173
|
compact: {
|
|
1149
1174
|
"1": 2,
|
|
@@ -1181,6 +1206,31 @@ var RADIUS_PRESETS = {
|
|
|
1181
1206
|
comfortable: { none: 0, sm: 2, md: 4, lg: 8, xl: 16, full: 9999 },
|
|
1182
1207
|
spacious: { none: 0, sm: 3, md: 6, lg: 12, xl: 20, full: 9999 }
|
|
1183
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
|
+
};
|
|
1214
|
+
var PRESET_BASE_UNITS = {
|
|
1215
|
+
compact: 2,
|
|
1216
|
+
comfortable: 4,
|
|
1217
|
+
spacious: 6
|
|
1218
|
+
};
|
|
1219
|
+
function buildSemanticSpacing(scale) {
|
|
1220
|
+
return {
|
|
1221
|
+
"component-padding-xs": `${scale["1"]}`,
|
|
1222
|
+
"component-padding-sm": `${scale["2"]}`,
|
|
1223
|
+
"component-padding-md": `${scale["4"]}`,
|
|
1224
|
+
"component-padding-lg": `${scale["5"]}`,
|
|
1225
|
+
"layout-gap-xs": `${scale["2"]}`,
|
|
1226
|
+
"layout-gap-sm": `${scale["3"]}`,
|
|
1227
|
+
"layout-gap-md": `${scale["5"]}`,
|
|
1228
|
+
"layout-gap-lg": `${scale["6"]}`,
|
|
1229
|
+
"layout-section": `${scale["7"]}`
|
|
1230
|
+
};
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1233
|
+
// src/cli/commands/init.ts
|
|
1184
1234
|
function buildInitialConfig(name, preset = "comfortable") {
|
|
1185
1235
|
const spacing = SPACING_PRESETS[preset];
|
|
1186
1236
|
const radius = RADIUS_PRESETS[preset];
|
|
@@ -1371,19 +1421,9 @@ function buildInitialConfig(name, preset = "comfortable") {
|
|
|
1371
1421
|
}
|
|
1372
1422
|
},
|
|
1373
1423
|
spacing: {
|
|
1374
|
-
baseUnit: preset
|
|
1424
|
+
baseUnit: PRESET_BASE_UNITS[preset],
|
|
1375
1425
|
scale: spacing,
|
|
1376
|
-
semantic:
|
|
1377
|
-
"component-padding-xs": `${spacing[1]}`,
|
|
1378
|
-
"component-padding-sm": `${spacing[2]}`,
|
|
1379
|
-
"component-padding-md": `${spacing[4]}`,
|
|
1380
|
-
"component-padding-lg": `${spacing[5]}`,
|
|
1381
|
-
"layout-gap-xs": `${spacing[2]}`,
|
|
1382
|
-
"layout-gap-sm": `${spacing[3]}`,
|
|
1383
|
-
"layout-gap-md": `${spacing[5]}`,
|
|
1384
|
-
"layout-gap-lg": `${spacing[6]}`,
|
|
1385
|
-
"layout-section": `${spacing[7]}`
|
|
1386
|
-
}
|
|
1426
|
+
semantic: buildSemanticSpacing(spacing)
|
|
1387
1427
|
},
|
|
1388
1428
|
radius,
|
|
1389
1429
|
elevation: {
|
|
@@ -1558,6 +1598,19 @@ function emitBaseCss(config, resolution) {
|
|
|
1558
1598
|
if (typoEntries.length > 0) {
|
|
1559
1599
|
sections.push(emitBlock(":root", typoEntries, "Typography"));
|
|
1560
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
|
+
);
|
|
1561
1614
|
const radiusEntries = Object.entries(
|
|
1562
1615
|
config.radius ?? {}
|
|
1563
1616
|
).filter(([, v]) => v !== void 0).map(([k, v]) => [`radius-${k}`, v === 9999 ? "9999px" : `${v}px`]);
|
|
@@ -2559,6 +2612,62 @@ function generateThemeProvider(config) {
|
|
|
2559
2612
|
const themeNames = Object.keys(config.themes ?? { light: {}, dark: {} });
|
|
2560
2613
|
const defaultTheme = themeNames.includes("light") ? "light" : themeNames[0] ?? "light";
|
|
2561
2614
|
const themeType = themeNames.map((t) => `"${t}"`).join(" | ");
|
|
2615
|
+
const isPro = isProUnlocked();
|
|
2616
|
+
const defaultDensity = config.meta.preset ?? "comfortable";
|
|
2617
|
+
const densityImport = isPro ? `
|
|
2618
|
+
import "../tokens/density.css";` : "";
|
|
2619
|
+
const densityTypes = isPro ? `
|
|
2620
|
+
export type DensityName = "compact" | "comfortable" | "spacious";
|
|
2621
|
+
` : "";
|
|
2622
|
+
const densityContextTypes = isPro ? `
|
|
2623
|
+
export interface DensityContextValue {
|
|
2624
|
+
density: DensityName;
|
|
2625
|
+
setDensity: (density: DensityName) => void;
|
|
2626
|
+
}
|
|
2627
|
+
` : "";
|
|
2628
|
+
const densityContext = isPro ? `
|
|
2629
|
+
export const DensityContext = React.createContext<DensityContextValue>({
|
|
2630
|
+
density: "${defaultDensity}",
|
|
2631
|
+
setDensity: () => undefined,
|
|
2632
|
+
});
|
|
2633
|
+
|
|
2634
|
+
/**
|
|
2635
|
+
* Hook to read and change the current density.
|
|
2636
|
+
* Must be used inside a <ThemeProvider>.
|
|
2637
|
+
*/
|
|
2638
|
+
export function useDensity(): DensityContextValue {
|
|
2639
|
+
return React.useContext(DensityContext);
|
|
2640
|
+
}
|
|
2641
|
+
` : "";
|
|
2642
|
+
const densityProp = isPro ? `
|
|
2643
|
+
/** Component density. Requires density.css to be imported. Defaults to "${defaultDensity}". */
|
|
2644
|
+
density?: DensityName;` : "";
|
|
2645
|
+
const densityOnChangeProp = isPro ? `
|
|
2646
|
+
/** Called when setDensity is invoked. */
|
|
2647
|
+
onDensityChange?: (density: DensityName) => void;` : "";
|
|
2648
|
+
const densityState = isPro ? `
|
|
2649
|
+
const [density, setDensityState] = React.useState<DensityName>(initialDensity);
|
|
2650
|
+
|
|
2651
|
+
React.useEffect(() => {
|
|
2652
|
+
setDensityState(initialDensity);
|
|
2653
|
+
}, [initialDensity]);
|
|
2654
|
+
|
|
2655
|
+
const setDensity = React.useCallback(
|
|
2656
|
+
(next: DensityName) => {
|
|
2657
|
+
setDensityState(next);
|
|
2658
|
+
onDensityChange?.(next);
|
|
2659
|
+
},
|
|
2660
|
+
[onDensityChange],
|
|
2661
|
+
);
|
|
2662
|
+
` : "";
|
|
2663
|
+
const densityDestructure = isPro ? `,
|
|
2664
|
+
density: initialDensity = "${defaultDensity}",
|
|
2665
|
+
onDensityChange,` : "";
|
|
2666
|
+
const densityProviderOpen = isPro ? `
|
|
2667
|
+
<DensityContext.Provider value={{ density, setDensity }}>` : "";
|
|
2668
|
+
const densityDataAttr = isPro ? ` data-density={density}` : "";
|
|
2669
|
+
const densityProviderClose = isPro ? `
|
|
2670
|
+
</DensityContext.Provider>` : "";
|
|
2562
2671
|
return `/**
|
|
2563
2672
|
* ThemeProvider \u2014 ${config.meta.name}
|
|
2564
2673
|
*
|
|
@@ -2570,27 +2679,27 @@ function generateThemeProvider(config) {
|
|
|
2570
2679
|
* import "@${config.meta.name}/tokens/light.css"; // or dark.css
|
|
2571
2680
|
* import { ThemeProvider } from "@${config.meta.name}";
|
|
2572
2681
|
*
|
|
2573
|
-
* <ThemeProvider theme="light">
|
|
2682
|
+
* <ThemeProvider theme="light"${isPro ? ` density="${defaultDensity}"` : ""}>
|
|
2574
2683
|
* <App />
|
|
2575
2684
|
* </ThemeProvider>
|
|
2576
2685
|
*/
|
|
2577
2686
|
|
|
2578
|
-
import React from "react"
|
|
2687
|
+
import React from "react";${densityImport}
|
|
2579
2688
|
|
|
2580
2689
|
// \u2500\u2500\u2500 Types \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\u2500\u2500\u2500
|
|
2581
2690
|
|
|
2582
2691
|
export type ThemeName = ${themeType};
|
|
2583
|
-
|
|
2692
|
+
${densityTypes}
|
|
2584
2693
|
export interface ThemeContextValue {
|
|
2585
2694
|
theme: ThemeName;
|
|
2586
2695
|
setTheme: (theme: ThemeName) => void;
|
|
2587
2696
|
}
|
|
2588
|
-
|
|
2697
|
+
${densityContextTypes}
|
|
2589
2698
|
export interface ThemeProviderProps {
|
|
2590
2699
|
/** Initial theme. Defaults to "${defaultTheme}". */
|
|
2591
2700
|
theme?: ThemeName;
|
|
2592
2701
|
/** Called when setTheme is invoked \u2014 use to persist theme preference. */
|
|
2593
|
-
onThemeChange?: (theme: ThemeName) => void
|
|
2702
|
+
onThemeChange?: (theme: ThemeName) => void;${densityProp}${densityOnChangeProp}
|
|
2594
2703
|
children: React.ReactNode;
|
|
2595
2704
|
}
|
|
2596
2705
|
|
|
@@ -2608,12 +2717,12 @@ export const ThemeContext = React.createContext<ThemeContextValue>({
|
|
|
2608
2717
|
export function useTheme(): ThemeContextValue {
|
|
2609
2718
|
return React.useContext(ThemeContext);
|
|
2610
2719
|
}
|
|
2611
|
-
|
|
2720
|
+
${densityContext}
|
|
2612
2721
|
// \u2500\u2500\u2500 Provider \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
|
|
2613
2722
|
|
|
2614
2723
|
export function ThemeProvider({
|
|
2615
2724
|
theme: initialTheme = "${defaultTheme}",
|
|
2616
|
-
onThemeChange
|
|
2725
|
+
onThemeChange,${densityDestructure}
|
|
2617
2726
|
children,
|
|
2618
2727
|
}: ThemeProviderProps) {
|
|
2619
2728
|
const [theme, setThemeState] = React.useState<ThemeName>(initialTheme);
|
|
@@ -2629,13 +2738,13 @@ export function ThemeProvider({
|
|
|
2629
2738
|
},
|
|
2630
2739
|
[onThemeChange],
|
|
2631
2740
|
);
|
|
2632
|
-
|
|
2633
|
-
return (
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2741
|
+
${densityState}
|
|
2742
|
+
return (${densityProviderOpen}
|
|
2743
|
+
<ThemeContext.Provider value={{ theme, setTheme }}>
|
|
2744
|
+
<div data-theme={theme}${densityDataAttr} style={{ display: "contents" }}>
|
|
2745
|
+
{children}
|
|
2746
|
+
</div>
|
|
2747
|
+
</ThemeContext.Provider>${densityProviderClose}
|
|
2639
2748
|
);
|
|
2640
2749
|
}
|
|
2641
2750
|
`;
|
|
@@ -2652,9 +2761,9 @@ function generateComponentIndex(config, componentNames) {
|
|
|
2652
2761
|
""
|
|
2653
2762
|
];
|
|
2654
2763
|
for (const name of componentNames) {
|
|
2655
|
-
lines.push(`export * from "
|
|
2764
|
+
lines.push(`export * from "./components/${name}/${name}";`);
|
|
2656
2765
|
}
|
|
2657
|
-
lines.push(`export * from "./ThemeProvider";`);
|
|
2766
|
+
lines.push(`export * from "./components/ThemeProvider/ThemeProvider";`);
|
|
2658
2767
|
lines.push("");
|
|
2659
2768
|
return lines.join("\n");
|
|
2660
2769
|
}
|
|
@@ -3057,12 +3166,14 @@ function generatePackageJson(config, componentNames) {
|
|
|
3057
3166
|
),
|
|
3058
3167
|
"./tokens": "./tokens/tokens.js",
|
|
3059
3168
|
"./tailwind": "./tokens/tailwind.js",
|
|
3060
|
-
"./metadata": "./metadata/index.json",
|
|
3061
3169
|
...Object.fromEntries(
|
|
3062
|
-
componentNames.map((c) =>
|
|
3170
|
+
componentNames.map((c) => {
|
|
3171
|
+
const pascal = c.charAt(0).toUpperCase() + c.slice(1);
|
|
3172
|
+
return [`./components/${pascal}`, `./components/${pascal}/${pascal}.json`];
|
|
3173
|
+
})
|
|
3063
3174
|
)
|
|
3064
3175
|
},
|
|
3065
|
-
files: ["dist", "tokens", "
|
|
3176
|
+
files: ["dist", "tokens", "components", "CHANGELOG.md"],
|
|
3066
3177
|
scripts: {
|
|
3067
3178
|
build: "tsc",
|
|
3068
3179
|
prepublishOnly: "npm run build"
|
|
@@ -3102,7 +3213,7 @@ function generateTsConfig() {
|
|
|
3102
3213
|
moduleResolution: "NodeNext",
|
|
3103
3214
|
lib: ["ES2020", "DOM"],
|
|
3104
3215
|
outDir: "./dist",
|
|
3105
|
-
rootDir: "
|
|
3216
|
+
rootDir: ".",
|
|
3106
3217
|
declaration: true,
|
|
3107
3218
|
declarationMap: true,
|
|
3108
3219
|
sourceMap: true,
|
|
@@ -3111,7 +3222,7 @@ function generateTsConfig() {
|
|
|
3111
3222
|
skipLibCheck: true,
|
|
3112
3223
|
jsx: "react-jsx"
|
|
3113
3224
|
},
|
|
3114
|
-
include: ["
|
|
3225
|
+
include: ["index.ts", "components/**/*"],
|
|
3115
3226
|
exclude: ["node_modules", "dist"]
|
|
3116
3227
|
},
|
|
3117
3228
|
null,
|
|
@@ -3160,7 +3271,10 @@ function App() {
|
|
|
3160
3271
|
## Components
|
|
3161
3272
|
|
|
3162
3273
|
${componentNames.map(
|
|
3163
|
-
(c) =>
|
|
3274
|
+
(c) => {
|
|
3275
|
+
const pascal = c.charAt(0).toUpperCase() + c.slice(1);
|
|
3276
|
+
return `- **${pascal}** \u2014 see \`components/${pascal}/${pascal}.json\` for props and usage`;
|
|
3277
|
+
}
|
|
3164
3278
|
).join("\n")}
|
|
3165
3279
|
|
|
3166
3280
|
## Themes
|
|
@@ -3235,20 +3349,10 @@ every semantic and component token that references it.
|
|
|
3235
3349
|
|
|
3236
3350
|
## AI tool integration
|
|
3237
3351
|
|
|
3238
|
-
|
|
3352
|
+
Each component ships with a machine-readable JSON contract (e.g. \`components/Button/Button.json\`).
|
|
3239
3353
|
AI coding assistants (Copilot, Cursor, Claude Code) can read these to
|
|
3240
3354
|
generate UI that respects your governance rules automatically.
|
|
3241
3355
|
|
|
3242
|
-
\`\`\`json
|
|
3243
|
-
// ${pkgName}/metadata/button.json
|
|
3244
|
-
{
|
|
3245
|
-
"component": "Button",
|
|
3246
|
-
"allowedVariants": ["primary", "secondary", "danger", "ghost"],
|
|
3247
|
-
"requiredProps": ["aria-label"],
|
|
3248
|
-
"accessibilityContract": { "keyboard": true, "focusRing": true }
|
|
3249
|
-
}
|
|
3250
|
-
\`\`\`
|
|
3251
|
-
|
|
3252
3356
|
---
|
|
3253
3357
|
|
|
3254
3358
|
Generated by [dsforge](https://github.com/nghitrum/dsforge) v${config.meta.version}.
|