@alepha/ui 0.18.1 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (280) hide show
  1. package/dist/admin/{AdminApiKeys-C-6_Q-lH.js → AdminApiKeys-Dy_k-4Vd.js} +17 -38
  2. package/dist/admin/AdminApiKeys-Dy_k-4Vd.js.map +1 -0
  3. package/dist/admin/{AdminAudits-Bgbf04hO.js → AdminAudits-CKiFMSSU.js} +23 -19
  4. package/dist/admin/AdminAudits-CKiFMSSU.js.map +1 -0
  5. package/dist/admin/AdminDashboard-PhC_dZqo.js +67 -0
  6. package/dist/admin/AdminDashboard-PhC_dZqo.js.map +1 -0
  7. package/dist/admin/{AdminFiles-B9a7G3cY.js → AdminFiles-DFTjijGp.js} +3 -7
  8. package/dist/admin/AdminFiles-DFTjijGp.js.map +1 -0
  9. package/dist/admin/{AdminJobDashboard-DaTwf5OY.js → AdminJobDashboard-BL8gGPDp.js} +2 -2
  10. package/dist/admin/{AdminJobDashboard-DaTwf5OY.js.map → AdminJobDashboard-BL8gGPDp.js.map} +1 -1
  11. package/dist/admin/{AdminJobExecutions-B9cek5dl.js → AdminJobExecutions-D9E-CS-U.js} +24 -36
  12. package/dist/admin/AdminJobExecutions-D9E-CS-U.js.map +1 -0
  13. package/dist/admin/{AdminJobRegistry-DFgV3oqx.js → AdminJobRegistry-Ci9ue1zC.js} +10 -18
  14. package/dist/admin/AdminJobRegistry-Ci9ue1zC.js.map +1 -0
  15. package/dist/admin/AdminLayout-I6TlUMPc.js +61 -0
  16. package/dist/admin/AdminLayout-I6TlUMPc.js.map +1 -0
  17. package/dist/admin/AdminNotifications-ZPHCYrv7.js +542 -0
  18. package/dist/admin/AdminNotifications-ZPHCYrv7.js.map +1 -0
  19. package/dist/admin/{AdminParameters-DHw9ATgl.js → AdminParameters-CqgvhRsb.js} +120 -105
  20. package/dist/admin/AdminParameters-CqgvhRsb.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BhGJPI3z.js → AdminSessions-Bz5NRuoW.js} +48 -53
  22. package/dist/admin/AdminSessions-Bz5NRuoW.js.map +1 -0
  23. package/dist/admin/{AdminUserLayout-BdC4Te8m.js → AdminUserLayout-lXT6I0Qq.js} +14 -8
  24. package/dist/admin/AdminUserLayout-lXT6I0Qq.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DAt23fqY.js → AdminUserProfile-vFBLoJ3h.js} +3 -3
  26. package/dist/admin/{AdminUserProfile-DAt23fqY.js.map → AdminUserProfile-vFBLoJ3h.js.map} +1 -1
  27. package/dist/admin/{AdminUserSessions-1uzcx02z.js → AdminUserSessions-CT_YDim0.js} +33 -35
  28. package/dist/admin/AdminUserSessions-CT_YDim0.js.map +1 -0
  29. package/dist/admin/AdminUsers-D1UfGya9.js +206 -0
  30. package/dist/admin/AdminUsers-D1UfGya9.js.map +1 -0
  31. package/dist/admin/{AuthLayout-DFJvCvzw.js → AuthLayout-_frhdgOO.js} +2 -2
  32. package/dist/admin/{AuthLayout-DFJvCvzw.js.map → AuthLayout-_frhdgOO.js.map} +1 -1
  33. package/dist/admin/{IconGoogle-CSQLPYwX.js → IconGoogle-Ch1m3Uzl.js} +1 -1
  34. package/dist/admin/{IconGoogle-CSQLPYwX.js.map → IconGoogle-Ch1m3Uzl.js.map} +1 -1
  35. package/dist/admin/Login-xtNmQtGh.js +275 -0
  36. package/dist/admin/Login-xtNmQtGh.js.map +1 -0
  37. package/dist/{auth/Profile-BMX_Ar_s.js → admin/Profile-_AtPUwAP.js} +31 -27
  38. package/dist/admin/Profile-_AtPUwAP.js.map +1 -0
  39. package/dist/admin/{Register-Cs10l8vX.js → Register-JcCjHUUn.js} +199 -143
  40. package/dist/admin/Register-JcCjHUUn.js.map +1 -0
  41. package/dist/admin/{ResetPassword-BwDdfkGH.js → ResetPassword-CwGBPLJO.js} +7 -7
  42. package/dist/admin/ResetPassword-CwGBPLJO.js.map +1 -0
  43. package/dist/admin/{VerifyEmail-DfXHAiQl.js → VerifyEmail-hNxWejWf.js} +23 -8
  44. package/dist/admin/VerifyEmail-hNxWejWf.js.map +1 -0
  45. package/dist/admin/{core-2xoLiT0o.js → core-CYaRQ8O-.js} +2082 -688
  46. package/dist/admin/core-CYaRQ8O-.js.map +1 -0
  47. package/dist/admin/index.d.ts +112 -48
  48. package/dist/admin/index.d.ts.map +1 -1
  49. package/dist/admin/index.js +467 -69
  50. package/dist/admin/index.js.map +1 -1
  51. package/dist/auth/{AuthLayout-CAE1pX9s.js → AuthLayout-AvLlcLjS.js} +2 -2
  52. package/dist/auth/{AuthLayout-CAE1pX9s.js.map → AuthLayout-AvLlcLjS.js.map} +1 -1
  53. package/dist/auth/Login-BA1E8IZl.js +275 -0
  54. package/dist/auth/Login-BA1E8IZl.js.map +1 -0
  55. package/dist/{admin/Profile-B-c9pCPf.js → auth/Profile-YcWdeuFz.js} +31 -27
  56. package/dist/auth/Profile-YcWdeuFz.js.map +1 -0
  57. package/dist/auth/{Register-6hi_cpfF.js → Register-CPhEO5MG.js} +198 -142
  58. package/dist/auth/Register-CPhEO5MG.js.map +1 -0
  59. package/dist/{demo/ResetPassword-DWN0lzr5.js → auth/ResetPassword-DCtGcneA.js} +7 -7
  60. package/dist/auth/ResetPassword-DCtGcneA.js.map +1 -0
  61. package/dist/{demo/VerifyEmail-DZWL72K4.js → auth/VerifyEmail-DkH7NBfn.js} +23 -8
  62. package/dist/auth/VerifyEmail-DkH7NBfn.js.map +1 -0
  63. package/dist/auth/{core-niW0sFLv.js → core-D5jIAVF2.js} +1385 -329
  64. package/dist/auth/core-D5jIAVF2.js.map +1 -0
  65. package/dist/auth/index.d.ts +105 -49
  66. package/dist/auth/index.d.ts.map +1 -1
  67. package/dist/auth/index.js +29 -26
  68. package/dist/auth/index.js.map +1 -1
  69. package/dist/core/index.d.ts +210 -74
  70. package/dist/core/index.d.ts.map +1 -1
  71. package/dist/core/index.js +2247 -834
  72. package/dist/core/index.js.map +1 -1
  73. package/dist/demo/{AuthLayout-jLa0aKsI.js → AuthLayout-Brri4A-L.js} +2 -2
  74. package/dist/demo/{AuthLayout-jLa0aKsI.js.map → AuthLayout-Brri4A-L.js.map} +1 -1
  75. package/dist/demo/DemoButton-wiCxZZ_L.js +182 -0
  76. package/dist/demo/DemoButton-wiCxZZ_L.js.map +1 -0
  77. package/dist/demo/DemoControlSelect-D7ILObVg.js +305 -0
  78. package/dist/demo/DemoControlSelect-D7ILObVg.js.map +1 -0
  79. package/dist/demo/DemoDataTable-DZ5Y8pFX.js +362 -0
  80. package/dist/demo/DemoDataTable-DZ5Y8pFX.js.map +1 -0
  81. package/dist/demo/{DemoDialog-4ItHLf9t.js → DemoDialog-CUWdLHim.js} +2 -2
  82. package/dist/demo/{DemoDialog-4ItHLf9t.js.map → DemoDialog-CUWdLHim.js.map} +1 -1
  83. package/dist/demo/{DemoFlex-EtVq8QfX.js → DemoFlex-a8OhMMvq.js} +3 -3
  84. package/dist/demo/{DemoFlex-EtVq8QfX.js.map → DemoFlex-a8OhMMvq.js.map} +1 -1
  85. package/dist/demo/{DemoHeading-BS-vGfkI.js → DemoHeading-C13OVDfS.js} +3 -3
  86. package/dist/demo/{DemoHeading-BS-vGfkI.js.map → DemoHeading-C13OVDfS.js.map} +1 -1
  87. package/dist/demo/{DemoHome-Clbn8AmS.js → DemoHome-D_De3UiT.js} +2 -2
  88. package/dist/demo/{DemoHome-Clbn8AmS.js.map → DemoHome-D_De3UiT.js.map} +1 -1
  89. package/dist/demo/{DemoJsonViewer-DkIX_ky2.js → DemoJsonViewer-B50s9aGM.js} +3 -3
  90. package/dist/demo/{DemoJsonViewer-DkIX_ky2.js.map → DemoJsonViewer-B50s9aGM.js.map} +1 -1
  91. package/dist/demo/{DemoLayout-C56xb5EE.js → DemoLayout-CHU8WTwO.js} +14 -5
  92. package/dist/demo/DemoLayout-CHU8WTwO.js.map +1 -0
  93. package/dist/demo/{DemoLogin-BZwpicOS.js → DemoLogin-BBlrWpml.js} +49 -32
  94. package/dist/demo/DemoLogin-BBlrWpml.js.map +1 -0
  95. package/dist/demo/{DemoRegister-C7_qc4MJ.js → DemoRegister-BuNE3_-f.js} +49 -50
  96. package/dist/demo/DemoRegister-BuNE3_-f.js.map +1 -0
  97. package/dist/demo/{DemoResetPassword-BI1Ct4Dw.js → DemoResetPassword-D_IjjjOJ.js} +12 -16
  98. package/dist/demo/DemoResetPassword-D_IjjjOJ.js.map +1 -0
  99. package/dist/demo/{DemoSidebar-CcBo4ltC.js → DemoSidebar-Giy2HRBD.js} +3 -3
  100. package/dist/demo/{DemoSidebar-CcBo4ltC.js.map → DemoSidebar-Giy2HRBD.js.map} +1 -1
  101. package/dist/demo/{DemoText-CzXuUn3g.js → DemoText-ubcw-vog.js} +3 -3
  102. package/dist/demo/{DemoText-CzXuUn3g.js.map → DemoText-ubcw-vog.js.map} +1 -1
  103. package/dist/demo/{DemoToast-BgHDhWrX.js → DemoToast-9die_dYT.js} +2 -2
  104. package/dist/demo/{DemoToast-BgHDhWrX.js.map → DemoToast-9die_dYT.js.map} +1 -1
  105. package/dist/demo/{DemoTypeForm-DDzWoMSV.js → DemoTypeForm-D_d6OVKL.js} +8 -4
  106. package/dist/demo/DemoTypeForm-D_d6OVKL.js.map +1 -0
  107. package/dist/demo/DemoVerifyEmail-B43KlF4F.js +34 -0
  108. package/dist/demo/DemoVerifyEmail-B43KlF4F.js.map +1 -0
  109. package/dist/demo/Login-C12N4oGs.js +275 -0
  110. package/dist/demo/Login-C12N4oGs.js.map +1 -0
  111. package/dist/demo/{Profile-CWqti7FB.js → Profile-DS5q4vOh.js} +31 -27
  112. package/dist/demo/Profile-DS5q4vOh.js.map +1 -0
  113. package/dist/demo/{Register-a70LPgs2.js → Register-B4hLBeEv.js} +198 -142
  114. package/dist/demo/Register-B4hLBeEv.js.map +1 -0
  115. package/dist/{auth/ResetPassword-CqfTk1FI.js → demo/ResetPassword-D8g9ha1N.js} +7 -7
  116. package/dist/demo/ResetPassword-D8g9ha1N.js.map +1 -0
  117. package/dist/demo/{Showcase-Dq3MISpd.js → Showcase-D6Fxt4X4.js} +64 -65
  118. package/dist/demo/Showcase-D6Fxt4X4.js.map +1 -0
  119. package/dist/{auth/VerifyEmail-nWiSTMjF.js → demo/VerifyEmail-BjDo0cZA.js} +23 -8
  120. package/dist/demo/VerifyEmail-BjDo0cZA.js.map +1 -0
  121. package/dist/demo/{auth-d6n3xbug.js → auth-ByVTreDl.js} +8 -8
  122. package/dist/demo/{auth-d6n3xbug.js.map → auth-ByVTreDl.js.map} +1 -1
  123. package/dist/demo/{core-RCUw1Q-a.js → core-DFgB3yU4.js} +2182 -756
  124. package/dist/demo/core-DFgB3yU4.js.map +1 -0
  125. package/dist/demo/index.d.ts +1 -0
  126. package/dist/demo/index.d.ts.map +1 -1
  127. package/dist/demo/index.js +24 -18
  128. package/dist/demo/index.js.map +1 -1
  129. package/package.json +7 -7
  130. package/src/admin/{AdminRouter.ts → AdminRouter.tsx} +150 -18
  131. package/src/admin/components/AdminDashboard.tsx +52 -0
  132. package/src/admin/components/AdminLayout.tsx +32 -40
  133. package/src/admin/components/audits/AdminAudits.tsx +22 -16
  134. package/src/admin/components/files/AdminFiles.tsx +1 -6
  135. package/src/admin/components/jobs/AdminJobExecutions.tsx +33 -39
  136. package/src/admin/components/jobs/AdminJobRegistry.tsx +9 -18
  137. package/src/admin/components/keys/AdminApiKeys.tsx +23 -41
  138. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  139. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  140. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  141. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  142. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  143. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  144. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  145. package/src/admin/components/sessions/AdminSessions.tsx +71 -71
  146. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  147. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  148. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  149. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  150. package/src/admin/components/users/AdminUserSessions.tsx +33 -31
  151. package/src/admin/components/users/AdminUsers.tsx +184 -72
  152. package/src/admin/index.ts +2 -2
  153. package/src/admin/primitives/$uiAdmin.ts +1 -1
  154. package/src/auth/components/Login.tsx +188 -121
  155. package/src/auth/components/Profile.tsx +1 -22
  156. package/src/auth/components/ProfileField.tsx +39 -0
  157. package/src/auth/components/Register.tsx +215 -158
  158. package/src/auth/components/ResetPassword.tsx +7 -11
  159. package/src/auth/components/VerifyEmail.tsx +35 -10
  160. package/src/auth/components/buttons/UserButton.tsx +20 -24
  161. package/src/auth/index.ts +1 -0
  162. package/src/core/atoms/alephaSidebarAtom.ts +1 -1
  163. package/src/core/atoms/alephaThemeListAtom.ts +14 -1
  164. package/src/core/atoms/alephaThemeOverridesAtom.ts +17 -0
  165. package/src/core/atoms/themes/editorial.ts +184 -0
  166. package/src/core/atoms/themes/monochrome.ts +197 -0
  167. package/src/core/atoms/themes/rosePine.ts +208 -0
  168. package/src/core/atoms/themes/softBrutalism.ts +221 -0
  169. package/src/core/atoms/themes/terminal.ts +186 -0
  170. package/src/core/components/Flex.tsx +101 -1
  171. package/src/core/components/Text.tsx +1 -1
  172. package/src/core/components/buttons/ActionButton.tsx +109 -87
  173. package/src/core/components/buttons/DarkModeButton.tsx +3 -3
  174. package/src/core/components/buttons/LanguageButton.tsx +1 -1
  175. package/src/core/components/buttons/OmnibarButton.tsx +1 -2
  176. package/src/core/components/buttons/ThemeButton.tsx +40 -11
  177. package/src/core/components/buttons/ThemeExpertModal.tsx +184 -0
  178. package/src/core/components/buttons/ToggleSidebarButton.tsx +1 -2
  179. package/src/core/components/data/DetailDrawer.tsx +102 -96
  180. package/src/core/components/data/DetailList.tsx +2 -1
  181. package/src/core/components/layout/AppBar.tsx +10 -0
  182. package/src/core/components/layout/Breadcrumb.tsx +3 -6
  183. package/src/core/components/layout/DashboardShell.tsx +28 -11
  184. package/src/core/components/layout/Sidebar.tsx +18 -235
  185. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  186. package/src/core/components/layout/SidebarItem.tsx +146 -0
  187. package/src/core/components/layout/index.ts +3 -1
  188. package/src/core/constants/ui.ts +5 -5
  189. package/src/core/form/components/Control.tsx +31 -29
  190. package/src/core/form/components/ControlArray.tsx +13 -39
  191. package/src/core/form/components/ControlDate.tsx +10 -21
  192. package/src/core/form/components/ControlNumber.tsx +4 -33
  193. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  194. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  195. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  196. package/src/core/form/components/ControlSelect.tsx +294 -92
  197. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  198. package/src/core/form/components/TypeForm.tsx +5 -2
  199. package/src/core/form/index.ts +8 -1
  200. package/src/core/form/utils/parseInput.ts +7 -3
  201. package/src/core/hooks/useTheme.ts +26 -3
  202. package/src/core/index.ts +9 -2
  203. package/src/core/interfaces/AlephaTheme.ts +2 -0
  204. package/src/core/json/components/JsonViewer.tsx +103 -319
  205. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  206. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  207. package/src/core/json/components/JsonViewerShared.ts +76 -0
  208. package/src/core/providers/ThemeProvider.ts +108 -8
  209. package/src/core/services/DialogService.tsx +24 -3
  210. package/src/core/styles.css +33 -20
  211. package/src/core/table/components/ColumnPicker.tsx +3 -3
  212. package/src/core/table/components/DataTable.tsx +233 -143
  213. package/src/core/table/components/DataTableFilters.tsx +6 -16
  214. package/src/core/table/components/DataTablePagination.tsx +58 -29
  215. package/src/core/table/components/DataTableToolbar.tsx +16 -7
  216. package/src/core/table/components/FilterPicker.tsx +3 -3
  217. package/src/core/table/index.ts +1 -0
  218. package/src/core/table/interfaces/types.ts +42 -9
  219. package/src/core/utils/icons.tsx +2 -2
  220. package/src/demo/DemoRouter.ts +8 -1
  221. package/src/demo/components/DemoLayout.tsx +12 -2
  222. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  223. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  224. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  225. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  226. package/src/demo/components/core/DemoButton.tsx +123 -103
  227. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  228. package/src/demo/components/core/DemoDataTable.tsx +255 -241
  229. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  230. package/src/demo/components/shared/MacWindow.tsx +5 -11
  231. package/src/demo/components/shared/Showcase.tsx +28 -42
  232. package/dist/admin/AdminApiKeys-C-6_Q-lH.js.map +0 -1
  233. package/dist/admin/AdminAudits-Bgbf04hO.js.map +0 -1
  234. package/dist/admin/AdminFiles-B9a7G3cY.js.map +0 -1
  235. package/dist/admin/AdminJobExecutions-B9cek5dl.js.map +0 -1
  236. package/dist/admin/AdminJobRegistry-DFgV3oqx.js.map +0 -1
  237. package/dist/admin/AdminLayout-DHsvWxVB.js +0 -70
  238. package/dist/admin/AdminLayout-DHsvWxVB.js.map +0 -1
  239. package/dist/admin/AdminParameters-DHw9ATgl.js.map +0 -1
  240. package/dist/admin/AdminSessions-BhGJPI3z.js.map +0 -1
  241. package/dist/admin/AdminUserLayout-BdC4Te8m.js.map +0 -1
  242. package/dist/admin/AdminUserSessions-1uzcx02z.js.map +0 -1
  243. package/dist/admin/AdminUsers-C85c3eiQ.js +0 -121
  244. package/dist/admin/AdminUsers-C85c3eiQ.js.map +0 -1
  245. package/dist/admin/Login-BGheURrg.js +0 -219
  246. package/dist/admin/Login-BGheURrg.js.map +0 -1
  247. package/dist/admin/Profile-B-c9pCPf.js.map +0 -1
  248. package/dist/admin/Register-Cs10l8vX.js.map +0 -1
  249. package/dist/admin/ResetPassword-BwDdfkGH.js.map +0 -1
  250. package/dist/admin/VerifyEmail-DfXHAiQl.js.map +0 -1
  251. package/dist/admin/auth-Dr0Cf8I7.js +0 -319
  252. package/dist/admin/auth-Dr0Cf8I7.js.map +0 -1
  253. package/dist/admin/core-2xoLiT0o.js.map +0 -1
  254. package/dist/auth/Login-Denw_UGy.js +0 -219
  255. package/dist/auth/Login-Denw_UGy.js.map +0 -1
  256. package/dist/auth/Profile-BMX_Ar_s.js.map +0 -1
  257. package/dist/auth/Register-6hi_cpfF.js.map +0 -1
  258. package/dist/auth/ResetPassword-CqfTk1FI.js.map +0 -1
  259. package/dist/auth/VerifyEmail-nWiSTMjF.js.map +0 -1
  260. package/dist/auth/core-niW0sFLv.js.map +0 -1
  261. package/dist/demo/DemoButton-BmaWZVwf.js +0 -178
  262. package/dist/demo/DemoButton-BmaWZVwf.js.map +0 -1
  263. package/dist/demo/DemoDataTable-Z9xyV221.js +0 -362
  264. package/dist/demo/DemoDataTable-Z9xyV221.js.map +0 -1
  265. package/dist/demo/DemoLayout-C56xb5EE.js.map +0 -1
  266. package/dist/demo/DemoLogin-BZwpicOS.js.map +0 -1
  267. package/dist/demo/DemoRegister-C7_qc4MJ.js.map +0 -1
  268. package/dist/demo/DemoResetPassword-BI1Ct4Dw.js.map +0 -1
  269. package/dist/demo/DemoTypeForm-DDzWoMSV.js.map +0 -1
  270. package/dist/demo/DemoVerifyEmail-C_Irdnov.js +0 -30
  271. package/dist/demo/DemoVerifyEmail-C_Irdnov.js.map +0 -1
  272. package/dist/demo/Login-hSOU3jZc.js +0 -219
  273. package/dist/demo/Login-hSOU3jZc.js.map +0 -1
  274. package/dist/demo/Profile-CWqti7FB.js.map +0 -1
  275. package/dist/demo/Register-a70LPgs2.js.map +0 -1
  276. package/dist/demo/ResetPassword-DWN0lzr5.js.map +0 -1
  277. package/dist/demo/Showcase-Dq3MISpd.js.map +0 -1
  278. package/dist/demo/VerifyEmail-DZWL72K4.js.map +0 -1
  279. package/dist/demo/core-RCUw1Q-a.js.map +0 -1
  280. package/src/demo/styles.css +0 -0
