@opencosmos/ui 1.3.1

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 (260) hide show
  1. package/.claude/CLAUDE.md +239 -0
  2. package/README.md +161 -0
  3. package/dist/cli.mjs +151 -0
  4. package/dist/dates.d.mts +20 -0
  5. package/dist/dates.d.ts +20 -0
  6. package/dist/dates.js +240 -0
  7. package/dist/dates.js.map +1 -0
  8. package/dist/dates.mjs +203 -0
  9. package/dist/dates.mjs.map +1 -0
  10. package/dist/dnd.d.mts +126 -0
  11. package/dist/dnd.d.ts +126 -0
  12. package/dist/dnd.js +274 -0
  13. package/dist/dnd.js.map +1 -0
  14. package/dist/dnd.mjs +250 -0
  15. package/dist/dnd.mjs.map +1 -0
  16. package/dist/fontThemes-Dh8mtXES.d.mts +868 -0
  17. package/dist/fontThemes-Dh8mtXES.d.ts +868 -0
  18. package/dist/forms.d.mts +38 -0
  19. package/dist/forms.d.ts +38 -0
  20. package/dist/forms.js +198 -0
  21. package/dist/forms.js.map +1 -0
  22. package/dist/forms.mjs +159 -0
  23. package/dist/forms.mjs.map +1 -0
  24. package/dist/hooks-1b8WaQf1.d.mts +225 -0
  25. package/dist/hooks-CKW8vE9H.d.ts +225 -0
  26. package/dist/hooks.d.mts +3 -0
  27. package/dist/hooks.d.ts +3 -0
  28. package/dist/hooks.js +971 -0
  29. package/dist/hooks.js.map +1 -0
  30. package/dist/hooks.mjs +943 -0
  31. package/dist/hooks.mjs.map +1 -0
  32. package/dist/index-DscTIrZ2.d.mts +29 -0
  33. package/dist/index-DscTIrZ2.d.ts +29 -0
  34. package/dist/index.d.mts +3382 -0
  35. package/dist/index.d.ts +3382 -0
  36. package/dist/index.js +15146 -0
  37. package/dist/index.js.map +1 -0
  38. package/dist/index.mjs +14802 -0
  39. package/dist/index.mjs.map +1 -0
  40. package/dist/providers-CXPDMsl7.d.mts +30 -0
  41. package/dist/providers-Dn_Msjvz.d.ts +30 -0
  42. package/dist/providers.d.mts +3 -0
  43. package/dist/providers.d.ts +3 -0
  44. package/dist/providers.js +1885 -0
  45. package/dist/providers.js.map +1 -0
  46. package/dist/providers.mjs +1859 -0
  47. package/dist/providers.mjs.map +1 -0
  48. package/dist/tables.d.mts +10 -0
  49. package/dist/tables.d.ts +10 -0
  50. package/dist/tables.js +248 -0
  51. package/dist/tables.js.map +1 -0
  52. package/dist/tables.mjs +218 -0
  53. package/dist/tables.mjs.map +1 -0
  54. package/dist/tokens.d.mts +1065 -0
  55. package/dist/tokens.d.ts +1065 -0
  56. package/dist/tokens.js +2637 -0
  57. package/dist/tokens.js.map +1 -0
  58. package/dist/tokens.mjs +2555 -0
  59. package/dist/tokens.mjs.map +1 -0
  60. package/dist/utils-CIIM7dAC.d.ts +986 -0
  61. package/dist/utils-Cs04sxth.d.mts +986 -0
  62. package/dist/utils.d.mts +4 -0
  63. package/dist/utils.d.ts +4 -0
  64. package/dist/utils.js +874 -0
  65. package/dist/utils.js.map +1 -0
  66. package/dist/utils.mjs +806 -0
  67. package/dist/utils.mjs.map +1 -0
  68. package/dist/validation-Bj1ye-v_.d.mts +114 -0
  69. package/dist/validation-Bj1ye-v_.d.ts +114 -0
  70. package/dist/webgl.d.mts +104 -0
  71. package/dist/webgl.d.ts +104 -0
  72. package/dist/webgl.js +226 -0
  73. package/dist/webgl.js.map +1 -0
  74. package/dist/webgl.mjs +195 -0
  75. package/dist/webgl.mjs.map +1 -0
  76. package/package.json +267 -0
  77. package/src/cli.ts +206 -0
  78. package/src/component-registry.ts +183 -0
  79. package/src/components/actions/Button.test.tsx +61 -0
  80. package/src/components/actions/Button.tsx +70 -0
  81. package/src/components/actions/Link.tsx +78 -0
  82. package/src/components/actions/Magnetic.tsx +68 -0
  83. package/src/components/actions/Toggle.test.tsx +40 -0
  84. package/src/components/actions/Toggle.tsx +47 -0
  85. package/src/components/actions/ToggleGroup.tsx +70 -0
  86. package/src/components/actions/index.ts +5 -0
  87. package/src/components/backgrounds/FaultyTerminal.tsx +426 -0
  88. package/src/components/backgrounds/OrbBackground.tsx +424 -0
  89. package/src/components/backgrounds/WarpBackground.tsx +358 -0
  90. package/src/components/backgrounds/index.ts +3 -0
  91. package/src/components/blocks/Hero.tsx +142 -0
  92. package/src/components/blocks/social/OpenGraphCard.tsx +243 -0
  93. package/src/components/cursor/SplashCursor.tsx +1315 -0
  94. package/src/components/cursor/TargetCursor.tsx +187 -0
  95. package/src/components/cursor/index.ts +2 -0
  96. package/src/components/data-display/AspectImage.tsx +73 -0
  97. package/src/components/data-display/Avatar.test.tsx +35 -0
  98. package/src/components/data-display/Avatar.tsx +55 -0
  99. package/src/components/data-display/Badge.test.tsx +43 -0
  100. package/src/components/data-display/Badge.tsx +84 -0
  101. package/src/components/data-display/Brand.tsx +123 -0
  102. package/src/components/data-display/Calendar.tsx +70 -0
  103. package/src/components/data-display/Card.test.tsx +92 -0
  104. package/src/components/data-display/Card.tsx +115 -0
  105. package/src/components/data-display/Code.tsx +210 -0
  106. package/src/components/data-display/CollapsibleCodeBlock.tsx +238 -0
  107. package/src/components/data-display/DataTable.tsx +119 -0
  108. package/src/components/data-display/DescriptionList.tsx +41 -0
  109. package/src/components/data-display/GitHubIcon.tsx +44 -0
  110. package/src/components/data-display/Heading.test.tsx +36 -0
  111. package/src/components/data-display/Heading.tsx +83 -0
  112. package/src/components/data-display/StatCard.tsx +195 -0
  113. package/src/components/data-display/Table.tsx +133 -0
  114. package/src/components/data-display/Text.test.tsx +48 -0
  115. package/src/components/data-display/Text.tsx +144 -0
  116. package/src/components/data-display/Timeline.tsx +194 -0
  117. package/src/components/data-display/TreeView.tsx +226 -0
  118. package/src/components/data-display/Typewriter.tsx +119 -0
  119. package/src/components/data-display/VariableWeightText.tsx +130 -0
  120. package/src/components/data-display/index.ts +19 -0
  121. package/src/components/feedback/Alert.test.tsx +44 -0
  122. package/src/components/feedback/Alert.tsx +65 -0
  123. package/src/components/feedback/EmptyState.tsx +113 -0
  124. package/src/components/feedback/Progress.test.tsx +60 -0
  125. package/src/components/feedback/Progress.tsx +30 -0
  126. package/src/components/feedback/ProgressBar.tsx +158 -0
  127. package/src/components/feedback/Skeleton.test.tsx +39 -0
  128. package/src/components/feedback/Skeleton.tsx +45 -0
  129. package/src/components/feedback/Sonner.tsx +28 -0
  130. package/src/components/feedback/Spinner.test.tsx +33 -0
  131. package/src/components/feedback/Spinner.tsx +99 -0
  132. package/src/components/feedback/Stepper.tsx +307 -0
  133. package/src/components/feedback/Toast/Toast.tsx +243 -0
  134. package/src/components/feedback/Toast/index.ts +2 -0
  135. package/src/components/feedback/index.ts +9 -0
  136. package/src/components/forms/Checkbox.test.tsx +40 -0
  137. package/src/components/forms/Checkbox.tsx +31 -0
  138. package/src/components/forms/ColorPicker.tsx +118 -0
  139. package/src/components/forms/Combobox.tsx +96 -0
  140. package/src/components/forms/DragDrop.tsx +440 -0
  141. package/src/components/forms/FileUpload.tsx +252 -0
  142. package/src/components/forms/FilterButton.tsx +65 -0
  143. package/src/components/forms/Form.tsx +197 -0
  144. package/src/components/forms/Input.test.tsx +46 -0
  145. package/src/components/forms/Input.tsx +43 -0
  146. package/src/components/forms/InputOTP.tsx +81 -0
  147. package/src/components/forms/Label.test.tsx +20 -0
  148. package/src/components/forms/Label.tsx +25 -0
  149. package/src/components/forms/RadioGroup.tsx +51 -0
  150. package/src/components/forms/SearchBar.tsx +215 -0
  151. package/src/components/forms/Select.test.tsx +118 -0
  152. package/src/components/forms/Select.tsx +274 -0
  153. package/src/components/forms/Slider.tsx +29 -0
  154. package/src/components/forms/Switch.test.tsx +76 -0
  155. package/src/components/forms/Switch.tsx +30 -0
  156. package/src/components/forms/TextField.tsx +152 -0
  157. package/src/components/forms/Textarea.test.tsx +41 -0
  158. package/src/components/forms/Textarea.tsx +29 -0
  159. package/src/components/forms/ThemeSwitcher.tsx +290 -0
  160. package/src/components/forms/ThemeToggle.tsx +151 -0
  161. package/src/components/forms/index.ts +19 -0
  162. package/src/components/layout/Accordion.test.tsx +66 -0
  163. package/src/components/layout/Accordion.tsx +64 -0
  164. package/src/components/layout/AspectRatio.tsx +7 -0
  165. package/src/components/layout/Carousel.tsx +277 -0
  166. package/src/components/layout/Collapsible.test.tsx +40 -0
  167. package/src/components/layout/Collapsible.tsx +31 -0
  168. package/src/components/layout/Container.test.tsx +45 -0
  169. package/src/components/layout/Container.tsx +99 -0
  170. package/src/components/layout/CustomizerPanel.tsx +400 -0
  171. package/src/components/layout/DatePicker.tsx +57 -0
  172. package/src/components/layout/Footer/Footer.tsx +175 -0
  173. package/src/components/layout/Footer/index.ts +2 -0
  174. package/src/components/layout/GlassSurface.tsx +82 -0
  175. package/src/components/layout/Grid.test.tsx +31 -0
  176. package/src/components/layout/Grid.tsx +130 -0
  177. package/src/components/layout/Header/Header.tsx +450 -0
  178. package/src/components/layout/Header/index.ts +2 -0
  179. package/src/components/layout/PageLayout.tsx +180 -0
  180. package/src/components/layout/PageTemplate.tsx +158 -0
  181. package/src/components/layout/Resizable.tsx +48 -0
  182. package/src/components/layout/ScrollArea.tsx +53 -0
  183. package/src/components/layout/Separator.test.tsx +28 -0
  184. package/src/components/layout/Separator.tsx +29 -0
  185. package/src/components/layout/Sidebar.tsx +171 -0
  186. package/src/components/layout/Stack.test.tsx +41 -0
  187. package/src/components/layout/Stack.tsx +89 -0
  188. package/src/components/layout/glass-surface.css +60 -0
  189. package/src/components/layout/index.ts +18 -0
  190. package/src/components/motion/AnimatedBeam.tsx +159 -0
  191. package/src/components/navigation/Breadcrumb.test.tsx +57 -0
  192. package/src/components/navigation/Breadcrumb.tsx +119 -0
  193. package/src/components/navigation/Breadcrumbs.tsx +221 -0
  194. package/src/components/navigation/Command.tsx +159 -0
  195. package/src/components/navigation/Menubar.tsx +115 -0
  196. package/src/components/navigation/NavLink.tsx +55 -0
  197. package/src/components/navigation/NavigationMenu.tsx +125 -0
  198. package/src/components/navigation/Pagination.tsx +121 -0
  199. package/src/components/navigation/SecondaryNav.tsx +100 -0
  200. package/src/components/navigation/Tabs.test.tsx +47 -0
  201. package/src/components/navigation/Tabs.tsx +60 -0
  202. package/src/components/navigation/TertiaryNav.tsx +90 -0
  203. package/src/components/navigation/index.ts +10 -0
  204. package/src/components/overlays/AlertDialog.test.tsx +69 -0
  205. package/src/components/overlays/AlertDialog.tsx +166 -0
  206. package/src/components/overlays/ContextMenu.tsx +243 -0
  207. package/src/components/overlays/Dialog.test.tsx +79 -0
  208. package/src/components/overlays/Dialog.tsx +158 -0
  209. package/src/components/overlays/Drawer.tsx +128 -0
  210. package/src/components/overlays/Dropdown.tsx +253 -0
  211. package/src/components/overlays/DropdownMenu.tsx +242 -0
  212. package/src/components/overlays/HoverCard.tsx +32 -0
  213. package/src/components/overlays/Modal.tsx +250 -0
  214. package/src/components/overlays/NotificationCenter.tsx +364 -0
  215. package/src/components/overlays/Popover.test.tsx +40 -0
  216. package/src/components/overlays/Popover.tsx +46 -0
  217. package/src/components/overlays/Sheet.tsx +163 -0
  218. package/src/components/overlays/Tooltip.test.tsx +33 -0
  219. package/src/components/overlays/Tooltip.tsx +32 -0
  220. package/src/components/overlays/index.ts +12 -0
  221. package/src/dates.ts +2 -0
  222. package/src/dnd.ts +1 -0
  223. package/src/forms.ts +1 -0
  224. package/src/globals.css +187 -0
  225. package/src/hooks/index.ts +6 -0
  226. package/src/hooks/useForm.ts +247 -0
  227. package/src/hooks/useMotionPreference.test.ts +102 -0
  228. package/src/hooks/useMotionPreference.ts +78 -0
  229. package/src/hooks/useTheme.ts +58 -0
  230. package/src/hooks.ts +9 -0
  231. package/src/index.ts +168 -0
  232. package/src/lib/animations.ts +356 -0
  233. package/src/lib/breadcrumbs.ts +94 -0
  234. package/src/lib/colors.ts +493 -0
  235. package/src/lib/store/customizer.ts +482 -0
  236. package/src/lib/store/index.ts +3 -0
  237. package/src/lib/store/theme.ts +55 -0
  238. package/src/lib/syntax-parser/index.ts +50 -0
  239. package/src/lib/syntax-parser/patterns.ts +64 -0
  240. package/src/lib/syntax-parser/tokenizer.ts +117 -0
  241. package/src/lib/syntax-parser/types.ts +27 -0
  242. package/src/lib/utils.ts +6 -0
  243. package/src/lib/validation.ts +204 -0
  244. package/src/lib/webgl/Color.ts +11 -0
  245. package/src/lib/webgl/Mesh.ts +41 -0
  246. package/src/lib/webgl/Program.ts +118 -0
  247. package/src/lib/webgl/Renderer.ts +51 -0
  248. package/src/lib/webgl/Triangle.ts +27 -0
  249. package/src/lib/webgl/Vec3.ts +18 -0
  250. package/src/lib/webgl/index.ts +13 -0
  251. package/src/nativewind-env.d.ts +1 -0
  252. package/src/providers/ThemeProvider.tsx +461 -0
  253. package/src/providers/index.ts +1 -0
  254. package/src/providers.ts +7 -0
  255. package/src/tables.ts +1 -0
  256. package/src/test/setup.ts +39 -0
  257. package/src/theme.css +158 -0
  258. package/src/tokens.ts +7 -0
  259. package/src/utils.ts +12 -0
  260. package/src/webgl.ts +1 -0
