@melcanz85/chaincss 1.8.0 → 1.9.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 +319 -317
- package/atomic-optimizer.js +275 -0
- package/cache-manager.js +68 -0
- package/chaincss.js +182 -17
- package/index.js +24 -0
- package/index.react.js +4 -0
- package/package.json +25 -2
- package/prefixer.js +2 -2
- package/react-hooks.js +175 -0
- package/tokens.js +256 -0
- package/transpiler.js +24 -35
- package/types.d.ts +148 -0
- package/.github/workflows/publish.yml +0 -22
- package/publish.sh +0 -7
package/README.md
CHANGED
|
@@ -1,446 +1,448 @@
|
|
|
1
|
-
#
|
|
1
|
+
# ChainCSS
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/@melcanz85/chaincss)
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
|
|
6
|
-
**
|
|
6
|
+
**Write CSS with JavaScript. The only CSS-in-JS library that lets you CHOOSE your runtime cost.**
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
ChainCSS is a revolutionary CSS-in-JS solution that gives you **two powerful modes** in one package:
|
|
9
9
|
|
|
10
|
+
**Build-time compilation** → Pure CSS, zero JavaScript in browser
|
|
11
|
+
|
|
12
|
+
**Runtime hooks** → Dynamic, prop-based styles when you need them
|
|
13
|
+
|
|
14
|
+
"The performance of vanilla CSS with the power of JavaScript — now with **CHOICE.**"
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
// Same beautiful API, two powerful modes
|
|
18
|
+
const button = $()
|
|
19
|
+
.color('white')
|
|
20
|
+
.backgroundColor('#667eea')
|
|
21
|
+
.padding('1rem')
|
|
22
|
+
.borderRadius('4px')
|
|
23
|
+
.block('.btn');
|
|
24
|
+
````
|
|
10
25
|
## Installation
|
|
11
26
|
|
|
12
27
|
```bash
|
|
28
|
+
|
|
13
29
|
npm install @melcanz85/chaincss
|
|
14
30
|
```
|
|
15
31
|
|
|
16
|
-
|
|
32
|
+
## Two Powerful Modes - One API
|
|
17
33
|
|
|
18
|
-
|
|
34
|
+
### Mode 1: Build-time (Zero Runtime)
|
|
19
35
|
|
|
20
|
-
|
|
36
|
+
**Perfect for:** Static styles, layouts, design systems — anything that doesn't change.
|
|
21
37
|
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
38
|
+
```javascript
|
|
39
|
+
// chaincss/button.jcss
|
|
40
|
+
const button = $()
|
|
41
|
+
.backgroundColor('#667eea')
|
|
42
|
+
.color('white')
|
|
43
|
+
.padding('0.5rem 1rem')
|
|
44
|
+
.borderRadius('4px')
|
|
45
|
+
.block('.btn');
|
|
27
46
|
|
|
28
|
-
|
|
29
|
-
|
|
47
|
+
module.exports = { button };
|
|
48
|
+
````
|
|
49
|
+
|
|
50
|
+
```javascript
|
|
51
|
+
// chaincss/processor.js
|
|
52
|
+
const chaincss = require('@melcanz85/chaincss');
|
|
53
|
+
|
|
54
|
+
chaincss.processor('./chaincss/main.jcss', './dist/style.css');
|
|
55
|
+
// Outputs pure CSS: .btn { background: #667eea; color: white; ... }
|
|
56
|
+
// Zero JavaScript sent to browser
|
|
57
|
+
// Max performance, smallest bundle
|
|
58
|
+
````
|
|
59
|
+
### Mode 2: Runtime (React Hooks)
|
|
60
|
+
|
|
61
|
+
**Perfect for:** Dynamic styles that respond to props, state, or themes.
|
|
62
|
+
|
|
63
|
+
```jsx
|
|
64
|
+
// components/DynamicButton.jsx
|
|
65
|
+
import { useChainStyles } from '@melcanz85/chaincss';
|
|
66
|
+
|
|
67
|
+
function DynamicButton({ variant = 'primary', children }) {
|
|
68
|
+
const styles = useChainStyles({
|
|
69
|
+
button: () => $()
|
|
70
|
+
.backgroundColor(variant === 'primary' ? '#667eea' : '#48bb78')
|
|
71
|
+
.color('white')
|
|
72
|
+
.padding('0.5rem 1rem')
|
|
73
|
+
.borderRadius('4px')
|
|
74
|
+
.hover()
|
|
75
|
+
.transform('translateY(-2px)')
|
|
76
|
+
.boxShadow('0 4px 6px rgba(0,0,0,0.1)')
|
|
77
|
+
.block()
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
return <button className={styles.button}>{children}</button>;
|
|
30
81
|
}
|
|
82
|
+
// Styles injected at runtime
|
|
83
|
+
// Automatic cleanup on unmount
|
|
84
|
+
// Fully dynamic based on props
|
|
85
|
+
```
|
|
31
86
|
|
|
87
|
+
## Use BOTH in the Same Project!
|
|
32
88
|
|
|
33
|
-
|
|
89
|
+
```jsx
|
|
90
|
+
// Best of both worlds:
|
|
91
|
+
// - Layout styles → Build-time (zero cost)
|
|
92
|
+
// - Interactive styles → Runtime (dynamic)
|
|
34
93
|
|
|
35
|
-
|
|
94
|
+
// chaincss/layout.jcss (build-time)
|
|
95
|
+
const grid = $().display('grid').gap('1rem').block('.grid');
|
|
36
96
|
|
|
37
|
-
|
|
97
|
+
// components/Card.jsx (runtime)
|
|
98
|
+
function Card({ isHighlighted }) {
|
|
99
|
+
const styles = useChainStyles({
|
|
100
|
+
card: () => $()
|
|
101
|
+
.backgroundColor(isHighlighted ? '#fffacd' : 'white')
|
|
102
|
+
.padding('1rem')
|
|
103
|
+
.block()
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
```
|
|
38
107
|
|
|
39
|
-
|
|
40
|
-
- Flexbox & Grid
|
|
41
|
-
- Transforms & Animations
|
|
42
|
-
- Filters & Effects
|
|
43
|
-
- Text effects
|
|
44
|
-
- Box properties
|
|
108
|
+
## Features at a Glance
|
|
45
109
|
|
|
46
|
-
|
|
47
|
-
```bash
|
|
48
|
-
npx chaincss input.jcss output.css --watch
|
|
49
|
-
```
|
|
50
|
-
### 2. Full Autoprefixer Mode (Complete Coverage)
|
|
110
|
+
Feature Status Description
|
|
51
111
|
|
|
52
|
-
|
|
112
|
+
Zero Runtime ✅ Pure CSS output, no JS in browser
|
|
53
113
|
|
|
54
|
-
|
|
55
|
-
npm install autoprefixer postcss browserslist caniuse-db
|
|
56
|
-
|
|
57
|
-
# then run this command
|
|
58
|
-
npx chaincss input.jcss output.css --watch --prefixer-mode full
|
|
114
|
+
React Hooks ✅ Dynamic runtime styles when needed
|
|
59
115
|
|
|
60
|
-
|
|
116
|
+
Atomic CSS ✅ 90% smaller CSS files
|
|
61
117
|
|
|
62
|
-
|
|
118
|
+
TypeScript ✅ First-class type support
|
|
63
119
|
|
|
64
|
-
|
|
120
|
+
Design Tokens ✅ Centralized design system
|
|
65
121
|
|
|
66
|
-
|
|
67
|
-
"css:watch": "chaincss src/styles.jcss dist/styles.css --watch --prefixer-mode full",
|
|
68
|
-
"start": "concurrently \"npm run dev\" \"npm run css:watch\""
|
|
69
|
-
}
|
|
122
|
+
Auto-prefixing ✅ Built-in + full Autoprefixer
|
|
70
123
|
|
|
124
|
+
Source Maps ✅ Debug your .jcss files
|
|
71
125
|
|
|
72
|
-
|
|
126
|
+
Watch Mode ✅ Instant recompilation
|
|
73
127
|
|
|
74
|
-
|
|
128
|
+
VM Security ✅ Safe code execution
|
|
75
129
|
|
|
76
|
-
your-project/
|
|
77
|
-
├── chaincss/ # ChainCSS source files
|
|
78
|
-
│ ├── main.jcss # Main entry file
|
|
79
|
-
│ ├── chain.jcss # Chaining definitions
|
|
80
|
-
│ └── processor.js # Processing script
|
|
81
|
-
├── public/ # Output files
|
|
82
|
-
│ ├── index.html
|
|
83
|
-
│ └── style.css # Generated CSS
|
|
84
|
-
├── node_modules/
|
|
85
|
-
├── package.json
|
|
86
|
-
├── package.lock.json
|
|
87
|
-
└── server.js
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
**The Initialization processor Setup**
|
|
91
|
-
|
|
92
|
-
In chaincss/processor.js:
|
|
93
|
-
|
|
94
|
-
const chain = require("@melcanz85/chaincss");
|
|
95
|
-
|
|
96
|
-
try {
|
|
97
|
-
// Process main file and output CSS
|
|
98
|
-
chain.processor('./chaincss/main.jcss', './public/style.css');
|
|
99
|
-
} catch (err) {
|
|
100
|
-
console.error('Error processing chainCSS file:', err.stack);
|
|
101
|
-
process.exit(1);
|
|
102
|
-
}
|
|
103
130
|
|
|
104
|
-
##
|
|
131
|
+
## The ChainCSS API
|
|
105
132
|
|
|
106
|
-
|
|
133
|
+
### The Chain Builder
|
|
107
134
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
135
|
+
```javascript
|
|
136
|
+
// jQuery-like fluent API
|
|
137
|
+
const style = $()
|
|
138
|
+
.propertyName('value') // camelCase → kebab-case
|
|
139
|
+
.anotherProperty('value')
|
|
140
|
+
.block('.selector'); // End the chain with selector(s)
|
|
112
141
|
|
|
113
|
-
|
|
114
|
-
const
|
|
115
|
-
|
|
116
|
-
|
|
142
|
+
// Pseudo-classes & nested styles
|
|
143
|
+
const button = $()
|
|
144
|
+
.color('white')
|
|
145
|
+
.backgroundColor('#667eea')
|
|
146
|
+
.hover()
|
|
147
|
+
.backgroundColor('#5a67d8')
|
|
148
|
+
.transform('scale(1.05)')
|
|
149
|
+
.focus()
|
|
150
|
+
.boxShadow('0 0 0 3px rgba(102,126,234,0.5)')
|
|
151
|
+
.block('.btn');
|
|
152
|
+
````
|
|
153
|
+
### File Structure
|
|
117
154
|
|
|
118
|
-
|
|
119
|
-
|
|
155
|
+
```text
|
|
156
|
+
your-project/
|
|
157
|
+
├── chaincss/
|
|
158
|
+
│ ├── main.jcss # Entry point - imports & compiles
|
|
159
|
+
│ ├── processor.cjs # Build script
|
|
160
|
+
│ └── *.jcss # Your style definitions
|
|
161
|
+
├── src/
|
|
162
|
+
│ └── style/
|
|
163
|
+
│ └── global.css # Generated CSS
|
|
164
|
+
└── package.json
|
|
165
|
+
```
|
|
166
|
+
### Basic Example
|
|
120
167
|
|
|
121
|
-
|
|
122
|
-
navbar,
|
|
123
|
-
nav_container
|
|
124
|
-
};
|
|
168
|
+
**chaincss/button.jcss**
|
|
125
169
|
|
|
170
|
+
```javascript
|
|
171
|
+
const button = $()
|
|
172
|
+
.backgroundColor('#667eea')
|
|
173
|
+
.color('white')
|
|
174
|
+
.padding('0.75rem 1.5rem')
|
|
175
|
+
.borderRadius('0.375rem')
|
|
176
|
+
.fontWeight('600')
|
|
177
|
+
.block('.btn');
|
|
126
178
|
|
|
127
|
-
|
|
179
|
+
module.exports = { button };
|
|
180
|
+
```
|
|
181
|
+
**chaincss/main.jcss**
|
|
128
182
|
|
|
183
|
+
```javascript
|
|
129
184
|
<@
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// Override specific styles
|
|
134
|
-
style.navbar.padding = '2rem 5%';
|
|
135
|
-
|
|
136
|
-
// Compile to CSS
|
|
137
|
-
compile(style);
|
|
185
|
+
const { button } = get('./button.jcss');
|
|
186
|
+
compile({ button });
|
|
138
187
|
@>
|
|
188
|
+
````
|
|
139
189
|
|
|
140
|
-
|
|
141
|
-
<@
|
|
142
|
-
const from = $().opacity('0').transform('translateY(20px)').block('from');
|
|
143
|
-
const to = $().chain.opacity('1').transform('translateY(0)').block('to');
|
|
144
|
-
run(from,to);
|
|
145
|
-
@>
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/* Responsive */
|
|
149
|
-
@media (max-width: 768px) {
|
|
150
|
-
<@
|
|
151
|
-
const hero_h1 = $().fontSize('2.5rem').block('.hero h1');
|
|
152
|
-
const stats = $().flexDirection('column').gap('1rem').block('.stats');
|
|
153
|
-
const cta_buttons = $().flexDirection('column').alignItems('center').block('.cta-buttons');
|
|
154
|
-
const ex_container = $().gridTemplateColumns('1fr').block('.example-container');
|
|
155
|
-
const nav_links = $().display('none').block('.nav-links');
|
|
156
|
-
run(hero_h1,stats,cta_buttons,ex_container,nav_links);
|
|
157
|
-
@>
|
|
158
|
-
}
|
|
159
|
-
|
|
190
|
+
**chaincss/processor.js**
|
|
160
191
|
|
|
161
|
-
|
|
192
|
+
```javascript
|
|
162
193
|
|
|
163
|
-
|
|
194
|
+
const chaincss = require('@melcanz85/chaincss');
|
|
164
195
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
196
|
+
chaincss.processor('./chaincss/main.jcss', './src/style');
|
|
197
|
+
// Generates ./src/style/global.css
|
|
198
|
+
```
|
|
199
|
+
## Advanced Features
|
|
200
|
+
|
|
201
|
+
### Design Tokens
|
|
202
|
+
|
|
203
|
+
```javascript
|
|
204
|
+
|
|
205
|
+
// tokens.js
|
|
206
|
+
const { createTokens } = require('@melcanz85/chaincss');
|
|
207
|
+
|
|
208
|
+
module.exports = createTokens({
|
|
209
|
+
colors: {
|
|
210
|
+
primary: '#667eea',
|
|
211
|
+
secondary: '#764ba2'
|
|
212
|
+
},
|
|
213
|
+
spacing: {
|
|
214
|
+
sm: '0.5rem',
|
|
215
|
+
md: '1rem',
|
|
216
|
+
lg: '1.5rem'
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
|
|
220
|
+
// In your styles
|
|
221
|
+
const button = $()
|
|
222
|
+
.color('$colors.primary') // ← Token syntax!
|
|
223
|
+
.padding('$spacing.md')
|
|
224
|
+
.block('.btn');
|
|
171
225
|
```
|
|
172
226
|
|
|
173
|
-
|
|
227
|
+
## Atomic CSS Optimization
|
|
174
228
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
│ ├── App.jsx
|
|
188
|
-
│ └── main.jsx
|
|
189
|
-
├── chaincss/
|
|
190
|
-
│ ├── main.jcss # Entry point - imports and compiles
|
|
191
|
-
│ └── processor.js # Processing script
|
|
192
|
-
└── package.json
|
|
229
|
+
```javascript
|
|
230
|
+
// chaincss.config.js
|
|
231
|
+
module.exports = {
|
|
232
|
+
atomic: {
|
|
233
|
+
enabled: true, // Enable 90% CSS size reduction
|
|
234
|
+
threshold: 3, // Styles used 3+ times become atomic
|
|
235
|
+
naming: 'hash' // Smallest class names
|
|
236
|
+
}
|
|
237
|
+
};
|
|
238
|
+
```
|
|
239
|
+
**Before (standard CSS):** 4,823 chars
|
|
240
|
+
**After (atomic CSS):** 499 chars → **90% smaller!**
|
|
193
241
|
|
|
194
|
-
###
|
|
242
|
+
### Built-in Security
|
|
195
243
|
|
|
196
|
-
|
|
197
|
-
2. **`main.jcss` imports all component styles** using `get()` function
|
|
198
|
-
3. **Styles are merged and compiled** into a single `global.css` file
|
|
199
|
-
4. **React components import the generated CSS** and use the class names
|
|
244
|
+
ChainCSS uses **secure VM sandboxing** to safely execute your .jcss files. No eval, no global leaks, no security risks.
|
|
200
245
|
|
|
201
|
-
### Example: Navbar & Hero Components
|
|
202
246
|
|
|
203
|
-
|
|
247
|
+
## Quick Start Guides
|
|
204
248
|
|
|
205
|
-
|
|
206
|
-
.bg('rgba(255, 255, 255, 0.95)')
|
|
207
|
-
.backdropFilter('blur(10px)')
|
|
208
|
-
.padding('1rem 5%')
|
|
209
|
-
.position('fixed')
|
|
210
|
-
.width('100%')
|
|
211
|
-
.top('0')
|
|
212
|
-
.zIndex('1000')
|
|
213
|
-
.boxShadow('0 2px 20px rgba(0,0,0,0.1)')
|
|
214
|
-
.block('.navbar');
|
|
249
|
+
### With Node.js (Vanilla)
|
|
215
250
|
|
|
216
|
-
|
|
251
|
+
```bash
|
|
252
|
+
# 1. Install
|
|
253
|
+
npm install @melcanz85/chaincss
|
|
217
254
|
|
|
218
|
-
|
|
255
|
+
# 2. Create processor.cjs
|
|
256
|
+
echo "const chaincss = require('@melcanz85/chaincss');
|
|
257
|
+
chaincss.processor('./chaincss/main.jcss', './dist');" > processor.js
|
|
219
258
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
.textAlign('center')
|
|
225
|
-
.block('.hero');
|
|
259
|
+
# 3. Create your first .jcss file
|
|
260
|
+
mkdir chaincss
|
|
261
|
+
echo "const hello = $().color('red').block('.hello');
|
|
262
|
+
compile({ hello });" > chaincss/main.jcss
|
|
226
263
|
|
|
227
|
-
|
|
264
|
+
# 4. Build
|
|
265
|
+
node processor.js
|
|
266
|
+
# ✅ ./dist/global.css generated!
|
|
267
|
+
```
|
|
268
|
+
### With React + Vite
|
|
228
269
|
|
|
229
|
-
|
|
270
|
+
```bash
|
|
271
|
+
# 1. Create React app
|
|
272
|
+
npm create vite@latest my-app -- --template react
|
|
273
|
+
cd my-app
|
|
230
274
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const reset = $().margin('0').padding('0').boxSizing('border-box').block('*');
|
|
234
|
-
const body = $().fontFamily("-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto,
|
|
235
|
-
Oxygen, Ubuntu, sans-serif").lineHeight('1.6').color('#1e293b')
|
|
236
|
-
.background('linear-gradient(135deg, #667eea 0%, #764ba2 100%)').block('body');
|
|
237
|
-
run(reset, body);
|
|
238
|
-
@>
|
|
275
|
+
# 2. Install ChainCSS
|
|
276
|
+
npm install @melcanz85/chaincss
|
|
239
277
|
|
|
240
|
-
.
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
278
|
+
# 3. Create component with styles
|
|
279
|
+
mkdir -p src/components/Button
|
|
280
|
+
```
|
|
281
|
+
**src/components/Button/Button.jsx**
|
|
282
|
+
|
|
283
|
+
```jsx
|
|
284
|
+
|
|
285
|
+
import { useChainStyles } from '@melcanz85/chaincss';
|
|
286
|
+
|
|
287
|
+
export function Button({ variant = 'primary', children }) {
|
|
288
|
+
const styles = useChainStyles({
|
|
289
|
+
button: () => $()
|
|
290
|
+
.backgroundColor(variant === 'primary' ? '#667eea' : '#48bb78')
|
|
291
|
+
.color('white')
|
|
292
|
+
.padding('0.5rem 1rem')
|
|
293
|
+
.borderRadius('0.375rem')
|
|
294
|
+
.hover()
|
|
295
|
+
.transform('translateY(-2px)')
|
|
296
|
+
.boxShadow('0 4px 6px rgba(0,0,0,0.1)')
|
|
297
|
+
.block()
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
return <button className={styles.button}>{children}</button>;
|
|
247
301
|
}
|
|
302
|
+
```
|
|
248
303
|
|
|
249
|
-
<@
|
|
250
|
-
// Import all component styles
|
|
251
|
-
const nav = get('./src/components/nav/nav.jcss');
|
|
252
|
-
const hero = get('./src/components/sect_hero/hero.jcss');
|
|
253
|
-
const feature = get('./src/components/sect_feature/feature.jcss');
|
|
254
|
-
const example = get('./src/components/sect_example/example.jcss');
|
|
255
|
-
const gstart = get('./src/components/sect_gStart/gStart.jcss');
|
|
256
|
-
const footer = get('./src/components/footer/footer.jcss');
|
|
257
|
-
|
|
258
|
-
const merged = Object.assign({},nav,hero,feature,example,gstart,footer);
|
|
259
|
-
|
|
260
|
-
// Overwrite your chaining file
|
|
261
|
-
nav.logo.textDecoration = 'none';
|
|
262
|
-
//example.css_output.overflowWrap = 'break-word';
|
|
263
|
-
|
|
264
|
-
compile(merged);
|
|
265
|
-
@>
|
|
266
|
-
|
|
267
|
-
// you can add keyframes and media queries in this setup
|
|
268
|
-
@keyframes fadeInUp {
|
|
269
|
-
<@
|
|
270
|
-
const from = $().opacity('0').transform('translateY(20px)').block('from');
|
|
271
|
-
const to = $().opacity('1').transform('translateY(0)').block('to');
|
|
272
|
-
run(from,to);
|
|
273
|
-
@>
|
|
274
|
-
}
|
|
275
304
|
|
|
276
|
-
|
|
277
|
-
@media (max-width: 768px) {
|
|
278
|
-
<@
|
|
279
|
-
const hero = $().fontSize('2.5rem').block('.hero h1');
|
|
280
|
-
const stats = $().flexDirection('column').gap('1rem').block('.stats');
|
|
281
|
-
const ctaButtons = $().flexDirection('column').alignItems('center').block('.cta-buttons');
|
|
282
|
-
const exampleContainer = $().gridTemplateColumns('1fr').block('.example-container');
|
|
283
|
-
const navLinks = $().display('none').block('.nav-links');
|
|
284
|
-
run(hero,stats,ctaButtons,exampleContainer,navLinks);
|
|
285
|
-
@>
|
|
286
|
-
}
|
|
305
|
+
## Performance Comparison
|
|
287
306
|
|
|
288
|
-
|
|
307
|
+
Approach Runtime Cost Bundle Size Dynamic Styles Learning Curve
|
|
289
308
|
|
|
290
|
-
|
|
309
|
+
**ChainCSS (Build)** **Zero** **Just CSS** Build-time Low
|
|
291
310
|
|
|
292
|
-
|
|
311
|
+
**ChainCSS (Runtime)** Minimal Small runtime ✅ Full Low
|
|
293
312
|
|
|
294
|
-
|
|
313
|
+
Styled Components 5-10KB runtime CSS + runtime ✅ Full Medium
|
|
295
314
|
|
|
296
|
-
|
|
315
|
+
Emotion 8-12KB runtime CSS + runtime ✅ Full Medium
|
|
297
316
|
|
|
298
|
-
|
|
317
|
+
Tailwind Zero Just CSS ⚠️ Limited High
|
|
299
318
|
|
|
300
|
-
|
|
301
|
-
`main.jcss` simply orchestrates the compilation.
|
|
319
|
+
CSS Modules Zero Just CSS ❌ None Low
|
|
302
320
|
|
|
303
|
-
|
|
321
|
+
**ChainCSS is the ONLY library that gives you BOTH worlds!**
|
|
304
322
|
|
|
305
|
-
1. Component-Specific Styles
|
|
306
323
|
|
|
307
|
-
|
|
324
|
+
## Configuration
|
|
308
325
|
|
|
309
|
-
|
|
326
|
+
Create chaincss.config.js in your project root:
|
|
310
327
|
|
|
311
|
-
|
|
328
|
+
```javascript
|
|
312
329
|
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
330
|
+
module.exports = {
|
|
331
|
+
// Atomic CSS optimization
|
|
332
|
+
atomic: {
|
|
333
|
+
enabled: true,
|
|
334
|
+
threshold: 3, // Min usage for atomic conversion
|
|
335
|
+
naming: 'hash' // 'hash' | 'readable' | 'short'
|
|
336
|
+
},
|
|
337
|
+
|
|
338
|
+
// Prefixer options
|
|
339
|
+
prefixer: {
|
|
340
|
+
mode: 'auto', // 'auto' or 'full'
|
|
341
|
+
browsers: ['> 0.5%', 'last 2 versions']
|
|
342
|
+
},
|
|
343
|
+
|
|
344
|
+
// Source maps
|
|
345
|
+
sourceMaps: true
|
|
346
|
+
};
|
|
347
|
+
```
|
|
316
348
|
|
|
317
|
-
3. Dynamic Styles
|
|
318
349
|
|
|
319
|
-
|
|
320
|
-
const theme = {
|
|
321
|
-
primary: '#667eea',
|
|
322
|
-
secondary: '#764ba2'
|
|
323
|
-
};
|
|
350
|
+
## API Reference
|
|
324
351
|
|
|
325
|
-
|
|
326
|
-
.backgroundColor(theme.primary)
|
|
327
|
-
.block('.btn');
|
|
328
|
-
|
|
329
|
-
const buttonHover = chain
|
|
330
|
-
.backgroundColor(theme.secondary)
|
|
331
|
-
.block('.btn:hover');
|
|
352
|
+
### Core Functions
|
|
332
353
|
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
You can directly put css syntax code on your main.jcss file.
|
|
354
|
+
Function Description
|
|
336
355
|
|
|
337
|
-
|
|
356
|
+
`$()` Create a new chain builder
|
|
338
357
|
|
|
339
|
-
|
|
358
|
+
`.block(selector)` End chain and assign selector(s)
|
|
340
359
|
|
|
341
|
-
|
|
360
|
+
`compile(styles)` Compile style objects to CSS
|
|
342
361
|
|
|
343
|
-
|
|
344
|
-
main file it will overwrite the styles in the chain file.
|
|
362
|
+
`run(...styles)` Process inline styles
|
|
345
363
|
|
|
346
|
-
|
|
364
|
+
`get(filename)` Import .jcss files
|
|
347
365
|
|
|
348
|
-
|
|
349
|
-
easily enable proper syntax highlighting in your editor:
|
|
366
|
+
`processor(input, output)` Build-time processor
|
|
350
367
|
|
|
351
|
-
**VS Code**
|
|
352
368
|
|
|
353
|
-
|
|
369
|
+
### React Hooks
|
|
354
370
|
|
|
355
|
-
|
|
356
|
-
"files.associations": {
|
|
357
|
-
"*.jcss": "javascript"
|
|
358
|
-
}
|
|
359
|
-
}
|
|
371
|
+
Hook Description
|
|
360
372
|
|
|
361
|
-
|
|
373
|
+
`useChainStyles(styles, options)` Basic styles hook
|
|
362
374
|
|
|
363
|
-
|
|
375
|
+
`useDynamicChainStyles(factory, deps)` Styles that depend on props/state
|
|
364
376
|
|
|
365
|
-
|
|
377
|
+
`useThemeChainStyles(styles, theme)` Theme-aware styles
|
|
366
378
|
|
|
367
|
-
|
|
379
|
+
`ChainCSSGlobal` Global styles component
|
|
368
380
|
|
|
369
|
-
|
|
381
|
+
`cx(...classes)` Conditional class merging
|
|
370
382
|
|
|
371
|
-
Add to your .vimrc or init.vim:
|
|
372
383
|
|
|
373
|
-
|
|
384
|
+
## Editor Support
|
|
374
385
|
|
|
375
|
-
|
|
386
|
+
### VS Code
|
|
376
387
|
|
|
377
|
-
|
|
388
|
+
```json
|
|
389
|
+
{
|
|
390
|
+
"files.associations": {
|
|
391
|
+
"*.jcss": "javascript"
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
```
|
|
378
395
|
|
|
379
|
-
|
|
396
|
+
### WebStorm
|
|
380
397
|
|
|
381
|
-
|
|
382
|
-
"extensions": ["jcss"],
|
|
383
|
-
"syntax": "Packages/JavaScript/JavaScript.sublime-syntax"
|
|
384
|
-
}
|
|
398
|
+
* Settings → Editor → File Types
|
|
385
399
|
|
|
386
|
-
|
|
400
|
+
* Add `*.jcss` as JavaScript
|
|
387
401
|
|
|
388
|
-
|
|
389
|
-
coffeescript
|
|
402
|
+
### Vim
|
|
390
403
|
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
"source.js": [
|
|
395
|
-
"jcss"
|
|
396
|
-
]
|
|
404
|
+
```vim
|
|
405
|
+
au BufRead,BufNewFile `*.jcss` setfiletype javascript
|
|
406
|
+
```
|
|
397
407
|
|
|
398
408
|
|
|
399
|
-
|
|
409
|
+
## Roadmap
|
|
400
410
|
|
|
401
|
-
|
|
402
|
-
Simply configure your editor to treat .jcss files as JavaScript.
|
|
411
|
+
* Zero-runtime compilation
|
|
403
412
|
|
|
413
|
+
* React hooks
|
|
404
414
|
|
|
405
|
-
|
|
415
|
+
* Atomic CSS optimization
|
|
406
416
|
|
|
407
|
-
|
|
417
|
+
* Design tokens
|
|
408
418
|
|
|
409
|
-
|
|
419
|
+
* TypeScript support
|
|
410
420
|
|
|
411
|
-
|
|
421
|
+
* Vue/Svelte integrations (coming soon)
|
|
412
422
|
|
|
413
|
-
|
|
423
|
+
* Plugin system (coming soon)
|
|
414
424
|
|
|
415
|
-
✅ Media queries responsive @media support
|
|
416
|
-
|
|
417
|
-
✅ Source maps Debug generated CSS
|
|
418
425
|
|
|
419
|
-
|
|
426
|
+
## Contributing
|
|
420
427
|
|
|
428
|
+
Contributions are welcome! Whether it's:
|
|
421
429
|
|
|
422
|
-
|
|
430
|
+
* Bug fixes
|
|
423
431
|
|
|
424
|
-
|
|
432
|
+
* Documentation improvements
|
|
425
433
|
|
|
426
|
-
|
|
434
|
+
* New features
|
|
427
435
|
|
|
428
|
-
|
|
436
|
+
* Test cases
|
|
429
437
|
|
|
438
|
+
Please see CONTRIBUTING.md for guidelines.
|
|
430
439
|
|
|
431
|
-
### chaincss vs Other Approaches
|
|
432
440
|
|
|
433
|
-
|
|
434
|
-
|----------------|-------------------|---------------------|---------------|-------------|
|
|
435
|
-
| **When CSS is generated** | **Build time** | Runtime (browser) | Build time | Already written |
|
|
436
|
-
| **Browser work**| None - just serves CSS | Executes JS to generate CSS | None - just serves CSS | None |
|
|
437
|
-
| **Dynamic values**| Via JS at build time | Via props at runtime | ⚠ Limited | Manual |
|
|
438
|
-
| **Bundle size** | Just the CSS | CSS + JS runtime | Just the CSS | Just the CSS |
|
|
441
|
+
## License
|
|
439
442
|
|
|
440
|
-
|
|
443
|
+
MIT © [Rommel Caneos]('https://github.com/melcanz08')
|
|
441
444
|
|
|
442
|
-
Contributions are welcome! Feel free to open issues or submit pull requests.
|
|
443
445
|
|
|
444
|
-
|
|
446
|
+
## Star Us on GitHub!
|
|
445
447
|
|
|
446
|
-
|
|
448
|
+
If ChainCSS helps you, please [give it a star!]('https://github.com/melcanz08/chaincss') It helps others discover it.
|