@thesage/ui 0.0.9

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 (43) hide show
  1. package/dist/fontThemes-Bwf7_lFg.d.mts +842 -0
  2. package/dist/fontThemes-Bwf7_lFg.d.ts +842 -0
  3. package/dist/hooks-C8PrmIXy.d.mts +225 -0
  4. package/dist/hooks-Ct9RBhg-.d.ts +225 -0
  5. package/dist/hooks.d.mts +3 -0
  6. package/dist/hooks.d.ts +3 -0
  7. package/dist/hooks.js +1342 -0
  8. package/dist/hooks.js.map +1 -0
  9. package/dist/hooks.mjs +1314 -0
  10. package/dist/hooks.mjs.map +1 -0
  11. package/dist/index-CsnncHSm.d.mts +23 -0
  12. package/dist/index-CsnncHSm.d.ts +23 -0
  13. package/dist/index.d.mts +2830 -0
  14. package/dist/index.d.ts +2830 -0
  15. package/dist/index.js +12637 -0
  16. package/dist/index.js.map +1 -0
  17. package/dist/index.mjs +12319 -0
  18. package/dist/index.mjs.map +1 -0
  19. package/dist/providers-Dv3LFGtJ.d.mts +17 -0
  20. package/dist/providers-Dv3LFGtJ.d.ts +17 -0
  21. package/dist/providers.d.mts +2 -0
  22. package/dist/providers.d.ts +2 -0
  23. package/dist/providers.js +1944 -0
  24. package/dist/providers.js.map +1 -0
  25. package/dist/providers.mjs +1918 -0
  26. package/dist/providers.mjs.map +1 -0
  27. package/dist/tokens.d.mts +831 -0
  28. package/dist/tokens.d.ts +831 -0
  29. package/dist/tokens.js +2399 -0
  30. package/dist/tokens.js.map +1 -0
  31. package/dist/tokens.mjs +2319 -0
  32. package/dist/tokens.mjs.map +1 -0
  33. package/dist/utils-DlJKRVzQ.d.mts +986 -0
  34. package/dist/utils-xrpHqxXR.d.ts +986 -0
  35. package/dist/utils.d.mts +4 -0
  36. package/dist/utils.d.ts +4 -0
  37. package/dist/utils.js +873 -0
  38. package/dist/utils.js.map +1 -0
  39. package/dist/utils.mjs +805 -0
  40. package/dist/utils.mjs.map +1 -0
  41. package/dist/validation-Bj1ye-v_.d.mts +114 -0
  42. package/dist/validation-Bj1ye-v_.d.ts +114 -0
  43. package/package.json +117 -0
