@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,11 +1794,43 @@ 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/Flex.tsx
1830
1832
  const Flex$1 = forwardRef((props, ref) => {
1831
- const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, ...rest } = props;
1833
+ const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, overflow, ...rest } = props;
1832
1834
  if (fill) rest.flex ??= 1;
1833
1835
  if (col) rest.direction ??= "column";
1834
1836
  if (center) {
@@ -1851,6 +1853,7 @@ const Flex$1 = forwardRef((props, ref) => {
1851
1853
  ...rest.style ?? {}
1852
1854
  };
1853
1855
  if (shadowed) rest.className = `${rest.className ?? ""} shadow-${shadowed === true ? "md" : shadowed}`.trim();
1856
+ if (overflow) rest.className = `${rest.className ?? ""} overflow-auto`.trim();
1854
1857
  return /* @__PURE__ */ jsx(Flex, {
1855
1858
  ref,
1856
1859
  ...rest
@@ -1868,6 +1871,15 @@ const Container$1 = forwardRef((props, ref) => {
1868
1871
  });
1869
1872
  Container$1.displayName = "Container";
1870
1873
 
1874
+ //#endregion
1875
+ //#region ../../src/core/helpers/renderIcon.tsx
1876
+ const renderIcon = (icon, size) => {
1877
+ if (!icon) return null;
1878
+ if (isValidElement(icon)) return icon;
1879
+ if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
1880
+ return icon;
1881
+ };
1882
+
1871
1883
  //#endregion
1872
1884
  //#region ../../src/core/components/Text.tsx
1873
1885
  const INTENT_COLORS = {
@@ -1902,7 +1914,7 @@ Text$1.displayName = "Text";
1902
1914
  const parseInput = (props, form) => {
1903
1915
  const disabled = false;
1904
1916
  const id = props.input.props.id;
1905
- 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);
1917
+ 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);
1906
1918
  const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
1907
1919
  const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
1908
1920
  const icon = !props.icon ? getDefaultIcon({
@@ -1910,17 +1922,20 @@ const parseInput = (props, form) => {
1910
1922
  format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
1911
1923
  name: props.input.props.name,
1912
1924
  isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
1913
- isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
1914
- }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.md });
1925
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array",
1926
+ size: props.size
1927
+ }) : isValidElement(props.icon) ? props.icon : createElement(props.icon, { size: ui.sizes.icon.sm });
1915
1928
  const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
1916
1929
  const required = props.input.required;
1917
1930
  const schema = props.input.schema;
1931
+ const testId = props.input.props?.["data-testid"];
1918
1932
  const inputProps = {
1919
1933
  label,
1920
1934
  description,
1921
1935
  error,
1922
1936
  required,
1923
- disabled
1937
+ disabled,
1938
+ ...testId ? { "data-testid": testId } : {}
1924
1939
  };
1925
1940
  if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
1926
1941
  if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
@@ -1945,8 +1960,8 @@ const useArrayItems = (input) => {
1945
1960
  const alepha = useAlepha();
1946
1961
  const keyCounter = useRef(0);
1947
1962
  const [items, setItemsState] = useState(() => {
1948
- const defaultValue = input?.props?.defaultValue;
1949
- if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
1963
+ const initial = input?.initialValue;
1964
+ if (Array.isArray(initial)) return initial.map((value) => ({
1950
1965
  key: keyCounter.current++,
1951
1966
  value
1952
1967
  }));
@@ -1972,22 +1987,9 @@ const useArrayItems = (input) => {
1972
1987
  if (!input?.form) return;
1973
1988
  const formId = input.form.id;
1974
1989
  const fieldPath = input.path;
1975
- const listeners = [alepha.events.on("form:reset", (event) => {
1976
- if (event.id === formId) {
1977
- const defaultValue = input.props?.defaultValue;
1978
- keyCounter.current = 0;
1979
- if (Array.isArray(defaultValue)) setItemsState(defaultValue.map((value) => ({
1980
- key: keyCounter.current++,
1981
- value
1982
- })));
1983
- else setItemsState([]);
1984
- }
1985
- }), alepha.events.on("form:change", (event) => {
1990
+ return alepha.events.on("form:change", (event) => {
1986
1991
  if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
1987
- })];
1988
- return () => {
1989
- for (const unsub of listeners) unsub();
1990
- };
1992
+ });
1991
1993
  }, [
1992
1994
  alepha,
1993
1995
  input,
@@ -2012,10 +2014,10 @@ const createArrayItemInput = (parentInput, itemSchema, index, _itemKey, value, o
2012
2014
  path: `${parentInput.path}/${index}`,
2013
2015
  required: false,
2014
2016
  form: parentInput.form,
2017
+ initialValue: value,
2015
2018
  props: {
2016
2019
  id: `${parentInput.props.id}-${index}`,
2017
- name: `${parentInput.props.name}[${index}]`,
2018
- defaultValue: value
2020
+ name: `${parentInput.props.name}[${index}]`
2019
2021
  },
2020
2022
  set: onValueChange
2021
2023
  };
@@ -2030,10 +2032,10 @@ const createArrayItemFieldInput = (parentInput, itemSchema, fieldName, index, _i
2030
2032
  path: `${parentInput.path}/${index}/${fieldName}`,
2031
2033
  required: itemSchema.required?.includes(fieldName) ?? false,
2032
2034
  form: parentInput.form,
2035
+ initialValue: itemValue?.[fieldName],
2033
2036
  props: {
2034
2037
  id: `${parentInput.props.id}-${index}-${fieldName}`,
2035
- name: `${parentInput.props.name}[${index}].${fieldName}`,
2036
- defaultValue: itemValue?.[fieldName]
2038
+ name: `${parentInput.props.name}[${index}].${fieldName}`
2037
2039
  },
2038
2040
  set: (value) => onFieldChange(fieldName, value)
2039
2041
  };
@@ -2251,7 +2253,9 @@ const ControlArray = (props) => {
2251
2253
  * Automatically detects date formats from schema and renders appropriate picker.
2252
2254
  */
2253
2255
  const ControlDate = (props) => {
2254
- const { inputProps, id, icon, format } = parseInput(props, useFormState(props.input));
2256
+ const form = useFormState(props.input);
2257
+ const [value, setValue] = useFieldValue(props.input);
2258
+ const { inputProps, id, icon, format } = parseInput(props, form);
2255
2259
  if (!props.input?.props) return null;
2256
2260
  if (props.datetime || format === "date-time") {
2257
2261
  const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
@@ -2259,10 +2263,8 @@ const ControlDate = (props) => {
2259
2263
  ...inputProps,
2260
2264
  id,
2261
2265
  leftSection: icon,
2262
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
2263
- onChange: (value) => {
2264
- props.input.set(value ? new Date(value).toISOString() : void 0);
2265
- },
2266
+ value: value ? new Date(value) : null,
2267
+ onChange: (val) => setValue(val ? new Date(val).toISOString() : void 0),
2266
2268
  ...dateTimePickerProps
2267
2269
  });
2268
2270
  }
@@ -2272,10 +2274,8 @@ const ControlDate = (props) => {
2272
2274
  ...inputProps,
2273
2275
  id,
2274
2276
  leftSection: icon,
2275
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
2276
- onChange: (value) => {
2277
- props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
2278
- },
2277
+ value: value ? new Date(value) : null,
2278
+ onChange: (val) => setValue(val ? new Date(val).toISOString().slice(0, 10) : void 0),
2279
2279
  ...dateInputProps
2280
2280
  });
2281
2281
  }
@@ -2285,10 +2285,8 @@ const ControlDate = (props) => {
2285
2285
  ...inputProps,
2286
2286
  id,
2287
2287
  leftSection: icon,
2288
- defaultValue: props.input.props.defaultValue,
2289
- onChange: (event) => {
2290
- props.input.set(event.currentTarget.value);
2291
- },
2288
+ value: value ?? "",
2289
+ onChange: (event) => setValue(event.currentTarget.value),
2292
2290
  ...timeInputProps
2293
2291
  });
2294
2292
  }
@@ -2301,14 +2299,10 @@ const ControlDate = (props) => {
2301
2299
  *
2302
2300
  */
2303
2301
  const ControlNumber = (props) => {
2304
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
2305
- const ref = useRef(null);
2306
- const [value, setValue] = useState(props.input.props.defaultValue);
2307
- useEvents({ "form:reset": (event) => {
2308
- if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
2309
- } }, [props.input]);
2302
+ const form = useFormState(props.input);
2303
+ const [value, setValue] = useFieldValue(props.input);
2304
+ const { inputProps, id, icon } = parseInput(props, form);
2310
2305
  if (!props.input?.props) return null;
2311
- const { type, ...inputPropsWithoutType } = props.input.props;
2312
2306
  if (props.sliderProps) {
2313
2307
  const min = props.sliderProps.min ?? inputProps.minimum ?? 0;
2314
2308
  const max = props.sliderProps.max ?? inputProps.maximum ?? 100;
@@ -2321,34 +2315,25 @@ const ControlNumber = (props) => {
2321
2315
  },
2322
2316
  children: /* @__PURE__ */ jsx(Slider, {
2323
2317
  ...inputProps,
2324
- ref,
2325
2318
  id,
2326
- ...inputPropsWithoutType,
2327
2319
  ...props.sliderProps,
2328
- value,
2320
+ value: value ?? 0,
2329
2321
  min,
2330
2322
  max,
2331
2323
  label: () => value,
2332
- onChange: (val) => {
2333
- setValue(val);
2334
- props.input.set(val);
2335
- }
2324
+ onChange: (val) => setValue(val)
2336
2325
  })
2337
2326
  })
2338
2327
  });
2339
2328
  }
2340
2329
  return /* @__PURE__ */ jsx(NumberInput, {
2341
2330
  ...inputProps,
2342
- ref,
2343
2331
  id,
2344
2332
  leftSection: icon,
2345
- ...inputPropsWithoutType,
2346
2333
  ...props.numberInputProps,
2347
2334
  value: value ?? "",
2348
2335
  onChange: (val) => {
2349
- const newValue = val !== null ? Number(val) : void 0;
2350
- setValue(newValue);
2351
- props.input.set(newValue);
2336
+ setValue(val !== null ? Number(val) : void 0);
2352
2337
  }
2353
2338
  });
2354
2339
  };
