@alepha/ui 0.17.2 → 0.18.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 (270) hide show
  1. package/dist/admin/{AdminApiKeys-CF_qOO3u.js → AdminApiKeys-C-6_Q-lH.js} +56 -192
  2. package/dist/admin/AdminApiKeys-C-6_Q-lH.js.map +1 -0
  3. package/dist/admin/{AdminAudits-BQno3hZG.js → AdminAudits-Bgbf04hO.js} +25 -61
  4. package/dist/admin/AdminAudits-Bgbf04hO.js.map +1 -0
  5. package/dist/admin/{AdminFiles-kvuUaASF.js → AdminFiles-B9a7G3cY.js} +6 -8
  6. package/dist/admin/AdminFiles-B9a7G3cY.js.map +1 -0
  7. package/dist/admin/{AdminJobDashboard-CrPxp0W1.js → AdminJobDashboard-DaTwf5OY.js} +55 -186
  8. package/dist/admin/AdminJobDashboard-DaTwf5OY.js.map +1 -0
  9. package/dist/admin/{AdminJobExecutions-D-b4Zt7W.js → AdminJobExecutions-B9cek5dl.js} +132 -168
  10. package/dist/admin/AdminJobExecutions-B9cek5dl.js.map +1 -0
  11. package/dist/admin/{AdminJobRegistry-CNX5cpDx.js → AdminJobRegistry-DFgV3oqx.js} +60 -83
  12. package/dist/admin/AdminJobRegistry-DFgV3oqx.js.map +1 -0
  13. package/dist/admin/AdminLayout-DHsvWxVB.js +70 -0
  14. package/dist/admin/AdminLayout-DHsvWxVB.js.map +1 -0
  15. package/dist/admin/{AdminParameters-DCGbpt2c.js → AdminParameters-DHw9ATgl.js} +53 -53
  16. package/dist/admin/AdminParameters-DHw9ATgl.js.map +1 -0
  17. package/dist/admin/{AdminSessions-DyhW6RZv.js → AdminSessions-BhGJPI3z.js} +11 -18
  18. package/dist/admin/AdminSessions-BhGJPI3z.js.map +1 -0
  19. package/dist/admin/{AdminUserLayout-CrBj4UuI.js → AdminUserLayout-BdC4Te8m.js} +112 -151
  20. package/dist/admin/AdminUserLayout-BdC4Te8m.js.map +1 -0
  21. package/dist/admin/AdminUserProfile-DAt23fqY.js +69 -0
  22. package/dist/admin/AdminUserProfile-DAt23fqY.js.map +1 -0
  23. package/dist/admin/AdminUserSessions-1uzcx02z.js +109 -0
  24. package/dist/admin/AdminUserSessions-1uzcx02z.js.map +1 -0
  25. package/dist/admin/AdminUsers-C85c3eiQ.js +121 -0
  26. package/dist/admin/AdminUsers-C85c3eiQ.js.map +1 -0
  27. package/dist/{auth/AuthLayout-CdJcrPs4.js → admin/AuthLayout-DFJvCvzw.js} +3 -3
  28. package/dist/{auth/AuthLayout-CdJcrPs4.js.map → admin/AuthLayout-DFJvCvzw.js.map} +1 -1
  29. package/dist/{auth/IconGoogle-Bm18QD2q.js → admin/IconGoogle-CSQLPYwX.js} +1 -1
  30. package/dist/{auth/IconGoogle-Bm18QD2q.js.map → admin/IconGoogle-CSQLPYwX.js.map} +1 -1
  31. package/dist/{demo/DemoLogin-DjJ9314c.js → admin/Login-BGheURrg.js} +15 -129
  32. package/dist/{auth/Login-BS_FYTy0.js.map → admin/Login-BGheURrg.js.map} +1 -1
  33. package/dist/{auth/Profile-CjDsW378.js → admin/Profile-B-c9pCPf.js} +5 -5
  34. package/dist/{auth/Profile-CjDsW378.js.map → admin/Profile-B-c9pCPf.js.map} +1 -1
  35. package/dist/{demo/DemoRegister-DzkJ5M83.js → admin/Register-Cs10l8vX.js} +20 -146
  36. package/dist/{auth/Register-C5eqzAaD.js.map → admin/Register-Cs10l8vX.js.map} +1 -1
  37. package/dist/{demo/DemoResetPassword-DWh4_BpQ.js → admin/ResetPassword-BwDdfkGH.js} +20 -82
  38. package/dist/{auth/ResetPassword-XifinVao.js.map → admin/ResetPassword-BwDdfkGH.js.map} +1 -1
  39. package/dist/{demo/DemoVerifyEmail-DbU_tCj8.js → admin/VerifyEmail-DfXHAiQl.js} +15 -32
  40. package/dist/{auth/VerifyEmail-DTgbeJOO.js.map → admin/VerifyEmail-DfXHAiQl.js.map} +1 -1
  41. package/dist/admin/auth-Dr0Cf8I7.js +319 -0
  42. package/dist/admin/auth-Dr0Cf8I7.js.map +1 -0
  43. package/dist/admin/core-2xoLiT0o.js +4031 -0
  44. package/dist/admin/core-2xoLiT0o.js.map +1 -0
  45. package/dist/admin/index.d.ts +739 -13
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +79 -111
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/admin/rolldown-runtime-CjeV3_4I.js +18 -0
  50. package/dist/auth/AuthLayout-CAE1pX9s.js +22 -0
  51. package/dist/auth/AuthLayout-CAE1pX9s.js.map +1 -0
  52. package/dist/auth/{Login-BS_FYTy0.js → Login-Denw_UGy.js} +8 -8
  53. package/dist/auth/Login-Denw_UGy.js.map +1 -0
  54. package/dist/auth/Profile-BMX_Ar_s.js +155 -0
  55. package/dist/auth/Profile-BMX_Ar_s.js.map +1 -0
  56. package/dist/auth/{Register-C5eqzAaD.js → Register-6hi_cpfF.js} +8 -8
  57. package/dist/auth/Register-6hi_cpfF.js.map +1 -0
  58. package/dist/auth/{ResetPassword-XifinVao.js → ResetPassword-CqfTk1FI.js} +6 -6
  59. package/dist/auth/ResetPassword-CqfTk1FI.js.map +1 -0
  60. package/dist/auth/{VerifyEmail-DTgbeJOO.js → VerifyEmail-nWiSTMjF.js} +5 -5
  61. package/dist/auth/VerifyEmail-nWiSTMjF.js.map +1 -0
  62. package/dist/auth/core-niW0sFLv.js +2264 -0
  63. package/dist/auth/core-niW0sFLv.js.map +1 -0
  64. package/dist/auth/index.d.ts +336 -8
  65. package/dist/auth/index.d.ts.map +1 -1
  66. package/dist/auth/index.js +18 -22
  67. package/dist/auth/index.js.map +1 -1
  68. package/dist/core/index.d.ts +1033 -843
  69. package/dist/core/index.d.ts.map +1 -1
  70. package/dist/core/index.js +1626 -1354
  71. package/dist/core/index.js.map +1 -1
  72. package/dist/demo/AuthLayout-jLa0aKsI.js +22 -0
  73. package/dist/demo/AuthLayout-jLa0aKsI.js.map +1 -0
  74. package/dist/demo/DemoButton-BmaWZVwf.js +178 -0
  75. package/dist/demo/DemoButton-BmaWZVwf.js.map +1 -0
  76. package/dist/demo/{DemoDataTable-lnBKWBf8.js → DemoDataTable-Z9xyV221.js} +18 -18
  77. package/dist/demo/DemoDataTable-Z9xyV221.js.map +1 -0
  78. package/dist/demo/DemoDialog-4ItHLf9t.js +101 -0
  79. package/dist/demo/DemoDialog-4ItHLf9t.js.map +1 -0
  80. package/dist/demo/DemoFlex-EtVq8QfX.js +105 -0
  81. package/dist/demo/DemoFlex-EtVq8QfX.js.map +1 -0
  82. package/dist/demo/DemoHeading-BS-vGfkI.js +18 -0
  83. package/dist/demo/DemoHeading-BS-vGfkI.js.map +1 -0
  84. package/dist/demo/{DemoHome-CUMZsYaH.js → DemoHome-Clbn8AmS.js} +9 -12
  85. package/dist/demo/DemoHome-Clbn8AmS.js.map +1 -0
  86. package/dist/demo/DemoJsonViewer-DkIX_ky2.js +109 -0
  87. package/dist/demo/DemoJsonViewer-DkIX_ky2.js.map +1 -0
  88. package/dist/demo/DemoLayout-C56xb5EE.js +73 -0
  89. package/dist/demo/DemoLayout-C56xb5EE.js.map +1 -0
  90. package/dist/demo/DemoLogin-BZwpicOS.js +128 -0
  91. package/dist/demo/DemoLogin-BZwpicOS.js.map +1 -0
  92. package/dist/demo/DemoRegister-C7_qc4MJ.js +140 -0
  93. package/dist/demo/DemoRegister-C7_qc4MJ.js.map +1 -0
  94. package/dist/demo/DemoResetPassword-BI1Ct4Dw.js +76 -0
  95. package/dist/demo/DemoResetPassword-BI1Ct4Dw.js.map +1 -0
  96. package/dist/demo/{DemoSidebar-C1csnGhX.js → DemoSidebar-CcBo4ltC.js} +6 -9
  97. package/dist/demo/DemoSidebar-CcBo4ltC.js.map +1 -0
  98. package/dist/demo/DemoText-CzXuUn3g.js +124 -0
  99. package/dist/demo/DemoText-CzXuUn3g.js.map +1 -0
  100. package/dist/demo/DemoToast-BgHDhWrX.js +95 -0
  101. package/dist/demo/DemoToast-BgHDhWrX.js.map +1 -0
  102. package/dist/demo/{DemoTypeForm-CWz6fJrJ.js → DemoTypeForm-DDzWoMSV.js} +4 -4
  103. package/dist/demo/{DemoTypeForm-CWz6fJrJ.js.map → DemoTypeForm-DDzWoMSV.js.map} +1 -1
  104. package/dist/demo/DemoVerifyEmail-C_Irdnov.js +30 -0
  105. package/dist/demo/DemoVerifyEmail-C_Irdnov.js.map +1 -0
  106. package/dist/demo/IconGoogle-CSQLPYwX.js +56 -0
  107. package/dist/demo/IconGoogle-CSQLPYwX.js.map +1 -0
  108. package/dist/demo/Login-hSOU3jZc.js +219 -0
  109. package/dist/demo/Login-hSOU3jZc.js.map +1 -0
  110. package/dist/demo/Profile-CWqti7FB.js +155 -0
  111. package/dist/demo/Profile-CWqti7FB.js.map +1 -0
  112. package/dist/demo/Register-a70LPgs2.js +375 -0
  113. package/dist/demo/Register-a70LPgs2.js.map +1 -0
  114. package/dist/demo/ResetPassword-DWN0lzr5.js +286 -0
  115. package/dist/demo/ResetPassword-DWN0lzr5.js.map +1 -0
  116. package/dist/demo/Showcase-Dq3MISpd.js +232 -0
  117. package/dist/demo/Showcase-Dq3MISpd.js.map +1 -0
  118. package/dist/demo/VerifyEmail-DZWL72K4.js +135 -0
  119. package/dist/demo/VerifyEmail-DZWL72K4.js.map +1 -0
  120. package/dist/demo/auth-d6n3xbug.js +257 -0
  121. package/dist/demo/auth-d6n3xbug.js.map +1 -0
  122. package/dist/demo/core-RCUw1Q-a.js +4217 -0
  123. package/dist/demo/core-RCUw1Q-a.js.map +1 -0
  124. package/dist/demo/index.d.ts +17 -6
  125. package/dist/demo/index.d.ts.map +1 -1
  126. package/dist/demo/index.js +92 -24
  127. package/dist/demo/index.js.map +1 -1
  128. package/dist/demo/rolldown-runtime-CjeV3_4I.js +18 -0
  129. package/package.json +16 -20
  130. package/src/admin/AdminRouter.ts +10 -39
  131. package/src/admin/components/AdminLayout.tsx +42 -10
  132. package/src/admin/components/audits/AdminAudits.tsx +10 -64
  133. package/src/admin/components/files/AdminFiles.tsx +2 -3
  134. package/src/admin/components/jobs/AdminJobDashboard.tsx +36 -142
  135. package/src/admin/components/jobs/AdminJobExecutions.tsx +117 -175
  136. package/src/admin/components/jobs/AdminJobRegistry.tsx +58 -73
  137. package/src/admin/components/keys/AdminApiKeys.tsx +21 -169
  138. package/src/admin/components/parameters/AdminParameters.tsx +4 -4
  139. package/src/admin/components/parameters/ParameterEmptyState.tsx +1 -2
  140. package/src/admin/components/parameters/ParameterHistory.tsx +3 -3
  141. package/src/admin/components/parameters/ParameterTree.tsx +2 -8
  142. package/src/admin/components/parameters/types.ts +3 -3
  143. package/src/admin/components/sessions/AdminSessions.tsx +8 -16
  144. package/src/admin/components/users/AdminUserLayout.tsx +113 -150
  145. package/src/admin/components/users/AdminUserProfile.tsx +50 -0
  146. package/src/admin/components/users/AdminUserSessions.tsx +106 -126
  147. package/src/admin/components/users/AdminUsers.tsx +46 -62
  148. package/src/admin/index.ts +0 -4
  149. package/src/auth/components/buttons/UserButton.tsx +1 -1
  150. package/src/auth/index.ts +0 -4
  151. package/src/core/UiRouter.ts +1 -1
  152. package/src/core/atoms/alephaSidebarAtom.ts +7 -31
  153. package/src/core/components/{layout/AlephaMantineProvider.tsx → AlephaMantineProvider.tsx} +3 -4
  154. package/src/core/components/Flex.tsx +63 -0
  155. package/src/core/components/Heading.tsx +19 -0
  156. package/src/core/components/Text.tsx +140 -0
  157. package/src/core/components/buttons/ActionButton.tsx +12 -1
  158. package/src/core/components/buttons/BurgerButton.tsx +3 -3
  159. package/src/core/components/buttons/LanguageButton.tsx +1 -1
  160. package/src/core/components/buttons/ToggleSidebarButton.tsx +1 -4
  161. package/src/core/components/data/DetailDrawer.tsx +144 -0
  162. package/src/core/components/data/DetailList.tsx +64 -0
  163. package/src/core/components/data/StatCards.tsx +50 -0
  164. package/src/core/components/layout/AppBar.tsx +11 -10
  165. package/src/core/components/layout/Breadcrumb.tsx +8 -8
  166. package/src/core/components/layout/Container.tsx +15 -0
  167. package/src/core/components/layout/DashboardShell.tsx +23 -238
  168. package/src/core/components/layout/Omnibar.tsx +1 -2
  169. package/src/core/components/layout/Sidebar.tsx +103 -71
  170. package/src/core/components/layout/index.ts +65 -0
  171. package/src/core/{components/form → form/components}/Control.tsx +32 -14
  172. package/src/core/{components/form → form/components}/ControlArray.tsx +2 -5
  173. package/src/core/{components/form → form/components}/ControlDate.tsx +1 -4
  174. package/src/core/{components/form → form/components}/ControlNumber.tsx +1 -4
  175. package/src/core/{components/form → form/components}/ControlObject.tsx +1 -4
  176. package/src/core/{components/form → form/components}/ControlQueryBuilder.tsx +7 -7
  177. package/src/core/{components/form → form/components}/ControlSelect.tsx +2 -4
  178. package/src/core/{components/form → form/components}/TypeForm.browser.spec.tsx +22 -64
  179. package/src/core/{components/form → form/components}/TypeForm.tsx +1 -3
  180. package/src/core/form/factories/dialogForm.tsx +31 -0
  181. package/src/core/form/index.ts +23 -0
  182. package/src/core/{utils → form/utils}/parseInput.ts +2 -4
  183. package/src/core/index.ts +43 -51
  184. package/src/core/interfaces/AlephaIntent.ts +6 -0
  185. package/src/core/interfaces/AlephaTheme.ts +0 -1
  186. package/src/core/json/factories/dialogJson.tsx +24 -0
  187. package/src/core/json/index.ts +2 -0
  188. package/src/core/primitives/$ui.ts +17 -0
  189. package/src/core/services/DialogService.tsx +1 -48
  190. package/src/core/styles.css +1 -8
  191. package/src/core/{components/table → table/components}/ColumnPicker.tsx +2 -3
  192. package/src/core/{components/table → table/components}/DataTable.tsx +8 -9
  193. package/src/core/{components/table → table/components}/DataTableFilters.tsx +6 -3
  194. package/src/core/{components/table → table/components}/DataTableToolbar.tsx +4 -5
  195. package/src/core/{components/table → table/components}/FilterPicker.tsx +2 -3
  196. package/src/core/table/index.ts +12 -0
  197. package/src/core/{components/table → table/interfaces}/types.ts +2 -2
  198. package/src/demo/DemoRouter.ts +87 -6
  199. package/src/demo/components/DemoHome.tsx +6 -10
  200. package/src/demo/components/DemoLayout.tsx +38 -8
  201. package/src/demo/components/auth/DemoLogin.tsx +1 -1
  202. package/src/demo/components/auth/DemoRegister.tsx +1 -1
  203. package/src/demo/components/auth/DemoResetPassword.tsx +1 -1
  204. package/src/demo/components/auth/DemoVerifyEmail.tsx +1 -1
  205. package/src/demo/components/core/DemoButton.tsx +160 -0
  206. package/src/demo/components/core/DemoFlex.tsx +101 -0
  207. package/src/demo/components/core/DemoHeading.tsx +13 -0
  208. package/src/demo/components/core/DemoText.tsx +110 -0
  209. package/src/demo/components/json/DemoJsonViewer.tsx +1 -1
  210. package/src/demo/components/layout/DemoDialog.tsx +103 -0
  211. package/src/demo/components/{core → layout}/DemoSidebar.tsx +0 -1
  212. package/src/demo/components/layout/DemoToast.tsx +96 -0
  213. package/src/demo/components/shared/MacWindow.tsx +149 -74
  214. package/src/demo/components/shared/Showcase.tsx +4 -8
  215. package/src/demo/index.ts +1 -4
  216. package/src/demo/primitives/$uiDemo.ts +10 -0
  217. package/dist/admin/AdminApiKeys-CF_qOO3u.js.map +0 -1
  218. package/dist/admin/AdminAudits-BQno3hZG.js.map +0 -1
  219. package/dist/admin/AdminFiles-kvuUaASF.js.map +0 -1
  220. package/dist/admin/AdminJobDashboard-CrPxp0W1.js.map +0 -1
  221. package/dist/admin/AdminJobExecutions-D-b4Zt7W.js.map +0 -1
  222. package/dist/admin/AdminJobRegistry-CNX5cpDx.js.map +0 -1
  223. package/dist/admin/AdminLayout-e-ZP5nWw.js +0 -37
  224. package/dist/admin/AdminLayout-e-ZP5nWw.js.map +0 -1
  225. package/dist/admin/AdminParameters-DCGbpt2c.js.map +0 -1
  226. package/dist/admin/AdminSessions-DyhW6RZv.js.map +0 -1
  227. package/dist/admin/AdminUserAudits-D1GcREEE.js +0 -177
  228. package/dist/admin/AdminUserAudits-D1GcREEE.js.map +0 -1
  229. package/dist/admin/AdminUserCreate-DR8LA0tv.js +0 -104
  230. package/dist/admin/AdminUserCreate-DR8LA0tv.js.map +0 -1
  231. package/dist/admin/AdminUserDetails-CDkZNHQD.js +0 -477
  232. package/dist/admin/AdminUserDetails-CDkZNHQD.js.map +0 -1
  233. package/dist/admin/AdminUserLayout-CrBj4UuI.js.map +0 -1
  234. package/dist/admin/AdminUserSessions-srgFHrqy.js +0 -129
  235. package/dist/admin/AdminUserSessions-srgFHrqy.js.map +0 -1
  236. package/dist/admin/AdminUserSettings-BFuxl-xT.js +0 -167
  237. package/dist/admin/AdminUserSettings-BFuxl-xT.js.map +0 -1
  238. package/dist/admin/AdminUsers-D1pDpiwK.js +0 -118
  239. package/dist/admin/AdminUsers-D1pDpiwK.js.map +0 -1
  240. package/dist/demo/DemoDataTable-lnBKWBf8.js.map +0 -1
  241. package/dist/demo/DemoHome-CUMZsYaH.js.map +0 -1
  242. package/dist/demo/DemoJsonViewer-_uokbGaW.js +0 -429
  243. package/dist/demo/DemoJsonViewer-_uokbGaW.js.map +0 -1
  244. package/dist/demo/DemoLayout-DHVoacE6.js +0 -46
  245. package/dist/demo/DemoLayout-DHVoacE6.js.map +0 -1
  246. package/dist/demo/DemoLogin-DjJ9314c.js.map +0 -1
  247. package/dist/demo/DemoRegister-DzkJ5M83.js.map +0 -1
  248. package/dist/demo/DemoResetPassword-DWh4_BpQ.js.map +0 -1
  249. package/dist/demo/DemoSidebar-C1csnGhX.js.map +0 -1
  250. package/dist/demo/DemoVerifyEmail-DbU_tCj8.js.map +0 -1
  251. package/dist/demo/Showcase-BzoXNlCn.js +0 -185
  252. package/dist/demo/Showcase-BzoXNlCn.js.map +0 -1
  253. package/dist/json/index.d.ts +0 -57
  254. package/dist/json/index.d.ts.map +0 -1
  255. package/dist/json/index.js +0 -325
  256. package/dist/json/index.js.map +0 -1
  257. package/src/admin/components/users/AdminUserAudits.tsx +0 -184
  258. package/src/admin/components/users/AdminUserCreate.tsx +0 -85
  259. package/src/admin/components/users/AdminUserDetails.tsx +0 -431
  260. package/src/admin/components/users/AdminUserSettings.tsx +0 -171
  261. package/src/core/components/data/ErrorViewer.tsx +0 -171
  262. package/src/json/extensions/DialogService.tsx +0 -31
  263. package/src/json/index.ts +0 -18
  264. package/src/json/styles.css +0 -1
  265. /package/dist/{demo → auth}/IconGoogle-Ch1m3Uzl.js +0 -0
  266. /package/dist/{demo → auth}/IconGoogle-Ch1m3Uzl.js.map +0 -0
  267. /package/src/{json → core/json}/components/JsonViewer.css +0 -0
  268. /package/src/{json → core/json}/components/JsonViewer.tsx +0 -0
  269. /package/src/core/{components/table → table/components}/DataTablePagination.tsx +0 -0
  270. /package/src/core/{components/table → table/components}/useTableSelection.ts +0 -0
