@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, CopyButton, Divider, Drawer, Fieldset, FileInput, Flex, Grid, Image, Input, Kbd, Loader, MantineProvider, Menu, MultiSelect, NumberInput, Pagination, Paper, PasswordInput, Popover, ScrollArea, SegmentedControl, Select, SimpleGrid, Slider, Switch, Table, Tabs, TagsInput, Text, TextInput, Textarea, Tooltip, UnstyledButton, useMantineColorScheme, useMantineTheme } 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, CopyButton, Divider, Drawer, Fieldset, FileInput, Flex, Grid, Image, Input, Kbd, Loader, MantineProvider, Menu, MultiSelect, NumberInput, Pagination, Paper, PasswordInput, Popover, ScrollArea, SegmentedControl, Select, Slider, Switch, Table, Tabs, TagsInput, Text, TextInput, Textarea, ThemeIcon, Tooltip, UnstyledButton, useMantineColorScheme, useMantineTheme } 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,74 +1525,36 @@ 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
  };
585
1541
 
586
- //#endregion
587
- //#region ../../src/core/helpers/isComponentType.ts
588
- function isComponentType(param) {
589
- if (isValidElement(param)) return false;
590
- return typeof param === "function" || typeof param === "object" && param !== null && "$$typeof" in param;
591
- }
592
-
593
- //#endregion
594
- //#region ../../src/core/components/buttons/ActionButton.tsx
595
- const ActionMenuItem = (props) => {
596
- const { item, index } = props;
597
- const router = useRouter();
598
- const action = useAction({ handler: async (e) => {
599
- await item.onClick?.();
600
- } }, [item.onClick]);
601
- if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
602
- if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
603
- if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
604
- trigger: "hover",
605
- position: "right-start",
606
- offset: 2,
607
- children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
608
- leftSection: item.icon,
609
- rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
610
- children: item.label
611
- }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
612
- item: child,
613
- index: childIndex
614
- }, childIndex)) })]
615
- }, index);
616
- const menuItemProps = {};
617
- if (props.item.onClick) menuItemProps.onClick = action.run;
618
- else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
619
- return /* @__PURE__ */ jsx(Menu.Item, {
620
- leftSection: item.icon,
621
- onClick: item.onClick,
622
- color: item.color,
623
- rightSection: item.active ? /* @__PURE__ */ jsx(ThemeIcon, {
624
- size: "xs",
625
- variant: "transparent",
626
- children: /* @__PURE__ */ jsx(IconCheck, {})
627
- }) : void 0,
628
- ...menuItemProps,
629
- children: item.label
630
- }, index);
631
- };
1542
+ //#endregion
1543
+ //#region ../../src/core/helpers/isComponentType.ts
1544
+ function isComponentType(param) {
1545
+ if (isValidElement(param)) return false;
1546
+ return typeof param === "function" || typeof param === "object" && param !== null && "$$typeof" in param;
1547
+ }
1548
+
1549
+ //#endregion
1550
+ //#region ../../src/core/components/buttons/ActionButton.tsx
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, { 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, {
2072
+ direction: "column",
2073
+ gap: "lg",
2074
+ children: [
2075
+ /* @__PURE__ */ jsxs(Flex, {
2076
+ direction: "column",
2077
+ gap: "xs",
2078
+ children: [/* @__PURE__ */ jsx(Text, {
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, {
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, {
2101
+ direction: "column",
2102
+ gap: "xs",
2103
+ children: [/* @__PURE__ */ jsx(Text, {
2104
+ fw: 500,
2105
+ size: "sm",
2106
+ children: "Border Radius"
2107
+ }), /* @__PURE__ */ jsx(Flex, {
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, {
2119
+ direction: "column",
2120
+ gap: "xs",
2121
+ children: [/* @__PURE__ */ jsx(Text, {
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, {
2133
+ direction: "column",
2134
+ gap: "xs",
2135
+ children: [/* @__PURE__ */ jsx(Text, {
2136
+ fw: 500,
2137
+ size: "sm",
2138
+ children: "Font Size"
2139
+ }), /* @__PURE__ */ jsx(Flex, {
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, {
2151
+ direction: "column",
2152
+ gap: "xs",
2153
+ children: [/* @__PURE__ */ jsx(Text, {
2154
+ fw: 500,
2155
+ size: "sm",
2156
+ children: "Scale"
2157
+ }), /* @__PURE__ */ jsx(Flex, {
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, {
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,7 +2236,8 @@ const ToggleSidebarButton = (props) => {
1048
2236
 
1049
2237
  //#endregion
1050
2238
  //#region ../../src/core/components/data/DetailList.tsx
1051
- const DetailList = ({ items, columns = 1 }) => {
2239
+ const DetailList = (props) => {
2240
+ const { items, columns = 1 } = props;
1052
2241
  return /* @__PURE__ */ jsx(Grid, {
1053
2242
  gutter: "xs",
1054
2243
  children: items.filter((item) => !item.hidden).map((item) => /* @__PURE__ */ jsx(Grid.Col, {
@@ -1127,7 +2316,7 @@ const StatCards = ({ items }) => /* @__PURE__ */ jsx(Flex, {
1127
2316
  //#endregion
1128
2317
  //#region ../../src/core/components/Flex.tsx
1129
2318
  const Flex$1 = forwardRef((props, ref) => {
1130
- const { fill, center, centerX, centerY, col, ...rest } = props;
2319
+ const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, overflow, ...rest } = props;
1131
2320
  if (fill) rest.flex ??= 1;
1132
2321
  if (col) rest.direction ??= "column";
1133
2322
  if (center) {
@@ -1136,6 +2325,21 @@ const Flex$1 = forwardRef((props, ref) => {
1136
2325
  }
1137
2326
  if (centerX) rest.justify ??= "center";
1138
2327
  if (centerY) rest.align ??= "center";
2328
+ if (ground) rest.bg = "var(--alepha-ground)";
2329
+ else if (surface) rest.bg = "var(--alepha-surface)";
2330
+ else if (elevated) rest.bg = "var(--alepha-elevated)";
2331
+ if (rounded) rest.bdrs = rounded === true ? "md" : rounded;
2332
+ if (bordered) rest.bd = "1px solid var(--alepha-border)";
2333
+ if (borderedTop) rest.style = {
2334
+ borderTop: "1px solid var(--alepha-border)",
2335
+ ...rest.style ?? {}
2336
+ };
2337
+ if (borderedBottom) rest.style = {
2338
+ borderBottom: "1px solid var(--alepha-border)",
2339
+ ...rest.style ?? {}
2340
+ };
2341
+ if (shadowed) rest.className = `${rest.className ?? ""} shadow-${shadowed === true ? "md" : shadowed}`.trim();
2342
+ if (overflow) rest.className = `${rest.className ?? ""} overflow-auto`.trim();
1139
2343
  return /* @__PURE__ */ jsx(Flex, {
1140
2344
  ref,
1141
2345
  ...rest
@@ -1153,6 +2357,7 @@ const AppBar = (props) => {
1153
2357
  if ("type" in item) {
1154
2358
  if (item.type === "burger") return /* @__PURE__ */ jsx(BurgerButton, {}, index);
1155
2359
  if (item.type === "dark") return /* @__PURE__ */ jsx(DarkModeButton, { ...item.props }, index);
2360
+ if (item.type === "theme") return /* @__PURE__ */ jsx(ThemeButton, { ...item.props }, index);
1156
2361
  if (item.type === "search") return /* @__PURE__ */ jsx(OmnibarButton, { ...item.props }, index);
1157
2362
  if (item.type === "lang") return /* @__PURE__ */ jsx(LanguageButton, { ...item.props }, index);
1158
2363
  if (item.type === "spacer") return /* @__PURE__ */ jsx(Flex$1, { w: 16 }, index);
@@ -1266,7 +2471,8 @@ const AppBar = (props) => {
1266
2471
  * Pages should define a `label` in their `$page()` options for best results.
1267
2472
  * Falls back to the page name converted to Title Case.
1268
2473
  */
1269
- const Breadcrumb = ({ home = "Home", separator, size = "sm", ...groupProps }) => {
2474
+ const Breadcrumb = (props) => {
2475
+ const { home = "Home", separator, size = "sm", ...groupProps } = props;
1270
2476
  const state = useRouterState();
1271
2477
  const router = useRouter();
1272
2478
  const crumbs = [];
@@ -1311,21 +2517,185 @@ const Breadcrumb = ({ home = "Home", separator, size = "sm", ...groupProps }) =>
1311
2517
  });
1312
2518
  };
1313
2519
 
1314
- //#endregion
1315
- //#region ../../src/core/components/layout/Container.tsx
1316
- const Container$1 = forwardRef((props, ref) => {
1317
- return /* @__PURE__ */ jsx(Container, {
1318
- ref,
1319
- ...props
1320
- });
1321
- });
1322
- Container$1.displayName = "Container";
1323
-
2520
+ //#endregion
2521
+ //#region ../../src/core/components/layout/Container.tsx
2522
+ const Container$1 = forwardRef((props, ref) => {
2523
+ return /* @__PURE__ */ jsx(Container, {
2524
+ ref,
2525
+ ...props
2526
+ });
2527
+ });
2528
+ Container$1.displayName = "Container";
2529
+
2530
+ //#endregion
2531
+ //#region ../../src/core/helpers/renderIcon.tsx
2532
+ const renderIcon = (icon, size) => {
2533
+ if (!icon) return null;
2534
+ if (isValidElement(icon)) return icon;
2535
+ if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
2536
+ return icon;
2537
+ };
2538
+
2539
+ //#endregion
2540
+ //#region ../../src/core/components/Text.tsx
2541
+ const INTENT_COLORS = {
2542
+ primary: "blue",
2543
+ info: "cyan",
2544
+ success: "green",
2545
+ warning: "yellow",
2546
+ danger: "red"
2547
+ };
2548
+ const Text$1 = forwardRef((props, ref) => {
2549
+ const { intent, bold, italic, light, muted, small, uppercase, capitalize, center, monospace, title, ...rest } = props;
2550
+ if (intent) rest.c ??= INTENT_COLORS[intent];
2551
+ if (bold) rest.fw ??= 700;
2552
+ if (light) rest.fw ??= 300;
2553
+ if (italic) rest.fs ??= "italic";
2554
+ if (muted) rest.c ??= "dimmed";
2555
+ if (small) rest.size ??= "xs";
2556
+ if (uppercase) rest.tt ??= "uppercase";
2557
+ if (capitalize) rest.tt ??= "capitalize";
2558
+ if (center) rest.ta ??= "center";
2559
+ if (monospace) rest.ff ??= "monospace";
2560
+ if (title) rest.size ??= "xl";
2561
+ return /* @__PURE__ */ jsx(Text, {
2562
+ ref,
2563
+ ...rest
2564
+ });
2565
+ });
2566
+ Text$1.displayName = "Text";
2567
+
2568
+ //#endregion
2569
+ //#region ../../src/core/components/layout/SidebarCollapsedItem.tsx
2570
+ const SidebarCollapsedItem = (props) => {
2571
+ const router = useRouter();
2572
+ const handleItemClick = () => {
2573
+ props.onItemClick?.(props.item);
2574
+ props.item.onClick?.();
2575
+ };
2576
+ const hasChildren = props.item.children && props.item.children.length > 0;
2577
+ const menu = hasChildren ? {
2578
+ on: "hover",
2579
+ position: "right",
2580
+ menuProps: {
2581
+ arrowPosition: "center",
2582
+ arrowSize: 10,
2583
+ withArrow: true
2584
+ },
2585
+ items: [{
2586
+ type: "label",
2587
+ label: props.item.label
2588
+ }, ...props.item.children.filter((child) => !child.can || child.can()).map((child) => ({
2589
+ label: child.label,
2590
+ icon: renderIcon(child.icon, ui.sizes.icon.sm),
2591
+ href: child.href,
2592
+ active: child.href ? router.isActive(child.href, { startWith: child.activeStartsWith }) : void 0
2593
+ }))]
2594
+ } : void 0;
2595
+ return /* @__PURE__ */ jsx(Flex$1, {
2596
+ w: "100%",
2597
+ justify: "center",
2598
+ pos: "relative",
2599
+ children: /* @__PURE__ */ jsx(ActionButton, {
2600
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (props.level === 0 ? "sm" : "xs"),
2601
+ bd: 0,
2602
+ variant: "default",
2603
+ propsActive: { variant: "outline" },
2604
+ tooltip: hasChildren ? void 0 : {
2605
+ label: props.item.label,
2606
+ position: "right"
2607
+ },
2608
+ onClick: hasChildren ? void 0 : handleItemClick,
2609
+ icon: renderIcon(props.item.icon, ui.sizes.icon.sm) ?? /* @__PURE__ */ jsx(IconSquareRounded, { size: ui.sizes.icon.sm }),
2610
+ href: hasChildren ? void 0 : props.item.href,
2611
+ target: hasChildren ? void 0 : props.item.target,
2612
+ menu,
2613
+ ...props.item.actionProps
2614
+ })
2615
+ });
2616
+ };
2617
+
2618
+ //#endregion
2619
+ //#region ../../src/core/components/layout/SidebarItem.tsx
2620
+ const SidebarItem = (props) => {
2621
+ const maxLevel = 2;
2622
+ const router = useRouter();
2623
+ const isActive = useCallback((item) => {
2624
+ if (!item.children) return false;
2625
+ for (const child of item.children) {
2626
+ if (child.href) {
2627
+ if (router.isActive(child.href)) return true;
2628
+ }
2629
+ if (isActive(child)) return true;
2630
+ }
2631
+ return false;
2632
+ }, []);
2633
+ const [isOpen, setIsOpen] = useState(isActive(props.item));
2634
+ useEvents({ "react:transition:end": () => {
2635
+ if (isActive(props.item)) setIsOpen(true);
2636
+ } }, []);
2637
+ if (props.level > maxLevel) return null;
2638
+ const handleItemClick = (e) => {
2639
+ if (!props.item.target) e.preventDefault();
2640
+ if (props.item.children && props.item.children.length > 0) setIsOpen(!isOpen);
2641
+ else {
2642
+ props.onItemClick?.(props.item);
2643
+ props.item.onClick?.();
2644
+ }
2645
+ };
2646
+ return /* @__PURE__ */ jsxs(Flex$1, {
2647
+ direction: "column",
2648
+ ps: props.level === 0 ? 0 : 32,
2649
+ pos: "relative",
2650
+ children: [/* @__PURE__ */ jsx(ActionButton, {
2651
+ w: "100%",
2652
+ justify: "space-between",
2653
+ href: props.item.href,
2654
+ target: props.item.target,
2655
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (props.level === 0 ? "sm" : "xs"),
2656
+ bd: 0,
2657
+ fw: "normal",
2658
+ variant: "default",
2659
+ propsActive: { variant: "outline" },
2660
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
2661
+ onClick: handleItemClick,
2662
+ leftSection: /* @__PURE__ */ jsxs(Flex$1, {
2663
+ w: "100%",
2664
+ align: "center",
2665
+ gap: "sm",
2666
+ children: [renderIcon(props.item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Flex$1, {
2667
+ direction: "column",
2668
+ children: /* @__PURE__ */ jsx(Flex$1, { children: props.item.label })
2669
+ })]
2670
+ }),
2671
+ rightSection: props.item.children ? /* @__PURE__ */ jsx(Flex$1, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
2672
+ ...props.item.actionProps
2673
+ }), props.item.children && isOpen && /* @__PURE__ */ jsxs(Flex$1, {
2674
+ direction: "column",
2675
+ "data-parent-level": props.level,
2676
+ gap: 2,
2677
+ py: 2,
2678
+ children: [/* @__PURE__ */ jsx(Flex$1, { style: {
2679
+ position: "absolute",
2680
+ width: 1,
2681
+ background: "linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
2682
+ top: 48,
2683
+ left: 20 + 32 * props.level,
2684
+ bottom: 16
2685
+ } }), props.item.children.filter((child) => !child.can || child.can()).map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
2686
+ item: child,
2687
+ level: props.level + 1,
2688
+ onItemClick: props.onItemClick,
2689
+ theme: props.theme
2690
+ }, index))]
2691
+ })]
2692
+ });
2693
+ };
2694
+
1324
2695
  //#endregion
1325
2696
  //#region ../../src/core/components/layout/Sidebar.tsx
1326
2697
  const Sidebar = (props) => {
1327
2698
  const router = useRouter();
1328
- const { onItemClick } = props;
1329
2699
  const divider = (key, fill, collapsed) => {
1330
2700
  return /* @__PURE__ */ jsx(Flex$1, {
1331
2701
  h: 1,
@@ -1343,6 +2713,9 @@ const Sidebar = (props) => {
1343
2713
  if (item.type === "divider") return divider(key, item.fill, collapsed);
1344
2714
  if (item.type === "search") return /* @__PURE__ */ jsx(Flex$1, {
1345
2715
  mb: "xs",
2716
+ w: "100%",
2717
+ justify: "center",
2718
+ pos: "relative",
1346
2719
  children: /* @__PURE__ */ jsx(OmnibarButton, { collapsed })
1347
2720
  }, key);
1348
2721
  if (item.type === "toggle") return /* @__PURE__ */ jsx(ToggleSidebarButton, {}, key);
@@ -1350,7 +2723,7 @@ const Sidebar = (props) => {
1350
2723
  if (item.children && item.children.length > 0) {
1351
2724
  if (!item.children.some((child) => !("can" in child) || !child.can || child.can())) return null;
1352
2725
  }
1353
- 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);
2726
+ if (collapsed) return /* @__PURE__ */ jsx(Fragment$1, { children: item.children?.map((child, index) => renderNode(child, `s${key}-${index}`, collapsed)) }, key);
1354
2727
  return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsxs(Flex$1, {
1355
2728
  mt: "md",
1356
2729
  align: "center",
@@ -1373,13 +2746,13 @@ const Sidebar = (props) => {
1373
2746
  if (collapsed) return /* @__PURE__ */ jsx(SidebarCollapsedItem, {
1374
2747
  item,
1375
2748
  level: 0,
1376
- onItemClick,
2749
+ onItemClick: props.onItemClick,
1377
2750
  theme: props.theme ?? {}
1378
2751
  }, key);
1379
2752
  return /* @__PURE__ */ jsx(SidebarItem, {
1380
2753
  item,
1381
2754
  level: 0,
1382
- onItemClick,
2755
+ onItemClick: props.onItemClick,
1383
2756
  theme: props.theme ?? {}
1384
2757
  }, key);
1385
2758
  };
@@ -1400,7 +2773,7 @@ const Sidebar = (props) => {
1400
2773
  return [];
1401
2774
  };
1402
2775
  const padding = "md";
1403
- const gap = props.items ? props.gap ?? 4 : "xs";
2776
+ const gap = props.items ? props.gap ?? 8 : "xs";
1404
2777
  const menu = useMemo(() => getSidebarNodes(), [props.items, props.autoPopulateMenu]);
1405
2778
  const renderSidebar = (collapsed) => /* @__PURE__ */ jsxs(Flex$1, {
1406
2779
  flex: 1,
@@ -1442,117 +2815,6 @@ const Sidebar = (props) => {
1442
2815
  })] });
1443
2816
  return renderSidebar(false);
1444
2817
  };
1445
- const SidebarItem = (props) => {
1446
- const { item, level } = props;
1447
- const maxLevel = 2;
1448
- const router = useRouter();
1449
- const isActive = useCallback((item) => {
1450
- if (!item.children) return false;
1451
- for (const child of item.children) {
1452
- if (child.href) {
1453
- if (router.isActive(child.href)) return true;
1454
- }
1455
- if (isActive(child)) return true;
1456
- }
1457
- return false;
1458
- }, []);
1459
- const [isOpen, setIsOpen] = useState(isActive(item));
1460
- useEvents({ "react:transition:end": () => {
1461
- if (isActive(item)) setIsOpen(true);
1462
- } }, []);
1463
- if (level > maxLevel) return null;
1464
- const handleItemClick = (e) => {
1465
- if (!props.item.target) e.preventDefault();
1466
- if (item.children && item.children.length > 0) setIsOpen(!isOpen);
1467
- else {
1468
- props.onItemClick?.(item);
1469
- item.onClick?.();
1470
- }
1471
- };
1472
- return /* @__PURE__ */ jsxs(Flex$1, {
1473
- direction: "column",
1474
- ps: level === 0 ? 0 : 32,
1475
- pos: "relative",
1476
- children: [/* @__PURE__ */ jsx(ActionButton, {
1477
- w: "100%",
1478
- justify: "space-between",
1479
- href: props.item.href,
1480
- target: props.item.target,
1481
- size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
1482
- bd: 0,
1483
- fw: "normal",
1484
- variant: "default",
1485
- propsActive: {
1486
- variant: "outline",
1487
- fw: "bold"
1488
- },
1489
- radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
1490
- onClick: handleItemClick,
1491
- leftSection: /* @__PURE__ */ jsxs(Flex$1, {
1492
- w: "100%",
1493
- align: "center",
1494
- gap: "sm",
1495
- children: [renderIcon(item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Flex$1, {
1496
- direction: "column",
1497
- children: /* @__PURE__ */ jsx(Flex$1, { children: item.label })
1498
- })]
1499
- }),
1500
- rightSection: item.children ? /* @__PURE__ */ jsx(Flex$1, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
1501
- ...props.item.actionProps
1502
- }), item.children && isOpen && /* @__PURE__ */ jsxs(Flex$1, {
1503
- direction: "column",
1504
- "data-parent-level": level,
1505
- children: [/* @__PURE__ */ jsx(Flex$1, { style: {
1506
- position: "absolute",
1507
- width: 1,
1508
- background: "linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
1509
- top: 48,
1510
- left: 20 + 32 * level,
1511
- bottom: 16
1512
- } }), item.children.filter((child) => !child.can || child.can()).map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
1513
- item: child,
1514
- level: level + 1,
1515
- onItemClick: props.onItemClick,
1516
- theme: props.theme
1517
- }, index))]
1518
- })]
1519
- });
1520
- };
1521
- const SidebarCollapsedItem = (props) => {
1522
- const { item, level } = props;
1523
- const router = useRouter();
1524
- const handleItemClick = () => {
1525
- props.onItemClick?.(item);
1526
- item.onClick?.();
1527
- };
1528
- const hasChildren = item.children && item.children.length > 0;
1529
- const menu = hasChildren ? {
1530
- on: "hover",
1531
- position: "right",
1532
- items: item.children.filter((child) => !child.can || child.can()).map((child) => ({
1533
- label: child.label,
1534
- icon: renderIcon(child.icon, ui.sizes.icon.sm),
1535
- href: child.href,
1536
- active: child.href ? router.isActive(child.href, { startWith: child.activeStartsWith }) : void 0
1537
- }))
1538
- } : void 0;
1539
- return /* @__PURE__ */ jsx(ActionButton, {
1540
- size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
1541
- variant: "subtle",
1542
- variantActive: "default",
1543
- tooltip: hasChildren ? void 0 : {
1544
- label: item.label,
1545
- position: "right"
1546
- },
1547
- radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
1548
- onClick: hasChildren ? void 0 : handleItemClick,
1549
- icon: renderIcon(item.icon, ui.sizes.icon.sm) ?? /* @__PURE__ */ jsx(IconSquareRounded, { size: ui.sizes.icon.sm }),
1550
- href: hasChildren ? void 0 : props.item.href,
1551
- target: hasChildren ? void 0 : props.item.target,
1552
- menu,
1553
- ...props.item.actionProps
1554
- });
1555
- };
1556
2818
 
1557
2819
  //#endregion
1558
2820
  //#region ../../src/core/components/layout/DashboardShell.tsx
@@ -1593,13 +2855,16 @@ const DashboardShell = (props) => {
1593
2855
  const fHeight = props.footerHeight ?? 24;
1594
2856
  const headerHeight = hasAppBar ? hHeight : 0;
1595
2857
  const footerHeight = footerElement ? fHeight : 0;
2858
+ const navbarWidth = collapsed ? collapsedWidth : expandedWidth;
2859
+ const mainContent = props.children ?? /* @__PURE__ */ jsx(NestedView, {});
1596
2860
  return /* @__PURE__ */ jsxs(AppShell, {
1597
2861
  layout: "alt",
1598
2862
  w: "100%",
2863
+ h: "100vh",
1599
2864
  flex: 1,
1600
2865
  header: hasAppBar ? { height: hHeight } : void 0,
1601
2866
  navbar: hasSidebar ? {
1602
- width: { base: collapsed ? collapsedWidth : expandedWidth },
2867
+ width: { base: navbarWidth },
1603
2868
  breakpoint: "md",
1604
2869
  collapsed: { mobile: sidebar.closed }
1605
2870
  } : void 0,
@@ -1614,13 +2879,12 @@ const DashboardShell = (props) => {
1614
2879
  })
1615
2880
  }),
1616
2881
  hasSidebar && /* @__PURE__ */ jsxs(AppShell.Navbar, {
1617
- className: "alepha-sidebar-navbar",
1618
2882
  ...props.appShellNavbarProps,
1619
2883
  children: [
1620
2884
  props.navbarHeader ? /* @__PURE__ */ jsx(Flex$1, {
1621
2885
  style: { borderBottom: "1px solid var(--mantine-color-default-border)" },
1622
2886
  h: headerHeight,
1623
- children: props.navbarHeader
2887
+ children: props.navbarHeader({ collapsed })
1624
2888
  }) : null,
1625
2889
  /* @__PURE__ */ jsx(Sidebar, {
1626
2890
  ...props.sidebarProps ?? {},
@@ -1634,9 +2898,15 @@ const DashboardShell = (props) => {
1634
2898
  ]
1635
2899
  }),
1636
2900
  /* @__PURE__ */ jsx(AppShell.Main, {
2901
+ display: "flex",
2902
+ bg: "var(--alepha-ground)",
1637
2903
  pos: "relative",
2904
+ h: props.fill ? "100%" : "inherit",
1638
2905
  ...props.appShellMainProps,
1639
- children: props.children ?? /* @__PURE__ */ jsx(NestedView, {})
2906
+ children: props.container ? /* @__PURE__ */ jsx(Container$1, {
2907
+ ...typeof props.container === "boolean" ? {} : props.container,
2908
+ children: mainContent
2909
+ }) : mainContent
1640
2910
  }),
1641
2911
  footerElement && /* @__PURE__ */ jsx(AppShell.Footer, {
1642
2912
  ...props.appShellFooterProps,
@@ -1646,41 +2916,12 @@ const DashboardShell = (props) => {
1646
2916
  });
1647
2917
  };
1648
2918
 
1649
- //#endregion
1650
- //#region ../../src/core/components/Text.tsx
1651
- const INTENT_COLORS = {
1652
- primary: "blue",
1653
- info: "cyan",
1654
- success: "green",
1655
- warning: "yellow",
1656
- danger: "red"
1657
- };
1658
- const Text$1 = forwardRef((props, ref) => {
1659
- const { intent, bold, italic, light, muted, small, uppercase, capitalize, center, monospace, title, ...rest } = props;
1660
- if (intent) rest.c ??= INTENT_COLORS[intent];
1661
- if (bold) rest.fw ??= 700;
1662
- if (light) rest.fw ??= 300;
1663
- if (italic) rest.fs ??= "italic";
1664
- if (muted) rest.c ??= "dimmed";
1665
- if (small) rest.size ??= "sm";
1666
- if (uppercase) rest.tt ??= "uppercase";
1667
- if (capitalize) rest.tt ??= "capitalize";
1668
- if (center) rest.ta ??= "center";
1669
- if (monospace) rest.ff ??= "monospace";
1670
- if (title) rest.size ??= "xl";
1671
- return /* @__PURE__ */ jsx(Text, {
1672
- ref,
1673
- ...rest
1674
- });
1675
- });
1676
- Text$1.displayName = "Text";
1677
-
1678
2919
  //#endregion
1679
2920
  //#region ../../src/core/form/utils/parseInput.ts
1680
2921
  const parseInput = (props, form) => {
1681
2922
  const disabled = false;
1682
2923
  const id = props.input.props.id;
1683
- 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);
2924
+ 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);
1684
2925
  const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
1685
2926
  const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
1686
2927
  const icon = !props.icon ? getDefaultIcon({
@@ -1688,17 +2929,20 @@ const parseInput = (props, form) => {
1688
2929
  format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
1689
2930
  name: props.input.props.name,
1690
2931
  isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
1691
- isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
1692
- }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.md });
2932
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array",
2933
+ size: props.size
2934
+ }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.sm });
1693
2935
  const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
1694
2936
  const required = props.input.required;
1695
2937
  const schema = props.input.schema;
2938
+ const testId = props.input.props?.["data-testid"];
1696
2939
  const inputProps = {
1697
2940
  label,
1698
2941
  description,
1699
2942
  error,
1700
2943
  required,
1701
- disabled
2944
+ disabled,
2945
+ ...testId ? { "data-testid": testId } : {}
1702
2946
  };
1703
2947
  if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
1704
2948
  if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
@@ -1723,8 +2967,8 @@ const useArrayItems = (input) => {
1723
2967
  const alepha = useAlepha();
1724
2968
  const keyCounter = useRef(0);
1725
2969
  const [items, setItemsState] = useState(() => {
1726
- const defaultValue = input?.props?.defaultValue;
1727
- if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
2970
+ const initial = input?.initialValue;
2971
+ if (Array.isArray(initial)) return initial.map((value) => ({
1728
2972
  key: keyCounter.current++,
1729
2973
  value
1730
2974
  }));
@@ -1750,22 +2994,9 @@ const useArrayItems = (input) => {
1750
2994
  if (!input?.form) return;
1751
2995
  const formId = input.form.id;
1752
2996
  const fieldPath = input.path;
1753
- const listeners = [alepha.events.on("form:reset", (event) => {
1754
- if (event.id === formId) {
1755
- const defaultValue = input.props?.defaultValue;
1756
- keyCounter.current = 0;
1757
- if (Array.isArray(defaultValue)) setItemsState(defaultValue.map((value) => ({
1758
- key: keyCounter.current++,
1759
- value
1760
- })));
1761
- else setItemsState([]);
1762
- }
1763
- }), alepha.events.on("form:change", (event) => {
2997
+ return alepha.events.on("form:change", (event) => {
1764
2998
  if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
1765
- })];
1766
- return () => {
1767
- for (const unsub of listeners) unsub();
1768
- };
2999
+ });
1769
3000
  }, [
1770
3001
  alepha,
1771
3002
  input,
@@ -1790,10 +3021,10 @@ const createArrayItemInput = (parentInput, itemSchema, index, _itemKey, value, o
1790
3021
  path: `${parentInput.path}/${index}`,
1791
3022
  required: false,
1792
3023
  form: parentInput.form,
3024
+ initialValue: value,
1793
3025
  props: {
1794
3026
  id: `${parentInput.props.id}-${index}`,
1795
- name: `${parentInput.props.name}[${index}]`,
1796
- defaultValue: value
3027
+ name: `${parentInput.props.name}[${index}]`
1797
3028
  },
1798
3029
  set: onValueChange
1799
3030
  };
@@ -1808,10 +3039,10 @@ const createArrayItemFieldInput = (parentInput, itemSchema, fieldName, index, _i
1808
3039
  path: `${parentInput.path}/${index}/${fieldName}`,
1809
3040
  required: itemSchema.required?.includes(fieldName) ?? false,
1810
3041
  form: parentInput.form,
3042
+ initialValue: itemValue?.[fieldName],
1811
3043
  props: {
1812
3044
  id: `${parentInput.props.id}-${index}-${fieldName}`,
1813
- name: `${parentInput.props.name}[${index}].${fieldName}`,
1814
- defaultValue: itemValue?.[fieldName]
3045
+ name: `${parentInput.props.name}[${index}].${fieldName}`
1815
3046
  },
1816
3047
  set: (value) => onFieldChange(fieldName, value)
1817
3048
  };
@@ -2029,7 +3260,9 @@ const ControlArray = (props) => {
2029
3260
  * Automatically detects date formats from schema and renders appropriate picker.
2030
3261
  */
2031
3262
  const ControlDate = (props) => {
2032
- const { inputProps, id, icon, format } = parseInput(props, useFormState(props.input));
3263
+ const form = useFormState(props.input);
3264
+ const [value, setValue] = useFieldValue(props.input);
3265
+ const { inputProps, id, icon, format } = parseInput(props, form);
2033
3266
  if (!props.input?.props) return null;
2034
3267
  if (props.datetime || format === "date-time") {
2035
3268
  const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
@@ -2037,10 +3270,8 @@ const ControlDate = (props) => {
2037
3270
  ...inputProps,
2038
3271
  id,
2039
3272
  leftSection: icon,
2040
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
2041
- onChange: (value) => {
2042
- props.input.set(value ? new Date(value).toISOString() : void 0);
2043
- },
3273
+ value: value ? new Date(value) : null,
3274
+ onChange: (val) => setValue(val ? new Date(val).toISOString() : void 0),
2044
3275
  ...dateTimePickerProps
2045
3276
  });
2046
3277
  }
@@ -2050,10 +3281,8 @@ const ControlDate = (props) => {
2050
3281
  ...inputProps,
2051
3282
  id,
2052
3283
  leftSection: icon,
2053
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
2054
- onChange: (value) => {
2055
- props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
2056
- },
3284
+ value: value ? new Date(value) : null,
3285
+ onChange: (val) => setValue(val ? new Date(val).toISOString().slice(0, 10) : void 0),
2057
3286
  ...dateInputProps
2058
3287
  });
2059
3288
  }
@@ -2063,10 +3292,8 @@ const ControlDate = (props) => {
2063
3292
  ...inputProps,
2064
3293
  id,
2065
3294
  leftSection: icon,
2066
- defaultValue: props.input.props.defaultValue,
2067
- onChange: (event) => {
2068
- props.input.set(event.currentTarget.value);
2069
- },
3295
+ value: value ?? "",
3296
+ onChange: (event) => setValue(event.currentTarget.value),
2070
3297
  ...timeInputProps
2071
3298
  });
2072
3299
  }
@@ -2079,14 +3306,10 @@ const ControlDate = (props) => {
2079
3306
  *
2080
3307
  */
2081
3308
  const ControlNumber = (props) => {
2082
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
2083
- const ref = useRef(null);
2084
- const [value, setValue] = useState(props.input.props.defaultValue);
2085
- useEvents({ "form:reset": (event) => {
2086
- if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
2087
- } }, [props.input]);
3309
+ const form = useFormState(props.input);
3310
+ const [value, setValue] = useFieldValue(props.input);
3311
+ const { inputProps, id, icon } = parseInput(props, form);
2088
3312
  if (!props.input?.props) return null;
2089
- const { type, ...inputPropsWithoutType } = props.input.props;
2090
3313
  if (props.sliderProps) {
2091
3314
  const min = props.sliderProps.min ?? inputProps.minimum ?? 0;
2092
3315
  const max = props.sliderProps.max ?? inputProps.maximum ?? 100;
@@ -2099,34 +3322,25 @@ const ControlNumber = (props) => {
2099
3322
  },
2100
3323
  children: /* @__PURE__ */ jsx(Slider, {
2101
3324
  ...inputProps,
2102
- ref,
2103
3325
  id,
2104
- ...inputPropsWithoutType,
2105
3326
  ...props.sliderProps,
2106
- value,
3327
+ value: value ?? 0,
2107
3328
  min,
2108
3329
  max,
2109
3330
  label: () => value,
2110
- onChange: (val) => {
2111
- setValue(val);
2112
- props.input.set(val);
2113
- }
3331
+ onChange: (val) => setValue(val)
2114
3332
  })
2115
3333
  })
2116
3334
  });
2117
3335
  }
2118
3336
  return /* @__PURE__ */ jsx(NumberInput, {
2119
3337
  ...inputProps,
2120
- ref,
2121
3338
  id,
2122
3339
  leftSection: icon,
2123
- ...inputPropsWithoutType,
2124
3340
  ...props.numberInputProps,
2125
3341
  value: value ?? "",
2126
3342
  onChange: (val) => {
2127
- const newValue = val !== null ? Number(val) : void 0;
2128
- setValue(newValue);
2129
- props.input.set(newValue);
3343
+ setValue(val !== null ? Number(val) : void 0);
2130
3344
  }
2131
3345
  });
2132
3346
  };
@@ -2209,92 +3423,9 @@ const ControlObject = (props) => {
2209
3423
  };
2210
3424
 
2211
3425
  //#endregion
2212
- //#region ../../src/core/form/components/ControlQueryBuilder.tsx
2213
- /**
2214
- * Query builder with text input and help popover.
2215
- * Generates query strings for parseQueryString syntax.
2216
- */
2217
- const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
2218
- const [helpOpened, setHelpOpened] = useState(false);
2219
- const [textValue, setTextValue] = useState(value);
2220
- const inputRef = useRef(null);
2221
- const fields = schema ? extractSchemaFields(schema) : [];
2222
- const [error, setError] = useState(null);
2223
- const isValid = (value) => {
2224
- try {
2225
- parseQueryString(value.trim());
2226
- } catch (e) {
2227
- setError(e.message);
2228
- return false;
2229
- }
2230
- setError(null);
2231
- return true;
2232
- };
2233
- const handleTextChange = (newValue) => {
2234
- setTextValue(newValue);
2235
- if (isValid(newValue)) onChange?.(newValue);
2236
- };
2237
- const handleClear = () => {
2238
- setTextValue("");
2239
- onChange?.("");
2240
- isValid("");
2241
- };
2242
- const handleInsert = (text) => {
2243
- const newValue = textValue ? `${textValue}${text} ` : `${text} `;
2244
- setTextValue(newValue);
2245
- if (isValid(newValue)) onChange?.(newValue);
2246
- setTimeout(() => {
2247
- inputRef.current?.focus();
2248
- const length = inputRef.current?.value.length || 0;
2249
- inputRef.current?.setSelectionRange(length, length);
2250
- }, 0);
2251
- };
2252
- useEvents({ "form:change": (event) => {
2253
- if (event.id === inputRef.current?.form?.id) {
2254
- if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
2255
- }
2256
- } }, []);
2257
- return /* @__PURE__ */ jsxs(Popover, {
2258
- width: 800,
2259
- position: "bottom-start",
2260
- shadow: "md",
2261
- opened: helpOpened,
2262
- onChange: setHelpOpened,
2263
- closeOnClickOutside: true,
2264
- closeOnEscape: true,
2265
- transitionProps: {
2266
- transition: "fade-up",
2267
- duration: 200,
2268
- timingFunction: "ease"
2269
- },
2270
- children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
2271
- ref: inputRef,
2272
- placeholder,
2273
- value: textValue,
2274
- onChange: (e) => handleTextChange(e.currentTarget.value),
2275
- onFocus: () => setHelpOpened(true),
2276
- leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
2277
- rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
2278
- size: "sm",
2279
- variant: "subtle",
2280
- color: "gray",
2281
- onClick: handleClear,
2282
- children: /* @__PURE__ */ jsx(IconX, { size: 14 })
2283
- }),
2284
- ...textInputProps
2285
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
2286
- bg: "transparent",
2287
- p: "xs",
2288
- bd: `1px solid ${ui.colors.border}`,
2289
- style: { backdropFilter: "blur(20px)" },
2290
- children: /* @__PURE__ */ jsx(QueryHelp, {
2291
- fields,
2292
- onInsert: handleInsert
2293
- })
2294
- })]
2295
- });
2296
- };
2297
- function QueryHelp({ fields, onInsert }) {
3426
+ //#region ../../src/core/form/components/ControlQueryBuilderHelp.tsx
3427
+ const ControlQueryBuilderHelp = (props) => {
3428
+ const { fields, onInsert } = props;
2298
3429
  return /* @__PURE__ */ jsxs(Flex, {
2299
3430
  gap: "md",
2300
3431
  align: "flex-start",
@@ -2455,113 +3586,316 @@ function QueryHelp({ fields, onInsert }) {
2455
3586
  }, field.path))
2456
3587
  })]
2457
3588
  })
2458
- ]
3589
+ ]
3590
+ });
3591
+ };
3592
+
3593
+ //#endregion
3594
+ //#region ../../src/core/form/components/ControlQueryBuilder.tsx
3595
+ /**
3596
+ * Query builder with text input and help popover.
3597
+ * Generates query strings for parseQueryString syntax.
3598
+ */
3599
+ const ControlQueryBuilder = (props) => {
3600
+ const { schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps } = props;
3601
+ const [helpOpened, setHelpOpened] = useState(false);
3602
+ const [textValue, setTextValue] = useState(value);
3603
+ const inputRef = useRef(null);
3604
+ const fields = schema ? extractSchemaFields(schema) : [];
3605
+ const [error, setError] = useState(null);
3606
+ const isValid = (value) => {
3607
+ try {
3608
+ parseQueryString(value.trim());
3609
+ } catch (e) {
3610
+ setError(e.message);
3611
+ return false;
3612
+ }
3613
+ setError(null);
3614
+ return true;
3615
+ };
3616
+ const handleTextChange = (newValue) => {
3617
+ setTextValue(newValue);
3618
+ if (isValid(newValue)) onChange?.(newValue);
3619
+ };
3620
+ const handleClear = () => {
3621
+ setTextValue("");
3622
+ onChange?.("");
3623
+ isValid("");
3624
+ };
3625
+ const handleInsert = (text) => {
3626
+ const newValue = textValue ? `${textValue}${text} ` : `${text} `;
3627
+ setTextValue(newValue);
3628
+ if (isValid(newValue)) onChange?.(newValue);
3629
+ setTimeout(() => {
3630
+ inputRef.current?.focus();
3631
+ const length = inputRef.current?.value.length || 0;
3632
+ inputRef.current?.setSelectionRange(length, length);
3633
+ }, 0);
3634
+ };
3635
+ useEvents({ "form:change": (event) => {
3636
+ if (event.id === inputRef.current?.form?.id) {
3637
+ if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
3638
+ }
3639
+ } }, []);
3640
+ return /* @__PURE__ */ jsxs(Popover, {
3641
+ width: 800,
3642
+ position: "bottom-start",
3643
+ shadow: "md",
3644
+ opened: helpOpened,
3645
+ onChange: setHelpOpened,
3646
+ closeOnClickOutside: true,
3647
+ closeOnEscape: true,
3648
+ transitionProps: {
3649
+ transition: "fade-up",
3650
+ duration: 200,
3651
+ timingFunction: "ease"
3652
+ },
3653
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
3654
+ ref: inputRef,
3655
+ placeholder,
3656
+ value: textValue,
3657
+ onChange: (e) => handleTextChange(e.currentTarget.value),
3658
+ onFocus: () => setHelpOpened(true),
3659
+ leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
3660
+ rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
3661
+ size: "sm",
3662
+ variant: "subtle",
3663
+ color: "gray",
3664
+ onClick: handleClear,
3665
+ children: /* @__PURE__ */ jsx(IconX, { size: 14 })
3666
+ }),
3667
+ ...textInputProps
3668
+ }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3669
+ bg: "transparent",
3670
+ p: "xs",
3671
+ bd: `1px solid ${ui.colors.border}`,
3672
+ style: { backdropFilter: "blur(20px)" },
3673
+ children: /* @__PURE__ */ jsx(ControlQueryBuilderHelp, {
3674
+ fields,
3675
+ onInsert: handleInsert
3676
+ })
3677
+ })]
2459
3678
  });
2460
- }
3679
+ };
2461
3680
 
2462
3681
  //#endregion
2463
3682
  //#region ../../src/core/form/components/ControlSelect.tsx
2464
3683
  /**
2465
- * ControlSelect component for handling Select, MultiSelect, and TagsInput.
3684
+ * ControlSelect component for handling Select, MultiSelect, Autocomplete, and TagsInput.
2466
3685
  *
2467
3686
  * Features:
2468
3687
  * - Basic Select with enum support
2469
3688
  * - MultiSelect for array of enums
2470
- * - TagsInput for array of strings (no enum)
2471
- * - Future: Lazy loading
2472
- * - Future: Searchable/filterable options
2473
- * - Future: Custom option rendering
3689
+ * - Autocomplete for creatable single values
3690
+ * - TagsInput for creatable array values
3691
+ * - Async lazy loading with auto short/long mode detection
3692
+ * - Short mode: client-side filtering with cached data
3693
+ * - Long mode: debounced server search
2474
3694
  *
2475
3695
  * Automatically detects enum values and array types from schema.
2476
3696
  */
2477
3697
  const ControlSelect = (props) => {
2478
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
3698
+ const form = useFormState(props.input);
3699
+ const [value, setValue] = useFieldValue(props.input);
3700
+ const { inputProps, id, icon } = parseInput(props, form);
2479
3701
  const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
2480
- let itemsEnum;
2481
- if (isArray && "items" in props.input.schema && props.input.schema.items) {
2482
- const items = props.input.schema.items;
2483
- if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
2484
- }
3702
+ const isNumeric = props.input.schema && "type" in props.input.schema && (props.input.schema.type === "integer" || props.input.schema.type === "number");
3703
+ const isBoolean = props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean";
2485
3704
  const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
2486
- const [data, setData] = useState([]);
3705
+ const { data: asyncData, loading, mode, search } = useAsyncLoader(props.loader, props.loaderThreshold ?? 100, props.loaderDebounce ?? 300, props.input.initialValue);
3706
+ const [staticData, setStaticData] = useState([]);
3707
+ const enumKey = JSON.stringify(enumValues);
2487
3708
  useEffect(() => {
2488
- if (!props.input?.props) return;
2489
- if (props.loader) props.loader().then(setData);
2490
- else setData(enumValues);
2491
- }, [props.input, props.loader]);
3709
+ if (!props.input?.props || props.loader) return;
3710
+ if (isBoolean && enumValues.length === 0) setStaticData([{
3711
+ value: "true",
3712
+ label: "True"
3713
+ }, {
3714
+ value: "false",
3715
+ label: "False"
3716
+ }]);
3717
+ else setStaticData(enumValues);
3718
+ }, [
3719
+ props.input,
3720
+ props.loader,
3721
+ enumKey,
3722
+ isBoolean
3723
+ ]);
3724
+ const data = props.loader ? asyncData : staticData;
2492
3725
  if (!props.input?.props) return null;
2493
- if (props.segmented) {
2494
- const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
3726
+ /**
3727
+ * Coerce value for numeric schemas Select values are always strings.
3728
+ */
3729
+ const coerceValue = (val) => {
3730
+ if (val == null) return val;
3731
+ if (isNumeric) return Number(val);
3732
+ if (isBoolean) return val === "true";
3733
+ return val;
3734
+ };
3735
+ if (props.segmentedProps) {
3736
+ const segmentedControlProps = typeof props.segmentedProps === "object" ? props.segmentedProps : {};
3737
+ const segmentedData = segmentedControlProps.data ?? data.slice(0, 10);
2495
3738
  return /* @__PURE__ */ jsx(Input.Wrapper, {
2496
3739
  ...inputProps,
2497
- children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(SegmentedControl, {
2498
- disabled: inputProps.disabled,
2499
- defaultValue: String(props.input.props.defaultValue),
2500
- ...segmentedControlProps,
2501
- onChange: (value) => {
2502
- props.input.set(value);
2503
- },
2504
- data: data.slice(0, 10)
2505
- }) })
3740
+ children: /* @__PURE__ */ jsx(Flex, {
3741
+ my: "calc(var(--mantine-spacing-xs) / 2)",
3742
+ children: /* @__PURE__ */ jsx(SegmentedControl, {
3743
+ disabled: inputProps.disabled,
3744
+ value: value != null ? String(value) : "",
3745
+ ...segmentedControlProps,
3746
+ onChange: (val) => {
3747
+ setValue(coerceValue(val));
3748
+ },
3749
+ data: segmentedData
3750
+ })
3751
+ })
2506
3752
  });
2507
3753
  }
2508
- if (props.autocomplete) {
2509
- const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
2510
- return /* @__PURE__ */ jsx(Autocomplete, {
3754
+ const sharedProps = {
3755
+ size: props.size,
3756
+ id,
3757
+ leftSection: loading ? /* @__PURE__ */ jsx(Loader, {
3758
+ color: "gray",
3759
+ size: 10
3760
+ }) : icon,
3761
+ data
3762
+ };
3763
+ const selectableProps = {
3764
+ ...sharedProps,
3765
+ searchable: true,
3766
+ rightSection: /* @__PURE__ */ jsx("span", {})
3767
+ };
3768
+ const longModeProps = mode === "long" ? {
3769
+ filter: ({ options }) => options,
3770
+ onSearchChange: search.run
3771
+ } : {};
3772
+ if (props.creatable && (isArray || props.tagsInputProps)) {
3773
+ const tagsInputExtraProps = props.tagsInputProps ?? {};
3774
+ return /* @__PURE__ */ jsx(TagsInput, {
2511
3775
  ...inputProps,
2512
- size: props.size,
2513
- id,
2514
- leftSection: icon,
2515
- data,
2516
- ...props.input.props,
2517
- ...autocompleteProps
3776
+ ...sharedProps,
3777
+ ...longModeProps,
3778
+ value: Array.isArray(value) ? value : [],
3779
+ onChange: (val) => {
3780
+ setValue(val);
3781
+ },
3782
+ ...tagsInputExtraProps
2518
3783
  });
2519
3784
  }
2520
- if (isArray && !itemsEnum || props.tags) {
2521
- const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
2522
- return /* @__PURE__ */ jsx(TagsInput, {
3785
+ if (props.creatable) {
3786
+ const autocompleteExtraProps = props.autocompleteProps ?? {};
3787
+ return /* @__PURE__ */ jsx(Autocomplete, {
2523
3788
  ...inputProps,
2524
- size: props.size,
2525
- id,
2526
- leftSection: icon,
2527
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
2528
- onChange: (value) => {
2529
- props.input.set(value);
3789
+ ...sharedProps,
3790
+ ...longModeProps,
3791
+ value: value != null ? String(value) : "",
3792
+ onChange: (val) => {
3793
+ setValue(coerceValue(val));
2530
3794
  },
2531
- ...tagsInputProps
3795
+ ...autocompleteExtraProps
2532
3796
  });
2533
3797
  }
2534
- if (isArray && itemsEnum || props.multi) {
2535
- const data = itemsEnum?.map((value) => ({
2536
- value,
2537
- label: value
2538
- })) || [];
2539
- const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
3798
+ if (isArray || props.multiSelectProps) {
3799
+ const multiSelectExtraProps = typeof props.multiSelectProps === "object" ? props.multiSelectProps : {};
2540
3800
  return /* @__PURE__ */ jsx(MultiSelect, {
2541
3801
  ...inputProps,
2542
- size: props.size,
2543
- id,
2544
- leftSection: icon,
2545
- data,
2546
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
2547
- onChange: (value) => {
2548
- props.input.set(value);
3802
+ ...selectableProps,
3803
+ ...longModeProps,
3804
+ value: Array.isArray(value) ? value : [],
3805
+ onChange: (val) => {
3806
+ setValue(val);
2549
3807
  },
2550
- ...multiSelectProps
3808
+ ...multiSelectExtraProps
2551
3809
  });
2552
3810
  }
2553
- const selectProps = typeof props.select === "object" ? props.select : {};
3811
+ const selectExtraProps = typeof props.selectProps === "object" ? props.selectProps : {};
3812
+ if (mode === "static") return /* @__PURE__ */ jsx(Select, {
3813
+ ...inputProps,
3814
+ ...selectableProps,
3815
+ value: value != null ? String(value) : null,
3816
+ onChange: (val) => {
3817
+ setValue(coerceValue(val));
3818
+ },
3819
+ ...selectExtraProps
3820
+ });
2554
3821
  return /* @__PURE__ */ jsx(Select, {
2555
3822
  ...inputProps,
2556
- size: props.size,
2557
- id,
2558
- leftSection: icon,
2559
- rightSection: null,
2560
- data,
2561
- ...props.input.props,
2562
- ...selectProps
3823
+ ...selectableProps,
3824
+ ...longModeProps,
3825
+ value: value != null ? String(value) : null,
3826
+ onChange: (val) => {
3827
+ setValue(coerceValue(val));
3828
+ },
3829
+ ...selectExtraProps
2563
3830
  });
2564
3831
  };
3832
+ /**
3833
+ * Hook for async select data loading with auto short/long mode detection.
3834
+ */
3835
+ const useAsyncLoader = (loader, threshold, debounceMs, defaultValue) => {
3836
+ const [data, setData] = useState([]);
3837
+ const [loading, setLoading] = useState(false);
3838
+ const [mode, setMode] = useState("static");
3839
+ const cache = useRef(/* @__PURE__ */ new Map());
3840
+ useAction({
3841
+ name: "select:loader:init",
3842
+ runOnInit: true,
3843
+ handler: async () => {
3844
+ if (!loader) {
3845
+ setMode("static");
3846
+ return;
3847
+ }
3848
+ setLoading(true);
3849
+ try {
3850
+ const result = await loader("");
3851
+ const isShort = result.length <= threshold;
3852
+ setMode(isShort ? "short" : "long");
3853
+ cache.current.set("", result);
3854
+ setData(result);
3855
+ if (!isShort && defaultValue != null && String(defaultValue) !== "") {
3856
+ const resolved = await loader("", [String(defaultValue)]);
3857
+ if (resolved.length > 0) setData((prev) => {
3858
+ const existing = new Set(prev.map((d) => typeof d === "string" ? d : d.value));
3859
+ const newItems = resolved.filter((r) => {
3860
+ const val = typeof r === "string" ? r : r.value;
3861
+ return !existing.has(val);
3862
+ });
3863
+ return [...prev, ...newItems];
3864
+ });
3865
+ }
3866
+ } finally {
3867
+ setLoading(false);
3868
+ }
3869
+ }
3870
+ }, [loader, threshold]);
3871
+ return {
3872
+ data,
3873
+ loading,
3874
+ mode,
3875
+ search: useAction({
3876
+ debounce: debounceMs,
3877
+ handler: async (text) => {
3878
+ if (!loader || mode !== "long") return;
3879
+ if (cache.current.has(text)) {
3880
+ setData(cache.current.get(text));
3881
+ return;
3882
+ }
3883
+ setLoading(true);
3884
+ try {
3885
+ const result = await loader(text);
3886
+ cache.current.set(text, result);
3887
+ setData(result);
3888
+ } finally {
3889
+ setLoading(false);
3890
+ }
3891
+ }
3892
+ }, [
3893
+ loader,
3894
+ mode,
3895
+ debounceMs
3896
+ ])
3897
+ };
3898
+ };
2565
3899
 
2566
3900
  //#endregion
2567
3901
  //#region ../../src/core/form/components/Control.tsx
@@ -2591,6 +3925,7 @@ const ControlSelect = (props) => {
2591
3925
  */
2592
3926
  const Control = (_props) => {
2593
3927
  const form = useFormState(_props.input, ["error"]);
3928
+ const [value, setValue] = useFieldValue(_props.input);
2594
3929
  if (!_props.input?.props) return null;
2595
3930
  const { inputProps, id, icon, format, schema } = parseInput(_props, form);
2596
3931
  const props = {
@@ -2598,12 +3933,11 @@ const Control = (_props) => {
2598
3933
  ...schema.$control
2599
3934
  };
2600
3935
  if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder, {
2601
- ...props.input.props,
2602
3936
  ...inputProps,
2603
3937
  schema: props.query,
2604
- value: props.input.props.value,
2605
- onChange: (value) => {
2606
- props.input.set(value);
3938
+ value,
3939
+ onChange: (val) => {
3940
+ setValue(val);
2607
3941
  }
2608
3942
  });
2609
3943
  if (props.custom) {
@@ -2614,9 +3948,9 @@ const Control = (_props) => {
2614
3948
  flex: 1,
2615
3949
  mt: "calc(var(--mantine-spacing-xs) / 2)",
2616
3950
  children: /* @__PURE__ */ jsx(Custom, {
2617
- defaultValue: props.input.props.defaultValue,
2618
- onChange: (value) => {
2619
- props.input.set(value);
3951
+ value,
3952
+ onChange: (val) => {
3953
+ setValue(val);
2620
3954
  }
2621
3955
  })
2622
3956
  })
@@ -2627,7 +3961,7 @@ const Control = (_props) => {
2627
3961
  const controlObjectProps = typeof props.object === "object" ? props.object : {};
2628
3962
  return /* @__PURE__ */ jsx(ControlObject, {
2629
3963
  input: props.input,
2630
- title: props.title,
3964
+ label: props.label,
2631
3965
  description: props.description,
2632
3966
  ...controlObjectProps
2633
3967
  });
@@ -2638,18 +3972,18 @@ const Control = (_props) => {
2638
3972
  const controlArrayProps = typeof props.array === "object" ? props.array : {};
2639
3973
  return /* @__PURE__ */ jsx(ControlArray, {
2640
3974
  input: props.input,
2641
- title: props.title,
3975
+ label: props.label,
2642
3976
  description: props.description,
2643
3977
  ...controlArrayProps
2644
3978
  });
2645
3979
  }
2646
- if (props.number || props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
3980
+ if (props.number || !props.select && props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
2647
3981
  const controlNumberProps = typeof props.number === "object" ? props.number : {};
2648
3982
  if (props.slider) controlNumberProps.sliderProps ??= {};
2649
3983
  return /* @__PURE__ */ jsx(ControlNumber, {
2650
3984
  size: props.size,
2651
3985
  input: props.input,
2652
- title: props.title,
3986
+ label: props.label,
2653
3987
  description: props.description,
2654
3988
  icon,
2655
3989
  ...controlNumberProps
@@ -2662,9 +3996,7 @@ const Control = (_props) => {
2662
3996
  size: props.size,
2663
3997
  id,
2664
3998
  leftSection: icon,
2665
- onChange: (file) => {
2666
- props.input.set(file);
2667
- },
3999
+ onChange: (file) => setValue(file),
2668
4000
  ...fileInputProps
2669
4001
  });
2670
4002
  }
@@ -2675,17 +4007,18 @@ const Control = (_props) => {
2675
4007
  size: props.size,
2676
4008
  id,
2677
4009
  leftSection: icon,
2678
- ...props.input.props,
4010
+ value: value ?? "",
4011
+ onChange: (val) => setValue(val),
2679
4012
  ...colorInputProps
2680
4013
  });
2681
4014
  }
2682
4015
  if (props.input.schema && "enum" in props.input.schema && props.input.schema.enum || isArray && !isArrayOfObjects || props.select) {
2683
4016
  const opts = typeof props.select === "object" ? props.select : {};
2684
- if (props.segmented) opts.segmented ??= {};
4017
+ if (props.segmented) opts.segmentedProps ??= {};
2685
4018
  return /* @__PURE__ */ jsx(ControlSelect, {
2686
4019
  size: props.size,
2687
4020
  input: props.input,
2688
- title: props.title,
4021
+ label: props.label,
2689
4022
  description: props.description,
2690
4023
  icon,
2691
4024
  ...opts
@@ -2699,16 +4032,16 @@ const Control = (_props) => {
2699
4032
  size: props.size,
2700
4033
  id,
2701
4034
  color: "blue",
2702
- defaultChecked: props.input.props.defaultValue,
4035
+ checked: Boolean(value),
2703
4036
  onChange: (event) => {
2704
- props.input.set(event.currentTarget.checked);
4037
+ setValue(event.currentTarget.checked);
2705
4038
  },
2706
4039
  ...switchProps
2707
4040
  });
2708
4041
  }
2709
4042
  const opts = {
2710
4043
  input: props.input,
2711
- select: { data: [{
4044
+ selectProps: { data: [{
2712
4045
  value: "true",
2713
4046
  label: "Yes"
2714
4047
  }, {
@@ -2718,7 +4051,7 @@ const Control = (_props) => {
2718
4051
  };
2719
4052
  return /* @__PURE__ */ jsx(ControlSelect, {
2720
4053
  size: props.size,
2721
- title: props.title,
4054
+ label: props.label,
2722
4055
  description: props.description,
2723
4056
  icon,
2724
4057
  ...opts
@@ -2731,7 +4064,8 @@ const Control = (_props) => {
2731
4064
  size: props.size,
2732
4065
  id,
2733
4066
  leftSection: icon,
2734
- ...props.input.props,
4067
+ value: value ?? "",
4068
+ onChange: (ev) => setValue(ev.target.value),
2735
4069
  ...passwordInputProps
2736
4070
  });
2737
4071
  }
@@ -2742,14 +4076,15 @@ const Control = (_props) => {
2742
4076
  size: props.size,
2743
4077
  id,
2744
4078
  leftSection: icon,
2745
- ...props.input.props,
4079
+ value: value ?? "",
4080
+ onChange: (ev) => setValue(ev.target.value),
2746
4081
  ...textAreaProps
2747
4082
  });
2748
4083
  }
2749
4084
  if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate, {
2750
4085
  size: props.size,
2751
4086
  input: props.input,
2752
- title: props.title,
4087
+ label: props.label,
2753
4088
  description: props.description,
2754
4089
  icon,
2755
4090
  date: props.date,
@@ -2764,7 +4099,7 @@ const Control = (_props) => {
2764
4099
  case "uri": return "url";
2765
4100
  case "tel":
2766
4101
  case "phone": return "tel";
2767
- default: return;
4102
+ default: return props.input.props.type ?? "text";
2768
4103
  }
2769
4104
  };
2770
4105
  return /* @__PURE__ */ jsx(TextInput, {
@@ -2773,14 +4108,9 @@ const Control = (_props) => {
2773
4108
  id,
2774
4109
  leftSection: icon,
2775
4110
  type: getInputType(),
2776
- ...props.input.props,
2777
- ...textInputProps,
2778
- inputWrapperOrder: [
2779
- "label",
2780
- "input",
2781
- "description",
2782
- "error"
2783
- ]
4111
+ value: value ?? "",
4112
+ onChange: (ev) => setValue(ev.target.value),
4113
+ ...textInputProps
2784
4114
  });
2785
4115
  };
2786
4116
 
@@ -2829,6 +4159,7 @@ const Control = (_props) => {
2829
4159
  */
2830
4160
  const TypeForm = (props) => {
2831
4161
  const { form, columns = 3, children, controlProps, fieldControlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps, fill = true, size } = props;
4162
+ const { dirty } = useFormState(form, ["dirty"]);
2832
4163
  const schema = props.schema || form.options.schema;
2833
4164
  if (!schema?.properties) return null;
2834
4165
  const supportedFields = Object.keys(schema.properties);
@@ -2891,10 +4222,12 @@ const TypeForm = (props) => {
2891
4222
  children: [/* @__PURE__ */ jsx(ActionButton, {
2892
4223
  variant: "subtle",
2893
4224
  type: "reset",
4225
+ disabled: !dirty,
2894
4226
  children: "Reset"
2895
4227
  }), /* @__PURE__ */ jsx(ActionButton, {
2896
4228
  intent: "primary",
2897
4229
  form,
4230
+ disabled: !dirty,
2898
4231
  ...submitButtonProps,
2899
4232
  children: submitButtonProps?.children ?? "Submit"
2900
4233
  })]
@@ -2913,39 +4246,14 @@ const TypeForm = (props) => {
2913
4246
  });
2914
4247
  };
2915
4248
 
2916
- //#endregion
2917
- //#region ../../src/core/helpers/renderIcon.tsx
2918
- const renderIcon = (icon, size) => {
2919
- if (!icon) return null;
2920
- if (isValidElement(icon)) return icon;
2921
- if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
2922
- return icon;
2923
- };
2924
-
2925
- //#endregion
2926
- //#region ../../src/core/hooks/useDialog.ts
2927
- /**
2928
- * Use this hook to access the Dialog Service for showing various dialog types.
2929
- *
2930
- * @example
2931
- * ```tsx
2932
- * const dialog = useDialog();
2933
- * await dialog.alert({ title: "Alert", message: "This is an alert message" });
2934
- * const confirmed = await dialog.confirm({ title: "Confirm", message: "Are you sure?" });
2935
- * const input = await dialog.prompt({ title: "Input", message: "Enter your name:" });
2936
- * ```
2937
- */
2938
- const useDialog = () => {
2939
- return useInject(DialogService);
2940
- };
2941
-
2942
4249
  //#endregion
2943
4250
  //#region ../../src/core/table/interfaces/types.ts
2944
4251
  const DEFAULT_MAX_VISIBLE_COLUMNS = 8;
2945
4252
 
2946
4253
  //#endregion
2947
4254
  //#region ../../src/core/table/components/DataTableFilters.tsx
2948
- const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) => {
4255
+ const DataTableFilters = (props) => {
4256
+ const { schema, form, typeFormProps, filterVisibility } = props;
2949
4257
  const visibleSchema = useMemo(() => {
2950
4258
  const visibleKeys = Object.keys(schema.properties).filter((key) => filterVisibility[key] !== false);
2951
4259
  if (visibleKeys.length === 0) return null;
@@ -2956,13 +4264,14 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
2956
4264
  return t.object(visibleProps);
2957
4265
  }, [schema, filterVisibility]);
2958
4266
  if (!visibleSchema) return null;
2959
- return /* @__PURE__ */ jsx(Flex, {
2960
- w: "100%",
4267
+ return /* @__PURE__ */ jsx(Flex$1, {
4268
+ surface: true,
4269
+ flex: 1,
4270
+ mt: -4,
2961
4271
  p: "xs",
2962
- bg: ui.colors.surface,
2963
- style: { borderBottom: "1px solid var(--alepha-border)" },
4272
+ m: "xs",
4273
+ bdrs: "md",
2964
4274
  children: /* @__PURE__ */ jsx(TypeForm, {
2965
- size: "xs",
2966
4275
  ...typeFormProps,
2967
4276
  skipSubmitButton: true,
2968
4277
  fill: true,
@@ -2973,7 +4282,7 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
2973
4282
  sm: 2,
2974
4283
  md: 3,
2975
4284
  lg: 4,
2976
- xl: 6
4285
+ xl: 5
2977
4286
  }
2978
4287
  })
2979
4288
  });
@@ -2981,48 +4290,64 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
2981
4290
 
2982
4291
  //#endregion
2983
4292
  //#region ../../src/core/table/components/DataTablePagination.tsx
2984
- const DataTablePagination = ({ page, size, totalPages, onPageChange, onSizeChange }) => {
2985
- return /* @__PURE__ */ jsxs(Flex, {
4293
+ const DataTablePagination = ({ page, size, totalPages, totalElements, isFirst, isLast, offset, numberOfElements, onPageChange, onSizeChange }) => {
4294
+ const from = numberOfElements > 0 ? offset + 1 : 0;
4295
+ const to = offset + numberOfElements;
4296
+ const hasTotal = totalPages != null;
4297
+ return /* @__PURE__ */ jsxs(Flex$1, {
2986
4298
  align: "center",
2987
- justify: "end",
4299
+ justify: "space-between",
2988
4300
  gap: "md",
2989
- p: "xs",
4301
+ px: "xs",
4302
+ py: 4,
2990
4303
  style: { borderTop: "1px solid var(--alepha-border)" },
2991
- children: [/* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(Select, {
2992
- w: 96,
2993
- variant: "default",
2994
- value: size,
2995
- onChange: (value) => {
2996
- if (value) onSizeChange(Number(value));
2997
- },
2998
- data: [
2999
- {
3000
- value: "5",
3001
- label: "5"
3002
- },
3003
- {
3004
- value: "10",
3005
- label: "10"
3006
- },
3007
- {
3008
- value: "25",
3009
- label: "25"
3010
- },
3011
- {
3012
- value: "50",
3013
- label: "50"
4304
+ children: [/* @__PURE__ */ jsx(Flex$1, {
4305
+ align: "center",
4306
+ children: /* @__PURE__ */ jsx(Text$1, {
4307
+ size: "xs",
4308
+ c: "dimmed",
4309
+ children: totalElements != null ? `Showing ${from} - ${to} of ${totalElements}` : `Showing ${from} - ${to}`
4310
+ })
4311
+ }), /* @__PURE__ */ jsxs(Flex$1, {
4312
+ align: "center",
4313
+ gap: "md",
4314
+ children: [/* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(Select, {
4315
+ color: "gray",
4316
+ c: "gray",
4317
+ size: "xs",
4318
+ w: 96,
4319
+ variant: "default",
4320
+ value: size,
4321
+ onChange: (value) => {
4322
+ if (value) onSizeChange(Number(value));
3014
4323
  },
3015
- {
3016
- value: "100",
3017
- label: "100"
3018
- }
3019
- ]
3020
- }) }), /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(Pagination, {
3021
- withEdges: true,
3022
- total: totalPages,
3023
- value: page,
3024
- onChange: onPageChange
3025
- }) })]
4324
+ data: [
4325
+ {
4326
+ value: "10",
4327
+ label: "10"
4328
+ },
4329
+ {
4330
+ value: "25",
4331
+ label: "25"
4332
+ },
4333
+ {
4334
+ value: "50",
4335
+ label: "50"
4336
+ },
4337
+ {
4338
+ value: "100",
4339
+ label: "100"
4340
+ }
4341
+ ]
4342
+ }) }), /* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(Pagination, {
4343
+ size: "sm",
4344
+ withEdges: hasTotal,
4345
+ withPages: hasTotal,
4346
+ total: hasTotal ? totalPages : isLast !== false ? page : page + 1,
4347
+ value: page,
4348
+ onChange: onPageChange
4349
+ }) })]
4350
+ })]
3026
4351
  });
3027
4352
  };
3028
4353
 
@@ -3069,7 +4394,7 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3069
4394
  timingFunction: "ease"
3070
4395
  },
3071
4396
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
3072
- variant: "subtle",
4397
+ variant: "minimal",
3073
4398
  icon: IconColumns,
3074
4399
  onClick: () => setOpened((o) => !o)
3075
4400
  }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
@@ -3099,12 +4424,12 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3099
4424
  gap: 4,
3100
4425
  children: [/* @__PURE__ */ jsx(ActionButton, {
3101
4426
  size: "compact-xs",
3102
- variant: "subtle",
4427
+ variant: "minimal",
3103
4428
  onClick: handleShowAll,
3104
4429
  children: "All"
3105
4430
  }), /* @__PURE__ */ jsx(ActionButton, {
3106
4431
  size: "compact-xs",
3107
- variant: "subtle",
4432
+ variant: "minimal",
3108
4433
  onClick: handleDefault,
3109
4434
  children: "Default"
3110
4435
  })]
@@ -3170,7 +4495,7 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3170
4495
  timingFunction: "ease"
3171
4496
  },
3172
4497
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
3173
- variant: "subtle",
4498
+ variant: "minimal",
3174
4499
  icon: IconFilter,
3175
4500
  onClick: () => setOpened((o) => !o)
3176
4501
  }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
@@ -3200,12 +4525,12 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3200
4525
  gap: 4,
3201
4526
  children: [/* @__PURE__ */ jsx(ActionButton, {
3202
4527
  size: "compact-xs",
3203
- variant: "subtle",
4528
+ variant: "minimal",
3204
4529
  onClick: handleShowAll,
3205
4530
  children: "All"
3206
4531
  }), /* @__PURE__ */ jsx(ActionButton, {
3207
4532
  size: "compact-xs",
3208
- variant: "subtle",
4533
+ variant: "minimal",
3209
4534
  onClick: handleHideAll,
3210
4535
  children: "None"
3211
4536
  })]
@@ -3244,7 +4569,7 @@ const extractText = (node) => {
3244
4569
  const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility, onColumnVisibilityChange, onFilterVisibilityChange, actions, onRefresh, items, withExport, selectedItems = [], checkboxActions, onClearSelection }) => {
3245
4570
  const hasSelection = selectedItems.length > 0;
3246
4571
  const exportableColumns = useCallback(() => {
3247
- return Object.entries(columns).filter(([key, col]) => !col.actions && columnVisibility[key] !== false);
4572
+ return Object.entries(columns).filter(([key]) => columnVisibility[key] !== false);
3248
4573
  }, [columns, columnVisibility]);
3249
4574
  const buildRows = useCallback(() => {
3250
4575
  const cols = exportableColumns();
@@ -3281,11 +4606,10 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3281
4606
  };
3282
4607
  await action.onClick(ctx);
3283
4608
  };
3284
- return /* @__PURE__ */ jsxs(Flex, {
4609
+ return /* @__PURE__ */ jsxs(Flex$1, {
3285
4610
  p: "xs",
3286
- style: { borderBottom: "1px solid var(--alepha-border)" },
3287
4611
  children: [
3288
- /* @__PURE__ */ jsxs(Flex, {
4612
+ /* @__PURE__ */ jsxs(Flex$1, {
3289
4613
  gap: 4,
3290
4614
  align: "center",
3291
4615
  children: [
@@ -3300,7 +4624,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3300
4624
  onVisibilityChange: onColumnVisibilityChange
3301
4625
  }),
3302
4626
  withExport && /* @__PURE__ */ jsx(ActionButton, {
3303
- variant: "subtle",
4627
+ variant: "minimal",
3304
4628
  icon: IconDownload,
3305
4629
  menu: { items: [{
3306
4630
  label: "Export as CSV",
@@ -3323,7 +4647,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3323
4647
  children: [selectedItems.length, " selected"]
3324
4648
  }),
3325
4649
  /* @__PURE__ */ jsx(ActionButton, {
3326
- variant: "subtle",
4650
+ variant: "minimal",
3327
4651
  size: "compact-sm",
3328
4652
  icon: IconX,
3329
4653
  onClick: onClearSelection,
@@ -3340,14 +4664,14 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3340
4664
  ] })
3341
4665
  ]
3342
4666
  }),
3343
- /* @__PURE__ */ jsx(Flex, { flex: 1 }),
3344
- /* @__PURE__ */ jsxs(Flex, {
4667
+ /* @__PURE__ */ jsx(Flex$1, { flex: 1 }),
4668
+ /* @__PURE__ */ jsxs(Flex$1, {
3345
4669
  gap: "xs",
3346
4670
  children: [actions?.map((props, index) => !isValidElement(props) ? /* @__PURE__ */ jsx(ActionButton, {
3347
4671
  ...props,
3348
4672
  children: props.label
3349
4673
  }, index) : props), /* @__PURE__ */ jsx(ActionButton, {
3350
- variant: "subtle",
4674
+ variant: "minimal",
3351
4675
  icon: IconRefresh,
3352
4676
  onClick: onRefresh
3353
4677
  })]
@@ -3456,12 +4780,16 @@ const FIT_STYLE = {
3456
4780
  };
3457
4781
  const DataTable = (props) => {
3458
4782
  const [items, setItems] = useState(typeof props.items === "function" ? { content: [] } : props.items);
3459
- const defaultSize = props.infinityScroll ? 100 : props.defaultSize || 10;
4783
+ const itemsRef = useRef(items);
4784
+ const [loaded, setLoaded] = useState(typeof props.items !== "function" || !props.submitOnInit);
4785
+ const defaultSize = props.defaultSize || (props.infinityScroll ? 100 : 10);
3460
4786
  const [page, setPage] = useState(1);
3461
4787
  const [size, setSize] = useState(String(defaultSize));
3462
4788
  const [currentPage, setCurrentPage] = useState(0);
3463
4789
  const alepha = useInject(Alepha);
4790
+ itemsRef.current = items;
3464
4791
  const sentinelRef = useRef(null);
4792
+ const debounceRef = useRef(null);
3465
4793
  const [columnVisibility, setColumnVisibility] = useState(() => {
3466
4794
  const entries = Object.entries(props.columns);
3467
4795
  let visibleCount = 0;
@@ -3534,13 +4862,14 @@ const DataTable = (props) => {
3534
4862
  }),
3535
4863
  handler: async (values) => {
3536
4864
  if (typeof props.items === "function") {
3537
- const response = await props.items(values, { items: items.content });
4865
+ const response = await props.items(values, { items: itemsRef.current.content });
3538
4866
  if (props.infinityScroll && values.page > 0) setItems((prev) => ({
3539
4867
  ...response,
3540
4868
  content: [...prev.content, ...response.content]
3541
4869
  }));
3542
4870
  else setItems(response);
3543
4871
  setCurrentPage(values.page);
4872
+ if (!loaded) setLoaded(true);
3544
4873
  }
3545
4874
  },
3546
4875
  onReset: async () => {
@@ -3560,9 +4889,23 @@ const DataTable = (props) => {
3560
4889
  return;
3561
4890
  }
3562
4891
  props.onFilterChange?.(key, value, form);
4892
+ if (props.skipSubmitOnChange) return;
4893
+ form.input.page.set(0);
4894
+ const delay = props.debounce ?? 300;
4895
+ if (delay > 0) {
4896
+ if (debounceRef.current) clearTimeout(debounceRef.current);
4897
+ debounceRef.current = setTimeout(() => {
4898
+ form.submit();
4899
+ }, delay);
4900
+ } else await form.submit();
3563
4901
  }
3564
- }, [items]);
4902
+ }, []);
3565
4903
  const dt = useInject(DateTimeProvider);
4904
+ useEffect(() => {
4905
+ return () => {
4906
+ if (debounceRef.current) clearTimeout(debounceRef.current);
4907
+ };
4908
+ }, []);
3566
4909
  useEffect(() => {
3567
4910
  if (props.submitOnInit) form.submit();
3568
4911
  if (props.submitEvery) {
@@ -3593,7 +4936,7 @@ const DataTable = (props) => {
3593
4936
  currentPage,
3594
4937
  form
3595
4938
  ]);
3596
- const totalColumns = visibleColumns.length + (panelConfig ? 1 : 0) + (props.withCheckbox ? 1 : 0);
4939
+ const totalColumns = visibleColumns.length + (panelConfig ? 1 : 0) + (props.withCheckbox ? 1 : 0) + (props.rowActions ? 1 : 0);
3597
4940
  const checkboxHeader = props.withCheckbox ? /* @__PURE__ */ jsx(Table.Th, {
3598
4941
  style: { width: 40 },
3599
4942
  children: /* @__PURE__ */ jsx(Checkbox, {
@@ -3616,18 +4959,20 @@ const DataTable = (props) => {
3616
4959
  userSelect: "none"
3617
4960
  } : {}
3618
4961
  },
3619
- children: /* @__PURE__ */ jsxs(Flex, {
4962
+ children: /* @__PURE__ */ jsxs(Flex$1, {
3620
4963
  align: "center",
3621
4964
  gap: 4,
3622
- children: [/* @__PURE__ */ jsx(Text, {
4965
+ children: [/* @__PURE__ */ jsx(Text$1, {
4966
+ bold: true,
4967
+ muted: true,
3623
4968
  size: "xs",
3624
4969
  children: col.label
3625
- }), col.sortable && /* @__PURE__ */ jsxs(Flex, {
4970
+ }), col.sortable && /* @__PURE__ */ jsxs(Flex$1, {
3626
4971
  c: "dimmed",
3627
4972
  children: [
3628
- sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.sm }),
3629
- sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.sm }),
3630
- sortDir === null && /* @__PURE__ */ jsx(IconArrowsSort, { size: ui.sizes.icon.sm })
4973
+ sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.xs }),
4974
+ sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.xs }),
4975
+ sortDir === null && /* @__PURE__ */ jsx(IconArrowsSort, { size: ui.sizes.icon.xs })
3631
4976
  ]
3632
4977
  })]
3633
4978
  })
@@ -3664,7 +5009,7 @@ const DataTable = (props) => {
3664
5009
  toggleExpand(itemKey);
3665
5010
  },
3666
5011
  style: { display: "inline-flex" },
3667
- children: /* @__PURE__ */ jsx(Flex, {
5012
+ children: /* @__PURE__ */ jsx(Flex$1, {
3668
5013
  c: "dimmed",
3669
5014
  align: "center",
3670
5015
  justify: "center",
@@ -3687,32 +5032,49 @@ const DataTable = (props) => {
3687
5032
  form,
3688
5033
  alepha
3689
5034
  };
3690
- if (col.actions) {
3691
- const rowActions = col.actions(item, ctx).filter((a) => a.visible !== false);
3692
- return /* @__PURE__ */ jsx(Table.Td, {
3693
- py: 2,
3694
- px: 4,
3695
- style: col.fit ? FIT_STYLE : void 0,
3696
- onClick: (e) => e.stopPropagation(),
3697
- children: /* @__PURE__ */ jsx(Flex, {
3698
- gap: 4,
3699
- children: rowActions.map(({ visible: _, ...actionProps }, i) => /* @__PURE__ */ jsx(ActionButton, {
3700
- variant: "subtle",
3701
- size: "xs",
3702
- preventDefault: true,
3703
- h: 20,
3704
- ...actionProps
3705
- }, i))
3706
- })
3707
- }, key);
3708
- }
5035
+ const content = col.value?.(item, ctx);
3709
5036
  return /* @__PURE__ */ jsx(Table.Td, {
3710
- py: 2,
3711
- px: 4,
3712
5037
  style: col.fit ? FIT_STYLE : void 0,
3713
- children: col.value?.(item, ctx)
5038
+ children: col.action ? /* @__PURE__ */ jsx(ActionButton, {
5039
+ td: "inherit",
5040
+ unstyled: true,
5041
+ ...col.action(item),
5042
+ children: content
5043
+ }) : content
3714
5044
  }, key);
3715
- })
5045
+ }),
5046
+ props.rowActions && (() => {
5047
+ const ctx = {
5048
+ index,
5049
+ form,
5050
+ alepha
5051
+ };
5052
+ const actions = props.rowActions(item, ctx).filter((a) => a.visible !== false);
5053
+ if (actions.length === 0) return /* @__PURE__ */ jsx(Table.Td, { style: FIT_STYLE });
5054
+ return /* @__PURE__ */ jsx(Table.Td, {
5055
+ py: 2,
5056
+ px: 4,
5057
+ style: FIT_STYLE,
5058
+ onClick: (e) => e.stopPropagation(),
5059
+ children: /* @__PURE__ */ jsx(ActionButton, {
5060
+ variant: "minimal",
5061
+ size: "xs",
5062
+ icon: IconDotsVertical,
5063
+ menu: { items: actions.map((action) => {
5064
+ const Icon = action.icon;
5065
+ return {
5066
+ label: action.label ?? (typeof action.tooltip === "string" ? action.tooltip : void 0),
5067
+ icon: Icon && isComponentType(Icon) ? /* @__PURE__ */ jsx(Icon, { size: 14 }) : Icon,
5068
+ onClick: action.onClick ? async () => {
5069
+ await action.onClick();
5070
+ if (!action.skipRefresh) await form.submit();
5071
+ } : void 0,
5072
+ color: action.color
5073
+ };
5074
+ }) }
5075
+ })
5076
+ });
5077
+ })()
3716
5078
  ]
3717
5079
  }, itemKey)];
3718
5080
  if (panelConfig && showPanel && isExpanded) elements.push(/* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
@@ -3730,13 +5092,19 @@ const DataTable = (props) => {
3730
5092
  "sort"
3731
5093
  ]);
3732
5094
  }, [props.filters, form.options.schema]);
3733
- return /* @__PURE__ */ jsxs(Flex, {
5095
+ return /* @__PURE__ */ jsxs(Flex$1, {
5096
+ gap: "xs",
3734
5097
  flex: 1,
3735
5098
  p: 0,
3736
- bdrs: "sm",
3737
5099
  direction: "column",
3738
- children: [
3739
- /* @__PURE__ */ jsx(DataTableToolbar, {
5100
+ style: { overflow: "hidden" },
5101
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
5102
+ rounded: true,
5103
+ bordered: true,
5104
+ elevated: true,
5105
+ shadowed: "xs",
5106
+ col: true,
5107
+ children: [/* @__PURE__ */ jsx(DataTableToolbar, {
3740
5108
  columns: props.columns,
3741
5109
  filters: props.filters,
3742
5110
  columnVisibility,
@@ -3750,71 +5118,97 @@ const DataTable = (props) => {
3750
5118
  selectedItems: selection.selectedItems,
3751
5119
  checkboxActions: props.checkboxActions,
3752
5120
  onClearSelection: selection.clear
3753
- }),
3754
- filterSchema && props.filters && /* @__PURE__ */ jsx(DataTableFilters, {
5121
+ }), filterSchema && props.filters && /* @__PURE__ */ jsx(DataTableFilters, {
3755
5122
  schema: filterSchema,
3756
5123
  form,
3757
5124
  typeFormProps: props.typeFormProps,
3758
5125
  filterVisibility
3759
- }),
3760
- /* @__PURE__ */ jsx(Flex, {
3761
- className: "overflow-auto",
3762
- children: /* @__PURE__ */ jsxs(Table, {
3763
- "aria-label": "Data table",
3764
- withColumnBorders: true,
3765
- withRowBorders: true,
3766
- ...props.tableProps,
3767
- children: [/* @__PURE__ */ jsx(Table.Thead, {
3768
- style: {
3769
- position: "sticky",
3770
- top: 0,
3771
- zIndex: 1,
3772
- backgroundColor: "var(--mantine-color-body)"
3773
- },
3774
- children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
3775
- panelConfig && /* @__PURE__ */ jsx(Table.Th, { style: { width: 36 } }),
3776
- checkboxHeader,
3777
- head
3778
- ] })
3779
- }), /* @__PURE__ */ jsxs(Table.Tbody, {
3780
- style: {
3781
- opacity: form.submitting ? .5 : 1,
3782
- transition: "opacity 150ms ease"
3783
- },
3784
- children: [rows, items.content.length === 0 && /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
5126
+ })]
5127
+ }), /* @__PURE__ */ jsxs(Flex$1, {
5128
+ col: true,
5129
+ rounded: true,
5130
+ bordered: true,
5131
+ elevated: true,
5132
+ shadowed: "xs",
5133
+ flex: 1,
5134
+ style: { minHeight: 0 },
5135
+ children: [
5136
+ /* @__PURE__ */ jsx(Flex$1, {
5137
+ className: "overflow-auto",
5138
+ flex: 1,
5139
+ style: { minHeight: 0 },
5140
+ col: true,
5141
+ children: /* @__PURE__ */ jsxs(Table, {
5142
+ "aria-label": "Data table",
5143
+ withRowBorders: true,
5144
+ highlightOnHover: true,
5145
+ ...props.tableProps,
5146
+ children: [/* @__PURE__ */ jsx(Table.Thead, {
5147
+ bdrs: "md",
5148
+ style: {
5149
+ position: "sticky",
5150
+ top: 0,
5151
+ zIndex: 1,
5152
+ backgroundColor: "var(--alepha-elevated)"
5153
+ },
5154
+ children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
5155
+ panelConfig && /* @__PURE__ */ jsx(Table.Th, { style: { width: 36 } }),
5156
+ checkboxHeader,
5157
+ head,
5158
+ props.rowActions && /* @__PURE__ */ jsx(Table.Th, { style: FIT_STYLE })
5159
+ ] })
5160
+ }), /* @__PURE__ */ jsx(Table.Tbody, { children: !loaded || form.submitting ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
5161
+ colSpan: totalColumns || 1,
5162
+ py: "sm",
5163
+ children: /* @__PURE__ */ jsx(Flex$1, {
5164
+ justify: "center",
5165
+ p: "md",
5166
+ children: /* @__PURE__ */ jsx(Loader, {
5167
+ size: "sm",
5168
+ type: "dots"
5169
+ })
5170
+ })
5171
+ }) }) : rows.length === 0 ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
3785
5172
  colSpan: totalColumns || 1,
3786
5173
  py: "xl",
3787
- style: { textAlign: "center" },
3788
- children: /* @__PURE__ */ jsx(Text, {
3789
- c: "dimmed",
3790
- size: "sm",
3791
- children: form.submitting ? "Loading…" : "No results"
5174
+ children: /* @__PURE__ */ jsx(Flex$1, {
5175
+ justify: "center",
5176
+ children: /* @__PURE__ */ jsx(Text$1, {
5177
+ c: "dimmed",
5178
+ size: "sm",
5179
+ children: props.emptyLabel ?? "No results"
5180
+ })
3792
5181
  })
3793
- }) })]
3794
- })]
5182
+ }) }) : rows })]
5183
+ })
5184
+ }),
5185
+ props.infinityScroll && /* @__PURE__ */ jsx("div", { ref: sentinelRef }),
5186
+ !props.infinityScroll && /* @__PURE__ */ jsx(DataTablePagination, {
5187
+ page,
5188
+ size,
5189
+ totalPages: items.page?.totalPages,
5190
+ totalElements: items.page?.totalElements,
5191
+ isFirst: items.page?.isFirst,
5192
+ isLast: items.page?.isLast,
5193
+ offset: items.page?.offset ?? 0,
5194
+ numberOfElements: items.content.length,
5195
+ onPageChange: (value) => {
5196
+ form.input.page.set(value - 1);
5197
+ },
5198
+ onSizeChange: (value) => {
5199
+ form.input.size.set(value);
5200
+ }
5201
+ }),
5202
+ drawerConfig && /* @__PURE__ */ jsx(Drawer, {
5203
+ opened: drawerItem !== null,
5204
+ onClose: () => setDrawerItem(null),
5205
+ position: "right",
5206
+ size: "xl",
5207
+ ...drawerConfig.props,
5208
+ children: drawerItem && drawerConfig.render(drawerItem)
3795
5209
  })
3796
- }),
3797
- props.infinityScroll && /* @__PURE__ */ jsx("div", { ref: sentinelRef }),
3798
- !props.infinityScroll && /* @__PURE__ */ jsx(DataTablePagination, {
3799
- page,
3800
- size,
3801
- totalPages: items.page?.totalPages ?? 1,
3802
- onPageChange: (value) => {
3803
- form.input.page.set(value - 1);
3804
- },
3805
- onSizeChange: (value) => {
3806
- form.input.size.set(value);
3807
- }
3808
- }),
3809
- drawerConfig && /* @__PURE__ */ jsx(Drawer, {
3810
- opened: drawerItem !== null,
3811
- onClose: () => setDrawerItem(null),
3812
- position: "right",
3813
- size: "xl",
3814
- ...drawerConfig.props,
3815
- children: drawerItem && drawerConfig.render(drawerItem)
3816
- })
3817
- ]
5210
+ ]
5211
+ })]
3818
5212
  });
3819
5213
  };
3820
5214
 
@@ -3913,8 +5307,8 @@ const OPERATOR_INFO = {
3913
5307
  * Get the default icon for an input based on its type, format, or name.
3914
5308
  */
3915
5309
  const getDefaultIcon = (params) => {
3916
- const { type, format, name, isEnum, isArray, size = "sm" } = params;
3917
- const iconSize = ui.sizes.icon[size];
5310
+ const { type, format, name, isEnum, isArray, size = "xs" } = params;
5311
+ const iconSize = ui.sizes.icon[size] - 4;
3918
5312
  if (format) switch (format) {
3919
5313
  case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
3920
5314
  case "url":
@@ -4027,5 +5421,5 @@ const AlephaUI = $module({
4027
5421
  });
4028
5422
 
4029
5423
  //#endregion
4030
- export { ActionButton as _, TypeForm as a, useToast as b, DashboardShell as c, StatCards as d, DetailList as f, ClipboardButton as g, LanguageButton as h, useDialog as i, Breadcrumb as l, ThemeButton as m, capitalize as n, Control as o, ToggleSidebarButton as p, DataTable as r, Text$1 as s, AlephaUI as t, Flex$1 as u, ui as v, AlephaMantineProvider as y };
4031
- //# sourceMappingURL=core-2xoLiT0o.js.map
5424
+ export { ActionButton as _, Control as a, useToast as b, Breadcrumb as c, DetailList as d, ToggleSidebarButton as f, ClipboardButton as g, LanguageButton as h, TypeForm as i, Flex$1 as l, useDialog as m, capitalize as n, DashboardShell as o, ThemeButton as p, DataTable as r, Text$1 as s, AlephaUI as t, StatCards as u, ui as v, alephaSidebarAtom as x, AlephaMantineProvider as y };
5425
+ //# sourceMappingURL=core-CYaRQ8O-.js.map