@@ -1,10 +1,10 @@
1
1
  import { $atom, $context, $inject, $module, Alepha, AlephaError, TypeBoxError, t } from "alepha";
2
- import { AlephaReactForm, FormValidationError, useForm, useFormState } from "alepha/react/form";
3
- import { $head, AlephaReactHead } from "alepha/react/head";
2
+ import { AlephaReactForm, FormValidationError, useFieldValue, useForm, useFormState } from "alepha/react/form";
3
+ import { $head, AlephaReactHead, BrowserHeadProvider } from "alepha/react/head";
4
4
  import { AlephaReactI18n, useI18n } from "alepha/react/i18n";
5
5
  import { $cookie } from "alepha/server/cookies";
6
+ import { ActionIcon, Anchor, Autocomplete, Badge, Button, Card, ColorInput, ColorSchemeScript, Container, Divider, Fieldset, FileInput, Flex, Grid, Image, Input, Loader, MantineProvider, Menu, MultiSelect, NumberInput, Paper, PasswordInput, Popover, SegmentedControl, Select, Slider, Switch, TagsInput, Text, TextInput, Textarea, Tooltip, UnstyledButton, useMantineTheme } from "@mantine/core";
6
7
  import { ModalsProvider, modals } from "@mantine/modals";
7
- import { ActionIcon, Anchor, Autocomplete, Badge, Button, Card, ColorInput, ColorSchemeScript, Container, Divider, Fieldset, FileInput, Flex, Grid, Image, Input, Loader, MantineProvider, Menu, MultiSelect, NumberInput, PasswordInput, Popover, SegmentedControl, Select, Slider, Switch, TagsInput, Text, TextInput, Textarea, ThemeIcon, Tooltip, UnstyledButton, useMantineTheme } from "@mantine/core";
8
8
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
9
9
  import { Children, createElement, forwardRef, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
10
10
  import { Notifications, notifications } from "@mantine/notifications";
@@ -32,7 +32,7 @@ const alephaSidebarAtom = $atom({
32
32
  closed: true,
33
33
  collapsed: false,
34
34
  expandedWidth: 300,
35
- collapsedWidth: 78
35
+ collapsedWidth: 72
36
36
  }
37
37
  });