@@ -0,0 +1,2264 @@
1
+ import { $atom, $context, $inject, $module, Alepha, AlephaError, TypeBoxError, t } from "alepha";
2
+ import { AlephaReactForm, FormValidationError, useForm, useFormState } from "alepha/react/form";
3
+ import { $head, AlephaReactHead } from "alepha/react/head";
4
+ import { AlephaReactI18n, useI18n } from "alepha/react/i18n";
5
+ import { $cookie } from "alepha/server/cookies";
6
+ import { ModalsProvider, modals } from "@mantine/modals";
7
+ import { ActionIcon, Anchor, Autocomplete, Badge, Button, Card, ColorInput, ColorSchemeScript, Container, Divider, Fieldset, FileInput, Flex, Grid, Image, Input, Loader, MantineProvider, Menu, MultiSelect, NumberInput, PasswordInput, Popover, SegmentedControl, Select, Slider, Switch, TagsInput, Text, TextInput, Textarea, ThemeIcon, Tooltip, UnstyledButton, useMantineTheme } from "@mantine/core";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ import { Children, createElement, forwardRef, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
10
+ import { Notifications, notifications } from "@mantine/notifications";
11
+ import { IconAlertTriangle, IconAt, IconCalendar, IconCheck, IconChevronRight, IconClock, IconColorPicker, IconFile, IconFilter, IconGripVertical, IconHash, IconInfoCircle, IconInfoTriangle, IconKey, IconLetterCase, IconLink, IconList, IconMail, IconPalette, IconPhone, IconPlus, IconSearch, IconSelector, IconToggleLeft, IconTrash, IconX } from "@tabler/icons-react";
12
+ import { $page, NestedView, useActive, useRouter, useRouterState } from "alepha/react/router";
13
+ import { NavigationProgress, nprogress } from "@mantine/nprogress";
14
+ import { useAction, useAlepha, useEvents, useInject, useStore } from "alepha/react";
15
+ import { Spotlight } from "@mantine/spotlight";
16
+ import { currentUserAtom } from "alepha/security";
17
+ import "@mantine/hooks";
18
+ import { DateInput, DateTimePicker, TimeInput } from "@mantine/dates";
19
+ import { parseQueryString } from "alepha/orm";
20
+ import "alepha/datetime";
21
+
22
+ //#region ../../src/core/atoms/alephaSidebarAtom.ts
23
+ const alephaSidebarAtom = $atom({
24
+ name: "alepha.ui.sidebar",
25
+ schema: t.object({
26
+ closed: t.boolean(),
27
+ collapsed: t.boolean(),
28
+ expandedWidth: t.number(),
29
+ collapsedWidth: t.number()
30
+ }),
31
+ default: {
32
+ closed: true,
33
+ collapsed: false,
34
+ expandedWidth: 300,
35
+ collapsedWidth: 78
36
+ }
37
+ });
38
+
39
+ //#endregion
40
+ //#region ../../src/core/atoms/alephaThemeAtom.ts
41
+ const alephaThemeAtom = $atom({
42
+ name: "alepha.ui.theme",
43
+ schema: t.object({ index: t.integer() }),
44
+ default: { index: 0 }
45
+ });
46
+
47
+ //#endregion
48
+ //#region ../../src/core/atoms/themes/default.ts
49
+ const defaultTheme = {
50
+ name: "Default",
51
+ description: "Default Alepha Theme"
52
+ };
53
+
54
+ //#endregion
55
+ //#region ../../src/core/atoms/themes/midnight.ts
56
+ const midnightTheme = {
57
+ name: "Midnight",
58
+ description: "Clean, developer-focused design",
59
+ primaryColor: "pink",
60
+ primaryShade: {
61
+ light: 7,
62
+ dark: 8
63
+ },
64
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif, \"Apple Color Emoji\", \"Segoe UI Emoji\"",
65
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
66
+ headings: {
67
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
68
+ fontWeight: "600",
69
+ textWrap: "wrap",
70
+ sizes: {
71
+ h1: {
72
+ fontSize: "2rem",
73
+ lineHeight: "1.25"
74
+ },
75
+ h2: {
76
+ fontSize: "1.5rem",
77
+ lineHeight: "1.3"
78
+ },
79
+ h3: {
80
+ fontSize: "1.25rem",
81
+ lineHeight: "1.4"
82
+ },
83
+ h4: {
84
+ fontSize: "1rem",
85
+ lineHeight: "1.5"
86
+ },
87
+ h5: {
88
+ fontSize: "0.875rem",
89
+ lineHeight: "1.5"
90
+ },
91
+ h6: {
92
+ fontSize: "0.75rem",
93
+ lineHeight: "1.5"
94
+ }
95
+ }
96
+ },
97
+ radius: {
98
+ xs: "3px",
99
+ sm: "6px",
100
+ md: "6px",
101
+ lg: "8px",
102
+ xl: "12px"
103
+ },
104
+ defaultRadius: "sm",
105
+ colors: {
106
+ dark: [
107
+ "#d0d7de",
108
+ "#8b949e",
109
+ "#6e7681",
110
+ "#484f58",
111
+ "#30363d",
112
+ "#21262d",
113
+ "#161b22",
114
+ "#151b23",
115
+ "#0d1117",
116
+ "#010409"
117
+ ],
118
+ gray: [
119
+ "#f6f8fa",
120
+ "#eaeef2",
121
+ "#d0d7de",
122
+ "#afb8c1",
123
+ "#8c959f",
124
+ "#6e7781",
125
+ "#57606a",
126
+ "#424a53",
127
+ "#32383f",
128
+ "#24292f"
129
+ ],
130
+ blue: [
131
+ "#ddf4ff",
132
+ "#b6e3ff",
133
+ "#80ccff",
134
+ "#54aeff",
135
+ "#218bff",
136
+ "#0969da",
137
+ "#0550ae",
138
+ "#033d8b",
139
+ "#0a3069",
140
+ "#002155"
141
+ ],
142
+ green: [
143
+ "#dafbe1",
144
+ "#aceebb",
145
+ "#6fdd8b",
146
+ "#4ac26b",
147
+ "#2da44e",
148
+ "#1a7f37",
149
+ "#116329",
150
+ "#044f1e",
151
+ "#003d16",
152
+ "#002d11"
153
+ ],
154
+ red: [
155
+ "#ffebe9",
156
+ "#ffcecb",
157
+ "#ffaba8",
158
+ "#ff8182",
159
+ "#fa4549",
160
+ "#cf222e",
161
+ "#a40e26",
162
+ "#82071e",
163
+ "#660018",
164
+ "#4c0014"
165
+ ]
166
+ }
167
+ };
168
+
169
+ //#endregion
170
+ //#region ../../src/core/atoms/alephaThemeListAtom.ts
171
+ const alephaThemeListAtom = $atom({
172
+ name: "alepha.ui.themeList",
173
+ schema: t.array(t.json()),
174
+ default: [defaultTheme, midnightTheme]
175
+ });
176
+
177
+ //#endregion
178
+ //#region ../../src/core/providers/ThemeProvider.ts
179
+ var ThemeProvider = class {
180
+ alepha = $inject(Alepha);
181
+ cookie = $cookie({
182
+ name: "theme",
183
+ schema: alephaThemeAtom.schema,
184
+ ttl: [1, "year"]
185
+ });
186
+ head = $head(() => {
187
+ const theme = this.getTheme();
188
+ if (!theme || !theme.name) return {};
189
+ return { htmlAttributes: { "data-theme": theme.name } };
190
+ });
191
+ setTheme(index) {
192
+ const newTheme = this.alepha.store.get(alephaThemeListAtom)[index];
193
+ if (!newTheme) throw new AlephaError(`Theme with index ${index} not found`);
194
+ this.cookie.set({ index });
195
+ this.alepha.store.set(alephaThemeAtom, { index });
196
+ if (typeof document === "undefined") return;
197
+ document.documentElement.removeAttribute("data-theme");
198
+ if (newTheme.name) document.documentElement.setAttribute("data-theme", newTheme.name);
199
+ }
200
+ getTheme() {
201
+ const index = this.getThemeIndex();
202
+ const list = this.alepha.store.get(alephaThemeListAtom);
203
+ return list[index] || list[0] || defaultTheme;
204
+ }
205
+ getThemeIndex() {
206
+ try {
207
+ return this.cookie.get()?.index ?? this.alepha.store.get(alephaThemeAtom)?.index ?? 0;
208
+ } catch {
209
+ return this.alepha.store.get(alephaThemeAtom)?.index ?? 0;
210
+ }
211
+ }
212
+ };
213
+
214
+ //#endregion
215
+ //#region ../../src/core/components/dialogs/AlertDialog.tsx
216
+ const AlertDialog = ({ options, onClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text, {
217
+ mb: "md",
218
+ children: options.message
219
+ }), /* @__PURE__ */ jsx(Flex, {
220
+ justify: "flex-end",
221
+ children: /* @__PURE__ */ jsx(Button, {
222
+ onClick: onClose,
223
+ children: options?.okLabel || "OK"
224
+ })
225
+ })] });
226
+
227
+ //#endregion
228
+ //#region ../../src/core/components/dialogs/ConfirmDialog.tsx
229
+ const ConfirmDialog = ({ options, onConfirm }) => /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text, {
230
+ mb: "md",
231
+ children: options.message
232
+ }), /* @__PURE__ */ jsxs(Flex, {
233
+ justify: "flex-end",
234
+ children: [/* @__PURE__ */ jsx(Button, {
235
+ variant: "subtle",
236
+ onClick: () => onConfirm(false),
237
+ children: options?.cancelLabel || "Cancel"
238
+ }), /* @__PURE__ */ jsx(Button, {
239
+ color: options?.confirmColor || "blue",
240
+ onClick: () => onConfirm(true),
241
+ children: options?.confirmLabel || "Confirm"
242
+ })]
243
+ })] });
244
+
245
+ //#endregion
246
+ //#region ../../src/core/components/dialogs/PromptDialog.tsx
247
+ const PromptDialog = ({ options, onSubmit }) => {
248
+ const [value, setValue] = useState(options?.defaultValue || "");
249
+ const inputRef = useRef(null);
250
+ useEffect(() => {
251
+ inputRef.current?.focus();
252
+ }, []);
253
+ const handleSubmit = () => {
254
+ if (!options?.required || value.trim()) onSubmit(value);
255
+ };
256
+ const handleKeyDown = (event) => {
257
+ if (event.key === "Enter") handleSubmit();
258
+ };
259
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
260
+ options?.message && /* @__PURE__ */ jsx(Text, {
261
+ mb: "md",
262
+ children: options.message
263
+ }),
264
+ /* @__PURE__ */ jsx(TextInput, {
265
+ ref: inputRef,
266
+ label: options?.label,
267
+ placeholder: options?.placeholder,
268
+ value,
269
+ onChange: (event) => setValue(event.currentTarget.value),
270
+ onKeyDown: handleKeyDown,
271
+ required: options?.required,
272
+ mb: "md"
273
+ }),
274
+ /* @__PURE__ */ jsxs(Flex, {
275
+ justify: "flex-end",
276
+ children: [/* @__PURE__ */ jsx(Button, {
277
+ variant: "subtle",
278
+ onClick: () => onSubmit(null),
279
+ children: options?.cancelLabel || "Cancel"
280
+ }), /* @__PURE__ */ jsx(Button, {
281
+ onClick: handleSubmit,
282
+ disabled: options?.required && !value.trim(),
283
+ children: options?.submitLabel || "OK"
284
+ })]
285
+ })
286
+ ] });
287
+ };
288
+
289
+ //#endregion
290
+ //#region ../../src/core/services/DialogService.tsx
291
+ var DialogService = class {
292
+ options = { default: {
293
+ centered: true,
294
+ withCloseButton: true,
295
+ size: "md",
296
+ overlayProps: {
297
+ backgroundOpacity: .55,
298
+ blur: 3
299
+ },
300
+ transitionProps: {
301
+ transition: "pop",
302
+ duration: 200
303
+ }
304
+ } };
305
+ /**
306
+ * Show an alert dialog with a message
307
+ */
308
+ alert(options) {
309
+ return new Promise((resolve) => {
310
+ const modalId = this.open({
311
+ ...options,
312
+ title: options?.title || "Alert",
313
+ content: /* @__PURE__ */ jsx(AlertDialog, {
314
+ options,
315
+ onClose: () => {
316
+ this.close(modalId);
317
+ resolve();
318
+ }
319
+ })
320
+ });
321
+ });
322
+ }
323
+ /**
324
+ * Show a confirmation dialog that returns a promise
325
+ */
326
+ confirm(options) {
327
+ return new Promise((resolve) => {
328
+ const modalId = this.open({
329
+ ...options,
330
+ title: options?.title || "Confirm",
331
+ closeOnClickOutside: false,
332
+ closeOnEscape: false,
333
+ content: /* @__PURE__ */ jsx(ConfirmDialog, {
334
+ options,
335
+ onConfirm: (confirmed) => {
336
+ this.close(modalId);
337
+ resolve(confirmed);
338
+ }
339
+ })
340
+ });
341
+ });
342
+ }
343
+ /**
344
+ * Show a prompt dialog to get user input
345
+ */
346
+ prompt(options) {
347
+ return new Promise((resolve) => {
348
+ const modalId = this.open({
349
+ ...options,
350
+ title: options?.title || "Input",
351
+ closeOnClickOutside: false,
352
+ closeOnEscape: false,
353
+ content: /* @__PURE__ */ jsx(PromptDialog, {
354
+ options,
355
+ onSubmit: (value) => {
356
+ this.close(modalId);
357
+ resolve(value);
358
+ }
359
+ })
360
+ });
361
+ });
362
+ }
363
+ /**
364
+ * Open a custom dialog with provided content
365
+ */
366
+ open(options) {
367
+ return modals.open({
368
+ ...this.options.default,
369
+ ...options,
370
+ children: options?.content || options?.message
371
+ });
372
+ }
373
+ /**
374
+ * Close the currently open dialog or a specific dialog by ID
375
+ */
376
+ close(modalId) {
377
+ if (modalId) modals.close(modalId);
378
+ else modals.closeAll();
379
+ }
380
+ };
381
+
382
+ //#endregion
383
+ //#region ../../src/core/services/ToastService.tsx
384
+ var ToastService = class {
385
+ raw = notifications;
386
+ options = { default: {
387
+ radius: "md",
388
+ withBorder: true,
389
+ withCloseButton: true,
390
+ autoClose: 5e3,
391
+ position: "top-center"
392
+ } };
393
+ show(options) {
394
+ notifications.show({
395
+ ...this.options.default,
396
+ ...options
397
+ });
398
+ }
399
+ info(options) {
400
+ if (typeof options === "string") options = { message: options };
401
+ this.show({
402
+ color: "blue",
403
+ icon: /* @__PURE__ */ jsx(IconInfoCircle, { size: 20 }),
404
+ title: "Info",
405
+ message: "Information notification",
406
+ ...options
407
+ });
408
+ }
409
+ success(options) {
410
+ if (typeof options === "string") options = { message: options };
411
+ this.show({
412
+ color: "green",
413
+ icon: /* @__PURE__ */ jsx(IconCheck, { size: 16 }),
414
+ title: "Success",
415
+ message: "Operation completed successfully",
416
+ ...options
417
+ });
418
+ }
419
+ warning(options) {
420
+ if (typeof options === "string") options = { message: options };
421
+ this.show({
422
+ color: "yellow",
423
+ icon: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 20 }),
424
+ title: "Warning",
425
+ message: "Please review this warning",
426
+ ...options
427
+ });
428
+ }
429
+ danger(options) {
430
+ if (typeof options === "string") options = { message: options };
431
+ this.show({
432
+ color: "red",
433
+ icon: /* @__PURE__ */ jsx(IconX, { size: 20 }),
434
+ title: "Error",
435
+ message: "An error occurred",
436
+ ...options
437
+ });
438
+ }
439
+ };
440
+
441
+ //#endregion
442
+ //#region ../../src/core/UiRouter.ts
443
+ /**
444
+ * UI Router defining the root page with AlephaMantineProvider.
445
+ *
446
+ * - Use UiRouter when you need Alepha's Mantine-based UI components and theming.
447
+ * - Prefer to use $ui() for convenience. (Custom Factory of UiRouter)
448
+ */
449
+ var UiRouter = class {
450
+ root = $page({
451
+ path: "/",
452
+ component: AlephaMantineProvider
453
+ });
454
+ };
455
+
456
+ //#endregion
457
+ //#region ../../src/core/hooks/useTheme.ts
458
+ /**
459
+ * Hook to get and set the current theme.
460
+ *
461
+ * Returns a tuple with the current theme and a function to set the theme.
462
+ *
463
+ * ```tsx
464
+ * const [theme, setTheme] = useTheme();
465
+ * ```
466
+ */
467
+ const useTheme = () => {
468
+ useStore(alephaThemeAtom);
469
+ const themeProvider = useInject(ThemeProvider);
470
+ const theme = themeProvider.getTheme();
471
+ const setTheme = (theme) => {
472
+ themeProvider.setTheme(theme.index);
473
+ };
474
+ return [theme, setTheme];
475
+ };
476
+
477
+ //#endregion
478
+ //#region ../../src/core/hooks/useToast.ts
479
+ /**
480
+ * Use this hook to access the Toast Service for showing notifications.
481
+ *
482
+ * @example
483
+ * ```tsx
484
+ * const toast = useToast();
485
+ * toast.success({ message: "Operation completed successfully!" });
486
+ * toast.error({ title: "Error", message: "Something went wrong" });
487
+ * ```
488
+ */
489
+ const useToast = () => {
490
+ return useInject(ToastService);
491
+ };
492
+
493
+ //#endregion
494
+ //#region ../../src/core/components/layout/Omnibar.tsx
495
+ const Omnibar = (props) => {
496
+ const shortcut = props.shortcut ?? "mod+K";
497
+ const searchPlaceholder = props.searchPlaceholder ?? "Search...";
498
+ const nothingFound = props.nothingFound ?? "Nothing found...";
499
+ const router = useRouter();
500
+ const [user] = useStore(currentUserAtom);
501
+ return /* @__PURE__ */ jsx(Spotlight, {
502
+ actions: useMemo(() => router.concretePages.filter((page) => {
503
+ if (page.can && !page.can()) return false;
504
+ return true;
505
+ }).map((page) => ({
506
+ id: page.name,
507
+ label: page.label ?? page.name,
508
+ description: page.description,
509
+ onClick: () => {
510
+ if (page.staticName) return router.push(page.staticName, { params: page.params });
511
+ return router.push(page.name);
512
+ },
513
+ leftSection: renderIcon(page.icon)
514
+ })), [user]),
515
+ shortcut,
516
+ limit: 10,
517
+ searchProps: {
518
+ leftSection: /* @__PURE__ */ jsx(IconSearch, { size: ui.sizes.icon.md }),
519
+ placeholder: searchPlaceholder
520
+ },
521
+ nothingFound
522
+ });
523
+ };
524
+
525
+ //#endregion
526
+ //#region ../../src/core/components/AlephaMantineProvider.tsx
527
+ const AlephaMantineProvider = (props) => {
528
+ const toast = useToast();
529
+ const [theme] = useTheme();
530
+ useEvents({
531
+ "react:transition:begin": () => {
532
+ nprogress.start();
533
+ },
534
+ "react:transition:end": () => {
535
+ nprogress.complete();
536
+ },
537
+ "react:action:error": ({ error, type }) => {
538
+ if (type === "transition" || error instanceof FormValidationError || error instanceof TypeBoxError) return;
539
+ toast.danger({
540
+ title: error.name || "Error",
541
+ message: error.message ?? "An error occurred while processing your action."
542
+ });
543
+ }
544
+ }, []);
545
+ const defaultColorScheme = props.mantine?.defaultColorScheme ?? theme.defaultColorScheme;
546
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ColorSchemeScript, {
547
+ defaultColorScheme,
548
+ ...props.colorSchemeScript
549
+ }), /* @__PURE__ */ jsxs(MantineProvider, {
550
+ ...props.mantine,
551
+ defaultColorScheme,
552
+ theme: {
553
+ ...theme,
554
+ ...props.mantine?.theme
555
+ },
556
+ children: [
557
+ /* @__PURE__ */ jsx(Notifications, { ...props.notifications }),
558
+ /* @__PURE__ */ jsx(NavigationProgress, { ...props.navigationProgress }),
559
+ /* @__PURE__ */ jsxs(ModalsProvider, {
560
+ ...props.modals,
561
+ children: [props.omnibar !== false && /* @__PURE__ */ jsx(Omnibar, { ...props.omnibar }), props.children ?? /* @__PURE__ */ jsx(NestedView, {})]
562
+ })
563
+ ]
564
+ })] });
565
+ };
566
+
567
+ //#endregion
568
+ //#region ../../src/core/constants/ui.ts
569
+ const ui = {
570
+ colors: {
571
+ transparent: "transparent",
572
+ background: "var(--alepha-background)",
573
+ surface: "var(--alepha-surface)",
574
+ elevated: "var(--alepha-elevated)",
575
+ border: "var(--alepha-border)"
576
+ },
577
+ sizes: { icon: {
578
+ xs: 14,
579
+ sm: 16,
580
+ md: 20,
581
+ lg: 24,
582
+ xl: 32
583
+ } }
584
+ };
585
+
586
+ //#endregion
587
+ //#region ../../src/core/helpers/isComponentType.ts
588
+ function isComponentType(param) {
589
+ if (isValidElement(param)) return false;
590
+ return typeof param === "function" || typeof param === "object" && param !== null && "$$typeof" in param;
591
+ }
592
+
593
+ //#endregion
594
+ //#region ../../src/core/components/buttons/ActionButton.tsx
595
+ const ActionMenuItem = (props) => {
596
+ const { item, index } = props;
597
+ const router = useRouter();
598
+ const action = useAction({ handler: async (e) => {
599
+ await item.onClick?.();
600
+ } }, [item.onClick]);
601
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
602
+ if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
603
+ if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
604
+ trigger: "hover",
605
+ position: "right-start",
606
+ offset: 2,
607
+ children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
608
+ leftSection: item.icon,
609
+ rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
610
+ children: item.label
611
+ }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
612
+ item: child,
613
+ index: childIndex
614
+ }, childIndex)) })]
615
+ }, index);
616
+ const menuItemProps = {};
617
+ if (props.item.onClick) menuItemProps.onClick = action.run;
618
+ else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
619
+ return /* @__PURE__ */ jsx(Menu.Item, {
620
+ leftSection: item.icon,
621
+ onClick: item.onClick,
622
+ color: item.color,
623
+ rightSection: item.active ? /* @__PURE__ */ jsx(ThemeIcon, {
624
+ size: "xs",
625
+ variant: "transparent",
626
+ children: /* @__PURE__ */ jsx(IconCheck, {})
627
+ }) : void 0,
628
+ ...menuItemProps,
629
+ children: item.label
630
+ }, index);
631
+ };
632
+ const ActionButton = (_props) => {
633
+ const theme = useMantineTheme();
634
+ const props = { ..._props };
635
+ const { tooltip, menu, icon, ...restProps } = props;
636
+ if (props.variant === "subtle" || props.variant === "outline") restProps.color ??= "gray";
637
+ if (props.intent) {
638
+ if (props.intent === "none") restProps.color ??= "gray";
639
+ else if (props.intent === "primary") restProps.color ??= theme.primaryColor;
640
+ else if (props.intent === "success") {
641
+ restProps.c ??= "white";
642
+ restProps.color ??= "green";
643
+ } else if (props.intent === "danger") {
644
+ restProps.c ??= "white";
645
+ restProps.color ??= "red";
646
+ } else if (props.intent === "warning") restProps.color ??= "yellow";
647
+ else if (props.intent === "info") {
648
+ restProps.c ??= "white";
649
+ restProps.color ??= "blue";
650
+ }
651
+ }
652
+ if (props.icon) {
653
+ const sizes = ui.sizes.icon;
654
+ const icon = isComponentType(props.icon) ? /* @__PURE__ */ jsx(props.icon, { size: sizes[props.size || "md"] }) : /* @__PURE__ */ jsx("span", { children: props.icon });
655
+ if (!props.children) {
656
+ restProps.children = Children.only(icon);
657
+ restProps.px ??= "xs";
658
+ } else restProps.leftSection = icon;
659
+ }
660
+ if (props.leftSection && !props.children) restProps.px ??= "xs";
661
+ if (props.textVisibleFrom) {
662
+ const { children, textVisibleFrom, leftSection, ...rest } = restProps;
663
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Flex, {
664
+ w: "100%",
665
+ visibleFrom: textVisibleFrom,
666
+ children: /* @__PURE__ */ jsx(ActionButton, {
667
+ flex: 1,
668
+ ...rest,
669
+ leftSection,
670
+ tooltip,
671
+ menu,
672
+ children
673
+ })
674
+ }), /* @__PURE__ */ jsx(Flex, {
675
+ w: "100%",
676
+ hiddenFrom: textVisibleFrom,
677
+ children: /* @__PURE__ */ jsx(ActionButton, {
678
+ px: "xs",
679
+ ...rest,
680
+ tooltip,
681
+ menu,
682
+ children: leftSection
683
+ })
684
+ })] });
685
+ }
686
+ const renderAction = () => {
687
+ if ("href" in restProps && restProps.href) {
688
+ if (restProps.href.startsWith("http") || restProps.target) return /* @__PURE__ */ jsx(ActionHrefButton, {
689
+ ...restProps,
690
+ href: restProps.href,
691
+ children: restProps.children
692
+ });
693
+ return /* @__PURE__ */ jsx(ActionNavigationButton, {
694
+ ...restProps,
695
+ href: restProps.href,
696
+ children: restProps.children
697
+ });
698
+ }
699
+ delete restProps.classNameActive;
700
+ delete restProps.variantActive;
701
+ delete restProps.propsActive;
702
+ if ("action" in restProps && restProps.action) return /* @__PURE__ */ jsx(ActionHookButton, {
703
+ ...restProps,
704
+ action: restProps.action,
705
+ children: restProps.children
706
+ });
707
+ if ("onClick" in restProps && restProps.onClick) return /* @__PURE__ */ jsx(ActionClickButton, {
708
+ ...restProps,
709
+ onClick: restProps.onClick,
710
+ children: restProps.children
711
+ });
712
+ if ("form" in restProps && restProps.form) {
713
+ if (restProps.type === "reset") return /* @__PURE__ */ jsx(ActionResetButton, {
714
+ ...restProps,
715
+ form: restProps.form,
716
+ children: restProps.children
717
+ });
718
+ return /* @__PURE__ */ jsx(ActionSubmitButton, {
719
+ ...restProps,
720
+ form: restProps.form,
721
+ children: restProps.children
722
+ });
723
+ }
724
+ return /* @__PURE__ */ jsx(Button, {
725
+ ...restProps,
726
+ children: restProps.children
727
+ });
728
+ };
729
+ let actionElement = renderAction();
730
+ if (menu) actionElement = /* @__PURE__ */ jsxs(Menu, {
731
+ position: menu.position || "bottom-start",
732
+ width: menu.width || 200,
733
+ shadow: menu.shadow || "md",
734
+ trigger: menu.on === "hover" ? "hover" : "click",
735
+ ...menu.menuProps,
736
+ children: [/* @__PURE__ */ jsx(Menu.Target, {
737
+ ...menu.targetProps,
738
+ children: actionElement
739
+ }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: menu.items.map((item, index) => /* @__PURE__ */ jsx(ActionMenuItem, {
740
+ item,
741
+ index
742
+ }, index)) })]
743
+ });
744
+ if (tooltip) {
745
+ const defaultTooltipProps = { openDelay: 1e3 };
746
+ return /* @__PURE__ */ jsx(Tooltip, { ...typeof tooltip === "string" || typeof tooltip === "number" ? {
747
+ ...defaultTooltipProps,
748
+ label: tooltip,
749
+ children: actionElement
750
+ } : {
751
+ ...defaultTooltipProps,
752
+ ...tooltip,
753
+ children: actionElement
754
+ } });
755
+ }
756
+ return actionElement;
757
+ };
758
+ /**
759
+ * Action button that submits a form with loading and disabled state handling.
760
+ */
761
+ const ActionSubmitButton = (props) => {
762
+ const { form, ...buttonProps } = props;
763
+ const state = useFormState(form);
764
+ return /* @__PURE__ */ jsx(Button, {
765
+ ...buttonProps,
766
+ loading: state.loading,
767
+ disabled: state.loading,
768
+ type: "submit",
769
+ children: props.children
770
+ });
771
+ };
772
+ const ActionResetButton = (props) => {
773
+ const { form, ...buttonProps } = props;
774
+ const state = useFormState(form);
775
+ return /* @__PURE__ */ jsx(Button, {
776
+ ...buttonProps,
777
+ disabled: state.loading,
778
+ type: "reset",
779
+ children: props.children
780
+ });
781
+ };
782
+ /**
783
+ * Action button that integrates with useAction hook return value.
784
+ * Automatically handles loading state and executes the action on click.
785
+ *
786
+ * @example
787
+ * ```tsx
788
+ * const saveAction = useAction({
789
+ * handler: async (data) => {
790
+ * await api.save(data);
791
+ * }
792
+ * }, []);
793
+ *
794
+ * <ActionButton action={saveAction}>
795
+ * Save
796
+ * </ActionButton>
797
+ * ```
798
+ */
799
+ const ActionHookButton = (props) => {
800
+ const { action, ...buttonProps } = props;
801
+ return /* @__PURE__ */ jsx(Button, {
802
+ ...buttonProps,
803
+ disabled: action.loading || props.disabled,
804
+ loading: action.loading,
805
+ onClick: () => action.run(),
806
+ children: props.children
807
+ });
808
+ };
809
+ /**
810
+ * Basic action button that handles click events with loading and error handling.
811
+ *
812
+ * @example
813
+ * ```tsx
814
+ * <ActionButton onClick={() => api.doSomething()}>
815
+ * Do Something
816
+ * </ActionButton>
817
+ * ```
818
+ */
819
+ const ActionClickButton = ({ preventDefault, ...props }) => {
820
+ const action = useAction({ handler: async (e) => {
821
+ if (preventDefault) e.preventDefault();
822
+ await props.onClick(e);
823
+ } }, [props.onClick, preventDefault]);
824
+ return /* @__PURE__ */ jsx(Button, {
825
+ ...props,
826
+ disabled: action.loading || props.disabled,
827
+ loading: action.loading,
828
+ onClick: action.run,
829
+ children: props.children
830
+ });
831
+ };
832
+ /**
833
+ * Action for navigation with active state support.
834
+ */
835
+ const ActionNavigationButton = (props) => {
836
+ const { active: options, classNameActive, variantActive, propsActive, routerGoOptions, onClick: propsOnClick, anchor, ...buttonProps } = props;
837
+ const router = useRouter();
838
+ const { isPending, isActive } = useActive(options ? {
839
+ href: props.href,
840
+ ...options
841
+ } : { href: props.href });
842
+ const anchorProps = router.anchor(props.href, routerGoOptions);
843
+ if (propsActive && isActive) Object.assign(buttonProps, propsActive);
844
+ const combinedOnClick = (e) => {
845
+ propsOnClick?.(e);
846
+ anchorProps.onClick?.(e);
847
+ };
848
+ const className = buttonProps.className || "";
849
+ if (isActive && options !== false && classNameActive) buttonProps.className = `${className} ${classNameActive}`.trim();
850
+ if (props.anchorProps || anchor) return /* @__PURE__ */ jsx(Anchor, {
851
+ component: "a",
852
+ ...anchorProps,
853
+ ...buttonProps,
854
+ ...props.anchorProps,
855
+ onClick: combinedOnClick,
856
+ children: props.children
857
+ });
858
+ return /* @__PURE__ */ jsx(Button, {
859
+ component: "a",
860
+ loading: isPending,
861
+ ...buttonProps,
862
+ ...anchorProps,
863
+ onClick: combinedOnClick,
864
+ variant: isActive && options !== false ? variantActive ?? "filled" : buttonProps.variant ?? "subtle",
865
+ children: props.children
866
+ });
867
+ };
868
+ const ActionHrefButton = (props) => {
869
+ const { active: options, classNameActive, variantActive, propsActive, routerGoOptions, target, ...buttonProps } = props;
870
+ return /* @__PURE__ */ jsx(Button, {
871
+ component: "a",
872
+ target,
873
+ ...buttonProps,
874
+ children: props.children
875
+ });
876
+ };
877
+
878
+ //#endregion
879
+ //#region ../../src/core/components/Flex.tsx
880
+ const Flex$1 = forwardRef((props, ref) => {
881
+ const { fill, center, centerX, centerY, col, ...rest } = props;
882
+ if (fill) rest.flex ??= 1;
883
+ if (col) rest.direction ??= "column";
884
+ if (center) {
885
+ rest.align ??= "center";
886
+ rest.justify ??= "center";
887
+ }
888
+ if (centerX) rest.justify ??= "center";
889
+ if (centerY) rest.align ??= "center";
890
+ return /* @__PURE__ */ jsx(Flex, {
891
+ ref,
892
+ ...rest
893
+ });
894
+ });
895
+ Flex$1.displayName = "Flex";
896
+
897
+ //#endregion
898
+ //#region ../../src/core/components/layout/Container.tsx
899
+ const Container$1 = forwardRef((props, ref) => {
900
+ return /* @__PURE__ */ jsx(Container, {
901
+ ref,
902
+ ...props
903
+ });
904
+ });
905
+ Container$1.displayName = "Container";
906
+
907
+ //#endregion
908
+ //#region ../../src/core/components/Text.tsx
909
+ const INTENT_COLORS = {
910
+ primary: "blue",
911
+ info: "cyan",
912
+ success: "green",
913
+ warning: "yellow",
914
+ danger: "red"
915
+ };
916
+ const Text$1 = forwardRef((props, ref) => {
917
+ const { intent, bold, italic, light, muted, small, uppercase, capitalize, center, monospace, title, ...rest } = props;
918
+ if (intent) rest.c ??= INTENT_COLORS[intent];
919
+ if (bold) rest.fw ??= 700;
920
+ if (light) rest.fw ??= 300;
921
+ if (italic) rest.fs ??= "italic";
922
+ if (muted) rest.c ??= "dimmed";
923
+ if (small) rest.size ??= "sm";
924
+ if (uppercase) rest.tt ??= "uppercase";
925
+ if (capitalize) rest.tt ??= "capitalize";
926
+ if (center) rest.ta ??= "center";
927
+ if (monospace) rest.ff ??= "monospace";
928
+ if (title) rest.size ??= "xl";
929
+ return /* @__PURE__ */ jsx(Text, {
930
+ ref,
931
+ ...rest
932
+ });
933
+ });
934
+ Text$1.displayName = "Text";
935
+
936
+ //#endregion
937
+ //#region ../../src/core/form/utils/parseInput.ts
938
+ const parseInput = (props, form) => {
939
+ const disabled = false;
940
+ const id = props.input.props.id;
941
+ 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);
942
+ const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
943
+ const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
944
+ const icon = !props.icon ? getDefaultIcon({
945
+ type: props.input.schema && "type" in props.input.schema ? String(props.input.schema.type) : void 0,
946
+ format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
947
+ name: props.input.props.name,
948
+ isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
949
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
950
+ }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.md });
951
+ const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
952
+ const required = props.input.required;
953
+ const schema = props.input.schema;
954
+ const inputProps = {
955
+ label,
956
+ description,
957
+ error,
958
+ required,
959
+ disabled
960
+ };
961
+ if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
962
+ if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
963
+ if ("minimum" in schema && typeof schema.minimum === "number") inputProps.minimum = schema.minimum;
964
+ if ("maximum" in schema && typeof schema.maximum === "number") inputProps.maximum = schema.maximum;
965
+ return {
966
+ id,
967
+ icon,
968
+ format,
969
+ schema: props.input.schema,
970
+ inputProps
971
+ };
972
+ };
973
+
974
+ //#endregion
975
+ //#region ../../src/core/form/components/ControlArray.tsx
976
+ /**
977
+ * Custom hook to sync array items with form state.
978
+ * Uses form events as the source of truth, eliminating dual-state issues.
979
+ */
980
+ const useArrayItems = (input) => {
981
+ const alepha = useAlepha();
982
+ const keyCounter = useRef(0);
983
+ const [items, setItemsState] = useState(() => {
984
+ const defaultValue = input?.props?.defaultValue;
985
+ if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
986
+ key: keyCounter.current++,
987
+ value
988
+ }));
989
+ return [];
990
+ });
991
+ const syncFromFormValue = useCallback((formValue) => {
992
+ if (!Array.isArray(formValue)) {
993
+ setItemsState([]);
994
+ return;
995
+ }
996
+ setItemsState((prevItems) => {
997
+ if (prevItems.length === formValue.length) {
998
+ if (prevItems.every((item, i) => item.value === formValue[i])) return prevItems;
999
+ }
1000
+ keyCounter.current = 0;
1001
+ return formValue.map((value) => ({
1002
+ key: keyCounter.current++,
1003
+ value
1004
+ }));
1005
+ });
1006
+ }, []);
1007
+ useEffect(() => {
1008
+ if (!input?.form) return;
1009
+ const formId = input.form.id;
1010
+ const fieldPath = input.path;
1011
+ const listeners = [alepha.events.on("form:reset", (event) => {
1012
+ if (event.id === formId) {
1013
+ const defaultValue = input.props?.defaultValue;
1014
+ keyCounter.current = 0;
1015
+ if (Array.isArray(defaultValue)) setItemsState(defaultValue.map((value) => ({
1016
+ key: keyCounter.current++,
1017
+ value
1018
+ })));
1019
+ else setItemsState([]);
1020
+ }
1021
+ }), alepha.events.on("form:change", (event) => {
1022
+ if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
1023
+ })];
1024
+ return () => {
1025
+ for (const unsub of listeners) unsub();
1026
+ };
1027
+ }, [
1028
+ alepha,
1029
+ input,
1030
+ syncFromFormValue
1031
+ ]);
1032
+ return {
1033
+ items,
1034
+ setItems: useCallback((newItems) => {
1035
+ setItemsState(newItems);
1036
+ input?.set(newItems.map((item) => item.value));
1037
+ }, [input]),
1038
+ nextKey: useCallback(() => keyCounter.current++, [])
1039
+ };
1040
+ };
1041
+ /**
1042
+ * Creates a proper InputField for an array item that integrates with the form system.
1043
+ * Uses array index for test IDs to ensure predictable, testable element identifiers.
1044
+ */
1045
+ const createArrayItemInput = (parentInput, itemSchema, index, _itemKey, value, onValueChange) => {
1046
+ return {
1047
+ schema: itemSchema,
1048
+ path: `${parentInput.path}/${index}`,
1049
+ required: false,
1050
+ form: parentInput.form,
1051
+ props: {
1052
+ id: `${parentInput.props.id}-${index}`,
1053
+ name: `${parentInput.props.name}[${index}]`,
1054
+ defaultValue: value
1055
+ },
1056
+ set: onValueChange
1057
+ };
1058
+ };
1059
+ /**
1060
+ * Creates a proper InputField for a nested object field within an array item.
1061
+ * Uses array index for test IDs to ensure predictable, testable element identifiers.
1062
+ */
1063
+ const createArrayItemFieldInput = (parentInput, itemSchema, fieldName, index, _itemKey, itemValue, onFieldChange) => {
1064
+ return {
1065
+ schema: itemSchema.properties[fieldName],
1066
+ path: `${parentInput.path}/${index}/${fieldName}`,
1067
+ required: itemSchema.required?.includes(fieldName) ?? false,
1068
+ form: parentInput.form,
1069
+ props: {
1070
+ id: `${parentInput.props.id}-${index}-${fieldName}`,
1071
+ name: `${parentInput.props.name}[${index}].${fieldName}`,
1072
+ defaultValue: itemValue?.[fieldName]
1073
+ },
1074
+ set: (value) => onFieldChange(fieldName, value)
1075
+ };
1076
+ };
1077
+ /**
1078
+ * ControlArray component for editing arrays of schema items.
1079
+ *
1080
+ * Features:
1081
+ * - Dynamic add/remove of items
1082
+ * - Supports arrays of objects with nested fields
1083
+ * - Supports arrays of primitives
1084
+ * - Grid layout for object items
1085
+ * - Min/max constraints
1086
+ * - Syncs with form state (handles external updates and resets)
1087
+ *
1088
+ * @example
1089
+ * ```tsx
1090
+ * // For a schema like:
1091
+ * // t.object({
1092
+ * // contacts: t.array(t.object({
1093
+ * // name: t.text(),
1094
+ * // email: t.text({ format: "email" }),
1095
+ * // }))
1096
+ * // })
1097
+ *
1098
+ * <ControlArray
1099
+ * input={form.input.contacts}
1100
+ * columns={2}
1101
+ * addLabel="Add contact"
1102
+ * controlProps={{
1103
+ * email: { text: { placeholder: "email@example.com" } }
1104
+ * }}
1105
+ * />
1106
+ * ```
1107
+ */
1108
+ const ControlArray = (props) => {
1109
+ const { inputProps } = parseInput(props, {});
1110
+ const { items, setItems, nextKey } = useArrayItems(props.input);
1111
+ if (!props.input?.props) return null;
1112
+ const schema = props.input.schema;
1113
+ if (!schema || !("items" in schema)) return null;
1114
+ const itemSchema = schema.items;
1115
+ const isObjectItem = itemSchema && "properties" in itemSchema;
1116
+ const { min = 0, max = Number.POSITIVE_INFINITY, columns = 1 } = props;
1117
+ const handleAdd = () => {
1118
+ if (items.length >= max) return;
1119
+ let newValue;
1120
+ if (isObjectItem) {
1121
+ newValue = {};
1122
+ const objSchema = itemSchema;
1123
+ for (const [key, propSchema] of Object.entries(objSchema.properties)) if ("default" in propSchema) newValue[key] = propSchema.default;
1124
+ } else newValue = "";
1125
+ setItems([...items, {
1126
+ key: nextKey(),
1127
+ value: newValue
1128
+ }]);
1129
+ };
1130
+ const handleRemove = (index) => {
1131
+ if (items.length <= min) return;
1132
+ setItems(items.filter((_, i) => i !== index));
1133
+ };
1134
+ const handleItemChange = (index, value) => {
1135
+ const newItems = [...items];
1136
+ newItems[index] = {
1137
+ ...newItems[index],
1138
+ value
1139
+ };
1140
+ setItems(newItems);
1141
+ };
1142
+ const handleFieldChange = (index, field, value) => {
1143
+ const newItems = [...items];
1144
+ newItems[index] = {
1145
+ ...newItems[index],
1146
+ value: {
1147
+ ...newItems[index].value,
1148
+ [field]: value
1149
+ }
1150
+ };
1151
+ setItems(newItems);
1152
+ };
1153
+ const colSpan = 12 / columns;
1154
+ const objectItemSchema = isObjectItem ? itemSchema : null;
1155
+ const fieldNames = objectItemSchema ? Object.keys(objectItemSchema.properties) : [];
1156
+ const renderItems = () => /* @__PURE__ */ jsxs(Flex, {
1157
+ direction: "column",
1158
+ gap: "sm",
1159
+ children: [items.map((item, index) => /* @__PURE__ */ jsxs(Flex, {
1160
+ gap: "sm",
1161
+ align: "flex-start",
1162
+ p: "xs",
1163
+ bg: ui.colors.surface,
1164
+ style: { borderRadius: "var(--mantine-radius-sm)" },
1165
+ children: [
1166
+ props.sortable && /* @__PURE__ */ jsx(ActionIcon, {
1167
+ variant: "subtle",
1168
+ color: "gray",
1169
+ style: { cursor: "grab" },
1170
+ children: /* @__PURE__ */ jsx(IconGripVertical, { size: 16 })
1171
+ }),
1172
+ objectItemSchema ? /* @__PURE__ */ jsx(Grid, {
1173
+ style: { flex: 1 },
1174
+ gutter: "sm",
1175
+ children: fieldNames.map((fieldName) => {
1176
+ const fieldControlProps = props.controlProps?.[fieldName] ?? {};
1177
+ const fieldInput = createArrayItemFieldInput(props.input, objectItemSchema, fieldName, index, item.key, item.value, (field, value) => handleFieldChange(index, field, value));
1178
+ return /* @__PURE__ */ jsx(Grid.Col, {
1179
+ span: colSpan,
1180
+ children: /* @__PURE__ */ jsx(Control, {
1181
+ input: fieldInput,
1182
+ ...fieldControlProps
1183
+ })
1184
+ }, fieldName);
1185
+ })
1186
+ }) : /* @__PURE__ */ jsx(Flex, {
1187
+ style: { flex: 1 },
1188
+ children: /* @__PURE__ */ jsx(Control, {
1189
+ input: createArrayItemInput(props.input, itemSchema, index, item.key, item.value, (value) => handleItemChange(index, value)),
1190
+ ...props.itemControlProps
1191
+ })
1192
+ }),
1193
+ /* @__PURE__ */ jsx(ActionIcon, {
1194
+ variant: "subtle",
1195
+ color: "red",
1196
+ onClick: () => handleRemove(index),
1197
+ disabled: items.length <= min,
1198
+ children: /* @__PURE__ */ jsx(IconTrash, { size: 16 })
1199
+ })
1200
+ ]
1201
+ }, item.key)), /* @__PURE__ */ jsxs(UnstyledButton, {
1202
+ onClick: handleAdd,
1203
+ disabled: items.length >= max,
1204
+ style: {
1205
+ display: "flex",
1206
+ alignItems: "center",
1207
+ justifyContent: "center",
1208
+ gap: 6,
1209
+ padding: "8px 12px",
1210
+ borderRadius: "var(--mantine-radius-sm)",
1211
+ border: "1px dashed var(--mantine-color-dimmed)",
1212
+ color: "var(--mantine-color-dimmed)",
1213
+ fontSize: "var(--mantine-font-size-sm)",
1214
+ cursor: items.length >= max ? "not-allowed" : "pointer",
1215
+ opacity: items.length >= max ? .5 : 1,
1216
+ transition: "all 150ms ease"
1217
+ },
1218
+ onMouseEnter: (e) => {
1219
+ if (items.length < max) {
1220
+ e.currentTarget.style.borderColor = "var(--mantine-color-blue-filled)";
1221
+ e.currentTarget.style.color = "var(--mantine-color-blue-filled)";
1222
+ e.currentTarget.style.background = "var(--mantine-color-blue-light)";
1223
+ }
1224
+ },
1225
+ onMouseLeave: (e) => {
1226
+ e.currentTarget.style.borderColor = "var(--mantine-color-dimmed)";
1227
+ e.currentTarget.style.color = "var(--mantine-color-dimmed)";
1228
+ e.currentTarget.style.background = "transparent";
1229
+ },
1230
+ children: [/* @__PURE__ */ jsx(IconPlus, { size: 14 }), props.addLabel ?? "Add"]
1231
+ })]
1232
+ });
1233
+ if (props.variant === "plain") return /* @__PURE__ */ jsxs(Flex, {
1234
+ direction: "column",
1235
+ gap: "xs",
1236
+ children: [
1237
+ inputProps.label && /* @__PURE__ */ jsx(Text, {
1238
+ size: "sm",
1239
+ fw: 500,
1240
+ children: inputProps.label
1241
+ }),
1242
+ inputProps.description && /* @__PURE__ */ jsx(Text, {
1243
+ size: "sm",
1244
+ c: "dimmed",
1245
+ children: inputProps.description
1246
+ }),
1247
+ renderItems(),
1248
+ inputProps.error && /* @__PURE__ */ jsx(Text, {
1249
+ size: "sm",
1250
+ c: "red",
1251
+ children: inputProps.error
1252
+ })
1253
+ ]
1254
+ });
1255
+ return /* @__PURE__ */ jsx(Fieldset, {
1256
+ legend: inputProps.label,
1257
+ children: /* @__PURE__ */ jsxs(Flex, {
1258
+ direction: "column",
1259
+ gap: "xs",
1260
+ children: [
1261
+ inputProps.description && /* @__PURE__ */ jsx(Text, {
1262
+ size: "sm",
1263
+ c: "dimmed",
1264
+ children: inputProps.description
1265
+ }),
1266
+ renderItems(),
1267
+ inputProps.error && /* @__PURE__ */ jsx(Text, {
1268
+ size: "sm",
1269
+ c: "red",
1270
+ children: inputProps.error
1271
+ })
1272
+ ]
1273
+ })
1274
+ });
1275
+ };
1276
+
1277
+ //#endregion
1278
+ //#region ../../src/core/form/components/ControlDate.tsx
1279
+ /**
1280
+ * ControlDate component for handling date, datetime, and time inputs.
1281
+ *
1282
+ * Features:
1283
+ * - DateInput for date format
1284
+ * - DateTimePicker for date-time format
1285
+ * - TimeInput for time format
1286
+ *
1287
+ * Automatically detects date formats from schema and renders appropriate picker.
1288
+ */
1289
+ const ControlDate = (props) => {
1290
+ const { inputProps, id, icon, format } = parseInput(props, useFormState(props.input));
1291
+ if (!props.input?.props) return null;
1292
+ if (props.datetime || format === "date-time") {
1293
+ const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
1294
+ return /* @__PURE__ */ jsx(DateTimePicker, {
1295
+ ...inputProps,
1296
+ id,
1297
+ leftSection: icon,
1298
+ defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
1299
+ onChange: (value) => {
1300
+ props.input.set(value ? new Date(value).toISOString() : void 0);
1301
+ },
1302
+ ...dateTimePickerProps
1303
+ });
1304
+ }
1305
+ if (props.date || format === "date") {
1306
+ const dateInputProps = typeof props.date === "object" ? props.date : {};
1307
+ return /* @__PURE__ */ jsx(DateInput, {
1308
+ ...inputProps,
1309
+ id,
1310
+ leftSection: icon,
1311
+ defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
1312
+ onChange: (value) => {
1313
+ props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
1314
+ },
1315
+ ...dateInputProps
1316
+ });
1317
+ }
1318
+ if (props.time || format === "time") {
1319
+ const timeInputProps = typeof props.time === "object" ? props.time : {};
1320
+ return /* @__PURE__ */ jsx(TimeInput, {
1321
+ ...inputProps,
1322
+ id,
1323
+ leftSection: icon,
1324
+ defaultValue: props.input.props.defaultValue,
1325
+ onChange: (event) => {
1326
+ props.input.set(event.currentTarget.value);
1327
+ },
1328
+ ...timeInputProps
1329
+ });
1330
+ }
1331
+ return null;
1332
+ };
1333
+
1334
+ //#endregion
1335
+ //#region ../../src/core/form/components/ControlNumber.tsx
1336
+ /**
1337
+ *
1338
+ */
1339
+ const ControlNumber = (props) => {
1340
+ const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
1341
+ const ref = useRef(null);
1342
+ const [value, setValue] = useState(props.input.props.defaultValue);
1343
+ useEvents({ "form:reset": (event) => {
1344
+ if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
1345
+ } }, [props.input]);
1346
+ if (!props.input?.props) return null;
1347
+ const { type, ...inputPropsWithoutType } = props.input.props;
1348
+ if (props.sliderProps) {
1349
+ const min = props.sliderProps.min ?? inputProps.minimum ?? 0;
1350
+ const max = props.sliderProps.max ?? inputProps.maximum ?? 100;
1351
+ return /* @__PURE__ */ jsx(Input.Wrapper, {
1352
+ ...inputProps,
1353
+ children: /* @__PURE__ */ jsx("div", {
1354
+ style: {
1355
+ height: 32,
1356
+ padding: 8
1357
+ },
1358
+ children: /* @__PURE__ */ jsx(Slider, {
1359
+ ...inputProps,
1360
+ ref,
1361
+ id,
1362
+ ...inputPropsWithoutType,
1363
+ ...props.sliderProps,
1364
+ value,
1365
+ min,
1366
+ max,
1367
+ label: () => value,
1368
+ onChange: (val) => {
1369
+ setValue(val);
1370
+ props.input.set(val);
1371
+ }
1372
+ })
1373
+ })
1374
+ });
1375
+ }
1376
+ return /* @__PURE__ */ jsx(NumberInput, {
1377
+ ...inputProps,
1378
+ ref,
1379
+ id,
1380
+ leftSection: icon,
1381
+ ...inputPropsWithoutType,
1382
+ ...props.numberInputProps,
1383
+ value: value ?? "",
1384
+ onChange: (val) => {
1385
+ const newValue = val !== null ? Number(val) : void 0;
1386
+ setValue(newValue);
1387
+ props.input.set(newValue);
1388
+ }
1389
+ });
1390
+ };
1391
+
1392
+ //#endregion
1393
+ //#region ../../src/core/form/components/ControlObject.tsx
1394
+ /**
1395
+ * ControlObject component for editing nested object schemas.
1396
+ *
1397
+ * Features:
1398
+ * - Renders all properties of an object schema
1399
+ * - Supports grid layout with configurable columns
1400
+ * - Per-field customization via controlProps
1401
+ * - Recursive support for deeply nested objects
1402
+ *
1403
+ * The form system provides nested InputFields under the `.items` property.
1404
+ * For example: form.input.address.items.street
1405
+ *
1406
+ * @example
1407
+ * ```tsx
1408
+ * // For a schema like:
1409
+ * // t.object({
1410
+ * // address: t.object({
1411
+ * // street: t.text(),
1412
+ * // city: t.text(),
1413
+ * // zip: t.text(),
1414
+ * // })
1415
+ * // })
1416
+ *
1417
+ * <ControlObject
1418
+ * input={form.input.address}
1419
+ * columns={2}
1420
+ * controlProps={{
1421
+ * zip: { text: { maxLength: 10 } }
1422
+ * }}
1423
+ * />
1424
+ * ```
1425
+ */
1426
+ const ControlObject = (props) => {
1427
+ const { inputProps } = parseInput(props, {});
1428
+ if (!props.input?.props) return null;
1429
+ const schema = props.input.schema;
1430
+ if (!schema?.properties) return null;
1431
+ const fieldNames = Object.keys(schema.properties);
1432
+ const colSpan = 12 / (props.columns ?? 1);
1433
+ const nestedItems = props.input.items;
1434
+ const renderFields = () => /* @__PURE__ */ jsx(Grid, { children: fieldNames.map((fieldName) => {
1435
+ const fieldControlProps = props.controlProps?.[fieldName] ?? {};
1436
+ const field = nestedItems?.[fieldName];
1437
+ if (!field) return null;
1438
+ return /* @__PURE__ */ jsx(Grid.Col, {
1439
+ span: colSpan,
1440
+ children: /* @__PURE__ */ jsx(Control, {
1441
+ input: field,
1442
+ ...fieldControlProps
1443
+ })
1444
+ }, fieldName);
1445
+ }) });
1446
+ if (props.variant === "plain") return renderFields();
1447
+ return /* @__PURE__ */ jsx(Fieldset, {
1448
+ legend: inputProps.label,
1449
+ children: /* @__PURE__ */ jsxs(Flex, {
1450
+ direction: "column",
1451
+ gap: "xs",
1452
+ children: [
1453
+ inputProps.description && /* @__PURE__ */ jsx(Text, {
1454
+ size: "sm",
1455
+ c: "dimmed",
1456
+ children: inputProps.description
1457
+ }),
1458
+ renderFields(),
1459
+ inputProps.error && /* @__PURE__ */ jsx(Text, {
1460
+ size: "sm",
1461
+ c: "red",
1462
+ children: inputProps.error
1463
+ })
1464
+ ]
1465
+ })
1466
+ });
1467
+ };
1468
+
1469
+ //#endregion
1470
+ //#region ../../src/core/form/components/ControlQueryBuilder.tsx
1471
+ /**
1472
+ * Query builder with text input and help popover.
1473
+ * Generates query strings for parseQueryString syntax.
1474
+ */
1475
+ const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
1476
+ const [helpOpened, setHelpOpened] = useState(false);
1477
+ const [textValue, setTextValue] = useState(value);
1478
+ const inputRef = useRef(null);
1479
+ const fields = schema ? extractSchemaFields(schema) : [];
1480
+ const [error, setError] = useState(null);
1481
+ const isValid = (value) => {
1482
+ try {
1483
+ parseQueryString(value.trim());
1484
+ } catch (e) {
1485
+ setError(e.message);
1486
+ return false;
1487
+ }
1488
+ setError(null);
1489
+ return true;
1490
+ };
1491
+ const handleTextChange = (newValue) => {
1492
+ setTextValue(newValue);
1493
+ if (isValid(newValue)) onChange?.(newValue);
1494
+ };
1495
+ const handleClear = () => {
1496
+ setTextValue("");
1497
+ onChange?.("");
1498
+ isValid("");
1499
+ };
1500
+ const handleInsert = (text) => {
1501
+ const newValue = textValue ? `${textValue}${text} ` : `${text} `;
1502
+ setTextValue(newValue);
1503
+ if (isValid(newValue)) onChange?.(newValue);
1504
+ setTimeout(() => {
1505
+ inputRef.current?.focus();
1506
+ const length = inputRef.current?.value.length || 0;
1507
+ inputRef.current?.setSelectionRange(length, length);
1508
+ }, 0);
1509
+ };
1510
+ useEvents({ "form:change": (event) => {
1511
+ if (event.id === inputRef.current?.form?.id) {
1512
+ if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
1513
+ }
1514
+ } }, []);
1515
+ return /* @__PURE__ */ jsxs(Popover, {
1516
+ width: 800,
1517
+ position: "bottom-start",
1518
+ shadow: "md",
1519
+ opened: helpOpened,
1520
+ onChange: setHelpOpened,
1521
+ closeOnClickOutside: true,
1522
+ closeOnEscape: true,
1523
+ transitionProps: {
1524
+ transition: "fade-up",
1525
+ duration: 200,
1526
+ timingFunction: "ease"
1527
+ },
1528
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
1529
+ ref: inputRef,
1530
+ placeholder,
1531
+ value: textValue,
1532
+ onChange: (e) => handleTextChange(e.currentTarget.value),
1533
+ onFocus: () => setHelpOpened(true),
1534
+ leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
1535
+ rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
1536
+ size: "sm",
1537
+ variant: "subtle",
1538
+ color: "gray",
1539
+ onClick: handleClear,
1540
+ children: /* @__PURE__ */ jsx(IconX, { size: 14 })
1541
+ }),
1542
+ ...textInputProps
1543
+ }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
1544
+ bg: "transparent",
1545
+ p: "xs",
1546
+ bd: `1px solid ${ui.colors.border}`,
1547
+ style: { backdropFilter: "blur(20px)" },
1548
+ children: /* @__PURE__ */ jsx(QueryHelp, {
1549
+ fields,
1550
+ onInsert: handleInsert
1551
+ })
1552
+ })]
1553
+ });
1554
+ };
1555
+ function QueryHelp({ fields, onInsert }) {
1556
+ return /* @__PURE__ */ jsxs(Flex, {
1557
+ gap: "md",
1558
+ align: "flex-start",
1559
+ wrap: "nowrap",
1560
+ bg: ui.colors.surface,
1561
+ p: "sm",
1562
+ bdrs: "sm",
1563
+ children: [
1564
+ /* @__PURE__ */ jsxs(Flex, {
1565
+ direction: "column",
1566
+ gap: "md",
1567
+ style: { flex: 1 },
1568
+ children: [
1569
+ /* @__PURE__ */ jsxs(Flex, {
1570
+ direction: "column",
1571
+ gap: "xs",
1572
+ children: [/* @__PURE__ */ jsx(Text, {
1573
+ size: "sm",
1574
+ fw: 600,
1575
+ children: "Operators"
1576
+ }), /* @__PURE__ */ jsx(Flex, {
1577
+ direction: "column",
1578
+ gap: 4,
1579
+ children: Object.entries(OPERATOR_INFO).map(([key, info]) => /* @__PURE__ */ jsxs(Flex, {
1580
+ gap: "xs",
1581
+ wrap: "nowrap",
1582
+ children: [/* @__PURE__ */ jsx(ActionButton, {
1583
+ px: "xs",
1584
+ size: "xs",
1585
+ h: 24,
1586
+ variant: "default",
1587
+ justify: "center",
1588
+ miw: 48,
1589
+ onClick: () => onInsert(info.symbol),
1590
+ children: info.symbol
1591
+ }), /* @__PURE__ */ jsx(Text, {
1592
+ size: "xs",
1593
+ c: "dimmed",
1594
+ style: { flex: 1 },
1595
+ children: info.label
1596
+ })]
1597
+ }, key))
1598
+ })]
1599
+ }),
1600
+ /* @__PURE__ */ jsx(Divider, {}),
1601
+ /* @__PURE__ */ jsxs(Flex, {
1602
+ direction: "column",
1603
+ gap: "xs",
1604
+ children: [/* @__PURE__ */ jsx(Text, {
1605
+ size: "sm",
1606
+ fw: 600,
1607
+ children: "Logic"
1608
+ }), /* @__PURE__ */ jsxs(Flex, {
1609
+ direction: "column",
1610
+ gap: 4,
1611
+ children: [/* @__PURE__ */ jsxs(Flex, {
1612
+ gap: "xs",
1613
+ wrap: "nowrap",
1614
+ children: [/* @__PURE__ */ jsx(ActionButton, {
1615
+ px: "xs",
1616
+ size: "xs",
1617
+ h: 24,
1618
+ variant: "default",
1619
+ justify: "center",
1620
+ miw: 48,
1621
+ onClick: () => onInsert("&"),
1622
+ children: "&"
1623
+ }), /* @__PURE__ */ jsx(Text, {
1624
+ size: "xs",
1625
+ c: "dimmed",
1626
+ children: "AND"
1627
+ })]
1628
+ }), /* @__PURE__ */ jsxs(Flex, {
1629
+ gap: "xs",
1630
+ wrap: "nowrap",
1631
+ children: [/* @__PURE__ */ jsx(ActionButton, {
1632
+ px: "xs",
1633
+ size: "xs",
1634
+ h: 24,
1635
+ variant: "default",
1636
+ justify: "center",
1637
+ miw: 48,
1638
+ onClick: () => onInsert("|"),
1639
+ children: "|"
1640
+ }), /* @__PURE__ */ jsx(Text, {
1641
+ size: "xs",
1642
+ c: "dimmed",
1643
+ children: "OR"
1644
+ })]
1645
+ })]
1646
+ })]
1647
+ })
1648
+ ]
1649
+ }),
1650
+ fields.length > 0 && /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }),
1651
+ fields.length > 0 && /* @__PURE__ */ jsxs(Flex, {
1652
+ direction: "column",
1653
+ gap: "xs",
1654
+ style: { flex: 2 },
1655
+ children: [/* @__PURE__ */ jsx(Text, {
1656
+ size: "sm",
1657
+ fw: 600,
1658
+ children: "Fields"
1659
+ }), /* @__PURE__ */ jsx(Flex, {
1660
+ direction: "column",
1661
+ gap: 4,
1662
+ style: {
1663
+ maxHeight: 300,
1664
+ overflowY: "auto"
1665
+ },
1666
+ children: fields.map((field) => /* @__PURE__ */ jsxs(Flex, {
1667
+ gap: "xs",
1668
+ wrap: "nowrap",
1669
+ align: "flex-start",
1670
+ children: [
1671
+ /* @__PURE__ */ jsx(ActionButton, {
1672
+ px: "xs",
1673
+ size: "xs",
1674
+ h: 24,
1675
+ variant: "default",
1676
+ justify: "end",
1677
+ miw: 120,
1678
+ onClick: () => onInsert(field.path),
1679
+ children: field.path
1680
+ }),
1681
+ /* @__PURE__ */ jsxs(Flex, {
1682
+ mt: 3,
1683
+ direction: "column",
1684
+ gap: 2,
1685
+ style: {
1686
+ flex: 1,
1687
+ minWidth: 0
1688
+ },
1689
+ children: [/* @__PURE__ */ jsx(Text, {
1690
+ size: "xs",
1691
+ c: "dimmed",
1692
+ lineClamp: 1,
1693
+ children: field.description || field.type
1694
+ }), field.enum && /* @__PURE__ */ jsx(Flex, {
1695
+ gap: 0,
1696
+ wrap: "wrap",
1697
+ children: field.enum.map((enumValue) => /* @__PURE__ */ jsx(ActionButton, {
1698
+ px: "xs",
1699
+ size: "xs",
1700
+ h: 24,
1701
+ onClick: () => onInsert(enumValue),
1702
+ children: enumValue
1703
+ }, enumValue))
1704
+ })]
1705
+ }),
1706
+ /* @__PURE__ */ jsx(Badge, {
1707
+ size: "xs",
1708
+ variant: "light",
1709
+ style: { flexShrink: 0 },
1710
+ children: field.type
1711
+ })
1712
+ ]
1713
+ }, field.path))
1714
+ })]
1715
+ })
1716
+ ]
1717
+ });
1718
+ }
1719
+
1720
+ //#endregion
1721
+ //#region ../../src/core/form/components/ControlSelect.tsx
1722
+ /**
1723
+ * ControlSelect component for handling Select, MultiSelect, and TagsInput.
1724
+ *
1725
+ * Features:
1726
+ * - Basic Select with enum support
1727
+ * - MultiSelect for array of enums
1728
+ * - TagsInput for array of strings (no enum)
1729
+ * - Future: Lazy loading
1730
+ * - Future: Searchable/filterable options
1731
+ * - Future: Custom option rendering
1732
+ *
1733
+ * Automatically detects enum values and array types from schema.
1734
+ */
1735
+ const ControlSelect = (props) => {
1736
+ const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
1737
+ const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
1738
+ let itemsEnum;
1739
+ if (isArray && "items" in props.input.schema && props.input.schema.items) {
1740
+ const items = props.input.schema.items;
1741
+ if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
1742
+ }
1743
+ const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
1744
+ const [data, setData] = useState([]);
1745
+ useEffect(() => {
1746
+ if (!props.input?.props) return;
1747
+ if (props.loader) props.loader().then(setData);
1748
+ else setData(enumValues);
1749
+ }, [props.input, props.loader]);
1750
+ if (!props.input?.props) return null;
1751
+ if (props.segmented) {
1752
+ const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
1753
+ return /* @__PURE__ */ jsx(Input.Wrapper, {
1754
+ ...inputProps,
1755
+ children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(SegmentedControl, {
1756
+ disabled: inputProps.disabled,
1757
+ defaultValue: String(props.input.props.defaultValue),
1758
+ ...segmentedControlProps,
1759
+ onChange: (value) => {
1760
+ props.input.set(value);
1761
+ },
1762
+ data: data.slice(0, 10)
1763
+ }) })
1764
+ });
1765
+ }
1766
+ if (props.autocomplete) {
1767
+ const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
1768
+ return /* @__PURE__ */ jsx(Autocomplete, {
1769
+ ...inputProps,
1770
+ size: props.size,
1771
+ id,
1772
+ leftSection: icon,
1773
+ data,
1774
+ ...props.input.props,
1775
+ ...autocompleteProps
1776
+ });
1777
+ }
1778
+ if (isArray && !itemsEnum || props.tags) {
1779
+ const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
1780
+ return /* @__PURE__ */ jsx(TagsInput, {
1781
+ ...inputProps,
1782
+ size: props.size,
1783
+ id,
1784
+ leftSection: icon,
1785
+ defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
1786
+ onChange: (value) => {
1787
+ props.input.set(value);
1788
+ },
1789
+ ...tagsInputProps
1790
+ });
1791
+ }
1792
+ if (isArray && itemsEnum || props.multi) {
1793
+ const data = itemsEnum?.map((value) => ({
1794
+ value,
1795
+ label: value
1796
+ })) || [];
1797
+ const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
1798
+ return /* @__PURE__ */ jsx(MultiSelect, {
1799
+ ...inputProps,
1800
+ size: props.size,
1801
+ id,
1802
+ leftSection: icon,
1803
+ data,
1804
+ defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
1805
+ onChange: (value) => {
1806
+ props.input.set(value);
1807
+ },
1808
+ ...multiSelectProps
1809
+ });
1810
+ }
1811
+ const selectProps = typeof props.select === "object" ? props.select : {};
1812
+ return /* @__PURE__ */ jsx(Select, {
1813
+ ...inputProps,
1814
+ size: props.size,
1815
+ id,
1816
+ leftSection: icon,
1817
+ rightSection: null,
1818
+ data,
1819
+ ...props.input.props,
1820
+ ...selectProps
1821
+ });
1822
+ };
1823
+
1824
+ //#endregion
1825
+ //#region ../../src/core/form/components/Control.tsx
1826
+ /**
1827
+ * Generic form control that renders the appropriate input based on the schema and props.
1828
+ *
1829
+ * Supports:
1830
+ * - TextInput (with format detection: email, url, tel)
1831
+ * - Textarea
1832
+ * - NumberInput (for number/integer types)
1833
+ * - FileInput
1834
+ * - ColorInput (for color format)
1835
+ * - Select (for enum types)
1836
+ * - Autocomplete
1837
+ * - PasswordInput
1838
+ * - Switch (for boolean types)
1839
+ * - SegmentedControl (for enum types)
1840
+ * - DateInput (for date format)
1841
+ * - DateTimePicker (for date-time format)
1842
+ * - TimeInput (for time format)
1843
+ * - QueryBuilder (for building type-safe queries with autocomplete)
1844
+ * - ControlObject (for nested object schemas)
1845
+ * - ControlArray (for arrays of objects)
1846
+ * - Custom component
1847
+ *
1848
+ * Automatically handles labels, descriptions, error messages, required state, and default icons.
1849
+ */
1850
+ const Control = (_props) => {
1851
+ const form = useFormState(_props.input, ["error"]);
1852
+ if (!_props.input?.props) return null;
1853
+ const { inputProps, id, icon, format, schema } = parseInput(_props, form);
1854
+ const props = {
1855
+ ..._props,
1856
+ ...schema.$control
1857
+ };
1858
+ if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder, {
1859
+ ...props.input.props,
1860
+ ...inputProps,
1861
+ schema: props.query,
1862
+ value: props.input.props.value,
1863
+ onChange: (value) => {
1864
+ props.input.set(value);
1865
+ }
1866
+ });
1867
+ if (props.custom) {
1868
+ const Custom = props.custom;
1869
+ return /* @__PURE__ */ jsx(Input.Wrapper, {
1870
+ ...inputProps,
1871
+ children: /* @__PURE__ */ jsx(Flex, {
1872
+ flex: 1,
1873
+ mt: "calc(var(--mantine-spacing-xs) / 2)",
1874
+ children: /* @__PURE__ */ jsx(Custom, {
1875
+ defaultValue: props.input.props.defaultValue,
1876
+ onChange: (value) => {
1877
+ props.input.set(value);
1878
+ }
1879
+ })
1880
+ })
1881
+ });
1882
+ }
1883
+ const isObject = props.input.schema && "type" in props.input.schema && props.input.schema.type === "object" && "properties" in props.input.schema;
1884
+ if (props.object || isObject) {
1885
+ const controlObjectProps = typeof props.object === "object" ? props.object : {};
1886
+ return /* @__PURE__ */ jsx(ControlObject, {
1887
+ input: props.input,
1888
+ title: props.title,
1889
+ description: props.description,
1890
+ ...controlObjectProps
1891
+ });
1892
+ }
1893
+ const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
1894
+ const isArrayOfObjects = isArray && "items" in props.input.schema && props.input.schema.items && typeof props.input.schema.items === "object" && "properties" in props.input.schema.items;
1895
+ if (props.array || isArrayOfObjects) {
1896
+ const controlArrayProps = typeof props.array === "object" ? props.array : {};
1897
+ return /* @__PURE__ */ jsx(ControlArray, {
1898
+ input: props.input,
1899
+ title: props.title,
1900
+ description: props.description,
1901
+ ...controlArrayProps
1902
+ });
1903
+ }
1904
+ if (props.number || props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
1905
+ const controlNumberProps = typeof props.number === "object" ? props.number : {};
1906
+ if (props.slider) controlNumberProps.sliderProps ??= {};
1907
+ return /* @__PURE__ */ jsx(ControlNumber, {
1908
+ size: props.size,
1909
+ input: props.input,
1910
+ title: props.title,
1911
+ description: props.description,
1912
+ icon,
1913
+ ...controlNumberProps
1914
+ });
1915
+ }
1916
+ if (props.file) {
1917
+ const fileInputProps = typeof props.file === "object" ? props.file : {};
1918
+ return /* @__PURE__ */ jsx(FileInput, {
1919
+ ...inputProps,
1920
+ size: props.size,
1921
+ id,
1922
+ leftSection: icon,
1923
+ onChange: (file) => {
1924
+ props.input.set(file);
1925
+ },
1926
+ ...fileInputProps
1927
+ });
1928
+ }
1929
+ if (props.color || format === "color") {
1930
+ const colorInputProps = typeof props.color === "object" ? props.color : {};
1931
+ return /* @__PURE__ */ jsx(ColorInput, {
1932
+ ...inputProps,
1933
+ size: props.size,
1934
+ id,
1935
+ leftSection: icon,
1936
+ ...props.input.props,
1937
+ ...colorInputProps
1938
+ });
1939
+ }
1940
+ if (props.input.schema && "enum" in props.input.schema && props.input.schema.enum || isArray && !isArrayOfObjects || props.select) {
1941
+ const opts = typeof props.select === "object" ? props.select : {};
1942
+ if (props.segmented) opts.segmented ??= {};
1943
+ return /* @__PURE__ */ jsx(ControlSelect, {
1944
+ size: props.size,
1945
+ input: props.input,
1946
+ title: props.title,
1947
+ description: props.description,
1948
+ icon,
1949
+ ...opts
1950
+ });
1951
+ }
1952
+ if (props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean") {
1953
+ if (props.switch) {
1954
+ const switchProps = typeof props.switch === "object" ? props.switch : {};
1955
+ return /* @__PURE__ */ jsx(Switch, {
1956
+ ...inputProps,
1957
+ size: props.size,
1958
+ id,
1959
+ color: "blue",
1960
+ defaultChecked: props.input.props.defaultValue,
1961
+ onChange: (event) => {
1962
+ props.input.set(event.currentTarget.checked);
1963
+ },
1964
+ ...switchProps
1965
+ });
1966
+ }
1967
+ const opts = {
1968
+ input: props.input,
1969
+ select: { data: [{
1970
+ value: "true",
1971
+ label: "Yes"
1972
+ }, {
1973
+ value: "false",
1974
+ label: "No"
1975
+ }] }
1976
+ };
1977
+ return /* @__PURE__ */ jsx(ControlSelect, {
1978
+ size: props.size,
1979
+ title: props.title,
1980
+ description: props.description,
1981
+ icon,
1982
+ ...opts
1983
+ });
1984
+ }
1985
+ if (props.password || props.input.props.name?.includes("password")) {
1986
+ const passwordInputProps = typeof props.password === "object" ? props.password : {};
1987
+ return /* @__PURE__ */ jsx(PasswordInput, {
1988
+ ...inputProps,
1989
+ size: props.size,
1990
+ id,
1991
+ leftSection: icon,
1992
+ ...props.input.props,
1993
+ ...passwordInputProps
1994
+ });
1995
+ }
1996
+ if (props.area) {
1997
+ const textAreaProps = typeof props.area === "object" ? props.area : {};
1998
+ return /* @__PURE__ */ jsx(Textarea, {
1999
+ ...inputProps,
2000
+ size: props.size,
2001
+ id,
2002
+ leftSection: icon,
2003
+ ...props.input.props,
2004
+ ...textAreaProps
2005
+ });
2006
+ }
2007
+ if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate, {
2008
+ size: props.size,
2009
+ input: props.input,
2010
+ title: props.title,
2011
+ description: props.description,
2012
+ icon,
2013
+ date: props.date,
2014
+ datetime: props.datetime,
2015
+ time: props.time
2016
+ });
2017
+ const textInputProps = typeof props.text === "object" ? props.text : {};
2018
+ const getInputType = () => {
2019
+ switch (format) {
2020
+ case "email": return "email";
2021
+ case "url":
2022
+ case "uri": return "url";
2023
+ case "tel":
2024
+ case "phone": return "tel";
2025
+ default: return;
2026
+ }
2027
+ };
2028
+ return /* @__PURE__ */ jsx(TextInput, {
2029
+ ...inputProps,
2030
+ size: props.size,
2031
+ id,
2032
+ leftSection: icon,
2033
+ type: getInputType(),
2034
+ ...props.input.props,
2035
+ ...textInputProps,
2036
+ inputWrapperOrder: [
2037
+ "label",
2038
+ "input",
2039
+ "description",
2040
+ "error"
2041
+ ]
2042
+ });
2043
+ };
2044
+
2045
+ //#endregion
2046
+ //#region ../../src/core/helpers/renderIcon.tsx
2047
+ const renderIcon = (icon, size) => {
2048
+ if (!icon) return null;
2049
+ if (isValidElement(icon)) return icon;
2050
+ if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
2051
+ return icon;
2052
+ };
2053
+
2054
+ //#endregion
2055
+ //#region ../../src/core/utils/extractSchemaFields.ts
2056
+ /**
2057
+ * Extract field information from a TypeBox schema for query building.
2058
+ * Supports nested objects and provides field metadata for autocomplete.
2059
+ */
2060
+ function extractSchemaFields(schema, prefix = "") {
2061
+ const fields = [];
2062
+ if (!schema || typeof schema !== "object") return fields;
2063
+ const properties = "properties" in schema ? schema.properties : schema;
2064
+ if (!properties || typeof properties !== "object") return fields;
2065
+ for (const [key, value] of Object.entries(properties)) {
2066
+ if (typeof value !== "object" || value === null) continue;
2067
+ const fieldSchema = value;
2068
+ const path = prefix ? `${prefix}.${key}` : key;
2069
+ const format = "format" in fieldSchema ? fieldSchema.format : void 0;
2070
+ let displayType = "type" in fieldSchema ? fieldSchema.type : "object";
2071
+ if (format === "date-time") displayType = "datetime";
2072
+ else if (format === "date") displayType = "date";
2073
+ else if (format === "time") displayType = "time";
2074
+ else if (format === "duration") displayType = "duration";
2075
+ const field = {
2076
+ name: key,
2077
+ path,
2078
+ type: displayType,
2079
+ format,
2080
+ description: "description" in fieldSchema ? fieldSchema.description : void 0
2081
+ };
2082
+ if ("enum" in fieldSchema && fieldSchema.enum) {
2083
+ field.enum = fieldSchema.enum;
2084
+ field.type = "enum";
2085
+ }
2086
+ if ("type" in fieldSchema && fieldSchema.type === "object" && "properties" in fieldSchema && typeof fieldSchema.properties === "object") field.nested = extractSchemaFields(fieldSchema.properties, path);
2087
+ fields.push(field);
2088
+ if (field.nested) fields.push(...field.nested);
2089
+ }
2090
+ return fields;
2091
+ }
2092
+ /**
2093
+ * Get operator symbol and description
2094
+ */
2095
+ const OPERATOR_INFO = {
2096
+ eq: {
2097
+ symbol: "=",
2098
+ label: "equals",
2099
+ example: "name=John"
2100
+ },
2101
+ ne: {
2102
+ symbol: "!=",
2103
+ label: "not equals",
2104
+ example: "status!=archived"
2105
+ },
2106
+ gt: {
2107
+ symbol: ">",
2108
+ label: "greater than",
2109
+ example: "age>18"
2110
+ },
2111
+ gte: {
2112
+ symbol: ">=",
2113
+ label: "greater or equal",
2114
+ example: "age>=18"
2115
+ },
2116
+ lt: {
2117
+ symbol: "<",
2118
+ label: "less than",
2119
+ example: "age<65"
2120
+ },
2121
+ lte: {
2122
+ symbol: "<=",
2123
+ label: "less or equal",
2124
+ example: "age<=65"
2125
+ },
2126
+ null: {
2127
+ symbol: "=null",
2128
+ label: "is null",
2129
+ example: "deletedAt=null"
2130
+ },
2131
+ notNull: {
2132
+ symbol: "!=null",
2133
+ label: "is not null",
2134
+ example: "email!=null"
2135
+ },
2136
+ in: {
2137
+ symbol: "[...]",
2138
+ label: "in array",
2139
+ example: "status=[active,pending]"
2140
+ }
2141
+ };
2142
+
2143
+ //#endregion
2144
+ //#region ../../src/core/utils/icons.tsx
2145
+ /**
2146
+ * Get the default icon for an input based on its type, format, or name.
2147
+ */
2148
+ const getDefaultIcon = (params) => {
2149
+ const { type, format, name, isEnum, isArray, size = "sm" } = params;
2150
+ const iconSize = ui.sizes.icon[size];
2151
+ if (format) switch (format) {
2152
+ case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
2153
+ case "url":
2154
+ case "uri": return /* @__PURE__ */ jsx(IconLink, { size: iconSize });
2155
+ case "tel":
2156
+ case "phone": return /* @__PURE__ */ jsx(IconPhone, { size: iconSize });
2157
+ case "date": return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
2158
+ case "date-time": return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
2159
+ case "time": return /* @__PURE__ */ jsx(IconClock, { size: iconSize });
2160
+ case "color": return /* @__PURE__ */ jsx(IconColorPicker, { size: iconSize });
2161
+ case "uuid": return /* @__PURE__ */ jsx(IconKey, { size: iconSize });
2162
+ }
2163
+ if (name) {
2164
+ const nameLower = name.toLowerCase();
2165
+ if (nameLower.includes("password") || nameLower.includes("secret")) return /* @__PURE__ */ jsx(IconKey, { size: iconSize });
2166
+ if (nameLower.includes("email") || nameLower.includes("mail")) return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
2167
+ if (nameLower.includes("url") || nameLower.includes("link")) return /* @__PURE__ */ jsx(IconLink, { size: iconSize });
2168
+ if (nameLower.includes("phone") || nameLower.includes("tel")) return /* @__PURE__ */ jsx(IconPhone, { size: iconSize });
2169
+ if (nameLower.includes("color")) return /* @__PURE__ */ jsx(IconPalette, { size: iconSize });
2170
+ if (nameLower.includes("file") || nameLower.includes("upload")) return /* @__PURE__ */ jsx(IconFile, { size: iconSize });
2171
+ if (nameLower.includes("date")) return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
2172
+ if (nameLower.includes("time")) return /* @__PURE__ */ jsx(IconClock, { size: iconSize });
2173
+ }
2174
+ if (isEnum || isArray) return /* @__PURE__ */ jsx(IconSelector, { size: iconSize });
2175
+ if (type) switch (type) {
2176
+ case "boolean": return /* @__PURE__ */ jsx(IconToggleLeft, { size: iconSize });
2177
+ case "number":
2178
+ case "integer": return /* @__PURE__ */ jsx(IconHash, { size: iconSize });
2179
+ case "array": return /* @__PURE__ */ jsx(IconList, { size: iconSize });
2180
+ case "string": return /* @__PURE__ */ jsx(IconLetterCase, { size: iconSize });
2181
+ }
2182
+ return /* @__PURE__ */ jsx(IconAt, { size: iconSize });
2183
+ };
2184
+
2185
+ //#endregion
2186
+ //#region ../../src/core/utils/string.ts
2187
+ /**
2188
+ * Capitalizes the first letter of a string.
2189
+ *
2190
+ * @example
2191
+ * capitalize("hello") // "Hello"
2192
+ */
2193
+ const capitalize = (str) => {
2194
+ return str.charAt(0).toUpperCase() + str.slice(1);
2195
+ };
2196
+ /**
2197
+ * Converts camelCase or snake_case to Title Case with spaces.
2198
+ *
2199
+ * @example
2200
+ * toTitleCase("userName") // "User Name"
2201
+ * toTitleCase("first_name") // "First Name"
2202
+ * toTitleCase("email") // "Email"
2203
+ */
2204
+ const toTitleCase = (str) => {
2205
+ return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
2206
+ };
2207
+ /**
2208
+ * Converts a path or identifier string into a pretty display name.
2209
+ * For paths like "/contacts/0/name", extracts just the field name "Name".
2210
+ * Handles camelCase and snake_case conversion to Title Case.
2211
+ *
2212
+ * @example
2213
+ * prettyName("/userName") // "User Name"
2214
+ * prettyName("/contacts/0/email") // "Email"
2215
+ * prettyName("/address/streetName") // "Street Name"
2216
+ * prettyName("first_name") // "First Name"
2217
+ */
2218
+ const prettyName = (name) => {
2219
+ const segments = name.split("/").filter((s) => s && !/^\d+$/.test(s));
2220
+ return toTitleCase(segments[segments.length - 1] || name.replaceAll("/", ""));
2221
+ };
2222
+
2223
+ //#endregion
2224
+ //#region ../../src/core/index.ts
2225
+ /**
2226
+ * Core UI components based on Mantine UI v8.
2227
+ *
2228
+ * **Features:**
2229
+ * - Mantine integration with theme support
2230
+ * - ActionButton, BurgerButton, ClipboardButton, DarkModeButton, LanguageButton, ThemeButton
2231
+ * - AlertDialog, ConfirmDialog, PromptDialog
2232
+ * - Form controls: Control, ControlArray, ControlDate, ControlNumber, ControlObject, ControlSelect, ControlQueryBuilder
2233
+ * - TypeForm for automatic form generation from TypeBox schemas
2234
+ * - DashboardShell layout component
2235
+ * - AppBar with configurable elements
2236
+ * - Sidebar navigation with sections and menu items
2237
+ * - Omnibar for command palette / search
2238
+ * - DataTable with filtering, sorting, pagination
2239
+ * - Toast notifications
2240
+ * - Theme system with dark mode
2241
+ *
2242
+ * @module alepha.ui
2243
+ */
2244
+ const AlephaUI = $module({
2245
+ name: "alepha.ui",
2246
+ services: [
2247
+ DialogService,
2248
+ ToastService,
2249
+ ThemeProvider,
2250
+ UiRouter
2251
+ ],
2252
+ register: (alepha) => {
2253
+ alepha.with(AlephaReactI18n);
2254
+ alepha.with(AlephaReactHead);
2255
+ alepha.with(AlephaReactForm);
2256
+ alepha.with(ThemeProvider);
2257
+ alepha.with(DialogService);
2258
+ alepha.with(ToastService);
2259
+ }
2260
+ });
2261
+
2262
+ //#endregion
2263
+ export { ui as a, ActionButton as i, capitalize as n, AlephaMantineProvider as o, Control as r, AlephaUI as t };
2264
+ //# sourceMappingURL=core-niW0sFLv.js.map