chaincss 1.13.2 → 1.13.3
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 +6 -14
- package/browser/index.js +1 -1
- package/browser/rtt.js +39 -9
- package/browser/vue-composables.js +200 -0
- package/node/atomic-optimizer.js +279 -144
- package/node/btt.js +149 -102
- package/node/chaincss.js +197 -44
- package/node/prefixer.js +2 -2
- package/node/strVal.js +37 -51
- package/node/theme-validator.js +4 -4
- package/package.json +13 -3
- package/types.d.ts +51 -3
- package/node/css-properties.json +0 -633
package/README.md
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
[](https://opensource.org/licenses/MIT)
|
|
5
5
|
[](https://chaincss.dev)
|
|
6
6
|
|
|
7
|
-
>
|
|
7
|
+
> ChainCSS is the JavaScript-native styling engine for the modern web
|
|
8
8
|
|
|
9
9
|
> **Note:** The previous package `@melcanz85/chaincss` is no longer supported.
|
|
10
10
|
> **Please install `chaincss` instead:** `npm install chaincss`
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
| **Hover States** | `.hover().backgroundColor('blue').end()` |
|
|
22
22
|
| **Hover Exit** | `.end()` method to exit hover mode |
|
|
23
23
|
| **Nested Selectors** | `.select('.parent .child')` |
|
|
24
|
-
| **Token Resolution** |
|
|
24
|
+
| **Token Resolution** | `:colors.primary` → actual color value |
|
|
25
25
|
| **CSS Property Validation** | Warns on invalid CSS properties |
|
|
26
26
|
|
|
27
27
|
### At-Rules (CSS Rules)
|
|
@@ -44,7 +44,6 @@
|
|
|
44
44
|
| **Design Tokens** | `createTokens()` with colors, spacing, typography |
|
|
45
45
|
| **Token Getter** | `tokens.get('colors.primary')` |
|
|
46
46
|
| **Token Resolution in Styles** | `$colors.primary` syntax |
|
|
47
|
-
| **Responsive Values** | `responsive({ base: '16px', sm: '14px', lg: '18px' })` |
|
|
48
47
|
| **Theme Switching** | Dynamic token updates at runtime |
|
|
49
48
|
| **CSS Variables Output** | `tokens.toCSSVariables()` |
|
|
50
49
|
|
|
@@ -129,20 +128,13 @@
|
|
|
129
128
|
| **Atomic CSS Optimization** | Eliminates duplicate styles |
|
|
130
129
|
| **Cache Strategy** | File + compiled function cache |
|
|
131
130
|
|
|
132
|
-
### Security & Compatibility
|
|
133
131
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
| **No vm2** | Native Node.js module system |
|
|
138
|
-
| **Node.js 14+** | Minimum version requirement |
|
|
139
|
-
| **ESM/CJS Support** | Dual module format |
|
|
140
|
-
| **Browser Support** | Modern browsers via autoprefixer |
|
|
132
|
+
For complete guide, documentation, examples, and API reference see:
|
|
133
|
+
|
|
134
|
+
## [Documentation](https://www.chaincss.dev/docs)
|
|
141
135
|
|
|
142
|
-
|
|
136
|
+
|
|
143
137
|
|
|
144
|
-
For complete guide, documentation, examples, and API reference,
|
|
145
|
-
just go to the docs section of [https://chaincss.dev](https://www.chaincss.dev)
|
|
146
138
|
|
|
147
139
|
## License
|
|
148
140
|
|
package/browser/index.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
// ChainCSS Browser Entry Point
|
|
2
|
-
export { $, run, compile, chain, createTokens,
|
|
2
|
+
export { $, run, compile, chain, createTokens, tokens } from './rtt.js';
|
|
3
3
|
export { useChainStyles, useDynamicChainStyles, useThemeChainStyles, ChainCSSGlobal, withChainStyles, cx } from './react-hooks.js';
|
package/browser/rtt.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { tokens
|
|
1
|
+
import { tokens as importedTokens, DesignTokens } from '../shared/tokens.mjs';
|
|
2
2
|
|
|
3
3
|
let cachedProperties = null;
|
|
4
4
|
|
|
@@ -28,7 +28,7 @@ const loadCSSProperties = async () => {
|
|
|
28
28
|
});
|
|
29
29
|
|
|
30
30
|
cachedProperties = Array.from(baseProperties).sort();
|
|
31
|
-
console.log(
|
|
31
|
+
//console.log(`Loaded ${cachedProperties.length} CSS properties from CDN`);
|
|
32
32
|
return cachedProperties;
|
|
33
33
|
}
|
|
34
34
|
} catch (error) {
|
|
@@ -303,19 +303,43 @@ function $(useTokens = true) {
|
|
|
303
303
|
|
|
304
304
|
const run = (...args) => {
|
|
305
305
|
let cssOutput = '';
|
|
306
|
+
|
|
306
307
|
args.forEach((value) => {
|
|
307
308
|
if (value && value.selectors) {
|
|
308
|
-
let
|
|
309
|
+
let normalStyles = '';
|
|
310
|
+
let hoverStyles = '';
|
|
311
|
+
|
|
312
|
+
// Separate normal properties from hover
|
|
309
313
|
for (let key in value) {
|
|
310
|
-
if (key
|
|
314
|
+
if (key === 'selectors') continue;
|
|
315
|
+
|
|
316
|
+
if (key === 'hover' && typeof value[key] === 'object') {
|
|
317
|
+
// Build hover styles separately
|
|
318
|
+
hoverStyles = `${value.selectors.join(', ')}:hover {\n`;
|
|
319
|
+
for (let hoverKey in value[key]) {
|
|
320
|
+
const kebabKey = hoverKey.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
321
|
+
hoverStyles += ` ${kebabKey}: ${value[key][hoverKey]};\n`;
|
|
322
|
+
}
|
|
323
|
+
hoverStyles += `}\n`;
|
|
324
|
+
} else {
|
|
325
|
+
// Build normal styles
|
|
311
326
|
const kebabKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
|
|
312
|
-
|
|
327
|
+
normalStyles += ` ${kebabKey}: ${value[key]};\n`;
|
|
313
328
|
}
|
|
314
329
|
}
|
|
315
|
-
|
|
316
|
-
|
|
330
|
+
|
|
331
|
+
// Output normal styles
|
|
332
|
+
if (normalStyles) {
|
|
333
|
+
cssOutput += `${value.selectors.join(', ')} {\n${normalStyles}}\n`;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Output hover styles
|
|
337
|
+
if (hoverStyles) {
|
|
338
|
+
cssOutput += hoverStyles;
|
|
339
|
+
}
|
|
317
340
|
}
|
|
318
341
|
});
|
|
342
|
+
|
|
319
343
|
chain.cssOutput = cssOutput.trim();
|
|
320
344
|
return cssOutput.trim();
|
|
321
345
|
};
|
|
@@ -359,12 +383,18 @@ const compile = (obj) => {
|
|
|
359
383
|
return cssString.trim();
|
|
360
384
|
};
|
|
361
385
|
|
|
386
|
+
function createTokens(tokenValues) {
|
|
387
|
+
const tokenObj = new DesignTokens(tokenValues);
|
|
388
|
+
return tokenObj;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
const tokens = importedTokens;
|
|
392
|
+
|
|
362
393
|
export {
|
|
363
394
|
chain,
|
|
364
395
|
$,
|
|
365
396
|
run,
|
|
366
397
|
compile,
|
|
367
398
|
tokens,
|
|
368
|
-
createTokens
|
|
369
|
-
responsive
|
|
399
|
+
createTokens
|
|
370
400
|
};
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { computed, inject, provide, ref, watch } from 'vue';
|
|
2
|
+
|
|
3
|
+
// Symbol for providing the global ChainCSS instance
|
|
4
|
+
const CHAIN_CSS_KEY = Symbol('chaincss');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Core function to process styles and generate class names
|
|
8
|
+
*/
|
|
9
|
+
function processStyles(styles, atomic = true) {
|
|
10
|
+
const result = {};
|
|
11
|
+
|
|
12
|
+
for (const [key, styleFn] of Object.entries(styles)) {
|
|
13
|
+
if (typeof styleFn === 'function') {
|
|
14
|
+
result[key] = styleFn();
|
|
15
|
+
} else if (styleFn && typeof styleFn === 'object') {
|
|
16
|
+
// If it's already processed, use it
|
|
17
|
+
result[key] = styleFn;
|
|
18
|
+
} else {
|
|
19
|
+
result[key] = styleFn;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
return result;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Main composable for using ChainCSS in Vue components
|
|
28
|
+
* @param {Object|Ref|ComputedRef} styles - Style definitions
|
|
29
|
+
* @param {Object} options - Configuration options
|
|
30
|
+
* @returns {Object} - Classes object
|
|
31
|
+
*/
|
|
32
|
+
export function useAtomicClasses(styles, options = {}) {
|
|
33
|
+
const { atomic = true, global = false } = options;
|
|
34
|
+
|
|
35
|
+
// Get global ChainCSS instance if available
|
|
36
|
+
const chainCSS = inject(CHAIN_CSS_KEY, null);
|
|
37
|
+
|
|
38
|
+
// Create reactive classes
|
|
39
|
+
const classes = computed(() => {
|
|
40
|
+
// Resolve styles if it's a ref or computed
|
|
41
|
+
const resolvedStyles = typeof styles === 'function'
|
|
42
|
+
? styles()
|
|
43
|
+
: styles?.value || styles;
|
|
44
|
+
|
|
45
|
+
// Process the styles
|
|
46
|
+
const processed = processStyles(resolvedStyles, atomic);
|
|
47
|
+
|
|
48
|
+
// If we have a global ChainCSS instance, register styles
|
|
49
|
+
if (chainCSS && typeof chainCSS.register === 'function') {
|
|
50
|
+
chainCSS.register(processed, { atomic, global });
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
return processed;
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
classes,
|
|
58
|
+
// Helper to get specific class
|
|
59
|
+
cx: (name) => classes.value[name],
|
|
60
|
+
// Helper to combine multiple classes
|
|
61
|
+
cn: (...names) => names.map(name => classes.value[name]).filter(Boolean).join(' ')
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Component for injecting global styles
|
|
67
|
+
*/
|
|
68
|
+
export const ChainCSSGlobal = {
|
|
69
|
+
name: 'ChainCSSGlobal',
|
|
70
|
+
props: {
|
|
71
|
+
styles: {
|
|
72
|
+
type: Object,
|
|
73
|
+
required: true
|
|
74
|
+
},
|
|
75
|
+
atomic: {
|
|
76
|
+
type: Boolean,
|
|
77
|
+
default: true
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
setup(props) {
|
|
81
|
+
// Create a computed ref for styles
|
|
82
|
+
const globalStyles = computed(() => props.styles);
|
|
83
|
+
|
|
84
|
+
// Process and inject styles
|
|
85
|
+
const processedStyles = computed(() => {
|
|
86
|
+
return processStyles(globalStyles.value, props.atomic);
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// Provide ChainCSS instance to children
|
|
90
|
+
const chainCSSInstance = {
|
|
91
|
+
register: (styles, options) => {
|
|
92
|
+
// This would integrate with your actual ChainCSS runtime
|
|
93
|
+
console.log('Registering styles:', styles, options);
|
|
94
|
+
// TODO: Connect to actual ChainCSS runtime
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
|
|
98
|
+
provide(CHAIN_CSS_KEY, chainCSSInstance);
|
|
99
|
+
|
|
100
|
+
// In development, log the styles
|
|
101
|
+
if (process.env.NODE_ENV === 'development') {
|
|
102
|
+
watch(processedStyles, (styles) => {
|
|
103
|
+
console.log('[ChainCSS] Global styles registered:', styles);
|
|
104
|
+
}, { immediate: true });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// This component doesn't render anything
|
|
108
|
+
return () => null;
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
/**
|
|
113
|
+
* Create a themed component with ChainCSS styles
|
|
114
|
+
* @param {Object|Function} styles - Style definitions
|
|
115
|
+
* @param {Object} options - Component options
|
|
116
|
+
* @returns {Object} - Vue component
|
|
117
|
+
*/
|
|
118
|
+
export function createStyledComponent(styles, options = {}) {
|
|
119
|
+
const { name = 'StyledComponent', atomic = true } = options;
|
|
120
|
+
|
|
121
|
+
return {
|
|
122
|
+
name,
|
|
123
|
+
props: {
|
|
124
|
+
as: {
|
|
125
|
+
type: String,
|
|
126
|
+
default: 'div'
|
|
127
|
+
},
|
|
128
|
+
className: {
|
|
129
|
+
type: String,
|
|
130
|
+
default: ''
|
|
131
|
+
},
|
|
132
|
+
...options.props
|
|
133
|
+
},
|
|
134
|
+
setup(props, { slots, attrs }) {
|
|
135
|
+
// Resolve styles (can be a function that receives props)
|
|
136
|
+
const resolvedStyles = computed(() => {
|
|
137
|
+
if (typeof styles === 'function') {
|
|
138
|
+
return styles(props);
|
|
139
|
+
}
|
|
140
|
+
return styles;
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
const { classes, cn } = useAtomicClasses(resolvedStyles, { atomic });
|
|
144
|
+
|
|
145
|
+
// Combine classes
|
|
146
|
+
const combinedClasses = computed(() => {
|
|
147
|
+
return cn('root', props.className);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
return () => {
|
|
151
|
+
const tag = props.as;
|
|
152
|
+
const componentProps = {
|
|
153
|
+
...attrs,
|
|
154
|
+
class: combinedClasses.value
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
// Remove props that shouldn't be passed to DOM elements
|
|
158
|
+
delete componentProps.as;
|
|
159
|
+
|
|
160
|
+
return h(tag, componentProps, slots.default?.());
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Create a reactive theme system
|
|
168
|
+
* @param {Object} themes - Theme definitions
|
|
169
|
+
* @returns {Object} - Theme utilities
|
|
170
|
+
*/
|
|
171
|
+
export function createTheme(themes) {
|
|
172
|
+
const currentTheme = ref(Object.keys(themes)[0] || 'light');
|
|
173
|
+
|
|
174
|
+
const themeStyles = computed(() => {
|
|
175
|
+
return themes[currentTheme.value] || {};
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const setTheme = (themeName) => {
|
|
179
|
+
if (themes[themeName]) {
|
|
180
|
+
currentTheme.value = themeName;
|
|
181
|
+
}
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
const toggleTheme = () => {
|
|
185
|
+
const keys = Object.keys(themes);
|
|
186
|
+
const currentIndex = keys.indexOf(currentTheme.value);
|
|
187
|
+
const nextIndex = (currentIndex + 1) % keys.length;
|
|
188
|
+
currentTheme.value = keys[nextIndex];
|
|
189
|
+
};
|
|
190
|
+
|
|
191
|
+
return {
|
|
192
|
+
currentTheme: readonly(currentTheme),
|
|
193
|
+
themeStyles,
|
|
194
|
+
setTheme,
|
|
195
|
+
toggleTheme
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Import Vue's h function for createStyledComponent
|
|
200
|
+
import { h, readonly } from 'vue';
|