czero 0.1.0 → 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/README.md +40 -0
- package/dist/cli/index.js +3780 -28
- package/dist/cli-new/cli/build-css.d.ts +19 -0
- package/dist/cli-new/cli/build-css.js +88 -0
- package/dist/cli-new/cli/generators/button.d.ts +9 -0
- package/dist/cli-new/cli/generators/button.js +224 -0
- package/dist/cli-new/cli/generators/card.d.ts +9 -0
- package/dist/cli-new/cli/generators/card.js +104 -0
- package/dist/cli-new/cli/generators/checkbox.d.ts +6 -0
- package/dist/cli-new/cli/generators/checkbox.js +163 -0
- package/dist/cli-new/cli/generators/index.d.ts +10 -0
- package/dist/cli-new/cli/generators/index.js +40 -0
- package/dist/cli-new/cli/generators/input.d.ts +9 -0
- package/dist/cli-new/cli/generators/input.js +231 -0
- package/dist/cli-new/cli/generators/switch.d.ts +6 -0
- package/dist/cli-new/cli/generators/switch.js +156 -0
- package/dist/cli-new/cli/generators/utilities.d.ts +9 -0
- package/dist/cli-new/cli/generators/utilities.js +150 -0
- package/dist/cli-new/cli/index.d.ts +8 -0
- package/dist/cli-new/cli/index.js +288 -0
- package/dist/cli-new/cli/token-resolver.d.ts +44 -0
- package/dist/cli-new/cli/token-resolver.js +137 -0
- package/dist/cli-new/cli/utils/deep-merge.d.ts +15 -0
- package/dist/cli-new/cli/utils/deep-merge.js +41 -0
- package/dist/cli-new/cli/validate-config.d.ts +19 -0
- package/dist/cli-new/cli/validate-config.js +151 -0
- package/dist/cli-new/src/core/component-defaults.d.ts +7 -0
- package/dist/cli-new/src/core/component-defaults.js +467 -0
- package/dist/cli-new/src/core/types/config.d.ts +489 -0
- package/dist/cli-new/src/core/types/config.js +5 -0
- package/dist/cli-new/src/presets/index.d.ts +44 -0
- package/dist/cli-new/src/presets/index.js +194 -0
- package/dist/components.css +1579 -2
- package/dist/react/core/component-defaults.d.ts +8 -0
- package/dist/react/core/component-defaults.d.ts.map +1 -0
- package/dist/react/core/types/config.d.ts +490 -0
- package/dist/react/core/types/config.d.ts.map +1 -0
- package/dist/react/index.cjs +11577 -17
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.ts +407 -4
- package/dist/react/index.js +11532 -6
- package/dist/react/index.js.map +1 -1
- package/dist/react/presets/index.d.ts +45 -0
- package/dist/react/presets/index.d.ts.map +1 -0
- package/dist/react/react/components/accordion.d.ts +30 -0
- package/dist/react/react/components/accordion.d.ts.map +1 -0
- package/dist/react/react/components/alert.d.ts +7 -0
- package/dist/react/react/components/alert.d.ts.map +1 -0
- package/dist/react/react/components/aspect-ratio.d.ts +8 -0
- package/dist/react/react/components/aspect-ratio.d.ts.map +1 -0
- package/dist/react/react/components/avatar.d.ts +10 -0
- package/dist/react/react/components/avatar.d.ts.map +1 -0
- package/dist/react/react/components/breadcrumb.d.ts +28 -0
- package/dist/react/react/components/breadcrumb.d.ts.map +1 -0
- package/dist/react/react/components/button.d.ts +3 -2
- package/dist/react/react/components/button.d.ts.map +1 -1
- package/dist/react/react/components/checkbox.d.ts +9 -0
- package/dist/react/react/components/checkbox.d.ts.map +1 -0
- package/dist/react/react/components/code.d.ts +6 -0
- package/dist/react/react/components/code.d.ts.map +1 -0
- package/dist/react/react/components/container.d.ts +8 -0
- package/dist/react/react/components/container.d.ts.map +1 -0
- package/dist/react/react/components/dialog.d.ts +28 -0
- package/dist/react/react/components/dialog.d.ts.map +1 -0
- package/dist/react/react/components/dropdown-menu.d.ts +32 -0
- package/dist/react/react/components/dropdown-menu.d.ts.map +1 -0
- package/dist/react/react/components/grid.d.ts +8 -0
- package/dist/react/react/components/grid.d.ts.map +1 -0
- package/dist/react/react/components/input.d.ts +4 -0
- package/dist/react/react/components/input.d.ts.map +1 -1
- package/dist/react/react/components/kbd.d.ts +6 -0
- package/dist/react/react/components/kbd.d.ts.map +1 -0
- package/dist/react/react/components/label.d.ts +7 -0
- package/dist/react/react/components/label.d.ts.map +1 -0
- package/dist/react/react/components/progress.d.ts +10 -0
- package/dist/react/react/components/progress.d.ts.map +1 -0
- package/dist/react/react/components/radio-group.d.ts +15 -0
- package/dist/react/react/components/radio-group.d.ts.map +1 -0
- package/dist/react/react/components/scroll-area.d.ts +8 -0
- package/dist/react/react/components/scroll-area.d.ts.map +1 -0
- package/dist/react/react/components/select.d.ts +29 -0
- package/dist/react/react/components/select.d.ts.map +1 -0
- package/dist/react/react/components/separator.d.ts +8 -0
- package/dist/react/react/components/separator.d.ts.map +1 -0
- package/dist/react/react/components/skeleton.d.ts +8 -0
- package/dist/react/react/components/skeleton.d.ts.map +1 -0
- package/dist/react/react/components/spinner.d.ts +7 -0
- package/dist/react/react/components/spinner.d.ts.map +1 -0
- package/dist/react/react/components/stack.d.ts +11 -0
- package/dist/react/react/components/stack.d.ts.map +1 -0
- package/dist/react/react/components/switch.d.ts +10 -0
- package/dist/react/react/components/switch.d.ts.map +1 -0
- package/dist/react/react/components/table.d.ts +27 -0
- package/dist/react/react/components/table.d.ts.map +1 -0
- package/dist/react/react/components/tabs.d.ts +21 -0
- package/dist/react/react/components/tabs.d.ts.map +1 -0
- package/dist/react/react/components/tag.d.ts +10 -0
- package/dist/react/react/components/tag.d.ts.map +1 -0
- package/dist/react/react/components/textarea.d.ts +11 -0
- package/dist/react/react/components/textarea.d.ts.map +1 -0
- package/dist/react/react/components/toast.d.ts +28 -0
- package/dist/react/react/components/toast.d.ts.map +1 -0
- package/dist/react/react/components/tooltip.d.ts +16 -0
- package/dist/react/react/components/tooltip.d.ts.map +1 -0
- package/dist/react/react/components/visually-hidden.d.ts +7 -0
- package/dist/react/react/components/visually-hidden.d.ts.map +1 -0
- package/dist/react/react/hooks/index.d.ts +5 -0
- package/dist/react/react/hooks/index.d.ts.map +1 -0
- package/dist/react/react/hooks/use-theme.d.ts +17 -0
- package/dist/react/react/hooks/use-theme.d.ts.map +1 -0
- package/dist/react/react/index.d.ts +30 -0
- package/dist/react/react/index.d.ts.map +1 -1
- package/dist/styles.css +1579 -2
- package/package.json +35 -4
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CZero CLI
|
|
4
|
+
* Generates CSS from user's theme configuration
|
|
5
|
+
*
|
|
6
|
+
* Usage: npx czero build [--config czero.config.js] [--output czero.css]
|
|
7
|
+
*/
|
|
8
|
+
import * as fs from "fs";
|
|
9
|
+
import * as path from "path";
|
|
10
|
+
import { fileURLToPath } from "url";
|
|
11
|
+
const __filename = fileURLToPath(import.meta.url);
|
|
12
|
+
const __dirname = path.dirname(__filename);
|
|
13
|
+
// Default theme values (fallback if user doesn't specify)
|
|
14
|
+
const defaultTheme = {
|
|
15
|
+
color: {
|
|
16
|
+
bg: { light: "0 0% 100%", dark: "220 40% 3%" },
|
|
17
|
+
fg: { light: "220 15% 10%", dark: "210 40% 96%" },
|
|
18
|
+
primary: { light: "222 47% 45%", dark: "210 80% 65%" },
|
|
19
|
+
primaryFg: { light: "0 0% 100%", dark: "220 40% 3%" },
|
|
20
|
+
secondary: { light: "220 10% 95%", dark: "220 8% 25%" },
|
|
21
|
+
secondaryFg: { light: "220 15% 10%", dark: "210 40% 96%" },
|
|
22
|
+
muted: { light: "220 10% 95%", dark: "220 8% 20%" },
|
|
23
|
+
mutedFg: { light: "220 10% 40%", dark: "220 10% 60%" },
|
|
24
|
+
danger: { light: "0 70% 55%", dark: "0 80% 65%" },
|
|
25
|
+
dangerFg: { light: "0 0% 100%", dark: "0 0% 100%" },
|
|
26
|
+
success: { light: "142 70% 45%", dark: "142 70% 55%" },
|
|
27
|
+
successFg: { light: "0 0% 100%", dark: "0 0% 100%" },
|
|
28
|
+
warning: { light: "38 92% 50%", dark: "38 92% 60%" },
|
|
29
|
+
warningFg: { light: "0 0% 100%", dark: "0 0% 0%" },
|
|
30
|
+
border: { light: "220 13% 90%", dark: "220 10% 20%" },
|
|
31
|
+
ring: { light: "222 47% 45%", dark: "210 80% 65%" },
|
|
32
|
+
},
|
|
33
|
+
radius: {
|
|
34
|
+
none: "0",
|
|
35
|
+
sm: "0.25rem",
|
|
36
|
+
md: "0.5rem",
|
|
37
|
+
lg: "0.75rem",
|
|
38
|
+
xl: "1rem",
|
|
39
|
+
full: "9999px",
|
|
40
|
+
},
|
|
41
|
+
shadow: {
|
|
42
|
+
none: "none",
|
|
43
|
+
sm: "0 1px 2px rgb(0 0 0 / 0.05)",
|
|
44
|
+
md: "0 2px 4px rgb(0 0 0 / 0.08)",
|
|
45
|
+
lg: "0 4px 12px rgb(0 0 0 / 0.12)",
|
|
46
|
+
},
|
|
47
|
+
spacing: {
|
|
48
|
+
xs: "0.25rem",
|
|
49
|
+
sm: "0.5rem",
|
|
50
|
+
md: "0.75rem",
|
|
51
|
+
lg: "1rem",
|
|
52
|
+
xl: "1.5rem",
|
|
53
|
+
"2xl": "2rem",
|
|
54
|
+
},
|
|
55
|
+
typography: {
|
|
56
|
+
fontFamily: "Inter, system-ui, -apple-system, sans-serif",
|
|
57
|
+
size: { xs: "0.75rem", sm: "0.875rem", md: "1rem", lg: "1.125rem", xl: "1.25rem" },
|
|
58
|
+
weight: { normal: "400", medium: "500", semibold: "600", bold: "700" },
|
|
59
|
+
lineHeight: { tight: "1.25", normal: "1.5", relaxed: "1.75" },
|
|
60
|
+
},
|
|
61
|
+
transition: { fast: "150ms ease", normal: "200ms ease", slow: "300ms ease" },
|
|
62
|
+
};
|
|
63
|
+
function deepMerge(target, source) {
|
|
64
|
+
const result = { ...target };
|
|
65
|
+
for (const key of Object.keys(source)) {
|
|
66
|
+
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
67
|
+
result[key] = deepMerge(target[key] || {}, source[key]);
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
result[key] = source[key];
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
return result;
|
|
74
|
+
}
|
|
75
|
+
function generateTokensCSS(theme) {
|
|
76
|
+
const lightVars = [];
|
|
77
|
+
const darkVars = [];
|
|
78
|
+
// Colors
|
|
79
|
+
for (const [name, values] of Object.entries(theme.color)) {
|
|
80
|
+
if (typeof values === "object" && "light" in values) {
|
|
81
|
+
lightVars.push(` --cz-color-${name}: ${values.light};`);
|
|
82
|
+
darkVars.push(` --cz-color-${name}: ${values.dark};`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Radius
|
|
86
|
+
for (const [name, value] of Object.entries(theme.radius)) {
|
|
87
|
+
lightVars.push(` --cz-radius-${name}: ${value};`);
|
|
88
|
+
}
|
|
89
|
+
// Shadow
|
|
90
|
+
for (const [name, value] of Object.entries(theme.shadow)) {
|
|
91
|
+
lightVars.push(` --cz-shadow-${name}: ${value};`);
|
|
92
|
+
}
|
|
93
|
+
// Spacing
|
|
94
|
+
for (const [name, value] of Object.entries(theme.spacing)) {
|
|
95
|
+
lightVars.push(` --cz-spacing-${name}: ${value};`);
|
|
96
|
+
}
|
|
97
|
+
// Typography
|
|
98
|
+
lightVars.push(` --cz-font-fontFamily: ${theme.typography.fontFamily};`);
|
|
99
|
+
for (const [name, value] of Object.entries(theme.typography.size)) {
|
|
100
|
+
lightVars.push(` --cz-font-size-${name}: ${value};`);
|
|
101
|
+
}
|
|
102
|
+
for (const [name, value] of Object.entries(theme.typography.weight)) {
|
|
103
|
+
lightVars.push(` --cz-font-weight-${name}: ${value};`);
|
|
104
|
+
}
|
|
105
|
+
for (const [name, value] of Object.entries(theme.typography.lineHeight)) {
|
|
106
|
+
lightVars.push(` --cz-font-lineHeight-${name}: ${value};`);
|
|
107
|
+
}
|
|
108
|
+
// Transitions
|
|
109
|
+
for (const [name, value] of Object.entries(theme.transition)) {
|
|
110
|
+
lightVars.push(` --cz-transition-${name}: ${value};`);
|
|
111
|
+
}
|
|
112
|
+
return `/**
|
|
113
|
+
* CZero Design Tokens
|
|
114
|
+
* Generated from czero.config.js
|
|
115
|
+
*/
|
|
116
|
+
|
|
117
|
+
:root {
|
|
118
|
+
${lightVars.join("\n")}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
.dark {
|
|
122
|
+
${darkVars.join("\n")}
|
|
123
|
+
}
|
|
124
|
+
`;
|
|
125
|
+
}
|
|
126
|
+
function getComponentsCSS() {
|
|
127
|
+
// Try multiple possible locations
|
|
128
|
+
const possiblePaths = [
|
|
129
|
+
path.join(__dirname, "components.css"), // dist/cli/../components.css = dist/components.css
|
|
130
|
+
path.join(__dirname, "../components.css"), // dist/components.css
|
|
131
|
+
path.join(__dirname, "../dist/components.css"), // from root
|
|
132
|
+
path.join(__dirname, "../../dist/components.css"), // from cli folder
|
|
133
|
+
path.join(__dirname, "../src/core/styles/components.css"), // dev mode
|
|
134
|
+
path.join(__dirname, "../../src/core/styles/components.css"), // dev mode from cli
|
|
135
|
+
];
|
|
136
|
+
for (const p of possiblePaths) {
|
|
137
|
+
if (fs.existsSync(p)) {
|
|
138
|
+
return fs.readFileSync(p, "utf-8");
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
console.error("Error: Could not find components.css");
|
|
142
|
+
console.error("Searched paths:", possiblePaths);
|
|
143
|
+
process.exit(1);
|
|
144
|
+
}
|
|
145
|
+
function getResetCSS() {
|
|
146
|
+
const possiblePaths = [
|
|
147
|
+
path.join(__dirname, "reset.css"),
|
|
148
|
+
path.join(__dirname, "../reset.css"),
|
|
149
|
+
path.join(__dirname, "../dist/reset.css"),
|
|
150
|
+
path.join(__dirname, "../../dist/reset.css"),
|
|
151
|
+
path.join(__dirname, "../src/core/styles/reset.css"),
|
|
152
|
+
path.join(__dirname, "../../src/core/styles/reset.css"),
|
|
153
|
+
];
|
|
154
|
+
for (const p of possiblePaths) {
|
|
155
|
+
if (fs.existsSync(p)) {
|
|
156
|
+
return fs.readFileSync(p, "utf-8");
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
// Minimal fallback reset
|
|
160
|
+
return `*, *::before, *::after { box-sizing: border-box; }
|
|
161
|
+
* { margin: 0; }
|
|
162
|
+
body { line-height: 1.5; -webkit-font-smoothing: antialiased; }
|
|
163
|
+
button, input, textarea, select { font: inherit; }
|
|
164
|
+
`;
|
|
165
|
+
}
|
|
166
|
+
async function loadUserConfig(configPath) {
|
|
167
|
+
const absolutePath = path.resolve(process.cwd(), configPath);
|
|
168
|
+
if (!fs.existsSync(absolutePath)) {
|
|
169
|
+
console.log(`No config found at ${configPath}, using defaults...`);
|
|
170
|
+
return {};
|
|
171
|
+
}
|
|
172
|
+
try {
|
|
173
|
+
// Import the config file
|
|
174
|
+
const config = await import(`file://${absolutePath}`);
|
|
175
|
+
return config.default || config.theme || config;
|
|
176
|
+
}
|
|
177
|
+
catch (error) {
|
|
178
|
+
console.error(`Error loading config: ${error}`);
|
|
179
|
+
return {};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
async function main() {
|
|
183
|
+
const args = process.argv.slice(2);
|
|
184
|
+
// Parse arguments
|
|
185
|
+
let configPath = "czero.config.js";
|
|
186
|
+
let outputPath = "czero.css";
|
|
187
|
+
let useNewSystem = false; // Flag for new generator-based system
|
|
188
|
+
let legacyMode = false;
|
|
189
|
+
for (let i = 0; i < args.length; i++) {
|
|
190
|
+
if (args[i] === "--config" && args[i + 1]) {
|
|
191
|
+
configPath = args[i + 1];
|
|
192
|
+
i++;
|
|
193
|
+
}
|
|
194
|
+
else if (args[i] === "--output" && args[i + 1]) {
|
|
195
|
+
outputPath = args[i + 1];
|
|
196
|
+
i++;
|
|
197
|
+
}
|
|
198
|
+
else if (args[i] === "--new" || args[i] === "--v2") {
|
|
199
|
+
useNewSystem = true;
|
|
200
|
+
}
|
|
201
|
+
else if (args[i] === "--legacy") {
|
|
202
|
+
legacyMode = true;
|
|
203
|
+
}
|
|
204
|
+
else if (args[i] === "build") {
|
|
205
|
+
// Just the build command, continue
|
|
206
|
+
}
|
|
207
|
+
else if (args[i] === "--help" || args[i] === "-h") {
|
|
208
|
+
console.log(`
|
|
209
|
+
CZero CLI - Generate CSS from your theme configuration
|
|
210
|
+
|
|
211
|
+
Usage:
|
|
212
|
+
npx czero build [options]
|
|
213
|
+
|
|
214
|
+
Options:
|
|
215
|
+
--config <path> Path to config file (default: czero.config.js)
|
|
216
|
+
--output <path> Output CSS file path (default: czero.css)
|
|
217
|
+
--new, --v2 Use new generator-based system (supports component tokens)
|
|
218
|
+
--legacy Force legacy mode (no component generation)
|
|
219
|
+
--help, -h Show this help message
|
|
220
|
+
|
|
221
|
+
Example:
|
|
222
|
+
npx czero build --config my-theme.js --output src/styles/czero.css
|
|
223
|
+
npx czero build --new --config czero.config.js --output dist/czero.css
|
|
224
|
+
`);
|
|
225
|
+
process.exit(0);
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
console.log("🎨 CZero CSS Generator");
|
|
229
|
+
console.log(` Config: ${configPath}`);
|
|
230
|
+
console.log(` Output: ${outputPath}`);
|
|
231
|
+
console.log(` Mode: ${useNewSystem ? "v2 (generators)" : "v1 (legacy)"}`);
|
|
232
|
+
console.log("");
|
|
233
|
+
// Load user config and merge with defaults
|
|
234
|
+
const userConfig = await loadUserConfig(configPath);
|
|
235
|
+
const theme = deepMerge(defaultTheme, userConfig);
|
|
236
|
+
// Generate CSS
|
|
237
|
+
const resetCSS = getResetCSS();
|
|
238
|
+
const tokensCSS = generateTokensCSS(theme);
|
|
239
|
+
let componentsCSS;
|
|
240
|
+
if (useNewSystem && !legacyMode) {
|
|
241
|
+
// New generator-based system
|
|
242
|
+
try {
|
|
243
|
+
const { buildComponentsCSS } = await import("./build-css.js");
|
|
244
|
+
const { generateUtilitiesCSS } = await import("./generators/index.js");
|
|
245
|
+
console.log(" Using v2 generator system...");
|
|
246
|
+
// Generate component CSS from config
|
|
247
|
+
componentsCSS = buildComponentsCSS(userConfig);
|
|
248
|
+
// Add utilities
|
|
249
|
+
componentsCSS += "\n" + generateUtilitiesCSS();
|
|
250
|
+
// Add remaining components from legacy CSS (those not yet migrated)
|
|
251
|
+
const legacyCSS = getLegacyComponentsCSS();
|
|
252
|
+
componentsCSS += "\n" + legacyCSS;
|
|
253
|
+
}
|
|
254
|
+
catch (err) {
|
|
255
|
+
console.warn("⚠️ Failed to load new system, falling back to legacy mode");
|
|
256
|
+
console.warn(` Error: ${err}`);
|
|
257
|
+
componentsCSS = getComponentsCSS();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
else {
|
|
261
|
+
// Legacy mode - use static CSS file
|
|
262
|
+
componentsCSS = getComponentsCSS();
|
|
263
|
+
}
|
|
264
|
+
const finalCSS = `${resetCSS}
|
|
265
|
+
${tokensCSS}
|
|
266
|
+
${componentsCSS}`;
|
|
267
|
+
// Write output
|
|
268
|
+
fs.writeFileSync(outputPath, finalCSS);
|
|
269
|
+
console.log(`✅ Generated ${outputPath}`);
|
|
270
|
+
console.log(` ${finalCSS.split("\n").length} lines`);
|
|
271
|
+
}
|
|
272
|
+
/**
|
|
273
|
+
* Get legacy components CSS, excluding migrated components
|
|
274
|
+
*/
|
|
275
|
+
function getLegacyComponentsCSS() {
|
|
276
|
+
const componentsCSS = getComponentsCSS();
|
|
277
|
+
// Components that are now generated - their CSS should be excluded
|
|
278
|
+
const migratedComponents = ["BUTTON", "INPUT", "CARD", "SWITCH", "CHECKBOX"];
|
|
279
|
+
let result = componentsCSS;
|
|
280
|
+
// Remove sections for migrated components
|
|
281
|
+
for (const component of migratedComponents) {
|
|
282
|
+
// Match /* ===== BUTTON ===== */ sections
|
|
283
|
+
const sectionRegex = new RegExp(`\\/\\*\\s*=====\\s*${component}\\s*=====\\s*\\*\\/[\\s\\S]*?(?=\\/\\*\\s*=====|$)`, "g");
|
|
284
|
+
result = result.replace(sectionRegex, "");
|
|
285
|
+
}
|
|
286
|
+
return result;
|
|
287
|
+
}
|
|
288
|
+
main().catch(console.error);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CZero Token Resolver
|
|
3
|
+
* Parses $token-name syntax and resolves to CSS variable references
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Resolve a token value to its CSS equivalent
|
|
7
|
+
*
|
|
8
|
+
* Examples:
|
|
9
|
+
* - "$color-primary" → "hsl(var(--cz-color-primary))"
|
|
10
|
+
* - "$radius-md" → "var(--cz-radius-md)"
|
|
11
|
+
* - "$font-sm" → "var(--cz-font-size-sm)"
|
|
12
|
+
* - "0.5rem" → "0.5rem" (literal, no change)
|
|
13
|
+
* - "$color-primary / 0.5" → "hsl(var(--cz-color-primary) / 0.5)"
|
|
14
|
+
*/
|
|
15
|
+
export declare function resolveToken(value: string | undefined): string;
|
|
16
|
+
/**
|
|
17
|
+
* Resolve all token references in a styles object
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveTokensInObject<T extends Record<string, any>>(obj: T, colorProperties?: string[]): T;
|
|
20
|
+
/**
|
|
21
|
+
* Generate CSS variable declaration
|
|
22
|
+
*/
|
|
23
|
+
export declare function cssVar(name: string, value: string): string;
|
|
24
|
+
/**
|
|
25
|
+
* Generate CSS variable reference
|
|
26
|
+
*/
|
|
27
|
+
export declare function cssVarRef(name: string): string;
|
|
28
|
+
/**
|
|
29
|
+
* Check if a value is a token reference
|
|
30
|
+
*/
|
|
31
|
+
export declare function isTokenReference(value: string): boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Convert camelCase to kebab-case
|
|
34
|
+
*/
|
|
35
|
+
export declare function toKebabCase(str: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Convert component property name to CSS variable name
|
|
38
|
+
*
|
|
39
|
+
* Examples:
|
|
40
|
+
* - ("button", "paddingX", "sm") → "--cz-btn-padding-x-sm"
|
|
41
|
+
* - ("button", "height", "md") → "--cz-btn-height-md"
|
|
42
|
+
* - ("input", "borderRadius") → "--cz-input-border-radius"
|
|
43
|
+
*/
|
|
44
|
+
export declare function componentVarName(component: string, property: string, size?: string): string;
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CZero Token Resolver
|
|
3
|
+
* Parses $token-name syntax and resolves to CSS variable references
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Resolve a token value to its CSS equivalent
|
|
7
|
+
*
|
|
8
|
+
* Examples:
|
|
9
|
+
* - "$color-primary" → "hsl(var(--cz-color-primary))"
|
|
10
|
+
* - "$radius-md" → "var(--cz-radius-md)"
|
|
11
|
+
* - "$font-sm" → "var(--cz-font-size-sm)"
|
|
12
|
+
* - "0.5rem" → "0.5rem" (literal, no change)
|
|
13
|
+
* - "$color-primary / 0.5" → "hsl(var(--cz-color-primary) / 0.5)"
|
|
14
|
+
*/
|
|
15
|
+
export function resolveToken(value) {
|
|
16
|
+
if (!value)
|
|
17
|
+
return "";
|
|
18
|
+
// If it doesn't start with $, return as-is (literal value)
|
|
19
|
+
if (!value.startsWith("$")) {
|
|
20
|
+
return value;
|
|
21
|
+
}
|
|
22
|
+
// Handle opacity syntax: "$color-primary / 0.5"
|
|
23
|
+
const opacityMatch = value.match(/^\$([a-zA-Z-]+)\s*\/\s*(.+)$/);
|
|
24
|
+
if (opacityMatch) {
|
|
25
|
+
const [, tokenName, opacity] = opacityMatch;
|
|
26
|
+
const cssVar = tokenNameToCssVar(tokenName);
|
|
27
|
+
// Color tokens need hsl() wrapper
|
|
28
|
+
if (tokenName.startsWith("color-")) {
|
|
29
|
+
return `hsl(var(${cssVar}) / ${opacity})`;
|
|
30
|
+
}
|
|
31
|
+
return `var(${cssVar}) / ${opacity}`;
|
|
32
|
+
}
|
|
33
|
+
// Simple token reference: "$color-primary"
|
|
34
|
+
const tokenName = value.slice(1); // Remove $
|
|
35
|
+
const cssVar = tokenNameToCssVar(tokenName);
|
|
36
|
+
// Color tokens need hsl() wrapper
|
|
37
|
+
if (tokenName.startsWith("color-")) {
|
|
38
|
+
return `hsl(var(${cssVar}))`;
|
|
39
|
+
}
|
|
40
|
+
return `var(${cssVar})`;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Convert token name to CSS variable name
|
|
44
|
+
*
|
|
45
|
+
* Examples:
|
|
46
|
+
* - "color-primary" → "--cz-color-primary"
|
|
47
|
+
* - "font-sm" → "--cz-font-size-sm"
|
|
48
|
+
* - "font-medium" → "--cz-font-weight-medium"
|
|
49
|
+
* - "radius-md" → "--cz-radius-md"
|
|
50
|
+
* - "spacing-lg" → "--cz-spacing-lg"
|
|
51
|
+
* - "transition-fast" → "--cz-transition-fast"
|
|
52
|
+
*/
|
|
53
|
+
function tokenNameToCssVar(tokenName) {
|
|
54
|
+
// Handle font shorthand tokens
|
|
55
|
+
if (tokenName.startsWith("font-")) {
|
|
56
|
+
const fontPart = tokenName.slice(5); // Remove "font-"
|
|
57
|
+
// Size tokens: xs, sm, md, lg, xl
|
|
58
|
+
if (["xs", "sm", "md", "lg", "xl"].includes(fontPart)) {
|
|
59
|
+
return `--cz-font-size-${fontPart}`;
|
|
60
|
+
}
|
|
61
|
+
// Weight tokens: normal, medium, semibold, bold
|
|
62
|
+
if (["normal", "medium", "semibold", "bold"].includes(fontPart)) {
|
|
63
|
+
return `--cz-font-weight-${fontPart}`;
|
|
64
|
+
}
|
|
65
|
+
// Line height tokens: tight, normal, relaxed
|
|
66
|
+
if (["tight", "relaxed"].includes(fontPart)) {
|
|
67
|
+
return `--cz-font-lineHeight-${fontPart}`;
|
|
68
|
+
}
|
|
69
|
+
// Default: pass through
|
|
70
|
+
return `--cz-font-${fontPart}`;
|
|
71
|
+
}
|
|
72
|
+
return `--cz-${tokenName}`;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Resolve all token references in a styles object
|
|
76
|
+
*/
|
|
77
|
+
export function resolveTokensInObject(obj, colorProperties = ["bg", "color", "borderColor", "indicatorColor", "thumbBg", "trackColor"]) {
|
|
78
|
+
const result = {};
|
|
79
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
80
|
+
if (typeof value === "string") {
|
|
81
|
+
result[key] = resolveToken(value);
|
|
82
|
+
}
|
|
83
|
+
else if (typeof value === "object" && value !== null) {
|
|
84
|
+
result[key] = resolveTokensInObject(value, colorProperties);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
result[key] = value;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return result;
|
|
91
|
+
}
|
|
92
|
+
/**
|
|
93
|
+
* Generate CSS variable declaration
|
|
94
|
+
*/
|
|
95
|
+
export function cssVar(name, value) {
|
|
96
|
+
return ` --cz-${name}: ${value};`;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Generate CSS variable reference
|
|
100
|
+
*/
|
|
101
|
+
export function cssVarRef(name) {
|
|
102
|
+
return `var(--cz-${name})`;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Check if a value is a token reference
|
|
106
|
+
*/
|
|
107
|
+
export function isTokenReference(value) {
|
|
108
|
+
return value.startsWith("$");
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Convert camelCase to kebab-case
|
|
112
|
+
*/
|
|
113
|
+
export function toKebabCase(str) {
|
|
114
|
+
return str.replace(/([a-z])([A-Z])/g, "$1-$2").toLowerCase();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Convert component property name to CSS variable name
|
|
118
|
+
*
|
|
119
|
+
* Examples:
|
|
120
|
+
* - ("button", "paddingX", "sm") → "--cz-btn-padding-x-sm"
|
|
121
|
+
* - ("button", "height", "md") → "--cz-btn-height-md"
|
|
122
|
+
* - ("input", "borderRadius") → "--cz-input-border-radius"
|
|
123
|
+
*/
|
|
124
|
+
export function componentVarName(component, property, size) {
|
|
125
|
+
// Component shorthand mapping
|
|
126
|
+
const componentShorthand = {
|
|
127
|
+
button: "btn",
|
|
128
|
+
dropdownMenu: "dropdown",
|
|
129
|
+
scrollArea: "scroll",
|
|
130
|
+
};
|
|
131
|
+
const compName = componentShorthand[component] || component;
|
|
132
|
+
const propName = toKebabCase(property);
|
|
133
|
+
if (size) {
|
|
134
|
+
return `--cz-${compName}-${propName}-${size}`;
|
|
135
|
+
}
|
|
136
|
+
return `--cz-${compName}-${propName}`;
|
|
137
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CZero Deep Merge Utility
|
|
3
|
+
* Properly merges nested config objects
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Deep merge two objects, with source values overriding target
|
|
7
|
+
* - Objects are recursively merged
|
|
8
|
+
* - Arrays are replaced (not merged)
|
|
9
|
+
* - Null/undefined in source removes the target value
|
|
10
|
+
*/
|
|
11
|
+
export declare function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T;
|
|
12
|
+
/**
|
|
13
|
+
* Deep merge multiple objects (left to right)
|
|
14
|
+
*/
|
|
15
|
+
export declare function deepMergeAll<T extends Record<string, any>>(...objects: Partial<T>[]): T;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CZero Deep Merge Utility
|
|
3
|
+
* Properly merges nested config objects
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Deep merge two objects, with source values overriding target
|
|
7
|
+
* - Objects are recursively merged
|
|
8
|
+
* - Arrays are replaced (not merged)
|
|
9
|
+
* - Null/undefined in source removes the target value
|
|
10
|
+
*/
|
|
11
|
+
export function deepMerge(target, source) {
|
|
12
|
+
const result = { ...target };
|
|
13
|
+
for (const key of Object.keys(source)) {
|
|
14
|
+
const sourceValue = source[key];
|
|
15
|
+
const targetValue = target[key];
|
|
16
|
+
// If source explicitly sets null/undefined, use it
|
|
17
|
+
if (sourceValue === null || sourceValue === undefined) {
|
|
18
|
+
result[key] = sourceValue;
|
|
19
|
+
continue;
|
|
20
|
+
}
|
|
21
|
+
// If both are objects (not arrays), merge recursively
|
|
22
|
+
if (typeof sourceValue === "object" &&
|
|
23
|
+
!Array.isArray(sourceValue) &&
|
|
24
|
+
typeof targetValue === "object" &&
|
|
25
|
+
!Array.isArray(targetValue) &&
|
|
26
|
+
targetValue !== null) {
|
|
27
|
+
result[key] = deepMerge(targetValue, sourceValue);
|
|
28
|
+
}
|
|
29
|
+
else {
|
|
30
|
+
// Otherwise, source value wins
|
|
31
|
+
result[key] = sourceValue;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return result;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Deep merge multiple objects (left to right)
|
|
38
|
+
*/
|
|
39
|
+
export function deepMergeAll(...objects) {
|
|
40
|
+
return objects.reduce((acc, obj) => deepMerge(acc, obj), {});
|
|
41
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CZero Config Validator
|
|
3
|
+
* Validates user configuration and provides helpful error messages
|
|
4
|
+
*/
|
|
5
|
+
import type { CZeroConfig } from "../src/core/types/config";
|
|
6
|
+
export interface ValidationResult {
|
|
7
|
+
valid: boolean;
|
|
8
|
+
warnings: string[];
|
|
9
|
+
errors: string[];
|
|
10
|
+
config: CZeroConfig;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Validate user config and return normalized version
|
|
14
|
+
*/
|
|
15
|
+
export declare function validateConfig(config: unknown): ValidationResult;
|
|
16
|
+
/**
|
|
17
|
+
* Print validation results to console
|
|
18
|
+
*/
|
|
19
|
+
export declare function printValidationResults(result: ValidationResult): void;
|