@alepha/ui 0.18.2 → 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 (231) hide show
  1. package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Dy_k-4Vd.js} +2 -2
  2. package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Dy_k-4Vd.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-CKiFMSSU.js} +2 -2
  4. package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-CKiFMSSU.js.map} +1 -1
  5. package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-PhC_dZqo.js} +2 -2
  6. package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-PhC_dZqo.js.map} +1 -1
  7. package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-DFTjijGp.js} +2 -2
  8. package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-DFTjijGp.js.map} +1 -1
  9. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BL8gGPDp.js} +2 -2
  10. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js.map → AdminJobDashboard-BL8gGPDp.js.map} +1 -1
  11. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D9E-CS-U.js} +2 -2
  12. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D9E-CS-U.js.map} +1 -1
  13. package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-Ci9ue1zC.js} +2 -2
  14. package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-Ci9ue1zC.js.map} +1 -1
  15. package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-I6TlUMPc.js} +2 -2
  16. package/dist/admin/{AdminLayout-B1DXZHDn.js.map → AdminLayout-I6TlUMPc.js.map} +1 -1
  17. package/dist/admin/AdminNotifications-ZPHCYrv7.js +542 -0
  18. package/dist/admin/AdminNotifications-ZPHCYrv7.js.map +1 -0
  19. package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CqgvhRsb.js} +120 -105
  20. package/dist/admin/AdminParameters-CqgvhRsb.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions-Bz5NRuoW.js} +2 -2
  22. package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions-Bz5NRuoW.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-lXT6I0Qq.js} +14 -8
  24. package/dist/admin/AdminUserLayout-lXT6I0Qq.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-vFBLoJ3h.js} +3 -3
  26. package/dist/admin/{AdminUserProfile-DuTUnjdG.js.map → AdminUserProfile-vFBLoJ3h.js.map} +1 -1
  27. package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-CT_YDim0.js} +2 -2
  28. package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-CT_YDim0.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-D1UfGya9.js} +2 -2
  30. package/dist/admin/{AdminUsers-CR9z0g_5.js.map → AdminUsers-D1UfGya9.js.map} +1 -1
  31. package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-_frhdgOO.js} +2 -2
  32. package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-_frhdgOO.js.map} +1 -1
  33. package/dist/admin/Login-xtNmQtGh.js +275 -0
  34. package/dist/admin/Login-xtNmQtGh.js.map +1 -0
  35. package/dist/admin/{Profile-B2EcIDB9.js → Profile-_AtPUwAP.js} +31 -27
  36. package/dist/admin/Profile-_AtPUwAP.js.map +1 -0
  37. package/dist/admin/{Register-Z3fxRbUF.js → Register-JcCjHUUn.js} +198 -142
  38. package/dist/admin/Register-JcCjHUUn.js.map +1 -0
  39. package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-CwGBPLJO.js} +7 -7
  40. package/dist/admin/ResetPassword-CwGBPLJO.js.map +1 -0
  41. package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-hNxWejWf.js} +23 -8
  42. package/dist/admin/VerifyEmail-hNxWejWf.js.map +1 -0
  43. package/dist/admin/{core-BVO_TQxb.js → core-CYaRQ8O-.js} +709 -556
  44. package/dist/admin/core-CYaRQ8O-.js.map +1 -0
  45. package/dist/admin/index.d.ts +83 -44
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +58 -39
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/auth/{AuthLayout-C161NeF6.js → AuthLayout-AvLlcLjS.js} +2 -2
  50. package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-AvLlcLjS.js.map} +1 -1
  51. package/dist/auth/Login-BA1E8IZl.js +275 -0
  52. package/dist/auth/Login-BA1E8IZl.js.map +1 -0
  53. package/dist/auth/{Profile-BMpXJ0oi.js → Profile-YcWdeuFz.js} +31 -27
  54. package/dist/auth/Profile-YcWdeuFz.js.map +1 -0
  55. package/dist/auth/{Register-2gx8qll-.js → Register-CPhEO5MG.js} +198 -142
  56. package/dist/auth/Register-CPhEO5MG.js.map +1 -0
  57. package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-DCtGcneA.js} +7 -7
  58. package/dist/auth/ResetPassword-DCtGcneA.js.map +1 -0
  59. package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-DkH7NBfn.js} +23 -8
  60. package/dist/auth/VerifyEmail-DkH7NBfn.js.map +1 -0
  61. package/dist/auth/{core-DyfeVr5c.js → core-D5jIAVF2.js} +386 -294
  62. package/dist/auth/core-D5jIAVF2.js.map +1 -0
  63. package/dist/auth/index.d.ts +93 -48
  64. package/dist/auth/index.d.ts.map +1 -1
  65. package/dist/auth/index.js +28 -24
  66. package/dist/auth/index.js.map +1 -1
  67. package/dist/core/index.d.ts +116 -61
  68. package/dist/core/index.d.ts.map +1 -1
  69. package/dist/core/index.js +873 -701
  70. package/dist/core/index.js.map +1 -1
  71. package/dist/demo/{AuthLayout-DN-ClJQk.js → AuthLayout-Brri4A-L.js} +2 -2
  72. package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Brri4A-L.js.map} +1 -1
  73. package/dist/demo/DemoButton-wiCxZZ_L.js +182 -0
  74. package/dist/demo/DemoButton-wiCxZZ_L.js.map +1 -0
  75. package/dist/demo/DemoControlSelect-D7ILObVg.js +305 -0
  76. package/dist/demo/DemoControlSelect-D7ILObVg.js.map +1 -0
  77. package/dist/demo/DemoDataTable-DZ5Y8pFX.js +362 -0
  78. package/dist/demo/DemoDataTable-DZ5Y8pFX.js.map +1 -0
  79. package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-CUWdLHim.js} +2 -2
  80. package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-CUWdLHim.js.map} +1 -1
  81. package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-a8OhMMvq.js} +3 -3
  82. package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-a8OhMMvq.js.map} +1 -1
  83. package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C13OVDfS.js} +3 -3
  84. package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C13OVDfS.js.map} +1 -1
  85. package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-D_De3UiT.js} +2 -2
  86. package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-D_De3UiT.js.map} +1 -1
  87. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-B50s9aGM.js} +3 -3
  88. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-B50s9aGM.js.map} +1 -1
  89. package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CHU8WTwO.js} +14 -5
  90. package/dist/demo/DemoLayout-CHU8WTwO.js.map +1 -0
  91. package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-BBlrWpml.js} +49 -32
  92. package/dist/demo/DemoLogin-BBlrWpml.js.map +1 -0
  93. package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-BuNE3_-f.js} +49 -50
  94. package/dist/demo/DemoRegister-BuNE3_-f.js.map +1 -0
  95. package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-D_IjjjOJ.js} +12 -16
  96. package/dist/demo/DemoResetPassword-D_IjjjOJ.js.map +1 -0
  97. package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-Giy2HRBD.js} +3 -3
  98. package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-Giy2HRBD.js.map} +1 -1
  99. package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-ubcw-vog.js} +3 -3
  100. package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-ubcw-vog.js.map} +1 -1
  101. package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-9die_dYT.js} +2 -2
  102. package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-9die_dYT.js.map} +1 -1
  103. package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-D_d6OVKL.js} +8 -4
  104. package/dist/demo/DemoTypeForm-D_d6OVKL.js.map +1 -0
  105. package/dist/demo/DemoVerifyEmail-B43KlF4F.js +34 -0
  106. package/dist/demo/DemoVerifyEmail-B43KlF4F.js.map +1 -0
  107. package/dist/demo/Login-C12N4oGs.js +275 -0
  108. package/dist/demo/Login-C12N4oGs.js.map +1 -0
  109. package/dist/demo/{Profile-BE_Y3co2.js → Profile-DS5q4vOh.js} +31 -27
  110. package/dist/demo/Profile-DS5q4vOh.js.map +1 -0
  111. package/dist/demo/{Register-fXHmBpr3.js → Register-B4hLBeEv.js} +198 -142
  112. package/dist/demo/Register-B4hLBeEv.js.map +1 -0
  113. package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-D8g9ha1N.js} +7 -7
  114. package/dist/demo/ResetPassword-D8g9ha1N.js.map +1 -0
  115. package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D6Fxt4X4.js} +64 -65
  116. package/dist/demo/Showcase-D6Fxt4X4.js.map +1 -0
  117. package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BjDo0cZA.js} +23 -8
  118. package/dist/demo/VerifyEmail-BjDo0cZA.js.map +1 -0
  119. package/dist/demo/{auth-Djd7SKiw.js → auth-ByVTreDl.js} +8 -8
  120. package/dist/demo/{auth-Djd7SKiw.js.map → auth-ByVTreDl.js.map} +1 -1
  121. package/dist/demo/{core-B7LNjM78.js → core-DFgB3yU4.js} +741 -573
  122. package/dist/demo/core-DFgB3yU4.js.map +1 -0
  123. package/dist/demo/index.d.ts +1 -0
  124. package/dist/demo/index.d.ts.map +1 -1
  125. package/dist/demo/index.js +24 -18
  126. package/dist/demo/index.js.map +1 -1
  127. package/package.json +7 -7
  128. package/src/admin/AdminRouter.tsx +24 -1
  129. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  130. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  131. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  132. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  133. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  134. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  135. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  136. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  137. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  138. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  139. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  140. package/src/auth/components/Login.tsx +188 -121
  141. package/src/auth/components/Profile.tsx +1 -22
  142. package/src/auth/components/ProfileField.tsx +39 -0
  143. package/src/auth/components/Register.tsx +215 -158
  144. package/src/auth/components/ResetPassword.tsx +7 -11
  145. package/src/auth/components/VerifyEmail.tsx +35 -10
  146. package/src/auth/components/buttons/UserButton.tsx +19 -21
  147. package/src/auth/index.ts +1 -0
  148. package/src/core/components/Flex.tsx +10 -0
  149. package/src/core/components/buttons/ActionButton.tsx +104 -78
  150. package/src/core/components/data/DetailDrawer.tsx +102 -96
  151. package/src/core/components/data/DetailList.tsx +2 -1
  152. package/src/core/components/layout/Breadcrumb.tsx +3 -6
  153. package/src/core/components/layout/DashboardShell.tsx +18 -4
  154. package/src/core/components/layout/Sidebar.tsx +16 -241
  155. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  156. package/src/core/components/layout/SidebarItem.tsx +146 -0
  157. package/src/core/components/layout/index.ts +3 -1
  158. package/src/core/form/components/Control.tsx +31 -29
  159. package/src/core/form/components/ControlArray.tsx +13 -39
  160. package/src/core/form/components/ControlDate.tsx +10 -21
  161. package/src/core/form/components/ControlNumber.tsx +4 -33
  162. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  163. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  164. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  165. package/src/core/form/components/ControlSelect.tsx +294 -92
  166. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  167. package/src/core/form/components/TypeForm.tsx +5 -2
  168. package/src/core/form/index.ts +8 -1
  169. package/src/core/form/utils/parseInput.ts +7 -3
  170. package/src/core/index.ts +3 -1
  171. package/src/core/json/components/JsonViewer.tsx +103 -319
  172. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  173. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  174. package/src/core/json/components/JsonViewerShared.ts +76 -0
  175. package/src/core/styles.css +12 -2
  176. package/src/core/table/components/ColumnPicker.tsx +3 -3
  177. package/src/core/table/components/DataTable.tsx +89 -29
  178. package/src/core/table/components/DataTableFilters.tsx +6 -11
  179. package/src/core/table/components/DataTablePagination.tsx +9 -3
  180. package/src/core/table/components/DataTableToolbar.tsx +7 -3
  181. package/src/core/table/components/FilterPicker.tsx +3 -3
  182. package/src/core/table/interfaces/types.ts +29 -0
  183. package/src/core/utils/icons.tsx +2 -2
  184. package/src/demo/DemoRouter.ts +8 -1
  185. package/src/demo/components/DemoLayout.tsx +12 -2
  186. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  187. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  188. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  189. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  190. package/src/demo/components/core/DemoButton.tsx +123 -103
  191. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  192. package/src/demo/components/core/DemoDataTable.tsx +255 -237
  193. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  194. package/src/demo/components/shared/MacWindow.tsx +5 -11
  195. package/src/demo/components/shared/Showcase.tsx +28 -42
  196. package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
  197. package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
  198. package/dist/admin/Login-DHbYJKwg.js +0 -219
  199. package/dist/admin/Login-DHbYJKwg.js.map +0 -1
  200. package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
  201. package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
  202. package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
  203. package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
  204. package/dist/admin/core-BVO_TQxb.js.map +0 -1
  205. package/dist/auth/Login-C7jIqf00.js +0 -219
  206. package/dist/auth/Login-C7jIqf00.js.map +0 -1
  207. package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
  208. package/dist/auth/Register-2gx8qll-.js.map +0 -1
  209. package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
  210. package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
  211. package/dist/auth/core-DyfeVr5c.js.map +0 -1
  212. package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
  213. package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
  214. package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
  215. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
  216. package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
  217. package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
  218. package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
  219. package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
  220. package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
  221. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
  222. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
  223. package/dist/demo/Login-CoYf_P_F.js +0 -219
  224. package/dist/demo/Login-CoYf_P_F.js.map +0 -1
  225. package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
  226. package/dist/demo/Register-fXHmBpr3.js.map +0 -1
  227. package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
  228. package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
  229. package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
  230. package/dist/demo/core-B7LNjM78.js.map +0 -1
  231. package/src/demo/styles.css +0 -0
