chaincss 1.13.3 → 2.0.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.
Files changed (101) hide show
  1. package/CHANGELOG.md +81 -0
  2. package/LICENSE +2 -3
  3. package/README.md +238 -105
  4. package/dist/cli/commands/build.d.ts +3 -0
  5. package/dist/cli/commands/build.d.ts.map +1 -0
  6. package/dist/cli/commands/compile.d.ts +3 -0
  7. package/dist/cli/commands/compile.d.ts.map +1 -0
  8. package/dist/cli/commands/init.d.ts +5 -0
  9. package/dist/cli/commands/init.d.ts.map +1 -0
  10. package/dist/cli/commands/timeline.d.ts +2 -0
  11. package/dist/cli/commands/timeline.d.ts.map +1 -0
  12. package/dist/cli/commands/watch.d.ts +6 -0
  13. package/dist/cli/commands/watch.d.ts.map +1 -0
  14. package/dist/cli/index.d.ts +2 -0
  15. package/dist/cli/index.d.ts.map +1 -0
  16. package/dist/cli/index.js +5960 -0
  17. package/dist/cli/types.d.ts +51 -0
  18. package/dist/cli/types.d.ts.map +1 -0
  19. package/dist/cli/utils/config-loader.d.ts +8 -0
  20. package/dist/cli/utils/config-loader.d.ts.map +1 -0
  21. package/dist/cli/utils/file-utils.d.ts +9 -0
  22. package/dist/cli/utils/file-utils.d.ts.map +1 -0
  23. package/dist/cli/utils/logger.d.ts +17 -0
  24. package/dist/cli/utils/logger.d.ts.map +1 -0
  25. package/dist/compiler/atomic-optimizer.d.ts +76 -0
  26. package/dist/compiler/atomic-optimizer.d.ts.map +1 -0
  27. package/dist/compiler/btt.d.ts +138 -0
  28. package/dist/compiler/btt.d.ts.map +1 -0
  29. package/dist/compiler/cache-manager.d.ts +20 -0
  30. package/dist/compiler/cache-manager.d.ts.map +1 -0
  31. package/dist/compiler/commonProps.d.ts +2 -0
  32. package/dist/compiler/commonProps.d.ts.map +1 -0
  33. package/dist/compiler/index.d.ts +12 -0
  34. package/dist/compiler/index.d.ts.map +1 -0
  35. package/dist/compiler/index.js +5177 -0
  36. package/dist/compiler/prefixer.d.ts +42 -0
  37. package/dist/compiler/prefixer.d.ts.map +1 -0
  38. package/dist/compiler/theme-contract.d.ts +61 -0
  39. package/dist/compiler/theme-contract.d.ts.map +1 -0
  40. package/dist/compiler/tokens.d.ts +52 -0
  41. package/dist/compiler/tokens.d.ts.map +1 -0
  42. package/dist/compiler/types.d.ts +57 -0
  43. package/dist/compiler/types.d.ts.map +1 -0
  44. package/dist/core/compiler.d.ts +32 -0
  45. package/dist/core/compiler.d.ts.map +1 -0
  46. package/dist/core/constants.d.ts +129 -0
  47. package/dist/core/constants.d.ts.map +1 -0
  48. package/dist/core/index.d.ts +4 -0
  49. package/dist/core/index.d.ts.map +1 -0
  50. package/dist/core/types.d.ts +88 -0
  51. package/dist/core/types.d.ts.map +1 -0
  52. package/dist/core/utils.d.ts +37 -0
  53. package/dist/core/utils.d.ts.map +1 -0
  54. package/dist/index.d.ts +13 -0
  55. package/dist/index.d.ts.map +1 -0
  56. package/dist/index.js +5667 -0
  57. package/dist/plugins/vite.d.ts +11 -0
  58. package/dist/plugins/vite.d.ts.map +1 -0
  59. package/dist/plugins/vite.js +25839 -0
  60. package/dist/plugins/webpack.d.ts +45 -0
  61. package/dist/plugins/webpack.d.ts.map +1 -0
  62. package/dist/plugins/webpack.js +107 -0
  63. package/dist/runtime/hmr.d.ts +3 -0
  64. package/dist/runtime/hmr.d.ts.map +1 -0
  65. package/dist/runtime/index.d.ts +15 -0
  66. package/dist/runtime/index.d.ts.map +1 -0
  67. package/dist/runtime/index.js +552 -0
  68. package/dist/runtime/injector.d.ts +85 -0
  69. package/dist/runtime/injector.d.ts.map +1 -0
  70. package/dist/runtime/react.d.ts +54 -0
  71. package/dist/runtime/react.d.ts.map +1 -0
  72. package/dist/runtime/react.js +270 -0
  73. package/dist/runtime/types.d.ts +45 -0
  74. package/dist/runtime/types.d.ts.map +1 -0
  75. package/dist/runtime/utils.d.ts +62 -0
  76. package/dist/runtime/utils.d.ts.map +1 -0
  77. package/dist/runtime/vue.d.ts +52 -0
  78. package/dist/runtime/vue.d.ts.map +1 -0
  79. package/dist/runtime/vue.js +232 -0
  80. package/package.json +90 -119
  81. package/browser/commonProps.js +0 -14
  82. package/browser/index.js +0 -3
  83. package/browser/react-hooks.js +0 -162
  84. package/browser/rtt.js +0 -400
  85. package/browser/vue-composables.js +0 -200
  86. package/node/atomic-optimizer.js +0 -526
  87. package/node/btt.js +0 -1009
  88. package/node/cache-manager.js +0 -56
  89. package/node/chaincss.js +0 -642
  90. package/node/index.js +0 -2
  91. package/node/loaders/chaincss-loader.js +0 -62
  92. package/node/plugins/next-plugin.js +0 -120
  93. package/node/plugins/vite-plugin.js +0 -383
  94. package/node/plugins/webpack-plugin.js +0 -41
  95. package/node/prefixer.js +0 -237
  96. package/node/strVal.js +0 -92
  97. package/node/theme-validator.js +0 -32
  98. package/shared/theme-contract.js +0 -98
  99. package/shared/tokens.cjs +0 -256
  100. package/shared/tokens.mjs +0 -320
  101. package/types.d.ts +0 -325
