@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/cli/index.js
CHANGED
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
generateChangelog,
|
|
4
4
|
generatePackageJson,
|
|
5
5
|
generateTsConfig
|
|
6
|
-
} from "../chunk-
|
|
6
|
+
} from "../chunk-ZZRPNO6Z.js";
|
|
7
7
|
import {
|
|
8
8
|
CONTROL_SIZE_PRESETS,
|
|
9
9
|
PRESETS,
|
|
@@ -11,9 +11,8 @@ import {
|
|
|
11
11
|
RADIUS_PRESETS,
|
|
12
12
|
SPACING_PRESETS,
|
|
13
13
|
applyPreset,
|
|
14
|
-
buildSemanticSpacing
|
|
15
|
-
|
|
16
|
-
} from "../chunk-YUPXTQZ5.js";
|
|
14
|
+
buildSemanticSpacing
|
|
15
|
+
} from "../chunk-5YT3VNE6.js";
|
|
17
16
|
|
|
18
17
|
// src/cli/index.ts
|
|
19
18
|
import { program } from "commander";
|
|
@@ -738,15 +737,7 @@ async function runInit(cwd, options) {
|
|
|
738
737
|
}
|
|
739
738
|
const name = rawName.replace(/\s+/g, "-").toLowerCase();
|
|
740
739
|
let preset;
|
|
741
|
-
if (
|
|
742
|
-
if (options.preset && options.preset !== "comfortable") {
|
|
743
|
-
logger.hint(
|
|
744
|
-
`Preset "${options.preset}" requires dsforge Pro`,
|
|
745
|
-
`Set DSFORGE_KEY to unlock compact and spacious. Using comfortable.`
|
|
746
|
-
);
|
|
747
|
-
}
|
|
748
|
-
preset = "comfortable";
|
|
749
|
-
} else if (options.preset && VALID_PRESETS.includes(options.preset)) {
|
|
740
|
+
if (options.preset && VALID_PRESETS.includes(options.preset)) {
|
|
750
741
|
preset = options.preset;
|
|
751
742
|
} else {
|
|
752
743
|
const answer = await ask(
|
|
@@ -1907,192 +1898,6 @@ function generateCssFiles(config, resolution) {
|
|
|
1907
1898
|
return files;
|
|
1908
1899
|
}
|
|
1909
1900
|
|
|
1910
|
-
// src/generators/metadata/generator.ts
|
|
1911
|
-
var COMPONENT_DEFAULTS = {
|
|
1912
|
-
button: {
|
|
1913
|
-
description: "Triggers an action or navigation. The primary interactive element.",
|
|
1914
|
-
role: "action-trigger",
|
|
1915
|
-
hierarchyLevel: "primary",
|
|
1916
|
-
interactionModel: "synchronous",
|
|
1917
|
-
layoutImpact: "inline",
|
|
1918
|
-
destructive: false,
|
|
1919
|
-
sizes: ["sm", "md", "lg"]
|
|
1920
|
-
},
|
|
1921
|
-
input: {
|
|
1922
|
-
description: "Accepts user text input. Use with a label for accessibility.",
|
|
1923
|
-
role: "data-entry",
|
|
1924
|
-
hierarchyLevel: "primary",
|
|
1925
|
-
interactionModel: "synchronous",
|
|
1926
|
-
layoutImpact: "block",
|
|
1927
|
-
destructive: false,
|
|
1928
|
-
sizes: ["sm", "md", "lg"]
|
|
1929
|
-
},
|
|
1930
|
-
card: {
|
|
1931
|
-
description: "Groups related content with optional header, body, and footer slots.",
|
|
1932
|
-
role: "content-container",
|
|
1933
|
-
hierarchyLevel: "utility",
|
|
1934
|
-
interactionModel: "none",
|
|
1935
|
-
layoutImpact: "block",
|
|
1936
|
-
destructive: false
|
|
1937
|
-
},
|
|
1938
|
-
badge: {
|
|
1939
|
-
description: "Compact label for status, categories, or counts. Display-only \u2014 not interactive.",
|
|
1940
|
-
role: "status-indicator",
|
|
1941
|
-
hierarchyLevel: "utility",
|
|
1942
|
-
interactionModel: "none",
|
|
1943
|
-
layoutImpact: "inline",
|
|
1944
|
-
destructive: false,
|
|
1945
|
-
sizes: ["sm", "md", "lg"]
|
|
1946
|
-
},
|
|
1947
|
-
checkbox: {
|
|
1948
|
-
description: "Binary toggle for boolean values. Supports indeterminate state for partial selections.",
|
|
1949
|
-
role: "data-entry",
|
|
1950
|
-
hierarchyLevel: "primary",
|
|
1951
|
-
interactionModel: "synchronous",
|
|
1952
|
-
layoutImpact: "inline",
|
|
1953
|
-
destructive: false,
|
|
1954
|
-
sizes: ["sm", "md", "lg"]
|
|
1955
|
-
},
|
|
1956
|
-
radio: {
|
|
1957
|
-
description: "Single selection within a mutually exclusive group. Always use inside RadioGroup.",
|
|
1958
|
-
role: "data-entry",
|
|
1959
|
-
hierarchyLevel: "primary",
|
|
1960
|
-
interactionModel: "synchronous",
|
|
1961
|
-
layoutImpact: "inline",
|
|
1962
|
-
destructive: false,
|
|
1963
|
-
sizes: ["sm", "md", "lg"]
|
|
1964
|
-
},
|
|
1965
|
-
select: {
|
|
1966
|
-
description: "Dropdown picker for selecting from a list of options. Wraps native <select> for accessibility.",
|
|
1967
|
-
role: "data-entry",
|
|
1968
|
-
hierarchyLevel: "primary",
|
|
1969
|
-
interactionModel: "synchronous",
|
|
1970
|
-
layoutImpact: "block",
|
|
1971
|
-
destructive: false,
|
|
1972
|
-
sizes: ["sm", "md", "lg"]
|
|
1973
|
-
},
|
|
1974
|
-
toast: {
|
|
1975
|
-
description: "Feedback messages for user actions. Alert is inline; Toast is an overlay with auto-dismiss.",
|
|
1976
|
-
role: "feedback",
|
|
1977
|
-
hierarchyLevel: "utility",
|
|
1978
|
-
interactionModel: "asynchronous",
|
|
1979
|
-
layoutImpact: "overlay",
|
|
1980
|
-
destructive: false
|
|
1981
|
-
},
|
|
1982
|
-
spinner: {
|
|
1983
|
-
description: "Loading indicator for async operations. Use with an accessible label for screen readers.",
|
|
1984
|
-
role: "loading-indicator",
|
|
1985
|
-
hierarchyLevel: "utility",
|
|
1986
|
-
interactionModel: "asynchronous",
|
|
1987
|
-
layoutImpact: "inline",
|
|
1988
|
-
destructive: false,
|
|
1989
|
-
sizes: ["xs", "sm", "md", "lg", "xl"]
|
|
1990
|
-
}
|
|
1991
|
-
};
|
|
1992
|
-
function buildComponentMetadata(componentName, rule, config) {
|
|
1993
|
-
const defaults = COMPONENT_DEFAULTS[componentName.toLowerCase()] ?? {};
|
|
1994
|
-
const variants = rule.allowedVariants ?? ["default"];
|
|
1995
|
-
const requiredProps = rule.requiredProps ?? [];
|
|
1996
|
-
const tokens = {};
|
|
1997
|
-
for (const [tokenName] of Object.entries(rule.tokens ?? {})) {
|
|
1998
|
-
tokens[tokenName] = `--${tokenName}`;
|
|
1999
|
-
}
|
|
2000
|
-
const meta = {
|
|
2001
|
-
component: pascalCase(componentName),
|
|
2002
|
-
version: config.meta.version,
|
|
2003
|
-
description: defaults.description ?? `A ${componentName} component.`,
|
|
2004
|
-
role: defaults.role ?? "ui-element",
|
|
2005
|
-
hierarchyLevel: defaults.hierarchyLevel ?? "utility",
|
|
2006
|
-
interactionModel: defaults.interactionModel ?? "none",
|
|
2007
|
-
layoutImpact: defaults.layoutImpact ?? "inline",
|
|
2008
|
-
destructive: componentName.toLowerCase().includes("delete") || variants.includes("danger"),
|
|
2009
|
-
allowedVariants: variants,
|
|
2010
|
-
defaultVariant: variants[0] ?? "default",
|
|
2011
|
-
requiredProps,
|
|
2012
|
-
optionalProps: buildOptionalProps(componentName, defaults),
|
|
2013
|
-
tokens,
|
|
2014
|
-
accessibilityContract: {
|
|
2015
|
-
keyboard: rule.a11y?.keyboard ?? true,
|
|
2016
|
-
focusRing: rule.a11y?.focusRing ?? true,
|
|
2017
|
-
ariaLabel: rule.a11y?.ariaLabel ?? "optional",
|
|
2018
|
-
...rule.a11y?.role ? { role: rule.a11y.role } : {}
|
|
2019
|
-
},
|
|
2020
|
-
governanceRules: {
|
|
2021
|
-
...rule.maxWidth ? { maxWidth: rule.maxWidth } : {},
|
|
2022
|
-
...rule.allowedRadius ? { allowedRadius: rule.allowedRadius } : {},
|
|
2023
|
-
...rule.allowedShadows ? { allowedShadows: rule.allowedShadows } : {},
|
|
2024
|
-
...rule.colorPalette ? { colorPalette: rule.colorPalette } : {}
|
|
2025
|
-
}
|
|
2026
|
-
};
|
|
2027
|
-
if (defaults.sizes) {
|
|
2028
|
-
meta.sizes = defaults.sizes;
|
|
2029
|
-
}
|
|
2030
|
-
return meta;
|
|
2031
|
-
}
|
|
2032
|
-
function buildOptionalProps(componentName, _defaults) {
|
|
2033
|
-
const common = ["className", "style", "id", "data-testid"];
|
|
2034
|
-
const byComponent = {
|
|
2035
|
-
button: [
|
|
2036
|
-
"size",
|
|
2037
|
-
"loading",
|
|
2038
|
-
"disabled",
|
|
2039
|
-
"fullWidth",
|
|
2040
|
-
"iconLeft",
|
|
2041
|
-
"iconRight",
|
|
2042
|
-
"onClick"
|
|
2043
|
-
],
|
|
2044
|
-
input: [
|
|
2045
|
-
"size",
|
|
2046
|
-
"disabled",
|
|
2047
|
-
"label",
|
|
2048
|
-
"helperText",
|
|
2049
|
-
"errorMessage",
|
|
2050
|
-
"placeholder",
|
|
2051
|
-
"startAdornment",
|
|
2052
|
-
"endAdornment",
|
|
2053
|
-
"onChange"
|
|
2054
|
-
],
|
|
2055
|
-
card: ["maxWidth", "noPadding", "onClick"],
|
|
2056
|
-
badge: ["size", "dot"],
|
|
2057
|
-
checkbox: ["size", "disabled", "label", "helperText", "indeterminate", "checked", "onChange"],
|
|
2058
|
-
radio: ["size", "disabled", "label", "value", "onChange"],
|
|
2059
|
-
select: ["size", "disabled", "label", "helperText", "errorMessage", "placeholder", "options", "fullWidth", "onChange"],
|
|
2060
|
-
toast: ["variant", "title", "dismissible", "duration", "onDismiss"],
|
|
2061
|
-
spinner: ["size", "variant", "label"]
|
|
2062
|
-
};
|
|
2063
|
-
return [...byComponent[componentName.toLowerCase()] ?? [], ...common];
|
|
2064
|
-
}
|
|
2065
|
-
function pascalCase(str) {
|
|
2066
|
-
return str.charAt(0).toUpperCase() + str.slice(1);
|
|
2067
|
-
}
|
|
2068
|
-
function buildIndexMetadata(config, componentNames, tokenCount) {
|
|
2069
|
-
return {
|
|
2070
|
-
name: config.meta.name,
|
|
2071
|
-
version: config.meta.version,
|
|
2072
|
-
generatedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
2073
|
-
components: componentNames.map(pascalCase),
|
|
2074
|
-
tokenCount,
|
|
2075
|
-
themes: Object.keys(config.themes ?? {})
|
|
2076
|
-
};
|
|
2077
|
-
}
|
|
2078
|
-
function generateMetadata(config, rules, tokenCount) {
|
|
2079
|
-
const files = [];
|
|
2080
|
-
const componentNames = Object.keys(rules);
|
|
2081
|
-
for (const [componentName, rule] of Object.entries(rules)) {
|
|
2082
|
-
const metadata = buildComponentMetadata(componentName, rule, config);
|
|
2083
|
-
files.push({
|
|
2084
|
-
filename: `${componentName}.json`,
|
|
2085
|
-
content: JSON.stringify(metadata, null, 2)
|
|
2086
|
-
});
|
|
2087
|
-
}
|
|
2088
|
-
const index = buildIndexMetadata(config, componentNames, tokenCount);
|
|
2089
|
-
files.push({
|
|
2090
|
-
filename: "index.json",
|
|
2091
|
-
content: JSON.stringify(index, null, 2)
|
|
2092
|
-
});
|
|
2093
|
-
return files;
|
|
2094
|
-
}
|
|
2095
|
-
|
|
2096
1901
|
// src/adapters/react/components/button.ts
|
|
2097
1902
|
function generateButton(config, rule) {
|
|
2098
1903
|
const variants = rule?.allowedVariants ?? [
|
|
@@ -4111,62 +3916,7 @@ function generateThemeProvider(config) {
|
|
|
4111
3916
|
const themeNames = Object.keys(config.themes ?? { light: {}, dark: {} });
|
|
4112
3917
|
const defaultTheme = themeNames.includes("light") ? "light" : themeNames[0] ?? "light";
|
|
4113
3918
|
const themeType = themeNames.map((t) => `"${t}"`).join(" | ");
|
|
4114
|
-
const isPro = isProUnlocked();
|
|
4115
3919
|
const defaultDensity = config.meta.preset ?? "comfortable";
|
|
4116
|
-
const densityImport = isPro ? `
|
|
4117
|
-
import "../tokens/density.css";` : "";
|
|
4118
|
-
const densityTypes = isPro ? `
|
|
4119
|
-
export type DensityName = "compact" | "comfortable" | "spacious";
|
|
4120
|
-
` : "";
|
|
4121
|
-
const densityContextTypes = isPro ? `
|
|
4122
|
-
export interface DensityContextValue {
|
|
4123
|
-
density: DensityName;
|
|
4124
|
-
setDensity: (density: DensityName) => void;
|
|
4125
|
-
}
|
|
4126
|
-
` : "";
|
|
4127
|
-
const densityContext = isPro ? `
|
|
4128
|
-
export const DensityContext = React.createContext<DensityContextValue>({
|
|
4129
|
-
density: "${defaultDensity}",
|
|
4130
|
-
setDensity: () => undefined,
|
|
4131
|
-
});
|
|
4132
|
-
|
|
4133
|
-
/**
|
|
4134
|
-
* Hook to read and change the current density.
|
|
4135
|
-
* Must be used inside a <ThemeProvider>.
|
|
4136
|
-
*/
|
|
4137
|
-
export function useDensity(): DensityContextValue {
|
|
4138
|
-
return React.useContext(DensityContext);
|
|
4139
|
-
}
|
|
4140
|
-
` : "";
|
|
4141
|
-
const densityProp = isPro ? `
|
|
4142
|
-
/** Component density. Requires density.css to be imported. Defaults to "${defaultDensity}". */
|
|
4143
|
-
density?: DensityName;` : "";
|
|
4144
|
-
const densityOnChangeProp = isPro ? `
|
|
4145
|
-
/** Called when setDensity is invoked. */
|
|
4146
|
-
onDensityChange?: (density: DensityName) => void;` : "";
|
|
4147
|
-
const densityState = isPro ? `
|
|
4148
|
-
const [density, setDensityState] = React.useState<DensityName>(initialDensity);
|
|
4149
|
-
|
|
4150
|
-
React.useEffect(() => {
|
|
4151
|
-
setDensityState(initialDensity);
|
|
4152
|
-
}, [initialDensity]);
|
|
4153
|
-
|
|
4154
|
-
const setDensity = React.useCallback(
|
|
4155
|
-
(next: DensityName) => {
|
|
4156
|
-
setDensityState(next);
|
|
4157
|
-
onDensityChange?.(next);
|
|
4158
|
-
},
|
|
4159
|
-
[onDensityChange],
|
|
4160
|
-
);
|
|
4161
|
-
` : "";
|
|
4162
|
-
const densityDestructure = isPro ? `,
|
|
4163
|
-
density: initialDensity = "${defaultDensity}",
|
|
4164
|
-
onDensityChange,` : "";
|
|
4165
|
-
const densityProviderOpen = isPro ? `
|
|
4166
|
-
<DensityContext.Provider value={{ density, setDensity }}>` : "";
|
|
4167
|
-
const densityDataAttr = isPro ? ` data-density={density}` : "";
|
|
4168
|
-
const densityProviderClose = isPro ? `
|
|
4169
|
-
</DensityContext.Provider>` : "";
|
|
4170
3920
|
return `/**
|
|
4171
3921
|
* ThemeProvider \u2014 ${config.meta.name}
|
|
4172
3922
|
*
|
|
@@ -4178,27 +3928,39 @@ export function useDensity(): DensityContextValue {
|
|
|
4178
3928
|
* import "@${config.meta.name}/tokens/light.css"; // or dark.css
|
|
4179
3929
|
* import { ThemeProvider } from "@${config.meta.name}";
|
|
4180
3930
|
*
|
|
4181
|
-
* <ThemeProvider theme="light"
|
|
3931
|
+
* <ThemeProvider theme="light" density="${defaultDensity}">
|
|
4182
3932
|
* <App />
|
|
4183
3933
|
* </ThemeProvider>
|
|
4184
3934
|
*/
|
|
4185
3935
|
|
|
4186
|
-
import React from "react"
|
|
3936
|
+
import React from "react";
|
|
3937
|
+
import "../tokens/density.css";
|
|
4187
3938
|
|
|
4188
3939
|
// \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
|
|
4189
3940
|
|
|
4190
3941
|
export type ThemeName = ${themeType};
|
|
4191
|
-
|
|
3942
|
+
|
|
3943
|
+
export type DensityName = "compact" | "comfortable" | "spacious";
|
|
3944
|
+
|
|
4192
3945
|
export interface ThemeContextValue {
|
|
4193
3946
|
theme: ThemeName;
|
|
4194
3947
|
setTheme: (theme: ThemeName) => void;
|
|
4195
3948
|
}
|
|
4196
|
-
|
|
3949
|
+
|
|
3950
|
+
export interface DensityContextValue {
|
|
3951
|
+
density: DensityName;
|
|
3952
|
+
setDensity: (density: DensityName) => void;
|
|
3953
|
+
}
|
|
3954
|
+
|
|
4197
3955
|
export interface ThemeProviderProps {
|
|
4198
3956
|
/** Initial theme. Defaults to "${defaultTheme}". */
|
|
4199
3957
|
theme?: ThemeName;
|
|
4200
3958
|
/** Called when setTheme is invoked \u2014 use to persist theme preference. */
|
|
4201
|
-
onThemeChange?: (theme: ThemeName) => void
|
|
3959
|
+
onThemeChange?: (theme: ThemeName) => void;
|
|
3960
|
+
/** Component density. Requires density.css to be imported. Defaults to "${defaultDensity}". */
|
|
3961
|
+
density?: DensityName;
|
|
3962
|
+
/** Called when setDensity is invoked. */
|
|
3963
|
+
onDensityChange?: (density: DensityName) => void;
|
|
4202
3964
|
children: React.ReactNode;
|
|
4203
3965
|
}
|
|
4204
3966
|
|
|
@@ -4216,12 +3978,27 @@ export const ThemeContext = React.createContext<ThemeContextValue>({
|
|
|
4216
3978
|
export function useTheme(): ThemeContextValue {
|
|
4217
3979
|
return React.useContext(ThemeContext);
|
|
4218
3980
|
}
|
|
4219
|
-
|
|
3981
|
+
|
|
3982
|
+
export const DensityContext = React.createContext<DensityContextValue>({
|
|
3983
|
+
density: "${defaultDensity}",
|
|
3984
|
+
setDensity: () => undefined,
|
|
3985
|
+
});
|
|
3986
|
+
|
|
3987
|
+
/**
|
|
3988
|
+
* Hook to read and change the current density.
|
|
3989
|
+
* Must be used inside a <ThemeProvider>.
|
|
3990
|
+
*/
|
|
3991
|
+
export function useDensity(): DensityContextValue {
|
|
3992
|
+
return React.useContext(DensityContext);
|
|
3993
|
+
}
|
|
3994
|
+
|
|
4220
3995
|
// \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
|
|
4221
3996
|
|
|
4222
3997
|
export function ThemeProvider({
|
|
4223
3998
|
theme: initialTheme = "${defaultTheme}",
|
|
4224
|
-
onThemeChange
|
|
3999
|
+
onThemeChange,
|
|
4000
|
+
density: initialDensity = "${defaultDensity}",
|
|
4001
|
+
onDensityChange,
|
|
4225
4002
|
children,
|
|
4226
4003
|
}: ThemeProviderProps) {
|
|
4227
4004
|
const [theme, setThemeState] = React.useState<ThemeName>(initialTheme);
|
|
@@ -4237,13 +4014,29 @@ export function ThemeProvider({
|
|
|
4237
4014
|
},
|
|
4238
4015
|
[onThemeChange],
|
|
4239
4016
|
);
|
|
4240
|
-
|
|
4241
|
-
|
|
4017
|
+
|
|
4018
|
+
const [density, setDensityState] = React.useState<DensityName>(initialDensity);
|
|
4019
|
+
|
|
4020
|
+
React.useEffect(() => {
|
|
4021
|
+
setDensityState(initialDensity);
|
|
4022
|
+
}, [initialDensity]);
|
|
4023
|
+
|
|
4024
|
+
const setDensity = React.useCallback(
|
|
4025
|
+
(next: DensityName) => {
|
|
4026
|
+
setDensityState(next);
|
|
4027
|
+
onDensityChange?.(next);
|
|
4028
|
+
},
|
|
4029
|
+
[onDensityChange],
|
|
4030
|
+
);
|
|
4031
|
+
|
|
4032
|
+
return (
|
|
4033
|
+
<DensityContext.Provider value={{ density, setDensity }}>
|
|
4242
4034
|
<ThemeContext.Provider value={{ theme, setTheme }}>
|
|
4243
|
-
<div data-theme={theme}
|
|
4035
|
+
<div data-theme={theme} data-density={density} style={{ display: "contents" }}>
|
|
4244
4036
|
{children}
|
|
4245
4037
|
</div>
|
|
4246
|
-
</ThemeContext.Provider
|
|
4038
|
+
</ThemeContext.Provider>
|
|
4039
|
+
</DensityContext.Provider>
|
|
4247
4040
|
);
|
|
4248
4041
|
}
|
|
4249
4042
|
`;
|
|
@@ -4260,9 +4053,9 @@ function generateComponentIndex(config, componentNames) {
|
|
|
4260
4053
|
""
|
|
4261
4054
|
];
|
|
4262
4055
|
for (const name of componentNames) {
|
|
4263
|
-
lines.push(`export * from "
|
|
4056
|
+
lines.push(`export * from "./components/${name}/${name}";`);
|
|
4264
4057
|
}
|
|
4265
|
-
lines.push(`export * from "./ThemeProvider";`);
|
|
4058
|
+
lines.push(`export * from "./components/ThemeProvider/ThemeProvider";`);
|
|
4266
4059
|
lines.push("");
|
|
4267
4060
|
return lines.join("\n");
|
|
4268
4061
|
}
|
|
@@ -4900,13 +4693,11 @@ async function runGenerate(cwd, options) {
|
|
|
4900
4693
|
await writeFile(path3.join(tokensDir, filename), content);
|
|
4901
4694
|
logger.dim(` \u2192 tokens/${filename}`);
|
|
4902
4695
|
}
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
logger.dim(` \u2192 tokens/density.css`);
|
|
4909
|
-
}
|
|
4696
|
+
await writeFile(
|
|
4697
|
+
path3.join(tokensDir, "density.css"),
|
|
4698
|
+
emitDensityCss(config)
|
|
4699
|
+
);
|
|
4700
|
+
logger.dim(` \u2192 tokens/density.css`);
|
|
4910
4701
|
const tokenFiles = reactAdapter.generateTokenFiles(config, resolution);
|
|
4911
4702
|
for (const { filename, content } of tokenFiles) {
|
|
4912
4703
|
await writeFile(path3.join(tokensDir, filename), content);
|
|
@@ -4916,21 +4707,53 @@ async function runGenerate(cwd, options) {
|
|
|
4916
4707
|
}
|
|
4917
4708
|
if (!only || only === "components") {
|
|
4918
4709
|
logger.step("Generating React components...");
|
|
4919
|
-
const
|
|
4920
|
-
await ensureDir(
|
|
4710
|
+
const componentsDir = path3.join(outRoot, "components");
|
|
4711
|
+
await ensureDir(componentsDir);
|
|
4921
4712
|
const generatedNames = [];
|
|
4713
|
+
const generatedComponentJsons = [];
|
|
4714
|
+
const flatTokens = {};
|
|
4715
|
+
for (const [k, v] of Object.entries(resolution.tokens)) {
|
|
4716
|
+
flatTokens[`--${k.replace(/^(global|semantic|component)\./, "")}`] = v;
|
|
4717
|
+
}
|
|
4718
|
+
const lightOverrides = config.themes?.["light"] ?? {};
|
|
4719
|
+
const darkOverrides = config.themes?.["dark"] ?? {};
|
|
4720
|
+
const lightCssVars = {
|
|
4721
|
+
...flatTokens,
|
|
4722
|
+
...Object.fromEntries(Object.entries(lightOverrides).map(([k, v]) => [`--${k}`, String(v)]))
|
|
4723
|
+
};
|
|
4724
|
+
const darkCssVars = {
|
|
4725
|
+
...flatTokens,
|
|
4726
|
+
...Object.fromEntries(Object.entries(darkOverrides).map(([k, v]) => [`--${k}`, String(v)]))
|
|
4727
|
+
};
|
|
4728
|
+
const resolvedCssVars = { light: lightCssVars, dark: darkCssVars };
|
|
4729
|
+
const { generateComponentJson } = await import("../generateComponentJson-XBEUWCW6.js");
|
|
4730
|
+
const { generateComponentMetadata } = await import("../generateComponentMetadata-2L5VNERD.js");
|
|
4922
4731
|
for (const componentName of REACT_COMPONENTS) {
|
|
4732
|
+
const pascalName = componentName.charAt(0).toUpperCase() + componentName.slice(1);
|
|
4923
4733
|
try {
|
|
4924
4734
|
const { filename, content } = reactAdapter.generateComponent(
|
|
4925
4735
|
componentName,
|
|
4926
4736
|
config,
|
|
4927
4737
|
rules[componentName]
|
|
4928
4738
|
);
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4739
|
+
const componentSubDir = path3.join(componentsDir, pascalName);
|
|
4740
|
+
await ensureDir(componentSubDir);
|
|
4741
|
+
await writeFile(path3.join(componentSubDir, filename), content);
|
|
4742
|
+
logger.dim(` \u2192 components/${pascalName}/${filename}`);
|
|
4743
|
+
generatedNames.push(pascalName);
|
|
4744
|
+
const componentJson = generateComponentJson(pascalName, resolvedCssVars);
|
|
4745
|
+
generatedComponentJsons.push(componentJson);
|
|
4746
|
+
await writeFile(
|
|
4747
|
+
path3.join(componentSubDir, `${pascalName}.json`),
|
|
4748
|
+
JSON.stringify(componentJson, null, 2)
|
|
4749
|
+
);
|
|
4750
|
+
logger.dim(` \u2192 components/${pascalName}/${pascalName}.json`);
|
|
4751
|
+
const metadata = generateComponentMetadata(pascalName);
|
|
4752
|
+
await writeFile(
|
|
4753
|
+
path3.join(componentSubDir, `${pascalName}.metadata.json`),
|
|
4754
|
+
JSON.stringify(metadata, null, 2)
|
|
4933
4755
|
);
|
|
4756
|
+
logger.dim(` \u2192 components/${pascalName}/${pascalName}.metadata.json`);
|
|
4934
4757
|
} catch (err) {
|
|
4935
4758
|
logger.warn(
|
|
4936
4759
|
`[dsforge] Could not generate ${componentName} \u2014 ${err.message}`
|
|
@@ -4938,23 +4761,31 @@ async function runGenerate(cwd, options) {
|
|
|
4938
4761
|
}
|
|
4939
4762
|
}
|
|
4940
4763
|
const { filename: tpFile, content: tpContent } = reactAdapter.generateThemeProvider(config);
|
|
4941
|
-
|
|
4942
|
-
|
|
4764
|
+
const tpDir = path3.join(componentsDir, "ThemeProvider");
|
|
4765
|
+
await ensureDir(tpDir);
|
|
4766
|
+
await writeFile(path3.join(tpDir, tpFile), tpContent);
|
|
4767
|
+
logger.dim(` \u2192 components/ThemeProvider/${tpFile}`);
|
|
4768
|
+
try {
|
|
4769
|
+
const tpJson = generateComponentJson("ThemeProvider", resolvedCssVars);
|
|
4770
|
+
generatedComponentJsons.push(tpJson);
|
|
4771
|
+
await writeFile(
|
|
4772
|
+
path3.join(tpDir, "ThemeProvider.json"),
|
|
4773
|
+
JSON.stringify(tpJson, null, 2)
|
|
4774
|
+
);
|
|
4775
|
+
logger.dim(` \u2192 components/ThemeProvider/ThemeProvider.json`);
|
|
4776
|
+
const tpMeta = generateComponentMetadata("ThemeProvider");
|
|
4777
|
+
await writeFile(
|
|
4778
|
+
path3.join(tpDir, "ThemeProvider.metadata.json"),
|
|
4779
|
+
JSON.stringify(tpMeta, null, 2)
|
|
4780
|
+
);
|
|
4781
|
+
logger.dim(` \u2192 components/ThemeProvider/ThemeProvider.metadata.json`);
|
|
4782
|
+
} catch {
|
|
4783
|
+
}
|
|
4943
4784
|
const { filename: idxFile, content: idxContent } = reactAdapter.generateComponentIndex(config, generatedNames);
|
|
4944
|
-
await writeFile(path3.join(
|
|
4945
|
-
logger.dim(` \u2192
|
|
4785
|
+
await writeFile(path3.join(outRoot, idxFile), idxContent);
|
|
4786
|
+
logger.dim(` \u2192 ${idxFile}`);
|
|
4946
4787
|
logger.success(`${generatedNames.length} components generated`);
|
|
4947
|
-
|
|
4948
|
-
if (isProUnlocked() && (!only || only === "metadata")) {
|
|
4949
|
-
logger.step("Writing AI metadata...");
|
|
4950
|
-
const metaDir = path3.join(outRoot, "metadata");
|
|
4951
|
-
await ensureDir(metaDir);
|
|
4952
|
-
const metaFiles = generateMetadata(config, fullRules, tokenCount);
|
|
4953
|
-
for (const { filename, content } of metaFiles) {
|
|
4954
|
-
await writeFile(path3.join(metaDir, filename), content);
|
|
4955
|
-
logger.dim(` \u2192 metadata/${filename}`);
|
|
4956
|
-
}
|
|
4957
|
-
logger.success(`Metadata written (${metaFiles.length} files)`);
|
|
4788
|
+
globalThis["__dsforgGeneratedJsons"] = generatedComponentJsons;
|
|
4958
4789
|
}
|
|
4959
4790
|
if (!only) {
|
|
4960
4791
|
logger.step("Writing package files...");
|
|
@@ -4965,28 +4796,80 @@ async function runGenerate(cwd, options) {
|
|
|
4965
4796
|
const tsConfig = generateTsConfig();
|
|
4966
4797
|
await writeFile(path3.join(outRoot, "tsconfig.json"), tsConfig);
|
|
4967
4798
|
logger.dim(` \u2192 tsconfig.json`);
|
|
4968
|
-
const { generateReadme } = await import("../emitter-
|
|
4799
|
+
const { generateReadme } = await import("../emitter-IC77G4QF.js");
|
|
4969
4800
|
await writeFile(
|
|
4970
4801
|
path3.join(outRoot, "README.md"),
|
|
4971
4802
|
generateReadme(config, componentNames)
|
|
4972
4803
|
);
|
|
4973
4804
|
logger.dim(` \u2192 README.md`);
|
|
4974
4805
|
const changelogPath = path3.join(outRoot, "CHANGELOG.md");
|
|
4975
|
-
const
|
|
4976
|
-
const fsE2 =
|
|
4806
|
+
const fsExtra = await import("fs-extra");
|
|
4807
|
+
const fsE2 = fsExtra.default ?? fsExtra;
|
|
4977
4808
|
if (!await fsE2.pathExists(changelogPath)) {
|
|
4978
4809
|
await writeFile(changelogPath, generateChangelog(config));
|
|
4979
4810
|
logger.dim(` \u2192 CHANGELOG.md (seeded)`);
|
|
4980
4811
|
}
|
|
4981
4812
|
logger.success(`Package files written`);
|
|
4982
4813
|
}
|
|
4814
|
+
if (!only || only === "components") {
|
|
4815
|
+
logger.step("Writing registry + AI outputs...");
|
|
4816
|
+
const generatedJsons = globalThis["__dsforgGeneratedJsons"] ?? [];
|
|
4817
|
+
const { generateRegistry } = await import("../generateRegistry-3MEZDJAJ.js");
|
|
4818
|
+
const {
|
|
4819
|
+
generateSystemPrompt,
|
|
4820
|
+
generateComponentsJson,
|
|
4821
|
+
generateCursorContext,
|
|
4822
|
+
generateCopilotInstructions
|
|
4823
|
+
} = await import("../generateAiFolder-3OOFWBH7.js");
|
|
4824
|
+
const systemName = config.meta.name;
|
|
4825
|
+
const version = config.meta.version;
|
|
4826
|
+
const registry = generateRegistry(systemName, version, generatedJsons);
|
|
4827
|
+
await writeFile(path3.join(outRoot, "registry.json"), JSON.stringify(registry, null, 2));
|
|
4828
|
+
logger.dim(` \u2192 registry.json`);
|
|
4829
|
+
const { COMPONENT_METADATA_DEFINITIONS } = await import("../componentDefinitions-5LFCNFQY.js");
|
|
4830
|
+
const metadataList = generatedJsons.map((c) => COMPONENT_METADATA_DEFINITIONS[c.name]).filter((m) => Boolean(m));
|
|
4831
|
+
const flatTokensForAi = {};
|
|
4832
|
+
for (const [k, v] of Object.entries(resolution.tokens)) {
|
|
4833
|
+
const cssVar2 = `--${k.replace(/^(global|semantic|component)\./, "")}`;
|
|
4834
|
+
flatTokensForAi[cssVar2] = {
|
|
4835
|
+
light: config.themes?.["light"]?.[cssVar2.slice(2)] ?? v,
|
|
4836
|
+
dark: config.themes?.["dark"]?.[cssVar2.slice(2)] ?? v
|
|
4837
|
+
};
|
|
4838
|
+
}
|
|
4839
|
+
const aiDir = path3.join(outRoot, "ai");
|
|
4840
|
+
await ensureDir(aiDir);
|
|
4841
|
+
const cursorDir = path3.join(aiDir, ".cursor");
|
|
4842
|
+
await ensureDir(cursorDir);
|
|
4843
|
+
const componentNames = generatedJsons.map((c) => c.name);
|
|
4844
|
+
await writeFile(
|
|
4845
|
+
path3.join(aiDir, "system-prompt.md"),
|
|
4846
|
+
generateSystemPrompt(systemName, flatTokensForAi, componentNames)
|
|
4847
|
+
);
|
|
4848
|
+
logger.dim(` \u2192 ai/system-prompt.md`);
|
|
4849
|
+
await writeFile(
|
|
4850
|
+
path3.join(aiDir, "components.json"),
|
|
4851
|
+
generateComponentsJson(systemName, generatedJsons, metadataList)
|
|
4852
|
+
);
|
|
4853
|
+
logger.dim(` \u2192 ai/components.json`);
|
|
4854
|
+
await writeFile(
|
|
4855
|
+
path3.join(cursorDir, "context.md"),
|
|
4856
|
+
generateCursorContext(systemName)
|
|
4857
|
+
);
|
|
4858
|
+
logger.dim(` \u2192 ai/.cursor/context.md`);
|
|
4859
|
+
await writeFile(
|
|
4860
|
+
path3.join(outRoot, "copilot-instructions.md"),
|
|
4861
|
+
generateCopilotInstructions(systemName)
|
|
4862
|
+
);
|
|
4863
|
+
logger.dim(` \u2192 copilot-instructions.md`);
|
|
4864
|
+
logger.success(`Registry + AI outputs written`);
|
|
4865
|
+
}
|
|
4983
4866
|
logger.step("Generating showcase...");
|
|
4984
|
-
const { generateShowcase } = await import("../html-
|
|
4867
|
+
const { generateShowcase } = await import("../html-4DD6GOHE.js");
|
|
4985
4868
|
const showcaseHtml = generateShowcase(config, resolution);
|
|
4986
4869
|
await writeFile(path3.join(outRoot, "showcase.html"), showcaseHtml);
|
|
4987
4870
|
logger.dim(` \u2192 showcase.html`);
|
|
4988
|
-
const
|
|
4989
|
-
const fsE =
|
|
4871
|
+
const fsExtraShowcase = await import("fs-extra");
|
|
4872
|
+
const fsE = fsExtraShowcase.default ?? fsExtraShowcase;
|
|
4990
4873
|
const faviconSrc = path3.join(cwd, "assets", "favicon.svg");
|
|
4991
4874
|
const faviconDest = path3.join(outRoot, "assets", "favicon.svg");
|
|
4992
4875
|
if (await fsE.pathExists(faviconSrc)) {
|
|
@@ -5368,7 +5251,7 @@ async function runMenu() {
|
|
|
5368
5251
|
// package.json
|
|
5369
5252
|
var package_default = {
|
|
5370
5253
|
name: "@nghitrum/dsforge",
|
|
5371
|
-
version: "0.
|
|
5254
|
+
version: "0.2.0",
|
|
5372
5255
|
description: "AI-native design system generator \u2014 tokens \u2192 components \u2192 docs \u2192 npm",
|
|
5373
5256
|
keywords: [
|
|
5374
5257
|
"design-system",
|