@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
@@ -2214,7 +2216,7 @@ const ToggleSidebarButton = (props) => {
2214
2216
  //#endregion
2215
2217
  //#region ../../src/core/components/Flex.tsx
2216
2218
  const Flex$1 = forwardRef((props, ref) => {
2217
- const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, ...rest } = props;
2219
+ const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, overflow, ...rest } = props;
2218
2220
  if (fill) rest.flex ??= 1;
2219
2221
  if (col) rest.direction ??= "column";
2220
2222
  if (center) {
@@ -2237,6 +2239,7 @@ const Flex$1 = forwardRef((props, ref) => {
2237
2239
  ...rest.style ?? {}
2238
2240
  };
2239
2241
  if (shadowed) rest.className = `${rest.className ?? ""} shadow-${shadowed === true ? "md" : shadowed}`.trim();
2242
+ if (overflow) rest.className = `${rest.className ?? ""} overflow-auto`.trim();
2240
2243
  return /* @__PURE__ */ jsx(Flex, {
2241
2244
  ref,
2242
2245
  ...rest
@@ -2374,7 +2377,8 @@ const AppBar = (props) => {
2374
2377
  * Pages should define a `label` in their `$page()` options for best results.
2375
2378
  * Falls back to the page name converted to Title Case.
2376
2379
  */
2377
- const Breadcrumb = ({ home = "Home", separator, size = "sm", ...groupProps }) => {
2380
+ const Breadcrumb = (props) => {
2381
+ const { home = "Home", separator, size = "sm", ...groupProps } = props;
2378
2382
  const state = useRouterState();
2379
2383
  const router = useRouter();
2380
2384
  const crumbs = [];
@@ -2429,11 +2433,175 @@ const Container$1 = forwardRef((props, ref) => {
2429
2433
  });
2430
2434
  Container$1.displayName = "Container";
2431
2435
 
2436
+ //#endregion
2437
+ //#region ../../src/core/helpers/renderIcon.tsx
2438
+ const renderIcon = (icon, size) => {
2439
+ if (!icon) return null;
2440
+ if (isValidElement(icon)) return icon;
2441
+ if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
2442
+ return icon;
2443
+ };
2444
+
2445
+ //#endregion
2446
+ //#region ../../src/core/components/Text.tsx
2447
+ const INTENT_COLORS = {
2448
+ primary: "blue",
2449
+ info: "cyan",
2450
+ success: "green",
2451
+ warning: "yellow",
2452
+ danger: "red"
2453
+ };
2454
+ const Text$1 = forwardRef((props, ref) => {
2455
+ const { intent, bold, italic, light, muted, small, uppercase, capitalize, center, monospace, title, ...rest } = props;
2456
+ if (intent) rest.c ??= INTENT_COLORS[intent];
2457
+ if (bold) rest.fw ??= 700;
2458
+ if (light) rest.fw ??= 300;
2459
+ if (italic) rest.fs ??= "italic";
2460
+ if (muted) rest.c ??= "dimmed";
2461
+ if (small) rest.size ??= "xs";
2462
+ if (uppercase) rest.tt ??= "uppercase";
2463
+ if (capitalize) rest.tt ??= "capitalize";
2464
+ if (center) rest.ta ??= "center";
2465
+ if (monospace) rest.ff ??= "monospace";
2466
+ if (title) rest.size ??= "xl";
2467
+ return /* @__PURE__ */ jsx(Text, {
2468
+ ref,
2469
+ ...rest
2470
+ });
2471
+ });
2472
+ Text$1.displayName = "Text";
2473
+
2474
+ //#endregion
2475
+ //#region ../../src/core/components/layout/SidebarCollapsedItem.tsx
2476
+ const SidebarCollapsedItem = (props) => {
2477
+ const router = useRouter();
2478
+ const handleItemClick = () => {
2479
+ props.onItemClick?.(props.item);
2480
+ props.item.onClick?.();
2481
+ };
2482
+ const hasChildren = props.item.children && props.item.children.length > 0;
2483
+ const menu = hasChildren ? {
2484
+ on: "hover",
2485
+ position: "right",
2486
+ menuProps: {
2487
+ arrowPosition: "center",
2488
+ arrowSize: 10,
2489
+ withArrow: true
2490
+ },
2491
+ items: [{
2492
+ type: "label",
2493
+ label: props.item.label
2494
+ }, ...props.item.children.filter((child) => !child.can || child.can()).map((child) => ({
2495
+ label: child.label,
2496
+ icon: renderIcon(child.icon, ui.sizes.icon.sm),
2497
+ href: child.href,
2498
+ active: child.href ? router.isActive(child.href, { startWith: child.activeStartsWith }) : void 0
2499
+ }))]
2500
+ } : void 0;
2501
+ return /* @__PURE__ */ jsx(Flex$1, {
2502
+ w: "100%",
2503
+ justify: "center",
2504
+ pos: "relative",
2505
+ children: /* @__PURE__ */ jsx(ActionButton, {
2506
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (props.level === 0 ? "sm" : "xs"),
2507
+ bd: 0,
2508
+ variant: "default",
2509
+ propsActive: { variant: "outline" },
2510
+ tooltip: hasChildren ? void 0 : {
2511
+ label: props.item.label,
2512
+ position: "right"
2513
+ },
2514
+ onClick: hasChildren ? void 0 : handleItemClick,
2515
+ icon: renderIcon(props.item.icon, ui.sizes.icon.sm) ?? /* @__PURE__ */ jsx(IconSquareRounded, { size: ui.sizes.icon.sm }),
2516
+ href: hasChildren ? void 0 : props.item.href,
2517
+ target: hasChildren ? void 0 : props.item.target,
2518
+ menu,
2519
+ ...props.item.actionProps
2520
+ })
2521
+ });
2522
+ };
2523
+
2524
+ //#endregion
2525
+ //#region ../../src/core/components/layout/SidebarItem.tsx
2526
+ const SidebarItem = (props) => {
2527
+ const maxLevel = 2;
2528
+ const router = useRouter();
2529
+ const isActive = useCallback((item) => {
2530
+ if (!item.children) return false;
2531
+ for (const child of item.children) {
2532
+ if (child.href) {
2533
+ if (router.isActive(child.href)) return true;
2534
+ }
2535
+ if (isActive(child)) return true;
2536
+ }
2537
+ return false;
2538
+ }, []);
2539
+ const [isOpen, setIsOpen] = useState(isActive(props.item));
2540
+ useEvents({ "react:transition:end": () => {
2541
+ if (isActive(props.item)) setIsOpen(true);
2542
+ } }, []);
2543
+ if (props.level > maxLevel) return null;
2544
+ const handleItemClick = (e) => {
2545
+ if (!props.item.target) e.preventDefault();
2546
+ if (props.item.children && props.item.children.length > 0) setIsOpen(!isOpen);
2547
+ else {
2548
+ props.onItemClick?.(props.item);
2549
+ props.item.onClick?.();
2550
+ }
2551
+ };
2552
+ return /* @__PURE__ */ jsxs(Flex$1, {
2553
+ direction: "column",
2554
+ ps: props.level === 0 ? 0 : 32,
2555
+ pos: "relative",
2556
+ children: [/* @__PURE__ */ jsx(ActionButton, {
2557
+ w: "100%",
2558
+ justify: "space-between",
2559
+ href: props.item.href,
2560
+ target: props.item.target,
2561
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (props.level === 0 ? "sm" : "xs"),
2562
+ bd: 0,
2563
+ fw: "normal",
2564
+ variant: "default",
2565
+ propsActive: { variant: "outline" },
2566
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
2567
+ onClick: handleItemClick,
2568
+ leftSection: /* @__PURE__ */ jsxs(Flex$1, {
2569
+ w: "100%",
2570
+ align: "center",
2571
+ gap: "sm",
2572
+ children: [renderIcon(props.item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Flex$1, {
2573
+ direction: "column",
2574
+ children: /* @__PURE__ */ jsx(Flex$1, { children: props.item.label })
2575
+ })]
2576
+ }),
2577
+ rightSection: props.item.children ? /* @__PURE__ */ jsx(Flex$1, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
2578
+ ...props.item.actionProps
2579
+ }), props.item.children && isOpen && /* @__PURE__ */ jsxs(Flex$1, {
2580
+ direction: "column",
2581
+ "data-parent-level": props.level,
2582
+ gap: 2,
2583
+ py: 2,
2584
+ children: [/* @__PURE__ */ jsx(Flex$1, { style: {
2585
+ position: "absolute",
2586
+ width: 1,
2587
+ background: "linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
2588
+ top: 48,
2589
+ left: 20 + 32 * props.level,
2590
+ bottom: 16
2591
+ } }), props.item.children.filter((child) => !child.can || child.can()).map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
2592
+ item: child,
2593
+ level: props.level + 1,
2594
+ onItemClick: props.onItemClick,
2595
+ theme: props.theme
2596
+ }, index))]
2597
+ })]
2598
+ });
2599
+ };
2600
+
2432
2601
  //#endregion
2433
2602
  //#region ../../src/core/components/layout/Sidebar.tsx
2434
2603
  const Sidebar = (props) => {
2435
2604
  const router = useRouter();
2436
- const { onItemClick } = props;
2437
2605
  const divider = (key, fill, collapsed) => {
2438
2606
  return /* @__PURE__ */ jsx(Flex$1, {
2439
2607
  h: 1,
@@ -2484,13 +2652,13 @@ const Sidebar = (props) => {
2484
2652
  if (collapsed) return /* @__PURE__ */ jsx(SidebarCollapsedItem, {
2485
2653
  item,
2486
2654
  level: 0,
2487
- onItemClick,
2655
+ onItemClick: props.onItemClick,
2488
2656
  theme: props.theme ?? {}
2489
2657
  }, key);
2490
2658
  return /* @__PURE__ */ jsx(SidebarItem, {
2491
2659
  item,
2492
2660
  level: 0,
2493
- onItemClick,
2661
+ onItemClick: props.onItemClick,
2494
2662
  theme: props.theme ?? {}
2495
2663
  }, key);
2496
2664
  };
@@ -2553,129 +2721,6 @@ const Sidebar = (props) => {
2553
2721
  })] });
2554
2722
  return renderSidebar(false);
2555
2723
  };
2556
- const SidebarItem = (props) => {
2557
- const { item, level } = props;
2558
- const maxLevel = 2;
2559
- const router = useRouter();
2560
- const isActive = useCallback((item) => {
2561
- if (!item.children) return false;
2562
- for (const child of item.children) {
2563
- if (child.href) {
2564
- if (router.isActive(child.href)) return true;
2565
- }
2566
- if (isActive(child)) return true;
2567
- }
2568
- return false;
2569
- }, []);
2570
- const [isOpen, setIsOpen] = useState(isActive(item));
2571
- useEvents({ "react:transition:end": () => {
2572
- if (isActive(item)) setIsOpen(true);
2573
- } }, []);
2574
- if (level > maxLevel) return null;
2575
- const handleItemClick = (e) => {
2576
- if (!props.item.target) e.preventDefault();
2577
- if (item.children && item.children.length > 0) setIsOpen(!isOpen);
2578
- else {
2579
- props.onItemClick?.(item);
2580
- item.onClick?.();
2581
- }
2582
- };
2583
- return /* @__PURE__ */ jsxs(Flex$1, {
2584
- direction: "column",
2585
- ps: level === 0 ? 0 : 32,
2586
- pos: "relative",
2587
- children: [/* @__PURE__ */ jsx(ActionButton, {
2588
- w: "100%",
2589
- justify: "space-between",
2590
- href: props.item.href,
2591
- target: props.item.target,
2592
- size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
2593
- bd: 0,
2594
- fw: "normal",
2595
- variant: "default",
2596
- propsActive: { variant: "outline" },
2597
- radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
2598
- onClick: handleItemClick,
2599
- leftSection: /* @__PURE__ */ jsxs(Flex$1, {
2600
- w: "100%",
2601
- align: "center",
2602
- gap: "sm",
2603
- children: [renderIcon(item.icon, ui.sizes.icon.sm), /* @__PURE__ */ jsx(Flex$1, {
2604
- direction: "column",
2605
- children: /* @__PURE__ */ jsx(Flex$1, { children: item.label })
2606
- })]
2607
- }),
2608
- rightSection: item.children ? /* @__PURE__ */ jsx(Flex$1, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
2609
- ...props.item.actionProps
2610
- }), item.children && isOpen && /* @__PURE__ */ jsxs(Flex$1, {
2611
- direction: "column",
2612
- "data-parent-level": level,
2613
- gap: 2,
2614
- py: 2,
2615
- children: [/* @__PURE__ */ jsx(Flex$1, { style: {
2616
- position: "absolute",
2617
- width: 1,
2618
- background: "linear-gradient(to bottom, transparent, var(--mantine-color-default-border), transparent)",
2619
- top: 48,
2620
- left: 20 + 32 * level,
2621
- bottom: 16
2622
- } }), item.children.filter((child) => !child.can || child.can()).map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
2623
- item: child,
2624
- level: level + 1,
2625
- onItemClick: props.onItemClick,
2626
- theme: props.theme
2627
- }, index))]
2628
- })]
2629
- });
2630
- };
2631
- const SidebarCollapsedItem = (props) => {
2632
- const { item, level } = props;
2633
- const router = useRouter();
2634
- const handleItemClick = () => {
2635
- props.onItemClick?.(item);
2636
- item.onClick?.();
2637
- };
2638
- const hasChildren = item.children && item.children.length > 0;
2639
- const menu = hasChildren ? {
2640
- on: "hover",
2641
- position: "right",
2642
- menuProps: {
2643
- arrowPosition: "center",
2644
- arrowSize: 10,
2645
- withArrow: true
2646
- },
2647
- items: [{
2648
- type: "label",
2649
- label: item.label
2650
- }, ...item.children.filter((child) => !child.can || child.can()).map((child) => ({
2651
- label: child.label,
2652
- icon: renderIcon(child.icon, ui.sizes.icon.sm),
2653
- href: child.href,
2654
- active: child.href ? router.isActive(child.href, { startWith: child.activeStartsWith }) : void 0
2655
- }))]
2656
- } : void 0;
2657
- return /* @__PURE__ */ jsx(Flex$1, {
2658
- w: "100%",
2659
- justify: "center",
2660
- pos: "relative",
2661
- children: /* @__PURE__ */ jsx(ActionButton, {
2662
- size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
2663
- bd: 0,
2664
- variant: "default",
2665
- propsActive: { variant: "outline" },
2666
- tooltip: hasChildren ? void 0 : {
2667
- label: item.label,
2668
- position: "right"
2669
- },
2670
- onClick: hasChildren ? void 0 : handleItemClick,
2671
- icon: renderIcon(item.icon, ui.sizes.icon.sm) ?? /* @__PURE__ */ jsx(IconSquareRounded, { size: ui.sizes.icon.sm }),
2672
- href: hasChildren ? void 0 : props.item.href,
2673
- target: hasChildren ? void 0 : props.item.target,
2674
- menu,
2675
- ...props.item.actionProps
2676
- })
2677
- });
2678
- };
2679
2724
 
2680
2725
  //#endregion
2681
2726
  //#region ../../src/core/components/layout/DashboardShell.tsx
@@ -2716,6 +2761,8 @@ const DashboardShell = (props) => {
2716
2761
  const fHeight = props.footerHeight ?? 24;
2717
2762
  const headerHeight = hasAppBar ? hHeight : 0;
2718
2763
  const footerHeight = footerElement ? fHeight : 0;
2764
+ const navbarWidth = collapsed ? collapsedWidth : expandedWidth;
2765
+ const mainContent = props.children ?? /* @__PURE__ */ jsx(NestedView, {});
2719
2766
  return /* @__PURE__ */ jsxs(AppShell, {
2720
2767
  layout: "alt",
2721
2768
  w: "100%",
@@ -2723,7 +2770,7 @@ const DashboardShell = (props) => {
2723
2770
  flex: 1,
2724
2771
  header: hasAppBar ? { height: hHeight } : void 0,
2725
2772
  navbar: hasSidebar ? {
2726
- width: { base: collapsed ? collapsedWidth : expandedWidth },
2773
+ width: { base: navbarWidth },
2727
2774
  breakpoint: "md",
2728
2775
  collapsed: { mobile: sidebar.closed }
2729
2776
  } : void 0,
@@ -2760,8 +2807,12 @@ const DashboardShell = (props) => {
2760
2807
  display: "flex",
2761
2808
  bg: "var(--alepha-ground)",
2762
2809
  pos: "relative",
2810
+ h: props.fill ? "100%" : "inherit",
2763
2811
  ...props.appShellMainProps,
2764
- children: props.children ?? /* @__PURE__ */ jsx(NestedView, {})
2812
+ children: props.container ? /* @__PURE__ */ jsx(Container$1, {
2813
+ ...typeof props.container === "boolean" ? {} : props.container,
2814
+ children: mainContent
2815
+ }) : mainContent
2765
2816
  }),
2766
2817
  footerElement && /* @__PURE__ */ jsx(AppShell.Footer, {
2767
2818
  ...props.appShellFooterProps,
@@ -2771,41 +2822,12 @@ const DashboardShell = (props) => {
2771
2822
  });
2772
2823
  };
2773
2824
 
2774
- //#endregion
2775
- //#region ../../src/core/components/Text.tsx
2776
- const INTENT_COLORS = {
2777
- primary: "blue",
2778
- info: "cyan",
2779
- success: "green",
2780
- warning: "yellow",
2781
- danger: "red"
2782
- };
2783
- const Text$1 = forwardRef((props, ref) => {
2784
- const { intent, bold, italic, light, muted, small, uppercase, capitalize, center, monospace, title, ...rest } = props;
2785
- if (intent) rest.c ??= INTENT_COLORS[intent];
2786
- if (bold) rest.fw ??= 700;
2787
- if (light) rest.fw ??= 300;
2788
- if (italic) rest.fs ??= "italic";
2789
- if (muted) rest.c ??= "dimmed";
2790
- if (small) rest.size ??= "xs";
2791
- if (uppercase) rest.tt ??= "uppercase";
2792
- if (capitalize) rest.tt ??= "capitalize";
2793
- if (center) rest.ta ??= "center";
2794
- if (monospace) rest.ff ??= "monospace";
2795
- if (title) rest.size ??= "xl";
2796
- return /* @__PURE__ */ jsx(Text, {
2797
- ref,
2798
- ...rest
2799
- });
2800
- });
2801
- Text$1.displayName = "Text";
2802
-
2803
2825
  //#endregion
2804
2826
  //#region ../../src/core/form/utils/parseInput.ts
2805
2827
  const parseInput = (props, form) => {
2806
2828
  const disabled = false;
2807
2829
  const id = props.input.props.id;
2808
- 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);
2830
+ 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);
2809
2831
  const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
2810
2832
  const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
2811
2833
  const icon = !props.icon ? getDefaultIcon({
@@ -2813,17 +2835,20 @@ const parseInput = (props, form) => {
2813
2835
  format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
2814
2836
  name: props.input.props.name,
2815
2837
  isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
2816
- isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
2817
- }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.md });
2838
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array",
2839
+ size: props.size
2840
+ }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.sm });
2818
2841
  const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
2819
2842
  const required = props.input.required;
2820
2843
  const schema = props.input.schema;
2844
+ const testId = props.input.props?.["data-testid"];
2821
2845
  const inputProps = {
2822
2846
  label,
2823
2847
  description,
2824
2848
  error,
2825
2849
  required,
2826
- disabled
2850
+ disabled,
2851
+ ...testId ? { "data-testid": testId } : {}
2827
2852
  };
2828
2853
  if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
2829
2854
  if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
@@ -2848,8 +2873,8 @@ const useArrayItems = (input) => {
2848
2873
  const alepha = useAlepha();
2849
2874
  const keyCounter = useRef(0);
2850
2875
  const [items, setItemsState] = useState(() => {
2851
- const defaultValue = input?.props?.defaultValue;
2852
- if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
2876
+ const initial = input?.initialValue;
2877
+ if (Array.isArray(initial)) return initial.map((value) => ({
2853
2878
  key: keyCounter.current++,
2854
2879
  value
2855
2880
  }));
@@ -2875,22 +2900,9 @@ const useArrayItems = (input) => {
2875
2900
  if (!input?.form) return;
2876
2901
  const formId = input.form.id;
2877
2902
  const fieldPath = input.path;
2878
- const listeners = [alepha.events.on("form:reset", (event) => {
2879
- if (event.id === formId) {
2880
- const defaultValue = input.props?.defaultValue;
2881
- keyCounter.current = 0;
2882
- if (Array.isArray(defaultValue)) setItemsState(defaultValue.map((value) => ({
2883
- key: keyCounter.current++,
2884
- value
2885
- })));
2886
- else setItemsState([]);
2887
- }
2888
- }), alepha.events.on("form:change", (event) => {
2903
+ return alepha.events.on("form:change", (event) => {
2889
2904
  if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
2890
- })];
2891
- return () => {
2892
- for (const unsub of listeners) unsub();
2893
- };
2905
+ });
2894
2906
  }, [
2895
2907
  alepha,
2896
2908
  input,
@@ -2915,10 +2927,10 @@ const createArrayItemInput = (parentInput, itemSchema, index, _itemKey, value, o
2915
2927
  path: `${parentInput.path}/${index}`,
2916
2928
  required: false,
2917
2929
  form: parentInput.form,
2930
+ initialValue: value,
2918
2931
  props: {
2919
2932
  id: `${parentInput.props.id}-${index}`,
2920
- name: `${parentInput.props.name}[${index}]`,
2921
- defaultValue: value
2933
+ name: `${parentInput.props.name}[${index}]`
2922
2934
  },
2923
2935
  set: onValueChange
2924
2936
  };
@@ -2933,10 +2945,10 @@ const createArrayItemFieldInput = (parentInput, itemSchema, fieldName, index, _i
2933
2945
  path: `${parentInput.path}/${index}/${fieldName}`,
2934
2946
  required: itemSchema.required?.includes(fieldName) ?? false,
2935
2947
  form: parentInput.form,
2948
+ initialValue: itemValue?.[fieldName],
2936
2949
  props: {
2937
2950
  id: `${parentInput.props.id}-${index}-${fieldName}`,
2938
- name: `${parentInput.props.name}[${index}].${fieldName}`,
2939
- defaultValue: itemValue?.[fieldName]
2951
+ name: `${parentInput.props.name}[${index}].${fieldName}`
2940
2952
  },
2941
2953
  set: (value) => onFieldChange(fieldName, value)
2942
2954
  };
@@ -3154,7 +3166,9 @@ const ControlArray = (props) => {
3154
3166
  * Automatically detects date formats from schema and renders appropriate picker.
3155
3167
  */
3156
3168
  const ControlDate = (props) => {
3157
- const { inputProps, id, icon, format } = parseInput(props, useFormState(props.input));
3169
+ const form = useFormState(props.input);
3170
+ const [value, setValue] = useFieldValue(props.input);
3171
+ const { inputProps, id, icon, format } = parseInput(props, form);
3158
3172
  if (!props.input?.props) return null;
3159
3173
  if (props.datetime || format === "date-time") {
3160
3174
  const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
@@ -3162,10 +3176,8 @@ const ControlDate = (props) => {
3162
3176
  ...inputProps,
3163
3177
  id,
3164
3178
  leftSection: icon,
3165
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
3166
- onChange: (value) => {
3167
- props.input.set(value ? new Date(value).toISOString() : void 0);
3168
- },
3179
+ value: value ? new Date(value) : null,
3180
+ onChange: (val) => setValue(val ? new Date(val).toISOString() : void 0),
3169
3181
  ...dateTimePickerProps
3170
3182
  });
3171
3183
  }
@@ -3175,10 +3187,8 @@ const ControlDate = (props) => {
3175
3187
  ...inputProps,
3176
3188
  id,
3177
3189
  leftSection: icon,
3178
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
3179
- onChange: (value) => {
3180
- props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
3181
- },
3190
+ value: value ? new Date(value) : null,
3191
+ onChange: (val) => setValue(val ? new Date(val).toISOString().slice(0, 10) : void 0),
3182
3192
  ...dateInputProps
3183
3193
  });
3184
3194
  }
@@ -3188,10 +3198,8 @@ const ControlDate = (props) => {
3188
3198
  ...inputProps,
3189
3199
  id,
3190
3200
  leftSection: icon,
3191
- defaultValue: props.input.props.defaultValue,
3192
- onChange: (event) => {
3193
- props.input.set(event.currentTarget.value);
3194
- },
3201
+ value: value ?? "",
3202
+ onChange: (event) => setValue(event.currentTarget.value),
3195
3203
  ...timeInputProps
3196
3204
  });
3197
3205
  }
@@ -3204,14 +3212,10 @@ const ControlDate = (props) => {
3204
3212
  *
3205
3213
  */
3206
3214
  const ControlNumber = (props) => {
3207
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
3208
- const ref = useRef(null);
3209
- const [value, setValue] = useState(props.input.props.defaultValue);
3210
- useEvents({ "form:reset": (event) => {
3211
- if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
3212
- } }, [props.input]);
3215
+ const form = useFormState(props.input);
3216
+ const [value, setValue] = useFieldValue(props.input);
3217
+ const { inputProps, id, icon } = parseInput(props, form);
3213
3218
  if (!props.input?.props) return null;
3214
- const { type, ...inputPropsWithoutType } = props.input.props;
3215
3219
  if (props.sliderProps) {
3216
3220
  const min = props.sliderProps.min ?? inputProps.minimum ?? 0;
3217
3221
  const max = props.sliderProps.max ?? inputProps.maximum ?? 100;
@@ -3224,34 +3228,25 @@ const ControlNumber = (props) => {
3224
3228
  },
3225
3229
  children: /* @__PURE__ */ jsx(Slider, {
3226
3230
  ...inputProps,
3227
- ref,
3228
3231
  id,
3229
- ...inputPropsWithoutType,
3230
3232
  ...props.sliderProps,
3231
- value,
3233
+ value: value ?? 0,
3232
3234
  min,
3233
3235
  max,
3234
3236
  label: () => value,
3235
- onChange: (val) => {
3236
- setValue(val);
3237
- props.input.set(val);
3238
- }
3237
+ onChange: (val) => setValue(val)
3239
3238
  })
3240
3239
  })
3241
3240
  });
3242
3241
  }
3243
3242
  return /* @__PURE__ */ jsx(NumberInput, {
3244
3243
  ...inputProps,
3245
- ref,
3246
3244
  id,
3247
3245
  leftSection: icon,
3248
- ...inputPropsWithoutType,
3249
3246
  ...props.numberInputProps,
3250
3247
  value: value ?? "",
3251
3248
  onChange: (val) => {
3252
- const newValue = val !== null ? Number(val) : void 0;
3253
- setValue(newValue);
3254
- props.input.set(newValue);
3249
+ setValue(val !== null ? Number(val) : void 0);
3255
3250
  }
3256
3251
  });
3257
3252
  };
