@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,2620 @@
1
+ let __alepha_react_form = require("@alepha/react/form");
2
+ let __alepha_react_head = require("@alepha/react/head");
3
+ let __alepha_react_i18n = require("@alepha/react/i18n");
4
+ let alepha = require("alepha");
5
+ let __alepha_react = require("@alepha/react");
6
+ let __mantine_core = require("@mantine/core");
7
+ let __mantine_modals = require("@mantine/modals");
8
+ let __mantine_notifications = require("@mantine/notifications");
9
+ let __mantine_nprogress = require("@mantine/nprogress");
10
+ let __tabler_icons_react = require("@tabler/icons-react");
11
+ let react_jsx_runtime = require("react/jsx-runtime");
12
+ let __mantine_spotlight = require("@mantine/spotlight");
13
+ let react = require("react");
14
+ let __mantine_dates = require("@mantine/dates");
15
+ let alepha_orm = require("alepha/orm");
16
+ let __mantine_hooks = require("@mantine/hooks");
17
+ let alepha_datetime = require("alepha/datetime");
18
+
19
+ //#region src/core/services/ToastService.tsx
20
+ var ToastService = class {
21
+ raw = __mantine_notifications.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
+ __mantine_notifications.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__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.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__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.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__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.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__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.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 (0, __alepha_react.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 = (0, __alepha_react.useRouter)();
100
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_spotlight.Spotlight, {
101
+ actions: (0, react.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__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.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
+ (0, __alepha_react.useEvents)({
124
+ "react:transition:begin": () => {
125
+ __mantine_nprogress.nprogress.start();
126
+ },
127
+ "react:transition:end": () => {
128
+ __mantine_nprogress.nprogress.complete();
129
+ },
130
+ "react:action:error": ({ error }) => {
131
+ if (error instanceof __alepha_react_form.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__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.ColorSchemeScript, {
139
+ defaultColorScheme: props.mantine?.defaultColorScheme,
140
+ ...props.colorSchemeScript
141
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.MantineProvider, {
142
+ ...props.mantine,
143
+ theme: { ...props.mantine?.theme },
144
+ children: [
145
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_notifications.Notifications, { ...props.notifications }),
146
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_nprogress.NavigationProgress, { ...props.navigationProgress }),
147
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_modals.ModalsProvider, {
148
+ ...props.modals,
149
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(Omnibar_default, { ...props.omnibar }), props.children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__alepha_react.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 = (0, __alepha_react.$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] = (0, react.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Box, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Box, {
286
+ style: {
287
+ display: "flex",
288
+ alignItems: "center",
289
+ gap: sizeConfig.gap,
290
+ minWidth: "max-content"
291
+ },
292
+ children: [
293
+ canExpand && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconChevronDown, { size: sizeConfig.icon }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconChevronRight, { size: sizeConfig.icon })
303
+ }),
304
+ !canExpand && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Box, {
305
+ w: sizeConfig.icon + 6,
306
+ style: { flexShrink: 0 }
307
+ }),
308
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Box, {
309
+ style: { flexShrink: 0 },
310
+ children: renderKey()
311
+ }),
312
+ " ",
313
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Collapse, {
351
+ in: expanded && canExpand,
352
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Box, {
368
+ style: {
369
+ display: "flex",
370
+ minWidth: "max-content"
371
+ },
372
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Box, {
373
+ w: sizeConfig.icon + 6,
374
+ style: { flexShrink: 0 }
375
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Box, {
386
+ style: {
387
+ display: "flex",
388
+ alignItems: "center",
389
+ gap: sizeConfig.gap,
390
+ minWidth: "max-content"
391
+ },
392
+ children: [
393
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Box, {
394
+ w: sizeConfig.icon + 6,
395
+ style: { flexShrink: 0 }
396
+ }),
397
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Box, {
398
+ style: { flexShrink: 0 },
399
+ children: renderKey()
400
+ }),
401
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Box, {
402
+ style: { flexShrink: 0 },
403
+ children: renderPrimitive(value)
404
+ }),
405
+ !isLast && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Box, {
419
+ pos: "relative",
420
+ w: "100%",
421
+ children: [copyable && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Box, {
422
+ pos: "absolute",
423
+ top: 0,
424
+ right: 0,
425
+ style: { zIndex: 1 },
426
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.CopyButton, {
427
+ value: JSON.stringify(data, null, 2),
428
+ children: ({ copied, copy }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Tooltip, {
429
+ label: copied ? "Copied" : "Copy JSON",
430
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.ActionIcon, {
431
+ color: copied ? "teal" : "gray",
432
+ variant: "subtle",
433
+ onClick: copy,
434
+ size,
435
+ children: copied ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconCheck, { size: copyIconSize }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconCopy, { size: copyIconSize })
436
+ })
437
+ })
438
+ })
439
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Box, {
440
+ pt: copyable ? 30 : 0,
441
+ style: { overflowX: "auto" },
442
+ children: /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [options?.message && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
456
+ mb: "md",
457
+ children: options.message
458
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Group, {
459
+ justify: "flex-end",
460
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [options?.message && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
470
+ mb: "md",
471
+ children: options.message
472
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Group, {
473
+ justify: "flex-end",
474
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Button, {
475
+ variant: "subtle",
476
+ onClick: () => onConfirm(false),
477
+ children: options?.cancelLabel || "Cancel"
478
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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] = (0, react.useState)(options?.defaultValue || "");
490
+ const inputRef = (0, react.useRef)(null);
491
+ (0, react.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__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
501
+ options?.message && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
502
+ mb: "md",
503
+ children: options.message
504
+ }),
505
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Group, {
516
+ justify: "flex-end",
517
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Button, {
518
+ variant: "subtle",
519
+ onClick: () => onSubmit(null),
520
+ children: options?.cancelLabel || "Cancel"
521
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.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 __mantine_modals.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) __mantine_modals.modals.close(modalId);
639
+ else __mantine_modals.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
650
+ bdrs: "md",
651
+ w: "100%",
652
+ flex: 1,
653
+ p: "sm",
654
+ bg: ui.colors.surface,
655
+ children: /* @__PURE__ */ (0, react_jsx_runtime.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 = (0, __alepha_react.useRouter)();
683
+ const action = (0, __alepha_react.useAction)({ handler: async (e) => {
684
+ await item.onClick?.();
685
+ } }, [item.onClick]);
686
+ if (item.type === "divider") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Menu.Divider, {}, index);
687
+ if (item.type === "label") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Menu.Label, { children: item.label }, index);
688
+ if (item.children && item.children.length > 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Menu, {
689
+ trigger: "hover",
690
+ position: "right-start",
691
+ offset: 2,
692
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Menu.Target, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Menu.Item, {
693
+ leftSection: item.icon,
694
+ rightSection: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconChevronRight, { size: 14 }),
695
+ children: item.label
696
+ }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Menu.Item, {
705
+ leftSection: item.icon,
706
+ onClick: item.onClick,
707
+ color: item.color,
708
+ rightSection: item.active ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.ThemeIcon, {
709
+ size: "xs",
710
+ variant: "transparent",
711
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.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__ */ (0, react_jsx_runtime.jsx)(props.icon, { size: ui.sizes.icon.md }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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 = react.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__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
744
+ w: "100%",
745
+ visibleFrom: textVisibleFrom,
746
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton, {
747
+ flex: 1,
748
+ ...rest,
749
+ leftSection,
750
+ tooltip,
751
+ menu,
752
+ children
753
+ })
754
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
755
+ w: "100%",
756
+ hiddenFrom: textVisibleFrom,
757
+ children: /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)(ActionHrefButton, {
769
+ ...restProps,
770
+ href: restProps.href,
771
+ children: restProps.children
772
+ });
773
+ return /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)(ActionHookButton, {
782
+ ...restProps,
783
+ action: restProps.action,
784
+ children: restProps.children
785
+ });
786
+ if ("onClick" in restProps && restProps.onClick) return /* @__PURE__ */ (0, react_jsx_runtime.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__ */ (0, react_jsx_runtime.jsx)(ActionResetButton, {
793
+ ...restProps,
794
+ form: restProps.form,
795
+ children: restProps.children
796
+ });
797
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionSubmitButton, {
798
+ ...restProps,
799
+ form: restProps.form,
800
+ children: restProps.children
801
+ });
802
+ }
803
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Button, {
804
+ ...restProps,
805
+ children: restProps.children
806
+ });
807
+ };
808
+ let actionElement = renderAction();
809
+ if (menu) actionElement = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Menu.Target, {
816
+ ...menu.targetProps,
817
+ children: actionElement
818
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Menu.Dropdown, { children: menu.items.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionMenuItem, {
819
+ item,
820
+ index
821
+ }, index)) })]
822
+ });
823
+ if (tooltip) {
824
+ const defaultTooltipProps = { openDelay: 1e3 };
825
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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 = (0, __alepha_react_form.useFormState)(form);
844
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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 = (0, __alepha_react_form.useFormState)(form);
855
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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 = (0, __alepha_react.useAction)({ handler: async (e) => {
901
+ await props.onClick(e);
902
+ } }, [props.onClick]);
903
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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 = (0, __alepha_react.useRouter)();
917
+ const { isPending, isActive } = (0, __alepha_react.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Anchor, {
925
+ component: "a",
926
+ ...anchorProps,
927
+ ...props.anchorProps,
928
+ children: props.children
929
+ });
930
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.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__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Button, {
942
+ component: "a",
943
+ target,
944
+ ...buttonProps,
945
+ children: props.children
946
+ });
947
+ };
948
+ function isComponentType(param) {
949
+ if ((0, react.isValidElement)(param)) return false;
950
+ return typeof param === "function" || typeof param === "object" && param !== null && "$$typeof" in param;
951
+ }
952
+ const renderIcon = (icon) => {
953
+ if (!icon) return null;
954
+ if ((0, react.isValidElement)(icon)) return icon;
955
+ if (isComponentType(icon)) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(icon, { size: ui.sizes.icon.md });
956
+ return icon;
957
+ };
958
+
959
+ //#endregion
960
+ //#region src/core/components/buttons/BurgerButton.tsx
961
+ const BurgerButton = (props) => {
962
+ const [opened, setOpened] = (0, __alepha_react.useStore)("alepha.ui.sidebar.opened");
963
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Burger, {
964
+ opened,
965
+ onClick: () => setOpened(!opened),
966
+ hiddenFrom: "sm",
967
+ size: "sm",
968
+ ...props
969
+ });
970
+ };
971
+ var BurgerButton_default = BurgerButton;
972
+
973
+ //#endregion
974
+ //#region src/core/components/buttons/ClipboardButton.tsx
975
+ const ClipboardButton = (props) => {
976
+ const { value, timeout = 2e3, copyLabel = "Copy", copiedLabel = "Copied", children, ...buttonProps } = props;
977
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.CopyButton, {
978
+ value,
979
+ timeout,
980
+ children: ({ copied, copy }) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Tooltip, {
981
+ label: copied ? copiedLabel : copyLabel,
982
+ openDelay: 500,
983
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
984
+ color: copied ? "teal" : void 0,
985
+ onClick: copy,
986
+ icon: copied ? __tabler_icons_react.IconCheck : __tabler_icons_react.IconCopy,
987
+ ...buttonProps,
988
+ children
989
+ })
990
+ })
991
+ });
992
+ };
993
+ var ClipboardButton_default = ClipboardButton;
994
+
995
+ //#endregion
996
+ //#region src/core/components/buttons/DarkModeButton.tsx
997
+ const DarkModeButton = (props) => {
998
+ const { setColorScheme } = (0, __mantine_core.useMantineColorScheme)();
999
+ const computedColorScheme = (0, __mantine_core.useComputedColorScheme)("light");
1000
+ const [colorScheme, setColorScheme2] = (0, react.useState)("default");
1001
+ const mode = props.mode ?? "minimal";
1002
+ (0, react.useEffect)(() => {
1003
+ setColorScheme2(computedColorScheme);
1004
+ }, [computedColorScheme]);
1005
+ const toggleColorScheme = () => {
1006
+ setColorScheme(computedColorScheme === "dark" ? "light" : "dark");
1007
+ };
1008
+ if (mode === "segmented") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.SegmentedControl, {
1009
+ value: colorScheme,
1010
+ onChange: (value) => setColorScheme(value),
1011
+ data: [{
1012
+ value: "light",
1013
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
1014
+ h: 20,
1015
+ align: "center",
1016
+ justify: "center",
1017
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconSun, { size: 16 })
1018
+ })
1019
+ }, {
1020
+ value: "dark",
1021
+ label: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
1022
+ h: 20,
1023
+ align: "center",
1024
+ justify: "center",
1025
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconMoon, { size: 16 })
1026
+ })
1027
+ }],
1028
+ w: props.fullWidth ? "100%" : void 0,
1029
+ ...props.segmentedProps
1030
+ });
1031
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
1032
+ onClick: toggleColorScheme,
1033
+ variant: props.variant ?? "default",
1034
+ size: props.size ?? "sm",
1035
+ "aria-label": "Toggle color scheme",
1036
+ px: "xs",
1037
+ c: colorScheme !== "default" ? void 0 : "transparent",
1038
+ fullWidth: props.fullWidth ?? false,
1039
+ icon: colorScheme === "dark" ? __tabler_icons_react.IconSun : colorScheme === "light" ? __tabler_icons_react.IconMoon : __tabler_icons_react.IconSun,
1040
+ ...props.actionProps
1041
+ });
1042
+ };
1043
+ var DarkModeButton_default = DarkModeButton;
1044
+
1045
+ //#endregion
1046
+ //#region src/core/components/buttons/LanguageButton.tsx
1047
+ const LanguageButton = (props) => {
1048
+ const i18n = (0, __alepha_react_i18n.useI18n)();
1049
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
1050
+ variant: "default",
1051
+ icon: __tabler_icons_react.IconLanguage,
1052
+ menu: { items: i18n.languages.map((lang) => ({
1053
+ label: i18n.tr(lang),
1054
+ onClick: () => i18n.setLang(lang),
1055
+ active: i18n.lang === lang
1056
+ })) },
1057
+ ...props.actionProps
1058
+ });
1059
+ };
1060
+ var LanguageButton_default = LanguageButton;
1061
+
1062
+ //#endregion
1063
+ //#region src/core/components/buttons/OmnibarButton.tsx
1064
+ const OmnibarButton = (props) => {
1065
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
1066
+ variant: "default",
1067
+ miw: 256,
1068
+ onClick: __mantine_spotlight.spotlight.open,
1069
+ justify: "space-between",
1070
+ rightSection: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Kbd, {
1071
+ size: "sm",
1072
+ children: "⌘+K"
1073
+ }),
1074
+ radius: "md",
1075
+ ...props.actionProps,
1076
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
1077
+ align: "center",
1078
+ gap: "xs",
1079
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconSearch, {
1080
+ size: 16,
1081
+ color: "gray"
1082
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
1083
+ size: "xs",
1084
+ c: "dimmed",
1085
+ children: "Search..."
1086
+ })]
1087
+ })
1088
+ });
1089
+ };
1090
+ var OmnibarButton_default = OmnibarButton;
1091
+
1092
+ //#endregion
1093
+ //#region src/core/utils/icons.tsx
1094
+ /**
1095
+ * Get the default icon for an input based on its type, format, or name.
1096
+ */
1097
+ const getDefaultIcon = (params) => {
1098
+ const { type, format, name, isEnum, isArray, size = "sm" } = params;
1099
+ const iconSize = ui.sizes.icon[size];
1100
+ if (format) switch (format) {
1101
+ case "email": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconMail, { size: iconSize });
1102
+ case "url":
1103
+ case "uri": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconLink, { size: iconSize });
1104
+ case "tel":
1105
+ case "phone": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconPhone, { size: iconSize });
1106
+ case "date": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconCalendar, { size: iconSize });
1107
+ case "date-time": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconCalendar, { size: iconSize });
1108
+ case "time": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconClock, { size: iconSize });
1109
+ case "color": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconColorPicker, { size: iconSize });
1110
+ case "uuid": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconKey, { size: iconSize });
1111
+ }
1112
+ if (name) {
1113
+ const nameLower = name.toLowerCase();
1114
+ if (nameLower.includes("password") || nameLower.includes("secret")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconKey, { size: iconSize });
1115
+ if (nameLower.includes("email") || nameLower.includes("mail")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconMail, { size: iconSize });
1116
+ if (nameLower.includes("url") || nameLower.includes("link")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconLink, { size: iconSize });
1117
+ if (nameLower.includes("phone") || nameLower.includes("tel")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconPhone, { size: iconSize });
1118
+ if (nameLower.includes("color")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconPalette, { size: iconSize });
1119
+ if (nameLower.includes("file") || nameLower.includes("upload")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconFile, { size: iconSize });
1120
+ if (nameLower.includes("date")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconCalendar, { size: iconSize });
1121
+ if (nameLower.includes("time")) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconClock, { size: iconSize });
1122
+ }
1123
+ if (isEnum || isArray) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconSelector, { size: iconSize });
1124
+ if (type) switch (type) {
1125
+ case "boolean": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconToggleLeft, { size: iconSize });
1126
+ case "number":
1127
+ case "integer": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconHash, { size: iconSize });
1128
+ case "array": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconList, { size: iconSize });
1129
+ case "string": return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconLetterCase, { size: iconSize });
1130
+ }
1131
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconAt, { size: iconSize });
1132
+ };
1133
+
1134
+ //#endregion
1135
+ //#region src/core/utils/string.ts
1136
+ /**
1137
+ * Capitalizes the first letter of a string.
1138
+ *
1139
+ * @example
1140
+ * capitalize("hello") // "Hello"
1141
+ */
1142
+ const capitalize = (str) => {
1143
+ return str.charAt(0).toUpperCase() + str.slice(1);
1144
+ };
1145
+ /**
1146
+ * Converts a path or identifier string into a pretty display name.
1147
+ * Removes slashes and capitalizes the first letter.
1148
+ *
1149
+ * @example
1150
+ * prettyName("/userName") // "UserName"
1151
+ * prettyName("email") // "Email"
1152
+ */
1153
+ const prettyName = (name) => {
1154
+ return capitalize(name.replaceAll("/", ""));
1155
+ };
1156
+
1157
+ //#endregion
1158
+ //#region src/core/utils/parseInput.ts
1159
+ const parseInput = (props, form) => {
1160
+ const disabled = false;
1161
+ const id = props.input.props.id;
1162
+ 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);
1163
+ const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
1164
+ const error = form.error && form.error instanceof alepha.TypeBoxError ? form.error.value.message : void 0;
1165
+ const icon = !props.icon ? getDefaultIcon({
1166
+ type: props.input.schema && "type" in props.input.schema ? String(props.input.schema.type) : void 0,
1167
+ format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
1168
+ name: props.input.props.name,
1169
+ isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
1170
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
1171
+ }) : (0, react.isValidElement)(props.icon) ? props.icon : (0, react.createElement)(props.icon, { size: ui.sizes.icon.md });
1172
+ const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
1173
+ const required = props.input.required;
1174
+ const schema = props.input.schema;
1175
+ const inputProps = {
1176
+ label,
1177
+ description,
1178
+ error,
1179
+ required,
1180
+ disabled
1181
+ };
1182
+ if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
1183
+ if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
1184
+ if ("minimum" in schema && typeof schema.minimum === "number") inputProps.minimum = schema.minimum;
1185
+ if ("maximum" in schema && typeof schema.maximum === "number") inputProps.maximum = schema.maximum;
1186
+ return {
1187
+ id,
1188
+ icon,
1189
+ format,
1190
+ schema: props.input.schema,
1191
+ inputProps
1192
+ };
1193
+ };
1194
+
1195
+ //#endregion
1196
+ //#region src/core/components/form/ControlDate.tsx
1197
+ /**
1198
+ * ControlDate component for handling date, datetime, and time inputs.
1199
+ *
1200
+ * Features:
1201
+ * - DateInput for date format
1202
+ * - DateTimePicker for date-time format
1203
+ * - TimeInput for time format
1204
+ *
1205
+ * Automatically detects date formats from schema and renders appropriate picker.
1206
+ */
1207
+ const ControlDate = (props) => {
1208
+ const { inputProps, id, icon, format } = parseInput(props, (0, __alepha_react_form.useFormState)(props.input));
1209
+ if (!props.input?.props) return null;
1210
+ if (props.datetime || format === "date-time") {
1211
+ const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
1212
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_dates.DateTimePicker, {
1213
+ ...inputProps,
1214
+ id,
1215
+ leftSection: icon,
1216
+ defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
1217
+ onChange: (value) => {
1218
+ props.input.set(value ? new Date(value).toISOString() : void 0);
1219
+ },
1220
+ ...dateTimePickerProps
1221
+ });
1222
+ }
1223
+ if (props.date || format === "date") {
1224
+ const dateInputProps = typeof props.date === "object" ? props.date : {};
1225
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_dates.DateInput, {
1226
+ ...inputProps,
1227
+ id,
1228
+ leftSection: icon,
1229
+ defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
1230
+ onChange: (value) => {
1231
+ props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
1232
+ },
1233
+ ...dateInputProps
1234
+ });
1235
+ }
1236
+ if (props.time || format === "time") {
1237
+ const timeInputProps = typeof props.time === "object" ? props.time : {};
1238
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_dates.TimeInput, {
1239
+ ...inputProps,
1240
+ id,
1241
+ leftSection: icon,
1242
+ defaultValue: props.input.props.defaultValue,
1243
+ onChange: (event) => {
1244
+ props.input.set(event.currentTarget.value);
1245
+ },
1246
+ ...timeInputProps
1247
+ });
1248
+ }
1249
+ return null;
1250
+ };
1251
+ var ControlDate_default = ControlDate;
1252
+
1253
+ //#endregion
1254
+ //#region src/core/components/form/ControlNumber.tsx
1255
+ /**
1256
+ *
1257
+ */
1258
+ const ControlNumber = (props) => {
1259
+ const { inputProps, id, icon } = parseInput(props, (0, __alepha_react_form.useFormState)(props.input));
1260
+ const ref = (0, react.useRef)(null);
1261
+ const [value, setValue] = (0, react.useState)(props.input.props.defaultValue);
1262
+ (0, __alepha_react.useEvents)({ "form:reset": (event) => {
1263
+ if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
1264
+ } }, [props.input]);
1265
+ if (!props.input?.props) return null;
1266
+ const { type, ...inputPropsWithoutType } = props.input.props;
1267
+ if (props.sliderProps) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Input.Wrapper, {
1268
+ ...inputProps,
1269
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1270
+ style: {
1271
+ height: 32,
1272
+ padding: 8
1273
+ },
1274
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Slider, {
1275
+ ...inputProps,
1276
+ ref,
1277
+ id,
1278
+ ...inputPropsWithoutType,
1279
+ ...props.sliderProps,
1280
+ value,
1281
+ onChange: (val) => {
1282
+ setValue(val);
1283
+ props.input.set(val);
1284
+ }
1285
+ })
1286
+ })
1287
+ });
1288
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.NumberInput, {
1289
+ ...inputProps,
1290
+ ref,
1291
+ id,
1292
+ leftSection: icon,
1293
+ ...inputPropsWithoutType,
1294
+ ...props.numberInputProps,
1295
+ value: value ?? "",
1296
+ onChange: (val) => {
1297
+ const newValue = val !== null ? Number(val) : void 0;
1298
+ setValue(newValue);
1299
+ props.input.set(newValue);
1300
+ }
1301
+ });
1302
+ };
1303
+ var ControlNumber_default = ControlNumber;
1304
+
1305
+ //#endregion
1306
+ //#region src/core/utils/extractSchemaFields.ts
1307
+ /**
1308
+ * Extract field information from a TypeBox schema for query building.
1309
+ * Supports nested objects and provides field metadata for autocomplete.
1310
+ */
1311
+ function extractSchemaFields(schema, prefix = "") {
1312
+ const fields = [];
1313
+ if (!schema || typeof schema !== "object") return fields;
1314
+ const properties = "properties" in schema ? schema.properties : schema;
1315
+ if (!properties || typeof properties !== "object") return fields;
1316
+ for (const [key, value] of Object.entries(properties)) {
1317
+ if (typeof value !== "object" || value === null) continue;
1318
+ const fieldSchema = value;
1319
+ const path = prefix ? `${prefix}.${key}` : key;
1320
+ const format = "format" in fieldSchema ? fieldSchema.format : void 0;
1321
+ let displayType = "type" in fieldSchema ? fieldSchema.type : "object";
1322
+ if (format === "date-time") displayType = "datetime";
1323
+ else if (format === "date") displayType = "date";
1324
+ else if (format === "time") displayType = "time";
1325
+ else if (format === "duration") displayType = "duration";
1326
+ const field = {
1327
+ name: key,
1328
+ path,
1329
+ type: displayType,
1330
+ format,
1331
+ description: "description" in fieldSchema ? fieldSchema.description : void 0
1332
+ };
1333
+ if ("enum" in fieldSchema && fieldSchema.enum) {
1334
+ field.enum = fieldSchema.enum;
1335
+ field.type = "enum";
1336
+ }
1337
+ if ("type" in fieldSchema && fieldSchema.type === "object" && "properties" in fieldSchema && typeof fieldSchema.properties === "object") field.nested = extractSchemaFields(fieldSchema.properties, path);
1338
+ fields.push(field);
1339
+ if (field.nested) fields.push(...field.nested);
1340
+ }
1341
+ return fields;
1342
+ }
1343
+ /**
1344
+ * Get suggested operators based on field type
1345
+ */
1346
+ function getOperatorsForField(field) {
1347
+ const allOperators = ["=", "!="];
1348
+ if (field.enum) return [...allOperators, "in"];
1349
+ switch (field.type) {
1350
+ case "string":
1351
+ case "text": return [...allOperators, "null"];
1352
+ case "number":
1353
+ case "integer": return [
1354
+ ...allOperators,
1355
+ ">",
1356
+ ">=",
1357
+ "<",
1358
+ "<="
1359
+ ];
1360
+ case "boolean": return allOperators;
1361
+ case "datetime":
1362
+ case "date": return [
1363
+ ...allOperators,
1364
+ ">",
1365
+ ">=",
1366
+ "<",
1367
+ "<="
1368
+ ];
1369
+ default: return [...allOperators, "null"];
1370
+ }
1371
+ }
1372
+ /**
1373
+ * Get operator symbol and description
1374
+ */
1375
+ const OPERATOR_INFO = {
1376
+ eq: {
1377
+ symbol: "=",
1378
+ label: "equals",
1379
+ example: "name=John"
1380
+ },
1381
+ ne: {
1382
+ symbol: "!=",
1383
+ label: "not equals",
1384
+ example: "status!=archived"
1385
+ },
1386
+ gt: {
1387
+ symbol: ">",
1388
+ label: "greater than",
1389
+ example: "age>18"
1390
+ },
1391
+ gte: {
1392
+ symbol: ">=",
1393
+ label: "greater or equal",
1394
+ example: "age>=18"
1395
+ },
1396
+ lt: {
1397
+ symbol: "<",
1398
+ label: "less than",
1399
+ example: "age<65"
1400
+ },
1401
+ lte: {
1402
+ symbol: "<=",
1403
+ label: "less or equal",
1404
+ example: "age<=65"
1405
+ },
1406
+ null: {
1407
+ symbol: "=null",
1408
+ label: "is null",
1409
+ example: "deletedAt=null"
1410
+ },
1411
+ notNull: {
1412
+ symbol: "!=null",
1413
+ label: "is not null",
1414
+ example: "email!=null"
1415
+ },
1416
+ in: {
1417
+ symbol: "[...]",
1418
+ label: "in array",
1419
+ example: "status=[active,pending]"
1420
+ }
1421
+ };
1422
+
1423
+ //#endregion
1424
+ //#region src/core/components/form/ControlQueryBuilder.tsx
1425
+ /**
1426
+ * Query builder with text input and help popover.
1427
+ * Generates query strings for parseQueryString syntax.
1428
+ */
1429
+ const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
1430
+ const [helpOpened, setHelpOpened] = (0, react.useState)(false);
1431
+ const [textValue, setTextValue] = (0, react.useState)(value);
1432
+ const inputRef = (0, react.useRef)(null);
1433
+ const fields = schema ? extractSchemaFields(schema) : [];
1434
+ const [error, setError] = (0, react.useState)(null);
1435
+ const isValid = (value$1) => {
1436
+ try {
1437
+ (0, alepha_orm.parseQueryString)(value$1.trim());
1438
+ } catch (e) {
1439
+ setError(e.message);
1440
+ return false;
1441
+ }
1442
+ setError(null);
1443
+ return true;
1444
+ };
1445
+ const handleTextChange = (newValue) => {
1446
+ setTextValue(newValue);
1447
+ if (isValid(newValue)) onChange?.(newValue);
1448
+ };
1449
+ const handleClear = () => {
1450
+ setTextValue("");
1451
+ onChange?.("");
1452
+ isValid("");
1453
+ };
1454
+ const handleInsert = (text) => {
1455
+ const newValue = textValue ? `${textValue}${text} ` : `${text} `;
1456
+ setTextValue(newValue);
1457
+ if (isValid(newValue)) onChange?.(newValue);
1458
+ setTimeout(() => {
1459
+ inputRef.current?.focus();
1460
+ const length = inputRef.current?.value.length || 0;
1461
+ inputRef.current?.setSelectionRange(length, length);
1462
+ }, 0);
1463
+ };
1464
+ (0, __alepha_react.useEvents)({ "form:change": (event) => {
1465
+ if (event.id === inputRef.current?.form?.id) {
1466
+ if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
1467
+ }
1468
+ } }, []);
1469
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Popover, {
1470
+ width: 800,
1471
+ position: "bottom-start",
1472
+ shadow: "md",
1473
+ opened: helpOpened,
1474
+ onChange: setHelpOpened,
1475
+ closeOnClickOutside: true,
1476
+ closeOnEscape: true,
1477
+ transitionProps: {
1478
+ transition: "fade-up",
1479
+ duration: 200,
1480
+ timingFunction: "ease"
1481
+ },
1482
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Popover.Target, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.TextInput, {
1483
+ ref: inputRef,
1484
+ placeholder,
1485
+ value: textValue,
1486
+ onChange: (e) => handleTextChange(e.currentTarget.value),
1487
+ onFocus: () => setHelpOpened(true),
1488
+ leftSection: error ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconFilter, { size: 16 }),
1489
+ rightSection: textValue && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.ActionIcon, {
1490
+ size: "sm",
1491
+ variant: "subtle",
1492
+ color: "gray",
1493
+ onClick: handleClear,
1494
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconX, { size: 14 })
1495
+ }),
1496
+ ...textInputProps
1497
+ }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Popover.Dropdown, {
1498
+ bg: "transparent",
1499
+ p: "xs",
1500
+ bd: `1px solid ${ui.colors.border}`,
1501
+ style: { backdropFilter: "blur(20px)" },
1502
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(QueryHelp, {
1503
+ fields,
1504
+ onInsert: handleInsert
1505
+ })
1506
+ })]
1507
+ });
1508
+ };
1509
+ function QueryHelp({ fields, onInsert }) {
1510
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Group, {
1511
+ gap: "md",
1512
+ align: "flex-start",
1513
+ wrap: "nowrap",
1514
+ bg: ui.colors.surface,
1515
+ p: "sm",
1516
+ bdrs: "sm",
1517
+ children: [
1518
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Stack, {
1519
+ gap: "md",
1520
+ style: { flex: 1 },
1521
+ children: [
1522
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Stack, {
1523
+ gap: "xs",
1524
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
1525
+ size: "sm",
1526
+ fw: 600,
1527
+ children: "Operators"
1528
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Stack, {
1529
+ gap: 4,
1530
+ children: Object.entries(OPERATOR_INFO).map(([key, info]) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Group, {
1531
+ gap: "xs",
1532
+ wrap: "nowrap",
1533
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
1534
+ px: "xs",
1535
+ size: "xs",
1536
+ h: 24,
1537
+ variant: "default",
1538
+ justify: "center",
1539
+ miw: 48,
1540
+ onClick: () => onInsert(info.symbol),
1541
+ children: info.symbol
1542
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
1543
+ size: "xs",
1544
+ c: "dimmed",
1545
+ style: { flex: 1 },
1546
+ children: info.label
1547
+ })]
1548
+ }, key))
1549
+ })]
1550
+ }),
1551
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Divider, {}),
1552
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Stack, {
1553
+ gap: "xs",
1554
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
1555
+ size: "sm",
1556
+ fw: 600,
1557
+ children: "Logic"
1558
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Stack, {
1559
+ gap: 4,
1560
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Group, {
1561
+ gap: "xs",
1562
+ wrap: "nowrap",
1563
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
1564
+ px: "xs",
1565
+ size: "xs",
1566
+ h: 24,
1567
+ variant: "default",
1568
+ justify: "center",
1569
+ miw: 48,
1570
+ onClick: () => onInsert("&"),
1571
+ children: "&"
1572
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
1573
+ size: "xs",
1574
+ c: "dimmed",
1575
+ children: "AND"
1576
+ })]
1577
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Group, {
1578
+ gap: "xs",
1579
+ wrap: "nowrap",
1580
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
1581
+ px: "xs",
1582
+ size: "xs",
1583
+ h: 24,
1584
+ variant: "default",
1585
+ justify: "center",
1586
+ miw: 48,
1587
+ onClick: () => onInsert("|"),
1588
+ children: "|"
1589
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
1590
+ size: "xs",
1591
+ c: "dimmed",
1592
+ children: "OR"
1593
+ })]
1594
+ })]
1595
+ })]
1596
+ })
1597
+ ]
1598
+ }),
1599
+ fields.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Divider, { orientation: "vertical" }),
1600
+ fields.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
1601
+ direction: "column",
1602
+ gap: "xs",
1603
+ style: { flex: 2 },
1604
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
1605
+ size: "sm",
1606
+ fw: 600,
1607
+ children: "Fields"
1608
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
1609
+ direction: "column",
1610
+ gap: 4,
1611
+ style: {
1612
+ maxHeight: 300,
1613
+ overflowY: "auto"
1614
+ },
1615
+ children: fields.map((field) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
1616
+ gap: "xs",
1617
+ wrap: "nowrap",
1618
+ align: "flex-start",
1619
+ children: [
1620
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
1621
+ px: "xs",
1622
+ size: "xs",
1623
+ h: 24,
1624
+ variant: "default",
1625
+ justify: "end",
1626
+ miw: 120,
1627
+ onClick: () => onInsert(field.path),
1628
+ children: field.path
1629
+ }),
1630
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
1631
+ mt: 3,
1632
+ direction: "column",
1633
+ gap: 2,
1634
+ style: {
1635
+ flex: 1,
1636
+ minWidth: 0
1637
+ },
1638
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
1639
+ size: "xs",
1640
+ c: "dimmed",
1641
+ lineClamp: 1,
1642
+ children: field.description || field.type
1643
+ }), field.enum && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Group, {
1644
+ gap: 0,
1645
+ wrap: "wrap",
1646
+ children: field.enum.map((enumValue) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
1647
+ px: "xs",
1648
+ size: "xs",
1649
+ h: 24,
1650
+ onClick: () => onInsert(enumValue),
1651
+ children: enumValue
1652
+ }, enumValue))
1653
+ })]
1654
+ }),
1655
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Badge, {
1656
+ size: "xs",
1657
+ variant: "light",
1658
+ style: { flexShrink: 0 },
1659
+ children: field.type
1660
+ })
1661
+ ]
1662
+ }, field.path))
1663
+ })]
1664
+ })
1665
+ ]
1666
+ });
1667
+ }
1668
+ var ControlQueryBuilder_default = ControlQueryBuilder;
1669
+
1670
+ //#endregion
1671
+ //#region src/core/components/form/ControlSelect.tsx
1672
+ /**
1673
+ * ControlSelect component for handling Select, MultiSelect, and TagsInput.
1674
+ *
1675
+ * Features:
1676
+ * - Basic Select with enum support
1677
+ * - MultiSelect for array of enums
1678
+ * - TagsInput for array of strings (no enum)
1679
+ * - Future: Lazy loading
1680
+ * - Future: Searchable/filterable options
1681
+ * - Future: Custom option rendering
1682
+ *
1683
+ * Automatically detects enum values and array types from schema.
1684
+ */
1685
+ const ControlSelect = (props) => {
1686
+ const { inputProps, id, icon } = parseInput(props, (0, __alepha_react_form.useFormState)(props.input));
1687
+ const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
1688
+ let itemsEnum;
1689
+ if (isArray && "items" in props.input.schema && props.input.schema.items) {
1690
+ const items = props.input.schema.items;
1691
+ if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
1692
+ }
1693
+ const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
1694
+ const [data, setData] = (0, react.useState)([]);
1695
+ (0, react.useEffect)(() => {
1696
+ if (!props.input?.props) return;
1697
+ if (props.loader) props.loader().then(setData);
1698
+ else setData(enumValues);
1699
+ }, [props.input, props.loader]);
1700
+ if (!props.input?.props) return null;
1701
+ if (props.segmented) {
1702
+ const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
1703
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Input.Wrapper, {
1704
+ ...inputProps,
1705
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.SegmentedControl, {
1706
+ disabled: inputProps.disabled,
1707
+ defaultValue: String(props.input.props.defaultValue),
1708
+ ...segmentedControlProps,
1709
+ onChange: (value) => {
1710
+ props.input.set(value);
1711
+ },
1712
+ data: data.slice(0, 10)
1713
+ }) })
1714
+ });
1715
+ }
1716
+ if (props.autocomplete) {
1717
+ const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
1718
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Autocomplete, {
1719
+ ...inputProps,
1720
+ id,
1721
+ leftSection: icon,
1722
+ data,
1723
+ ...props.input.props,
1724
+ ...autocompleteProps
1725
+ });
1726
+ }
1727
+ if (isArray && !itemsEnum || props.tags) {
1728
+ const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
1729
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.TagsInput, {
1730
+ ...inputProps,
1731
+ id,
1732
+ leftSection: icon,
1733
+ defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
1734
+ onChange: (value) => {
1735
+ props.input.set(value);
1736
+ },
1737
+ ...tagsInputProps
1738
+ });
1739
+ }
1740
+ if (isArray && itemsEnum || props.multi) {
1741
+ const data$1 = itemsEnum?.map((value) => ({
1742
+ value,
1743
+ label: value
1744
+ })) || [];
1745
+ const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
1746
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.MultiSelect, {
1747
+ ...inputProps,
1748
+ id,
1749
+ leftSection: icon,
1750
+ data: data$1,
1751
+ defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
1752
+ onChange: (value) => {
1753
+ props.input.set(value);
1754
+ },
1755
+ ...multiSelectProps
1756
+ });
1757
+ }
1758
+ const selectProps = typeof props.select === "object" ? props.select : {};
1759
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Select, {
1760
+ ...inputProps,
1761
+ id,
1762
+ leftSection: icon,
1763
+ data,
1764
+ ...props.input.props,
1765
+ ...selectProps
1766
+ });
1767
+ };
1768
+ var ControlSelect_default = ControlSelect;
1769
+
1770
+ //#endregion
1771
+ //#region src/core/components/form/Control.tsx
1772
+ /**
1773
+ * Generic form control that renders the appropriate input based on the schema and props.
1774
+ *
1775
+ * Supports:
1776
+ * - TextInput (with format detection: email, url, tel)
1777
+ * - Textarea
1778
+ * - NumberInput (for number/integer types)
1779
+ * - FileInput
1780
+ * - ColorInput (for color format)
1781
+ * - Select (for enum types)
1782
+ * - Autocomplete
1783
+ * - PasswordInput
1784
+ * - Switch (for boolean types)
1785
+ * - SegmentedControl (for enum types)
1786
+ * - DateInput (for date format)
1787
+ * - DateTimePicker (for date-time format)
1788
+ * - TimeInput (for time format)
1789
+ * - QueryBuilder (for building type-safe queries with autocomplete)
1790
+ * - Custom component
1791
+ *
1792
+ * Automatically handles labels, descriptions, error messages, required state, and default icons.
1793
+ */
1794
+ const Control = (_props) => {
1795
+ const { inputProps, id, icon, format, schema } = parseInput(_props, (0, __alepha_react_form.useFormState)(_props.input, ["error"]));
1796
+ if (!_props.input?.props) return null;
1797
+ const props = {
1798
+ ..._props,
1799
+ ...schema.$control
1800
+ };
1801
+ if (props.query) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlQueryBuilder_default, {
1802
+ ...props.input.props,
1803
+ ...inputProps,
1804
+ schema: props.query,
1805
+ value: props.input.props.value,
1806
+ onChange: (value) => {
1807
+ props.input.set(value);
1808
+ }
1809
+ });
1810
+ if (props.custom) {
1811
+ const Custom = props.custom;
1812
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Input.Wrapper, {
1813
+ ...inputProps,
1814
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
1815
+ flex: 1,
1816
+ mt: "calc(var(--mantine-spacing-xs) / 2)",
1817
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Custom, {
1818
+ defaultValue: props.input.props.defaultValue,
1819
+ onChange: (value) => {
1820
+ props.input.set(value);
1821
+ }
1822
+ })
1823
+ })
1824
+ });
1825
+ }
1826
+ if (props.number || props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
1827
+ const controlNumberProps = typeof props.number === "object" ? props.number : {};
1828
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlNumber_default, {
1829
+ input: props.input,
1830
+ title: props.title,
1831
+ description: props.description,
1832
+ icon,
1833
+ ...controlNumberProps
1834
+ });
1835
+ }
1836
+ if (props.file) {
1837
+ const fileInputProps = typeof props.file === "object" ? props.file : {};
1838
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.FileInput, {
1839
+ ...inputProps,
1840
+ id,
1841
+ leftSection: icon,
1842
+ onChange: (file) => {
1843
+ props.input.set(file);
1844
+ },
1845
+ ...fileInputProps
1846
+ });
1847
+ }
1848
+ if (props.color || format === "color") {
1849
+ const colorInputProps = typeof props.color === "object" ? props.color : {};
1850
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.ColorInput, {
1851
+ ...inputProps,
1852
+ id,
1853
+ leftSection: icon,
1854
+ ...props.input.props,
1855
+ ...colorInputProps
1856
+ });
1857
+ }
1858
+ const isEnum = props.input.schema && "enum" in props.input.schema && props.input.schema.enum;
1859
+ const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
1860
+ if (isEnum || isArray || props.select) {
1861
+ const opts = typeof props.select === "object" ? props.select : {};
1862
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlSelect_default, {
1863
+ input: props.input,
1864
+ title: props.title,
1865
+ description: props.description,
1866
+ icon,
1867
+ ...opts
1868
+ });
1869
+ }
1870
+ if (props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean" || props.switch) {
1871
+ const switchProps = typeof props.switch === "object" ? props.switch : {};
1872
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Switch, {
1873
+ ...inputProps,
1874
+ id,
1875
+ color: "blue",
1876
+ defaultChecked: props.input.props.defaultValue,
1877
+ ...props.input.props,
1878
+ ...switchProps
1879
+ });
1880
+ }
1881
+ if (props.password || props.input.props.name?.includes("password")) {
1882
+ const passwordInputProps = typeof props.password === "object" ? props.password : {};
1883
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.PasswordInput, {
1884
+ ...inputProps,
1885
+ id,
1886
+ leftSection: icon,
1887
+ ...props.input.props,
1888
+ ...passwordInputProps
1889
+ });
1890
+ }
1891
+ if (props.area) {
1892
+ const textAreaProps = typeof props.area === "object" ? props.area : {};
1893
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Textarea, {
1894
+ ...inputProps,
1895
+ id,
1896
+ leftSection: icon,
1897
+ ...props.input.props,
1898
+ ...textAreaProps
1899
+ });
1900
+ }
1901
+ if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ControlDate_default, {
1902
+ input: props.input,
1903
+ title: props.title,
1904
+ description: props.description,
1905
+ icon,
1906
+ date: props.date,
1907
+ datetime: props.datetime,
1908
+ time: props.time
1909
+ });
1910
+ const textInputProps = typeof props.text === "object" ? props.text : {};
1911
+ const getInputType = () => {
1912
+ switch (format) {
1913
+ case "email": return "email";
1914
+ case "url":
1915
+ case "uri": return "url";
1916
+ case "tel":
1917
+ case "phone": return "tel";
1918
+ default: return;
1919
+ }
1920
+ };
1921
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.TextInput, {
1922
+ ...inputProps,
1923
+ id,
1924
+ leftSection: icon,
1925
+ type: getInputType(),
1926
+ ...props.input.props,
1927
+ ...textInputProps,
1928
+ inputWrapperOrder: [
1929
+ "label",
1930
+ "input",
1931
+ "description",
1932
+ "error"
1933
+ ]
1934
+ });
1935
+ };
1936
+ var Control_default = Control;
1937
+
1938
+ //#endregion
1939
+ //#region src/core/components/form/TypeForm.tsx
1940
+ /**
1941
+ * TypeForm component that automatically renders all form inputs based on schema.
1942
+ * Uses the Control component to render individual fields and Mantine Grid for responsive layout.
1943
+ *
1944
+ * @example
1945
+ * ```tsx
1946
+ * import { t } from "alepha";
1947
+ * import { useForm } from "@alepha/react/form";
1948
+ * import { TypeForm } from "@alepha/ui";
1949
+ *
1950
+ * const form = useForm({
1951
+ * schema: t.object({
1952
+ * username: t.text(),
1953
+ * email: t.text(),
1954
+ * age: t.integer(),
1955
+ * subscribe: t.boolean(),
1956
+ * }),
1957
+ * handler: (values) => {
1958
+ * console.log(values);
1959
+ * },
1960
+ * });
1961
+ *
1962
+ * return <TypeForm form={form} columns={2} />;
1963
+ * ```
1964
+ */
1965
+ const TypeForm = (props) => {
1966
+ const { form, columns = 3, children, controlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps } = props;
1967
+ const schema = props.schema || form.options.schema;
1968
+ if (!schema?.properties) return null;
1969
+ const supportedFields = Object.keys(schema.properties).filter((fieldName) => {
1970
+ const field = form.input[fieldName];
1971
+ if (!field || typeof field !== "object" || !("schema" in field)) return false;
1972
+ const schema$1 = field.schema;
1973
+ if ("type" in schema$1) {
1974
+ if (schema$1.type === "object") return false;
1975
+ }
1976
+ if ("properties" in schema$1 && schema$1.properties) return false;
1977
+ return true;
1978
+ });
1979
+ const colSpan = typeof columns === "number" ? {
1980
+ xs: 12,
1981
+ sm: 6,
1982
+ lg: 12 / columns
1983
+ } : {
1984
+ base: columns.base ? 12 / columns.base : void 0,
1985
+ xs: columns.xs ? 12 / columns.xs : 12,
1986
+ sm: columns.sm ? 12 / columns.sm : 6,
1987
+ md: columns.md ? 12 / columns.md : void 0,
1988
+ lg: columns.lg ? 12 / columns.lg : 4,
1989
+ xl: columns.xl ? 12 / columns.xl : void 0
1990
+ };
1991
+ const renderFields = () => {
1992
+ if (children) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: children(form.input) });
1993
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Grid, { children: supportedFields.map((fieldName) => {
1994
+ const field = form.input[fieldName];
1995
+ if (!field || typeof field !== "object" || !("schema" in field)) return null;
1996
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Grid.Col, {
1997
+ span: colSpan,
1998
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Control_default, {
1999
+ input: field,
2000
+ ...controlProps
2001
+ })
2002
+ }, fieldName);
2003
+ }) });
2004
+ };
2005
+ const content = /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2006
+ direction: "column",
2007
+ gap: "sm",
2008
+ children: [renderFields(), !skipSubmitButton && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2009
+ gap: "sm",
2010
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
2011
+ form,
2012
+ ...submitButtonProps,
2013
+ children: submitButtonProps?.children ?? "Submit"
2014
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
2015
+ type: "reset",
2016
+ children: "Reset"
2017
+ })]
2018
+ })]
2019
+ });
2020
+ if (skipFormElement) return content;
2021
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("form", {
2022
+ ...form.props,
2023
+ children: content
2024
+ });
2025
+ };
2026
+ var TypeForm_default = TypeForm;
2027
+
2028
+ //#endregion
2029
+ //#region src/core/components/layout/AppBar.tsx
2030
+ const AppBar = (props) => {
2031
+ const { items = [] } = props;
2032
+ const renderItem = (item, index) => {
2033
+ if ("type" in item) {
2034
+ if (item.type === "burger") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(BurgerButton_default, {}, index);
2035
+ if (item.type === "dark") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DarkModeButton_default, { ...item.props }, index);
2036
+ if (item.type === "search") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OmnibarButton_default, { ...item.props }, index);
2037
+ if (item.type === "lang") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(LanguageButton_default, { ...item.props }, index);
2038
+ if (item.type === "spacer") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { w: 16 }, index);
2039
+ if (item.type === "divider") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Divider, { orientation: "vertical" }, index);
2040
+ }
2041
+ if ("element" in item) return item.element;
2042
+ return null;
2043
+ };
2044
+ const leftItems = items.filter((item) => item.position === "left");
2045
+ const centerItems = items.filter((item) => item.position === "center");
2046
+ const rightItems = items.filter((item) => item.position === "right");
2047
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2048
+ h: "100%",
2049
+ align: "center",
2050
+ px: "md",
2051
+ justify: "space-between",
2052
+ ...props.flexProps,
2053
+ children: [
2054
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
2055
+ flex: 1,
2056
+ children: leftItems.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
2057
+ ml: index === 0 ? 0 : "md",
2058
+ align: "center",
2059
+ children: renderItem(item, index)
2060
+ }, index))
2061
+ }),
2062
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { children: centerItems.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
2063
+ mx: "md",
2064
+ align: "center",
2065
+ children: renderItem(item, index)
2066
+ }, index)) }),
2067
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
2068
+ flex: 1,
2069
+ align: "center",
2070
+ justify: "end",
2071
+ children: rightItems.map((item, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
2072
+ ml: index === 0 ? 0 : "md",
2073
+ align: "center",
2074
+ children: renderItem(item, index)
2075
+ }, index))
2076
+ })
2077
+ ]
2078
+ });
2079
+ };
2080
+ var AppBar_default = AppBar;
2081
+
2082
+ //#endregion
2083
+ //#region src/core/components/layout/Sidebar.tsx
2084
+ const Sidebar = (props) => {
2085
+ const router = (0, __alepha_react.useRouter)();
2086
+ const { top = [], bottom = [], onItemClick } = props;
2087
+ const renderNode = (item, key) => {
2088
+ if ("type" in item) {
2089
+ if (item.type === "spacer") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { h: 16 }, key);
2090
+ if (item.type === "divider") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
2091
+ h: 1,
2092
+ bg: "var(--alepha-border)",
2093
+ my: "md",
2094
+ mx: "sm"
2095
+ }, key);
2096
+ if (item.type === "search") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(OmnibarButton_default, { collapsed: props.collapsed }, key);
2097
+ if (item.type === "section") {
2098
+ if (props.collapsed) return;
2099
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2100
+ mt: "md",
2101
+ mb: "xs",
2102
+ align: "center",
2103
+ gap: "xs",
2104
+ children: [renderIcon(item.icon), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
2105
+ size: "xs",
2106
+ c: "dimmed",
2107
+ tt: "uppercase",
2108
+ fw: "bold",
2109
+ children: item.label
2110
+ }, key)]
2111
+ }, key);
2112
+ }
2113
+ }
2114
+ if ("element" in item) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { children: item.element }, key);
2115
+ if (props.collapsed) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarCollapsedItem, {
2116
+ item,
2117
+ level: 0,
2118
+ onItemClick,
2119
+ theme: props.theme ?? {}
2120
+ }, key);
2121
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarItem, {
2122
+ item,
2123
+ level: 0,
2124
+ onItemClick,
2125
+ theme: props.theme ?? {}
2126
+ }, key);
2127
+ };
2128
+ const padding = "md";
2129
+ const gap = props.gap;
2130
+ const menu = props.menu ?? router.concretePages.map((page) => ({
2131
+ label: page.label ?? page.name,
2132
+ description: page.description,
2133
+ icon: renderIcon(page.icon),
2134
+ href: router.path(page.name)
2135
+ }));
2136
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2137
+ flex: 1,
2138
+ py: padding,
2139
+ direction: "column",
2140
+ className: "overflow-auto",
2141
+ ...props.flexProps,
2142
+ children: [
2143
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2144
+ gap,
2145
+ px: padding,
2146
+ direction: "column",
2147
+ children: [top.map((item, index) => renderNode(item, index)), menu.filter((it) => it.position === "top").map((item, index) => renderNode(item, index + top.length))]
2148
+ }),
2149
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
2150
+ gap,
2151
+ px: padding,
2152
+ direction: "column",
2153
+ flex: 1,
2154
+ className: "overflow-auto",
2155
+ children: menu.filter((it) => !it.position).map((item, index) => renderNode(item, index))
2156
+ }),
2157
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2158
+ gap,
2159
+ px: padding,
2160
+ direction: "column",
2161
+ children: [bottom.map((item, index) => renderNode(item, index)), menu.filter((it) => it.position === "bottom").map((item, index) => renderNode(item, index + bottom.length))]
2162
+ })
2163
+ ]
2164
+ });
2165
+ };
2166
+ const SidebarItem = (props) => {
2167
+ const { item, level } = props;
2168
+ const maxLevel = 2;
2169
+ const router = (0, __alepha_react.useRouter)();
2170
+ const isActive = (0, react.useCallback)((item$1) => {
2171
+ if (!item$1.children) return false;
2172
+ for (const child of item$1.children) {
2173
+ if (child.href) {
2174
+ if (router.isActive(child.href)) return true;
2175
+ }
2176
+ if (isActive(child)) return true;
2177
+ }
2178
+ return false;
2179
+ }, []);
2180
+ const [isOpen, setIsOpen] = (0, react.useState)(isActive(item));
2181
+ (0, __alepha_react.useEvents)({ "react:transition:end": () => {
2182
+ if (isActive(item)) setIsOpen(true);
2183
+ } }, []);
2184
+ if (level > maxLevel) return null;
2185
+ const handleItemClick = (e) => {
2186
+ if (!props.item.target) e.preventDefault();
2187
+ if (item.children && item.children.length > 0) setIsOpen(!isOpen);
2188
+ else {
2189
+ props.onItemClick?.(item);
2190
+ item.onClick?.();
2191
+ }
2192
+ };
2193
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2194
+ direction: "column",
2195
+ ps: level === 0 ? 0 : 32,
2196
+ pos: "relative",
2197
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
2198
+ w: "100%",
2199
+ justify: "space-between",
2200
+ href: props.item.href,
2201
+ target: props.item.target,
2202
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
2203
+ color: "var(--alepha-text)",
2204
+ variant: "subtle",
2205
+ variantActive: "default",
2206
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
2207
+ onClick: handleItemClick,
2208
+ leftSection: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2209
+ w: "100%",
2210
+ align: "center",
2211
+ gap: "sm",
2212
+ children: [renderIcon(item.icon), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2213
+ direction: "column",
2214
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { children: item.label }), item.description && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Text, {
2215
+ size: "xs",
2216
+ c: "dimmed",
2217
+ children: item.description
2218
+ })]
2219
+ })]
2220
+ }),
2221
+ rightSection: item.children ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { children: isOpen ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconChevronDown, { size: 14 }) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconChevronRight, { size: 14 }) }) : props.item.rightSection,
2222
+ ...props.item.actionProps
2223
+ }), item.children && isOpen && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2224
+ direction: "column",
2225
+ "data-parent-level": level,
2226
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { style: {
2227
+ position: "absolute",
2228
+ width: 1,
2229
+ background: "linear-gradient(to bottom, transparent, var(--alepha-border), transparent)",
2230
+ top: 48,
2231
+ left: 20 + 32 * level,
2232
+ bottom: 16
2233
+ } }), item.children.map((child, index) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(SidebarItem, {
2234
+ item: child,
2235
+ level: level + 1,
2236
+ onItemClick: props.onItemClick,
2237
+ theme: props.theme
2238
+ }, index))]
2239
+ })]
2240
+ });
2241
+ };
2242
+ const SidebarCollapsedItem = (props) => {
2243
+ const { item, level } = props;
2244
+ const router = (0, __alepha_react.useRouter)();
2245
+ const isActive = (0, react.useCallback)((item$1) => {
2246
+ if (!item$1.children) return false;
2247
+ for (const child of item$1.children) {
2248
+ if (child.href) {
2249
+ if (router.isActive(child.href)) return true;
2250
+ }
2251
+ if (isActive(child)) return true;
2252
+ }
2253
+ return false;
2254
+ }, []);
2255
+ const [isOpen, setIsOpen] = (0, react.useState)(isActive(item));
2256
+ const handleItemClick = (e) => {
2257
+ if (!props.item.target) e.preventDefault();
2258
+ if (item.children && item.children.length > 0) setIsOpen(!isOpen);
2259
+ else {
2260
+ props.onItemClick?.(item);
2261
+ item.onClick?.();
2262
+ }
2263
+ };
2264
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
2265
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
2266
+ color: "var(--alepha-text)",
2267
+ variant: "subtle",
2268
+ variantActive: "default",
2269
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
2270
+ onClick: handleItemClick,
2271
+ icon: renderIcon(item.icon) ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__tabler_icons_react.IconSquareRounded, {}),
2272
+ href: props.item.href,
2273
+ target: props.item.target,
2274
+ menu: item.children ? {
2275
+ position: "right",
2276
+ on: "hover",
2277
+ items: item.children.map((child) => ({
2278
+ label: child.label,
2279
+ href: child.href,
2280
+ icon: renderIcon(child.icon),
2281
+ children: child.children
2282
+ }))
2283
+ } : void 0,
2284
+ ...props.item.actionProps
2285
+ });
2286
+ };
2287
+
2288
+ //#endregion
2289
+ //#region src/core/components/layout/AdminShell.tsx
2290
+ const AdminShell = (props) => {
2291
+ const router = (0, __alepha_react.useRouter)();
2292
+ const [opened, setOpened] = (0, __alepha_react.useStore)("alepha.ui.sidebar.opened");
2293
+ const [collapsed] = (0, __alepha_react.useStore)("alepha.ui.sidebar.collapsed", props.sidebarProps?.collapsed);
2294
+ const shouldShowSidebar = () => {
2295
+ if (props.noSidebarWhen?.paths) {
2296
+ for (const path of props.noSidebarWhen.paths) if (router.isActive(path, { startWith: true })) return false;
2297
+ }
2298
+ return true;
2299
+ };
2300
+ const [showSidebar, setShowSidebar] = (0, react.useState)(shouldShowSidebar());
2301
+ (0, __alepha_react.useEvents)({
2302
+ "react:transition:end": () => {
2303
+ setShowSidebar(shouldShowSidebar());
2304
+ },
2305
+ "react:transition:begin": () => {
2306
+ setOpened(false);
2307
+ }
2308
+ }, []);
2309
+ const defaultAppBarItems = [{
2310
+ position: "left",
2311
+ type: "burger"
2312
+ }];
2313
+ const hasSidebar = showSidebar && props.sidebarProps !== void 0;
2314
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.AppShell, {
2315
+ padding: "md",
2316
+ header: hasSidebar || props.appBarProps || props.header ? { height: 60 } : void 0,
2317
+ navbar: hasSidebar ? {
2318
+ width: collapsed ? { base: 72 } : { base: 300 },
2319
+ breakpoint: "sm",
2320
+ collapsed: { mobile: !opened }
2321
+ } : void 0,
2322
+ footer: props.footer ? { height: 60 } : void 0,
2323
+ ...props.appShellProps,
2324
+ children: [
2325
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.AppShell.Header, {
2326
+ bg: ui.colors.surface,
2327
+ ...props.appShellHeaderProps,
2328
+ children: props.header ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(AppBar_default, {
2329
+ items: defaultAppBarItems,
2330
+ ...props.appBarProps
2331
+ })
2332
+ }),
2333
+ hasSidebar && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.AppShell.Navbar, {
2334
+ bg: ui.colors.surface,
2335
+ ...props.appShellNavbarProps,
2336
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Sidebar, {
2337
+ collapsed,
2338
+ ...props.sidebarProps ?? {}
2339
+ })
2340
+ }),
2341
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.AppShell.Main, {
2342
+ display: "flex",
2343
+ flex: 1,
2344
+ ...props.appShellMainProps,
2345
+ children: props.children ?? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__alepha_react.NestedView, {})
2346
+ }),
2347
+ props.footer && /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.AppShell.Footer, {
2348
+ bg: ui.colors.surface,
2349
+ ...props.appShellFooterProps,
2350
+ children: props.footer
2351
+ })
2352
+ ]
2353
+ });
2354
+ };
2355
+ var AdminShell_default = AdminShell;
2356
+
2357
+ //#endregion
2358
+ //#region src/core/components/table/DataTable.tsx
2359
+ const DataTable = (props) => {
2360
+ const [items, setItems] = (0, react.useState)(typeof props.items === "function" ? { content: [] } : props.items);
2361
+ const defaultSize = props.infinityScroll ? 100 : props.defaultSize || 10;
2362
+ const [page, setPage] = (0, react.useState)(1);
2363
+ const [size, setSize] = (0, react.useState)(String(defaultSize));
2364
+ const [currentPage, setCurrentPage] = (0, react.useState)(0);
2365
+ const alepha$1 = (0, __alepha_react.useInject)(alepha.Alepha);
2366
+ const form = (0, __alepha_react_form.useForm)({
2367
+ schema: alepha.t.object({
2368
+ ...props.filters ? props.filters.properties : {},
2369
+ page: alepha.t.number({ default: 0 }),
2370
+ size: alepha.t.number({ default: defaultSize }),
2371
+ sort: alepha.t.optional(alepha.t.string())
2372
+ }),
2373
+ handler: async (values, args) => {
2374
+ if (typeof props.items === "function") {
2375
+ const response = await props.items(values, { items: items.content });
2376
+ if (props.infinityScroll && values.page > 0) setItems((prev) => ({
2377
+ ...response,
2378
+ content: [...prev.content, ...response.content]
2379
+ }));
2380
+ else setItems(response);
2381
+ setCurrentPage(values.page);
2382
+ }
2383
+ },
2384
+ onReset: async () => {
2385
+ setPage(1);
2386
+ setSize("10");
2387
+ await form.submit();
2388
+ },
2389
+ onChange: async (key, value) => {
2390
+ if (key === "page") {
2391
+ setPage(value + 1);
2392
+ await form.submit();
2393
+ return;
2394
+ }
2395
+ if (key === "size") {
2396
+ setSize(String(value));
2397
+ form.input.page.set(0);
2398
+ return;
2399
+ }
2400
+ props.onFilterChange?.(key, value, form);
2401
+ }
2402
+ }, [items]);
2403
+ (0, __mantine_hooks.useDebouncedCallback)(() => form.submit(), { delay: 800 });
2404
+ const dt = (0, __alepha_react.useInject)(alepha_datetime.DateTimeProvider);
2405
+ (0, react.useEffect)(() => {
2406
+ if (props.submitOnInit) form.submit();
2407
+ if (props.submitEvery) {
2408
+ const it = dt.createInterval(() => {
2409
+ form.submit();
2410
+ }, props.submitEvery);
2411
+ return () => dt.clearInterval(it);
2412
+ }
2413
+ }, []);
2414
+ (0, react.useEffect)(() => {
2415
+ if (typeof props.items !== "function") setItems(props.items);
2416
+ }, [props.items]);
2417
+ (0, react.useEffect)(() => {
2418
+ if (!props.infinityScroll || typeof props.items !== "function") return;
2419
+ const handleScroll = () => {
2420
+ if (form.submitting) return;
2421
+ const scrollTop = window.scrollY;
2422
+ const windowHeight = window.innerHeight;
2423
+ const docHeight = document.documentElement.scrollHeight;
2424
+ if (scrollTop + windowHeight >= docHeight - 300) {
2425
+ const totalPages = items.page?.totalPages ?? 1;
2426
+ if (currentPage + 1 < totalPages) form.input.page.set(currentPage + 1);
2427
+ }
2428
+ };
2429
+ window.addEventListener("scroll", handleScroll);
2430
+ return () => window.removeEventListener("scroll", handleScroll);
2431
+ }, [
2432
+ props.infinityScroll,
2433
+ form.submitting,
2434
+ items.page?.totalPages,
2435
+ currentPage,
2436
+ form
2437
+ ]);
2438
+ const head = Object.entries(props.columns).map(([key, col]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Table.Th, {
2439
+ style: { ...col.fit ? {
2440
+ width: "1%",
2441
+ whiteSpace: "nowrap"
2442
+ } : {} },
2443
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(ActionButton_default, {
2444
+ justify: "space-between",
2445
+ radius: 0,
2446
+ fullWidth: true,
2447
+ size: "xs",
2448
+ children: col.label
2449
+ })
2450
+ }, key));
2451
+ const rows = items.content.map((item, index) => {
2452
+ const trProps = props.tableTrProps ? props.tableTrProps(item) : {};
2453
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Table.Tr, {
2454
+ ...trProps,
2455
+ children: Object.entries(props.columns).map(([key, col]) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Table.Td, { children: col.value(item, {
2456
+ index,
2457
+ form,
2458
+ alepha: alepha$1
2459
+ }) }, key))
2460
+ }, JSON.stringify(item));
2461
+ });
2462
+ const schema = alepha.t.omit(form.options.schema, [
2463
+ "page",
2464
+ "size",
2465
+ "sort"
2466
+ ]);
2467
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2468
+ direction: "column",
2469
+ gap: "sm",
2470
+ flex: 1,
2471
+ children: [
2472
+ props.filters ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(TypeForm_default, {
2473
+ ...props.typeFormProps,
2474
+ form,
2475
+ schema
2476
+ }) : null,
2477
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, {
2478
+ className: "overflow-auto",
2479
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Table, {
2480
+ striped: true,
2481
+ withRowBorders: true,
2482
+ withColumnBorders: true,
2483
+ withTableBorder: true,
2484
+ stripedColor: "",
2485
+ ...props.tableProps,
2486
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Table.Thead, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Table.Tr, { children: head }) }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Table.Tbody, { children: rows })]
2487
+ })
2488
+ }),
2489
+ !props.infinityScroll && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(__mantine_core.Flex, {
2490
+ justify: "space-between",
2491
+ align: "center",
2492
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Pagination, {
2493
+ withEdges: true,
2494
+ total: items.page?.totalPages ?? 1,
2495
+ value: page,
2496
+ onChange: (value) => {
2497
+ form.input.page.set(value - 1);
2498
+ }
2499
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Flex, { children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(__mantine_core.Select, {
2500
+ value: size,
2501
+ onChange: (value) => {
2502
+ form.input.size.set(Number(value));
2503
+ },
2504
+ data: [
2505
+ {
2506
+ value: "5",
2507
+ label: "5"
2508
+ },
2509
+ {
2510
+ value: "10",
2511
+ label: "10"
2512
+ },
2513
+ {
2514
+ value: "25",
2515
+ label: "25"
2516
+ },
2517
+ {
2518
+ value: "50",
2519
+ label: "50"
2520
+ },
2521
+ {
2522
+ value: "100",
2523
+ label: "100"
2524
+ }
2525
+ ]
2526
+ }) })]
2527
+ })
2528
+ ]
2529
+ });
2530
+ };
2531
+ var DataTable_default = DataTable;
2532
+
2533
+ //#endregion
2534
+ //#region src/core/hooks/useDialog.ts
2535
+ /**
2536
+ * Use this hook to access the Dialog Service for showing various dialog types.
2537
+ *
2538
+ * @example
2539
+ * ```tsx
2540
+ * const dialog = useDialog();
2541
+ * await dialog.alert({ title: "Alert", message: "This is an alert message" });
2542
+ * const confirmed = await dialog.confirm({ title: "Confirm", message: "Are you sure?" });
2543
+ * const input = await dialog.prompt({ title: "Input", message: "Enter your name:" });
2544
+ * ```
2545
+ */
2546
+ const useDialog = () => {
2547
+ return (0, __alepha_react.useInject)(DialogService);
2548
+ };
2549
+
2550
+ //#endregion
2551
+ //#region src/core/index.ts
2552
+ /**
2553
+ * Mantine
2554
+ *
2555
+ * @module alepha.ui
2556
+ */
2557
+ const AlephaUI = (0, alepha.$module)({
2558
+ name: "alepha.ui",
2559
+ services: [
2560
+ DialogService,
2561
+ ToastService,
2562
+ RootRouter
2563
+ ],
2564
+ register: (alepha$1) => {
2565
+ alepha$1.with(__alepha_react_i18n.AlephaReactI18n);
2566
+ alepha$1.with(__alepha_react_head.AlephaReactHead);
2567
+ alepha$1.with(__alepha_react_form.AlephaReactForm);
2568
+ alepha$1.with(DialogService);
2569
+ alepha$1.with(ToastService);
2570
+ }
2571
+ });
2572
+
2573
+ //#endregion
2574
+ exports.ActionButton = ActionButton_default;
2575
+ exports.AdminShell = AdminShell_default;
2576
+ exports.AlephaMantineProvider = AlephaMantineProvider_default;
2577
+ exports.AlephaUI = AlephaUI;
2578
+ exports.AlertDialog = AlertDialog_default;
2579
+ exports.AppBar = AppBar_default;
2580
+ exports.BurgerButton = BurgerButton_default;
2581
+ exports.ClipboardButton = ClipboardButton_default;
2582
+ exports.ConfirmDialog = ConfirmDialog_default;
2583
+ exports.Control = Control_default;
2584
+ exports.ControlDate = ControlDate_default;
2585
+ exports.ControlQueryBuilder = ControlQueryBuilder_default;
2586
+ exports.ControlSelect = ControlSelect_default;
2587
+ exports.DarkModeButton = DarkModeButton_default;
2588
+ exports.DataTable = DataTable_default;
2589
+ exports.DialogService = DialogService;
2590
+ Object.defineProperty(exports, 'Flex', {
2591
+ enumerable: true,
2592
+ get: function () {
2593
+ return __mantine_core.Flex;
2594
+ }
2595
+ });
2596
+ exports.JsonViewer = JsonViewer_default;
2597
+ exports.LanguageButton = LanguageButton_default;
2598
+ exports.OPERATOR_INFO = OPERATOR_INFO;
2599
+ exports.Omnibar = Omnibar_default;
2600
+ exports.OmnibarButton = OmnibarButton_default;
2601
+ exports.PromptDialog = PromptDialog_default;
2602
+ exports.RootRouter = RootRouter;
2603
+ exports.Sidebar = Sidebar;
2604
+ Object.defineProperty(exports, 'Text', {
2605
+ enumerable: true,
2606
+ get: function () {
2607
+ return __mantine_core.Text;
2608
+ }
2609
+ });
2610
+ exports.ToastService = ToastService;
2611
+ exports.TypeForm = TypeForm_default;
2612
+ exports.capitalize = capitalize;
2613
+ exports.extractSchemaFields = extractSchemaFields;
2614
+ exports.getDefaultIcon = getDefaultIcon;
2615
+ exports.getOperatorsForField = getOperatorsForField;
2616
+ exports.prettyName = prettyName;
2617
+ exports.ui = ui;
2618
+ exports.useDialog = useDialog;
2619
+ exports.useToast = useToast;
2620
+ //# sourceMappingURL=index.cjs.map