@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/hooks.js ADDED
@@ -0,0 +1,724 @@
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
+ var import_tokens = require("@sage/tokens");
72
+
73
+ // src/lib/colors.ts
74
+ var colorTokens = {
75
+ // Background colors
76
+ background: "var(--color-background)",
77
+ backgroundSecondary: "var(--color-background-secondary)",
78
+ backgroundTertiary: "var(--color-background-tertiary)",
79
+ surface: "var(--color-surface)",
80
+ // Foreground/Text colors
81
+ foreground: "var(--color-foreground)",
82
+ foregroundSecondary: "var(--color-foreground-secondary)",
83
+ foregroundTertiary: "var(--color-foreground-tertiary)",
84
+ textPrimary: "var(--color-text-primary)",
85
+ textSecondary: "var(--color-text-secondary)",
86
+ textMuted: "var(--color-text-muted)",
87
+ // Brand colors
88
+ primary: "var(--color-primary)",
89
+ primaryForeground: "var(--color-primary-foreground)",
90
+ secondary: "var(--color-secondary)",
91
+ secondaryForeground: "var(--color-secondary-foreground)",
92
+ accent: "var(--color-accent)",
93
+ accentForeground: "var(--color-accent-foreground)",
94
+ // Semantic colors
95
+ success: "var(--color-success)",
96
+ successForeground: "var(--color-success-foreground)",
97
+ warning: "var(--color-warning)",
98
+ warningForeground: "var(--color-warning-foreground)",
99
+ error: "var(--color-error)",
100
+ errorForeground: "var(--color-error-foreground)",
101
+ info: "var(--color-info)",
102
+ infoForeground: "var(--color-info-foreground)",
103
+ // Borders
104
+ border: "var(--color-border)",
105
+ borderSubtle: "var(--color-border-subtle)",
106
+ // Interactive states
107
+ hover: "var(--color-hover)",
108
+ active: "var(--color-active)",
109
+ focus: "var(--color-focus)",
110
+ // Links
111
+ link: "var(--color-link)",
112
+ linkHover: "var(--color-link-hover)",
113
+ linkHoverForeground: "var(--color-link-hover-foreground)"
114
+ };
115
+ var semanticColors = {
116
+ /**
117
+ * Status colors for indicating states
118
+ */
119
+ status: {
120
+ success: {
121
+ bg: colorTokens.success,
122
+ fg: colorTokens.successForeground
123
+ },
124
+ warning: {
125
+ bg: colorTokens.warning,
126
+ fg: colorTokens.warningForeground
127
+ },
128
+ error: {
129
+ bg: colorTokens.error,
130
+ fg: colorTokens.errorForeground
131
+ },
132
+ info: {
133
+ bg: colorTokens.info,
134
+ fg: colorTokens.infoForeground
135
+ }
136
+ },
137
+ /**
138
+ * Brand colors for primary UI elements
139
+ */
140
+ brand: {
141
+ primary: {
142
+ bg: colorTokens.primary,
143
+ fg: colorTokens.primaryForeground
144
+ },
145
+ secondary: {
146
+ bg: colorTokens.secondary,
147
+ fg: colorTokens.secondaryForeground
148
+ },
149
+ accent: {
150
+ bg: colorTokens.accent,
151
+ fg: colorTokens.accentForeground
152
+ }
153
+ },
154
+ /**
155
+ * Interactive state colors
156
+ */
157
+ interactive: {
158
+ default: {
159
+ bg: colorTokens.background,
160
+ fg: colorTokens.foreground
161
+ },
162
+ hover: {
163
+ bg: colorTokens.hover,
164
+ fg: colorTokens.foreground
165
+ },
166
+ active: {
167
+ bg: colorTokens.active,
168
+ fg: colorTokens.foreground
169
+ },
170
+ focus: {
171
+ border: colorTokens.focus
172
+ }
173
+ }
174
+ };
175
+ function hexToRgb(hex) {
176
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
177
+ return result ? {
178
+ r: parseInt(result[1], 16),
179
+ g: parseInt(result[2], 16),
180
+ b: parseInt(result[3], 16)
181
+ } : null;
182
+ }
183
+ function getLuminance(r, g, b) {
184
+ const [rs, gs, bs] = [r, g, b].map((c) => {
185
+ const srgb = c / 255;
186
+ return srgb <= 0.03928 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
187
+ });
188
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
189
+ }
190
+ function getContrastRatio(hex1, hex2) {
191
+ const rgb1 = hexToRgb(hex1);
192
+ const rgb2 = hexToRgb(hex2);
193
+ if (!rgb1 || !rgb2) return 0;
194
+ const lum1 = getLuminance(rgb1.r, rgb1.g, rgb1.b);
195
+ const lum2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);
196
+ const lighter = Math.max(lum1, lum2);
197
+ const darker = Math.min(lum1, lum2);
198
+ return (lighter + 0.05) / (darker + 0.05);
199
+ }
200
+ function hexToHSL(hex) {
201
+ const rgb = hexToRgb(hex);
202
+ if (!rgb) return { h: 0, s: 0, l: 0 };
203
+ const r = rgb.r / 255;
204
+ const g = rgb.g / 255;
205
+ const b = rgb.b / 255;
206
+ const max = Math.max(r, g, b);
207
+ const min = Math.min(r, g, b);
208
+ let h = 0, s = 0, l = (max + min) / 2;
209
+ if (max !== min) {
210
+ const d = max - min;
211
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
212
+ switch (max) {
213
+ case r:
214
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
215
+ break;
216
+ case g:
217
+ h = ((b - r) / d + 2) / 6;
218
+ break;
219
+ case b:
220
+ h = ((r - g) / d + 4) / 6;
221
+ break;
222
+ }
223
+ }
224
+ return {
225
+ h: Math.round(h * 360),
226
+ s: Math.round(s * 100),
227
+ l: Math.round(l * 100)
228
+ };
229
+ }
230
+ function hslToHex(h, s, l) {
231
+ h = h / 360;
232
+ s = s / 100;
233
+ l = l / 100;
234
+ let r, g, b;
235
+ if (s === 0) {
236
+ r = g = b = l;
237
+ } else {
238
+ const hue2rgb = (p2, q2, t) => {
239
+ if (t < 0) t += 1;
240
+ if (t > 1) t -= 1;
241
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
242
+ if (t < 1 / 2) return q2;
243
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
244
+ return p2;
245
+ };
246
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
247
+ const p = 2 * l - q;
248
+ r = hue2rgb(p, q, h + 1 / 3);
249
+ g = hue2rgb(p, q, h);
250
+ b = hue2rgb(p, q, h - 1 / 3);
251
+ }
252
+ const toHex = (x) => {
253
+ const hex = Math.round(x * 255).toString(16);
254
+ return hex.length === 1 ? "0" + hex : hex;
255
+ };
256
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
257
+ }
258
+ function getOptimalForeground(bgHex, whiteHex = "#ffffff", blackHex = "#000000") {
259
+ const whiteRatio = getContrastRatio(bgHex, whiteHex);
260
+ const blackRatio = getContrastRatio(bgHex, blackHex);
261
+ return whiteRatio > blackRatio ? whiteHex : blackHex;
262
+ }
263
+ function generateColorScale(baseHex) {
264
+ const hsl = hexToHSL(baseHex);
265
+ return {
266
+ 50: hslToHex(hsl.h, Math.max(hsl.s - 10, 20), 95),
267
+ 100: hslToHex(hsl.h, Math.max(hsl.s - 5, 30), 90),
268
+ 200: hslToHex(hsl.h, hsl.s, 80),
269
+ 300: hslToHex(hsl.h, hsl.s, 70),
270
+ 400: hslToHex(hsl.h, hsl.s, 60),
271
+ 500: baseHex,
272
+ // Base color
273
+ 600: hslToHex(hsl.h, Math.min(hsl.s + 5, 100), 45),
274
+ 700: hslToHex(hsl.h, Math.min(hsl.s + 10, 100), 35),
275
+ 800: hslToHex(hsl.h, Math.min(hsl.s + 15, 100), 25),
276
+ 900: hslToHex(hsl.h, Math.min(hsl.s + 20, 100), 15)
277
+ };
278
+ }
279
+
280
+ // src/lib/store/customizer.ts
281
+ var useCustomizer = (0, import_zustand2.create)()(
282
+ (0, import_middleware2.persist)(
283
+ (set, get) => ({
284
+ motion: 5,
285
+ prefersReducedMotion: false,
286
+ customizationMode: "simple",
287
+ customColors: {},
288
+ savedPalettes: [],
289
+ customFontThemes: {},
290
+ savedFontThemes: [],
291
+ setMotion: (level) => set({ motion: level }),
292
+ setPrefersReducedMotion: (value) => set({ prefersReducedMotion: value }),
293
+ setCustomizationMode: (mode) => set({ customizationMode: mode }),
294
+ setCustomPrimaryColor: (theme, mode, hexColor) => {
295
+ const state = get();
296
+ const currentPalette = state.customColors[theme]?.[mode];
297
+ const scale = generateColorScale(hexColor);
298
+ const primaryForeground = getOptimalForeground(hexColor);
299
+ const derivedTokens = (0, import_tokens.computeDerivedTokens)("--color-primary", hexColor, mode);
300
+ const isSimple = state.customizationMode === "simple";
301
+ const palette = {
302
+ primary: hexColor,
303
+ primaryForeground,
304
+ secondary: isSimple ? void 0 : currentPalette?.secondary,
305
+ secondaryForeground: isSimple ? void 0 : currentPalette?.secondaryForeground,
306
+ accent: isSimple ? void 0 : currentPalette?.accent,
307
+ accentForeground: isSimple ? void 0 : currentPalette?.accentForeground,
308
+ scale,
309
+ derivedTokens
310
+ };
311
+ set((state2) => ({
312
+ customColors: {
313
+ ...state2.customColors,
314
+ [theme]: {
315
+ ...state2.customColors[theme],
316
+ [mode]: palette
317
+ }
318
+ }
319
+ }));
320
+ },
321
+ setCustomSecondaryColor: (theme, mode, hexColor) => {
322
+ const state = get();
323
+ const currentPalette = state.customColors[theme]?.[mode];
324
+ if (!currentPalette) return;
325
+ const secondaryForeground = getOptimalForeground(hexColor);
326
+ const derivedTokens = (0, import_tokens.computeDerivedTokens)("--color-secondary", hexColor, mode);
327
+ set((state2) => ({
328
+ customColors: {
329
+ ...state2.customColors,
330
+ [theme]: {
331
+ ...state2.customColors[theme],
332
+ [mode]: {
333
+ ...currentPalette,
334
+ secondary: hexColor,
335
+ secondaryForeground,
336
+ derivedTokens: {
337
+ ...currentPalette.derivedTokens,
338
+ ...derivedTokens
339
+ }
340
+ }
341
+ }
342
+ }
343
+ }));
344
+ },
345
+ setCustomAccentColor: (theme, mode, hexColor) => {
346
+ const state = get();
347
+ const currentPalette = state.customColors[theme]?.[mode];
348
+ if (!currentPalette) return;
349
+ const accentForeground = getOptimalForeground(hexColor);
350
+ const derivedTokens = (0, import_tokens.computeDerivedTokens)("--color-accent", hexColor, mode);
351
+ set((state2) => ({
352
+ customColors: {
353
+ ...state2.customColors,
354
+ [theme]: {
355
+ ...state2.customColors[theme],
356
+ [mode]: {
357
+ ...currentPalette,
358
+ accent: hexColor,
359
+ accentForeground,
360
+ derivedTokens: {
361
+ ...currentPalette.derivedTokens,
362
+ ...derivedTokens
363
+ }
364
+ }
365
+ }
366
+ }
367
+ }));
368
+ },
369
+ applyColorPalette: (theme, mode, colors) => {
370
+ const scale = generateColorScale(colors.primary);
371
+ const primaryForeground = getOptimalForeground(colors.primary);
372
+ let derivedTokens = (0, import_tokens.computeDerivedTokens)("--color-primary", colors.primary, mode);
373
+ let secondary = colors.secondary;
374
+ let secondaryForeground = secondary ? getOptimalForeground(secondary) : void 0;
375
+ if (secondary) {
376
+ const secondaryDerived = (0, import_tokens.computeDerivedTokens)("--color-secondary", secondary, mode);
377
+ derivedTokens = { ...derivedTokens, ...secondaryDerived };
378
+ }
379
+ let accent = colors.accent;
380
+ let accentForeground = accent ? getOptimalForeground(accent) : void 0;
381
+ if (accent) {
382
+ const accentDerived = (0, import_tokens.computeDerivedTokens)("--color-accent", accent, mode);
383
+ derivedTokens = { ...derivedTokens, ...accentDerived };
384
+ }
385
+ const palette = {
386
+ name: colors.name,
387
+ description: colors.description,
388
+ primary: colors.primary,
389
+ primaryForeground,
390
+ secondary,
391
+ secondaryForeground,
392
+ accent,
393
+ accentForeground,
394
+ scale,
395
+ derivedTokens
396
+ };
397
+ set((state) => ({
398
+ customColors: {
399
+ ...state.customColors,
400
+ [theme]: {
401
+ ...state.customColors[theme],
402
+ [mode]: palette
403
+ }
404
+ }
405
+ }));
406
+ },
407
+ resetCustomColors: (theme, mode) => {
408
+ if (mode) {
409
+ set((state) => ({
410
+ customColors: {
411
+ ...state.customColors,
412
+ [theme]: {
413
+ ...state.customColors[theme],
414
+ [mode]: void 0
415
+ }
416
+ }
417
+ }));
418
+ } else {
419
+ set((state) => {
420
+ const { [theme]: _, ...rest } = state.customColors;
421
+ return { customColors: rest };
422
+ });
423
+ }
424
+ },
425
+ getActiveColorPalette: (theme, mode) => {
426
+ return get().customColors[theme]?.[mode] || null;
427
+ },
428
+ // Saved palette management
429
+ savePalette: (paletteData) => {
430
+ const id = `custom-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
431
+ const newPalette = {
432
+ ...paletteData,
433
+ id,
434
+ category: "custom",
435
+ createdAt: Date.now()
436
+ };
437
+ set((state) => ({
438
+ savedPalettes: [...state.savedPalettes, newPalette]
439
+ }));
440
+ },
441
+ updatePalette: (id, updates) => {
442
+ set((state) => ({
443
+ savedPalettes: state.savedPalettes.map(
444
+ (p) => p.id === id ? { ...p, ...updates } : p
445
+ )
446
+ }));
447
+ },
448
+ renamePalette: (id, newName) => {
449
+ set((state) => ({
450
+ savedPalettes: state.savedPalettes.map(
451
+ (p) => p.id === id ? { ...p, name: newName } : p
452
+ )
453
+ }));
454
+ },
455
+ deletePalette: (id) => {
456
+ set((state) => ({
457
+ savedPalettes: state.savedPalettes.filter((p) => p.id !== id)
458
+ }));
459
+ },
460
+ reorderPalettes: (palettes) => {
461
+ set({ savedPalettes: palettes });
462
+ },
463
+ getSavedPalettes: () => {
464
+ return get().savedPalettes;
465
+ },
466
+ // Font theme management
467
+ applyFontTheme: (theme, mode, fontTheme) => {
468
+ set((state) => ({
469
+ customFontThemes: {
470
+ ...state.customFontThemes,
471
+ [theme]: {
472
+ ...state.customFontThemes[theme],
473
+ [mode]: fontTheme
474
+ }
475
+ }
476
+ }));
477
+ },
478
+ resetCustomFonts: (theme, mode) => {
479
+ if (mode) {
480
+ set((state) => ({
481
+ customFontThemes: {
482
+ ...state.customFontThemes,
483
+ [theme]: {
484
+ ...state.customFontThemes[theme],
485
+ [mode]: void 0
486
+ }
487
+ }
488
+ }));
489
+ } else {
490
+ set((state) => {
491
+ const { [theme]: _, ...rest } = state.customFontThemes;
492
+ return { customFontThemes: rest };
493
+ });
494
+ }
495
+ },
496
+ getActiveFontTheme: (theme, mode) => {
497
+ return get().customFontThemes[theme]?.[mode] || null;
498
+ },
499
+ // Saved font theme management
500
+ saveFontTheme: (fontThemeData) => {
501
+ const id = `font-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
502
+ const newFontTheme = {
503
+ ...fontThemeData,
504
+ id,
505
+ category: "custom",
506
+ createdAt: Date.now(),
507
+ isCustom: true
508
+ };
509
+ set((state) => ({
510
+ savedFontThemes: [...state.savedFontThemes, newFontTheme]
511
+ }));
512
+ },
513
+ updateFontTheme: (id, updates) => {
514
+ set((state) => ({
515
+ savedFontThemes: state.savedFontThemes.map(
516
+ (ft) => ft.id === id ? { ...ft, ...updates } : ft
517
+ )
518
+ }));
519
+ },
520
+ renameFontTheme: (id, newName) => {
521
+ set((state) => ({
522
+ savedFontThemes: state.savedFontThemes.map(
523
+ (ft) => ft.id === id ? { ...ft, name: newName } : ft
524
+ )
525
+ }));
526
+ },
527
+ deleteFontTheme: (id) => {
528
+ set((state) => ({
529
+ savedFontThemes: state.savedFontThemes.filter((ft) => ft.id !== id)
530
+ }));
531
+ },
532
+ reorderFontThemes: (fontThemes) => {
533
+ set({ savedFontThemes: fontThemes });
534
+ },
535
+ getSavedFontThemes: () => {
536
+ return get().savedFontThemes;
537
+ }
538
+ }),
539
+ {
540
+ name: "ecosystem-customizer",
541
+ version: 4,
542
+ partialize: (state) => ({
543
+ motion: state.motion,
544
+ prefersReducedMotion: state.prefersReducedMotion,
545
+ customizationMode: state.customizationMode,
546
+ customColors: state.customColors,
547
+ savedPalettes: state.savedPalettes,
548
+ customFontThemes: state.customFontThemes,
549
+ savedFontThemes: state.savedFontThemes
550
+ })
551
+ }
552
+ )
553
+ );
554
+
555
+ // src/hooks/useMotionPreference.ts
556
+ function useMotionPreference() {
557
+ const { motion, prefersReducedMotion, setPrefersReducedMotion } = useCustomizer();
558
+ (0, import_react.useEffect)(() => {
559
+ if (typeof window === "undefined") return;
560
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
561
+ setPrefersReducedMotion(mediaQuery.matches);
562
+ const handleChange = (e) => {
563
+ setPrefersReducedMotion(e.matches);
564
+ };
565
+ mediaQuery.addEventListener("change", handleChange);
566
+ return () => mediaQuery.removeEventListener("change", handleChange);
567
+ }, [setPrefersReducedMotion]);
568
+ return {
569
+ scale: motion,
570
+ shouldAnimate: motion > 0 && !prefersReducedMotion,
571
+ prefersReducedMotion
572
+ };
573
+ }
574
+
575
+ // src/hooks/useForm.ts
576
+ var import_react2 = require("react");
577
+
578
+ // src/lib/validation.ts
579
+ function validateField(value, rules) {
580
+ if (rules.required) {
581
+ const isEmpty = value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
582
+ if (isEmpty) {
583
+ return typeof rules.required === "string" ? rules.required : "This field is required";
584
+ }
585
+ }
586
+ if (!value && !rules.required) {
587
+ return void 0;
588
+ }
589
+ if (rules.minLength && value.length < rules.minLength.value) {
590
+ return rules.minLength.message;
591
+ }
592
+ if (rules.maxLength && value.length > rules.maxLength.value) {
593
+ return rules.maxLength.message;
594
+ }
595
+ if (rules.pattern && !rules.pattern.value.test(value)) {
596
+ return rules.pattern.message;
597
+ }
598
+ if (rules.custom) {
599
+ for (const rule of rules.custom) {
600
+ if (!rule.validate(value)) {
601
+ return rule.message;
602
+ }
603
+ }
604
+ }
605
+ return void 0;
606
+ }
607
+ function validateForm(values, validations) {
608
+ const errors = {};
609
+ for (const [field, rules] of Object.entries(validations)) {
610
+ const error = validateField(values[field], rules);
611
+ if (error) {
612
+ errors[field] = error;
613
+ }
614
+ }
615
+ return errors;
616
+ }
617
+
618
+ // src/hooks/useForm.ts
619
+ function useForm({
620
+ initialValues,
621
+ validations = {},
622
+ onSubmit,
623
+ validateOn = "onBlur"
624
+ }) {
625
+ const [values, setValues] = (0, import_react2.useState)(initialValues);
626
+ const [errors, setErrors] = (0, import_react2.useState)({});
627
+ const [isSubmitting, setIsSubmitting] = (0, import_react2.useState)(false);
628
+ const [isDirty, setIsDirty] = (0, import_react2.useState)(false);
629
+ const setValue = (0, import_react2.useCallback)((name, value) => {
630
+ setValues((prev) => ({ ...prev, [name]: value }));
631
+ setIsDirty(true);
632
+ }, []);
633
+ const setError = (0, import_react2.useCallback)((name, error) => {
634
+ setErrors((prev) => ({ ...prev, [name]: error }));
635
+ }, []);
636
+ const validateFieldByName = (0, import_react2.useCallback)(
637
+ (name) => {
638
+ const fieldRules = validations[name];
639
+ if (!fieldRules) return;
640
+ const error = validateField(values[name], fieldRules);
641
+ setError(name, error);
642
+ return !error;
643
+ },
644
+ [values, validations, setError]
645
+ );
646
+ const handleChange = (0, import_react2.useCallback)(
647
+ (e) => {
648
+ const { name, value, type } = e.target;
649
+ const fieldValue = type === "checkbox" ? e.target.checked : value;
650
+ setValue(name, fieldValue);
651
+ if (validateOn === "onChange") {
652
+ validateFieldByName(name);
653
+ }
654
+ },
655
+ [setValue, validateOn, validateFieldByName]
656
+ );
657
+ const handleBlur = (0, import_react2.useCallback)(
658
+ (e) => {
659
+ const { name } = e.target;
660
+ if (validateOn === "onBlur") {
661
+ validateFieldByName(name);
662
+ }
663
+ },
664
+ [validateOn, validateFieldByName]
665
+ );
666
+ const validate = (0, import_react2.useCallback)(() => {
667
+ const formErrors = validateForm(values, validations);
668
+ setErrors(formErrors);
669
+ return Object.keys(formErrors).length === 0;
670
+ }, [values, validations]);
671
+ const handleSubmit = (0, import_react2.useCallback)(
672
+ async (e) => {
673
+ e?.preventDefault();
674
+ const isValid = validate();
675
+ if (!isValid) return;
676
+ if (onSubmit) {
677
+ setIsSubmitting(true);
678
+ try {
679
+ await onSubmit(values);
680
+ } finally {
681
+ setIsSubmitting(false);
682
+ }
683
+ }
684
+ },
685
+ [validate, onSubmit, values]
686
+ );
687
+ const reset = (0, import_react2.useCallback)(() => {
688
+ setValues(initialValues);
689
+ setErrors({});
690
+ setIsDirty(false);
691
+ setIsSubmitting(false);
692
+ }, [initialValues]);
693
+ const getFieldProps = (0, import_react2.useCallback)(
694
+ (name) => ({
695
+ name,
696
+ value: values[name] ?? "",
697
+ onChange: handleChange,
698
+ onBlur: handleBlur,
699
+ error: !!errors[name]
700
+ }),
701
+ [values, errors, handleChange, handleBlur]
702
+ );
703
+ return {
704
+ values,
705
+ errors,
706
+ isSubmitting,
707
+ isDirty,
708
+ setValue,
709
+ setError,
710
+ handleChange,
711
+ handleBlur,
712
+ handleSubmit,
713
+ reset,
714
+ validate,
715
+ getFieldProps
716
+ };
717
+ }
718
+ // Annotate the CommonJS export names for ESM import in node:
719
+ 0 && (module.exports = {
720
+ useForm,
721
+ useMotionPreference,
722
+ useTheme
723
+ });
724
+ //# sourceMappingURL=hooks.js.map