@@ -3334,92 +3329,9 @@ const ControlObject = (props) => {
3334
3329
  };
3335
3330
 
3336
3331
  //#endregion
3337
- //#region ../../src/core/form/components/ControlQueryBuilder.tsx
3338
- /**
3339
- * Query builder with text input and help popover.
3340
- * Generates query strings for parseQueryString syntax.
3341
- */
3342
- const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
3343
- const [helpOpened, setHelpOpened] = useState(false);
3344
- const [textValue, setTextValue] = useState(value);
3345
- const inputRef = useRef(null);
3346
- const fields = schema ? extractSchemaFields(schema) : [];
3347
- const [error, setError] = useState(null);
3348
- const isValid = (value) => {
3349
- try {
3350
- parseQueryString(value.trim());
3351
- } catch (e) {
3352
- setError(e.message);
3353
- return false;
3354
- }
3355
- setError(null);
3356
- return true;
3357
- };
3358
- const handleTextChange = (newValue) => {
3359
- setTextValue(newValue);
3360
- if (isValid(newValue)) onChange?.(newValue);
3361
- };
3362
- const handleClear = () => {
3363
- setTextValue("");
3364
- onChange?.("");
3365
- isValid("");
3366
- };
3367
- const handleInsert = (text) => {
3368
- const newValue = textValue ? `${textValue}${text} ` : `${text} `;
3369
- setTextValue(newValue);
3370
- if (isValid(newValue)) onChange?.(newValue);
3371
- setTimeout(() => {
3372
- inputRef.current?.focus();
3373
- const length = inputRef.current?.value.length || 0;
3374
- inputRef.current?.setSelectionRange(length, length);
3375
- }, 0);
3376
- };
3377
- useEvents({ "form:change": (event) => {
3378
- if (event.id === inputRef.current?.form?.id) {
3379
- if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
3380
- }
3381
- } }, []);
3382
- return /* @__PURE__ */ jsxs(Popover, {
3383
- width: 800,
3384
- position: "bottom-start",
3385
- shadow: "md",
3386
- opened: helpOpened,
3387
- onChange: setHelpOpened,
3388
- closeOnClickOutside: true,
3389
- closeOnEscape: true,
3390
- transitionProps: {
3391
- transition: "fade-up",
3392
- duration: 200,
3393
- timingFunction: "ease"
3394
- },
3395
- children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
3396
- ref: inputRef,
3397
- placeholder,
3398
- value: textValue,
3399
- onChange: (e) => handleTextChange(e.currentTarget.value),
3400
- onFocus: () => setHelpOpened(true),
3401
- leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
3402
- rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
3403
- size: "sm",
3404
- variant: "subtle",
3405
- color: "gray",
3406
- onClick: handleClear,
3407
- children: /* @__PURE__ */ jsx(IconX, { size: 14 })
3408
- }),
3409
- ...textInputProps
3410
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3411
- bg: "transparent",
3412
- p: "xs",
3413
- bd: `1px solid ${ui.colors.border}`,
3414
- style: { backdropFilter: "blur(20px)" },
3415
- children: /* @__PURE__ */ jsx(QueryHelp, {
3416
- fields,
3417
- onInsert: handleInsert
3418
- })
3419
- })]
3420
- });
3421
- };
3422
- function QueryHelp({ fields, onInsert }) {
3332
+ //#region ../../src/core/form/components/ControlQueryBuilderHelp.tsx
3333
+ const ControlQueryBuilderHelp = (props) => {
3334
+ const { fields, onInsert } = props;
3423
3335
  return /* @__PURE__ */ jsxs(Flex, {
3424
3336
  gap: "md",
3425
3337
  align: "flex-start",
@@ -3580,113 +3492,316 @@ function QueryHelp({ fields, onInsert }) {
3580
3492
  }, field.path))
3581
3493
  })]
