@alepha/ui 0.18.1 → 0.18.3

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 (280) hide show
  1. package/dist/admin/{AdminApiKeys-C-6_Q-lH.js → AdminApiKeys-Dy_k-4Vd.js} +17 -38
  2. package/dist/admin/AdminApiKeys-Dy_k-4Vd.js.map +1 -0
  3. package/dist/admin/{AdminAudits-Bgbf04hO.js → AdminAudits-CKiFMSSU.js} +23 -19
  4. package/dist/admin/AdminAudits-CKiFMSSU.js.map +1 -0
  5. package/dist/admin/AdminDashboard-PhC_dZqo.js +67 -0
  6. package/dist/admin/AdminDashboard-PhC_dZqo.js.map +1 -0
  7. package/dist/admin/{AdminFiles-B9a7G3cY.js → AdminFiles-DFTjijGp.js} +3 -7
  8. package/dist/admin/AdminFiles-DFTjijGp.js.map +1 -0
  9. package/dist/admin/{AdminJobDashboard-DaTwf5OY.js → AdminJobDashboard-BL8gGPDp.js} +2 -2
  10. package/dist/admin/{AdminJobDashboard-DaTwf5OY.js.map → AdminJobDashboard-BL8gGPDp.js.map} +1 -1
  11. package/dist/admin/{AdminJobExecutions-B9cek5dl.js → AdminJobExecutions-D9E-CS-U.js} +24 -36
  12. package/dist/admin/AdminJobExecutions-D9E-CS-U.js.map +1 -0
  13. package/dist/admin/{AdminJobRegistry-DFgV3oqx.js → AdminJobRegistry-Ci9ue1zC.js} +10 -18
  14. package/dist/admin/AdminJobRegistry-Ci9ue1zC.js.map +1 -0
  15. package/dist/admin/AdminLayout-I6TlUMPc.js +61 -0
  16. package/dist/admin/AdminLayout-I6TlUMPc.js.map +1 -0
  17. package/dist/admin/AdminNotifications-ZPHCYrv7.js +542 -0
  18. package/dist/admin/AdminNotifications-ZPHCYrv7.js.map +1 -0
  19. package/dist/admin/{AdminParameters-DHw9ATgl.js → AdminParameters-CqgvhRsb.js} +120 -105
  20. package/dist/admin/AdminParameters-CqgvhRsb.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BhGJPI3z.js → AdminSessions-Bz5NRuoW.js} +48 -53
  22. package/dist/admin/AdminSessions-Bz5NRuoW.js.map +1 -0
  23. package/dist/admin/{AdminUserLayout-BdC4Te8m.js → AdminUserLayout-lXT6I0Qq.js} +14 -8
  24. package/dist/admin/AdminUserLayout-lXT6I0Qq.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DAt23fqY.js → AdminUserProfile-vFBLoJ3h.js} +3 -3
  26. package/dist/admin/{AdminUserProfile-DAt23fqY.js.map → AdminUserProfile-vFBLoJ3h.js.map} +1 -1
  27. package/dist/admin/{AdminUserSessions-1uzcx02z.js → AdminUserSessions-CT_YDim0.js} +33 -35
  28. package/dist/admin/AdminUserSessions-CT_YDim0.js.map +1 -0
  29. package/dist/admin/AdminUsers-D1UfGya9.js +206 -0
  30. package/dist/admin/AdminUsers-D1UfGya9.js.map +1 -0
  31. package/dist/admin/{AuthLayout-DFJvCvzw.js → AuthLayout-_frhdgOO.js} +2 -2
  32. package/dist/admin/{AuthLayout-DFJvCvzw.js.map → AuthLayout-_frhdgOO.js.map} +1 -1
  33. package/dist/admin/{IconGoogle-CSQLPYwX.js → IconGoogle-Ch1m3Uzl.js} +1 -1
  34. package/dist/admin/{IconGoogle-CSQLPYwX.js.map → IconGoogle-Ch1m3Uzl.js.map} +1 -1
  35. package/dist/admin/Login-xtNmQtGh.js +275 -0
  36. package/dist/admin/Login-xtNmQtGh.js.map +1 -0
  37. package/dist/{auth/Profile-BMX_Ar_s.js → admin/Profile-_AtPUwAP.js} +31 -27
  38. package/dist/admin/Profile-_AtPUwAP.js.map +1 -0
  39. package/dist/admin/{Register-Cs10l8vX.js → Register-JcCjHUUn.js} +199 -143
  40. package/dist/admin/Register-JcCjHUUn.js.map +1 -0
  41. package/dist/admin/{ResetPassword-BwDdfkGH.js → ResetPassword-CwGBPLJO.js} +7 -7
  42. package/dist/admin/ResetPassword-CwGBPLJO.js.map +1 -0
  43. package/dist/admin/{VerifyEmail-DfXHAiQl.js → VerifyEmail-hNxWejWf.js} +23 -8
  44. package/dist/admin/VerifyEmail-hNxWejWf.js.map +1 -0
  45. package/dist/admin/{core-2xoLiT0o.js → core-CYaRQ8O-.js} +2082 -688
  46. package/dist/admin/core-CYaRQ8O-.js.map +1 -0
  47. package/dist/admin/index.d.ts +112 -48
  48. package/dist/admin/index.d.ts.map +1 -1
  49. package/dist/admin/index.js +467 -69
  50. package/dist/admin/index.js.map +1 -1
  51. package/dist/auth/{AuthLayout-CAE1pX9s.js → AuthLayout-AvLlcLjS.js} +2 -2
  52. package/dist/auth/{AuthLayout-CAE1pX9s.js.map → AuthLayout-AvLlcLjS.js.map} +1 -1
  53. package/dist/auth/Login-BA1E8IZl.js +275 -0
  54. package/dist/auth/Login-BA1E8IZl.js.map +1 -0
  55. package/dist/{admin/Profile-B-c9pCPf.js → auth/Profile-YcWdeuFz.js} +31 -27
  56. package/dist/auth/Profile-YcWdeuFz.js.map +1 -0
  57. package/dist/auth/{Register-6hi_cpfF.js → Register-CPhEO5MG.js} +198 -142
  58. package/dist/auth/Register-CPhEO5MG.js.map +1 -0
  59. package/dist/{demo/ResetPassword-DWN0lzr5.js → auth/ResetPassword-DCtGcneA.js} +7 -7
  60. package/dist/auth/ResetPassword-DCtGcneA.js.map +1 -0
  61. package/dist/{demo/VerifyEmail-DZWL72K4.js → auth/VerifyEmail-DkH7NBfn.js} +23 -8
  62. package/dist/auth/VerifyEmail-DkH7NBfn.js.map +1 -0
  63. package/dist/auth/{core-niW0sFLv.js → core-D5jIAVF2.js} +1385 -329
  64. package/dist/auth/core-D5jIAVF2.js.map +1 -0
  65. package/dist/auth/index.d.ts +105 -49
  66. package/dist/auth/index.d.ts.map +1 -1
  67. package/dist/auth/index.js +29 -26
  68. package/dist/auth/index.js.map +1 -1
  69. package/dist/core/index.d.ts +210 -74
  70. package/dist/core/index.d.ts.map +1 -1
  71. package/dist/core/index.js +2247 -834
  72. package/dist/core/index.js.map +1 -1
  73. package/dist/demo/{AuthLayout-jLa0aKsI.js → AuthLayout-Brri4A-L.js} +2 -2
  74. package/dist/demo/{AuthLayout-jLa0aKsI.js.map → AuthLayout-Brri4A-L.js.map} +1 -1
  75. package/dist/demo/DemoButton-wiCxZZ_L.js +182 -0
  76. package/dist/demo/DemoButton-wiCxZZ_L.js.map +1 -0
  77. package/dist/demo/DemoControlSelect-D7ILObVg.js +305 -0
  78. package/dist/demo/DemoControlSelect-D7ILObVg.js.map +1 -0
  79. package/dist/demo/DemoDataTable-DZ5Y8pFX.js +362 -0
  80. package/dist/demo/DemoDataTable-DZ5Y8pFX.js.map +1 -0
  81. package/dist/demo/{DemoDialog-4ItHLf9t.js → DemoDialog-CUWdLHim.js} +2 -2
  82. package/dist/demo/{DemoDialog-4ItHLf9t.js.map → DemoDialog-CUWdLHim.js.map} +1 -1
  83. package/dist/demo/{DemoFlex-EtVq8QfX.js → DemoFlex-a8OhMMvq.js} +3 -3
  84. package/dist/demo/{DemoFlex-EtVq8QfX.js.map → DemoFlex-a8OhMMvq.js.map} +1 -1
  85. package/dist/demo/{DemoHeading-BS-vGfkI.js → DemoHeading-C13OVDfS.js} +3 -3
  86. package/dist/demo/{DemoHeading-BS-vGfkI.js.map → DemoHeading-C13OVDfS.js.map} +1 -1
  87. package/dist/demo/{DemoHome-Clbn8AmS.js → DemoHome-D_De3UiT.js} +2 -2
  88. package/dist/demo/{DemoHome-Clbn8AmS.js.map → DemoHome-D_De3UiT.js.map} +1 -1
  89. package/dist/demo/{DemoJsonViewer-DkIX_ky2.js → DemoJsonViewer-B50s9aGM.js} +3 -3
  90. package/dist/demo/{DemoJsonViewer-DkIX_ky2.js.map → DemoJsonViewer-B50s9aGM.js.map} +1 -1
  91. package/dist/demo/{DemoLayout-C56xb5EE.js → DemoLayout-CHU8WTwO.js} +14 -5
  92. package/dist/demo/DemoLayout-CHU8WTwO.js.map +1 -0
  93. package/dist/demo/{DemoLogin-BZwpicOS.js → DemoLogin-BBlrWpml.js} +49 -32
  94. package/dist/demo/DemoLogin-BBlrWpml.js.map +1 -0
  95. package/dist/demo/{DemoRegister-C7_qc4MJ.js → DemoRegister-BuNE3_-f.js} +49 -50
  96. package/dist/demo/DemoRegister-BuNE3_-f.js.map +1 -0
  97. package/dist/demo/{DemoResetPassword-BI1Ct4Dw.js → DemoResetPassword-D_IjjjOJ.js} +12 -16
  98. package/dist/demo/DemoResetPassword-D_IjjjOJ.js.map +1 -0
  99. package/dist/demo/{DemoSidebar-CcBo4ltC.js → DemoSidebar-Giy2HRBD.js} +3 -3
  100. package/dist/demo/{DemoSidebar-CcBo4ltC.js.map → DemoSidebar-Giy2HRBD.js.map} +1 -1
  101. package/dist/demo/{DemoText-CzXuUn3g.js → DemoText-ubcw-vog.js} +3 -3
  102. package/dist/demo/{DemoText-CzXuUn3g.js.map → DemoText-ubcw-vog.js.map} +1 -1
  103. package/dist/demo/{DemoToast-BgHDhWrX.js → DemoToast-9die_dYT.js} +2 -2
  104. package/dist/demo/{DemoToast-BgHDhWrX.js.map → DemoToast-9die_dYT.js.map} +1 -1
  105. package/dist/demo/{DemoTypeForm-DDzWoMSV.js → DemoTypeForm-D_d6OVKL.js} +8 -4
  106. package/dist/demo/DemoTypeForm-D_d6OVKL.js.map +1 -0
  107. package/dist/demo/DemoVerifyEmail-B43KlF4F.js +34 -0
  108. package/dist/demo/DemoVerifyEmail-B43KlF4F.js.map +1 -0
  109. package/dist/demo/Login-C12N4oGs.js +275 -0
  110. package/dist/demo/Login-C12N4oGs.js.map +1 -0
  111. package/dist/demo/{Profile-CWqti7FB.js → Profile-DS5q4vOh.js} +31 -27
  112. package/dist/demo/Profile-DS5q4vOh.js.map +1 -0
  113. package/dist/demo/{Register-a70LPgs2.js → Register-B4hLBeEv.js} +198 -142
  114. package/dist/demo/Register-B4hLBeEv.js.map +1 -0
  115. package/dist/{auth/ResetPassword-CqfTk1FI.js → demo/ResetPassword-D8g9ha1N.js} +7 -7
  116. package/dist/demo/ResetPassword-D8g9ha1N.js.map +1 -0
  117. package/dist/demo/{Showcase-Dq3MISpd.js → Showcase-D6Fxt4X4.js} +64 -65
  118. package/dist/demo/Showcase-D6Fxt4X4.js.map +1 -0
  119. package/dist/{auth/VerifyEmail-nWiSTMjF.js → demo/VerifyEmail-BjDo0cZA.js} +23 -8
  120. package/dist/demo/VerifyEmail-BjDo0cZA.js.map +1 -0
  121. package/dist/demo/{auth-d6n3xbug.js → auth-ByVTreDl.js} +8 -8
  122. package/dist/demo/{auth-d6n3xbug.js.map → auth-ByVTreDl.js.map} +1 -1
  123. package/dist/demo/{core-RCUw1Q-a.js → core-DFgB3yU4.js} +2182 -756
  124. package/dist/demo/core-DFgB3yU4.js.map +1 -0
  125. package/dist/demo/index.d.ts +1 -0
  126. package/dist/demo/index.d.ts.map +1 -1
  127. package/dist/demo/index.js +24 -18
  128. package/dist/demo/index.js.map +1 -1
  129. package/package.json +7 -7
  130. package/src/admin/{AdminRouter.ts → AdminRouter.tsx} +150 -18
  131. package/src/admin/components/AdminDashboard.tsx +52 -0
  132. package/src/admin/components/AdminLayout.tsx +32 -40
  133. package/src/admin/components/audits/AdminAudits.tsx +22 -16
  134. package/src/admin/components/files/AdminFiles.tsx +1 -6
  135. package/src/admin/components/jobs/AdminJobExecutions.tsx +33 -39
  136. package/src/admin/components/jobs/AdminJobRegistry.tsx +9 -18
  137. package/src/admin/components/keys/AdminApiKeys.tsx +23 -41
  138. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  139. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  140. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  141. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  142. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  143. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  144. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  145. package/src/admin/components/sessions/AdminSessions.tsx +71 -71
  146. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  147. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  148. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  149. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  150. package/src/admin/components/users/AdminUserSessions.tsx +33 -31
  151. package/src/admin/components/users/AdminUsers.tsx +184 -72
  152. package/src/admin/index.ts +2 -2
  153. package/src/admin/primitives/$uiAdmin.ts +1 -1
  154. package/src/auth/components/Login.tsx +188 -121
  155. package/src/auth/components/Profile.tsx +1 -22
  156. package/src/auth/components/ProfileField.tsx +39 -0
  157. package/src/auth/components/Register.tsx +215 -158
  158. package/src/auth/components/ResetPassword.tsx +7 -11
  159. package/src/auth/components/VerifyEmail.tsx +35 -10
  160. package/src/auth/components/buttons/UserButton.tsx +20 -24
  161. package/src/auth/index.ts +1 -0
  162. package/src/core/atoms/alephaSidebarAtom.ts +1 -1
  163. package/src/core/atoms/alephaThemeListAtom.ts +14 -1
  164. package/src/core/atoms/alephaThemeOverridesAtom.ts +17 -0
  165. package/src/core/atoms/themes/editorial.ts +184 -0
  166. package/src/core/atoms/themes/monochrome.ts +197 -0
  167. package/src/core/atoms/themes/rosePine.ts +208 -0
  168. package/src/core/atoms/themes/softBrutalism.ts +221 -0
  169. package/src/core/atoms/themes/terminal.ts +186 -0
  170. package/src/core/components/Flex.tsx +101 -1
  171. package/src/core/components/Text.tsx +1 -1
  172. package/src/core/components/buttons/ActionButton.tsx +109 -87
  173. package/src/core/components/buttons/DarkModeButton.tsx +3 -3
  174. package/src/core/components/buttons/LanguageButton.tsx +1 -1
  175. package/src/core/components/buttons/OmnibarButton.tsx +1 -2
  176. package/src/core/components/buttons/ThemeButton.tsx +40 -11
  177. package/src/core/components/buttons/ThemeExpertModal.tsx +184 -0
  178. package/src/core/components/buttons/ToggleSidebarButton.tsx +1 -2
  179. package/src/core/components/data/DetailDrawer.tsx +102 -96
  180. package/src/core/components/data/DetailList.tsx +2 -1
  181. package/src/core/components/layout/AppBar.tsx +10 -0
  182. package/src/core/components/layout/Breadcrumb.tsx +3 -6
  183. package/src/core/components/layout/DashboardShell.tsx +28 -11
  184. package/src/core/components/layout/Sidebar.tsx +18 -235
  185. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  186. package/src/core/components/layout/SidebarItem.tsx +146 -0
  187. package/src/core/components/layout/index.ts +3 -1
  188. package/src/core/constants/ui.ts +5 -5
  189. package/src/core/form/components/Control.tsx +31 -29
  190. package/src/core/form/components/ControlArray.tsx +13 -39
  191. package/src/core/form/components/ControlDate.tsx +10 -21
  192. package/src/core/form/components/ControlNumber.tsx +4 -33
  193. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  194. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  195. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  196. package/src/core/form/components/ControlSelect.tsx +294 -92
  197. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  198. package/src/core/form/components/TypeForm.tsx +5 -2
  199. package/src/core/form/index.ts +8 -1
  200. package/src/core/form/utils/parseInput.ts +7 -3
  201. package/src/core/hooks/useTheme.ts +26 -3
  202. package/src/core/index.ts +9 -2
  203. package/src/core/interfaces/AlephaTheme.ts +2 -0
  204. package/src/core/json/components/JsonViewer.tsx +103 -319
  205. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  206. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  207. package/src/core/json/components/JsonViewerShared.ts +76 -0
  208. package/src/core/providers/ThemeProvider.ts +108 -8
  209. package/src/core/services/DialogService.tsx +24 -3
  210. package/src/core/styles.css +33 -20
  211. package/src/core/table/components/ColumnPicker.tsx +3 -3
  212. package/src/core/table/components/DataTable.tsx +233 -143
  213. package/src/core/table/components/DataTableFilters.tsx +6 -16
  214. package/src/core/table/components/DataTablePagination.tsx +58 -29
  215. package/src/core/table/components/DataTableToolbar.tsx +16 -7
  216. package/src/core/table/components/FilterPicker.tsx +3 -3
  217. package/src/core/table/index.ts +1 -0
  218. package/src/core/table/interfaces/types.ts +42 -9
  219. package/src/core/utils/icons.tsx +2 -2
  220. package/src/demo/DemoRouter.ts +8 -1
  221. package/src/demo/components/DemoLayout.tsx +12 -2
  222. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  223. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  224. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  225. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  226. package/src/demo/components/core/DemoButton.tsx +123 -103
  227. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  228. package/src/demo/components/core/DemoDataTable.tsx +255 -241
  229. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  230. package/src/demo/components/shared/MacWindow.tsx +5 -11
  231. package/src/demo/components/shared/Showcase.tsx +28 -42
  232. package/dist/admin/AdminApiKeys-C-6_Q-lH.js.map +0 -1
  233. package/dist/admin/AdminAudits-Bgbf04hO.js.map +0 -1
  234. package/dist/admin/AdminFiles-B9a7G3cY.js.map +0 -1
  235. package/dist/admin/AdminJobExecutions-B9cek5dl.js.map +0 -1
  236. package/dist/admin/AdminJobRegistry-DFgV3oqx.js.map +0 -1
  237. package/dist/admin/AdminLayout-DHsvWxVB.js +0 -70
  238. package/dist/admin/AdminLayout-DHsvWxVB.js.map +0 -1
  239. package/dist/admin/AdminParameters-DHw9ATgl.js.map +0 -1
  240. package/dist/admin/AdminSessions-BhGJPI3z.js.map +0 -1
  241. package/dist/admin/AdminUserLayout-BdC4Te8m.js.map +0 -1
  242. package/dist/admin/AdminUserSessions-1uzcx02z.js.map +0 -1
  243. package/dist/admin/AdminUsers-C85c3eiQ.js +0 -121
  244. package/dist/admin/AdminUsers-C85c3eiQ.js.map +0 -1
  245. package/dist/admin/Login-BGheURrg.js +0 -219
  246. package/dist/admin/Login-BGheURrg.js.map +0 -1
  247. package/dist/admin/Profile-B-c9pCPf.js.map +0 -1
  248. package/dist/admin/Register-Cs10l8vX.js.map +0 -1
  249. package/dist/admin/ResetPassword-BwDdfkGH.js.map +0 -1
  250. package/dist/admin/VerifyEmail-DfXHAiQl.js.map +0 -1
  251. package/dist/admin/auth-Dr0Cf8I7.js +0 -319
  252. package/dist/admin/auth-Dr0Cf8I7.js.map +0 -1
  253. package/dist/admin/core-2xoLiT0o.js.map +0 -1
  254. package/dist/auth/Login-Denw_UGy.js +0 -219
  255. package/dist/auth/Login-Denw_UGy.js.map +0 -1
  256. package/dist/auth/Profile-BMX_Ar_s.js.map +0 -1
  257. package/dist/auth/Register-6hi_cpfF.js.map +0 -1
  258. package/dist/auth/ResetPassword-CqfTk1FI.js.map +0 -1
  259. package/dist/auth/VerifyEmail-nWiSTMjF.js.map +0 -1
  260. package/dist/auth/core-niW0sFLv.js.map +0 -1
  261. package/dist/demo/DemoButton-BmaWZVwf.js +0 -178
  262. package/dist/demo/DemoButton-BmaWZVwf.js.map +0 -1
  263. package/dist/demo/DemoDataTable-Z9xyV221.js +0 -362
  264. package/dist/demo/DemoDataTable-Z9xyV221.js.map +0 -1
  265. package/dist/demo/DemoLayout-C56xb5EE.js.map +0 -1
  266. package/dist/demo/DemoLogin-BZwpicOS.js.map +0 -1
  267. package/dist/demo/DemoRegister-C7_qc4MJ.js.map +0 -1
  268. package/dist/demo/DemoResetPassword-BI1Ct4Dw.js.map +0 -1
  269. package/dist/demo/DemoTypeForm-DDzWoMSV.js.map +0 -1
  270. package/dist/demo/DemoVerifyEmail-C_Irdnov.js +0 -30
  271. package/dist/demo/DemoVerifyEmail-C_Irdnov.js.map +0 -1
  272. package/dist/demo/Login-hSOU3jZc.js +0 -219
  273. package/dist/demo/Login-hSOU3jZc.js.map +0 -1
  274. package/dist/demo/Profile-CWqti7FB.js.map +0 -1
  275. package/dist/demo/Register-a70LPgs2.js.map +0 -1
  276. package/dist/demo/ResetPassword-DWN0lzr5.js.map +0 -1
  277. package/dist/demo/Showcase-Dq3MISpd.js.map +0 -1
  278. package/dist/demo/VerifyEmail-DZWL72K4.js.map +0 -1
  279. package/dist/demo/core-RCUw1Q-a.js.map +0 -1
  280. package/src/demo/styles.css +0 -0
