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/node/chaincss.js CHANGED
@@ -4,7 +4,7 @@ const fs = require('fs');
4
4
  const Module = require('module');
5
5
  const chokidar = require('chokidar');
6
6
  const CleanCSS = require('clean-css');
7
- const { $, run, compile: originalCompile, chain } = require('./btt');
7
+ const { $, run, compile: originalCompile, chain, setAtomicOptimizer, createTokens, responsive, tokens } = require('./btt');
8
8
  const ChainCSSPrefixer = require('./prefixer.js');
9
9
  const strVal = require('./strVal.js');
10
10
  const { AtomicOptimizer } = require('./atomic-optimizer');
@@ -17,11 +17,21 @@ let atomicOptimizer = null;
17
17
  let config = {
18
18
  atomic: {
19
19
  enabled: false,
20
- threshold: 3,
21
- naming: 'hash',
20
+ threshold: 2,
21
+ naming: 'hash',
22
22
  cache: true,
23
23
  cachePath: './.chaincss-cache',
24
- minify: true
24
+ minify: true,
25
+ mode: 'hybrid',
26
+ alwaysAtomic: [],
27
+ neverAtomic: ['content', 'animation', 'transition', 'keyframes', 'counterIncrement', 'counterReset'],
28
+ frameworkOutput: {
29
+ react: false,
30
+ vue: false,
31
+ vanilla: true
32
+ },
33
+ preserveSelectors: false,
34
+ verbose: false
25
35
  },
26
36
  prefixer: {
27
37
  enabled: true,
@@ -35,9 +45,14 @@ let config = {
35
45
  let prefixer = new ChainCSSPrefixer(config.prefixer);
36
46
 
37
47
  function deft_to_userConf(target, source) {
48
+ // Handle arrays specially
49
+ if (Array.isArray(source)) {
50
+ return source; // Return array as-is, don't merge
51
+ }
52
+
38
53
  const result = { ...target };
39
54
  for (const key in source) {
40
- if (source[key] instanceof Object && key in target) {
55
+ if (source[key] instanceof Object && !Array.isArray(source[key]) && key in target) {
41
56
  result[key] = deft_to_userConf(target[key], source[key]);
42
57
  } else {
43
58
  result[key] = source[key];
@@ -50,8 +65,7 @@ const ensureConfigExists = () => {
50
65
  const configPath = path.join(process.cwd(), 'chaincss.config.cjs');
51
66
  const configExists = fs.existsSync(configPath);
52
67
  if (!configExists && !process.env.CHAINCSS_SKIP_CONFIG) {
53
- const defaultConfig = strVal.userConf;
54
- fs.writeFileSync(configPath, defaultConfig);
68
+ fs.writeFileSync(configPath, strVal.userConf);
55
69
  console.log('-- Successfully created config file: ./chaincss.config.cjs\n');
56
70
  }
57
71
  };
@@ -61,7 +75,35 @@ const loadUserConfig = () => {
61
75
  if (fs.existsSync(configPath)) {
62
76
  try {
63
77
  const userConfig = require(configPath);
64
- config = deft_to_userConf(config, userConfig);
78
+
79
+ // Deep merge that preserves arrays
80
+ function deepMerge(target, source) {
81
+ const result = { ...target };
82
+ for (const key in source) {
83
+ if (Array.isArray(source[key])) {
84
+ result[key] = [...source[key]]; // Copy array
85
+ } else if (source[key] instanceof Object && key in target) {
86
+ result[key] = deepMerge(target[key], source[key]);
87
+ } else {
88
+ result[key] = source[key];
89
+ }
90
+ }
91
+ return result;
92
+ }
93
+
94
+ config = deepMerge(config, userConfig);
95
+
96
+ // Ensure atomic arrays are arrays
97
+ if (config.atomic) {
98
+ if (!Array.isArray(config.atomic.alwaysAtomic)) {
99
+ config.atomic.alwaysAtomic = [];
100
+ }
101
+ if (!Array.isArray(config.atomic.neverAtomic)) {
102
+ config.atomic.neverAtomic = [];
103
+ }
104
+ }
105
+
106
+ // Validate prefixer browsers
65
107
  if (config.prefixer) {
66
108
  if (typeof config.prefixer.browsers === 'string') {
67
109
  config.prefixer.browsers = config.prefixer.browsers.split(',').map(b => b.trim());
@@ -78,9 +120,14 @@ const loadUserConfig = () => {
78
120
 
79
121
  const initAtomicOptimizer = () => {
80
122
  if (config.atomic.enabled) {
123
+ //if (config.atomic.verbose) {
124
+ //console.log('--Initializing Atomic Optimizer with config:', JSON.stringify(config.atomic, null, 2));
125
+ //}
126
+
81
127
  atomicOptimizer = new AtomicOptimizer(config.atomic);
82
- } else {
83
- console.log('-- Atomic optimizer disabled\n');
128
+
129
+ // Inject the configured atomic optimizer into btt
130
+ setAtomicOptimizer(atomicOptimizer);
84
131
  }
85
132
  };
86
133
 
@@ -98,7 +145,11 @@ function parseArgs(args) {
98
145
  prefixerMode: null,
99
146
  sourceMap: null,
100
147
  sourceMapInline: false,
101
- atomic: false
148
+ atomic: false,
149
+ atomicMode: null,
150
+ atomicNaming: null,
151
+ atomicVerbose: false,
152
+ preserveSelectors: false
102
153
  };
103
154
 
104
155
  for (let i = 0; i < args.length; i++) {
@@ -120,12 +171,20 @@ function parseArgs(args) {
120
171
  result.sourceMapInline = true;
121
172
  } else if (arg === '--atomic') {
122
173
  result.atomic = true;
174
+ } else if (arg === '--atomic-mode' && args[i + 1]) {
175
+ result.atomicMode = args[i + 1];
176
+ i++;
177
+ } else if (arg === '--atomic-naming' && args[i + 1]) {
178
+ result.atomicNaming = args[i + 1];
179
+ i++;
180
+ } else if (arg === '--atomic-verbose') {
181
+ result.atomicVerbose = true;
182
+ } else if (arg === '--preserve-selectors') {
183
+ result.preserveSelectors = true;
123
184
  } else if (!result.inputFile) {
124
185
  result.inputFile = arg;
125
186
  } else if (!result.outputFile) {
126
187
  result.outputFile = arg;
127
- }else if (arg === '--validate-themes') {
128
- result.validateThemes = true;
129
188
  }
130
189
  }
131
190
  return result;
@@ -150,14 +209,18 @@ const applyCliOptions = (cliOptions) => {
150
209
  if (cliOptions.atomic) {
151
210
  config.atomic.enabled = true;
152
211
  }
153
- /*if (cliOptions.validateThemes) {
154
- const configPath = path.join(process.cwd(), 'chaincss.config.cjs');
155
- if (fs.existsSync(configPath)) {
156
- await import('./theme-validator.js').then(module => {
157
- module.validateThemeFiles(configPath);
158
- });
159
- }
160
- }*/
212
+ if (cliOptions.atomicMode && ['atomic', 'standard', 'hybrid'].includes(cliOptions.atomicMode)) {
213
+ config.atomic.mode = cliOptions.atomicMode;
214
+ }
215
+ if (cliOptions.atomicNaming && ['hash', 'readable'].includes(cliOptions.atomicNaming)) {
216
+ config.atomic.naming = cliOptions.atomicNaming;
217
+ }
218
+ if (cliOptions.atomicVerbose) {
219
+ config.atomic.verbose = true;
220
+ }
221
+ if (cliOptions.preserveSelectors) {
222
+ config.atomic.preserveSelectors = true;
223
+ }
161
224
  };
162
225
 
163
226
  function watch(inputFile, outputFile) {
@@ -190,7 +253,7 @@ const transpilerModule = {
190
253
  chain
191
254
  };
192
255
 
193
- // Native module-based JCSS file processor (replaces vm2)
256
+ // Native module-based JCSS file processor
194
257
  const processJCSSFile = (filePath) => {
195
258
  const abs = path.resolve(filePath);
196
259
 
@@ -222,6 +285,9 @@ const processJCSSFile = (filePath) => {
222
285
  'compile',
223
286
  'chain',
224
287
  'get',
288
+ 'createTokens',
289
+ 'responsive',
290
+ 'tokens',
225
291
  content
226
292
  );
227
293
  compiledCache.set(abs, compiledFn);
@@ -238,7 +304,10 @@ const processJCSSFile = (filePath) => {
238
304
  run,
239
305
  originalCompile,
240
306
  chain,
241
- get
307
+ get,
308
+ createTokens,
309
+ responsive,
310
+ tokens
242
311
  );
243
312
  } catch (err) {
244
313
  console.error(`Error processing ${abs}:`, err.message);
@@ -263,6 +332,9 @@ const processScript = (scriptBlock, filename) => {
263
332
  'compile',
264
333
  'chain',
265
334
  'get',
335
+ 'createTokens',
336
+ 'responsive',
337
+ 'tokens',
266
338
  '__filename',
267
339
  '__dirname',
268
340
  scriptBlock
@@ -271,7 +343,7 @@ const processScript = (scriptBlock, filename) => {
271
343
  }
272
344
 
273
345
  try {
274
- compiledFn($, run, originalCompile, chain, get, filename, dirname);
346
+ compiledFn($, run, originalCompile, chain, get, createTokens, responsive, tokens, filename, dirname);
275
347
  } catch (err) {
276
348
  console.error(`Error processing script in ${filename}:`, err.message);
277
349
  throw err;
@@ -289,14 +361,16 @@ const processJavascriptBlocks = (content, inputpath) => {
289
361
  outputCSS += blocks[i];
290
362
  } else {
291
363
  const scriptBlock = blocks[i];
292
- try {
293
- const blockCSS = processScript(scriptBlock, inputpath);
294
- if (typeof blockCSS !== 'object' && typeof blockCSS !== 'undefined') {
295
- outputCSS += blockCSS;
364
+ if (scriptBlock && scriptBlock.trim()) {
365
+ try {
366
+ const blockCSS = processScript(scriptBlock, inputpath);
367
+ if (typeof blockCSS !== 'object' && typeof blockCSS !== 'undefined') {
368
+ outputCSS += blockCSS;
369
+ }
370
+ } catch (err) {
371
+ console.error(`Error processing script block:`, err.stack);
372
+ throw err;
296
373
  }
297
- } catch (err) {
298
- console.error(`Error processing script block:`, err.stack);
299
- throw err;
300
374
  }
301
375
  }
302
376
  }
@@ -351,6 +425,26 @@ const processAndMinifyCss = async (css, inputFile, outputFile) => {
351
425
  return { css: finalCss, map: finalSourceMap };
352
426
  };
353
427
 
428
+ const writeFrameworkOutput = (outputDir, result) => {
429
+ const frameworkOutputs = [];
430
+
431
+ if (config.atomic.frameworkOutput.react && result.frameworkOutput) {
432
+ const reactPath = path.join(outputDir, 'atomic.react.js');
433
+ fs.writeFileSync(reactPath, result.frameworkOutput, 'utf8');
434
+ frameworkOutputs.push(`React: ${reactPath}`);
435
+ }
436
+
437
+ if (config.atomic.frameworkOutput.vue && result.frameworkOutput) {
438
+ const vuePath = path.join(outputDir, 'atomic.vue.js');
439
+ fs.writeFileSync(vuePath, result.frameworkOutput, 'utf8');
440
+ frameworkOutputs.push(`Vue: ${vuePath}`);
441
+ }
442
+
443
+ if (frameworkOutputs.length > 0) {
444
+ console.log(`Framework outputs: ${frameworkOutputs.join(', ')}`);
445
+ }
446
+ };
447
+
354
448
  const processor = async (inputFile, outputFile) => {
355
449
  try {
356
450
  const input = path.resolve(inputFile);
@@ -365,6 +459,7 @@ const processor = async (inputFile, outputFile) => {
365
459
  }
366
460
  const stylePath = path.join(outputDir, 'global.css');
367
461
  const result = await processAndMinifyCss(processedCSS, input, stylePath);
462
+
368
463
  if (result.css) {
369
464
  fs.writeFileSync(stylePath, result.css, 'utf8');
370
465
  if (result.map) {
@@ -373,38 +468,81 @@ const processor = async (inputFile, outputFile) => {
373
468
  }
374
469
 
375
470
  // ========== ATOMIC CLASS MAP GENERATION ==========
376
- if (atomicOptimizer && config.atomic.enabled && chain.classMap && Object.keys(chain.classMap).length > 0) {
377
- // Write map.json (selector → atomic class string)
471
+ // ALWAYS generate atomic files when atomic optimizer is enabled
472
+ if (atomicOptimizer && config.atomic.enabled) {
473
+
474
+ // Get atomic classes from the optimizer
475
+ const atomicClasses = atomicOptimizer.getAllAtomicClasses();
476
+ const atomicClassMap = {};
477
+
478
+ // Build class map from component map
479
+ if (atomicOptimizer.componentMap) {
480
+ for (const [selector, data] of atomicOptimizer.componentMap) {
481
+ if (data.atomicClasses && data.atomicClasses.length > 0) {
482
+ atomicClassMap[selector] = data.atomicClasses.join(' ');
483
+ }
484
+ if (data.hoverAtomicClasses && data.hoverAtomicClasses.length > 0) {
485
+ atomicClassMap[`${selector}:hover`] = data.hoverAtomicClasses.join(' ');
486
+ }
487
+ }
488
+ }
489
+
490
+ // Write map.json
378
491
  const mapJsonPath = path.join(outputDir, 'global.map.json');
379
492
  const mapData = {
380
- version: '1.0.0',
493
+ version: '2.0.0',
381
494
  generated: new Date().toISOString(),
382
495
  input: inputFile,
383
496
  output: stylePath,
384
497
  atomicEnabled: true,
498
+ mode: config.atomic.mode,
499
+ naming: config.atomic.naming,
500
+ outputStrategy: config.atomic.outputStrategy,
385
501
  threshold: config.atomic.threshold,
386
- classMap: chain.classMap,
387
- stats: chain.atomicStats
502
+ classMap: atomicClassMap,
503
+ atomicClasses: atomicClasses.map(a => ({ className: a.className, prop: a.prop, value: a.value })),
504
+ stats: chain.atomicStats || atomicOptimizer.getStats()
388
505
  };
389
506
  fs.writeFileSync(mapJsonPath, JSON.stringify(mapData, null, 2), 'utf8');
390
- console.log(` Class map: ${mapJsonPath}`);
391
507
 
392
- // Write JS module for easy import
508
+
509
+ // Write JS module
393
510
  const jsPath = path.join(outputDir, 'global.classes.js');
394
- const jsContent = `/**
511
+ let jsContent = `/**
395
512
  * ChainCSS Atomic Class Map
396
513
  * Generated: ${new Date().toISOString()}
514
+ * Mode: ${config.atomic.mode}
515
+ * Output Strategy: ${config.atomic.outputStrategy}
516
+ * Naming: ${config.atomic.naming}
397
517
  * Threshold: ${config.atomic.threshold}
398
518
  */
399
519
 
400
- export const classMap = ${JSON.stringify(chain.classMap, null, 2)};
520
+ export const classMap = ${JSON.stringify(atomicClassMap, null, 2)};
521
+
522
+ export const atomicClasses = ${JSON.stringify(atomicClasses.map(a => a.className), null, 2)};
401
523
 
402
524
  export const getClass = (selector) => classMap[selector] || '';
403
525
 
526
+ export const getAtomicClass = (prop, value) => {
527
+ const atomic = atomicClasses.find(a => a.prop === prop && a.value === value);
528
+ return atomic ? atomic.className : null;
529
+ };
530
+
531
+ export const getAllClasses = () => Object.values(classMap).join(' ');
532
+
533
+ export const applyClasses = (element, selector) => {
534
+ if (!element) return;
535
+ const classes = getClass(selector);
536
+ if (classes) {
537
+ element.className = classes;
538
+ }
539
+ return classes;
540
+ };
541
+
404
542
  export default classMap;
405
543
  `;
544
+
406
545
  fs.writeFileSync(jsPath, jsContent, 'utf8');
407
- console.log(` JS module: ${jsPath}`);
408
546
 
409
547
  // Write TypeScript definitions
410
548
  const dtsPath = path.join(outputDir, 'global.classes.d.ts');
@@ -413,13 +551,24 @@ export default classMap;
413
551
  * Generated: ${new Date().toISOString()}
414
552
  */
415
553
 
554
+ export interface AtomicClass {
555
+ className: string;
556
+ prop: string;
557
+ value: string;
558
+ }
559
+
416
560
  export const classMap: Record<string, string>;
561
+ export const atomicClasses: string[];
417
562
  export const getClass: (selector: string) => string;
563
+ export const getAtomicClass: (prop: string, value: string) => string | null;
564
+ export const getAllClasses: () => string;
565
+ export const applyClasses: (element: HTMLElement | null, selector: string) => string | undefined;
566
+
418
567
  declare const _default: Record<string, string>;
419
568
  export default _default;
420
569
  `;
421
570
  fs.writeFileSync(dtsPath, dtsContent, 'utf8');
422
- console.log(` TypeScript definitions: ${dtsPath}`);
571
+
423
572
 
424
573
  // Update manifest
425
574
  const manifestPath = path.join(outputDir, 'chaincss-manifest.json');
@@ -431,18 +580,22 @@ export default _default;
431
580
  }
432
581
 
433
582
  manifest[path.basename(stylePath)] = {
583
+ version: '2.0.0',
434
584
  css: path.basename(stylePath),
435
585
  map: path.basename(mapJsonPath),
436
586
  js: path.basename(jsPath),
437
587
  dts: path.basename(dtsPath),
438
588
  generated: new Date().toISOString(),
439
589
  input: inputFile,
590
+ mode: config.atomic.mode,
591
+ outputStrategy: config.atomic.outputStrategy,
592
+ naming: config.atomic.naming,
440
593
  threshold: config.atomic.threshold,
441
- stats: chain.atomicStats
594
+ atomicClassesCount: atomicClasses.length,
595
+ stats: chain.atomicStats || atomicOptimizer.getStats()
442
596
  };
443
597
 
444
598
  fs.writeFileSync(manifestPath, JSON.stringify(manifest, null, 2), 'utf8');
445
- console.log(` Manifest: ${manifestPath}`);
446
599
  }
447
600
  }
448
601
  } catch (err) {
package/node/prefixer.js CHANGED
@@ -39,8 +39,8 @@ class ChainCSSPrefixer {
39
39
  }
40
40
  determineMode() {
41
41
  if (this.config.mode === 'full' && !this.hasAutoprefixer) {
42
- console.warn('āš ļø Full mode requested but autoprefixer not installed. Falling back to lightweight mode.');
43
- console.warn(' To use full mode install this devDenpendecies: "npm install -D autoprefixer postcss caniuse-db browserslist"\n');
42
+ console.warn('Full mode requested but autoprefixer not installed. Falling back to lightweight mode.');
43
+ console.warn(' To use full mode: npm install autoprefixer postcss caniuse-db browserslist\n');
44
44
  return 'lightweight';
45
45
  }
46
46
  if (this.config.mode === 'lightweight') {
package/node/strVal.js CHANGED
@@ -1,18 +1,34 @@
1
1
  const strVal = {
2
- userConf: `// Project Configuration
2
+ userConf: `// ChainCSS Configuration
3
+ // Generated: ${new Date().toISOString()}
4
+
3
5
  module.exports = {
4
6
  atomic: {
5
- enabled: true,
6
- threshold: 3,
7
- naming: 'hash',
8
- cache: true,
7
+ enabled: true, // Enable atomic CSS optimization
8
+ threshold: 3, // Minimum usage count for atomic conversion
9
+ naming: 'hash', // 'hash' (c_3b82f6) or 'readable' (bg-blue-500)
10
+ cache: true, // Cache atomic classes between builds
9
11
  cachePath: './.chaincss-cache',
10
- minify: true
12
+ minify: true, // Minify CSS output
13
+ mode: 'hybrid', // 'atomic' | 'standard' | 'hybrid'
14
+ alwaysAtomic: [], // Force these properties to be atomic
15
+ neverAtomic: [ // Never make these properties atomic
16
+ 'content', 'animation', 'transition', 'keyframes',
17
+ 'counterIncrement', 'counterReset'
18
+ ],
19
+ outputStrategy: 'component-first',
20
+ frameworkOutput: {
21
+ react: false, // Generate React hooks
22
+ vue: false, // Generate Vue composables
23
+ vanilla: true // Generate vanilla JS class map
24
+ },
25
+ preserveSelectors: false, // Keep original selector names in comments
26
+ verbose: true // Show detailed atomic optimization stats
11
27
  },
12
28
  prefixer: {
13
- mode: 'auto',
14
- browsers: ['> 0.5%', 'last 2 versions', 'not dead'],
15
29
  enabled: true,
30
+ mode: 'auto', // 'auto' | 'always' | 'never'
31
+ browsers: ['> 0.5%', 'last 2 versions', 'not dead'],
16
32
  sourceMap: true,
17
33
  sourceMapInline: false
18
34
  }
@@ -34,27 +50,14 @@ Options:
34
50
 
35
51
  # Atomic CSS Optimization
36
52
  --atomic Enable atomic CSS optimization
37
- --threshold <number> Minimum usage count for atomic classes (default: 3)
38
- --atomic-naming <type> Atomic class naming (hash|readable) (default: hash)
53
+ --atomic-mode <mode> Atomic mode: atomic, standard, hybrid (default: hybrid)
54
+ --atomic-naming <scheme> Naming scheme: hash, readable (default: hash)
55
+ --atomic-verbose Show detailed atomic optimization stats
56
+ --preserve-selectors Keep original selector names in comments
39
57
  --no-atomic-cache Disable atomic CSS cache
40
58
 
41
- # Performance & Debug
42
- --verbose Enable verbose logging
43
- --debug Enable debug mode with detailed output
44
- --tree-shake Remove unused CSS classes (dead code elimination)
45
-
46
59
  # Output Control
47
- --minify Minify CSS output (default: true in production)
48
60
  --no-minify Disable CSS minification
49
- --out-dir <dir> Output directory (default: same as outputFile dir)
50
- --manifest Generate build manifest file
51
-
52
- # Configuration
53
- --config <path> Path to config file (default: chaincss.config.cjs)
54
- --no-config Ignore config file, use CLI options only
55
-
56
- # Theme Validation
57
- --validate-themes Validate theme contracts during build
58
61
 
59
62
  # Help
60
63
  --help, -h Show this help message
@@ -62,44 +65,27 @@ Options:
62
65
 
63
66
  Examples:
64
67
  # Basic compilation
65
- chaincss style.jcss style.css
68
+ chaincss style.jcss dist/
66
69
 
67
70
  # Watch mode for development
68
- chaincss style.jcss style.css --watch
71
+ chaincss style.jcss dist/ --watch
69
72
 
70
73
  # Atomic CSS optimization
71
- chaincss style.jcss style.css --atomic
74
+ chaincss style.jcss dist/ --atomic
72
75
 
73
- # With custom threshold for atomic classes
74
- chaincss style.jcss style.css --atomic --threshold 5
76
+ # With custom naming scheme
77
+ chaincss style.jcss dist/ --atomic --atomic-naming readable
75
78
 
76
- # Full production build with all optimizations
77
- chaincss style.jcss style.css --atomic --minify --tree-shake --source-map
79
+ # Verbose output for debugging
80
+ chaincss style.jcss dist/ --atomic --atomic-verbose
78
81
 
79
82
  # Custom browser support
80
- chaincss style.jcss style.css --browsers "> 1%, last 2 versions, not dead"
81
-
82
- # Full autoprefixer mode
83
- chaincss style.jcss style.css --prefixer-mode full
84
-
85
- # Validate themes during build
86
- chaincss style.jcss style.css --validate-themes
87
-
88
- # Debug mode with verbose output
89
- chaincss style.jcss style.css --debug --verbose
90
-
91
- # Disable prefixing (for modern browsers only)
92
- chaincss style.jcss style.css --no-prefix
93
-
94
- # With custom config file
95
- chaincss style.jcss style.css --config ./my-chaincss.config.cjs
83
+ chaincss style.jcss dist/ --browsers "> 1%, last 2 versions, not dead"
96
84
 
97
85
  Notes:
98
86
  - Atomic CSS optimization reduces CSS size by reusing common style patterns
99
- - Tree shaking removes unused CSS classes from final bundle
100
- - Theme validation ensures all themes have required tokens
101
87
  - Use --watch during development for instant updates
102
- - Use --atomic --minify --tree-shake for production builds
88
+ - Use --atomic for production builds to optimize CSS bundle size
103
89
  `
104
90
  }
105
91
 
@@ -8,7 +8,7 @@ export function validateThemeFiles(configPath) {
8
8
 
9
9
  const { contract, themes } = config;
10
10
 
11
- console.log('\nšŸŽØ Validating Theme Contract...\n');
11
+ console.log('\nValidating Theme Contract...\n');
12
12
 
13
13
  const errors = [];
14
14
 
@@ -16,9 +16,9 @@ export function validateThemeFiles(configPath) {
16
16
  const themeName = theme.name || `theme-${index}`;
17
17
  try {
18
18
  validateTheme(contract, theme.values);
19
- console.log(`āœ… ${themeName}: Valid`);
19
+ console.log(`${themeName}: Valid`);
20
20
  } catch (err) {
21
- errors.push(`āŒ ${themeName}: ${err.message}`);
21
+ errors.push(`${themeName}: ${err.message}`);
22
22
  }
23
23
  });
24
24
 
@@ -28,5 +28,5 @@ export function validateThemeFiles(configPath) {
28
28
  process.exit(1);
29
29
  }
30
30
 
31
- console.log('\nāœ… All themes valid!\n');
31
+ console.log('\nAll themes valid!\n');
32
32
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "chaincss",
3
- "version": "1.13.2",
3
+ "version": "1.13.3",
4
4
  "description": "Chainable CSS-in-JS with build-time compilation, atomic CSS, and zero-runtime options",
5
5
  "keywords": [
6
6
  "css",
@@ -61,11 +61,20 @@
61
61
  },
62
62
  "default": "./browser/react-hooks.js"
63
63
  },
64
- "./browser/*": {
64
+ "./vue": {
65
+ "types": "./types.d.ts",
66
+ "browser": {
67
+ "import": "./browser/vue-composables.js",
68
+ "require": "./browser/vue-composables.js"
69
+ },
70
+ "default": "./browser/vue-composables.js"
71
+ },
72
+ "./browser": {
65
73
  "browser": {
66
74
  "import": "./browser/*",
67
75
  "require": "./browser/*"
68
- }
76
+ },
77
+ "default": "./browser/index.js"
69
78
  },
70
79
  "./node/*": {
71
80
  "node": {
@@ -120,6 +129,7 @@
120
129
  "clean-css": "^5.3.3"
121
130
  },
122
131
  "peerDependencies": {
132
+ "vue": "^3.0.0",
123
133
  "react": ">=16.8.0",
124
134
  "autoprefixer": "^10.0.0",
125
135
  "postcss": "^8.5.6",