@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
@@ -3,18 +3,17 @@ import { AlephaReactForm, FormValidationError, useForm, useFormState } from "ale
3
3
  import { $head, AlephaReactHead } from "alepha/react/head";
4
4
  import { AlephaReactI18n, useI18n } from "alepha/react/i18n";
5
5
  import { $cookie } from "alepha/server/cookies";
6
- import { ActionIcon, Anchor, AppShell, Autocomplete, Badge, Burger, Button, Card, Checkbox, Collapse, ColorInput, ColorSchemeScript, Container, CopyButton, Divider, Drawer, Fieldset, FileInput, Flex, Flex as Flex$1, Grid, Image, Input, Kbd, MantineProvider, Menu, MultiSelect, NumberInput, Pagination, PasswordInput, Popover, ScrollArea, SegmentedControl, Select, Slider, Switch, Table, TagsInput, Text, Text as Text$1, TextInput, Textarea, ThemeIcon, Tooltip, UnstyledButton, useMantineColorScheme, useMantineTheme } from "@mantine/core";
7
6
  import { ModalsProvider, modals } from "@mantine/modals";
8
- import { IconAlertTriangle, IconArrowDown, IconArrowLeft, IconArrowUp, IconArrowsSort, IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClipboard, IconClock, IconColorPicker, IconColumns, IconCopy, IconDownload, IconFile, IconFilter, IconGripVertical, IconHash, IconInfoCircle, IconInfoTriangle, IconKey, IconLanguage, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightCollapse, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconPlus, IconRefresh, IconSearch, IconSelector, IconSquareRounded, IconSun, IconToggleLeft, IconTrash, IconX } from "@tabler/icons-react";
9
- import { Children, Fragment, createElement, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
10
- import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
+ import { ActionIcon, Anchor, AppShell, Autocomplete, Badge, Burger, Button, Card, Checkbox, ColorInput, ColorSchemeScript, Container as Container$1, CopyButton, Divider, Drawer, Fieldset, FileInput, Flex as Flex$1, Grid, Image, Input, Kbd, Loader, MantineProvider, Menu, MultiSelect, NumberInput, Pagination, Paper, PasswordInput, Popover, ScrollArea, SegmentedControl, Select, Slider, Switch, Table, Tabs, TagsInput, Text as Text$1, TextInput, Textarea, ThemeIcon, Tooltip, Tree, UnstyledButton, getTreeExpandedState, useMantineColorScheme, useMantineTheme, useTree } from "@mantine/core";
8
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
+ import { Children, Fragment as Fragment$1, createElement, forwardRef, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
11
10
  import { Notifications, notifications } from "@mantine/notifications";
11
+ import { IconAlertTriangle, IconArrowDown, IconArrowLeft, IconArrowUp, IconArrowsSort, IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClipboard, IconClock, IconColorPicker, IconColumns, IconCopy, IconDownload, IconFile, IconFilter, IconGripVertical, IconHash, IconInfoCircle, IconInfoTriangle, IconKey, IconLanguage, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightCollapse, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconPlus, IconRefresh, IconSearch, IconSelector, IconSquareRounded, IconSun, IconToggleLeft, IconTrash, IconX } from "@tabler/icons-react";
12
12
  import { $page, Link, NestedView, useActive, useRouter, useRouterState } from "alepha/react/router";
13
13
  import { NavigationProgress, nprogress } from "@mantine/nprogress";
14
14
  import { ClientOnly, useAction, useAlepha, useEvents, useInject, useStore } from "alepha/react";
15
15
  import { Spotlight, spotlight } from "@mantine/spotlight";
16
16
  import { currentUserAtom } from "alepha/security";
17
- import { ui as ui$1 } from "@alepha/ui";
18
17
  import { useOs } from "@mantine/hooks";
19
18
  import { DateInput, DateTimePicker, TimeInput } from "@mantine/dates";
20
19
  import { parseQueryString } from "alepha/orm";
@@ -24,24 +23,16 @@ import { DateTimeProvider } from "alepha/datetime";
24
23
  const alephaSidebarAtom = $atom({
25
24
  name: "alepha.ui.sidebar",
26
25
  schema: t.object({
27
- opened: t.boolean(),
26
+ closed: t.boolean(),
28
27
  collapsed: t.boolean(),
29
- width: t.number(),
30
- defaultWidth: t.number(),
31
- collapsedWidth: t.number(),
32
- maxWidth: t.number(),
33
- collapseThreshold: t.number(),
34
- hoverDelay: t.number()
28
+ expandedWidth: t.number(),
29
+ collapsedWidth: t.number()
35
30
  }),
36
31
  default: {
37
- opened: false,
32
+ closed: true,
38
33
  collapsed: false,
39
- width: 300,
40
- defaultWidth: 300,
41
- collapsedWidth: 78,
42
- maxWidth: 500,
43
- collapseThreshold: 240,
44
- hoverDelay: 300
34
+ expandedWidth: 300,
35
+ collapsedWidth: 78
45
36
  }
46
37
  });
47
38
 
@@ -220,148 +211,9 @@ var ThemeProvider = class {
220
211
  }
221
212
  };
222
213
 
223
- //#endregion
224
- //#region ../../src/core/components/data/ErrorViewer.tsx
225
- const getSizeConfig = (size = "sm") => {
226
- const configs = {
227
- xs: {
228
- text: "xs",
229
- icon: 12,
230
- gap: 2
231
- },
232
- sm: {
233
- text: "sm",
234
- icon: 14,
235
- gap: 4
236
- },
237
- md: {
238
- text: "md",
239
- icon: 16,
240
- gap: 6
241
- },
242
- lg: {
243
- text: "lg",
244
- icon: 18,
245
- gap: 8
246
- },
247
- xl: {
248
- text: "xl",
249
- icon: 20,
250
- gap: 10
251
- }
252
- };
253
- return configs[size] || configs.sm;
254
- };
255
- const parseStackTrace = (stack) => {
256
- return stack.split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
257
- };
258
- const ErrorViewer = ({ error, showStack = true, copyable = true, size = "sm" }) => {
259
- const [stackExpanded, setStackExpanded] = useState(false);
260
- const sizeConfig = getSizeConfig(size);
261
- const copyIconSize = sizeConfig.icon + 2;
262
- const isError = error instanceof Error;
263
- const errorName = isError ? error.name : "Error";
264
- const errorMessage = isError ? error.message : String(error);
265
- const errorStack = isError ? error.stack : void 0;
266
- const stackLines = errorStack ? parseStackTrace(errorStack) : [];
267
- const getCopyContent = () => {
268
- if (isError) return `${errorName}: ${errorMessage}${errorStack ? `\n\n${errorStack}` : ""}`;
269
- return String(error);
270
- };
271
- return /* @__PURE__ */ jsxs(Flex$1, {
272
- pos: "relative",
273
- w: "100%",
274
- children: [copyable && /* @__PURE__ */ jsx(Flex$1, {
275
- pos: "absolute",
276
- top: 0,
277
- right: 0,
278
- style: { zIndex: 1 },
279
- children: /* @__PURE__ */ jsx(CopyButton, {
280
- value: getCopyContent(),
281
- children: ({ copied, copy }) => /* @__PURE__ */ jsx(Tooltip, {
282
- label: copied ? "Copied" : "Copy Error",
283
- children: /* @__PURE__ */ jsx(ActionIcon, {
284
- color: copied ? "teal" : "gray",
285
- variant: "subtle",
286
- onClick: copy,
287
- size,
288
- children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: copyIconSize }) : /* @__PURE__ */ jsx(IconCopy, { size: copyIconSize })
289
- })
290
- })
291
- })
292
- }), /* @__PURE__ */ jsxs(Flex$1, {
293
- pt: copyable ? 30 : 0,
294
- children: [/* @__PURE__ */ jsxs(Flex$1, {
295
- style: {
296
- display: "flex",
297
- alignItems: "flex-start",
298
- gap: sizeConfig.gap
299
- },
300
- children: [/* @__PURE__ */ jsxs(Text$1, {
301
- component: "span",
302
- c: "red",
303
- ff: "monospace",
304
- fw: 600,
305
- size: sizeConfig.text,
306
- children: [errorName, ":"]
307
- }), /* @__PURE__ */ jsx(Text$1, {
308
- component: "span",
309
- ff: "monospace",
310
- size: sizeConfig.text,
311
- style: { wordBreak: "break-word" },
312
- children: errorMessage
313
- })]
314
- }), showStack && stackLines.length > 1 && /* @__PURE__ */ jsxs(Flex$1, {
315
- mt: "sm",
316
- children: [/* @__PURE__ */ jsxs(Flex$1, {
317
- style: {
318
- display: "flex",
319
- alignItems: "center",
320
- gap: sizeConfig.gap,
321
- cursor: "pointer"
322
- },
323
- onClick: () => setStackExpanded(!stackExpanded),
324
- children: [/* @__PURE__ */ jsx(ActionIcon, {
325
- size: "xs",
326
- variant: "transparent",
327
- c: "dimmed",
328
- children: stackExpanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: sizeConfig.icon }) : /* @__PURE__ */ jsx(IconChevronRight, { size: sizeConfig.icon })
329
- }), /* @__PURE__ */ jsxs(Text$1, {
330
- c: "dimmed",
331
- size: sizeConfig.text,
332
- fw: 500,
333
- children: [
334
- "Stack Trace (",
335
- stackLines.length - 1,
336
- " frames)"
337
- ]
338
- })]
339
- }), /* @__PURE__ */ jsx(Collapse, {
340
- in: stackExpanded,
341
- children: /* @__PURE__ */ jsx(Flex$1, {
342
- mt: "xs",
343
- pl: "md",
344
- style: { borderLeft: "1px solid var(--mantine-color-default-border)" },
345
- children: stackLines.slice(1).map((line, index) => /* @__PURE__ */ jsx(Text$1, {
346
- ff: "monospace",
347
- size: "xs",
348
- c: "dimmed",
349
- style: {
350
- whiteSpace: "pre-wrap",
351
- wordBreak: "break-all"
352
- },
353
- children: line
354
- }, index))
355
- })
356
- })]
357
- })]
358
- })]
359
- });
360
- };
361
-
362
214
  //#endregion
363
215
  //#region ../../src/core/components/dialogs/AlertDialog.tsx