package/dist/hooks.mjs ADDED
@@ -0,0 +1,943 @@
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/color-utils.ts
46
+ function hexToRgb(hex) {
47
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
48
+ return result ? {
49
+ r: parseInt(result[1], 16),
50
+ g: parseInt(result[2], 16),
51
+ b: parseInt(result[3], 16)
52
+ } : null;
53
+ }
54
+ function hexToHSL(hex) {
55
+ const rgb = hexToRgb(hex);
56
+ if (!rgb) return { h: 0, s: 0, l: 0 };
57
+ const r = rgb.r / 255;
58
+ const g = rgb.g / 255;
59
+ const b = rgb.b / 255;
60
+ const max = Math.max(r, g, b);
61
+ const min = Math.min(r, g, b);
62
+ let h = 0, s = 0, l = (max + min) / 2;
63
+ if (max !== min) {
64
+ const d = max - min;
65
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
66
+ switch (max) {
67
+ case r:
68
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
69
+ break;
70
+ case g:
71
+ h = ((b - r) / d + 2) / 6;
72
+ break;
73
+ case b:
74
+ h = ((r - g) / d + 4) / 6;
75
+ break;
76
+ }
77
+ }
78
+ return {
79
+ h: Math.round(h * 360),
80
+ s: Math.round(s * 100),
81
+ l: Math.round(l * 100)
82
+ };
83
+ }
84
+ function hslToHex(h, s, l) {
85
+ h = h / 360;
86
+ s = s / 100;
87
+ l = l / 100;
88
+ let r, g, b;
89
+ if (s === 0) {
90
+ r = g = b = l;
91
+ } else {
92
+ const hue2rgb = (p2, q2, t) => {
93
+ if (t < 0) t += 1;
94
+ if (t > 1) t -= 1;
95
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
96
+ if (t < 1 / 2) return q2;
97
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
98
+ return p2;
99
+ };
100
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
101
+ const p = 2 * l - q;
102
+ r = hue2rgb(p, q, h + 1 / 3);
103
+ g = hue2rgb(p, q, h);
104
+ b = hue2rgb(p, q, h - 1 / 3);
105
+ }
106
+ const toHex = (x) => {
107
+ const hex = Math.round(x * 255).toString(16);
108
+ return hex.length === 1 ? "0" + hex : hex;
109
+ };
110
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
111
+ }
112
+ function adjustLightness(hex, percent) {
113
+ const hsl = hexToHSL(hex);
114
+ const newL = Math.max(0, Math.min(100, hsl.l + percent));
115
+ return hslToHex(hsl.h, hsl.s, newL);
116
+ }
117
+ function adjustSaturation(hex, percent) {
118
+ const hsl = hexToHSL(hex);
119
+ const newS = Math.max(0, Math.min(100, hsl.s + percent));
120
+ return hslToHex(hsl.h, newS, hsl.l);
121
+ }
122
+ function rotateHue(hex, degrees) {
123
+ const hsl = hexToHSL(hex);
124
+ const newH = (hsl.h + degrees) % 360;
125
+ return hslToHex(newH, hsl.s, hsl.l);
126
+ }
127
+ function adjustOpacity(hex, opacity) {
128
+ const rgb = hexToRgb(hex);
129
+ if (!rgb) return hex;
130
+ return `rgba(${rgb.r}, ${rgb.g}, ${rgb.b}, ${opacity})`;
131
+ }
132
+ function getLuminance(r, g, b) {
133
+ const [rs, gs, bs] = [r, g, b].map((c) => {
134
+ const srgb = c / 255;
135
+ return srgb <= 0.03928 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
136
+ });
137
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
138
+ }
139
+ function getContrastRatio(hex1, hex2) {
140
+ const rgb1 = hexToRgb(hex1);
141
+ const rgb2 = hexToRgb(hex2);
142
+ if (!rgb1 || !rgb2) return 0;
143
+ const lum1 = getLuminance(rgb1.r, rgb1.g, rgb1.b);
144
+ const lum2 = getLuminance(rgb2.r, rgb2.g, rgb2.b);
145
+ const lighter = Math.max(lum1, lum2);
146
+ const darker = Math.min(lum1, lum2);
147
+ return (lighter + 0.05) / (darker + 0.05);
148
+ }
149
+ function getOptimalForeground(bgHex, whiteHex = "#ffffff", blackHex = "#000000") {
150
+ const whiteRatio = getContrastRatio(bgHex, whiteHex);
151
+ const blackRatio = getContrastRatio(bgHex, blackHex);
152
+ return whiteRatio > blackRatio ? whiteHex : blackHex;
153
+ }
154
+
155
+ // ../tokens/src/token-graph.ts
156
+ var primaryColorDerivations = {
157
+ // Links use primary color
158
+ "--color-link": {
159
+ source: "--color-primary",
160
+ transform: (primary) => primary,
161
+ description: "Links inherit primary brand color"
162
+ },
163
+ // Focus ring uses primary color
164
+ "--color-ring": {
165
+ source: "--color-primary",
166
+ transform: (primary) => primary,
167
+ description: "Focus rings use primary for brand consistency"
168
+ },
169
+ // Link hover is slightly darker primary
170
+ "--color-link-hover": {
171
+ source: "--color-primary",
172
+ transform: (primary) => adjustLightness(primary, -10),
173
+ description: "Link hover is 10% darker for visual feedback"
174
+ },
175
+ // Chart primary series
176
+ "--chart-1": {
177
+ source: "--color-primary",
178
+ transform: (primary) => primary,
179
+ description: "First chart series uses primary"
180
+ },
181
+ // Chart secondary series (lighter tint)
182
+ "--chart-2": {
183
+ source: "--color-primary",
184
+ transform: (primary) => adjustLightness(primary, 20),
185
+ description: "Second chart series is lighter tint of primary"
186
+ },
187
+ // Chart tertiary series (darker shade)
188
+ "--chart-3": {
189
+ source: "--color-primary",
190
+ transform: (primary) => adjustLightness(primary, -15),
191
+ description: "Third chart series is darker shade of primary"
192
+ },
193
+ // Chart quaternary (desaturated primary)
194
+ "--chart-4": {
195
+ source: "--color-primary",
196
+ transform: (primary) => adjustSaturation(primary, -30),
197
+ description: "Fourth chart series is muted primary"
198
+ },
199
+ // Chart quinary (complementary color)
200
+ "--chart-5": {
201
+ source: "--color-primary",
202
+ transform: (primary) => rotateHue(primary, 180),
203
+ description: "Fifth chart series is complementary to primary"
204
+ }
205
+ };
206
+ var secondaryColorDerivations = {
207
+ // Hover states
208
+ "--color-hover": {
209
+ source: "--color-secondary",
210
+ transform: (secondary) => secondary,
211
+ description: "Hover backgrounds use secondary"
212
+ },
213
+ // Active states
214
+ "--color-active": {
215
+ source: "--color-secondary",
216
+ transform: (secondary) => adjustLightness(secondary, -5),
217
+ description: "Active state is slightly darker secondary"
218
+ },
219
+ // Muted backgrounds
220
+ "--color-muted": {
221
+ source: "--color-secondary",
222
+ transform: (secondary) => secondary,
223
+ description: "Muted sections use secondary color"
224
+ }
225
+ };
226
+ var accentColorDerivations = {
227
+ // Info semantic color uses accent
228
+ "--color-info": {
229
+ source: "--color-accent",
230
+ transform: (accent) => accent,
231
+ description: "Info semantic color uses accent"
232
+ },
233
+ // Info foreground calculated for contrast
234
+ "--color-info-foreground": {
235
+ source: "--color-accent",
236
+ transform: (accent) => getOptimalForeground(accent),
237
+ description: "Info foreground calculated for contrast"
238
+ }
239
+ };
240
+ var modeSpecificDerivations = {
241
+ "--color-primary-muted": {
242
+ light: {
243
+ source: "--color-primary",
244
+ transform: (primary) => adjustLightness(primary, 40),
245
+ description: "Muted primary for light backgrounds"
246
+ },
247
+ dark: {
248
+ source: "--color-primary",
249
+ transform: (primary) => adjustLightness(primary, -20),
250
+ description: "Muted primary for dark backgrounds"
251
+ }
252
+ },
253
+ "--color-primary-subtle": {
254
+ light: {
255
+ source: "--color-primary",
256
+ transform: (primary) => adjustOpacity(primary, 0.1),
257
+ description: "Subtle primary background for light mode"
258
+ },
259
+ dark: {
260
+ source: "--color-primary",
261
+ transform: (primary) => adjustOpacity(primary, 0.2),
262
+ description: "Subtle primary background for dark mode"
263
+ }
264
+ }
265
+ };
266
+ function computeDerivedTokens(sourceToken, sourceValue, mode) {
267
+ const derived = {};
268
+ Object.entries(primaryColorDerivations).forEach(([token, config]) => {
269
+ if (config.source === sourceToken) {
270
+ derived[token] = config.transform(sourceValue);
271
+ }
272
+ });
273
+ Object.entries(secondaryColorDerivations).forEach(([token, config]) => {
274
+ if (config.source === sourceToken) {
275
+ derived[token] = config.transform(sourceValue);
276
+ }
277
+ });
278
+ Object.entries(accentColorDerivations).forEach(([token, config]) => {
279
+ if (config.source === sourceToken) {
280
+ derived[token] = config.transform(sourceValue);
281
+ }
282
+ });
283
+ Object.entries(modeSpecificDerivations).forEach(([token, configs]) => {
284
+ const config = configs[mode];
285
+ if (config.source === sourceToken) {
286
+ derived[token] = config.transform(sourceValue);
287
+ }
288
+ });
289
+ return derived;
290
+ }
291
+
292
+ // src/lib/colors.ts
293
+ var colorTokens = {
294
+ // Background colors
295
+ background: "var(--color-background)",
296
+ backgroundSecondary: "var(--color-background-secondary)",
297
+ backgroundTertiary: "var(--color-background-tertiary)",
298
+ surface: "var(--color-surface)",
299
+ // Foreground/Text colors
300
+ foreground: "var(--color-foreground)",
301
+ foregroundSecondary: "var(--color-foreground-secondary)",
302
+ foregroundTertiary: "var(--color-foreground-tertiary)",
303
+ textPrimary: "var(--color-text-primary)",
304
+ textSecondary: "var(--color-text-secondary)",
305
+ textMuted: "var(--color-text-muted)",
306
+ // Brand colors
307
+ primary: "var(--color-primary)",
308
+ primaryForeground: "var(--color-primary-foreground)",
309
+ secondary: "var(--color-secondary)",
310
+ secondaryForeground: "var(--color-secondary-foreground)",
311
+ accent: "var(--color-accent)",
312
+ accentForeground: "var(--color-accent-foreground)",
313
+ // Semantic colors
314
+ success: "var(--color-success)",
315
+ successForeground: "var(--color-success-foreground)",
316
+ warning: "var(--color-warning)",
317
+ warningForeground: "var(--color-warning-foreground)",
318
+ error: "var(--color-error)",
319
+ errorForeground: "var(--color-error-foreground)",
320
+ info: "var(--color-info)",
321
+ infoForeground: "var(--color-info-foreground)",
322
+ // Borders
323
+ border: "var(--color-border)",
324
+ borderSubtle: "var(--color-border-subtle)",
325
+ // Interactive states
326
+ hover: "var(--color-hover)",
327
+ active: "var(--color-active)",
328
+ focus: "var(--color-focus)",
329
+ // Links
330
+ link: "var(--color-link)",
331
+ linkHover: "var(--color-link-hover)",
332
+ linkHoverForeground: "var(--color-link-hover-foreground)"
333
+ };
334
+ var semanticColors = {
335
+ /**
336
+ * Status colors for indicating states
337
+ */
338
+ status: {
339
+ success: {
340
+ bg: colorTokens.success,
341
+ fg: colorTokens.successForeground
342
+ },
343
+ warning: {
344
+ bg: colorTokens.warning,
345
+ fg: colorTokens.warningForeground
346
+ },
347
+ error: {
348
+ bg: colorTokens.error,
349
+ fg: colorTokens.errorForeground
350
+ },
351
+ info: {
352
+ bg: colorTokens.info,
353
+ fg: colorTokens.infoForeground
354
+ }
355
+ },
356
+ /**
357
+ * Brand colors for primary UI elements
358
+ */
359
+ brand: {
360
+ primary: {
361
+ bg: colorTokens.primary,
362
+ fg: colorTokens.primaryForeground
363
+ },
364
+ secondary: {
365
+ bg: colorTokens.secondary,
366
+ fg: colorTokens.secondaryForeground
367
+ },
368
+ accent: {
369
+ bg: colorTokens.accent,
370
+ fg: colorTokens.accentForeground
371
+ }
372
+ },
373
+ /**
374
+ * Interactive state colors
375
+ */
376
+ interactive: {
377
+ default: {
378
+ bg: colorTokens.background,
379
+ fg: colorTokens.foreground
380
+ },
381
+ hover: {
382
+ bg: colorTokens.hover,
383
+ fg: colorTokens.foreground
384
+ },
385
+ active: {
386
+ bg: colorTokens.active,
387
+ fg: colorTokens.foreground
388
+ },
389
+ focus: {
390
+ border: colorTokens.focus
391
+ }
392
+ }
393
+ };
394
+ function hexToRgb2(hex) {
395
+ const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
396
+ return result ? {
397
+ r: parseInt(result[1], 16),
398
+ g: parseInt(result[2], 16),
399
+ b: parseInt(result[3], 16)
400
+ } : null;
401
+ }
402
+ function getLuminance2(r, g, b) {
403
+ const [rs, gs, bs] = [r, g, b].map((c) => {
404
+ const srgb = c / 255;
405
+ return srgb <= 0.03928 ? srgb / 12.92 : Math.pow((srgb + 0.055) / 1.055, 2.4);
406
+ });
407
+ return 0.2126 * rs + 0.7152 * gs + 0.0722 * bs;
408
+ }
409
+ function getContrastRatio2(hex1, hex2) {
410
+ const rgb1 = hexToRgb2(hex1);
411
+ const rgb2 = hexToRgb2(hex2);
412
+ if (!rgb1 || !rgb2) return 0;
413
+ const lum1 = getLuminance2(rgb1.r, rgb1.g, rgb1.b);
414
+ const lum2 = getLuminance2(rgb2.r, rgb2.g, rgb2.b);
415
+ const lighter = Math.max(lum1, lum2);
416
+ const darker = Math.min(lum1, lum2);
417
+ return (lighter + 0.05) / (darker + 0.05);
418
+ }
419
+ function hexToHSL2(hex) {
420
+ const rgb = hexToRgb2(hex);
421
+ if (!rgb) return { h: 0, s: 0, l: 0 };
422
+ const r = rgb.r / 255;
423
+ const g = rgb.g / 255;
424
+ const b = rgb.b / 255;
425
+ const max = Math.max(r, g, b);
426
+ const min = Math.min(r, g, b);
427
+ let h = 0, s = 0;
428
+ const l = (max + min) / 2;
429
+ if (max !== min) {
430
+ const d = max - min;
431
+ s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
432
+ switch (max) {
433
+ case r:
434
+ h = ((g - b) / d + (g < b ? 6 : 0)) / 6;
435
+ break;
436
+ case g:
437
+ h = ((b - r) / d + 2) / 6;
438
+ break;
439
+ case b:
440
+ h = ((r - g) / d + 4) / 6;
441
+ break;
442
+ }
443
+ }
444
+ return {
445
+ h: Math.round(h * 360),
446
+ s: Math.round(s * 100),
447
+ l: Math.round(l * 100)
448
+ };
449
+ }
450
+ function hslToHex2(h, s, l) {
451
+ h = h / 360;
452
+ s = s / 100;
453
+ l = l / 100;
454
+ let r, g, b;
455
+ if (s === 0) {
456
+ r = g = b = l;
457
+ } else {
458
+ const hue2rgb = (p2, q2, t) => {
459
+ if (t < 0) t += 1;
460
+ if (t > 1) t -= 1;
461
+ if (t < 1 / 6) return p2 + (q2 - p2) * 6 * t;
462
+ if (t < 1 / 2) return q2;
463
+ if (t < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - t) * 6;
464
+ return p2;
465
+ };
466
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
467
+ const p = 2 * l - q;
468
+ r = hue2rgb(p, q, h + 1 / 3);
469
+ g = hue2rgb(p, q, h);
470
+ b = hue2rgb(p, q, h - 1 / 3);
471
+ }
472
+ const toHex = (x) => {
473
+ const hex = Math.round(x * 255).toString(16);
474
+ return hex.length === 1 ? "0" + hex : hex;
475
+ };
476
+ return `#${toHex(r)}${toHex(g)}${toHex(b)}`;
477
+ }
478
+ function getOptimalForeground2(bgHex, whiteHex = "#ffffff", blackHex = "#000000") {
479
+ const whiteRatio = getContrastRatio2(bgHex, whiteHex);
480
+ const blackRatio = getContrastRatio2(bgHex, blackHex);
481
+ return whiteRatio > blackRatio ? whiteHex : blackHex;
482
+ }
483
+ function generateColorScale(baseHex) {
484
+ const hsl = hexToHSL2(baseHex);
485
+ return {
486
+ 50: hslToHex2(hsl.h, Math.max(hsl.s - 10, 20), 95),
487
+ 100: hslToHex2(hsl.h, Math.max(hsl.s - 5, 30), 90),
488
+ 200: hslToHex2(hsl.h, hsl.s, 80),
489
+ 300: hslToHex2(hsl.h, hsl.s, 70),
490
+ 400: hslToHex2(hsl.h, hsl.s, 60),
491
+ 500: baseHex,
492
+ // Base color
493
+ 600: hslToHex2(hsl.h, Math.min(hsl.s + 5, 100), 45),
494
+ 700: hslToHex2(hsl.h, Math.min(hsl.s + 10, 100), 35),
495
+ 800: hslToHex2(hsl.h, Math.min(hsl.s + 15, 100), 25),
496
+ 900: hslToHex2(hsl.h, Math.min(hsl.s + 20, 100), 15)
497
+ };
498
+ }
499
+
500
+ // src/lib/store/customizer.ts
501
+ var useCustomizer = create2()(
502
+ persist2(
503
+ (set, get) => ({
504
+ motion: 5,
505
+ prefersReducedMotion: false,
506
+ customizationMode: "simple",
507
+ customColors: {},
508
+ savedPalettes: [],
509
+ customFontThemes: {},
510
+ savedFontThemes: [],
511
+ setMotion: (level) => set({ motion: level }),
512
+ setPrefersReducedMotion: (value) => set({ prefersReducedMotion: value }),
513
+ setCustomizationMode: (mode) => set({ customizationMode: mode }),
514
+ setCustomPrimaryColor: (theme, mode, hexColor) => {
515
+ const state = get();
516
+ const currentPalette = state.customColors[theme]?.[mode];
517
+ const scale = generateColorScale(hexColor);
518
+ const primaryForeground = getOptimalForeground2(hexColor);
519
+ const derivedTokens = computeDerivedTokens("--color-primary", hexColor, mode);
520
+ const isSimple = state.customizationMode === "simple";
521
+ const palette = {
522
+ primary: hexColor,
523
+ primaryForeground,
524
+ secondary: isSimple ? void 0 : currentPalette?.secondary,
525
+ secondaryForeground: isSimple ? void 0 : currentPalette?.secondaryForeground,
526
+ accent: isSimple ? void 0 : currentPalette?.accent,
527
+ accentForeground: isSimple ? void 0 : currentPalette?.accentForeground,
528
+ scale,
529
+ derivedTokens
530
+ };
531
+ set((state2) => ({
532
+ customColors: {
533
+ ...state2.customColors,
534
+ [theme]: {
535
+ ...state2.customColors[theme],
536
+ [mode]: palette
537
+ }
538
+ }
539
+ }));
540
+ },
541
+ setCustomSecondaryColor: (theme, mode, hexColor) => {
542
+ const state = get();
543
+ const currentPalette = state.customColors[theme]?.[mode];
544
+ if (!currentPalette) return;
545
+ const secondaryForeground = getOptimalForeground2(hexColor);
546
+ const derivedTokens = computeDerivedTokens("--color-secondary", hexColor, mode);
547
+ set((state2) => ({
548
+ customColors: {
549
+ ...state2.customColors,
550
+ [theme]: {
551
+ ...state2.customColors[theme],
552
+ [mode]: {
553
+ ...currentPalette,
554
+ secondary: hexColor,
555
+ secondaryForeground,
556
+ derivedTokens: {
557
+ ...currentPalette.derivedTokens,
558
+ ...derivedTokens
559
+ }
560
+ }
561
+ }
562
+ }
563
+ }));
564
+ },
565
+ setCustomAccentColor: (theme, mode, hexColor) => {
566
+ const state = get();
567
+ const currentPalette = state.customColors[theme]?.[mode];
568
+ if (!currentPalette) return;
569
+ const accentForeground = getOptimalForeground2(hexColor);
570
+ const derivedTokens = computeDerivedTokens("--color-accent", hexColor, mode);
571
+ set((state2) => ({
572
+ customColors: {
573
+ ...state2.customColors,
574
+ [theme]: {
575
+ ...state2.customColors[theme],
576
+ [mode]: {
577
+ ...currentPalette,
578
+ accent: hexColor,
579
+ accentForeground,
580
+ derivedTokens: {
581
+ ...currentPalette.derivedTokens,
582
+ ...derivedTokens
583
+ }
584
+ }
585
+ }
586
+ }
587
+ }));
588
+ },
589
+ applyColorPalette: (theme, mode, colors) => {
590
+ const scale = generateColorScale(colors.primary);
591
+ const primaryForeground = getOptimalForeground2(colors.primary);
592
+ let derivedTokens = computeDerivedTokens("--color-primary", colors.primary, mode);
593
+ const secondary = colors.secondary;
594
+ const secondaryForeground = secondary ? getOptimalForeground2(secondary) : void 0;
595
+ if (secondary) {
596
+ const secondaryDerived = computeDerivedTokens("--color-secondary", secondary, mode);
597
+ derivedTokens = { ...derivedTokens, ...secondaryDerived };
598
+ }
599
+ const accent = colors.accent;
600
+ const accentForeground = accent ? getOptimalForeground2(accent) : void 0;
601
+ if (accent) {
602
+ const accentDerived = computeDerivedTokens("--color-accent", accent, mode);
603
+ derivedTokens = { ...derivedTokens, ...accentDerived };
604
+ }
605
+ const palette = {
606
+ name: colors.name,
607
+ description: colors.description,
608
+ primary: colors.primary,
609
+ primaryForeground,
610
+ secondary,
611
+ secondaryForeground,
612
+ accent,
613
+ accentForeground,
614
+ scale,
615
+ derivedTokens
616
+ };
617
+ set((state) => ({
618
+ customColors: {
619
+ ...state.customColors,
620
+ [theme]: {
621
+ ...state.customColors[theme],
622
+ [mode]: palette
623
+ }
624
+ }
625
+ }));
626
+ },
627
+ resetCustomColors: (theme, mode) => {
628
+ if (mode) {
629
+ set((state) => ({
630
+ customColors: {
631
+ ...state.customColors,
632
+ [theme]: {
633
+ ...state.customColors[theme],
634
+ [mode]: void 0
635
+ }
636
+ }
637
+ }));
638
+ } else {
639
+ set((state) => {
640
+ const { [theme]: _, ...rest } = state.customColors;
641
+ return { customColors: rest };
642
+ });
643
+ }
644
+ },
645
+ getActiveColorPalette: (theme, mode) => {
646
+ return get().customColors[theme]?.[mode] || null;
647
+ },
648
+ // Saved palette management
649
+ savePalette: (paletteData) => {
650
+ const id = `custom-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
651
+ const newPalette = {
652
+ ...paletteData,
653
+ id,
654
+ category: "custom",
655
+ createdAt: Date.now()
656
+ };
657
+ set((state) => ({
658
+ savedPalettes: [...state.savedPalettes, newPalette]
659
+ }));
660
+ },
661
+ updatePalette: (id, updates) => {
662
+ set((state) => ({
663
+ savedPalettes: state.savedPalettes.map(
664
+ (p) => p.id === id ? { ...p, ...updates } : p
665
+ )
666
+ }));
667
+ },
668
+ renamePalette: (id, newName) => {
669
+ set((state) => ({
670
+ savedPalettes: state.savedPalettes.map(
671
+ (p) => p.id === id ? { ...p, name: newName } : p
672
+ )
673
+ }));
674
+ },
675
+ deletePalette: (id) => {
676
+ set((state) => ({
677
+ savedPalettes: state.savedPalettes.filter((p) => p.id !== id)
678
+ }));
679
+ },
680
+ reorderPalettes: (palettes) => {
681
+ set({ savedPalettes: palettes });
682
+ },
683
+ getSavedPalettes: () => {
684
+ return get().savedPalettes;
685
+ },
686
+ // Font theme management
687
+ applyFontTheme: (theme, mode, fontTheme) => {
688
+ set((state) => ({
689
+ customFontThemes: {
690
+ ...state.customFontThemes,
691
+ [theme]: {
692
+ ...state.customFontThemes[theme],
693
+ [mode]: fontTheme
694
+ }
695
+ }
696
+ }));
697
+ },
698
+ resetCustomFonts: (theme, mode) => {
699
+ if (mode) {
700
+ set((state) => ({
701
+ customFontThemes: {
702
+ ...state.customFontThemes,
703
+ [theme]: {
704
+ ...state.customFontThemes[theme],
705
+ [mode]: void 0
706
+ }
707
+ }
708
+ }));
709
+ } else {
710
+ set((state) => {
711
+ const { [theme]: _, ...rest } = state.customFontThemes;
712
+ return { customFontThemes: rest };
713
+ });
714
+ }
715
+ },
716
+ getActiveFontTheme: (theme, mode) => {
717
+ return get().customFontThemes[theme]?.[mode] || null;
718
+ },
719
+ // Saved font theme management
720
+ saveFontTheme: (fontThemeData) => {
721
+ const id = `font-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
722
+ const newFontTheme = {
723
+ ...fontThemeData,
724
+ id,
725
+ category: "custom",
726
+ createdAt: Date.now(),
727
+ isCustom: true
728
+ };
729
+ set((state) => ({
730
+ savedFontThemes: [...state.savedFontThemes, newFontTheme]
731
+ }));
732
+ },
733
+ updateFontTheme: (id, updates) => {
734
+ set((state) => ({
735
+ savedFontThemes: state.savedFontThemes.map(
736
+ (ft) => ft.id === id ? { ...ft, ...updates } : ft
737
+ )
738
+ }));
739
+ },
740
+ renameFontTheme: (id, newName) => {
741
+ set((state) => ({
742
+ savedFontThemes: state.savedFontThemes.map(
743
+ (ft) => ft.id === id ? { ...ft, name: newName } : ft
744
+ )
745
+ }));
746
+ },
747
+ deleteFontTheme: (id) => {
748
+ set((state) => ({
749
+ savedFontThemes: state.savedFontThemes.filter((ft) => ft.id !== id)
750
+ }));
751
+ },
752
+ reorderFontThemes: (fontThemes) => {
753
+ set({ savedFontThemes: fontThemes });
754
+ },
755
+ getSavedFontThemes: () => {
756
+ return get().savedFontThemes;
757
+ }
758
+ }),
759
+ {
760
+ name: "ecosystem-customizer",
761
+ version: 4,
762
+ partialize: (state) => ({
763
+ motion: state.motion,
764
+ prefersReducedMotion: state.prefersReducedMotion,
765
+ customizationMode: state.customizationMode,
766
+ customColors: state.customColors,
767
+ savedPalettes: state.savedPalettes,
768
+ customFontThemes: state.customFontThemes,
769
+ savedFontThemes: state.savedFontThemes
770
+ })
771
+ }
772
+ )
773
+ );
774
+
775
+ // src/hooks/useMotionPreference.ts
776
+ function useMotionPreference() {
777
+ const { motion, prefersReducedMotion, setPrefersReducedMotion } = useCustomizer();
778
+ useEffect(() => {
779
+ if (typeof window === "undefined") return;
780
+ const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
781
+ setPrefersReducedMotion(mediaQuery.matches);
782
+ const handleChange = (e) => {
783
+ setPrefersReducedMotion(e.matches);
784
+ };
785
+ mediaQuery.addEventListener("change", handleChange);
786
+ return () => mediaQuery.removeEventListener("change", handleChange);
787
+ }, [setPrefersReducedMotion]);
788
+ return {
789
+ scale: motion,
790
+ shouldAnimate: motion > 0 && !prefersReducedMotion,
791
+ prefersReducedMotion
792
+ };
793
+ }
794
+
795
+ // src/hooks/useForm.ts
796
+ import { useState, useCallback } from "react";
797
+
798
+ // src/lib/validation.ts
799
+ function validateField(value, rules) {
800
+ if (rules.required) {
801
+ const isEmpty = value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0;
802
+ if (isEmpty) {
803
+ return typeof rules.required === "string" ? rules.required : "This field is required";
804
+ }
805
+ }
806
+ if (!value && !rules.required) {
807
+ return void 0;
808
+ }
809
+ if (rules.minLength && value.length < rules.minLength.value) {
810
+ return rules.minLength.message;
811
+ }
812
+ if (rules.maxLength && value.length > rules.maxLength.value) {
813
+ return rules.maxLength.message;
814
+ }
815
+ if (rules.pattern && !rules.pattern.value.test(value)) {
816
+ return rules.pattern.message;
817
+ }
818
+ if (rules.custom) {
819
+ for (const rule of rules.custom) {
820
+ if (!rule.validate(value)) {
821
+ return rule.message;
822
+ }
823
+ }
824
+ }
825
+ return void 0;
826
+ }
827
+ function validateForm(values, validations) {
828
+ const errors = {};
829
+ for (const [field, rules] of Object.entries(validations)) {
830
+ const error = validateField(values[field], rules);
831
+ if (error) {
832
+ errors[field] = error;
833
+ }
834
+ }
835
+ return errors;
836
+ }
837
+
838
+ // src/hooks/useForm.ts
839
+ function useForm({
840
+ initialValues,
841
+ validations = {},
842
+ onSubmit,
843
+ validateOn = "onBlur"
844
+ }) {
845
+ const [values, setValues] = useState(initialValues);
846
+ const [errors, setErrors] = useState({});
847
+ const [isSubmitting, setIsSubmitting] = useState(false);
848
+ const [isDirty, setIsDirty] = useState(false);
849
+ const setValue = useCallback((name, value) => {
850
+ setValues((prev) => ({ ...prev, [name]: value }));
851
+ setIsDirty(true);
852
+ }, []);
853
+ const setError = useCallback((name, error) => {
854
+ setErrors((prev) => ({ ...prev, [name]: error }));
855
+ }, []);
856
+ const validateFieldByName = useCallback(
857
+ (name) => {
858
+ const fieldRules = validations[name];
859
+ if (!fieldRules) return;
860
+ const error = validateField(values[name], fieldRules);
861
+ setError(name, error);
862
+ return !error;
863
+ },
864
+ [values, validations, setError]
865
+ );
866
+ const handleChange = useCallback(
867
+ (e) => {
868
+ const { name, value, type } = e.target;
869
+ const fieldValue = type === "checkbox" ? e.target.checked : value;
870
+ setValue(name, fieldValue);
871
+ if (validateOn === "onChange") {
872
+ validateFieldByName(name);
873
+ }
874
+ },
875
+ [setValue, validateOn, validateFieldByName]
876
+ );
877
+ const handleBlur = useCallback(
878
+ (e) => {
879
+ const { name } = e.target;
880
+ if (validateOn === "onBlur") {
881
+ validateFieldByName(name);
882
+ }
883
+ },
884
+ [validateOn, validateFieldByName]
885
+ );
886
+ const validate = useCallback(() => {
887
+ const formErrors = validateForm(values, validations);
888
+ setErrors(formErrors);
889
+ return Object.keys(formErrors).length === 0;
890
+ }, [values, validations]);
891
+ const handleSubmit = useCallback(
892
+ async (e) => {
893
+ e?.preventDefault();
894
+ const isValid = validate();
895
+ if (!isValid) return;
896
+ if (onSubmit) {
897
+ setIsSubmitting(true);
898
+ try {
899
+ await onSubmit(values);
900
+ } finally {
901
+ setIsSubmitting(false);
902
+ }
903
+ }
904
+ },
905
+ [validate, onSubmit, values]
906
+ );
907
+ const reset = useCallback(() => {
908
+ setValues(initialValues);
909
+ setErrors({});
910
+ setIsDirty(false);
911
+ setIsSubmitting(false);
912
+ }, [initialValues]);
913
+ const getFieldProps = useCallback(
914
+ (name) => ({
915
+ name,
916
+ value: values[name] ?? "",
917
+ onChange: handleChange,
918
+ onBlur: handleBlur,
919
+ error: !!errors[name]
920
+ }),
921
+ [values, errors, handleChange, handleBlur]
922
+ );
923
+ return {
924
+ values,
925
+ errors,
926
+ isSubmitting,
927
+ isDirty,
928
+ setValue,
929
+ setError,
930
+ handleChange,
931
+ handleBlur,
932
+ handleSubmit,
933
+ reset,
934
+ validate,
935
+ getFieldProps
936
+ };
937
+ }
938
+ export {
939
+ useForm,
940
+ useMotionPreference,
941
+ useTheme
942
+ };
943
+ //# sourceMappingURL=hooks.mjs.map