3582
3494
  })
3583
- ]
3495
+ ]
3496
+ });
3497
+ };
3498
+
3499
+ //#endregion
3500
+ //#region ../../src/core/form/components/ControlQueryBuilder.tsx
3501
+ /**
3502
+ * Query builder with text input and help popover.
3503
+ * Generates query strings for parseQueryString syntax.
3504
+ */
3505
+ const ControlQueryBuilder = (props) => {
3506
+ const { schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps } = props;
3507
+ const [helpOpened, setHelpOpened] = useState(false);
3508
+ const [textValue, setTextValue] = useState(value);
3509
+ const inputRef = useRef(null);
3510
+ const fields = schema ? extractSchemaFields(schema) : [];
3511
+ const [error, setError] = useState(null);
3512
+ const isValid = (value) => {
3513
+ try {
3514
+ parseQueryString(value.trim());
3515
+ } catch (e) {
3516
+ setError(e.message);
3517
+ return false;
3518
+ }
3519
+ setError(null);
3520
+ return true;
3521
+ };
3522
+ const handleTextChange = (newValue) => {
3523
+ setTextValue(newValue);
3524
+ if (isValid(newValue)) onChange?.(newValue);
3525
+ };
3526
+ const handleClear = () => {
3527
+ setTextValue("");
3528
+ onChange?.("");
3529
+ isValid("");
3530
+ };
3531
+ const handleInsert = (text) => {
3532
+ const newValue = textValue ? `${textValue}${text} ` : `${text} `;
3533
+ setTextValue(newValue);
3534
+ if (isValid(newValue)) onChange?.(newValue);
3535
+ setTimeout(() => {
3536
+ inputRef.current?.focus();
3537
+ const length = inputRef.current?.value.length || 0;
3538
+ inputRef.current?.setSelectionRange(length, length);
3539
+ }, 0);
3540
+ };
3541
+ useEvents({ "form:change": (event) => {
3542
+ if (event.id === inputRef.current?.form?.id) {
3543
+ if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
3544
+ }
3545
+ } }, []);
3546
+ return /* @__PURE__ */ jsxs(Popover, {
3547
+ width: 800,
3548
+ position: "bottom-start",
3549
+ shadow: "md",
3550
+ opened: helpOpened,
3551
+ onChange: setHelpOpened,
3552
+ closeOnClickOutside: true,
3553
+ closeOnEscape: true,
3554
+ transitionProps: {
3555
+ transition: "fade-up",
3556
+ duration: 200,
3557
+ timingFunction: "ease"
3558
+ },
3559
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
3560
+ ref: inputRef,
3561
+ placeholder,
3562
+ value: textValue,
3563
+ onChange: (e) => handleTextChange(e.currentTarget.value),
3564
+ onFocus: () => setHelpOpened(true),
3565
+ leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
3566
+ rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
3567
+ size: "sm",
3568
+ variant: "subtle",
3569
+ color: "gray",
3570
+ onClick: handleClear,
3571
+ children: /* @__PURE__ */ jsx(IconX, { size: 14 })
3572
+ }),
3573
+ ...textInputProps
3574
+ }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3575
+ bg: "transparent",
3576
+ p: "xs",
3577
+ bd: `1px solid ${ui.colors.border}`,
3578
+ style: { backdropFilter: "blur(20px)" },
3579
+ children: /* @__PURE__ */ jsx(ControlQueryBuilderHelp, {
3580
+ fields,
3581
+ onInsert: handleInsert
3582
+ })
3583
+ })]
3584
3584
  });