38
38
 
@@ -44,6 +44,20 @@ const alephaThemeAtom = $atom({
44
44
  default: { index: 0 }
45
45
  });
46
46
 
47
+ //#endregion
48
+ //#region ../../src/core/atoms/alephaThemeOverridesAtom.ts
49
+ const alephaThemeOverridesAtom = $atom({
50
+ name: "alepha.ui.themeOverrides",
51
+ schema: t.object({
52
+ primaryColor: t.optional(t.text()),
53
+ radius: t.optional(t.text()),
54
+ fontFamily: t.optional(t.text()),
55
+ fontSize: t.optional(t.text()),
56
+ scale: t.optional(t.text())
57
+ }),
58
+ default: {}
59
+ });
60
+
47
61
  //#endregion
48
62
  //#region ../../src/core/atoms/themes/default.ts
49
63
  const defaultTheme = {
@@ -51,6 +65,161 @@ const defaultTheme = {
51
65
  description: "Default Alepha Theme"
52
66
  };
53
67
 
68
+ //#endregion
69
+ //#region ../../src/core/atoms/themes/editorial.ts
70
+ /**
71
+ * Editorial theme.
72
+ *
73
+ * Serif typography, high contrast black and white, thin borders, generous whitespace.
74
+ * Newspaper/magazine aesthetic — elegant restraint.
75
+ */
76
+ const editorialTheme = {
77
+ name: "Editorial",
78
+ description: "Serif typography with newspaper elegance",
79
+ defaultColorScheme: "light",
80
+ head: { link: [
81
+ {
82
+ rel: "preconnect",
83
+ href: "https://fonts.googleapis.com"
84
+ },
85
+ {
86
+ rel: "preconnect",
87
+ href: "https://fonts.gstatic.com",
88
+ crossorigin: ""
89
+ },
90
+ {
91
+ rel: "stylesheet",
92
+ href: "https://fonts.googleapis.com/css2?family=Playfair+Display:wght@400;600;700;800&family=Source+Serif+4:ital,wght@0,300;0,400;0,600;1,300;1,400&display=swap"
93
+ }
94
+ ] },
95
+ primaryColor: "ink",
96
+ primaryShade: {
97
+ light: 7,
98
+ dark: 3
99
+ },
100
+ autoContrast: true,
101
+ fontFamily: "\"Source Serif 4\", \"Georgia\", \"Times New Roman\", serif",
102
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
103
+ headings: {
104
+ fontFamily: "\"Playfair Display\", \"Georgia\", \"Times New Roman\", serif",
105
+ fontWeight: "700",
106
+ textWrap: "wrap",
107
+ sizes: {
108
+ h1: {
109
+ fontSize: "2.5rem",
110
+ lineHeight: "1.15"
111
+ },
112
+ h2: {
113
+ fontSize: "1.75rem",
114
+ lineHeight: "1.2"
115
+ },
116
+ h3: {
117
+ fontSize: "1.375rem",
118
+ lineHeight: "1.3"
119
+ },
120
+ h4: {
121
+ fontSize: "1.125rem",
122
+ lineHeight: "1.4"
123
+ },
124
+ h5: {
125
+ fontSize: "1rem",
126
+ lineHeight: "1.5"
127
+ },
128
+ h6: {
129
+ fontSize: "0.875rem",
130
+ lineHeight: "1.5"
131
+ }
132
+ }
133
+ },
134
+ defaultRadius: "sm",
135
+ radius: {
136
+ xs: "2px",
137
+ sm: "3px",
138
+ md: "4px",
139
+ lg: "6px",
140
+ xl: "8px"
141
+ },
142
+ shadows: {
143
+ xs: "0 1px 2px rgba(0, 0, 0, 0.06)",
144
+ sm: "0 1px 3px rgba(0, 0, 0, 0.08)",
145
+ md: "0 2px 6px rgba(0, 0, 0, 0.08)",
146
+ lg: "0 4px 12px rgba(0, 0, 0, 0.1)",
147
+ xl: "0 8px 24px rgba(0, 0, 0, 0.1)"
148
+ },
149
+ colors: {
150
+ ink: [
151
+ "#f5f3f0",
152
+ "#e8e4de",
153
+ "#d4cec5",
154
+ "#b5ad9f",
155
+ "#8c8272",
156
+ "#6b6050",
157
+ "#4a4035",
158
+ "#332b22",
159
+ "#1f1812",
160
+ "#0d0a07"
161
+ ],
162
+ burgundy: [
163
+ "#faf0f0",
164
+ "#f0d4d4",
165
+ "#e0adad",
166
+ "#cc8585",
167
+ "#b35e5e",
168
+ "#944545",
169
+ "#763636",
170
+ "#5a2828",
171
+ "#3d1b1b",
172
+ "#220f0f"
173
+ ],
174
+ gray: [
175
+ "#faf9f7",
176
+ "#f0eee9",
177
+ "#e0dcd5",
178
+ "#c8c2b8",
179
+ "#a8a194",
180
+ "#8a8273",
181
+ "#6b6456",
182
+ "#504a3f",
183
+ "#36322b",
184
+ "#1e1b17"
185
+ ],
186
+ dark: [
187
+ "#d5d2cd",
188
+ "#aba59c",
189
+ "#817a6e",
190
+ "#5e584e",
191
+ "#46413a",
192
+ "#36322c",
193
+ "#2a2721",
194
+ "#201d19",
195
+ "#171411",
196
+ "#0d0b09"
197
+ ]
198
+ },
199
+ components: {
200
+ Button: Button.extend({
201
+ defaultProps: { fw: 600 },
202
+ styles: { root: { letterSpacing: "0.02em" } }
203
+ }),
204
+ ActionIcon: ActionIcon.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
205
+ Paper: Paper.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
206
+ Card: Card.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
207
+ TextInput: TextInput.extend({ styles: { input: { border: "1px solid var(--mantine-color-default-border)" } } }),
208
+ Badge: Badge.extend({
209
+ defaultProps: {
210
+ fw: 600,
211
+ variant: "outline"
212
+ },
213
+ styles: { root: {
214
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", sans-serif",
215
+ letterSpacing: "0.04em",
216
+ textTransform: "uppercase",
217
+ fontSize: "0.65rem"
218
+ } }
219
+ })
220
+ }
221
+ };
222
+
54
223
  //#endregion
55
224
  //#region ../../src/core/atoms/themes/midnight.ts
56
225
  const midnightTheme = {
@@ -166,41 +335,793 @@ const midnightTheme = {
166
335
  }
167
336
  };
168
337
 
338
+ //#endregion
339
+ //#region ../../src/core/atoms/themes/monochrome.ts
340
+ /**
341
+ * Monochrome theme.
342
+ *
343
+ * Pure black and white. No color. Bold typography does all the heavy lifting.
344
+ * A design-school statement piece — minimalist color, maximalist type.
345
+ */
346
+ const monochromeTheme = {
347
+ name: "Monochrome",
348
+ description: "Pure black and white — zero color, maximum typography",
349
+ primaryColor: "mono",
350
+ primaryShade: {
351
+ light: 8,
352
+ dark: 1
353
+ },
354
+ autoContrast: true,
355
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
356
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
357
+ headings: {
358
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
359
+ fontWeight: "800",
360
+ textWrap: "wrap",
361
+ sizes: {
362
+ h1: {
363
+ fontSize: "2.25rem",
364
+ lineHeight: "1.15"
365
+ },
366
+ h2: {
367
+ fontSize: "1.625rem",
368
+ lineHeight: "1.25"
369
+ },
370
+ h3: {
371
+ fontSize: "1.25rem",
372
+ lineHeight: "1.35"
373
+ },
374
+ h4: {
375
+ fontSize: "1.0625rem",
376
+ lineHeight: "1.45"
377
+ },
378
+ h5: {
379
+ fontSize: "0.9375rem",
380
+ lineHeight: "1.5"
381
+ },
382
+ h6: {
383
+ fontSize: "0.8125rem",
384
+ lineHeight: "1.5"
385
+ }
386
+ }
387
+ },
388
+ defaultRadius: "0",
389
+ radius: {
390
+ xs: "0",
391
+ sm: "0",
392
+ md: "0",
393
+ lg: "0",
394
+ xl: "2px"
395
+ },
396
+ shadows: {
397
+ xs: "0 1px 2px rgba(0, 0, 0, 0.08)",
398
+ sm: "0 1px 4px rgba(0, 0, 0, 0.1)",
399
+ md: "0 2px 8px rgba(0, 0, 0, 0.12)",
400
+ lg: "0 4px 16px rgba(0, 0, 0, 0.14)",
401
+ xl: "0 8px 32px rgba(0, 0, 0, 0.16)"
402
+ },
403
+ colors: {
404
+ mono: [
405
+ "#f5f5f5",
406
+ "#e0e0e0",
407
+ "#c0c0c0",
408
+ "#a0a0a0",
409
+ "#808080",
410
+ "#606060",
411
+ "#404040",
412
+ "#282828",
413
+ "#141414",
414
+ "#000000"
415
+ ],
416
+ gray: [
417
+ "#f5f5f5",
418
+ "#e5e5e5",
419
+ "#cccccc",
420
+ "#b0b0b0",
421
+ "#909090",
422
+ "#707070",
423
+ "#555555",
424
+ "#3a3a3a",
425
+ "#252525",
426
+ "#121212"
427
+ ],
428
+ blue: [
429
+ "#f5f5f5",
430
+ "#e0e0e0",
431
+ "#c0c0c0",
432
+ "#a0a0a0",
433
+ "#808080",
434
+ "#606060",
435
+ "#404040",
436
+ "#282828",
437
+ "#141414",
438
+ "#000000"
439
+ ],
440
+ green: [
441
+ "#f5f5f5",
442
+ "#e0e0e0",
443
+ "#c0c0c0",
444
+ "#a0a0a0",
445
+ "#808080",
446
+ "#606060",
447
+ "#404040",
448
+ "#282828",
449
+ "#141414",
450
+ "#000000"
451
+ ],
452
+ red: [
453
+ "#f5f5f5",
454
+ "#e0e0e0",
455
+ "#c0c0c0",
456
+ "#a0a0a0",
457
+ "#808080",
458
+ "#606060",
459
+ "#404040",
460
+ "#282828",
461
+ "#141414",
462
+ "#000000"
463
+ ],
464
+ dark: [
465
+ "#d0d0d0",
466
+ "#a0a0a0",
467
+ "#707070",
468
+ "#505050",
469
+ "#383838",
470
+ "#282828",
471
+ "#1c1c1c",
472
+ "#141414",
473
+ "#0a0a0a",
474
+ "#000000"
475
+ ]
476
+ },
477
+ components: {
478
+ Button: Button.extend({
479
+ defaultProps: { fw: 700 },
480
+ styles: { root: {
481
+ border: "2px solid currentColor",
482
+ letterSpacing: "0.03em",
483
+ textTransform: "uppercase",
484
+ fontSize: "0.8125rem"
485
+ } }
486
+ }),
487
+ ActionIcon: ActionIcon.extend({ styles: { root: { border: "2px solid currentColor" } } }),
488
+ Paper: Paper.extend({ styles: { root: { border: "2px solid var(--mantine-color-default-border)" } } }),
489
+ Card: Card.extend({ styles: { root: { border: "2px solid var(--mantine-color-default-border)" } } }),
490
+ TextInput: TextInput.extend({ styles: { input: { border: "2px solid var(--mantine-color-default-border)" } } }),
491
+ Badge: Badge.extend({
492
+ defaultProps: {
493
+ fw: 700,
494
+ variant: "outline"
495
+ },
496
+ styles: { root: {
497
+ textTransform: "uppercase",
498
+ letterSpacing: "0.06em",
499
+ fontSize: "0.65rem",
500
+ border: "2px solid currentColor"
501
+ } }
502
+ })
503
+ }
504
+ };
505
+
506
+ //#endregion
507
+ //#region ../../src/core/atoms/themes/rosePine.ts
508
+ /**
509
+ * Rosé Pine theme.
510
+ *
511
+ * Muted pinks, golds, and subtle greens on warm dark backgrounds.
512
+ * Cozy, low-contrast, easy on the eyes.
513
+ * Based on the Rosé Pine color philosophy.
514
+ */
515
+ const rosePineTheme = {
516
+ name: "Rosé Pine",
517
+ description: "Muted pinks and golds on warm dark backgrounds",
518
+ defaultColorScheme: "dark",
519
+ primaryColor: "rose",
520
+ primaryShade: {
521
+ light: 5,
522
+ dark: 4
523
+ },
524
+ autoContrast: true,
525
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
526
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
527
+ headings: {
528
+ fontFamily: "-apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
529
+ fontWeight: "600",
530
+ textWrap: "wrap",
531
+ sizes: {
532
+ h1: {
533
+ fontSize: "2rem",
534
+ lineHeight: "1.25"
535
+ },
536
+ h2: {
537
+ fontSize: "1.5rem",
538
+ lineHeight: "1.3"
539
+ },
540
+ h3: {
541
+ fontSize: "1.25rem",
542
+ lineHeight: "1.4"
543
+ },
544
+ h4: {
545
+ fontSize: "1rem",
546
+ lineHeight: "1.5"
547
+ },
548
+ h5: {
549
+ fontSize: "0.875rem",
550
+ lineHeight: "1.5"
551
+ },
552
+ h6: {
553
+ fontSize: "0.75rem",
554
+ lineHeight: "1.5"
555
+ }
556
+ }
557
+ },
558
+ defaultRadius: "md",
559
+ radius: {
560
+ xs: "4px",
561
+ sm: "6px",
562
+ md: "8px",
563
+ lg: "12px",
564
+ xl: "16px"
565
+ },
566
+ shadows: {
567
+ xs: "0 1px 3px rgba(0, 0, 0, 0.2)",
568
+ sm: "0 2px 6px rgba(0, 0, 0, 0.2)",
569
+ md: "0 4px 12px rgba(0, 0, 0, 0.25)",
570
+ lg: "0 8px 24px rgba(0, 0, 0, 0.3)",
571
+ xl: "0 12px 36px rgba(0, 0, 0, 0.35)"
572
+ },
573
+ colors: {
574
+ rose: [
575
+ "#faf0f4",
576
+ "#f2d8e3",
577
+ "#eabdd0",
578
+ "#e0a0bb",
579
+ "#d4849f",
580
+ "#c4748f",
581
+ "#b06282",
582
+ "#9a5275",
583
+ "#7a3f5e",
584
+ "#5c2e47"
585
+ ],
586
+ gold: [
587
+ "#fdf8ec",
588
+ "#f8ecc8",
589
+ "#f2dda0",
590
+ "#eacb72",
591
+ "#e0b94d",
592
+ "#c9a33e",
593
+ "#a98830",
594
+ "#866b24",
595
+ "#634f1a",
596
+ "#403310"
597
+ ],
598
+ pine: [
599
+ "#ecf5f0",
600
+ "#d0e6da",
601
+ "#add4be",
602
+ "#86c0a0",
603
+ "#62ac84",
604
+ "#4e9670",
605
+ "#3e7a5a",
606
+ "#2f5e44",
607
+ "#20412f",
608
+ "#12251b"
609
+ ],
610
+ foam: [
611
+ "#edf6f7",
612
+ "#d2e9eb",
613
+ "#b0d9dd",
614
+ "#8bc6cc",
615
+ "#6ab3bb",
616
+ "#569da5",
617
+ "#438088",
618
+ "#33636a",
619
+ "#23454a",
620
+ "#14292c"
621
+ ],
622
+ red: [
623
+ "#f9eef0",
624
+ "#efd3d8",
625
+ "#e3b2bb",
626
+ "#d68e9b",
627
+ "#c86c7c",
628
+ "#b25566",
629
+ "#944454",
630
+ "#733442",
631
+ "#52252f",
632
+ "#33161d"
633
+ ],
634
+ gray: [
635
+ "#f4f0f2",
636
+ "#e4dde1",
637
+ "#cec5cb",
638
+ "#b5aab2",
639
+ "#9a8e96",
640
+ "#7e737a",
641
+ "#635a60",
642
+ "#4a4248",
643
+ "#332d31",
644
+ "#1e1a1c"
645
+ ],
646
+ dark: [
647
+ "#e0d8e0",
648
+ "#b0a6b2",
649
+ "#817786",
650
+ "#615768",
651
+ "#4a3f54",
652
+ "#3a3044",
653
+ "#2a2436",
654
+ "#211e2e",
655
+ "#1a1724",
656
+ "#110f1a"
657
+ ]
658
+ },
659
+ components: {
660
+ Button: Button.extend({
661
+ defaultProps: { fw: 500 },
662
+ styles: { root: { transition: "background-color 0.15s ease, opacity 0.15s ease" } }
663
+ }),
664
+ ActionIcon: ActionIcon.extend({ styles: { root: { transition: "background-color 0.15s ease, opacity 0.15s ease" } } }),
665
+ Paper: Paper.extend({
666
+ defaultProps: { shadow: "sm" },
667
+ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } }
668
+ }),
669
+ Card: Card.extend({
670
+ defaultProps: { shadow: "sm" },
671
+ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } }
672
+ }),
673
+ TextInput: TextInput.extend({ styles: { input: { border: "1px solid var(--mantine-color-default-border)" } } }),
674
+ Badge: Badge.extend({ defaultProps: { fw: 500 } })
675
+ }
676
+ };
677
+
678
+ //#endregion
679
+ //#region ../../src/core/atoms/themes/softBrutalism.ts
680
+ /**
681
+ * Soft Brutalism theme.
682
+ *
683
+ * Pastel pop palette with solid offset shadows, rounded corners, and bold borders.
684
+ * A friendlier take on neubrutalism — playful but production-ready.
685
+ */
686
+ const softBrutalismTheme = {
687
+ name: "Soft Brutalism",
688
+ description: "Pastel pop with bold borders and offset shadows",
689
+ head: { link: [
690
+ {
691
+ rel: "preconnect",
692
+ href: "https://fonts.googleapis.com"
693
+ },
694
+ {
695
+ rel: "preconnect",
696
+ href: "https://fonts.gstatic.com",
697
+ crossorigin: ""
698
+ },
699
+ {
700
+ rel: "stylesheet",
701
+ href: "https://fonts.googleapis.com/css2?family=Inter:wght@400;600;700&display=swap"
702
+ }
703
+ ] },
704
+ primaryColor: "lavender",
705
+ primaryShade: {
706
+ light: 5,
707
+ dark: 7
708
+ },
709
+ autoContrast: true,
710
+ cursorType: "pointer",
711
+ fontFamily: "Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
712
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
713
+ headings: {
714
+ fontFamily: "Inter, -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Noto Sans\", Helvetica, Arial, sans-serif",
715
+ fontWeight: "700",
716
+ textWrap: "wrap",
717
+ sizes: {
718
+ h1: {
719
+ fontSize: "2rem",
720
+ lineHeight: "1.25"
721
+ },
722
+ h2: {
723
+ fontSize: "1.5rem",
724
+ lineHeight: "1.3"
725
+ },
726
+ h3: {
727
+ fontSize: "1.25rem",
728
+ lineHeight: "1.4"
729
+ },
730
+ h4: {
731
+ fontSize: "1rem",
732
+ lineHeight: "1.5"
733
+ },
734
+ h5: {
735
+ fontSize: "0.875rem",
736
+ lineHeight: "1.5"
737
+ },
738
+ h6: {
739
+ fontSize: "0.75rem",
740
+ lineHeight: "1.5"
741
+ }
742
+ }
743
+ },
744
+ defaultRadius: "md",
745
+ radius: {
746
+ xs: "6px",
747
+ sm: "8px",
748
+ md: "12px",
749
+ lg: "16px",
750
+ xl: "24px"
751
+ },
752
+ shadows: {
753
+ xs: "2px 2px 0 0 rgba(100, 80, 140, 0.15)",
754
+ sm: "3px 3px 0 0 rgba(100, 80, 140, 0.2)",
755
+ md: "4px 4px 0 0 rgba(100, 80, 140, 0.2)",
756
+ lg: "6px 6px 0 0 rgba(100, 80, 140, 0.25)",
757
+ xl: "8px 8px 0 0 rgba(100, 80, 140, 0.3)"
758
+ },
759
+ colors: {
760
+ lavender: [
761
+ "#f3f0fa",
762
+ "#e4dcf4",
763
+ "#d1c4e9",
764
+ "#b4a7d6",
765
+ "#9a8bc4",
766
+ "#7f6cb0",
767
+ "#6a549e",
768
+ "#543f87",
769
+ "#3d2d6b",
770
+ "#2a1d52"
771
+ ],
772
+ peach: [
773
+ "#fef3ec",
774
+ "#fce4d0",
775
+ "#f9d0ae",
776
+ "#f4b886",
777
+ "#f4a261",
778
+ "#e68a42",
779
+ "#c67234",
780
+ "#a35a28",
781
+ "#6b3a1a",
782
+ "#4a2710"
783
+ ],
784
+ mint: [
785
+ "#ecfaf0",
786
+ "#d4f2dc",
787
+ "#b3e8c2",
788
+ "#8edba4",
789
+ "#81c995",
790
+ "#5ab874",
791
+ "#42a05c",
792
+ "#2e8548",
793
+ "#1a5c2e",
794
+ "#0f3f1e"
795
+ ],
796
+ coral: [
797
+ "#fef0ef",
798
+ "#fcd9d7",
799
+ "#f8b8b4",
800
+ "#f29490",
801
+ "#e97171",
802
+ "#d65454",
803
+ "#b83e3e",
804
+ "#962d2d",
805
+ "#6b1f1f",
806
+ "#4a1414"
807
+ ],
808
+ gray: [
809
+ "#faf8f6",
810
+ "#f0ece8",
811
+ "#ddd7d0",
812
+ "#c4bbb2",
813
+ "#a89e95",
814
+ "#8c8279",
815
+ "#6e655d",
816
+ "#524b44",
817
+ "#3a342f",
818
+ "#24211e"
819
+ ],
820
+ dark: [
821
+ "#d4d0dc",
822
+ "#a9a2b5",
823
+ "#7e7690",
824
+ "#5c546e",
825
+ "#443c56",
826
+ "#342d45",
827
+ "#2a2339",
828
+ "#1e1a2e",
829
+ "#161224",
830
+ "#0f0c1a"
831
+ ]
832
+ },
833
+ components: {
834
+ Button: Button.extend({
835
+ defaultProps: { fw: 600 },
836
+ styles: { root: {
837
+ border: "2px solid currentColor",
838
+ boxShadow: "3px 3px 0 0 rgba(100, 80, 140, 0.2)",
839
+ transition: "box-shadow 0.15s ease, transform 0.15s ease"
840
+ } }
841
+ }),
842
+ ActionIcon: ActionIcon.extend({ styles: { root: {
843
+ border: "2px solid currentColor",
844
+ boxShadow: "2px 2px 0 0 rgba(100, 80, 140, 0.15)"
845
+ } } }),
846
+ Paper: Paper.extend({
847
+ defaultProps: { shadow: "sm" },
848
+ styles: { root: { border: "2px solid var(--mantine-color-default-border)" } }
849
+ }),
850
+ Card: Card.extend({
851
+ defaultProps: { shadow: "sm" },
852
+ styles: { root: { border: "2px solid var(--mantine-color-default-border)" } }
853
+ }),
854
+ TextInput: TextInput.extend({ styles: { input: {
855
+ border: "2px solid var(--mantine-color-default-border)",
856
+ transition: "box-shadow 0.15s ease, border-color 0.15s ease"
857
+ } } }),
858
+ Badge: Badge.extend({
859
+ defaultProps: { fw: 600 },
860
+ styles: { root: { border: "2px solid currentColor" } }
861
+ })
862
+ }
863
+ };
864
+
865
+ //#endregion
866
+ //#region ../../src/core/atoms/themes/terminal.ts
867
+ /**
868
+ * Terminal theme.
869
+ *
870
+ * Monospace everything, green-on-black, zero radius.
871
+ * CRT/hacker aesthetic for developer tools and dashboards.
872
+ */
873
+ const terminalTheme = {
874
+ name: "Terminal",
875
+ description: "Green phosphor on black — monospace hacker aesthetic",
876
+ defaultColorScheme: "dark",
877
+ primaryColor: "terminal",
878
+ primaryShade: {
879
+ light: 5,
880
+ dark: 4
881
+ },
882
+ autoContrast: true,
883
+ fontFamily: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
884
+ fontFamilyMonospace: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
885
+ headings: {
886
+ fontFamily: "ui-monospace, SFMono-Regular, \"SF Mono\", Menlo, Consolas, \"Liberation Mono\", monospace",
887
+ fontWeight: "700",
888
+ textWrap: "wrap",
889
+ sizes: {
890
+ h1: {
891
+ fontSize: "1.75rem",
892
+ lineHeight: "1.3"
893
+ },
894
+ h2: {
895
+ fontSize: "1.375rem",
896
+ lineHeight: "1.35"
897
+ },
898
+ h3: {
899
+ fontSize: "1.125rem",
900
+ lineHeight: "1.4"
901
+ },
902
+ h4: {
903
+ fontSize: "1rem",
904
+ lineHeight: "1.5"
905
+ },
906
+ h5: {
907
+ fontSize: "0.875rem",
908
+ lineHeight: "1.5"
909
+ },
910
+ h6: {
911
+ fontSize: "0.75rem",
912
+ lineHeight: "1.5"
913
+ }
914
+ }
915
+ },
916
+ defaultRadius: "0",
917
+ radius: {
918
+ xs: "0",
919
+ sm: "0",
920
+ md: "0",
921
+ lg: "2px",
922
+ xl: "4px"
923
+ },
924
+ shadows: {
925
+ xs: "none",
926
+ sm: "none",
927
+ md: "0 0 8px rgba(0, 255, 65, 0.08)",
928
+ lg: "0 0 16px rgba(0, 255, 65, 0.1)",
929
+ xl: "0 0 24px rgba(0, 255, 65, 0.12)"
930
+ },
931
+ colors: {
932
+ terminal: [
933
+ "#e6fff0",
934
+ "#b3ffd1",
935
+ "#80ffb3",
936
+ "#4dff94",
937
+ "#00ff41",
938
+ "#00d636",
939
+ "#00ad2b",
940
+ "#008521",
941
+ "#005c17",
942
+ "#00330d"
943
+ ],
944
+ amber: [
945
+ "#fff8e6",
946
+ "#ffecb3",
947
+ "#ffe080",
948
+ "#ffd54d",
949
+ "#ffca28",
950
+ "#d4a520",
951
+ "#aa8418",
952
+ "#806310",
953
+ "#554208",
954
+ "#2b2104"
955
+ ],
956
+ red: [
957
+ "#ffe6e6",
958
+ "#ffb3b3",
959
+ "#ff8080",
960
+ "#ff4d4d",
961
+ "#ff1a1a",
962
+ "#d41515",
963
+ "#aa1010",
964
+ "#800c0c",
965
+ "#550808",
966
+ "#2b0404"
967
+ ],
968
+ gray: [
969
+ "#e8eaed",
970
+ "#c8cdd3",
971
+ "#a4aab3",
972
+ "#808892",
973
+ "#5f6872",
974
+ "#474f58",
975
+ "#363c44",
976
+ "#282d33",
977
+ "#1c2026",
978
+ "#12151a"
979
+ ],
980
+ dark: [
981
+ "#c9cdd2",
982
+ "#8b9198",
983
+ "#5c636b",
984
+ "#3d444c",
985
+ "#2b3138",
986
+ "#1e242b",
987
+ "#151a20",
988
+ "#0e1216",
989
+ "#080c0f",
990
+ "#020303"
991
+ ]
992
+ },
993
+ components: {
994
+ Button: Button.extend({
995
+ defaultProps: { fw: 600 },
996
+ styles: { root: {
997
+ border: "1px solid currentColor",
998
+ textTransform: "uppercase",
999
+ letterSpacing: "0.05em",
1000
+ fontSize: "0.8125rem"
1001
+ } }
1002
+ }),
1003
+ ActionIcon: ActionIcon.extend({ styles: { root: { border: "1px solid currentColor" } } }),
1004
+ Paper: Paper.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
1005
+ Card: Card.extend({ styles: { root: { border: "1px solid var(--mantine-color-default-border)" } } }),
1006
+ TextInput: TextInput.extend({ styles: { input: {
1007
+ border: "1px solid var(--mantine-color-default-border)",
1008
+ fontFamily: "inherit"
1009
+ } } }),
1010
+ Badge: Badge.extend({
1011
+ defaultProps: { fw: 600 },
1012
+ styles: { root: {
1013
+ border: "1px solid currentColor",
1014
+ textTransform: "uppercase",
1015
+ letterSpacing: "0.05em"
1016
+ } }
1017
+ })
1018
+ }
1019
+ };
1020
+
169
1021
  //#endregion