@@ -2431,92 +2416,9 @@ const ControlObject = (props) => {
2431
2416
  };
2432
2417
 
2433
2418
  //#endregion
2434
- //#region ../../src/core/form/components/ControlQueryBuilder.tsx
2435
- /**
2436
- * Query builder with text input and help popover.
2437
- * Generates query strings for parseQueryString syntax.
2438
- */
2439
- const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
2440
- const [helpOpened, setHelpOpened] = useState(false);
2441
- const [textValue, setTextValue] = useState(value);
2442
- const inputRef = useRef(null);
2443
- const fields = schema ? extractSchemaFields(schema) : [];
2444
- const [error, setError] = useState(null);
2445
- const isValid = (value) => {
2446
- try {
2447
- parseQueryString(value.trim());
2448
- } catch (e) {
2449
- setError(e.message);
2450
- return false;
2451
- }
2452
- setError(null);
2453
- return true;
2454
- };
2455
- const handleTextChange = (newValue) => {
2456
- setTextValue(newValue);
2457
- if (isValid(newValue)) onChange?.(newValue);
2458
- };
2459
- const handleClear = () => {
2460
- setTextValue("");
2461
- onChange?.("");
2462
- isValid("");
2463
- };
2464
- const handleInsert = (text) => {
2465
- const newValue = textValue ? `${textValue}${text} ` : `${text} `;
2466
- setTextValue(newValue);
2467
- if (isValid(newValue)) onChange?.(newValue);
2468
- setTimeout(() => {
2469
- inputRef.current?.focus();
2470
- const length = inputRef.current?.value.length || 0;
2471
- inputRef.current?.setSelectionRange(length, length);
2472
- }, 0);
2473
- };
2474
- useEvents({ "form:change": (event) => {
2475
- if (event.id === inputRef.current?.form?.id) {
2476
- if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
2477
- }
2478
- } }, []);
2479
- return /* @__PURE__ */ jsxs(Popover, {
2480
- width: 800,
2481
- position: "bottom-start",
2482
- shadow: "md",
2483
- opened: helpOpened,
2484
- onChange: setHelpOpened,
2485
- closeOnClickOutside: true,
2486
- closeOnEscape: true,
2487
- transitionProps: {
2488
- transition: "fade-up",
2489
- duration: 200,
2490
- timingFunction: "ease"
2491
- },
2492
- children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
2493
- ref: inputRef,
2494
- placeholder,
2495
- value: textValue,
2496
- onChange: (e) => handleTextChange(e.currentTarget.value),
2497
- onFocus: () => setHelpOpened(true),
2498
- leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
2499
- rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
2500
- size: "sm",
2501
- variant: "subtle",
2502
- color: "gray",
2503
- onClick: handleClear,
2504
- children: /* @__PURE__ */ jsx(IconX, { size: 14 })
2505
- }),
2506
- ...textInputProps
2507
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
2508
- bg: "transparent",
2509
- p: "xs",
2510
- bd: `1px solid ${ui.colors.border}`,
2511
- style: { backdropFilter: "blur(20px)" },
2512
- children: /* @__PURE__ */ jsx(QueryHelp, {
2513
- fields,
2514
- onInsert: handleInsert
2515
- })
2516
- })]
2517
- });
2518
- };
2519
- function QueryHelp({ fields, onInsert }) {
2419
+ //#region ../../src/core/form/components/ControlQueryBuilderHelp.tsx
2420
+ const ControlQueryBuilderHelp = (props) => {
2421
+ const { fields, onInsert } = props;
2520
2422
  return /* @__PURE__ */ jsxs(Flex, {
2521
2423
  gap: "md",
2522
2424
  align: "flex-start",
@@ -2679,111 +2581,314 @@ function QueryHelp({ fields, onInsert }) {
2679
2581
  })
2680
2582
  ]
2681
2583
  });