3585
- }
3585
+ };
3586
3586
 
3587
3587
  //#endregion
3588
3588
  //#region ../../src/core/form/components/ControlSelect.tsx
3589
3589
  /**
3590
- * ControlSelect component for handling Select, MultiSelect, and TagsInput.
3590
+ * ControlSelect component for handling Select, MultiSelect, Autocomplete, and TagsInput.
3591
3591
  *
3592
3592
  * Features:
3593
3593
  * - Basic Select with enum support
3594
3594
  * - MultiSelect for array of enums
3595
- * - TagsInput for array of strings (no enum)
3596
- * - Future: Lazy loading
3597
- * - Future: Searchable/filterable options
3598
- * - Future: Custom option rendering
3595
+ * - Autocomplete for creatable single values
3596
+ * - TagsInput for creatable array values
3597
+ * - Async lazy loading with auto short/long mode detection
3598
+ * - Short mode: client-side filtering with cached data
3599
+ * - Long mode: debounced server search
3599
3600
  *
3600
3601
  * Automatically detects enum values and array types from schema.
3601
3602
  */
3602
3603
  const ControlSelect = (props) => {
3603
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
3604
+ const form = useFormState(props.input);
3605
+ const [value, setValue] = useFieldValue(props.input);
3606
+ const { inputProps, id, icon } = parseInput(props, form);
3604
3607
  const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
3605
- let itemsEnum;
3606
- if (isArray && "items" in props.input.schema && props.input.schema.items) {
3607
- const items = props.input.schema.items;
3608
- if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
3609
- }
3608
+ const isNumeric = props.input.schema && "type" in props.input.schema && (props.input.schema.type === "integer" || props.input.schema.type === "number");
3609
+ const isBoolean = props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean";
3610
3610
  const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
3611
- const [data, setData] = useState([]);
3611
+ const { data: asyncData, loading, mode, search } = useAsyncLoader(props.loader, props.loaderThreshold ?? 100, props.loaderDebounce ?? 300, props.input.initialValue);
3612
+ const [staticData, setStaticData] = useState([]);
3613
+ const enumKey = JSON.stringify(enumValues);
3612
3614
  useEffect(() => {
3613
- if (!props.input?.props) return;
3614
- if (props.loader) props.loader().then(setData);
3615
- else setData(enumValues);
3616
- }, [props.input, props.loader]);
3615
+ if (!props.input?.props || props.loader) return;
3616
+ if (isBoolean && enumValues.length === 0) setStaticData([{
3617
+ value: "true",
3618
+ label: "True"
3619
+ }, {
3620
+ value: "false",
3621
+ label: "False"
3622
+ }]);
3623
+ else setStaticData(enumValues);
3624
+ }, [
3625
+ props.input,
3626
+ props.loader,
3627
+ enumKey,
3628
+ isBoolean
3629
+ ]);
3630
+ const data = props.loader ? asyncData : staticData;
3617
3631
  if (!props.input?.props) return null;
3618
- if (props.segmented) {
3619
- const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
3632
+ /**
3633
+ * Coerce value for numeric schemas Select values are always strings.
3634
+ */
3635
+ const coerceValue = (val) => {
3636
+ if (val == null) return val;
3637
+ if (isNumeric) return Number(val);
3638
+ if (isBoolean) return val === "true";
3639
+ return val;
3640
+ };
3641
+ if (props.segmentedProps) {
3642
+ const segmentedControlProps = typeof props.segmentedProps === "object" ? props.segmentedProps : {};
3643
+ const segmentedData = segmentedControlProps.data ?? data.slice(0, 10);
3620
3644
  return /* @__PURE__ */ jsx(Input.Wrapper, {
3621
3645
  ...inputProps,
3622
- children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(SegmentedControl, {
3623
- disabled: inputProps.disabled,
3624
- defaultValue: String(props.input.props.defaultValue),
3625
- ...segmentedControlProps,
3626
- onChange: (value) => {
3627
- props.input.set(value);
3628
- },
3629
- data: data.slice(0, 10)
3630
- }) })
3646
+ children: /* @__PURE__ */ jsx(Flex, {
3647
+ my: "calc(var(--mantine-spacing-xs) / 2)",
3648
+ children: /* @__PURE__ */ jsx(SegmentedControl, {
3649
+ disabled: inputProps.disabled,
3650
+ value: value != null ? String(value) : "",
3651
+ ...segmentedControlProps,
3652
+ onChange: (val) => {
3653
+ setValue(coerceValue(val));
3654
+ },
3655
+ data: segmentedData
3656
+ })
3657
+ })
3631
3658
  });
3632
3659
  }