@@ -1,14 +1,14 @@
1
1
  import { $atom, $context, $inject, $module, Alepha, AlephaError, TypeBoxError, t } from "alepha";
2
- import { AlephaReactForm, FormValidationError, useForm, useFormState } from "alepha/react/form";
3
- import { $head, AlephaReactHead } from "alepha/react/head";
2
+ import { AlephaReactForm, FormValidationError, useFieldValue, useForm, useFormState } from "alepha/react/form";
3
+ import { $head, AlephaReactHead, BrowserHeadProvider } 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, ColorInput, ColorSchemeScript, ColorSwatch, 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, SimpleGrid, Slider, Switch, Table, Tabs, TagsInput, Text as Text$1, TextInput, Textarea, Tooltip, Tree, UnstyledButton, getTreeExpandedState, useMantineColorScheme, useMantineTheme, useTree } from "@mantine/core";
6
7
  import { ModalsProvider, modals } from "@mantine/modals";
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
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Children, Fragment as Fragment$1, createElement, forwardRef, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
10
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";
11
+ import { IconAlertTriangle, IconArrowDown, IconArrowLeft, IconArrowUp, IconArrowsSort, IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClipboard, IconClock, IconColorPicker, IconColumns, IconCopy, IconDotsVertical, 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";
@@ -32,7 +32,7 @@ const alephaSidebarAtom = $atom({
32
32
  closed: true,
33
33
  collapsed: false,
34
34
  expandedWidth: 300,
35
- collapsedWidth: 78
35
+ collapsedWidth: 72
36
36
  }
37
37
  });
38
38
 
@@ -44,6 +44,20 @@ const alephaThemeAtom = $atom({
44
44
  default: { index: 0 }
45
45
  });
46
46
 
47
+ //#endregion
48
+ //#region ../../src/core/atoms/alephaThemeOverridesAtom.ts
49
+ const alephaThemeOverridesAtom = $atom({
50
+ name: "alepha.ui.themeOverrides",
51
+ schema: t.object({
52
+ primaryColor: t.optional(t.text()),
53
+ radius: t.optional(t.text()),
54
+ fontFamily: t.optional(t.text()),
55
+ fontSize: t.optional(t.text()),
56
+ scale: t.optional(t.text())
57
+ }),
58
+ default: {}
59
+ });
60
+
47
61
  //#endregion
48
62
  //#region ../../src/core/atoms/themes/default.ts
49
63
  const defaultTheme = {
@@ -51,6 +65,161 @@ const defaultTheme = {
51
65
  description: "Default Alepha Theme"
52
66
  };
53
67
 
68
+ //#endregion
69
+ //#region ../../src/core/atoms/themes/editorial.ts
70
+ /**
71
+ * Editorial theme.
72
+ *
73
+ * Serif typography, high contrast black and white, thin borders, generous whitespace.
74
+ * Newspaper/magazine aesthetic — elegant restraint.
75
+ */
76
+ const editorialTheme = {
77
+ name: "Editorial",
78
+ description: "Serif typography with newspaper elegance",
79
+ defaultColorScheme: "light",
80
+ head: { link: [
81
+ {
82
+ rel: "preconnect",
83
+ href: "https://fonts.googleapis.com"
84
+ },
85
+ {
86
+ rel: "preconnect",
87
+ href: "https://fonts.gstatic.com",
88
+ crossorigin: ""
89
+ },
90
+ {
91
+ rel: "stylesheet",
92
+ href: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700;800&family=Source+Serif+4:ital,wght@0,300;0,400;0,600;1,300;1,400&display=swap"
93
+ }
94
+ ] },
95
+ primaryColor: "ink",
96
+ primaryShade: {
97
+ light: 7,
98
+ dark: 3
99
+ },
100
+ autoContrast: true,
101
+ fontFamily: "\"Source Serif 4\", \"Georgia\", \"Times New Roman\", serif",
102
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
103
+ headings: {
104
+ fontFamily: "\"Playfair Display\", \"Georgia\", \"Times New Roman\", serif",
105
+ fontWeight: "700",
106
+ textWrap: "wrap",
107
+ sizes: {
108
+ h1: {
109
+ fontSize: "2.5rem",
110
+ lineHeight: "1.15"
111
+ },
112
+ h2: {
113
+ fontSize: "1.75rem",
114
+ lineHeight: "1.2"
115
+ },
116
+ h3: {
117
+ fontSize: "1.375rem",
118
+ lineHeight: "1.3"
119
+ },
120
+ h4: {
121
+ fontSize: "1.125rem",
122
+ lineHeight: "1.4"
123
+ },
124
+ h5: {
125
+ fontSize: "1rem",
126
+ lineHeight: "1.5"
127
+ },
128
+ h6: {
129
+ fontSize: "0.875rem",
130
+ lineHeight: "1.5"
131
+ }
132
+ }
133
+ },
134
+ defaultRadius: "sm",
135
+ radius: {
136
+ xs: "2px",
137
+ sm: "3px",
138
+ md: "4px",
139
+ lg: "6px",
140
+ xl: "8px"
141
+ },
142
+ shadows: {
143
+ xs: "0 1px 2px rgba(0, 0, 0, 0.06)",
144
+ sm: "0 1px 3px rgba(0, 0, 0, 0.08)",
145
+ md: "0 2px 6px rgba(0, 0, 0, 0.08)",
146
+ lg: "0 4px 12px rgba(0, 0, 0, 0.1)",
147
+ xl: "0 8px 24px rgba(0, 0, 0, 0.1)"
148
+ },
149
+ colors: {
150
+ ink: [
151
+ "#f5f3f0",
152
+ "#e8e4de",
153
+ "#d4cec5",
154
+ "#b5ad9f",
155
+ "#8c8272",
156
+ "#6b6050",
157
+ "#4a4035",
158
+ "#332b22",
159
+ "#1f1812",
160
+ "#0d0a07"
161
+ ],
162
+ burgundy: [
163
+ "#faf0f0",
164
+ "#f0d4d4",
165
+ "#e0adad",
166
+ "#cc8585",
167
+ "#b35e5e",
168
+ "#944545",
169
+ "#763636",
170
+ "#5a2828",
171
+ "#3d1b1b",
172
+ "#220f0f"
173
+ ],
174
+ gray: [
175
+ "#faf9f7",
176
+ "#f0eee9",
177
+ "#e0dcd5",
178
+ "#c8c2b8",
179
+ "#a8a194",
180
+ "#8a8273",
181
+ "#6b6456",
182
+ "#504a3f",
183
+ "#36322b",
184
+ "#1e1b17"
185
+ ],
186
+ dark: [
187
+ "#d5d2cd",
188
+ "#aba59c",
189
+ "#817a6e",
190
+ "#5e584e",
191
+ "#46413a",
192
+ "#36322c",
193
+ "#2a2721",
194
+ "#201d19",
195
+ "#171411",
196
+ "#0d0b09"
197
+ ]
198
+ },
199
+ components: {
200
+ Button: Button.extend({
201
+ defaultProps: { fw: 600 },
202
+ styles: { root: { letterSpacing: "0.02em" } }
203
+ }),
204
+ ActionIcon: ActionIcon.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
205
+ Paper: Paper.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
206
+ Card: Card.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
207
+ TextInput: TextInput.extend({ styles: { input: { border: "1px solid var(--mantine-color-default-border)" } } }),
208
+ Badge: Badge.extend({
209
+ defaultProps: {
210
+ fw: 600,
211
+ variant: "outline"
212
+ },
213
+ styles: { root: {
214
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif",
215
+ letterSpacing: "0.04em",
216
+ textTransform: "uppercase",
217
+ fontSize: "0.65rem"
218
+ } }
219
+ })
220
+ }
221
+ };
222
+
54
223
  //#endregion
55
224
  //#region ../../src/core/atoms/themes/midnight.ts
56
225
  const midnightTheme = {
@@ -166,41 +335,793 @@ const midnightTheme = {
166
335
  }
167
336
  };
168
337
 
338
+ //#endregion
339
+ //#region ../../src/core/atoms/themes/monochrome.ts
340
+ /**
341
+ * Monochrome theme.
342
+ *
343
+ * Pure black and white. No color. Bold typography does all the heavy lifting.
344
+ * A design-school statement piece — minimalist color, maximalist type.
345
+ */
346
+ const monochromeTheme = {
347
+ name: "Monochrome",
348
+ description: "Pure black and white — zero color, maximum typography",
349
+ primaryColor: "mono",
350
+ primaryShade: {
351
+ light: 8,
352
+ dark: 1
353
+ },
354
+ autoContrast: true,
355
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
356
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
357
+ headings: {
358
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
359
+ fontWeight: "800",
360
+ textWrap: "wrap",
361
+ sizes: {
362
+ h1: {
363
+ fontSize: "2.25rem",
364
+ lineHeight: "1.15"
365
+ },
366
+ h2: {
367
+ fontSize: "1.625rem",
368
+ lineHeight: "1.25"
369
+ },
370
+ h3: {
371
+ fontSize: "1.25rem",
372
+ lineHeight: "1.35"
373
+ },
374
+ h4: {
375
+ fontSize: "1.0625rem",
376
+ lineHeight: "1.45"
377
+ },
378
+ h5: {
379
+ fontSize: "0.9375rem",
380
+ lineHeight: "1.5"
381
+ },
382
+ h6: {
383
+ fontSize: "0.8125rem",
384
+ lineHeight: "1.5"
385
+ }
386
+ }
387
+ },
388
+ defaultRadius: "0",
389
+ radius: {
390
+ xs: "0",
391
+ sm: "0",
392
+ md: "0",
393
+ lg: "0",
394
+ xl: "2px"
395
+ },
396
+ shadows: {
397
+ xs: "0 1px 2px rgba(0, 0, 0, 0.08)",
398
+ sm: "0 1px 4px rgba(0, 0, 0, 0.1)",
399
+ md: "0 2px 8px rgba(0, 0, 0, 0.12)",
400
+ lg: "0 4px 16px rgba(0, 0, 0, 0.14)",
401
+ xl: "0 8px 32px rgba(0, 0, 0, 0.16)"
402
+ },
403
+ colors: {
404
+ mono: [
405
+ "#f5f5f5",
406
+ "#e0e0e0",
407
+ "#c0c0c0",
408
+ "#a0a0a0",
409
+ "#808080",
410
+ "#606060",
411
+ "#404040",
412
+ "#282828",
413
+ "#141414",
414
+ "#000000"
415
+ ],
416
+ gray: [
417
+ "#f5f5f5",
418
+ "#e5e5e5",
419
+ "#cccccc",
420
+ "#b0b0b0",
421
+ "#909090",
422
+ "#707070",
423
+ "#555555",
424
+ "#3a3a3a",
425
+ "#252525",
426
+ "#121212"
427
+ ],
428
+ blue: [
429
+ "#f5f5f5",
430
+ "#e0e0e0",
431
+ "#c0c0c0",
432
+ "#a0a0a0",
433
+ "#808080",
434
+ "#606060",
435
+ "#404040",
436
+ "#282828",
437
+ "#141414",
438
+ "#000000"
439
+ ],
440
+ green: [
441
+ "#f5f5f5",
442
+ "#e0e0e0",
443
+ "#c0c0c0",
444
+ "#a0a0a0",
445
+ "#808080",
446
+ "#606060",
447
+ "#404040",
448
+ "#282828",
449
+ "#141414",
450
+ "#000000"
451
+ ],
452
+ red: [
453
+ "#f5f5f5",
454
+ "#e0e0e0",
455
+ "#c0c0c0",
456
+ "#a0a0a0",
457
+ "#808080",
458
+ "#606060",
459
+ "#404040",
460
+ "#282828",
461
+ "#141414",
462
+ "#000000"
463
+ ],
464
+ dark: [
465
+ "#d0d0d0",
466
+ "#a0a0a0",
467
+ "#707070",
468
+ "#505050",
469
+ "#383838",
470
+ "#282828",
471
+ "#1c1c1c",
472
+ "#141414",
473
+ "#0a0a0a",
474
+ "#000000"
475
+ ]
476
+ },
477
+ components: {
478
+ Button: Button.extend({
479
+ defaultProps: { fw: 700 },
480
+ styles: { root: {
481
+ border: "2px solid currentColor",
482
+ letterSpacing: "0.03em",
483
+ textTransform: "uppercase",
484
+ fontSize: "0.8125rem"
485
+ } }
486
+ }),
487
+ ActionIcon: ActionIcon.extend({ styles: { root: { border: "2px solid currentColor" } } }),
488
+ Paper: Paper.extend({ styles: { root: { border: "2px solid var(--mantine-color-default-border)" } } }),
489
+ Card: Card.extend({ styles: { root: { border: "2px solid var(--mantine-color-default-border)" } } }),
490
+ TextInput: TextInput.extend({ styles: { input: { border: "2px solid var(--mantine-color-default-border)" } } }),
491
+ Badge: Badge.extend({
492
+ defaultProps: {
493
+ fw: 700,
494
+ variant: "outline"
495
+ },
496
+ styles: { root: {
497
+ textTransform: "uppercase",
498
+ letterSpacing: "0.06em",
499
+ fontSize: "0.65rem",
500
+ border: "2px solid currentColor"
501
+ } }
502
+ })
503
+ }
504
+ };
505
+
506
+ //#endregion
507
+ //#region ../../src/core/atoms/themes/rosePine.ts
508
+ /**
509
+ * Rosé Pine theme.
510
+ *
511
+ * Muted pinks, golds, and subtle greens on warm dark backgrounds.
512
+ * Cozy, low-contrast, easy on the eyes.
513
+ * Based on the Rosé Pine color philosophy.
514
+ */
515
+ const rosePineTheme = {
516
+ name: "Rosé Pine",
517
+ description: "Muted pinks and golds on warm dark backgrounds",
518
+ defaultColorScheme: "dark",
519
+ primaryColor: "rose",
520
+ primaryShade: {
521
+ light: 5,
522
+ dark: 4
523
+ },
524
+ autoContrast: true,
525
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
526
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
527
+ headings: {
528
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
529
+ fontWeight: "600",
530
+ textWrap: "wrap",
531
+ sizes: {
532
+ h1: {
533
+ fontSize: "2rem",
534
+ lineHeight: "1.25"
535
+ },
536
+ h2: {
537
+ fontSize: "1.5rem",
538
+ lineHeight: "1.3"
539
+ },
540
+ h3: {
541
+ fontSize: "1.25rem",
542
+ lineHeight: "1.4"
543
+ },
544
+ h4: {
545
+ fontSize: "1rem",
546
+ lineHeight: "1.5"
547
+ },
548
+ h5: {
549
+ fontSize: "0.875rem",
550
+ lineHeight: "1.5"
551
+ },
552
+ h6: {
553
+ fontSize: "0.75rem",
554
+ lineHeight: "1.5"
555
+ }
556
+ }
557
+ },
558
+ defaultRadius: "md",
559
+ radius: {
560
+ xs: "4px",
561
+ sm: "6px",
562
+ md: "8px",
563
+ lg: "12px",
564
+ xl: "16px"
565
+ },
566
+ shadows: {
567
+ xs: "0 1px 3px rgba(0, 0, 0, 0.2)",
568
+ sm: "0 2px 6px rgba(0, 0, 0, 0.2)",
569
+ md: "0 4px 12px rgba(0, 0, 0, 0.25)",
570
+ lg: "0 8px 24px rgba(0, 0, 0, 0.3)",
571
+ xl: "0 12px 36px rgba(0, 0, 0, 0.35)"
572
+ },
573
+ colors: {
574
+ rose: [
575
+ "#faf0f4",
576
+ "#f2d8e3",
577
+ "#eabdd0",
578
+ "#e0a0bb",
579
+ "#d4849f",
580
+ "#c4748f",
581
+ "#b06282",
582
+ "#9a5275",
583
+ "#7a3f5e",
584
+ "#5c2e47"
585
+ ],
586
+ gold: [
587
+ "#fdf8ec",
588
+ "#f8ecc8",
589
+ "#f2dda0",
590
+ "#eacb72",
591
+ "#e0b94d",
592
+ "#c9a33e",
593
+ "#a98830",
594
+ "#866b24",
595
+ "#634f1a",
596
+ "#403310"
597
+ ],
598
+ pine: [
599
+ "#ecf5f0",
600
+ "#d0e6da",
601
+ "#add4be",
602
+ "#86c0a0",
603
+ "#62ac84",
604
+ "#4e9670",
605
+ "#3e7a5a",
606
+ "#2f5e44",
607
+ "#20412f",
608
+ "#12251b"
609
+ ],
610
+ foam: [
611
+ "#edf6f7",
612
+ "#d2e9eb",
613
+ "#b0d9dd",
614
+ "#8bc6cc",
615
+ "#6ab3bb",
616
+ "#569da5",
617
+ "#438088",
618
+ "#33636a",
619
+ "#23454a",
620
+ "#14292c"
621
+ ],
622
+ red: [
623
+ "#f9eef0",
624
+ "#efd3d8",
625
+ "#e3b2bb",
626
+ "#d68e9b",
627
+ "#c86c7c",
628
+ "#b25566",
629
+ "#944454",
630
+ "#733442",
631
+ "#52252f",
632
+ "#33161d"
633
+ ],
634
+ gray: [
635
+ "#f4f0f2",
636
+ "#e4dde1",
637
+ "#cec5cb",
638
+ "#b5aab2",
639
+ "#9a8e96",
640
+ "#7e737a",
641
+ "#635a60",
642
+ "#4a4248",
643
+ "#332d31",
644
+ "#1e1a1c"
645
+ ],
646
+ dark: [
647
+ "#e0d8e0",
648
+ "#b0a6b2",
649
+ "#817786",
650
+ "#615768",
651
+ "#4a3f54",
652
+ "#3a3044",
653
+ "#2a2436",
654
+ "#211e2e",
655
+ "#1a1724",
656
+ "#110f1a"
657
+ ]
658
+ },
659
+ components: {
660
+ Button: Button.extend({
661
+ defaultProps: { fw: 500 },
662
+ styles: { root: { transition: "background-color 0.15s ease, opacity 0.15s ease" } }
663
+ }),
664
+ ActionIcon: ActionIcon.extend({ styles: { root: { transition: "background-color 0.15s ease, opacity 0.15s ease" } } }),
665
+ Paper: Paper.extend({
666
+ defaultProps: { shadow: "sm" },
667
+ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } }
668
+ }),
669
+ Card: Card.extend({
670
+ defaultProps: { shadow: "sm" },
671
+ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } }
672
+ }),
673
+ TextInput: TextInput.extend({ styles: { input: { border: "1px solid var(--mantine-color-default-border)" } } }),
674
+ Badge: Badge.extend({ defaultProps: { fw: 500 } })
675
+ }
676
+ };
677
+
678
+ //#endregion
679
+ //#region ../../src/core/atoms/themes/softBrutalism.ts
680
+ /**
681
+ * Soft Brutalism theme.
682
+ *
683
+ * Pastel pop palette with solid offset shadows, rounded corners, and bold borders.
684
+ * A friendlier take on neubrutalism — playful but production-ready.
685
+ */
686
+ const softBrutalismTheme = {
687
+ name: "Soft Brutalism",
688
+ description: "Pastel pop with bold borders and offset shadows",
689
+ head: { link: [
690
+ {
691
+ rel: "preconnect",
692
+ href: "https://fonts.googleapis.com"
693
+ },
694
+ {
695
+ rel: "preconnect",
696
+ href: "https://fonts.gstatic.com",
697
+ crossorigin: ""
698
+ },
699
+ {
700
+ rel: "stylesheet",
701
+ href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
702
+ }
703
+ ] },
704
+ primaryColor: "lavender",
705
+ primaryShade: {
706
+ light: 5,
707
+ dark: 7
708
+ },
709
+ autoContrast: true,
710
+ cursorType: "pointer",
711
+ fontFamily: "Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
712
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
713
+ headings: {
714
+ fontFamily: "Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
715
+ fontWeight: "700",
716
+ textWrap: "wrap",
717
+ sizes: {
718
+ h1: {
719
+ fontSize: "2rem",
720
+ lineHeight: "1.25"
721
+ },
722
+ h2: {
723
+ fontSize: "1.5rem",
724
+ lineHeight: "1.3"
725
+ },
726
+ h3: {
727
+ fontSize: "1.25rem",
728
+ lineHeight: "1.4"
729
+ },
730
+ h4: {
731
+ fontSize: "1rem",
732
+ lineHeight: "1.5"
733
+ },
734
+ h5: {
735
+ fontSize: "0.875rem",
736
+ lineHeight: "1.5"
737
+ },
738
+ h6: {
739
+ fontSize: "0.75rem",
740
+ lineHeight: "1.5"
741
+ }
742
+ }
743
+ },
744
+ defaultRadius: "md",
745
+ radius: {
746
+ xs: "6px",
747
+ sm: "8px",
748
+ md: "12px",
749
+ lg: "16px",
750
+ xl: "24px"
751
+ },
752
+ shadows: {
753
+ xs: "2px 2px 0 0 rgba(100, 80, 140, 0.15)",
754
+ sm: "3px 3px 0 0 rgba(100, 80, 140, 0.2)",
755
+ md: "4px 4px 0 0 rgba(100, 80, 140, 0.2)",
756
+ lg: "6px 6px 0 0 rgba(100, 80, 140, 0.25)",
757
+ xl: "8px 8px 0 0 rgba(100, 80, 140, 0.3)"
758
+ },
759
+ colors: {
760
+ lavender: [
761
+ "#f3f0fa",
762
+ "#e4dcf4",
763
+ "#d1c4e9",
764
+ "#b4a7d6",
765
+ "#9a8bc4",
766
+ "#7f6cb0",
767
+ "#6a549e",
768
+ "#543f87",
769
+ "#3d2d6b",
770
+ "#2a1d52"
771
+ ],
772
+ peach: [
773
+ "#fef3ec",
774
+ "#fce4d0",
775
+ "#f9d0ae",
776
+ "#f4b886",
777
+ "#f4a261",
778
+ "#e68a42",
779
+ "#c67234",
780
+ "#a35a28",
781
+ "#6b3a1a",
782
+ "#4a2710"
783
+ ],
784
+ mint: [
785
+ "#ecfaf0",
786
+ "#d4f2dc",
787
+ "#b3e8c2",
788
+ "#8edba4",
789
+ "#81c995",
790
+ "#5ab874",
791
+ "#42a05c",
792
+ "#2e8548",
793
+ "#1a5c2e",
794
+ "#0f3f1e"
795
+ ],
796
+ coral: [
797
+ "#fef0ef",
798
+ "#fcd9d7",
799
+ "#f8b8b4",
800
+ "#f29490",
801
+ "#e97171",
802
+ "#d65454",
803
+ "#b83e3e",
804
+ "#962d2d",
805
+ "#6b1f1f",
806
+ "#4a1414"
807
+ ],
808
+ gray: [
809
+ "#faf8f6",
810
+ "#f0ece8",
811
+ "#ddd7d0",
812
+ "#c4bbb2",
813
+ "#a89e95",
814
+ "#8c8279",
815
+ "#6e655d",
816
+ "#524b44",
817
+ "#3a342f",
818
+ "#24211e"
819
+ ],
820
+ dark: [
821
+ "#d4d0dc",
822
+ "#a9a2b5",
823
+ "#7e7690",
824
+ "#5c546e",
825
+ "#443c56",
826
+ "#342d45",
827
+ "#2a2339",
828
+ "#1e1a2e",
829
+ "#161224",
830
+ "#0f0c1a"
831
+ ]
832
+ },
833
+ components: {
834
+ Button: Button.extend({
835
+ defaultProps: { fw: 600 },
836
+ styles: { root: {
837
+ border: "2px solid currentColor",
838
+ boxShadow: "3px 3px 0 0 rgba(100, 80, 140, 0.2)",
839
+ transition: "box-shadow 0.15s ease, transform 0.15s ease"
840
+ } }
841
+ }),
842
+ ActionIcon: ActionIcon.extend({ styles: { root: {
843
+ border: "2px solid currentColor",
844
+ boxShadow: "2px 2px 0 0 rgba(100, 80, 140, 0.15)"
845
+ } } }),
846
+ Paper: Paper.extend({
847
+ defaultProps: { shadow: "sm" },
848
+ styles: { root: { border: "2px solid var(--mantine-color-default-border)" } }
849
+ }),
850
+ Card: Card.extend({
851
+ defaultProps: { shadow: "sm" },
852
+ styles: { root: { border: "2px solid var(--mantine-color-default-border)" } }
853
+ }),
854
+ TextInput: TextInput.extend({ styles: { input: {
855
+ border: "2px solid var(--mantine-color-default-border)",
856
+ transition: "box-shadow 0.15s ease, border-color 0.15s ease"
857
+ } } }),
858
+ Badge: Badge.extend({
859
+ defaultProps: { fw: 600 },
860
+ styles: { root: { border: "2px solid currentColor" } }
861
+ })
862
+ }
863
+ };
864
+
865
+ //#endregion
866
+ //#region ../../src/core/atoms/themes/terminal.ts
867
+ /**
868
+ * Terminal theme.
869
+ *
870
+ * Monospace everything, green-on-black, zero radius.
871
+ * CRT/hacker aesthetic for developer tools and dashboards.
872
+ */
873
+ const terminalTheme = {
874
+ name: "Terminal",
875
+ description: "Green phosphor on black — monospace hacker aesthetic",
876
+ defaultColorScheme: "dark",
877
+ primaryColor: "terminal",
878
+ primaryShade: {
879
+ light: 5,
880
+ dark: 4
881
+ },
882
+ autoContrast: true,
883
+ fontFamily: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
884
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
885
+ headings: {
886
+ fontFamily: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
887
+ fontWeight: "700",
888
+ textWrap: "wrap",
889
+ sizes: {
890
+ h1: {
891
+ fontSize: "1.75rem",
892
+ lineHeight: "1.3"
893
+ },
894
+ h2: {
895
+ fontSize: "1.375rem",
896
+ lineHeight: "1.35"
897
+ },
898
+ h3: {
899
+ fontSize: "1.125rem",
900
+ lineHeight: "1.4"
901
+ },
902
+ h4: {
903
+ fontSize: "1rem",
904
+ lineHeight: "1.5"
905
+ },
906
+ h5: {
907
+ fontSize: "0.875rem",
908
+ lineHeight: "1.5"
909
+ },
910
+ h6: {
911
+ fontSize: "0.75rem",
912
+ lineHeight: "1.5"
913
+ }
914
+ }
915
+ },
916
+ defaultRadius: "0",
917
+ radius: {
918
+ xs: "0",
919
+ sm: "0",
920
+ md: "0",
921
+ lg: "2px",
922
+ xl: "4px"
923
+ },
924
+ shadows: {
925
+ xs: "none",
926
+ sm: "none",
927
+ md: "0 0 8px rgba(0, 255, 65, 0.08)",
928
+ lg: "0 0 16px rgba(0, 255, 65, 0.1)",
929
+ xl: "0 0 24px rgba(0, 255, 65, 0.12)"
930
+ },
931
+ colors: {
932
+ terminal: [
933
+ "#e6fff0",
934
+ "#b3ffd1",
935
+ "#80ffb3",
936
+ "#4dff94",
937
+ "#00ff41",
938
+ "#00d636",
939
+ "#00ad2b",
940
+ "#008521",
941
+ "#005c17",
942
+ "#00330d"
943
+ ],
944
+ amber: [
945
+ "#fff8e6",
946
+ "#ffecb3",
947
+ "#ffe080",
948
+ "#ffd54d",
949
+ "#ffca28",
950
+ "#d4a520",
951
+ "#aa8418",
952
+ "#806310",
953
+ "#554208",
954
+ "#2b2104"
955
+ ],
956
+ red: [
957
+ "#ffe6e6",
958
+ "#ffb3b3",
959
+ "#ff8080",
960
+ "#ff4d4d",
961
+ "#ff1a1a",
962
+ "#d41515",
963
+ "#aa1010",
964
+ "#800c0c",
965
+ "#550808",
966
+ "#2b0404"
967
+ ],
968
+ gray: [
969
+ "#e8eaed",
970
+ "#c8cdd3",
971
+ "#a4aab3",
972
+ "#808892",
973
+ "#5f6872",
974
+ "#474f58",
975
+ "#363c44",
976
+ "#282d33",
977
+ "#1c2026",
978
+ "#12151a"
979
+ ],
980
+ dark: [
981
+ "#c9cdd2",
982
+ "#8b9198",
983
+ "#5c636b",
984
+ "#3d444c",
985
+ "#2b3138",
986
+ "#1e242b",
987
+ "#151a20",
988
+ "#0e1216",
989
+ "#080c0f",
990
+ "#020303"
991
+ ]
992
+ },
993
+ components: {
994
+ Button: Button.extend({
995
+ defaultProps: { fw: 600 },
996
+ styles: { root: {
997
+ border: "1px solid currentColor",
998
+ textTransform: "uppercase",
999
+ letterSpacing: "0.05em",
1000
+ fontSize: "0.8125rem"
1001
+ } }
1002
+ }),
1003
+ ActionIcon: ActionIcon.extend({ styles: { root: { border: "1px solid currentColor" } } }),
1004
+ Paper: Paper.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
1005
+ Card: Card.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
1006
+ TextInput: TextInput.extend({ styles: { input: {
1007
+ border: "1px solid var(--mantine-color-default-border)",
1008
+ fontFamily: "inherit"
1009
+ } } }),
1010
+ Badge: Badge.extend({
1011
+ defaultProps: { fw: 600 },
1012
+ styles: { root: {
1013
+ border: "1px solid currentColor",
1014
+ textTransform: "uppercase",
1015
+ letterSpacing: "0.05em"
1016
+ } }
1017
+ })
1018
+ }
1019
+ };
1020
+
169
1021
  //#endregion
