@alepha/ui 0.12.0 → 0.12.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 (164) hide show
  1. package/README.md +2 -30
  2. package/dist/admin/AdminFiles-BM6_7_5A.cjs +4 -0
  3. package/dist/admin/AdminFiles-BaCIMeNt.js +4 -0
  4. package/dist/admin/AdminFiles-CllAxb1B.js +117 -0
  5. package/dist/admin/AdminFiles-CllAxb1B.js.map +1 -0
  6. package/dist/admin/AdminFiles-DC3T8uWZ.cjs +122 -0
  7. package/dist/admin/AdminFiles-DC3T8uWZ.cjs.map +1 -0
  8. package/dist/admin/AdminJobs-BXkFtlVo.js +125 -0
  9. package/dist/admin/AdminJobs-BXkFtlVo.js.map +1 -0
  10. package/dist/admin/AdminJobs-C428qrNQ.cjs +130 -0
  11. package/dist/admin/AdminJobs-C428qrNQ.cjs.map +1 -0
  12. package/dist/admin/AdminJobs-DCPPaJ4i.cjs +4 -0
  13. package/dist/admin/AdminJobs-yC6DarGO.js +4 -0
  14. package/dist/admin/AdminLayout-Bqo4cd33.cjs +4 -0
  15. package/dist/admin/AdminLayout-CQpxfko6.js +4 -0
  16. package/dist/admin/AdminLayout-CiLlywAQ.cjs +93 -0
  17. package/dist/admin/AdminLayout-CiLlywAQ.cjs.map +1 -0
  18. package/dist/admin/AdminLayout-CtkVYk-u.js +88 -0
  19. package/dist/admin/AdminLayout-CtkVYk-u.js.map +1 -0
  20. package/dist/admin/AdminNotifications-DNUeJ-PW.cjs +44 -0
  21. package/dist/admin/AdminNotifications-DNUeJ-PW.cjs.map +1 -0
  22. package/dist/admin/AdminNotifications-DaMu1AQ4.js +4 -0
  23. package/dist/admin/AdminNotifications-DnnulNNV.js +40 -0
  24. package/dist/admin/AdminNotifications-DnnulNNV.js.map +1 -0
  25. package/dist/admin/AdminNotifications-ihgbKVCx.cjs +4 -0
  26. package/dist/admin/AdminParameters-B3hvpLpu.js +40 -0
  27. package/dist/admin/AdminParameters-B3hvpLpu.js.map +1 -0
  28. package/dist/admin/AdminParameters-U4lU1rUF.cjs +4 -0
  29. package/dist/admin/AdminParameters-gdf7036N.cjs +44 -0
  30. package/dist/admin/AdminParameters-gdf7036N.cjs.map +1 -0
  31. package/dist/admin/AdminParameters-prMcCgxf.js +4 -0
  32. package/dist/admin/AdminSessions-BF_P4lHs.cjs +128 -0
  33. package/dist/admin/AdminSessions-BF_P4lHs.cjs.map +1 -0
  34. package/dist/admin/AdminSessions-CATIU61I.cjs +4 -0
  35. package/dist/admin/AdminSessions-DqOXOpYR.js +4 -0
  36. package/dist/admin/AdminSessions-Pjdz-iZx.js +123 -0
  37. package/dist/admin/AdminSessions-Pjdz-iZx.js.map +1 -0
  38. package/dist/admin/AdminUsers-BgTL-zSY.js +4 -0
  39. package/dist/admin/AdminUsers-C1HsrRxn.js +104 -0
  40. package/dist/admin/AdminUsers-C1HsrRxn.js.map +1 -0
  41. package/dist/admin/AdminUsers-HqvxwNGZ.cjs +4 -0
  42. package/dist/admin/AdminUsers-M2uEQbp5.cjs +109 -0
  43. package/dist/admin/AdminUsers-M2uEQbp5.cjs.map +1 -0
  44. package/dist/admin/AdminVerifications-BVssbtfU.cjs +44 -0
  45. package/dist/admin/AdminVerifications-BVssbtfU.cjs.map +1 -0
  46. package/dist/admin/AdminVerifications-Df6DRgNo.js +4 -0
  47. package/dist/admin/AdminVerifications-DxAtcYUR.cjs +4 -0
  48. package/dist/admin/AdminVerifications-VMpm30mS.js +40 -0
  49. package/dist/admin/AdminVerifications-VMpm30mS.js.map +1 -0
  50. package/dist/admin/core-CzO6aavT.js +2507 -0
  51. package/dist/admin/core-CzO6aavT.js.map +1 -0
  52. package/dist/{index.cjs → admin/core-aFtK4l9I.cjs} +287 -204
  53. package/dist/admin/core-aFtK4l9I.cjs.map +1 -0
  54. package/dist/admin/index.cjs +87 -0
  55. package/dist/admin/index.cjs.map +1 -0
  56. package/dist/admin/index.d.cts +1739 -0
  57. package/dist/admin/index.d.ts +1745 -0
  58. package/dist/admin/index.js +78 -0
  59. package/dist/admin/index.js.map +1 -0
  60. package/dist/auth/IconGoogle-B17BTQyD.cjs +69 -0
  61. package/dist/auth/IconGoogle-B17BTQyD.cjs.map +1 -0
  62. package/dist/auth/IconGoogle-Bfmuv9Rv.js +58 -0
  63. package/dist/auth/IconGoogle-Bfmuv9Rv.js.map +1 -0
  64. package/dist/auth/Login-BTBmbnWl.cjs +181 -0
  65. package/dist/auth/Login-BTBmbnWl.cjs.map +1 -0
  66. package/dist/auth/Login-BcQOtG3v.js +5 -0
  67. package/dist/auth/Login-Btmd70Um.cjs +5 -0
  68. package/dist/auth/Login-JeXFsUf5.js +176 -0
  69. package/dist/auth/Login-JeXFsUf5.js.map +1 -0
  70. package/dist/auth/Register-CPQnvXCZ.js +318 -0
  71. package/dist/auth/Register-CPQnvXCZ.js.map +1 -0
  72. package/dist/auth/Register-CbesZal3.cjs +5 -0
  73. package/dist/auth/Register-DpI_JdyO.js +5 -0
  74. package/dist/auth/Register-HP3rP71B.cjs +323 -0
  75. package/dist/auth/Register-HP3rP71B.cjs.map +1 -0
  76. package/dist/auth/ResetPassword-B-tkzV7g.cjs +248 -0
  77. package/dist/auth/ResetPassword-B-tkzV7g.cjs.map +1 -0
  78. package/dist/auth/ResetPassword-BlK3xEpU.js +4 -0
  79. package/dist/auth/ResetPassword-BzUjGG_-.js +243 -0
  80. package/dist/auth/ResetPassword-BzUjGG_-.js.map +1 -0
  81. package/dist/auth/ResetPassword-W3xjOnWy.cjs +4 -0
  82. package/dist/auth/chunk-DhGyd7sr.js +28 -0
  83. package/dist/auth/core-D1MHij1j.js +1795 -0
  84. package/dist/auth/core-D1MHij1j.js.map +1 -0
  85. package/dist/auth/core-rDZ9d92K.cjs +1824 -0
  86. package/dist/auth/core-rDZ9d92K.cjs.map +1 -0
  87. package/dist/auth/index.cjs +211 -0
  88. package/dist/auth/index.cjs.map +1 -0
  89. package/dist/auth/index.d.cts +6265 -0
  90. package/dist/auth/index.d.ts +6274 -0
  91. package/dist/auth/index.js +206 -0
  92. package/dist/auth/index.js.map +1 -0
  93. package/dist/core/index.cjs +2620 -0
  94. package/dist/core/index.cjs.map +1 -0
  95. package/dist/core/index.d.cts +2737 -0
  96. package/dist/core/index.d.ts +2743 -0
  97. package/dist/{index.js → core/index.js} +298 -126
  98. package/dist/core/index.js.map +1 -0
  99. package/package.json +32 -14
  100. package/src/admin/AdminRouter.ts +58 -0
  101. package/src/admin/components/AdminFiles.tsx +117 -0
  102. package/src/admin/components/AdminJobs.tsx +158 -0
  103. package/src/admin/components/AdminLayout.tsx +114 -0
  104. package/src/admin/components/AdminNotifications.tsx +20 -0
  105. package/src/admin/components/AdminParameters.tsx +24 -0
  106. package/src/admin/components/AdminSessions.tsx +159 -0
  107. package/src/admin/components/AdminUsers.tsx +137 -0
  108. package/src/admin/components/AdminVerifications.tsx +25 -0
  109. package/src/admin/index.ts +29 -0
  110. package/src/auth/AuthI18n.ts +118 -0
  111. package/src/auth/AuthRouter.ts +53 -0
  112. package/src/auth/components/Login.tsx +193 -0
  113. package/src/auth/components/Register.tsx +421 -0
  114. package/src/auth/components/ResetPassword.tsx +259 -0
  115. package/src/auth/components/buttons/UserButton.tsx +118 -0
  116. package/src/auth/components/icons/IconGithub.tsx +21 -0
  117. package/src/auth/components/icons/IconGoogle.tsx +30 -0
  118. package/src/auth/index.ts +27 -0
  119. package/src/{RootRouter.ts → core/RootRouter.ts} +2 -1
  120. package/src/{components → core/components}/buttons/ActionButton.tsx +49 -6
  121. package/src/core/components/buttons/ClipboardButton.tsx +56 -0
  122. package/src/{components → core/components}/buttons/DarkModeButton.tsx +7 -8
  123. package/src/{components → core/components}/buttons/LanguageButton.tsx +2 -2
  124. package/src/{components → core/components}/buttons/OmnibarButton.tsx +1 -1
  125. package/src/{components → core/components}/dialogs/AlertDialog.tsx +1 -1
  126. package/src/{components → core/components}/dialogs/ConfirmDialog.tsx +1 -1
  127. package/src/{components → core/components}/dialogs/PromptDialog.tsx +1 -1
  128. package/src/{components → core/components}/form/Control.tsx +1 -0
  129. package/src/{components → core/components}/layout/AdminShell.tsx +38 -7
  130. package/src/{components → core/components}/layout/AlephaMantineProvider.tsx +12 -8
  131. package/src/{components → core/components}/layout/AppBar.tsx +1 -1
  132. package/src/{components → core/components}/layout/Omnibar.tsx +1 -1
  133. package/src/{components → core/components}/layout/Sidebar.tsx +29 -26
  134. package/src/{components → core/components}/table/DataTable.tsx +1 -1
  135. package/src/{constants → core/constants}/ui.ts +9 -0
  136. package/src/{index.ts → core/index.ts} +3 -0
  137. package/src/{services → core/services}/DialogService.tsx +3 -3
  138. package/src/{services → core/services}/ToastService.tsx +3 -1
  139. package/src/{utils → core/utils}/extractSchemaFields.ts +2 -8
  140. package/src/{utils → core/utils}/icons.tsx +5 -15
  141. package/src/{utils → core/utils}/parseInput.ts +34 -26
  142. package/dist/AlephaMantineProvider-CGpgWDt8.cjs +0 -3
  143. package/dist/AlephaMantineProvider-D8cHYAge.js +0 -152
  144. package/dist/AlephaMantineProvider-D8cHYAge.js.map +0 -1
  145. package/dist/AlephaMantineProvider-DuvZFAuk.cjs +0 -175
  146. package/dist/AlephaMantineProvider-DuvZFAuk.cjs.map +0 -1
  147. package/dist/AlephaMantineProvider-twBqV4IO.js +0 -3
  148. package/dist/index.cjs.map +0 -1
  149. package/dist/index.d.cts +0 -821
  150. package/dist/index.d.cts.map +0 -1
  151. package/dist/index.d.ts +0 -821
  152. package/dist/index.d.ts.map +0 -1
  153. package/dist/index.js.map +0 -1
  154. /package/src/{components → core/components}/buttons/BurgerButton.tsx +0 -0
  155. /package/src/{components → core/components}/buttons/ToggleSidebarButton.tsx +0 -0
  156. /package/src/{components → core/components}/data/JsonViewer.tsx +0 -0
  157. /package/src/{components → core/components}/form/ControlDate.tsx +0 -0
  158. /package/src/{components → core/components}/form/ControlNumber.tsx +0 -0
  159. /package/src/{components → core/components}/form/ControlQueryBuilder.tsx +0 -0
  160. /package/src/{components → core/components}/form/ControlSelect.tsx +0 -0
  161. /package/src/{components → core/components}/form/TypeForm.tsx +0 -0
  162. /package/src/{hooks → core/hooks}/useDialog.ts +0 -0
  163. /package/src/{hooks → core/hooks}/useToast.ts +0 -0
  164. /package/src/{utils → core/utils}/string.ts +0 -0