2682
- }
2584
+ };
2585
+
2586
+ //#endregion
2587
+ //#region ../../src/core/form/components/ControlQueryBuilder.tsx
2588
+ /**
2589
+ * Query builder with text input and help popover.
2590
+ * Generates query strings for parseQueryString syntax.
2591
+ */
2592
+ const ControlQueryBuilder = (props) => {
2593
+ const { schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps } = props;
2594
+ const [helpOpened, setHelpOpened] = useState(false);
2595
+ const [textValue, setTextValue] = useState(value);
2596
+ const inputRef = useRef(null);
2597
+ const fields = schema ? extractSchemaFields(schema) : [];
2598
+ const [error, setError] = useState(null);
2599
+ const isValid = (value) => {
2600
+ try {
2601
+ parseQueryString(value.trim());
2602
+ } catch (e) {
2603
+ setError(e.message);
2604
+ return false;
2605
+ }
2606
+ setError(null);
2607
+ return true;
2608
+ };
2609
+ const handleTextChange = (newValue) => {
2610
+ setTextValue(newValue);
2611
+ if (isValid(newValue)) onChange?.(newValue);
2612
+ };
2613
+ const handleClear = () => {
2614
+ setTextValue("");
2615
+ onChange?.("");
2616
+ isValid("");
2617
+ };
2618
+ const handleInsert = (text) => {
2619
+ const newValue = textValue ? `${textValue}${text} ` : `${text} `;
2620
+ setTextValue(newValue);
2621
+ if (isValid(newValue)) onChange?.(newValue);
2622
+ setTimeout(() => {
2623
+ inputRef.current?.focus();
2624
+ const length = inputRef.current?.value.length || 0;
2625
+ inputRef.current?.setSelectionRange(length, length);
2626
+ }, 0);
2627
+ };
2628
+ useEvents({ "form:change": (event) => {
2629
+ if (event.id === inputRef.current?.form?.id) {
2630
+ if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
2631
+ }
2632
+ } }, []);
2633
+ return /* @__PURE__ */ jsxs(Popover, {
2634
+ width: 800,
2635
+ position: "bottom-start",
2636
+ shadow: "md",
2637
+ opened: helpOpened,
2638
+ onChange: setHelpOpened,
2639
+ closeOnClickOutside: true,
2640
+ closeOnEscape: true,
2641
+ transitionProps: {
2642
+ transition: "fade-up",
2643
+ duration: 200,
2644
+ timingFunction: "ease"
2645
+ },
2646
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
2647
+ ref: inputRef,
2648
+ placeholder,
2649
+ value: textValue,
2650
+ onChange: (e) => handleTextChange(e.currentTarget.value),
2651
+ onFocus: () => setHelpOpened(true),
2652
+ leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
2653
+ rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
2654
+ size: "sm",
2655
+ variant: "subtle",
2656
+ color: "gray",
2657
+ onClick: handleClear,
2658
+ children: /* @__PURE__ */ jsx(IconX, { size: 14 })
2659
+ }),
2660
+ ...textInputProps
2661
+ }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
2662
+ bg: "transparent",
2663
+ p: "xs",
2664
+ bd: `1px solid ${ui.colors.border}`,
2665
+ style: { backdropFilter: "blur(20px)" },
2666
+ children: /* @__PURE__ */ jsx(ControlQueryBuilderHelp, {
2667
+ fields,
2668
+ onInsert: handleInsert
2669
+ })
2670
+ })]
2671
+ });
2672
+ };
2683
2673
 