170
1022
  //#region ../../src/core/atoms/alephaThemeListAtom.ts
171
1023
  const alephaThemeListAtom = $atom({
172
1024
  name: "alepha.ui.themeList",
173
1025
  schema: t.array(t.json()),
174
- default: [defaultTheme, midnightTheme]
1026
+ default: [
1027
+ defaultTheme,
1028
+ midnightTheme,
1029
+ softBrutalismTheme,
1030
+ terminalTheme,
1031
+ editorialTheme,
1032
+ rosePineTheme,
1033
+ monochromeTheme
1034
+ ]
175
1035
  });
176
1036
 
177
1037
  //#endregion
178
1038
  //#region ../../src/core/providers/ThemeProvider.ts
179
- var ThemeProvider = class {
1039
+ var ThemeProvider = class ThemeProvider {
180
1040
  alepha = $inject(Alepha);
181
1041
  cookie = $cookie({
182
1042
  name: "theme",
183
1043
  schema: alephaThemeAtom.schema,
184
1044
  ttl: [1, "year"]
185
1045
  });
1046
+ overridesCookie = $cookie({
1047
+ name: "themeOverrides",
1048
+ schema: alephaThemeOverridesAtom.schema,
1049
+ ttl: [1, "year"]
1050
+ });
186
1051
  head = $head(() => {
187
1052
  const theme = this.getTheme();
188
1053
  if (!theme || !theme.name) return {};
189
- return { htmlAttributes: { "data-theme": theme.name } };
1054
+ return {
1055
+ htmlAttributes: { "data-theme": this.slugify(theme.name) },
1056
+ ...theme.head
1057
+ };
190
1058
  });
191
1059
  setTheme(index) {
192
- const newTheme = this.alepha.store.get(alephaThemeListAtom)[index];
193
- if (!newTheme) throw new AlephaError(`Theme with index ${index} not found`);
1060
+ if (!this.alepha.store.get(alephaThemeListAtom)[index]) throw new AlephaError(`Theme with index ${index} not found`);
194
1061
  this.cookie.set({ index });
195
1062
  this.alepha.store.set(alephaThemeAtom, { index });
196
- if (typeof document === "undefined") return;
197
- document.documentElement.removeAttribute("data-theme");
198
- if (newTheme.name) document.documentElement.setAttribute("data-theme", newTheme.name);
1063
+ if (!this.alepha.isBrowser()) return;
1064
+ this.alepha.inject(BrowserHeadProvider).refreshGlobalHead();
1065
+ }
1066
+ slugify(name) {
1067
+ return name.toLowerCase().replace(/\s+/g, "-");
199
1068
  }
1069
+ static FONT_SIZE_MULTIPLIERS = {
1070
+ xs: .85,
1071
+ sm: .925,
1072
+ md: 1,
1073
+ lg: 1.1,
1074
+ xl: 1.25
1075
+ };
1076
+ static SCALE_VALUES = {
1077
+ xs: .85,
1078
+ sm: .925,
1079
+ md: 1,
1080
+ lg: 1.1,
1081
+ xl: 1.25
1082
+ };
1083
+ static DEFAULT_FONT_SIZES = {
1084
+ xs: "0.75rem",
1085
+ sm: "0.875rem",
1086
+ md: "1rem",
1087
+ lg: "1.125rem",
1088
+ xl: "1.25rem"
1089
+ };
200
1090
  getTheme() {
201
1091
  const index = this.getThemeIndex();
202
1092
  const list = this.alepha.store.get(alephaThemeListAtom);
203
- return list[index] || list[0] || defaultTheme;
1093
+ const base = list[index] || list[0] || defaultTheme;
1094
+ const overrides = this.getThemeOverrides();
1095
+ if (!overrides.primaryColor && !overrides.radius && !overrides.fontFamily && !overrides.fontSize && !overrides.scale) return base;
1096
+ const merged = {
1097
+ ...base,
1098
+ ...overrides.primaryColor && { primaryColor: overrides.primaryColor },
1099
+ ...overrides.radius && { defaultRadius: overrides.radius },
1100
+ ...overrides.fontFamily && { fontFamily: overrides.fontFamily },
1101
+ ...overrides.scale && overrides.scale !== "md" && { scale: ThemeProvider.SCALE_VALUES[overrides.scale] ?? 1 }
1102
+ };
1103
+ if (overrides.fontSize && overrides.fontSize !== "md") {
1104
+ const multiplier = ThemeProvider.FONT_SIZE_MULTIPLIERS[overrides.fontSize] ?? 1;
1105
+ const baseSizes = base.fontSizes ?? ThemeProvider.DEFAULT_FONT_SIZES;
1106
+ merged.fontSizes = Object.fromEntries(Object.entries(baseSizes).map(([key, val]) => [key, `${(Number.parseFloat(String(val)) * multiplier).toFixed(4)}rem`]));
1107
+ }
1108
+ return merged;
1109
+ }
1110
+ setThemeOverrides(overrides) {
1111
+ this.overridesCookie.set(overrides);
1112
+ this.alepha.store.set(alephaThemeOverridesAtom, overrides);
1113
+ if (!this.alepha.isBrowser()) return;
1114
+ this.alepha.inject(BrowserHeadProvider).refreshGlobalHead();
1115
+ }
1116
+ getThemeOverrides() {
1117
+ try {
1118
+ return this.overridesCookie.get() ?? this.alepha.store.get(alephaThemeOverridesAtom) ?? {};
1119
+ } catch {
1120
+ return this.alepha.store.get(alephaThemeOverridesAtom) ?? {};
1121
+ }
1122
+ }
1123
+ resetThemeOverrides() {
1124
+ this.setThemeOverrides({});
204
1125
  }
205
1126
  getThemeIndex() {
206
1127
  try {
@@ -307,14 +1228,21 @@ var DialogService = class {
307
1228
  */
308
1229
  alert(options) {
309
1230
  return new Promise((resolve) => {
1231
+ let resolved = false;
1232
+ const done = () => {
1233
+ if (resolved) return;
1234
+ resolved = true;
1235
+ resolve();
1236
+ };
310
1237
  const modalId = this.open({
311
1238
  ...options,
312
1239
  title: options?.title || "Alert",
1240
+ onClose: done,
313
1241
  content: /* @__PURE__ */ jsx(AlertDialog, {
314
1242
  options,
315
1243
  onClose: () => {
316
1244
  this.close(modalId);
317
- resolve();
1245
+ done();
318
1246
  }
319
1247
  })
320
1248
  });
@@ -325,16 +1253,23 @@ var DialogService = class {
325
1253
  */
326
1254
  confirm(options) {
327
1255
  return new Promise((resolve) => {
1256
+ let resolved = false;
1257
+ const done = (confirmed) => {
1258
+ if (resolved) return;
1259
+ resolved = true;
1260
+ resolve(confirmed);
1261
+ };
328
1262
  const modalId = this.open({
329
1263
  ...options,
330
1264
  title: options?.title || "Confirm",
331
1265
  closeOnClickOutside: false,
332
1266
  closeOnEscape: false,
1267
+ onClose: () => done(false),
333
1268
  content: /* @__PURE__ */ jsx(ConfirmDialog, {
334
1269
  options,
335
1270
  onConfirm: (confirmed) => {
336
1271
  this.close(modalId);
337
- resolve(confirmed);
1272
+ done(confirmed);
338
1273
  }
339
1274
  })
340
1275
  });
@@ -345,16 +1280,23 @@ var DialogService = class {
345
1280
  */
346
1281
  prompt(options) {
347
1282
  return new Promise((resolve) => {
1283
+ let resolved = false;
1284
+ const done = (value) => {
1285
+ if (resolved) return;
1286
+ resolved = true;
1287
+ resolve(value);
1288
+ };
348
1289
  const modalId = this.open({
349
1290
  ...options,
350
1291
  title: options?.title || "Input",
351
1292
  closeOnClickOutside: false,
352
1293
  closeOnEscape: false,
1294
+ onClose: () => done(null),
353
1295
  content: /* @__PURE__ */ jsx(PromptDialog, {
354
1296
  options,
355
1297
  onSubmit: (value) => {
356
1298
  this.close(modalId);
357
- resolve(value);
1299
+ done(value);
358
1300
  }
359
1301
  })
360
1302
  });
@@ -458,20 +1400,34 @@ var UiRouter = class {
458
1400
  /**
459
1401
  * Hook to get and set the current theme.
460
1402
  *
461
- * Returns a tuple with the current theme and a function to set the theme.
1403
+ * Returns a tuple with the current theme, a function to set the theme,
1404
+ * and expert mode controls for fine-grained customization.
462
1405
  *
463
1406
  * ```tsx
464
- * const [theme, setTheme] = useTheme();
1407
+ * const [theme, setTheme, expert] = useTheme();
465
1408
  * ```
466
1409
  */
467
1410
  const useTheme = () => {
468
1411
  useStore(alephaThemeAtom);
1412
+ useStore(alephaThemeOverridesAtom);
469
1413
  const themeProvider = useInject(ThemeProvider);
470
1414
  const theme = themeProvider.getTheme();
471
1415
  const setTheme = (theme) => {
472
1416
  themeProvider.setTheme(theme.index);
473
1417
  };
474
- return [theme, setTheme];
1418
+ return [
1419
+ theme,
1420
+ setTheme,
1421
+ {
1422
+ overrides: themeProvider.getThemeOverrides(),
1423
+ setOverrides: (overrides) => {
1424
+ themeProvider.setThemeOverrides(overrides);
1425
+ },
1426
+ resetOverrides: () => {
1427
+ themeProvider.resetThemeOverrides();
1428
+ }
1429
+ }
1430
+ ];
475
1431
  };
476
1432
 
477
1433
  //#endregion
@@ -569,16 +1525,16 @@ const AlephaMantineProvider = (props) => {
569
1525
  const ui = {
570
1526
  colors: {
571
1527
  transparent: "transparent",
572
- background: "var(--alepha-background)",
1528
+ background: "var(--alepha-ground)",
573
1529
  surface: "var(--alepha-surface)",
574
1530
  elevated: "var(--alepha-elevated)",
575
1531
  border: "var(--alepha-border)"
576
1532
  },
577
1533
  sizes: { icon: {
578
- xs: 14,
579
- sm: 16,
580
- md: 20,
581
- lg: 24,
1534
+ xs: 16,
1535
+ sm: 20,
1536
+ md: 24,
1537
+ lg: 28,
582
1538
  xl: 32
583
1539
  } }
584
1540
  };
@@ -592,51 +1548,13 @@ function isComponentType(param) {
592
1548
 
593
1549
  //#endregion
594
1550
  //#region ../../src/core/components/buttons/ActionButton.tsx
595
- const ActionMenuItem = (props) => {
596
- const { item, index } = props;
597
- const router = useRouter();
598
- const action = useAction({ handler: async (e) => {
599
- await item.onClick?.();
600
- } }, [item.onClick]);
601
- if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
602
- if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
603
- if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
604
- trigger: "hover",
605
- position: "right-start",
606
- offset: 2,
607
- children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
608
- leftSection: item.icon,
609
- rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
610
- children: item.label
611
- }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
612
- item: child,
613
- index: childIndex
614
- }, childIndex)) })]
615
- }, index);
616
- const menuItemProps = {};
617
- if (props.item.onClick) menuItemProps.onClick = action.run;
618
- else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
619
- return /* @__PURE__ */ jsx(Menu.Item, {
620
- leftSection: item.icon,
621
- onClick: item.onClick,
622
- color: item.color,
623
- rightSection: item.active ? /* @__PURE__ */ jsx(ThemeIcon, {
624
- size: "xs",
625
- variant: "transparent",
626
- children: /* @__PURE__ */ jsx(IconCheck, {})
627
- }) : void 0,
628
- ...menuItemProps,
629
- children: item.label
630
- }, index);
631
- };
632
1551
  const ActionButton = (_props) => {
633
1552
  const theme = useMantineTheme();
634
1553
  const props = { ..._props };
635
- const { tooltip, menu, icon, ...restProps } = props;
636
- if (props.variant === "subtle" || props.variant === "outline") restProps.color ??= "gray";
1554
+ if (props.variant === "minimal") {}
1555
+ const { tooltip, menu, icon, iconSize, ...restProps } = props;
637
1556
  if (props.intent) {
638
- if (props.intent === "none") restProps.color ??= "gray";
639
- else if (props.intent === "primary") restProps.color ??= theme.primaryColor;
1557
+ if (props.intent === "primary") restProps.color ??= theme.primaryColor;
640
1558
  else if (props.intent === "success") {
641
1559
  restProps.c ??= "white";
642
1560
  restProps.color ??= "green";
@@ -651,10 +1569,11 @@ const ActionButton = (_props) => {
651
1569
  }
652
1570
  if (props.icon) {
653
1571
  const sizes = ui.sizes.icon;
654
- const icon = isComponentType(props.icon) ? /* @__PURE__ */ jsx(props.icon, { size: sizes[props.size || "md"] }) : /* @__PURE__ */ jsx("span", { children: props.icon });
1572
+ const iconSize = props.iconSize ?? sizes[props.size || "sm"];
1573
+ const icon = isComponentType(props.icon) ? /* @__PURE__ */ jsx(props.icon, { size: iconSize }) : /* @__PURE__ */ jsx("span", { children: props.icon });
655
1574
  if (!props.children) {
656
1575
  restProps.children = Children.only(icon);
657
- restProps.px ??= "xs";
1576
+ restProps.p ??= 8;
658
1577
  } else restProps.leftSection = icon;
659
1578
  }
660
1579
  if (props.leftSection && !props.children) restProps.px ??= "xs";
@@ -677,6 +1596,7 @@ const ActionButton = (_props) => {
677
1596
  children: /* @__PURE__ */ jsx(ActionButton, {
678
1597
  px: "xs",
679
1598
  ...rest,
1599
+ "aria-label": typeof children === "string" ? children : void 0,
680
1600
  tooltip,
681
1601
  menu,
682
1602
  children: leftSection
@@ -833,7 +1753,7 @@ const ActionClickButton = ({ preventDefault, ...props }) => {
833
1753
  * Action for navigation with active state support.
834
1754
  */
835
1755
  const ActionNavigationButton = (props) => {
836
- const { active: options, classNameActive, variantActive, propsActive, routerGoOptions, onClick: propsOnClick, anchor, ...buttonProps } = props;
1756
+ const { active: options, classNameActive, variantActive, propsActive, routerGoOptions, onClick: propsOnClick, anchorProps: buttonAnchorProps, anchor, ...buttonProps } = props;
837
1757
  const router = useRouter();
838
1758
  const { isPending, isActive } = useActive(options ? {
839
1759
  href: props.href,
@@ -847,11 +1767,11 @@ const ActionNavigationButton = (props) => {
847
1767
  };
848
1768
  const className = buttonProps.className || "";
849
1769
  if (isActive && options !== false && classNameActive) buttonProps.className = `${className} ${classNameActive}`.trim();
850
- if (props.anchorProps || anchor) return /* @__PURE__ */ jsx(Anchor, {
1770
+ if (buttonAnchorProps || anchor) return /* @__PURE__ */ jsx(Anchor, {
851
1771
  component: "a",
852
1772
  ...anchorProps,
853
1773
  ...buttonProps,
854
- ...props.anchorProps,
1774
+ ...buttonAnchorProps,
855
1775
  onClick: combinedOnClick,
856
1776
  children: props.children
857
1777
  });
@@ -874,11 +1794,43 @@ const ActionHrefButton = (props) => {
874
1794
  children: props.children
875
1795
  });
876
1796
  };
1797
+ const ActionMenuItem = (props) => {
1798
+ const { item, index } = props;
1799
+ const router = useRouter();
1800
+ const action = useAction({ handler: async (e) => {
1801
+ await item.onClick?.();
1802
+ } }, [item.onClick]);
1803
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
1804
+ if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
1805
+ if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
1806
+ trigger: "hover",
1807
+ position: "right-start",
1808
+ offset: 2,
1809
+ children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
1810
+ leftSection: item.icon,
1811
+ rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
1812
+ children: item.label
1813
+ }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
1814
+ item: child,
1815
+ index: childIndex
1816
+ }, childIndex)) })]
1817
+ }, index);
1818
+ const menuItemProps = {};
1819
+ if (props.item.onClick) menuItemProps.onClick = action.run;
1820
+ else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
1821
+ return /* @__PURE__ */ jsx(Menu.Item, {
1822
+ leftSection: item.icon ?? (item.active ? /* @__PURE__ */ jsx(IconCheck, { size: ui.sizes.icon.sm }) : /* @__PURE__ */ jsx(Flex, { w: ui.sizes.icon.sm })),
1823
+ onClick: item.onClick,
1824
+ color: item.color,
1825
+ ...menuItemProps,
1826
+ children: item.label
1827
+ }, index);
1828
+ };
877
1829
 
878
1830
  //#endregion
879
1831
  //#region ../../src/core/components/Flex.tsx
880
1832
  const Flex$1 = forwardRef((props, ref) => {
881
- const { fill, center, centerX, centerY, col, ...rest } = props;
1833
+ const { fill, center, centerX, centerY, col, ground, surface, elevated, rounded, bordered, borderedTop, borderedBottom, shadowed, overflow, ...rest } = props;
882
1834
  if (fill) rest.flex ??= 1;
883
1835
  if (col) rest.direction ??= "column";
884
1836
  if (center) {
@@ -887,6 +1839,21 @@ const Flex$1 = forwardRef((props, ref) => {
887
1839
  }
888
1840
  if (centerX) rest.justify ??= "center";
889
1841
  if (centerY) rest.align ??= "center";
1842
+ if (ground) rest.bg = "var(--alepha-ground)";
1843
+ else if (surface) rest.bg = "var(--alepha-surface)";
1844
+ else if (elevated) rest.bg = "var(--alepha-elevated)";
1845
+ if (rounded) rest.bdrs = rounded === true ? "md" : rounded;
1846
+ if (bordered) rest.bd = "1px solid var(--alepha-border)";
1847
+ if (borderedTop) rest.style = {
1848
+ borderTop: "1px solid var(--alepha-border)",
1849
+ ...rest.style ?? {}
1850
+ };
1851
+ if (borderedBottom) rest.style = {
1852
+ borderBottom: "1px solid var(--alepha-border)",
1853
+ ...rest.style ?? {}
1854
+ };
1855
+ if (shadowed) rest.className = `${rest.className ?? ""} shadow-${shadowed === true ? "md" : shadowed}`.trim();
1856
+ if (overflow) rest.className = `${rest.className ?? ""} overflow-auto`.trim();
890
1857
  return /* @__PURE__ */ jsx(Flex, {
891
1858
  ref,
892
1859
  ...rest
@@ -904,6 +1871,15 @@ const Container$1 = forwardRef((props, ref) => {
904
1871
  });
905
1872
  Container$1.displayName = "Container";
906
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
+
907
1883
  //#endregion
908
1884
  //#region ../../src/core/components/Text.tsx
909
1885
  const INTENT_COLORS = {
@@ -920,7 +1896,7 @@ const Text$1 = forwardRef((props, ref) => {
920
1896
  if (light) rest.fw ??= 300;
921
1897
  if (italic) rest.fs ??= "italic";
922
1898
  if (muted) rest.c ??= "dimmed";
923
- if (small) rest.size ??= "sm";
1899
+ if (small) rest.size ??= "xs";
924
1900
  if (uppercase) rest.tt ??= "uppercase";
925
1901
  if (capitalize) rest.tt ??= "capitalize";
926
1902
  if (center) rest.ta ??= "center";
@@ -938,7 +1914,7 @@ Text$1.displayName = "Text";
938
1914
  const parseInput = (props, form) => {
939
1915
  const disabled = false;
940
1916
  const id = props.input.props.id;
941
- 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);
942
1918
  const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
943
1919
  const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
944
1920
  const icon = !props.icon ? getDefaultIcon({
@@ -946,17 +1922,20 @@ const parseInput = (props, form) => {
946
1922
  format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
947
1923
  name: props.input.props.name,
948
1924
  isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
949
- isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
950
- }) : 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 });
951
1928
  const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
952
1929
  const required = props.input.required;
953
1930
  const schema = props.input.schema;
1931
+ const testId = props.input.props?.["data-testid"];
954
1932
  const inputProps = {
955
1933
  label,
956
1934
  description,
957
1935
  error,
958
1936
  required,
959
- disabled
1937
+ disabled,
1938
+ ...testId ? { "data-testid": testId } : {}
960
1939
  };
961
1940
  if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
962
1941
  if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
@@ -981,8 +1960,8 @@ const useArrayItems = (input) => {
981
1960
  const alepha = useAlepha();
982
1961
  const keyCounter = useRef(0);
983
1962
  const [items, setItemsState] = useState(() => {
984
- const defaultValue = input?.props?.defaultValue;
985
- if (Array.isArray(defaultValue)) return defaultValue.map((value) => ({
1963
+ const initial = input?.initialValue;
1964
+ if (Array.isArray(initial)) return initial.map((value) => ({
986
1965
  key: keyCounter.current++,
987
1966
  value
988
1967
  }));
@@ -1008,22 +1987,9 @@ const useArrayItems = (input) => {
1008
1987
  if (!input?.form) return;
1009
1988
  const formId = input.form.id;
1010
1989
  const fieldPath = input.path;
1011
- const listeners = [alepha.events.on("form:reset", (event) => {
1012
- if (event.id === formId) {
1013
- const defaultValue = input.props?.defaultValue;
1014
- keyCounter.current = 0;
1015
- if (Array.isArray(defaultValue)) setItemsState(defaultValue.map((value) => ({
1016
- key: keyCounter.current++,
1017
- value
1018
- })));
1019
- else setItemsState([]);
1020
- }
1021
- }), alepha.events.on("form:change", (event) => {
1990
+ return alepha.events.on("form:change", (event) => {
1022
1991
  if (event.id === formId && event.path === fieldPath) syncFromFormValue(event.value);
1023
- })];
1024
- return () => {
1025
- for (const unsub of listeners) unsub();
1026
- };
1992
+ });
1027
1993
  }, [
1028
1994
  alepha,
1029
1995
  input,
@@ -1048,10 +2014,10 @@ const createArrayItemInput = (parentInput, itemSchema, index, _itemKey, value, o
1048
2014
  path: `${parentInput.path}/${index}`,
1049
2015
  required: false,
1050
2016
  form: parentInput.form,
2017
+ initialValue: value,
1051
2018
  props: {
1052
2019
  id: `${parentInput.props.id}-${index}`,
1053
- name: `${parentInput.props.name}[${index}]`,
1054
- defaultValue: value
2020
+ name: `${parentInput.props.name}[${index}]`
1055
2021
  },
1056
2022
  set: onValueChange
1057
2023
  };
@@ -1066,10 +2032,10 @@ const createArrayItemFieldInput = (parentInput, itemSchema, fieldName, index, _i
1066
2032
  path: `${parentInput.path}/${index}/${fieldName}`,
1067
2033
  required: itemSchema.required?.includes(fieldName) ?? false,
1068
2034
  form: parentInput.form,
2035
+ initialValue: itemValue?.[fieldName],
1069
2036
  props: {
1070
2037
  id: `${parentInput.props.id}-${index}-${fieldName}`,
1071
- name: `${parentInput.props.name}[${index}].${fieldName}`,
1072
- defaultValue: itemValue?.[fieldName]
2038
+ name: `${parentInput.props.name}[${index}].${fieldName}`
1073
2039
  },
1074
2040
  set: (value) => onFieldChange(fieldName, value)
1075
2041
  };
@@ -1287,7 +2253,9 @@ const ControlArray = (props) => {
1287
2253
  * Automatically detects date formats from schema and renders appropriate picker.
1288
2254
  */
1289
2255
  const ControlDate = (props) => {
1290
- 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);
1291
2259
  if (!props.input?.props) return null;
1292
2260
  if (props.datetime || format === "date-time") {
1293
2261
  const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
@@ -1295,10 +2263,8 @@ const ControlDate = (props) => {
1295
2263
  ...inputProps,
1296
2264
  id,
1297
2265
  leftSection: icon,
1298
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
1299
- onChange: (value) => {
1300
- props.input.set(value ? new Date(value).toISOString() : void 0);
1301
- },
2266
+ value: value ? new Date(value) : null,
2267
+ onChange: (val) => setValue(val ? new Date(val).toISOString() : void 0),
1302
2268
  ...dateTimePickerProps
1303
2269
  });
1304
2270
  }
@@ -1308,10 +2274,8 @@ const ControlDate = (props) => {
1308
2274
  ...inputProps,
1309
2275
  id,
1310
2276
  leftSection: icon,
1311
- defaultValue: props.input.props.defaultValue ? new Date(props.input.props.defaultValue) : void 0,
1312
- onChange: (value) => {
1313
- props.input.set(value ? new Date(value).toISOString().slice(0, 10) : void 0);
1314
- },
2277
+ value: value ? new Date(value) : null,
2278
+ onChange: (val) => setValue(val ? new Date(val).toISOString().slice(0, 10) : void 0),
1315
2279
  ...dateInputProps
1316
2280
  });
1317
2281
  }
@@ -1321,10 +2285,8 @@ const ControlDate = (props) => {
1321
2285
  ...inputProps,
1322
2286
  id,
1323
2287
  leftSection: icon,
1324
- defaultValue: props.input.props.defaultValue,
1325
- onChange: (event) => {
1326
- props.input.set(event.currentTarget.value);
1327
- },
2288
+ value: value ?? "",
2289
+ onChange: (event) => setValue(event.currentTarget.value),
1328
2290
  ...timeInputProps
1329
2291
  });
1330
2292
  }
@@ -1337,14 +2299,10 @@ const ControlDate = (props) => {
1337
2299
  *
1338
2300
  */
1339
2301
  const ControlNumber = (props) => {
1340
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
1341
- const ref = useRef(null);
1342
- const [value, setValue] = useState(props.input.props.defaultValue);
1343
- useEvents({ "form:reset": (event) => {
1344
- if (event.id === props.input?.form.id && ref.current) setValue(props.input.props.defaultValue);
1345
- } }, [props.input]);
2302
+ const form = useFormState(props.input);
2303
+ const [value, setValue] = useFieldValue(props.input);
2304
+ const { inputProps, id, icon } = parseInput(props, form);
1346
2305
  if (!props.input?.props) return null;
1347
- const { type, ...inputPropsWithoutType } = props.input.props;
1348
2306
  if (props.sliderProps) {
1349
2307
  const min = props.sliderProps.min ?? inputProps.minimum ?? 0;
1350
2308
  const max = props.sliderProps.max ?? inputProps.maximum ?? 100;
@@ -1357,34 +2315,25 @@ const ControlNumber = (props) => {
1357
2315
  },
1358
2316
  children: /* @__PURE__ */ jsx(Slider, {
1359
2317
  ...inputProps,
1360
- ref,
1361
2318
  id,
1362
- ...inputPropsWithoutType,
1363
2319
  ...props.sliderProps,
1364
- value,
2320
+ value: value ?? 0,
1365
2321
  min,
1366
2322
  max,
1367
2323
  label: () => value,
1368
- onChange: (val) => {
1369
- setValue(val);
1370
- props.input.set(val);
1371
- }
2324
+ onChange: (val) => setValue(val)
1372
2325
  })
1373
2326
  })
1374
2327
  });
1375
2328
  }
1376
2329
  return /* @__PURE__ */ jsx(NumberInput, {
1377
2330
  ...inputProps,
1378
- ref,
1379
2331
  id,
1380
2332
  leftSection: icon,
1381
- ...inputPropsWithoutType,
1382
2333
  ...props.numberInputProps,
1383
2334
  value: value ?? "",
1384
2335
  onChange: (val) => {
1385
- const newValue = val !== null ? Number(val) : void 0;
1386
- setValue(newValue);
1387
- props.input.set(newValue);
2336
+ setValue(val !== null ? Number(val) : void 0);
1388
2337
  }
1389
2338
  });
1390
2339
  };
@@ -1467,92 +2416,9 @@ const ControlObject = (props) => {
1467
2416
  };
1468
2417
 
1469
2418
  //#endregion
1470
- //#region ../../src/core/form/components/ControlQueryBuilder.tsx
1471
- /**
1472
- * Query builder with text input and help popover.
1473
- * Generates query strings for parseQueryString syntax.
1474
- */
1475
- const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Enter query or click for assistance...", ...textInputProps }) => {
1476
- const [helpOpened, setHelpOpened] = useState(false);
1477
- const [textValue, setTextValue] = useState(value);
1478
- const inputRef = useRef(null);
1479
- const fields = schema ? extractSchemaFields(schema) : [];
1480
- const [error, setError] = useState(null);
1481
- const isValid = (value) => {
1482
- try {
1483
- parseQueryString(value.trim());
1484
- } catch (e) {
1485
- setError(e.message);
1486
- return false;
1487
- }
1488
- setError(null);
1489
- return true;
1490
- };
1491
- const handleTextChange = (newValue) => {
1492
- setTextValue(newValue);
1493
- if (isValid(newValue)) onChange?.(newValue);
1494
- };
1495
- const handleClear = () => {
1496
- setTextValue("");
1497
- onChange?.("");
1498
- isValid("");
1499
- };
1500
- const handleInsert = (text) => {
1501
- const newValue = textValue ? `${textValue}${text} ` : `${text} `;
1502
- setTextValue(newValue);
1503
- if (isValid(newValue)) onChange?.(newValue);
1504
- setTimeout(() => {
1505
- inputRef.current?.focus();
1506
- const length = inputRef.current?.value.length || 0;
1507
- inputRef.current?.setSelectionRange(length, length);
1508
- }, 0);
1509
- };
1510
- useEvents({ "form:change": (event) => {
1511
- if (event.id === inputRef.current?.form?.id) {
1512
- if (event.path === textInputProps["data-path"]) setTextValue(event.value ?? "");
1513
- }
1514
- } }, []);
1515
- return /* @__PURE__ */ jsxs(Popover, {
1516
- width: 800,
1517
- position: "bottom-start",
1518
- shadow: "md",
1519
- opened: helpOpened,
1520
- onChange: setHelpOpened,
1521
- closeOnClickOutside: true,
1522
- closeOnEscape: true,
1523
- transitionProps: {
1524
- transition: "fade-up",
1525
- duration: 200,
1526
- timingFunction: "ease"
1527
- },
1528
- children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(TextInput, {
1529
- ref: inputRef,
1530
- placeholder,
1531
- value: textValue,
1532
- onChange: (e) => handleTextChange(e.currentTarget.value),
1533
- onFocus: () => setHelpOpened(true),
1534
- leftSection: error ? /* @__PURE__ */ jsx(IconInfoTriangle, { size: 16 }) : /* @__PURE__ */ jsx(IconFilter, { size: 16 }),
1535
- rightSection: textValue && /* @__PURE__ */ jsx(ActionIcon, {
1536
- size: "sm",
1537
- variant: "subtle",
1538
- color: "gray",
1539
- onClick: handleClear,
1540
- children: /* @__PURE__ */ jsx(IconX, { size: 14 })
1541
- }),
1542
- ...textInputProps
1543
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
1544
- bg: "transparent",
1545
- p: "xs",
1546
- bd: `1px solid ${ui.colors.border}`,
1547
- style: { backdropFilter: "blur(20px)" },
1548
- children: /* @__PURE__ */ jsx(QueryHelp, {
1549
- fields,
1550
- onInsert: handleInsert
1551
- })
1552
- })]
1553
- });
1554
- };
1555
- function QueryHelp({ fields, onInsert }) {
2419
+ //#region ../../src/core/form/components/ControlQueryBuilderHelp.tsx
2420
+ const ControlQueryBuilderHelp = (props) => {
2421
+ const { fields, onInsert } = props;
1556
2422
  return /* @__PURE__ */ jsxs(Flex, {
1557
2423
  gap: "md",
1558
2424
  align: "flex-start",
@@ -1715,111 +2581,314 @@ function QueryHelp({ fields, onInsert }) {
1715
2581
  })
1716
2582
  ]
1717
2583
  });
1718
- }
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
+ };
1719
2673
 
1720
2674
  //#endregion
1721
2675
  //#region ../../src/core/form/components/ControlSelect.tsx
1722
2676
  /**
1723
- * ControlSelect component for handling Select, MultiSelect, and TagsInput.
2677
+ * ControlSelect component for handling Select, MultiSelect, Autocomplete, and TagsInput.
1724
2678
  *
1725
2679
  * Features:
1726
2680
  * - Basic Select with enum support
1727
2681
  * - MultiSelect for array of enums
1728
- * - TagsInput for array of strings (no enum)
1729
- * - Future: Lazy loading
1730
- * - Future: Searchable/filterable options
1731
- * - 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
1732
2687
  *
1733
2688
  * Automatically detects enum values and array types from schema.
1734
2689
  */
1735
2690
  const ControlSelect = (props) => {
1736
- 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);
1737
2694
  const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
1738
- let itemsEnum;
1739
- if (isArray && "items" in props.input.schema && props.input.schema.items) {
1740
- const items = props.input.schema.items;
1741
- if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
1742
- }
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";
1743
2697
  const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
1744
- 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);
1745
2701
  useEffect(() => {
1746
- if (!props.input?.props) return;
1747
- if (props.loader) props.loader().then(setData);
1748
- else setData(enumValues);
1749
- }, [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;
1750
2718
  if (!props.input?.props) return null;
1751
- if (props.segmented) {
1752
- 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);
1753
2731
  return /* @__PURE__ */ jsx(Input.Wrapper, {
1754
2732
  ...inputProps,
1755
- children: /* @__PURE__ */ jsx(Flex, { children: /* @__PURE__ */ jsx(SegmentedControl, {
1756
- disabled: inputProps.disabled,
1757
- defaultValue: String(props.input.props.defaultValue),
1758
- ...segmentedControlProps,
1759
- onChange: (value) => {
1760
- props.input.set(value);
1761
- },
1762
- data: data.slice(0, 10)
1763
- }) })
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
+ })
1764
2745
  });
1765
2746
  }
1766
- if (props.autocomplete) {
1767
- const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
1768
- 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, {
1769
2768
  ...inputProps,
1770
- size: props.size,
1771
- id,
1772
- leftSection: icon,
1773
- data,
1774
- ...props.input.props,
1775
- ...autocompleteProps
2769
+ ...sharedProps,
2770
+ ...longModeProps,
2771
+ value: Array.isArray(value) ? value : [],
2772
+ onChange: (val) => {
2773
+ setValue(val);
2774
+ },
2775
+ ...tagsInputExtraProps
1776
2776
  });
1777
2777
  }
1778
- if (isArray && !itemsEnum || props.tags) {
1779
- const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
1780
- return /* @__PURE__ */ jsx(TagsInput, {
2778
+ if (props.creatable) {
2779
+ const autocompleteExtraProps = props.autocompleteProps ?? {};
2780
+ return /* @__PURE__ */ jsx(Autocomplete, {
1781
2781
  ...inputProps,
1782
- size: props.size,
1783
- id,
1784
- leftSection: icon,
1785
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
1786
- onChange: (value) => {
1787
- props.input.set(value);
2782
+ ...sharedProps,
2783
+ ...longModeProps,
2784
+ value: value != null ? String(value) : "",
2785
+ onChange: (val) => {
2786
+ setValue(coerceValue(val));
1788
2787
  },
1789
- ...tagsInputProps
2788
+ ...autocompleteExtraProps
1790
2789
  });
1791
2790
  }
1792
- if (isArray && itemsEnum || props.multi) {
1793
- const data = itemsEnum?.map((value) => ({
1794
- value,
1795
- label: value
1796
- })) || [];
1797
- const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
2791
+ if (isArray || props.multiSelectProps) {
2792
+ const multiSelectExtraProps = typeof props.multiSelectProps === "object" ? props.multiSelectProps : {};
1798
2793
  return /* @__PURE__ */ jsx(MultiSelect, {
1799
2794
  ...inputProps,
1800
- size: props.size,
1801
- id,
1802
- leftSection: icon,
1803
- data,
1804
- defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
1805
- onChange: (value) => {
1806
- props.input.set(value);
2795
+ ...selectableProps,
2796
+ ...longModeProps,
2797
+ value: Array.isArray(value) ? value : [],
2798
+ onChange: (val) => {
2799
+ setValue(val);
1807
2800
  },
1808
- ...multiSelectProps
2801
+ ...multiSelectExtraProps
1809
2802
  });
1810
2803
  }
1811
- 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
+ });
1812
2814
  return /* @__PURE__ */ jsx(Select, {
1813
2815
  ...inputProps,
1814
- size: props.size,
1815
- id,
1816
- leftSection: icon,
1817
- rightSection: null,
1818
- data,
1819
- ...props.input.props,
1820
- ...selectProps
2816
+ ...selectableProps,
2817
+ ...longModeProps,
2818
+ value: value != null ? String(value) : null,
2819
+ onChange: (val) => {
2820
+ setValue(coerceValue(val));
2821
+ },
2822
+ ...selectExtraProps
1821
2823
  });
1822
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
+ };
1823
2892
 
1824
2893
  //#endregion
1825
2894
  //#region ../../src/core/form/components/Control.tsx
@@ -1849,6 +2918,7 @@ const ControlSelect = (props) => {
1849
2918
  */
1850
2919
  const Control = (_props) => {
1851
2920
  const form = useFormState(_props.input, ["error"]);
2921
+ const [value, setValue] = useFieldValue(_props.input);
1852
2922
  if (!_props.input?.props) return null;
1853
2923
  const { inputProps, id, icon, format, schema } = parseInput(_props, form);
1854
2924
  const props = {
@@ -1856,12 +2926,11 @@ const Control = (_props) => {
1856
2926
  ...schema.$control
1857
2927
  };
1858
2928
  if (props.query) return /* @__PURE__ */ jsx(ControlQueryBuilder, {
1859
- ...props.input.props,
1860
2929
  ...inputProps,
1861
2930
  schema: props.query,
1862
- value: props.input.props.value,
1863
- onChange: (value) => {
1864
- props.input.set(value);
2931
+ value,
2932
+ onChange: (val) => {
2933
+ setValue(val);
1865
2934
  }
1866
2935
  });
1867
2936
  if (props.custom) {
@@ -1872,9 +2941,9 @@ const Control = (_props) => {
1872
2941
  flex: 1,
1873
2942
  mt: "calc(var(--mantine-spacing-xs) / 2)",
1874
2943
  children: /* @__PURE__ */ jsx(Custom, {
1875
- defaultValue: props.input.props.defaultValue,
1876
- onChange: (value) => {
1877
- props.input.set(value);
2944
+ value,
2945
+ onChange: (val) => {
2946
+ setValue(val);
1878
2947
  }
1879
2948
  })
1880
2949
  })
@@ -1885,7 +2954,7 @@ const Control = (_props) => {
1885
2954
  const controlObjectProps = typeof props.object === "object" ? props.object : {};
1886
2955
  return /* @__PURE__ */ jsx(ControlObject, {
1887
2956
  input: props.input,
1888
- title: props.title,
2957
+ label: props.label,
1889
2958
  description: props.description,
1890
2959
  ...controlObjectProps
1891
2960
  });
@@ -1896,18 +2965,18 @@ const Control = (_props) => {
1896
2965
  const controlArrayProps = typeof props.array === "object" ? props.array : {};
1897
2966
  return /* @__PURE__ */ jsx(ControlArray, {
1898
2967
  input: props.input,
1899
- title: props.title,
2968
+ label: props.label,
1900
2969
  description: props.description,
1901
2970
  ...controlArrayProps
1902
2971
  });
1903
2972
  }
1904
- 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")) {
1905
2974
  const controlNumberProps = typeof props.number === "object" ? props.number : {};
1906
2975
  if (props.slider) controlNumberProps.sliderProps ??= {};
1907
2976
  return /* @__PURE__ */ jsx(ControlNumber, {
1908
2977
  size: props.size,
1909
2978
  input: props.input,
1910
- title: props.title,
2979
+ label: props.label,
1911
2980
  description: props.description,
1912
2981
  icon,
1913
2982
  ...controlNumberProps
@@ -1920,9 +2989,7 @@ const Control = (_props) => {
1920
2989
  size: props.size,
1921
2990
  id,
1922
2991
  leftSection: icon,
1923
- onChange: (file) => {
1924
- props.input.set(file);
1925
- },
2992
+ onChange: (file) => setValue(file),
1926
2993
  ...fileInputProps
1927
2994
  });
1928
2995
  }
@@ -1933,17 +3000,18 @@ const Control = (_props) => {
1933
3000
  size: props.size,
1934
3001
  id,
1935
3002
  leftSection: icon,
1936
- ...props.input.props,
3003
+ value: value ?? "",
3004
+ onChange: (val) => setValue(val),
1937
3005
  ...colorInputProps
1938
3006
  });
1939
3007
  }
1940
3008
  if (props.input.schema && "enum" in props.input.schema && props.input.schema.enum || isArray && !isArrayOfObjects || props.select) {
1941
3009
  const opts = typeof props.select === "object" ? props.select : {};
1942
- if (props.segmented) opts.segmented ??= {};
3010
+ if (props.segmented) opts.segmentedProps ??= {};
1943
3011
  return /* @__PURE__ */ jsx(ControlSelect, {
1944
3012
  size: props.size,
1945
3013
  input: props.input,
1946
- title: props.title,
3014
+ label: props.label,
1947
3015
  description: props.description,
1948
3016
  icon,
1949
3017
  ...opts
@@ -1957,16 +3025,16 @@ const Control = (_props) => {
1957
3025
  size: props.size,
1958
3026
  id,
1959
3027
  color: "blue",
1960
- defaultChecked: props.input.props.defaultValue,
3028
+ checked: Boolean(value),
1961
3029
  onChange: (event) => {
1962
- props.input.set(event.currentTarget.checked);
3030
+ setValue(event.currentTarget.checked);
1963
3031
  },
1964
3032
  ...switchProps
1965
3033
  });
1966
3034
  }
1967
3035
  const opts = {
1968
3036
  input: props.input,
1969
- select: { data: [{
3037
+ selectProps: { data: [{
1970
3038
  value: "true",
1971
3039
  label: "Yes"
1972
3040
  }, {
@@ -1976,7 +3044,7 @@ const Control = (_props) => {
1976
3044
  };
1977
3045
  return /* @__PURE__ */ jsx(ControlSelect, {
1978
3046
  size: props.size,
1979
- title: props.title,
3047
+ label: props.label,
1980
3048
  description: props.description,
1981
3049
  icon,
1982
3050
  ...opts
@@ -1989,7 +3057,8 @@ const Control = (_props) => {
1989
3057
  size: props.size,
1990
3058
  id,
1991
3059
  leftSection: icon,
1992
- ...props.input.props,
3060
+ value: value ?? "",
3061
+ onChange: (ev) => setValue(ev.target.value),
1993
3062
  ...passwordInputProps
1994
3063
  });
1995
3064
  }
@@ -2000,14 +3069,15 @@ const Control = (_props) => {
2000
3069
  size: props.size,
2001
3070
  id,
2002
3071
  leftSection: icon,
2003
- ...props.input.props,
3072
+ value: value ?? "",
3073
+ onChange: (ev) => setValue(ev.target.value),
2004
3074
  ...textAreaProps
2005
3075
  });
2006
3076
  }
2007
3077
  if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate, {
2008
3078
  size: props.size,
2009
3079
  input: props.input,
2010
- title: props.title,
3080
+ label: props.label,
2011
3081
  description: props.description,
2012
3082
  icon,
2013
3083
  date: props.date,
@@ -2022,7 +3092,7 @@ const Control = (_props) => {
2022
3092
  case "uri": return "url";
2023
3093
  case "tel":
2024
3094
  case "phone": return "tel";
2025
- default: return;
3095
+ default: return props.input.props.type ?? "text";
2026
3096
  }
2027
3097
  };
2028
3098
  return /* @__PURE__ */ jsx(TextInput, {
@@ -2031,26 +3101,12 @@ const Control = (_props) => {
2031
3101
  id,
2032
3102
  leftSection: icon,
2033
3103
  type: getInputType(),
2034
- ...props.input.props,
2035
- ...textInputProps,
2036
- inputWrapperOrder: [
2037
- "label",
2038
- "input",
2039
- "description",
2040
- "error"
2041
- ]
3104
+ value: value ?? "",
3105
+ onChange: (ev) => setValue(ev.target.value),
3106
+ ...textInputProps
2042
3107
  });
2043
3108
  };
2044
3109
 
2045
- //#endregion
2046
- //#region ../../src/core/helpers/renderIcon.tsx
2047
- const renderIcon = (icon, size) => {
2048
- if (!icon) return null;
2049
- if (isValidElement(icon)) return icon;
2050
- if (isComponentType(icon)) return /* @__PURE__ */ jsx(icon, { size: size ?? ui.sizes.icon.md });
2051
- return icon;
2052
- };
2053
-
2054
3110
  //#endregion
2055
3111
  //#region ../../src/core/utils/extractSchemaFields.ts
2056
3112
  /**
@@ -2146,8 +3202,8 @@ const OPERATOR_INFO = {
2146
3202
  * Get the default icon for an input based on its type, format, or name.
2147
3203
  */
2148
3204
  const getDefaultIcon = (params) => {
2149
- const { type, format, name, isEnum, isArray, size = "sm" } = params;
2150
- const iconSize = ui.sizes.icon[size];
3205
+ const { type, format, name, isEnum, isArray, size = "xs" } = params;
3206
+ const iconSize = ui.sizes.icon[size] - 4;
2151
3207
  if (format) switch (format) {
2152
3208
  case "email": return /* @__PURE__ */ jsx(IconMail, { size: iconSize });
2153
3209
  case "url":
@@ -2261,4 +3317,4 @@ const AlephaUI = $module({
2261
3317
 
2262
3318
  //#endregion
2263
3319
  export { ui as a, ActionButton as i, capitalize as n, AlephaMantineProvider as o, Control as r, AlephaUI as t };
2264
- //# sourceMappingURL=core-niW0sFLv.js.map
3320
+ //# sourceMappingURL=core-D5jIAVF2.js.map