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,831 @@
1
+ // src/compiler/Chain.ts
2
+
3
+ import * as CSS from 'csstype';
4
+ import { shorthandMap, handleShorthand, macros } from './shorthands.js';
5
+ import { getSuggestion } from './suggestions.js';
6
+ import { resolveToken } from './token-resolver.js';
7
+ import { currentBreakpoints } from './breakpoints.js';
8
+ import { animationPresets, createAnimation, AnimationConfig } from './animations.js';
9
+ import { helpers } from './helpers.js';
10
+ import chalk from 'chalk';
11
+
12
+ /**
13
+ * Helper to extract the correct CSS value type for a shorthand
14
+ */
15
+ type GetCSSValue<T extends string> = T extends keyof CSS.Properties
16
+ ? CSS.Properties[T]
17
+ : any;
18
+
19
+ /**
20
+ * Automatically generate methods for standard 1-to-1 shorthands
21
+ */
22
+ type ShorthandMethods = {
23
+ [K in keyof typeof shorthandMap]: (value: GetCSSValue<typeof shorthandMap[K]>) => Chain;
24
+ };
25
+
26
+ /**
27
+ * Special handler methods
28
+ */
29
+ interface SpecialMethods {
30
+ // --- Spacing & Sizing ---
31
+ mx(value: string | number): Chain;
32
+ my(value: string | number): Chain;
33
+ px(value: string | number): Chain;
34
+ py(value: string | number): Chain;
35
+ size(value: string | number): Chain;
36
+ inset(value: string | number | { top?: any, right?: any, bottom?: any, left?: any }): Chain;
37
+ insetX(value: string | number): Chain;
38
+ insetY(value: string | number): Chain;
39
+
40
+ // --- Gap ---
41
+ gap(value: string | number): Chain;
42
+ gapX(value: string | number): Chain;
43
+ gapY(value: string | number): Chain;
44
+
45
+ // --- Borders ---
46
+ borderX(value: string): Chain;
47
+ borderY(value: string): Chain;
48
+ border(value: string | number): Chain;
49
+
50
+ // --- Layouts & Display ---
51
+ flex(value?: string | boolean): Chain;
52
+ inlineFlex(value?: any): Chain;
53
+ grid(value?: string | boolean): Chain;
54
+ inlineGrid(value?: any): Chain;
55
+ cols(value: number | string): Chain;
56
+ rows(value: number | string): Chain;
57
+ center(type?: 'flex' | 'inline'): Chain;
58
+ flexCenter(dir?: 'row' | 'col' | 'column'): Chain;
59
+ gridCenter(): Chain;
60
+ stack(config: string | number | 'row' | { spacing: any, dir?: 'row' | 'col' }): Chain;
61
+ gridTable(minWidth: string | number): Chain;
62
+ aspect(ratio: 'square' | 'video' | 'golden' | string): Chain;
63
+
64
+ // --- Visibility & Behavior ---
65
+ hide(): Chain;
66
+ show(): Chain;
67
+ unselectable(): Chain;
68
+ scrollable(axis?: 'x' | 'y' | 'both'): Chain;
69
+ safeArea(edge?: 'top' | 'bottom' | 'left' | 'right' | 'all' | string[]): Chain;
70
+
71
+ // --- Positioning ---
72
+ absolute(coords?: { top?: any, right?: any, bottom?: any, left?: any }): Chain;
73
+ fixed(coords?: { top?: any, right?: any, bottom?: any, left?: any }): Chain;
74
+ sticky(coords?: { top?: any, right?: any, bottom?: any, left?: any }): Chain;
75
+ relative(coords?: { top?: any, right?: any, bottom?: any, left?: any }): Chain;
76
+
77
+ // --- Shapes & Typography ---
78
+ circle(size: string | number): Chain;
79
+ square(size: string | number): Chain;
80
+ truncate(): Chain;
81
+ fluidText(config: { min: number | string, max: number | string, vw?: string }): Chain;
82
+
83
+ // --- Aesthetic Effects ---
84
+ glass(blur?: string | number): Chain;
85
+ glow(config: string | { color: string, size?: number }): Chain;
86
+ textGradient(colors: string[] | { colors: string[], angle?: number }): Chain;
87
+ meshGradient(colors: string[]): Chain;
88
+ noise(opacity?: number): Chain;
89
+
90
+ // --- State & Logic ---
91
+ skeleton(active: boolean | { active: boolean, color?: string, highlight?: string }): Chain;
92
+ clickScale(amount?: number): Chain;
93
+ onInteracting(callback: (css: Chain) => void): Chain;
94
+ children(callback: (css: Chain) => void): Chain;
95
+ dark(callback: (css: Chain) => void): Chain;
96
+ light(callback: (css: Chain) => void): Chain;
97
+
98
+ // --- Transforms ---
99
+ scale(value: number): Chain;
100
+ rotate(value: string | number): Chain;
101
+ x(value: string | number): Chain;
102
+ y(value: string | number): Chain;
103
+ skew(value: string | number): Chain;
104
+
105
+ // --- Utility ---
106
+ pill(): Chain;
107
+ containerMacro(maxWidth?: string | number): Chain;
108
+ fullScreen(zIndex?: number): Chain;
109
+ shimmer(): Chain;
110
+ bento(cols?: number): Chain;
111
+ pressable(): Chain;
112
+ focusRing(color?: string): Chain;
113
+ outlineDebug(): Chain;
114
+ parallax(scale?: number): Chain;
115
+ lineClamp(lines?: number): Chain;
116
+ frostedNav(blur?: number | string): Chain;
117
+ }
118
+
119
+ interface ChainBase {
120
+ // Finalizers
121
+ $el(...selectors: string[]): any;
122
+ end(): Chain;
123
+
124
+ // State & Nesting
125
+ hover(): Chain;
126
+ nest(selector: string, callback: (css: Chain) => void): Chain;
127
+ use(mixin: Record<string, any>): Chain;
128
+ when(condition: boolean, callback: (css: Chain) => void): Chain;
129
+
130
+ // Responsive & AT-Rules
131
+ responsive(breakpoint: string, callback: (css: Chain) => void): Chain;
132
+ media(query: string, callback: (css: Chain) => void): Chain;
133
+ supports(condition: string, callback: (css: Chain) => void): Chain;
134
+ containerQuery(condition: string, callback: (css: Chain) => void): Chain;
135
+ layer(name: string, callback: (css: Chain) => void): Chain;
136
+ keyframes(name: string, steps: Record<string, any>): Chain;
137
+ fontFace(properties: Record<string, string>): Chain;
138
+
139
+ // Component Logic
140
+ componentName(name: string): Chain;
141
+ component(framework?: 'react' | 'vue' | 'svelte' | 'solid' | 'auto'): Chain;
142
+ props(propsDefinition?: Record<string, any>): Chain;
143
+
144
+ // Animations
145
+ animation(name: string, config?: AnimationConfig): Chain;
146
+ animate(name: string, keyframes: Record<string, any>, config?: AnimationConfig): Chain;
147
+ duration(v: string): Chain;
148
+ delay(v: string): Chain;
149
+ timing(v: string): Chain;
150
+ iteration(v: string | number): Chain;
151
+ infinite(): Chain;
152
+
153
+ // Math Helpers
154
+ calc(expr: string): any;
155
+ add(...args: any[]): any;
156
+ subtract(...args: any[]): any;
157
+ sub(...args: any[]): any;
158
+ multiply(...args: any[]): any;
159
+ mul(...args: any[]): any;
160
+ divide(...args: any[]): any;
161
+ div(...args: any[]): any;
162
+ mpx(v: number | string): string;
163
+ rem(v: number | string): string;
164
+ em(v: number | string): string;
165
+ percent(v: number | string): string;
166
+ vw(v: number | string): string;
167
+ vh(v: number | string): string;
168
+ min(...args: any[]): any;
169
+ max(...args: any[]): any;
170
+ clamp(min: any, val: any, max: any): any;
171
+
172
+ // Meta
173
+ debug(): Chain;
174
+ explain(shorthand: string): Chain;
175
+ }
176
+
177
+ type CSSMethods = {
178
+ [K in keyof CSS.Properties]-?: (value: CSS.Properties[K]) => Chain;
179
+ };
180
+
181
+ export type Chain = SpecialMethods & ChainBase & CSSMethods & ShorthandMethods;
182
+
183
+ let currentTokenContext: any = null;
184
+
185
+ export function setTokenContext(context: any): void {
186
+ currentTokenContext = context;
187
+ }
188
+
189
+ export function getTokenContext(): any {
190
+ return currentTokenContext;
191
+ }
192
+
193
+ let debugMode = false;
194
+
195
+ export function enableDebug(enable: boolean = true): void {
196
+ debugMode = enable;
197
+ if (enable) {
198
+ console.log('🔍 ChainCSS Debug Mode Enabled');
199
+ }
200
+ }
201
+
202
+ // ============================================================================
203
+ // Whitelist of public methods accessible via Proxy
204
+ // ============================================================================
205
+ const PUBLIC_METHODS = new Set([
206
+ // Finalizers
207
+ '$el', 'end',
208
+ // State & Nesting
209
+ 'hover', 'use', 'when', 'nest',
210
+ // Component
211
+ 'component', 'componentName', 'props',
212
+ // Responsive & AT-Rules
213
+ 'responsive', 'media', 'supports', 'containerQuery', 'layer',
214
+ 'keyframes', 'fontFace',
215
+ // Animations
216
+ 'animation', 'animate', 'duration', 'delay', 'timing',
217
+ 'iteration', 'infinite',
218
+ // Math Helpers
219
+ 'calc', 'add', 'subtract', 'sub', 'multiply', 'mul',
220
+ 'divide', 'div', 'mpx', 'rem', 'em', 'percent',
221
+ 'vw', 'vh', 'min', 'max', 'clamp',
222
+ // Meta
223
+ 'debug', 'explain'
224
+ ]);
225
+
226
+ // ============================================================================
227
+ // Main Chain Class
228
+ // ============================================================================
229
+ export class ChainClass {
230
+ private catcher: Record<string, any> = {};
231
+ private useTokens: boolean;
232
+ private hoverCatcher: Record<string, any> | null = null;
233
+ private valueCache = new Map<string, any>();
234
+ private readonly MAX_CACHE_SIZE = 200;
235
+ public __proxy: any = null;
236
+
237
+ constructor(useTokens: boolean = true) {
238
+ this.useTokens = useTokens;
239
+ }
240
+
241
+ // ==========================================================================
242
+ // Core Methods
243
+ // ==========================================================================
244
+
245
+ private resolveValue(value: any): any {
246
+ const cacheKey = typeof value === 'function' ? `fn_${value.toString().slice(0, 100)}` : JSON.stringify(value);
247
+ if (this.valueCache.has(cacheKey)) {
248
+ return this.valueCache.get(cacheKey);
249
+ }
250
+
251
+ let resolved = value;
252
+ if (typeof value === 'function') {
253
+ resolved = value(helpers);
254
+ }
255
+ if (this.useTokens && typeof resolved === 'string' && resolved.includes('$')) {
256
+ const tokenResolved = resolveToken(resolved, this.useTokens, currentTokenContext);
257
+ resolved = tokenResolved !== undefined && tokenResolved !== null ? tokenResolved : resolved;
258
+ }
259
+
260
+ // Prune cache if too large
261
+ if (this.valueCache.size >= this.MAX_CACHE_SIZE) {
262
+ const firstKey = this.valueCache.keys().next().value;
263
+ if (firstKey) this.valueCache.delete(firstKey);
264
+ }
265
+
266
+ this.valueCache.set(cacheKey, resolved);
267
+ return resolved;
268
+ }
269
+
270
+ private setTransform(type: string, value: any): this {
271
+ if (!this.catcher._transforms) this.catcher._transforms = {};
272
+ this.catcher._transforms[type] = this.resolveValue(value);
273
+ return this.__proxy || this;
274
+ }
275
+
276
+ private setProperty(prop: string, value: any): any {
277
+ // Handle shorthand first
278
+ if (handleShorthand(prop, value, this.catcher, this.useTokens)) {
279
+ return this.__proxy || this;
280
+ }
281
+
282
+ const mappedProp = shorthandMap[prop] || prop;
283
+ let resolvedValue = this.resolveValue(value);
284
+
285
+ if (debugMode) {
286
+ const displayProp = prop === mappedProp ? prop : `${prop} (${mappedProp})`;
287
+ console.log(
288
+ chalk.blue(`[ChainCSS Debug]`),
289
+ chalk.gray(displayProp),
290
+ '->',
291
+ chalk.green(resolvedValue)
292
+ );
293
+ }
294
+
295
+ // Auto-unit logic: if it's a number and needs a unit, add 'px'
296
+ const unitlessProperties = new Set([
297
+ 'zIndex', 'opacity', 'flex', 'order', 'flexGrow', 'flexShrink', 'flexBasis',
298
+ 'fontWeight', 'lineHeight', 'scale', 'zoom', 'animationIterationCount',
299
+ 'columnCount', 'orphans', 'widows', 'tabSize'
300
+ ]);
301
+
302
+ if (typeof resolvedValue === 'number' && !unitlessProperties.has(prop) && !unitlessProperties.has(mappedProp)) {
303
+ resolvedValue = `${resolvedValue}px`;
304
+ }
305
+
306
+ if (this.hoverCatcher !== null) {
307
+ this.hoverCatcher[mappedProp] = resolvedValue;
308
+ } else {
309
+ this.catcher[mappedProp] = resolvedValue;
310
+ }
311
+ return this.__proxy || this;
312
+ }
313
+
314
+ // ==========================================================================
315
+ // Proxy handler - routes all property access
316
+ // ==========================================================================
317
+
318
+ get(prop: string | symbol): any {
319
+ if (typeof prop === 'symbol') return undefined;
320
+
321
+ // ===== MACROS (check first - they take priority) =====
322
+
323
+ // Spacing & Sizing
324
+ if (prop === 'mx') return (value: string | number) => this.macroHandler('mx', value);
325
+ if (prop === 'my') return (value: string | number) => this.macroHandler('my', value);
326
+ if (prop === 'px') return (value: string | number) => this.macroHandler('px', value);
327
+ if (prop === 'py') return (value: string | number) => this.macroHandler('py', value);
328
+ if (prop === 'size') return (value: string | number) => this.macroHandler('size', value);
329
+ if (prop === 'inset') return (value: any) => this.macroHandler('inset', value);
330
+ if (prop === 'insetX') return (value: string | number) => this.macroHandler('insetX', value);
331
+ if (prop === 'insetY') return (value: string | number) => this.macroHandler('insetY', value);
332
+
333
+ // Borders
334
+ if (prop === 'borderX') return (value: string) => this.macroHandler('borderX', value);
335
+ if (prop === 'borderY') return (value: string) => this.macroHandler('borderY', value);
336
+
337
+ // Layout & Display
338
+ if (prop === 'flex') return (value?: string | boolean) => this.macroHandler('flex', value);
339
+ if (prop === 'inlineFlex') return (value?: any) => this.macroHandler('inlineFlex', value);
340
+ if (prop === 'grid') return (value?: string | boolean) => this.macroHandler('grid', value);
341
+ if (prop === 'inlineGrid') return (value?: any) => this.macroHandler('inlineGrid', value);
342
+ if (prop === 'cols') return (value: number | string) => this.macroHandler('cols', value);
343
+ if (prop === 'rows') return (value: number | string) => this.macroHandler('rows', value);
344
+ if (prop === 'center') return (type?: 'flex' | 'inline') => this.macroHandler('center', type);
345
+ if (prop === 'flexCenter') return (dir?: 'row' | 'col' | 'column') => this.macroHandler('flexCenter', dir);
346
+ if (prop === 'gridCenter') return () => this.macroHandler('gridCenter');
347
+ if (prop === 'stack') return (config: any) => this.macroHandler('stack', config);
348
+ if (prop === 'gridTable') return (minWidth: string | number) => this.macroHandler('gridTable', minWidth);
349
+ if (prop === 'aspect') return (ratio: string) => this.macroHandler('aspect', ratio);
350
+
351
+ // Visibility & Behavior
352
+ if (prop === 'hide') return () => this.macroHandler('hide');
353
+ if (prop === 'show') return () => this.macroHandler('show');
354
+ if (prop === 'unselectable') return () => this.macroHandler('unselectable');
355
+ if (prop === 'scrollable') return (axis?: 'x' | 'y' | 'both') => this.macroHandler('scrollable', axis);
356
+ if (prop === 'safeArea') return (edge?: any) => this.macroHandler('safeArea', edge);
357
+
358
+ // Positioning
359
+ if (prop === 'absolute') return (coords?: any) => this.macroHandler('absolute', coords);
360
+ if (prop === 'fixed') return (coords?: any) => this.macroHandler('fixed', coords);
361
+ if (prop === 'sticky') return (coords?: any) => this.macroHandler('sticky', coords);
362
+ if (prop === 'relative') return (coords?: any) => this.macroHandler('relative', coords);
363
+
364
+ // Shapes & Typography
365
+ if (prop === 'circle') return (size: string | number) => this.macroHandler('circle', size);
366
+ if (prop === 'square') return (size: string | number) => this.macroHandler('square', size);
367
+ if (prop === 'truncate') return () => this.macroHandler('truncate');
368
+ if (prop === 'fluidText') return (config: any) => this.macroHandler('fluidText', config);
369
+
370
+ // Aesthetic Effects
371
+ if (prop === 'glass') return (blur?: string | number) => this.macroHandler('glass', blur);
372
+ if (prop === 'glow') return (config: any) => this.macroHandler('glow', config);
373
+ if (prop === 'textGradient') return (colors: any) => this.macroHandler('textGradient', colors);
374
+ if (prop === 'meshGradient') return (colors: string[]) => this.macroHandler('meshGradient', colors);
375
+ if (prop === 'noise') return (opacity?: number) => this.macroHandler('noise', opacity);
376
+
377
+ // State & Logic
378
+ if (prop === 'skeleton') return (active: any) => this.macroHandler('skeleton', active);
379
+ if (prop === 'clickScale') return (amount?: number) => this.macroHandler('clickScale', amount);
380
+ if (prop === 'onInteracting') return (callback: (css: Chain) => void) => this.macroHandler('onInteracting', callback);
381
+ if (prop === 'children') return (callback: (css: Chain) => void) => this.macroHandler('children', callback);
382
+ if (prop === 'dark') return (callback: (css: Chain) => void) => this.macroHandler('dark', callback);
383
+ if (prop === 'light') return (callback: (css: Chain) => void) => this.macroHandler('light', callback);
384
+
385
+ // Utility
386
+ if (prop === 'pill') return () => this.macroHandler('pill');
387
+ if (prop === 'containerMacro') return (maxWidth?: string | number) => this.macroHandler('containerMacro', maxWidth);
388
+ if (prop === 'fullScreen') return (zIndex?: number) => this.macroHandler('fullScreen', zIndex);
389
+ if (prop === 'shimmer') return () => this.macroHandler('shimmer');
390
+ if (prop === 'bento') return (cols?: any) => this.macroHandler('bento', cols);
391
+ if (prop === 'pressable') return () => this.macroHandler('pressable');
392
+ if (prop === 'focusRing') return (color?: string) => this.macroHandler('focusRing', color);
393
+ if (prop === 'outlineDebug') return () => this.macroHandler('outlineDebug');
394
+ if (prop === 'parallax') return (scale?: number) => this.macroHandler('parallax', scale);
395
+ if (prop === 'lineClamp') return (lines?: number) => this.macroHandler('lineClamp', lines);
396
+ if (prop === 'frostedNav') return (blur?: number | string) => this.macroHandler('frostedNav', blur);
397
+
398
+ // Gap macros
399
+ if (prop === 'gap') return (value: string | number) => this.setProperty('gap', value);
400
+ if (prop === 'gapX') return (value: string | number) => this.setProperty('columnGap', value);
401
+ if (prop === 'gapY') return (value: string | number) => this.setProperty('rowGap', value);
402
+
403
+ // ===== PUBLIC METHODS =====
404
+ if (prop === 'hover') return this.createHover.bind(this);
405
+ if (prop === 'end') return this.endHover.bind(this);
406
+ if (prop === 'use') return this.useMixin.bind(this);
407
+ if (prop === 'when') return this.whenCondition.bind(this);
408
+ if (prop === 'nest') return this.nestSelector.bind(this);
409
+ if (prop === 'component') return this.setComponent.bind(this);
410
+ if (prop === 'componentName') return this.setComponentName.bind(this);
411
+ if (prop === 'props') return this.setProps.bind(this);
412
+ if (prop === 'debug') return this.enableDebugMode.bind(this);
413
+ if (prop === 'explain') return this.explainShorthand.bind(this);
414
+ if (prop === '$el') return this.finalize.bind(this);
415
+
416
+ // ===== TRANSFORMS =====
417
+ if (prop === 'scale') return (value: number) => this.setTransform('scale', value);
418
+ if (prop === 'rotate') return (value: string | number) => this.setTransform('rotate', value);
419
+ if (prop === 'x') return (value: string | number) => this.setTransform('translateX', value);
420
+ if (prop === 'y') return (value: string | number) => this.setTransform('translateY', value);
421
+ if (prop === 'skew') return (value: string | number) => this.setTransform('skew', value);
422
+
423
+ // ===== ANIMATIONS =====
424
+ if (animationPresets[prop]) {
425
+ return (config?: AnimationConfig) => this.applyAnimation(prop, config);
426
+ }
427
+ if (prop === 'animate') return this.createAnimation.bind(this);
428
+ if (prop === 'duration') return (v: string) => this.setProperty('animationDuration', v);
429
+ if (prop === 'delay') return (v: string) => this.setProperty('animationDelay', v);
430
+ if (prop === 'timing') return (v: string) => this.setProperty('animationTimingFunction', v);
431
+ if (prop === 'iteration') return (v: any) => this.setProperty('animationIterationCount', v);
432
+ if (prop === 'infinite') return () => this.setProperty('animationIterationCount', 'infinite');
433
+
434
+ // ===== MATH HELPERS =====
435
+ if (prop === 'calc') return helpers.calc;
436
+ if (prop === 'add') return helpers.add;
437
+ if (prop === 'subtract' || prop === 'sub') return helpers.subtract;
438
+ if (prop === 'multiply' || prop === 'mul') return helpers.multiply;
439
+ if (prop === 'divide' || prop === 'div') return helpers.divide;
440
+ if (prop === 'mpx') return (v: number | string) => helpers.mpx(v);
441
+ if (prop === 'rem') return (v: number | string) => helpers.rem(v);
442
+ if (prop === 'em') return helpers.em;
443
+ if (prop === 'percent') return helpers.percent;
444
+ if (prop === 'vw') return helpers.vw;
445
+ if (prop === 'vh') return helpers.vh;
446
+ if (prop === 'min') return helpers.min;
447
+ if (prop === 'max') return helpers.max;
448
+ if (prop === 'clamp') return helpers.clamp;
449
+
450
+ // ===== RESPONSIVE BREAKPOINTS =====
451
+ if (currentBreakpoints && currentBreakpoints[prop]) {
452
+ return (callback: (chain: Chain) => any) => this.applyResponsive(prop, callback);
453
+ }
454
+
455
+ // ===== AT-RULES =====
456
+ if (prop === 'media') return this.applyMedia.bind(this);
457
+ if (prop === 'keyframes') return this.defineKeyframes.bind(this);
458
+ if (prop === 'fontFace') return this.defineFontFace.bind(this);
459
+ if (prop === 'supports') return this.applySupports.bind(this);
460
+ if (prop === 'containerQuery') return this.applyContainerQuery.bind(this);
461
+ if (prop === 'layer') return this.applyLayer.bind(this);
462
+
463
+ // ===== CSS PROPERTY (fallthrough) =====
464
+ return (value: any) => this.setProperty(prop, value);
465
+ }
466
+
467
+ // ==========================================================================
468
+ // Finalize
469
+ // ==========================================================================
470
+
471
+ private finalize(...selectors: string[]): any {
472
+ // Deep clone to prevent reference sharing
473
+ const styles: any = structuredClone(this.catcher);
474
+
475
+ // Strip component metadata from output
476
+ delete styles._componentName;
477
+ delete styles._generateComponent;
478
+ delete styles._framework;
479
+ delete styles._propsDefinition;
480
+
481
+ // Process transforms
482
+ if (this.catcher._transforms) {
483
+ const t = this.catcher._transforms;
484
+ const transformString = Object.entries(t)
485
+ .map(([k, v]) => {
486
+ const needsUnit = (k.includes('translate') || k === 'x' || k === 'y');
487
+ const unit = needsUnit && typeof v === 'number' ? 'px' : '';
488
+ return `${k}(${v}${unit})`;
489
+ })
490
+ .join(' ');
491
+ styles.transform = transformString;
492
+ delete styles._transforms;
493
+ }
494
+
495
+ // Flatten nested rules
496
+ if (this.catcher.nestedRules) {
497
+ styles.nestedRules = structuredClone(this.catcher.nestedRules);
498
+ }
499
+
500
+ // Process pseudo-class styles (&:hover -> :hover)
501
+ for (const key of Object.keys(styles)) {
502
+ if (key.startsWith('&:')) {
503
+ const pseudoSelector = key.substring(1);
504
+ styles[pseudoSelector] = styles[key];
505
+ delete styles[key];
506
+ }
507
+ }
508
+
509
+ this.clear();
510
+
511
+ if (selectors.length === 0) return styles;
512
+
513
+ if (debugMode) {
514
+ console.log('[ChainCSS Debug] Raw selectors:', selectors);
515
+ }
516
+
517
+ // Clean selectors - preserve user's dots, only strip internal chain- prefix from .chain- prefixed ones
518
+ const cleanSelectors = selectors.map(selector => {
519
+ let clean = selector;
520
+ // Only remove .chain- prefix if it exists
521
+ if (clean.startsWith('.chain-')) {
522
+ clean = clean.replace(/^\./, '').replace(/^chain-/, '');
523
+ } else if (clean.startsWith('chain-')) {
524
+ clean = clean.substring(6);
525
+ }
526
+ if (debugMode) {
527
+ console.log(`[ChainCSS Debug] Cleaned: "${selector}" -> "${clean}"`);
528
+ }
529
+ return clean;
530
+ });
531
+
532
+ if (debugMode) {
533
+ console.log('[ChainCSS Debug] Final selectors:', cleanSelectors);
534
+ }
535
+
536
+ return {
537
+ selectors: cleanSelectors,
538
+ ...styles
539
+ };
540
+ }
541
+
542
+ // ==========================================================================
543
+ // Public Method Implementations (renamed to avoid collisions)
544
+ // ==========================================================================
545
+
546
+ private macroHandler(macroName: string, value?: any): this {
547
+ const macroFn = macros[macroName];
548
+ if (macroFn) {
549
+ macroFn(value, this.catcher, this.useTokens);
550
+ } else {
551
+ this.setProperty(macroName, value);
552
+ }
553
+ return this.__proxy || this;
554
+ }
555
+
556
+ private createHover(): this {
557
+ if (debugMode) {
558
+ console.log(` 🖱️ Hover styles added`);
559
+ }
560
+ this.hoverCatcher = {};
561
+ return this.__proxy || this;
562
+ }
563
+
564
+ private endHover(): this {
565
+ if (this.hoverCatcher !== null) {
566
+ this.catcher.hover = { ...this.hoverCatcher };
567
+ this.hoverCatcher = null;
568
+ }
569
+ return this.__proxy || this;
570
+ }
571
+
572
+ private useMixin(mixin: Record<string, any>): this {
573
+ const { selectors, atRules, ...styles } = mixin;
574
+ Object.assign(this.catcher, styles);
575
+ if (atRules) {
576
+ this.catcher.atRules = [...(this.catcher.atRules || []), ...atRules];
577
+ }
578
+ return this.__proxy || this;
579
+ }
580
+
581
+ private whenCondition(condition: boolean, callback: (chain: Chain) => void): this {
582
+ if (condition) {
583
+ callback(this.__proxy || this);
584
+ }
585
+ return this.__proxy || this;
586
+ }
587
+
588
+ private nestSelector(selector: string, callback: (chain: Chain) => void): this {
589
+ const subChain = createChain(this.useTokens);
590
+ callback(subChain);
591
+ const result = subChain.$el();
592
+
593
+ if (!this.catcher.nestedRules) this.catcher.nestedRules = [];
594
+ this.catcher.nestedRules.push({
595
+ selector: selector,
596
+ styles: result
597
+ });
598
+ return this.__proxy || this;
599
+ }
600
+
601
+ private setComponentName(name: string): this {
602
+ this.catcher._componentName = name;
603
+ return this.__proxy || this;
604
+ }
605
+
606
+ private setComponent(framework: 'react' | 'vue' | 'svelte' | 'solid' | 'auto' = 'auto'): this {
607
+ this.catcher._generateComponent = true;
608
+ this.catcher._framework = framework;
609
+ return this.__proxy || this;
610
+ }
611
+
612
+ private setProps(propsDefinition?: Record<string, any>): this {
613
+ if (propsDefinition) {
614
+ this.catcher._propsDefinition = propsDefinition;
615
+ }
616
+ return this.__proxy || this;
617
+ }
618
+
619
+ private enableDebugMode(): this {
620
+ debugMode = true;
621
+ return this.__proxy || this;
622
+ }
623
+
624
+ private explainShorthand(shorthand: string): this {
625
+ const mapped = shorthandMap[shorthand];
626
+ if (mapped) {
627
+ console.log(`\n📖 ChainCSS Explanation:`);
628
+ console.log(` .${shorthand}() → ${mapped}`);
629
+ console.log(` Example: .${shorthand}('value') sets CSS property '${mapped}'\n`);
630
+ } else {
631
+ const suggestion = getSuggestion(shorthand);
632
+ if (suggestion && typeof suggestion === 'string') {
633
+ console.log(`\n⚠️ ChainCSS: '${shorthand}' is not a recognized shorthand.`);
634
+ console.log(` Did you mean .${suggestion}()?\n`);
635
+ } else {
636
+ console.log(`\n⚠️ ChainCSS: '${shorthand}' is not a recognized shorthand or CSS property.\n`);
637
+ }
638
+ }
639
+ return this.__proxy || this;
640
+ }
641
+
642
+ // ==========================================================================
643
+ // Animation Methods
644
+ // ==========================================================================
645
+
646
+ private applyAnimation(name: string, config?: AnimationConfig): this {
647
+ if (!name) {
648
+ console.warn('⚠️ ChainCSS: animation() requires a name parameter');
649
+ return this.__proxy || this;
650
+ }
651
+
652
+ if (!this.catcher.atRules) this.catcher.atRules = [];
653
+
654
+ const preset = animationPresets[name];
655
+ if (!preset && !this.catcher.atRules.some((rule: any) => rule.type === 'keyframes' && rule.name === name)) {
656
+ console.warn(`⚠️ ChainCSS: Unknown animation preset '${name}'. Available: ${Object.keys(animationPresets).join(', ')}`);
657
+ return this.__proxy || this;
658
+ }
659
+
660
+ const hasKeyframes = this.catcher.atRules.some(
661
+ (rule: any) => rule.type === 'keyframes' && rule.name === name
662
+ );
663
+
664
+ if (!hasKeyframes && preset) {
665
+ this.catcher.atRules.push({
666
+ type: 'keyframes',
667
+ name: name,
668
+ steps: preset
669
+ });
670
+ }
671
+
672
+ const animationStyles = createAnimation(name, config);
673
+ Object.assign(this.catcher, animationStyles);
674
+ return this.__proxy || this;
675
+ }
676
+
677
+ private createAnimation(name: string, keyframes: Record<string, any>, config?: AnimationConfig): this {
678
+ if (!name || !keyframes) {
679
+ console.warn('⚠️ ChainCSS: animate() requires name and keyframes parameters');
680
+ return this.__proxy || this;
681
+ }
682
+
683
+ if (!this.catcher.atRules) this.catcher.atRules = [];
684
+
685
+ this.catcher.atRules.push({
686
+ type: 'keyframes',
687
+ name: name,
688
+ steps: keyframes
689
+ });
690
+
691
+ const animationStyles = createAnimation(name, config);
692
+ Object.assign(this.catcher, animationStyles);
693
+ return this.__proxy || this;
694
+ }
695
+
696
+ // ==========================================================================
697
+ // Responsive & AT-Rules
698
+ // ==========================================================================
699
+
700
+ private applyResponsive(breakpoint: string, callback: (chain: Chain) => void): this {
701
+ const subChain = createChain(this.useTokens);
702
+ callback(subChain);
703
+ const result = subChain.$el();
704
+ const { selectors, ...pureStyles } = result || {};
705
+
706
+ if (!this.catcher.atRules) this.catcher.atRules = [];
707
+ this.catcher.atRules.push({
708
+ type: 'media',
709
+ query: currentBreakpoints[breakpoint],
710
+ styles: pureStyles
711
+ });
712
+ return this.__proxy || this;
713
+ }
714
+
715
+ private applyMedia(query: string, callback: (chain: Chain) => void): this {
716
+ const subChain = createChain(this.useTokens);
717
+ callback(subChain);
718
+ const result = subChain.$el();
719
+ const { selectors, ...pureStyles } = result || {};
720
+
721
+ if (!this.catcher.atRules) this.catcher.atRules = [];
722
+ this.catcher.atRules.push({
723
+ type: 'media',
724
+ query: query,
725
+ styles: pureStyles
726
+ });
727
+ return this.__proxy || this;
728
+ }
729
+
730
+ private defineKeyframes(name: string, steps: Record<string, any>): this {
731
+ if (!this.catcher.atRules) this.catcher.atRules = [];
732
+ this.catcher.atRules.push({
733
+ type: 'keyframes',
734
+ name: name,
735
+ steps: steps
736
+ });
737
+ return this.__proxy || this;
738
+ }
739
+
740
+ private defineFontFace(properties: Record<string, string>): this {
741
+ if (!this.catcher.atRules) this.catcher.atRules = [];
742
+ this.catcher.atRules.push({
743
+ type: 'font-face',
744
+ properties: properties
745
+ });
746
+ return this.__proxy || this;
747
+ }
748
+
749
+ private applySupports(condition: string, callback: (chain: Chain) => void): this {
750
+ const subChain = createChain(this.useTokens);
751
+ callback(subChain);
752
+ const result = subChain.$el();
753
+
754
+ if (!this.catcher.atRules) this.catcher.atRules = [];
755
+ this.catcher.atRules.push({
756
+ type: 'supports',
757
+ condition: condition,
758
+ styles: result
759
+ });
760
+ return this.__proxy || this;
761
+ }
762
+
763
+ private applyContainerQuery(condition: string, callback: (chain: Chain) => void): this {
764
+ const subChain = createChain(this.useTokens);
765
+ callback(subChain);
766
+ const result = subChain.$el();
767
+
768
+ if (!this.catcher.atRules) this.catcher.atRules = [];
769
+ this.catcher.atRules.push({
770
+ type: 'container',
771
+ condition: condition,
772
+ styles: result
773
+ });
774
+ return this.__proxy || this;
775
+ }
776
+
777
+ private applyLayer(name: string, callback: (chain: Chain) => void): this {
778
+ const subChain = createChain(this.useTokens);
779
+ callback(subChain);
780
+ const result = subChain.$el();
781
+
782
+ if (!this.catcher.atRules) this.catcher.atRules = [];
783
+ this.catcher.atRules.push({
784
+ type: 'layer',
785
+ name: name,
786
+ styles: result
787
+ });
788
+ return this.__proxy || this;
789
+ }
790
+
791
+ // ==========================================================================
792
+ // Cleanup
793
+ // ==========================================================================
794
+
795
+ private clear(): void {
796
+ this.catcher = {};
797
+ this.hoverCatcher = null;
798
+ this.valueCache.clear();
799
+ }
800
+ }
801
+
802
+ // ============================================================================
803
+ // Factory Function
804
+ // ============================================================================
805
+
806
+ export function createChain(useTokens: boolean = true): Chain {
807
+ const chained = new ChainClass(useTokens);
808
+
809
+ const proxy = new Proxy(chained, {
810
+ get(target, prop: string | symbol) {
811
+ if (typeof prop === 'symbol') return undefined;
812
+
813
+ // Only expose whitelisted public methods directly
814
+ if (PUBLIC_METHODS.has(prop) && prop in target) {
815
+ const val = (target as any)[prop];
816
+ return typeof val === 'function' ? val.bind(target) : val;
817
+ }
818
+
819
+ // Route everything else through the get handler
820
+ return target.get(prop);
821
+ }
822
+ });
823
+
824
+ // Set proxy reference on the instance so methods can return it
825
+ (chained as any).__proxy = proxy;
826
+
827
+ return proxy as unknown as Chain;
828
+ }
829
+
830
+ // Default export
831
+ export const chain = (useTokens: boolean = true) => createChain(useTokens);