loopwind 0.12.2 → 0.13.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.
@@ -0,0 +1,656 @@
1
+ /**
2
+ * Browser-safe version of tailwind.ts
3
+ * This version doesn't import any Node.js modules and can be bundled for browser use.
4
+ */
5
+ // Tailwind color palette
6
+ const TAILWIND_COLORS = {
7
+ slate: { 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a', 950: '#020617' },
8
+ gray: { 50: '#f9fafb', 100: '#f3f4f6', 200: '#e5e7eb', 300: '#d1d5db', 400: '#9ca3af', 500: '#6b7280', 600: '#4b5563', 700: '#374151', 800: '#1f2937', 900: '#111827', 950: '#030712' },
9
+ zinc: { 50: '#fafafa', 100: '#f4f4f5', 200: '#e4e4e7', 300: '#d4d4d8', 400: '#a1a1aa', 500: '#71717a', 600: '#52525b', 700: '#3f3f46', 800: '#27272a', 900: '#18181b', 950: '#09090b' },
10
+ neutral: { 50: '#fafafa', 100: '#f5f5f5', 200: '#e5e5e5', 300: '#d4d4d4', 400: '#a3a3a3', 500: '#737373', 600: '#525252', 700: '#404040', 800: '#262626', 900: '#171717', 950: '#0a0a0a' },
11
+ stone: { 50: '#fafaf9', 100: '#f5f5f4', 200: '#e7e5e4', 300: '#d6d3d1', 400: '#a8a29e', 500: '#78716c', 600: '#57534e', 700: '#44403c', 800: '#292524', 900: '#1c1917', 950: '#0c0a09' },
12
+ red: { 50: '#fef2f2', 100: '#fee2e2', 200: '#fecaca', 300: '#fca5a5', 400: '#f87171', 500: '#ef4444', 600: '#dc2626', 700: '#b91c1c', 800: '#991b1b', 900: '#7f1d1d', 950: '#450a0a' },
13
+ orange: { 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74', 400: '#fb923c', 500: '#f97316', 600: '#ea580c', 700: '#c2410c', 800: '#9a3412', 900: '#7c2d12', 950: '#431407' },
14
+ amber: { 50: '#fffbeb', 100: '#fef3c7', 200: '#fde68a', 300: '#fcd34d', 400: '#fbbf24', 500: '#f59e0b', 600: '#d97706', 700: '#b45309', 800: '#92400e', 900: '#78350f', 950: '#451a03' },
15
+ yellow: { 50: '#fefce8', 100: '#fef9c3', 200: '#fef08a', 300: '#fde047', 400: '#facc15', 500: '#eab308', 600: '#ca8a04', 700: '#a16207', 800: '#854d0e', 900: '#713f12', 950: '#422006' },
16
+ lime: { 50: '#f7fee7', 100: '#ecfccb', 200: '#d9f99d', 300: '#bef264', 400: '#a3e635', 500: '#84cc16', 600: '#65a30d', 700: '#4d7c0f', 800: '#3f6212', 900: '#365314', 950: '#1a2e05' },
17
+ green: { 50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac', 400: '#4ade80', 500: '#22c55e', 600: '#16a34a', 700: '#15803d', 800: '#166534', 900: '#14532d', 950: '#052e16' },
18
+ emerald: { 50: '#ecfdf5', 100: '#d1fae5', 200: '#a7f3d0', 300: '#6ee7b7', 400: '#34d399', 500: '#10b981', 600: '#059669', 700: '#047857', 800: '#065f46', 900: '#064e3b', 950: '#022c22' },
19
+ teal: { 50: '#f0fdfa', 100: '#ccfbf1', 200: '#99f6e4', 300: '#5eead4', 400: '#2dd4bf', 500: '#14b8a6', 600: '#0d9488', 700: '#0f766e', 800: '#115e59', 900: '#134e4a', 950: '#042f2e' },
20
+ cyan: { 50: '#ecfeff', 100: '#cffafe', 200: '#a5f3fc', 300: '#67e8f9', 400: '#22d3ee', 500: '#06b6d4', 600: '#0891b2', 700: '#0e7490', 800: '#155e75', 900: '#164e63', 950: '#083344' },
21
+ sky: { 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', 300: '#7dd3fc', 400: '#38bdf8', 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1', 800: '#075985', 900: '#0c4a6e', 950: '#082f49' },
22
+ blue: { 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a', 950: '#172554' },
23
+ indigo: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81', 950: '#1e1b4b' },
24
+ violet: { 50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd', 400: '#a78bfa', 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9', 800: '#5b21b6', 900: '#4c1d95', 950: '#2e1065' },
25
+ purple: { 50: '#faf5ff', 100: '#f3e8ff', 200: '#e9d5ff', 300: '#d8b4fe', 400: '#c084fc', 500: '#a855f7', 600: '#9333ea', 700: '#7e22ce', 800: '#6b21a8', 900: '#581c87', 950: '#3b0764' },
26
+ fuchsia: { 50: '#fdf4ff', 100: '#fae8ff', 200: '#f5d0fe', 300: '#f0abfc', 400: '#e879f9', 500: '#d946ef', 600: '#c026d3', 700: '#a21caf', 800: '#86198f', 900: '#701a75', 950: '#4a044e' },
27
+ pink: { 50: '#fdf2f8', 100: '#fce7f3', 200: '#fbcfe8', 300: '#f9a8d4', 400: '#f472b6', 500: '#ec4899', 600: '#db2777', 700: '#be185d', 800: '#9d174d', 900: '#831843', 950: '#500724' },
28
+ rose: { 50: '#fff1f2', 100: '#ffe4e6', 200: '#fecdd3', 300: '#fda4af', 400: '#fb7185', 500: '#f43f5e', 600: '#e11d48', 700: '#be123c', 800: '#9f1239', 900: '#881337', 950: '#4c0519' },
29
+ };
30
+ // Browser-safe resolver functions
31
+ function resolveColor(colorName, config) {
32
+ // First check Tailwind palette (e.g., "blue-600")
33
+ const colorMatch = colorName.match(/^(\w+)-(\d+)$/);
34
+ if (colorMatch) {
35
+ const [, name, shade] = colorMatch;
36
+ if (TAILWIND_COLORS[name]?.[shade]) {
37
+ return TAILWIND_COLORS[name][shade];
38
+ }
39
+ }
40
+ // Check config
41
+ if (!config?.theme)
42
+ return null;
43
+ // Check extend first
44
+ const extendColors = config.theme.extend?.colors;
45
+ if (extendColors?.[colorName])
46
+ return extendColors[colorName];
47
+ // Check base colors
48
+ const baseColors = config.theme.colors;
49
+ if (baseColors?.[colorName])
50
+ return baseColors[colorName];
51
+ return null;
52
+ }
53
+ function resolveSpacing(value, config) {
54
+ if (!config?.theme)
55
+ return null;
56
+ const extendSpacing = config.theme.extend?.spacing;
57
+ if (extendSpacing?.[value])
58
+ return extendSpacing[value];
59
+ const baseSpacing = config.theme.spacing;
60
+ if (baseSpacing?.[value])
61
+ return baseSpacing[value];
62
+ return null;
63
+ }
64
+ function resolveFontSize(size, config) {
65
+ if (!config?.theme)
66
+ return null;
67
+ const extendFontSize = config.theme.extend?.fontSize;
68
+ if (extendFontSize?.[size]) {
69
+ const val = extendFontSize[size];
70
+ if (Array.isArray(val)) {
71
+ return { fontSize: val[0], lineHeight: val[1] };
72
+ }
73
+ return { fontSize: val };
74
+ }
75
+ const baseFontSize = config.theme.fontSize;
76
+ if (baseFontSize?.[size]) {
77
+ const val = baseFontSize[size];
78
+ if (Array.isArray(val)) {
79
+ return { fontSize: val[0], lineHeight: val[1] };
80
+ }
81
+ return { fontSize: val };
82
+ }
83
+ return null;
84
+ }
85
+ function resolveBorderRadius(value, config) {
86
+ if (!config?.theme)
87
+ return null;
88
+ const extendRadius = config.theme.extend?.borderRadius;
89
+ if (extendRadius?.[value])
90
+ return extendRadius[value];
91
+ const baseRadius = config.theme.borderRadius;
92
+ if (baseRadius?.[value])
93
+ return baseRadius[value];
94
+ return null;
95
+ }
96
+ /**
97
+ * Tailwind class to style property mapping
98
+ */
99
+ const TAILWIND_MAP = {
100
+ // Display
101
+ 'flex': { display: 'flex' },
102
+ 'inline-flex': { display: 'inline-flex' },
103
+ 'block': { display: 'block' },
104
+ 'inline-block': { display: 'inline-block' },
105
+ 'hidden': { display: 'none' },
106
+ 'contents': { display: 'contents' },
107
+ // Position
108
+ 'static': { position: 'static' },
109
+ 'relative': { position: 'relative' },
110
+ 'absolute': { position: 'absolute' },
111
+ // Overflow
112
+ 'overflow-visible': { overflow: 'visible' },
113
+ 'overflow-hidden': { overflow: 'hidden' },
114
+ // Flex Direction
115
+ 'flex-row': { flexDirection: 'row' },
116
+ 'flex-col': { flexDirection: 'column' },
117
+ 'flex-row-reverse': { flexDirection: 'row-reverse' },
118
+ 'flex-col-reverse': { flexDirection: 'column-reverse' },
119
+ // Flex Wrap
120
+ 'flex-wrap': { flexWrap: 'wrap' },
121
+ 'flex-nowrap': { flexWrap: 'nowrap' },
122
+ 'flex-wrap-reverse': { flexWrap: 'wrap-reverse' },
123
+ // Flex
124
+ 'flex-1': { flex: '1 1 0%' },
125
+ 'flex-auto': { flex: '1 1 auto' },
126
+ 'flex-initial': { flex: '0 1 auto' },
127
+ 'flex-none': { flex: 'none' },
128
+ // Justify Content
129
+ 'justify-start': { justifyContent: 'flex-start' },
130
+ 'justify-end': { justifyContent: 'flex-end' },
131
+ 'justify-center': { justifyContent: 'center' },
132
+ 'justify-between': { justifyContent: 'space-between' },
133
+ 'justify-around': { justifyContent: 'space-around' },
134
+ 'justify-evenly': { justifyContent: 'space-evenly' },
135
+ // Align Items
136
+ 'items-start': { alignItems: 'flex-start' },
137
+ 'items-end': { alignItems: 'flex-end' },
138
+ 'items-center': { alignItems: 'center' },
139
+ 'items-baseline': { alignItems: 'baseline' },
140
+ 'items-stretch': { alignItems: 'stretch' },
141
+ // Width & Height
142
+ 'w-full': { width: '100%' },
143
+ 'h-full': { height: '100%' },
144
+ 'w-screen': { width: '100vw' },
145
+ 'h-screen': { height: '100vh' },
146
+ 'w-auto': { width: 'auto' },
147
+ 'h-auto': { height: 'auto' },
148
+ // Text Alignment
149
+ 'text-left': { textAlign: 'left' },
150
+ 'text-center': { textAlign: 'center' },
151
+ 'text-right': { textAlign: 'right' },
152
+ 'text-justify': { textAlign: 'justify' },
153
+ // Font Weight
154
+ 'font-thin': { fontWeight: 100 },
155
+ 'font-extralight': { fontWeight: 200 },
156
+ 'font-light': { fontWeight: 300 },
157
+ 'font-normal': { fontWeight: 400 },
158
+ 'font-medium': { fontWeight: 500 },
159
+ 'font-semibold': { fontWeight: 600 },
160
+ 'font-bold': { fontWeight: 700 },
161
+ 'font-extrabold': { fontWeight: 800 },
162
+ 'font-black': { fontWeight: 900 },
163
+ // Colors
164
+ 'text-white': { color: '#ffffff' },
165
+ 'text-black': { color: '#000000' },
166
+ 'bg-white': { background: '#ffffff' },
167
+ 'bg-black': { background: '#000000' },
168
+ 'bg-transparent': { background: 'transparent' },
169
+ // Rounded
170
+ 'rounded': { borderRadius: '0.25rem' },
171
+ 'rounded-none': { borderRadius: '0' },
172
+ 'rounded-sm': { borderRadius: '0.125rem' },
173
+ 'rounded-md': { borderRadius: '0.375rem' },
174
+ 'rounded-lg': { borderRadius: '0.5rem' },
175
+ 'rounded-xl': { borderRadius: '0.75rem' },
176
+ 'rounded-2xl': { borderRadius: '1rem' },
177
+ 'rounded-3xl': { borderRadius: '1.5rem' },
178
+ 'rounded-full': { borderRadius: '9999px' },
179
+ };
180
+ // Spacing scale
181
+ const SPACING_SCALE = {
182
+ '0': '0px',
183
+ '1': '0.25rem',
184
+ '2': '0.5rem',
185
+ '3': '0.75rem',
186
+ '4': '1rem',
187
+ '5': '1.25rem',
188
+ '6': '1.5rem',
189
+ '8': '2rem',
190
+ '10': '2.5rem',
191
+ '12': '3rem',
192
+ '16': '4rem',
193
+ '20': '5rem',
194
+ '24': '6rem',
195
+ '32': '8rem',
196
+ '40': '10rem',
197
+ '48': '12rem',
198
+ '56': '14rem',
199
+ '64': '16rem',
200
+ };
201
+ // Font size map
202
+ const FONT_SIZE_MAP = {
203
+ 'text-xs': { fontSize: '0.75rem', lineHeight: '1rem' },
204
+ 'text-sm': { fontSize: '0.875rem', lineHeight: '1.25rem' },
205
+ 'text-base': { fontSize: '1rem', lineHeight: '1.5rem' },
206
+ 'text-lg': { fontSize: '1.125rem', lineHeight: '1.75rem' },
207
+ 'text-xl': { fontSize: '1.25rem', lineHeight: '1.75rem' },
208
+ 'text-2xl': { fontSize: '1.5rem', lineHeight: '2rem' },
209
+ 'text-3xl': { fontSize: '1.875rem', lineHeight: '2.25rem' },
210
+ 'text-4xl': { fontSize: '2.25rem', lineHeight: '2.5rem' },
211
+ 'text-5xl': { fontSize: '3rem', lineHeight: '1' },
212
+ 'text-6xl': { fontSize: '3.75rem', lineHeight: '1' },
213
+ 'text-7xl': { fontSize: '4.5rem', lineHeight: '1' },
214
+ 'text-8xl': { fontSize: '6rem', lineHeight: '1' },
215
+ 'text-9xl': { fontSize: '8rem', lineHeight: '1' },
216
+ };
217
+ // Easing functions
218
+ const easingFunctions = {
219
+ 'linear': (t) => t,
220
+ 'ease-in': (t) => t * t,
221
+ 'ease-out': (t) => t * (2 - t),
222
+ 'ease-in-out': (t) => t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t,
223
+ 'ease-in-cubic': (t) => t * t * t,
224
+ 'ease-out-cubic': (t) => (--t) * t * t + 1,
225
+ 'ease-in-out-cubic': (t) => t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1,
226
+ 'ease-in-quart': (t) => t * t * t * t,
227
+ 'ease-out-quart': (t) => 1 - (--t) * t * t * t,
228
+ 'ease-in-out-quart': (t) => t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t,
229
+ };
230
+ function hexToRgba(hex, opacity) {
231
+ const cleanHex = hex.replace('#', '');
232
+ const r = parseInt(cleanHex.substring(0, 2), 16);
233
+ const g = parseInt(cleanHex.substring(2, 4), 16);
234
+ const b = parseInt(cleanHex.substring(4, 6), 16);
235
+ return `rgba(${r}, ${g}, ${b}, ${opacity})`;
236
+ }
237
+ function parseTimeValue(value) {
238
+ if (value.startsWith('[') && value.endsWith(']')) {
239
+ const inner = value.slice(1, -1);
240
+ if (inner.endsWith('ms')) {
241
+ return parseFloat(inner.slice(0, -2));
242
+ }
243
+ else if (inner.endsWith('s')) {
244
+ return parseFloat(inner.slice(0, -1)) * 1000;
245
+ }
246
+ return parseFloat(inner);
247
+ }
248
+ return parseFloat(value);
249
+ }
250
+ function parseClass(className, tailwindConfig = null, loopwindConfig = null) {
251
+ if (TAILWIND_MAP[className]) {
252
+ return TAILWIND_MAP[className];
253
+ }
254
+ // Parse arbitrary values like text-[62px], w-[200px], etc.
255
+ const arbitraryFontMatch = className.match(/^text-\[(.+)\]$/);
256
+ if (arbitraryFontMatch) {
257
+ return { fontSize: arbitraryFontMatch[1] };
258
+ }
259
+ const arbitraryWidthMatch = className.match(/^w-\[(.+)\]$/);
260
+ if (arbitraryWidthMatch) {
261
+ return { width: arbitraryWidthMatch[1] };
262
+ }
263
+ const arbitraryHeightMatch = className.match(/^h-\[(.+)\]$/);
264
+ if (arbitraryHeightMatch) {
265
+ return { height: arbitraryHeightMatch[1] };
266
+ }
267
+ const arbitraryPaddingMatch = className.match(/^(p)(x|y|t|b|l|r)?-\[(.+)\]$/);
268
+ if (arbitraryPaddingMatch) {
269
+ const [, , direction, value] = arbitraryPaddingMatch;
270
+ if (!direction)
271
+ return { padding: value };
272
+ if (direction === 'x')
273
+ return { paddingLeft: value, paddingRight: value };
274
+ if (direction === 'y')
275
+ return { paddingTop: value, paddingBottom: value };
276
+ const dirMap = { t: 'Top', b: 'Bottom', l: 'Left', r: 'Right' };
277
+ return { [`padding${dirMap[direction]}`]: value };
278
+ }
279
+ const arbitraryMarginMatch = className.match(/^(m)(x|y|t|b|l|r)?-\[(.+)\]$/);
280
+ if (arbitraryMarginMatch) {
281
+ const [, , direction, value] = arbitraryMarginMatch;
282
+ if (!direction)
283
+ return { margin: value };
284
+ if (direction === 'x')
285
+ return { marginLeft: value, marginRight: value };
286
+ if (direction === 'y')
287
+ return { marginTop: value, marginBottom: value };
288
+ const dirMap = { t: 'Top', b: 'Bottom', l: 'Left', r: 'Right' };
289
+ return { [`margin${dirMap[direction]}`]: value };
290
+ }
291
+ const arbitraryGapMatch = className.match(/^gap(-x|-y)?-\[(.+)\]$/);
292
+ if (arbitraryGapMatch) {
293
+ const [, direction, value] = arbitraryGapMatch;
294
+ if (!direction)
295
+ return { gap: value };
296
+ if (direction === '-x')
297
+ return { columnGap: value };
298
+ if (direction === '-y')
299
+ return { rowGap: value };
300
+ }
301
+ const arbitraryRoundedMatch = className.match(/^rounded-\[(.+)\]$/);
302
+ if (arbitraryRoundedMatch) {
303
+ return { borderRadius: arbitraryRoundedMatch[1] };
304
+ }
305
+ const arbitraryLeadingMatch = className.match(/^leading-\[(.+)\]$/);
306
+ if (arbitraryLeadingMatch) {
307
+ return { lineHeight: arbitraryLeadingMatch[1] };
308
+ }
309
+ const arbitraryTrackingMatch = className.match(/^tracking-\[(.+)\]$/);
310
+ if (arbitraryTrackingMatch) {
311
+ return { letterSpacing: arbitraryTrackingMatch[1] };
312
+ }
313
+ // Parse font sizes
314
+ const fontSizeMatch = className.match(/^text-(xs|sm|base|lg|xl|2xl|3xl|4xl|5xl|6xl|7xl|8xl|9xl)$/);
315
+ if (fontSizeMatch) {
316
+ const size = fontSizeMatch[1];
317
+ const configSize = resolveFontSize(size, tailwindConfig);
318
+ if (configSize)
319
+ return configSize;
320
+ if (FONT_SIZE_MAP[className])
321
+ return FONT_SIZE_MAP[className];
322
+ }
323
+ // Parse padding/margin
324
+ const spacingMatch = className.match(/^(p|m)(x|y|t|b|l|r)?-(\d+|px)$/);
325
+ if (spacingMatch) {
326
+ const [, type, direction, value] = spacingMatch;
327
+ let size = resolveSpacing(value, tailwindConfig) || SPACING_SCALE[value] || `${parseInt(value) * 0.25}rem`;
328
+ const prop = type === 'p' ? 'padding' : 'margin';
329
+ if (!direction) {
330
+ return { [prop]: size };
331
+ }
332
+ else if (direction === 'x') {
333
+ return { [`${prop}Left`]: size, [`${prop}Right`]: size };
334
+ }
335
+ else if (direction === 'y') {
336
+ return { [`${prop}Top`]: size, [`${prop}Bottom`]: size };
337
+ }
338
+ else {
339
+ const dirMap = { t: 'Top', b: 'Bottom', l: 'Left', r: 'Right' };
340
+ return { [`${prop}${dirMap[direction]}`]: size };
341
+ }
342
+ }
343
+ // Parse width/height
344
+ const sizeMatch = className.match(/^(w|h)-(\d+)$/);
345
+ if (sizeMatch) {
346
+ const [, prop, value] = sizeMatch;
347
+ const size = resolveSpacing(value, tailwindConfig) || SPACING_SCALE[value] || `${parseInt(value) * 0.25}rem`;
348
+ return { [prop === 'w' ? 'width' : 'height']: size };
349
+ }
350
+ // Parse gap
351
+ const gapMatch = className.match(/^gap(-x|-y)?-(\d+)$/);
352
+ if (gapMatch) {
353
+ const [, direction, value] = gapMatch;
354
+ const size = resolveSpacing(value, tailwindConfig) || SPACING_SCALE[value] || `${parseInt(value) * 0.25}rem`;
355
+ if (!direction) {
356
+ return { gap: size };
357
+ }
358
+ else if (direction === '-x') {
359
+ return { columnGap: size };
360
+ }
361
+ else if (direction === '-y') {
362
+ return { rowGap: size };
363
+ }
364
+ }
365
+ // Parse opacity
366
+ const opacityMatch = className.match(/^opacity-(\d+)$/);
367
+ if (opacityMatch) {
368
+ return { opacity: parseInt(opacityMatch[1]) / 100 };
369
+ }
370
+ // Parse colors with opacity modifier
371
+ const bgMatch = className.match(/^bg-([\w-]+)(?:\/(\d+))?$/);
372
+ if (bgMatch) {
373
+ const colorName = bgMatch[1];
374
+ const opacityValue = bgMatch[2];
375
+ let color = resolveColor(colorName, tailwindConfig);
376
+ if (!color && loopwindConfig?.colors?.[colorName]) {
377
+ color = loopwindConfig.colors[colorName];
378
+ }
379
+ if (color) {
380
+ if (opacityValue) {
381
+ const opacity = parseInt(opacityValue) / 100;
382
+ const hex = color.replace('#', '');
383
+ const r = parseInt(hex.substring(0, 2), 16);
384
+ const g = parseInt(hex.substring(2, 4), 16);
385
+ const b = parseInt(hex.substring(4, 6), 16);
386
+ return { background: `rgba(${r}, ${g}, ${b}, ${opacity})` };
387
+ }
388
+ return { background: color };
389
+ }
390
+ }
391
+ const textMatch = className.match(/^text-([\w-]+)(?:\/(\d+))?$/);
392
+ if (textMatch) {
393
+ const colorName = textMatch[1];
394
+ const opacityValue = textMatch[2];
395
+ let color = resolveColor(colorName, tailwindConfig);
396
+ if (!color && loopwindConfig?.colors?.[colorName]) {
397
+ color = loopwindConfig.colors[colorName];
398
+ }
399
+ if (color) {
400
+ if (opacityValue) {
401
+ const opacity = parseInt(opacityValue) / 100;
402
+ const hex = color.replace('#', '');
403
+ const r = parseInt(hex.substring(0, 2), 16);
404
+ const g = parseInt(hex.substring(2, 4), 16);
405
+ const b = parseInt(hex.substring(4, 6), 16);
406
+ return { color: `rgba(${r}, ${g}, ${b}, ${opacity})` };
407
+ }
408
+ return { color: color };
409
+ }
410
+ }
411
+ // Parse gradients
412
+ const gradientMatch = className.match(/^bg-(?:gradient|linear)-to-(t|b|l|r|tr|tl|br|bl)$/);
413
+ if (gradientMatch) {
414
+ const normalizedClass = className.replace('bg-linear-to-', 'bg-gradient-to-');
415
+ return { __gradientDirection: normalizedClass };
416
+ }
417
+ const gradientStopMatch = className.match(/^(from|via|to)-([\w-]+)(?:\/(\d+))?$/);
418
+ if (gradientStopMatch) {
419
+ const [, position, colorName, opacityValue] = gradientStopMatch;
420
+ let color = resolveColor(colorName, tailwindConfig);
421
+ if (!color && loopwindConfig?.colors?.[colorName]) {
422
+ color = loopwindConfig.colors[colorName];
423
+ }
424
+ if (color) {
425
+ let finalColor = color;
426
+ if (opacityValue) {
427
+ const opacity = parseInt(opacityValue) / 100;
428
+ const hex = color.replace('#', '');
429
+ const r = parseInt(hex.substring(0, 2), 16);
430
+ const g = parseInt(hex.substring(2, 4), 16);
431
+ const b = parseInt(hex.substring(4, 6), 16);
432
+ finalColor = `rgba(${r}, ${g}, ${b}, ${opacity})`;
433
+ }
434
+ return { [`__gradient${position.charAt(0).toUpperCase() + position.slice(1)}`]: finalColor };
435
+ }
436
+ }
437
+ return {};
438
+ }
439
+ function parseAnimationClass(className, context, easing) {
440
+ const { frame = 0, totalFrames = 100, durationMs = 3000 } = context;
441
+ const easeFn = easingFunctions[easing] || easingFunctions['ease-out'];
442
+ const currentMs = (frame / totalFrames) * durationMs;
443
+ // Enter animations
444
+ const enterMatch = className.match(/^enter-([\w-]+)(?:\/(\[[\d.]+(?:ms|s)?\]|\d+)\/(\[[\d.]+(?:ms|s)?\]|\d+))?$/);
445
+ if (enterMatch) {
446
+ const [, type, startStr, durationStr] = enterMatch;
447
+ const startMs = startStr ? parseTimeValue(startStr) : 0;
448
+ const animDurationMs = durationStr ? parseTimeValue(durationStr) : durationMs;
449
+ const endMs = startMs + animDurationMs;
450
+ let localProgress = 0;
451
+ if (currentMs <= startMs) {
452
+ localProgress = 0;
453
+ }
454
+ else if (currentMs >= endMs) {
455
+ localProgress = 1;
456
+ }
457
+ else {
458
+ localProgress = (currentMs - startMs) / animDurationMs;
459
+ }
460
+ const easedProgress = easeFn(localProgress);
461
+ return getEnterAnimationStyles(type, easedProgress);
462
+ }
463
+ // Exit animations
464
+ const exitMatch = className.match(/^exit-([\w-]+)(?:\/(\[[\d.]+(?:ms|s)?\]|\d+)\/(\[[\d.]+(?:ms|s)?\]|\d+))?$/);
465
+ if (exitMatch) {
466
+ const [, type, startStr, durationStr] = exitMatch;
467
+ const startMs = startStr ? parseTimeValue(startStr) : 0;
468
+ const animDurationMs = durationStr ? parseTimeValue(durationStr) : durationMs;
469
+ const endMs = startMs + animDurationMs;
470
+ let localProgress = 0;
471
+ if (currentMs <= startMs) {
472
+ localProgress = 0;
473
+ }
474
+ else if (currentMs >= endMs) {
475
+ localProgress = 1;
476
+ }
477
+ else {
478
+ localProgress = (currentMs - startMs) / animDurationMs;
479
+ }
480
+ const easedProgress = easeFn(localProgress);
481
+ return getExitAnimationStyles(type, easedProgress);
482
+ }
483
+ // Loop animations
484
+ const loopMatch = className.match(/^loop-([\w-]+)(?:\/(\[[\d.]+(?:ms|s)?\]|\d+))?$/);
485
+ if (loopMatch) {
486
+ const [, type, loopDurationStr] = loopMatch;
487
+ const loopDurationMs = loopDurationStr ? parseTimeValue(loopDurationStr) : 1000;
488
+ const loopProgress = (currentMs % loopDurationMs) / loopDurationMs;
489
+ return getLoopAnimationStyles(type, loopProgress);
490
+ }
491
+ return null;
492
+ }
493
+ function getEnterAnimationStyles(type, easedProgress) {
494
+ switch (type) {
495
+ case 'fade-in':
496
+ return { opacity: easedProgress };
497
+ case 'fade-in-up':
498
+ return { transform: `translateY(${(1 - easedProgress) * 30}px)`, opacity: easedProgress };
499
+ case 'fade-in-down':
500
+ return { transform: `translateY(${(1 - easedProgress) * -30}px)`, opacity: easedProgress };
501
+ case 'fade-in-left':
502
+ return { transform: `translateX(${(1 - easedProgress) * -30}px)`, opacity: easedProgress };
503
+ case 'fade-in-right':
504
+ return { transform: `translateX(${(1 - easedProgress) * 30}px)`, opacity: easedProgress };
505
+ case 'slide-up':
506
+ return { transform: `translateY(${(1 - easedProgress) * 100}px)`, opacity: easedProgress };
507
+ case 'slide-down':
508
+ return { transform: `translateY(${(1 - easedProgress) * -100}px)`, opacity: easedProgress };
509
+ case 'slide-left':
510
+ return { transform: `translateX(${(1 - easedProgress) * -100}px)`, opacity: easedProgress };
511
+ case 'slide-right':
512
+ return { transform: `translateX(${(1 - easedProgress) * 100}px)`, opacity: easedProgress };
513
+ case 'scale-in':
514
+ return { transform: `scale(${0.5 + easedProgress * 0.5})`, opacity: easedProgress };
515
+ case 'zoom-in':
516
+ return { transform: `scale(${easedProgress})`, opacity: easedProgress };
517
+ case 'bounce-in': {
518
+ const bounce = easedProgress < 0.7
519
+ ? easedProgress / 0.7 * 1.1
520
+ : 1.1 - Math.sin((easedProgress - 0.7) / 0.3 * Math.PI / 2) * 0.1;
521
+ return { transform: `scale(${bounce})`, opacity: Math.min(1, easedProgress * 2) };
522
+ }
523
+ case 'bounce-in-up': {
524
+ const bounceY = easedProgress < 0.7
525
+ ? (1 - easedProgress / 0.7) * 50 - (easedProgress / 0.7) * 8
526
+ : -8 + (easedProgress - 0.7) / 0.3 * 8;
527
+ return { transform: `translateY(${bounceY}px)`, opacity: Math.min(1, easedProgress * 2) };
528
+ }
529
+ default:
530
+ return null;
531
+ }
532
+ }
533
+ function getExitAnimationStyles(type, easedProgress) {
534
+ switch (type) {
535
+ case 'fade-out':
536
+ return { opacity: 1 - easedProgress };
537
+ case 'fade-out-up':
538
+ return { transform: `translateY(${easedProgress * -30}px)`, opacity: 1 - easedProgress };
539
+ case 'fade-out-down':
540
+ return { transform: `translateY(${easedProgress * 30}px)`, opacity: 1 - easedProgress };
541
+ default:
542
+ return null;
543
+ }
544
+ }
545
+ function getLoopAnimationStyles(type, loopProgress) {
546
+ switch (type) {
547
+ case 'fade': {
548
+ const pulseValue = 0.5 + Math.sin(loopProgress * Math.PI * 2) * 0.5;
549
+ return { opacity: pulseValue };
550
+ }
551
+ case 'bounce': {
552
+ const bounceY = Math.abs(Math.sin(loopProgress * Math.PI)) * -20;
553
+ return { transform: `translateY(${bounceY}px)` };
554
+ }
555
+ case 'spin': {
556
+ const spinAngle = loopProgress * 360;
557
+ return { transform: `rotate(${spinAngle}deg)` };
558
+ }
559
+ case 'ping': {
560
+ const pingScale = 1 + loopProgress;
561
+ const pingOpacity = 1 - loopProgress;
562
+ return { transform: `scale(${pingScale})`, opacity: pingOpacity };
563
+ }
564
+ case 'float': {
565
+ const floatY = Math.sin(loopProgress * Math.PI * 2) * 10;
566
+ return { transform: `translateY(${floatY}px)` };
567
+ }
568
+ case 'pulse': {
569
+ const pulseScale = 1 + Math.sin(loopProgress * Math.PI * 2) * 0.05;
570
+ return { transform: `scale(${pulseScale})` };
571
+ }
572
+ default:
573
+ return null;
574
+ }
575
+ }
576
+ export function tw(classes, tailwindConfig = null, loopwindConfig = null, animationContext = {}) {
577
+ const classArray = classes.split(' ').filter(Boolean);
578
+ let styles = {};
579
+ let gradientData = {};
580
+ let transforms = [];
581
+ let animationOpacities = [];
582
+ let animationEasing = 'ease-out';
583
+ for (const className of classArray) {
584
+ // Check for easing modifiers
585
+ if (easingFunctions[className]) {
586
+ animationEasing = className;
587
+ continue;
588
+ }
589
+ // Check for animation classes
590
+ const animationResult = parseAnimationClass(className, animationContext, animationEasing);
591
+ if (animationResult) {
592
+ if (animationResult.opacity !== undefined) {
593
+ animationOpacities.push(animationResult.opacity);
594
+ }
595
+ if (animationResult.transform) {
596
+ transforms.push(animationResult.transform);
597
+ }
598
+ if (animationResult.transformOrigin) {
599
+ styles.transformOrigin = animationResult.transformOrigin;
600
+ }
601
+ continue;
602
+ }
603
+ const parsed = parseClass(className, tailwindConfig, loopwindConfig);
604
+ // Collect gradient markers
605
+ if (parsed.__gradientDirection) {
606
+ gradientData.direction = parsed.__gradientDirection;
607
+ }
608
+ else if (parsed.__gradientFrom) {
609
+ gradientData.from = parsed.__gradientFrom;
610
+ }
611
+ else if (parsed.__gradientVia) {
612
+ gradientData.via = parsed.__gradientVia;
613
+ }
614
+ else if (parsed.__gradientTo) {
615
+ gradientData.to = parsed.__gradientTo;
616
+ }
617
+ else if (parsed.transform) {
618
+ transforms.push(parsed.transform);
619
+ }
620
+ else {
621
+ styles = { ...styles, ...parsed };
622
+ }
623
+ }
624
+ // Convert gradient data to backgroundImage
625
+ if (gradientData.direction && (gradientData.from || gradientData.to)) {
626
+ const directionMap = {
627
+ 'bg-gradient-to-t': 'to top',
628
+ 'bg-gradient-to-b': 'to bottom',
629
+ 'bg-gradient-to-l': 'to left',
630
+ 'bg-gradient-to-r': 'to right',
631
+ 'bg-gradient-to-tr': 'to top right',
632
+ 'bg-gradient-to-tl': 'to top left',
633
+ 'bg-gradient-to-br': 'to bottom right',
634
+ 'bg-gradient-to-bl': 'to bottom left',
635
+ };
636
+ const direction = directionMap[gradientData.direction] || 'to bottom';
637
+ const stops = [];
638
+ if (gradientData.from)
639
+ stops.push(gradientData.from);
640
+ if (gradientData.via)
641
+ stops.push(gradientData.via);
642
+ if (gradientData.to)
643
+ stops.push(gradientData.to);
644
+ styles.backgroundImage = `linear-gradient(${direction}, ${stops.join(', ')})`;
645
+ }
646
+ // Combine transforms
647
+ if (transforms.length > 0) {
648
+ styles.transform = transforms.join(' ');
649
+ }
650
+ // Combine animation opacities
651
+ if (animationOpacities.length > 0) {
652
+ styles.opacity = animationOpacities.reduce((acc, val) => acc * val, 1);
653
+ }
654
+ return styles;
655
+ }
656
+ //# sourceMappingURL=tailwind-browser.js.map