package/dist/hooks.mjs ADDED
@@ -0,0 +1,1314 @@
1
+ "use client";
2
+
3
+ // src/lib/store/theme.ts
4
+ import { create } from "zustand";
5
+ import { persist } from "zustand/middleware";
6
+ var useThemeStore = create()(
7
+ persist(
8
+ (set, get) => ({
9
+ // Defaults
10
+ theme: "volt",
11
+ mode: "dark",
12
+ // Actions
13
+ setTheme: (theme) => set({ theme }),
14
+ setMode: (mode) => set({ mode }),
15
+ toggleMode: () => set((state) => ({ mode: state.mode === "light" ? "dark" : "light" })),
16
+ // Computed
17
+ get themeConfig() {
18
+ const state = get();
19
+ return { name: state.theme, mode: state.mode };
20
+ }
21
+ }),
22
+ {
23
+ name: "ecosystem-theme",
24
+ // Only persist theme and mode
25
+ partialize: (state) => ({
26
+ theme: state.theme,
27
+ mode: state.mode
28
+ })
29
+ }
30
+ )
31
+ );
32
+
33
+ // src/hooks/useTheme.ts
34
+ function useTheme() {
35
+ return useThemeStore();
36
+ }
37
+
38
+ // src/hooks/useMotionPreference.ts
39
+ import { useEffect } from "react";
40
+
41
+ // src/lib/store/customizer.ts
42
+ import { create as create2 } from "zustand";
43
+ import { persist as persist2 } from "zustand/middleware";
44
+
45
+ // ../tokens/src/base.ts
46
+ var baseTokens = {
47
+ /**
48
+ * Spacing scale (based on 4px grid)
49
+ */
50
+ spacing: {
51
+ "0": "0",
52
+ "0.5": "0.125rem",
53
+ // 2px
54
+ "1": "0.25rem",
55
+ // 4px
56
+ "2": "0.5rem",
57
+ // 8px
58
+ "3": "0.75rem",
59
+ // 12px
60
+ "4": "1rem",
61
+ // 16px
62
+ "5": "1.25rem",
63
+ // 20px
64
+ "6": "1.5rem",
65
+ // 24px
66
+ "8": "2rem",
67
+ // 32px
68
+ "10": "2.5rem",
69
+ // 40px
70
+ "12": "3rem",
71
+ // 48px
72
+ "16": "4rem",
73
+ // 64px
74
+ "20": "5rem",
75
+ // 80px
76
+ "24": "6rem",
77
+ // 96px
78
+ "32": "8rem"
79
+ // 128px
80
+ },
81
+ /**
82
+ * Typography scales
83
+ */
84
+ fontSize: {
85
+ "xs": "0.75rem",
86
+ // 12px
87
+ "sm": "0.875rem",
88
+ // 14px
89
+ "base": "1rem",
90
+ // 16px
91
+ "lg": "1.125rem",
92
+ // 18px
93
+ "xl": "1.25rem",
94
+ // 20px
95
+ "2xl": "1.5rem",
96
+ // 24px
97
+ "3xl": "1.875rem",
98
+ // 30px
99
+ "4xl": "2.25rem",
100
+ // 36px
101
+ "5xl": "3rem",
102
+ // 48px
103
+ "6xl": "3.75rem",
104
+ // 60px
105
+ "7xl": "4.5rem",
106
+ // 72px
107
+ "8xl": "6rem"
108
+ // 96px
109
+ },
110
+ fontWeight: {
111
+ light: "300",
112
+ normal: "400",
113
+ medium: "500",
114
+ semibold: "600",
115
+ bold: "700",
116
+ extrabold: "800",
117
+ black: "900"
118
+ },
119
+ lineHeight: {
120
+ none: "1",
121
+ tight: "1.25",
122
+ snug: "1.375",
123
+ normal: "1.5",
124
+ relaxed: "1.625",
125
+ loose: "2"
126
+ },
127
+ /**
128
+ * Border radius
129
+ */
130
+ borderRadius: {
131
+ none: "0",
132
+ sm: "0.125rem",
133
+ // 2px
134
+ DEFAULT: "0.25rem",
135
+ // 4px
136
+ md: "0.375rem",
137
+ // 6px
138
+ lg: "0.5rem",
139
+ // 8px
140
+ xl: "0.75rem",
141
+ // 12px
142
+ "2xl": "1rem",
143
+ // 16px
144
+ "3xl": "1.5rem",
145
+ // 24px
146
+ full: "9999px"
147
+ },
148
+ /**
149
+ * Motion durations (base values - themes can override)
150
+ */
151
+ duration: {
152
+ instant: "0ms",
153
+ fast: "150ms",
154
+ normal: "300ms",
155
+ slow: "500ms",
156
+ slower: "800ms"
157
+ },
158
+ /**
159
+ * Easing curves (base values - themes can override)
160
+ */
161
+ ease: {
162
+ linear: "linear",
163
+ in: "cubic-bezier(0.4, 0, 1, 1)",
164
+ out: "cubic-bezier(0, 0, 0.2, 1)",
165
+ inOut: "cubic-bezier(0.4, 0, 0.2, 1)"
166
+ },
167
+ /**
168
+ * Z-index scale
169
+ */
170
+ zIndex: {
171
+ "auto": "auto",
172
+ "0": "0",
173
+ "10": "10",
174
+ "20": "20",
175
+ "30": "30",
176
+ "40": "40",
177
+ "50": "50",
178
+ dropdown: "1000",
179
+ sticky: "1020",
180
+ fixed: "1030",
181
+ modalBackdrop: "1040",
182
+ modal: "1050",
183
+ popover: "1060",
184
+ tooltip: "1070"
185
+ },
186
+ /**
187
+ * Focus ring configuration
188
+ */
189
+ focus: {
190
+ width: "2px",
191
+ offset: "2px",
192
+ style: "solid"
193
+ }
194
+ };
195
+ var spacing = {
196
+ xs: baseTokens.spacing["1"],
197
+ // 4px — Tight internal padding
198
+ sm: baseTokens.spacing["2"],
199
+ // 8px — Default gap
200
+ md: baseTokens.spacing["4"],
201
+ // 16px — Section padding
202
+ lg: baseTokens.spacing["6"],
203
+ // 24px — Card padding
204
+ xl: baseTokens.spacing["8"],
205
+ // 32px — Section margins
206
+ "2xl": baseTokens.spacing["12"],
207
+ // 48px — Page sections
208
+ "3xl": baseTokens.spacing["16"]
209
+ // 64px — Major divisions
210
+ };
211
+ var typography = {
212
+ fonts: {
213
+ sans: "var(--font-body)",
214
+ serif: "var(--font-heading)",
215
+ mono: "var(--font-mono)"
216
+ },
217
+ sizes: {
218
+ xs: baseTokens.fontSize.xs,
219
+ // 12px — Fine print
220
+ sm: baseTokens.fontSize.sm,
221
+ // 14px — Secondary text
222
+ base: baseTokens.fontSize.base,
223
+ // 16px — Body text
224
+ lg: baseTokens.fontSize.lg,
225
+ // 18px — Lead paragraphs
226
+ xl: baseTokens.fontSize.xl,
227
+ // 20px — Section headers
228
+ "2xl": baseTokens.fontSize["2xl"],
229
+ // 24px — Page headers
230
+ "3xl": baseTokens.fontSize["3xl"]
231
+ // 30px — Hero text
232
+ },
233
+ weights: {
234
+ normal: baseTokens.fontWeight.normal,
235
+ // 400
236
+ medium: baseTokens.fontWeight.medium,
237
+ // 500
238
+ semibold: baseTokens.fontWeight.semibold,
239
+ // 600
240
+ bold: baseTokens.fontWeight.bold
241
+ // 700
242
+ },
243
+ leading: {
244
+ tight: baseTokens.lineHeight.tight,
245
+ // 1.25 — Headings
246
+ normal: baseTokens.lineHeight.normal,
247
+ // 1.5 — Body
248
+ relaxed: baseTokens.lineHeight.relaxed
249
+ // 1.625 — Spacious reading
250
+ }
251
+ };
252
+ var motion = {
253
+ duration: baseTokens.duration,
254
+ easing: {
255
+ default: baseTokens.ease.out,
256
+ // Most transitions
257
+ spring: "cubic-bezier(0.16, 1, 0.3, 1)",
258
+ // Playful interactions
259
+ linear: baseTokens.ease.linear
260
+ // Progress indicators
261
+ }
262
+ };
263
+
264
+ // ../tokens/src/typography.ts
265
+ var fontSizes = {
266
+ // Body text scale
267
+ xs: { base: "0.75rem", mobile: "0.75rem" },
268
+ // 12px
269
+ sm: { base: "0.875rem", mobile: "0.875rem" },
270
+ // 14px
271
+ base: { base: "1rem", mobile: "1rem" },
272
+ // 16px
273
+ lg: { base: "1.125rem", mobile: "1rem" },
274
+ // 18px / 16px mobile
275
+ xl: { base: "1.25rem", mobile: "1.125rem" },
276
+ // 20px / 18px mobile
277
+ "2xl": { base: "1.5rem", mobile: "1.25rem" },
278
+ // 24px / 20px mobile
279
+ "3xl": { base: "1.875rem", mobile: "1.5rem" },
280
+ // 30px / 24px mobile
281
+ // Heading scale (h6 → h1)
282
+ "4xl": { base: "2.25rem", mobile: "1.875rem" },
283
+ // 36px / 30px - h3
284
+ "5xl": { base: "3rem", mobile: "2.25rem" },
285
+ // 48px / 36px - h2
286
+ "6xl": { base: "3.75rem", mobile: "2.5rem" },
287
+ // 60px / 40px - h1
288
+ "7xl": { base: "4.5rem", mobile: "3rem" },
289
+ // 72px / 48px - Display
290
+ "8xl": { base: "6rem", mobile: "3.75rem" },
291
+ // 96px / 60px - Hero
292
+ "9xl": { base: "8rem", mobile: "4.5rem" }
293
+ // 128px / 72px - Ultra
294
+ };
295
+ var fontWeights = {
296
+ thin: "100",
297
+ extralight: "200",
298
+ light: "300",
299
+ normal: "400",
300
+ medium: "500",
301
+ semibold: "600",
302
+ bold: "700",
303
+ extrabold: "800",
304
+ black: "900"
305
+ };
306
+ var lineHeights = {
307
+ none: "1",
308
+ tight: "1.25",
309
+ snug: "1.375",
310
+ normal: "1.5",
311
+ relaxed: "1.625",
312
+ loose: "1.75",
313
+ extraloose: "2"
314
+ };
315
+ var letterSpacing = {
316
+ tighter: "-0.05em",
317
+ tight: "-0.025em",
318
+ normal: "0",
319
+ wide: "0.025em",
320
+ wider: "0.05em",
321
+ widest: "0.1em"
322
+ };
323
+ var typePresets = {
324
+ "display-large": {
325
+ size: fontSizes["8xl"],
326
+ weight: fontWeights.bold,
327
+ lineHeight: lineHeights.none,
328
+ letterSpacing: letterSpacing.tighter,
329
+ description: "Large hero text, landing pages"
330
+ },
331
+ "display": {
332
+ size: fontSizes["7xl"],
333
+ weight: fontWeights.bold,
334
+ lineHeight: lineHeights.tight,
335
+ letterSpacing: letterSpacing.tight,
336
+ description: "Hero sections, major headings"
337
+ },
338
+ "heading-1": {
339
+ size: fontSizes["6xl"],
340
+ weight: fontWeights.bold,
341
+ lineHeight: lineHeights.tight,
342
+ letterSpacing: letterSpacing.tight,
343
+ description: "Page titles, h1"
344
+ },
345
+ "heading-2": {
346
+ size: fontSizes["5xl"],
347
+ weight: fontWeights.bold,
348
+ lineHeight: lineHeights.tight,
349
+ letterSpacing: letterSpacing.normal,
350
+ description: "Section titles, h2"
351
+ },
352
+ "heading-3": {
353
+ size: fontSizes["4xl"],
354
+ weight: fontWeights.semibold,
355
+ lineHeight: lineHeights.snug,
356
+ letterSpacing: letterSpacing.normal,
357
+ description: "Subsection titles, h3"
358
+ },
359
+ "heading-4": {
360
+ size: fontSizes["2xl"],
361
+ weight: fontWeights.semibold,
362
+ lineHeight: lineHeights.snug,
363
+ letterSpacing: letterSpacing.normal,
364
+ description: "Component titles, h4"
365
+ },
366
+ "heading-5": {
367
+ size: fontSizes.xl,
368
+ weight: fontWeights.medium,
369
+ lineHeight: lineHeights.normal,
370
+ letterSpacing: letterSpacing.normal,
371
+ description: "Small headings, h5"
372
+ },
373
+ "heading-6": {
374
+ size: fontSizes.lg,
375
+ weight: fontWeights.medium,
376
+ lineHeight: lineHeights.normal,
377
+ letterSpacing: letterSpacing.normal,
378
+ description: "Tiny headings, h6"
379
+ },
380
+ "body-large": {
381
+ size: fontSizes.lg,
382
+ weight: fontWeights.normal,
383
+ lineHeight: lineHeights.relaxed,
384
+ letterSpacing: letterSpacing.normal,
385
+ description: "Lead paragraphs, intro text"
386
+ },
387
+ "body": {
388
+ size: fontSizes.base,
389
+ weight: fontWeights.normal,
390
+ lineHeight: lineHeights.normal,
391
+ letterSpacing: letterSpacing.normal,
392
+ description: "Default body text"
393
+ },
394
+ "body-small": {
395
+ size: fontSizes.sm,
396
+ weight: fontWeights.normal,
397
+ lineHeight: lineHeights.normal,
398
+ letterSpacing: letterSpacing.normal,
399
+ description: "Small body text, fine print"
400
+ },
401
+ "caption": {
402
+ size: fontSizes.xs,
403
+ weight: fontWeights.normal,
404
+ lineHeight: lineHeights.snug,
405
+ letterSpacing: letterSpacing.wide,
406
+ description: "Captions, labels, metadata"
407
+ },
408
+ "overline": {
409
+ size: fontSizes.xs,
410
+ weight: fontWeights.semibold,
411
+ lineHeight: lineHeights.normal,
412
+ letterSpacing: letterSpacing.widest,
413
+ description: "Eyebrows, categories, all-caps labels"
414
+ }
415
+ };
416
+
417
+ // ../tokens/src/color-utils.ts
418
+ function hexToRgb(hex) {
419
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
420
+ return result ? {
421
+ r: parseInt(result[1], 16),
422
+ g: parseInt(result[2], 16),
423
+ b: parseInt(result[3], 16)
424
+ } : null;
425
+ }
426
+ function hexToHSL(hex) {
427
+ const rgb = hexToRgb(hex);
428
+ if (!rgb) return { h: 0, s: 0, l: 0 };
429
+ const r = rgb.r / 255;
430
+ const g = rgb.g / 255;
431
+ const b = rgb.b / 255;
432
+ const max = Math.max(r, g, b);
433
+ const min = Math.min(r, g, b);
434
+ let h = 0, s = 0, l = (max + min) / 2;
435
+ if (max !== min) {
436
+ const d = max - min;
437
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
438
+ switch (max) {
439
+ case r:
440
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
441
+ break;
442
+ case g:
443
+ h = ((b - r) / d + 2) / 6;
444
+ break;
445
+ case b:
446
+ h = ((r - g) / d + 4) / 6;
447
+ break;
448
+ }
449
+ }
450
+ return {
451
+ h: Math.round(h * 360),
452
+ s: Math.round(s * 100),
453
+ l: Math.round(l * 100)
454
+ };
455
+ }
456
+ function hslToHex(h, s, l) {
457
+ h = h / 360;
458
+ s = s / 100;
459
+ l = l / 100;
460
+ let r, g, b;
461
+ if (s === 0) {
462
+ r = g = b = l;
463
+ } else {
464
+ const hue2rgb = (p2, q2, t) => {
465
+ if (t < 0) t += 1;
466
+ if (t > 1) t -= 1;
467
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
468
+ if (t < 1 / 2) return q2;
469
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
470
+ return p2;
471
+ };
472
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
473
+ const p = 2 * l - q;
474
+ r = hue2rgb(p, q, h + 1 / 3);
475
+ g = hue2rgb(p, q, h);
476
+ b = hue2rgb(p, q, h - 1 / 3);
477
+ }
478
+ const toHex = (x) => {
479
+ const hex = Math.round(x * 255).toString(16);
480
+ return hex.length === 1 ? "0" + hex : hex;
481
+ };
482
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
483
+ }
484
+ function adjustLightness(hex, percent) {
485
+ const hsl = hexToHSL(hex);
486
+ const newL = Math.max(0, Math.min(100, hsl.l + percent));
487
+ return hslToHex(hsl.h, hsl.s, newL);
488
+ }
489
+ function adjustSaturation(hex, percent) {
490
+ const hsl = hexToHSL(hex);
491
+ const newS = Math.max(0, Math.min(100, hsl.s + percent));
492
+ return hslToHex(hsl.h, newS, hsl.l);
493
+ }
494
+ function rotateHue(hex, degrees) {
495
+ const hsl = hexToHSL(hex);
496
+ const newH = (hsl.h + degrees) % 360;
497
+ return hslToHex(newH, hsl.s, hsl.l);
498
+ }
499
+ function adjustOpacity(hex, opacity) {
500
+ const rgb = hexToRgb(hex);
501
+ if (!rgb) return hex;
502
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${opacity})`;
503
+ }
504
+ function getLuminance(r, g, b) {
505
+ const [rs, gs, bs] = [r, g, b].map((c) => {
506
+ const srgb = c / 255;
507
+ return srgb <= 0.03928 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
508
+ });
509
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
510
+ }
511
+ function getContrastRatio(hex1, hex2) {
512
+ const rgb1 = hexToRgb(hex1);
513
+ const rgb2 = hexToRgb(hex2);
514
+ if (!rgb1 || !rgb2) return 0;
515
+ const lum1 = getLuminance(rgb1.r, rgb1.g, rgb1.b);
516
+ const lum2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);
517
+ const lighter = Math.max(lum1, lum2);
518
+ const darker = Math.min(lum1, lum2);
519
+ return (lighter + 0.05) / (darker + 0.05);
520
+ }
521
+ function getOptimalForeground(bgHex, whiteHex = "#ffffff", blackHex = "#000000") {
522
+ const whiteRatio = getContrastRatio(bgHex, whiteHex);
523
+ const blackRatio = getContrastRatio(bgHex, blackHex);
524
+ return whiteRatio > blackRatio ? whiteHex : blackHex;
525
+ }
526
+
527
+ // ../tokens/src/token-graph.ts
528
+ var primaryColorDerivations = {
529
+ // Links use primary color
530
+ "--color-link": {
531
+ source: "--color-primary",
532
+ transform: (primary) => primary,
533
+ description: "Links inherit primary brand color"
534
+ },
535
+ // Focus ring uses primary color
536
+ "--color-ring": {
537
+ source: "--color-primary",
538
+ transform: (primary) => primary,
539
+ description: "Focus rings use primary for brand consistency"
540
+ },
541
+ // Link hover is slightly darker primary
542
+ "--color-link-hover": {
543
+ source: "--color-primary",
544
+ transform: (primary) => adjustLightness(primary, -10),
545
+ description: "Link hover is 10% darker for visual feedback"
546
+ },
547
+ // Chart primary series
548
+ "--chart-1": {
549
+ source: "--color-primary",
550
+ transform: (primary) => primary,
551
+ description: "First chart series uses primary"
552
+ },
553
+ // Chart secondary series (lighter tint)
554
+ "--chart-2": {
555
+ source: "--color-primary",
556
+ transform: (primary) => adjustLightness(primary, 20),
557
+ description: "Second chart series is lighter tint of primary"
558
+ },
559
+ // Chart tertiary series (darker shade)
560
+ "--chart-3": {
561
+ source: "--color-primary",
562
+ transform: (primary) => adjustLightness(primary, -15),
563
+ description: "Third chart series is darker shade of primary"
564
+ },
565
+ // Chart quaternary (desaturated primary)
566
+ "--chart-4": {
567
+ source: "--color-primary",
568
+ transform: (primary) => adjustSaturation(primary, -30),
569
+ description: "Fourth chart series is muted primary"
570
+ },
571
+ // Chart quinary (complementary color)
572
+ "--chart-5": {
573
+ source: "--color-primary",
574
+ transform: (primary) => rotateHue(primary, 180),
575
+ description: "Fifth chart series is complementary to primary"
576
+ }
577
+ };
578
+ var secondaryColorDerivations = {
579
+ // Hover states
580
+ "--color-hover": {
581
+ source: "--color-secondary",
582
+ transform: (secondary) => secondary,
583
+ description: "Hover backgrounds use secondary"
584
+ },
585
+ // Active states
586
+ "--color-active": {
587
+ source: "--color-secondary",
588
+ transform: (secondary) => adjustLightness(secondary, -5),
589
+ description: "Active state is slightly darker secondary"
590
+ },
591
+ // Muted backgrounds
592
+ "--color-muted": {
593
+ source: "--color-secondary",
594
+ transform: (secondary) => secondary,
595
+ description: "Muted sections use secondary color"
596
+ }
597
+ };
598
+ var accentColorDerivations = {
599
+ // Info semantic color uses accent
600
+ "--color-info": {
601
+ source: "--color-accent",
602
+ transform: (accent) => accent,
603
+ description: "Info semantic color uses accent"
604
+ },
605
+ // Info foreground calculated for contrast
606
+ "--color-info-foreground": {
607
+ source: "--color-accent",
608
+ transform: (accent) => getOptimalForeground(accent),
609
+ description: "Info foreground calculated for contrast"
610
+ }
611
+ };
612
+ var modeSpecificDerivations = {
613
+ "--color-primary-muted": {
614
+ light: {
615
+ source: "--color-primary",
616
+ transform: (primary) => adjustLightness(primary, 40),
617
+ description: "Muted primary for light backgrounds"
618
+ },
619
+ dark: {
620
+ source: "--color-primary",
621
+ transform: (primary) => adjustLightness(primary, -20),
622
+ description: "Muted primary for dark backgrounds"
623
+ }
624
+ },
625
+ "--color-primary-subtle": {
626
+ light: {
627
+ source: "--color-primary",
628
+ transform: (primary) => adjustOpacity(primary, 0.1),
629
+ description: "Subtle primary background for light mode"
630
+ },
631
+ dark: {
632
+ source: "--color-primary",
633
+ transform: (primary) => adjustOpacity(primary, 0.2),
634
+ description: "Subtle primary background for dark mode"
635
+ }
636
+ }
637
+ };
638
+ function computeDerivedTokens(sourceToken, sourceValue, mode) {
639
+ const derived = {};
640
+ Object.entries(primaryColorDerivations).forEach(([token, config]) => {
641
+ if (config.source === sourceToken) {
642
+ derived[token] = config.transform(sourceValue);
643
+ }
644
+ });
645
+ Object.entries(secondaryColorDerivations).forEach(([token, config]) => {
646
+ if (config.source === sourceToken) {
647
+ derived[token] = config.transform(sourceValue);
648
+ }
649
+ });
650
+ Object.entries(accentColorDerivations).forEach(([token, config]) => {
651
+ if (config.source === sourceToken) {
652
+ derived[token] = config.transform(sourceValue);
653
+ }
654
+ });
655
+ Object.entries(modeSpecificDerivations).forEach(([token, configs]) => {
656
+ const config = configs[mode];
657
+ if (config.source === sourceToken) {
658
+ derived[token] = config.transform(sourceValue);
659
+ }
660
+ });
661
+ return derived;
662
+ }
663
+
664
+ // src/lib/colors.ts
665
+ var colorTokens = {
666
+ // Background colors
667
+ background: "var(--color-background)",
668
+ backgroundSecondary: "var(--color-background-secondary)",
669
+ backgroundTertiary: "var(--color-background-tertiary)",
670
+ surface: "var(--color-surface)",
671
+ // Foreground/Text colors
672
+ foreground: "var(--color-foreground)",
673
+ foregroundSecondary: "var(--color-foreground-secondary)",
674
+ foregroundTertiary: "var(--color-foreground-tertiary)",
675
+ textPrimary: "var(--color-text-primary)",
676
+ textSecondary: "var(--color-text-secondary)",
677
+ textMuted: "var(--color-text-muted)",
678
+ // Brand colors
679
+ primary: "var(--color-primary)",
680
+ primaryForeground: "var(--color-primary-foreground)",
681
+ secondary: "var(--color-secondary)",
682
+ secondaryForeground: "var(--color-secondary-foreground)",
683
+ accent: "var(--color-accent)",
684
+ accentForeground: "var(--color-accent-foreground)",
685
+ // Semantic colors
686
+ success: "var(--color-success)",
687
+ successForeground: "var(--color-success-foreground)",
688
+ warning: "var(--color-warning)",
689
+ warningForeground: "var(--color-warning-foreground)",
690
+ error: "var(--color-error)",
691
+ errorForeground: "var(--color-error-foreground)",
692
+ info: "var(--color-info)",
693
+ infoForeground: "var(--color-info-foreground)",
694
+ // Borders
695
+ border: "var(--color-border)",
696
+ borderSubtle: "var(--color-border-subtle)",
697
+ // Interactive states
698
+ hover: "var(--color-hover)",
699
+ active: "var(--color-active)",
700
+ focus: "var(--color-focus)",
701
+ // Links
702
+ link: "var(--color-link)",
703
+ linkHover: "var(--color-link-hover)",
704
+ linkHoverForeground: "var(--color-link-hover-foreground)"
705
+ };
706
+ var semanticColors = {
707
+ /**
708
+ * Status colors for indicating states
709
+ */
710
+ status: {
711
+ success: {
712
+ bg: colorTokens.success,
713
+ fg: colorTokens.successForeground
714
+ },
715
+ warning: {
716
+ bg: colorTokens.warning,
717
+ fg: colorTokens.warningForeground
718
+ },
719
+ error: {
720
+ bg: colorTokens.error,
721
+ fg: colorTokens.errorForeground
722
+ },
723
+ info: {
724
+ bg: colorTokens.info,
725
+ fg: colorTokens.infoForeground
726
+ }
727
+ },
728
+ /**
729
+ * Brand colors for primary UI elements
730
+ */
731
+ brand: {
732
+ primary: {
733
+ bg: colorTokens.primary,
734
+ fg: colorTokens.primaryForeground
735
+ },
736
+ secondary: {
737
+ bg: colorTokens.secondary,
738
+ fg: colorTokens.secondaryForeground
739
+ },
740
+ accent: {
741
+ bg: colorTokens.accent,
742
+ fg: colorTokens.accentForeground
743
+ }
744
+ },
745
+ /**
746
+ * Interactive state colors
747
+ */
748
+ interactive: {
749
+ default: {
750
+ bg: colorTokens.background,
751
+ fg: colorTokens.foreground
752
+ },
753
+ hover: {
754
+ bg: colorTokens.hover,
755
+ fg: colorTokens.foreground
756
+ },
757
+ active: {
758
+ bg: colorTokens.active,
759
+ fg: colorTokens.foreground
760
+ },
761
+ focus: {
762
+ border: colorTokens.focus
763
+ }
764
+ }
765
+ };
766
+ function hexToRgb2(hex) {
767
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
768
+ return result ? {
769
+ r: parseInt(result[1], 16),
770
+ g: parseInt(result[2], 16),
771
+ b: parseInt(result[3], 16)
772
+ } : null;
773
+ }
774
+ function getLuminance2(r, g, b) {
775
+ const [rs, gs, bs] = [r, g, b].map((c) => {
776
+ const srgb = c / 255;
777
+ return srgb <= 0.03928 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
778
+ });
779
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
780
+ }
781
+ function getContrastRatio2(hex1, hex2) {
782
+ const rgb1 = hexToRgb2(hex1);
783
+ const rgb2 = hexToRgb2(hex2);
784
+ if (!rgb1 || !rgb2) return 0;
785
+ const lum1 = getLuminance2(rgb1.r, rgb1.g, rgb1.b);
786
+ const lum2 = getLuminance2(rgb2.r, rgb2.g, rgb2.b);
787
+ const lighter = Math.max(lum1, lum2);
788
+ const darker = Math.min(lum1, lum2);
789
+ return (lighter + 0.05) / (darker + 0.05);
790
+ }
791
+ function hexToHSL2(hex) {
792
+ const rgb = hexToRgb2(hex);
793
+ if (!rgb) return { h: 0, s: 0, l: 0 };
794
+ const r = rgb.r / 255;
795
+ const g = rgb.g / 255;
796
+ const b = rgb.b / 255;
797
+ const max = Math.max(r, g, b);
798
+ const min = Math.min(r, g, b);
799
+ let h = 0, s = 0, l = (max + min) / 2;
800
+ if (max !== min) {
801
+ const d = max - min;
802
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
803
+ switch (max) {
804
+ case r:
805
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
806
+ break;
807
+ case g:
808
+ h = ((b - r) / d + 2) / 6;
809
+ break;
810
+ case b:
811
+ h = ((r - g) / d + 4) / 6;
812
+ break;
813
+ }
814
+ }
815
+ return {
816
+ h: Math.round(h * 360),
817
+ s: Math.round(s * 100),
818
+ l: Math.round(l * 100)
819
+ };
820
+ }
821
+ function hslToHex2(h, s, l) {
822
+ h = h / 360;
823
+ s = s / 100;
824
+ l = l / 100;
825
+ let r, g, b;
826
+ if (s === 0) {
827
+ r = g = b = l;
828
+ } else {
829
+ const hue2rgb = (p2, q2, t) => {
830
+ if (t < 0) t += 1;
831
+ if (t > 1) t -= 1;
832
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
833
+ if (t < 1 / 2) return q2;
834
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
835
+ return p2;
836
+ };
837
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
838
+ const p = 2 * l - q;
839
+ r = hue2rgb(p, q, h + 1 / 3);
840
+ g = hue2rgb(p, q, h);
841
+ b = hue2rgb(p, q, h - 1 / 3);
842
+ }
843
+ const toHex = (x) => {
844
+ const hex = Math.round(x * 255).toString(16);
845
+ return hex.length === 1 ? "0" + hex : hex;
846
+ };
847
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
848
+ }
849
+ function getOptimalForeground2(bgHex, whiteHex = "#ffffff", blackHex = "#000000") {
850
+ const whiteRatio = getContrastRatio2(bgHex, whiteHex);
851
+ const blackRatio = getContrastRatio2(bgHex, blackHex);
852
+ return whiteRatio > blackRatio ? whiteHex : blackHex;
853
+ }
854
+ function generateColorScale(baseHex) {
855
+ const hsl = hexToHSL2(baseHex);
856
+ return {
857
+ 50: hslToHex2(hsl.h, Math.max(hsl.s - 10, 20), 95),
858
+ 100: hslToHex2(hsl.h, Math.max(hsl.s - 5, 30), 90),
859
+ 200: hslToHex2(hsl.h, hsl.s, 80),
860
+ 300: hslToHex2(hsl.h, hsl.s, 70),
861
+ 400: hslToHex2(hsl.h, hsl.s, 60),
862
+ 500: baseHex,
863
+ // Base color
864
+ 600: hslToHex2(hsl.h, Math.min(hsl.s + 5, 100), 45),
865
+ 700: hslToHex2(hsl.h, Math.min(hsl.s + 10, 100), 35),
866
+ 800: hslToHex2(hsl.h, Math.min(hsl.s + 15, 100), 25),
867
+ 900: hslToHex2(hsl.h, Math.min(hsl.s + 20, 100), 15)
868
+ };
869
+ }
870
+
871
+ // src/lib/store/customizer.ts
872
+ var useCustomizer = create2()(
873
+ persist2(
874
+ (set, get) => ({
875
+ motion: 5,
876
+ prefersReducedMotion: false,
877
+ customizationMode: "simple",
878
+ customColors: {},
879
+ savedPalettes: [],
880
+ customFontThemes: {},
881
+ savedFontThemes: [],
882
+ setMotion: (level) => set({ motion: level }),
883
+ setPrefersReducedMotion: (value) => set({ prefersReducedMotion: value }),
884
+ setCustomizationMode: (mode) => set({ customizationMode: mode }),
885
+ setCustomPrimaryColor: (theme, mode, hexColor) => {
886
+ const state = get();
887
+ const currentPalette = state.customColors[theme]?.[mode];
888
+ const scale = generateColorScale(hexColor);
889
+ const primaryForeground = getOptimalForeground2(hexColor);
890
+ const derivedTokens = computeDerivedTokens("--color-primary", hexColor, mode);
891
+ const isSimple = state.customizationMode === "simple";
892
+ const palette = {
893
+ primary: hexColor,
894
+ primaryForeground,
895
+ secondary: isSimple ? void 0 : currentPalette?.secondary,
896
+ secondaryForeground: isSimple ? void 0 : currentPalette?.secondaryForeground,
897
+ accent: isSimple ? void 0 : currentPalette?.accent,
898
+ accentForeground: isSimple ? void 0 : currentPalette?.accentForeground,
899
+ scale,
900
+ derivedTokens
901
+ };
902
+ set((state2) => ({
903
+ customColors: {
904
+ ...state2.customColors,
905
+ [theme]: {
906
+ ...state2.customColors[theme],
907
+ [mode]: palette
908
+ }
909
+ }
910
+ }));
911
+ },
912
+ setCustomSecondaryColor: (theme, mode, hexColor) => {
913
+ const state = get();
914
+ const currentPalette = state.customColors[theme]?.[mode];
915
+ if (!currentPalette) return;
916
+ const secondaryForeground = getOptimalForeground2(hexColor);
917
+ const derivedTokens = computeDerivedTokens("--color-secondary", hexColor, mode);
918
+ set((state2) => ({
919
+ customColors: {
920
+ ...state2.customColors,
921
+ [theme]: {
922
+ ...state2.customColors[theme],
923
+ [mode]: {
924
+ ...currentPalette,
925
+ secondary: hexColor,
926
+ secondaryForeground,
927
+ derivedTokens: {
928
+ ...currentPalette.derivedTokens,
929
+ ...derivedTokens
930
+ }
931
+ }
932
+ }
933
+ }
934
+ }));
935
+ },
936
+ setCustomAccentColor: (theme, mode, hexColor) => {
937
+ const state = get();
938
+ const currentPalette = state.customColors[theme]?.[mode];
939
+ if (!currentPalette) return;
940
+ const accentForeground = getOptimalForeground2(hexColor);
941
+ const derivedTokens = computeDerivedTokens("--color-accent", hexColor, mode);
942
+ set((state2) => ({
943
+ customColors: {
944
+ ...state2.customColors,
945
+ [theme]: {
946
+ ...state2.customColors[theme],
947
+ [mode]: {
948
+ ...currentPalette,
949
+ accent: hexColor,
950
+ accentForeground,
951
+ derivedTokens: {
952
+ ...currentPalette.derivedTokens,
953
+ ...derivedTokens
954
+ }
955
+ }
956
+ }
957
+ }
958
+ }));
959
+ },
960
+ applyColorPalette: (theme, mode, colors) => {
961
+ const scale = generateColorScale(colors.primary);
962
+ const primaryForeground = getOptimalForeground2(colors.primary);
963
+ let derivedTokens = computeDerivedTokens("--color-primary", colors.primary, mode);
964
+ let secondary = colors.secondary;
965
+ let secondaryForeground = secondary ? getOptimalForeground2(secondary) : void 0;
966
+ if (secondary) {
967
+ const secondaryDerived = computeDerivedTokens("--color-secondary", secondary, mode);
968
+ derivedTokens = { ...derivedTokens, ...secondaryDerived };
969
+ }
970
+ let accent = colors.accent;
971
+ let accentForeground = accent ? getOptimalForeground2(accent) : void 0;
972
+ if (accent) {
973
+ const accentDerived = computeDerivedTokens("--color-accent", accent, mode);
974
+ derivedTokens = { ...derivedTokens, ...accentDerived };
975
+ }
976
+ const palette = {
977
+ name: colors.name,
978
+ description: colors.description,
979
+ primary: colors.primary,
980
+ primaryForeground,
981
+ secondary,
982
+ secondaryForeground,
983
+ accent,
984
+ accentForeground,
985
+ scale,
986
+ derivedTokens
987
+ };
988
+ set((state) => ({
989
+ customColors: {
990
+ ...state.customColors,
991
+ [theme]: {
992
+ ...state.customColors[theme],
993
+ [mode]: palette
994
+ }
995
+ }
996
+ }));
997
+ },
998
+ resetCustomColors: (theme, mode) => {
999
+ if (mode) {
1000
+ set((state) => ({
1001
+ customColors: {
1002
+ ...state.customColors,
1003
+ [theme]: {
1004
+ ...state.customColors[theme],
1005
+ [mode]: void 0
1006
+ }
1007
+ }
1008
+ }));
1009
+ } else {
1010
+ set((state) => {
1011
+ const { [theme]: _, ...rest } = state.customColors;
1012
+ return { customColors: rest };
1013
+ });
1014
+ }
1015
+ },
1016
+ getActiveColorPalette: (theme, mode) => {
1017
+ return get().customColors[theme]?.[mode] || null;
1018
+ },
1019
+ // Saved palette management
1020
+ savePalette: (paletteData) => {
1021
+ const id = `custom-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1022
+ const newPalette = {
1023
+ ...paletteData,
1024
+ id,
1025
+ category: "custom",
1026
+ createdAt: Date.now()
1027
+ };
1028
+ set((state) => ({
1029
+ savedPalettes: [...state.savedPalettes, newPalette]
1030
+ }));
1031
+ },
1032
+ updatePalette: (id, updates) => {
1033
+ set((state) => ({
1034
+ savedPalettes: state.savedPalettes.map(
1035
+ (p) => p.id === id ? { ...p, ...updates } : p
1036
+ )
1037
+ }));
1038
+ },
1039
+ renamePalette: (id, newName) => {
1040
+ set((state) => ({
1041
+ savedPalettes: state.savedPalettes.map(
1042
+ (p) => p.id === id ? { ...p, name: newName } : p
1043
+ )
1044
+ }));
1045
+ },
1046
+ deletePalette: (id) => {
1047
+ set((state) => ({
1048
+ savedPalettes: state.savedPalettes.filter((p) => p.id !== id)
1049
+ }));
1050
+ },
1051
+ reorderPalettes: (palettes) => {
1052
+ set({ savedPalettes: palettes });
1053
+ },
1054
+ getSavedPalettes: () => {
1055
+ return get().savedPalettes;
1056
+ },
1057
+ // Font theme management
1058
+ applyFontTheme: (theme, mode, fontTheme) => {
1059
+ set((state) => ({
1060
+ customFontThemes: {
1061
+ ...state.customFontThemes,
1062
+ [theme]: {
1063
+ ...state.customFontThemes[theme],
1064
+ [mode]: fontTheme
1065
+ }
1066
+ }
1067
+ }));
1068
+ },
1069
+ resetCustomFonts: (theme, mode) => {
1070
+ if (mode) {
1071
+ set((state) => ({
1072
+ customFontThemes: {
1073
+ ...state.customFontThemes,
1074
+ [theme]: {
1075
+ ...state.customFontThemes[theme],
1076
+ [mode]: void 0
1077
+ }
1078
+ }
1079
+ }));
1080
+ } else {
1081
+ set((state) => {
1082
+ const { [theme]: _, ...rest } = state.customFontThemes;
1083
+ return { customFontThemes: rest };
1084
+ });
1085
+ }
1086
+ },
1087
+ getActiveFontTheme: (theme, mode) => {
1088
+ return get().customFontThemes[theme]?.[mode] || null;
1089
+ },
1090
+ // Saved font theme management
1091
+ saveFontTheme: (fontThemeData) => {
1092
+ const id = `font-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
1093
+ const newFontTheme = {
1094
+ ...fontThemeData,
1095
+ id,
1096
+ category: "custom",
1097
+ createdAt: Date.now(),
1098
+ isCustom: true
1099
+ };
1100
+ set((state) => ({
1101
+ savedFontThemes: [...state.savedFontThemes, newFontTheme]
1102
+ }));
1103
+ },
1104
+ updateFontTheme: (id, updates) => {
1105
+ set((state) => ({
1106
+ savedFontThemes: state.savedFontThemes.map(
1107
+ (ft) => ft.id === id ? { ...ft, ...updates } : ft
1108
+ )
1109
+ }));
1110
+ },
1111
+ renameFontTheme: (id, newName) => {
1112
+ set((state) => ({
1113
+ savedFontThemes: state.savedFontThemes.map(
1114
+ (ft) => ft.id === id ? { ...ft, name: newName } : ft
1115
+ )
1116
+ }));
1117
+ },
1118
+ deleteFontTheme: (id) => {
1119
+ set((state) => ({
1120
+ savedFontThemes: state.savedFontThemes.filter((ft) => ft.id !== id)
1121
+ }));
1122
+ },
1123
+ reorderFontThemes: (fontThemes) => {
1124
+ set({ savedFontThemes: fontThemes });
1125
+ },
1126
+ getSavedFontThemes: () => {
1127
+ return get().savedFontThemes;
1128
+ }
1129
+ }),
1130
+ {
1131
+ name: "ecosystem-customizer",
1132
+ version: 4,
1133
+ partialize: (state) => ({
1134
+ motion: state.motion,
1135
+ prefersReducedMotion: state.prefersReducedMotion,
1136
+ customizationMode: state.customizationMode,
1137
+ customColors: state.customColors,
1138
+ savedPalettes: state.savedPalettes,
1139
+ customFontThemes: state.customFontThemes,
1140
+ savedFontThemes: state.savedFontThemes
1141
+ })
1142
+ }
1143
+ )
1144
+ );
1145
+
1146
+ // src/hooks/useMotionPreference.ts
1147
+ function useMotionPreference() {
1148
+ const { motion: motion2, prefersReducedMotion, setPrefersReducedMotion } = useCustomizer();
1149
+ useEffect(() => {
1150
+ if (typeof window === "undefined") return;
1151
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
1152
+ setPrefersReducedMotion(mediaQuery.matches);
1153
+ const handleChange = (e) => {
1154
+ setPrefersReducedMotion(e.matches);
1155
+ };
1156
+ mediaQuery.addEventListener("change", handleChange);
1157
+ return () => mediaQuery.removeEventListener("change", handleChange);
1158
+ }, [setPrefersReducedMotion]);
1159
+ return {
1160
+ scale: motion2,
1161
+ shouldAnimate: motion2 > 0 && !prefersReducedMotion,
1162
+ prefersReducedMotion
1163
+ };
1164
+ }
1165
+
1166
+ // src/hooks/useForm.ts
1167
+ import { useState, useCallback } from "react";
1168
+
1169
+ // src/lib/validation.ts
1170
+ function validateField(value, rules) {
1171
+ if (rules.required) {
1172
+ const isEmpty = value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
1173
+ if (isEmpty) {
1174
+ return typeof rules.required === "string" ? rules.required : "This field is required";
1175
+ }
1176
+ }
1177
+ if (!value && !rules.required) {
1178
+ return void 0;
1179
+ }
1180
+ if (rules.minLength && value.length < rules.minLength.value) {
1181
+ return rules.minLength.message;
1182
+ }
1183
+ if (rules.maxLength && value.length > rules.maxLength.value) {
1184
+ return rules.maxLength.message;
1185
+ }
1186
+ if (rules.pattern && !rules.pattern.value.test(value)) {
1187
+ return rules.pattern.message;
1188
+ }
1189
+ if (rules.custom) {
1190
+ for (const rule of rules.custom) {
1191
+ if (!rule.validate(value)) {
1192
+ return rule.message;
1193
+ }
1194
+ }
1195
+ }
1196
+ return void 0;
1197
+ }
1198
+ function validateForm(values, validations) {
1199
+ const errors = {};
1200
+ for (const [field, rules] of Object.entries(validations)) {
1201
+ const error = validateField(values[field], rules);
1202
+ if (error) {
1203
+ errors[field] = error;
1204
+ }
1205
+ }
1206
+ return errors;
1207
+ }
1208
+
1209
+ // src/hooks/useForm.ts
1210
+ function useForm({
1211
+ initialValues,
1212
+ validations = {},
1213
+ onSubmit,
1214
+ validateOn = "onBlur"
1215
+ }) {
1216
+ const [values, setValues] = useState(initialValues);
1217
+ const [errors, setErrors] = useState({});
1218
+ const [isSubmitting, setIsSubmitting] = useState(false);
1219
+ const [isDirty, setIsDirty] = useState(false);
1220
+ const setValue = useCallback((name, value) => {
1221
+ setValues((prev) => ({ ...prev, [name]: value }));
1222
+ setIsDirty(true);
1223
+ }, []);
1224
+ const setError = useCallback((name, error) => {
1225
+ setErrors((prev) => ({ ...prev, [name]: error }));
1226
+ }, []);
1227
+ const validateFieldByName = useCallback(
1228
+ (name) => {
1229
+ const fieldRules = validations[name];
1230
+ if (!fieldRules) return;
1231
+ const error = validateField(values[name], fieldRules);
1232
+ setError(name, error);
1233
+ return !error;
1234
+ },
1235
+ [values, validations, setError]
1236
+ );
1237
+ const handleChange = useCallback(
1238
+ (e) => {
1239
+ const { name, value, type } = e.target;
1240
+ const fieldValue = type === "checkbox" ? e.target.checked : value;
1241
+ setValue(name, fieldValue);
1242
+ if (validateOn === "onChange") {
1243
+ validateFieldByName(name);
1244
+ }
1245
+ },
1246
+ [setValue, validateOn, validateFieldByName]
1247
+ );
1248
+ const handleBlur = useCallback(
1249
+ (e) => {
1250
+ const { name } = e.target;
1251
+ if (validateOn === "onBlur") {
1252
+ validateFieldByName(name);
1253
+ }
1254
+ },
1255
+ [validateOn, validateFieldByName]
1256
+ );
1257
+ const validate = useCallback(() => {
1258
+ const formErrors = validateForm(values, validations);
1259
+ setErrors(formErrors);
1260
+ return Object.keys(formErrors).length === 0;
1261
+ }, [values, validations]);
1262
+ const handleSubmit = useCallback(
1263
+ async (e) => {
1264
+ e?.preventDefault();
1265
+ const isValid = validate();
1266
+ if (!isValid) return;
1267
+ if (onSubmit) {
1268
+ setIsSubmitting(true);
1269
+ try {
1270
+ await onSubmit(values);
1271
+ } finally {
1272
+ setIsSubmitting(false);
1273
+ }
1274
+ }
1275
+ },
1276
+ [validate, onSubmit, values]
1277
+ );
1278
+ const reset = useCallback(() => {
1279
+ setValues(initialValues);
1280
+ setErrors({});
1281
+ setIsDirty(false);
1282
+ setIsSubmitting(false);
1283
+ }, [initialValues]);
1284
+ const getFieldProps = useCallback(
1285
+ (name) => ({
1286
+ name,
1287
+ value: values[name] ?? "",
1288
+ onChange: handleChange,
1289
+ onBlur: handleBlur,
1290
+ error: !!errors[name]
1291
+ }),
1292
+ [values, errors, handleChange, handleBlur]
1293
+ );
1294
+ return {
1295
+ values,
1296
+ errors,
1297
+ isSubmitting,
1298
+ isDirty,
1299
+ setValue,
1300
+ setError,
1301
+ handleChange,
1302
+ handleBlur,
1303
+ handleSubmit,
1304
+ reset,
1305
+ validate,
1306
+ getFieldProps
1307
+ };
1308
+ }
1309
+ export {
1310
+ useForm,
1311
+ useMotionPreference,
1312
+ useTheme
1313
+ };
1314
+ //# sourceMappingURL=hooks.mjs.map