czero 0.1.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 +169 -0
- package/dist/cli/index.js +218 -0
- package/dist/components.css +336 -0
- package/dist/react/core/build-tokens.d.ts +6 -0
- package/dist/react/core/build-tokens.d.ts.map +1 -0
- package/dist/react/core/theme.config.d.ts +122 -0
- package/dist/react/core/theme.config.d.ts.map +1 -0
- package/dist/react/index.cjs +90 -0
- package/dist/react/index.cjs.map +1 -0
- package/dist/react/index.d.ts +35 -0
- package/dist/react/index.d.ts.map +1 -0
- package/dist/react/index.js +66 -0
- package/dist/react/index.js.map +1 -0
- package/dist/react/react/components/badge.d.ts +7 -0
- package/dist/react/react/components/badge.d.ts.map +1 -0
- package/dist/react/react/components/button.d.ts +8 -0
- package/dist/react/react/components/button.d.ts.map +1 -0
- package/dist/react/react/components/card.d.ts +12 -0
- package/dist/react/react/components/card.d.ts.map +1 -0
- package/dist/react/react/components/input.d.ts +8 -0
- package/dist/react/react/components/input.d.ts.map +1 -0
- package/dist/react/react/index.d.ts +8 -0
- package/dist/react/react/index.d.ts.map +1 -0
- package/dist/react/react/lib/cn.d.ts +7 -0
- package/dist/react/react/lib/cn.d.ts.map +1 -0
- package/dist/reset.css +21 -0
- package/dist/styles.css +431 -0
- package/package.json +61 -0
package/README.md
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# CZero
|
|
2
|
+
|
|
3
|
+
A lightweight, design-token-driven React component library.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- 🎨 **Design Token Driven** - Single config file controls entire look & feel
|
|
8
|
+
- âš¡ **No Runtime Dependencies** - Precompiled CSS, no Tailwind required
|
|
9
|
+
- 🌙 **Dark Mode Ready** - Add `.dark` class and all components adapt
|
|
10
|
+
- ♿ **Accessible** - Built with accessibility in mind
|
|
11
|
+
|
|
12
|
+
## Quick Start
|
|
13
|
+
|
|
14
|
+
### 1. Install
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
npm install czero
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
### 2. Create Theme Config
|
|
21
|
+
|
|
22
|
+
Create `czero.config.js` in your project root:
|
|
23
|
+
|
|
24
|
+
```js
|
|
25
|
+
// czero.config.js
|
|
26
|
+
export default {
|
|
27
|
+
color: {
|
|
28
|
+
primary: { light: "222 47% 45%", dark: "210 80% 65%" },
|
|
29
|
+
primaryFg: { light: "0 0% 100%", dark: "220 40% 3%" },
|
|
30
|
+
// Override any token...
|
|
31
|
+
},
|
|
32
|
+
radius: {
|
|
33
|
+
md: "0.5rem",
|
|
34
|
+
lg: "0.75rem",
|
|
35
|
+
},
|
|
36
|
+
typography: {
|
|
37
|
+
fontFamily: "Inter, system-ui, sans-serif",
|
|
38
|
+
},
|
|
39
|
+
};
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
### 3. Generate CSS
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
npx czero build
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
This creates `czero.css` with your custom tokens + component styles.
|
|
49
|
+
|
|
50
|
+
Options:
|
|
51
|
+
- `--config <path>` - Config file path (default: `czero.config.js`)
|
|
52
|
+
- `--output <path>` - Output CSS path (default: `czero.css`)
|
|
53
|
+
|
|
54
|
+
### 4. Import & Use
|
|
55
|
+
|
|
56
|
+
```jsx
|
|
57
|
+
// Import generated CSS
|
|
58
|
+
import "./czero.css";
|
|
59
|
+
|
|
60
|
+
// Import components
|
|
61
|
+
import { Button, Input, Card, Badge } from "czero/react";
|
|
62
|
+
|
|
63
|
+
function App() {
|
|
64
|
+
return (
|
|
65
|
+
<Card>
|
|
66
|
+
<Card.Header>
|
|
67
|
+
<Card.Title>Hello CZero</Card.Title>
|
|
68
|
+
</Card.Header>
|
|
69
|
+
<Card.Body>
|
|
70
|
+
<Button variant="primary">Click me</Button>
|
|
71
|
+
</Card.Body>
|
|
72
|
+
</Card>
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
## Components
|
|
78
|
+
|
|
79
|
+
### Button
|
|
80
|
+
|
|
81
|
+
```jsx
|
|
82
|
+
<Button variant="primary">Primary</Button>
|
|
83
|
+
<Button variant="secondary">Secondary</Button>
|
|
84
|
+
<Button variant="outline">Outline</Button>
|
|
85
|
+
<Button variant="ghost">Ghost</Button>
|
|
86
|
+
<Button variant="danger">Danger</Button>
|
|
87
|
+
|
|
88
|
+
<Button size="sm">Small</Button>
|
|
89
|
+
<Button size="md">Medium</Button>
|
|
90
|
+
<Button size="lg">Large</Button>
|
|
91
|
+
|
|
92
|
+
<Button loading>Loading...</Button>
|
|
93
|
+
<Button disabled>Disabled</Button>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### Input
|
|
97
|
+
|
|
98
|
+
```jsx
|
|
99
|
+
<Input placeholder="Enter text..." />
|
|
100
|
+
<Input label="Email" type="email" />
|
|
101
|
+
<Input label="Password" error="Required" />
|
|
102
|
+
<Input size="sm" />
|
|
103
|
+
<Input size="lg" />
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### Card
|
|
107
|
+
|
|
108
|
+
```jsx
|
|
109
|
+
<Card>
|
|
110
|
+
<Card.Header>
|
|
111
|
+
<Card.Title>Title</Card.Title>
|
|
112
|
+
<Card.Description>Description text</Card.Description>
|
|
113
|
+
</Card.Header>
|
|
114
|
+
<Card.Body>Content goes here</Card.Body>
|
|
115
|
+
<Card.Footer>
|
|
116
|
+
<Button variant="ghost">Cancel</Button>
|
|
117
|
+
<Button>Save</Button>
|
|
118
|
+
</Card.Footer>
|
|
119
|
+
</Card>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### Badge
|
|
123
|
+
|
|
124
|
+
```jsx
|
|
125
|
+
<Badge>Default</Badge>
|
|
126
|
+
<Badge variant="primary">Primary</Badge>
|
|
127
|
+
<Badge variant="success">Success</Badge>
|
|
128
|
+
<Badge variant="danger">Danger</Badge>
|
|
129
|
+
<Badge variant="warning">Warning</Badge>
|
|
130
|
+
<Badge variant="outline">Outline</Badge>
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Dark Mode
|
|
134
|
+
|
|
135
|
+
Add the `.dark` class to your root element:
|
|
136
|
+
|
|
137
|
+
```html
|
|
138
|
+
<html class="dark">
|
|
139
|
+
...
|
|
140
|
+
</html>
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
All components automatically adapt to the dark color scheme.
|
|
144
|
+
|
|
145
|
+
## Theming
|
|
146
|
+
|
|
147
|
+
All design tokens use the `--cz-*` prefix. Override any token in your CSS:
|
|
148
|
+
|
|
149
|
+
```css
|
|
150
|
+
:root {
|
|
151
|
+
--cz-color-primary: 280 70% 50%; /* Purple */
|
|
152
|
+
--cz-radius-md: 1rem; /* More rounded */
|
|
153
|
+
}
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## Available Tokens
|
|
157
|
+
|
|
158
|
+
| Category | Tokens |
|
|
159
|
+
|----------|--------|
|
|
160
|
+
| Colors | `bg`, `fg`, `primary`, `secondary`, `muted`, `danger`, `success`, `warning`, `border`, `ring` |
|
|
161
|
+
| Radius | `none`, `sm`, `md`, `lg`, `xl`, `full` |
|
|
162
|
+
| Spacing | `xs`, `sm`, `md`, `lg`, `xl`, `2xl` |
|
|
163
|
+
| Typography | `fontFamily`, `size-*`, `weight-*`, `lineHeight-*` |
|
|
164
|
+
| Shadow | `none`, `sm`, `md`, `lg` |
|
|
165
|
+
| Transition | `fast`, `normal`, `slow` |
|
|
166
|
+
|
|
167
|
+
## License
|
|
168
|
+
|
|
169
|
+
MIT
|
|
@@ -0,0 +1,218 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// cli/index.ts
|
|
4
|
+
import * as fs from "fs";
|
|
5
|
+
import * as path from "path";
|
|
6
|
+
import { fileURLToPath } from "url";
|
|
7
|
+
var __filename = fileURLToPath(import.meta.url);
|
|
8
|
+
var __dirname = path.dirname(__filename);
|
|
9
|
+
var defaultTheme = {
|
|
10
|
+
color: {
|
|
11
|
+
bg: { light: "0 0% 100%", dark: "220 40% 3%" },
|
|
12
|
+
fg: { light: "220 15% 10%", dark: "210 40% 96%" },
|
|
13
|
+
primary: { light: "222 47% 45%", dark: "210 80% 65%" },
|
|
14
|
+
primaryFg: { light: "0 0% 100%", dark: "220 40% 3%" },
|
|
15
|
+
secondary: { light: "220 10% 95%", dark: "220 8% 25%" },
|
|
16
|
+
secondaryFg: { light: "220 15% 10%", dark: "210 40% 96%" },
|
|
17
|
+
muted: { light: "220 10% 95%", dark: "220 8% 20%" },
|
|
18
|
+
mutedFg: { light: "220 10% 40%", dark: "220 10% 60%" },
|
|
19
|
+
danger: { light: "0 70% 55%", dark: "0 80% 65%" },
|
|
20
|
+
dangerFg: { light: "0 0% 100%", dark: "0 0% 100%" },
|
|
21
|
+
success: { light: "142 70% 45%", dark: "142 70% 55%" },
|
|
22
|
+
successFg: { light: "0 0% 100%", dark: "0 0% 100%" },
|
|
23
|
+
warning: { light: "38 92% 50%", dark: "38 92% 60%" },
|
|
24
|
+
warningFg: { light: "0 0% 100%", dark: "0 0% 0%" },
|
|
25
|
+
border: { light: "220 13% 90%", dark: "220 10% 20%" },
|
|
26
|
+
ring: { light: "222 47% 45%", dark: "210 80% 65%" }
|
|
27
|
+
},
|
|
28
|
+
radius: {
|
|
29
|
+
none: "0",
|
|
30
|
+
sm: "0.25rem",
|
|
31
|
+
md: "0.5rem",
|
|
32
|
+
lg: "0.75rem",
|
|
33
|
+
xl: "1rem",
|
|
34
|
+
full: "9999px"
|
|
35
|
+
},
|
|
36
|
+
shadow: {
|
|
37
|
+
none: "none",
|
|
38
|
+
sm: "0 1px 2px rgb(0 0 0 / 0.05)",
|
|
39
|
+
md: "0 2px 4px rgb(0 0 0 / 0.08)",
|
|
40
|
+
lg: "0 4px 12px rgb(0 0 0 / 0.12)"
|
|
41
|
+
},
|
|
42
|
+
spacing: {
|
|
43
|
+
xs: "0.25rem",
|
|
44
|
+
sm: "0.5rem",
|
|
45
|
+
md: "0.75rem",
|
|
46
|
+
lg: "1rem",
|
|
47
|
+
xl: "1.5rem",
|
|
48
|
+
"2xl": "2rem"
|
|
49
|
+
},
|
|
50
|
+
typography: {
|
|
51
|
+
fontFamily: "Inter, system-ui, -apple-system, sans-serif",
|
|
52
|
+
size: { xs: "0.75rem", sm: "0.875rem", md: "1rem", lg: "1.125rem", xl: "1.25rem" },
|
|
53
|
+
weight: { normal: "400", medium: "500", semibold: "600", bold: "700" },
|
|
54
|
+
lineHeight: { tight: "1.25", normal: "1.5", relaxed: "1.75" }
|
|
55
|
+
},
|
|
56
|
+
transition: { fast: "150ms ease", normal: "200ms ease", slow: "300ms ease" }
|
|
57
|
+
};
|
|
58
|
+
function deepMerge(target, source) {
|
|
59
|
+
const result = { ...target };
|
|
60
|
+
for (const key of Object.keys(source)) {
|
|
61
|
+
if (source[key] && typeof source[key] === "object" && !Array.isArray(source[key])) {
|
|
62
|
+
result[key] = deepMerge(target[key] || {}, source[key]);
|
|
63
|
+
} else {
|
|
64
|
+
result[key] = source[key];
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return result;
|
|
68
|
+
}
|
|
69
|
+
function generateTokensCSS(theme) {
|
|
70
|
+
const lightVars = [];
|
|
71
|
+
const darkVars = [];
|
|
72
|
+
for (const [name, values] of Object.entries(theme.color)) {
|
|
73
|
+
if (typeof values === "object" && "light" in values) {
|
|
74
|
+
lightVars.push(` --cz-color-${name}: ${values.light};`);
|
|
75
|
+
darkVars.push(` --cz-color-${name}: ${values.dark};`);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
for (const [name, value] of Object.entries(theme.radius)) {
|
|
79
|
+
lightVars.push(` --cz-radius-${name}: ${value};`);
|
|
80
|
+
}
|
|
81
|
+
for (const [name, value] of Object.entries(theme.shadow)) {
|
|
82
|
+
lightVars.push(` --cz-shadow-${name}: ${value};`);
|
|
83
|
+
}
|
|
84
|
+
for (const [name, value] of Object.entries(theme.spacing)) {
|
|
85
|
+
lightVars.push(` --cz-spacing-${name}: ${value};`);
|
|
86
|
+
}
|
|
87
|
+
lightVars.push(` --cz-font-fontFamily: ${theme.typography.fontFamily};`);
|
|
88
|
+
for (const [name, value] of Object.entries(theme.typography.size)) {
|
|
89
|
+
lightVars.push(` --cz-font-size-${name}: ${value};`);
|
|
90
|
+
}
|
|
91
|
+
for (const [name, value] of Object.entries(theme.typography.weight)) {
|
|
92
|
+
lightVars.push(` --cz-font-weight-${name}: ${value};`);
|
|
93
|
+
}
|
|
94
|
+
for (const [name, value] of Object.entries(theme.typography.lineHeight)) {
|
|
95
|
+
lightVars.push(` --cz-font-lineHeight-${name}: ${value};`);
|
|
96
|
+
}
|
|
97
|
+
for (const [name, value] of Object.entries(theme.transition)) {
|
|
98
|
+
lightVars.push(` --cz-transition-${name}: ${value};`);
|
|
99
|
+
}
|
|
100
|
+
return `/**
|
|
101
|
+
* CZero Design Tokens
|
|
102
|
+
* Generated from czero.config.js
|
|
103
|
+
*/
|
|
104
|
+
|
|
105
|
+
:root {
|
|
106
|
+
${lightVars.join("\n")}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.dark {
|
|
110
|
+
${darkVars.join("\n")}
|
|
111
|
+
}
|
|
112
|
+
`;
|
|
113
|
+
}
|
|
114
|
+
function getComponentsCSS() {
|
|
115
|
+
const possiblePaths = [
|
|
116
|
+
path.join(__dirname, "components.css"),
|
|
117
|
+
// dist/cli/../components.css = dist/components.css
|
|
118
|
+
path.join(__dirname, "../components.css"),
|
|
119
|
+
// dist/components.css
|
|
120
|
+
path.join(__dirname, "../dist/components.css"),
|
|
121
|
+
// from root
|
|
122
|
+
path.join(__dirname, "../../dist/components.css"),
|
|
123
|
+
// from cli folder
|
|
124
|
+
path.join(__dirname, "../src/core/styles/components.css"),
|
|
125
|
+
// dev mode
|
|
126
|
+
path.join(__dirname, "../../src/core/styles/components.css")
|
|
127
|
+
// dev mode from cli
|
|
128
|
+
];
|
|
129
|
+
for (const p of possiblePaths) {
|
|
130
|
+
if (fs.existsSync(p)) {
|
|
131
|
+
return fs.readFileSync(p, "utf-8");
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
console.error("Error: Could not find components.css");
|
|
135
|
+
console.error("Searched paths:", possiblePaths);
|
|
136
|
+
process.exit(1);
|
|
137
|
+
}
|
|
138
|
+
function getResetCSS() {
|
|
139
|
+
const possiblePaths = [
|
|
140
|
+
path.join(__dirname, "reset.css"),
|
|
141
|
+
path.join(__dirname, "../reset.css"),
|
|
142
|
+
path.join(__dirname, "../dist/reset.css"),
|
|
143
|
+
path.join(__dirname, "../../dist/reset.css"),
|
|
144
|
+
path.join(__dirname, "../src/core/styles/reset.css"),
|
|
145
|
+
path.join(__dirname, "../../src/core/styles/reset.css")
|
|
146
|
+
];
|
|
147
|
+
for (const p of possiblePaths) {
|
|
148
|
+
if (fs.existsSync(p)) {
|
|
149
|
+
return fs.readFileSync(p, "utf-8");
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return `*, *::before, *::after { box-sizing: border-box; }
|
|
153
|
+
* { margin: 0; }
|
|
154
|
+
body { line-height: 1.5; -webkit-font-smoothing: antialiased; }
|
|
155
|
+
button, input, textarea, select { font: inherit; }
|
|
156
|
+
`;
|
|
157
|
+
}
|
|
158
|
+
async function loadUserConfig(configPath) {
|
|
159
|
+
const absolutePath = path.resolve(process.cwd(), configPath);
|
|
160
|
+
if (!fs.existsSync(absolutePath)) {
|
|
161
|
+
console.log(`No config found at ${configPath}, using defaults...`);
|
|
162
|
+
return {};
|
|
163
|
+
}
|
|
164
|
+
try {
|
|
165
|
+
const config = await import(`file://${absolutePath}`);
|
|
166
|
+
return config.default || config.theme || config;
|
|
167
|
+
} catch (error) {
|
|
168
|
+
console.error(`Error loading config: ${error}`);
|
|
169
|
+
return {};
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
async function main() {
|
|
173
|
+
const args = process.argv.slice(2);
|
|
174
|
+
let configPath = "czero.config.js";
|
|
175
|
+
let outputPath = "czero.css";
|
|
176
|
+
for (let i = 0; i < args.length; i++) {
|
|
177
|
+
if (args[i] === "--config" && args[i + 1]) {
|
|
178
|
+
configPath = args[i + 1];
|
|
179
|
+
i++;
|
|
180
|
+
} else if (args[i] === "--output" && args[i + 1]) {
|
|
181
|
+
outputPath = args[i + 1];
|
|
182
|
+
i++;
|
|
183
|
+
} else if (args[i] === "build") {
|
|
184
|
+
} else if (args[i] === "--help" || args[i] === "-h") {
|
|
185
|
+
console.log(`
|
|
186
|
+
CZero CLI - Generate CSS from your theme configuration
|
|
187
|
+
|
|
188
|
+
Usage:
|
|
189
|
+
npx czero build [options]
|
|
190
|
+
|
|
191
|
+
Options:
|
|
192
|
+
--config <path> Path to config file (default: czero.config.js)
|
|
193
|
+
--output <path> Output CSS file path (default: czero.css)
|
|
194
|
+
--help, -h Show this help message
|
|
195
|
+
|
|
196
|
+
Example:
|
|
197
|
+
npx czero build --config my-theme.js --output src/styles/czero.css
|
|
198
|
+
`);
|
|
199
|
+
process.exit(0);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
console.log("\u{1F3A8} CZero CSS Generator");
|
|
203
|
+
console.log(` Config: ${configPath}`);
|
|
204
|
+
console.log(` Output: ${outputPath}`);
|
|
205
|
+
console.log("");
|
|
206
|
+
const userConfig = await loadUserConfig(configPath);
|
|
207
|
+
const theme = deepMerge(defaultTheme, userConfig);
|
|
208
|
+
const resetCSS = getResetCSS();
|
|
209
|
+
const tokensCSS = generateTokensCSS(theme);
|
|
210
|
+
const componentsCSS = getComponentsCSS();
|
|
211
|
+
const finalCSS = `${resetCSS}
|
|
212
|
+
${tokensCSS}
|
|
213
|
+
${componentsCSS}`;
|
|
214
|
+
fs.writeFileSync(outputPath, finalCSS);
|
|
215
|
+
console.log(`\u2705 Generated ${outputPath}`);
|
|
216
|
+
console.log(` ${finalCSS.split("\n").length} lines`);
|
|
217
|
+
}
|
|
218
|
+
main().catch(console.error);
|