2684
2674
  //#endregion
2685
2675
  //#region ../../src/core/form/components/ControlSelect.tsx
2686
2676
  /**
2687
- * ControlSelect component for handling Select, MultiSelect, and TagsInput.
2677
+ * ControlSelect component for handling Select, MultiSelect, Autocomplete, and TagsInput.
2688
2678
  *
2689
2679
  * Features:
2690
2680
  * - Basic Select with enum support
2691
2681
  * - MultiSelect for array of enums
2692
- * - TagsInput for array of strings (no enum)
2693
- * - Future: Lazy loading
2694
- * - Future: Searchable/filterable options
2695
- * - Future: Custom option rendering
2682
+ * - Autocomplete for creatable single values
2683
+ * - TagsInput for creatable array values
2684
+ * - Async lazy loading with auto short/long mode detection
2685
+ * - Short mode: client-side filtering with cached data
2686
+ * - Long mode: debounced server search
2696
2687
  *
2697
2688
  * Automatically detects enum values and array types from schema.
2698
2689
  */
2699
2690
  const ControlSelect = (props) => {
2700
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
2691
+ const form = useFormState(props.input);
2692
+ const [value, setValue] = useFieldValue(props.input);
2693
+ const { inputProps, id, icon } = parseInput(props, form);
2701
2694
  const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
2702
- let itemsEnum;
2703
- if (isArray && "items" in props.input.schema && props.input.schema.items) {
2704
- const items = props.input.schema.items;
2705
- if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
2706
- }
2695
+ const isNumeric = props.input.schema && "type" in props.input.schema && (props.input.schema.type === "integer" || props.input.schema.type === "number");
2696
+ const isBoolean = props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean";
2707
2697
  const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
2708
- const [data, setData] = useState([]);
2698
+ const { data: asyncData, loading, mode, search } = useAsyncLoader(props.loader, props.loaderThreshold ?? 100, props.loaderDebounce ?? 300, props.input.initialValue);
2699
+ const [staticData, setStaticData] = useState([]);
2700
+ const enumKey = JSON.stringify(enumValues);
2709
2701
  useEffect(() => {
2710
- if (!props.input?.props) return;
2711
- if (props.loader) props.loader().then(setData);
2712
- else setData(enumValues);
2713
- }, [props.input, props.loader]);
2702
+ if (!props.input?.props || props.loader) return;
2703
+ if (isBoolean && enumValues.length === 0) setStaticData([{
2704
+ value: "true",
2705
+ label: "True"
2706
+ }, {
2707
+ value: "false",
2708
+ label: "False"
2709
+ }]);
2710
+ else setStaticData(enumValues);
2711
+ }, [
2712
+ props.input,
2713
+ props.loader,
2714
+ enumKey,
2715
+ isBoolean
2716
+ ]);
2717
+ const data = props.loader ? asyncData : staticData;
2714
2718
  if (!props.input?.props) return null;
