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