package/node/btt.js DELETED
@@ -1,1009 +0,0 @@
1
- const path = require('path');
2
- const fs = require('fs');
3
- const https = require('https');
4
- const {tokens, DesignTokens } = require('../shared/tokens.cjs');
5
- const { COMMON_CSS_PROPERTIES } = require('../browser/commonProps.js');
6
-
7
- // Remove the hardcoded atomicOptimizer instance
8
- let atomicOptimizer = null;
9
-
10
- // Function to set the atomic optimizer from outside
11
- function setAtomicOptimizer(optimizer) {
12
- atomicOptimizer = optimizer;
13
- }
14
-
15
- function configureAtomic(opts) {
16
- if (atomicOptimizer) {
17
- Object.assign(atomicOptimizer.options, opts);
18
- }
19
- }
20
-
21
- // Helper function for Node.js HTTP requests (for older Node versions)
22
- const fetchWithHttps = (url) => {
23
- return new Promise((resolve, reject) => {
24
- const timeout = setTimeout(() => {
25
- req.destroy();
26
- reject(new Error('Request timeout'));
27
- }, 3000);
28
-
29
- const req = https.get(url, (response) => {
30
- clearTimeout(timeout);
31
- let data = '';
32
- response.on('data', (chunk) => data += chunk);
33
- response.on('end', () => {
34
- try {
35
- resolve(JSON.parse(data));
36
- } catch (error) {
37
- reject(error);
38
- }
39
- });
40
- });
41
-
42
- req.on('error', (error) => {
43
- clearTimeout(timeout);
44
- reject(error);
45
- });
46
- });
47
- };
48
-
49
- const loadCSSProperties = async () => {
50
- // Return cached if already loaded
51
- if (chain.cachedValidProperties !== null) {
52
- return chain.cachedValidProperties;
53
- }
54
-
55
- // Try CDN first (only once) - same as runtime
56
- try {
57
- const url = 'https://raw.githubusercontent.com/mdn/data/main/css/properties.json';
58
- let data;
59
-
60
- // Use fetch if available (Node 18+), otherwise use https
61
- if (globalThis.fetch) {
62
- const controller = new AbortController();
63
- const timeoutId = setTimeout(() => controller.abort(), 3000);
64
- const response = await fetch(url, { signal: controller.signal });
65
- clearTimeout(timeoutId);
66
- data = await response.json();
67
- } else {
68
- // Fallback for older Node versions
69
- data = await fetchWithHttps(url);
70
- }
71
-
72
- const allProperties = Object.keys(data);
73
- const baseProperties = new Set();
74
-
75
- allProperties.forEach(prop => {
76
- const baseProp = prop.replace(/^-(webkit|moz|ms|o)-/, '');
77
- baseProperties.add(baseProp);
78
- });
79
-
80
- chain.cachedValidProperties = Array.from(baseProperties).sort();
81
- return chain.cachedValidProperties;
82
-
83
- } catch (error) {
84
- // Use imported fallback (clean and separate)
85
- chain.cachedValidProperties = COMMON_CSS_PROPERTIES;
86
- return chain.cachedValidProperties;
87
- }
88
- };
89
-
90
- const chain = {
91
- cssOutput: undefined,
92
- catcher: {},
93
- cachedValidProperties: [],
94
- classMap: {},
95
- atomicStats: null,
96
-
97
- async initializeProperties() {
98
- if (this.cachedValidProperties.length > 0) {
99
- return;
100
- }
101
-
102
- const properties = await loadCSSProperties();
103
- this.cachedValidProperties = properties;
104
- },
105
-
106
- getCachedProperties() {
107
- return this.cachedValidProperties;
108
- }
109
- };
110
-
111
- chain.initializeProperties();
112
-
113
- //token pointer
114
- const originalToken = tokens;
115
-
116
- let currentTokenContext = null;
117
-
118
- // createTokens pointer
119
- function createTokens(tokenValues) {
120
- const tokenObj = new DesignTokens(tokenValues);
121
- currentTokenContext = tokenObj;
122
- return tokenObj;
123
- }
124
-
125
- function $(useTokens = true) {
126
- const catcher = {};
127
- let validProperties = chain.cachedValidProperties;
128
- const tokenContext = currentTokenContext || null;
129
-
130
- const resolveToken = (value) => {
131
- if (!useTokens || typeof value !== 'string') return value;
132
-
133
- // Check if string contains any token patterns
134
- if (value.includes('$')) {
135
- // Replace all $token.path patterns with their resolved values
136
- return value.replace(/\$([a-zA-Z0-9.-]+)/g, (match, path) => {
137
- if (tokenContext) {
138
- const resolved = tokenContext.get(path);
139
- if (resolved !== undefined) {
140
- return resolved;
141
- }
142
- }
143
- // Also try global tokens as fallback
144
- const globalResolved = tokens.get(path);
145
- if (globalResolved !== undefined) {
146
- return globalResolved;
147
- }
148
- return match; // Return original if not found
149
- });
150
- }
151
-
152
- return value;
153
- };
154
-
155
- const handler = {
156
- get: (target, prop) => {
157
- // Handle .block()
158
- if (prop === 'block') {
159
- return function(...args) {
160
- if (args.length === 0) {
161
- const result = { ...catcher };
162
- Object.keys(catcher).forEach(key => delete catcher[key]);
163
- return result;
164
- }
165
- const result = {
166
- selectors: args,
167
- ...catcher
168
- };
169
- Object.keys(catcher).forEach(key => delete catcher[key]);
170
- return result;
171
- };
172
- }
173
-
174
- // Handle .hover()
175
- if (prop === 'hover') {
176
- return () => {
177
- const hoverCatcher = {};
178
- const hoverHandler = {
179
- get: (hoverTarget, hoverProp) => {
180
- if (hoverProp === 'end') {
181
- return () => {
182
- catcher.hover = { ...hoverCatcher };
183
- Object.keys(hoverCatcher).forEach(key => delete hoverCatcher[key]);
184
- return proxy;
185
- };
186
- }
187
- const cssProperty = hoverProp.replace(/([A-Z])/g, '-$1').toLowerCase();
188
- if (validProperties && validProperties.length > 0 && !validProperties.includes(cssProperty)) {
189
- console.warn(`Warning: '${cssProperty}' may not be a valid CSS property`);
190
- }
191
- return (value) => {
192
- hoverCatcher[hoverProp] = resolveToken(value, useTokens);
193
- return hoverProxy;
194
- };
195
- }
196
- };
197
- const hoverProxy = new Proxy({}, hoverHandler);
198
- return hoverProxy;
199
- };
200
- }
201
-
202
- // Handle .end()
203
- if (prop === 'end') {
204
- return () => {
205
- return proxy;
206
- };
207
- }
208
-
209
- // Handle .select() - nested selectors
210
- if (prop === 'select') {
211
- return function(selector) {
212
- const nestedStyles = {};
213
- const nestedHandler = {
214
- get: (nestedTarget, nestedProp) => {
215
- if (nestedProp === 'block') {
216
- return () => {
217
- if (!catcher.nestedRules) catcher.nestedRules = [];
218
- catcher.nestedRules.push({
219
- selector: selector,
220
- styles: { ...nestedStyles }
221
- });
222
- return proxy;
223
- };
224
- }
225
- return (value) => {
226
- nestedStyles[nestedProp] = resolveToken(value, useTokens);
227
- return nestedProxy;
228
- };
229
- }
230
- };
231
- const nestedProxy = new Proxy({}, nestedHandler);
232
- return nestedProxy;
233
- };
234
- }
235
-
236
- // ========== AT-RULES ==========
237
-
238
- // @media
239
- if (prop === 'media') {
240
- return function(query, callback) {
241
- const subChain = $(useTokens);
242
- const result = callback(subChain);
243
- if (!catcher.atRules) catcher.atRules = [];
244
- catcher.atRules.push({
245
- type: 'media',
246
- query: query,
247
- styles: result
248
- });
249
- return proxy;
250
- };
251
- }
252
-
253
- // @keyframes
254
- if (prop === 'keyframes') {
255
- return function(name, callback) {
256
- const keyframeContext = { _keyframeSteps: {} };
257
- const keyframeProxy = new Proxy(keyframeContext, {
258
- get: (target, stepProp) => {
259
- if (stepProp === 'from' || stepProp === 'to') {
260
- return function(stepCallback) {
261
- const subChain = $(useTokens);
262
- const properties = stepCallback(subChain).block();
263
- target._keyframeSteps[stepProp] = properties;
264
- return keyframeProxy;
265
- };
266
- }
267
- if (stepProp === 'percent') {
268
- return function(value, stepCallback) {
269
- const subChain = $(useTokens);
270
- const properties = stepCallback(subChain).block();
271
- target._keyframeSteps[`${value}%`] = properties;
272
- return keyframeProxy;
273
- };
274
- }
275
- return undefined;
276
- }
277
- });
278
- callback(keyframeProxy);
279
- if (!catcher.atRules) catcher.atRules = [];
280
- catcher.atRules.push({
281
- type: 'keyframes',
282
- name: name,
283
- steps: keyframeContext._keyframeSteps
284
- });
285
- return proxy;
286
- };
287
- }
288
-
289
- // @font-face
290
- if (prop === 'fontFace') {
291
- return function(callback) {
292
- const fontProps = {};
293
- const fontHandler = {
294
- get: (target, fontProp) => {
295
- return (value) => {
296
- fontProps[fontProp] = resolveToken(value, useTokens);
297
- return fontProxy;
298
- };
299
- }
300
- };
301
- const fontProxy = new Proxy({}, fontHandler);
302
- callback(fontProxy);
303
-
304
- if (!catcher.atRules) catcher.atRules = [];
305
- catcher.atRules.push({
306
- type: 'font-face',
307
- properties: fontProps
308
- });
309
- return proxy;
310
- };
311
- }
312
-
313
- // @supports
314
- if (prop === 'supports') {
315
- return function(condition, callback) {
316
- const subChain = $(useTokens);
317
- const result = callback(subChain);
318
- if (!catcher.atRules) catcher.atRules = [];
319
- catcher.atRules.push({
320
- type: 'supports',
321
- condition: condition,
322
- styles: result
323
- });
324
- return proxy;
325
- };
326
- }
327
-
328
- // @container
329
- if (prop === 'container') {
330
- return function(condition, callback) {
331
- const subChain = $(useTokens);
332
- const result = callback(subChain);
333
- if (!catcher.atRules) catcher.atRules = [];
334
- catcher.atRules.push({
335
- type: 'container',
336
- condition: condition,
337
- styles: result
338
- });
339
- return proxy;
340
- };
341
- }
342
-
343
- // @layer
344
- if (prop === 'layer') {
345
- return function(name, callback) {
346
- const subChain = $(useTokens);
347
- const result = callback(subChain);
348
- if (!catcher.atRules) catcher.atRules = [];
349
- catcher.atRules.push({
350
- type: 'layer',
351
- name: name,
352
- styles: result
353
- });
354
- return proxy;
355
- };
356
- }
357
-
358
- // @counter-style
359
- if (prop === 'counterStyle') {
360
- return function(name, callback) {
361
- const counterProps = {};
362
- const counterHandler = {
363
- get: (target, counterProp) => {
364
- return (value) => {
365
- counterProps[counterProp] = resolveToken(value, useTokens);
366
- return counterProxy;
367
- };
368
- }
369
- };
370
- const counterProxy = new Proxy({}, counterHandler);
371
- callback(counterProxy);
372
-
373
- if (!catcher.atRules) catcher.atRules = [];
374
- catcher.atRules.push({
375
- type: 'counter-style',
376
- name: name,
377
- properties: counterProps
378
- });
379
- return proxy;
380
- };
381
- }
382
-
383
- // @property
384
- if (prop === 'property') {
385
- return function(name, callback) {
386
- const propertyDescs = {};
387
- const propertyHandler = {
388
- get: (target, descProp) => {
389
- return (value) => {
390
- propertyDescs[descProp] = resolveToken(value, useTokens);
391
- return propertyProxy;
392
- };
393
- }
394
- };
395
- const propertyProxy = new Proxy({}, propertyHandler);
396
- callback(propertyProxy);
397
-
398
- if (!catcher.atRules) catcher.atRules = [];
399
- catcher.atRules.push({
400
- type: 'property',
401
- name: name,
402
- descriptors: propertyDescs
403
- });
404
- return proxy;
405
- };
406
- }
407
-
408
- // theme method
409
- if (prop === 'theme') {
410
- return function(themeTokens, callback) {
411
- const originalTokens = tokens;
412
-
413
- const themeTokenStore = {
414
- get: (path) => {
415
- const themeValue = themeTokens.get ? themeTokens.get(path) : null;
416
- if (themeValue !== null && themeValue !== undefined) {
417
- return themeValue;
418
- }
419
- return originalTokens.get(path);
420
- },
421
- ...themeTokens
422
- };
423
-
424
- const tokenProxy = new Proxy(themeTokenStore, {
425
- get: (target, prop) => {
426
- if (prop === 'get') {
427
- return target.get.bind(target);
428
- }
429
- return target[prop];
430
- }
431
- });
432
-
433
- const originalTokensRef = globalThis.__CHAINCSS_TOKENS__ || tokens;
434
- const tempTokens = themeTokenStore;
435
-
436
- const themed$ = (useTokens = true) => {
437
- const originalResolver = resolveToken;
438
-
439
- const themeResolver = (value, useTokensFlag) => {
440
- if (!useTokensFlag || typeof value !== 'string' || !value.startsWith('$')) {
441
- return value;
442
- }
443
- const tokenPath = value.slice(1);
444
- const tokenValue = tempTokens.get(tokenPath);
445
- return tokenValue || value;
446
- };
447
-
448
- globalThis.__CHAINCSS_TEMP_RESOLVER__ = themeResolver;
449
-
450
- const result = $(useTokens);
451
-
452
- delete globalThis.__CHAINCSS_TEMP_RESOLVER__;
453
-
454
- return result;
455
- };
456
-
457
- const result = callback(themed$);
458
-
459
- if (!catcher.themes) catcher.themes = [];
460
- catcher.themes.push({
461
- name: `theme-${Date.now()}`,
462
- styles: result,
463
- tokens: themeTokens,
464
- fallback: originalTokens
465
- });
466
-
467
- return proxy;
468
- };
469
- }
470
-
471
- // Regular CSS properties
472
- const cssProperty = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
473
- if (validProperties && validProperties.length > 0 && !validProperties.includes(cssProperty)) {
474
- console.warn(`Warning: '${cssProperty}' may not be a valid CSS property`);
475
- }
476
-
477
- return function(value) {
478
- catcher[prop] = resolveToken(value, useTokens);
479
- return proxy;
480
- };
481
- }
482
- };
483
-
484
- const proxy = new Proxy({}, handler);
485
- return proxy;
486
- }
487
-
488
- // Process at-rules for CSS generation
489
- function processAtRule(rule, parentSelectors = null) {
490
- let output = '';
491
-
492
- switch(rule.type) {
493
- case 'media':
494
- if (parentSelectors) {
495
- let mediaBody = '';
496
- if (rule.styles && typeof rule.styles === 'object') {
497
- for (let prop in rule.styles) {
498
- if (prop !== 'selectors' && rule.styles.hasOwnProperty(prop)) {
499
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
500
- mediaBody += ` ${kebabKey}: ${rule.styles[prop]};\n`;
501
- }
502
- }
503
- }
504
- if (mediaBody.trim()) {
505
- output = `@media ${rule.query} {\n ${parentSelectors.join(', ')} {\n${mediaBody} }\n}\n`;
506
- }
507
- } else {
508
- output = `@media ${rule.query} {\n`;
509
- if (rule.styles && rule.styles.selectors) {
510
- let ruleBody = '';
511
- for (let prop in rule.styles) {
512
- if (prop !== 'selectors' && rule.styles.hasOwnProperty(prop)) {
513
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
514
- ruleBody += ` ${kebabKey}: ${rule.styles[prop]};\n`;
515
- }
516
- }
517
- if (ruleBody.trim()) {
518
- output += ` ${rule.styles.selectors.join(', ')} {\n${ruleBody} }\n`;
519
- }
520
- }
521
- output += '}\n';
522
- }
523
- break;
524
-
525
- case 'keyframes':
526
- output = `@keyframes ${rule.name} {\n`;
527
- for (let step in rule.steps) {
528
- output += ` ${step} {\n`;
529
- for (let prop in rule.steps[step]) {
530
- if (prop !== 'selectors') {
531
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
532
- output += ` ${kebabKey}: ${rule.steps[step][prop]};\n`;
533
- }
534
- }
535
- output += ' }\n';
536
- }
537
- output += '}\n';
538
- break;
539
-
540
- case 'font-face':
541
- output = '@font-face {\n';
542
- for (let prop in rule.properties) {
543
- if (prop !== 'selectors') {
544
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
545
- output += ` ${kebabKey}: ${rule.properties[prop]};\n`;
546
- }
547
- }
548
- output += '}\n';
549
- break;
550
-
551
- case 'supports':
552
- output = `@supports ${rule.condition} {\n`;
553
- if (rule.styles && rule.styles.selectors) {
554
- let ruleBody = '';
555
- for (let prop in rule.styles) {
556
- if (prop !== 'selectors' && rule.styles.hasOwnProperty(prop)) {
557
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
558
- ruleBody += ` ${kebabKey}: ${rule.styles[prop]};\n`;
559
- }
560
- }
561
- if (ruleBody.trim()) {
562
- output += ` ${rule.styles.selectors.join(', ')} {\n${ruleBody} }\n`;
563
- }
564
- }
565
- output += '}\n';
566
- break;
567
-
568
- case 'container':
569
- output = `@container ${rule.condition} {\n`;
570
- if (rule.styles && rule.styles.selectors) {
571
- let ruleBody = '';
572
- for (let prop in rule.styles) {
573
- if (prop !== 'selectors' && rule.styles.hasOwnProperty(prop)) {
574
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
575
- ruleBody += ` ${kebabKey}: ${rule.styles[prop]};\n`;
576
- }
577
- }
578
- if (ruleBody.trim()) {
579
- output += ` ${rule.styles.selectors.join(', ')} {\n${ruleBody} }\n`;
580
- }
581
- }
582
- output += '}\n';
583
- break;
584
-
585
- case 'layer':
586
- output = `@layer ${rule.name} {\n`;
587
- if (rule.styles && rule.styles.selectors) {
588
- let ruleBody = '';
589
- for (let prop in rule.styles) {
590
- if (prop !== 'selectors' && rule.styles.hasOwnProperty(prop)) {
591
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
592
- ruleBody += ` ${kebabKey}: ${rule.styles[prop]};\n`;
593
- }
594
- }
595
- if (ruleBody.trim()) {
596
- output += ` ${rule.styles.selectors.join(', ')} {\n${ruleBody} }\n`;
597
- }
598
- }
599
- output += '}\n';
600
- break;
601
-
602
- case 'counter-style':
603
- output = `@counter-style ${rule.name} {\n`;
604
- for (let prop in rule.properties) {
605
- if (prop !== 'selectors') {
606
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
607
- output += ` ${kebabKey}: ${rule.properties[prop]};\n`;
608
- }
609
- }
610
- output += '}\n';
611
- break;
612
-
613
- case 'property':
614
- output = `@property ${rule.name} {\n`;
615
- for (let desc in rule.descriptors) {
616
- if (desc !== 'selectors') {
617
- const kebabKey = desc.replace(/([A-Z])/g, '-$1').toLowerCase();
618
- output += ` ${kebabKey}: ${rule.descriptors[desc]};\n`;
619
- }
620
- }
621
- output += '}\n';
622
- break;
623
- }
624
-
625
- return output;
626
- }
627
-
628
- function processStandaloneAtRule(rule) {
629
- let output = '';
630
-
631
- switch(rule.type) {
632
- case 'font-face':
633
- output = '@font-face {\n';
634
- for (let prop in rule.properties) {
635
- if (prop !== 'selectors') {
636
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
637
- output += ` ${kebabKey}: ${rule.properties[prop]};\n`;
638
- }
639
- }
640
- output += '}\n';
641
- break;
642
-
643
- case 'keyframes':
644
- output = `@keyframes ${rule.name} {\n`;
645
- for (let step in rule.steps) {
646
- output += ` ${step} {\n`;
647
- for (let prop in rule.steps[step]) {
648
- if (prop !== 'selectors') {
649
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
650
- output += ` ${kebabKey}: ${rule.steps[step][prop]};\n`;
651
- }
652
- }
653
- output += ' }\n';
654
- }
655
- output += '}\n';
656
- break;
657
-
658
- case 'counter-style':
659
- output = `@counter-style ${rule.name} {\n`;
660
- for (let prop in rule.properties) {
661
- if (prop !== 'selectors') {
662
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
663
- output += ` ${kebabKey}: ${rule.properties[prop]};\n`;
664
- }
665
- }
666
- output += '}\n';
667
- break;
668
-
669
- case 'property':
670
- output = `@property ${rule.name} {\n`;
671
- for (let desc in rule.descriptors) {
672
- if (desc !== 'selectors') {
673
- const kebabKey = desc.replace(/([A-Z])/g, '-$1').toLowerCase();
674
- output += ` ${kebabKey}: ${rule.descriptors[desc]};\n`;
675
- }
676
- }
677
- output += '}\n';
678
- break;
679
- }
680
-
681
- return output;
682
- }
683
-
684
- // btt.js - Updated run() function
685
- const run = (...args) => {
686
- let cssOutput = '';
687
- const styleObjs = [];
688
-
689
- args.forEach((value) => {
690
- if (!value) return;
691
- styleObjs.push(value);
692
-
693
- if (value.selectors) {
694
- let mainRuleBody = '';
695
- let atRulesOutput = '';
696
-
697
- for (let key in value) {
698
- if (key === 'selectors' || !value.hasOwnProperty(key)) continue;
699
-
700
- if (key === 'atRules' && Array.isArray(value[key])) {
701
- value[key].forEach(rule => {
702
- atRulesOutput += processAtRule(rule, value.selectors);
703
- });
704
- continue;
705
- }
706
-
707
- if (key === 'nestedRules' && Array.isArray(value[key])) {
708
- value[key].forEach(rule => {
709
- let nestedBody = '';
710
- for (let prop in rule.styles) {
711
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
712
- nestedBody += ` ${kebabKey}: ${rule.styles[prop]};\n`;
713
- }
714
- if (nestedBody) {
715
- atRulesOutput += `${value.selectors.join(', ')} ${rule.selector} {\n${nestedBody} }\n`;
716
- }
717
- });
718
- continue;
719
- }
720
-
721
- if (key === 'hover' && typeof value[key] === 'object') {
722
- let hoverBody = '';
723
- for (let hoverKey in value[key]) {
724
- const kebabKey = hoverKey.replace(/([A-Z])/g, '-$1').toLowerCase();
725
- hoverBody += ` ${kebabKey}: ${value[key][hoverKey]};\n`;
726
- }
727
- if (hoverBody) {
728
- cssOutput += `${value.selectors.join(', ')}:hover {\n${hoverBody}}\n`;
729
- }
730
- continue;
731
- }
732
-
733
- const kebabKey = key.replace(/([A-Z])/g, '-$1').toLowerCase();
734
- mainRuleBody += ` ${kebabKey}: ${value[key]};\n`;
735
- }
736
-
737
- if (mainRuleBody.trim()) {
738
- cssOutput += `${value.selectors.join(', ')} {\n${mainRuleBody}}\n`;
739
- }
740
- cssOutput += atRulesOutput;
741
-
742
- } else if (value.type) {
743
- cssOutput += processStandaloneAtRule(value);
744
- }
745
- });
746
-
747
- cssOutput = cssOutput.replace(/\n{3,}/g, '\n\n').trim();
748
- chain.cssOutput = cssOutput;
749
-
750
- // Use the injected atomic optimizer
751
- if (atomicOptimizer && atomicOptimizer.options.enabled) {
752
- const result = atomicOptimizer.optimize(styleObjs);
753
-
754
- // IMPORTANT: In component-first mode, we need to combine
755
- // atomic utilities with the component CSS
756
- if (atomicOptimizer.options.outputStrategy === 'component-first') {
757
- // Component CSS already contains all styles, but we want to add
758
- // atomic utilities as optional extras. The atomic optimizer's result.css
759
- // already includes atomicCSS + componentCSS (with all styles)
760
- chain.cssOutput = result.css;
761
- } else {
762
- // utility-first mode
763
- chain.cssOutput = result.css;
764
- }
765
-
766
- chain.classMap = result.map;
767
- chain.atomicStats = result.stats;
768
- return chain.cssOutput;
769
- }
770
-
771
- return cssOutput;
772
- };
773
-
774
- const compile = (obj) => {
775
- let cssString = '';
776
- const collected = [];
777
-
778
- for (const key in obj) {
779
- if (!obj.hasOwnProperty(key)) continue;
780
- const element = obj[key];
781
-
782
- // Handle themes
783
- if (element.themes && Array.isArray(element.themes)) {
784
- element.themes.forEach(theme => {
785
- if (theme.styles && theme.styles.selectors) {
786
- let themeCSS = '';
787
- let themeSelectors = theme.styles.selectors || [];
788
-
789
- for (let prop in theme.styles) {
790
- if (prop !== 'selectors' && theme.styles.hasOwnProperty(prop)) {
791
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
792
- themeCSS += ` ${kebabKey}: ${theme.styles[prop]};\n`;
793
- }
794
- }
795
-
796
- if (themeCSS) {
797
- cssString += `${themeSelectors.join(', ')} {\n${themeCSS}}\n`;
798
- }
799
- }
800
- });
801
- continue;
802
- }
803
-
804
- if (element.atRules && Array.isArray(element.atRules)) {
805
- element.atRules.forEach(rule => {
806
- cssString += processAtRule(rule, null);
807
- });
808
- continue;
809
- }
810
-
811
- if (element.selectors) {
812
- collected.push(element);
813
- let elementCSS = '';
814
- let atRulesCSS = '';
815
-
816
- for (let prop in element) {
817
- if (prop === 'selectors' || !element.hasOwnProperty(prop)) continue;
818
-
819
- if (prop === 'atRules' && Array.isArray(element[prop])) {
820
- element[prop].forEach(rule => {
821
- atRulesCSS += processAtRule(rule, element.selectors);
822
- });
823
- } else if (prop === 'themes' && Array.isArray(element[prop])) {
824
- continue;
825
- } else if (prop === 'hover' && typeof element[prop] === 'object') {
826
- let hoverBody = '';
827
- for (let hoverKey in element[prop]) {
828
- const kebabKey = hoverKey.replace(/([A-Z])/g, '-$1').toLowerCase();
829
- hoverBody += ` ${kebabKey}: ${element[prop][hoverKey]};\n`;
830
- }
831
- if (hoverBody) {
832
- cssString += `${element.selectors.join(', ')}:hover {\n${hoverBody}}\n`;
833
- }
834
- } else {
835
- const kebabKey = prop.replace(/([A-Z])/g, '-$1').toLowerCase();
836
- elementCSS += ` ${kebabKey}: ${element[prop]};\n`;
837
- }
838
- }
839
-
840
- if (elementCSS.trim()) {
841
- cssString += `${element.selectors.join(', ')} {\n${elementCSS}}\n`;
842
- }
843
- cssString += atRulesCSS;
844
- }
845
- }
846
-
847
- chain.cssOutput = cssString.trim();
848
-
849
- // Use the injected atomic optimizer instead of a local instance
850
- if (atomicOptimizer && atomicOptimizer.options.enabled) {
851
- const result = atomicOptimizer.optimize(collected);
852
- chain.cssOutput = result.css;
853
- chain.classMap = result.map;
854
- chain.atomicStats = result.stats;
855
- chain.componentMap = result.componentMap;
856
- return result.css;
857
- }
858
-
859
- return chain.cssOutput;
860
- };
861
-
862
- function recipe(options) {
863
- const {
864
- base,
865
- variants = {},
866
- defaultVariants = {},
867
- compoundVariants = []
868
- } = options;
869
-
870
- const baseStyle = typeof base === 'function' ? base() : base;
871
- const variantStyles = {};
872
-
873
- for (const [variantName, variantMap] of Object.entries(variants)) {
874
- variantStyles[variantName] = {};
875
- for (const [variantKey, variantStyle] of Object.entries(variantMap)) {
876
- variantStyles[variantName][variantKey] = typeof variantStyle === 'function'
877
- ? variantStyle()
878
- : variantStyle;
879
- }
880
- }
881
-
882
- const compoundStyles = compoundVariants.map(cv => ({
883
- condition: cv.variants || cv,
884
- style: typeof cv.style === 'function' ? cv.style() : cv.style
885
- }));
886
-
887
- function mergeStyles(...styles) {
888
- const merged = {};
889
- for (const style of styles) {
890
- if (!style) continue;
891
- for (const [key, value] of Object.entries(style)) {
892
- if (key === 'selectors') {
893
- merged.selectors = merged.selectors || [];
894
- merged.selectors.push(...(Array.isArray(value) ? value : [value]));
895
- } else if (key === 'hover' && typeof value === 'object') {
896
- if (!merged.hover) merged.hover = {};
897
- Object.assign(merged.hover, value);
898
- } else if (key !== 'selectors') {
899
- merged[key] = value;
900
- }
901
- }
902
- }
903
- return merged;
904
- }
905
-
906
- function pick(variantSelection = {}) {
907
- const selected = { ...defaultVariants, ...variantSelection };
908
- const stylesToMerge = [];
909
-
910
- if (baseStyle) stylesToMerge.push(baseStyle);
911
- for (const [variantName, variantValue] of Object.entries(selected)) {
912
- const variantStyle = variantStyles[variantName]?.[variantValue];
913
- if (variantStyle) stylesToMerge.push(variantStyle);
914
- }
915
- for (const cv of compoundStyles) {
916
- const matches = Object.entries(cv.condition).every(
917
- ([key, value]) => selected[key] === value
918
- );
919
- if (matches && cv.style) stylesToMerge.push(cv.style);
920
- }
921
-
922
- const merged = mergeStyles(...stylesToMerge);
923
-
924
- const styleBuilder = $(true);
925
- for (const [prop, value] of Object.entries(merged)) {
926
- if (prop === 'selectors' || prop === 'hover') continue;
927
- if (styleBuilder[prop]) styleBuilder[prop](value);
928
- }
929
-
930
- if (merged.hover) {
931
- styleBuilder.hover();
932
- for (const [hoverProp, hoverValue] of Object.entries(merged.hover)) {
933
- if (styleBuilder[hoverProp]) styleBuilder[hoverProp](hoverValue);
934
- }
935
- styleBuilder.end();
936
- }
937
-
938
- const selectors = merged.selectors || [];
939
- return styleBuilder.block(...selectors);
940
- }
941
-
942
- pick.variants = variants;
943
- pick.defaultVariants = defaultVariants;
944
- pick.base = baseStyle;
945
-
946
- pick.getAllVariants = () => {
947
- const result = [];
948
- const variantKeys = Object.keys(variants);
949
-
950
- function generate(current, index) {
951
- if (index === variantKeys.length) {
952
- result.push({ ...current });
953
- return;
954
- }
955
- const variantName = variantKeys[index];
956
- for (const variantValue of Object.keys(variants[variantName])) {
957
- current[variantName] = variantValue;
958
- generate(current, index + 1);
959
- }
960
- }
961
-
962
- generate({}, 0);
963
- return result;
964
- };
965
-
966
- pick.compileAll = () => {
967
- const allVariants = pick.getAllVariants();
968
- const styles = [];
969
-
970
- if (baseStyle) styles.push(baseStyle);
971
- for (const variantMap of Object.values(variants)) {
972
- for (const variantStyle of Object.values(variantMap)) {
973
- if (variantStyle) styles.push(variantStyle);
974
- }
975
- }
976
- for (const cv of compoundStyles) {
977
- if (cv.style) styles.push(cv.style);
978
- }
979
-
980
- if (atomicOptimizer && atomicOptimizer.options.enabled) {
981
- const styleObj = {};
982
- styles.forEach((style, i) => {
983
- const selectors = style.selectors || [`variant-${i}`];
984
- styleObj[selectors[0].replace(/^\./, '')] = style;
985
- });
986
- const result = atomicOptimizer.optimize(styleObj);
987
- chain.cssOutput = (chain.cssOutput || '') + result.css;
988
- chain.classMap = { ...chain.classMap, ...result.map };
989
- return result.css;
990
- }
991
-
992
- return run(...styles);
993
- };
994
-
995
- return pick;
996
- }
997
-
998
- module.exports = {
999
- chain,
1000
- $,
1001
- run,
1002
- tokens : originalToken,
1003
- compile,
1004
- createTokens,
1005
- configureAtomic,
1006
- setAtomicOptimizer, // Export this for dependency injection
1007
- atomicOptimizer, // Will be null until set
1008
- recipe
1009
- };