2715
- if (props.segmented) {
2716
- const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
2719
+ /**
2720
+ * Coerce value for numeric schemas Select values are always strings.
2721
+ */
2722
+ const coerceValue = (val) => {
2723
+ if (val == null) return val;
2724
+ if (isNumeric) return Number(val);
2725
+ if (isBoolean) return val === "true";
2726
+ return val;
2727
+ };
2728
+ if (props.segmentedProps) {
2729
+ const segmentedControlProps = typeof props.segmentedProps === "object" ? props.segmentedProps : {};
2730
+ const segmentedData = segmentedControlProps.data ?? data.slice(0, 10);
2717
2731
  return /* @__PURE__ */ jsx(Input.Wrapper, {
2718
2732
  ...inputProps,
2719
- children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(SegmentedControl, {
2720
- disabled: inputProps.disabled,
2721
- defaultValue: String(props.input.props.defaultValue),
2722
- ...segmentedControlProps,
2723
- onChange: (value) => {
2724
- props.input.set(value);
2725
- },
2726
- data: data.slice(0, 10)
2727
- }) })
2733
+ children: /* @__PURE__ */ jsx(Flex, {
2734
+ my: "calc(var(--mantine-spacing-xs) / 2)",
2735
+ children: /* @__PURE__ */ jsx(SegmentedControl, {
2736
+ disabled: inputProps.disabled,
2737
+ value: value != null ? String(value) : "",
2738
+ ...segmentedControlProps,
2739
+ onChange: (val) => {
2740
+ setValue(coerceValue(val));
2741
+ },
2742
+ data: segmentedData
2743
+ })
2744
+ })
2728
2745
  });
2729
2746
  }
