chaincss 2.0.7 → 2.1.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 (159) hide show
  1. package/CHANGELOG.md +30 -0
  2. package/CODE_OF_CONDUCT.md +21 -0
  3. package/CONTRIBUTING.md +28 -0
  4. package/README.md +455 -226
  5. package/demo/demo/node_modules/caniuse-db/fulldata-json/data-2.0.json +1 -0
  6. package/demo/index.html +16 -0
  7. package/demo/package.json +20 -0
  8. package/demo/src/App.tsx +117 -0
  9. package/demo/src/chaincss-barrel.ts +9 -0
  10. package/demo/src/main.tsx +8 -0
  11. package/demo/src/styles.chain.ts +300 -0
  12. package/demo/vite.config.ts +46 -0
  13. package/dist/cli/commands/build.d.ts +0 -1
  14. package/dist/cli/commands/cache.d.ts +1 -0
  15. package/dist/cli/commands/init.d.ts +6 -3
  16. package/dist/cli/commands/timeline.d.ts +0 -1
  17. package/dist/cli/commands/watch.d.ts +0 -1
  18. package/dist/cli/index.d.ts +0 -1
  19. package/dist/cli/index.js +3213 -5296
  20. package/dist/cli/types.d.ts +51 -20
  21. package/dist/cli/utils/config-loader.d.ts +0 -1
  22. package/dist/cli/utils/file-utils.d.ts +27 -3
  23. package/dist/cli/utils/logger.d.ts +0 -1
  24. package/dist/compiler/Chain.d.ts +215 -0
  25. package/dist/compiler/animations.d.ts +76 -0
  26. package/dist/compiler/atomic-optimizer.d.ts +47 -12
  27. package/dist/compiler/breakpoints.d.ts +46 -0
  28. package/dist/compiler/btt.d.ts +36 -60
  29. package/dist/compiler/cache-manager.d.ts +58 -4
  30. package/dist/compiler/commonProps.d.ts +0 -1
  31. package/dist/compiler/content-addressable-cache.d.ts +78 -0
  32. package/dist/compiler/helpers.d.ts +54 -0
  33. package/dist/compiler/index.d.ts +16 -9
  34. package/dist/compiler/index.js +4450 -4316
  35. package/dist/compiler/prefixer.d.ts +17 -1
  36. package/dist/compiler/shorthands.d.ts +28 -0
  37. package/dist/compiler/suggestions.d.ts +43 -0
  38. package/dist/compiler/theme-contract.d.ts +16 -27
  39. package/dist/compiler/token-resolver.d.ts +69 -0
  40. package/dist/compiler/tokens.d.ts +33 -8
  41. package/dist/core/auto-detector.d.ts +34 -0
  42. package/dist/core/common-utils.d.ts +97 -0
  43. package/dist/core/compiler.d.ts +63 -23
  44. package/dist/core/constants.d.ts +137 -36
  45. package/dist/core/smart-chain.d.ts +3 -0
  46. package/dist/core/types.d.ts +122 -15
  47. package/dist/core/utils.d.ts +134 -17
  48. package/dist/index.d.ts +52 -8
  49. package/dist/index.js +7090 -5578
  50. package/dist/plugins/vite.d.ts +7 -5
  51. package/dist/plugins/vite.js +2964 -25641
  52. package/dist/plugins/webpack.d.ts +24 -1
  53. package/dist/plugins/webpack.js +209 -72
  54. package/dist/runtime/Chain.d.ts +32 -0
  55. package/dist/runtime/auto-hooks.d.ts +11 -0
  56. package/dist/runtime/hmr.d.ts +22 -2
  57. package/dist/runtime/index.d.ts +3 -2
  58. package/dist/runtime/index.js +3648 -301
  59. package/dist/runtime/injector.d.ts +39 -72
  60. package/dist/runtime/react.d.ts +17 -12
  61. package/dist/runtime/svelte.d.ts +15 -0
  62. package/dist/runtime/types.d.ts +126 -4
  63. package/dist/runtime/utils.d.ts +0 -1
  64. package/dist/runtime/vue.d.ts +34 -14
  65. package/package.json +59 -66
  66. package/src/cli/commands/build.ts +133 -0
  67. package/src/cli/commands/cache.ts +371 -0
  68. package/src/cli/commands/init.ts +230 -0
  69. package/src/cli/commands/timeline.ts +435 -0
  70. package/src/cli/commands/watch.ts +211 -0
  71. package/src/cli/index.ts +226 -0
  72. package/src/cli/types.ts +100 -0
  73. package/src/cli/utils/config-loader.ts +174 -0
  74. package/src/cli/utils/file-utils.ts +139 -0
  75. package/src/cli/utils/logger.ts +74 -0
  76. package/src/compiler/Chain.ts +831 -0
  77. package/src/compiler/animations.ts +517 -0
  78. package/src/compiler/atomic-optimizer.ts +786 -0
  79. package/src/compiler/breakpoints.ts +347 -0
  80. package/src/compiler/btt.ts +1147 -0
  81. package/src/compiler/cache-manager.ts +446 -0
  82. package/src/compiler/commonProps.ts +18 -0
  83. package/src/compiler/content-addressable-cache.ts +478 -0
  84. package/src/compiler/helpers.ts +407 -0
  85. package/src/compiler/index.ts +72 -0
  86. package/src/compiler/prefixer.ts +724 -0
  87. package/src/compiler/shorthands.ts +558 -0
  88. package/src/compiler/suggestions.ts +436 -0
  89. package/src/compiler/theme-contract.ts +197 -0
  90. package/src/compiler/token-resolver.ts +241 -0
  91. package/src/compiler/tokens.ts +612 -0
  92. package/src/core/auto-detector.ts +187 -0
  93. package/src/core/common-utils.ts +423 -0
  94. package/src/core/compiler.ts +835 -0
  95. package/src/core/constants.ts +424 -0
  96. package/src/core/index.ts +107 -0
  97. package/src/core/smart-chain.ts +163 -0
  98. package/src/core/types.ts +257 -0
  99. package/src/core/utils.ts +598 -0
  100. package/src/index.ts +208 -0
  101. package/src/plugins/vite.d.ts +316 -0
  102. package/src/plugins/vite.ts +424 -0
  103. package/src/plugins/webpack.d.ts +289 -0
  104. package/src/plugins/webpack.ts +416 -0
  105. package/src/runtime/Chain.ts +242 -0
  106. package/src/runtime/auto-hooks.tsx +127 -0
  107. package/src/runtime/auto-vue.ts +72 -0
  108. package/src/runtime/hmr.ts +212 -0
  109. package/src/runtime/index.ts +82 -0
  110. package/src/runtime/injector.ts +273 -0
  111. package/src/runtime/react.tsx +269 -0
  112. package/src/runtime/svelte.ts +15 -0
  113. package/src/runtime/types.ts +256 -0
  114. package/src/runtime/utils.ts +128 -0
  115. package/src/runtime/vite-env.d.ts +120 -0
  116. package/src/runtime/vue.ts +231 -0
  117. package/tsconfig.build.json +41 -0
  118. package/tsconfig.json +25 -0
  119. package/tsconfig.runtimes.json +18 -0
  120. package/dist/cli/cli.cjs +0 -7
  121. package/dist/cli/commands/build.d.ts.map +0 -1
  122. package/dist/cli/commands/compile.d.ts +0 -3
  123. package/dist/cli/commands/compile.d.ts.map +0 -1
  124. package/dist/cli/commands/init.d.ts.map +0 -1
  125. package/dist/cli/commands/timeline.d.ts.map +0 -1
  126. package/dist/cli/commands/watch.d.ts.map +0 -1
  127. package/dist/cli/index.d.ts.map +0 -1
  128. package/dist/cli/types.d.ts.map +0 -1
  129. package/dist/cli/utils/config-loader.d.ts.map +0 -1
  130. package/dist/cli/utils/file-utils.d.ts.map +0 -1
  131. package/dist/cli/utils/logger.d.ts.map +0 -1
  132. package/dist/compiler/atomic-optimizer.d.ts.map +0 -1
  133. package/dist/compiler/btt.d.ts.map +0 -1
  134. package/dist/compiler/cache-manager.d.ts.map +0 -1
  135. package/dist/compiler/commonProps.d.ts.map +0 -1
  136. package/dist/compiler/index.d.ts.map +0 -1
  137. package/dist/compiler/prefixer.d.ts.map +0 -1
  138. package/dist/compiler/theme-contract.d.ts.map +0 -1
  139. package/dist/compiler/tokens.d.ts.map +0 -1
  140. package/dist/compiler/types.d.ts +0 -57
  141. package/dist/compiler/types.d.ts.map +0 -1
  142. package/dist/core/compiler.d.ts.map +0 -1
  143. package/dist/core/constants.d.ts.map +0 -1
  144. package/dist/core/index.d.ts +0 -4
  145. package/dist/core/index.d.ts.map +0 -1
  146. package/dist/core/types.d.ts.map +0 -1
  147. package/dist/core/utils.d.ts.map +0 -1
  148. package/dist/index.d.ts.map +0 -1
  149. package/dist/plugins/vite.d.ts.map +0 -1
  150. package/dist/plugins/webpack.d.ts.map +0 -1
  151. package/dist/runtime/hmr.d.ts.map +0 -1
  152. package/dist/runtime/index.d.ts.map +0 -1
  153. package/dist/runtime/injector.d.ts.map +0 -1
  154. package/dist/runtime/react.d.ts.map +0 -1
  155. package/dist/runtime/react.js +0 -324
  156. package/dist/runtime/types.d.ts.map +0 -1
  157. package/dist/runtime/utils.d.ts.map +0 -1
  158. package/dist/runtime/vue.d.ts.map +0 -1
  159. package/dist/runtime/vue.js +0 -286