3633
- if (props.autocomplete) {
3634
- const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
3635
- return /* @__PURE__ */ jsx(Autocomplete, {
3660
+ const sharedProps = {
3661
+ size: props.size,
3662
+ id,
3663
+ leftSection: loading ? /* @__PURE__ */ jsx(Loader, {
3664
+ color: "gray",
3665
+ size: 10
3666
+ }) : icon,
3667
+ data
3668
+ };
3669
+ const selectableProps = {
3670
+ ...sharedProps,
3671
+ searchable: true,
3672
+ rightSection: /* @__PURE__ */ jsx("span", {})
3673
+ };
3674
+ const longModeProps = mode === "long" ? {
3675
+ filter: ({ options }) => options,
3676
+ onSearchChange: search.run
3677
+ } : {};
3678
+ if (props.creatable && (isArray || props.tagsInputProps)) {
3679
+ const tagsInputExtraProps = props.tagsInputProps ?? {};
3680
+ return /* @__PURE__ */ jsx(TagsInput, {
3636
3681
  ...inputProps,
3637
- size: props.size,
3638
- id,
3639
- leftSection: icon,
3640
- data,
3641
- ...props.input.props,
3642
- ...autocompleteProps
3682
+ ...sharedProps,
3683
+ ...longModeProps,
3684
+ value: Array.isArray(value) ? value : [],
3685
+ onChange: (val) => {
3686
+ setValue(val);
3687
+ },
3688
+ ...tagsInputExtraProps
3643
3689
  });
3644
3690
  }
3645
- if (isArray && !itemsEnum || props.tags) {
3646
- const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
3647
- return /* @__PURE__ */ jsx(TagsInput, {
3691
+ if (props.creatable) {
3692
+ const autocompleteExtraProps = props.autocompleteProps ?? {};
3693
+ return /* @__PURE__ */ jsx(Autocomplete, {
3648
3694
  ...inputProps,
3649
- size: props.size,
3650
- id,
3651
- leftSection: icon,
3652
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
3653
- onChange: (value) => {
3654
- props.input.set(value);
3695
+ ...sharedProps,
3696
+ ...longModeProps,
3697
+ value: value != null ? String(value) : "",
3698
+ onChange: (val) => {
3699
+ setValue(coerceValue(val));
3655
3700
  },
3656
- ...tagsInputProps
3701
+ ...autocompleteExtraProps
3657
3702
  });
3658
3703
  }
3659
- if (isArray && itemsEnum || props.multi) {
3660
- const data = itemsEnum?.map((value) => ({
3661
- value,
3662
- label: value
3663
- })) || [];
3664
- const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
3704
+ if (isArray || props.multiSelectProps) {
3705
+ const multiSelectExtraProps = typeof props.multiSelectProps === "object" ? props.multiSelectProps : {};
3665
3706
  return /* @__PURE__ */ jsx(MultiSelect, {
3666
3707
  ...inputProps,
3667
- size: props.size,
3668
- id,
3669
- leftSection: icon,
3670
- data,
3671
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
3672
- onChange: (value) => {
3673
- props.input.set(value);
3708
+ ...selectableProps,
3709
+ ...longModeProps,
3710
+ value: Array.isArray(value) ? value : [],
3711
+ onChange: (val) => {
3712
+ setValue(val);
3674
3713
  },
3675
- ...multiSelectProps
3714
+ ...multiSelectExtraProps
3676
3715
  });
3677
3716
  }
3678
- const selectProps = typeof props.select === "object" ? props.select : {};
3717
+ const selectExtraProps = typeof props.selectProps === "object" ? props.selectProps : {};
3718
+ if (mode === "static") return /* @__PURE__ */ jsx(Select, {
3719
+ ...inputProps,
3720
+ ...selectableProps,
3721
+ value: value != null ? String(value) : null,
3722
+ onChange: (val) => {
3723
+ setValue(coerceValue(val));
3724
+ },
3725
+ ...selectExtraProps
3726
+ });
3679
3727
  return /* @__PURE__ */ jsx(Select, {
3680
3728
  ...inputProps,
3681
- size: props.size,
3682
- id,
3683
- leftSection: icon,
3684
- rightSection: null,
3685
- data,
3686
- ...props.input.props,
3687
- ...selectProps
3729
+ ...selectableProps,
3730
+ ...longModeProps,
3731
+ value: value != null ? String(value) : null,
3732
+ onChange: (val) => {
3733
+ setValue(coerceValue(val));
3734
+ },
3735
+ ...selectExtraProps
3688
3736
  });
3689
3737
  };
3738
+ /**
3739
+ * Hook for async select data loading with auto short/long mode detection.
3740
+ */
3741
+ const useAsyncLoader = (loader, threshold, debounceMs, defaultValue) => {
3742
+ const [data, setData] = useState([]);
3743
+ const [loading, setLoading] = useState(false);
3744
+ const [mode, setMode] = useState("static");
3745
+ const cache = useRef(/* @__PURE__ */ new Map());
3746
+ useAction({
3747
+ name: "select:loader:init",
3748
+ runOnInit: true,
3749
+ handler: async () => {
3750
+ if (!loader) {
3751
+ setMode("static");
3752
+ return;
3753
+ }
3754
+ setLoading(true);
3755
+ try {
3756
+ const result = await loader("");
3757
+ const isShort = result.length <= threshold;
3758
+ setMode(isShort ? "short" : "long");
3759
+ cache.current.set("", result);
3760
+ setData(result);
3761
+ if (!isShort && defaultValue != null && String(defaultValue) !== "") {
3762
+ const resolved = await loader("", [String(defaultValue)]);
3763
+ if (resolved.length > 0) setData((prev) => {
3764
+ const existing = new Set(prev.map((d) => typeof d === "string" ? d : d.value));
3765
+ const newItems = resolved.filter((r) => {
3766
+ const val = typeof r === "string" ? r : r.value;
3767
+ return !existing.has(val);
3768
+ });
3769
+ return [...prev, ...newItems];
3770
+ });
3771
+ }
3772
+ } finally {
3773
+ setLoading(false);
3774
+ }
3775
+ }
3776
+ }, [loader, threshold]);
3777
+ return {
3778
+ data,
3779
+ loading,
3780
+ mode,
3781
+ search: useAction({
3782
+ debounce: debounceMs,
3783
+ handler: async (text) => {
3784
+ if (!loader || mode !== "long") return;
3785
+ if (cache.current.has(text)) {
3786
+ setData(cache.current.get(text));
3787
+ return;
3788
+ }
3789
+ setLoading(true);
3790
+ try {
3791
+ const result = await loader(text);
3792
+ cache.current.set(text, result);
3793
+ setData(result);
3794
+ } finally {
3795
+ setLoading(false);
3796
+ }
3797
+ }
3798
+ }, [
3799
+ loader,
3800
+ mode,
3801
+ debounceMs
3802
+ ])
3803
+ };
3804
+ };
3690
3805
 
3691
3806
  //#endregion
3692
3807
  //#region ../../src/core/form/components/Control.tsx
@@ -3716,6 +3831,7 @@ const ControlSelect = (props) => {
3716
3831
  */
3717
3832
  const Control = (_props) => {
3718
3833
  const form = useFormState(_props.input, ["error"]);
3834
+ const [value, setValue] = useFieldValue(_props.input);
3719
3835
  if (!_props.input?.props) return null;
3720
3836
  const { inputProps, id, icon, format, schema } = parseInput(_props, form);
3721
3837
  const props = {
@@ -3723,12 +3839,11 @@ const Control = (_props) => {
3723
3839
  ...schema.$control
3724
3840
  };
3725
3841
  if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder, {
3726
- ...props.input.props,
3727
3842
  ...inputProps,
3728
3843
  schema: props.query,
3729
- value: props.input.props.value,
3730
- onChange: (value) => {
3731
- props.input.set(value);
3844
+ value,
3845
+ onChange: (val) => {
3846
+ setValue(val);
3732
3847
  }
3733
3848
  });
3734
3849
  if (props.custom) {
@@ -3739,9 +3854,9 @@ const Control = (_props) => {
3739
3854
  flex: 1,
3740
3855
  mt: "calc(var(--mantine-spacing-xs) / 2)",
3741
3856
  children: /* @__PURE__ */ jsx(Custom, {
3742
- defaultValue: props.input.props.defaultValue,
3743
- onChange: (value) => {
3744
- props.input.set(value);
3857
+ value,
3858
+ onChange: (val) => {
3859
+ setValue(val);
3745
3860
  }
3746
3861
  })
3747
3862
  })
@@ -3752,7 +3867,7 @@ const Control = (_props) => {
3752
3867
  const controlObjectProps = typeof props.object === "object" ? props.object : {};
3753
3868
  return /* @__PURE__ */ jsx(ControlObject, {
3754
3869
  input: props.input,
3755
- title: props.title,
3870
+ label: props.label,
3756
3871
  description: props.description,
3757
3872
  ...controlObjectProps
3758
3873
  });
@@ -3763,18 +3878,18 @@ const Control = (_props) => {
3763
3878
  const controlArrayProps = typeof props.array === "object" ? props.array : {};
3764
3879
  return /* @__PURE__ */ jsx(ControlArray, {
3765
3880
  input: props.input,
3766
- title: props.title,
3881
+ label: props.label,
3767
3882
  description: props.description,
3768
3883
  ...controlArrayProps
3769
3884
  });
3770
3885
  }
3771
- if (props.number || props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
3886
+ if (props.number || !props.select && props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
3772
3887
  const controlNumberProps = typeof props.number === "object" ? props.number : {};
3773
3888
  if (props.slider) controlNumberProps.sliderProps ??= {};
3774
3889
  return /* @__PURE__ */ jsx(ControlNumber, {
3775
3890
  size: props.size,
3776
3891
  input: props.input,
3777
- title: props.title,
3892
+ label: props.label,
3778
3893
  description: props.description,
3779
3894
  icon,
3780
3895
  ...controlNumberProps
@@ -3787,9 +3902,7 @@ const Control = (_props) => {
3787
3902
  size: props.size,
3788
3903
  id,
3789
3904
  leftSection: icon,
3790
- onChange: (file) => {
3791
- props.input.set(file);
3792
- },
3905
+ onChange: (file) => setValue(file),
3793
3906
  ...fileInputProps
3794
3907
  });
3795
3908
  }
@@ -3800,17 +3913,18 @@ const Control = (_props) => {
3800
3913
  size: props.size,
3801
3914
  id,
3802
3915
  leftSection: icon,
3803
- ...props.input.props,
3916
+ value: value ?? "",
3917
+ onChange: (val) => setValue(val),
3804
3918
  ...colorInputProps
3805
3919
  });
3806
3920
  }
3807
3921
  if (props.input.schema && "enum" in props.input.schema && props.input.schema.enum || isArray && !isArrayOfObjects || props.select) {
3808
3922
  const opts = typeof props.select === "object" ? props.select : {};
3809
- if (props.segmented) opts.segmented ??= {};
3923
+ if (props.segmented) opts.segmentedProps ??= {};
3810
3924
  return /* @__PURE__ */ jsx(ControlSelect, {
3811
3925
  size: props.size,
3812
3926
  input: props.input,
3813
- title: props.title,
3927
+ label: props.label,
3814
3928
  description: props.description,
3815
3929
  icon,
3816
3930
  ...opts
@@ -3824,16 +3938,16 @@ const Control = (_props) => {
3824
3938
  size: props.size,
3825
3939
  id,
3826
3940
  color: "blue",
3827
- defaultChecked: props.input.props.defaultValue,
3941
+ checked: Boolean(value),
3828
3942
  onChange: (event) => {
3829
- props.input.set(event.currentTarget.checked);
3943
+ setValue(event.currentTarget.checked);
3830
3944
  },
3831
3945
  ...switchProps
3832
3946
  });
3833
3947
  }
3834
3948
  const opts = {
3835
3949
  input: props.input,
3836
- select: { data: [{
3950
+ selectProps: { data: [{
3837
3951
  value: "true",
3838
3952
  label: "Yes"
3839
3953
  }, {
@@ -3843,7 +3957,7 @@ const Control = (_props) => {
3843
3957
  };
3844
3958
  return /* @__PURE__ */ jsx(ControlSelect, {
3845
3959
  size: props.size,
3846
- title: props.title,
3960
+ label: props.label,
3847
3961
  description: props.description,
3848
3962
  icon,
3849
3963
  ...opts
@@ -3856,7 +3970,8 @@ const Control = (_props) => {
3856
3970
  size: props.size,
3857
3971
  id,
3858
3972
  leftSection: icon,
3859
- ...props.input.props,
3973
+ value: value ?? "",
3974
+ onChange: (ev) => setValue(ev.target.value),
3860
3975
  ...passwordInputProps
3861
3976
  });
3862
3977
  }
@@ -3867,14 +3982,15 @@ const Control = (_props) => {
3867
3982
  size: props.size,
3868
3983
  id,
3869
3984
  leftSection: icon,
3870
- ...props.input.props,
3985
+ value: value ?? "",
3986
+ onChange: (ev) => setValue(ev.target.value),
3871
3987
  ...textAreaProps
3872
3988
  });
3873
3989
  }
3874
3990
  if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate, {
3875
3991
  size: props.size,
3876
3992
  input: props.input,
3877
- title: props.title,
3993
+ label: props.label,
3878
3994
  description: props.description,
3879
3995
  icon,
3880
3996
  date: props.date,
@@ -3889,7 +4005,7 @@ const Control = (_props) => {
3889
4005
  case "uri": return "url";
3890
4006
  case "tel":
3891
4007
  case "phone": return "tel";
3892
- default: return;
4008
+ default: return props.input.props.type ?? "text";
3893
4009
  }
3894
4010
  };
3895
4011
  return /* @__PURE__ */ jsx(TextInput, {
@@ -3898,14 +4014,9 @@ const Control = (_props) => {
3898
4014
  id,
3899
4015
  leftSection: icon,
3900
4016
  type: getInputType(),
3901
- ...props.input.props,
3902
- ...textInputProps,
3903
- inputWrapperOrder: [
3904
- "label",
3905
- "input",
3906
- "description",
3907
- "error"
3908
- ]
4017
+ value: value ?? "",
4018
+ onChange: (ev) => setValue(ev.target.value),
4019
+ ...textInputProps
3909
4020
  });
3910
4021
  };
3911
4022
 
@@ -3954,6 +4065,7 @@ const Control = (_props) => {
3954
4065
  */
3955
4066
  const TypeForm = (props) => {
3956
4067
  const { form, columns = 3, children, controlProps, fieldControlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps, fill = true, size } = props;
4068
+ const { dirty } = useFormState(form, ["dirty"]);
3957
4069
  const schema = props.schema || form.options.schema;
3958
4070
  if (!schema?.properties) return null;
3959
4071
  const supportedFields = Object.keys(schema.properties);
@@ -4016,10 +4128,12 @@ const TypeForm = (props) => {
4016
4128
  children: [/* @__PURE__ */ jsx(ActionButton, {
4017
4129
  variant: "subtle",
4018
4130
  type: "reset",
4131
+ disabled: !dirty,
4019
4132
  children: "Reset"
4020
4133
  }), /* @__PURE__ */ jsx(ActionButton, {
4021
4134
  intent: "primary",
4022
4135
  form,
4136
+ disabled: !dirty,
4023
4137
  ...submitButtonProps,
4024
4138
  children: submitButtonProps?.children ?? "Submit"
4025
4139
  })]
@@ -4039,16 +4153,27 @@ const TypeForm = (props) => {
4039
4153
  };
4040
4154
 
4041
4155
  //#endregion
4042
- //#region ../../src/core/helpers/renderIcon.tsx
4043
- const renderIcon = (icon, size) => {
4044
- if (!icon) return null;
4045
- if (isValidElement(icon)) return icon;
4046
- if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
4047
- return icon;
4156
+ //#region ../../src/core/json/components/JsonViewerCopyButton.tsx
4157
+ const JsonViewerCopyButton = (props) => {
4158
+ const [copied, setCopied] = useState(false);
4159
+ const handleCopy = useCallback((e) => {
4160
+ e.stopPropagation();
4161
+ navigator.clipboard.writeText(props.value);
4162
+ setCopied(true);
4163
+ setTimeout(() => setCopied(false), 1500);
4164
+ }, [props.value]);
4165
+ return /* @__PURE__ */ jsx(ActionIcon, {
4166
+ size: props.iconSize + 4,
4167
+ variant: "transparent",
4168
+ c: copied ? "green" : "dimmed",
4169
+ onClick: handleCopy,
4170
+ className: "alepha-json-viewer-copy",
4171
+ children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: props.iconSize }) : /* @__PURE__ */ jsx(IconCopy, { size: props.iconSize })
4172
+ });
4048
4173
  };
4049
4174
 
4050
4175
  //#endregion
4051
- //#region ../../src/core/json/components/JsonViewer.tsx
4176
+ //#region ../../src/core/json/components/JsonViewerShared.ts
4052
4177
  const SIZE_CONFIG = {
4053
4178
  xs: {
4054
4179
  icon: 14,
@@ -4097,77 +4222,21 @@ const getValueType = (val) => {
4097
4222
  if (Array.isArray(val)) return "array";
4098
4223
  return typeof val;
4099
4224
  };
4100
- function buildTreeNodes(data, path = [], key, isArrayItem = false, maxDepth = 10) {
4101
- const currentPath = key !== void 0 ? [...path, key] : path;
4102
- const nodeId = currentPath.length > 0 ? currentPath.join(".") : "root";
4103
- if (currentPath.length > maxDepth) return {
4104
- value: nodeId,
4105
- label: key ?? "",
4106
- nodeValue: data,
4107
- nodeKey: key,
4108
- path: currentPath,
4109
- isArrayItem
4110
- };
4111
- const type = getValueType(data);
4112
- if (type === "object" || type === "array") {
4113
- const children = (type === "array" ? data.map((v, i) => [String(i), v]) : Object.entries(data)).map(([k, v]) => buildTreeNodes(v, currentPath, k, type === "array", maxDepth)).filter((n) => n !== null);
4114
- return {
4115
- value: nodeId,
4116
- label: key ?? "",
4117
- nodeValue: data,
4118
- nodeKey: key,
4119
- path: currentPath,
4120
- isArrayItem,
4121
- children: children.length > 0 ? children : void 0
4122
- };
4123
- }
4124
- return {
4125
- value: nodeId,
4126
- label: key ?? "",
4127
- nodeValue: data,
4128
- nodeKey: key,
4129
- path: currentPath,
4130
- isArrayItem
4131
- };
4132
- }
4133
- function getExpandedIds(nodes, targetDepth, currentDepth = 0) {
4134
- if (currentDepth >= targetDepth) return [];
4135
- const ids = [];
4136
- for (const node of nodes) if (node.children) {
4137
- ids.push(node.value);
4138
- ids.push(...getExpandedIds(node.children, targetDepth, currentDepth + 1));
4139
- }
4140
- return ids;
4141
- }
4142
- const CopyButton = ({ value, iconSize }) => {
4143
- const [copied, setCopied] = useState(false);
4144
- const handleCopy = useCallback((e) => {
4145
- e.stopPropagation();
4146
- navigator.clipboard.writeText(value);
4147
- setCopied(true);
4148
- setTimeout(() => setCopied(false), 1500);
4149
- }, [value]);
4150
- return /* @__PURE__ */ jsx(ActionIcon, {
4151
- size: iconSize + 4,
4152
- variant: "transparent",
4153
- c: copied ? "green" : "dimmed",
4154
- onClick: handleCopy,
4155
- className: "alepha-json-viewer-copy",
4156
- children: copied ? /* @__PURE__ */ jsx(IconCheck, { size: iconSize }) : /* @__PURE__ */ jsx(IconCopy, { size: iconSize })
4157
- });
4158
- };
4159
- const RowNode = ({ node, expanded, hasChildren, elementProps, size, config, showQuotes, showCopyButton, renderValue }) => {
4160
- const { nodeValue, nodeKey, path, isArrayItem, isRoot } = node;
4225
+
4226
+ //#endregion
4227
+ //#region ../../src/core/json/components/JsonViewerRowNode.tsx
4228
+ const JsonViewerRowNode = (props) => {
4229
+ const { nodeValue, nodeKey, path, isArrayItem } = props.node;
4161
4230
  const type = getValueType(nodeValue);
4162
4231
  const isExpandable = type === "object" || type === "array";
4163
4232
  const getPreview = () => {
4164
4233
  if (!isExpandable) return null;
4165
4234
  const count = (type === "array" ? nodeValue : Object.keys(nodeValue)).length;
4166
4235
  const label = type === "array" ? "item" : "key";
4167
- if (!expanded) return /* @__PURE__ */ jsx(Text, {
4236
+ if (!props.expanded) return /* @__PURE__ */ jsx(Text, {
4168
4237
  fs: "italic",
4169
4238
  component: "span",
4170
- size,
4239
+ size: props.size,
4171
4240
  style: STYLES.preview,
4172
4241
  children: count === 0 ? type === "array" ? "[]" : "{}" : type === "array" ? `[ ${count} ${count === 1 ? label : `${label}s`} ]` : `{ ${count} ${count === 1 ? label : `${label}s`} }`
4173
4242
  });
@@ -4177,25 +4246,25 @@ const RowNode = ({ node, expanded, hasChildren, elementProps, size, config, show
4177
4246
  return /* @__PURE__ */ jsxs(Flex, {
4178
4247
  gap: 6,
4179
4248
  wrap: "nowrap",
4180
- ...elementProps,
4181
- className: `alepha-json-viewer-row ${elementProps.className || ""}`,
4249
+ ...props.elementProps,
4250
+ className: `alepha-json-viewer-row ${props.elementProps.className || ""}`,
4182
4251
  children: [
4183
- hasChildren ? expanded ? /* @__PURE__ */ jsx(IconChevronDown, {
4184
- size: config.icon,
4252
+ props.hasChildren ? props.expanded ? /* @__PURE__ */ jsx(IconChevronDown, {
4253
+ size: props.config.icon,
4185
4254
  style: STYLES.chevron
4186
4255
  }) : /* @__PURE__ */ jsx(IconChevronRight, {
4187
- size: config.icon,
4256
+ size: props.config.icon,
4188
4257
  style: STYLES.chevron
4189
4258
  }) : /* @__PURE__ */ jsx("span", { style: {
4190
- width: config.icon,
4259
+ width: props.config.icon,
4191
4260
  flexShrink: 0
4192
4261
  } }),
4193
4262
  nodeKey !== void 0 && !isArrayItem && /* @__PURE__ */ jsxs(Text, {
4194
4263
  component: "span",
4195
- size,
4264
+ size: props.size,
4196
4265
  children: [/* @__PURE__ */ jsx("span", {
4197
4266
  style: STYLES.key,
4198
- children: showQuotes ? `"${nodeKey}"` : nodeKey
4267
+ children: props.showQuotes ? `"${nodeKey}"` : nodeKey
4199
4268
  }), /* @__PURE__ */ jsx("span", {
4200
4269
  style: STYLES.colon,
4201
4270
  children: ":"
@@ -4203,7 +4272,7 @@ const RowNode = ({ node, expanded, hasChildren, elementProps, size, config, show
4203
4272
  }),
4204
4273
  nodeKey !== void 0 && isArrayItem && /* @__PURE__ */ jsxs(Text, {
4205
4274
  component: "span",
4206
- size,
4275
+ size: props.size,
4207
4276
  children: [/* @__PURE__ */ jsx("span", {
4208
4277
  style: STYLES.key,
4209
4278
  children: nodeKey
@@ -4212,25 +4281,29 @@ const RowNode = ({ node, expanded, hasChildren, elementProps, size, config, show
4212
4281
  children: ":"
4213
4282
  })]
4214
4283
  }),
4215
- hasChildren ? getPreview() : isExpandable ? type === "array" ? /* @__PURE__ */ jsx(Text, {
4284
+ props.hasChildren ? getPreview() : isExpandable ? type === "array" ? /* @__PURE__ */ jsx(Text, {
4216
4285
  component: "span",
4217
- size,
4286
+ size: props.size,
4218
4287
  style: STYLES.preview,
4219
4288
  children: "[]"
4220
4289
  }) : /* @__PURE__ */ jsx(Text, {
4221
4290
  component: "span",
4222
- size,
4291
+ size: props.size,
4223
4292
  style: STYLES.preview,
4224
4293
  children: "{}"
4225
- }) : renderValue(nodeValue, nodeKey, path),
4226
- showCopyButton && /* @__PURE__ */ jsx(CopyButton, {
4294
+ }) : props.renderValue(nodeValue, nodeKey, path),
4295
+ props.showCopyButton && /* @__PURE__ */ jsx(JsonViewerCopyButton, {
4227
4296
  value: getCopyValue(),
4228
- iconSize: config.icon
4297
+ iconSize: props.config.icon
4229
4298
  })
4230
4299
  ]
4231
4300
  });
4232
4301
  };
4233
- const JsonViewer = ({ data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm", showQuotes = false, showCopyButton = true, formatValue }) => {
4302
+
4303
+ //#endregion
4304
+ //#region ../../src/core/json/components/JsonViewer.tsx
4305
+ const JsonViewer = (props) => {
4306
+ const { data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm", showQuotes = false, showCopyButton = true, formatValue } = props;
4234
4307
  const config = SIZE_CONFIG[size] || SIZE_CONFIG.sm;
4235
4308
  const treeData = useMemo(() => {
4236
4309
  const type = getValueType(data);
@@ -4310,7 +4383,7 @@ const JsonViewer = ({ data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm"
4310
4383
  size
4311
4384
  ]);
4312
4385
  const renderNode = useCallback(({ node, expanded, hasChildren, elementProps }) => {
4313
- return /* @__PURE__ */ jsx(RowNode, {
4386
+ return /* @__PURE__ */ jsx(JsonViewerRowNode, {
4314
4387
  node,
4315
4388
  expanded,
4316
4389
  hasChildren,
@@ -4342,6 +4415,54 @@ const JsonViewer = ({ data, defaultExpandedDepth = 2, maxDepth = 10, size = "sm"
4342
4415
  styles: { root: STYLES.root }
4343
4416
  });
4344
4417
  };
4418
+ /**
4419
+ * Convert JSON to tree data structure.
4420
+ */
4421
+ const buildTreeNodes = (data, path = [], key, isArrayItem = false, maxDepth = 10) => {
4422
+ const currentPath = key !== void 0 ? [...path, key] : path;
4423
+ const nodeId = currentPath.length > 0 ? currentPath.join(".") : "root";
4424
+ if (currentPath.length > maxDepth) return {
4425
+ value: nodeId,
4426
+ label: key ?? "",
4427
+ nodeValue: data,
4428
+ nodeKey: key,
4429
+ path: currentPath,
4430
+ isArrayItem
4431
+ };
4432
+ const type = getValueType(data);
4433
+ if (type === "object" || type === "array") {
4434
+ const children = (type === "array" ? data.map((v, i) => [String(i), v]) : Object.entries(data)).map(([k, v]) => buildTreeNodes(v, currentPath, k, type === "array", maxDepth)).filter((n) => n !== null);
4435
+ return {
4436
+ value: nodeId,
4437
+ label: key ?? "",
4438
+ nodeValue: data,
4439
+ nodeKey: key,
4440
+ path: currentPath,
4441
+ isArrayItem,
4442
+ children: children.length > 0 ? children : void 0
4443
+ };
4444
+ }
4445
+ return {
4446
+ value: nodeId,
4447
+ label: key ?? "",
4448
+ nodeValue: data,
4449
+ nodeKey: key,
4450
+ path: currentPath,
4451
+ isArrayItem
4452
+ };
4453
+ };
4454
+ /**
4455
+ * Get all expandable node IDs up to a certain depth.
4456
+ */
4457
+ const getExpandedIds = (nodes, targetDepth, currentDepth = 0) => {
4458
+ if (currentDepth >= targetDepth) return [];
4459
+ const ids = [];
4460
+ for (const node of nodes) if (node.children) {
4461
+ ids.push(node.value);
4462
+ ids.push(...getExpandedIds(node.children, targetDepth, currentDepth + 1));
4463
+ }
4464
+ return ids;
4465
+ };
4345
4466
 
4346
4467
  //#endregion
4347
4468
  //#region ../../src/core/table/interfaces/types.ts
@@ -4349,7 +4470,8 @@ const DEFAULT_MAX_VISIBLE_COLUMNS = 8;
4349
4470
 
4350
4471
  //#endregion
4351
4472
  //#region ../../src/core/table/components/DataTableFilters.tsx
4352
- const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) => {
4473
+ const DataTableFilters = (props) => {
4474
+ const { schema, form, typeFormProps, filterVisibility } = props;
4353
4475
  const visibleSchema = useMemo(() => {
4354
4476
  const visibleKeys = Object.keys(schema.properties).filter((key) => filterVisibility[key] !== false);
4355
4477
  if (visibleKeys.length === 0) return null;
@@ -4360,14 +4482,14 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
4360
4482
  return t.object(visibleProps);
4361
4483
  }, [schema, filterVisibility]);
4362
4484
  if (!visibleSchema) return null;
4363
- return /* @__PURE__ */ jsx(Flex, {
4364
- w: "100%",
4485
+ return /* @__PURE__ */ jsx(Flex$1, {
4486
+ surface: true,
4487
+ flex: 1,
4488
+ mt: -4,
4365
4489
  p: "xs",
4366
4490
  m: "xs",
4367
4491
  bdrs: "md",
4368
- bg: ui.colors.surface,
4369
4492
  children: /* @__PURE__ */ jsx(TypeForm, {
4370
- size: "xs",
4371
4493
  ...typeFormProps,
4372
4494
  skipSubmitButton: true,
4373
4495
  fill: true,
@@ -4378,7 +4500,7 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
4378
4500
  sm: 2,
4379
4501
  md: 3,
4380
4502
  lg: 4,
4381
- xl: 6
4503
+ xl: 5
4382
4504
  }
4383
4505
  })
4384
4506
  });
@@ -4386,9 +4508,10 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
4386
4508
 
4387
4509
  //#endregion
4388
4510
  //#region ../../src/core/table/components/DataTablePagination.tsx
4389
- const DataTablePagination = ({ page, size, totalPages, totalElements, offset, numberOfElements, onPageChange, onSizeChange }) => {
4511
+ const DataTablePagination = ({ page, size, totalPages, totalElements, isFirst, isLast, offset, numberOfElements, onPageChange, onSizeChange }) => {
4390
4512
  const from = numberOfElements > 0 ? offset + 1 : 0;
4391
4513
  const to = offset + numberOfElements;
4514
+ const hasTotal = totalPages != null;
4392
4515
  return /* @__PURE__ */ jsxs(Flex$1, {
4393
4516
  align: "center",
4394
4517
  justify: "space-between",
@@ -4436,8 +4559,9 @@ const DataTablePagination = ({ page, size, totalPages, totalElements, offset, nu
4436
4559
  ]
4437
4560
  }) }), /* @__PURE__ */ jsx(Flex$1, { children: /* @__PURE__ */ jsx(Pagination, {
4438
4561
  size: "sm",
4439
- withEdges: true,
4440
- total: totalPages,
4562
+ withEdges: hasTotal,
4563
+ withPages: hasTotal,
4564
+ total: hasTotal ? totalPages : isLast !== false ? page : page + 1,
4441
4565
  value: page,
4442
4566
  onChange: onPageChange
4443
4567
  }) })]
@@ -4488,7 +4612,7 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
4488
4612
  timingFunction: "ease"
4489
4613
  },
4490
4614
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
4491
- variant: "subtle",
4615
+ variant: "minimal",
4492
4616
  icon: IconColumns,
4493
4617
  onClick: () => setOpened((o) => !o)
4494
4618
  }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
@@ -4518,12 +4642,12 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
4518
4642
  gap: 4,
4519
4643
  children: [/* @__PURE__ */ jsx(ActionButton, {
4520
4644
  size: "compact-xs",
4521
- variant: "subtle",
4645
+ variant: "minimal",
4522
4646
  onClick: handleShowAll,
4523
4647
  children: "All"
4524
4648
  }), /* @__PURE__ */ jsx(ActionButton, {
4525
4649
  size: "compact-xs",
4526
- variant: "subtle",
4650
+ variant: "minimal",
4527
4651
  onClick: handleDefault,
4528
4652
  children: "Default"
4529
4653
  })]
@@ -4589,7 +4713,7 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
4589
4713
  timingFunction: "ease"
4590
4714
  },
4591
4715
  children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
4592
- variant: "subtle",
4716
+ variant: "minimal",
4593
4717
  icon: IconFilter,
4594
4718
  onClick: () => setOpened((o) => !o)
4595
4719
  }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
@@ -4619,12 +4743,12 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
4619
4743
  gap: 4,
4620
4744
  children: [/* @__PURE__ */ jsx(ActionButton, {
4621
4745
  size: "compact-xs",
4622
- variant: "subtle",
4746
+ variant: "minimal",
4623
4747
  onClick: handleShowAll,
4624
4748
  children: "All"
4625
4749
  }), /* @__PURE__ */ jsx(ActionButton, {
4626
4750
  size: "compact-xs",
4627
- variant: "subtle",
4751
+ variant: "minimal",
4628
4752
  onClick: handleHideAll,
4629
4753
  children: "None"
4630
4754
  })]
@@ -4718,7 +4842,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
4718
4842
  onVisibilityChange: onColumnVisibilityChange
4719
4843
  }),
4720
4844
  withExport && /* @__PURE__ */ jsx(ActionButton, {
4721
- variant: "subtle",
4845
+ variant: "minimal",
4722
4846
  icon: IconDownload,
4723
4847
  menu: { items: [{
4724
4848
  label: "Export as CSV",
@@ -4741,7 +4865,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
4741
4865
  children: [selectedItems.length, " selected"]
4742
4866
  }),
4743
4867
  /* @__PURE__ */ jsx(ActionButton, {
4744
- variant: "subtle",
4868
+ variant: "minimal",
4745
4869
  size: "compact-sm",
4746
4870
  icon: IconX,
4747
4871
  onClick: onClearSelection,
@@ -4765,7 +4889,7 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
4765
4889
  ...props,
4766
4890
  children: props.label
4767
4891
  }, index) : props), /* @__PURE__ */ jsx(ActionButton, {
4768
- variant: "subtle",
4892
+ variant: "minimal",
4769
4893
  icon: IconRefresh,
4770
4894
  onClick: onRefresh
4771
4895
  })]
@@ -4874,12 +4998,16 @@ const FIT_STYLE = {
4874
4998
  };
4875
4999
  const DataTable = (props) => {
4876
5000
  const [items, setItems] = useState(typeof props.items === "function" ? { content: [] } : props.items);
4877
- const defaultSize = props.infinityScroll ? 100 : props.defaultSize || 10;
5001
+ const itemsRef = useRef(items);
5002
+ const [loaded, setLoaded] = useState(typeof props.items !== "function" || !props.submitOnInit);
5003
+ const defaultSize = props.defaultSize || (props.infinityScroll ? 100 : 10);
4878
5004
  const [page, setPage] = useState(1);
4879
5005
  const [size, setSize] = useState(String(defaultSize));
4880
5006
  const [currentPage, setCurrentPage] = useState(0);
4881
5007
  const alepha = useInject(Alepha);
5008
+ itemsRef.current = items;
4882
5009
  const sentinelRef = useRef(null);
5010
+ const debounceRef = useRef(null);
4883
5011
  const [columnVisibility, setColumnVisibility] = useState(() => {
4884
5012
  const entries = Object.entries(props.columns);
4885
5013
  let visibleCount = 0;
@@ -4952,13 +5080,14 @@ const DataTable = (props) => {
4952
5080
  }),
4953
5081
  handler: async (values) => {
4954
5082
  if (typeof props.items === "function") {
4955
- const response = await props.items(values, { items: items.content });
5083
+ const response = await props.items(values, { items: itemsRef.current.content });
4956
5084
  if (props.infinityScroll && values.page > 0) setItems((prev) => ({
4957
5085
  ...response,
4958
5086
  content: [...prev.content, ...response.content]
4959
5087
  }));
4960
5088
  else setItems(response);
4961
5089
  setCurrentPage(values.page);
5090
+ if (!loaded) setLoaded(true);
4962
5091
  }
4963
5092
  },
4964
5093
  onReset: async () => {
@@ -4978,9 +5107,23 @@ const DataTable = (props) => {
4978
5107
  return;
4979
5108
  }
4980
5109
  props.onFilterChange?.(key, value, form);
5110
+ if (props.skipSubmitOnChange) return;
5111
+ form.input.page.set(0);
5112
+ const delay = props.debounce ?? 300;
5113
+ if (delay > 0) {
5114
+ if (debounceRef.current) clearTimeout(debounceRef.current);
5115
+ debounceRef.current = setTimeout(() => {
5116
+ form.submit();
5117
+ }, delay);
5118
+ } else await form.submit();
4981
5119
  }
4982
- }, [items]);
5120
+ }, []);
4983
5121
  const dt = useInject(DateTimeProvider);
5122
+ useEffect(() => {
5123
+ return () => {
5124
+ if (debounceRef.current) clearTimeout(debounceRef.current);
5125
+ };
5126
+ }, []);
4984
5127
  useEffect(() => {
4985
5128
  if (props.submitOnInit) form.submit();
4986
5129
  if (props.submitEvery) {
@@ -5045,9 +5188,9 @@ const DataTable = (props) => {
5045
5188
  }), col.sortable && /* @__PURE__ */ jsxs(Flex$1, {
5046
5189
  c: "dimmed",
5047
5190
  children: [
5048
- sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.sm }),
5049
- sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.sm }),
5050
- sortDir === null && /* @__PURE__ */ jsx(IconArrowsSort, { size: ui.sizes.icon.sm })
5191
+ sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.xs }),
5192
+ sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.xs }),
5193
+ sortDir === null && /* @__PURE__ */ jsx(IconArrowsSort, { size: ui.sizes.icon.xs })
5051
5194
  ]
5052
5195
  })]
5053
5196
  })
@@ -5107,9 +5250,15 @@ const DataTable = (props) => {
5107
5250
  form,
5108
5251
  alepha
5109
5252
  };
5253
+ const content = col.value?.(item, ctx);
5110
5254
  return /* @__PURE__ */ jsx(Table.Td, {
5111
5255
  style: col.fit ? FIT_STYLE : void 0,
5112
- children: col.value?.(item, ctx)
5256
+ children: col.action ? /* @__PURE__ */ jsx(ActionButton, {
5257
+ td: "inherit",
5258
+ unstyled: true,
5259
+ ...col.action(item),
5260
+ children: content
5261
+ }) : content
5113
5262
  }, key);
5114
5263
  }),
5115
5264
  props.rowActions && (() => {
@@ -5126,7 +5275,7 @@ const DataTable = (props) => {
5126
5275
  style: FIT_STYLE,
5127
5276
  onClick: (e) => e.stopPropagation(),
5128
5277
  children: /* @__PURE__ */ jsx(ActionButton, {
5129
- variant: "subtle",
5278
+ variant: "minimal",
5130
5279
  size: "xs",
5131
5280
  icon: IconDotsVertical,
5132
5281
  menu: { items: actions.map((action) => {
@@ -5134,7 +5283,10 @@ const DataTable = (props) => {
5134
5283
  return {
5135
5284
  label: action.label ?? (typeof action.tooltip === "string" ? action.tooltip : void 0),
5136
5285
  icon: Icon && isComponentType(Icon) ? /* @__PURE__ */ jsx(Icon, { size: 14 }) : Icon,
5137
- onClick: action.onClick,
5286
+ onClick: action.onClick ? async () => {
5287
+ await action.onClick();
5288
+ if (!action.skipRefresh) await form.submit();
5289
+ } : void 0,
5138
5290
  color: action.color
5139
5291
  };
5140
5292
  }) }
@@ -5196,19 +5348,26 @@ const DataTable = (props) => {
5196
5348
  bordered: true,
5197
5349
  elevated: true,
5198
5350
  shadowed: "xs",
5351
+ flex: 1,
5352
+ style: { minHeight: 0 },
5199
5353
  children: [
5200
5354
  /* @__PURE__ */ jsx(Flex$1, {
5201
5355
  className: "overflow-auto",
5356
+ flex: 1,
5357
+ style: { minHeight: 0 },
5358
+ col: true,
5202
5359
  children: /* @__PURE__ */ jsxs(Table, {
5203
5360
  "aria-label": "Data table",
5204
5361
  withRowBorders: true,
5205
5362
  highlightOnHover: true,
5206
5363
  ...props.tableProps,
5207
5364
  children: [/* @__PURE__ */ jsx(Table.Thead, {
5365
+ bdrs: "md",
5208
5366
  style: {
5209
5367
  position: "sticky",
5210
5368
  top: 0,
5211
- zIndex: 1
5369
+ zIndex: 1,
5370
+ backgroundColor: "var(--alepha-elevated)"
5212
5371
  },
5213
5372
  children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
5214
5373
  panelConfig && /* @__PURE__ */ jsx(Table.Th, { style: { width: 36 } }),
@@ -5216,30 +5375,39 @@ const DataTable = (props) => {
5216
5375
  head,
5217
5376
  props.rowActions && /* @__PURE__ */ jsx(Table.Th, { style: FIT_STYLE })
5218
5377
  ] })
5219
- }), /* @__PURE__ */ jsxs(Table.Tbody, {
5220
- style: {
5221
- opacity: form.submitting ? .5 : 1,
5222
- transition: "opacity 150ms ease"
5223
- },
5224
- children: [rows, items.content.length === 0 && /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
5225
- colSpan: totalColumns || 1,
5226
- py: "xl",
5227
- style: { textAlign: "center" },
5378
+ }), /* @__PURE__ */ jsx(Table.Tbody, { children: !loaded || form.submitting ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
5379
+ colSpan: totalColumns || 1,
5380
+ py: "sm",
5381
+ children: /* @__PURE__ */ jsx(Flex$1, {
5382
+ justify: "center",
5383
+ p: "md",
5384
+ children: /* @__PURE__ */ jsx(Loader, {
5385
+ size: "sm",
5386
+ type: "dots"
5387
+ })
5388
+ })
5389
+ }) }) : rows.length === 0 ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
5390
+ colSpan: totalColumns || 1,
5391
+ py: "xl",
5392
+ children: /* @__PURE__ */ jsx(Flex$1, {
5393
+ justify: "center",
5228
5394
  children: /* @__PURE__ */ jsx(Text$1, {
5229
5395
  c: "dimmed",
5230
5396
  size: "sm",
5231
- children: form.submitting ? "Loading…" : "No results"
5397
+ children: props.emptyLabel ?? "No results"
5232
5398
  })
5233
- }) })]
5234
- })]
5399
+ })
5400
+ }) }) : rows })]
5235
5401
  })
5236
5402
  }),
5237
5403
  props.infinityScroll && /* @__PURE__ */ jsx("div", { ref: sentinelRef }),
5238
5404
  !props.infinityScroll && /* @__PURE__ */ jsx(DataTablePagination, {
5239
5405
  page,
5240
5406
  size,
5241
- totalPages: items.page?.totalPages ?? 1,
5407
+ totalPages: items.page?.totalPages,
5242
5408
  totalElements: items.page?.totalElements,
5409
+ isFirst: items.page?.isFirst,
5410
+ isLast: items.page?.isLast,
5243
5411
  offset: items.page?.offset ?? 0,
5244
5412
  numberOfElements: items.content.length,
5245
5413
  onPageChange: (value) => {
@@ -5357,8 +5525,8 @@ const OPERATOR_INFO = {
5357
5525
  * Get the default icon for an input based on its type, format, or name.
5358
5526
  */
5359
5527
  const getDefaultIcon = (params) => {
5360
- const { type, format, name, isEnum, isArray, size = "sm" } = params;
5361
- const iconSize = ui.sizes.icon[size];
5528
+ const { type, format, name, isEnum, isArray, size = "xs" } = params;
5529
+ const iconSize = ui.sizes.icon[size] - 4;
5362
5530
  if (format) switch (format) {
5363
5531
  case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
5364
5532
  case "url":
@@ -5471,5 +5639,5 @@ const AlephaUI = $module({
5471
5639
  });
5472
5640
 
5473
5641
  //#endregion
5474
- export { AlephaMantineProvider as _, TypeForm as a, DashboardShell as c, Heading as d, Flex$1 as f, ui as g, ActionButton as h, JsonViewer as i, Sidebar as l, useDialog as m, capitalize as n, Control as o, ToggleSidebarButton as p, DataTable as r, Text$1 as s, AlephaUI as t, Breadcrumb as u, useToast as v };
5475
- //# sourceMappingURL=core-B7LNjM78.js.map
5642
+ export { AlephaMantineProvider as _, TypeForm as a, Sidebar as c, Heading as d, Flex$1 as f, ui as g, ActionButton as h, JsonViewer as i, Text$1 as l, useDialog as m, capitalize as n, Control as o, ToggleSidebarButton as p, DataTable as r, DashboardShell as s, AlephaUI as t, Breadcrumb as u, useToast as v };
5643
+ //# sourceMappingURL=core-DFgB3yU4.js.map