170
1022
  //#region ../../src/core/atoms/alephaThemeListAtom.ts
171
1023
  const alephaThemeListAtom = $atom({
172
1024
  name: "alepha.ui.themeList",
173
1025
  schema: t.array(t.json()),
174
- default: [defaultTheme, midnightTheme]
1026
+ default: [
1027
+ defaultTheme,
1028
+ midnightTheme,
1029
+ softBrutalismTheme,
1030
+ terminalTheme,
1031
+ editorialTheme,
1032
+ rosePineTheme,
1033
+ monochromeTheme
1034
+ ]
175
1035
  });
176
1036
 
177
1037
  //#endregion
178
1038
  //#region ../../src/core/providers/ThemeProvider.ts
179
- var ThemeProvider = class {
1039
+ var ThemeProvider = class ThemeProvider {
180
1040
  alepha = $inject(Alepha);
181
1041
  cookie = $cookie({
182
1042
  name: "theme",
183
1043
  schema: alephaThemeAtom.schema,
184
1044
  ttl: [1, "year"]
185
1045
  });
1046
+ overridesCookie = $cookie({
1047
+ name: "themeOverrides",
1048
+ schema: alephaThemeOverridesAtom.schema,
1049
+ ttl: [1, "year"]
1050
+ });
186
1051
  head = $head(() => {
187
1052
  const theme = this.getTheme();
188
1053
  if (!theme || !theme.name) return {};
189
- return { htmlAttributes: { "data-theme": theme.name } };
1054
+ return {
1055
+ htmlAttributes: { "data-theme": this.slugify(theme.name) },
1056
+ ...theme.head
1057
+ };
190
1058
  });
191
1059
  setTheme(index) {
192
- const newTheme = this.alepha.store.get(alephaThemeListAtom)[index];
193
- if (!newTheme) throw new AlephaError(`Theme with index ${index} not found`);
1060
+ if (!this.alepha.store.get(alephaThemeListAtom)[index]) throw new AlephaError(`Theme with index ${index} not found`);
194
1061
  this.cookie.set({ index });
195
1062
  this.alepha.store.set(alephaThemeAtom, { index });
196
- if (typeof document === "undefined") return;
197
- document.documentElement.removeAttribute("data-theme");
198
- if (newTheme.name) document.documentElement.setAttribute("data-theme", newTheme.name);
1063
+ if (!this.alepha.isBrowser()) return;
1064
+ this.alepha.inject(BrowserHeadProvider).refreshGlobalHead();
1065
+ }
1066
+ slugify(name) {
1067
+ return name.toLowerCase().replace(/\s+/g, "-");
199
1068
  }
1069
+ static FONT_SIZE_MULTIPLIERS = {
1070
+ xs: .85,
1071
+ sm: .925,
1072
+ md: 1,
1073
+ lg: 1.1,
1074
+ xl: 1.25
1075
+ };
1076
+ static SCALE_VALUES = {
1077
+ xs: .85,
1078
+ sm: .925,
1079
+ md: 1,
1080
+ lg: 1.1,
1081
+ xl: 1.25
1082
+ };
1083
+ static DEFAULT_FONT_SIZES = {
1084
+ xs: "0.75rem",
1085
+ sm: "0.875rem",
1086
+ md: "1rem",
1087
+ lg: "1.125rem",
1088
+ xl: "1.25rem"
1089
+ };
200
1090
  getTheme() {
201
1091
  const index = this.getThemeIndex();
202
1092
  const list = this.alepha.store.get(alephaThemeListAtom);
203
- return list[index] || list[0] || defaultTheme;
1093
+ const base = list[index] || list[0] || defaultTheme;
1094
+ const overrides = this.getThemeOverrides();
1095
+ if (!overrides.primaryColor && !overrides.radius && !overrides.fontFamily && !overrides.fontSize && !overrides.scale) return base;
1096
+ const merged = {
1097
+ ...base,
1098
+ ...overrides.primaryColor && { primaryColor: overrides.primaryColor },
1099
+ ...overrides.radius && { defaultRadius: overrides.radius },
1100
+ ...overrides.fontFamily && { fontFamily: overrides.fontFamily },
1101
+ ...overrides.scale && overrides.scale !== "md" && { scale: ThemeProvider.SCALE_VALUES[overrides.scale] ?? 1 }
1102
+ };
1103
+ if (overrides.fontSize && overrides.fontSize !== "md") {
1104
+ const multiplier = ThemeProvider.FONT_SIZE_MULTIPLIERS[overrides.fontSize] ?? 1;
1105
+ const baseSizes = base.fontSizes ?? ThemeProvider.DEFAULT_FONT_SIZES;
1106
+ merged.fontSizes = Object.fromEntries(Object.entries(baseSizes).map(([key, val]) => [key, `${(Number.parseFloat(String(val)) * multiplier).toFixed(4)}rem`]));
1107
+ }
1108
+ return merged;
1109
+ }
1110
+ setThemeOverrides(overrides) {
1111
+ this.overridesCookie.set(overrides);
1112
+ this.alepha.store.set(alephaThemeOverridesAtom, overrides);
1113
+ if (!this.alepha.isBrowser()) return;
1114
+ this.alepha.inject(BrowserHeadProvider).refreshGlobalHead();
1115
+ }
1116
+ getThemeOverrides() {
1117
+ try {
1118
+ return this.overridesCookie.get() ?? this.alepha.store.get(alephaThemeOverridesAtom) ?? {};
1119
+ } catch {
1120
+ return this.alepha.store.get(alephaThemeOverridesAtom) ?? {};
1121
+ }
1122
+ }
1123
+ resetThemeOverrides() {
1124
+ this.setThemeOverrides({});
204
1125
  }
205
1126
  getThemeIndex() {
206
1127
  try {
@@ -307,14 +1228,21 @@ var DialogService = class {
307
1228
  */
308
1229
  alert(options) {
309
1230
  return new Promise((resolve) => {
1231
+ let resolved = false;
1232
+ const done = () => {
1233
+ if (resolved) return;
1234
+ resolved = true;
1235
+ resolve();
1236
+ };
310
1237
  const modalId = this.open({
311
1238
  ...options,
312
1239
  title: options?.title || "Alert",
1240
+ onClose: done,
313
1241
  content: /* @__PURE__ */ jsx(AlertDialog, {
314
1242
  options,
315
1243
  onClose: () => {
316
1244
  this.close(modalId);
317
- resolve();
1245
+ done();
318
1246
  }
319
1247
  })
320
1248
  });
@@ -325,16 +1253,23 @@ var DialogService = class {
325
1253
  */
326
1254
  confirm(options) {
327
1255
  return new Promise((resolve) => {
1256
+ let resolved = false;
1257
+ const done = (confirmed) => {
1258
+ if (resolved) return;
1259
+ resolved = true;
1260
+ resolve(confirmed);
1261
+ };
328
1262
  const modalId = this.open({
329
1263
  ...options,
330
1264
  title: options?.title || "Confirm",
331
1265
  closeOnClickOutside: false,
332
1266
  closeOnEscape: false,
1267
+ onClose: () => done(false),
333
1268
  content: /* @__PURE__ */ jsx(ConfirmDialog, {
334
1269
  options,
335
1270
  onConfirm: (confirmed) => {
336
1271
  this.close(modalId);
337
- resolve(confirmed);
1272
+ done(confirmed);
338
1273
  }
339
1274
  })
340
1275
  });
@@ -345,16 +1280,23 @@ var DialogService = class {
345
1280
  */
346
1281
  prompt(options) {
347
1282
  return new Promise((resolve) => {
1283
+ let resolved = false;
1284
+ const done = (value) => {
1285
+ if (resolved) return;
1286
+ resolved = true;
1287
+ resolve(value);
1288
+ };
348
1289
  const modalId = this.open({
349
1290
  ...options,
350
1291
  title: options?.title || "Input",
351
1292
  closeOnClickOutside: false,
352
1293
  closeOnEscape: false,
1294
+ onClose: () => done(null),
353
1295
  content: /* @__PURE__ */ jsx(PromptDialog, {
354
1296
  options,
355
1297
  onSubmit: (value) => {
356
1298
  this.close(modalId);
357
- resolve(value);
1299
+ done(value);
358
1300
  }
359
1301
  })
360
1302
  });
@@ -458,20 +1400,34 @@ var UiRouter = class {
458
1400
  /**
459
1401
  * Hook to get and set the current theme.
460
1402
  *
461
- * Returns a tuple with the current theme and a function to set the theme.
1403
+ * Returns a tuple with the current theme, a function to set the theme,
1404
+ * and expert mode controls for fine-grained customization.
462
1405
  *
463
1406
  * ```tsx
464
- * const [theme, setTheme] = useTheme();
1407
+ * const [theme, setTheme, expert] = useTheme();
465
1408
  * ```
466
1409
  */
467
1410
  const useTheme = () => {
468
1411
  useStore(alephaThemeAtom);
1412
+ useStore(alephaThemeOverridesAtom);
469
1413
  const themeProvider = useInject(ThemeProvider);
470
1414
  const theme = themeProvider.getTheme();
471
1415
  const setTheme = (theme) => {
472
1416
  themeProvider.setTheme(theme.index);
473
1417
  };
474
- return [theme, setTheme];
1418
+ return [
1419
+ theme,
1420
+ setTheme,
1421
+ {
1422
+ overrides: themeProvider.getThemeOverrides(),
1423
+ setOverrides: (overrides) => {
1424
+ themeProvider.setThemeOverrides(overrides);
1425
+ },
1426
+ resetOverrides: () => {
1427
+ themeProvider.resetThemeOverrides();
1428
+ }
1429
+ }
1430
+ ];
475
1431
  };
476
1432
 
477
1433
  //#endregion
@@ -569,16 +1525,16 @@ const AlephaMantineProvider = (props) => {
569
1525
  const ui = {
570
1526
  colors: {
571
1527
  transparent: "transparent",
572
- background: "var(--alepha-background)",
1528
+ background: "var(--alepha-ground)",
573
1529
  surface: "var(--alepha-surface)",
574
1530
  elevated: "var(--alepha-elevated)",
575
1531
  border: "var(--alepha-border)"
576
1532
  },
577
1533
  sizes: { icon: {
578
- xs: 14,
579
- sm: 16,
580
- md: 20,
581
- lg: 24,
1534
+ xs: 16,
1535
+ sm: 20,
1536
+ md: 24,
1537
+ lg: 28,
582
1538
  xl: 32
583
1539
  } }
584
1540
  };
@@ -592,51 +1548,13 @@ function isComponentType(param) {
592
1548
 
593
1549
  //#endregion
594
1550
  //#region ../../src/core/components/buttons/ActionButton.tsx
595
- const ActionMenuItem = (props) => {
596
- const { item, index } = props;
597
- const router = useRouter();
598
- const action = useAction({ handler: async (e) => {
599
- await item.onClick?.();
600
- } }, [item.onClick]);
601
- if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
602
- if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
603
- if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
604
- trigger: "hover",
605
- position: "right-start",
606
- offset: 2,
607
- children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
608
- leftSection: item.icon,
609
- rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
610
- children: item.label
611
- }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
612
- item: child,
613
- index: childIndex
614
- }, childIndex)) })]
615
- }, index);
616
- const menuItemProps = {};
617
- if (props.item.onClick) menuItemProps.onClick = action.run;
618
- else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
619
- return /* @__PURE__ */ jsx(Menu.Item, {
620
- leftSection: item.icon,
621
- onClick: item.onClick,
622
- color: item.color,
623
- rightSection: item.active ? /* @__PURE__ */ jsx(ThemeIcon, {
624
- size: "xs",
625
- variant: "transparent",
626
- children: /* @__PURE__ */ jsx(IconCheck, {})
627
- }) : void 0,
628
- ...menuItemProps,
629
- children: item.label
630
- }, index);
631
- };
632
1551
  const ActionButton = (_props) => {
633
1552
  const theme = useMantineTheme();
634
1553
  const props = { ..._props };
635
- const { tooltip, menu, icon, ...restProps } = props;
636
- if (props.variant === "subtle" || props.variant === "outline") restProps.color ??= "gray";
1554
+ if (props.variant === "minimal") {}
1555
+ const { tooltip, menu, icon, iconSize, ...restProps } = props;
637
1556
  if (props.intent) {
638
- if (props.intent === "none") restProps.color ??= "gray";
639
- else if (props.intent === "primary") restProps.color ??= theme.primaryColor;
1557
+ if (props.intent === "primary") restProps.color ??= theme.primaryColor;
640
1558
  else if (props.intent === "success") {
641
1559
  restProps.c ??= "white";
642
1560
  restProps.color ??= "green";
@@ -651,10 +1569,11 @@ const ActionButton = (_props) => {
651
1569
  }
652
1570
  if (props.icon) {
653
1571
  const sizes = ui.sizes.icon;
654
- const icon = isComponentType(props.icon) ? /* @__PURE__ */ jsx(props.icon, { size: sizes[props.size || "md"] }) : /* @__PURE__ */ jsx("span", { children: props.icon });
1572
+ const iconSize = props.iconSize ?? sizes[props.size || "sm"];
1573
+ const icon = isComponentType(props.icon) ? /* @__PURE__ */ jsx(props.icon, { size: iconSize }) : /* @__PURE__ */ jsx("span", { children: props.icon });
655
1574
  if (!props.children) {
656
1575
  restProps.children = Children.only(icon);
657
- restProps.px ??= "xs";
1576
+ restProps.p ??= 8;
658
1577
  } else restProps.leftSection = icon;
659
1578
  }
660
1579
  if (props.leftSection && !props.children) restProps.px ??= "xs";
@@ -677,6 +1596,7 @@ const ActionButton = (_props) => {
677
1596
  children: /* @__PURE__ */ jsx(ActionButton, {
678
1597
  px: "xs",
679
1598
  ...rest,
1599
+ "aria-label": typeof children === "string" ? children : void 0,
680
1600
  tooltip,
681
1601
  menu,
682
1602
  children: leftSection
@@ -833,7 +1753,7 @@ const ActionClickButton = ({ preventDefault, ...props }) => {
833
1753
  * Action for navigation with active state support.
834
1754
  */
835
1755
  const ActionNavigationButton = (props) => {
836
- const { active: options, classNameActive, variantActive, propsActive, routerGoOptions, onClick: propsOnClick, anchor, ...buttonProps } = props;
1756
+ const { active: options, classNameActive, variantActive, propsActive, routerGoOptions, onClick: propsOnClick, anchorProps: buttonAnchorProps, anchor, ...buttonProps } = props;
837
1757
  const router = useRouter();
838
1758
  const { isPending, isActive } = useActive(options ? {
839
1759
  href: props.href,
@@ -847,11 +1767,11 @@ const ActionNavigationButton = (props) => {
847
1767
  };
848
1768
  const className = buttonProps.className || "";
849
1769
  if (isActive && options !== false && classNameActive) buttonProps.className = `${className} ${classNameActive}`.trim();
850
- if (props.anchorProps || anchor) return /* @__PURE__ */ jsx(Anchor, {
1770
+ if (buttonAnchorProps || anchor) return /* @__PURE__ */ jsx(Anchor, {
851
1771
  component: "a",
852
1772
  ...anchorProps,
853
1773
  ...buttonProps,
854
- ...props.anchorProps,
1774
+ ...buttonAnchorProps,
855
1775
  onClick: combinedOnClick,
856
1776
  children: props.children
857
1777
  });
@@ -874,6 +1794,38 @@ const ActionHrefButton = (props) => {
874
1794
  children: props.children
875
1795
  });
876
1796
  };
1797
+ const ActionMenuItem = (props) => {
1798
+ const { item, index } = props;
1799
+ const router = useRouter();
1800
+ const action = useAction({ handler: async (e) => {
1801
+ await item.onClick?.();
1802
+ } }, [item.onClick]);
1803
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
1804
+ if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
1805
+ if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
1806
+ trigger: "hover",
1807
+ position: "right-start",
1808
+ offset: 2,
1809
+ children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
1810
+ leftSection: item.icon,
1811
+ rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
1812
+ children: item.label
1813
+ }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
1814
+ item: child,
1815
+ index: childIndex
1816
+ }, childIndex)) })]
1817
+ }, index);
1818
+ const menuItemProps = {};
1819
+ if (props.item.onClick) menuItemProps.onClick = action.run;
1820
+ else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
1821
+ return /* @__PURE__ */ jsx(Menu.Item, {
1822
+ leftSection: item.icon ?? (item.active ? /* @__PURE__ */ jsx(IconCheck, { size: ui.sizes.icon.sm }) : /* @__PURE__ */ jsx(Flex$1, { w: ui.sizes.icon.sm })),
1823
+ onClick: item.onClick,
1824
+ color: item.color,
1825
+ ...menuItemProps,
1826
+ children: item.label
1827
+ }, index);
1828
+ };
877
1829
 
878
1830
  //#endregion
879
1831
  //#region ../../src/core/components/buttons/BurgerButton.tsx
@@ -926,11 +1878,11 @@ const DarkModeButton = (props) => {
926
1878
  const toggleColorScheme = () => {
927
1879
  setColorScheme((document.documentElement.getAttribute("data-mantine-color-scheme") ?? "light") === "dark" ? "light" : "dark");
928
1880
  };
929
- const size = props.size ?? "md";
930
- const iconSize = ui.sizes.icon[size] ?? ui.sizes.icon.md;
1881
+ const size = props.size ?? "sm";
1882
+ const iconSize = ui.sizes.icon[size] ?? ui.sizes.icon.sm;
931
1883
  return /* @__PURE__ */ jsx(ActionButton, {
932
1884
  onClick: toggleColorScheme,
933
- variant: props.variant ?? "subtle",
1885
+ variant: props.variant ?? "default",
934
1886
  size,
935
1887
  "aria-label": "Toggle color scheme",
936
1888
  icon: /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(IconSun, {
@@ -949,7 +1901,7 @@ const DarkModeButton = (props) => {
949
1901
  const LanguageButton = (props) => {
950
1902
  const i18n = useI18n();
951
1903
  return /* @__PURE__ */ jsx(ActionButton, {
952
- variant: "subtle",
1904
+ variant: "default",
953
1905
  icon: IconLanguage,
954
1906
  menu: { items: i18n.languages.map((lang) => ({
955
1907
  label: i18n.tr(lang),
@@ -968,8 +1920,7 @@ const OmnibarButton = (props) => {
968
1920
  if (props.collapsed) return /* @__PURE__ */ jsx(ActionButton, {
969
1921
  variant: "subtle",
970
1922
  onClick: spotlight.open,
971
- radius: "md",
972
- icon: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
1923
+ icon: IconSearch,
973
1924
  tooltip: {
974
1925
  label: "Search",
975
1926
  position: "right"
@@ -1006,20 +1957,258 @@ const OmnibarButton = (props) => {
1006
1957
  });
1007
1958
  };
1008
1959
 
1960
+ //#endregion
1961
+ //#region ../../src/core/hooks/useDialog.ts
1962
+ /**
1963
+ * Use this hook to access the Dialog Service for showing various dialog types.
1964
+ *
1965
+ * @example
1966
+ * ```tsx
1967
+ * const dialog = useDialog();
1968
+ * await dialog.alert({ title: "Alert", message: "This is an alert message" });
1969
+ * const confirmed = await dialog.confirm({ title: "Confirm", message: "Are you sure?" });
1970
+ * const input = await dialog.prompt({ title: "Input", message: "Enter your name:" });
1971
+ * ```
1972
+ */
1973
+ const useDialog = () => {
1974
+ return useInject(DialogService);
1975
+ };
1976
+
1977
+ //#endregion
1978
+ //#region ../../src/core/components/buttons/ThemeExpertModal.tsx
1979
+ const MANTINE_COLORS = [
1980
+ "red",
1981
+ "pink",
1982
+ "grape",
1983
+ "violet",
1984
+ "indigo",
1985
+ "blue",
1986
+ "cyan",
1987
+ "teal",
1988
+ "green",
1989
+ "lime",
1990
+ "yellow",
1991
+ "orange"
1992
+ ];
1993
+ const RADIUS_OPTIONS = [
1994
+ {
1995
+ label: "xs",
1996
+ value: "xs"
1997
+ },
1998
+ {
1999
+ label: "sm",
2000
+ value: "sm"
2001
+ },
2002
+ {
2003
+ label: "md",
2004
+ value: "md"
2005
+ },
2006
+ {
2007
+ label: "lg",
2008
+ value: "lg"
2009
+ },
2010
+ {
2011
+ label: "xl",
2012
+ value: "xl"
2013
+ }
2014
+ ];
2015
+ const SIZE_OPTIONS = [
2016
+ {
2017
+ label: "xs",
2018
+ value: "xs"
2019
+ },
2020
+ {
2021
+ label: "sm",
2022
+ value: "sm"
2023
+ },
2024
+ {
2025
+ label: "md",
2026
+ value: "md"
2027
+ },
2028
+ {
2029
+ label: "lg",
2030
+ value: "lg"
2031
+ },
2032
+ {
2033
+ label: "xl",
2034
+ value: "xl"
2035
+ }
2036
+ ];
2037
+ const FONT_OPTIONS = [
2038
+ {
2039
+ label: "System",
2040
+ value: ""
2041
+ },
2042
+ {
2043
+ label: "Inter",
2044
+ value: "Inter, sans-serif"
2045
+ },
2046
+ {
2047
+ label: "Mono",
2048
+ value: "ui-monospace, SFMono-Regular, Menlo, monospace"
2049
+ },
2050
+ {
2051
+ label: "Serif",
2052
+ value: "Georgia, 'Times New Roman', serif"
2053
+ }
2054
+ ];
2055
+ const ThemeExpertModal = () => {
2056
+ const [, , expert] = useTheme();
2057
+ const dialog = useDialog();
2058
+ const mantineTheme = useMantineTheme();
2059
+ const { overrides, setOverrides } = expert;
2060
+ const currentColor = overrides.primaryColor || mantineTheme.primaryColor;
2061
+ const currentRadius = overrides.radius || mantineTheme.defaultRadius || "md";
2062
+ const currentFont = overrides.fontFamily || "";
2063
+ const currentFontSize = overrides.fontSize || "md";
2064
+ const currentScale = overrides.scale || "md";
2065
+ const updateOverrides = (patch) => {
2066
+ setOverrides({
2067
+ ...overrides,
2068
+ ...patch
2069
+ });
2070
+ };
2071
+ return /* @__PURE__ */ jsxs(Flex$1, {
2072
+ direction: "column",
2073
+ gap: "lg",
2074
+ children: [
2075
+ /* @__PURE__ */ jsxs(Flex$1, {
2076
+ direction: "column",
2077
+ gap: "xs",
2078
+ children: [/* @__PURE__ */ jsx(Text$1, {
2079
+ fw: 500,
2080
+ size: "sm",
2081
+ children: "Primary Color"
2082
+ }), /* @__PURE__ */ jsx(SimpleGrid, {
2083
+ cols: 6,
2084
+ spacing: "xs",
2085
+ children: MANTINE_COLORS.map((color) => /* @__PURE__ */ jsx(Flex$1, {
2086
+ justify: "center",
2087
+ children: /* @__PURE__ */ jsx(ColorSwatch, {
2088
+ color: mantineTheme.colors[color]?.[6] ?? color,
2089
+ onClick: () => updateOverrides({ primaryColor: color }),
2090
+ style: { cursor: "pointer" },
2091
+ size: 32,
2092
+ children: currentColor === color && /* @__PURE__ */ jsx(IconCheck, {
2093
+ size: 14,
2094
+ color: "white"
2095
+ })
2096
+ })
2097
+ }, color))
2098
+ })]
2099
+ }),
2100
+ /* @__PURE__ */ jsxs(Flex$1, {
2101
+ direction: "column",
2102
+ gap: "xs",
2103
+ children: [/* @__PURE__ */ jsx(Text$1, {
2104
+ fw: 500,
2105
+ size: "sm",
2106
+ children: "Border Radius"
2107
+ }), /* @__PURE__ */ jsx(Flex$1, {
2108
+ gap: "xs",
2109
+ children: RADIUS_OPTIONS.map((opt) => /* @__PURE__ */ jsx(ActionButton, {
2110
+ variant: String(currentRadius) === opt.value ? "filled" : "default",
2111
+ size: "xs",
2112
+ flex: 1,
2113
+ onClick: () => updateOverrides({ radius: opt.value }),
2114
+ children: opt.label
2115
+ }, opt.value))
2116
+ })]
2117
+ }),
2118
+ /* @__PURE__ */ jsxs(Flex$1, {
2119
+ direction: "column",
2120
+ gap: "xs",
2121
+ children: [/* @__PURE__ */ jsx(Text$1, {
2122
+ fw: 500,
2123
+ size: "sm",
2124
+ children: "Font Family"
2125
+ }), /* @__PURE__ */ jsx(Select, {
2126
+ data: FONT_OPTIONS,
2127
+ value: currentFont,
2128
+ onChange: (value) => updateOverrides({ fontFamily: value ?? "" }),
2129
+ allowDeselect: false
2130
+ })]
2131
+ }),
2132
+ /* @__PURE__ */ jsxs(Flex$1, {
2133
+ direction: "column",
2134
+ gap: "xs",
2135
+ children: [/* @__PURE__ */ jsx(Text$1, {
2136
+ fw: 500,
2137
+ size: "sm",
2138
+ children: "Font Size"
2139
+ }), /* @__PURE__ */ jsx(Flex$1, {
2140
+ gap: "xs",
2141
+ children: SIZE_OPTIONS.map((opt) => /* @__PURE__ */ jsx(ActionButton, {
2142
+ variant: currentFontSize === opt.value ? "filled" : "default",
2143
+ size: "xs",
2144
+ flex: 1,
2145
+ onClick: () => updateOverrides({ fontSize: opt.value }),
2146
+ children: opt.label
2147
+ }, opt.value))
2148
+ })]
2149
+ }),
2150
+ /* @__PURE__ */ jsxs(Flex$1, {
2151
+ direction: "column",
2152
+ gap: "xs",
2153
+ children: [/* @__PURE__ */ jsx(Text$1, {
2154
+ fw: 500,
2155
+ size: "sm",
2156
+ children: "Scale"
2157
+ }), /* @__PURE__ */ jsx(Flex$1, {
2158
+ gap: "xs",
2159
+ children: SIZE_OPTIONS.map((opt) => /* @__PURE__ */ jsx(ActionButton, {
2160
+ variant: currentScale === opt.value ? "filled" : "default",
2161
+ size: "xs",
2162
+ flex: 1,
2163
+ onClick: () => updateOverrides({ scale: opt.value }),
2164
+ children: opt.label
2165
+ }, opt.value))
2166
+ })]
2167
+ }),
2168
+ /* @__PURE__ */ jsxs(Flex$1, {
2169
+ justify: "space-between",
2170
+ children: [/* @__PURE__ */ jsx(ActionButton, {
2171
+ variant: "subtle",
2172
+ color: "red",
2173
+ onClick: () => expert.resetOverrides(),
2174
+ children: "Reset"
2175
+ }), /* @__PURE__ */ jsx(ActionButton, {
2176
+ variant: "default",
2177
+ px: "xl",
2178
+ onClick: () => dialog.close(),
2179
+ children: "OK"
2180
+ })]
2181
+ })
2182
+ ]
2183
+ });
2184
+ };
2185
+
1009
2186
  //#endregion
1010
2187
  //#region ../../src/core/components/buttons/ThemeButton.tsx
1011
2188
  const ThemeButton = (props) => {
2189
+ const { expert, ...actionProps } = props;
1012
2190
  const [theme, setTheme] = useTheme();
1013
2191
  const themeList = useStore(alephaThemeListAtom)[0];
2192
+ const dialog = useDialog();
2193
+ const items = themeList.map((it, index) => ({
2194
+ label: it.name,
2195
+ onClick: () => setTheme({ index }),
2196
+ active: theme.name === it.name
2197
+ }));
2198
+ if (expert) items.push({ type: "divider" }, {
2199
+ label: "Customize...",
2200
+ onClick: () => {
2201
+ dialog.open({
2202
+ title: "Customize Theme",
2203
+ content: /* @__PURE__ */ jsx(ThemeExpertModal, {})
2204
+ });
2205
+ }
2206
+ });
1014
2207
  return /* @__PURE__ */ jsx(ActionButton, {
1015
- variant: "subtle",
2208
+ variant: "default",
1016
2209
  icon: IconPalette,
1017
- menu: { items: themeList.map((it, index) => ({
1018
- label: it.name,
1019
- onClick: () => setTheme({ index }),
1020
- active: theme.name === it.name
1021
- })) },
1022
- ...props
2210
+ menu: { items },
2211
+ ...actionProps
1023
2212
  });
1024
2213
  };
1025
2214
 
@@ -1030,8 +2219,7 @@ const ToggleSidebarButton = (props) => {
1030
2219
  return /* @__PURE__ */ jsx(ActionButton, {
1031
2220
  icon: sidebar.collapsed ? IconLayoutSidebarRightCollapse : IconLayoutSidebarLeftCollapse,
1032
2221
  visibleFrom: "md",
1033
- variant: "subtle",
1034
- size: "md",
2222
+ variant: "default",
1035
2223
  onClick: () => {
1036
2224
  setSidebar({
1037
2225
  ...sidebar,
@@ -1048,99 +2236,103 @@ const ToggleSidebarButton = (props) => {
1048
2236
 
1049
2237
  //#endregion
1050
2238
  //#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)" },
2239
+ const DetailDrawer = (props) => {
2240
+ const { opened, onClose, title, subtitle, status, actions, tabs, children, loading, size = "xl", defaultTab } = props;
2241
+ return /* @__PURE__ */ jsxs(Drawer, {
2242
+ opened,
2243
+ onClose,
2244
+ position: "right",
2245
+ size,
2246
+ withCloseButton: false,
2247
+ padding: 0,
1063
2248
  children: [/* @__PURE__ */ jsxs(Flex$1, {
1064
- direction: "column",
1065
- gap: 2,
1066
- style: {
1067
- minWidth: 0,
1068
- flex: 1
1069
- },
2249
+ p: "md",
2250
+ justify: "space-between",
2251
+ align: "flex-start",
2252
+ style: { borderBottom: "1px solid var(--mantine-color-default-border)" },
1070
2253
  children: [/* @__PURE__ */ jsxs(Flex$1, {
2254
+ direction: "column",
2255
+ gap: 2,
2256
+ style: {
2257
+ minWidth: 0,
2258
+ flex: 1
2259
+ },
2260
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
2261
+ gap: "xs",
2262
+ align: "center",
2263
+ children: [status && /* @__PURE__ */ jsx(Flex$1, {
2264
+ w: 8,
2265
+ h: 8,
2266
+ style: {
2267
+ borderRadius: "50%",
2268
+ backgroundColor: status.active ? "var(--mantine-color-green-6)" : "var(--mantine-color-red-6)",
2269
+ flexShrink: 0
2270
+ }
2271
+ }), /* @__PURE__ */ jsx(Text$1, {
2272
+ size: "lg",
2273
+ fw: 600,
2274
+ truncate: true,
2275
+ children: title
2276
+ })]
2277
+ }), subtitle && /* @__PURE__ */ jsx(Text$1, {
2278
+ size: "sm",
2279
+ c: "dimmed",
2280
+ truncate: true,
2281
+ children: subtitle
2282
+ })]
2283
+ }), /* @__PURE__ */ jsxs(Flex$1, {
1071
2284
  gap: "xs",
1072
2285
  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
2286
+ style: { flexShrink: 0 },
2287
+ children: [actions && actions.length > 0 && /* @__PURE__ */ jsx(ActionButton, {
2288
+ variant: "default",
2289
+ size: "xs",
2290
+ menu: {
2291
+ items: actions,
2292
+ position: "bottom-end",
2293
+ width: 200
2294
+ },
2295
+ children: "Actions"
2296
+ }), /* @__PURE__ */ jsx(ActionButton, {
2297
+ variant: "subtle",
2298
+ size: "xs",
2299
+ c: "dimmed",
2300
+ onClick: onClose,
2301
+ children: "Close"
1086
2302
  })]
1087
- }), subtitle && /* @__PURE__ */ jsx(Text$1, {
1088
- size: "sm",
1089
- c: "dimmed",
1090
- truncate: true,
1091
- children: subtitle
1092
2303
  })]
1093
- }), /* @__PURE__ */ jsxs(Flex$1, {
1094
- gap: "xs",
2304
+ }), loading ? /* @__PURE__ */ jsx(Flex$1, {
2305
+ flex: 1,
2306
+ justify: "center",
1095
2307
  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, {
2308
+ py: "xl",
2309
+ children: /* @__PURE__ */ jsx(Loader, {})
2310
+ }) : tabs && tabs.length > 0 ? /* @__PURE__ */ jsxs(Tabs, {
2311
+ defaultValue: defaultTab || tabs[0].value,
2312
+ children: [/* @__PURE__ */ jsx(Tabs.List, {
2313
+ px: "md",
2314
+ children: tabs.map((tab) => /* @__PURE__ */ jsx(Tabs.Tab, {
2315
+ value: tab.value,
2316
+ leftSection: tab.icon ? /* @__PURE__ */ jsx(tab.icon, { size: 14 }) : void 0,
2317
+ children: tab.label
2318
+ }, tab.value))
2319
+ }), tabs.map((tab) => /* @__PURE__ */ jsx(Tabs.Panel, {
1125
2320
  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,
2321
+ p: "md",
2322
+ children: tab.content
2323
+ }, tab.value))]
2324
+ }) : /* @__PURE__ */ jsx(Flex$1, {
2325
+ direction: "column",
1131
2326
  p: "md",
1132
- children: tab.content
1133
- }, tab.value))]
1134
- }) : /* @__PURE__ */ jsx(Flex$1, {
1135
- direction: "column",
1136
- p: "md",
1137
- children
1138
- })]
1139
- });
2327
+ children
2328
+ })]
2329
+ });
2330
+ };
1140
2331
 
1141
2332
  //#endregion
1142
2333
  //#region ../../src/core/components/data/DetailList.tsx
1143
- const DetailList = ({ items, columns = 1 }) => {
2334
+ const DetailList = (props) => {
2335
+ const { items, columns = 1 } = props;
1144
2336
  return /* @__PURE__ */ jsx(Grid, {
1145
2337
  gutter: "xs",
1146
2338
  children: items.filter((item) => !item.hidden).map((item) => /* @__PURE__ */ jsx(Grid.Col, {
@@ -1219,7 +2411,7 @@ const StatCards = ({ items }) => /* @__PURE__ */ jsx(Flex$1, {
1219
2411
  //#endregion
1220
2412
  //#region ../../src/core/components/Flex.tsx
1221
2413
  const Flex = forwardRef((props, ref) => {
1222
- const { fill, center, centerX, centerY, col, ...rest } = props;
2414
+ const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, overflow, ...rest } = props;
1223
2415
  if (fill) rest.flex ??= 1;
1224
2416
  if (col) rest.direction ??= "column";
1225
2417
  if (center) {
@@ -1228,6 +2420,21 @@ const Flex = forwardRef((props, ref) => {
1228
2420
  }
1229
2421
  if (centerX) rest.justify ??= "center";
1230
2422
  if (centerY) rest.align ??= "center";
2423
+ if (ground) rest.bg = "var(--alepha-ground)";
2424
+ else if (surface) rest.bg = "var(--alepha-surface)";
2425
+ else if (elevated) rest.bg = "var(--alepha-elevated)";
2426
+ if (rounded) rest.bdrs = rounded === true ? "md" : rounded;
2427
+ if (bordered) rest.bd = "1px solid var(--alepha-border)";
2428
+ if (borderedTop) rest.style = {
2429
+ borderTop: "1px solid var(--alepha-border)",
2430
+ ...rest.style ?? {}
2431
+ };
2432
+ if (borderedBottom) rest.style = {
2433
+ borderBottom: "1px solid var(--alepha-border)",
2434
+ ...rest.style ?? {}
2435
+ };
2436
+ if (shadowed) rest.className = `${rest.className ?? ""} shadow-${shadowed === true ? "md" : shadowed}`.trim();
2437
+ if (overflow) rest.className = `${rest.className ?? ""} overflow-auto`.trim();
1231
2438
  return /* @__PURE__ */ jsx(Flex$1, {
1232
2439
  ref,
1233
2440
  ...rest
@@ -1251,6 +2458,7 @@ const AppBar = (props) => {
1251
2458
  if ("type" in item) {
1252
2459
  if (item.type === "burger") return /* @__PURE__ */ jsx(BurgerButton, {}, index);
1253
2460
  if (item.type === "dark") return /* @__PURE__ */ jsx(DarkModeButton, { ...item.props }, index);
2461
+ if (item.type === "theme") return /* @__PURE__ */ jsx(ThemeButton, { ...item.props }, index);
1254
2462
  if (item.type === "search") return /* @__PURE__ */ jsx(OmnibarButton, { ...item.props }, index);
1255
2463
  if (item.type === "lang") return /* @__PURE__ */ jsx(LanguageButton, { ...item.props }, index);
1256
2464
  if (item.type === "spacer") return /* @__PURE__ */ jsx(Flex, { w: 16 }, index);
@@ -1364,7 +2572,8 @@ const AppBar = (props) => {
1364
2572
  * Pages should define a `label` in their `$page()` options for best results.
1365
2573
  * Falls back to the page name converted to Title Case.
1366
2574
  */
1367
- const Breadcrumb = ({ home = "Home", separator, size = "sm", ...groupProps }) => {
2575
+ const Breadcrumb = (props) => {
2576
+ const { home = "Home", separator, size = "sm", ...groupProps } = props;
1368
2577
  const state = useRouterState();
1369
2578
  const router = useRouter();
1370
2579
  const crumbs = [];
@@ -1419,11 +2628,175 @@ const Container = forwardRef((props, ref) => {
1419
2628
  });
1420
2629
  Container.displayName = "Container";
1421
2630
 
2631
+ //#endregion
2632
+ //#region ../../src/core/helpers/renderIcon.tsx
2633
+ const renderIcon = (icon, size) => {
2634
+ if (!icon) return null;
2635
+ if (isValidElement(icon)) return icon;
2636
+ if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
2637
+ return icon;
2638
+ };
2639
+
2640
+ //#endregion
2641
+ //#region ../../src/core/components/Text.tsx
2642
+ const INTENT_COLORS = {
2643
+ primary: "blue",
2644
+ info: "cyan",
2645
+ success: "green",
2646
+ warning: "yellow",
2647
+ danger: "red"
2648
+ };
2649
+ const Text = forwardRef((props, ref) => {
2650
+ const { intent, bold, italic, light, muted, small, uppercase, capitalize, center, monospace, title, ...rest } = props;
2651
+ if (intent) rest.c ??= INTENT_COLORS[intent];
2652
+ if (bold) rest.fw ??= 700;
2653
+ if (light) rest.fw ??= 300;
2654
+ if (italic) rest.fs ??= "italic";
2655
+ if (muted) rest.c ??= "dimmed";
2656
+ if (small) rest.size ??= "xs";
2657
+ if (uppercase) rest.tt ??= "uppercase";
2658
+ if (capitalize) rest.tt ??= "capitalize";
2659
+ if (center) rest.ta ??= "center";
2660
+ if (monospace) rest.ff ??= "monospace";
2661
+ if (title) rest.size ??= "xl";
2662
+ return /* @__PURE__ */ jsx(Text$1, {
2663
+ ref,
2664
+ ...rest
2665
+ });
2666
+ });
2667
+ Text.displayName = "Text";
2668
+
2669
+ //#endregion
2670
+ //#region ../../src/core/components/layout/SidebarCollapsedItem.tsx
2671
+ const SidebarCollapsedItem = (props) => {
2672
+ const router = useRouter();
2673
+ const handleItemClick = () => {
2674
+ props.onItemClick?.(props.item);
2675
+ props.item.onClick?.();
2676
+ };
2677
+ const hasChildren = props.item.children && props.item.children.length > 0;
2678
+ const menu = hasChildren ? {
2679
+ on: "hover",
2680
+ position: "right",
2681
+ menuProps: {
2682
+ arrowPosition: "center",
2683
+ arrowSize: 10,
2684
+ withArrow: true
2685
+ },
2686
+ items: [{
2687
+ type: "label",
2688
+ label: props.item.label
2689
+ }, ...props.item.children.filter((child) => !child.can || child.can()).map((child) => ({
2690
+ label: child.label,
2691
+ icon: renderIcon(child.icon, ui.sizes.icon.sm),
2692
+ href: child.href,
2693
+ active: child.href ? router.isActive(child.href, { startWith: child.activeStartsWith }) : void 0
2694
+ }))]
2695
+ } : void 0;
2696
+ return /* @__PURE__ */ jsx(Flex, {
2697
+ w: "100%",
2698
+ justify: "center",
2699
+ pos: "relative",
2700
+ children: /* @__PURE__ */ jsx(ActionButton, {
2701
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (props.level === 0 ? "sm" : "xs"),
2702
+ bd: 0,
2703
+ variant: "default",
2704
+ propsActive: { variant: "outline" },
2705
+ tooltip: hasChildren ? void 0 : {
2706
+ label: props.item.label,
2707
+ position: "right"
2708
+ },
2709
+ onClick: hasChildren ? void 0 : handleItemClick,
2710
+ icon: renderIcon(props.item.icon, ui.sizes.icon.sm) ?? /* @__PURE__ */ jsx(IconSquareRounded, { size: ui.sizes.icon.sm }),
2711
+ href: hasChildren ? void 0 : props.item.href,
2712
+ target: hasChildren ? void 0 : props.item.target,
2713
+ menu,
2714
+ ...props.item.actionProps
2715
+ })
2716
+ });
2717
+ };
2718
+
2719
+ //#endregion
2720
+ //#region ../../src/core/components/layout/SidebarItem.tsx
2721
+ const SidebarItem = (props) => {
2722
+ const maxLevel = 2;
2723
+ const router = useRouter();
2724
+ const isActive = useCallback((item) => {
2725
+ if (!item.children) return false;
2726
+ for (const child of item.children) {
2727
+ if (child.href) {
2728
+ if (router.isActive(child.href)) return true;
2729
+ }
2730
+ if (isActive(child)) return true;
2731
+ }
2732
+ return false;
2733
+ }, []);
2734
+ const [isOpen, setIsOpen] = useState(isActive(props.item));
2735
+ useEvents({ "react:transition:end": () => {
2736
+ if (isActive(props.item)) setIsOpen(true);
2737
+ } }, []);
2738
+ if (props.level > maxLevel) return null;
2739
+ const handleItemClick = (e) => {
2740
+ if (!props.item.target) e.preventDefault();
2741
+ if (props.item.children && props.item.children.length > 0) setIsOpen(!isOpen);
2742
+ else {
2743
+ props.onItemClick?.(props.item);
2744
+ props.item.onClick?.();
2745
+ }
2746
+ };
2747
+ return /* @__PURE__ */ jsxs(Flex, {
2748
+ direction: "column",
2749
+ ps: props.level === 0 ? 0 : 32,
2750
+ pos: "relative",
2751
+ children: [/* @__PURE__ */ jsx(ActionButton, {
2752
+ w: "100%",
2753
+ justify: "space-between",
2754
+ href: props.item.href,
2755
+ target: props.item.target,
2756
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (props.level === 0 ? "sm" : "xs"),
2757
+ bd: 0,
2758
+ fw: "normal",
2759
+ variant: "default",
2760
+ propsActive: { variant: "outline" },
2761
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
2762
+ onClick: handleItemClick,
2763
+ leftSection: /* @__PURE__ */ jsxs(Flex, {
2764
+ w: "100%",
2765
+ align: "center",
2766
+ gap: "sm",
2767
+ children: [renderIcon(props.item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Flex, {
2768
+ direction: "column",
2769
+ children: /* @__PURE__ */ jsx(Flex, { children: props.item.label })
2770
+ })]
2771
+ }),
2772
+ rightSection: props.item.children ? /* @__PURE__ */ jsx(Flex, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
2773
+ ...props.item.actionProps
2774
+ }), props.item.children && isOpen && /* @__PURE__ */ jsxs(Flex, {
2775
+ direction: "column",
2776
+ "data-parent-level": props.level,
2777
+ gap: 2,
2778
+ py: 2,
2779
+ children: [/* @__PURE__ */ jsx(Flex, { style: {
2780
+ position: "absolute",
2781
+ width: 1,
2782
+ background: "linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
2783
+ top: 48,
2784
+ left: 20 + 32 * props.level,
2785
+ bottom: 16
2786
+ } }), props.item.children.filter((child) => !child.can || child.can()).map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
2787
+ item: child,
2788
+ level: props.level + 1,
2789
+ onItemClick: props.onItemClick,
2790
+ theme: props.theme
2791
+ }, index))]
2792
+ })]
2793
+ });
2794
+ };
2795
+
1422
2796
  //#endregion
1423
2797
  //#region ../../src/core/components/layout/Sidebar.tsx
1424
2798
  const Sidebar = (props) => {
1425
2799
  const router = useRouter();
1426
- const { onItemClick } = props;
1427
2800
  const divider = (key, fill, collapsed) => {
1428
2801
  return /* @__PURE__ */ jsx(Flex, {
1429
2802
  h: 1,
@@ -1441,6 +2814,9 @@ const Sidebar = (props) => {
1441
2814
  if (item.type === "divider") return divider(key, item.fill, collapsed);
1442
2815
  if (item.type === "search") return /* @__PURE__ */ jsx(Flex, {
1443
2816
  mb: "xs",
2817
+ w: "100%",
2818
+ justify: "center",
2819
+ pos: "relative",
1444
2820
  children: /* @__PURE__ */ jsx(OmnibarButton, { collapsed })
1445
2821
  }, key);
1446
2822
  if (item.type === "toggle") return /* @__PURE__ */ jsx(ToggleSidebarButton, {}, key);
@@ -1448,7 +2824,7 @@ const Sidebar = (props) => {
1448
2824
  if (item.children && item.children.length > 0) {
1449
2825
  if (!item.children.some((child) => !("can" in child) || !child.can || child.can())) return null;
1450
2826
  }
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);
2827
+ if (collapsed) return /* @__PURE__ */ jsx(Fragment$1, { children: item.children?.map((child, index) => renderNode(child, `s${key}-${index}`, collapsed)) }, key);
1452
2828
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Flex, {
1453
2829
  mt: "md",
1454
2830
  align: "center",
@@ -1471,13 +2847,13 @@ const Sidebar = (props) => {
1471
2847
  if (collapsed) return /* @__PURE__ */ jsx(SidebarCollapsedItem, {
1472
2848
  item,
1473
2849
  level: 0,
1474
- onItemClick,
2850
+ onItemClick: props.onItemClick,
1475
2851
  theme: props.theme ?? {}
1476
2852
  }, key);
1477
2853
  return /* @__PURE__ */ jsx(SidebarItem, {
1478
2854
  item,
1479
2855
  level: 0,
1480
- onItemClick,
2856
+ onItemClick: props.onItemClick,
1481
2857
  theme: props.theme ?? {}
1482
2858
  }, key);
1483
2859
  };
@@ -1498,7 +2874,7 @@ const Sidebar = (props) => {
1498
2874
  return [];
1499
2875
  };
1500
2876
  const padding = "md";
1501
- const gap = props.items ? props.gap ?? 4 : "xs";
2877
+ const gap = props.items ? props.gap ?? 8 : "xs";
1502
2878
  const menu = useMemo(() => getSidebarNodes(), [props.items, props.autoPopulateMenu]);
1503
2879
  const renderSidebar = (collapsed) => /* @__PURE__ */ jsxs(Flex, {
1504
2880
  flex: 1,
@@ -1540,117 +2916,6 @@ const Sidebar = (props) => {
1540
2916
  })] });
1541
2917
  return renderSidebar(false);
1542
2918
  };
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
2919
 
1655
2920
  //#endregion
1656
2921
  //#region ../../src/core/components/layout/DashboardShell.tsx
@@ -1691,13 +2956,16 @@ const DashboardShell = (props) => {
1691
2956
  const fHeight = props.footerHeight ?? 24;
1692
2957
  const headerHeight = hasAppBar ? hHeight : 0;
1693
2958
  const footerHeight = footerElement ? fHeight : 0;
2959
+ const navbarWidth = collapsed ? collapsedWidth : expandedWidth;
2960
+ const mainContent = props.children ?? /* @__PURE__ */ jsx(NestedView, {});
1694
2961
  return /* @__PURE__ */ jsxs(AppShell, {
1695
2962
  layout: "alt",
1696
2963
  w: "100%",
2964
+ h: "100vh",
1697
2965
  flex: 1,
1698
2966
  header: hasAppBar ? { height: hHeight } : void 0,
1699
2967
  navbar: hasSidebar ? {
1700
- width: { base: collapsed ? collapsedWidth : expandedWidth },
2968
+ width: { base: navbarWidth },
1701
2969
  breakpoint: "md",
1702
2970
  collapsed: { mobile: sidebar.closed }
1703
2971
  } : void 0,
@@ -1712,13 +2980,12 @@ const DashboardShell = (props) => {
1712
2980
  })
1713
2981
  }),
1714
2982
  hasSidebar && /* @__PURE__ */ jsxs(AppShell.Navbar, {
1715
- className: "alepha-sidebar-navbar",
1716
2983
  ...props.appShellNavbarProps,
1717
2984
  children: [
1718
2985
  props.navbarHeader ? /* @__PURE__ */ jsx(Flex, {
1719
2986
  style: { borderBottom: "1px solid var(--mantine-color-default-border)" },
1720
2987
  h: headerHeight,
1721
- children: props.navbarHeader
2988
+ children: props.navbarHeader({ collapsed })
1722
2989
  }) : null,
1723
2990
  /* @__PURE__ */ jsx(Sidebar, {
1724
2991
  ...props.sidebarProps ?? {},
@@ -1732,53 +2999,30 @@ const DashboardShell = (props) => {
1732
2999
  ]
1733
3000
  }),
1734
3001
  /* @__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
3002
+ display: "flex",
3003
+ bg: "var(--alepha-ground)",
3004
+ pos: "relative",
3005
+ h: props.fill ? "100%" : "inherit",
3006
+ ...props.appShellMainProps,
3007
+ children: props.container ? /* @__PURE__ */ jsx(Container, {
3008
+ ...typeof props.container === "boolean" ? {} : props.container,
3009
+ children: mainContent
3010
+ }) : mainContent
3011
+ }),
3012
+ footerElement && /* @__PURE__ */ jsx(AppShell.Footer, {
3013
+ ...props.appShellFooterProps,
3014
+ children: footerElement
3015
+ })
3016
+ ]
1772
3017
  });
1773
- });
1774
- Text.displayName = "Text";
3018
+ };
1775
3019
 
1776
3020
  //#endregion
1777
3021
  //#region ../../src/core/form/utils/parseInput.ts
1778
3022
  const parseInput = (props, form) => {
1779
3023
  const disabled = false;
1780
3024
  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);
3025
+ const label = props.label ?? ("title" in props.input.schema && typeof props.input.schema.title === "string" ? props.input.schema.title : void 0) ?? prettyName(props.input.path);
1782
3026
  const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
1783
3027
  const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
1784
3028
  const icon = !props.icon ? getDefaultIcon({
@@ -1786,17 +3030,20 @@ const parseInput = (props, form) => {
1786
3030
  format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
1787
3031
  name: props.input.props.name,
1788
3032
  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 });
3033
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array",
3034
+ size: props.size
3035
+ }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.sm });
1791
3036
  const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
1792
3037
  const required = props.input.required;
1793
3038
  const schema = props.input.schema;
3039
+ const testId = props.input.props?.["data-testid"];
1794
3040
  const inputProps = {
1795
3041
  label,
1796
3042
  description,
1797
3043
  error,
1798
3044
  required,
1799
- disabled
3045
+ disabled,
3046
+ ...testId ? { "data-testid": testId } : {}
1800
3047
  };
1801
3048
  if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
1802
3049
  if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
@@ -1821,8 +3068,8 @@ const useArrayItems = (input) => {
1821
3068
  const alepha = useAlepha();
1822
3069
  const keyCounter = useRef(0);
1823
3070
  const [items, setItemsState] = useState(() => {
1824
- const defaultValue = input?.props?.defaultValue;
1825
- if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
3071
+ const initial = input?.initialValue;
3072
+ if (Array.isArray(initial)) return initial.map((value) => ({
1826
3073
  key: keyCounter.current++,
1827
3074
  value
1828
3075
  }));
@@ -1848,22 +3095,9 @@ const useArrayItems = (input) => {
1848
3095
  if (!input?.form) return;
1849
3096
  const formId = input.form.id;
1850
3097
  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) => {
3098
+ return alepha.events.on("form:change", (event) => {
1862
3099
  if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
1863
- })];
1864
- return () => {
1865
- for (const unsub of listeners) unsub();
1866
- };
3100
+ });
1867
3101
  }, [
1868
3102
  alepha,
1869
3103
  input,
@@ -1888,10 +3122,10 @@ const createArrayItemInput = (parentInput, itemSchema, index, _itemKey, value, o
1888
3122
  path: `${parentInput.path}/${index}`,
1889
3123
  required: false,
1890
3124
  form: parentInput.form,
3125
+ initialValue: value,
1891
3126
  props: {
1892
3127
  id: `${parentInput.props.id}-${index}`,
1893
- name: `${parentInput.props.name}[${index}]`,
1894
- defaultValue: value
3128
+ name: `${parentInput.props.name}[${index}]`
1895
3129
  },
1896
3130
  set: onValueChange
1897
3131
  };
@@ -1906,10 +3140,10 @@ const createArrayItemFieldInput = (parentInput, itemSchema, fieldName, index, _i
1906
3140
  path: `${parentInput.path}/${index}/${fieldName}`,
1907
3141
  required: itemSchema.required?.includes(fieldName) ?? false,
1908
3142
  form: parentInput.form,
3143
+ initialValue: itemValue?.[fieldName],
1909
3144
  props: {
1910
3145
  id: `${parentInput.props.id}-${index}-${fieldName}`,
1911
- name: `${parentInput.props.name}[${index}].${fieldName}`,
1912
- defaultValue: itemValue?.[fieldName]
3146
+ name: `${parentInput.props.name}[${index}].${fieldName}`
1913
3147
  },
1914
3148
  set: (value) => onFieldChange(fieldName, value)
1915
3149
  };
@@ -2127,7 +3361,9 @@ const ControlArray = (props) => {
2127
3361
  * Automatically detects date formats from schema and renders appropriate picker.
2128
3362
  */
2129
3363
  const ControlDate = (props) => {
2130
- const { inputProps, id, icon, format } = parseInput(props, useFormState(props.input));
3364
+ const form = useFormState(props.input);
3365
+ const [value, setValue] = useFieldValue(props.input);
3366
+ const { inputProps, id, icon, format } = parseInput(props, form);
2131
3367
  if (!props.input?.props) return null;
2132
3368
  if (props.datetime || format === "date-time") {
2133
3369
  const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
@@ -2135,10 +3371,8 @@ const ControlDate = (props) => {
2135
3371
  ...inputProps,
2136
3372
  id,
2137
3373
  leftSection: icon,
2138
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
2139
- onChange: (value) => {
2140
- props.input.set(value ? new Date(value).toISOString() : void 0);
2141
- },
3374
+ value: value ? new Date(value) : null,
3375
+ onChange: (val) => setValue(val ? new Date(val).toISOString() : void 0),
2142
3376
  ...dateTimePickerProps
2143
3377
  });
2144
3378
  }
@@ -2148,10 +3382,8 @@ const ControlDate = (props) => {
2148
3382
  ...inputProps,
2149
3383
  id,
2150
3384
  leftSection: icon,
2151
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
2152
- onChange: (value) => {
2153
- props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
2154
- },
3385
+ value: value ? new Date(value) : null,
3386
+ onChange: (val) => setValue(val ? new Date(val).toISOString().slice(0, 10) : void 0),
2155
3387
  ...dateInputProps
2156
3388
  });
2157
3389
  }
@@ -2161,10 +3393,8 @@ const ControlDate = (props) => {
2161
3393
  ...inputProps,
2162
3394
  id,
2163
3395
  leftSection: icon,
2164
- defaultValue: props.input.props.defaultValue,
2165
- onChange: (event) => {
2166
- props.input.set(event.currentTarget.value);
2167
- },
3396
+ value: value ?? "",
3397
+ onChange: (event) => setValue(event.currentTarget.value),
2168
3398
  ...timeInputProps
2169
3399
  });
2170
3400
  }
@@ -2177,14 +3407,10 @@ const ControlDate = (props) => {
2177
3407
  *
2178
3408
  */
2179
3409
  const ControlNumber = (props) => {
2180
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
2181
- const ref = useRef(null);
2182
- const [value, setValue] = useState(props.input.props.defaultValue);
2183
- useEvents({ "form:reset": (event) => {
2184
- if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
2185
- } }, [props.input]);
3410
+ const form = useFormState(props.input);
3411
+ const [value, setValue] = useFieldValue(props.input);
3412
+ const { inputProps, id, icon } = parseInput(props, form);
2186
3413
  if (!props.input?.props) return null;
2187
- const { type, ...inputPropsWithoutType } = props.input.props;
2188
3414
  if (props.sliderProps) {
2189
3415
  const min = props.sliderProps.min ?? inputProps.minimum ?? 0;
2190
3416
  const max = props.sliderProps.max ?? inputProps.maximum ?? 100;
@@ -2197,34 +3423,25 @@ const ControlNumber = (props) => {
2197
3423
  },
2198
3424
  children: /* @__PURE__ */ jsx(Slider, {
2199
3425
  ...inputProps,
2200
- ref,
2201
3426
  id,
2202
- ...inputPropsWithoutType,
2203
3427
  ...props.sliderProps,
2204
- value,
3428
+ value: value ?? 0,
2205
3429
  min,
2206
3430
  max,
2207
3431
  label: () => value,
2208
- onChange: (val) => {
2209
- setValue(val);
2210
- props.input.set(val);
2211
- }
3432
+ onChange: (val) => setValue(val)
2212
3433
  })
2213
3434
  })
2214
3435
  });
2215
3436
  }
2216
3437
  return /* @__PURE__ */ jsx(NumberInput, {
2217
3438
  ...inputProps,
2218
- ref,
2219
3439
  id,
2220
3440
  leftSection: icon,
2221
- ...inputPropsWithoutType,
2222
3441
  ...props.numberInputProps,
2223
3442
  value: value ?? "",
2224
3443
  onChange: (val) => {
2225
- const newValue = val !== null ? Number(val) : void 0;
2226
- setValue(newValue);
2227
- props.input.set(newValue);
3444
+ setValue(val !== null ? Number(val) : void 0);
2228
3445
  }
2229
3446
  });
2230
3447
  };
@@ -2307,92 +3524,9 @@ const ControlObject = (props) => {
2307
3524
  };
2308
3525
 
2309
3526
  //#endregion
2310
- //#region ../../src/core/form/components/ControlQueryBuilder.tsx
2311
- /**
2312
- * Query builder with text input and help popover.
2313
- * Generates query strings for parseQueryString syntax.
2314
- */
2315
- const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
2316
- const [helpOpened, setHelpOpened] = useState(false);
2317
- const [textValue, setTextValue] = useState(value);
2318
- const inputRef = useRef(null);
2319
- const fields = schema ? extractSchemaFields(schema) : [];
2320
- const [error, setError] = useState(null);
2321
- const isValid = (value) => {
2322
- try {
2323
- parseQueryString(value.trim());
2324
- } catch (e) {
2325
- setError(e.message);
2326
- return false;
2327
- }
2328
- setError(null);
2329
- return true;
2330
- };
2331
- const handleTextChange = (newValue) => {
2332
- setTextValue(newValue);
2333
- if (isValid(newValue)) onChange?.(newValue);
2334
- };
2335
- const handleClear = () => {
2336
- setTextValue("");
2337
- onChange?.("");
2338
- isValid("");
2339
- };
2340
- const handleInsert = (text) => {
2341
- const newValue = textValue ? `${textValue}${text} ` : `${text} `;
2342
- setTextValue(newValue);
2343
- if (isValid(newValue)) onChange?.(newValue);
2344
- setTimeout(() => {
2345
- inputRef.current?.focus();
2346
- const length = inputRef.current?.value.length || 0;
2347
- inputRef.current?.setSelectionRange(length, length);
2348
- }, 0);
2349
- };
2350
- useEvents({ "form:change": (event) => {
2351
- if (event.id === inputRef.current?.form?.id) {
2352
- if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
2353
- }
2354
- } }, []);
2355
- return /* @__PURE__ */ jsxs(Popover, {
2356
- width: 800,
2357
- position: "bottom-start",
2358
- shadow: "md",
2359
- opened: helpOpened,
2360
- onChange: setHelpOpened,
2361
- closeOnClickOutside: true,
2362
- closeOnEscape: true,
2363
- transitionProps: {
2364
- transition: "fade-up",
2365
- duration: 200,
2366
- timingFunction: "ease"
2367
- },
2368
- children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
2369
- ref: inputRef,
2370
- placeholder,
2371
- value: textValue,
2372
- onChange: (e) => handleTextChange(e.currentTarget.value),
2373
- onFocus: () => setHelpOpened(true),
2374
- leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
2375
- rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
2376
- size: "sm",
2377
- variant: "subtle",
2378
- color: "gray",
2379
- onClick: handleClear,
2380
- children: /* @__PURE__ */ jsx(IconX, { size: 14 })
2381
- }),
2382
- ...textInputProps
2383
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
2384
- bg: "transparent",
2385
- p: "xs",
2386
- bd: `1px solid ${ui.colors.border}`,
2387
- style: { backdropFilter: "blur(20px)" },
2388
- children: /* @__PURE__ */ jsx(QueryHelp, {
2389
- fields,
2390
- onInsert: handleInsert
2391
- })
2392
- })]
2393
- });
2394
- };
2395
- function QueryHelp({ fields, onInsert }) {
3527
+ //#region ../../src/core/form/components/ControlQueryBuilderHelp.tsx
3528
+ const ControlQueryBuilderHelp = (props) => {
3529
+ const { fields, onInsert } = props;
2396
3530
  return /* @__PURE__ */ jsxs(Flex$1, {
2397
3531
  gap: "md",
2398
3532
  align: "flex-start",
@@ -2555,111 +3689,314 @@ function QueryHelp({ fields, onInsert }) {
2555
3689
  })
2556
3690
  ]
2557
3691
  });
2558
- }
3692
+ };
3693
+
3694
+ //#endregion
3695
+ //#region ../../src/core/form/components/ControlQueryBuilder.tsx
3696
+ /**
3697
+ * Query builder with text input and help popover.
3698
+ * Generates query strings for parseQueryString syntax.
3699
+ */
3700
+ const ControlQueryBuilder = (props) => {
3701
+ const { schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps } = props;
3702
+ const [helpOpened, setHelpOpened] = useState(false);
3703
+ const [textValue, setTextValue] = useState(value);
3704
+ const inputRef = useRef(null);
3705
+ const fields = schema ? extractSchemaFields(schema) : [];
3706
+ const [error, setError] = useState(null);
3707
+ const isValid = (value) => {
3708
+ try {
3709
+ parseQueryString(value.trim());
3710
+ } catch (e) {
3711
+ setError(e.message);
3712
+ return false;
3713
+ }
3714
+ setError(null);
3715
+ return true;
3716
+ };
3717
+ const handleTextChange = (newValue) => {
3718
+ setTextValue(newValue);
3719
+ if (isValid(newValue)) onChange?.(newValue);
3720
+ };
3721
+ const handleClear = () => {
3722
+ setTextValue("");
3723
+ onChange?.("");
3724
+ isValid("");
3725
+ };
3726
+ const handleInsert = (text) => {
3727
+ const newValue = textValue ? `${textValue}${text} ` : `${text} `;
3728
+ setTextValue(newValue);
3729
+ if (isValid(newValue)) onChange?.(newValue);
3730
+ setTimeout(() => {
3731
+ inputRef.current?.focus();
3732
+ const length = inputRef.current?.value.length || 0;
3733
+ inputRef.current?.setSelectionRange(length, length);
3734
+ }, 0);
3735
+ };
3736
+ useEvents({ "form:change": (event) => {
3737
+ if (event.id === inputRef.current?.form?.id) {
3738
+ if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
3739
+ }
3740
+ } }, []);
3741
+ return /* @__PURE__ */ jsxs(Popover, {
3742
+ width: 800,
3743
+ position: "bottom-start",
3744
+ shadow: "md",
3745
+ opened: helpOpened,
3746
+ onChange: setHelpOpened,
3747
+ closeOnClickOutside: true,
3748
+ closeOnEscape: true,
3749
+ transitionProps: {
3750
+ transition: "fade-up",
3751
+ duration: 200,
3752
+ timingFunction: "ease"
3753
+ },
3754
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
3755
+ ref: inputRef,
3756
+ placeholder,
3757
+ value: textValue,
3758
+ onChange: (e) => handleTextChange(e.currentTarget.value),
3759
+ onFocus: () => setHelpOpened(true),
3760
+ leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
3761
+ rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
3762
+ size: "sm",
3763
+ variant: "subtle",
3764
+ color: "gray",
3765
+ onClick: handleClear,
3766
+ children: /* @__PURE__ */ jsx(IconX, { size: 14 })
3767
+ }),
3768
+ ...textInputProps
3769
+ }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3770
+ bg: "transparent",
3771
+ p: "xs",
3772
+ bd: `1px solid ${ui.colors.border}`,
3773
+ style: { backdropFilter: "blur(20px)" },
3774
+ children: /* @__PURE__ */ jsx(ControlQueryBuilderHelp, {
3775
+ fields,
3776
+ onInsert: handleInsert
3777
+ })
3778
+ })]
3779
+ });
3780
+ };
2559
3781
 
2560
3782
  //#endregion
2561
3783
  //#region ../../src/core/form/components/ControlSelect.tsx
2562
3784
  /**
2563
- * ControlSelect component for handling Select, MultiSelect, and TagsInput.
3785
+ * ControlSelect component for handling Select, MultiSelect, Autocomplete, and TagsInput.
2564
3786
  *
2565
3787
  * Features:
2566
3788
  * - Basic Select with enum support
2567
3789
  * - MultiSelect for array of enums
2568
- * - TagsInput for array of strings (no enum)
2569
- * - Future: Lazy loading
2570
- * - Future: Searchable/filterable options
2571
- * - Future: Custom option rendering
3790
+ * - Autocomplete for creatable single values
3791
+ * - TagsInput for creatable array values
3792
+ * - Async lazy loading with auto short/long mode detection
3793
+ * - Short mode: client-side filtering with cached data
3794
+ * - Long mode: debounced server search
2572
3795
  *
2573
3796
  * Automatically detects enum values and array types from schema.
2574
3797
  */
2575
3798
  const ControlSelect = (props) => {
2576
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
3799
+ const form = useFormState(props.input);
3800
+ const [value, setValue] = useFieldValue(props.input);
3801
+ const { inputProps, id, icon } = parseInput(props, form);
2577
3802
  const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
2578
- let itemsEnum;
2579
- if (isArray && "items" in props.input.schema && props.input.schema.items) {
2580
- const items = props.input.schema.items;
2581
- if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
2582
- }
3803
+ const isNumeric = props.input.schema && "type" in props.input.schema && (props.input.schema.type === "integer" || props.input.schema.type === "number");
3804
+ const isBoolean = props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean";
2583
3805
  const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
2584
- const [data, setData] = useState([]);
3806
+ const { data: asyncData, loading, mode, search } = useAsyncLoader(props.loader, props.loaderThreshold ?? 100, props.loaderDebounce ?? 300, props.input.initialValue);
3807
+ const [staticData, setStaticData] = useState([]);
3808
+ const enumKey = JSON.stringify(enumValues);
2585
3809
  useEffect(() => {
2586
- if (!props.input?.props) return;
2587
- if (props.loader) props.loader().then(setData);
2588
- else setData(enumValues);
2589
- }, [props.input, props.loader]);
3810
+ if (!props.input?.props || props.loader) return;
3811
+ if (isBoolean && enumValues.length === 0) setStaticData([{
3812
+ value: "true",
3813
+ label: "True"
3814
+ }, {
3815
+ value: "false",
3816
+ label: "False"
3817
+ }]);
3818
+ else setStaticData(enumValues);
3819
+ }, [
3820
+ props.input,
3821
+ props.loader,
3822
+ enumKey,
3823
+ isBoolean
3824
+ ]);
3825
+ const data = props.loader ? asyncData : staticData;
2590
3826
  if (!props.input?.props) return null;
2591
- if (props.segmented) {
2592
- const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
3827
+ /**
3828
+ * Coerce value for numeric schemas Select values are always strings.
3829
+ */
3830
+ const coerceValue = (val) => {
3831
+ if (val == null) return val;
3832
+ if (isNumeric) return Number(val);
3833
+ if (isBoolean) return val === "true";
3834
+ return val;
3835
+ };
3836
+ if (props.segmentedProps) {
3837
+ const segmentedControlProps = typeof props.segmentedProps === "object" ? props.segmentedProps : {};
3838
+ const segmentedData = segmentedControlProps.data ?? data.slice(0, 10);
2593
3839
  return /* @__PURE__ */ jsx(Input.Wrapper, {
2594
3840
  ...inputProps,
2595
- children: /* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(SegmentedControl, {
2596
- disabled: inputProps.disabled,
2597
- defaultValue: String(props.input.props.defaultValue),
2598
- ...segmentedControlProps,
2599
- onChange: (value) => {
2600
- props.input.set(value);
2601
- },
2602
- data: data.slice(0, 10)
2603
- }) })
3841
+ children: /* @__PURE__ */ jsx(Flex$1, {
3842
+ my: "calc(var(--mantine-spacing-xs) / 2)",
3843
+ children: /* @__PURE__ */ jsx(SegmentedControl, {
3844
+ disabled: inputProps.disabled,
3845
+ value: value != null ? String(value) : "",
3846
+ ...segmentedControlProps,
3847
+ onChange: (val) => {
3848
+ setValue(coerceValue(val));
3849
+ },
3850
+ data: segmentedData
3851
+ })
3852
+ })
2604
3853
  });
2605
3854
  }
2606
- if (props.autocomplete) {
2607
- const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
2608
- return /* @__PURE__ */ jsx(Autocomplete, {
3855
+ const sharedProps = {
3856
+ size: props.size,
3857
+ id,
3858
+ leftSection: loading ? /* @__PURE__ */ jsx(Loader, {
3859
+ color: "gray",
3860
+ size: 10
3861
+ }) : icon,
3862
+ data
3863
+ };
3864
+ const selectableProps = {
3865
+ ...sharedProps,
3866
+ searchable: true,
3867
+ rightSection: /* @__PURE__ */ jsx("span", {})
3868
+ };
3869
+ const longModeProps = mode === "long" ? {
3870
+ filter: ({ options }) => options,
3871
+ onSearchChange: search.run
3872
+ } : {};
3873
+ if (props.creatable && (isArray || props.tagsInputProps)) {
3874
+ const tagsInputExtraProps = props.tagsInputProps ?? {};
3875
+ return /* @__PURE__ */ jsx(TagsInput, {
2609
3876
  ...inputProps,
2610
- size: props.size,
2611
- id,
2612
- leftSection: icon,
2613
- data,
2614
- ...props.input.props,
2615
- ...autocompleteProps
3877
+ ...sharedProps,
3878
+ ...longModeProps,
3879
+ value: Array.isArray(value) ? value : [],
3880
+ onChange: (val) => {
3881
+ setValue(val);
3882
+ },
3883
+ ...tagsInputExtraProps
2616
3884
  });
2617
3885
  }
2618
- if (isArray && !itemsEnum || props.tags) {
2619
- const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
2620
- return /* @__PURE__ */ jsx(TagsInput, {
3886
+ if (props.creatable) {
3887
+ const autocompleteExtraProps = props.autocompleteProps ?? {};
3888
+ return /* @__PURE__ */ jsx(Autocomplete, {
2621
3889
  ...inputProps,
2622
- size: props.size,
2623
- id,
2624
- leftSection: icon,
2625
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
2626
- onChange: (value) => {
2627
- props.input.set(value);
3890
+ ...sharedProps,
3891
+ ...longModeProps,
3892
+ value: value != null ? String(value) : "",
3893
+ onChange: (val) => {
3894
+ setValue(coerceValue(val));
2628
3895
  },
2629
- ...tagsInputProps
3896
+ ...autocompleteExtraProps
2630
3897
  });
2631
3898
  }
2632
- if (isArray && itemsEnum || props.multi) {
2633
- const data = itemsEnum?.map((value) => ({
2634
- value,
2635
- label: value
2636
- })) || [];
2637
- const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
3899
+ if (isArray || props.multiSelectProps) {
3900
+ const multiSelectExtraProps = typeof props.multiSelectProps === "object" ? props.multiSelectProps : {};
2638
3901
  return /* @__PURE__ */ jsx(MultiSelect, {
2639
3902
  ...inputProps,
2640
- size: props.size,
2641
- id,
2642
- leftSection: icon,
2643
- data,
2644
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
2645
- onChange: (value) => {
2646
- props.input.set(value);
3903
+ ...selectableProps,
3904
+ ...longModeProps,
3905
+ value: Array.isArray(value) ? value : [],
3906
+ onChange: (val) => {
3907
+ setValue(val);
2647
3908
  },
2648
- ...multiSelectProps
3909
+ ...multiSelectExtraProps
2649
3910
  });
2650
3911
  }
2651
- const selectProps = typeof props.select === "object" ? props.select : {};
3912
+ const selectExtraProps = typeof props.selectProps === "object" ? props.selectProps : {};
3913
+ if (mode === "static") return /* @__PURE__ */ jsx(Select, {
3914
+ ...inputProps,
3915
+ ...selectableProps,
3916
+ value: value != null ? String(value) : null,
3917
+ onChange: (val) => {
3918
+ setValue(coerceValue(val));
3919
+ },
3920
+ ...selectExtraProps
3921
+ });
2652
3922
  return /* @__PURE__ */ jsx(Select, {
2653
3923
  ...inputProps,
2654
- size: props.size,
2655
- id,
2656
- leftSection: icon,
2657
- rightSection: null,
2658
- data,
2659
- ...props.input.props,
2660
- ...selectProps
3924
+ ...selectableProps,
3925
+ ...longModeProps,
3926
+ value: value != null ? String(value) : null,
3927
+ onChange: (val) => {
3928
+ setValue(coerceValue(val));
3929
+ },
3930
+ ...selectExtraProps
2661
3931
  });
2662
3932
  };
3933
+ /**
3934
+ * Hook for async select data loading with auto short/long mode detection.
3935
+ */
3936
+ const useAsyncLoader = (loader, threshold, debounceMs, defaultValue) => {
3937
+ const [data, setData] = useState([]);
3938
+ const [loading, setLoading] = useState(false);
3939
+ const [mode, setMode] = useState("static");
3940
+ const cache = useRef(/* @__PURE__ */ new Map());
3941
+ useAction({
3942
+ name: "select:loader:init",
3943
+ runOnInit: true,
3944
+ handler: async () => {
3945
+ if (!loader) {
3946
+ setMode("static");
3947
+ return;
3948
+ }
3949
+ setLoading(true);
3950
+ try {
3951
+ const result = await loader("");
3952
+ const isShort = result.length <= threshold;
3953
+ setMode(isShort ? "short" : "long");
3954
+ cache.current.set("", result);
3955
+ setData(result);
3956
+ if (!isShort && defaultValue != null && String(defaultValue) !== "") {
3957
+ const resolved = await loader("", [String(defaultValue)]);
3958
+ if (resolved.length > 0) setData((prev) => {
3959
+ const existing = new Set(prev.map((d) => typeof d === "string" ? d : d.value));
3960
+ const newItems = resolved.filter((r) => {
3961
+ const val = typeof r === "string" ? r : r.value;
3962
+ return !existing.has(val);
3963
+ });
3964
+ return [...prev, ...newItems];
3965
+ });
3966
+ }
3967
+ } finally {
3968
+ setLoading(false);
3969
+ }
3970
+ }
3971
+ }, [loader, threshold]);
3972
+ return {
3973
+ data,
3974
+ loading,
3975
+ mode,
3976
+ search: useAction({
3977
+ debounce: debounceMs,
3978
+ handler: async (text) => {
3979
+ if (!loader || mode !== "long") return;
3980
+ if (cache.current.has(text)) {
3981
+ setData(cache.current.get(text));
3982
+ return;
3983
+ }
3984
+ setLoading(true);
3985
+ try {
3986
+ const result = await loader(text);
3987
+ cache.current.set(text, result);
3988
+ setData(result);
3989
+ } finally {
3990
+ setLoading(false);
3991
+ }
3992
+ }
3993
+ }, [
3994
+ loader,
3995
+ mode,
3996
+ debounceMs
3997
+ ])
3998
+ };
3999
+ };
2663
4000
 
2664
4001
  //#endregion
2665
4002
  //#region ../../src/core/form/components/Control.tsx
@@ -2689,6 +4026,7 @@ const ControlSelect = (props) => {
2689
4026
  */
2690
4027
  const Control = (_props) => {
2691
4028
  const form = useFormState(_props.input, ["error"]);
4029
+ const [value, setValue] = useFieldValue(_props.input);
2692
4030
  if (!_props.input?.props) return null;
2693
4031
  const { inputProps, id, icon, format, schema } = parseInput(_props, form);
2694
4032
  const props = {
@@ -2696,12 +4034,11 @@ const Control = (_props) => {
2696
4034
  ...schema.$control
2697
4035
  };
2698
4036
  if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder, {
2699
- ...props.input.props,
2700
4037
  ...inputProps,
2701
4038
  schema: props.query,
2702
- value: props.input.props.value,
2703
- onChange: (value) => {
2704
- props.input.set(value);
4039
+ value,
4040
+ onChange: (val) => {
4041
+ setValue(val);
2705
4042
  }
2706
4043
  });
2707
4044
  if (props.custom) {
@@ -2712,9 +4049,9 @@ const Control = (_props) => {
2712
4049
  flex: 1,
2713
4050
  mt: "calc(var(--mantine-spacing-xs) / 2)",
2714
4051
  children: /* @__PURE__ */ jsx(Custom, {
2715
- defaultValue: props.input.props.defaultValue,
2716
- onChange: (value) => {
2717
- props.input.set(value);
4052
+ value,
4053
+ onChange: (val) => {
4054
+ setValue(val);
2718
4055
  }
2719
4056
  })
2720
4057
  })
@@ -2725,7 +4062,7 @@ const Control = (_props) => {
2725
4062
  const controlObjectProps = typeof props.object === "object" ? props.object : {};
2726
4063
  return /* @__PURE__ */ jsx(ControlObject, {
2727
4064
  input: props.input,
2728
- title: props.title,
4065
+ label: props.label,
2729
4066
  description: props.description,
2730
4067
  ...controlObjectProps
2731
4068
  });
@@ -2736,18 +4073,18 @@ const Control = (_props) => {
2736
4073
  const controlArrayProps = typeof props.array === "object" ? props.array : {};
2737
4074
  return /* @__PURE__ */ jsx(ControlArray, {
2738
4075
  input: props.input,
2739
- title: props.title,
4076
+ label: props.label,
2740
4077
  description: props.description,
2741
4078
  ...controlArrayProps
2742
4079
  });
2743
4080
  }
2744
- if (props.number || props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
4081
+ if (props.number || !props.select && props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
2745
4082
  const controlNumberProps = typeof props.number === "object" ? props.number : {};
2746
4083
  if (props.slider) controlNumberProps.sliderProps ??= {};
2747
4084
  return /* @__PURE__ */ jsx(ControlNumber, {
2748
4085
  size: props.size,
2749
4086
  input: props.input,
2750
- title: props.title,
4087
+ label: props.label,
2751
4088
  description: props.description,
2752
4089
  icon,
2753
4090
  ...controlNumberProps
@@ -2760,9 +4097,7 @@ const Control = (_props) => {
2760
4097
  size: props.size,
2761
4098
  id,
2762
4099
  leftSection: icon,
2763
- onChange: (file) => {
2764
- props.input.set(file);
2765
- },
4100
+ onChange: (file) => setValue(file),
2766
4101
  ...fileInputProps
2767
4102
  });
2768
4103
  }
@@ -2773,17 +4108,18 @@ const Control = (_props) => {
2773
4108
  size: props.size,
2774
4109
  id,
2775
4110
  leftSection: icon,
2776
- ...props.input.props,
4111
+ value: value ?? "",
4112
+ onChange: (val) => setValue(val),
2777
4113
  ...colorInputProps
2778
4114
  });
2779
4115
  }
2780
4116
  if (props.input.schema && "enum" in props.input.schema && props.input.schema.enum || isArray && !isArrayOfObjects || props.select) {
2781
4117
  const opts = typeof props.select === "object" ? props.select : {};
2782
- if (props.segmented) opts.segmented ??= {};
4118
+ if (props.segmented) opts.segmentedProps ??= {};
2783
4119
  return /* @__PURE__ */ jsx(ControlSelect, {
2784
4120
  size: props.size,
2785
4121
  input: props.input,
2786
- title: props.title,
4122
+ label: props.label,
2787
4123
  description: props.description,
2788
4124
  icon,
2789
4125
  ...opts
@@ -2797,16 +4133,16 @@ const Control = (_props) => {
2797
4133
  size: props.size,
2798
4134
  id,
2799
4135
  color: "blue",
2800
- defaultChecked: props.input.props.defaultValue,
4136
+ checked: Boolean(value),
2801
4137
  onChange: (event) => {
2802
- props.input.set(event.currentTarget.checked);
4138
+ setValue(event.currentTarget.checked);
2803
4139
  },
2804
4140
  ...switchProps
2805
4141
  });
2806
4142
  }
2807
4143
  const opts = {
2808
4144
  input: props.input,
2809
- select: { data: [{
4145
+ selectProps: { data: [{
2810
4146
  value: "true",
2811
4147
  label: "Yes"
2812
4148
  }, {
@@ -2816,7 +4152,7 @@ const Control = (_props) => {
2816
4152
  };
2817
4153
  return /* @__PURE__ */ jsx(ControlSelect, {
2818
4154
  size: props.size,
2819
- title: props.title,
4155
+ label: props.label,
2820
4156
  description: props.description,
2821
4157
  icon,
2822
4158
  ...opts
@@ -2829,7 +4165,8 @@ const Control = (_props) => {
2829
4165
  size: props.size,
2830
4166
  id,
2831
4167
  leftSection: icon,
2832
- ...props.input.props,
4168
+ value: value ?? "",
4169
+ onChange: (ev) => setValue(ev.target.value),
2833
4170
  ...passwordInputProps
2834
4171
  });
2835
4172
  }
@@ -2840,14 +4177,15 @@ const Control = (_props) => {
2840
4177
  size: props.size,
2841
4178
  id,
2842
4179
  leftSection: icon,
2843
- ...props.input.props,
4180
+ value: value ?? "",
4181
+ onChange: (ev) => setValue(ev.target.value),
2844
4182
  ...textAreaProps
2845
4183
  });
2846
4184
  }
2847
4185
  if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate, {
2848
4186
  size: props.size,
2849
4187
  input: props.input,
2850
- title: props.title,
4188
+ label: props.label,
2851
4189
  description: props.description,
2852
4190
  icon,
2853
4191
  date: props.date,
@@ -2862,7 +4200,7 @@ const Control = (_props) => {
2862
4200
  case "uri": return "url";
2863
4201
  case "tel":
2864
4202
  case "phone": return "tel";
2865
- default: return;
4203
+ default: return props.input.props.type ?? "text";
2866
4204
  }
2867
4205
  };
2868
4206
  return /* @__PURE__ */ jsx(TextInput, {
@@ -2871,14 +4209,9 @@ const Control = (_props) => {
2871
4209
  id,
2872
4210
  leftSection: icon,
2873
4211
  type: getInputType(),
2874
- ...props.input.props,
2875
- ...textInputProps,
2876
- inputWrapperOrder: [
2877
- "label",
2878
- "input",
2879
- "description",
2880
- "error"
2881
- ]
4212
+ value: value ?? "",
4213
+ onChange: (ev) => setValue(ev.target.value),
4214
+ ...textInputProps
2882
4215
  });
2883
4216
  };
2884
4217
 
@@ -2927,6 +4260,7 @@ const Control = (_props) => {
2927
4260
  */
2928
4261
  const TypeForm = (props) => {
2929
4262
  const { form, columns = 3, children, controlProps, fieldControlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps, fill = true, size } = props;
4263
+ const { dirty } = useFormState(form, ["dirty"]);
2930
4264
  const schema = props.schema || form.options.schema;
2931
4265
  if (!schema?.properties) return null;
2932
4266
  const supportedFields = Object.keys(schema.properties);
@@ -2989,10 +4323,12 @@ const TypeForm = (props) => {
2989
4323
  children: [/* @__PURE__ */ jsx(ActionButton, {
2990
4324
  variant: "subtle",
2991
4325
  type: "reset",
4326
+ disabled: !dirty,
2992
4327
  children: "Reset"
2993
4328
  }), /* @__PURE__ */ jsx(ActionButton, {
2994
4329
  intent: "primary",
2995
4330
  form,
4331
+ disabled: !dirty,
2996
4332
  ...submitButtonProps,
2997
4333
  children: submitButtonProps?.children ?? "Submit"
2998
4334
  })]
@@ -3031,33 +4367,27 @@ const dialogForm = (form, options) => ({
3031
4367
  });
3032
4368
 
3033
4369
  //#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);
4370
+ //#region ../../src/core/json/components/JsonViewerCopyButton.tsx
4371
+ const JsonViewerCopyButton = (props) => {
4372
+ const [copied, setCopied] = useState(false);
4373
+ const handleCopy = useCallback((e) => {
4374
+ e.stopPropagation();
4375
+ navigator.clipboard.writeText(props.value);
4376
+ setCopied(true);
4377
+ setTimeout(() => setCopied(false), 1500);
4378
+ }, [props.value]);
4379
+ return /* @__PURE__ */ jsx(ActionIcon, {
4380
+ size: props.iconSize + 4,
4381
+ variant: "transparent",
4382
+ c: copied ? "green" : "dimmed",
4383
+ onClick: handleCopy,
4384
+ className: "alepha-json-viewer-copy",
4385
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: props.iconSize }) : /* @__PURE__ */ jsx(IconCopy, { size: props.iconSize })
4386
+ });
3057
4387
  };
3058
4388
 
3059
4389
  //#endregion
3060
- //#region ../../src/core/json/components/JsonViewer.tsx
4390
+ //#region ../../src/core/json/components/JsonViewerShared.ts
3061
4391
  const SIZE_CONFIG = {
3062
4392
  xs: {
3063
4393
  icon: 14,
@@ -3106,77 +4436,21 @@ const getValueType = (val) => {
3106
4436
  if (Array.isArray(val)) return "array";
3107
4437
  return typeof val;
3108
4438
  };
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
3131
- };
3132
- }
3133
- return {
3134
- value: nodeId,
3135
- label: key ?? "",
3136
- nodeValue: data,
3137
- nodeKey: key,
3138
- path: currentPath,
3139
- isArrayItem
3140
- };
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;
4439
+
4440
+ //#endregion
4441
+ //#region ../../src/core/json/components/JsonViewerRowNode.tsx
4442
+ const JsonViewerRowNode = (props) => {
4443
+ const { nodeValue, nodeKey, path, isArrayItem } = props.node;
3170
4444
  const type = getValueType(nodeValue);
3171
4445
  const isExpandable = type === "object" || type === "array";
3172
4446
  const getPreview = () => {
3173
4447
  if (!isExpandable) return null;
3174
4448
  const count = (type === "array" ? nodeValue : Object.keys(nodeValue)).length;
3175
4449
  const label = type === "array" ? "item" : "key";
3176
- if (!expanded) return /* @__PURE__ */ jsx(Text$1, {
4450
+ if (!props.expanded) return /* @__PURE__ */ jsx(Text$1, {
3177
4451
  fs: "italic",
3178
4452
  component: "span",
3179
- size,
4453
+ size: props.size,
3180
4454
  style: STYLES.preview,
3181
4455
  children: count === 0 ? type === "array" ? "[]" : "{}" : type === "array" ? `[ ${count} ${count === 1 ? label : `${label}s`} ]` : `{ ${count} ${count === 1 ? label : `${label}s`} }`
3182
4456
  });
@@ -3186,25 +4460,25 @@ const RowNode = ({ node, expanded, hasChildren, elementProps, size, config, show
3186
4460
  return /* @__PURE__ */ jsxs(Flex$1, {
3187
4461
  gap: 6,
3188
4462
  wrap: "nowrap",
3189
- ...elementProps,
3190
- className: `alepha-json-viewer-row ${elementProps.className || ""}`,
4463
+ ...props.elementProps,
4464
+ className: `alepha-json-viewer-row ${props.elementProps.className || ""}`,
3191
4465
  children: [
3192
- hasChildren ? expanded ? /* @__PURE__ */ jsx(IconChevronDown, {
3193
- size: config.icon,
4466
+ props.hasChildren ? props.expanded ? /* @__PURE__ */ jsx(IconChevronDown, {
4467
+ size: props.config.icon,
3194
4468
  style: STYLES.chevron
3195
4469
  }) : /* @__PURE__ */ jsx(IconChevronRight, {
3196
- size: config.icon,
4470
+ size: props.config.icon,
3197
4471
  style: STYLES.chevron
3198
4472
  }) : /* @__PURE__ */ jsx("span", { style: {
3199
- width: config.icon,
4473
+ width: props.config.icon,
3200
4474
  flexShrink: 0
3201
4475
  } }),
3202
4476
  nodeKey !== void 0 && !isArrayItem && /* @__PURE__ */ jsxs(Text$1, {
3203
4477
  component: "span",
3204
- size,
4478
+ size: props.size,
3205
4479
  children: [/* @__PURE__ */ jsx("span", {
3206
4480
  style: STYLES.key,
3207
- children: showQuotes ? `"${nodeKey}"` : nodeKey
4481
+ children: props.showQuotes ? `"${nodeKey}"` : nodeKey
3208
4482
  }), /* @__PURE__ */ jsx("span", {
3209
4483
  style: STYLES.colon,
3210
4484
  children: ":"
@@ -3212,7 +4486,7 @@ const RowNode = ({ node, expanded, hasChildren, elementProps, size, config, show
3212
4486
  }),
3213
4487
  nodeKey !== void 0 && isArrayItem && /* @__PURE__ */ jsxs(Text$1, {
3214
4488
  component: "span",
3215
- size,
4489
+ size: props.size,
3216
4490
  children: [/* @__PURE__ */ jsx("span", {
3217
4491
  style: STYLES.key,
3218
4492
  children: nodeKey
@@ -3221,25 +4495,29 @@ const RowNode = ({ node, expanded, hasChildren, elementProps, size, config, show
3221
4495
  children: ":"
3222
4496
  })]
3223
4497
  }),
3224
- hasChildren ? getPreview() : isExpandable ? type === "array" ? /* @__PURE__ */ jsx(Text$1, {
4498
+ props.hasChildren ? getPreview() : isExpandable ? type === "array" ? /* @__PURE__ */ jsx(Text$1, {
3225
4499
  component: "span",
3226
- size,
4500
+ size: props.size,
3227
4501
  style: STYLES.preview,
3228
4502
  children: "[]"
3229
4503
  }) : /* @__PURE__ */ jsx(Text$1, {
3230
4504
  component: "span",
3231
- size,
4505
+ size: props.size,
3232
4506
  style: STYLES.preview,
3233
4507
  children: "{}"
3234
- }) : renderValue(nodeValue, nodeKey, path),
3235
- showCopyButton && /* @__PURE__ */ jsx(CopyButton$1, {
4508
+ }) : props.renderValue(nodeValue, nodeKey, path),
4509
+ props.showCopyButton && /* @__PURE__ */ jsx(JsonViewerCopyButton, {
3236
4510
  value: getCopyValue(),
3237
- iconSize: config.icon
4511
+ iconSize: props.config.icon
3238
4512
  })
3239
4513
  ]
3240
4514
  });
3241
4515
  };
3242
- const JsonViewer = ({ data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm", showQuotes = false, showCopyButton = true, formatValue }) => {
4516
+
4517
+ //#endregion
4518
+ //#region ../../src/core/json/components/JsonViewer.tsx
4519
+ const JsonViewer = (props) => {
4520
+ const { data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm", showQuotes = false, showCopyButton = true, formatValue } = props;
3243
4521
  const config = SIZE_CONFIG[size] || SIZE_CONFIG.sm;
3244
4522
  const treeData = useMemo(() => {
3245
4523
  const type = getValueType(data);
@@ -3319,7 +4597,7 @@ const JsonViewer = ({ data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm"
3319
4597
  size
3320
4598
  ]);
3321
4599
  const renderNode = useCallback(({ node, expanded, hasChildren, elementProps }) => {
3322
- return /* @__PURE__ */ jsx(RowNode, {
4600
+ return /* @__PURE__ */ jsx(JsonViewerRowNode, {
3323
4601
  node,
3324
4602
  expanded,
3325
4603
  hasChildren,
@@ -3351,6 +4629,54 @@ const JsonViewer = ({ data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm"
3351
4629
  styles: { root: STYLES.root }
3352
4630
  });
3353
4631
  };
4632
+ /**
4633
+ * Convert JSON to tree data structure.
4634
+ */
4635
+ const buildTreeNodes = (data, path = [], key, isArrayItem = false, maxDepth = 10) => {
4636
+ const currentPath = key !== void 0 ? [...path, key] : path;
4637
+ const nodeId = currentPath.length > 0 ? currentPath.join(".") : "root";
4638
+ if (currentPath.length > maxDepth) return {
4639
+ value: nodeId,
4640
+ label: key ?? "",
4641
+ nodeValue: data,
4642
+ nodeKey: key,
4643
+ path: currentPath,
4644
+ isArrayItem
4645
+ };
4646
+ const type = getValueType(data);
4647
+ if (type === "object" || type === "array") {
4648
+ 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);
4649
+ return {
4650
+ value: nodeId,
4651
+ label: key ?? "",
4652
+ nodeValue: data,
4653
+ nodeKey: key,
4654
+ path: currentPath,
4655
+ isArrayItem,
4656
+ children: children.length > 0 ? children : void 0
4657
+ };
4658
+ }
4659
+ return {
4660
+ value: nodeId,
4661
+ label: key ?? "",
4662
+ nodeValue: data,
4663
+ nodeKey: key,
4664
+ path: currentPath,
4665
+ isArrayItem
4666
+ };
4667
+ };
4668
+ /**
4669
+ * Get all expandable node IDs up to a certain depth.
4670
+ */
4671
+ const getExpandedIds = (nodes, targetDepth, currentDepth = 0) => {
4672
+ if (currentDepth >= targetDepth) return [];
4673
+ const ids = [];
4674
+ for (const node of nodes) if (node.children) {
4675
+ ids.push(node.value);
4676
+ ids.push(...getExpandedIds(node.children, targetDepth, currentDepth + 1));
4677
+ }
4678
+ return ids;
4679
+ };
3354
4680
 
3355
4681
  //#endregion
3356
4682
  //#region ../../src/core/json/factories/dialogJson.tsx
@@ -3394,7 +4720,8 @@ const DEFAULT_MAX_VISIBLE_COLUMNS = 8;
3394
4720
 
3395
4721
  //#endregion
3396
4722
  //#region ../../src/core/table/components/DataTableFilters.tsx
3397
- const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) => {
4723
+ const DataTableFilters = (props) => {
4724
+ const { schema, form, typeFormProps, filterVisibility } = props;
3398
4725
  const visibleSchema = useMemo(() => {
3399
4726
  const visibleKeys = Object.keys(schema.properties).filter((key) => filterVisibility[key] !== false);
3400
4727
  if (visibleKeys.length === 0) return null;
@@ -3405,13 +4732,14 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
3405
4732
  return t.object(visibleProps);
3406
4733
  }, [schema, filterVisibility]);
3407
4734
  if (!visibleSchema) return null;
3408
- return /* @__PURE__ */ jsx(Flex$1, {
3409
- w: "100%",
4735
+ return /* @__PURE__ */ jsx(Flex, {
4736
+ surface: true,
4737
+ flex: 1,
4738
+ mt: -4,
3410
4739
  p: "xs",
3411
- bg: ui.colors.surface,
3412
- style: { borderBottom: "1px solid var(--alepha-border)" },
4740
+ m: "xs",
4741
+ bdrs: "md",
3413
4742
  children: /* @__PURE__ */ jsx(TypeForm, {
3414
- size: "xs",
3415
4743
  ...typeFormProps,
3416
4744
  skipSubmitButton: true,
3417
4745
  fill: true,
@@ -3422,7 +4750,7 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
3422
4750
  sm: 2,
3423
4751
  md: 3,
3424
4752
  lg: 4,
3425
- xl: 6
4753
+ xl: 5
3426
4754
  }
3427
4755
  })
3428
4756
  });
@@ -3430,48 +4758,64 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
3430
4758
 
3431
4759
  //#endregion
3432
4760
  //#region ../../src/core/table/components/DataTablePagination.tsx
3433
- const DataTablePagination = ({ page, size, totalPages, onPageChange, onSizeChange }) => {
3434
- return /* @__PURE__ */ jsxs(Flex$1, {
4761
+ const DataTablePagination = ({ page, size, totalPages, totalElements, isFirst, isLast, offset, numberOfElements, onPageChange, onSizeChange }) => {
4762
+ const from = numberOfElements > 0 ? offset + 1 : 0;
4763
+ const to = offset + numberOfElements;
4764
+ const hasTotal = totalPages != null;
4765
+ return /* @__PURE__ */ jsxs(Flex, {
3435
4766
  align: "center",
3436
- justify: "end",
4767
+ justify: "space-between",
3437
4768
  gap: "md",
3438
- p: "xs",
4769
+ px: "xs",
4770
+ py: 4,
3439
4771
  style: { borderTop: "1px solid var(--alepha-border)" },
3440
- children: [/* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(Select, {
3441
- w: 96,
3442
- variant: "default",
3443
- value: size,
3444
- onChange: (value) => {
3445
- if (value) onSizeChange(Number(value));
3446
- },
3447
- data: [
3448
- {
3449
- value: "5",
3450
- label: "5"
3451
- },
3452
- {
3453
- value: "10",
3454
- label: "10"
3455
- },
3456
- {
3457
- value: "25",
3458
- label: "25"
3459
- },
3460
- {
3461
- value: "50",
3462
- label: "50"
4772
+ children: [/* @__PURE__ */ jsx(Flex, {
4773
+ align: "center",
4774
+ children: /* @__PURE__ */ jsx(Text, {
4775
+ size: "xs",
4776
+ c: "dimmed",
4777
+ children: totalElements != null ? `Showing ${from} - ${to} of ${totalElements}` : `Showing ${from} - ${to}`
4778
+ })
4779
+ }), /* @__PURE__ */ jsxs(Flex, {
4780
+ align: "center",
4781
+ gap: "md",
4782
+ children: [/* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(Select, {
4783
+ color: "gray",
4784
+ c: "gray",
4785
+ size: "xs",
4786
+ w: 96,
4787
+ variant: "default",
4788
+ value: size,
4789
+ onChange: (value) => {
4790
+ if (value) onSizeChange(Number(value));
3463
4791
  },
3464
- {
3465
- value: "100",
3466
- label: "100"
3467
- }
3468
- ]
3469
- }) }), /* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(Pagination, {
3470
- withEdges: true,
3471
- total: totalPages,
3472
- value: page,
3473
- onChange: onPageChange
3474
- }) })]
4792
+ data: [
4793
+ {
4794
+ value: "10",
4795
+ label: "10"
4796
+ },
4797
+ {
4798
+ value: "25",
4799
+ label: "25"
4800
+ },
4801
+ {
4802
+ value: "50",
4803
+ label: "50"
4804
+ },
4805
+ {
4806
+ value: "100",
4807
+ label: "100"
4808
+ }
4809
+ ]
4810
+ }) }), /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(Pagination, {
4811
+ size: "sm",
4812
+ withEdges: hasTotal,
4813
+ withPages: hasTotal,
4814
+ total: hasTotal ? totalPages : isLast !== false ? page : page + 1,
4815
+ value: page,
4816
+ onChange: onPageChange
4817
+ }) })]
4818
+ })]
3475
4819
  });
3476
4820
  };
3477
4821
 
@@ -3518,7 +4862,7 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3518
4862
  timingFunction: "ease"
3519
4863
  },
3520
4864
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
3521
- variant: "subtle",
4865
+ variant: "minimal",
3522
4866
  icon: IconColumns,
3523
4867
  onClick: () => setOpened((o) => !o)
3524
4868
  }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
@@ -3548,12 +4892,12 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3548
4892
  gap: 4,
3549
4893
  children: [/* @__PURE__ */ jsx(ActionButton, {
3550
4894
  size: "compact-xs",
3551
- variant: "subtle",
4895
+ variant: "minimal",
3552
4896
  onClick: handleShowAll,
3553
4897
  children: "All"
3554
4898
  }), /* @__PURE__ */ jsx(ActionButton, {
3555
4899
  size: "compact-xs",
3556
- variant: "subtle",
4900
+ variant: "minimal",
3557
4901
  onClick: handleDefault,
3558
4902
  children: "Default"
3559
4903
  })]
@@ -3619,7 +4963,7 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3619
4963
  timingFunction: "ease"
3620
4964
  },
3621
4965
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
3622
- variant: "subtle",
4966
+ variant: "minimal",
3623
4967
  icon: IconFilter,
3624
4968
  onClick: () => setOpened((o) => !o)
3625
4969
  }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
@@ -3649,12 +4993,12 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3649
4993
  gap: 4,
3650
4994
  children: [/* @__PURE__ */ jsx(ActionButton, {
3651
4995
  size: "compact-xs",
3652
- variant: "subtle",
4996
+ variant: "minimal",
3653
4997
  onClick: handleShowAll,
3654
4998
  children: "All"
3655
4999
  }), /* @__PURE__ */ jsx(ActionButton, {
3656
5000
  size: "compact-xs",
3657
- variant: "subtle",
5001
+ variant: "minimal",
3658
5002
  onClick: handleHideAll,
3659
5003
  children: "None"
3660
5004
  })]
@@ -3693,7 +5037,7 @@ const extractText = (node) => {
3693
5037
  const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility, onColumnVisibilityChange, onFilterVisibilityChange, actions, onRefresh, items, withExport, selectedItems = [], checkboxActions, onClearSelection }) => {
3694
5038
  const hasSelection = selectedItems.length > 0;
3695
5039
  const exportableColumns = useCallback(() => {
3696
- return Object.entries(columns).filter(([key, col]) => !col.actions && columnVisibility[key] !== false);
5040
+ return Object.entries(columns).filter(([key]) => columnVisibility[key] !== false);
3697
5041
  }, [columns, columnVisibility]);
3698
5042
  const buildRows = useCallback(() => {
3699
5043
  const cols = exportableColumns();
@@ -3730,11 +5074,10 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3730
5074
  };
3731
5075
  await action.onClick(ctx);
3732
5076
  };
3733
- return /* @__PURE__ */ jsxs(Flex$1, {
5077
+ return /* @__PURE__ */ jsxs(Flex, {
3734
5078
  p: "xs",
3735
- style: { borderBottom: "1px solid var(--alepha-border)" },
3736
5079
  children: [
3737
- /* @__PURE__ */ jsxs(Flex$1, {
5080
+ /* @__PURE__ */ jsxs(Flex, {
3738
5081
  gap: 4,
3739
5082
  align: "center",
3740
5083
  children: [
@@ -3749,7 +5092,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3749
5092
  onVisibilityChange: onColumnVisibilityChange
3750
5093
  }),
3751
5094
  withExport && /* @__PURE__ */ jsx(ActionButton, {
3752
- variant: "subtle",
5095
+ variant: "minimal",
3753
5096
  icon: IconDownload,
3754
5097
  menu: { items: [{
3755
5098
  label: "Export as CSV",
@@ -3772,7 +5115,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3772
5115
  children: [selectedItems.length, " selected"]
3773
5116
  }),
3774
5117
  /* @__PURE__ */ jsx(ActionButton, {
3775
- variant: "subtle",
5118
+ variant: "minimal",
3776
5119
  size: "compact-sm",
3777
5120
  icon: IconX,
3778
5121
  onClick: onClearSelection,
@@ -3789,14 +5132,14 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3789
5132
  ] })
3790
5133
  ]
3791
5134
  }),
3792
- /* @__PURE__ */ jsx(Flex$1, { flex: 1 }),
3793
- /* @__PURE__ */ jsxs(Flex$1, {
5135
+ /* @__PURE__ */ jsx(Flex, { flex: 1 }),
5136
+ /* @__PURE__ */ jsxs(Flex, {
3794
5137
  gap: "xs",
3795
5138
  children: [actions?.map((props, index) => !isValidElement(props) ? /* @__PURE__ */ jsx(ActionButton, {
3796
5139
  ...props,
3797
5140
  children: props.label
3798
5141
  }, index) : props), /* @__PURE__ */ jsx(ActionButton, {
3799
- variant: "subtle",
5142
+ variant: "minimal",
3800
5143
  icon: IconRefresh,
3801
5144
  onClick: onRefresh
3802
5145
  })]
@@ -3905,12 +5248,16 @@ const FIT_STYLE = {
3905
5248
  };
3906
5249
  const DataTable = (props) => {
3907
5250
  const [items, setItems] = useState(typeof props.items === "function" ? { content: [] } : props.items);
3908
- const defaultSize = props.infinityScroll ? 100 : props.defaultSize || 10;
5251
+ const itemsRef = useRef(items);
5252
+ const [loaded, setLoaded] = useState(typeof props.items !== "function" || !props.submitOnInit);
5253
+ const defaultSize = props.defaultSize || (props.infinityScroll ? 100 : 10);
3909
5254
  const [page, setPage] = useState(1);
3910
5255
  const [size, setSize] = useState(String(defaultSize));
3911
5256
  const [currentPage, setCurrentPage] = useState(0);
3912
5257
  const alepha = useInject(Alepha);
5258
+ itemsRef.current = items;
3913
5259
  const sentinelRef = useRef(null);
5260
+ const debounceRef = useRef(null);
3914
5261
  const [columnVisibility, setColumnVisibility] = useState(() => {
3915
5262
  const entries = Object.entries(props.columns);
3916
5263
  let visibleCount = 0;
@@ -3983,13 +5330,14 @@ const DataTable = (props) => {
3983
5330
  }),
3984
5331
  handler: async (values) => {
3985
5332
  if (typeof props.items === "function") {
3986
- const response = await props.items(values, { items: items.content });
5333
+ const response = await props.items(values, { items: itemsRef.current.content });
3987
5334
  if (props.infinityScroll && values.page > 0) setItems((prev) => ({
3988
5335
  ...response,
3989
5336
  content: [...prev.content, ...response.content]
3990
5337
  }));
3991
5338
  else setItems(response);
3992
5339
  setCurrentPage(values.page);
5340
+ if (!loaded) setLoaded(true);
3993
5341
  }
3994
5342
  },
3995
5343
  onReset: async () => {
@@ -4009,9 +5357,23 @@ const DataTable = (props) => {
4009
5357
  return;
4010
5358
  }
4011
5359
  props.onFilterChange?.(key, value, form);
5360
+ if (props.skipSubmitOnChange) return;
5361
+ form.input.page.set(0);
5362
+ const delay = props.debounce ?? 300;
5363
+ if (delay > 0) {
5364
+ if (debounceRef.current) clearTimeout(debounceRef.current);
5365
+ debounceRef.current = setTimeout(() => {
5366
+ form.submit();
5367
+ }, delay);
5368
+ } else await form.submit();
4012
5369
  }
4013
- }, [items]);
5370
+ }, []);
4014
5371
  const dt = useInject(DateTimeProvider);
5372
+ useEffect(() => {
5373
+ return () => {
5374
+ if (debounceRef.current) clearTimeout(debounceRef.current);
5375
+ };
5376
+ }, []);
4015
5377
  useEffect(() => {
4016
5378
  if (props.submitOnInit) form.submit();
4017
5379
  if (props.submitEvery) {
@@ -4042,7 +5404,7 @@ const DataTable = (props) => {
4042
5404
  currentPage,
4043
5405
  form
4044
5406
  ]);
4045
- const totalColumns = visibleColumns.length + (panelConfig ? 1 : 0) + (props.withCheckbox ? 1 : 0);
5407
+ const totalColumns = visibleColumns.length + (panelConfig ? 1 : 0) + (props.withCheckbox ? 1 : 0) + (props.rowActions ? 1 : 0);
4046
5408
  const checkboxHeader = props.withCheckbox ? /* @__PURE__ */ jsx(Table.Th, {
4047
5409
  style: { width: 40 },
4048
5410
  children: /* @__PURE__ */ jsx(Checkbox, {
@@ -4065,18 +5427,20 @@ const DataTable = (props) => {
4065
5427
  userSelect: "none"
4066
5428
  } : {}
4067
5429
  },
4068
- children: /* @__PURE__ */ jsxs(Flex$1, {
5430
+ children: /* @__PURE__ */ jsxs(Flex, {
4069
5431
  align: "center",
4070
5432
  gap: 4,
4071
- children: [/* @__PURE__ */ jsx(Text$1, {
5433
+ children: [/* @__PURE__ */ jsx(Text, {
5434
+ bold: true,
5435
+ muted: true,
4072
5436
  size: "xs",
4073
5437
  children: col.label
4074
- }), col.sortable && /* @__PURE__ */ jsxs(Flex$1, {
5438
+ }), col.sortable && /* @__PURE__ */ jsxs(Flex, {
4075
5439
  c: "dimmed",
4076
5440
  children: [
4077
- sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.sm }),
4078
- sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.sm }),
4079
- sortDir === null && /* @__PURE__ */ jsx(IconArrowsSort, { size: ui.sizes.icon.sm })
5441
+ sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.xs }),
5442
+ sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.xs }),
5443
+ sortDir === null && /* @__PURE__ */ jsx(IconArrowsSort, { size: ui.sizes.icon.xs })
4080
5444
  ]
4081
5445
  })]
4082
5446
  })
@@ -4113,7 +5477,7 @@ const DataTable = (props) => {
4113
5477
  toggleExpand(itemKey);
4114
5478
  },
4115
5479
  style: { display: "inline-flex" },
4116
- children: /* @__PURE__ */ jsx(Flex$1, {
5480
+ children: /* @__PURE__ */ jsx(Flex, {
4117
5481
  c: "dimmed",
4118
5482
  align: "center",
4119
5483
  justify: "center",
@@ -4136,32 +5500,49 @@ const DataTable = (props) => {
4136
5500
  form,
4137
5501
  alepha
4138
5502
  };
4139
- if (col.actions) {
4140
- const rowActions = col.actions(item, ctx).filter((a) => a.visible !== false);
4141
- return /* @__PURE__ */ jsx(Table.Td, {
4142
- py: 2,
4143
- px: 4,
4144
- style: col.fit ? FIT_STYLE : void 0,
4145
- onClick: (e) => e.stopPropagation(),
4146
- children: /* @__PURE__ */ jsx(Flex$1, {
4147
- gap: 4,
4148
- children: rowActions.map(({ visible: _, ...actionProps }, i) => /* @__PURE__ */ jsx(ActionButton, {
4149
- variant: "subtle",
4150
- size: "xs",
4151
- preventDefault: true,
4152
- h: 20,
4153
- ...actionProps
4154
- }, i))
4155
- })
4156
- }, key);
4157
- }
5503
+ const content = col.value?.(item, ctx);
4158
5504
  return /* @__PURE__ */ jsx(Table.Td, {
4159
- py: 2,
4160
- px: 4,
4161
5505
  style: col.fit ? FIT_STYLE : void 0,
4162
- children: col.value?.(item, ctx)
5506
+ children: col.action ? /* @__PURE__ */ jsx(ActionButton, {
5507
+ td: "inherit",
5508
+ unstyled: true,
5509
+ ...col.action(item),
5510
+ children: content
5511
+ }) : content
4163
5512
  }, key);
4164
- })
5513
+ }),
5514
+ props.rowActions && (() => {
5515
+ const ctx = {
5516
+ index,
5517
+ form,
5518
+ alepha
5519
+ };
5520
+ const actions = props.rowActions(item, ctx).filter((a) => a.visible !== false);
5521
+ if (actions.length === 0) return /* @__PURE__ */ jsx(Table.Td, { style: FIT_STYLE });
5522
+ return /* @__PURE__ */ jsx(Table.Td, {
5523
+ py: 2,
5524
+ px: 4,
5525
+ style: FIT_STYLE,
5526
+ onClick: (e) => e.stopPropagation(),
5527
+ children: /* @__PURE__ */ jsx(ActionButton, {
5528
+ variant: "minimal",
5529
+ size: "xs",
5530
+ icon: IconDotsVertical,
5531
+ menu: { items: actions.map((action) => {
5532
+ const Icon = action.icon;
5533
+ return {
5534
+ label: action.label ?? (typeof action.tooltip === "string" ? action.tooltip : void 0),
5535
+ icon: Icon && isComponentType(Icon) ? /* @__PURE__ */ jsx(Icon, { size: 14 }) : Icon,
5536
+ onClick: action.onClick ? async () => {
5537
+ await action.onClick();
5538
+ if (!action.skipRefresh) await form.submit();
5539
+ } : void 0,
5540
+ color: action.color
5541
+ };
5542
+ }) }
5543
+ })
5544
+ });
5545
+ })()
4165
5546
  ]
4166
5547
  }, itemKey)];
4167
5548
  if (panelConfig && showPanel && isExpanded) elements.push(/* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
@@ -4179,13 +5560,19 @@ const DataTable = (props) => {
4179
5560
  "sort"
4180
5561
  ]);
4181
5562
  }, [props.filters, form.options.schema]);
4182
- return /* @__PURE__ */ jsxs(Flex$1, {
5563
+ return /* @__PURE__ */ jsxs(Flex, {
5564
+ gap: "xs",
4183
5565
  flex: 1,
4184
5566
  p: 0,
4185
- bdrs: "sm",
4186
5567
  direction: "column",
4187
- children: [
4188
- /* @__PURE__ */ jsx(DataTableToolbar, {
5568
+ style: { overflow: "hidden" },
5569
+ children: [/* @__PURE__ */ jsxs(Flex, {
5570
+ rounded: true,
5571
+ bordered: true,
5572
+ elevated: true,
5573
+ shadowed: "xs",
5574
+ col: true,
5575
+ children: [/* @__PURE__ */ jsx(DataTableToolbar, {
4189
5576
  columns: props.columns,
4190
5577
  filters: props.filters,
4191
5578
  columnVisibility,
@@ -4199,71 +5586,97 @@ const DataTable = (props) => {
4199
5586
  selectedItems: selection.selectedItems,
4200
5587
  checkboxActions: props.checkboxActions,
4201
5588
  onClearSelection: selection.clear
4202
- }),
4203
- filterSchema && props.filters && /* @__PURE__ */ jsx(DataTableFilters, {
5589
+ }), filterSchema && props.filters && /* @__PURE__ */ jsx(DataTableFilters, {
4204
5590
  schema: filterSchema,
4205
5591
  form,
4206
5592
  typeFormProps: props.typeFormProps,
4207
5593
  filterVisibility
4208
- }),
4209
- /* @__PURE__ */ jsx(Flex$1, {
4210
- className: "overflow-auto",
4211
- children: /* @__PURE__ */ jsxs(Table, {
4212
- "aria-label": "Data table",
4213
- withColumnBorders: true,
4214
- withRowBorders: true,
4215
- ...props.tableProps,
4216
- children: [/* @__PURE__ */ jsx(Table.Thead, {
4217
- style: {
4218
- position: "sticky",
4219
- top: 0,
4220
- zIndex: 1,
4221
- backgroundColor: "var(--mantine-color-body)"
4222
- },
4223
- children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
4224
- panelConfig && /* @__PURE__ */ jsx(Table.Th, { style: { width: 36 } }),
4225
- checkboxHeader,
4226
- head
4227
- ] })
4228
- }), /* @__PURE__ */ jsxs(Table.Tbody, {
4229
- style: {
4230
- opacity: form.submitting ? .5 : 1,
4231
- transition: "opacity 150ms ease"
4232
- },
4233
- children: [rows, items.content.length === 0 && /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
5594
+ })]
5595
+ }), /* @__PURE__ */ jsxs(Flex, {
5596
+ col: true,
5597
+ rounded: true,
5598
+ bordered: true,
5599
+ elevated: true,
5600
+ shadowed: "xs",
5601
+ flex: 1,
5602
+ style: { minHeight: 0 },
5603
+ children: [
5604
+ /* @__PURE__ */ jsx(Flex, {
5605
+ className: "overflow-auto",
5606
+ flex: 1,
5607
+ style: { minHeight: 0 },
5608
+ col: true,
5609
+ children: /* @__PURE__ */ jsxs(Table, {
5610
+ "aria-label": "Data table",
5611
+ withRowBorders: true,
5612
+ highlightOnHover: true,
5613
+ ...props.tableProps,
5614
+ children: [/* @__PURE__ */ jsx(Table.Thead, {
5615
+ bdrs: "md",
5616
+ style: {
5617
+ position: "sticky",
5618
+ top: 0,
5619
+ zIndex: 1,
5620
+ backgroundColor: "var(--alepha-elevated)"
5621
+ },
5622
+ children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
5623
+ panelConfig && /* @__PURE__ */ jsx(Table.Th, { style: { width: 36 } }),
5624
+ checkboxHeader,
5625
+ head,
5626
+ props.rowActions && /* @__PURE__ */ jsx(Table.Th, { style: FIT_STYLE })
5627
+ ] })
5628
+ }), /* @__PURE__ */ jsx(Table.Tbody, { children: !loaded || form.submitting ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
5629
+ colSpan: totalColumns || 1,
5630
+ py: "sm",
5631
+ children: /* @__PURE__ */ jsx(Flex, {
5632
+ justify: "center",
5633
+ p: "md",
5634
+ children: /* @__PURE__ */ jsx(Loader, {
5635
+ size: "sm",
5636
+ type: "dots"
5637
+ })
5638
+ })
5639
+ }) }) : rows.length === 0 ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
4234
5640
  colSpan: totalColumns || 1,
4235
5641
  py: "xl",
4236
- style: { textAlign: "center" },
4237
- children: /* @__PURE__ */ jsx(Text$1, {
4238
- c: "dimmed",
4239
- size: "sm",
4240
- children: form.submitting ? "Loading…" : "No results"
5642
+ children: /* @__PURE__ */ jsx(Flex, {
5643
+ justify: "center",
5644
+ children: /* @__PURE__ */ jsx(Text, {
5645
+ c: "dimmed",
5646
+ size: "sm",
5647
+ children: props.emptyLabel ?? "No results"
5648
+ })
4241
5649
  })
4242
- }) })]
4243
- })]
5650
+ }) }) : rows })]
5651
+ })
5652
+ }),
5653
+ props.infinityScroll && /* @__PURE__ */ jsx("div", { ref: sentinelRef }),
5654
+ !props.infinityScroll && /* @__PURE__ */ jsx(DataTablePagination, {
5655
+ page,
5656
+ size,
5657
+ totalPages: items.page?.totalPages,
5658
+ totalElements: items.page?.totalElements,
5659
+ isFirst: items.page?.isFirst,
5660
+ isLast: items.page?.isLast,
5661
+ offset: items.page?.offset ?? 0,
5662
+ numberOfElements: items.content.length,
5663
+ onPageChange: (value) => {
5664
+ form.input.page.set(value - 1);
5665
+ },
5666
+ onSizeChange: (value) => {
5667
+ form.input.size.set(value);
5668
+ }
5669
+ }),
5670
+ drawerConfig && /* @__PURE__ */ jsx(Drawer, {
5671
+ opened: drawerItem !== null,
5672
+ onClose: () => setDrawerItem(null),
5673
+ position: "right",
5674
+ size: "xl",
5675
+ ...drawerConfig.props,
5676
+ children: drawerItem && drawerConfig.render(drawerItem)
4244
5677
  })
4245
- }),
4246
- props.infinityScroll && /* @__PURE__ */ jsx("div", { ref: sentinelRef }),
4247
- !props.infinityScroll && /* @__PURE__ */ jsx(DataTablePagination, {
4248
- page,
4249
- size,
4250
- totalPages: items.page?.totalPages ?? 1,
4251
- onPageChange: (value) => {
4252
- form.input.page.set(value - 1);
4253
- },
4254
- onSizeChange: (value) => {
4255
- form.input.size.set(value);
4256
- }
4257
- }),
4258
- drawerConfig && /* @__PURE__ */ jsx(Drawer, {
4259
- opened: drawerItem !== null,
4260
- onClose: () => setDrawerItem(null),
4261
- position: "right",
4262
- size: "xl",
4263
- ...drawerConfig.props,
4264
- children: drawerItem && drawerConfig.render(drawerItem)
4265
- })
4266
- ]
5678
+ ]
5679
+ })]
4267
5680
  });
4268
5681
  };
4269
5682
 
@@ -4391,8 +5804,8 @@ const OPERATOR_INFO = {
4391
5804
  * Get the default icon for an input based on its type, format, or name.
4392
5805
  */
4393
5806
  const getDefaultIcon = (params) => {
4394
- const { type, format, name, isEnum, isArray, size = "sm" } = params;
4395
- const iconSize = ui.sizes.icon[size];
5807
+ const { type, format, name, isEnum, isArray, size = "xs" } = params;
5808
+ const iconSize = ui.sizes.icon[size] - 4;
4396
5809
  if (format) switch (format) {
4397
5810
  case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
4398
5811
  case "url":
@@ -4505,5 +5918,5 @@ const AlephaUI = $module({
4505
5918
  });
4506
5919
 
4507
5920
  //#endregion
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 };
5921
+ 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, SidebarCollapsedItem, SidebarItem, StatCards, Text, ThemeButton, ThemeProvider, ToastService, TypeForm, UiRouter, alephaSidebarAtom, alephaThemeAtom, alephaThemeListAtom, alephaThemeOverridesAtom, capitalize, defaultTheme, dialogForm, dialogJson, extractSchemaFields, getDefaultIcon, getOperatorsForField, isComponentType, midnightTheme, prettyName, renderIcon, toTitleCase, ui, useDialog, useTheme, useToast };
4509
5922
  //# sourceMappingURL=index.js.map