@@ -0,0 +1,187 @@
1
+ // src/core/auto-detector.ts
2
+
3
+ export type ValueType = 'static' | 'dynamic' | 'runtime-only';
4
+ export type Mode = 'build' | 'runtime' | 'hybrid' | 'auto';
5
+
6
+ export interface DetectedPart {
7
+ type: ValueType;
8
+ prop: string;
9
+ value: any;
10
+ originalValue: any;
11
+ index: number;
12
+ }
13
+
14
+ export interface AnalysisResult {
15
+ staticParts: DetectedPart[];
16
+ dynamicParts: DetectedPart[];
17
+ runtimeOnlyParts: DetectedPart[];
18
+ isHybrid: boolean;
19
+ mode: Mode;
20
+ }
21
+
22
+ export class AutoDetector {
23
+ private static instance: AutoDetector;
24
+ private dynamicPatterns: RegExp[] = [
25
+ /\$\{.*\}/, // Template literals: ${variable}
26
+ /props\.[a-zA-Z]+/, // Props access: props.color
27
+ /theme\.[a-zA-Z]+/, // Theme access: theme.primary
28
+ /state\.[a-zA-Z]+/, // State access: state.isActive
29
+ /this\.[a-zA-Z]+/, // This binding
30
+ /useContext\(/, // React hook
31
+ /useSelector\(/, // Redux selector
32
+ /getState\(/, // Store getter
33
+ ];
34
+
35
+ private staticPatterns: RegExp[] = [
36
+ /^#[0-9a-f]{3,6}$/i, // Hex colors
37
+ /^[a-z]+$/, // Simple words (red, blue, flex)
38
+ /^\d+(?:\.\d+)?(?:px|rem|em|%)?$/, // Numbers with optional units
39
+ ];
40
+
41
+ private debug = false;
42
+
43
+ static getInstance(): AutoDetector {
44
+ if (!AutoDetector.instance) {
45
+ AutoDetector.instance = new AutoDetector();
46
+ }
47
+ return AutoDetector.instance;
48
+ }
49
+
50
+ enableDebug(enabled: boolean): void {
51
+ this.debug = enabled;
52
+ }
53
+
54
+ detectValueType(value: any, prop?: string): ValueType {
55
+ // Runtime-only patterns (functions, callbacks)
56
+ if (typeof value === 'function') {
57
+ if (this.debug) console.log(`[AutoDetector] Function detected for ${prop} -> runtime-only`);
58
+ return 'runtime-only';
59
+ }
60
+
61
+ // Undefined or null values
62
+ if (value === undefined || value === null) {
63
+ return 'static';
64
+ }
65
+
66
+ // Objects (nested styles)
67
+ if (typeof value === 'object' && value !== null) {
68
+ if (this.debug) console.log(`[AutoDetector] Object detected for ${prop} -> dynamic`);
69
+ return 'dynamic';
70
+ }
71
+
72
+ // Check static patterns
73
+ if (typeof value === 'string') {
74
+ // Check if it matches static patterns
75
+ for (const pattern of this.staticPatterns) {
76
+ if (pattern.test(value)) {
77
+ if (this.debug) console.log(`[AutoDetector] Static pattern matched for ${prop}: ${value}`);
78
+ return 'static';
79
+ }
80
+ }
81
+
82
+ // Check dynamic patterns
83
+ for (const pattern of this.dynamicPatterns) {
84
+ if (pattern.test(value)) {
85
+ if (this.debug) console.log(`[AutoDetector] Dynamic pattern matched for ${prop}: ${value}`);
86
+ return 'dynamic';
87
+ }
88
+ }
89
+ }
90
+
91
+ // Numbers, booleans are static
92
+ if (typeof value === 'number' || typeof value === 'boolean') {
93
+ return 'static';
94
+ }
95
+
96
+ // Default to static
97
+ return 'static';
98
+ }
99
+
100
+ analyzeChain(calls: Array<{ prop: string; value: any; index: number }>): AnalysisResult {
101
+ const staticParts: DetectedPart[] = [];
102
+ const dynamicParts: DetectedPart[] = [];
103
+ const runtimeOnlyParts: DetectedPart[] = [];
104
+
105
+ for (const call of calls) {
106
+ const type = this.detectValueType(call.value, call.prop);
107
+ const part: DetectedPart = {
108
+ type,
109
+ prop: call.prop,
110
+ value: call.value,
111
+ originalValue: call.value,
112
+ index: call.index
113
+ };
114
+
115
+ switch (type) {
116
+ case 'static':
117
+ staticParts.push(part);
118
+ break;
119
+ case 'dynamic':
120
+ dynamicParts.push(part);
121
+ break;
122
+ case 'runtime-only':
123
+ runtimeOnlyParts.push(part);
124
+ break;
125
+ }
126
+ }
127
+
128
+ const isHybrid = staticParts.length > 0 && (dynamicParts.length > 0 || runtimeOnlyParts.length > 0);
129
+ let mode: Mode = 'build';
130
+
131
+ if (isHybrid) {
132
+ mode = 'hybrid';
133
+ } else if (dynamicParts.length > 0 || runtimeOnlyParts.length > 0) {
134
+ mode = 'runtime';
135
+ } else {
136
+ mode = 'build';
137
+ }
138
+
139
+ if (this.debug) {
140
+ console.log('[AutoDetector] Analysis:', {
141
+ static: staticParts.length,
142
+ dynamic: dynamicParts.length,
143
+ runtimeOnly: runtimeOnlyParts.length,
144
+ mode,
145
+ isHybrid
146
+ });
147
+ }
148
+
149
+ return {
150
+ staticParts,
151
+ dynamicParts,
152
+ runtimeOnlyParts,
153
+ isHybrid,
154
+ mode
155
+ };
156
+ }
157
+
158
+ addDynamicPattern(pattern: RegExp): void {
159
+ this.dynamicPatterns.push(pattern);
160
+ if (this.debug) console.log(`[AutoDetector] Added dynamic pattern: ${pattern}`);
161
+ }
162
+
163
+ addStaticPattern(pattern: RegExp): void {
164
+ this.staticPatterns.push(pattern);
165
+ if (this.debug) console.log(`[AutoDetector] Added static pattern: ${pattern}`);
166
+ }
167
+
168
+ reset(): void {
169
+ this.dynamicPatterns = [
170
+ /\$\{.*\}/,
171
+ /props\.[a-zA-Z]+/,
172
+ /theme\.[a-zA-Z]+/,
173
+ /state\.[a-zA-Z]+/,
174
+ /this\.[a-zA-Z]+/,
175
+ /useContext\(/,
176
+ /useSelector\(/,
177
+ /getState\(/,
178
+ ];
179
+ this.staticPatterns = [
180
+ /^#[0-9a-f]{3,6}$/i,
181
+ /^[a-z]+$/,
182
+ /^\d+(?:\.\d+)?(?:px|rem|em|%)?$/,
183
+ ];
184
+ }
185
+ }
186
+
187
+ export const autoDetector = AutoDetector.getInstance();
@@ -0,0 +1,423 @@
1
+ // src/core/common-utils.ts
2
+
3
+ import { shorthandMap, macros } from '../compiler/shorthands.js';
4
+ import type { DesignTokens } from '../compiler/tokens.js';
5
+
6
+ // ============================================================================
7
+ // Utility Functions
8
+ // ============================================================================
9
+
10
+ /**
11
+ * Convert camelCase to kebab-case
12
+ */
13
+ export function kebabCase(str: string): string {
14
+ return str.replace(/([A-Z])/g, '-$1').toLowerCase();
15
+ }
16
+
17
+ /**
18
+ * Convert kebab-case to camelCase
19
+ */
20
+ export function camelCase(str: string): string {
21
+ return str.replace(/-([a-z])/g, (_, letter) => letter.toUpperCase());
22
+ }
23
+
24
+ // ============================================================================
25
+ // Token Resolution
26
+ // ============================================================================
27
+
28
+ /**
29
+ * Resolve token references in a value
30
+ * Supports $token.path format
31
+ */
32
+ export function resolveToken(
33
+ value: any,
34
+ tokenStore: Record<string, any> | DesignTokens = {},
35
+ debug: boolean = false
36
+ ): any {
37
+ if (typeof value !== 'string' || !value.includes('$')) return value;
38
+
39
+ return value.replace(/\$([a-zA-Z0-9.-]+)/g, (match, pathStr) => {
40
+ const parts = pathStr.split('.');
41
+ let current: any = tokenStore;
42
+
43
+ // Handle DesignTokens instance
44
+ if (current && typeof current.get === 'function') {
45
+ const resolved = current.get(pathStr);
46
+ if (resolved !== undefined && resolved !== null) {
47
+ if (debug) {
48
+ console.log(`✨ Resolved ${match} to ${resolved}`);
49
+ }
50
+ return String(resolved);
51
+ }
52
+ }
53
+
54
+ // Handle plain object
55
+ for (const part of parts) {
56
+ if (current && current[part] !== undefined) {
57
+ current = current[part];
58
+ } else {
59
+ if (debug) {
60
+ console.warn(`⚠️ Token not found: ${match}`);
61
+ }
62
+ return match;
63
+ }
64
+ }
65
+
66
+ if (typeof current === 'string' || typeof current === 'number') {
67
+ if (debug) {
68
+ console.log(`✨ Resolved ${match} to ${current}`);
69
+ }
70
+ return String(current);
71
+ }
72
+
73
+ return match;
74
+ });
75
+ }
76
+
77
+ // ============================================================================
78
+ // Style Object Processing
79
+ // ============================================================================
80
+
81
+ /**
82
+ * Process a style object, expanding shorthands and resolving tokens
83
+ */
84
+ export function processStyleObject(
85
+ obj: Record<string, any>,
86
+ tokenStore: Record<string, any> | DesignTokens = {},
87
+ options: { useTokens?: boolean; debug?: boolean } = {}
88
+ ): string {
89
+ const { useTokens = true, debug = false } = options;
90
+ let css = '';
91
+ const expandedProps: Record<string, any> = {};
92
+
93
+ if (debug) {
94
+ console.log('[ChainCSS] Processing style object:', obj);
95
+ if (tokenStore && typeof tokenStore === 'object') {
96
+ const tokenKeys = Object.keys(tokenStore);
97
+ if (tokenKeys.length > 0) {
98
+ console.log('[ChainCSS] Token store available:', tokenKeys);
99
+ }
100
+ }
101
+ }
102
+
103
+ for (let [key, value] of Object.entries(obj)) {
104
+ // Skip internal properties
105
+ if (key.startsWith('_')) continue;
106
+
107
+ // Skip nested objects (handled separately)
108
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
109
+ continue;
110
+ }
111
+
112
+ // Handle macros (mx, my, px, py, etc.)
113
+ if (macros && macros[key]) {
114
+ try {
115
+ macros[key](value, expandedProps, useTokens);
116
+ } catch (error) {
117
+ console.warn(`[ChainCSS] Error applying macro "${key}":`, error);
118
+ }
119
+ } else {
120
+ const realKey = shorthandMap[key] || key;
121
+ expandedProps[realKey] = value;
122
+ }
123
+ }
124
+
125
+ if (debug) {
126
+ console.log('[ChainCSS] Expanded properties:', expandedProps);
127
+ }
128
+
129
+ // Generate CSS string from expanded properties
130
+ const unitlessProps = [
131
+ 'opacity', 'zIndex', 'fontWeight', 'flex', 'flexGrow', 'flexShrink',
132
+ 'order', 'gridColumn', 'gridRow', 'animationIterationCount', 'lineHeight'
133
+ ];
134
+
135
+ for (let [key, value] of Object.entries(expandedProps)) {
136
+ if (debug) {
137
+ console.log(`[ChainCSS] Processing property: ${key} = ${value}`);
138
+ }
139
+
140
+ // Resolve token references
141
+ let finalValue = value;
142
+ if (useTokens && typeof value === 'string') {
143
+ finalValue = resolveToken(value, tokenStore, debug);
144
+ }
145
+
146
+ const kebabKey = kebabCase(key);
147
+
148
+ // Add unit for numeric values
149
+ let unit = '';
150
+ if (typeof value === 'number' && !unitlessProps.includes(key)) {
151
+ unit = 'px';
152
+ }
153
+
154
+ css += ` ${kebabKey}: ${finalValue}${unit};\n`;
155
+ }
156
+
157
+ return css;
158
+ }
159
+
160
+ // ============================================================================
161
+ // Style Extraction
162
+ // ============================================================================
163
+
164
+ /**
165
+ * Extract CSS string from style definition
166
+ */
167
+ export function extractCSS(styleDef: Record<string, any>): string {
168
+ let css = '';
169
+ const selectors = styleDef.selectors || [''];
170
+
171
+ for (const [key, value] of Object.entries(styleDef)) {
172
+ if (key === 'selectors' || key === 'hover' || key === 'atRules' || key === 'nestedRules') {
173
+ continue;
174
+ }
175
+
176
+ const kebabKey = kebabCase(key);
177
+ css += `${kebabKey}: ${value};`;
178
+ }
179
+
180
+ if (!css) return '';
181
+
182
+ return `${selectors.join(', ')} { ${css} }`;
183
+ }
184
+
185
+ /**
186
+ * Extract hover CSS from style definition
187
+ */
188
+ export function extractHoverCSS(styleDef: Record<string, any>): string {
189
+ const hover = styleDef.hover;
190
+ if (!hover || typeof hover !== 'object') return '';
191
+
192
+ const selectors = styleDef.selectors || [''];
193
+ let hoverCSS = '';
194
+
195
+ for (const [key, value] of Object.entries(hover)) {
196
+ const kebabKey = kebabCase(key);
197
+ hoverCSS += `${kebabKey}: ${value};`;
198
+ }
199
+
200
+ if (!hoverCSS) return '';
201
+
202
+ return `${selectors.join(', ')}:hover { ${hoverCSS} }`;
203
+ }
204
+
205
+ // ============================================================================
206
+ // Style Merging
207
+ // ============================================================================
208
+
209
+ /**
210
+ * Merge multiple style objects
211
+ */
212
+ export function mergeStyles(...styles: Record<string, any>[]): Record<string, any> {
213
+ const result: Record<string, any> = {};
214
+
215
+ for (const style of styles) {
216
+ if (!style) continue;
217
+
218
+ for (const [key, value] of Object.entries(style)) {
219
+ if (key === 'hover' && result.hover && typeof value === 'object') {
220
+ result.hover = { ...result.hover, ...value };
221
+ } else if (key === 'selectors' && result.selectors) {
222
+ const newSelectors = Array.isArray(value) ? value : [value];
223
+ const existingSelectors = Array.isArray(result.selectors) ? result.selectors : [result.selectors];
224
+ result.selectors = [...new Set([...existingSelectors, ...newSelectors])];
225
+ } else {
226
+ result[key] = value;
227
+ }
228
+ }
229
+ }
230
+
231
+ return result;
232
+ }
233
+
234
+ // ============================================================================
235
+ // Validation Utilities
236
+ // ============================================================================
237
+
238
+ /**
239
+ * Check if a value is a valid CSS length
240
+ */
241
+ export function isValidCSSLength(value: any): boolean {
242
+ if (typeof value === 'number') return true;
243
+ if (typeof value !== 'string') return false;
244
+
245
+ const lengthRegex = /^[+-]?\d*\.?\d+(px|rem|em|%|vw|vh|vmin|vmax|ch|ex|cm|mm|in|pt|pc)?$/;
246
+ return lengthRegex.test(value);
247
+ }
248
+
249
+ /**
250
+ * Check if a value is a valid CSS color
251
+ */
252
+ export function isValidCSSColor(value: any): boolean {
253
+ if (typeof value !== 'string') return false;
254
+
255
+ // Hex colors
256
+ if (/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(value)) return true;
257
+
258
+ // RGB/RGBA
259
+ if (/^rgba?\([^)]+\)$/.test(value)) return true;
260
+
261
+ // HSL/HSLA
262
+ if (/^hsla?\([^)]+\)$/.test(value)) return true;
263
+
264
+ // Named colors
265
+ const namedColors = [
266
+ 'black', 'white', 'red', 'green', 'blue', 'yellow', 'cyan', 'magenta',
267
+ 'gray', 'grey', 'transparent', 'currentColor', 'inherit', 'initial',
268
+ 'aliceblue', 'antiquewhite', 'aqua', 'aquamarine', 'azure', 'beige',
269
+ 'bisque', 'blanchedalmond', 'blueviolet', 'brown', 'burlywood', 'cadetblue',
270
+ 'chartreuse', 'chocolate', 'coral', 'cornflowerblue', 'cornsilk', 'crimson'
271
+ ];
272
+ if (namedColors.includes(value.toLowerCase())) return true;
273
+
274
+ return false;
275
+ }
276
+
277
+ // ============================================================================
278
+ // Selector Utilities
279
+ // ============================================================================
280
+
281
+ /**
282
+ * Escape CSS selector
283
+ */
284
+ export function escapeSelector(selector: string): string {
285
+ if (!selector) return '';
286
+
287
+ // Escape special characters in CSS selectors
288
+ return selector.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, '\\$1');
289
+ }
290
+
291
+ /**
292
+ * Clean class name for CSS
293
+ */
294
+ export function cleanClassName(className: string): string {
295
+ if (!className) return '';
296
+
297
+ // Remove invalid characters and ensure it starts with a letter or underscore
298
+ let cleaned = className.replace(/[^a-zA-Z0-9_-]/g, '-');
299
+
300
+ // Ensure it starts with a valid character
301
+ if (!/^[a-zA-Z_]/.test(cleaned)) {
302
+ cleaned = `c-${cleaned}`;
303
+ }
304
+
305
+ return cleaned;
306
+ }
307
+
308
+ // ============================================================================
309
+ // Value Extraction
310
+ // ============================================================================
311
+
312
+ /**
313
+ * Extract numeric value from CSS value
314
+ */
315
+ export function extractNumericValue(value: string): number {
316
+ const match = value.match(/^[+-]?\d*\.?\d+/);
317
+ return match ? parseFloat(match[0]) : 0;
318
+ }
319
+
320
+ /**
321
+ * Extract unit from CSS value
322
+ */
323
+ export function extractUnit(value: string): string {
324
+ const match = value.match(/[a-z%]+$/);
325
+ return match ? match[0] : '';
326
+ }
327
+
328
+ /**
329
+ * Add unit to numeric value if missing
330
+ */
331
+ export function addUnit(value: number | string, unit: string = 'px'): string {
332
+ if (typeof value === 'number') return `${value}${unit}`;
333
+ if (typeof value === 'string') {
334
+ if (/^\d+(?:\.\d+)?$/.test(value)) return `${value}${unit}`;
335
+ return value;
336
+ }
337
+ return String(value);
338
+ }
339
+
340
+ // ============================================================================
341
+ // Class Name Utilities
342
+ // ============================================================================
343
+
344
+ /**
345
+ * Sort class names for consistent output
346
+ */
347
+ export function sortClassNames(classNames: string[]): string[] {
348
+ return [...classNames].sort((a, b) => {
349
+ // Atomic classes (a-*) come first
350
+ const aIsAtomic = a.startsWith('a-');
351
+ const bIsAtomic = b.startsWith('a-');
352
+ if (aIsAtomic && !bIsAtomic) return -1;
353
+ if (!aIsAtomic && bIsAtomic) return 1;
354
+
355
+ // Component classes (c-*) come next
356
+ const aIsComponent = a.startsWith('c-');
357
+ const bIsComponent = b.startsWith('c-');
358
+ if (aIsComponent && !bIsComponent) return -1;
359
+ if (!aIsComponent && bIsComponent) return 1;
360
+
361
+ // Then alphabetically
362
+ return a.localeCompare(b);
363
+ });
364
+ }
365
+
366
+ /**
367
+ * Join class names safely
368
+ */
369
+ export function cn(...classes: (string | undefined | null | false)[]): string {
370
+ return classes.filter(Boolean).join(' ');
371
+ }
372
+
373
+ // ============================================================================
374
+ // Debug Utilities
375
+ // ============================================================================
376
+
377
+ /**
378
+ * Create a debug logger
379
+ */
380
+ let debugMode = false;
381
+
382
+ export function enableDebug(enable: boolean = true): void {
383
+ debugMode = enable;
384
+ }
385
+
386
+ export function isDebugEnabled(): boolean {
387
+ return debugMode;
388
+ }
389
+
390
+ /**
391
+ * Debug log function
392
+ */
393
+ export function debugLog(message: string, ...args: any[]): void {
394
+ if (debugMode) {
395
+ console.log(`[ChainCSS Debug] ${message}`, ...args);
396
+ }
397
+ }
398
+
399
+ // ============================================================================
400
+ // Default Export
401
+ // ============================================================================
402
+
403
+ export default {
404
+ kebabCase,
405
+ camelCase,
406
+ resolveToken,
407
+ processStyleObject,
408
+ extractCSS,
409
+ extractHoverCSS,
410
+ mergeStyles,
411
+ isValidCSSLength,
412
+ isValidCSSColor,
413
+ escapeSelector,
414
+ cleanClassName,
415
+ extractNumericValue,
416
+ extractUnit,
417
+ addUnit,
418
+ sortClassNames,
419
+ cn,
420
+ enableDebug,
421
+ isDebugEnabled,
422
+ debugLog
423
+ };