@@ -1,5 +1,5 @@
1
1
  import { $atom, $context, $inject, $module, Alepha, AlephaError, TypeBoxError, t } from "alepha";
2
- import { AlephaReactForm, FormValidationError, useForm, useFormState } from "alepha/react/form";
2
+ import { AlephaReactForm, FormValidationError, useFieldValue, useForm, useFormState } from "alepha/react/form";
3
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";
@@ -1548,41 +1548,10 @@ function isComponentType(param) {
1548
1548
 
1549
1549
  //#endregion
1550
1550
  //#region ../../src/core/components/buttons/ActionButton.tsx
1551
- const ActionMenuItem = (props) => {
1552
- const { item, index } = props;
1553
- const router = useRouter();
1554
- const action = useAction({ handler: async (e) => {
1555
- await item.onClick?.();
1556
- } }, [item.onClick]);
1557
- if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
1558
- if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
1559
- if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
1560
- trigger: "hover",
1561
- position: "right-start",
1562
- offset: 2,
1563
- children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
1564
- leftSection: item.icon,
1565
- rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
1566
- children: item.label
1567
- }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
1568
- item: child,
1569
- index: childIndex
1570
- }, childIndex)) })]
1571
- }, index);
1572
- const menuItemProps = {};
1573
- if (props.item.onClick) menuItemProps.onClick = action.run;
1574
- else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
1575
- return /* @__PURE__ */ jsx(Menu.Item, {
1576
- leftSection: item.icon ?? (item.active ? /* @__PURE__ */ jsx(IconCheck, { size: ui.sizes.icon.sm }) : /* @__PURE__ */ jsx(Flex, { w: ui.sizes.icon.sm })),
1577
- onClick: item.onClick,
1578
- color: item.color,
1579
- ...menuItemProps,
1580
- children: item.label
1581
- }, index);
1582
- };
1583
1551
  const ActionButton = (_props) => {
1584
1552
  const theme = useMantineTheme();
1585
1553
  const props = { ..._props };
1554
+ if (props.variant === "minimal") {}
1586
1555
  const { tooltip, menu, icon, iconSize, ...restProps } = props;
1587
1556
  if (props.intent) {
1588
1557
  if (props.intent === "primary") restProps.color ??= theme.primaryColor;
@@ -1627,6 +1596,7 @@ const ActionButton = (_props) => {
1627
1596
  children: /* @__PURE__ */ jsx(ActionButton, {
1628
1597
  px: "xs",
1629
1598
  ...rest,
1599
+ "aria-label": typeof children === "string" ? children : void 0,
1630
1600
  tooltip,
1631
1601
  menu,
1632
1602
  children: leftSection
@@ -1783,7 +1753,7 @@ const ActionClickButton = ({ preventDefault, ...props }) => {
1783
1753
  * Action for navigation with active state support.
1784
1754
  */
1785
1755
  const ActionNavigationButton = (props) => {
1786
- 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;
1787
1757
  const router = useRouter();
1788
1758
  const { isPending, isActive } = useActive(options ? {
1789
1759
  href: props.href,
@@ -1797,11 +1767,11 @@ const ActionNavigationButton = (props) => {
1797
1767
  };
1798
1768
  const className = buttonProps.className || "";
1799
1769
  if (isActive && options !== false && classNameActive) buttonProps.className = `${className} ${classNameActive}`.trim();
1800
- if (props.anchorProps || anchor) return /* @__PURE__ */ jsx(Anchor, {
1770
+ if (buttonAnchorProps || anchor) return /* @__PURE__ */ jsx(Anchor, {
1801
1771
  component: "a",
1802
1772
  ...anchorProps,
1803
1773
  ...buttonProps,
1804
- ...props.anchorProps,
1774
+ ...buttonAnchorProps,
1805
1775
  onClick: combinedOnClick,
1806
1776
  children: props.children
1807
1777
  });
@@ -1824,6 +1794,38 @@ const ActionHrefButton = (props) => {
1824
1794
  children: props.children
1825
1795
  });
1826
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
+ };
1827
1829
 
1828
1830
  //#endregion
1829
1831
  //#region ../../src/core/components/buttons/BurgerButton.tsx
@@ -2234,7 +2236,8 @@ const ToggleSidebarButton = (props) => {
2234
2236
 
2235
2237
  //#endregion
2236
2238
  //#region ../../src/core/components/data/DetailList.tsx
2237
- const DetailList = ({ items, columns = 1 }) => {
2239
+ const DetailList = (props) => {
2240
+ const { items, columns = 1 } = props;
2238
2241
  return /* @__PURE__ */ jsx(Grid, {
2239
2242
  gutter: "xs",
2240
2243
  children: items.filter((item) => !item.hidden).map((item) => /* @__PURE__ */ jsx(Grid.Col, {
@@ -2313,7 +2316,7 @@ const StatCards = ({ items }) => /* @__PURE__ */ jsx(Flex, {
2313
2316
  //#endregion
2314
2317
  //#region ../../src/core/components/Flex.tsx
2315
2318
  const Flex$1 = forwardRef((props, ref) => {
2316
- const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, ...rest } = props;
2319
+ const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, overflow, ...rest } = props;
2317
2320
  if (fill) rest.flex ??= 1;
2318
2321
  if (col) rest.direction ??= "column";
2319
2322
  if (center) {
@@ -2336,6 +2339,7 @@ const Flex$1 = forwardRef((props, ref) => {
2336
2339
  ...rest.style ?? {}
2337
2340
  };
2338
2341
  if (shadowed) rest.className = `${rest.className ?? ""} shadow-${shadowed === true ? "md" : shadowed}`.trim();
2342
+ if (overflow) rest.className = `${rest.className ?? ""} overflow-auto`.trim();
2339
2343
  return /* @__PURE__ */ jsx(Flex, {
2340
2344
  ref,
2341
2345
  ...rest
@@ -2467,7 +2471,8 @@ const AppBar = (props) => {
2467
2471
  * Pages should define a `label` in their `$page()` options for best results.
2468
2472
  * Falls back to the page name converted to Title Case.
2469
2473
  */
2470
- const Breadcrumb = ({ home = "Home", separator, size = "sm", ...groupProps }) => {
2474
+ const Breadcrumb = (props) => {
2475
+ const { home = "Home", separator, size = "sm", ...groupProps } = props;
2471
2476
  const state = useRouterState();
2472
2477
  const router = useRouter();
2473
2478
  const crumbs = [];
@@ -2522,11 +2527,175 @@ const Container$1 = forwardRef((props, ref) => {
2522
2527
  });
2523
2528
  Container$1.displayName = "Container";
2524
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
+
2525
2695
  //#endregion
2526
2696
  //#region ../../src/core/components/layout/Sidebar.tsx
2527
2697
  const Sidebar = (props) => {
2528
2698
  const router = useRouter();
2529
- const { onItemClick } = props;
2530
2699
  const divider = (key, fill, collapsed) => {
2531
2700
  return /* @__PURE__ */ jsx(Flex$1, {
2532
2701
  h: 1,
@@ -2577,13 +2746,13 @@ const Sidebar = (props) => {
2577
2746
  if (collapsed) return /* @__PURE__ */ jsx(SidebarCollapsedItem, {
2578
2747
  item,
2579
2748
  level: 0,
2580
- onItemClick,
2749
+ onItemClick: props.onItemClick,
2581
2750
  theme: props.theme ?? {}
2582
2751
  }, key);
2583
2752
  return /* @__PURE__ */ jsx(SidebarItem, {
2584
2753
  item,
2585
2754
  level: 0,
2586
- onItemClick,
2755
+ onItemClick: props.onItemClick,
2587
2756
  theme: props.theme ?? {}
2588
2757
  }, key);
2589
2758
  };
@@ -2646,129 +2815,6 @@ const Sidebar = (props) => {
2646
2815
  })] });
2647
2816
  return renderSidebar(false);
2648
2817
  };
2649
- const SidebarItem = (props) => {
2650
- const { item, level } = props;
2651
- const maxLevel = 2;
2652
- const router = useRouter();
2653
- const isActive = useCallback((item) => {
2654
- if (!item.children) return false;
2655
- for (const child of item.children) {
2656
- if (child.href) {
2657
- if (router.isActive(child.href)) return true;
2658
- }
2659
- if (isActive(child)) return true;
2660
- }
2661
- return false;
2662
- }, []);
2663
- const [isOpen, setIsOpen] = useState(isActive(item));
2664
- useEvents({ "react:transition:end": () => {
2665
- if (isActive(item)) setIsOpen(true);
2666
- } }, []);
2667
- if (level > maxLevel) return null;
2668
- const handleItemClick = (e) => {
2669
- if (!props.item.target) e.preventDefault();
2670
- if (item.children && item.children.length > 0) setIsOpen(!isOpen);
2671
- else {
2672
- props.onItemClick?.(item);
2673
- item.onClick?.();
2674
- }
2675
- };
2676
- return /* @__PURE__ */ jsxs(Flex$1, {
2677
- direction: "column",
2678
- ps: level === 0 ? 0 : 32,
2679
- pos: "relative",
2680
- children: [/* @__PURE__ */ jsx(ActionButton, {
2681
- w: "100%",
2682
- justify: "space-between",
2683
- href: props.item.href,
2684
- target: props.item.target,
2685
- size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
2686
- bd: 0,
2687
- fw: "normal",
2688
- variant: "default",
2689
- propsActive: { variant: "outline" },
2690
- radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
2691
- onClick: handleItemClick,
2692
- leftSection: /* @__PURE__ */ jsxs(Flex$1, {
2693
- w: "100%",
2694
- align: "center",
2695
- gap: "sm",
2696
- children: [renderIcon(item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Flex$1, {
2697
- direction: "column",
2698
- children: /* @__PURE__ */ jsx(Flex$1, { children: item.label })
2699
- })]
2700
- }),
2701
- rightSection: item.children ? /* @__PURE__ */ jsx(Flex$1, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
2702
- ...props.item.actionProps
2703
- }), item.children && isOpen && /* @__PURE__ */ jsxs(Flex$1, {
2704
- direction: "column",
2705
- "data-parent-level": level,
2706
- gap: 2,
2707
- py: 2,
2708
- children: [/* @__PURE__ */ jsx(Flex$1, { style: {
2709
- position: "absolute",
2710
- width: 1,
2711
- background: "linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
2712
- top: 48,
2713
- left: 20 + 32 * level,
2714
- bottom: 16
2715
- } }), item.children.filter((child) => !child.can || child.can()).map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
2716
- item: child,
2717
- level: level + 1,
2718
- onItemClick: props.onItemClick,
2719
- theme: props.theme
2720
- }, index))]
2721
- })]
2722
- });
2723
- };
2724
- const SidebarCollapsedItem = (props) => {
2725
- const { item, level } = props;
2726
- const router = useRouter();
2727
- const handleItemClick = () => {
2728
- props.onItemClick?.(item);
2729
- item.onClick?.();
2730
- };
2731
- const hasChildren = item.children && item.children.length > 0;
2732
- const menu = hasChildren ? {
2733
- on: "hover",
2734
- position: "right",
2735
- menuProps: {
2736
- arrowPosition: "center",
2737
- arrowSize: 10,
2738
- withArrow: true
2739
- },
2740
- items: [{
2741
- type: "label",
2742
- label: item.label
2743
- }, ...item.children.filter((child) => !child.can || child.can()).map((child) => ({
2744
- label: child.label,
2745
- icon: renderIcon(child.icon, ui.sizes.icon.sm),
2746
- href: child.href,
2747
- active: child.href ? router.isActive(child.href, { startWith: child.activeStartsWith }) : void 0
2748
- }))]
2749
- } : void 0;
2750
- return /* @__PURE__ */ jsx(Flex$1, {
2751
- w: "100%",
2752
- justify: "center",
2753
- pos: "relative",
2754
- children: /* @__PURE__ */ jsx(ActionButton, {
2755
- size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
2756
- bd: 0,
2757
- variant: "default",
2758
- propsActive: { variant: "outline" },
2759
- tooltip: hasChildren ? void 0 : {
2760
- label: item.label,
2761
- position: "right"
2762
- },
2763
- onClick: hasChildren ? void 0 : handleItemClick,
2764
- icon: renderIcon(item.icon, ui.sizes.icon.sm) ?? /* @__PURE__ */ jsx(IconSquareRounded, { size: ui.sizes.icon.sm }),
2765
- href: hasChildren ? void 0 : props.item.href,
2766
- target: hasChildren ? void 0 : props.item.target,
2767
- menu,
2768
- ...props.item.actionProps
2769
- })
2770
- });
2771
- };
2772
2818
 
2773
2819
  //#endregion
2774
2820
  //#region ../../src/core/components/layout/DashboardShell.tsx
@@ -2809,6 +2855,8 @@ const DashboardShell = (props) => {
2809
2855
  const fHeight = props.footerHeight ?? 24;
2810
2856
  const headerHeight = hasAppBar ? hHeight : 0;
2811
2857
  const footerHeight = footerElement ? fHeight : 0;
2858
+ const navbarWidth = collapsed ? collapsedWidth : expandedWidth;
2859
+ const mainContent = props.children ?? /* @__PURE__ */ jsx(NestedView, {});
2812
2860
  return /* @__PURE__ */ jsxs(AppShell, {
2813
2861
  layout: "alt",
2814
2862
  w: "100%",
@@ -2816,7 +2864,7 @@ const DashboardShell = (props) => {
2816
2864
  flex: 1,
2817
2865
  header: hasAppBar ? { height: hHeight } : void 0,
2818
2866
  navbar: hasSidebar ? {
2819
- width: { base: collapsed ? collapsedWidth : expandedWidth },
2867
+ width: { base: navbarWidth },
2820
2868
  breakpoint: "md",
2821
2869
  collapsed: { mobile: sidebar.closed }
2822
2870
  } : void 0,
@@ -2853,8 +2901,12 @@ const DashboardShell = (props) => {
2853
2901
  display: "flex",
2854
2902
  bg: "var(--alepha-ground)",
2855
2903
  pos: "relative",
2904
+ h: props.fill ? "100%" : "inherit",
2856
2905
  ...props.appShellMainProps,
2857
- 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
2858
2910
  }),
2859
2911
  footerElement && /* @__PURE__ */ jsx(AppShell.Footer, {
2860
2912
  ...props.appShellFooterProps,
@@ -2864,41 +2916,12 @@ const DashboardShell = (props) => {
2864
2916
  });
2865
2917
  };
2866
2918
 
2867
- //#endregion
2868
- //#region ../../src/core/components/Text.tsx
2869
- const INTENT_COLORS = {
2870
- primary: "blue",
2871
- info: "cyan",
2872
- success: "green",
2873
- warning: "yellow",
2874
- danger: "red"
2875
- };
2876
- const Text$1 = forwardRef((props, ref) => {
2877
- const { intent, bold, italic, light, muted, small, uppercase, capitalize, center, monospace, title, ...rest } = props;
2878
- if (intent) rest.c ??= INTENT_COLORS[intent];
2879
- if (bold) rest.fw ??= 700;
2880
- if (light) rest.fw ??= 300;
2881
- if (italic) rest.fs ??= "italic";
2882
- if (muted) rest.c ??= "dimmed";
2883
- if (small) rest.size ??= "xs";
2884
- if (uppercase) rest.tt ??= "uppercase";
2885
- if (capitalize) rest.tt ??= "capitalize";
2886
- if (center) rest.ta ??= "center";
2887
- if (monospace) rest.ff ??= "monospace";
2888
- if (title) rest.size ??= "xl";
2889
- return /* @__PURE__ */ jsx(Text, {
2890
- ref,
2891
- ...rest
2892
- });
2893
- });
2894
- Text$1.displayName = "Text";
2895
-
2896
2919
  //#endregion
2897
2920
  //#region ../../src/core/form/utils/parseInput.ts
2898
2921
  const parseInput = (props, form) => {
2899
2922
  const disabled = false;
2900
2923
  const id = props.input.props.id;
2901
- 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);
2902
2925
  const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
2903
2926
  const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
2904
2927
  const icon = !props.icon ? getDefaultIcon({
@@ -2906,17 +2929,20 @@ const parseInput = (props, form) => {
2906
2929
  format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
2907
2930
  name: props.input.props.name,
2908
2931
  isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
2909
- isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
2910
- }) : 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 });
2911
2935
  const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
2912
2936
  const required = props.input.required;
2913
2937
  const schema = props.input.schema;
2938
+ const testId = props.input.props?.["data-testid"];
2914
2939
  const inputProps = {
2915
2940
  label,
2916
2941
  description,
2917
2942
  error,
2918
2943
  required,
2919
- disabled
2944
+ disabled,
2945
+ ...testId ? { "data-testid": testId } : {}
2920
2946
  };
2921
2947
  if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
2922
2948
  if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
@@ -2941,8 +2967,8 @@ const useArrayItems = (input) => {
2941
2967
  const alepha = useAlepha();
2942
2968
  const keyCounter = useRef(0);
2943
2969
  const [items, setItemsState] = useState(() => {
2944
- const defaultValue = input?.props?.defaultValue;
2945
- if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
2970
+ const initial = input?.initialValue;
2971
+ if (Array.isArray(initial)) return initial.map((value) => ({
2946
2972
  key: keyCounter.current++,
2947
2973
  value
2948
2974
  }));
@@ -2968,22 +2994,9 @@ const useArrayItems = (input) => {
2968
2994
  if (!input?.form) return;
2969
2995
  const formId = input.form.id;
2970
2996
  const fieldPath = input.path;
2971
- const listeners = [alepha.events.on("form:reset", (event) => {
2972
- if (event.id === formId) {
2973
- const defaultValue = input.props?.defaultValue;
2974
- keyCounter.current = 0;
2975
- if (Array.isArray(defaultValue)) setItemsState(defaultValue.map((value) => ({
2976
- key: keyCounter.current++,
2977
- value
2978
- })));
2979
- else setItemsState([]);
2980
- }
2981
- }), alepha.events.on("form:change", (event) => {
2997
+ return alepha.events.on("form:change", (event) => {
2982
2998
  if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
2983
- })];
2984
- return () => {
2985
- for (const unsub of listeners) unsub();
2986
- };
2999
+ });
2987
3000
  }, [
2988
3001
  alepha,
2989
3002
  input,
@@ -3008,10 +3021,10 @@ const createArrayItemInput = (parentInput, itemSchema, index, _itemKey, value, o
3008
3021
  path: `${parentInput.path}/${index}`,
3009
3022
  required: false,
3010
3023
  form: parentInput.form,
3024
+ initialValue: value,
3011
3025
  props: {
3012
3026
  id: `${parentInput.props.id}-${index}`,
3013
- name: `${parentInput.props.name}[${index}]`,
3014
- defaultValue: value
3027
+ name: `${parentInput.props.name}[${index}]`
3015
3028
  },
3016
3029
  set: onValueChange
3017
3030
  };
@@ -3026,10 +3039,10 @@ const createArrayItemFieldInput = (parentInput, itemSchema, fieldName, index, _i
3026
3039
  path: `${parentInput.path}/${index}/${fieldName}`,
3027
3040
  required: itemSchema.required?.includes(fieldName) ?? false,
3028
3041
  form: parentInput.form,
3042
+ initialValue: itemValue?.[fieldName],
3029
3043
  props: {
3030
3044
  id: `${parentInput.props.id}-${index}-${fieldName}`,
3031
- name: `${parentInput.props.name}[${index}].${fieldName}`,
3032
- defaultValue: itemValue?.[fieldName]
3045
+ name: `${parentInput.props.name}[${index}].${fieldName}`
3033
3046
  },
3034
3047
  set: (value) => onFieldChange(fieldName, value)
3035
3048
  };
@@ -3247,7 +3260,9 @@ const ControlArray = (props) => {
3247
3260
  * Automatically detects date formats from schema and renders appropriate picker.
3248
3261
  */
3249
3262
  const ControlDate = (props) => {
3250
- 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);
3251
3266
  if (!props.input?.props) return null;
3252
3267
  if (props.datetime || format === "date-time") {
3253
3268
  const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
@@ -3255,10 +3270,8 @@ const ControlDate = (props) => {
3255
3270
  ...inputProps,
3256
3271
  id,
3257
3272
  leftSection: icon,
3258
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
3259
- onChange: (value) => {
3260
- props.input.set(value ? new Date(value).toISOString() : void 0);
3261
- },
3273
+ value: value ? new Date(value) : null,
3274
+ onChange: (val) => setValue(val ? new Date(val).toISOString() : void 0),
3262
3275
  ...dateTimePickerProps
3263
3276
  });
3264
3277
  }
@@ -3268,10 +3281,8 @@ const ControlDate = (props) => {
3268
3281
  ...inputProps,
3269
3282
  id,
3270
3283
  leftSection: icon,
3271
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
3272
- onChange: (value) => {
3273
- props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
3274
- },
3284
+ value: value ? new Date(value) : null,
3285
+ onChange: (val) => setValue(val ? new Date(val).toISOString().slice(0, 10) : void 0),
3275
3286
  ...dateInputProps
3276
3287
  });
3277
3288
  }
@@ -3281,10 +3292,8 @@ const ControlDate = (props) => {
3281
3292
  ...inputProps,
3282
3293
  id,
3283
3294
  leftSection: icon,
3284
- defaultValue: props.input.props.defaultValue,
3285
- onChange: (event) => {
3286
- props.input.set(event.currentTarget.value);
3287
- },
3295
+ value: value ?? "",
3296
+ onChange: (event) => setValue(event.currentTarget.value),
3288
3297
  ...timeInputProps
3289
3298
  });
3290
3299
  }
@@ -3297,14 +3306,10 @@ const ControlDate = (props) => {
3297
3306
  *
3298
3307
  */
3299
3308
  const ControlNumber = (props) => {
3300
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
3301
- const ref = useRef(null);
3302
- const [value, setValue] = useState(props.input.props.defaultValue);
3303
- useEvents({ "form:reset": (event) => {
3304
- if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
3305
- } }, [props.input]);
3309
+ const form = useFormState(props.input);
3310
+ const [value, setValue] = useFieldValue(props.input);
3311
+ const { inputProps, id, icon } = parseInput(props, form);
3306
3312
  if (!props.input?.props) return null;
3307
- const { type, ...inputPropsWithoutType } = props.input.props;
3308
3313
  if (props.sliderProps) {
3309
3314
  const min = props.sliderProps.min ?? inputProps.minimum ?? 0;
3310
3315
  const max = props.sliderProps.max ?? inputProps.maximum ?? 100;
@@ -3317,34 +3322,25 @@ const ControlNumber = (props) => {
3317
3322
  },
3318
3323
  children: /* @__PURE__ */ jsx(Slider, {
3319
3324
  ...inputProps,
3320
- ref,
3321
3325
  id,
3322
- ...inputPropsWithoutType,
3323
3326
  ...props.sliderProps,
3324
- value,
3327
+ value: value ?? 0,
3325
3328
  min,
3326
3329
  max,
3327
3330
  label: () => value,
3328
- onChange: (val) => {
3329
- setValue(val);
3330
- props.input.set(val);
3331
- }
3331
+ onChange: (val) => setValue(val)
3332
3332
  })
3333
3333
  })
3334
3334
  });
3335
3335
  }
3336
3336
  return /* @__PURE__ */ jsx(NumberInput, {
3337
3337
  ...inputProps,
3338
- ref,
3339
3338
  id,
3340
3339
  leftSection: icon,
3341
- ...inputPropsWithoutType,
3342
3340
  ...props.numberInputProps,
3343
3341
  value: value ?? "",
3344
3342
  onChange: (val) => {
3345
- const newValue = val !== null ? Number(val) : void 0;
3346
- setValue(newValue);
3347
- props.input.set(newValue);
3343
+ setValue(val !== null ? Number(val) : void 0);
3348
3344
  }
3349
3345
  });
3350
3346
  };
@@ -3363,156 +3359,73 @@ const ControlNumber = (props) => {
3363
3359
  * The form system provides nested InputFields under the `.items` property.
3364
3360
  * For example: form.input.address.items.street
3365
3361
  *
3366
- * @example
3367
- * ```tsx
3368
- * // For a schema like:
3369
- * // t.object({
3370
- * // address: t.object({
3371
- * // street: t.text(),
3372
- * // city: t.text(),
3373
- * // zip: t.text(),
3374
- * // })
3375
- * // })
3376
- *
3377
- * <ControlObject
3378
- * input={form.input.address}
3379
- * columns={2}
3380
- * controlProps={{
3381
- * zip: { text: { maxLength: 10 } }
3382
- * }}
3383
- * />
3384
- * ```
3385
- */
3386
- const ControlObject = (props) => {
3387
- const { inputProps } = parseInput(props, {});
3388
- if (!props.input?.props) return null;
3389
- const schema = props.input.schema;
3390
- if (!schema?.properties) return null;
3391
- const fieldNames = Object.keys(schema.properties);
3392
- const colSpan = 12 / (props.columns ?? 1);
3393
- const nestedItems = props.input.items;
3394
- const renderFields = () => /* @__PURE__ */ jsx(Grid, { children: fieldNames.map((fieldName) => {
3395
- const fieldControlProps = props.controlProps?.[fieldName] ?? {};
3396
- const field = nestedItems?.[fieldName];
3397
- if (!field) return null;
3398
- return /* @__PURE__ */ jsx(Grid.Col, {
3399
- span: colSpan,
3400
- children: /* @__PURE__ */ jsx(Control, {
3401
- input: field,
3402
- ...fieldControlProps
3403
- })
3404
- }, fieldName);
3405
- }) });
3406
- if (props.variant === "plain") return renderFields();
3407
- return /* @__PURE__ */ jsx(Fieldset, {
3408
- legend: inputProps.label,
3409
- children: /* @__PURE__ */ jsxs(Flex, {
3410
- direction: "column",
3411
- gap: "xs",
3412
- children: [
3413
- inputProps.description && /* @__PURE__ */ jsx(Text, {
3414
- size: "sm",
3415
- c: "dimmed",
3416
- children: inputProps.description
3417
- }),
3418
- renderFields(),
3419
- inputProps.error && /* @__PURE__ */ jsx(Text, {
3420
- size: "sm",
3421
- c: "red",
3422
- children: inputProps.error
3423
- })
3424
- ]
3425
- })
3426
- });
3427
- };
3428
-
3429
- //#endregion
3430
- //#region ../../src/core/form/components/ControlQueryBuilder.tsx
3431
- /**
3432
- * Query builder with text input and help popover.
3433
- * Generates query strings for parseQueryString syntax.
3434
- */
3435
- const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
3436
- const [helpOpened, setHelpOpened] = useState(false);
3437
- const [textValue, setTextValue] = useState(value);
3438
- const inputRef = useRef(null);
3439
- const fields = schema ? extractSchemaFields(schema) : [];
3440
- const [error, setError] = useState(null);
3441
- const isValid = (value) => {
3442
- try {
3443
- parseQueryString(value.trim());
3444
- } catch (e) {
3445
- setError(e.message);
3446
- return false;
3447
- }
3448
- setError(null);
3449
- return true;
3450
- };
3451
- const handleTextChange = (newValue) => {
3452
- setTextValue(newValue);
3453
- if (isValid(newValue)) onChange?.(newValue);
3454
- };
3455
- const handleClear = () => {
3456
- setTextValue("");
3457
- onChange?.("");
3458
- isValid("");
3459
- };
3460
- const handleInsert = (text) => {
3461
- const newValue = textValue ? `${textValue}${text} ` : `${text} `;
3462
- setTextValue(newValue);
3463
- if (isValid(newValue)) onChange?.(newValue);
3464
- setTimeout(() => {
3465
- inputRef.current?.focus();
3466
- const length = inputRef.current?.value.length || 0;
3467
- inputRef.current?.setSelectionRange(length, length);
3468
- }, 0);
3469
- };
3470
- useEvents({ "form:change": (event) => {
3471
- if (event.id === inputRef.current?.form?.id) {
3472
- if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
3473
- }
3474
- } }, []);
3475
- return /* @__PURE__ */ jsxs(Popover, {
3476
- width: 800,
3477
- position: "bottom-start",
3478
- shadow: "md",
3479
- opened: helpOpened,
3480
- onChange: setHelpOpened,
3481
- closeOnClickOutside: true,
3482
- closeOnEscape: true,
3483
- transitionProps: {
3484
- transition: "fade-up",
3485
- duration: 200,
3486
- timingFunction: "ease"
3487
- },
3488
- children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
3489
- ref: inputRef,
3490
- placeholder,
3491
- value: textValue,
3492
- onChange: (e) => handleTextChange(e.currentTarget.value),
3493
- onFocus: () => setHelpOpened(true),
3494
- leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
3495
- rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
3496
- size: "sm",
3497
- variant: "subtle",
3498
- color: "gray",
3499
- onClick: handleClear,
3500
- children: /* @__PURE__ */ jsx(IconX, { size: 14 })
3501
- }),
3502
- ...textInputProps
3503
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3504
- bg: "transparent",
3505
- p: "xs",
3506
- bd: `1px solid ${ui.colors.border}`,
3507
- style: { backdropFilter: "blur(20px)" },
3508
- children: /* @__PURE__ */ jsx(QueryHelp, {
3509
- fields,
3510
- onInsert: handleInsert
3362
+ * @example
3363
+ * ```tsx
3364
+ * // For a schema like:
3365
+ * // t.object({
3366
+ * // address: t.object({
3367
+ * // street: t.text(),
3368
+ * // city: t.text(),
3369
+ * // zip: t.text(),
3370
+ * // })
3371
+ * // })
3372
+ *
3373
+ * <ControlObject
3374
+ * input={form.input.address}
3375
+ * columns={2}
3376
+ * controlProps={{
3377
+ * zip: { text: { maxLength: 10 } }
3378
+ * }}
3379
+ * />
3380
+ * ```
3381
+ */
3382
+ const ControlObject = (props) => {
3383
+ const { inputProps } = parseInput(props, {});
3384
+ if (!props.input?.props) return null;
3385
+ const schema = props.input.schema;
3386
+ if (!schema?.properties) return null;
3387
+ const fieldNames = Object.keys(schema.properties);
3388
+ const colSpan = 12 / (props.columns ?? 1);
3389
+ const nestedItems = props.input.items;
3390
+ const renderFields = () => /* @__PURE__ */ jsx(Grid, { children: fieldNames.map((fieldName) => {
3391
+ const fieldControlProps = props.controlProps?.[fieldName] ?? {};
3392
+ const field = nestedItems?.[fieldName];
3393
+ if (!field) return null;
3394
+ return /* @__PURE__ */ jsx(Grid.Col, {
3395
+ span: colSpan,
3396
+ children: /* @__PURE__ */ jsx(Control, {
3397
+ input: field,
3398
+ ...fieldControlProps
3511
3399
  })
3512
- })]
3400
+ }, fieldName);
3401
+ }) });
3402
+ if (props.variant === "plain") return renderFields();
3403
+ return /* @__PURE__ */ jsx(Fieldset, {
3404
+ legend: inputProps.label,
3405
+ children: /* @__PURE__ */ jsxs(Flex, {
3406
+ direction: "column",
3407
+ gap: "xs",
3408
+ children: [
3409
+ inputProps.description && /* @__PURE__ */ jsx(Text, {
3410
+ size: "sm",
3411
+ c: "dimmed",
3412
+ children: inputProps.description
3413
+ }),
3414
+ renderFields(),
3415
+ inputProps.error && /* @__PURE__ */ jsx(Text, {
3416
+ size: "sm",
3417
+ c: "red",
3418
+ children: inputProps.error
3419
+ })
3420
+ ]
3421
+ })
3513
3422
  });
3514
3423
  };
3515
- function QueryHelp({ fields, onInsert }) {
3424
+
3425
+ //#endregion
3426
+ //#region ../../src/core/form/components/ControlQueryBuilderHelp.tsx
3427
+ const ControlQueryBuilderHelp = (props) => {
3428
+ const { fields, onInsert } = props;
3516
3429
  return /* @__PURE__ */ jsxs(Flex, {
3517
3430
  gap: "md",
3518
3431
  align: "flex-start",
@@ -3675,111 +3588,314 @@ function QueryHelp({ fields, onInsert }) {
3675
3588
  })
3676
3589
  ]
3677
3590
  });
3678
- }
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
+ })]
3678
+ });
3679
+ };
3679
3680
 
3680
3681
  //#endregion
3681
3682
  //#region ../../src/core/form/components/ControlSelect.tsx
3682
3683
  /**
3683
- * ControlSelect component for handling Select, MultiSelect, and TagsInput.
3684
+ * ControlSelect component for handling Select, MultiSelect, Autocomplete, and TagsInput.
3684
3685
  *
3685
3686
  * Features:
3686
3687
  * - Basic Select with enum support
3687
3688
  * - MultiSelect for array of enums
3688
- * - TagsInput for array of strings (no enum)
3689
- * - Future: Lazy loading
3690
- * - Future: Searchable/filterable options
3691
- * - 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
3692
3694
  *
3693
3695
  * Automatically detects enum values and array types from schema.
3694
3696
  */
3695
3697
  const ControlSelect = (props) => {
3696
- 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);
3697
3701
  const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
3698
- let itemsEnum;
3699
- if (isArray && "items" in props.input.schema && props.input.schema.items) {
3700
- const items = props.input.schema.items;
3701
- if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
3702
- }
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";
3703
3704
  const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
3704
- 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);
3705
3708
  useEffect(() => {
3706
- if (!props.input?.props) return;
3707
- if (props.loader) props.loader().then(setData);
3708
- else setData(enumValues);
3709
- }, [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;
3710
3725
  if (!props.input?.props) return null;
3711
- if (props.segmented) {
3712
- 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);
3713
3738
  return /* @__PURE__ */ jsx(Input.Wrapper, {
3714
3739
  ...inputProps,
3715
- children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(SegmentedControl, {
3716
- disabled: inputProps.disabled,
3717
- defaultValue: String(props.input.props.defaultValue),
3718
- ...segmentedControlProps,
3719
- onChange: (value) => {
3720
- props.input.set(value);
3721
- },
3722
- data: data.slice(0, 10)
3723
- }) })
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
+ })
3724
3752
  });
3725
3753
  }
3726
- if (props.autocomplete) {
3727
- const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
3728
- 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, {
3729
3775
  ...inputProps,
3730
- size: props.size,
3731
- id,
3732
- leftSection: icon,
3733
- data,
3734
- ...props.input.props,
3735
- ...autocompleteProps
3776
+ ...sharedProps,
3777
+ ...longModeProps,
3778
+ value: Array.isArray(value) ? value : [],
3779
+ onChange: (val) => {
3780
+ setValue(val);
3781
+ },
3782
+ ...tagsInputExtraProps
3736
3783
  });
3737
3784
  }
3738
- if (isArray && !itemsEnum || props.tags) {
3739
- const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
3740
- return /* @__PURE__ */ jsx(TagsInput, {
3785
+ if (props.creatable) {
3786
+ const autocompleteExtraProps = props.autocompleteProps ?? {};
3787
+ return /* @__PURE__ */ jsx(Autocomplete, {
3741
3788
  ...inputProps,
3742
- size: props.size,
3743
- id,
3744
- leftSection: icon,
3745
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
3746
- onChange: (value) => {
3747
- props.input.set(value);
3789
+ ...sharedProps,
3790
+ ...longModeProps,
3791
+ value: value != null ? String(value) : "",
3792
+ onChange: (val) => {
3793
+ setValue(coerceValue(val));
3748
3794
  },
3749
- ...tagsInputProps
3795
+ ...autocompleteExtraProps
3750
3796
  });
3751
3797
  }
3752
- if (isArray && itemsEnum || props.multi) {
3753
- const data = itemsEnum?.map((value) => ({
3754
- value,
3755
- label: value
3756
- })) || [];
3757
- const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
3798
+ if (isArray || props.multiSelectProps) {
3799
+ const multiSelectExtraProps = typeof props.multiSelectProps === "object" ? props.multiSelectProps : {};
3758
3800
  return /* @__PURE__ */ jsx(MultiSelect, {
3759
3801
  ...inputProps,
3760
- size: props.size,
3761
- id,
3762
- leftSection: icon,
3763
- data,
3764
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
3765
- onChange: (value) => {
3766
- props.input.set(value);
3802
+ ...selectableProps,
3803
+ ...longModeProps,
3804
+ value: Array.isArray(value) ? value : [],
3805
+ onChange: (val) => {
3806
+ setValue(val);
3767
3807
  },
3768
- ...multiSelectProps
3808
+ ...multiSelectExtraProps
3769
3809
  });
3770
3810
  }
3771
- 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
+ });
3772
3821
  return /* @__PURE__ */ jsx(Select, {
3773
3822
  ...inputProps,
3774
- size: props.size,
3775
- id,
3776
- leftSection: icon,
3777
- rightSection: null,
3778
- data,
3779
- ...props.input.props,
3780
- ...selectProps
3823
+ ...selectableProps,
3824
+ ...longModeProps,
3825
+ value: value != null ? String(value) : null,
3826
+ onChange: (val) => {
3827
+ setValue(coerceValue(val));
3828
+ },
3829
+ ...selectExtraProps
3781
3830
  });
3782
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
+ };
3783
3899
 
3784
3900
  //#endregion
3785
3901
  //#region ../../src/core/form/components/Control.tsx
@@ -3809,6 +3925,7 @@ const ControlSelect = (props) => {
3809
3925
  */
3810
3926
  const Control = (_props) => {
3811
3927
  const form = useFormState(_props.input, ["error"]);
3928
+ const [value, setValue] = useFieldValue(_props.input);
3812
3929
  if (!_props.input?.props) return null;
3813
3930
  const { inputProps, id, icon, format, schema } = parseInput(_props, form);
3814
3931
  const props = {
@@ -3816,12 +3933,11 @@ const Control = (_props) => {
3816
3933
  ...schema.$control
3817
3934
  };
3818
3935
  if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder, {
3819
- ...props.input.props,
3820
3936
  ...inputProps,
3821
3937
  schema: props.query,
3822
- value: props.input.props.value,
3823
- onChange: (value) => {
3824
- props.input.set(value);
3938
+ value,
3939
+ onChange: (val) => {
3940
+ setValue(val);
3825
3941
  }
3826
3942
  });
3827
3943
  if (props.custom) {
@@ -3832,9 +3948,9 @@ const Control = (_props) => {
3832
3948
  flex: 1,
3833
3949
  mt: "calc(var(--mantine-spacing-xs) / 2)",
3834
3950
  children: /* @__PURE__ */ jsx(Custom, {
3835
- defaultValue: props.input.props.defaultValue,
3836
- onChange: (value) => {
3837
- props.input.set(value);
3951
+ value,
3952
+ onChange: (val) => {
3953
+ setValue(val);
3838
3954
  }
3839
3955
  })
3840
3956
  })
@@ -3845,7 +3961,7 @@ const Control = (_props) => {
3845
3961
  const controlObjectProps = typeof props.object === "object" ? props.object : {};
3846
3962
  return /* @__PURE__ */ jsx(ControlObject, {
3847
3963
  input: props.input,
3848
- title: props.title,
3964
+ label: props.label,
3849
3965
  description: props.description,
3850
3966
  ...controlObjectProps
3851
3967
  });
@@ -3856,18 +3972,18 @@ const Control = (_props) => {
3856
3972
  const controlArrayProps = typeof props.array === "object" ? props.array : {};
3857
3973
  return /* @__PURE__ */ jsx(ControlArray, {
3858
3974
  input: props.input,
3859
- title: props.title,
3975
+ label: props.label,
3860
3976
  description: props.description,
3861
3977
  ...controlArrayProps
3862
3978
  });
3863
3979
  }
3864
- 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")) {
3865
3981
  const controlNumberProps = typeof props.number === "object" ? props.number : {};
3866
3982
  if (props.slider) controlNumberProps.sliderProps ??= {};
3867
3983
  return /* @__PURE__ */ jsx(ControlNumber, {
3868
3984
  size: props.size,
3869
3985
  input: props.input,
3870
- title: props.title,
3986
+ label: props.label,
3871
3987
  description: props.description,
3872
3988
  icon,
3873
3989
  ...controlNumberProps
@@ -3880,9 +3996,7 @@ const Control = (_props) => {
3880
3996
  size: props.size,
3881
3997
  id,
3882
3998
  leftSection: icon,
3883
- onChange: (file) => {
3884
- props.input.set(file);
3885
- },
3999
+ onChange: (file) => setValue(file),
3886
4000
  ...fileInputProps
3887
4001
  });
3888
4002
  }
@@ -3893,17 +4007,18 @@ const Control = (_props) => {
3893
4007
  size: props.size,
3894
4008
  id,
3895
4009
  leftSection: icon,
3896
- ...props.input.props,
4010
+ value: value ?? "",
4011
+ onChange: (val) => setValue(val),
3897
4012
  ...colorInputProps
3898
4013
  });
3899
4014
  }
3900
4015
  if (props.input.schema && "enum" in props.input.schema && props.input.schema.enum || isArray && !isArrayOfObjects || props.select) {
3901
4016
  const opts = typeof props.select === "object" ? props.select : {};
3902
- if (props.segmented) opts.segmented ??= {};
4017
+ if (props.segmented) opts.segmentedProps ??= {};
3903
4018
  return /* @__PURE__ */ jsx(ControlSelect, {
3904
4019
  size: props.size,
3905
4020
  input: props.input,
3906
- title: props.title,
4021
+ label: props.label,
3907
4022
  description: props.description,
3908
4023
  icon,
3909
4024
  ...opts
@@ -3917,16 +4032,16 @@ const Control = (_props) => {
3917
4032
  size: props.size,
3918
4033
  id,
3919
4034
  color: "blue",
3920
- defaultChecked: props.input.props.defaultValue,
4035
+ checked: Boolean(value),
3921
4036
  onChange: (event) => {
3922
- props.input.set(event.currentTarget.checked);
4037
+ setValue(event.currentTarget.checked);
3923
4038
  },
3924
4039
  ...switchProps
3925
4040
  });
3926
4041
  }
3927
4042
  const opts = {
3928
4043
  input: props.input,
3929
- select: { data: [{
4044
+ selectProps: { data: [{
3930
4045
  value: "true",
3931
4046
  label: "Yes"
3932
4047
  }, {
@@ -3936,7 +4051,7 @@ const Control = (_props) => {
3936
4051
  };
3937
4052
  return /* @__PURE__ */ jsx(ControlSelect, {
3938
4053
  size: props.size,
3939
- title: props.title,
4054
+ label: props.label,
3940
4055
  description: props.description,
3941
4056
  icon,
3942
4057
  ...opts
@@ -3949,7 +4064,8 @@ const Control = (_props) => {
3949
4064
  size: props.size,
3950
4065
  id,
3951
4066
  leftSection: icon,
3952
- ...props.input.props,
4067
+ value: value ?? "",
4068
+ onChange: (ev) => setValue(ev.target.value),
3953
4069
  ...passwordInputProps
3954
4070
  });
3955
4071
  }
@@ -3960,14 +4076,15 @@ const Control = (_props) => {
3960
4076
  size: props.size,
3961
4077
  id,
3962
4078
  leftSection: icon,
3963
- ...props.input.props,
4079
+ value: value ?? "",
4080
+ onChange: (ev) => setValue(ev.target.value),
3964
4081
  ...textAreaProps
3965
4082
  });
3966
4083
  }
3967
4084
  if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate, {
3968
4085
  size: props.size,
3969
4086
  input: props.input,
3970
- title: props.title,
4087
+ label: props.label,
3971
4088
  description: props.description,
3972
4089
  icon,
3973
4090
  date: props.date,
@@ -3982,7 +4099,7 @@ const Control = (_props) => {
3982
4099
  case "uri": return "url";
3983
4100
  case "tel":
3984
4101
  case "phone": return "tel";
3985
- default: return;
4102
+ default: return props.input.props.type ?? "text";
3986
4103
  }
3987
4104
  };
3988
4105
  return /* @__PURE__ */ jsx(TextInput, {
@@ -3991,14 +4108,9 @@ const Control = (_props) => {
3991
4108
  id,
3992
4109
  leftSection: icon,
3993
4110
  type: getInputType(),
3994
- ...props.input.props,
3995
- ...textInputProps,
3996
- inputWrapperOrder: [
3997
- "label",
3998
- "input",
3999
- "description",
4000
- "error"
4001
- ]
4111
+ value: value ?? "",
4112
+ onChange: (ev) => setValue(ev.target.value),
4113
+ ...textInputProps
4002
4114
  });
4003
4115
  };
4004
4116
 
@@ -4047,6 +4159,7 @@ const Control = (_props) => {
4047
4159
  */
4048
4160
  const TypeForm = (props) => {
4049
4161
  const { form, columns = 3, children, controlProps, fieldControlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps, fill = true, size } = props;
4162
+ const { dirty } = useFormState(form, ["dirty"]);
4050
4163
  const schema = props.schema || form.options.schema;
4051
4164
  if (!schema?.properties) return null;
4052
4165
  const supportedFields = Object.keys(schema.properties);
@@ -4109,10 +4222,12 @@ const TypeForm = (props) => {
4109
4222
  children: [/* @__PURE__ */ jsx(ActionButton, {
4110
4223
  variant: "subtle",
4111
4224
  type: "reset",
4225
+ disabled: !dirty,
4112
4226
  children: "Reset"
4113
4227
  }), /* @__PURE__ */ jsx(ActionButton, {
4114
4228
  intent: "primary",
4115
4229
  form,
4230
+ disabled: !dirty,
4116
4231
  ...submitButtonProps,
4117
4232
  children: submitButtonProps?.children ?? "Submit"
4118
4233
  })]
@@ -4131,22 +4246,14 @@ const TypeForm = (props) => {
4131
4246
  });
4132
4247
  };
4133
4248
 
4134
- //#endregion
4135
- //#region ../../src/core/helpers/renderIcon.tsx
4136
- const renderIcon = (icon, size) => {
4137
- if (!icon) return null;
4138
- if (isValidElement(icon)) return icon;
4139
- if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
4140
- return icon;
4141
- };
4142
-
4143
4249
  //#endregion
4144
4250
  //#region ../../src/core/table/interfaces/types.ts
4145
4251
  const DEFAULT_MAX_VISIBLE_COLUMNS = 8;
4146
4252
 
4147
4253
  //#endregion
4148
4254
  //#region ../../src/core/table/components/DataTableFilters.tsx
4149
- const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) => {
4255
+ const DataTableFilters = (props) => {
4256
+ const { schema, form, typeFormProps, filterVisibility } = props;
4150
4257
  const visibleSchema = useMemo(() => {
4151
4258
  const visibleKeys = Object.keys(schema.properties).filter((key) => filterVisibility[key] !== false);
4152
4259
  if (visibleKeys.length === 0) return null;
@@ -4157,14 +4264,14 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
4157
4264
  return t.object(visibleProps);
4158
4265
  }, [schema, filterVisibility]);
4159
4266
  if (!visibleSchema) return null;
4160
- return /* @__PURE__ */ jsx(Flex, {
4161
- w: "100%",
4267
+ return /* @__PURE__ */ jsx(Flex$1, {
4268
+ surface: true,
4269
+ flex: 1,
4270
+ mt: -4,
4162
4271
  p: "xs",
4163
4272
  m: "xs",
4164
4273
  bdrs: "md",
4165
- bg: ui.colors.surface,
4166
4274
  children: /* @__PURE__ */ jsx(TypeForm, {
4167
- size: "xs",
4168
4275
  ...typeFormProps,
4169
4276
  skipSubmitButton: true,
4170
4277
  fill: true,
@@ -4175,7 +4282,7 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
4175
4282
  sm: 2,
4176
4283
  md: 3,
4177
4284
  lg: 4,
4178
- xl: 6
4285
+ xl: 5
4179
4286
  }
4180
4287
  })
4181
4288
  });
@@ -4183,9 +4290,10 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
4183
4290
 
4184
4291
  //#endregion
4185
4292
  //#region ../../src/core/table/components/DataTablePagination.tsx
4186
- const DataTablePagination = ({ page, size, totalPages, totalElements, offset, numberOfElements, onPageChange, onSizeChange }) => {
4293
+ const DataTablePagination = ({ page, size, totalPages, totalElements, isFirst, isLast, offset, numberOfElements, onPageChange, onSizeChange }) => {
4187
4294
  const from = numberOfElements > 0 ? offset + 1 : 0;
4188
4295
  const to = offset + numberOfElements;
4296
+ const hasTotal = totalPages != null;
4189
4297
  return /* @__PURE__ */ jsxs(Flex$1, {
4190
4298
  align: "center",
4191
4299
  justify: "space-between",
@@ -4233,8 +4341,9 @@ const DataTablePagination = ({ page, size, totalPages, totalElements, offset, nu
4233
4341
  ]
4234
4342
  }) }), /* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(Pagination, {
4235
4343
  size: "sm",
4236
- withEdges: true,
4237
- total: totalPages,
4344
+ withEdges: hasTotal,
4345
+ withPages: hasTotal,
4346
+ total: hasTotal ? totalPages : isLast !== false ? page : page + 1,
4238
4347
  value: page,
4239
4348
  onChange: onPageChange
4240
4349
  }) })]
@@ -4285,7 +4394,7 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
4285
4394
  timingFunction: "ease"
4286
4395
  },
4287
4396
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
4288
- variant: "subtle",
4397
+ variant: "minimal",
4289
4398
  icon: IconColumns,
4290
4399
  onClick: () => setOpened((o) => !o)
4291
4400
  }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
@@ -4315,12 +4424,12 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
4315
4424
  gap: 4,
4316
4425
  children: [/* @__PURE__ */ jsx(ActionButton, {
4317
4426
  size: "compact-xs",
4318
- variant: "subtle",
4427
+ variant: "minimal",
4319
4428
  onClick: handleShowAll,
4320
4429
  children: "All"
4321
4430
  }), /* @__PURE__ */ jsx(ActionButton, {
4322
4431
  size: "compact-xs",
4323
- variant: "subtle",
4432
+ variant: "minimal",
4324
4433
  onClick: handleDefault,
4325
4434
  children: "Default"
4326
4435
  })]
@@ -4386,7 +4495,7 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
4386
4495
  timingFunction: "ease"
4387
4496
  },
4388
4497
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
4389
- variant: "subtle",
4498
+ variant: "minimal",
4390
4499
  icon: IconFilter,
4391
4500
  onClick: () => setOpened((o) => !o)
4392
4501
  }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
@@ -4416,12 +4525,12 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
4416
4525
  gap: 4,
4417
4526
  children: [/* @__PURE__ */ jsx(ActionButton, {
4418
4527
  size: "compact-xs",
4419
- variant: "subtle",
4528
+ variant: "minimal",
4420
4529
  onClick: handleShowAll,
4421
4530
  children: "All"
4422
4531
  }), /* @__PURE__ */ jsx(ActionButton, {
4423
4532
  size: "compact-xs",
4424
- variant: "subtle",
4533
+ variant: "minimal",
4425
4534
  onClick: handleHideAll,
4426
4535
  children: "None"
4427
4536
  })]
@@ -4515,7 +4624,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
4515
4624
  onVisibilityChange: onColumnVisibilityChange
4516
4625
  }),
4517
4626
  withExport && /* @__PURE__ */ jsx(ActionButton, {
4518
- variant: "subtle",
4627
+ variant: "minimal",
4519
4628
  icon: IconDownload,
4520
4629
  menu: { items: [{
4521
4630
  label: "Export as CSV",
@@ -4538,7 +4647,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
4538
4647
  children: [selectedItems.length, " selected"]
4539
4648
  }),
4540
4649
  /* @__PURE__ */ jsx(ActionButton, {
4541
- variant: "subtle",
4650
+ variant: "minimal",
4542
4651
  size: "compact-sm",
4543
4652
  icon: IconX,
4544
4653
  onClick: onClearSelection,
@@ -4562,7 +4671,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
4562
4671
  ...props,
4563
4672
  children: props.label
4564
4673
  }, index) : props), /* @__PURE__ */ jsx(ActionButton, {
4565
- variant: "subtle",
4674
+ variant: "minimal",
4566
4675
  icon: IconRefresh,
4567
4676
  onClick: onRefresh
4568
4677
  })]
@@ -4671,12 +4780,16 @@ const FIT_STYLE = {
4671
4780
  };
4672
4781
  const DataTable = (props) => {
4673
4782
  const [items, setItems] = useState(typeof props.items === "function" ? { content: [] } : props.items);
4674
- 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);
4675
4786
  const [page, setPage] = useState(1);
4676
4787
  const [size, setSize] = useState(String(defaultSize));
4677
4788
  const [currentPage, setCurrentPage] = useState(0);
4678
4789
  const alepha = useInject(Alepha);
4790
+ itemsRef.current = items;
4679
4791
  const sentinelRef = useRef(null);
4792
+ const debounceRef = useRef(null);
4680
4793
  const [columnVisibility, setColumnVisibility] = useState(() => {
4681
4794
  const entries = Object.entries(props.columns);
4682
4795
  let visibleCount = 0;
@@ -4749,13 +4862,14 @@ const DataTable = (props) => {
4749
4862
  }),
4750
4863
  handler: async (values) => {
4751
4864
  if (typeof props.items === "function") {
4752
- const response = await props.items(values, { items: items.content });
4865
+ const response = await props.items(values, { items: itemsRef.current.content });
4753
4866
  if (props.infinityScroll && values.page > 0) setItems((prev) => ({
4754
4867
  ...response,
4755
4868
  content: [...prev.content, ...response.content]
4756
4869
  }));
4757
4870
  else setItems(response);
4758
4871
  setCurrentPage(values.page);
4872
+ if (!loaded) setLoaded(true);
4759
4873
  }
4760
4874
  },
4761
4875
  onReset: async () => {
@@ -4775,9 +4889,23 @@ const DataTable = (props) => {
4775
4889
  return;
4776
4890
  }
4777
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();
4778
4901
  }
4779
- }, [items]);
4902
+ }, []);
4780
4903
  const dt = useInject(DateTimeProvider);
4904
+ useEffect(() => {
4905
+ return () => {
4906
+ if (debounceRef.current) clearTimeout(debounceRef.current);
4907
+ };
4908
+ }, []);
4781
4909
  useEffect(() => {
4782
4910
  if (props.submitOnInit) form.submit();
4783
4911
  if (props.submitEvery) {
@@ -4842,9 +4970,9 @@ const DataTable = (props) => {
4842
4970
  }), col.sortable && /* @__PURE__ */ jsxs(Flex$1, {
4843
4971
  c: "dimmed",
4844
4972
  children: [
4845
- sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.sm }),
4846
- sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.sm }),
4847
- 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 })
4848
4976
  ]
4849
4977
  })]
4850
4978
  })
@@ -4904,9 +5032,15 @@ const DataTable = (props) => {
4904
5032
  form,
4905
5033
  alepha
4906
5034
  };
5035
+ const content = col.value?.(item, ctx);
4907
5036
  return /* @__PURE__ */ jsx(Table.Td, {
4908
5037
  style: col.fit ? FIT_STYLE : void 0,
4909
- 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
4910
5044
  }, key);
4911
5045
  }),
4912
5046
  props.rowActions && (() => {
@@ -4923,7 +5057,7 @@ const DataTable = (props) => {
4923
5057
  style: FIT_STYLE,
4924
5058
  onClick: (e) => e.stopPropagation(),
4925
5059
  children: /* @__PURE__ */ jsx(ActionButton, {
4926
- variant: "subtle",
5060
+ variant: "minimal",
4927
5061
  size: "xs",
4928
5062
  icon: IconDotsVertical,
4929
5063
  menu: { items: actions.map((action) => {
@@ -4931,7 +5065,10 @@ const DataTable = (props) => {
4931
5065
  return {
4932
5066
  label: action.label ?? (typeof action.tooltip === "string" ? action.tooltip : void 0),
4933
5067
  icon: Icon && isComponentType(Icon) ? /* @__PURE__ */ jsx(Icon, { size: 14 }) : Icon,
4934
- onClick: action.onClick,
5068
+ onClick: action.onClick ? async () => {
5069
+ await action.onClick();
5070
+ if (!action.skipRefresh) await form.submit();
5071
+ } : void 0,
4935
5072
  color: action.color
4936
5073
  };
4937
5074
  }) }
@@ -4993,19 +5130,26 @@ const DataTable = (props) => {
4993
5130
  bordered: true,
4994
5131
  elevated: true,
4995
5132
  shadowed: "xs",
5133
+ flex: 1,
5134
+ style: { minHeight: 0 },
4996
5135
  children: [
4997
5136
  /* @__PURE__ */ jsx(Flex$1, {
4998
5137
  className: "overflow-auto",
5138
+ flex: 1,
5139
+ style: { minHeight: 0 },
5140
+ col: true,
4999
5141
  children: /* @__PURE__ */ jsxs(Table, {
5000
5142
  "aria-label": "Data table",
5001
5143
  withRowBorders: true,
5002
5144
  highlightOnHover: true,
5003
5145
  ...props.tableProps,
5004
5146
  children: [/* @__PURE__ */ jsx(Table.Thead, {
5147
+ bdrs: "md",
5005
5148
  style: {
5006
5149
  position: "sticky",
5007
5150
  top: 0,
5008
- zIndex: 1
5151
+ zIndex: 1,
5152
+ backgroundColor: "var(--alepha-elevated)"
5009
5153
  },
5010
5154
  children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
5011
5155
  panelConfig && /* @__PURE__ */ jsx(Table.Th, { style: { width: 36 } }),
@@ -5013,30 +5157,39 @@ const DataTable = (props) => {
5013
5157
  head,
5014
5158
  props.rowActions && /* @__PURE__ */ jsx(Table.Th, { style: FIT_STYLE })
5015
5159
  ] })
5016
- }), /* @__PURE__ */ jsxs(Table.Tbody, {
5017
- style: {
5018
- opacity: form.submitting ? .5 : 1,
5019
- transition: "opacity 150ms ease"
5020
- },
5021
- children: [rows, items.content.length === 0 && /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
5022
- colSpan: totalColumns || 1,
5023
- py: "xl",
5024
- style: { textAlign: "center" },
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, {
5172
+ colSpan: totalColumns || 1,
5173
+ py: "xl",
5174
+ children: /* @__PURE__ */ jsx(Flex$1, {
5175
+ justify: "center",
5025
5176
  children: /* @__PURE__ */ jsx(Text$1, {
5026
5177
  c: "dimmed",
5027
5178
  size: "sm",
5028
- children: form.submitting ? "Loading…" : "No results"
5179
+ children: props.emptyLabel ?? "No results"
5029
5180
  })
5030
- }) })]
5031
- })]
5181
+ })
5182
+ }) }) : rows })]
5032
5183
  })
5033
5184
  }),
5034
5185
  props.infinityScroll && /* @__PURE__ */ jsx("div", { ref: sentinelRef }),
5035
5186
  !props.infinityScroll && /* @__PURE__ */ jsx(DataTablePagination, {
5036
5187
  page,
5037
5188
  size,
5038
- totalPages: items.page?.totalPages ?? 1,
5189
+ totalPages: items.page?.totalPages,
5039
5190
  totalElements: items.page?.totalElements,
5191
+ isFirst: items.page?.isFirst,
5192
+ isLast: items.page?.isLast,
5040
5193
  offset: items.page?.offset ?? 0,
5041
5194
  numberOfElements: items.content.length,
5042
5195
  onPageChange: (value) => {
@@ -5154,8 +5307,8 @@ const OPERATOR_INFO = {
5154
5307
  * Get the default icon for an input based on its type, format, or name.
5155
5308
  */
5156
5309
  const getDefaultIcon = (params) => {
5157
- const { type, format, name, isEnum, isArray, size = "sm" } = params;
5158
- const iconSize = ui.sizes.icon[size];
5310
+ const { type, format, name, isEnum, isArray, size = "xs" } = params;
5311
+ const iconSize = ui.sizes.icon[size] - 4;
5159
5312
  if (format) switch (format) {
5160
5313
  case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
5161
5314
  case "url":
@@ -5268,5 +5421,5 @@ const AlephaUI = $module({
5268
5421
  });
5269
5422
 
5270
5423
  //#endregion
5271
- 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, Text$1 as o, ThemeButton as p, DataTable as r, DashboardShell as s, AlephaUI as t, StatCards as u, ui as v, alephaSidebarAtom as x, AlephaMantineProvider as y };
5272
- //# sourceMappingURL=core-BVO_TQxb.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