364
- const AlertDialog = ({ options, onClose }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [options?.message && /* @__PURE__ */ jsx(Text$1, {
216
+ const AlertDialog = ({ options, onClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text$1, {
365
217
  mb: "md",
366
218
  children: options.message
367
219
  }), /* @__PURE__ */ jsx(Flex$1, {
@@ -374,7 +226,7 @@ const AlertDialog = ({ options, onClose }) => /* @__PURE__ */ jsxs(Fragment$1, {
374
226
 
375
227
  //#endregion
376
228
  //#region ../../src/core/components/dialogs/ConfirmDialog.tsx
377
- const ConfirmDialog = ({ options, onConfirm }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [options?.message && /* @__PURE__ */ jsx(Text$1, {
229
+ const ConfirmDialog = ({ options, onConfirm }) => /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text$1, {
378
230
  mb: "md",
379
231
  children: options.message
380
232
  }), /* @__PURE__ */ jsxs(Flex$1, {
@@ -404,7 +256,7 @@ const PromptDialog = ({ options, onSubmit }) => {
404
256
  const handleKeyDown = (event) => {
405
257
  if (event.key === "Enter") handleSubmit();
406
258
  };
407
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [
259
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
408
260
  options?.message && /* @__PURE__ */ jsx(Text$1, {
409
261
  mb: "md",
410
262
  children: options.message
@@ -434,25 +286,6 @@ const PromptDialog = ({ options, onSubmit }) => {
434
286
  ] });
435
287
  };
436
288
 
437
- //#endregion
438
- //#region ../../src/core/constants/ui.ts
439
- const ui = {
440
- colors: {
441
- transparent: "transparent",
442
- background: "var(--alepha-background)",
443
- surface: "var(--alepha-surface)",
444
- elevated: "var(--alepha-elevated)",
445
- border: "var(--alepha-border)"
446
- },
447
- sizes: { icon: {
448
- xs: 14,
449
- sm: 16,
450
- md: 20,
451
- lg: 24,
452
- xl: 32
453
- } }
454
- };
455
-
456
289
  //#endregion
457
290
  //#region ../../src/core/services/DialogService.tsx
458
291
  var DialogService = class {
@@ -544,42 +377,6 @@ var DialogService = class {
544
377
  if (modalId) modals.close(modalId);
545
378
  else modals.closeAll();
546
379
  }
547
- /**
548
- * Show an error viewer dialog
549
- */
550
- error(error, options) {
551
- this.open({
552
- size: "lg",
553
- title: options?.title || "Error",
554
- ...options,
555
- content: /* @__PURE__ */ jsx(Flex$1, {
556
- bdrs: "md",
557
- w: "100%",
558
- flex: 1,
559
- p: "sm",
560
- bg: ui.colors.surface,
561
- children: /* @__PURE__ */ jsx(ErrorViewer, {
562
- size: "xs",
563
- error,
564
- showStack: options?.showStack ?? true
565
- })
566
- })
567
- });
568
- }
569
- /**
570
- * Show a form dialog for structured input
571
- */
572
- form(options) {
573
- return Promise.resolve(null);
574
- }
575
- /**
576
- * Show a loading/progress dialog with optional progress percentage
577
- */
578
- loading(options) {}
579
- /**
580
- * Show an image viewer/gallery dialog
581
- */
582
- image(src, options) {}
583
380
  };
584
381
 
585
382
  //#endregion
@@ -641,6 +438,21 @@ var ToastService = class {
641
438
  }
642
439
  };
643
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
+
644
456
  //#endregion
645
457
  //#region ../../src/core/hooks/useTheme.ts
646
458
  /**
@@ -678,22 +490,6 @@ const useToast = () => {
678
490
  return useInject(ToastService);
679
491
  };
680
492
 
681
- //#endregion
682
- //#region ../../src/core/helpers/isComponentType.ts
683
- function isComponentType(param) {
684
- if (isValidElement(param)) return false;
685
- return typeof param === "function" || typeof param === "object" && param !== null && "$$typeof" in param;
686
- }
687
-
688
- //#endregion
689
- //#region ../../src/core/helpers/renderIcon.tsx
690
- const renderIcon = (icon, size) => {
691
- if (!icon) return null;
692
- if (isValidElement(icon)) return icon;
693
- if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui$1.sizes.icon.md });
694
- return icon;
695
- };
696
-
697
493
  //#endregion
698
494
  //#region ../../src/core/components/layout/Omnibar.tsx
699
495
  const Omnibar = (props) => {
@@ -727,7 +523,7 @@ const Omnibar = (props) => {
727
523
  };
728
524
 
729
525
  //#endregion
730
- //#region ../../src/core/components/layout/AlephaMantineProvider.tsx
526
+ //#region ../../src/core/components/AlephaMantineProvider.tsx
731
527
  const AlephaMantineProvider = (props) => {
732
528
  const toast = useToast();
733
529
  const [theme] = useTheme();
@@ -747,14 +543,13 @@ const AlephaMantineProvider = (props) => {
747
543
  }
748
544
  }, []);
749
545
  const defaultColorScheme = props.mantine?.defaultColorScheme ?? theme.defaultColorScheme;
750
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(ColorSchemeScript, {
546
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ColorSchemeScript, {
751
547
  defaultColorScheme,
752
548
  ...props.colorSchemeScript
753
549
  }), /* @__PURE__ */ jsxs(MantineProvider, {
754
550
  ...props.mantine,
755
551
  defaultColorScheme,
756
552
  theme: {
757
- cursorType: "pointer",
758
553
  ...theme,
759
554
  ...props.mantine?.theme
760
555
  },
@@ -770,20 +565,31 @@ const AlephaMantineProvider = (props) => {
770
565
  };
771
566
 
772
567
  //#endregion
773
- //#region ../../src/core/UiRouter.ts
774
- /**
775
- * UI Router defining the root page with AlephaMantineProvider.
776
- *
777
- * - Use UiRouter when you need Alepha's Mantine-based UI components and theming.
778
- * - Prefer to use $ui() for convenience. (Custom Factory of UiRouter)
779
- */
780
- var UiRouter = class {
781
- root = $page({
782
- path: "/",
783
- component: AlephaMantineProvider
784
- });
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
+ } }
785
584
  };
786
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
+
787
593
  //#endregion
788
594
  //#region ../../src/core/components/buttons/ActionButton.tsx
789
595
  const ActionMenuItem = (props) => {
@@ -854,7 +660,7 @@ const ActionButton = (_props) => {
854
660
  if (props.leftSection && !props.children) restProps.px ??= "xs";
855
661
  if (props.textVisibleFrom) {
856
662
  const { children, textVisibleFrom, leftSection, ...rest } = restProps;
857
- return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(Flex$1, {
663
+ return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Flex$1, {
858
664
  w: "100%",
859
665
  visibleFrom: textVisibleFrom,
860
666
  children: /* @__PURE__ */ jsx(ActionButton, {
@@ -892,6 +698,7 @@ const ActionButton = (_props) => {
892
698
  }
893
699
  delete restProps.classNameActive;
894
700
  delete restProps.variantActive;
701
+ delete restProps.propsActive;
895
702
  if ("action" in restProps && restProps.action) return /* @__PURE__ */ jsx(ActionHookButton, {
896
703
  ...restProps,
897
704
  action: restProps.action,
@@ -1026,22 +833,24 @@ const ActionClickButton = ({ preventDefault, ...props }) => {
1026
833
  * Action for navigation with active state support.
1027
834
  */
1028
835
  const ActionNavigationButton = (props) => {
1029
- const { active: options, classNameActive, variantActive, routerGoOptions, onClick: propsOnClick, ...buttonProps } = props;
836
+ const { active: options, classNameActive, variantActive, propsActive, routerGoOptions, onClick: propsOnClick, anchor, ...buttonProps } = props;
1030
837
  const router = useRouter();
1031
838
  const { isPending, isActive } = useActive(options ? {
1032
839
  href: props.href,
1033
840
  ...options
1034
841
  } : { href: props.href });
1035
842
  const anchorProps = router.anchor(props.href, routerGoOptions);
843
+ if (propsActive && isActive) Object.assign(buttonProps, propsActive);
1036
844
  const combinedOnClick = (e) => {
1037
845
  propsOnClick?.(e);
1038
846
  anchorProps.onClick?.(e);
1039
847
  };
1040
848
  const className = buttonProps.className || "";
1041
849
  if (isActive && options !== false && classNameActive) buttonProps.className = `${className} ${classNameActive}`.trim();
1042
- if (props.anchorProps) return /* @__PURE__ */ jsx(Anchor, {
850
+ if (props.anchorProps || anchor) return /* @__PURE__ */ jsx(Anchor, {
1043
851
  component: "a",
1044
852
  ...anchorProps,
853
+ ...buttonProps,
1045
854
  ...props.anchorProps,
1046
855
  onClick: combinedOnClick,
1047
856
  children: props.children
@@ -1057,7 +866,7 @@ const ActionNavigationButton = (props) => {
1057
866
  });
1058
867
  };
1059
868
  const ActionHrefButton = (props) => {
1060
- const { active: options, classNameActive, variantActive, routerGoOptions, target, ...buttonProps } = props;
869
+ const { active: options, classNameActive, variantActive, propsActive, routerGoOptions, target, ...buttonProps } = props;
1061
870
  return /* @__PURE__ */ jsx(Button, {
1062
871
  component: "a",
1063
872
  target,
@@ -1071,12 +880,12 @@ const ActionHrefButton = (props) => {
1071
880
  const BurgerButton = (props) => {
1072
881
  const [sidebar, setSidebar] = useStore(alephaSidebarAtom);
1073
882
  return /* @__PURE__ */ jsx(Burger, {
1074
- opened: sidebar.opened,
883
+ opened: !sidebar.closed,
1075
884
  onClick: () => setSidebar({
1076
885
  ...sidebar,
1077
- opened: !sidebar.opened
886
+ closed: !sidebar.closed
1078
887
  }),
1079
- hiddenFrom: "sm",
888
+ hiddenFrom: "md",
1080
889
  size: "sm",
1081
890
  ...props
1082
891
  });
@@ -1124,7 +933,7 @@ const DarkModeButton = (props) => {
1124
933
  variant: props.variant ?? "subtle",
1125
934
  size,
1126
935
  "aria-label": "Toggle color scheme",
1127
- icon: /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx(IconSun, {
936
+ icon: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(IconSun, {
1128
937
  size: iconSize,
1129
938
  className: "alepha-light-hidden"
1130
939
  }), /* @__PURE__ */ jsx(IconMoon, {
@@ -1140,7 +949,7 @@ const DarkModeButton = (props) => {
1140
949
  const LanguageButton = (props) => {
1141
950
  const i18n = useI18n();
1142
951
  return /* @__PURE__ */ jsx(ActionButton, {
1143
- variant: "default",
952
+ variant: "subtle",
1144
953
  icon: IconLanguage,
1145
954
  menu: { items: i18n.languages.map((lang) => ({
1146
955
  label: i18n.tr(lang),
@@ -1220,15 +1029,13 @@ const ToggleSidebarButton = (props) => {
1220
1029
  const [sidebar, setSidebar] = useStore(alephaSidebarAtom);
1221
1030
  return /* @__PURE__ */ jsx(ActionButton, {
1222
1031
  icon: sidebar.collapsed ? IconLayoutSidebarRightCollapse : IconLayoutSidebarLeftCollapse,
1223
- visibleFrom: "sm",
1032
+ visibleFrom: "md",
1224
1033
  variant: "subtle",
1225
1034
  size: "md",
1226
1035
  onClick: () => {
1227
- const expanding = sidebar.collapsed;
1228
1036
  setSidebar({
1229
1037
  ...sidebar,
1230
- collapsed: !sidebar.collapsed,
1231
- width: expanding ? sidebar.defaultWidth : sidebar.width
1038
+ collapsed: !sidebar.collapsed
1232
1039
  });
1233
1040
  },
1234
1041
  tooltip: {
@@ -1240,190 +1047,837 @@ const ToggleSidebarButton = (props) => {
1240
1047
  };
1241
1048
 
1242
1049
  //#endregion
1243
- //#region ../../src/core/utils/icons.tsx
1244
- /**
1245
- * Get the default icon for an input based on its type, format, or name.
1246
- */
1247
- const getDefaultIcon = (params) => {
1248
- const { type, format, name, isEnum, isArray, size = "sm" } = params;
1249
- const iconSize = ui.sizes.icon[size];
1250
- if (format) switch (format) {
1251
- case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
1252
- case "url":
1253
- case "uri": return /* @__PURE__ */ jsx(IconLink, { size: iconSize });
1254
- case "tel":
1255
- case "phone": return /* @__PURE__ */ jsx(IconPhone, { size: iconSize });
1256
- case "date": return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
1257
- case "date-time": return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
1258
- case "time": return /* @__PURE__ */ jsx(IconClock, { size: iconSize });
1259
- case "color": return /* @__PURE__ */ jsx(IconColorPicker, { size: iconSize });
1260
- case "uuid": return /* @__PURE__ */ jsx(IconKey, { size: iconSize });
1261
- }
1262
- if (name) {
1263
- const nameLower = name.toLowerCase();
1264
- if (nameLower.includes("password") || nameLower.includes("secret")) return /* @__PURE__ */ jsx(IconKey, { size: iconSize });
1265
- if (nameLower.includes("email") || nameLower.includes("mail")) return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
1266
- if (nameLower.includes("url") || nameLower.includes("link")) return /* @__PURE__ */ jsx(IconLink, { size: iconSize });
1267
- if (nameLower.includes("phone") || nameLower.includes("tel")) return /* @__PURE__ */ jsx(IconPhone, { size: iconSize });
1268
- if (nameLower.includes("color")) return /* @__PURE__ */ jsx(IconPalette, { size: iconSize });
1269
- if (nameLower.includes("file") || nameLower.includes("upload")) return /* @__PURE__ */ jsx(IconFile, { size: iconSize });
1270
- if (nameLower.includes("date")) return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
1271
- if (nameLower.includes("time")) return /* @__PURE__ */ jsx(IconClock, { size: iconSize });
1272
- }
1273
- if (isEnum || isArray) return /* @__PURE__ */ jsx(IconSelector, { size: iconSize });
1274
- if (type) switch (type) {
1275
- case "boolean": return /* @__PURE__ */ jsx(IconToggleLeft, { size: iconSize });
1276
- case "number":
1277
- case "integer": return /* @__PURE__ */ jsx(IconHash, { size: iconSize });
1278
- case "array": return /* @__PURE__ */ jsx(IconList, { size: iconSize });
1279
- case "string": return /* @__PURE__ */ jsx(IconLetterCase, { size: iconSize });
1280
- }
1281
- return /* @__PURE__ */ jsx(IconAt, { size: iconSize });
1282
- };
1050
+ //#region ../../src/core/components/data/DetailDrawer.tsx
1051
+ const DetailDrawer = ({ opened, onClose, title, subtitle, status, actions, tabs, children, loading, size = "xl", defaultTab }) => /* @__PURE__ */ jsxs(Drawer, {
1052
+ opened,
1053
+ onClose,
1054
+ position: "right",
1055
+ size,
1056
+ withCloseButton: false,
1057
+ padding: 0,
1058
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
1059
+ p: "md",
1060
+ justify: "space-between",
1061
+ align: "flex-start",
1062
+ style: { borderBottom: "1px solid var(--mantine-color-default-border)" },
1063
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
1064
+ direction: "column",
1065
+ gap: 2,
1066
+ style: {
1067
+ minWidth: 0,
1068
+ flex: 1
1069
+ },
1070
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
1071
+ gap: "xs",
1072
+ align: "center",
1073
+ children: [status && /* @__PURE__ */ jsx(Flex$1, {
1074
+ w: 8,
1075
+ h: 8,
1076
+ style: {
1077
+ borderRadius: "50%",
1078
+ backgroundColor: status.active ? "var(--mantine-color-green-6)" : "var(--mantine-color-red-6)",
1079
+ flexShrink: 0
1080
+ }
1081
+ }), /* @__PURE__ */ jsx(Text$1, {
1082
+ size: "lg",
1083
+ fw: 600,
1084
+ truncate: true,
1085
+ children: title
1086
+ })]
1087
+ }), subtitle && /* @__PURE__ */ jsx(Text$1, {
1088
+ size: "sm",
1089
+ c: "dimmed",
1090
+ truncate: true,
1091
+ children: subtitle
1092
+ })]
1093
+ }), /* @__PURE__ */ jsxs(Flex$1, {
1094
+ gap: "xs",
1095
+ align: "center",
1096
+ style: { flexShrink: 0 },
1097
+ children: [actions && actions.length > 0 && /* @__PURE__ */ jsx(ActionButton, {
1098
+ variant: "default",
1099
+ size: "xs",
1100
+ menu: {
1101
+ items: actions,
1102
+ position: "bottom-end",
1103
+ width: 200
1104
+ },
1105
+ children: "Actions"
1106
+ }), /* @__PURE__ */ jsx(ActionButton, {
1107
+ variant: "subtle",
1108
+ size: "xs",
1109
+ c: "dimmed",
1110
+ onClick: onClose,
1111
+ children: "Close"
1112
+ })]
1113
+ })]
1114
+ }), loading ? /* @__PURE__ */ jsx(Flex$1, {
1115
+ flex: 1,
1116
+ justify: "center",
1117
+ align: "center",
1118
+ py: "xl",
1119
+ children: /* @__PURE__ */ jsx(Loader, {})
1120
+ }) : tabs && tabs.length > 0 ? /* @__PURE__ */ jsxs(Tabs, {
1121
+ defaultValue: defaultTab || tabs[0].value,
1122
+ children: [/* @__PURE__ */ jsx(Tabs.List, {
1123
+ px: "md",
1124
+ children: tabs.map((tab) => /* @__PURE__ */ jsx(Tabs.Tab, {
1125
+ value: tab.value,
1126
+ leftSection: tab.icon ? /* @__PURE__ */ jsx(tab.icon, { size: 14 }) : void 0,
1127
+ children: tab.label
1128
+ }, tab.value))
1129
+ }), tabs.map((tab) => /* @__PURE__ */ jsx(Tabs.Panel, {
1130
+ value: tab.value,
1131
+ p: "md",
1132
+ children: tab.content
1133
+ }, tab.value))]
1134
+ }) : /* @__PURE__ */ jsx(Flex$1, {
1135
+ direction: "column",
1136
+ p: "md",
1137
+ children
1138
+ })]
1139
+ });
1283
1140
 
1284
1141
  //#endregion
1285
- //#region ../../src/core/utils/string.ts
1286
- /**
1287
- * Capitalizes the first letter of a string.
1288
- *
1289
- * @example
1290
- * capitalize("hello") // "Hello"
1291
- */
1292
- const capitalize = (str) => {
1293
- return str.charAt(0).toUpperCase() + str.slice(1);
1142
+ //#region ../../src/core/components/data/DetailList.tsx
1143
+ const DetailList = ({ items, columns = 1 }) => {
1144
+ return /* @__PURE__ */ jsx(Grid, {
1145
+ gutter: "xs",
1146
+ children: items.filter((item) => !item.hidden).map((item) => /* @__PURE__ */ jsx(Grid.Col, {
1147
+ span: 12 / columns,
1148
+ children: /* @__PURE__ */ jsxs(Flex$1, {
1149
+ py: 6,
1150
+ justify: "space-between",
1151
+ align: "center",
1152
+ style: { borderBottom: "1px solid var(--mantine-color-default-border)" },
1153
+ children: [/* @__PURE__ */ jsx(Text$1, {
1154
+ size: "xs",
1155
+ c: "dimmed",
1156
+ style: { flexShrink: 0 },
1157
+ children: item.label
1158
+ }), /* @__PURE__ */ jsxs(Flex$1, {
1159
+ gap: 4,
1160
+ align: "center",
1161
+ style: { minWidth: 0 },
1162
+ children: [typeof item.value === "string" || typeof item.value === "number" ? /* @__PURE__ */ jsx(Text$1, {
1163
+ size: "sm",
1164
+ fw: 500,
1165
+ truncate: true,
1166
+ children: item.value || "—"
1167
+ }) : item.value ?? /* @__PURE__ */ jsx(Text$1, {
1168
+ size: "sm",
1169
+ c: "dimmed",
1170
+ children: "—"
1171
+ }), item.copyable && /* @__PURE__ */ jsx(ClipboardButton, {
1172
+ value: item.copyable,
1173
+ size: "xs",
1174
+ variant: "subtle",
1175
+ c: "dimmed"
1176
+ })]
1177
+ })]
1178
+ })
1179
+ }, item.label))
1180
+ });
1294
1181
  };
1295
- /**
1296
- * Converts camelCase or snake_case to Title Case with spaces.
1297
- *
1298
- * @example
1299
- * toTitleCase("userName") // "User Name"
1300
- * toTitleCase("first_name") // "First Name"
1301
- * toTitleCase("email") // "Email"
1302
- */
1303
- const toTitleCase = (str) => {
1304
- return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
1305
- };
1306
- /**
1307
- * Converts a path or identifier string into a pretty display name.
1308
- * For paths like "/contacts/0/name", extracts just the field name "Name".
1309
- * Handles camelCase and snake_case conversion to Title Case.
1310
- *
1311
- * @example
1312
- * prettyName("/userName") // "User Name"
1313
- * prettyName("/contacts/0/email") // "Email"
1314
- * prettyName("/address/streetName") // "Street Name"
1315
- * prettyName("first_name") // "First Name"
1316
- */
1317
- const prettyName = (name) => {
1318
- const segments = name.split("/").filter((s) => s && !/^\d+$/.test(s));
1319
- return toTitleCase(segments[segments.length - 1] || name.replaceAll("/", ""));
1182
+
1183
+ //#endregion
1184
+ //#region ../../src/core/components/data/StatCards.tsx
1185
+ const StatCards = ({ items }) => /* @__PURE__ */ jsx(Flex$1, {
1186
+ gap: "sm",
1187
+ wrap: "wrap",
1188
+ children: items.map((item) => {
1189
+ (item.icon && typeof item.icon === "function" ? item.icon : null) ? ui.sizes.icon.md : item.icon;
1190
+ return /* @__PURE__ */ jsx(Paper, {
1191
+ p: "md",
1192
+ radius: "md",
1193
+ withBorder: true,
1194
+ style: {
1195
+ flex: "1 1 0",
1196
+ minWidth: 120
1197
+ },
1198
+ children: /* @__PURE__ */ jsx(Flex$1, {
1199
+ gap: "sm",
1200
+ align: "center",
1201
+ children: /* @__PURE__ */ jsxs(Flex$1, {
1202
+ direction: "column",
1203
+ children: [/* @__PURE__ */ jsx(Text$1, {
1204
+ size: "xl",
1205
+ fw: 700,
1206
+ lh: 1,
1207
+ children: item.value
1208
+ }), /* @__PURE__ */ jsx(Text$1, {
1209
+ size: "xs",
1210
+ c: "dimmed",
1211
+ children: item.label
1212
+ })]
1213
+ })
1214
+ })
1215
+ }, item.label);
1216
+ })
1217
+ });
1218
+
1219
+ //#endregion
1220
+ //#region ../../src/core/components/Flex.tsx
1221
+ const Flex = forwardRef((props, ref) => {
1222
+ const { fill, center, centerX, centerY, col, ...rest } = props;
1223
+ if (fill) rest.flex ??= 1;
1224
+ if (col) rest.direction ??= "column";
1225
+ if (center) {
1226
+ rest.align ??= "center";
1227
+ rest.justify ??= "center";
1228
+ }
1229
+ if (centerX) rest.justify ??= "center";
1230
+ if (centerY) rest.align ??= "center";
1231
+ return /* @__PURE__ */ jsx(Flex$1, {
1232
+ ref,
1233
+ ...rest
1234
+ });
1235
+ });
1236
+ Flex.displayName = "Flex";
1237
+
1238
+ //#endregion
1239
+ //#region ../../src/core/components/Heading.tsx
1240
+ const Heading = (props) => {
1241
+ return /* @__PURE__ */ jsx("h1", { children: "Heading" });
1320
1242
  };
1321
1243
 
1322
1244
  //#endregion
1323
- //#region ../../src/core/utils/parseInput.ts
1324
- const parseInput = (props, form) => {
1325
- const disabled = false;
1326
- const id = props.input.props.id;
1327
- 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);
1328
- const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
1329
- const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
1330
- const icon = !props.icon ? getDefaultIcon({
1331
- type: props.input.schema && "type" in props.input.schema ? String(props.input.schema.type) : void 0,
1332
- format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
1333
- name: props.input.props.name,
1334
- isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
1335
- isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
1336
- }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.md });
1337
- const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
1338
- const required = props.input.required;
1339
- const schema = props.input.schema;
1340
- const inputProps = {
1341
- label,
1342
- description,
1343
- error,
1344
- required,
1345
- disabled
1245
+ //#region ../../src/core/components/layout/AppBar.tsx
1246
+ const AppBar = (props) => {
1247
+ const { items = [] } = props;
1248
+ const router = useRouter();
1249
+ const renderItem = (item, index) => {
1250
+ if (item.can && !item.can()) return null;
1251
+ if ("type" in item) {
1252
+ if (item.type === "burger") return /* @__PURE__ */ jsx(BurgerButton, {}, index);
1253
+ if (item.type === "dark") return /* @__PURE__ */ jsx(DarkModeButton, { ...item.props }, index);
1254
+ if (item.type === "search") return /* @__PURE__ */ jsx(OmnibarButton, { ...item.props }, index);
1255
+ if (item.type === "lang") return /* @__PURE__ */ jsx(LanguageButton, { ...item.props }, index);
1256
+ if (item.type === "spacer") return /* @__PURE__ */ jsx(Flex, { w: 16 }, index);
1257
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }, index);
1258
+ if (item.type === "logo") return renderLogo(item, index);
1259
+ if (item.type === "back") return renderBack(item, index);
1260
+ }
1261
+ if ("element" in item) return item.element;
1262
+ return null;
1346
1263
  };
1347
- if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
1348
- if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
1349
- if ("minimum" in schema && typeof schema.minimum === "number") inputProps.minimum = schema.minimum;
1350
- if ("maximum" in schema && typeof schema.maximum === "number") inputProps.maximum = schema.maximum;
1351
- return {
1352
- id,
1353
- icon,
1354
- format,
1355
- schema: props.input.schema,
1356
- inputProps
1264
+ const renderLogo = (item, index) => {
1265
+ const { src, text, icon, href, height = 32, width, fontWeight = 700, fontSize = "lg" } = item.props ?? {};
1266
+ const logoContent = src ? /* @__PURE__ */ jsx(Image, {
1267
+ src,
1268
+ h: height,
1269
+ w: width,
1270
+ fit: "contain"
1271
+ }) : icon ? typeof icon === "function" ? /* @__PURE__ */ jsx(icon, {}) : icon : text ? /* @__PURE__ */ jsx(Text, {
1272
+ fw: fontWeight,
1273
+ size: fontSize,
1274
+ children: text
1275
+ }) : null;
1276
+ if (href) return /* @__PURE__ */ jsx(Anchor, {
1277
+ component: Link,
1278
+ href,
1279
+ underline: "never",
1280
+ c: "inherit",
1281
+ children: logoContent
1282
+ }, index);
1283
+ return /* @__PURE__ */ jsx(Flex, { children: logoContent }, index);
1284
+ };
1285
+ const renderBack = (item, index) => {
1286
+ const { label = "Back", iconOnly = true, href, icon } = item.props ?? {};
1287
+ const renderIcon = () => {
1288
+ if (!icon) return /* @__PURE__ */ jsx(IconArrowLeft, { size: 18 });
1289
+ if (typeof icon === "function") return /* @__PURE__ */ jsx(icon, { size: 18 });
1290
+ return icon;
1291
+ };
1292
+ const iconElement = renderIcon();
1293
+ const handleClick = () => {
1294
+ if (href) router.push(href);
1295
+ else router.back();
1296
+ };
1297
+ if (iconOnly) return /* @__PURE__ */ jsx(ActionButton, {
1298
+ icon: iconElement,
1299
+ variant: "subtle",
1300
+ color: "gray",
1301
+ onClick: handleClick,
1302
+ tooltip: {
1303
+ label,
1304
+ position: "bottom"
1305
+ }
1306
+ }, index);
1307
+ return /* @__PURE__ */ jsx(ActionButton, {
1308
+ leftSection: iconElement,
1309
+ variant: "subtle",
1310
+ color: "gray",
1311
+ onClick: handleClick,
1312
+ children: label
1313
+ }, index);
1357
1314
  };
1315
+ const leftItems = items.filter((item) => item.position === "left");
1316
+ const centerItems = items.filter((item) => item.position === "center");
1317
+ const rightItems = items.filter((item) => item.position === "right");
1318
+ const content = /* @__PURE__ */ jsxs(Flex, {
1319
+ h: "100%",
1320
+ align: "center",
1321
+ px: props.container ? 0 : "md",
1322
+ justify: "space-between",
1323
+ ...props.flexProps,
1324
+ children: [
1325
+ /* @__PURE__ */ jsx(Flex, {
1326
+ flex: 1,
1327
+ children: leftItems.map((item, index) => /* @__PURE__ */ jsx(Flex, {
1328
+ ml: index === 0 ? 0 : "md",
1329
+ align: "center",
1330
+ children: renderItem(item, index)
1331
+ }, index))
1332
+ }),
1333
+ /* @__PURE__ */ jsx(Flex, { children: centerItems.map((item, index) => /* @__PURE__ */ jsx(Flex, {
1334
+ mx: "md",
1335
+ align: "center",
1336
+ children: renderItem(item, index)
1337
+ }, index)) }),
1338
+ /* @__PURE__ */ jsx(Flex, {
1339
+ flex: 1,
1340
+ align: "center",
1341
+ justify: "end",
1342
+ children: rightItems.map((item, index) => /* @__PURE__ */ jsx(Flex, {
1343
+ ml: index === 0 ? 0 : "md",
1344
+ align: "center",
1345
+ children: renderItem(item, index)
1346
+ }, index))
1347
+ })
1348
+ ]
1349
+ });
1350
+ if (props.container) return /* @__PURE__ */ jsx(Container$1, {
1351
+ h: "100%",
1352
+ ...typeof props.container === "boolean" ? {} : props.container,
1353
+ children: content
1354
+ });
1355
+ return content;
1358
1356
  };
1359
1357
 
1360
1358
  //#endregion
1361
- //#region ../../src/core/components/form/ControlArray.tsx
1359
+ //#region ../../src/core/components/layout/Breadcrumb.tsx
1362
1360
  /**
1363
- * Custom hook to sync array items with form state.
1364
- * Uses form events as the source of truth, eliminating dual-state issues.
1361
+ * Automatic breadcrumb component that reads the current route hierarchy
1362
+ * from the Alepha router's layer stack.
1363
+ *
1364
+ * Pages should define a `label` in their `$page()` options for best results.
1365
+ * Falls back to the page name converted to Title Case.
1365
1366
  */
1366
- const useArrayItems = (input) => {
1367
- const alepha = useAlepha();
1368
- const keyCounter = useRef(0);
1369
- const [items, setItemsState] = useState(() => {
1370
- const defaultValue = input?.props?.defaultValue;
1371
- if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
1372
- key: keyCounter.current++,
1373
- value
1374
- }));
1375
- return [];
1367
+ const Breadcrumb = ({ home = "Home", separator, size = "sm", ...groupProps }) => {
1368
+ const state = useRouterState();
1369
+ const router = useRouter();
1370
+ const crumbs = [];
1371
+ if (home !== false) crumbs.push({
1372
+ label: home,
1373
+ href: "/"
1376
1374
  });
1377
- const syncFromFormValue = useCallback((formValue) => {
1378
- if (!Array.isArray(formValue)) {
1379
- setItemsState([]);
1380
- return;
1381
- }
1382
- setItemsState((prevItems) => {
1383
- if (prevItems.length === formValue.length) {
1384
- if (prevItems.every((item, i) => item.value === formValue[i])) return prevItems;
1385
- }
1386
- keyCounter.current = 0;
1387
- return formValue.map((value) => ({
1388
- key: keyCounter.current++,
1389
- value
1390
- }));
1375
+ for (let i = 1; i < state.layers.length; i++) {
1376
+ const layer = state.layers[i];
1377
+ const route = layer.route;
1378
+ if (route?.path === "/" || route?.path === "") continue;
1379
+ const label = route?.label ?? toTitleCase(layer.name);
1380
+ const href = router.path(layer.name);
1381
+ crumbs.push({
1382
+ label,
1383
+ href
1391
1384
  });
1392
- }, []);
1393
- useEffect(() => {
1394
- if (!input?.form) return;
1395
- const formId = input.form.id;
1396
- const fieldPath = input.path;
1397
- const listeners = [alepha.events.on("form:reset", (event) => {
1398
- if (event.id === formId) {
1399
- const defaultValue = input.props?.defaultValue;
1400
- keyCounter.current = 0;
1401
- if (Array.isArray(defaultValue)) setItemsState(defaultValue.map((value) => ({
1402
- key: keyCounter.current++,
1403
- value
1404
- })));
1405
- else setItemsState([]);
1406
- }
1407
- }), alepha.events.on("form:change", (event) => {
1408
- if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
1409
- })];
1410
- return () => {
1411
- for (const unsub of listeners) unsub();
1412
- };
1413
- }, [
1414
- alepha,
1415
- input,
1416
- syncFromFormValue
1417
- ]);
1418
- return {
1419
- items,
1420
- setItems: useCallback((newItems) => {
1421
- setItemsState(newItems);
1422
- input?.set(newItems.map((item) => item.value));
1423
- }, [input]),
1424
- nextKey: useCallback(() => keyCounter.current++, [])
1425
- };
1426
- };
1385
+ }
1386
+ if (crumbs.length === 0) return null;
1387
+ const sep = separator ?? /* @__PURE__ */ jsx(IconChevronRight, {
1388
+ size: 12,
1389
+ color: "#9ca3af"
1390
+ });
1391
+ return /* @__PURE__ */ jsx(Flex, {
1392
+ gap: "sm",
1393
+ ...groupProps,
1394
+ children: crumbs.map((crumb, i) => /* @__PURE__ */ jsxs(Flex, {
1395
+ align: "center",
1396
+ gap: "sm",
1397
+ children: [i > 0 && sep, i < crumbs.length - 1 ? /* @__PURE__ */ jsx(ActionButton, {
1398
+ anchor: true,
1399
+ href: crumb.href,
1400
+ size,
1401
+ c: "dimmed",
1402
+ children: crumb.label
1403
+ }) : /* @__PURE__ */ jsx(Text, {
1404
+ size,
1405
+ fw: 500,
1406
+ children: crumb.label
1407
+ })]
1408
+ }, crumb.href))
1409
+ });
1410
+ };
1411
+
1412
+ //#endregion
1413
+ //#region ../../src/core/components/layout/Container.tsx
1414
+ const Container = forwardRef((props, ref) => {
1415
+ return /* @__PURE__ */ jsx(Container$1, {
1416
+ ref,
1417
+ ...props
1418
+ });
1419
+ });
1420
+ Container.displayName = "Container";
1421
+
1422
+ //#endregion
1423
+ //#region ../../src/core/components/layout/Sidebar.tsx
1424
+ const Sidebar = (props) => {
1425
+ const router = useRouter();
1426
+ const { onItemClick } = props;
1427
+ const divider = (key, fill, collapsed) => {
1428
+ return /* @__PURE__ */ jsx(Flex, {
1429
+ h: 1,
1430
+ bg: "var(--mantine-color-default-border)",
1431
+ my: "xs",
1432
+ mx: fill ? "calc(-1 * var(--mantine-spacing-md))" : collapsed ? 0 : "sm"
1433
+ }, key);
1434
+ };
1435
+ const renderNode = (item, key, collapsed) => {
1436
+ if ("type" in item) {
1437
+ if (item.type === "spacer") {
1438
+ if (collapsed) return null;
1439
+ return /* @__PURE__ */ jsx(Flex, { h: 16 }, key);
1440
+ }
1441
+ if (item.type === "divider") return divider(key, item.fill, collapsed);
1442
+ if (item.type === "search") return /* @__PURE__ */ jsx(Flex, {
1443
+ mb: "xs",
1444
+ children: /* @__PURE__ */ jsx(OmnibarButton, { collapsed })
1445
+ }, key);
1446
+ if (item.type === "toggle") return /* @__PURE__ */ jsx(ToggleSidebarButton, {}, key);
1447
+ if (item.type === "section") {
1448
+ if (item.children && item.children.length > 0) {
1449
+ if (!item.children.some((child) => !("can" in child) || !child.can || child.can())) return null;
1450
+ }
1451
+ if (collapsed) return /* @__PURE__ */ jsxs(Fragment$1, { children: [divider(`${key}-d`, void 0, collapsed), item.children?.map((child, index) => renderNode(child, `s${key}-${index}`, collapsed))] }, key);
1452
+ return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Flex, {
1453
+ mt: "md",
1454
+ align: "center",
1455
+ gap: "xs",
1456
+ children: [renderIcon(item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Text, {
1457
+ size: "xs",
1458
+ c: "dimmed",
1459
+ tt: "uppercase",
1460
+ fw: "bold",
1461
+ children: item.label
1462
+ })]
1463
+ }), item.children?.map((child, index) => renderNode(child, `s${key}-${index}`, collapsed))] }, key);
1464
+ }
1465
+ }
1466
+ if ("element" in item) return /* @__PURE__ */ jsx(Fragment$1, { children: item.element }, key);
1467
+ if (item.can && !item.can()) return null;
1468
+ if (item.children && item.children.length > 0) {
1469
+ if (!item.children.some((child) => !child.can || child.can())) return null;
1470
+ }
1471
+ if (collapsed) return /* @__PURE__ */ jsx(SidebarCollapsedItem, {
1472
+ item,
1473
+ level: 0,
1474
+ onItemClick,
1475
+ theme: props.theme ?? {}
1476
+ }, key);
1477
+ return /* @__PURE__ */ jsx(SidebarItem, {
1478
+ item,
1479
+ level: 0,
1480
+ onItemClick,
1481
+ theme: props.theme ?? {}
1482
+ }, key);
1483
+ };
1484
+ const getSidebarNodes = () => {
1485
+ if (props.items) return props.items;
1486
+ if (props.autoPopulateMenu) {
1487
+ const items = router.concretePages.filter((page) => !page.can || page.can()).map((page) => ({
1488
+ label: page.label ?? page.name,
1489
+ icon: renderIcon(page.icon),
1490
+ href: router.path(page.name)
1491
+ }));
1492
+ if (typeof props.autoPopulateMenu === "object" && props.autoPopulateMenu.startsWith) {
1493
+ const startsWith = props.autoPopulateMenu.startsWith;
1494
+ return items.filter((item) => item.href?.startsWith(startsWith));
1495
+ }
1496
+ return items;
1497
+ }
1498
+ return [];
1499
+ };
1500
+ const padding = "md";
1501
+ const gap = props.items ? props.gap ?? 4 : "xs";
1502
+ const menu = useMemo(() => getSidebarNodes(), [props.items, props.autoPopulateMenu]);
1503
+ const renderSidebar = (collapsed) => /* @__PURE__ */ jsxs(Flex, {
1504
+ flex: 1,
1505
+ py: padding,
1506
+ direction: "column",
1507
+ ...props.flexProps,
1508
+ children: [
1509
+ /* @__PURE__ */ jsx(Flex, {
1510
+ gap,
1511
+ px: padding,
1512
+ direction: "column",
1513
+ children: menu.filter((it) => it.position === "top").map((item, index) => renderNode(item, index, collapsed))
1514
+ }),
1515
+ /* @__PURE__ */ jsx(Flex, {
1516
+ gap,
1517
+ px: padding,
1518
+ direction: "column",
1519
+ flex: 1,
1520
+ children: menu.filter((it) => !it.position).map((item, index) => renderNode(item, index, collapsed))
1521
+ }),
1522
+ /* @__PURE__ */ jsx(Flex, {
1523
+ gap,
1524
+ px: padding,
1525
+ direction: "column",
1526
+ children: menu.filter((it) => it.position === "bottom").map((item, index) => renderNode(item, index, collapsed))
1527
+ })
1528
+ ]
1529
+ });
1530
+ if (props.collapsed) return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Flex, {
1531
+ flex: 1,
1532
+ direction: "column",
1533
+ visibleFrom: "md",
1534
+ children: renderSidebar(true)
1535
+ }), /* @__PURE__ */ jsx(Flex, {
1536
+ flex: 1,
1537
+ direction: "column",
1538
+ hiddenFrom: "md",
1539
+ children: renderSidebar(false)
1540
+ })] });
1541
+ return renderSidebar(false);
1542
+ };
1543
+ const SidebarItem = (props) => {
1544
+ const { item, level } = props;
1545
+ const maxLevel = 2;
1546
+ const router = useRouter();
1547
+ const isActive = useCallback((item) => {
1548
+ if (!item.children) return false;
1549
+ for (const child of item.children) {
1550
+ if (child.href) {
1551
+ if (router.isActive(child.href)) return true;
1552
+ }
1553
+ if (isActive(child)) return true;
1554
+ }
1555
+ return false;
1556
+ }, []);
1557
+ const [isOpen, setIsOpen] = useState(isActive(item));
1558
+ useEvents({ "react:transition:end": () => {
1559
+ if (isActive(item)) setIsOpen(true);
1560
+ } }, []);
1561
+ if (level > maxLevel) return null;
1562
+ const handleItemClick = (e) => {
1563
+ if (!props.item.target) e.preventDefault();
1564
+ if (item.children && item.children.length > 0) setIsOpen(!isOpen);
1565
+ else {
1566
+ props.onItemClick?.(item);
1567
+ item.onClick?.();
1568
+ }
1569
+ };
1570
+ return /* @__PURE__ */ jsxs(Flex, {
1571
+ direction: "column",
1572
+ ps: level === 0 ? 0 : 32,
1573
+ pos: "relative",
1574
+ children: [/* @__PURE__ */ jsx(ActionButton, {
1575
+ w: "100%",
1576
+ justify: "space-between",
1577
+ href: props.item.href,
1578
+ target: props.item.target,
1579
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
1580
+ bd: 0,
1581
+ fw: "normal",
1582
+ variant: "default",
1583
+ propsActive: {
1584
+ variant: "outline",
1585
+ fw: "bold"
1586
+ },
1587
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
1588
+ onClick: handleItemClick,
1589
+ leftSection: /* @__PURE__ */ jsxs(Flex, {
1590
+ w: "100%",
1591
+ align: "center",
1592
+ gap: "sm",
1593
+ children: [renderIcon(item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Flex, {
1594
+ direction: "column",
1595
+ children: /* @__PURE__ */ jsx(Flex, { children: item.label })
1596
+ })]
1597
+ }),
1598
+ rightSection: item.children ? /* @__PURE__ */ jsx(Flex, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
1599
+ ...props.item.actionProps
1600
+ }), item.children && isOpen && /* @__PURE__ */ jsxs(Flex, {
1601
+ direction: "column",
1602
+ "data-parent-level": level,
1603
+ children: [/* @__PURE__ */ jsx(Flex, { style: {
1604
+ position: "absolute",
1605
+ width: 1,
1606
+ background: "linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
1607
+ top: 48,
1608
+ left: 20 + 32 * level,
1609
+ bottom: 16
1610
+ } }), item.children.filter((child) => !child.can || child.can()).map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
1611
+ item: child,
1612
+ level: level + 1,
1613
+ onItemClick: props.onItemClick,
1614
+ theme: props.theme
1615
+ }, index))]
1616
+ })]
1617
+ });
1618
+ };
1619
+ const SidebarCollapsedItem = (props) => {
1620
+ const { item, level } = props;
1621
+ const router = useRouter();
1622
+ const handleItemClick = () => {
1623
+ props.onItemClick?.(item);
1624
+ item.onClick?.();
1625
+ };
1626
+ const hasChildren = item.children && item.children.length > 0;
1627
+ const menu = hasChildren ? {
1628
+ on: "hover",
1629
+ position: "right",
1630
+ items: item.children.filter((child) => !child.can || child.can()).map((child) => ({
1631
+ label: child.label,
1632
+ icon: renderIcon(child.icon, ui.sizes.icon.sm),
1633
+ href: child.href,
1634
+ active: child.href ? router.isActive(child.href, { startWith: child.activeStartsWith }) : void 0
1635
+ }))
1636
+ } : void 0;
1637
+ return /* @__PURE__ */ jsx(ActionButton, {
1638
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
1639
+ variant: "subtle",
1640
+ variantActive: "default",
1641
+ tooltip: hasChildren ? void 0 : {
1642
+ label: item.label,
1643
+ position: "right"
1644
+ },
1645
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
1646
+ onClick: hasChildren ? void 0 : handleItemClick,
1647
+ icon: renderIcon(item.icon, ui.sizes.icon.sm) ?? /* @__PURE__ */ jsx(IconSquareRounded, { size: ui.sizes.icon.sm }),
1648
+ href: hasChildren ? void 0 : props.item.href,
1649
+ target: hasChildren ? void 0 : props.item.target,
1650
+ menu,
1651
+ ...props.item.actionProps
1652
+ });
1653
+ };
1654
+
1655
+ //#endregion
1656
+ //#region ../../src/core/components/layout/DashboardShell.tsx
1657
+ const DashboardShell = (props) => {
1658
+ const router = useRouter();
1659
+ const [sidebar, setSidebar] = useStore(alephaSidebarAtom);
1660
+ const collapsed = props.sidebarProps?.collapsed !== void 0 ? props.sidebarProps.collapsed : sidebar.collapsed;
1661
+ const { collapsedWidth, expandedWidth } = sidebar;
1662
+ const shouldShowSidebar = () => {
1663
+ if (props.noSidebarWhen?.paths) {
1664
+ for (const path of props.noSidebarWhen.paths) if (router.isActive(path, { startWith: true })) return false;
1665
+ }
1666
+ return true;
1667
+ };
1668
+ const [showSidebar, setShowSidebar] = useState(shouldShowSidebar());
1669
+ useEvents({
1670
+ "react:transition:end": () => {
1671
+ setShowSidebar(shouldShowSidebar());
1672
+ },
1673
+ "react:transition:begin": () => {
1674
+ setSidebar({
1675
+ ...sidebar,
1676
+ closed: true
1677
+ });
1678
+ }
1679
+ }, [sidebar]);
1680
+ const defaultAppBarItems = [{
1681
+ position: "left",
1682
+ type: "burger"
1683
+ }];
1684
+ const appBarProps = { ...props.appBarProps };
1685
+ appBarProps.container ??= props.container;
1686
+ const hasSidebar = showSidebar && props.sidebarProps !== void 0;
1687
+ const hasAppBar = props.appBarProps || props.header;
1688
+ let footerElement = props.footer;
1689
+ if (props.footerHeight) footerElement ??= /* @__PURE__ */ jsx(Flex, { h: props.footerHeight });
1690
+ const hHeight = props.headerHeight ?? 60;
1691
+ const fHeight = props.footerHeight ?? 24;
1692
+ const headerHeight = hasAppBar ? hHeight : 0;
1693
+ const footerHeight = footerElement ? fHeight : 0;
1694
+ return /* @__PURE__ */ jsxs(AppShell, {
1695
+ layout: "alt",
1696
+ w: "100%",
1697
+ flex: 1,
1698
+ header: hasAppBar ? { height: hHeight } : void 0,
1699
+ navbar: hasSidebar ? {
1700
+ width: { base: collapsed ? collapsedWidth : expandedWidth },
1701
+ breakpoint: "md",
1702
+ collapsed: { mobile: sidebar.closed }
1703
+ } : void 0,
1704
+ footer: footerElement ? { height: fHeight } : void 0,
1705
+ ...props.appShellProps,
1706
+ children: [
1707
+ hasAppBar && /* @__PURE__ */ jsx(AppShell.Header, {
1708
+ ...props.appShellHeaderProps,
1709
+ children: props.header ?? /* @__PURE__ */ jsx(AppBar, {
1710
+ items: defaultAppBarItems,
1711
+ ...appBarProps
1712
+ })
1713
+ }),
1714
+ hasSidebar && /* @__PURE__ */ jsxs(AppShell.Navbar, {
1715
+ className: "alepha-sidebar-navbar",
1716
+ ...props.appShellNavbarProps,
1717
+ children: [
1718
+ props.navbarHeader ? /* @__PURE__ */ jsx(Flex, {
1719
+ style: { borderBottom: "1px solid var(--mantine-color-default-border)" },
1720
+ h: headerHeight,
1721
+ children: props.navbarHeader
1722
+ }) : null,
1723
+ /* @__PURE__ */ jsx(Sidebar, {
1724
+ ...props.sidebarProps ?? {},
1725
+ collapsed
1726
+ }),
1727
+ props.navbarFooter ? /* @__PURE__ */ jsx(Flex, {
1728
+ style: { borderTop: "1px solid var(--mantine-color-default-border)" },
1729
+ h: footerHeight,
1730
+ children: props.navbarFooter
1731
+ }) : null
1732
+ ]
1733
+ }),
1734
+ /* @__PURE__ */ jsx(AppShell.Main, {
1735
+ pos: "relative",
1736
+ ...props.appShellMainProps,
1737
+ children: props.children ?? /* @__PURE__ */ jsx(NestedView, {})
1738
+ }),
1739
+ footerElement && /* @__PURE__ */ jsx(AppShell.Footer, {
1740
+ ...props.appShellFooterProps,
1741
+ children: footerElement
1742
+ })
1743
+ ]
1744
+ });
1745
+ };
1746
+
1747
+ //#endregion
1748
+ //#region ../../src/core/components/Text.tsx
1749
+ const INTENT_COLORS = {
1750
+ primary: "blue",
1751
+ info: "cyan",
1752
+ success: "green",
1753
+ warning: "yellow",
1754
+ danger: "red"
1755
+ };
1756
+ const Text = forwardRef((props, ref) => {
1757
+ const { intent, bold, italic, light, muted, small, uppercase, capitalize, center, monospace, title, ...rest } = props;
1758
+ if (intent) rest.c ??= INTENT_COLORS[intent];
1759
+ if (bold) rest.fw ??= 700;
1760
+ if (light) rest.fw ??= 300;
1761
+ if (italic) rest.fs ??= "italic";
1762
+ if (muted) rest.c ??= "dimmed";
1763
+ if (small) rest.size ??= "sm";
1764
+ if (uppercase) rest.tt ??= "uppercase";
1765
+ if (capitalize) rest.tt ??= "capitalize";
1766
+ if (center) rest.ta ??= "center";
1767
+ if (monospace) rest.ff ??= "monospace";
1768
+ if (title) rest.size ??= "xl";
1769
+ return /* @__PURE__ */ jsx(Text$1, {
1770
+ ref,
1771
+ ...rest
1772
+ });
1773
+ });
1774
+ Text.displayName = "Text";
1775
+
1776
+ //#endregion
1777
+ //#region ../../src/core/form/utils/parseInput.ts
1778
+ const parseInput = (props, form) => {
1779
+ const disabled = false;
1780
+ const id = props.input.props.id;
1781
+ 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);
1782
+ const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
1783
+ const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
1784
+ const icon = !props.icon ? getDefaultIcon({
1785
+ type: props.input.schema && "type" in props.input.schema ? String(props.input.schema.type) : void 0,
1786
+ format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
1787
+ name: props.input.props.name,
1788
+ isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
1789
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
1790
+ }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.md });
1791
+ const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
1792
+ const required = props.input.required;
1793
+ const schema = props.input.schema;
1794
+ const inputProps = {
1795
+ label,
1796
+ description,
1797
+ error,
1798
+ required,
1799
+ disabled
1800
+ };
1801
+ if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
1802
+ if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
1803
+ if ("minimum" in schema && typeof schema.minimum === "number") inputProps.minimum = schema.minimum;
1804
+ if ("maximum" in schema && typeof schema.maximum === "number") inputProps.maximum = schema.maximum;
1805
+ return {
1806
+ id,
1807
+ icon,
1808
+ format,
1809
+ schema: props.input.schema,
1810
+ inputProps
1811
+ };
1812
+ };
1813
+
1814
+ //#endregion
1815
+ //#region ../../src/core/form/components/ControlArray.tsx
1816
+ /**
1817
+ * Custom hook to sync array items with form state.
1818
+ * Uses form events as the source of truth, eliminating dual-state issues.
1819
+ */
1820
+ const useArrayItems = (input) => {
1821
+ const alepha = useAlepha();
1822
+ const keyCounter = useRef(0);
1823
+ const [items, setItemsState] = useState(() => {
1824
+ const defaultValue = input?.props?.defaultValue;
1825
+ if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
1826
+ key: keyCounter.current++,
1827
+ value
1828
+ }));
1829
+ return [];
1830
+ });
1831
+ const syncFromFormValue = useCallback((formValue) => {
1832
+ if (!Array.isArray(formValue)) {
1833
+ setItemsState([]);
1834
+ return;
1835
+ }
1836
+ setItemsState((prevItems) => {
1837
+ if (prevItems.length === formValue.length) {
1838
+ if (prevItems.every((item, i) => item.value === formValue[i])) return prevItems;
1839
+ }
1840
+ keyCounter.current = 0;
1841
+ return formValue.map((value) => ({
1842
+ key: keyCounter.current++,
1843
+ value
1844
+ }));
1845
+ });
1846
+ }, []);
1847
+ useEffect(() => {
1848
+ if (!input?.form) return;
1849
+ const formId = input.form.id;
1850
+ const fieldPath = input.path;
1851
+ const listeners = [alepha.events.on("form:reset", (event) => {
1852
+ if (event.id === formId) {
1853
+ const defaultValue = input.props?.defaultValue;
1854
+ keyCounter.current = 0;
1855
+ if (Array.isArray(defaultValue)) setItemsState(defaultValue.map((value) => ({
1856
+ key: keyCounter.current++,
1857
+ value
1858
+ })));
1859
+ else setItemsState([]);
1860
+ }
1861
+ }), alepha.events.on("form:change", (event) => {
1862
+ if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
1863
+ })];
1864
+ return () => {
1865
+ for (const unsub of listeners) unsub();
1866
+ };
1867
+ }, [
1868
+ alepha,
1869
+ input,
1870
+ syncFromFormValue
1871
+ ]);
1872
+ return {
1873
+ items,
1874
+ setItems: useCallback((newItems) => {
1875
+ setItemsState(newItems);
1876
+ input?.set(newItems.map((item) => item.value));
1877
+ }, [input]),
1878
+ nextKey: useCallback(() => keyCounter.current++, [])
1879
+ };
1880
+ };
1427
1881
  /**
1428
1882
  * Creates a proper InputField for an array item that integrates with the form system.
1429
1883
  * Uses array index for test IDs to ensure predictable, testable element identifiers.
@@ -1661,7 +2115,7 @@ const ControlArray = (props) => {
1661
2115
  };
1662
2116
 
1663
2117
  //#endregion
1664
- //#region ../../src/core/components/form/ControlDate.tsx
2118
+ //#region ../../src/core/form/components/ControlDate.tsx
1665
2119
  /**
1666
2120
  * ControlDate component for handling date, datetime, and time inputs.
1667
2121
  *
@@ -1718,7 +2172,7 @@ const ControlDate = (props) => {
1718
2172
  };
1719
2173
 
1720
2174
  //#endregion
1721
- //#region ../../src/core/components/form/ControlNumber.tsx
2175
+ //#region ../../src/core/form/components/ControlNumber.tsx
1722
2176
  /**
1723
2177
  *
1724
2178
  */
@@ -1776,7 +2230,7 @@ const ControlNumber = (props) => {
1776
2230
  };
1777
2231
 
1778
2232
  //#endregion
1779
- //#region ../../src/core/components/form/ControlObject.tsx
2233
+ //#region ../../src/core/form/components/ControlObject.tsx
1780
2234
  /**
1781
2235
  * ControlObject component for editing nested object schemas.
1782
2236
  *
@@ -1853,125 +2307,7 @@ const ControlObject = (props) => {
1853
2307
  };
1854
2308
 
1855
2309
  //#endregion
1856
- //#region ../../src/core/utils/extractSchemaFields.ts
1857
- /**
1858
- * Extract field information from a TypeBox schema for query building.
1859
- * Supports nested objects and provides field metadata for autocomplete.
1860
- */
1861
- function extractSchemaFields(schema, prefix = "") {
1862
- const fields = [];
1863
- if (!schema || typeof schema !== "object") return fields;
1864
- const properties = "properties" in schema ? schema.properties : schema;
1865
- if (!properties || typeof properties !== "object") return fields;
1866
- for (const [key, value] of Object.entries(properties)) {
1867
- if (typeof value !== "object" || value === null) continue;
1868
- const fieldSchema = value;
1869
- const path = prefix ? `${prefix}.${key}` : key;
1870
- const format = "format" in fieldSchema ? fieldSchema.format : void 0;
1871
- let displayType = "type" in fieldSchema ? fieldSchema.type : "object";
1872
- if (format === "date-time") displayType = "datetime";
1873
- else if (format === "date") displayType = "date";
1874
- else if (format === "time") displayType = "time";
1875
- else if (format === "duration") displayType = "duration";
1876
- const field = {
1877
- name: key,
1878
- path,
1879
- type: displayType,
1880
- format,
1881
- description: "description" in fieldSchema ? fieldSchema.description : void 0
1882
- };
1883
- if ("enum" in fieldSchema && fieldSchema.enum) {
1884
- field.enum = fieldSchema.enum;
1885
- field.type = "enum";
1886
- }
1887
- if ("type" in fieldSchema && fieldSchema.type === "object" && "properties" in fieldSchema && typeof fieldSchema.properties === "object") field.nested = extractSchemaFields(fieldSchema.properties, path);
1888
- fields.push(field);
1889
- if (field.nested) fields.push(...field.nested);
1890
- }
1891
- return fields;
1892
- }
1893
- /**
1894
- * Get suggested operators based on field type
1895
- */
1896
- function getOperatorsForField(field) {
1897
- const allOperators = ["=", "!="];
1898
- if (field.enum) return [...allOperators, "in"];
1899
- switch (field.type) {
1900
- case "string":
1901
- case "text": return [...allOperators, "null"];
1902
- case "number":
1903
- case "integer": return [
1904
- ...allOperators,
1905
- ">",
1906
- ">=",
1907
- "<",
1908
- "<="
1909
- ];
1910
- case "boolean": return allOperators;
1911
- case "datetime":
1912
- case "date": return [
1913
- ...allOperators,
1914
- ">",
1915
- ">=",
1916
- "<",
1917
- "<="
1918
- ];
1919
- default: return [...allOperators, "null"];
1920
- }
1921
- }
1922
- /**
1923
- * Get operator symbol and description
1924
- */
1925
- const OPERATOR_INFO = {
1926
- eq: {
1927
- symbol: "=",
1928
- label: "equals",
1929
- example: "name=John"
1930
- },
1931
- ne: {
1932
- symbol: "!=",
1933
- label: "not equals",
1934
- example: "status!=archived"
1935
- },
1936
- gt: {
1937
- symbol: ">",
1938
- label: "greater than",
1939
- example: "age>18"
1940
- },
1941
- gte: {
1942
- symbol: ">=",
1943
- label: "greater or equal",
1944
- example: "age>=18"
1945
- },
1946
- lt: {
1947
- symbol: "<",
1948
- label: "less than",
1949
- example: "age<65"
1950
- },
1951
- lte: {
1952
- symbol: "<=",
1953
- label: "less or equal",
1954
- example: "age<=65"
1955
- },
1956
- null: {
1957
- symbol: "=null",
1958
- label: "is null",
1959
- example: "deletedAt=null"
1960
- },
1961
- notNull: {
1962
- symbol: "!=null",
1963
- label: "is not null",
1964
- example: "email!=null"
1965
- },
1966
- in: {
1967
- symbol: "[...]",
1968
- label: "in array",
1969
- example: "status=[active,pending]"
1970
- }
1971
- };
1972
-
1973
- //#endregion
1974
- //#region ../../src/core/components/form/ControlQueryBuilder.tsx
2310
+ //#region ../../src/core/form/components/ControlQueryBuilder.tsx
1975
2311
  /**
1976
2312
  * Query builder with text input and help popover.
1977
2313
  * Generates query strings for parseQueryString syntax.
@@ -2222,7 +2558,7 @@ function QueryHelp({ fields, onInsert }) {
2222
2558
  }
2223
2559
 
2224
2560
  //#endregion
2225
- //#region ../../src/core/components/form/ControlSelect.tsx
2561
+ //#region ../../src/core/form/components/ControlSelect.tsx
2226
2562
  /**
2227
2563
  * ControlSelect component for handling Select, MultiSelect, and TagsInput.
2228
2564
  *
@@ -2318,6 +2654,7 @@ const ControlSelect = (props) => {
2318
2654
  size: props.size,
2319
2655
  id,
2320
2656
  leftSection: icon,
2657
+ rightSection: null,
2321
2658
  data,
2322
2659
  ...props.input.props,
2323
2660
  ...selectProps
@@ -2325,7 +2662,7 @@ const ControlSelect = (props) => {
2325
2662
  };
2326
2663
 
2327
2664
  //#endregion
2328
- //#region ../../src/core/components/form/Control.tsx
2665
+ //#region ../../src/core/form/components/Control.tsx
2329
2666
  /**
2330
2667
  * Generic form control that renders the appropriate input based on the schema and props.
2331
2668
  *
@@ -2445,27 +2782,46 @@ const Control = (_props) => {
2445
2782
  if (props.segmented) opts.segmented ??= {};
2446
2783
  return /* @__PURE__ */ jsx(ControlSelect, {
2447
2784
  size: props.size,
2448
- input: props.input,
2785
+ input: props.input,
2786
+ title: props.title,
2787
+ description: props.description,
2788
+ icon,
2789
+ ...opts
2790
+ });
2791
+ }
2792
+ if (props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean") {
2793
+ if (props.switch) {
2794
+ const switchProps = typeof props.switch === "object" ? props.switch : {};
2795
+ return /* @__PURE__ */ jsx(Switch, {
2796
+ ...inputProps,
2797
+ size: props.size,
2798
+ id,
2799
+ color: "blue",
2800
+ defaultChecked: props.input.props.defaultValue,
2801
+ onChange: (event) => {
2802
+ props.input.set(event.currentTarget.checked);
2803
+ },
2804
+ ...switchProps
2805
+ });
2806
+ }
2807
+ const opts = {
2808
+ input: props.input,
2809
+ select: { data: [{
2810
+ value: "true",
2811
+ label: "Yes"
2812
+ }, {
2813
+ value: "false",
2814
+ label: "No"
2815
+ }] }
2816
+ };
2817
+ return /* @__PURE__ */ jsx(ControlSelect, {
2818
+ size: props.size,
2449
2819
  title: props.title,
2450
2820
  description: props.description,
2451
2821
  icon,
2452
2822
  ...opts
2453
2823
  });
2454
2824
  }
2455
- if (props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean") {
2456
- const switchProps = typeof props.switch === "object" ? props.switch : {};
2457
- return /* @__PURE__ */ jsx(Switch, {
2458
- ...inputProps,
2459
- size: props.size,
2460
- id,
2461
- color: "blue",
2462
- defaultChecked: props.input.props.defaultValue,
2463
- onChange: (event) => {
2464
- props.input.set(event.currentTarget.checked);
2465
- },
2466
- ...switchProps
2467
- });
2468
- }
2469
2825
  if (props.password || props.input.props.name?.includes("password")) {
2470
2826
  const passwordInputProps = typeof props.password === "object" ? props.password : {};
2471
2827
  return /* @__PURE__ */ jsx(PasswordInput, {
@@ -2505,788 +2861,539 @@ const Control = (_props) => {
2505
2861
  case "url":
2506
2862
  case "uri": return "url";
2507
2863
  case "tel":
2508
- case "phone": return "tel";
2509
- default: return;
2510
- }
2511
- };
2512
- return /* @__PURE__ */ jsx(TextInput, {
2513
- ...inputProps,
2514
- size: props.size,
2515
- id,
2516
- leftSection: icon,
2517
- type: getInputType(),
2518
- ...props.input.props,
2519
- ...textInputProps,
2520
- inputWrapperOrder: [
2521
- "label",
2522
- "input",
2523
- "description",
2524
- "error"
2525
- ]
2526
- });
2527
- };
2528
-
2529
- //#endregion
2530
- //#region ../../src/core/components/form/TypeForm.tsx
2531
- /**
2532
- * TypeForm component that automatically renders all form inputs based on schema.
2533
- * Uses the Control component to render individual fields and Mantine Grid for responsive layout.
2534
- *
2535
- * Supports all field types including:
2536
- * - Primitive types (string, number, boolean, etc.)
2537
- * - Enum types (rendered as Select)
2538
- * - Arrays of primitives (rendered as MultiSelect/TagsInput)
2539
- * - Arrays of objects (rendered as ControlArray)
2540
- * - Nested objects (rendered as ControlObject)
2541
- *
2542
- * @example
2543
- * ```tsx
2544
- * import { t } from "alepha";
2545
- * import { useForm } from "alepha/react/form";
2546
- * import { TypeForm } from "@alepha/ui";
2547
- *
2548
- * const form = useForm({
2549
- * schema: t.object({
2550
- * username: t.text(),
2551
- * email: t.text(),
2552
- * age: t.integer(),
2553
- * subscribe: t.boolean(),
2554
- * address: t.object({
2555
- * street: t.text(),
2556
- * city: t.text(),
2557
- * }),
2558
- * tags: t.array(t.text()),
2559
- * contacts: t.array(t.object({
2560
- * name: t.text(),
2561
- * email: t.text(),
2562
- * })),
2563
- * }),
2564
- * handler: (values) => {
2565
- * console.log(values);
2566
- * },
2567
- * });
2568
- *
2569
- * return <TypeForm form={form} columns={2} />;
2570
- * ```
2571
- */
2572
- const TypeForm = (props) => {
2573
- const { form, columns = 3, children, controlProps, fieldControlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps, fill = true, size } = props;
2574
- const schema = props.schema || form.options.schema;
2575
- if (!schema?.properties) return null;
2576
- const supportedFields = Object.keys(schema.properties);
2577
- const colSpan = typeof columns === "number" ? {
2578
- xs: 12,
2579
- sm: 6,
2580
- lg: 12 / columns
2581
- } : {
2582
- base: columns.base ? 12 / columns.base : void 0,
2583
- xs: columns.xs ? 12 / columns.xs : 12,
2584
- sm: columns.sm ? 12 / columns.sm : 6,
2585
- md: columns.md ? 12 / columns.md : void 0,
2586
- lg: columns.lg ? 12 / columns.lg : 4,
2587
- xl: columns.xl ? 12 / columns.xl : void 0
2588
- };
2589
- const renderFields = () => {
2590
- if (children) return /* @__PURE__ */ jsx(Fragment$1, { children: children(form.input) });
2591
- return /* @__PURE__ */ jsx(Grid, { children: supportedFields.map((fieldName) => {
2592
- const field = form.input[fieldName];
2593
- const fieldSchema = schema.properties[fieldName];
2594
- if (!field || !fieldSchema) return null;
2595
- const isObject = fieldSchema && "type" in fieldSchema && fieldSchema.type === "object";
2596
- const isArrayOfObjects = fieldSchema && "type" in fieldSchema && fieldSchema.type === "array" && "items" in fieldSchema && fieldSchema.items && "properties" in fieldSchema.items;
2597
- const span = isObject || isArrayOfObjects ? 12 : colSpan;
2598
- const mergedControlProps = {
2599
- ...controlProps,
2600
- ...fieldControlProps?.[fieldName]
2601
- };
2602
- if (size) mergedControlProps.size = size;
2603
- return /* @__PURE__ */ jsx(Grid.Col, {
2604
- span,
2605
- children: /* @__PURE__ */ jsx(Control, {
2606
- input: field,
2607
- ...mergedControlProps
2608
- })
2609
- }, fieldName);
2610
- }) });
2611
- };
2612
- const content = /* @__PURE__ */ jsxs(Flex$1, {
2613
- direction: "column",
2614
- gap: "sm",
2615
- flex: fill ? 1 : void 0,
2616
- ...props.flexProps,
2617
- children: [/* @__PURE__ */ jsx(Flex$1, {
2618
- direction: "column",
2619
- gap: "sm",
2620
- flex: 1,
2621
- children: renderFields()
2622
- }), !skipSubmitButton && /* @__PURE__ */ jsx(Card, {
2623
- w: "100%",
2624
- withBorder: true,
2625
- children: /* @__PURE__ */ jsxs(Flex$1, {
2626
- gap: "sm",
2627
- flex: 1,
2628
- children: [
2629
- /* @__PURE__ */ jsx(Flex$1, {}),
2630
- /* @__PURE__ */ jsx(Flex$1, { flex: 1 }),
2631
- /* @__PURE__ */ jsxs(Flex$1, {
2632
- gap: "sm",
2633
- children: [/* @__PURE__ */ jsx(ActionButton, {
2634
- variant: "subtle",
2635
- type: "reset",
2636
- children: "Reset"
2637
- }), /* @__PURE__ */ jsx(ActionButton, {
2638
- intent: "primary",
2639
- form,
2640
- ...submitButtonProps,
2641
- children: submitButtonProps?.children ?? "Submit"
2642
- })]
2643
- })
2644
- ]
2645
- })
2646
- })]
2647
- });
2648
- if (skipFormElement) return content;
2649
- return /* @__PURE__ */ jsx(Flex$1, {
2650
- component: "form",
2651
- flex: fill ? 1 : void 0,
2652
- ...form.props,
2653
- ...props.flexProps,
2654
- children: content
2655
- });
2656
- };
2657
-
2658
- //#endregion
2659
- //#region ../../src/core/components/layout/AppBar.tsx
2660
- const AppBar = (props) => {
2661
- const { items = [] } = props;
2662
- const router = useRouter();
2663
- const renderItem = (item, index) => {
2664
- if (item.can && !item.can()) return null;
2665
- if ("type" in item) {
2666
- if (item.type === "burger") return /* @__PURE__ */ jsx(BurgerButton, {}, index);
2667
- if (item.type === "dark") return /* @__PURE__ */ jsx(DarkModeButton, { ...item.props }, index);
2668
- if (item.type === "search") return /* @__PURE__ */ jsx(OmnibarButton, { ...item.props }, index);
2669
- if (item.type === "lang") return /* @__PURE__ */ jsx(LanguageButton, { ...item.props }, index);
2670
- if (item.type === "spacer") return /* @__PURE__ */ jsx(Flex$1, { w: 16 }, index);
2671
- if (item.type === "divider") return /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }, index);
2672
- if (item.type === "logo") return renderLogo(item, index);
2673
- if (item.type === "back") return renderBack(item, index);
2674
- }
2675
- if ("element" in item) return item.element;
2676
- return null;
2677
- };
2678
- const renderLogo = (item, index) => {
2679
- const { src, text, icon, href, height = 32, width, fontWeight = 700, fontSize = "lg" } = item.props ?? {};
2680
- const logoContent = src ? /* @__PURE__ */ jsx(Image, {
2681
- src,
2682
- h: height,
2683
- w: width,
2684
- fit: "contain"
2685
- }) : icon ? typeof icon === "function" ? /* @__PURE__ */ jsx(icon, {}) : icon : text ? /* @__PURE__ */ jsx(Text$1, {
2686
- fw: fontWeight,
2687
- size: fontSize,
2688
- children: text
2689
- }) : null;
2690
- if (href) return /* @__PURE__ */ jsx(Anchor, {
2691
- component: Link,
2692
- href,
2693
- underline: "never",
2694
- c: "inherit",
2695
- children: logoContent
2696
- }, index);
2697
- return /* @__PURE__ */ jsx(Flex$1, { children: logoContent }, index);
2698
- };
2699
- const renderBack = (item, index) => {
2700
- const { label = "Back", iconOnly = true, href, icon } = item.props ?? {};
2701
- const renderIcon = () => {
2702
- if (!icon) return /* @__PURE__ */ jsx(IconArrowLeft, { size: 18 });
2703
- if (typeof icon === "function") return /* @__PURE__ */ jsx(icon, { size: 18 });
2704
- return icon;
2705
- };
2706
- const iconElement = renderIcon();
2707
- const handleClick = () => {
2708
- if (href) router.push(href);
2709
- else router.back();
2710
- };
2711
- if (iconOnly) return /* @__PURE__ */ jsx(ActionButton, {
2712
- icon: iconElement,
2713
- variant: "subtle",
2714
- color: "gray",
2715
- onClick: handleClick,
2716
- tooltip: {
2717
- label,
2718
- position: "bottom"
2719
- }
2720
- }, index);
2721
- return /* @__PURE__ */ jsx(ActionButton, {
2722
- leftSection: iconElement,
2723
- variant: "subtle",
2724
- color: "gray",
2725
- onClick: handleClick,
2726
- children: label
2727
- }, index);
2728
- };
2729
- const leftItems = items.filter((item) => item.position === "left");
2730
- const centerItems = items.filter((item) => item.position === "center");
2731
- const rightItems = items.filter((item) => item.position === "right");
2732
- const content = /* @__PURE__ */ jsxs(Flex$1, {
2733
- h: "100%",
2734
- align: "center",
2735
- px: props.container ? 0 : "md",
2736
- justify: "space-between",
2737
- ...props.flexProps,
2738
- children: [
2739
- /* @__PURE__ */ jsx(Flex$1, {
2740
- flex: 1,
2741
- children: leftItems.map((item, index) => /* @__PURE__ */ jsx(Flex$1, {
2742
- ml: index === 0 ? 0 : "md",
2743
- align: "center",
2744
- children: renderItem(item, index)
2745
- }, index))
2746
- }),
2747
- /* @__PURE__ */ jsx(Flex$1, { children: centerItems.map((item, index) => /* @__PURE__ */ jsx(Flex$1, {
2748
- mx: "md",
2749
- align: "center",
2750
- children: renderItem(item, index)
2751
- }, index)) }),
2752
- /* @__PURE__ */ jsx(Flex$1, {
2753
- flex: 1,
2754
- align: "center",
2755
- justify: "end",
2756
- children: rightItems.map((item, index) => /* @__PURE__ */ jsx(Flex$1, {
2757
- ml: index === 0 ? 0 : "md",
2758
- align: "center",
2759
- children: renderItem(item, index)
2760
- }, index))
2761
- })
2864
+ case "phone": return "tel";
2865
+ default: return;
2866
+ }
2867
+ };
2868
+ return /* @__PURE__ */ jsx(TextInput, {
2869
+ ...inputProps,
2870
+ size: props.size,
2871
+ id,
2872
+ leftSection: icon,
2873
+ type: getInputType(),
2874
+ ...props.input.props,
2875
+ ...textInputProps,
2876
+ inputWrapperOrder: [
2877
+ "label",
2878
+ "input",
2879
+ "description",
2880
+ "error"
2762
2881
  ]
2763
2882
  });
2764
- if (props.container) return /* @__PURE__ */ jsx(Container, {
2765
- h: "100%",
2766
- ...typeof props.container === "boolean" ? {} : props.container,
2767
- children: content
2768
- });
2769
- return content;
2770
2883
  };
2771
2884
 
2772
2885
  //#endregion
2773
- //#region ../../src/core/components/layout/Breadcrumb.tsx
2886
+ //#region ../../src/core/form/components/TypeForm.tsx
2774
2887
  /**
2775
- * Automatic breadcrumb component that reads the current route hierarchy
2776
- * from the Alepha router's layer stack.
2888
+ * TypeForm component that automatically renders all form inputs based on schema.
2889
+ * Uses the Control component to render individual fields and Mantine Grid for responsive layout.
2777
2890
  *
2778
- * Pages should define a `label` in their `$page()` options for best results.
2779
- * Falls back to the page name converted to Title Case.
2891
+ * Supports all field types including:
2892
+ * - Primitive types (string, number, boolean, etc.)
2893
+ * - Enum types (rendered as Select)
2894
+ * - Arrays of primitives (rendered as MultiSelect/TagsInput)
2895
+ * - Arrays of objects (rendered as ControlArray)
2896
+ * - Nested objects (rendered as ControlObject)
2897
+ *
2898
+ * @example
2899
+ * ```tsx
2900
+ * import { t } from "alepha";
2901
+ * import { useForm } from "alepha/react/form";
2902
+ * import { TypeForm } from "@alepha/ui";
2903
+ *
2904
+ * const form = useForm({
2905
+ * schema: t.object({
2906
+ * username: t.text(),
2907
+ * email: t.text(),
2908
+ * age: t.integer(),
2909
+ * subscribe: t.boolean(),
2910
+ * address: t.object({
2911
+ * street: t.text(),
2912
+ * city: t.text(),
2913
+ * }),
2914
+ * tags: t.array(t.text()),
2915
+ * contacts: t.array(t.object({
2916
+ * name: t.text(),
2917
+ * email: t.text(),
2918
+ * })),
2919
+ * }),
2920
+ * handler: (values) => {
2921
+ * console.log(values);
2922
+ * },
2923
+ * });
2924
+ *
2925
+ * return <TypeForm form={form} columns={2} />;
2926
+ * ```
2780
2927
  */
2781
- const Breadcrumb = ({ home = "Home", separator, size = "xs", ...groupProps }) => {
2782
- const state = useRouterState();
2783
- const router = useRouter();
2784
- const crumbs = [];
2785
- if (home !== false) crumbs.push({
2786
- label: home,
2787
- href: "/"
2788
- });
2789
- for (let i = 1; i < state.layers.length; i++) {
2790
- const layer = state.layers[i];
2791
- const route = layer.route;
2792
- if (route?.path === "/" || route?.path === "") continue;
2793
- const label = route?.label ?? toTitleCase(layer.name);
2794
- const href = router.path(layer.name);
2795
- crumbs.push({
2796
- label,
2797
- href
2798
- });
2799
- }
2800
- if (crumbs.length === 0) return null;
2801
- const sep = separator ?? /* @__PURE__ */ jsx(IconChevronRight, {
2802
- size: 12,
2803
- color: "#9ca3af"
2804
- });
2805
- return /* @__PURE__ */ jsx(Flex$1, {
2806
- gap: 4,
2807
- ...groupProps,
2808
- children: crumbs.map((crumb, i) => /* @__PURE__ */ jsxs(Flex$1, {
2809
- gap: 4,
2810
- children: [i > 0 && sep, i < crumbs.length - 1 ? /* @__PURE__ */ jsx(Anchor, {
2811
- component: Link,
2812
- href: crumb.href,
2813
- size,
2814
- c: "dimmed",
2815
- children: crumb.label
2816
- }) : /* @__PURE__ */ jsx(Text$1, {
2817
- size,
2818
- fw: 500,
2819
- children: crumb.label
2820
- })]
2821
- }, crumb.href))
2822
- });
2823
- };
2824
-
2825
- //#endregion
2826
- //#region ../../src/core/components/layout/Sidebar.tsx
2827
- const Sidebar = (props) => {
2828
- const router = useRouter();
2829
- const { onItemClick } = props;
2830
- const divider = (key, fill) => {
2831
- return /* @__PURE__ */ jsx(Flex$1, {
2832
- h: 1,
2833
- bg: "var(--mantine-color-default-border)",
2834
- my: "xs",
2835
- mx: fill ? "calc(-1 * var(--mantine-spacing-md))" : props.collapsed ? 0 : "sm"
2836
- }, key);
2837
- };
2838
- const renderNode = (item, key) => {
2839
- if ("type" in item) {
2840
- if (item.type === "spacer") {
2841
- if (props.collapsed) return null;
2842
- return /* @__PURE__ */ jsx(Flex$1, { h: 16 }, key);
2843
- }
2844
- if (item.type === "divider") return divider(key, item.fill);
2845
- if (item.type === "search") return /* @__PURE__ */ jsx(Flex$1, {
2846
- mb: "xs",
2847
- children: /* @__PURE__ */ jsx(OmnibarButton, { collapsed: props.collapsed })
2848
- }, key);
2849
- if (item.type === "toggle") return /* @__PURE__ */ jsx(ToggleSidebarButton, {}, key);
2850
- if (item.type === "section") {
2851
- if (item.children && item.children.length > 0) {
2852
- if (!item.children.some((child) => !("can" in child) || !child.can || child.can())) return null;
2853
- }
2854
- if (props.collapsed) return /* @__PURE__ */ jsxs(Fragment, { children: [divider(`${key}-d`), item.children?.map((child, index) => renderNode(child, `s${key}-${index}`))] }, key);
2855
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsxs(Flex$1, {
2856
- mt: "md",
2857
- align: "center",
2858
- gap: "xs",
2859
- children: [renderIcon(item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Text$1, {
2860
- size: "xs",
2861
- c: "dimmed",
2862
- tt: "uppercase",
2863
- fw: "bold",
2864
- children: item.label
2865
- })]
2866
- }), item.children?.map((child, index) => renderNode(child, `s${key}-${index}`))] }, key);
2867
- }
2868
- }
2869
- if ("element" in item) return /* @__PURE__ */ jsx(Fragment, { children: item.element }, key);
2870
- if (item.can && !item.can()) return null;
2871
- if (item.children && item.children.length > 0) {
2872
- if (!item.children.some((child) => !child.can || child.can())) return null;
2873
- }
2874
- if (props.collapsed) return /* @__PURE__ */ jsx(SidebarCollapsedItem, {
2875
- item,
2876
- level: 0,
2877
- onItemClick,
2878
- theme: props.theme ?? {}
2879
- }, key);
2880
- return /* @__PURE__ */ jsx(SidebarItem, {
2881
- item,
2882
- level: 0,
2883
- onItemClick,
2884
- theme: props.theme ?? {}
2885
- }, key);
2886
- };
2887
- const getSidebarNodes = () => {
2888
- if (props.items) return props.items;
2889
- if (props.autoPopulateMenu) {
2890
- const items = router.concretePages.filter((page) => !page.can || page.can()).map((page) => ({
2891
- label: page.label ?? page.name,
2892
- icon: renderIcon(page.icon),
2893
- href: router.path(page.name)
2894
- }));
2895
- if (typeof props.autoPopulateMenu === "object" && props.autoPopulateMenu.startsWith) {
2896
- const startsWith = props.autoPopulateMenu.startsWith;
2897
- return items.filter((item) => item.href?.startsWith(startsWith));
2898
- }
2899
- return items;
2900
- }
2901
- return [];
2928
+ const TypeForm = (props) => {
2929
+ const { form, columns = 3, children, controlProps, fieldControlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps, fill = true, size } = props;
2930
+ const schema = props.schema || form.options.schema;
2931
+ if (!schema?.properties) return null;
2932
+ const supportedFields = Object.keys(schema.properties);
2933
+ const colSpan = typeof columns === "number" ? {
2934
+ xs: 12,
2935
+ sm: 6,
2936
+ lg: 12 / columns
2937
+ } : {
2938
+ base: columns.base ? 12 / columns.base : void 0,
2939
+ xs: columns.xs ? 12 / columns.xs : 12,
2940
+ sm: columns.sm ? 12 / columns.sm : 6,
2941
+ md: columns.md ? 12 / columns.md : void 0,
2942
+ lg: columns.lg ? 12 / columns.lg : 4,
2943
+ xl: columns.xl ? 12 / columns.xl : void 0
2902
2944
  };
2903
- const padding = "md";
2904
- const gap = props.items ? props.gap ?? 4 : "xs";
2905
- const menu = useMemo(() => getSidebarNodes(), [props.items, props.autoPopulateMenu]);
2906
- return /* @__PURE__ */ jsxs(Flex$1, {
2907
- flex: 1,
2908
- py: padding,
2909
- direction: "column",
2910
- className: "alepha-sidebar-scroll",
2911
- ...props.flexProps,
2912
- children: [
2913
- /* @__PURE__ */ jsx(Flex$1, {
2914
- gap,
2915
- px: padding,
2916
- direction: "column",
2917
- children: menu.filter((it) => it.position === "top").map((item, index) => renderNode(item, index))
2918
- }),
2919
- /* @__PURE__ */ jsx(Flex$1, {
2920
- gap,
2921
- px: padding,
2922
- direction: "column",
2923
- flex: 1,
2924
- className: "alepha-sidebar-scroll",
2925
- children: menu.filter((it) => !it.position).map((item, index) => renderNode(item, index))
2926
- }),
2927
- /* @__PURE__ */ jsx(Flex$1, {
2928
- gap,
2929
- px: padding,
2930
- direction: "column",
2931
- children: menu.filter((it) => it.position === "bottom").map((item, index) => renderNode(item, index))
2932
- })
2933
- ]
2934
- });
2935
- };
2936
- const SidebarItem = (props) => {
2937
- const { item, level } = props;
2938
- const maxLevel = 2;
2939
- const router = useRouter();
2940
- const isActive = useCallback((item) => {
2941
- if (!item.children) return false;
2942
- for (const child of item.children) {
2943
- if (child.href) {
2944
- if (router.isActive(child.href)) return true;
2945
- }
2946
- if (isActive(child)) return true;
2947
- }
2948
- return false;
2949
- }, []);
2950
- const [isOpen, setIsOpen] = useState(isActive(item));
2951
- useEvents({ "react:transition:end": () => {
2952
- if (isActive(item)) setIsOpen(true);
2953
- } }, []);
2954
- if (level > maxLevel) return null;
2955
- const handleItemClick = (e) => {
2956
- if (!props.item.target) e.preventDefault();
2957
- if (item.children && item.children.length > 0) setIsOpen(!isOpen);
2958
- else {
2959
- props.onItemClick?.(item);
2960
- item.onClick?.();
2961
- }
2945
+ const renderFields = () => {
2946
+ if (children) return /* @__PURE__ */ jsx(Fragment, { children: children(form.input) });
2947
+ return /* @__PURE__ */ jsx(Grid, { children: supportedFields.map((fieldName) => {
2948
+ const field = form.input[fieldName];
2949
+ const fieldSchema = schema.properties[fieldName];
2950
+ if (!field || !fieldSchema) return null;
2951
+ const isObject = fieldSchema && "type" in fieldSchema && fieldSchema.type === "object";
2952
+ const isArrayOfObjects = fieldSchema && "type" in fieldSchema && fieldSchema.type === "array" && "items" in fieldSchema && fieldSchema.items && "properties" in fieldSchema.items;
2953
+ const span = isObject || isArrayOfObjects ? 12 : colSpan;
2954
+ const mergedControlProps = {
2955
+ ...controlProps,
2956
+ ...fieldControlProps?.[fieldName]
2957
+ };
2958
+ if (size) mergedControlProps.size = size;
2959
+ return /* @__PURE__ */ jsx(Grid.Col, {
2960
+ span,
2961
+ children: /* @__PURE__ */ jsx(Control, {
2962
+ input: field,
2963
+ ...mergedControlProps
2964
+ })
2965
+ }, fieldName);
2966
+ }) });
2962
2967
  };
2963
- return /* @__PURE__ */ jsxs(Flex$1, {
2968
+ const content = /* @__PURE__ */ jsxs(Flex$1, {
2964
2969
  direction: "column",
2965
- ps: level === 0 ? 0 : 32,
2966
- pos: "relative",
2967
- children: [/* @__PURE__ */ jsx(ActionButton, {
2970
+ gap: "sm",
2971
+ flex: fill ? 1 : void 0,
2972
+ ...props.flexProps,
2973
+ children: [/* @__PURE__ */ jsx(Flex$1, {
2974
+ direction: "column",
2975
+ gap: "sm",
2976
+ flex: 1,
2977
+ children: renderFields()
2978
+ }), !skipSubmitButton && /* @__PURE__ */ jsx(Card, {
2968
2979
  w: "100%",
2969
- justify: "space-between",
2970
- href: props.item.href,
2971
- target: props.item.target,
2972
- size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
2973
- tooltip: item.description ? {
2974
- label: item.description,
2975
- position: "right"
2976
- } : void 0,
2977
- color: "gray",
2978
- variant: "subtle",
2979
- variantActive: "default",
2980
- radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
2981
- onClick: handleItemClick,
2982
- leftSection: /* @__PURE__ */ jsxs(Flex$1, {
2983
- w: "100%",
2984
- align: "center",
2980
+ withBorder: true,
2981
+ children: /* @__PURE__ */ jsxs(Flex$1, {
2985
2982
  gap: "sm",
2986
- children: [renderIcon(item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Flex$1, {
2987
- direction: "column",
2988
- children: /* @__PURE__ */ jsx(Flex$1, { children: item.label })
2989
- })]
2990
- }),
2991
- rightSection: item.children ? /* @__PURE__ */ jsx(Flex$1, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
2992
- ...props.item.actionProps
2993
- }), item.children && isOpen && /* @__PURE__ */ jsxs(Flex$1, {
2994
- direction: "column",
2995
- "data-parent-level": level,
2996
- children: [/* @__PURE__ */ jsx(Flex$1, { style: {
2997
- position: "absolute",
2998
- width: 1,
2999
- background: "linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
3000
- top: 48,
3001
- left: 20 + 32 * level,
3002
- bottom: 16
3003
- } }), item.children.filter((child) => !child.can || child.can()).map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
3004
- item: child,
3005
- level: level + 1,
3006
- onItemClick: props.onItemClick,
3007
- theme: props.theme
3008
- }, index))]
2983
+ flex: 1,
2984
+ children: [
2985
+ /* @__PURE__ */ jsx(Flex$1, {}),
2986
+ /* @__PURE__ */ jsx(Flex$1, { flex: 1 }),
2987
+ /* @__PURE__ */ jsxs(Flex$1, {
2988
+ gap: "sm",
2989
+ children: [/* @__PURE__ */ jsx(ActionButton, {
2990
+ variant: "subtle",
2991
+ type: "reset",
2992
+ children: "Reset"
2993
+ }), /* @__PURE__ */ jsx(ActionButton, {
2994
+ intent: "primary",
2995
+ form,
2996
+ ...submitButtonProps,
2997
+ children: submitButtonProps?.children ?? "Submit"
2998
+ })]
2999
+ })
3000
+ ]
3001
+ })
3009
3002
  })]
3010
3003
  });
3011
- };
3012
- const SidebarCollapsedItem = (props) => {
3013
- const { item, level } = props;
3014
- const handleItemClick = () => {
3015
- props.onItemClick?.(item);
3016
- item.onClick?.();
3017
- };
3018
- return /* @__PURE__ */ jsx(ActionButton, {
3019
- size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
3020
- variant: "subtle",
3021
- variantActive: "default",
3022
- tooltip: {
3023
- label: item.label,
3024
- position: "right"
3025
- },
3026
- radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
3027
- onClick: handleItemClick,
3028
- icon: renderIcon(item.icon, ui.sizes.icon.sm) ?? /* @__PURE__ */ jsx(IconSquareRounded, { size: ui.sizes.icon.sm }),
3029
- href: props.item.href,
3030
- target: props.item.target,
3031
- ...props.item.actionProps
3004
+ if (skipFormElement) return content;
3005
+ return /* @__PURE__ */ jsx(Flex$1, {
3006
+ component: "form",
3007
+ flex: fill ? 1 : void 0,
3008
+ ...form.props,
3009
+ ...props.flexProps,
3010
+ children: content
3032
3011
  });
3033
3012
  };
3034
3013
 
3035
3014
  //#endregion
3036
- //#region ../../src/core/components/layout/DashboardShell.tsx
3037
- const DashboardShell = (props) => {
3038
- const router = useRouter();
3039
- const [sidebar, setSidebar] = useStore(alephaSidebarAtom);
3040
- const { opened } = sidebar;
3041
- const collapsed = props.sidebarProps?.collapsed !== void 0 ? props.sidebarProps.collapsed : sidebar.collapsed;
3042
- const [isResizing, setIsResizing] = useState(false);
3043
- const [isHovering, setIsHovering] = useState(false);
3044
- const [collapseEffect, setCollapseEffect] = useState({
3045
- offset: 0,
3046
- opacity: 1
3047
- });
3048
- const resizeRef = useRef(null);
3049
- const { collapsedWidth, collapseThreshold, maxWidth, hoverDelay, defaultWidth } = sidebar;
3050
- const handleResizeStart = useCallback((e) => {
3051
- if (!props.sidebarResizable) return;
3052
- e.preventDefault();
3053
- if (collapsed) {
3054
- setSidebar({
3055
- ...sidebar,
3056
- collapsed: false,
3057
- width: defaultWidth
3058
- });
3059
- setIsResizing(true);
3060
- resizeRef.current = {
3061
- startX: e.clientX,
3062
- startWidth: defaultWidth
3063
- };
3064
- } else {
3065
- setIsResizing(true);
3066
- resizeRef.current = {
3067
- startX: e.clientX,
3068
- startWidth: sidebar.width
3069
- };
3070
- }
3071
- }, [
3072
- props.sidebarResizable,
3073
- collapsed,
3074
- sidebar,
3075
- setSidebar,
3076
- defaultWidth
3077
- ]);
3078
- useEffect(() => {
3079
- if (!isResizing) return;
3080
- const handleMouseMove = (e) => {
3081
- if (!resizeRef.current) return;
3082
- const delta = e.clientX - resizeRef.current.startX;
3083
- const rawWidth = resizeRef.current.startWidth + delta;
3084
- const newWidth = Math.min(Math.max(rawWidth, collapsedWidth), maxWidth);
3085
- if (rawWidth < collapseThreshold) {
3086
- const progress = Math.max(0, (collapseThreshold - rawWidth) / collapseThreshold);
3087
- setCollapseEffect({
3088
- offset: -progress * collapsedWidth,
3089
- opacity: 1 - progress * .7
3090
- });
3091
- setSidebar({
3092
- ...sidebar,
3093
- width: collapseThreshold,
3094
- collapsed: false
3095
- });
3096
- } else {
3097
- setCollapseEffect({
3098
- offset: 0,
3099
- opacity: 1
3100
- });
3101
- setSidebar({
3102
- ...sidebar,
3103
- width: newWidth,
3104
- collapsed: false
3105
- });
3106
- }
3107
- };
3108
- const handleMouseUp = () => {
3109
- if (collapseEffect.offset < 0) setSidebar({
3110
- ...sidebar,
3111
- collapsed: true
3112
- });
3113
- setCollapseEffect({
3114
- offset: 0,
3115
- opacity: 1
3116
- });
3117
- setIsResizing(false);
3118
- resizeRef.current = null;
3119
- };
3120
- document.addEventListener("mousemove", handleMouseMove);
3121
- document.addEventListener("mouseup", handleMouseUp);
3122
- return () => {
3123
- document.removeEventListener("mousemove", handleMouseMove);
3124
- document.removeEventListener("mouseup", handleMouseUp);
3015
+ //#region ../../src/core/form/factories/dialogForm.tsx
3016
+ /**
3017
+ * Creates dialog options for a form dialog.
3018
+ *
3019
+ * @param form - The form model to render.
3020
+ * @param options - Additional dialog and TypeForm options.
3021
+ */
3022
+ const dialogForm = (form, options) => ({
3023
+ size: "lg",
3024
+ title: options?.title || "Form",
3025
+ ...options,
3026
+ content: /* @__PURE__ */ jsx(TypeForm, {
3027
+ form,
3028
+ skipSubmitButton: false,
3029
+ ...options?.typeFormProps
3030
+ })
3031
+ });
3032
+
3033
+ //#endregion
3034
+ //#region ../../src/core/helpers/renderIcon.tsx
3035
+ const renderIcon = (icon, size) => {
3036
+ if (!icon) return null;
3037
+ if (isValidElement(icon)) return icon;
3038
+ if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
3039
+ return icon;
3040
+ };
3041
+
3042
+ //#endregion
3043
+ //#region ../../src/core/hooks/useDialog.ts
3044
+ /**
3045
+ * Use this hook to access the Dialog Service for showing various dialog types.
3046
+ *
3047
+ * @example
3048
+ * ```tsx
3049
+ * const dialog = useDialog();
3050
+ * await dialog.alert({ title: "Alert", message: "This is an alert message" });
3051
+ * const confirmed = await dialog.confirm({ title: "Confirm", message: "Are you sure?" });
3052
+ * const input = await dialog.prompt({ title: "Input", message: "Enter your name:" });
3053
+ * ```
3054
+ */
3055
+ const useDialog = () => {
3056
+ return useInject(DialogService);
3057
+ };
3058
+
3059
+ //#endregion
3060
+ //#region ../../src/core/json/components/JsonViewer.tsx
3061
+ const SIZE_CONFIG = {
3062
+ xs: {
3063
+ icon: 14,
3064
+ levelOffset: 16
3065
+ },
3066
+ sm: {
3067
+ icon: 16,
3068
+ levelOffset: 20
3069
+ },
3070
+ md: {
3071
+ icon: 18,
3072
+ levelOffset: 24
3073
+ },
3074
+ lg: {
3075
+ icon: 20,
3076
+ levelOffset: 28
3077
+ },
3078
+ xl: {
3079
+ icon: 22,
3080
+ levelOffset: 32
3081
+ }
3082
+ };
3083
+ const STYLES = {
3084
+ root: { fontFamily: "var(--mantine-font-family-monospace)" },
3085
+ chevron: {
3086
+ flexShrink: 0,
3087
+ color: "var(--mantine-color-dimmed)"
3088
+ },
3089
+ key: {
3090
+ color: "var(--mantine-color-cyan-text)",
3091
+ fontWeight: 500
3092
+ },
3093
+ colon: { color: "var(--mantine-color-dimmed)" },
3094
+ string: { color: "var(--mantine-color-teal-text)" },
3095
+ number: { color: "var(--mantine-color-blue-text)" },
3096
+ boolean: { color: "var(--mantine-color-violet-text)" },
3097
+ null: {
3098
+ color: "var(--mantine-color-dimmed)",
3099
+ fontStyle: "italic"
3100
+ },
3101
+ preview: { color: "var(--mantine-color-dimmed)" }
3102
+ };
3103
+ const getValueType = (val) => {
3104
+ if (val === null) return "null";
3105
+ if (val === void 0) return "undefined";
3106
+ if (Array.isArray(val)) return "array";
3107
+ return typeof val;
3108
+ };
3109
+ function buildTreeNodes(data, path = [], key, isArrayItem = false, maxDepth = 10) {
3110
+ const currentPath = key !== void 0 ? [...path, key] : path;
3111
+ const nodeId = currentPath.length > 0 ? currentPath.join(".") : "root";
3112
+ if (currentPath.length > maxDepth) return {
3113
+ value: nodeId,
3114
+ label: key ?? "",
3115
+ nodeValue: data,
3116
+ nodeKey: key,
3117
+ path: currentPath,
3118
+ isArrayItem
3119
+ };
3120
+ const type = getValueType(data);
3121
+ if (type === "object" || type === "array") {
3122
+ const children = (type === "array" ? data.map((v, i) => [String(i), v]) : Object.entries(data)).map(([k, v]) => buildTreeNodes(v, currentPath, k, type === "array", maxDepth)).filter((n) => n !== null);
3123
+ return {
3124
+ value: nodeId,
3125
+ label: key ?? "",
3126
+ nodeValue: data,
3127
+ nodeKey: key,
3128
+ path: currentPath,
3129
+ isArrayItem,
3130
+ children: children.length > 0 ? children : void 0
3125
3131
  };
3126
- }, [
3127
- isResizing,
3128
- sidebar,
3129
- setSidebar,
3130
- collapsedWidth,
3131
- maxWidth,
3132
- collapseThreshold,
3133
- collapseEffect.offset
3134
- ]);
3135
- const hoverTimeoutRef = useRef(null);
3136
- const expandOnHover = props.sidebarProps?.expandOnHover !== false;
3137
- const handleNavbarMouseEnter = useCallback(() => {
3138
- if (collapsed && expandOnHover) hoverTimeoutRef.current = setTimeout(() => {
3139
- setIsHovering(true);
3140
- }, hoverDelay);
3141
- }, [
3142
- collapsed,
3143
- expandOnHover,
3144
- hoverDelay
3145
- ]);
3146
- const handleNavbarMouseLeave = useCallback(() => {
3147
- if (hoverTimeoutRef.current) {
3148
- clearTimeout(hoverTimeoutRef.current);
3149
- hoverTimeoutRef.current = null;
3150
- }
3151
- setIsHovering(false);
3152
- }, []);
3153
- useEffect(() => {
3154
- if (collapsed) {
3155
- setIsHovering(false);
3156
- if (hoverTimeoutRef.current) {
3157
- clearTimeout(hoverTimeoutRef.current);
3158
- hoverTimeoutRef.current = null;
3159
- }
3160
- }
3161
- }, [collapsed]);
3162
- const shouldShowSidebar = () => {
3163
- if (props.noSidebarWhen?.paths) {
3164
- for (const path of props.noSidebarWhen.paths) if (router.isActive(path, { startWith: true })) return false;
3165
- }
3166
- return true;
3132
+ }
3133
+ return {
3134
+ value: nodeId,
3135
+ label: key ?? "",
3136
+ nodeValue: data,
3137
+ nodeKey: key,
3138
+ path: currentPath,
3139
+ isArrayItem
3167
3140
  };
3168
- const [showSidebar, setShowSidebar] = useState(shouldShowSidebar());
3169
- useEvents({
3170
- "react:transition:end": () => {
3171
- setShowSidebar(shouldShowSidebar());
3172
- },
3173
- "react:transition:begin": () => {
3174
- setSidebar({
3175
- ...sidebar,
3176
- opened: false
3177
- });
3178
- }
3179
- }, [sidebar]);
3180
- const defaultAppBarItems = [{
3181
- position: "left",
3182
- type: "burger"
3183
- }];
3184
- const appBarProps = { ...props.appBarProps };
3185
- appBarProps.container ??= props.container;
3186
- const hasSidebar = showSidebar && props.sidebarProps !== void 0;
3187
- const hasAppBar = props.appBarProps || props.header;
3188
- const hHeight = props.headerHeight ?? 60;
3189
- const fHeight = props.footerHeight ?? 24;
3190
- const headerHeight = hasAppBar ? hHeight : 0;
3191
- const footerHeight = props.footer ? fHeight : 0;
3192
- const expandedWidth = Math.max(sidebar.width, collapsedWidth);
3193
- const isExpandedByHover = collapsed && isHovering;
3194
- const effectiveCollapsed = collapsed && !isHovering;
3195
- const handleSidebarItemClick = useCallback((item) => {
3196
- if (isExpandedByHover) setIsHovering(false);
3197
- props.sidebarProps?.onItemClick?.(item);
3198
- }, [isExpandedByHover, props.sidebarProps?.onItemClick]);
3199
- const hoverWidth = Math.max(defaultWidth, collapsedWidth);
3200
- const canResize = props.sidebarResizable && !collapsed;
3201
- return /* @__PURE__ */ jsxs(AppShell, {
3202
- layout: props.layout,
3203
- w: "100%",
3204
- flex: 1,
3205
- header: hasAppBar ? { height: hHeight } : void 0,
3206
- navbar: hasSidebar ? {
3207
- width: effectiveCollapsed || isExpandedByHover ? { base: collapsedWidth } : { base: expandedWidth },
3208
- breakpoint: "sm",
3209
- collapsed: { mobile: !opened }
3210
- } : void 0,
3211
- footer: props.footer ? { height: fHeight } : void 0,
3212
- ...props.appShellProps,
3141
+ }
3142
+ function getExpandedIds(nodes, targetDepth, currentDepth = 0) {
3143
+ if (currentDepth >= targetDepth) return [];
3144
+ const ids = [];
3145
+ for (const node of nodes) if (node.children) {
3146
+ ids.push(node.value);
3147
+ ids.push(...getExpandedIds(node.children, targetDepth, currentDepth + 1));
3148
+ }
3149
+ return ids;
3150
+ }
3151
+ const CopyButton$1 = ({ value, iconSize }) => {
3152
+ const [copied, setCopied] = useState(false);
3153
+ const handleCopy = useCallback((e) => {
3154
+ e.stopPropagation();
3155
+ navigator.clipboard.writeText(value);
3156
+ setCopied(true);
3157
+ setTimeout(() => setCopied(false), 1500);
3158
+ }, [value]);
3159
+ return /* @__PURE__ */ jsx(ActionIcon, {
3160
+ size: iconSize + 4,
3161
+ variant: "transparent",
3162
+ c: copied ? "green" : "dimmed",
3163
+ onClick: handleCopy,
3164
+ className: "alepha-json-viewer-copy",
3165
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: iconSize }) : /* @__PURE__ */ jsx(IconCopy, { size: iconSize })
3166
+ });
3167
+ };
3168
+ const RowNode = ({ node, expanded, hasChildren, elementProps, size, config, showQuotes, showCopyButton, renderValue }) => {
3169
+ const { nodeValue, nodeKey, path, isArrayItem, isRoot } = node;
3170
+ const type = getValueType(nodeValue);
3171
+ const isExpandable = type === "object" || type === "array";
3172
+ const getPreview = () => {
3173
+ if (!isExpandable) return null;
3174
+ const count = (type === "array" ? nodeValue : Object.keys(nodeValue)).length;
3175
+ const label = type === "array" ? "item" : "key";
3176
+ if (!expanded) return /* @__PURE__ */ jsx(Text$1, {
3177
+ fs: "italic",
3178
+ component: "span",
3179
+ size,
3180
+ style: STYLES.preview,
3181
+ children: count === 0 ? type === "array" ? "[]" : "{}" : type === "array" ? `[ ${count} ${count === 1 ? label : `${label}s`} ]` : `{ ${count} ${count === 1 ? label : `${label}s`} }`
3182
+ });
3183
+ return null;
3184
+ };
3185
+ const getCopyValue = () => isExpandable ? JSON.stringify(nodeValue, null, 2) : String(nodeValue ?? "");
3186
+ return /* @__PURE__ */ jsxs(Flex$1, {
3187
+ gap: 6,
3188
+ wrap: "nowrap",
3189
+ ...elementProps,
3190
+ className: `alepha-json-viewer-row ${elementProps.className || ""}`,
3213
3191
  children: [
3214
- hasAppBar && /* @__PURE__ */ jsx(AppShell.Header, {
3215
- ...props.appShellHeaderProps,
3216
- children: props.header ?? /* @__PURE__ */ jsx(AppBar, {
3217
- items: defaultAppBarItems,
3218
- ...appBarProps
3219
- })
3220
- }),
3221
- hasSidebar && /* @__PURE__ */ jsxs(AppShell.Navbar, {
3222
- className: "alepha-sidebar-navbar",
3223
- "data-resizing": isResizing,
3224
- "data-hover-expanded": isExpandedByHover,
3225
- onMouseEnter: handleNavbarMouseEnter,
3226
- onMouseLeave: handleNavbarMouseLeave,
3227
- style: {
3228
- transform: collapseEffect.offset ? `translateX(${collapseEffect.offset}px)` : void 0,
3229
- opacity: collapseEffect.opacity,
3230
- ...isExpandedByHover && {
3231
- width: hoverWidth,
3232
- zIndex: 200,
3233
- boxShadow: "var(--mantine-shadow-xl)"
3234
- }
3235
- },
3236
- ...props.appShellNavbarProps,
3237
- children: [
3238
- props.navbarHeader ? /* @__PURE__ */ jsx(Flex$1, {
3239
- style: { borderBottom: "1px solid var(--mantine-color-default-border)" },
3240
- h: headerHeight,
3241
- children: props.navbarHeader
3242
- }) : null,
3243
- /* @__PURE__ */ jsx(Sidebar, {
3244
- ...props.sidebarProps ?? {},
3245
- collapsed: effectiveCollapsed,
3246
- onItemClick: handleSidebarItemClick
3247
- }),
3248
- props.navbarFooter ? /* @__PURE__ */ jsx(Flex$1, {
3249
- style: { borderTop: "1px solid var(--mantine-color-default-border)" },
3250
- h: footerHeight,
3251
- children: props.navbarFooter
3252
- }) : null,
3253
- (canResize || isExpandedByHover) && /* @__PURE__ */ jsx(Flex$1, {
3254
- pos: "absolute",
3255
- right: -6,
3256
- top: 0,
3257
- bottom: 0,
3258
- w: 12,
3259
- style: {
3260
- cursor: "col-resize",
3261
- userSelect: "none"
3262
- },
3263
- onMouseDown: handleResizeStart
3264
- })
3265
- ]
3192
+ hasChildren ? expanded ? /* @__PURE__ */ jsx(IconChevronDown, {
3193
+ size: config.icon,
3194
+ style: STYLES.chevron
3195
+ }) : /* @__PURE__ */ jsx(IconChevronRight, {
3196
+ size: config.icon,
3197
+ style: STYLES.chevron
3198
+ }) : /* @__PURE__ */ jsx("span", { style: {
3199
+ width: config.icon,
3200
+ flexShrink: 0
3201
+ } }),
3202
+ nodeKey !== void 0 && !isArrayItem && /* @__PURE__ */ jsxs(Text$1, {
3203
+ component: "span",
3204
+ size,
3205
+ children: [/* @__PURE__ */ jsx("span", {
3206
+ style: STYLES.key,
3207
+ children: showQuotes ? `"${nodeKey}"` : nodeKey
3208
+ }), /* @__PURE__ */ jsx("span", {
3209
+ style: STYLES.colon,
3210
+ children: ":"
3211
+ })]
3266
3212
  }),
3267
- /* @__PURE__ */ jsx(AppShell.Main, {
3268
- className: "alepha-sidebar-main",
3269
- "data-resizing": isResizing,
3270
- ...props.appShellMainProps,
3271
- children: props.container ? /* @__PURE__ */ jsx(Container, {
3272
- w: "100%",
3273
- flex: 1,
3274
- display: "flex",
3275
- style: { flexDirection: "column" },
3276
- ...typeof props.container === "boolean" ? {} : props.container,
3277
- children: props.children ?? /* @__PURE__ */ jsx(NestedView, {})
3278
- }) : props.children ?? /* @__PURE__ */ jsx(NestedView, {})
3213
+ nodeKey !== void 0 && isArrayItem && /* @__PURE__ */ jsxs(Text$1, {
3214
+ component: "span",
3215
+ size,
3216
+ children: [/* @__PURE__ */ jsx("span", {
3217
+ style: STYLES.key,
3218
+ children: nodeKey
3219
+ }), /* @__PURE__ */ jsx("span", {
3220
+ style: STYLES.colon,
3221
+ children: ":"
3222
+ })]
3279
3223
  }),
3280
- props.footer && /* @__PURE__ */ jsx(AppShell.Footer, {
3281
- ...props.appShellFooterProps,
3282
- children: props.footer
3224
+ hasChildren ? getPreview() : isExpandable ? type === "array" ? /* @__PURE__ */ jsx(Text$1, {
3225
+ component: "span",
3226
+ size,
3227
+ style: STYLES.preview,
3228
+ children: "[]"
3229
+ }) : /* @__PURE__ */ jsx(Text$1, {
3230
+ component: "span",
3231
+ size,
3232
+ style: STYLES.preview,
3233
+ children: "{}"
3234
+ }) : renderValue(nodeValue, nodeKey, path),
3235
+ showCopyButton && /* @__PURE__ */ jsx(CopyButton$1, {
3236
+ value: getCopyValue(),
3237
+ iconSize: config.icon
3283
3238
  })
3284
3239
  ]
3285
3240
  });
3286
3241
  };
3242
+ const JsonViewer = ({ data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm", showQuotes = false, showCopyButton = true, formatValue }) => {
3243
+ const config = SIZE_CONFIG[size] || SIZE_CONFIG.sm;
3244
+ const treeData = useMemo(() => {
3245
+ const type = getValueType(data);
3246
+ if (type === "object" || type === "array") {
3247
+ const children = (type === "array" ? data.map((v, i) => [String(i), v]) : Object.entries(data)).map(([k, v]) => buildTreeNodes(v, [], k, type === "array", maxDepth)).filter((n) => n !== null);
3248
+ return [{
3249
+ value: "root",
3250
+ label: "",
3251
+ nodeValue: data,
3252
+ nodeKey: void 0,
3253
+ path: [],
3254
+ isArrayItem: false,
3255
+ isRoot: true,
3256
+ children: children.length > 0 ? children : void 0
3257
+ }];
3258
+ }
3259
+ const node = buildTreeNodes(data, [], void 0, false, maxDepth);
3260
+ return node ? [node] : [];
3261
+ }, [data, maxDepth]);
3262
+ const tree = useTree({ initialExpandedState: useMemo(() => {
3263
+ if (defaultExpandedDepth === 0) return {};
3264
+ if (defaultExpandedDepth === Infinity) return getTreeExpandedState(treeData, "*");
3265
+ return getTreeExpandedState(treeData, getExpandedIds(treeData, defaultExpandedDepth + 1));
3266
+ }, [treeData, defaultExpandedDepth]) });
3267
+ const renderValue = useCallback((val, key, path) => {
3268
+ const custom = formatValue?.(key, val, path);
3269
+ if (custom !== void 0) return /* @__PURE__ */ jsx(Text$1, {
3270
+ component: "span",
3271
+ size,
3272
+ style: STYLES.string,
3273
+ className: "alepha-json-viewer-value",
3274
+ title: String(val),
3275
+ children: custom
3276
+ });
3277
+ const type = getValueType(val);
3278
+ switch (type) {
3279
+ case "string": return /* @__PURE__ */ jsxs(Text$1, {
3280
+ style: STYLES.string,
3281
+ component: "span",
3282
+ size,
3283
+ className: "alepha-json-viewer-value",
3284
+ title: val,
3285
+ children: [
3286
+ "\"",
3287
+ val,
3288
+ "\""
3289
+ ]
3290
+ });
3291
+ case "number": return /* @__PURE__ */ jsx(Text$1, {
3292
+ component: "span",
3293
+ size,
3294
+ style: STYLES.number,
3295
+ children: val
3296
+ });
3297
+ case "boolean": return /* @__PURE__ */ jsx(Text$1, {
3298
+ component: "span",
3299
+ size,
3300
+ style: STYLES.boolean,
3301
+ children: String(val)
3302
+ });
3303
+ case "null":
3304
+ case "undefined": return /* @__PURE__ */ jsx(Text$1, {
3305
+ component: "span",
3306
+ size,
3307
+ style: STYLES.null,
3308
+ children: type
3309
+ });
3310
+ default: return /* @__PURE__ */ jsx(Text$1, {
3311
+ component: "span",
3312
+ size,
3313
+ children: String(val)
3314
+ });
3315
+ }
3316
+ }, [
3317
+ formatValue,
3318
+ showQuotes,
3319
+ size
3320
+ ]);
3321
+ const renderNode = useCallback(({ node, expanded, hasChildren, elementProps }) => {
3322
+ return /* @__PURE__ */ jsx(RowNode, {
3323
+ node,
3324
+ expanded,
3325
+ hasChildren,
3326
+ elementProps,
3327
+ size,
3328
+ config,
3329
+ showQuotes,
3330
+ showCopyButton,
3331
+ renderValue
3332
+ });
3333
+ }, [
3334
+ config,
3335
+ renderValue,
3336
+ showCopyButton,
3337
+ showQuotes,
3338
+ size
3339
+ ]);
3340
+ if (treeData.length === 0) return /* @__PURE__ */ jsx(Text$1, {
3341
+ size,
3342
+ style: STYLES.null,
3343
+ children: data === null ? "null" : data === void 0 ? "undefined" : "{}"
3344
+ });
3345
+ return /* @__PURE__ */ jsx(Tree, {
3346
+ data: treeData,
3347
+ tree,
3348
+ levelOffset: config.levelOffset,
3349
+ expandOnClick: true,
3350
+ renderNode,
3351
+ styles: { root: STYLES.root }
3352
+ });
3353
+ };
3354
+
3355
+ //#endregion
3356
+ //#region ../../src/core/json/factories/dialogJson.tsx
3357
+ /**
3358
+ * Creates dialog options for a JSON viewer dialog.
3359
+ *
3360
+ * @param data - The JSON data to display.
3361
+ * @param options - Additional dialog options.
3362
+ */
3363
+ const dialogJson = (data, options) => ({
3364
+ size: "lg",
3365
+ title: options?.title || "Json Viewer",
3366
+ ...options,
3367
+ content: /* @__PURE__ */ jsx(Flex$1, {
3368
+ bdrs: "md",
3369
+ w: "100%",
3370
+ flex: 1,
3371
+ p: "sm",
3372
+ bg: ui.colors.surface,
3373
+ children: /* @__PURE__ */ jsx(JsonViewer, {
3374
+ size: "xs",
3375
+ data
3376
+ })
3377
+ })
3378
+ });
3379
+
3380
+ //#endregion
3381
+ //#region ../../src/core/primitives/$ui.ts
3382
+ /**
3383
+ * Convenience function to configure and inject the UiRouter.
3384
+ */
3385
+ const $ui = (options = {}) => {
3386
+ const { alepha } = $context();
3387
+ if (options.themes) alepha.store.set(alephaThemeListAtom, options.themes);
3388
+ return alepha.inject(UiRouter);
3389
+ };
3287
3390
 
3288
3391
  //#endregion
3289
- //#region ../../src/core/components/table/DataTableFilters.tsx
3392
+ //#region ../../src/core/table/interfaces/types.ts
3393
+ const DEFAULT_MAX_VISIBLE_COLUMNS = 8;
3394
+
3395
+ //#endregion
3396
+ //#region ../../src/core/table/components/DataTableFilters.tsx
3290
3397
  const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) => {
3291
3398
  const visibleSchema = useMemo(() => {
3292
3399
  const visibleKeys = Object.keys(schema.properties).filter((key) => filterVisibility[key] !== false);
@@ -3322,7 +3429,7 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
3322
3429
  };
3323
3430
 
3324
3431
  //#endregion
3325
- //#region ../../src/core/components/table/DataTablePagination.tsx
3432
+ //#region ../../src/core/table/components/DataTablePagination.tsx
3326
3433
  const DataTablePagination = ({ page, size, totalPages, onPageChange, onSizeChange }) => {
3327
3434
  return /* @__PURE__ */ jsxs(Flex$1, {
3328
3435
  align: "center",
@@ -3369,11 +3476,7 @@ const DataTablePagination = ({ page, size, totalPages, onPageChange, onSizeChang
3369
3476
  };
3370
3477
 
3371
3478
  //#endregion
3372
- //#region ../../src/core/components/table/types.ts
3373
- const DEFAULT_MAX_VISIBLE_COLUMNS = 8;
3374
-
3375
- //#endregion
3376
- //#region ../../src/core/components/table/ColumnPicker.tsx
3479
+ //#region ../../src/core/table/components/ColumnPicker.tsx
3377
3480
  const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3378
3481
  const [opened, setOpened] = useState(false);
3379
3482
  const columnEntries = Object.entries(columns);
@@ -3474,7 +3577,7 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3474
3577
  };
3475
3578
 
3476
3579
  //#endregion
3477
- //#region ../../src/core/components/table/FilterPicker.tsx
3580
+ //#region ../../src/core/table/components/FilterPicker.tsx
3478
3581
  const getFieldLabel = (schema, key) => {
3479
3582
  const prop = schema.properties[key];
3480
3583
  if (prop && typeof prop === "object" && "title" in prop && prop.title) return prop.title;
@@ -3575,7 +3678,7 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3575
3678
  };
3576
3679
 
3577
3680
  //#endregion
3578
- //#region ../../src/core/components/table/DataTableToolbar.tsx
3681
+ //#region ../../src/core/table/components/DataTableToolbar.tsx
3579
3682
  const escapeCsvField = (value) => {
3580
3683
  if (value.includes(",") || value.includes("\"") || value.includes("\n")) return `"${value.replace(/"/g, "\"\"")}"`;
3581
3684
  return value;
@@ -3658,7 +3761,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3658
3761
  onClick: exportClipboard
3659
3762
  }] }
3660
3763
  }),
3661
- hasSelection && /* @__PURE__ */ jsxs(Fragment$1, { children: [
3764
+ hasSelection && /* @__PURE__ */ jsxs(Fragment, { children: [
3662
3765
  /* @__PURE__ */ jsx(Divider, {
3663
3766
  orientation: "vertical",
3664
3767
  mx: "xs"
@@ -3703,7 +3806,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3703
3806
  };
3704
3807
 
3705
3808
  //#endregion
3706
- //#region ../../src/core/components/table/useTableSelection.ts
3809
+ //#region ../../src/core/table/components/useTableSelection.ts
3707
3810
  const useTableSelection = (items, getItemKey, enabled) => {
3708
3811
  const [selectedKeys, setSelectedKeys] = useState(/* @__PURE__ */ new Set());
3709
3812
  const selectedItems = useMemo(() => {
@@ -3766,7 +3869,7 @@ const useTableSelection = (items, getItemKey, enabled) => {
3766
3869
  };
3767
3870
 
3768
3871
  //#endregion
3769
- //#region ../../src/core/components/table/DataTable.tsx
3872
+ //#region ../../src/core/table/components/DataTable.tsx
3770
3873
  /**
3771
3874
  * Parse the sort string to get direction for a specific field.
3772
3875
  * Alepha convention: 'field' = ASC, '-field' = DESC
@@ -4165,29 +4268,206 @@ const DataTable = (props) => {
4165
4268
  };
4166
4269
 
4167
4270
  //#endregion
4168
- //#region ../../src/core/hooks/useDialog.ts
4271
+ //#region ../../src/core/utils/extractSchemaFields.ts
4169
4272
  /**
4170
- * Use this hook to access the Dialog Service for showing various dialog types.
4273
+ * Extract field information from a TypeBox schema for query building.
4274
+ * Supports nested objects and provides field metadata for autocomplete.
4275
+ */
4276
+ function extractSchemaFields(schema, prefix = "") {
4277
+ const fields = [];
4278
+ if (!schema || typeof schema !== "object") return fields;
4279
+ const properties = "properties" in schema ? schema.properties : schema;
4280
+ if (!properties || typeof properties !== "object") return fields;
4281
+ for (const [key, value] of Object.entries(properties)) {
4282
+ if (typeof value !== "object" || value === null) continue;
4283
+ const fieldSchema = value;
4284
+ const path = prefix ? `${prefix}.${key}` : key;
4285
+ const format = "format" in fieldSchema ? fieldSchema.format : void 0;
4286
+ let displayType = "type" in fieldSchema ? fieldSchema.type : "object";
4287
+ if (format === "date-time") displayType = "datetime";
4288
+ else if (format === "date") displayType = "date";
4289
+ else if (format === "time") displayType = "time";
4290
+ else if (format === "duration") displayType = "duration";
4291
+ const field = {
4292
+ name: key,
4293
+ path,
4294
+ type: displayType,
4295
+ format,
4296
+ description: "description" in fieldSchema ? fieldSchema.description : void 0
4297
+ };
4298
+ if ("enum" in fieldSchema && fieldSchema.enum) {
4299
+ field.enum = fieldSchema.enum;
4300
+ field.type = "enum";
4301
+ }
4302
+ if ("type" in fieldSchema && fieldSchema.type === "object" && "properties" in fieldSchema && typeof fieldSchema.properties === "object") field.nested = extractSchemaFields(fieldSchema.properties, path);
4303
+ fields.push(field);
4304
+ if (field.nested) fields.push(...field.nested);
4305
+ }
4306
+ return fields;
4307
+ }
4308
+ /**
4309
+ * Get suggested operators based on field type
4310
+ */
4311
+ function getOperatorsForField(field) {
4312
+ const allOperators = ["=", "!="];
4313
+ if (field.enum) return [...allOperators, "in"];
4314
+ switch (field.type) {
4315
+ case "string":
4316
+ case "text": return [...allOperators, "null"];
4317
+ case "number":
4318
+ case "integer": return [
4319
+ ...allOperators,
4320
+ ">",
4321
+ ">=",
4322
+ "<",
4323
+ "<="
4324
+ ];
4325
+ case "boolean": return allOperators;
4326
+ case "datetime":
4327
+ case "date": return [
4328
+ ...allOperators,
4329
+ ">",
4330
+ ">=",
4331
+ "<",
4332
+ "<="
4333
+ ];
4334
+ default: return [...allOperators, "null"];
4335
+ }
4336
+ }
4337
+ /**
4338
+ * Get operator symbol and description
4339
+ */
4340
+ const OPERATOR_INFO = {
4341
+ eq: {
4342
+ symbol: "=",
4343
+ label: "equals",
4344
+ example: "name=John"
4345
+ },
4346
+ ne: {
4347
+ symbol: "!=",
4348
+ label: "not equals",
4349
+ example: "status!=archived"
4350
+ },
4351
+ gt: {
4352
+ symbol: ">",
4353
+ label: "greater than",
4354
+ example: "age>18"
4355
+ },
4356
+ gte: {
4357
+ symbol: ">=",
4358
+ label: "greater or equal",
4359
+ example: "age>=18"
4360
+ },
4361
+ lt: {
4362
+ symbol: "<",
4363
+ label: "less than",
4364
+ example: "age<65"
4365
+ },
4366
+ lte: {
4367
+ symbol: "<=",
4368
+ label: "less or equal",
4369
+ example: "age<=65"
4370
+ },
4371
+ null: {
4372
+ symbol: "=null",
4373
+ label: "is null",
4374
+ example: "deletedAt=null"
4375
+ },
4376
+ notNull: {
4377
+ symbol: "!=null",
4378
+ label: "is not null",
4379
+ example: "email!=null"
4380
+ },
4381
+ in: {
4382
+ symbol: "[...]",
4383
+ label: "in array",
4384
+ example: "status=[active,pending]"
4385
+ }
4386
+ };
4387
+
4388
+ //#endregion
4389
+ //#region ../../src/core/utils/icons.tsx
4390
+ /**
4391
+ * Get the default icon for an input based on its type, format, or name.
4392
+ */
4393
+ const getDefaultIcon = (params) => {
4394
+ const { type, format, name, isEnum, isArray, size = "sm" } = params;
4395
+ const iconSize = ui.sizes.icon[size];
4396
+ if (format) switch (format) {
4397
+ case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
4398
+ case "url":
4399
+ case "uri": return /* @__PURE__ */ jsx(IconLink, { size: iconSize });
4400
+ case "tel":
4401
+ case "phone": return /* @__PURE__ */ jsx(IconPhone, { size: iconSize });
4402
+ case "date": return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
4403
+ case "date-time": return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
4404
+ case "time": return /* @__PURE__ */ jsx(IconClock, { size: iconSize });
4405
+ case "color": return /* @__PURE__ */ jsx(IconColorPicker, { size: iconSize });
4406
+ case "uuid": return /* @__PURE__ */ jsx(IconKey, { size: iconSize });
4407
+ }
4408
+ if (name) {
4409
+ const nameLower = name.toLowerCase();
4410
+ if (nameLower.includes("password") || nameLower.includes("secret")) return /* @__PURE__ */ jsx(IconKey, { size: iconSize });
4411
+ if (nameLower.includes("email") || nameLower.includes("mail")) return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
4412
+ if (nameLower.includes("url") || nameLower.includes("link")) return /* @__PURE__ */ jsx(IconLink, { size: iconSize });
4413
+ if (nameLower.includes("phone") || nameLower.includes("tel")) return /* @__PURE__ */ jsx(IconPhone, { size: iconSize });
4414
+ if (nameLower.includes("color")) return /* @__PURE__ */ jsx(IconPalette, { size: iconSize });
4415
+ if (nameLower.includes("file") || nameLower.includes("upload")) return /* @__PURE__ */ jsx(IconFile, { size: iconSize });
4416
+ if (nameLower.includes("date")) return /* @__PURE__ */ jsx(IconCalendar, { size: iconSize });
4417
+ if (nameLower.includes("time")) return /* @__PURE__ */ jsx(IconClock, { size: iconSize });
4418
+ }
4419
+ if (isEnum || isArray) return /* @__PURE__ */ jsx(IconSelector, { size: iconSize });
4420
+ if (type) switch (type) {
4421
+ case "boolean": return /* @__PURE__ */ jsx(IconToggleLeft, { size: iconSize });
4422
+ case "number":
4423
+ case "integer": return /* @__PURE__ */ jsx(IconHash, { size: iconSize });
4424
+ case "array": return /* @__PURE__ */ jsx(IconList, { size: iconSize });
4425
+ case "string": return /* @__PURE__ */ jsx(IconLetterCase, { size: iconSize });
4426
+ }
4427
+ return /* @__PURE__ */ jsx(IconAt, { size: iconSize });
4428
+ };
4429
+
4430
+ //#endregion
4431
+ //#region ../../src/core/utils/string.ts
4432
+ /**
4433
+ * Capitalizes the first letter of a string.
4171
4434
  *
4172
4435
  * @example
4173
- * ```tsx
4174
- * const dialog = useDialog();
4175
- * await dialog.alert({ title: "Alert", message: "This is an alert message" });
4176
- * const confirmed = await dialog.confirm({ title: "Confirm", message: "Are you sure?" });
4177
- * const input = await dialog.prompt({ title: "Input", message: "Enter your name:" });
4178
- * ```
4436
+ * capitalize("hello") // "Hello"
4179
4437
  */
4180
- const useDialog = () => {
4181
- return useInject(DialogService);
4438
+ const capitalize = (str) => {
4439
+ return str.charAt(0).toUpperCase() + str.slice(1);
4440
+ };
4441
+ /**
4442
+ * Converts camelCase or snake_case to Title Case with spaces.
4443
+ *
4444
+ * @example
4445
+ * toTitleCase("userName") // "User Name"
4446
+ * toTitleCase("first_name") // "First Name"
4447
+ * toTitleCase("email") // "Email"
4448
+ */
4449
+ const toTitleCase = (str) => {
4450
+ return str.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/_/g, " ").replace(/\b\w/g, (c) => c.toUpperCase());
4451
+ };
4452
+ /**
4453
+ * Converts a path or identifier string into a pretty display name.
4454
+ * For paths like "/contacts/0/name", extracts just the field name "Name".
4455
+ * Handles camelCase and snake_case conversion to Title Case.
4456
+ *
4457
+ * @example
4458
+ * prettyName("/userName") // "User Name"
4459
+ * prettyName("/contacts/0/email") // "Email"
4460
+ * prettyName("/address/streetName") // "Street Name"
4461
+ * prettyName("first_name") // "First Name"
4462
+ */
4463
+ const prettyName = (name) => {
4464
+ const segments = name.split("/").filter((s) => s && !/^\d+$/.test(s));
4465
+ return toTitleCase(segments[segments.length - 1] || name.replaceAll("/", ""));
4182
4466
  };
4183
4467
 
4184
4468
  //#endregion
4185
4469
  //#region ../../src/core/index.ts
4186
4470
  /**
4187
- * | Stability | Since | Runtime |
4188
- * |-----------|-------|---------|
4189
- * | 2 - beta | 0.12.0 | node, bun, workerd, browser|
4190
- *
4191
4471
  * Core UI components based on Mantine UI v8.
4192
4472
  *
4193
4473
  * **Features:**
@@ -4223,15 +4503,7 @@ const AlephaUI = $module({
4223
4503
  alepha.with(ToastService);
4224
4504
  }
4225
4505
  });
4226
- /**
4227
- * Convenience function to configure and inject the UiRouter.
4228
- */
4229
- const $ui = (options = {}) => {
4230
- const { alepha } = $context();
4231
- if (options.themes) alepha.store.set(alephaThemeListAtom, options.themes);
4232
- return alepha.inject(UiRouter);
4233
- };
4234
4506
 
4235
4507
  //#endregion
4236
- export { $ui, ActionButton, DashboardShell as AdminShell, DashboardShell, AlephaMantineProvider, AlephaUI, AlertDialog, AppBar, Breadcrumb, BurgerButton, ClipboardButton, ConfirmDialog, Control, ControlArray, ControlDate, ControlNumber, ControlObject, ControlQueryBuilder, ControlSelect, DarkModeButton, DataTable, DialogService, Flex, LanguageButton, OPERATOR_INFO, Omnibar, OmnibarButton, PromptDialog, Sidebar, Text, ThemeButton, ThemeProvider, ToastService, ToggleSidebarButton, TypeForm, UiRouter, alephaSidebarAtom, alephaThemeAtom, alephaThemeListAtom, capitalize, defaultTheme, extractSchemaFields, getDefaultIcon, getOperatorsForField, midnightTheme, prettyName, toTitleCase, ui, useDialog, useToast };
4508
+ export { $ui, ActionButton, DashboardShell as AdminShell, DashboardShell, AlephaMantineProvider, AlephaUI, AlertDialog, AppBar, Breadcrumb as Breadcrumbs, BurgerButton, ClipboardButton, ConfirmDialog, Container, Control, ControlArray, ControlDate, ControlNumber, ControlObject, ControlQueryBuilder, ControlSelect, DarkModeButton, DataTable, DetailDrawer, DetailList, DialogService, Flex, Heading, JsonViewer, LanguageButton, OPERATOR_INFO, Omnibar, OmnibarButton, PromptDialog, Sidebar, ToggleSidebarButton as SidebarCollapseButton, StatCards, Text, ThemeButton, ThemeProvider, ToastService, TypeForm, UiRouter, alephaSidebarAtom, alephaThemeAtom, alephaThemeListAtom, capitalize, defaultTheme, dialogForm, dialogJson, extractSchemaFields, getDefaultIcon, getOperatorsForField, isComponentType, midnightTheme, prettyName, renderIcon, toTitleCase, ui, useDialog, useTheme, useToast };
4237
4509
  //# sourceMappingURL=index.js.map