@nghitrum/dsforge 0.1.5-alpha.9 → 0.2.0
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/LICENSE.md +21 -0
- package/README.md +0 -1
- package/dist/{chunk-YUPXTQZ5.js → chunk-5YT3VNE6.js} +0 -26
- package/dist/chunk-A7VW6SII.js +436 -0
- package/dist/{chunk-QHE35QQQ.js → chunk-ZZRPNO6Z.js} +12 -17
- package/dist/cli/index.js +185 -302
- package/dist/componentDefinitions-5LFCNFQY.js +8 -0
- package/dist/{emitter-KNYIQTS5.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-DJJSDXRX.js → html-4DD6GOHE.js} +193 -100
- package/dist/index.js +68 -110
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1143,31 +1143,6 @@ 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
|
-
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
1146
|
// src/presets/index.ts
|
|
1172
1147
|
var SPACING_PRESETS = {
|
|
1173
1148
|
compact: {
|
|
@@ -2612,62 +2587,7 @@ function generateThemeProvider(config) {
|
|
|
2612
2587
|
const themeNames = Object.keys(config.themes ?? { light: {}, dark: {} });
|
|
2613
2588
|
const defaultTheme = themeNames.includes("light") ? "light" : themeNames[0] ?? "light";
|
|
2614
2589
|
const themeType = themeNames.map((t) => `"${t}"`).join(" | ");
|
|
2615
|
-
const isPro = isProUnlocked();
|
|
2616
2590
|
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>` : "";
|
|
2671
2591
|
return `/**
|
|
2672
2592
|
* ThemeProvider \u2014 ${config.meta.name}
|
|
2673
2593
|
*
|
|
@@ -2679,27 +2599,39 @@ export function useDensity(): DensityContextValue {
|
|
|
2679
2599
|
* import "@${config.meta.name}/tokens/light.css"; // or dark.css
|
|
2680
2600
|
* import { ThemeProvider } from "@${config.meta.name}";
|
|
2681
2601
|
*
|
|
2682
|
-
* <ThemeProvider theme="light"
|
|
2602
|
+
* <ThemeProvider theme="light" density="${defaultDensity}">
|
|
2683
2603
|
* <App />
|
|
2684
2604
|
* </ThemeProvider>
|
|
2685
2605
|
*/
|
|
2686
2606
|
|
|
2687
|
-
import React from "react"
|
|
2607
|
+
import React from "react";
|
|
2608
|
+
import "../tokens/density.css";
|
|
2688
2609
|
|
|
2689
2610
|
// \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
|
|
2690
2611
|
|
|
2691
2612
|
export type ThemeName = ${themeType};
|
|
2692
|
-
|
|
2613
|
+
|
|
2614
|
+
export type DensityName = "compact" | "comfortable" | "spacious";
|
|
2615
|
+
|
|
2693
2616
|
export interface ThemeContextValue {
|
|
2694
2617
|
theme: ThemeName;
|
|
2695
2618
|
setTheme: (theme: ThemeName) => void;
|
|
2696
2619
|
}
|
|
2697
|
-
|
|
2620
|
+
|
|
2621
|
+
export interface DensityContextValue {
|
|
2622
|
+
density: DensityName;
|
|
2623
|
+
setDensity: (density: DensityName) => void;
|
|
2624
|
+
}
|
|
2625
|
+
|
|
2698
2626
|
export interface ThemeProviderProps {
|
|
2699
2627
|
/** Initial theme. Defaults to "${defaultTheme}". */
|
|
2700
2628
|
theme?: ThemeName;
|
|
2701
2629
|
/** Called when setTheme is invoked \u2014 use to persist theme preference. */
|
|
2702
|
-
onThemeChange?: (theme: ThemeName) => void
|
|
2630
|
+
onThemeChange?: (theme: ThemeName) => void;
|
|
2631
|
+
/** Component density. Requires density.css to be imported. Defaults to "${defaultDensity}". */
|
|
2632
|
+
density?: DensityName;
|
|
2633
|
+
/** Called when setDensity is invoked. */
|
|
2634
|
+
onDensityChange?: (density: DensityName) => void;
|
|
2703
2635
|
children: React.ReactNode;
|
|
2704
2636
|
}
|
|
2705
2637
|
|
|
@@ -2717,12 +2649,27 @@ export const ThemeContext = React.createContext<ThemeContextValue>({
|
|
|
2717
2649
|
export function useTheme(): ThemeContextValue {
|
|
2718
2650
|
return React.useContext(ThemeContext);
|
|
2719
2651
|
}
|
|
2720
|
-
|
|
2652
|
+
|
|
2653
|
+
export const DensityContext = React.createContext<DensityContextValue>({
|
|
2654
|
+
density: "${defaultDensity}",
|
|
2655
|
+
setDensity: () => undefined,
|
|
2656
|
+
});
|
|
2657
|
+
|
|
2658
|
+
/**
|
|
2659
|
+
* Hook to read and change the current density.
|
|
2660
|
+
* Must be used inside a <ThemeProvider>.
|
|
2661
|
+
*/
|
|
2662
|
+
export function useDensity(): DensityContextValue {
|
|
2663
|
+
return React.useContext(DensityContext);
|
|
2664
|
+
}
|
|
2665
|
+
|
|
2721
2666
|
// \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
|
|
2722
2667
|
|
|
2723
2668
|
export function ThemeProvider({
|
|
2724
2669
|
theme: initialTheme = "${defaultTheme}",
|
|
2725
|
-
onThemeChange
|
|
2670
|
+
onThemeChange,
|
|
2671
|
+
density: initialDensity = "${defaultDensity}",
|
|
2672
|
+
onDensityChange,
|
|
2726
2673
|
children,
|
|
2727
2674
|
}: ThemeProviderProps) {
|
|
2728
2675
|
const [theme, setThemeState] = React.useState<ThemeName>(initialTheme);
|
|
@@ -2738,13 +2685,29 @@ export function ThemeProvider({
|
|
|
2738
2685
|
},
|
|
2739
2686
|
[onThemeChange],
|
|
2740
2687
|
);
|
|
2741
|
-
|
|
2742
|
-
|
|
2688
|
+
|
|
2689
|
+
const [density, setDensityState] = React.useState<DensityName>(initialDensity);
|
|
2690
|
+
|
|
2691
|
+
React.useEffect(() => {
|
|
2692
|
+
setDensityState(initialDensity);
|
|
2693
|
+
}, [initialDensity]);
|
|
2694
|
+
|
|
2695
|
+
const setDensity = React.useCallback(
|
|
2696
|
+
(next: DensityName) => {
|
|
2697
|
+
setDensityState(next);
|
|
2698
|
+
onDensityChange?.(next);
|
|
2699
|
+
},
|
|
2700
|
+
[onDensityChange],
|
|
2701
|
+
);
|
|
2702
|
+
|
|
2703
|
+
return (
|
|
2704
|
+
<DensityContext.Provider value={{ density, setDensity }}>
|
|
2743
2705
|
<ThemeContext.Provider value={{ theme, setTheme }}>
|
|
2744
|
-
<div data-theme={theme}
|
|
2706
|
+
<div data-theme={theme} data-density={density} style={{ display: "contents" }}>
|
|
2745
2707
|
{children}
|
|
2746
2708
|
</div>
|
|
2747
|
-
</ThemeContext.Provider
|
|
2709
|
+
</ThemeContext.Provider>
|
|
2710
|
+
</DensityContext.Provider>
|
|
2748
2711
|
);
|
|
2749
2712
|
}
|
|
2750
2713
|
`;
|
|
@@ -2761,9 +2724,9 @@ function generateComponentIndex(config, componentNames) {
|
|
|
2761
2724
|
""
|
|
2762
2725
|
];
|
|
2763
2726
|
for (const name of componentNames) {
|
|
2764
|
-
lines.push(`export * from "
|
|
2727
|
+
lines.push(`export * from "./components/${name}/${name}";`);
|
|
2765
2728
|
}
|
|
2766
|
-
lines.push(`export * from "./ThemeProvider";`);
|
|
2729
|
+
lines.push(`export * from "./components/ThemeProvider/ThemeProvider";`);
|
|
2767
2730
|
lines.push("");
|
|
2768
2731
|
return lines.join("\n");
|
|
2769
2732
|
}
|
|
@@ -3166,12 +3129,14 @@ function generatePackageJson(config, componentNames) {
|
|
|
3166
3129
|
),
|
|
3167
3130
|
"./tokens": "./tokens/tokens.js",
|
|
3168
3131
|
"./tailwind": "./tokens/tailwind.js",
|
|
3169
|
-
"./metadata": "./metadata/index.json",
|
|
3170
3132
|
...Object.fromEntries(
|
|
3171
|
-
componentNames.map((c) =>
|
|
3133
|
+
componentNames.map((c) => {
|
|
3134
|
+
const pascal = c.charAt(0).toUpperCase() + c.slice(1);
|
|
3135
|
+
return [`./components/${pascal}`, `./components/${pascal}/${pascal}.json`];
|
|
3136
|
+
})
|
|
3172
3137
|
)
|
|
3173
3138
|
},
|
|
3174
|
-
files: ["dist", "tokens", "
|
|
3139
|
+
files: ["dist", "tokens", "components", "CHANGELOG.md"],
|
|
3175
3140
|
scripts: {
|
|
3176
3141
|
build: "tsc",
|
|
3177
3142
|
prepublishOnly: "npm run build"
|
|
@@ -3211,7 +3176,7 @@ function generateTsConfig() {
|
|
|
3211
3176
|
moduleResolution: "NodeNext",
|
|
3212
3177
|
lib: ["ES2020", "DOM"],
|
|
3213
3178
|
outDir: "./dist",
|
|
3214
|
-
rootDir: "
|
|
3179
|
+
rootDir: ".",
|
|
3215
3180
|
declaration: true,
|
|
3216
3181
|
declarationMap: true,
|
|
3217
3182
|
sourceMap: true,
|
|
@@ -3220,7 +3185,7 @@ function generateTsConfig() {
|
|
|
3220
3185
|
skipLibCheck: true,
|
|
3221
3186
|
jsx: "react-jsx"
|
|
3222
3187
|
},
|
|
3223
|
-
include: ["
|
|
3188
|
+
include: ["index.ts", "components/**/*"],
|
|
3224
3189
|
exclude: ["node_modules", "dist"]
|
|
3225
3190
|
},
|
|
3226
3191
|
null,
|
|
@@ -3269,7 +3234,10 @@ function App() {
|
|
|
3269
3234
|
## Components
|
|
3270
3235
|
|
|
3271
3236
|
${componentNames.map(
|
|
3272
|
-
(c) =>
|
|
3237
|
+
(c) => {
|
|
3238
|
+
const pascal = c.charAt(0).toUpperCase() + c.slice(1);
|
|
3239
|
+
return `- **${pascal}** \u2014 see \`components/${pascal}/${pascal}.json\` for props and usage`;
|
|
3240
|
+
}
|
|
3273
3241
|
).join("\n")}
|
|
3274
3242
|
|
|
3275
3243
|
## Themes
|
|
@@ -3344,20 +3312,10 @@ every semantic and component token that references it.
|
|
|
3344
3312
|
|
|
3345
3313
|
## AI tool integration
|
|
3346
3314
|
|
|
3347
|
-
|
|
3315
|
+
Each component ships with a machine-readable JSON contract (e.g. \`components/Button/Button.json\`).
|
|
3348
3316
|
AI coding assistants (Copilot, Cursor, Claude Code) can read these to
|
|
3349
3317
|
generate UI that respects your governance rules automatically.
|
|
3350
3318
|
|
|
3351
|
-
\`\`\`json
|
|
3352
|
-
// ${pkgName}/metadata/button.json
|
|
3353
|
-
{
|
|
3354
|
-
"component": "Button",
|
|
3355
|
-
"allowedVariants": ["primary", "secondary", "danger", "ghost"],
|
|
3356
|
-
"requiredProps": ["aria-label"],
|
|
3357
|
-
"accessibilityContract": { "keyboard": true, "focusRing": true }
|
|
3358
|
-
}
|
|
3359
|
-
\`\`\`
|
|
3360
|
-
|
|
3361
3319
|
---
|
|
3362
3320
|
|
|
3363
3321
|
Generated by [dsforge](https://github.com/nghitrum/dsforge) v${config.meta.version}.
|