2730
- if (props.autocomplete) {
2731
- const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
2732
- return /* @__PURE__ */ jsx(Autocomplete, {
2747
+ const sharedProps = {
2748
+ size: props.size,
2749
+ id,
2750
+ leftSection: loading ? /* @__PURE__ */ jsx(Loader, {
2751
+ color: "gray",
2752
+ size: 10
2753
+ }) : icon,
2754
+ data
2755
+ };
2756
+ const selectableProps = {
2757
+ ...sharedProps,
2758
+ searchable: true,
2759
+ rightSection: /* @__PURE__ */ jsx("span", {})
2760
+ };
2761
+ const longModeProps = mode === "long" ? {
2762
+ filter: ({ options }) => options,
2763
+ onSearchChange: search.run
2764
+ } : {};
2765
+ if (props.creatable && (isArray || props.tagsInputProps)) {
2766
+ const tagsInputExtraProps = props.tagsInputProps ?? {};
2767
+ return /* @__PURE__ */ jsx(TagsInput, {
2733
2768
  ...inputProps,
2734
- size: props.size,
2735
- id,
2736
- leftSection: icon,
2737
- data,
2738
- ...props.input.props,
2739
- ...autocompleteProps
2769
+ ...sharedProps,
2770
+ ...longModeProps,
2771
+ value: Array.isArray(value) ? value : [],
2772
+ onChange: (val) => {
2773
+ setValue(val);
2774
+ },
2775
+ ...tagsInputExtraProps
2740
2776
  });
2741
2777
  }
2742
- if (isArray && !itemsEnum || props.tags) {
2743
- const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
2744
- return /* @__PURE__ */ jsx(TagsInput, {
2778
+ if (props.creatable) {
2779
+ const autocompleteExtraProps = props.autocompleteProps ?? {};
2780
+ return /* @__PURE__ */ jsx(Autocomplete, {
2745
2781
  ...inputProps,
2746
- size: props.size,
2747
- id,
2748
- leftSection: icon,
2749
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
2750
- onChange: (value) => {
2751
- props.input.set(value);
2782
+ ...sharedProps,
2783
+ ...longModeProps,
2784
+ value: value != null ? String(value) : "",
2785
+ onChange: (val) => {
2786
+ setValue(coerceValue(val));
2752
2787
  },
2753
- ...tagsInputProps
2788
+ ...autocompleteExtraProps
2754
2789
  });
2755
2790
  }
2756
- if (isArray && itemsEnum || props.multi) {
2757
- const data = itemsEnum?.map((value) => ({
2758
- value,
2759
- label: value
2760
- })) || [];
2761
- const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
2791
+ if (isArray || props.multiSelectProps) {
2792
+ const multiSelectExtraProps = typeof props.multiSelectProps === "object" ? props.multiSelectProps : {};
2762
2793
  return /* @__PURE__ */ jsx(MultiSelect, {
2763
2794
  ...inputProps,
2764
- size: props.size,
2765
- id,
2766
- leftSection: icon,
2767
- data,
2768
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
2769
- onChange: (value) => {
2770
- props.input.set(value);
2795
+ ...selectableProps,
2796
+ ...longModeProps,
2797
+ value: Array.isArray(value) ? value : [],
2798
+ onChange: (val) => {
2799
+ setValue(val);
2771
2800
  },
2772
- ...multiSelectProps
2801
+ ...multiSelectExtraProps
2773
2802
  });
2774
2803
  }
2775
- const selectProps = typeof props.select === "object" ? props.select : {};
2804
+ const selectExtraProps = typeof props.selectProps === "object" ? props.selectProps : {};
2805
+ if (mode === "static") return /* @__PURE__ */ jsx(Select, {
2806
+ ...inputProps,
2807
+ ...selectableProps,
2808
+ value: value != null ? String(value) : null,
2809
+ onChange: (val) => {
2810
+ setValue(coerceValue(val));
2811
+ },
2812
+ ...selectExtraProps
2813
+ });
2776
2814
  return /* @__PURE__ */ jsx(Select, {
2777
2815
  ...inputProps,
2778
- size: props.size,
2779
- id,
2780
- leftSection: icon,
2781
- rightSection: null,
2782
- data,
2783
- ...props.input.props,
2784
- ...selectProps
2816
+ ...selectableProps,
2817
+ ...longModeProps,
2818
+ value: value != null ? String(value) : null,
2819
+ onChange: (val) => {
2820
+ setValue(coerceValue(val));
2821
+ },
2822
+ ...selectExtraProps
2785
2823
  });
2786
2824
  };
2825
+ /**
2826
+ * Hook for async select data loading with auto short/long mode detection.
2827
+ */
2828
+ const useAsyncLoader = (loader, threshold, debounceMs, defaultValue) => {
2829
+ const [data, setData] = useState([]);
2830
+ const [loading, setLoading] = useState(false);
2831
+ const [mode, setMode] = useState("static");
2832
+ const cache = useRef(/* @__PURE__ */ new Map());
2833
+ useAction({
2834
+ name: "select:loader:init",
2835
+ runOnInit: true,
2836
+ handler: async () => {
2837
+ if (!loader) {
2838
+ setMode("static");
2839
+ return;
2840
+ }
2841
+ setLoading(true);
2842
+ try {
2843
+ const result = await loader("");
2844
+ const isShort = result.length <= threshold;
2845
+ setMode(isShort ? "short" : "long");
2846
+ cache.current.set("", result);
2847
+ setData(result);
2848
+ if (!isShort && defaultValue != null && String(defaultValue) !== "") {
2849
+ const resolved = await loader("", [String(defaultValue)]);
2850
+ if (resolved.length > 0) setData((prev) => {
2851
+ const existing = new Set(prev.map((d) => typeof d === "string" ? d : d.value));
2852
+ const newItems = resolved.filter((r) => {
2853
+ const val = typeof r === "string" ? r : r.value;
2854
+ return !existing.has(val);
2855
+ });
2856
+ return [...prev, ...newItems];
2857
+ });
2858
+ }
2859
+ } finally {
2860
+ setLoading(false);
2861
+ }
2862
+ }
2863
+ }, [loader, threshold]);
2864
+ return {
2865
+ data,
2866
+ loading,
2867
+ mode,
2868
+ search: useAction({
2869
+ debounce: debounceMs,
2870
+ handler: async (text) => {
2871
+ if (!loader || mode !== "long") return;
2872
+ if (cache.current.has(text)) {
2873
+ setData(cache.current.get(text));
2874
+ return;
2875
+ }
2876
+ setLoading(true);
2877
+ try {
2878
+ const result = await loader(text);
2879
+ cache.current.set(text, result);
2880
+ setData(result);
2881
+ } finally {
2882
+ setLoading(false);
2883
+ }
2884
+ }
2885
+ }, [
2886
+ loader,
2887
+ mode,
2888
+ debounceMs
2889
+ ])
2890
+ };
2891
+ };
2787
2892
 
2788
2893
  //#endregion
2789
2894
  //#region ../../src/core/form/components/Control.tsx
@@ -2813,6 +2918,7 @@ const ControlSelect = (props) => {
2813
2918
  */
2814
2919
  const Control = (_props) => {
2815
2920
  const form = useFormState(_props.input, ["error"]);
2921
+ const [value, setValue] = useFieldValue(_props.input);
2816
2922
  if (!_props.input?.props) return null;
2817
2923
  const { inputProps, id, icon, format, schema } = parseInput(_props, form);
2818
2924
  const props = {
@@ -2820,12 +2926,11 @@ const Control = (_props) => {
2820
2926
  ...schema.$control
2821
2927
  };
2822
2928
  if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder, {
2823
- ...props.input.props,
2824
2929
  ...inputProps,
2825
2930
  schema: props.query,
2826
- value: props.input.props.value,
2827
- onChange: (value) => {
2828
- props.input.set(value);
2931
+ value,
2932
+ onChange: (val) => {
2933
+ setValue(val);
2829
2934
  }
2830
2935
  });
2831
2936
  if (props.custom) {
@@ -2836,9 +2941,9 @@ const Control = (_props) => {
2836
2941
  flex: 1,
2837
2942
  mt: "calc(var(--mantine-spacing-xs) / 2)",
2838
2943
  children: /* @__PURE__ */ jsx(Custom, {
2839
- defaultValue: props.input.props.defaultValue,
2840
- onChange: (value) => {
2841
- props.input.set(value);
2944
+ value,
2945
+ onChange: (val) => {
2946
+ setValue(val);
2842
2947
  }
2843
2948
  })
2844
2949
  })
@@ -2849,7 +2954,7 @@ const Control = (_props) => {
2849
2954
  const controlObjectProps = typeof props.object === "object" ? props.object : {};
2850
2955
  return /* @__PURE__ */ jsx(ControlObject, {
2851
2956
  input: props.input,
2852
- title: props.title,
2957
+ label: props.label,
2853
2958
  description: props.description,
2854
2959
  ...controlObjectProps
2855
2960
  });
@@ -2860,18 +2965,18 @@ const Control = (_props) => {
2860
2965
  const controlArrayProps = typeof props.array === "object" ? props.array : {};
2861
2966
  return /* @__PURE__ */ jsx(ControlArray, {
2862
2967
  input: props.input,
2863
- title: props.title,
2968
+ label: props.label,
2864
2969
  description: props.description,
2865
2970
  ...controlArrayProps
2866
2971
  });
2867
2972
  }
2868
- if (props.number || props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
2973
+ if (props.number || !props.select && props.input.schema && "type" in props.input.schema && (props.input.schema.type === "number" || props.input.schema.type === "integer")) {
2869
2974
  const controlNumberProps = typeof props.number === "object" ? props.number : {};
2870
2975
  if (props.slider) controlNumberProps.sliderProps ??= {};
2871
2976
  return /* @__PURE__ */ jsx(ControlNumber, {
2872
2977
  size: props.size,
2873
2978
  input: props.input,
2874
- title: props.title,
2979
+ label: props.label,
2875
2980
  description: props.description,
2876
2981
  icon,
2877
2982
  ...controlNumberProps
@@ -2884,9 +2989,7 @@ const Control = (_props) => {
2884
2989
  size: props.size,
2885
2990
  id,
2886
2991
  leftSection: icon,
2887
- onChange: (file) => {
2888
- props.input.set(file);
2889
- },
2992
+ onChange: (file) => setValue(file),
2890
2993
  ...fileInputProps
2891
2994
  });
2892
2995
  }
@@ -2897,17 +3000,18 @@ const Control = (_props) => {
2897
3000
  size: props.size,
2898
3001
  id,
2899
3002
  leftSection: icon,
2900
- ...props.input.props,
3003
+ value: value ?? "",
3004
+ onChange: (val) => setValue(val),
2901
3005
  ...colorInputProps
2902
3006
  });
2903
3007
  }
2904
3008
  if (props.input.schema && "enum" in props.input.schema && props.input.schema.enum || isArray && !isArrayOfObjects || props.select) {
2905
3009
  const opts = typeof props.select === "object" ? props.select : {};
2906
- if (props.segmented) opts.segmented ??= {};
3010
+ if (props.segmented) opts.segmentedProps ??= {};
2907
3011
  return /* @__PURE__ */ jsx(ControlSelect, {
2908
3012
  size: props.size,
2909
3013
  input: props.input,
2910
- title: props.title,
3014
+ label: props.label,
2911
3015
  description: props.description,
2912
3016
  icon,
2913
3017
  ...opts
@@ -2921,16 +3025,16 @@ const Control = (_props) => {
2921
3025
  size: props.size,
2922
3026
  id,
2923
3027
  color: "blue",
2924
- defaultChecked: props.input.props.defaultValue,
3028
+ checked: Boolean(value),
2925
3029
  onChange: (event) => {
2926
- props.input.set(event.currentTarget.checked);
3030
+ setValue(event.currentTarget.checked);
2927
3031
  },
2928
3032
  ...switchProps
2929
3033
  });
2930
3034
  }
2931
3035
  const opts = {
2932
3036
  input: props.input,
2933
- select: { data: [{
3037
+ selectProps: { data: [{
2934
3038
  value: "true",
2935
3039
  label: "Yes"
2936
3040
  }, {
@@ -2940,7 +3044,7 @@ const Control = (_props) => {
2940
3044
  };
2941
3045
  return /* @__PURE__ */ jsx(ControlSelect, {
2942
3046
  size: props.size,
2943
- title: props.title,
3047
+ label: props.label,
2944
3048
  description: props.description,
2945
3049
  icon,
2946
3050
  ...opts
@@ -2953,7 +3057,8 @@ const Control = (_props) => {
2953
3057
  size: props.size,
2954
3058
  id,
2955
3059
  leftSection: icon,
2956
- ...props.input.props,
3060
+ value: value ?? "",
3061
+ onChange: (ev) => setValue(ev.target.value),
2957
3062
  ...passwordInputProps
2958
3063
  });
2959
3064
  }
@@ -2964,14 +3069,15 @@ const Control = (_props) => {
2964
3069
  size: props.size,
2965
3070
  id,
2966
3071
  leftSection: icon,
2967
- ...props.input.props,
3072
+ value: value ?? "",
3073
+ onChange: (ev) => setValue(ev.target.value),
2968
3074
  ...textAreaProps
2969
3075
  });
2970
3076
  }
2971
3077
  if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate, {
2972
3078
  size: props.size,
2973
3079
  input: props.input,
2974
- title: props.title,
3080
+ label: props.label,
2975
3081
  description: props.description,
2976
3082
  icon,
2977
3083
  date: props.date,
@@ -2986,7 +3092,7 @@ const Control = (_props) => {
2986
3092
  case "uri": return "url";
2987
3093
  case "tel":
2988
3094
  case "phone": return "tel";
2989
- default: return;
3095
+ default: return props.input.props.type ?? "text";
2990
3096
  }
2991
3097
  };
2992
3098
  return /* @__PURE__ */ jsx(TextInput, {
@@ -2995,26 +3101,12 @@ const Control = (_props) => {
2995
3101
  id,
2996
3102
  leftSection: icon,
2997
3103
  type: getInputType(),
2998
- ...props.input.props,
2999
- ...textInputProps,
3000
- inputWrapperOrder: [
3001
- "label",
3002
- "input",
3003
- "description",
3004
- "error"
3005
- ]
3104
+ value: value ?? "",
3105
+ onChange: (ev) => setValue(ev.target.value),
3106
+ ...textInputProps
3006
3107
  });
3007
3108
  };
3008
3109
 
3009
- //#endregion
3010
- //#region ../../src/core/helpers/renderIcon.tsx
3011
- const renderIcon = (icon, size) => {
3012
- if (!icon) return null;
3013
- if (isValidElement(icon)) return icon;
3014
- if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
3015
- return icon;
3016
- };
3017
-
3018
3110
  //#endregion
3019
3111
  //#region ../../src/core/utils/extractSchemaFields.ts
3020
3112
  /**
@@ -3110,8 +3202,8 @@ const OPERATOR_INFO = {
3110
3202
  * Get the default icon for an input based on its type, format, or name.
3111
3203
  */
3112
3204
  const getDefaultIcon = (params) => {
3113
- const { type, format, name, isEnum, isArray, size = "sm" } = params;
3114
- const iconSize = ui.sizes.icon[size];
3205
+ const { type, format, name, isEnum, isArray, size = "xs" } = params;
3206
+ const iconSize = ui.sizes.icon[size] - 4;
3115
3207
  if (format) switch (format) {
3116
3208
  case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
3117
3209
  case "url":
@@ -3225,4 +3317,4 @@ const AlephaUI = $module({
3225
3317
 
3226
3318
  //#endregion
3227
3319
  export { ui as a, ActionButton as i, capitalize as n, AlephaMantineProvider as o, Control as r, AlephaUI as t };
3228
- //# sourceMappingURL=core-DyfeVr5c.js.map
3320
+ //# sourceMappingURL=core-D5jIAVF2.js.map