@shalomormsby/ui 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/utils.mjs ADDED
@@ -0,0 +1,805 @@
1
+ "use client";
2
+
3
+ // src/lib/animations.ts
4
+ var durations = {
5
+ instant: 0,
6
+ fast: 0.15,
7
+ normal: 0.3,
8
+ slow: 0.5,
9
+ slower: 0.7
10
+ };
11
+ var easings = {
12
+ // Standard easing - default for most transitions
13
+ standard: [0.4, 0, 0.2, 1],
14
+ // Deceleration - use when objects enter screen
15
+ decelerate: [0, 0, 0.2, 1],
16
+ // Acceleration - use when objects exit screen
17
+ accelerate: [0.4, 0, 1, 1],
18
+ // Sharp - use for very quick transitions
19
+ sharp: [0.4, 0, 0.6, 1],
20
+ // Bounce - playful animation
21
+ bounce: [0.68, -0.55, 0.265, 1.55]
22
+ };
23
+ var transitions = {
24
+ default: {
25
+ duration: durations.normal,
26
+ ease: easings.standard
27
+ },
28
+ fast: {
29
+ duration: durations.fast,
30
+ ease: easings.standard
31
+ },
32
+ slow: {
33
+ duration: durations.slow,
34
+ ease: easings.standard
35
+ },
36
+ bounce: {
37
+ duration: durations.normal,
38
+ ease: easings.bounce
39
+ },
40
+ spring: {
41
+ type: "spring",
42
+ damping: 20,
43
+ stiffness: 300
44
+ },
45
+ springBouncy: {
46
+ type: "spring",
47
+ damping: 10,
48
+ stiffness: 100
49
+ }
50
+ };
51
+ var fadeVariants = {
52
+ hidden: { opacity: 0 },
53
+ visible: { opacity: 1 },
54
+ exit: { opacity: 0 }
55
+ };
56
+ var slideVariants = {
57
+ fromLeft: {
58
+ hidden: { x: -20, opacity: 0 },
59
+ visible: { x: 0, opacity: 1 },
60
+ exit: { x: -20, opacity: 0 }
61
+ },
62
+ fromRight: {
63
+ hidden: { x: 20, opacity: 0 },
64
+ visible: { x: 0, opacity: 1 },
65
+ exit: { x: 20, opacity: 0 }
66
+ },
67
+ fromTop: {
68
+ hidden: { y: -20, opacity: 0 },
69
+ visible: { y: 0, opacity: 1 },
70
+ exit: { y: -20, opacity: 0 }
71
+ },
72
+ fromBottom: {
73
+ hidden: { y: 20, opacity: 0 },
74
+ visible: { y: 0, opacity: 1 },
75
+ exit: { y: 20, opacity: 0 }
76
+ }
77
+ };
78
+ var scaleVariants = {
79
+ default: {
80
+ hidden: { scale: 0.95, opacity: 0 },
81
+ visible: { scale: 1, opacity: 1 },
82
+ exit: { scale: 0.95, opacity: 0 }
83
+ },
84
+ grow: {
85
+ hidden: { scale: 0.8, opacity: 0 },
86
+ visible: { scale: 1, opacity: 1 },
87
+ exit: { scale: 0.8, opacity: 0 }
88
+ },
89
+ pop: {
90
+ hidden: { scale: 0 },
91
+ visible: { scale: 1 },
92
+ exit: { scale: 0 }
93
+ }
94
+ };
95
+ var rotateVariants = {
96
+ default: {
97
+ hidden: { rotate: -10, opacity: 0 },
98
+ visible: { rotate: 0, opacity: 1 },
99
+ exit: { rotate: 10, opacity: 0 }
100
+ },
101
+ flip: {
102
+ hidden: { rotateX: 90, opacity: 0 },
103
+ visible: { rotateX: 0, opacity: 1 },
104
+ exit: { rotateX: -90, opacity: 0 }
105
+ }
106
+ };
107
+ var listVariants = {
108
+ container: {
109
+ hidden: { opacity: 0 },
110
+ visible: {
111
+ opacity: 1,
112
+ transition: {
113
+ staggerChildren: 0.1
114
+ }
115
+ }
116
+ },
117
+ item: {
118
+ hidden: { y: 20, opacity: 0 },
119
+ visible: {
120
+ y: 0,
121
+ opacity: 1
122
+ }
123
+ }
124
+ };
125
+ var modalVariants = {
126
+ overlay: {
127
+ hidden: { opacity: 0 },
128
+ visible: { opacity: 1 },
129
+ exit: { opacity: 0 }
130
+ },
131
+ content: {
132
+ hidden: { scale: 0.95, opacity: 0, y: 20 },
133
+ visible: { scale: 1, opacity: 1, y: 0 },
134
+ exit: { scale: 0.95, opacity: 0, y: 20 }
135
+ }
136
+ };
137
+ var drawerVariants = {
138
+ fromLeft: {
139
+ hidden: { x: "-100%" },
140
+ visible: { x: 0 },
141
+ exit: { x: "-100%" }
142
+ },
143
+ fromRight: {
144
+ hidden: { x: "100%" },
145
+ visible: { x: 0 },
146
+ exit: { x: "100%" }
147
+ },
148
+ fromTop: {
149
+ hidden: { y: "-100%" },
150
+ visible: { y: 0 },
151
+ exit: { y: "-100%" }
152
+ },
153
+ fromBottom: {
154
+ hidden: { y: "100%" },
155
+ visible: { y: 0 },
156
+ exit: { y: "100%" }
157
+ }
158
+ };
159
+ var collapseVariants = {
160
+ collapsed: {
161
+ height: 0,
162
+ opacity: 0,
163
+ transition: { duration: durations.fast }
164
+ },
165
+ expanded: {
166
+ height: "auto",
167
+ opacity: 1,
168
+ transition: { duration: durations.normal }
169
+ }
170
+ };
171
+ var presets = {
172
+ /**
173
+ * Fade in/out animation
174
+ */
175
+ fade: {
176
+ initial: "hidden",
177
+ animate: "visible",
178
+ exit: "exit",
179
+ variants: fadeVariants,
180
+ transition: transitions.default
181
+ },
182
+ /**
183
+ * Slide from bottom animation
184
+ */
185
+ slideUp: {
186
+ initial: "hidden",
187
+ animate: "visible",
188
+ exit: "exit",
189
+ variants: slideVariants.fromBottom,
190
+ transition: transitions.default
191
+ },
192
+ /**
193
+ * Scale animation
194
+ */
195
+ scale: {
196
+ initial: "hidden",
197
+ animate: "visible",
198
+ exit: "exit",
199
+ variants: scaleVariants.default,
200
+ transition: transitions.default
201
+ },
202
+ /**
203
+ * Modal animation (overlay + content)
204
+ */
205
+ modal: {
206
+ overlay: {
207
+ initial: "hidden",
208
+ animate: "visible",
209
+ exit: "exit",
210
+ variants: modalVariants.overlay,
211
+ transition: transitions.fast
212
+ },
213
+ content: {
214
+ initial: "hidden",
215
+ animate: "visible",
216
+ exit: "exit",
217
+ variants: modalVariants.content,
218
+ transition: transitions.default
219
+ }
220
+ },
221
+ /**
222
+ * List stagger animation
223
+ */
224
+ list: {
225
+ container: {
226
+ initial: "hidden",
227
+ animate: "visible",
228
+ variants: listVariants.container
229
+ },
230
+ item: {
231
+ variants: listVariants.item
232
+ }
233
+ }
234
+ };
235
+ function createAnimation(variants, transition = transitions.default) {
236
+ return {
237
+ initial: "hidden",
238
+ animate: "visible",
239
+ exit: "exit",
240
+ variants,
241
+ transition
242
+ };
243
+ }
244
+ function scaleDuration(duration, scale) {
245
+ return duration * (scale / 10);
246
+ }
247
+
248
+ // src/lib/breadcrumbs.ts
249
+ function generateBreadcrumbs(hash, routeConfig, baseUrl = "#") {
250
+ const cleanHash = hash.replace(/^#/, "").trim();
251
+ if (!cleanHash) {
252
+ return [{ label: "Home", href: baseUrl }];
253
+ }
254
+ const segments = cleanHash.split("/").filter(Boolean);
255
+ const breadcrumbs = [{ label: "Home", href: baseUrl }];
256
+ let currentPath = "";
257
+ let currentConfig = routeConfig;
258
+ for (let i = 0; i < segments.length; i++) {
259
+ const segment = segments[i];
260
+ const isLast = i === segments.length - 1;
261
+ currentPath += (currentPath ? "/" : "") + segment;
262
+ const config = currentConfig[segment];
263
+ if (!config) {
264
+ const label = segment.split("-").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
265
+ breadcrumbs.push({
266
+ label,
267
+ // No href for the last item (current page)
268
+ href: isLast ? void 0 : `${baseUrl}${currentPath}`
269
+ });
270
+ } else {
271
+ breadcrumbs.push({
272
+ label: config.label,
273
+ // No href for the last item (current page)
274
+ href: isLast ? void 0 : `${baseUrl}${currentPath}`
275
+ });
276
+ if (config.children) {
277
+ currentConfig = config.children;
278
+ }
279
+ }
280
+ }
281
+ return breadcrumbs;
282
+ }
283
+
284
+ // src/lib/colors.ts
285
+ var colorTokens = {
286
+ // Background colors
287
+ background: "var(--color-background)",
288
+ backgroundSecondary: "var(--color-background-secondary)",
289
+ backgroundTertiary: "var(--color-background-tertiary)",
290
+ surface: "var(--color-surface)",
291
+ // Foreground/Text colors
292
+ foreground: "var(--color-foreground)",
293
+ foregroundSecondary: "var(--color-foreground-secondary)",
294
+ foregroundTertiary: "var(--color-foreground-tertiary)",
295
+ textPrimary: "var(--color-text-primary)",
296
+ textSecondary: "var(--color-text-secondary)",
297
+ textMuted: "var(--color-text-muted)",
298
+ // Brand colors
299
+ primary: "var(--color-primary)",
300
+ primaryForeground: "var(--color-primary-foreground)",
301
+ secondary: "var(--color-secondary)",
302
+ secondaryForeground: "var(--color-secondary-foreground)",
303
+ accent: "var(--color-accent)",
304
+ accentForeground: "var(--color-accent-foreground)",
305
+ // Semantic colors
306
+ success: "var(--color-success)",
307
+ successForeground: "var(--color-success-foreground)",
308
+ warning: "var(--color-warning)",
309
+ warningForeground: "var(--color-warning-foreground)",
310
+ error: "var(--color-error)",
311
+ errorForeground: "var(--color-error-foreground)",
312
+ info: "var(--color-info)",
313
+ infoForeground: "var(--color-info-foreground)",
314
+ // Borders
315
+ border: "var(--color-border)",
316
+ borderSubtle: "var(--color-border-subtle)",
317
+ // Interactive states
318
+ hover: "var(--color-hover)",
319
+ active: "var(--color-active)",
320
+ focus: "var(--color-focus)",
321
+ // Links
322
+ link: "var(--color-link)",
323
+ linkHover: "var(--color-link-hover)",
324
+ linkHoverForeground: "var(--color-link-hover-foreground)"
325
+ };
326
+ function getCSSVariable(variableName, element = document.documentElement) {
327
+ const name = variableName.startsWith("--") ? variableName : `--${variableName}`;
328
+ return getComputedStyle(element).getPropertyValue(name).trim();
329
+ }
330
+ function setCSSVariable(variableName, value, element = document.documentElement) {
331
+ const name = variableName.startsWith("--") ? variableName : `--${variableName}`;
332
+ element.style.setProperty(name, value);
333
+ }
334
+ function getForegroundColor(backgroundToken) {
335
+ const token = backgroundToken.replace(/var\(|\)/g, "");
336
+ const foregroundMap = {
337
+ "--color-primary": "var(--color-primary-foreground)",
338
+ "--color-secondary": "var(--color-secondary-foreground)",
339
+ "--color-accent": "var(--color-accent-foreground)",
340
+ "--color-success": "var(--color-success-foreground)",
341
+ "--color-warning": "var(--color-warning-foreground)",
342
+ "--color-error": "var(--color-error-foreground)",
343
+ "--color-info": "var(--color-info-foreground)",
344
+ "--color-background": "var(--color-foreground)",
345
+ "--color-surface": "var(--color-text-primary)"
346
+ };
347
+ return foregroundMap[token] || "var(--color-text-primary)";
348
+ }
349
+ var semanticColors = {
350
+ /**
351
+ * Status colors for indicating states
352
+ */
353
+ status: {
354
+ success: {
355
+ bg: colorTokens.success,
356
+ fg: colorTokens.successForeground
357
+ },
358
+ warning: {
359
+ bg: colorTokens.warning,
360
+ fg: colorTokens.warningForeground
361
+ },
362
+ error: {
363
+ bg: colorTokens.error,
364
+ fg: colorTokens.errorForeground
365
+ },
366
+ info: {
367
+ bg: colorTokens.info,
368
+ fg: colorTokens.infoForeground
369
+ }
370
+ },
371
+ /**
372
+ * Brand colors for primary UI elements
373
+ */
374
+ brand: {
375
+ primary: {
376
+ bg: colorTokens.primary,
377
+ fg: colorTokens.primaryForeground
378
+ },
379
+ secondary: {
380
+ bg: colorTokens.secondary,
381
+ fg: colorTokens.secondaryForeground
382
+ },
383
+ accent: {
384
+ bg: colorTokens.accent,
385
+ fg: colorTokens.accentForeground
386
+ }
387
+ },
388
+ /**
389
+ * Interactive state colors
390
+ */
391
+ interactive: {
392
+ default: {
393
+ bg: colorTokens.background,
394
+ fg: colorTokens.foreground
395
+ },
396
+ hover: {
397
+ bg: colorTokens.hover,
398
+ fg: colorTokens.foreground
399
+ },
400
+ active: {
401
+ bg: colorTokens.active,
402
+ fg: colorTokens.foreground
403
+ },
404
+ focus: {
405
+ border: colorTokens.focus
406
+ }
407
+ }
408
+ };
409
+ function getSemanticColorPair(type) {
410
+ if (type === "primary" || type === "secondary" || type === "accent") {
411
+ return semanticColors.brand[type];
412
+ }
413
+ return semanticColors.status[type];
414
+ }
415
+ function hexToRgb(hex) {
416
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
417
+ return result ? {
418
+ r: parseInt(result[1], 16),
419
+ g: parseInt(result[2], 16),
420
+ b: parseInt(result[3], 16)
421
+ } : null;
422
+ }
423
+ function getLuminance(r, g, b) {
424
+ const [rs, gs, bs] = [r, g, b].map((c) => {
425
+ const srgb = c / 255;
426
+ return srgb <= 0.03928 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
427
+ });
428
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
429
+ }
430
+ function getContrastRatio(hex1, hex2) {
431
+ const rgb1 = hexToRgb(hex1);
432
+ const rgb2 = hexToRgb(hex2);
433
+ if (!rgb1 || !rgb2) return 0;
434
+ const lum1 = getLuminance(rgb1.r, rgb1.g, rgb1.b);
435
+ const lum2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);
436
+ const lighter = Math.max(lum1, lum2);
437
+ const darker = Math.min(lum1, lum2);
438
+ return (lighter + 0.05) / (darker + 0.05);
439
+ }
440
+ function meetsContrastRequirements(foreground, background, level = "AA", size = "normal") {
441
+ const ratio = getContrastRatio(foreground, background);
442
+ const requirements = {
443
+ AA: { normal: 4.5, large: 3 },
444
+ AAA: { normal: 7, large: 4.5 }
445
+ };
446
+ return ratio >= requirements[level][size];
447
+ }
448
+ function hexToHSL(hex) {
449
+ const rgb = hexToRgb(hex);
450
+ if (!rgb) return { h: 0, s: 0, l: 0 };
451
+ const r = rgb.r / 255;
452
+ const g = rgb.g / 255;
453
+ const b = rgb.b / 255;
454
+ const max = Math.max(r, g, b);
455
+ const min = Math.min(r, g, b);
456
+ let h = 0, s = 0, l = (max + min) / 2;
457
+ if (max !== min) {
458
+ const d = max - min;
459
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
460
+ switch (max) {
461
+ case r:
462
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
463
+ break;
464
+ case g:
465
+ h = ((b - r) / d + 2) / 6;
466
+ break;
467
+ case b:
468
+ h = ((r - g) / d + 4) / 6;
469
+ break;
470
+ }
471
+ }
472
+ return {
473
+ h: Math.round(h * 360),
474
+ s: Math.round(s * 100),
475
+ l: Math.round(l * 100)
476
+ };
477
+ }
478
+ function hslToHex(h, s, l) {
479
+ h = h / 360;
480
+ s = s / 100;
481
+ l = l / 100;
482
+ let r, g, b;
483
+ if (s === 0) {
484
+ r = g = b = l;
485
+ } else {
486
+ const hue2rgb = (p2, q2, t) => {
487
+ if (t < 0) t += 1;
488
+ if (t > 1) t -= 1;
489
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
490
+ if (t < 1 / 2) return q2;
491
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
492
+ return p2;
493
+ };
494
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
495
+ const p = 2 * l - q;
496
+ r = hue2rgb(p, q, h + 1 / 3);
497
+ g = hue2rgb(p, q, h);
498
+ b = hue2rgb(p, q, h - 1 / 3);
499
+ }
500
+ const toHex = (x) => {
501
+ const hex = Math.round(x * 255).toString(16);
502
+ return hex.length === 1 ? "0" + hex : hex;
503
+ };
504
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
505
+ }
506
+ function adjustLightness(hex, percent) {
507
+ const hsl = hexToHSL(hex);
508
+ const newL = Math.max(0, Math.min(100, hsl.l + percent));
509
+ return hslToHex(hsl.h, hsl.s, newL);
510
+ }
511
+ function adjustSaturation(hex, percent) {
512
+ const hsl = hexToHSL(hex);
513
+ const newS = Math.max(0, Math.min(100, hsl.s + percent));
514
+ return hslToHex(hsl.h, newS, hsl.l);
515
+ }
516
+ function rotateHue(hex, degrees) {
517
+ const hsl = hexToHSL(hex);
518
+ const newH = (hsl.h + degrees) % 360;
519
+ return hslToHex(newH, hsl.s, hsl.l);
520
+ }
521
+ function adjustOpacity(hex, opacity) {
522
+ const rgb = hexToRgb(hex);
523
+ if (!rgb) return hex;
524
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${opacity})`;
525
+ }
526
+ function getOptimalForeground(bgHex, whiteHex = "#ffffff", blackHex = "#000000") {
527
+ const whiteRatio = getContrastRatio(bgHex, whiteHex);
528
+ const blackRatio = getContrastRatio(bgHex, blackHex);
529
+ return whiteRatio > blackRatio ? whiteHex : blackHex;
530
+ }
531
+ function generateColorScale(baseHex) {
532
+ const hsl = hexToHSL(baseHex);
533
+ return {
534
+ 50: hslToHex(hsl.h, Math.max(hsl.s - 10, 20), 95),
535
+ 100: hslToHex(hsl.h, Math.max(hsl.s - 5, 30), 90),
536
+ 200: hslToHex(hsl.h, hsl.s, 80),
537
+ 300: hslToHex(hsl.h, hsl.s, 70),
538
+ 400: hslToHex(hsl.h, hsl.s, 60),
539
+ 500: baseHex,
540
+ // Base color
541
+ 600: hslToHex(hsl.h, Math.min(hsl.s + 5, 100), 45),
542
+ 700: hslToHex(hsl.h, Math.min(hsl.s + 10, 100), 35),
543
+ 800: hslToHex(hsl.h, Math.min(hsl.s + 15, 100), 25),
544
+ 900: hslToHex(hsl.h, Math.min(hsl.s + 20, 100), 15)
545
+ };
546
+ }
547
+ var colorUtils = {
548
+ getCSSVariable,
549
+ setCSSVariable,
550
+ getForegroundColor,
551
+ getSemanticColorPair,
552
+ hexToRgb,
553
+ hexToHSL,
554
+ hslToHex,
555
+ adjustLightness,
556
+ adjustSaturation,
557
+ rotateHue,
558
+ adjustOpacity,
559
+ getOptimalForeground,
560
+ generateColorScale,
561
+ getContrastRatio,
562
+ meetsContrastRequirements
563
+ };
564
+
565
+ // src/lib/utils.ts
566
+ import { clsx } from "clsx";
567
+ import { twMerge } from "tailwind-merge";
568
+ function cn(...inputs) {
569
+ return twMerge(clsx(inputs));
570
+ }
571
+
572
+ // src/lib/validation.ts
573
+ var patterns = {
574
+ email: {
575
+ value: /^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i,
576
+ message: "Invalid email address"
577
+ },
578
+ url: {
579
+ value: /^https?:\/\/.+\..+/,
580
+ message: "Invalid URL"
581
+ },
582
+ phone: {
583
+ value: /^[\d\s\-\+\(\)]+$/,
584
+ message: "Invalid phone number"
585
+ },
586
+ alphanumeric: {
587
+ value: /^[a-zA-Z0-9]+$/,
588
+ message: "Only letters and numbers allowed"
589
+ },
590
+ noSpaces: {
591
+ value: /^\S+$/,
592
+ message: "Spaces are not allowed"
593
+ }
594
+ };
595
+ function validateField(value, rules2) {
596
+ if (rules2.required) {
597
+ const isEmpty = value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
598
+ if (isEmpty) {
599
+ return typeof rules2.required === "string" ? rules2.required : "This field is required";
600
+ }
601
+ }
602
+ if (!value && !rules2.required) {
603
+ return void 0;
604
+ }
605
+ if (rules2.minLength && value.length < rules2.minLength.value) {
606
+ return rules2.minLength.message;
607
+ }
608
+ if (rules2.maxLength && value.length > rules2.maxLength.value) {
609
+ return rules2.maxLength.message;
610
+ }
611
+ if (rules2.pattern && !rules2.pattern.value.test(value)) {
612
+ return rules2.pattern.message;
613
+ }
614
+ if (rules2.custom) {
615
+ for (const rule of rules2.custom) {
616
+ if (!rule.validate(value)) {
617
+ return rule.message;
618
+ }
619
+ }
620
+ }
621
+ return void 0;
622
+ }
623
+ function validateForm(values, validations) {
624
+ const errors = {};
625
+ for (const [field, rules2] of Object.entries(validations)) {
626
+ const error = validateField(values[field], rules2);
627
+ if (error) {
628
+ errors[field] = error;
629
+ }
630
+ }
631
+ return errors;
632
+ }
633
+ function hasErrors(errors) {
634
+ return Object.values(errors).some((error) => error !== void 0);
635
+ }
636
+ var rules = {
637
+ required: (message = "This field is required") => ({
638
+ required: message
639
+ }),
640
+ email: (message = "Invalid email address") => ({
641
+ pattern: { value: patterns.email.value, message }
642
+ }),
643
+ minLength: (length, message) => ({
644
+ minLength: {
645
+ value: length,
646
+ message: message || `Minimum ${length} characters required`
647
+ }
648
+ }),
649
+ maxLength: (length, message) => ({
650
+ maxLength: {
651
+ value: length,
652
+ message: message || `Maximum ${length} characters allowed`
653
+ }
654
+ }),
655
+ match: (otherValue, message = "Values do not match") => ({
656
+ custom: [
657
+ {
658
+ validate: (value) => value === otherValue,
659
+ message
660
+ }
661
+ ]
662
+ })
663
+ };
664
+
665
+ // src/lib/syntax-parser/patterns.ts
666
+ var TOKEN_PATTERNS = [
667
+ // Single-line comments
668
+ { type: "comment", pattern: /\/\/.*$/gm },
669
+ // Multi-line comments
670
+ { type: "comment", pattern: /\/\*[\s\S]*?\*\//g },
671
+ // Template literals and strings
672
+ { type: "string", pattern: /`(?:\\.|[^`\\])*`/g },
673
+ { type: "string", pattern: /"(?:\\.|[^"\\])*"/g },
674
+ { type: "string", pattern: /'(?:\\.|[^'\\])*'/g },
675
+ // JSX/TSX tags
676
+ { type: "tag", pattern: /<\/?[A-Z][a-zA-Z0-9]*(?=[\s>])/g },
677
+ { type: "tag", pattern: /<\/?[a-z][a-zA-Z0-9-]*(?=[\s>])/g },
678
+ // Keywords
679
+ {
680
+ type: "keyword",
681
+ pattern: /\b(const|let|var|function|return|if|else|for|while|do|switch|case|break|continue|throw|try|catch|finally|new|typeof|instanceof|void|delete|async|await|yield|export|import|from|default|class|extends|implements|interface|type|enum|namespace|declare|public|private|protected|static|readonly|abstract|as|is|in|of|null|undefined)\b/g
682
+ },
683
+ // Booleans
684
+ { type: "boolean", pattern: /\b(true|false)\b/g },
685
+ // Numbers
686
+ { type: "number", pattern: /\b\d+\.?\d*(?:e[+-]?\d+)?(?:n)?\b/gi },
687
+ { type: "number", pattern: /\b0x[0-9a-f]+\b/gi },
688
+ // Function calls
689
+ { type: "function", pattern: /\b[a-zA-Z_$][a-zA-Z0-9_$]*(?=\s*\()/g },
690
+ // Class names (PascalCase identifiers)
691
+ { type: "className", pattern: /\b[A-Z][a-zA-Z0-9]*\b/g },
692
+ // JSX attributes
693
+ { type: "attribute", pattern: /\b[a-z][a-zA-Z0-9]*(?=\s*=)/g },
694
+ // Object properties (after dot)
695
+ { type: "property", pattern: /(?<=\.)[a-zA-Z_$][a-zA-Z0-9_$]*/g },
696
+ // Operators
697
+ {
698
+ type: "operator",
699
+ pattern: /[+\-*/%=!<>&|^~?:]+|&&|\|\||\.\.\.|\?\?|===|!==|==|!=|<=|>=|<<|>>|>>>/g
700
+ },
701
+ // Punctuation
702
+ { type: "punctuation", pattern: /[{}[\](),.;]/g }
703
+ ];
704
+
705
+ // src/lib/syntax-parser/tokenizer.ts
706
+ function tokenize(code, language = "typescript") {
707
+ if (!code || code.trim() === "") {
708
+ return [{ text: code, type: "plain" }];
709
+ }
710
+ const matches = [];
711
+ for (const { type, pattern } of TOKEN_PATTERNS) {
712
+ pattern.lastIndex = 0;
713
+ let match;
714
+ while ((match = pattern.exec(code)) !== null) {
715
+ matches.push({
716
+ text: match[0],
717
+ type,
718
+ index: match.index
719
+ });
720
+ }
721
+ }
722
+ matches.sort((a, b) => a.index - b.index);
723
+ const nonOverlapping = [];
724
+ let lastEnd = 0;
725
+ for (const match of matches) {
726
+ if (match.index >= lastEnd) {
727
+ nonOverlapping.push(match);
728
+ lastEnd = match.index + match.text.length;
729
+ }
730
+ }
731
+ const tokens = [];
732
+ let position = 0;
733
+ for (const match of nonOverlapping) {
734
+ if (match.index > position) {
735
+ const plainText = code.slice(position, match.index);
736
+ tokens.push({ text: plainText, type: "plain" });
737
+ }
738
+ tokens.push({ text: match.text, type: match.type });
739
+ position = match.index + match.text.length;
740
+ }
741
+ if (position < code.length) {
742
+ tokens.push({ text: code.slice(position), type: "plain" });
743
+ }
744
+ return tokens;
745
+ }
746
+ function detectLanguage(code, filename) {
747
+ if (filename) {
748
+ if (filename.endsWith(".tsx")) return "tsx";
749
+ if (filename.endsWith(".jsx")) return "jsx";
750
+ if (filename.endsWith(".js")) return "javascript";
751
+ }
752
+ return "typescript";
753
+ }
754
+
755
+ // src/lib/syntax-parser/index.ts
756
+ function parseCode(code, language) {
757
+ const lang = language || detectLanguage(code);
758
+ return tokenize(code, lang);
759
+ }
760
+ export {
761
+ adjustLightness,
762
+ adjustOpacity,
763
+ adjustSaturation,
764
+ cn,
765
+ collapseVariants,
766
+ colorTokens,
767
+ colorUtils,
768
+ createAnimation,
769
+ detectLanguage,
770
+ drawerVariants,
771
+ durations,
772
+ easings,
773
+ fadeVariants,
774
+ generateBreadcrumbs,
775
+ generateColorScale,
776
+ getCSSVariable,
777
+ getContrastRatio,
778
+ getForegroundColor,
779
+ getLuminance,
780
+ getOptimalForeground,
781
+ getSemanticColorPair,
782
+ hasErrors,
783
+ hexToHSL,
784
+ hexToRgb,
785
+ hslToHex,
786
+ listVariants,
787
+ meetsContrastRequirements,
788
+ modalVariants,
789
+ parseCode,
790
+ patterns,
791
+ presets,
792
+ rotateHue,
793
+ rotateVariants,
794
+ rules,
795
+ scaleDuration,
796
+ scaleVariants,
797
+ semanticColors,
798
+ setCSSVariable,
799
+ slideVariants,
800
+ tokenize,
801
+ transitions,
802
+ validateField,
803
+ validateForm
804
+ };
805
+ //# sourceMappingURL=utils.mjs.map