@melcanz85/chaincss 1.10.1 → 1.11.1
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 +110 -61
- package/browser/index.js +1 -1
- package/browser/react-hooks.jsx +1 -63
- package/browser/rtt.js +1 -45
- package/node/atomic-optimizer.js +2 -67
- package/node/btt.js +348 -84
- package/node/cache-manager.js +0 -12
- package/node/chaincss.js +14 -99
- package/node/index.js +2 -13
- package/node/prefixer.js +2 -61
- package/node/strVal.js +1 -1
- package/package.json +1 -1
- package/types.d.ts +0 -26
- package/node/css-properties.json +0 -633
package/README.md
CHANGED
|
@@ -6,9 +6,7 @@
|
|
|
6
6
|
|
|
7
7
|
[](https://melcanz08.github.io/chaincss_react_website/)
|
|
8
8
|
|
|
9
|
-
**Write CSS with JavaScript.
|
|
10
|
-
|
|
11
|
-
ChainCSS is a revolutionary CSS-in-JS solution that gives you **two powerful modes** in one package:
|
|
9
|
+
**Write CSS with JavaScript. Lets you CHOOSE your runtime cost. DUAL MODE**
|
|
12
10
|
|
|
13
11
|
**Build-time compilation** → Pure CSS, zero JavaScript in browser
|
|
14
12
|
|
|
@@ -16,11 +14,56 @@ ChainCSS is a revolutionary CSS-in-JS solution that gives you **two powerful mod
|
|
|
16
14
|
|
|
17
15
|
## Installation
|
|
18
16
|
|
|
17
|
+
* Install [nodejs.](https://nodejs.org/en/download)
|
|
18
|
+
|
|
19
19
|
```bash
|
|
20
20
|
|
|
21
21
|
npm install @melcanz85/chaincss
|
|
22
22
|
```
|
|
23
23
|
|
|
24
|
+
* In your html add a link tag with an href value of style/global.css this serves as the
|
|
25
|
+
stylesheet for your entire webpage. You dont need to touch this css file.
|
|
26
|
+
|
|
27
|
+
```html
|
|
28
|
+
<!-- index.html -->
|
|
29
|
+
<!DOCTYPE html>
|
|
30
|
+
<html>
|
|
31
|
+
<head>
|
|
32
|
+
<title>chaincss</title>
|
|
33
|
+
<link rel="stylesheet" type="text/css" href="style/global.css">
|
|
34
|
+
</head>
|
|
35
|
+
<body>
|
|
36
|
+
<p>Hello World</p>
|
|
37
|
+
</body>
|
|
38
|
+
</html>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Syntax
|
|
42
|
+
|
|
43
|
+
```javascript
|
|
44
|
+
// main.jcss
|
|
45
|
+
<@
|
|
46
|
+
const text = $().color('blue').textAlign('center').block('p');
|
|
47
|
+
|
|
48
|
+
//text.fontSize = '2rem';
|
|
49
|
+
|
|
50
|
+
run(text);
|
|
51
|
+
@>
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
* To apply this styles run this in your terminal / command prompt.
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
npx chaincss ./src/main.jcss ./style --watch
|
|
58
|
+
````
|
|
59
|
+
|
|
60
|
+
* Open your index.html in the browser.
|
|
61
|
+
|
|
62
|
+
* To make changes uncomment styles between text variable declaration and run() method.
|
|
63
|
+
|
|
64
|
+
* Thats how you add or modify the style block you treat them as a regular javascript object.
|
|
65
|
+
|
|
66
|
+
|
|
24
67
|
### File Structure
|
|
25
68
|
|
|
26
69
|
```text
|
|
@@ -67,62 +110,68 @@ ChainCSS is a revolutionary CSS-in-JS solution that gives you **two powerful mod
|
|
|
67
110
|
npx chaincss ./src/main.jcss ./style --watch
|
|
68
111
|
# ./style/global.css generated!
|
|
69
112
|
````
|
|
70
|
-
OR with vanilla nodejs project
|
|
71
|
-
|
|
72
|
-
```bash
|
|
73
|
-
npx chaincss ./src/main.jcss ./style --watch & node server.js
|
|
74
|
-
# ./style/global.css generated!
|
|
75
|
-
````
|
|
76
113
|
* Note: running `npx chaincss ./src/main.jcss ./style --watch ` for the first time will
|
|
77
114
|
generate ./chaincss.config.js with default values. You can edit this to
|
|
78
115
|
customize your build!.
|
|
79
116
|
|
|
80
|
-
|
|
81
117
|
### Mode 2: Runtime (React Hooks)
|
|
82
118
|
|
|
83
119
|
**Perfect for:** Dynamic styles that respond to props, state, or themes.
|
|
84
120
|
|
|
85
121
|
```jsx
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
122
|
+
// src/components/Counter.jsx
|
|
123
|
+
import { useState } from 'react';
|
|
124
|
+
import { useChainStyles, $ } from '@melcanz85/chaincss/react';
|
|
125
|
+
|
|
126
|
+
export default function Counter() {
|
|
127
|
+
const [count, setCount] = useState(0);
|
|
128
|
+
|
|
129
|
+
const styles = useChainStyles(() => {
|
|
130
|
+
const container = $()
|
|
131
|
+
.display('flex')
|
|
132
|
+
.flexDirection('column')
|
|
133
|
+
.alignItems('center')
|
|
134
|
+
.justifyContent('center')
|
|
135
|
+
.gap('3rem')
|
|
136
|
+
.padding('4rem 2.5rem')
|
|
137
|
+
.backgroundColor('rgba(255, 255, 255, 0.92)')
|
|
138
|
+
.borderRadius('2rem')
|
|
139
|
+
.boxShadow('0 25px 50px -12px rgba(0, 0, 0, 0.25)')
|
|
140
|
+
.backdropFilter('blur(12px)')
|
|
141
|
+
.maxWidth('420px')
|
|
142
|
+
.width('90%')
|
|
143
|
+
.block();
|
|
144
|
+
|
|
145
|
+
const numberBase = $()
|
|
146
|
+
.fontSize('6rem')
|
|
147
|
+
.fontWeight('800')
|
|
148
|
+
.letterSpacing('-0.05em')
|
|
149
|
+
.transition('color 0.5s ease, transform 0.3s ease')
|
|
150
|
+
.transform(count === 0 ? 'scale(1)' : 'scale(1.1)')
|
|
151
|
+
.animation(count > 0 ? 'pulse 1.8s infinite ease-in-out' : 'none')
|
|
152
|
+
.block();
|
|
153
|
+
|
|
154
|
+
const numberColor = $()
|
|
155
|
+
.color(
|
|
156
|
+
count === 0 ? '#4a5568' : `hsl(${ (count * 40) % 360 }, 80%, 60%)`
|
|
157
|
+
)
|
|
158
|
+
.block();
|
|
159
|
+
|
|
160
|
+
return { container, numberBase, numberColor };
|
|
161
|
+
}, [count]);
|
|
162
|
+
|
|
163
|
+
return (
|
|
164
|
+
<div className={styles.container}>
|
|
165
|
+
<div className={`${styles.numberBase} ${styles.numberColor}`}>
|
|
166
|
+
{count}
|
|
167
|
+
</div>
|
|
168
|
+
|
|
169
|
+
<button className="increment-btn" onClick={() => setCount(prev => prev + 1)}>
|
|
170
|
+
Tap to Count Up
|
|
171
|
+
</button>
|
|
172
|
+
</div>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
126
175
|
```
|
|
127
176
|
|
|
128
177
|
## Use BOTH in the Same Project!
|
|
@@ -137,8 +186,8 @@ OR with vanilla nodejs project
|
|
|
137
186
|
|
|
138
187
|
// components/Card.jsx (runtime)
|
|
139
188
|
function Card({ isHighlighted }) {
|
|
140
|
-
const styles = useChainStyles({
|
|
141
|
-
card
|
|
189
|
+
const styles = useChainStyles(() => {
|
|
190
|
+
const card = $()
|
|
142
191
|
.backgroundColor(isHighlighted ? '#fffacd' : 'white')
|
|
143
192
|
.padding('1rem')
|
|
144
193
|
.block()
|
|
@@ -248,9 +297,9 @@ OR with vanilla nodejs project
|
|
|
248
297
|
// chaincss.config.js
|
|
249
298
|
module.exports = {
|
|
250
299
|
atomic: {
|
|
251
|
-
enabled: true,
|
|
252
|
-
threshold: 3,
|
|
253
|
-
naming: 'hash'
|
|
300
|
+
enabled: true,
|
|
301
|
+
threshold: 3,
|
|
302
|
+
naming: 'hash'
|
|
254
303
|
}
|
|
255
304
|
};
|
|
256
305
|
```
|
|
@@ -297,8 +346,8 @@ compile({ hello });" > chaincss/main.jcss
|
|
|
297
346
|
import { useChainStyles } from '@melcanz85/chaincss';
|
|
298
347
|
|
|
299
348
|
export function Button({ variant = 'primary', children }) {
|
|
300
|
-
const styles = useChainStyles({
|
|
301
|
-
button
|
|
349
|
+
const styles = useChainStyles(() => {
|
|
350
|
+
const button = $()
|
|
302
351
|
.backgroundColor(variant === 'primary' ? '#667eea' : '#48bb78')
|
|
303
352
|
.color('white')
|
|
304
353
|
.padding('0.5rem 1rem')
|
|
@@ -307,8 +356,8 @@ compile({ hello });" > chaincss/main.jcss
|
|
|
307
356
|
.transform('translateY(-2px)')
|
|
308
357
|
.boxShadow('0 4px 6px rgba(0,0,0,0.1)')
|
|
309
358
|
.block()
|
|
359
|
+
return { button };
|
|
310
360
|
});
|
|
311
|
-
|
|
312
361
|
return <button className={styles.button}>{children}</button>;
|
|
313
362
|
}
|
|
314
363
|
```
|
|
@@ -333,7 +382,7 @@ See ChainCSS in action! Visit our interactive demo site - [https://melcanz08.git
|
|
|
333
382
|
|
|
334
383
|
CSS Modules Zero Just CSS None Low
|
|
335
384
|
|
|
336
|
-
**ChainCSS
|
|
385
|
+
**ChainCSS a "DUAL MODE optioned" css-in-js library**
|
|
337
386
|
|
|
338
387
|
## API Reference
|
|
339
388
|
|
|
@@ -410,9 +459,9 @@ Please see CONTRIBUTING.md for guidelines.
|
|
|
410
459
|
|
|
411
460
|
## License
|
|
412
461
|
|
|
413
|
-
MIT © [Rommel Caneos](
|
|
462
|
+
MIT © [Rommel Caneos](https://github.com/melcanz08)
|
|
414
463
|
|
|
415
464
|
|
|
416
465
|
## Star Us on GitHub!
|
|
417
466
|
|
|
418
|
-
If ChainCSS helps you, please [give it a star!](
|
|
467
|
+
If ChainCSS helps you, please [give it a star!](https://github.com/melcanz08/chaincss) It helps others discover it.
|
package/browser/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export * from './react-hooks.jsx';
|
|
2
|
-
export {
|
|
2
|
+
export {$,run,compile,chain,createTokens,responsive,tokens } from './rtt.js';
|
package/browser/react-hooks.jsx
CHANGED
|
@@ -1,129 +1,81 @@
|
|
|
1
1
|
import { useMemo, useEffect, useRef, useState } from 'react';
|
|
2
2
|
import { $, compile, chain } from './rtt';
|
|
3
|
-
|
|
4
|
-
// Cache for generated styles to avoid duplication
|
|
5
3
|
const styleCache = new Map();
|
|
6
4
|
let styleSheet = null;
|
|
7
|
-
|
|
8
|
-
// Initialize style sheet (add to document head)
|
|
9
5
|
const initStyleSheet = () => {
|
|
10
|
-
if (typeof document === 'undefined') return null;
|
|
11
|
-
|
|
6
|
+
if (typeof document === 'undefined') return null;
|
|
12
7
|
if (!styleSheet) {
|
|
13
|
-
// Check if already exists
|
|
14
8
|
const existing = document.getElementById('chaincss-styles');
|
|
15
9
|
if (existing) {
|
|
16
10
|
styleSheet = existing;
|
|
17
11
|
return styleSheet;
|
|
18
12
|
}
|
|
19
|
-
|
|
20
|
-
// Create new style element
|
|
21
13
|
const style = document.createElement('style');
|
|
22
14
|
style.id = 'chaincss-styles';
|
|
23
15
|
style.setAttribute('data-chaincss', 'true');
|
|
24
16
|
document.head.appendChild(style);
|
|
25
17
|
styleSheet = style;
|
|
26
18
|
}
|
|
27
|
-
|
|
28
19
|
return styleSheet;
|
|
29
20
|
};
|
|
30
|
-
|
|
31
|
-
// Update styles in the style sheet
|
|
32
21
|
const updateStyles = (css) => {
|
|
33
22
|
const sheet = initStyleSheet();
|
|
34
23
|
if (sheet) {
|
|
35
24
|
sheet.textContent = css;
|
|
36
25
|
}
|
|
37
26
|
};
|
|
38
|
-
|
|
39
|
-
// Main hook for using ChainCSS styles in React
|
|
40
27
|
export function useChainStyles(styles, deps = [], options = {}) {
|
|
41
28
|
const {
|
|
42
29
|
cache = true,
|
|
43
30
|
namespace = 'chain',
|
|
44
31
|
watch = false
|
|
45
32
|
} = options;
|
|
46
|
-
|
|
47
|
-
// Generate a unique ID for this component instance
|
|
48
33
|
const id = useRef(`chain-${Math.random().toString(36).substr(2, 9)}`);
|
|
49
|
-
|
|
50
|
-
// Store the generated class names
|
|
51
34
|
const [classNames, setClassNames] = useState({});
|
|
52
|
-
|
|
53
|
-
// Process styles and generate CSS
|
|
54
35
|
const processed = useMemo(() => {
|
|
55
|
-
// ✅ FIRST: Resolve styles if it's a function
|
|
56
36
|
const resolvedStyles = typeof styles === 'function' ? styles() : styles;
|
|
57
|
-
|
|
58
37
|
if (!resolvedStyles || Object.keys(resolvedStyles).length === 0) {
|
|
59
38
|
return { classNames: {}, css: '' };
|
|
60
39
|
}
|
|
61
|
-
|
|
62
|
-
// ✅ NOW use resolvedStyles for cache key
|
|
63
40
|
const cacheKey = JSON.stringify(resolvedStyles);
|
|
64
41
|
if (cache && styleCache.has(cacheKey)) {
|
|
65
42
|
return styleCache.get(cacheKey);
|
|
66
43
|
}
|
|
67
|
-
|
|
68
|
-
// Generate unique class names for each style
|
|
69
44
|
const newClassNames = {};
|
|
70
45
|
const compiledStyles = {};
|
|
71
|
-
|
|
72
|
-
// ✅ Use resolvedStyles here
|
|
73
46
|
Object.entries(resolvedStyles).forEach(([key, styleDef]) => {
|
|
74
|
-
// Generate a unique class name
|
|
75
47
|
const className = `${namespace}-${key}-${id.current}`;
|
|
76
|
-
|
|
77
|
-
// Create a style definition with the unique class
|
|
78
48
|
const styleObj = typeof styleDef === 'function'
|
|
79
49
|
? styleDef()
|
|
80
50
|
: styleDef;
|
|
81
|
-
|
|
82
|
-
// Store the class name mapping
|
|
83
51
|
newClassNames[key] = className;
|
|
84
|
-
|
|
85
|
-
// Create the style rule
|
|
86
52
|
compiledStyles[`${key}_${id.current}`] = {
|
|
87
53
|
selectors: [`.${className}`],
|
|
88
54
|
...styleObj
|
|
89
55
|
};
|
|
90
56
|
});
|
|
91
|
-
|
|
92
|
-
// Compile to CSS
|
|
93
57
|
compile(compiledStyles);
|
|
94
58
|
const css = chain.cssOutput;
|
|
95
|
-
|
|
96
59
|
const result = { classNames: newClassNames, css };
|
|
97
|
-
|
|
98
60
|
if (cache) {
|
|
99
61
|
styleCache.set(cacheKey, result);
|
|
100
62
|
}
|
|
101
|
-
|
|
102
63
|
return result;
|
|
103
64
|
}, [styles, namespace, id.current, ...deps]);
|
|
104
|
-
|
|
105
|
-
// Update the style sheet when styles change
|
|
106
65
|
useEffect(() => {
|
|
107
66
|
if (processed.css) {
|
|
108
|
-
// For simple apps, just append
|
|
109
67
|
if (!watch) {
|
|
110
68
|
const sheet = initStyleSheet();
|
|
111
69
|
if (sheet) {
|
|
112
|
-
// Remove old styles for this component
|
|
113
70
|
const existingStyles = sheet.textContent || '';
|
|
114
71
|
const styleRegex = new RegExp(`\\.[\\w-]*${id.current}[\\s\\S]*?}`, 'g');
|
|
115
72
|
const cleanedStyles = existingStyles.replace(styleRegex, '');
|
|
116
|
-
|
|
117
|
-
// Add new styles
|
|
118
73
|
sheet.textContent = cleanedStyles + processed.css;
|
|
119
74
|
}
|
|
120
75
|
} else {
|
|
121
|
-
// For watch mode, update everything
|
|
122
76
|
updateStyles(processed.css);
|
|
123
77
|
}
|
|
124
78
|
}
|
|
125
|
-
|
|
126
|
-
// Cleanup on unmount
|
|
127
79
|
return () => {
|
|
128
80
|
if (!watch && styleSheet) {
|
|
129
81
|
const existingStyles = styleSheet.textContent || '';
|
|
@@ -132,20 +84,14 @@ export function useChainStyles(styles, deps = [], options = {}) {
|
|
|
132
84
|
}
|
|
133
85
|
};
|
|
134
86
|
}, [processed.css, watch]);
|
|
135
|
-
|
|
136
87
|
return processed.classNames;
|
|
137
88
|
}
|
|
138
|
-
|
|
139
|
-
// Hook for dynamic styles that depend on props/state
|
|
140
89
|
export function useDynamicChainStyles(styleFactory, deps = [], options = {}) {
|
|
141
90
|
const styles = useMemo(() => {
|
|
142
91
|
return styleFactory();
|
|
143
92
|
}, deps);
|
|
144
|
-
|
|
145
93
|
return useChainStyles(styles, options);
|
|
146
94
|
}
|
|
147
|
-
|
|
148
|
-
// Hook for theme-aware styles
|
|
149
95
|
export function useThemeChainStyles(styles, theme, options = {}) {
|
|
150
96
|
const themedStyles = useMemo(() => {
|
|
151
97
|
if (typeof styles === 'function') {
|
|
@@ -153,29 +99,21 @@ export function useThemeChainStyles(styles, theme, options = {}) {
|
|
|
153
99
|
}
|
|
154
100
|
return styles;
|
|
155
101
|
}, [styles, theme]);
|
|
156
|
-
|
|
157
102
|
return useChainStyles(themedStyles, options);
|
|
158
103
|
}
|
|
159
|
-
|
|
160
|
-
// Component for injecting global ChainCSS styles
|
|
161
104
|
export function ChainCSSGlobal({ styles }) {
|
|
162
105
|
useChainStyles(styles, { watch: true });
|
|
163
106
|
return null;
|
|
164
107
|
}
|
|
165
|
-
|
|
166
|
-
// HOC for adding ChainCSS styles to components
|
|
167
108
|
export function withChainStyles(styles, options = {}) {
|
|
168
109
|
return function WrappedComponent(props) {
|
|
169
110
|
const classNames = useChainStyles(
|
|
170
111
|
typeof styles === 'function' ? styles(props) : styles,
|
|
171
112
|
options
|
|
172
113
|
);
|
|
173
|
-
|
|
174
114
|
return <WrappedComponent {...props} chainStyles={classNames} />;
|
|
175
115
|
};
|
|
176
116
|
}
|
|
177
|
-
|
|
178
|
-
// Utility to combine multiple class names
|
|
179
117
|
export function cx(...classes) {
|
|
180
118
|
return classes.filter(Boolean).join(' ');
|
|
181
119
|
}
|
package/browser/rtt.js
CHANGED
|
@@ -1,25 +1,18 @@
|
|
|
1
1
|
import { tokens, createTokens, responsive } from '../shared/tokens.mjs';
|
|
2
|
-
|
|
3
2
|
let cssProperties = [];
|
|
4
|
-
|
|
5
|
-
// Try to import the JSON file, fallback to fetch if it fails
|
|
6
3
|
try {
|
|
7
|
-
// Dynamic import - will fail gracefully if file doesn't exist
|
|
8
4
|
const module = await import('../node/css-properties.json', {
|
|
9
5
|
assert: { type: 'json' },
|
|
10
|
-
// This prevents the error from breaking the build
|
|
11
6
|
ignore: true
|
|
12
7
|
});
|
|
13
8
|
cssProperties = module.default;
|
|
14
9
|
} catch (e) {
|
|
15
10
|
console.log('CSS properties file not found, will fetch from CDN');
|
|
16
11
|
}
|
|
17
|
-
|
|
18
12
|
const chain = {
|
|
19
13
|
cssOutput: undefined,
|
|
20
14
|
catcher: {},
|
|
21
15
|
cachedValidProperties: [],
|
|
22
|
-
|
|
23
16
|
async initializeProperties() {
|
|
24
17
|
if (cssProperties && cssProperties.length > 0) {
|
|
25
18
|
this.cachedValidProperties = cssProperties;
|
|
@@ -45,128 +38,91 @@ const chain = {
|
|
|
45
38
|
}
|
|
46
39
|
}
|
|
47
40
|
},
|
|
48
|
-
|
|
49
|
-
// Synchronous version for internal use
|
|
50
41
|
getCachedProperties() {
|
|
51
42
|
return this.cachedValidProperties;
|
|
52
43
|
}
|
|
53
44
|
};
|
|
54
|
-
|
|
55
|
-
// Initialize properties synchronously when module loads
|
|
56
45
|
chain.initializeProperties();
|
|
57
|
-
|
|
58
46
|
const resolveToken = (value, useTokens) => {
|
|
59
47
|
if (!useTokens || typeof value !== 'string' || !value.startsWith('$')) {
|
|
60
48
|
return value;
|
|
61
49
|
}
|
|
62
|
-
|
|
63
50
|
const tokenPath = value.slice(1);
|
|
64
51
|
const tokenValue = tokens.get(tokenPath);
|
|
65
|
-
|
|
66
52
|
if (!tokenValue) {
|
|
67
53
|
return value;
|
|
68
54
|
}
|
|
69
|
-
|
|
70
55
|
return tokenValue;
|
|
71
56
|
};
|
|
72
|
-
|
|
73
57
|
function $(useTokens = true){
|
|
74
58
|
const catcher = {};
|
|
75
|
-
|
|
76
|
-
// Use cached properties if available
|
|
77
59
|
const validProperties = chain.cachedValidProperties;
|
|
78
|
-
|
|
79
60
|
const handler = {
|
|
80
61
|
get: (target, prop) => {
|
|
81
62
|
if (prop === 'block') {
|
|
82
63
|
return function(...args) {
|
|
83
|
-
// If no args, just return current catcher
|
|
84
64
|
if (args.length === 0) {
|
|
85
65
|
const result = { ...catcher };
|
|
86
|
-
// Clear catcher
|
|
87
66
|
Object.keys(catcher).forEach(key => delete catcher[key]);
|
|
88
67
|
return result;
|
|
89
68
|
}
|
|
90
|
-
|
|
91
|
-
// Create result with selectors
|
|
92
69
|
const result = {
|
|
93
70
|
selectors: args,
|
|
94
71
|
...catcher
|
|
95
72
|
};
|
|
96
|
-
|
|
97
|
-
// Clear catcher
|
|
98
73
|
Object.keys(catcher).forEach(key => delete catcher[key]);
|
|
99
|
-
|
|
100
74
|
return result;
|
|
101
75
|
};
|
|
102
76
|
}
|
|
103
|
-
// Convert camelCase to kebab-case for CSS property
|
|
104
77
|
const cssProperty = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
105
|
-
// Validate property exists (optional) - use cached properties
|
|
106
78
|
if (validProperties && validProperties.length > 0 && !validProperties.includes(cssProperty)) {
|
|
107
79
|
console.warn(`Warning: '${cssProperty}' may not be a valid CSS property`);
|
|
108
80
|
}
|
|
109
|
-
// Return a function that sets the value
|
|
110
81
|
return function(value) {
|
|
111
82
|
catcher[prop] = resolveToken(value, useTokens);
|
|
112
83
|
return proxy;
|
|
113
84
|
};
|
|
114
85
|
}
|
|
115
86
|
};
|
|
116
|
-
|
|
117
|
-
// Create the proxy
|
|
118
87
|
const proxy = new Proxy({}, handler);
|
|
119
|
-
|
|
120
88
|
return proxy;
|
|
121
89
|
}
|
|
122
|
-
|
|
123
90
|
const run = (...args) => {
|
|
124
91
|
let cssOutput = '';
|
|
125
|
-
|
|
126
92
|
args.forEach((value) => {
|
|
127
93
|
if (value && value.selectors) {
|
|
128
94
|
let rule = `${value.selectors.join(', ')} {\n`;
|
|
129
|
-
|
|
130
|
-
// Add all properties (excluding 'selectors')
|
|
131
95
|
for (let key in value) {
|
|
132
96
|
if (key !== 'selectors' && value.hasOwnProperty(key)) {
|
|
133
97
|
const kebabKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
134
98
|
rule += ` ${kebabKey}: ${value[key]};\n`;
|
|
135
99
|
}
|
|
136
100
|
}
|
|
137
|
-
|
|
138
101
|
rule += `}\n\n`;
|
|
139
102
|
cssOutput += rule;
|
|
140
103
|
}
|
|
141
104
|
});
|
|
142
|
-
|
|
143
105
|
chain.cssOutput = cssOutput.trim();
|
|
144
106
|
return cssOutput.trim();
|
|
145
107
|
};
|
|
146
|
-
|
|
147
108
|
const compile = (obj) => {
|
|
148
109
|
let cssString = '';
|
|
149
|
-
|
|
150
110
|
for (const key in obj) {
|
|
151
111
|
if (obj.hasOwnProperty(key)) {
|
|
152
112
|
const element = obj[key];
|
|
153
113
|
let selectors = element.selectors || [];
|
|
154
114
|
let elementCSS = '';
|
|
155
|
-
|
|
156
115
|
for (let prop in element) {
|
|
157
116
|
if (element.hasOwnProperty(prop) && prop !== 'selectors') {
|
|
158
|
-
// Convert camelCase to kebab-case
|
|
159
117
|
const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
160
118
|
elementCSS += ` ${kebabKey}: ${element[prop]};\n`;
|
|
161
119
|
}
|
|
162
120
|
}
|
|
163
|
-
|
|
164
121
|
cssString += `${selectors.join(', ')} {\n${elementCSS}}\n`;
|
|
165
122
|
}
|
|
166
123
|
}
|
|
167
|
-
|
|
168
124
|
chain.cssOutput = cssString.trim();
|
|
169
|
-
return cssString.trim();
|
|
125
|
+
return cssString.trim();
|
|
170
126
|
};
|
|
171
127
|
|
|
172
128
|
export {
|