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