@@ -0,0 +1,1795 @@
1
+ import { AlephaReactI18n, useI18n } from "@alepha/react/i18n";
2
+ import { AlephaReactForm, FormValidationError, useForm, useFormState } from "@alepha/react/form";
3
+ import { AlephaReactHead } from "@alepha/react/head";
4
+ import { $module, Alepha, TypeBoxError, t } from "alepha";
5
+ import { $page, NestedView, useAction, useActive, useEvents, useInject, useRouter } from "@alepha/react";
6
+ import { ActionIcon, Anchor, Autocomplete, Badge, Box, Button, Collapse, ColorInput, ColorSchemeScript, CopyButton, Divider, FileInput, Flex, Group, Input, MantineProvider, Menu, MultiSelect, NumberInput, PasswordInput, Popover, SegmentedControl, Select, Slider, Stack, Switch, TagsInput, Text, TextInput, Textarea, ThemeIcon, Tooltip } from "@mantine/core";
7
+ import { ModalsProvider, modals } from "@mantine/modals";
8
+ import { Notifications, notifications } from "@mantine/notifications";
9
+ import { NavigationProgress, nprogress } from "@mantine/nprogress";
10
+ import { IconAlertTriangle, IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClock, IconColorPicker, IconCopy, IconFile, IconFilter, IconHash, IconInfoCircle, IconInfoTriangle, IconKey, IconLetterCase, IconLink, IconList, IconMail, IconPalette, IconPhone, IconSearch, IconSelector, IconToggleLeft, IconX } from "@tabler/icons-react";
11
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
12
+ import { Spotlight } from "@mantine/spotlight";
13
+ import { Children, createElement, isValidElement, useEffect, useMemo, useRef, useState } from "react";
14
+ import { DateInput, DateTimePicker, TimeInput } from "@mantine/dates";
15
+ import { parseQueryString } from "alepha/orm";
16
+ import "@mantine/hooks";
17
+ import "alepha/datetime";
18
+
19
+ //#region src/core/services/ToastService.tsx
20
+ var ToastService = class {
21
+ raw = notifications;
22
+ options = { default: {
23
+ radius: "md",
24
+ withBorder: true,
25
+ withCloseButton: true,
26
+ autoClose: 5e3,
27
+ position: "top-center"
28
+ } };
29
+ show(options) {
30
+ notifications.show({
31
+ ...this.options.default,
32
+ ...options
33
+ });
34
+ }
35
+ info(options) {
36
+ if (typeof options === "string") options = { message: options };
37
+ this.show({
38
+ color: "blue",
39
+ icon: /* @__PURE__ */ jsx(IconInfoCircle, { size: 20 }),
40
+ title: "Info",
41
+ message: "Information notification",
42
+ ...options
43
+ });
44
+ }
45
+ success(options) {
46
+ if (typeof options === "string") options = { message: options };
47
+ this.show({
48
+ color: "green",
49
+ icon: /* @__PURE__ */ jsx(IconCheck, { size: 16 }),
50
+ title: "Success",
51
+ message: "Operation completed successfully",
52
+ ...options
53
+ });
54
+ }
55
+ warning(options) {
56
+ if (typeof options === "string") options = { message: options };
57
+ this.show({
58
+ color: "yellow",
59
+ icon: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 20 }),
60
+ title: "Warning",
61
+ message: "Please review this warning",
62
+ ...options
63
+ });
64
+ }
65
+ danger(options) {
66
+ if (typeof options === "string") options = { message: options };
67
+ this.show({
68
+ color: "red",
69
+ icon: /* @__PURE__ */ jsx(IconX, { size: 20 }),
70
+ title: "Error",
71
+ message: "An error occurred",
72
+ ...options
73
+ });
74
+ }
75
+ };
76
+
77
+ //#endregion
78
+ //#region src/core/hooks/useToast.ts
79
+ /**
80
+ * Use this hook to access the Toast Service for showing notifications.
81
+ *
82
+ * @example
83
+ * ```tsx
84
+ * const toast = useToast();
85
+ * toast.success({ message: "Operation completed successfully!" });
86
+ * toast.error({ title: "Error", message: "Something went wrong" });
87
+ * ```
88
+ */
89
+ const useToast = () => {
90
+ return useInject(ToastService);
91
+ };
92
+
93
+ //#endregion
94
+ //#region src/core/components/layout/Omnibar.tsx
95
+ const Omnibar = (props) => {
96
+ const shortcut = props.shortcut ?? "mod+K";
97
+ const searchPlaceholder = props.searchPlaceholder ?? "Search...";
98
+ const nothingFound = props.nothingFound ?? "Nothing found...";
99
+ const router = useRouter();
100
+ return /* @__PURE__ */ jsx(Spotlight, {
101
+ actions: useMemo(() => router.concretePages.map((page) => ({
102
+ id: page.name,
103
+ label: page.label ?? page.name,
104
+ description: page.description,
105
+ onClick: () => router.go(page.name),
106
+ leftSection: page.icon
107
+ })), []),
108
+ shortcut,
109
+ limit: 10,
110
+ searchProps: {
111
+ leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 20 }),
112
+ placeholder: searchPlaceholder
113
+ },
114
+ nothingFound
115
+ });
116
+ };
117
+ var Omnibar_default = Omnibar;
118
+
119
+ //#endregion
120
+ //#region src/core/components/layout/AlephaMantineProvider.tsx
121
+ const AlephaMantineProvider = (props) => {
122
+ const toast = useToast();
123
+ useEvents({
124
+ "react:transition:begin": () => {
125
+ nprogress.start();
126
+ },
127
+ "react:transition:end": () => {
128
+ nprogress.complete();
129
+ },
130
+ "react:action:error": ({ error }) => {
131
+ if (error instanceof FormValidationError) return;
132
+ toast.danger({
133
+ title: error.name || "Error",
134
+ message: error.message ?? "An error occurred while processing your action."
135
+ });
136
+ }
137
+ }, []);
138
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ColorSchemeScript, {
139
+ defaultColorScheme: props.mantine?.defaultColorScheme,
140
+ ...props.colorSchemeScript
141
+ }), /* @__PURE__ */ jsxs(MantineProvider, {
142
+ ...props.mantine,
143
+ theme: { ...props.mantine?.theme },
144
+ children: [
145
+ /* @__PURE__ */ jsx(Notifications, { ...props.notifications }),
146
+ /* @__PURE__ */ jsx(NavigationProgress, { ...props.navigationProgress }),
147
+ /* @__PURE__ */ jsxs(ModalsProvider, {
148
+ ...props.modals,
149
+ children: [/* @__PURE__ */ jsx(Omnibar_default, { ...props.omnibar }), props.children ?? /* @__PURE__ */ jsx(NestedView, {})]
150
+ })
151
+ ]
152
+ })] });
153
+ };
154
+ var AlephaMantineProvider_default = AlephaMantineProvider;
155
+
156
+ //#endregion
157
+ //#region src/core/RootRouter.ts
158
+ var RootRouter = class {
159
+ root = $page({
160
+ path: "/",
161
+ component: AlephaMantineProvider_default
162
+ });
163
+ };
164
+
165
+ //#endregion
166
+ //#region src/core/components/data/JsonViewer.tsx
167
+ const getSizeConfig = (size = "sm") => {
168
+ const configs = {
169
+ xs: {
170
+ text: "xs",
171
+ icon: 12,
172
+ indent: 16,
173
+ gap: 2
174
+ },
175
+ sm: {
176
+ text: "sm",
177
+ icon: 14,
178
+ indent: 20,
179
+ gap: 4
180
+ },
181
+ md: {
182
+ text: "md",
183
+ icon: 16,
184
+ indent: 24,
185
+ gap: 6
186
+ },
187
+ lg: {
188
+ text: "lg",
189
+ icon: 18,
190
+ indent: 28,
191
+ gap: 8
192
+ },
193
+ xl: {
194
+ text: "xl",
195
+ icon: 20,
196
+ indent: 32,
197
+ gap: 10
198
+ }
199
+ };
200
+ return configs[size] || configs.sm;
201
+ };
202
+ const JsonNode = ({ name, value, depth, maxDepth, isLast = false, isArrayItem = false, size = "sm" }) => {
203
+ const [expanded, setExpanded] = useState(depth < 2);
204
+ const sizeConfig = getSizeConfig(size);
205
+ const getValueType = (val) => {
206
+ if (val === null) return "null";
207
+ if (val === void 0) return "undefined";
208
+ if (Array.isArray(val)) return "array";
209
+ return typeof val;
210
+ };
211
+ const valueType = getValueType(value);
212
+ const renderPrimitive = (val) => {
213
+ switch (getValueType(val)) {
214
+ case "string": return /* @__PURE__ */ jsxs(Text, {
215
+ component: "span",
216
+ c: "teal",
217
+ ff: "monospace",
218
+ size: sizeConfig.text,
219
+ style: { whiteSpace: "nowrap" },
220
+ children: [
221
+ "\"",
222
+ val,
223
+ "\""
224
+ ]
225
+ });
226
+ case "number": return /* @__PURE__ */ jsx(Text, {
227
+ component: "span",
228
+ c: "blue",
229
+ ff: "monospace",
230
+ size: sizeConfig.text,
231
+ style: { whiteSpace: "nowrap" },
232
+ children: val
233
+ });
234
+ case "boolean": return /* @__PURE__ */ jsx(Text, {
235
+ component: "span",
236
+ c: "violet",
237
+ ff: "monospace",
238
+ size: sizeConfig.text,
239
+ style: { whiteSpace: "nowrap" },
240
+ children: String(val)
241
+ });
242
+ case "null": return /* @__PURE__ */ jsx(Text, {
243
+ component: "span",
244
+ c: "dimmed",
245
+ ff: "monospace",
246
+ size: sizeConfig.text,
247
+ style: { whiteSpace: "nowrap" },
248
+ children: "null"
249
+ });
250
+ case "undefined": return /* @__PURE__ */ jsx(Text, {
251
+ component: "span",
252
+ c: "dimmed",
253
+ ff: "monospace",
254
+ size: sizeConfig.text,
255
+ style: { whiteSpace: "nowrap" },
256
+ children: "undefined"
257
+ });
258
+ default: return /* @__PURE__ */ jsx(Text, {
259
+ component: "span",
260
+ ff: "monospace",
261
+ size: sizeConfig.text,
262
+ style: { whiteSpace: "nowrap" },
263
+ children: String(val)
264
+ });
265
+ }
266
+ };
267
+ const renderKey = () => {
268
+ if (!name) return null;
269
+ return /* @__PURE__ */ jsxs(Text, {
270
+ component: "span",
271
+ c: "cyan",
272
+ ff: "monospace",
273
+ fw: 500,
274
+ size: sizeConfig.text,
275
+ children: [isArrayItem ? `[${name}]` : `"${name}"`, ":"]
276
+ });
277
+ };
278
+ if (valueType === "object" || valueType === "array") {
279
+ const isObject = valueType === "object";
280
+ const entries = isObject ? Object.entries(value) : value.map((v, i) => [i, v]);
281
+ const isEmpty = entries.length === 0;
282
+ const canExpand = depth < maxDepth && !isEmpty;
283
+ const preview = isObject ? "{...}" : "[...]";
284
+ const brackets = isObject ? ["{", "}"] : ["[", "]"];
285
+ return /* @__PURE__ */ jsxs(Box, { children: [/* @__PURE__ */ jsxs(Box, {
286
+ style: {
287
+ display: "flex",
288
+ alignItems: "center",
289
+ gap: sizeConfig.gap,
290
+ minWidth: "max-content"
291
+ },
292
+ children: [
293
+ canExpand && /* @__PURE__ */ jsx(ActionIcon, {
294
+ size: "xs",
295
+ variant: "transparent",
296
+ c: "dimmed",
297
+ onClick: () => setExpanded(!expanded),
298
+ style: {
299
+ cursor: "pointer",
300
+ flexShrink: 0
301
+ },
302
+ children: expanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: sizeConfig.icon }) : /* @__PURE__ */ jsx(IconChevronRight, { size: sizeConfig.icon })
303
+ }),
304
+ !canExpand && /* @__PURE__ */ jsx(Box, {
305
+ w: sizeConfig.icon + 6,
306
+ style: { flexShrink: 0 }
307
+ }),
308
+ /* @__PURE__ */ jsx(Box, {
309
+ style: { flexShrink: 0 },
310
+ children: renderKey()
311
+ }),
312
+ " ",
313
+ /* @__PURE__ */ jsx(Text, {
314
+ component: "span",
315
+ c: "dimmed",
316
+ ff: "monospace",
317
+ size: sizeConfig.text,
318
+ style: { flexShrink: 0 },
319
+ children: brackets[0]
320
+ }),
321
+ !expanded && !isEmpty && /* @__PURE__ */ jsx(Text, {
322
+ component: "span",
323
+ c: "dimmed",
324
+ ff: "monospace",
325
+ fs: "italic",
326
+ size: sizeConfig.text,
327
+ style: { flexShrink: 0 },
328
+ children: preview
329
+ }),
330
+ (isEmpty || !expanded) && /* @__PURE__ */ jsx(Text, {
331
+ component: "span",
332
+ c: "dimmed",
333
+ ff: "monospace",
334
+ size: sizeConfig.text,
335
+ style: { flexShrink: 0 },
336
+ children: brackets[1]
337
+ }),
338
+ !isEmpty && !expanded && /* @__PURE__ */ jsxs(Text, {
339
+ component: "span",
340
+ c: "dimmed",
341
+ size: sizeConfig.text,
342
+ style: { flexShrink: 0 },
343
+ children: [
344
+ entries.length,
345
+ " ",
346
+ entries.length === 1 ? "item" : "items"
347
+ ]
348
+ })
349
+ ]
350
+ }), /* @__PURE__ */ jsxs(Collapse, {
351
+ in: expanded && canExpand,
352
+ children: [/* @__PURE__ */ jsx(Box, {
353
+ pl: sizeConfig.indent,
354
+ style: {
355
+ borderLeft: "1px solid var(--mantine-color-default-border)",
356
+ marginLeft: Math.floor((sizeConfig.icon + 6) / 2)
357
+ },
358
+ children: entries.map(([key, val], index) => /* @__PURE__ */ jsx(JsonNode, {
359
+ name: String(key),
360
+ value: val,
361
+ depth: depth + 1,
362
+ maxDepth,
363
+ isLast: index === entries.length - 1,
364
+ isArrayItem: !isObject,
365
+ size
366
+ }, String(key)))
367
+ }), /* @__PURE__ */ jsxs(Box, {
368
+ style: {
369
+ display: "flex",
370
+ minWidth: "max-content"
371
+ },
372
+ children: [/* @__PURE__ */ jsx(Box, {
373
+ w: sizeConfig.icon + 6,
374
+ style: { flexShrink: 0 }
375
+ }), /* @__PURE__ */ jsx(Text, {
376
+ c: "dimmed",
377
+ ff: "monospace",
378
+ size: sizeConfig.text,
379
+ style: { flexShrink: 0 },
380
+ children: brackets[1]
381
+ })]
382
+ })]
383
+ })] });
384
+ }
385
+ return /* @__PURE__ */ jsxs(Box, {
386
+ style: {
387
+ display: "flex",
388
+ alignItems: "center",
389
+ gap: sizeConfig.gap,
390
+ minWidth: "max-content"
391
+ },
392
+ children: [
393
+ /* @__PURE__ */ jsx(Box, {
394
+ w: sizeConfig.icon + 6,
395
+ style: { flexShrink: 0 }
396
+ }),
397
+ /* @__PURE__ */ jsx(Box, {
398
+ style: { flexShrink: 0 },
399
+ children: renderKey()
400
+ }),
401
+ /* @__PURE__ */ jsx(Box, {
402
+ style: { flexShrink: 0 },
403
+ children: renderPrimitive(value)
404
+ }),
405
+ !isLast && /* @__PURE__ */ jsx(Text, {
406
+ component: "span",
407
+ c: "dimmed",
408
+ ff: "monospace",
409
+ size: sizeConfig.text,
410
+ style: { flexShrink: 0 },
411
+ children: ","
412
+ })
413
+ ]
414
+ });
415
+ };
416
+ const JsonViewer = ({ data, defaultExpanded = true, maxDepth = 10, copyable = true, size = "sm" }) => {
417
+ const copyIconSize = getSizeConfig(size).icon + 2;
418
+ return /* @__PURE__ */ jsxs(Box, {
419
+ pos: "relative",
420
+ w: "100%",
421
+ children: [copyable && /* @__PURE__ */ jsx(Box, {
422
+ pos: "absolute",
423
+ top: 0,
424
+ right: 0,
425
+ style: { zIndex: 1 },
426
+ children: /* @__PURE__ */ jsx(CopyButton, {
427
+ value: JSON.stringify(data, null, 2),
428
+ children: ({ copied, copy }) => /* @__PURE__ */ jsx(Tooltip, {
429
+ label: copied ? "Copied" : "Copy JSON",
430
+ children: /* @__PURE__ */ jsx(ActionIcon, {
431
+ color: copied ? "teal" : "gray",
432
+ variant: "subtle",
433
+ onClick: copy,
434
+ size,
435
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: copyIconSize }) : /* @__PURE__ */ jsx(IconCopy, { size: copyIconSize })
436
+ })
437
+ })
438
+ })
439
+ }), /* @__PURE__ */ jsx(Box, {
440
+ pt: copyable ? 30 : 0,
441
+ style: { overflowX: "auto" },
442
+ children: /* @__PURE__ */ jsx(JsonNode, {
443
+ value: data,
444
+ depth: 0,
445
+ maxDepth,
446
+ size
447
+ })
448
+ })]
449
+ });
450
+ };
451
+ var JsonViewer_default = JsonViewer;
452
+
453
+ //#endregion
454
+ //#region src/core/components/dialogs/AlertDialog.tsx
455
+ const AlertDialog = ({ options, onClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text, {
456
+ mb: "md",
457
+ children: options.message
458
+ }), /* @__PURE__ */ jsx(Group, {
459
+ justify: "flex-end",
460
+ children: /* @__PURE__ */ jsx(Button, {
461
+ onClick: onClose,
462
+ children: options?.okLabel || "OK"
463
+ })
464
+ })] });
465
+ var AlertDialog_default = AlertDialog;
466
+
467
+ //#endregion
468
+ //#region src/core/components/dialogs/ConfirmDialog.tsx
469
+ const ConfirmDialog = ({ options, onConfirm }) => /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text, {
470
+ mb: "md",
471
+ children: options.message
472
+ }), /* @__PURE__ */ jsxs(Group, {
473
+ justify: "flex-end",
474
+ children: [/* @__PURE__ */ jsx(Button, {
475
+ variant: "subtle",
476
+ onClick: () => onConfirm(false),
477
+ children: options?.cancelLabel || "Cancel"
478
+ }), /* @__PURE__ */ jsx(Button, {
479
+ color: options?.confirmColor || "blue",
480
+ onClick: () => onConfirm(true),
481
+ children: options?.confirmLabel || "Confirm"
482
+ })]
483
+ })] });
484
+ var ConfirmDialog_default = ConfirmDialog;
485
+
486
+ //#endregion
487
+ //#region src/core/components/dialogs/PromptDialog.tsx
488
+ const PromptDialog = ({ options, onSubmit }) => {
489
+ const [value, setValue] = useState(options?.defaultValue || "");
490
+ const inputRef = useRef(null);
491
+ useEffect(() => {
492
+ inputRef.current?.focus();
493
+ }, []);
494
+ const handleSubmit = () => {
495
+ if (!options?.required || value.trim()) onSubmit(value);
496
+ };
497
+ const handleKeyDown = (event) => {
498
+ if (event.key === "Enter") handleSubmit();
499
+ };
500
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
501
+ options?.message && /* @__PURE__ */ jsx(Text, {
502
+ mb: "md",
503
+ children: options.message
504
+ }),
505
+ /* @__PURE__ */ jsx(TextInput, {
506
+ ref: inputRef,
507
+ label: options?.label,
508
+ placeholder: options?.placeholder,
509
+ value,
510
+ onChange: (event) => setValue(event.currentTarget.value),
511
+ onKeyDown: handleKeyDown,
512
+ required: options?.required,
513
+ mb: "md"
514
+ }),
515
+ /* @__PURE__ */ jsxs(Group, {
516
+ justify: "flex-end",
517
+ children: [/* @__PURE__ */ jsx(Button, {
518
+ variant: "subtle",
519
+ onClick: () => onSubmit(null),
520
+ children: options?.cancelLabel || "Cancel"
521
+ }), /* @__PURE__ */ jsx(Button, {
522
+ onClick: handleSubmit,
523
+ disabled: options?.required && !value.trim(),
524
+ children: options?.submitLabel || "OK"
525
+ })]
526
+ })
527
+ ] });
528
+ };
529
+ var PromptDialog_default = PromptDialog;
530
+
531
+ //#endregion
532
+ //#region src/core/constants/ui.ts
533
+ const ui = {
534
+ colors: {
535
+ transparent: "transparent",
536
+ background: "var(--alepha-background)",
537
+ surface: "var(--alepha-surface)",
538
+ elevated: "var(--alepha-elevated)",
539
+ border: "var(--alepha-border)"
540
+ },
541
+ sizes: { icon: {
542
+ xs: 12,
543
+ sm: 16,
544
+ md: 20,
545
+ lg: 24,
546
+ xl: 32
547
+ } }
548
+ };
549
+
550
+ //#endregion
551
+ //#region src/core/services/DialogService.tsx
552
+ var DialogService = class {
553
+ options = { default: {
554
+ centered: true,
555
+ withCloseButton: true,
556
+ size: "md",
557
+ overlayProps: {
558
+ backgroundOpacity: .55,
559
+ blur: 3
560
+ },
561
+ transitionProps: {
562
+ transition: "pop",
563
+ duration: 200
564
+ }
565
+ } };
566
+ /**
567
+ * Show an alert dialog with a message
568
+ */
569
+ alert(options) {
570
+ return new Promise((resolve) => {
571
+ const modalId = this.open({
572
+ ...options,
573
+ title: options?.title || "Alert",
574
+ content: /* @__PURE__ */ jsx(AlertDialog_default, {
575
+ options,
576
+ onClose: () => {
577
+ this.close(modalId);
578
+ resolve();
579
+ }
580
+ })
581
+ });
582
+ });
583
+ }
584
+ /**
585
+ * Show a confirmation dialog that returns a promise
586
+ */
587
+ confirm(options) {
588
+ return new Promise((resolve) => {
589
+ const modalId = this.open({
590
+ ...options,
591
+ title: options?.title || "Confirm",
592
+ closeOnClickOutside: false,
593
+ closeOnEscape: false,
594
+ content: /* @__PURE__ */ jsx(ConfirmDialog_default, {
595
+ options,
596
+ onConfirm: (confirmed) => {
597
+ this.close(modalId);
598
+ resolve(confirmed);
599
+ }
600
+ })
601
+ });
602
+ });
603
+ }
604
+ /**
605
+ * Show a prompt dialog to get user input
606
+ */
607
+ prompt(options) {
608
+ return new Promise((resolve) => {
609
+ const modalId = this.open({
610
+ ...options,
611
+ title: options?.title || "Input",
612
+ closeOnClickOutside: false,
613
+ closeOnEscape: false,
614
+ content: /* @__PURE__ */ jsx(PromptDialog_default, {
615
+ options,
616
+ onSubmit: (value) => {
617
+ this.close(modalId);
618
+ resolve(value);
619
+ }
620
+ })
621
+ });
622
+ });
623
+ }
624
+ /**
625
+ * Open a custom dialog with provided content
626
+ */
627
+ open(options) {
628
+ return modals.open({
629
+ ...this.options.default,
630
+ ...options,
631
+ children: options?.content || options?.message
632
+ });
633
+ }
634
+ /**
635
+ * Close the currently open dialog or a specific dialog by ID
636
+ */
637
+ close(modalId) {
638
+ if (modalId) modals.close(modalId);
639
+ else modals.closeAll();
640
+ }
641
+ /**
642
+ * Show a JSON editor/viewer dialog
643
+ */
644
+ json(data, options) {
645
+ this.open({
646
+ size: "lg",
647
+ title: options?.title || "Json Viewer",
648
+ ...options,
649
+ content: /* @__PURE__ */ jsx(Flex, {
650
+ bdrs: "md",
651
+ w: "100%",
652
+ flex: 1,
653
+ p: "sm",
654
+ bg: ui.colors.surface,
655
+ children: /* @__PURE__ */ jsx(JsonViewer_default, {
656
+ size: "xs",
657
+ data
658
+ })
659
+ })
660
+ });
661
+ }
662
+ /**
663
+ * Show a form dialog for structured input
664
+ */
665
+ form(options) {
666
+ return Promise.resolve(null);
667
+ }
668
+ /**
669
+ * Show a loading/progress dialog with optional progress percentage
670
+ */
671
+ loading(options) {}
672
+ /**
673
+ * Show an image viewer/gallery dialog
674
+ */
675
+ image(src, options) {}
676
+ };
677
+
678
+ //#endregion
679
+ //#region src/core/components/buttons/ActionButton.tsx
680
+ const ActionMenuItem = (props) => {
681
+ const { item, index } = props;
682
+ const router = useRouter();
683
+ const action = useAction({ handler: async (e) => {
684
+ await item.onClick?.();
685
+ } }, [item.onClick]);
686
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
687
+ if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
688
+ if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
689
+ trigger: "hover",
690
+ position: "right-start",
691
+ offset: 2,
692
+ children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
693
+ leftSection: item.icon,
694
+ rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
695
+ children: item.label
696
+ }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
697
+ item: child,
698
+ index: childIndex
699
+ }, childIndex)) })]
700
+ }, index);
701
+ const menuItemProps = {};
702
+ if (props.item.onClick) menuItemProps.onClick = action.run;
703
+ else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
704
+ return /* @__PURE__ */ jsx(Menu.Item, {
705
+ leftSection: item.icon,
706
+ onClick: item.onClick,
707
+ color: item.color,
708
+ rightSection: item.active ? /* @__PURE__ */ jsx(ThemeIcon, {
709
+ size: "xs",
710
+ variant: "transparent",
711
+ children: /* @__PURE__ */ jsx(IconCheck, {})
712
+ }) : void 0,
713
+ ...menuItemProps,
714
+ children: item.label
715
+ }, index);
716
+ };
717
+ const ActionButton = (_props) => {
718
+ const props = {
719
+ variant: "default",
720
+ ..._props
721
+ };
722
+ const { tooltip, menu, icon, ...restProps } = props;
723
+ if (props.icon) {
724
+ const icon$1 = isComponentType(props.icon) ? /* @__PURE__ */ jsx(props.icon, { size: ui.sizes.icon.md }) : /* @__PURE__ */ jsx(ThemeIcon, {
725
+ w: 24,
726
+ variant: "transparent",
727
+ size: "sm",
728
+ c: "var(--mantine-color-text)",
729
+ ...props.themeIconProps,
730
+ children: props.icon
731
+ });
732
+ if (!props.children) {
733
+ restProps.children = Children.only(icon$1);
734
+ restProps.p ??= "xs";
735
+ } else restProps.leftSection = icon$1;
736
+ }
737
+ if (props.leftSection && !props.children) {
738
+ restProps.className ??= "mantine-Action-iconOnly";
739
+ restProps.p ??= "xs";
740
+ }
741
+ if (props.textVisibleFrom) {
742
+ const { children, textVisibleFrom, leftSection, ...rest } = restProps;
743
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Flex, {
744
+ w: "100%",
745
+ visibleFrom: textVisibleFrom,
746
+ children: /* @__PURE__ */ jsx(ActionButton, {
747
+ flex: 1,
748
+ ...rest,
749
+ leftSection,
750
+ tooltip,
751
+ menu,
752
+ children
753
+ })
754
+ }), /* @__PURE__ */ jsx(Flex, {
755
+ w: "100%",
756
+ hiddenFrom: textVisibleFrom,
757
+ children: /* @__PURE__ */ jsx(ActionButton, {
758
+ px: "xs",
759
+ ...rest,
760
+ tooltip,
761
+ menu,
762
+ children: leftSection
763
+ })
764
+ })] });
765
+ }
766
+ const renderAction = () => {
767
+ if ("href" in restProps && restProps.href) {
768
+ if (restProps.href.startsWith("http") || restProps.target) return /* @__PURE__ */ jsx(ActionHrefButton, {
769
+ ...restProps,
770
+ href: restProps.href,
771
+ children: restProps.children
772
+ });
773
+ return /* @__PURE__ */ jsx(ActionNavigationButton, {
774
+ ...restProps,
775
+ href: restProps.href,
776
+ children: restProps.children
777
+ });
778
+ }
779
+ delete restProps.classNameActive;
780
+ delete restProps.variantActive;
781
+ if ("action" in restProps && restProps.action) return /* @__PURE__ */ jsx(ActionHookButton, {
782
+ ...restProps,
783
+ action: restProps.action,
784
+ children: restProps.children
785
+ });
786
+ if ("onClick" in restProps && restProps.onClick) return /* @__PURE__ */ jsx(ActionClickButton, {
787
+ ...restProps,
788
+ onClick: restProps.onClick,
789
+ children: restProps.children
790
+ });
791
+ if ("form" in restProps && restProps.form) {
792
+ if (restProps.type === "reset") return /* @__PURE__ */ jsx(ActionResetButton, {
793
+ ...restProps,
794
+ form: restProps.form,
795
+ children: restProps.children
796
+ });
797
+ return /* @__PURE__ */ jsx(ActionSubmitButton, {
798
+ ...restProps,
799
+ form: restProps.form,
800
+ children: restProps.children
801
+ });
802
+ }
803
+ return /* @__PURE__ */ jsx(Button, {
804
+ ...restProps,
805
+ children: restProps.children
806
+ });
807
+ };
808
+ let actionElement = renderAction();
809
+ if (menu) actionElement = /* @__PURE__ */ jsxs(Menu, {
810
+ position: menu.position || "bottom-start",
811
+ width: menu.width || 200,
812
+ shadow: menu.shadow || "md",
813
+ trigger: menu.on === "hover" ? "hover" : "click",
814
+ ...menu.menuProps,
815
+ children: [/* @__PURE__ */ jsx(Menu.Target, {
816
+ ...menu.targetProps,
817
+ children: actionElement
818
+ }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: menu.items.map((item, index) => /* @__PURE__ */ jsx(ActionMenuItem, {
819
+ item,
820
+ index
821
+ }, index)) })]
822
+ });
823
+ if (tooltip) {
824
+ const defaultTooltipProps = { openDelay: 1e3 };
825
+ return /* @__PURE__ */ jsx(Tooltip, { ...typeof tooltip === "string" ? {
826
+ ...defaultTooltipProps,
827
+ label: tooltip,
828
+ children: actionElement
829
+ } : {
830
+ ...defaultTooltipProps,
831
+ ...tooltip,
832
+ children: actionElement
833
+ } });
834
+ }
835
+ return actionElement;
836
+ };
837
+ var ActionButton_default = ActionButton;
838
+ /**
839
+ * Action button that submits a form with loading and disabled state handling.
840
+ */
841
+ const ActionSubmitButton = (props) => {
842
+ const { form, ...buttonProps } = props;
843
+ const state = useFormState(form);
844
+ return /* @__PURE__ */ jsx(Button, {
845
+ ...buttonProps,
846
+ loading: state.loading,
847
+ disabled: state.loading,
848
+ type: "submit",
849
+ children: props.children
850
+ });
851
+ };
852
+ const ActionResetButton = (props) => {
853
+ const { form, ...buttonProps } = props;
854
+ const state = useFormState(form);
855
+ return /* @__PURE__ */ jsx(Button, {
856
+ ...buttonProps,
857
+ disabled: state.loading,
858
+ type: "reset",
859
+ children: props.children
860
+ });
861
+ };
862
+ /**
863
+ * Action button that integrates with useAction hook return value.
864
+ * Automatically handles loading state and executes the action on click.
865
+ *
866
+ * @example
867
+ * ```tsx
868
+ * const saveAction = useAction({
869
+ * handler: async (data) => {
870
+ * await api.save(data);
871
+ * }
872
+ * }, []);
873
+ *
874
+ * <ActionButton action={saveAction}>
875
+ * Save
876
+ * </ActionButton>
877
+ * ```
878
+ */
879
+ const ActionHookButton = (props) => {
880
+ const { action, ...buttonProps } = props;
881
+ return /* @__PURE__ */ jsx(Button, {
882
+ ...buttonProps,
883
+ disabled: action.loading || props.disabled,
884
+ loading: action.loading,
885
+ onClick: () => action.run(),
886
+ children: props.children
887
+ });
888
+ };
889
+ /**
890
+ * Basic action button that handles click events with loading and error handling.
891
+ *
892
+ * @example
893
+ * ```tsx
894
+ * <ActionButton onClick={() => api.doSomething()}>
895
+ * Do Something
896
+ * </ActionButton>
897
+ * ```
898
+ */
899
+ const ActionClickButton = (props) => {
900
+ const action = useAction({ handler: async (e) => {
901
+ await props.onClick(e);
902
+ } }, [props.onClick]);
903
+ return /* @__PURE__ */ jsx(Button, {
904
+ ...props,
905
+ disabled: action.loading || props.disabled,
906
+ loading: action.loading,
907
+ onClick: action.run,
908
+ children: props.children
909
+ });
910
+ };
911
+ /**
912
+ * Action for navigation with active state support.
913
+ */
914
+ const ActionNavigationButton = (props) => {
915
+ const { active: options, classNameActive, variantActive, routerGoOptions, ...buttonProps } = props;
916
+ const router = useRouter();
917
+ const { isPending, isActive } = useActive(options ? {
918
+ href: props.href,
919
+ ...options
920
+ } : { href: props.href });
921
+ const anchorProps = router.anchor(props.href, routerGoOptions);
922
+ const className = buttonProps.className || "";
923
+ if (isActive && options !== false && classNameActive) buttonProps.className = `${className} ${classNameActive}`.trim();
924
+ if (props.anchorProps) return /* @__PURE__ */ jsx(Anchor, {
925
+ component: "a",
926
+ ...anchorProps,
927
+ ...props.anchorProps,
928
+ children: props.children
929
+ });
930
+ return /* @__PURE__ */ jsx(Button, {
931
+ component: "a",
932
+ loading: isPending,
933
+ ...buttonProps,
934
+ ...anchorProps,
935
+ variant: isActive && options !== false ? variantActive ?? "filled" : buttonProps.variant ?? "subtle",
936
+ children: props.children
937
+ });
938
+ };
939
+ const ActionHrefButton = (props) => {
940
+ const { active: options, classNameActive, variantActive, routerGoOptions, target, ...buttonProps } = props;
941
+ return /* @__PURE__ */ jsx(Button, {
942
+ component: "a",
943
+ target,
944
+ ...buttonProps,
945
+ children: props.children
946
+ });
947
+ };
948
+ function isComponentType(param) {
949
+ if (isValidElement(param)) return false;
950
+ return typeof param === "function" || typeof param === "object" && param !== null && "$$typeof" in param;
951
+ }
952
+
953
+ //#endregion
954
+ //#region src/core/utils/icons.tsx
955
+ /**
956
+ * Get the default icon for an input based on its type, format, or name.
957
+ */
958
+ const getDefaultIcon = (params) => {
959
+ const { type, format, name, isEnum, isArray, size = "sm" } = params;
960
+ const iconSize = ui.sizes.icon[size];
961
+ if (format) switch (format) {
962
+ case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
963
+ case "url":
964
+ case "uri": return /* @__PURE__ */ jsx(IconLink, { size: iconSize });
965
+ case "tel":
966
+ case "phone": return /* @__PURE__ */ jsx(IconPhone, { size: iconSize });
967
+ case "date": return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
968
+ case "date-time": return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
969
+ case "time": return /* @__PURE__ */ jsx(IconClock, { size: iconSize });
970
+ case "color": return /* @__PURE__ */ jsx(IconColorPicker, { size: iconSize });
971
+ case "uuid": return /* @__PURE__ */ jsx(IconKey, { size: iconSize });
972
+ }
973
+ if (name) {
974
+ const nameLower = name.toLowerCase();
975
+ if (nameLower.includes("password") || nameLower.includes("secret")) return /* @__PURE__ */ jsx(IconKey, { size: iconSize });
976
+ if (nameLower.includes("email") || nameLower.includes("mail")) return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
977
+ if (nameLower.includes("url") || nameLower.includes("link")) return /* @__PURE__ */ jsx(IconLink, { size: iconSize });
978
+ if (nameLower.includes("phone") || nameLower.includes("tel")) return /* @__PURE__ */ jsx(IconPhone, { size: iconSize });
979
+ if (nameLower.includes("color")) return /* @__PURE__ */ jsx(IconPalette, { size: iconSize });
980
+ if (nameLower.includes("file") || nameLower.includes("upload")) return /* @__PURE__ */ jsx(IconFile, { size: iconSize });
981
+ if (nameLower.includes("date")) return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
982
+ if (nameLower.includes("time")) return /* @__PURE__ */ jsx(IconClock, { size: iconSize });
983
+ }
984
+ if (isEnum || isArray) return /* @__PURE__ */ jsx(IconSelector, { size: iconSize });
985
+ if (type) switch (type) {
986
+ case "boolean": return /* @__PURE__ */ jsx(IconToggleLeft, { size: iconSize });
987
+ case "number":
988
+ case "integer": return /* @__PURE__ */ jsx(IconHash, { size: iconSize });
989
+ case "array": return /* @__PURE__ */ jsx(IconList, { size: iconSize });
990
+ case "string": return /* @__PURE__ */ jsx(IconLetterCase, { size: iconSize });
991
+ }
992
+ return /* @__PURE__ */ jsx(IconAt, { size: iconSize });
993
+ };
994
+
995
+ //#endregion
996
+ //#region src/core/utils/string.ts
997
+ /**
998
+ * Capitalizes the first letter of a string.
999
+ *
1000
+ * @example
1001
+ * capitalize("hello") // "Hello"
1002
+ */
1003
+ const capitalize = (str) => {
1004
+ return str.charAt(0).toUpperCase() + str.slice(1);
1005
+ };
1006
+ /**
1007
+ * Converts a path or identifier string into a pretty display name.
1008
+ * Removes slashes and capitalizes the first letter.
1009
+ *
1010
+ * @example
1011
+ * prettyName("/userName") // "UserName"
1012
+ * prettyName("email") // "Email"
1013
+ */
1014
+ const prettyName = (name) => {
1015
+ return capitalize(name.replaceAll("/", ""));
1016
+ };
1017
+
1018
+ //#endregion
1019
+ //#region src/core/utils/parseInput.ts
1020
+ const parseInput = (props, form) => {
1021
+ const disabled = false;
1022
+ const id = props.input.props.id;
1023
+ const label = props.title ?? ("title" in props.input.schema && typeof props.input.schema.title === "string" ? props.input.schema.title : void 0) ?? prettyName(props.input.path);
1024
+ const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
1025
+ const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
1026
+ const icon = !props.icon ? getDefaultIcon({
1027
+ type: props.input.schema && "type" in props.input.schema ? String(props.input.schema.type) : void 0,
1028
+ format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
1029
+ name: props.input.props.name,
1030
+ isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
1031
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
1032
+ }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.md });
1033
+ const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
1034
+ const required = props.input.required;
1035
+ const schema = props.input.schema;
1036
+ const inputProps = {
1037
+ label,
1038
+ description,
1039
+ error,
1040
+ required,
1041
+ disabled
1042
+ };
1043
+ if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
1044
+ if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
1045
+ if ("minimum" in schema && typeof schema.minimum === "number") inputProps.minimum = schema.minimum;
1046
+ if ("maximum" in schema && typeof schema.maximum === "number") inputProps.maximum = schema.maximum;
1047
+ return {
1048
+ id,
1049
+ icon,
1050
+ format,
1051
+ schema: props.input.schema,
1052
+ inputProps
1053
+ };
1054
+ };
1055
+
1056
+ //#endregion
1057
+ //#region src/core/components/form/ControlDate.tsx
1058
+ /**
1059
+ * ControlDate component for handling date, datetime, and time inputs.
1060
+ *
1061
+ * Features:
1062
+ * - DateInput for date format
1063
+ * - DateTimePicker for date-time format
1064
+ * - TimeInput for time format
1065
+ *
1066
+ * Automatically detects date formats from schema and renders appropriate picker.
1067
+ */
1068
+ const ControlDate = (props) => {
1069
+ const { inputProps, id, icon, format } = parseInput(props, useFormState(props.input));
1070
+ if (!props.input?.props) return null;
1071
+ if (props.datetime || format === "date-time") {
1072
+ const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
1073
+ return /* @__PURE__ */ jsx(DateTimePicker, {
1074
+ ...inputProps,
1075
+ id,
1076
+ leftSection: icon,
1077
+ defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
1078
+ onChange: (value) => {
1079
+ props.input.set(value ? new Date(value).toISOString() : void 0);
1080
+ },
1081
+ ...dateTimePickerProps
1082
+ });
1083
+ }
1084
+ if (props.date || format === "date") {
1085
+ const dateInputProps = typeof props.date === "object" ? props.date : {};
1086
+ return /* @__PURE__ */ jsx(DateInput, {
1087
+ ...inputProps,
1088
+ id,
1089
+ leftSection: icon,
1090
+ defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
1091
+ onChange: (value) => {
1092
+ props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
1093
+ },
1094
+ ...dateInputProps
1095
+ });
1096
+ }
1097
+ if (props.time || format === "time") {
1098
+ const timeInputProps = typeof props.time === "object" ? props.time : {};
1099
+ return /* @__PURE__ */ jsx(TimeInput, {
1100
+ ...inputProps,
1101
+ id,
1102
+ leftSection: icon,
1103
+ defaultValue: props.input.props.defaultValue,
1104
+ onChange: (event) => {
1105
+ props.input.set(event.currentTarget.value);
1106
+ },
1107
+ ...timeInputProps
1108
+ });
1109
+ }
1110
+ return null;
1111
+ };
1112
+ var ControlDate_default = ControlDate;
1113
+
1114
+ //#endregion
1115
+ //#region src/core/components/form/ControlNumber.tsx
1116
+ /**
1117
+ *
1118
+ */
1119
+ const ControlNumber = (props) => {
1120
+ const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
1121
+ const ref = useRef(null);
1122
+ const [value, setValue] = useState(props.input.props.defaultValue);
1123
+ useEvents({ "form:reset": (event) => {
1124
+ if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
1125
+ } }, [props.input]);
1126
+ if (!props.input?.props) return null;
1127
+ const { type, ...inputPropsWithoutType } = props.input.props;
1128
+ if (props.sliderProps) return /* @__PURE__ */ jsx(Input.Wrapper, {
1129
+ ...inputProps,
1130
+ children: /* @__PURE__ */ jsx("div", {
1131
+ style: {
1132
+ height: 32,
1133
+ padding: 8
1134
+ },
1135
+ children: /* @__PURE__ */ jsx(Slider, {
1136
+ ...inputProps,
1137
+ ref,
1138
+ id,
1139
+ ...inputPropsWithoutType,
1140
+ ...props.sliderProps,
1141
+ value,
1142
+ onChange: (val) => {
1143
+ setValue(val);
1144
+ props.input.set(val);
1145
+ }
1146
+ })
1147
+ })
1148
+ });
1149
+ return /* @__PURE__ */ jsx(NumberInput, {
1150
+ ...inputProps,
1151
+ ref,
1152
+ id,
1153
+ leftSection: icon,
1154
+ ...inputPropsWithoutType,
1155
+ ...props.numberInputProps,
1156
+ value: value ?? "",
1157
+ onChange: (val) => {
1158
+ const newValue = val !== null ? Number(val) : void 0;
1159
+ setValue(newValue);
1160
+ props.input.set(newValue);
1161
+ }
1162
+ });
1163
+ };
1164
+ var ControlNumber_default = ControlNumber;
1165
+
1166
+ //#endregion
1167
+ //#region src/core/utils/extractSchemaFields.ts
1168
+ /**
1169
+ * Extract field information from a TypeBox schema for query building.
1170
+ * Supports nested objects and provides field metadata for autocomplete.
1171
+ */
1172
+ function extractSchemaFields(schema, prefix = "") {
1173
+ const fields = [];
1174
+ if (!schema || typeof schema !== "object") return fields;
1175
+ const properties = "properties" in schema ? schema.properties : schema;
1176
+ if (!properties || typeof properties !== "object") return fields;
1177
+ for (const [key, value] of Object.entries(properties)) {
1178
+ if (typeof value !== "object" || value === null) continue;
1179
+ const fieldSchema = value;
1180
+ const path = prefix ? `${prefix}.${key}` : key;
1181
+ const format = "format" in fieldSchema ? fieldSchema.format : void 0;
1182
+ let displayType = "type" in fieldSchema ? fieldSchema.type : "object";
1183
+ if (format === "date-time") displayType = "datetime";
1184
+ else if (format === "date") displayType = "date";
1185
+ else if (format === "time") displayType = "time";
1186
+ else if (format === "duration") displayType = "duration";
1187
+ const field = {
1188
+ name: key,
1189
+ path,
1190
+ type: displayType,
1191
+ format,
1192
+ description: "description" in fieldSchema ? fieldSchema.description : void 0
1193
+ };
1194
+ if ("enum" in fieldSchema && fieldSchema.enum) {
1195
+ field.enum = fieldSchema.enum;
1196
+ field.type = "enum";
1197
+ }
1198
+ if ("type" in fieldSchema && fieldSchema.type === "object" && "properties" in fieldSchema && typeof fieldSchema.properties === "object") field.nested = extractSchemaFields(fieldSchema.properties, path);
1199
+ fields.push(field);
1200
+ if (field.nested) fields.push(...field.nested);
1201
+ }
1202
+ return fields;
1203
+ }
1204
+ /**
1205
+ * Get operator symbol and description
1206
+ */
1207
+ const OPERATOR_INFO = {
1208
+ eq: {
1209
+ symbol: "=",
1210
+ label: "equals",
1211
+ example: "name=John"
1212
+ },
1213
+ ne: {
1214
+ symbol: "!=",
1215
+ label: "not equals",
1216
+ example: "status!=archived"
1217
+ },
1218
+ gt: {
1219
+ symbol: ">",
1220
+ label: "greater than",
1221
+ example: "age>18"
1222
+ },
1223
+ gte: {
1224
+ symbol: ">=",
1225
+ label: "greater or equal",
1226
+ example: "age>=18"
1227
+ },
1228
+ lt: {
1229
+ symbol: "<",
1230
+ label: "less than",
1231
+ example: "age<65"
1232
+ },
1233
+ lte: {
1234
+ symbol: "<=",
1235
+ label: "less or equal",
1236
+ example: "age<=65"
1237
+ },
1238
+ null: {
1239
+ symbol: "=null",
1240
+ label: "is null",
1241
+ example: "deletedAt=null"
1242
+ },
1243
+ notNull: {
1244
+ symbol: "!=null",
1245
+ label: "is not null",
1246
+ example: "email!=null"
1247
+ },
1248
+ in: {
1249
+ symbol: "[...]",
1250
+ label: "in array",
1251
+ example: "status=[active,pending]"
1252
+ }
1253
+ };
1254
+
1255
+ //#endregion
1256
+ //#region src/core/components/form/ControlQueryBuilder.tsx
1257
+ /**
1258
+ * Query builder with text input and help popover.
1259
+ * Generates query strings for parseQueryString syntax.
1260
+ */
1261
+ const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
1262
+ const [helpOpened, setHelpOpened] = useState(false);
1263
+ const [textValue, setTextValue] = useState(value);
1264
+ const inputRef = useRef(null);
1265
+ const fields = schema ? extractSchemaFields(schema) : [];
1266
+ const [error, setError] = useState(null);
1267
+ const isValid = (value$1) => {
1268
+ try {
1269
+ parseQueryString(value$1.trim());
1270
+ } catch (e) {
1271
+ setError(e.message);
1272
+ return false;
1273
+ }
1274
+ setError(null);
1275
+ return true;
1276
+ };
1277
+ const handleTextChange = (newValue) => {
1278
+ setTextValue(newValue);
1279
+ if (isValid(newValue)) onChange?.(newValue);
1280
+ };
1281
+ const handleClear = () => {
1282
+ setTextValue("");
1283
+ onChange?.("");
1284
+ isValid("");
1285
+ };
1286
+ const handleInsert = (text) => {
1287
+ const newValue = textValue ? `${textValue}${text} ` : `${text} `;
1288
+ setTextValue(newValue);
1289
+ if (isValid(newValue)) onChange?.(newValue);
1290
+ setTimeout(() => {
1291
+ inputRef.current?.focus();
1292
+ const length = inputRef.current?.value.length || 0;
1293
+ inputRef.current?.setSelectionRange(length, length);
1294
+ }, 0);
1295
+ };
1296
+ useEvents({ "form:change": (event) => {
1297
+ if (event.id === inputRef.current?.form?.id) {
1298
+ if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
1299
+ }
1300
+ } }, []);
1301
+ return /* @__PURE__ */ jsxs(Popover, {
1302
+ width: 800,
1303
+ position: "bottom-start",
1304
+ shadow: "md",
1305
+ opened: helpOpened,
1306
+ onChange: setHelpOpened,
1307
+ closeOnClickOutside: true,
1308
+ closeOnEscape: true,
1309
+ transitionProps: {
1310
+ transition: "fade-up",
1311
+ duration: 200,
1312
+ timingFunction: "ease"
1313
+ },
1314
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
1315
+ ref: inputRef,
1316
+ placeholder,
1317
+ value: textValue,
1318
+ onChange: (e) => handleTextChange(e.currentTarget.value),
1319
+ onFocus: () => setHelpOpened(true),
1320
+ leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
1321
+ rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
1322
+ size: "sm",
1323
+ variant: "subtle",
1324
+ color: "gray",
1325
+ onClick: handleClear,
1326
+ children: /* @__PURE__ */ jsx(IconX, { size: 14 })
1327
+ }),
1328
+ ...textInputProps
1329
+ }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
1330
+ bg: "transparent",
1331
+ p: "xs",
1332
+ bd: `1px solid ${ui.colors.border}`,
1333
+ style: { backdropFilter: "blur(20px)" },
1334
+ children: /* @__PURE__ */ jsx(QueryHelp, {
1335
+ fields,
1336
+ onInsert: handleInsert
1337
+ })
1338
+ })]
1339
+ });
1340
+ };
1341
+ function QueryHelp({ fields, onInsert }) {
1342
+ return /* @__PURE__ */ jsxs(Group, {
1343
+ gap: "md",
1344
+ align: "flex-start",
1345
+ wrap: "nowrap",
1346
+ bg: ui.colors.surface,
1347
+ p: "sm",
1348
+ bdrs: "sm",
1349
+ children: [
1350
+ /* @__PURE__ */ jsxs(Stack, {
1351
+ gap: "md",
1352
+ style: { flex: 1 },
1353
+ children: [
1354
+ /* @__PURE__ */ jsxs(Stack, {
1355
+ gap: "xs",
1356
+ children: [/* @__PURE__ */ jsx(Text, {
1357
+ size: "sm",
1358
+ fw: 600,
1359
+ children: "Operators"
1360
+ }), /* @__PURE__ */ jsx(Stack, {
1361
+ gap: 4,
1362
+ children: Object.entries(OPERATOR_INFO).map(([key, info]) => /* @__PURE__ */ jsxs(Group, {
1363
+ gap: "xs",
1364
+ wrap: "nowrap",
1365
+ children: [/* @__PURE__ */ jsx(ActionButton_default, {
1366
+ px: "xs",
1367
+ size: "xs",
1368
+ h: 24,
1369
+ variant: "default",
1370
+ justify: "center",
1371
+ miw: 48,
1372
+ onClick: () => onInsert(info.symbol),
1373
+ children: info.symbol
1374
+ }), /* @__PURE__ */ jsx(Text, {
1375
+ size: "xs",
1376
+ c: "dimmed",
1377
+ style: { flex: 1 },
1378
+ children: info.label
1379
+ })]
1380
+ }, key))
1381
+ })]
1382
+ }),
1383
+ /* @__PURE__ */ jsx(Divider, {}),
1384
+ /* @__PURE__ */ jsxs(Stack, {
1385
+ gap: "xs",
1386
+ children: [/* @__PURE__ */ jsx(Text, {
1387
+ size: "sm",
1388
+ fw: 600,
1389
+ children: "Logic"
1390
+ }), /* @__PURE__ */ jsxs(Stack, {
1391
+ gap: 4,
1392
+ children: [/* @__PURE__ */ jsxs(Group, {
1393
+ gap: "xs",
1394
+ wrap: "nowrap",
1395
+ children: [/* @__PURE__ */ jsx(ActionButton_default, {
1396
+ px: "xs",
1397
+ size: "xs",
1398
+ h: 24,
1399
+ variant: "default",
1400
+ justify: "center",
1401
+ miw: 48,
1402
+ onClick: () => onInsert("&"),
1403
+ children: "&"
1404
+ }), /* @__PURE__ */ jsx(Text, {
1405
+ size: "xs",
1406
+ c: "dimmed",
1407
+ children: "AND"
1408
+ })]
1409
+ }), /* @__PURE__ */ jsxs(Group, {
1410
+ gap: "xs",
1411
+ wrap: "nowrap",
1412
+ children: [/* @__PURE__ */ jsx(ActionButton_default, {
1413
+ px: "xs",
1414
+ size: "xs",
1415
+ h: 24,
1416
+ variant: "default",
1417
+ justify: "center",
1418
+ miw: 48,
1419
+ onClick: () => onInsert("|"),
1420
+ children: "|"
1421
+ }), /* @__PURE__ */ jsx(Text, {
1422
+ size: "xs",
1423
+ c: "dimmed",
1424
+ children: "OR"
1425
+ })]
1426
+ })]
1427
+ })]
1428
+ })
1429
+ ]
1430
+ }),
1431
+ fields.length > 0 && /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }),
1432
+ fields.length > 0 && /* @__PURE__ */ jsxs(Flex, {
1433
+ direction: "column",
1434
+ gap: "xs",
1435
+ style: { flex: 2 },
1436
+ children: [/* @__PURE__ */ jsx(Text, {
1437
+ size: "sm",
1438
+ fw: 600,
1439
+ children: "Fields"
1440
+ }), /* @__PURE__ */ jsx(Flex, {
1441
+ direction: "column",
1442
+ gap: 4,
1443
+ style: {
1444
+ maxHeight: 300,
1445
+ overflowY: "auto"
1446
+ },
1447
+ children: fields.map((field) => /* @__PURE__ */ jsxs(Flex, {
1448
+ gap: "xs",
1449
+ wrap: "nowrap",
1450
+ align: "flex-start",
1451
+ children: [
1452
+ /* @__PURE__ */ jsx(ActionButton_default, {
1453
+ px: "xs",
1454
+ size: "xs",
1455
+ h: 24,
1456
+ variant: "default",
1457
+ justify: "end",
1458
+ miw: 120,
1459
+ onClick: () => onInsert(field.path),
1460
+ children: field.path
1461
+ }),
1462
+ /* @__PURE__ */ jsxs(Flex, {
1463
+ mt: 3,
1464
+ direction: "column",
1465
+ gap: 2,
1466
+ style: {
1467
+ flex: 1,
1468
+ minWidth: 0
1469
+ },
1470
+ children: [/* @__PURE__ */ jsx(Text, {
1471
+ size: "xs",
1472
+ c: "dimmed",
1473
+ lineClamp: 1,
1474
+ children: field.description || field.type
1475
+ }), field.enum && /* @__PURE__ */ jsx(Group, {
1476
+ gap: 0,
1477
+ wrap: "wrap",
1478
+ children: field.enum.map((enumValue) => /* @__PURE__ */ jsx(ActionButton_default, {
1479
+ px: "xs",
1480
+ size: "xs",
1481
+ h: 24,
1482
+ onClick: () => onInsert(enumValue),
1483
+ children: enumValue
1484
+ }, enumValue))
1485
+ })]
1486
+ }),
1487
+ /* @__PURE__ */ jsx(Badge, {
1488
+ size: "xs",
1489
+ variant: "light",
1490
+ style: { flexShrink: 0 },
1491
+ children: field.type
1492
+ })
1493
+ ]
1494
+ }, field.path))
1495
+ })]
1496
+ })
1497
+ ]
1498
+ });
1499
+ }
1500
+ var ControlQueryBuilder_default = ControlQueryBuilder;
1501
+
1502
+ //#endregion
1503
+ //#region src/core/components/form/ControlSelect.tsx
1504
+ /**
1505
+ * ControlSelect component for handling Select, MultiSelect, and TagsInput.
1506
+ *
1507
+ * Features:
1508
+ * - Basic Select with enum support
1509
+ * - MultiSelect for array of enums
1510
+ * - TagsInput for array of strings (no enum)
1511
+ * - Future: Lazy loading
1512
+ * - Future: Searchable/filterable options
1513
+ * - Future: Custom option rendering
1514
+ *
1515
+ * Automatically detects enum values and array types from schema.
1516
+ */
1517
+ const ControlSelect = (props) => {
1518
+ const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
1519
+ const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
1520
+ let itemsEnum;
1521
+ if (isArray && "items" in props.input.schema && props.input.schema.items) {
1522
+ const items = props.input.schema.items;
1523
+ if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
1524
+ }
1525
+ const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
1526
+ const [data, setData] = useState([]);
1527
+ useEffect(() => {
1528
+ if (!props.input?.props) return;
1529
+ if (props.loader) props.loader().then(setData);
1530
+ else setData(enumValues);
1531
+ }, [props.input, props.loader]);
1532
+ if (!props.input?.props) return null;
1533
+ if (props.segmented) {
1534
+ const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
1535
+ return /* @__PURE__ */ jsx(Input.Wrapper, {
1536
+ ...inputProps,
1537
+ children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(SegmentedControl, {
1538
+ disabled: inputProps.disabled,
1539
+ defaultValue: String(props.input.props.defaultValue),
1540
+ ...segmentedControlProps,
1541
+ onChange: (value) => {
1542
+ props.input.set(value);
1543
+ },
1544
+ data: data.slice(0, 10)
1545
+ }) })
1546
+ });
1547
+ }
1548
+ if (props.autocomplete) {
1549
+ const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
1550
+ return /* @__PURE__ */ jsx(Autocomplete, {
1551
+ ...inputProps,
1552
+ id,
1553
+ leftSection: icon,
1554
+ data,
1555
+ ...props.input.props,
1556
+ ...autocompleteProps
1557
+ });
1558
+ }
1559
+ if (isArray && !itemsEnum || props.tags) {
1560
+ const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
1561
+ return /* @__PURE__ */ jsx(TagsInput, {
1562
+ ...inputProps,
1563
+ id,
1564
+ leftSection: icon,
1565
+ defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
1566
+ onChange: (value) => {
1567
+ props.input.set(value);
1568
+ },
1569
+ ...tagsInputProps
1570
+ });
1571
+ }
1572
+ if (isArray && itemsEnum || props.multi) {
1573
+ const data$1 = itemsEnum?.map((value) => ({
1574
+ value,
1575
+ label: value
1576
+ })) || [];
1577
+ const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
1578
+ return /* @__PURE__ */ jsx(MultiSelect, {
1579
+ ...inputProps,
1580
+ id,
1581
+ leftSection: icon,
1582
+ data: data$1,
1583
+ defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
1584
+ onChange: (value) => {
1585
+ props.input.set(value);
1586
+ },
1587
+ ...multiSelectProps
1588
+ });
1589
+ }
1590
+ const selectProps = typeof props.select === "object" ? props.select : {};
1591
+ return /* @__PURE__ */ jsx(Select, {
1592
+ ...inputProps,
1593
+ id,
1594
+ leftSection: icon,
1595
+ data,
1596
+ ...props.input.props,
1597
+ ...selectProps
1598
+ });
1599
+ };
1600
+ var ControlSelect_default = ControlSelect;
1601
+
1602
+ //#endregion
1603
+ //#region src/core/components/form/Control.tsx
1604
+ /**
1605
+ * Generic form control that renders the appropriate input based on the schema and props.
1606
+ *
1607
+ * Supports:
1608
+ * - TextInput (with format detection: email, url, tel)
1609
+ * - Textarea
1610
+ * - NumberInput (for number/integer types)
1611
+ * - FileInput
1612
+ * - ColorInput (for color format)
1613
+ * - Select (for enum types)
1614
+ * - Autocomplete
1615
+ * - PasswordInput
1616
+ * - Switch (for boolean types)
1617
+ * - SegmentedControl (for enum types)
1618
+ * - DateInput (for date format)
1619
+ * - DateTimePicker (for date-time format)
1620
+ * - TimeInput (for time format)
1621
+ * - QueryBuilder (for building type-safe queries with autocomplete)
1622
+ * - Custom component
1623
+ *
1624
+ * Automatically handles labels, descriptions, error messages, required state, and default icons.
1625
+ */
1626
+ const Control = (_props) => {
1627
+ const { inputProps, id, icon, format, schema } = parseInput(_props, useFormState(_props.input, ["error"]));
1628
+ if (!_props.input?.props) return null;
1629
+ const props = {
1630
+ ..._props,
1631
+ ...schema.$control
1632
+ };
1633
+ if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder_default, {
1634
+ ...props.input.props,
1635
+ ...inputProps,
1636
+ schema: props.query,
1637
+ value: props.input.props.value,
1638
+ onChange: (value) => {
1639
+ props.input.set(value);
1640
+ }
1641
+ });
1642
+ if (props.custom) {
1643
+ const Custom = props.custom;
1644
+ return /* @__PURE__ */ jsx(Input.Wrapper, {
1645
+ ...inputProps,
1646
+ children: /* @__PURE__ */ jsx(Flex, {
1647
+ flex: 1,
1648
+ mt: "calc(var(--mantine-spacing-xs) / 2)",
1649
+ children: /* @__PURE__ */ jsx(Custom, {
1650
+ defaultValue: props.input.props.defaultValue,
1651
+ onChange: (value) => {
1652
+ props.input.set(value);
1653
+ }
1654
+ })
1655
+ })
1656
+ });
1657
+ }
1658
+ if (props.number || props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
1659
+ const controlNumberProps = typeof props.number === "object" ? props.number : {};
1660
+ return /* @__PURE__ */ jsx(ControlNumber_default, {
1661
+ input: props.input,
1662
+ title: props.title,
1663
+ description: props.description,
1664
+ icon,
1665
+ ...controlNumberProps
1666
+ });
1667
+ }
1668
+ if (props.file) {
1669
+ const fileInputProps = typeof props.file === "object" ? props.file : {};
1670
+ return /* @__PURE__ */ jsx(FileInput, {
1671
+ ...inputProps,
1672
+ id,
1673
+ leftSection: icon,
1674
+ onChange: (file) => {
1675
+ props.input.set(file);
1676
+ },
1677
+ ...fileInputProps
1678
+ });
1679
+ }
1680
+ if (props.color || format === "color") {
1681
+ const colorInputProps = typeof props.color === "object" ? props.color : {};
1682
+ return /* @__PURE__ */ jsx(ColorInput, {
1683
+ ...inputProps,
1684
+ id,
1685
+ leftSection: icon,
1686
+ ...props.input.props,
1687
+ ...colorInputProps
1688
+ });
1689
+ }
1690
+ const isEnum = props.input.schema && "enum" in props.input.schema && props.input.schema.enum;
1691
+ const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
1692
+ if (isEnum || isArray || props.select) {
1693
+ const opts = typeof props.select === "object" ? props.select : {};
1694
+ return /* @__PURE__ */ jsx(ControlSelect_default, {
1695
+ input: props.input,
1696
+ title: props.title,
1697
+ description: props.description,
1698
+ icon,
1699
+ ...opts
1700
+ });
1701
+ }
1702
+ if (props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean" || props.switch) {
1703
+ const switchProps = typeof props.switch === "object" ? props.switch : {};
1704
+ return /* @__PURE__ */ jsx(Switch, {
1705
+ ...inputProps,
1706
+ id,
1707
+ color: "blue",
1708
+ defaultChecked: props.input.props.defaultValue,
1709
+ ...props.input.props,
1710
+ ...switchProps
1711
+ });
1712
+ }
1713
+ if (props.password || props.input.props.name?.includes("password")) {
1714
+ const passwordInputProps = typeof props.password === "object" ? props.password : {};
1715
+ return /* @__PURE__ */ jsx(PasswordInput, {
1716
+ ...inputProps,
1717
+ id,
1718
+ leftSection: icon,
1719
+ ...props.input.props,
1720
+ ...passwordInputProps
1721
+ });
1722
+ }
1723
+ if (props.area) {
1724
+ const textAreaProps = typeof props.area === "object" ? props.area : {};
1725
+ return /* @__PURE__ */ jsx(Textarea, {
1726
+ ...inputProps,
1727
+ id,
1728
+ leftSection: icon,
1729
+ ...props.input.props,
1730
+ ...textAreaProps
1731
+ });
1732
+ }
1733
+ if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate_default, {
1734
+ input: props.input,
1735
+ title: props.title,
1736
+ description: props.description,
1737
+ icon,
1738
+ date: props.date,
1739
+ datetime: props.datetime,
1740
+ time: props.time
1741
+ });
1742
+ const textInputProps = typeof props.text === "object" ? props.text : {};
1743
+ const getInputType = () => {
1744
+ switch (format) {
1745
+ case "email": return "email";
1746
+ case "url":
1747
+ case "uri": return "url";
1748
+ case "tel":
1749
+ case "phone": return "tel";
1750
+ default: return;
1751
+ }
1752
+ };
1753
+ return /* @__PURE__ */ jsx(TextInput, {
1754
+ ...inputProps,
1755
+ id,
1756
+ leftSection: icon,
1757
+ type: getInputType(),
1758
+ ...props.input.props,
1759
+ ...textInputProps,
1760
+ inputWrapperOrder: [
1761
+ "label",
1762
+ "input",
1763
+ "description",
1764
+ "error"
1765
+ ]
1766
+ });
1767
+ };
1768
+ var Control_default = Control;
1769
+
1770
+ //#endregion
1771
+ //#region src/core/index.ts
1772
+ /**
1773
+ * Mantine
1774
+ *
1775
+ * @module alepha.ui
1776
+ */
1777
+ const AlephaUI = $module({
1778
+ name: "alepha.ui",
1779
+ services: [
1780
+ DialogService,
1781
+ ToastService,
1782
+ RootRouter
1783
+ ],
1784
+ register: (alepha) => {
1785
+ alepha.with(AlephaReactI18n);
1786
+ alepha.with(AlephaReactHead);
1787
+ alepha.with(AlephaReactForm);
1788
+ alepha.with(DialogService);
1789
+ alepha.with(ToastService);
1790
+ }
1791
+ });
1792
+
1793
+ //#endregion
1794
+ export { ui as a, ActionButton_default as i, Control_default as n, capitalize as r, AlephaUI as t };
1795
+ //# sourceMappingURL=core-D1MHij1j.js.map