@alepha/ui 0.18.2 → 0.18.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/dist/admin/{AdminApiKeys-BJhIwfD6.js → AdminApiKeys-Dy_k-4Vd.js} +2 -2
  2. package/dist/admin/{AdminApiKeys-BJhIwfD6.js.map → AdminApiKeys-Dy_k-4Vd.js.map} +1 -1
  3. package/dist/admin/{AdminAudits-DzD_4cDt.js → AdminAudits-CKiFMSSU.js} +2 -2
  4. package/dist/admin/{AdminAudits-DzD_4cDt.js.map → AdminAudits-CKiFMSSU.js.map} +1 -1
  5. package/dist/admin/{AdminDashboard-C92tIc6x.js → AdminDashboard-PhC_dZqo.js} +2 -2
  6. package/dist/admin/{AdminDashboard-C92tIc6x.js.map → AdminDashboard-PhC_dZqo.js.map} +1 -1
  7. package/dist/admin/{AdminFiles-DLpfhBkf.js → AdminFiles-DFTjijGp.js} +2 -2
  8. package/dist/admin/{AdminFiles-DLpfhBkf.js.map → AdminFiles-DFTjijGp.js.map} +1 -1
  9. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js → AdminJobDashboard-BL8gGPDp.js} +2 -2
  10. package/dist/admin/{AdminJobDashboard-KIOkeMgE.js.map → AdminJobDashboard-BL8gGPDp.js.map} +1 -1
  11. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js → AdminJobExecutions-D9E-CS-U.js} +2 -2
  12. package/dist/admin/{AdminJobExecutions-D0Yo_PU0.js.map → AdminJobExecutions-D9E-CS-U.js.map} +1 -1
  13. package/dist/admin/{AdminJobRegistry-PFajqaGK.js → AdminJobRegistry-Ci9ue1zC.js} +2 -2
  14. package/dist/admin/{AdminJobRegistry-PFajqaGK.js.map → AdminJobRegistry-Ci9ue1zC.js.map} +1 -1
  15. package/dist/admin/{AdminLayout-B1DXZHDn.js → AdminLayout-I6TlUMPc.js} +2 -2
  16. package/dist/admin/{AdminLayout-B1DXZHDn.js.map → AdminLayout-I6TlUMPc.js.map} +1 -1
  17. package/dist/admin/AdminNotifications-ZPHCYrv7.js +542 -0
  18. package/dist/admin/AdminNotifications-ZPHCYrv7.js.map +1 -0
  19. package/dist/admin/{AdminParameters-BspPeqp_.js → AdminParameters-CqgvhRsb.js} +120 -105
  20. package/dist/admin/AdminParameters-CqgvhRsb.js.map +1 -0
  21. package/dist/admin/{AdminSessions-BnH5CZQl.js → AdminSessions-Bz5NRuoW.js} +2 -2
  22. package/dist/admin/{AdminSessions-BnH5CZQl.js.map → AdminSessions-Bz5NRuoW.js.map} +1 -1
  23. package/dist/admin/{AdminUserLayout-DUbC6-BI.js → AdminUserLayout-lXT6I0Qq.js} +14 -8
  24. package/dist/admin/AdminUserLayout-lXT6I0Qq.js.map +1 -0
  25. package/dist/admin/{AdminUserProfile-DuTUnjdG.js → AdminUserProfile-vFBLoJ3h.js} +3 -3
  26. package/dist/admin/{AdminUserProfile-DuTUnjdG.js.map → AdminUserProfile-vFBLoJ3h.js.map} +1 -1
  27. package/dist/admin/{AdminUserSessions-DvZdAGpL.js → AdminUserSessions-CT_YDim0.js} +2 -2
  28. package/dist/admin/{AdminUserSessions-DvZdAGpL.js.map → AdminUserSessions-CT_YDim0.js.map} +1 -1
  29. package/dist/admin/{AdminUsers-CR9z0g_5.js → AdminUsers-D1UfGya9.js} +2 -2
  30. package/dist/admin/{AdminUsers-CR9z0g_5.js.map → AdminUsers-D1UfGya9.js.map} +1 -1
  31. package/dist/admin/{AuthLayout-DsUfp9RG.js → AuthLayout-_frhdgOO.js} +2 -2
  32. package/dist/admin/{AuthLayout-DsUfp9RG.js.map → AuthLayout-_frhdgOO.js.map} +1 -1
  33. package/dist/admin/Login-xtNmQtGh.js +275 -0
  34. package/dist/admin/Login-xtNmQtGh.js.map +1 -0
  35. package/dist/admin/{Profile-B2EcIDB9.js → Profile-_AtPUwAP.js} +31 -27
  36. package/dist/admin/Profile-_AtPUwAP.js.map +1 -0
  37. package/dist/admin/{Register-Z3fxRbUF.js → Register-JcCjHUUn.js} +198 -142
  38. package/dist/admin/Register-JcCjHUUn.js.map +1 -0
  39. package/dist/admin/{ResetPassword-_Y1qTTKh.js → ResetPassword-CwGBPLJO.js} +7 -7
  40. package/dist/admin/ResetPassword-CwGBPLJO.js.map +1 -0
  41. package/dist/admin/{VerifyEmail-Bg22bwcC.js → VerifyEmail-hNxWejWf.js} +23 -8
  42. package/dist/admin/VerifyEmail-hNxWejWf.js.map +1 -0
  43. package/dist/admin/{core-BVO_TQxb.js → core-CYaRQ8O-.js} +709 -556
  44. package/dist/admin/core-CYaRQ8O-.js.map +1 -0
  45. package/dist/admin/index.d.ts +83 -44
  46. package/dist/admin/index.d.ts.map +1 -1
  47. package/dist/admin/index.js +58 -39
  48. package/dist/admin/index.js.map +1 -1
  49. package/dist/auth/{AuthLayout-C161NeF6.js → AuthLayout-AvLlcLjS.js} +2 -2
  50. package/dist/auth/{AuthLayout-C161NeF6.js.map → AuthLayout-AvLlcLjS.js.map} +1 -1
  51. package/dist/auth/Login-BA1E8IZl.js +275 -0
  52. package/dist/auth/Login-BA1E8IZl.js.map +1 -0
  53. package/dist/auth/{Profile-BMpXJ0oi.js → Profile-YcWdeuFz.js} +31 -27
  54. package/dist/auth/Profile-YcWdeuFz.js.map +1 -0
  55. package/dist/auth/{Register-2gx8qll-.js → Register-CPhEO5MG.js} +198 -142
  56. package/dist/auth/Register-CPhEO5MG.js.map +1 -0
  57. package/dist/{demo/ResetPassword-CAPj8MO3.js → auth/ResetPassword-DCtGcneA.js} +7 -7
  58. package/dist/auth/ResetPassword-DCtGcneA.js.map +1 -0
  59. package/dist/{demo/VerifyEmail-DFmdCdYs.js → auth/VerifyEmail-DkH7NBfn.js} +23 -8
  60. package/dist/auth/VerifyEmail-DkH7NBfn.js.map +1 -0
  61. package/dist/auth/{core-DyfeVr5c.js → core-D5jIAVF2.js} +386 -294
  62. package/dist/auth/core-D5jIAVF2.js.map +1 -0
  63. package/dist/auth/index.d.ts +93 -48
  64. package/dist/auth/index.d.ts.map +1 -1
  65. package/dist/auth/index.js +28 -24
  66. package/dist/auth/index.js.map +1 -1
  67. package/dist/core/index.d.ts +116 -61
  68. package/dist/core/index.d.ts.map +1 -1
  69. package/dist/core/index.js +873 -701
  70. package/dist/core/index.js.map +1 -1
  71. package/dist/demo/{AuthLayout-DN-ClJQk.js → AuthLayout-Brri4A-L.js} +2 -2
  72. package/dist/demo/{AuthLayout-DN-ClJQk.js.map → AuthLayout-Brri4A-L.js.map} +1 -1
  73. package/dist/demo/DemoButton-wiCxZZ_L.js +182 -0
  74. package/dist/demo/DemoButton-wiCxZZ_L.js.map +1 -0
  75. package/dist/demo/DemoControlSelect-D7ILObVg.js +305 -0
  76. package/dist/demo/DemoControlSelect-D7ILObVg.js.map +1 -0
  77. package/dist/demo/DemoDataTable-DZ5Y8pFX.js +362 -0
  78. package/dist/demo/DemoDataTable-DZ5Y8pFX.js.map +1 -0
  79. package/dist/demo/{DemoDialog-DW8QEvD1.js → DemoDialog-CUWdLHim.js} +2 -2
  80. package/dist/demo/{DemoDialog-DW8QEvD1.js.map → DemoDialog-CUWdLHim.js.map} +1 -1
  81. package/dist/demo/{DemoFlex-CAhLUanT.js → DemoFlex-a8OhMMvq.js} +3 -3
  82. package/dist/demo/{DemoFlex-CAhLUanT.js.map → DemoFlex-a8OhMMvq.js.map} +1 -1
  83. package/dist/demo/{DemoHeading-yIFmNjHB.js → DemoHeading-C13OVDfS.js} +3 -3
  84. package/dist/demo/{DemoHeading-yIFmNjHB.js.map → DemoHeading-C13OVDfS.js.map} +1 -1
  85. package/dist/demo/{DemoHome-BSGuBHus.js → DemoHome-D_De3UiT.js} +2 -2
  86. package/dist/demo/{DemoHome-BSGuBHus.js.map → DemoHome-D_De3UiT.js.map} +1 -1
  87. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js → DemoJsonViewer-B50s9aGM.js} +3 -3
  88. package/dist/demo/{DemoJsonViewer-DsA2IpgV.js.map → DemoJsonViewer-B50s9aGM.js.map} +1 -1
  89. package/dist/demo/{DemoLayout-Cy6xjn6P.js → DemoLayout-CHU8WTwO.js} +14 -5
  90. package/dist/demo/DemoLayout-CHU8WTwO.js.map +1 -0
  91. package/dist/demo/{DemoLogin-vqxgTu4P.js → DemoLogin-BBlrWpml.js} +49 -32
  92. package/dist/demo/DemoLogin-BBlrWpml.js.map +1 -0
  93. package/dist/demo/{DemoRegister-YHPvPg77.js → DemoRegister-BuNE3_-f.js} +49 -50
  94. package/dist/demo/DemoRegister-BuNE3_-f.js.map +1 -0
  95. package/dist/demo/{DemoResetPassword-mOW18Zlm.js → DemoResetPassword-D_IjjjOJ.js} +12 -16
  96. package/dist/demo/DemoResetPassword-D_IjjjOJ.js.map +1 -0
  97. package/dist/demo/{DemoSidebar-od7aLjP_.js → DemoSidebar-Giy2HRBD.js} +3 -3
  98. package/dist/demo/{DemoSidebar-od7aLjP_.js.map → DemoSidebar-Giy2HRBD.js.map} +1 -1
  99. package/dist/demo/{DemoText-DU3JeRS0.js → DemoText-ubcw-vog.js} +3 -3
  100. package/dist/demo/{DemoText-DU3JeRS0.js.map → DemoText-ubcw-vog.js.map} +1 -1
  101. package/dist/demo/{DemoToast-CUJEiPRa.js → DemoToast-9die_dYT.js} +2 -2
  102. package/dist/demo/{DemoToast-CUJEiPRa.js.map → DemoToast-9die_dYT.js.map} +1 -1
  103. package/dist/demo/{DemoTypeForm-C1dNkahD.js → DemoTypeForm-D_d6OVKL.js} +8 -4
  104. package/dist/demo/DemoTypeForm-D_d6OVKL.js.map +1 -0
  105. package/dist/demo/DemoVerifyEmail-B43KlF4F.js +34 -0
  106. package/dist/demo/DemoVerifyEmail-B43KlF4F.js.map +1 -0
  107. package/dist/demo/Login-C12N4oGs.js +275 -0
  108. package/dist/demo/Login-C12N4oGs.js.map +1 -0
  109. package/dist/demo/{Profile-BE_Y3co2.js → Profile-DS5q4vOh.js} +31 -27
  110. package/dist/demo/Profile-DS5q4vOh.js.map +1 -0
  111. package/dist/demo/{Register-fXHmBpr3.js → Register-B4hLBeEv.js} +198 -142
  112. package/dist/demo/Register-B4hLBeEv.js.map +1 -0
  113. package/dist/{auth/ResetPassword-DBxt9hKk.js → demo/ResetPassword-D8g9ha1N.js} +7 -7
  114. package/dist/demo/ResetPassword-D8g9ha1N.js.map +1 -0
  115. package/dist/demo/{Showcase-BtEU0pY9.js → Showcase-D6Fxt4X4.js} +64 -65
  116. package/dist/demo/Showcase-D6Fxt4X4.js.map +1 -0
  117. package/dist/{auth/VerifyEmail-Z80Ubajk.js → demo/VerifyEmail-BjDo0cZA.js} +23 -8
  118. package/dist/demo/VerifyEmail-BjDo0cZA.js.map +1 -0
  119. package/dist/demo/{auth-Djd7SKiw.js → auth-ByVTreDl.js} +8 -8
  120. package/dist/demo/{auth-Djd7SKiw.js.map → auth-ByVTreDl.js.map} +1 -1
  121. package/dist/demo/{core-B7LNjM78.js → core-DFgB3yU4.js} +741 -573
  122. package/dist/demo/core-DFgB3yU4.js.map +1 -0
  123. package/dist/demo/index.d.ts +1 -0
  124. package/dist/demo/index.d.ts.map +1 -1
  125. package/dist/demo/index.js +24 -18
  126. package/dist/demo/index.js.map +1 -1
  127. package/package.json +7 -7
  128. package/src/admin/AdminRouter.tsx +24 -1
  129. package/src/admin/components/notifications/AdminNotifications.tsx +519 -0
  130. package/src/admin/components/parameters/ParameterDetails.tsx +12 -270
  131. package/src/admin/components/parameters/ParameterDetailsConfigForm.tsx +238 -0
  132. package/src/admin/components/parameters/ParameterDetailsLoading.tsx +24 -0
  133. package/src/admin/components/parameters/ParameterHistory.tsx +10 -11
  134. package/src/admin/components/parameters/ParameterTree.tsx +28 -184
  135. package/src/admin/components/parameters/ParameterTreeNode.tsx +151 -0
  136. package/src/admin/components/shared/AdminResourceHeader.tsx +2 -25
  137. package/src/admin/components/shared/AdminResourceHeaderMenuItem.tsx +37 -0
  138. package/src/admin/components/shared/AdminResourceTabs.tsx +2 -26
  139. package/src/admin/components/shared/AdminResourceTabsItem.tsx +36 -0
  140. package/src/auth/components/Login.tsx +188 -121
  141. package/src/auth/components/Profile.tsx +1 -22
  142. package/src/auth/components/ProfileField.tsx +39 -0
  143. package/src/auth/components/Register.tsx +215 -158
  144. package/src/auth/components/ResetPassword.tsx +7 -11
  145. package/src/auth/components/VerifyEmail.tsx +35 -10
  146. package/src/auth/components/buttons/UserButton.tsx +19 -21
  147. package/src/auth/index.ts +1 -0
  148. package/src/core/components/Flex.tsx +10 -0
  149. package/src/core/components/buttons/ActionButton.tsx +104 -78
  150. package/src/core/components/data/DetailDrawer.tsx +102 -96
  151. package/src/core/components/data/DetailList.tsx +2 -1
  152. package/src/core/components/layout/Breadcrumb.tsx +3 -6
  153. package/src/core/components/layout/DashboardShell.tsx +18 -4
  154. package/src/core/components/layout/Sidebar.tsx +16 -241
  155. package/src/core/components/layout/SidebarCollapsedItem.tsx +91 -0
  156. package/src/core/components/layout/SidebarItem.tsx +146 -0
  157. package/src/core/components/layout/index.ts +3 -1
  158. package/src/core/form/components/Control.tsx +31 -29
  159. package/src/core/form/components/ControlArray.tsx +13 -39
  160. package/src/core/form/components/ControlDate.tsx +10 -21
  161. package/src/core/form/components/ControlNumber.tsx +4 -33
  162. package/src/core/form/components/ControlQueryBuilder.tsx +12 -175
  163. package/src/core/form/components/ControlQueryBuilderHelp.tsx +165 -0
  164. package/src/core/form/components/ControlSelect.browser.spec.tsx +343 -0
  165. package/src/core/form/components/ControlSelect.tsx +294 -92
  166. package/src/core/form/components/TypeForm.browser.spec.tsx +3 -3
  167. package/src/core/form/components/TypeForm.tsx +5 -2
  168. package/src/core/form/index.ts +8 -1
  169. package/src/core/form/utils/parseInput.ts +7 -3
  170. package/src/core/index.ts +3 -1
  171. package/src/core/json/components/JsonViewer.tsx +103 -319
  172. package/src/core/json/components/JsonViewerCopyButton.tsx +46 -0
  173. package/src/core/json/components/JsonViewerRowNode.tsx +120 -0
  174. package/src/core/json/components/JsonViewerShared.ts +76 -0
  175. package/src/core/styles.css +12 -2
  176. package/src/core/table/components/ColumnPicker.tsx +3 -3
  177. package/src/core/table/components/DataTable.tsx +89 -29
  178. package/src/core/table/components/DataTableFilters.tsx +6 -11
  179. package/src/core/table/components/DataTablePagination.tsx +9 -3
  180. package/src/core/table/components/DataTableToolbar.tsx +7 -3
  181. package/src/core/table/components/FilterPicker.tsx +3 -3
  182. package/src/core/table/interfaces/types.ts +29 -0
  183. package/src/core/utils/icons.tsx +2 -2
  184. package/src/demo/DemoRouter.ts +8 -1
  185. package/src/demo/components/DemoLayout.tsx +12 -2
  186. package/src/demo/components/auth/DemoLogin.tsx +35 -28
  187. package/src/demo/components/auth/DemoRegister.tsx +35 -49
  188. package/src/demo/components/auth/DemoResetPassword.tsx +5 -9
  189. package/src/demo/components/auth/DemoVerifyEmail.tsx +7 -6
  190. package/src/demo/components/core/DemoButton.tsx +123 -103
  191. package/src/demo/components/core/DemoControlSelect.tsx +325 -0
  192. package/src/demo/components/core/DemoDataTable.tsx +255 -237
  193. package/src/demo/components/core/DemoTypeForm.tsx +7 -2
  194. package/src/demo/components/shared/MacWindow.tsx +5 -11
  195. package/src/demo/components/shared/Showcase.tsx +28 -42
  196. package/dist/admin/AdminParameters-BspPeqp_.js.map +0 -1
  197. package/dist/admin/AdminUserLayout-DUbC6-BI.js.map +0 -1
  198. package/dist/admin/Login-DHbYJKwg.js +0 -219
  199. package/dist/admin/Login-DHbYJKwg.js.map +0 -1
  200. package/dist/admin/Profile-B2EcIDB9.js.map +0 -1
  201. package/dist/admin/Register-Z3fxRbUF.js.map +0 -1
  202. package/dist/admin/ResetPassword-_Y1qTTKh.js.map +0 -1
  203. package/dist/admin/VerifyEmail-Bg22bwcC.js.map +0 -1
  204. package/dist/admin/core-BVO_TQxb.js.map +0 -1
  205. package/dist/auth/Login-C7jIqf00.js +0 -219
  206. package/dist/auth/Login-C7jIqf00.js.map +0 -1
  207. package/dist/auth/Profile-BMpXJ0oi.js.map +0 -1
  208. package/dist/auth/Register-2gx8qll-.js.map +0 -1
  209. package/dist/auth/ResetPassword-DBxt9hKk.js.map +0 -1
  210. package/dist/auth/VerifyEmail-Z80Ubajk.js.map +0 -1
  211. package/dist/auth/core-DyfeVr5c.js.map +0 -1
  212. package/dist/demo/DemoButton-CGUyR9eM.js +0 -178
  213. package/dist/demo/DemoButton-CGUyR9eM.js.map +0 -1
  214. package/dist/demo/DemoDataTable-QFG-xXSx.js +0 -358
  215. package/dist/demo/DemoDataTable-QFG-xXSx.js.map +0 -1
  216. package/dist/demo/DemoLayout-Cy6xjn6P.js.map +0 -1
  217. package/dist/demo/DemoLogin-vqxgTu4P.js.map +0 -1
  218. package/dist/demo/DemoRegister-YHPvPg77.js.map +0 -1
  219. package/dist/demo/DemoResetPassword-mOW18Zlm.js.map +0 -1
  220. package/dist/demo/DemoTypeForm-C1dNkahD.js.map +0 -1
  221. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js +0 -30
  222. package/dist/demo/DemoVerifyEmail-D9EcXZ38.js.map +0 -1
  223. package/dist/demo/Login-CoYf_P_F.js +0 -219
  224. package/dist/demo/Login-CoYf_P_F.js.map +0 -1
  225. package/dist/demo/Profile-BE_Y3co2.js.map +0 -1
  226. package/dist/demo/Register-fXHmBpr3.js.map +0 -1
  227. package/dist/demo/ResetPassword-CAPj8MO3.js.map +0 -1
  228. package/dist/demo/Showcase-BtEU0pY9.js.map +0 -1
  229. package/dist/demo/VerifyEmail-DFmdCdYs.js.map +0 -1
  230. package/dist/demo/core-B7LNjM78.js.map +0 -1
  231. package/src/demo/styles.css +0 -0
@@ -111,9 +111,19 @@
111
111
  }
112
112
 
113
113
  /* ------------------------------------------------------------------------------------------------------------------ */
114
- /* Modal Customizations */
114
+ /* our custom "minimal" variant for <Button/> - from Blueprint */
115
+ .mantine-Button-root[data-variant="minimal"] {
116
+ background-color: transparent;
117
+ color: var(--mantine-color-text);
118
+ }
119
+
120
+ .mantine-Button-root[data-variant="minimal"]:hover {
121
+ /* imitate the hover effect of <Table/> rows */
122
+ background-color: light-dark(rgba(0, 0, 0, 0.08), rgba(255, 255, 255, 0.1));
123
+ }
124
+
125
+ /* ------------------------------------------------------------------------------------------------------------------ */
115
126
 
116
- /* Custom modal scale animation */
117
127
  @keyframes modalScaleIn {
118
128
  from {
119
129
  opacity: 0;
@@ -76,7 +76,7 @@ const ColumnPicker = <T extends object, Filters extends TObject>({
76
76
  <Popover.Target>
77
77
  <div>
78
78
  <ActionButton
79
- variant="subtle"
79
+ variant={"minimal"}
80
80
  icon={IconColumns}
81
81
  onClick={() => setOpened((o) => !o)}
82
82
  />
@@ -104,14 +104,14 @@ const ColumnPicker = <T extends object, Filters extends TObject>({
104
104
  <Flex gap={4}>
105
105
  <ActionButton
106
106
  size="compact-xs"
107
- variant="subtle"
107
+ variant={"minimal"}
108
108
  onClick={handleShowAll}
109
109
  >
110
110
  All
111
111
  </ActionButton>
112
112
  <ActionButton
113
113
  size="compact-xs"
114
- variant="subtle"
114
+ variant={"minimal"}
115
115
  onClick={handleDefault}
116
116
  >
117
117
  Default
@@ -1,5 +1,5 @@
1
1
  import { ActionButton, Flex, isComponentType, Text, ui } from "@alepha/ui";
2
- import { Checkbox, Drawer, Table, UnstyledButton } from "@mantine/core";
2
+ import { Checkbox, Drawer, Loader, Table, UnstyledButton } from "@mantine/core";
3
3
  import {
4
4
  IconArrowDown,
5
5
  IconArrowsSort,
@@ -98,13 +98,19 @@ const DataTable = <T extends object, Filters extends TObject>(
98
98
  const [items, setItems] = useState<MaybePage<T>>(
99
99
  typeof props.items === "function" ? { content: [] } : props.items,
100
100
  );
101
+ const itemsRef = useRef(items);
102
+ const [loaded, setLoaded] = useState(
103
+ typeof props.items !== "function" || !props.submitOnInit,
104
+ );
101
105
 
102
- const defaultSize = props.infinityScroll ? 100 : props.defaultSize || 10;
106
+ const defaultSize = props.defaultSize || (props.infinityScroll ? 100 : 10);
103
107
  const [page, setPage] = useState(1);
104
108
  const [size, setSize] = useState(String(defaultSize));
105
109
  const [currentPage, setCurrentPage] = useState(0);
106
110
  const alepha = useInject(Alepha);
111
+ itemsRef.current = items;
107
112
  const sentinelRef = useRef<HTMLDivElement>(null);
113
+ const debounceRef = useRef<ReturnType<typeof setTimeout> | null>(null);
108
114
 
109
115
  // Column visibility state
110
116
  const [columnVisibility, setColumnVisibility] = useState<ColumnVisibility>(
@@ -221,7 +227,7 @@ const DataTable = <T extends object, Filters extends TObject>(
221
227
  sort?: string;
222
228
  },
223
229
  {
224
- items: items.content,
230
+ items: itemsRef.current.content,
225
231
  },
226
232
  );
227
233
 
@@ -236,6 +242,7 @@ const DataTable = <T extends object, Filters extends TObject>(
236
242
  }
237
243
 
238
244
  setCurrentPage(values.page);
245
+ if (!loaded) setLoaded(true);
239
246
  }
240
247
  },
241
248
  onReset: async () => {
@@ -261,13 +268,33 @@ const DataTable = <T extends object, Filters extends TObject>(
261
268
  value,
262
269
  form as unknown as FormModel<Filters>,
263
270
  );
271
+
272
+ if (props.skipSubmitOnChange) return;
273
+
274
+ form.input.page.set(0);
275
+
276
+ const delay = props.debounce ?? 300;
277
+ if (delay > 0) {
278
+ if (debounceRef.current) clearTimeout(debounceRef.current);
279
+ debounceRef.current = setTimeout(() => {
280
+ form.submit();
281
+ }, delay);
282
+ } else {
283
+ await form.submit();
284
+ }
264
285
  },
265
286
  },
266
- [items],
287
+ [],
267
288
  );
268
289
 
269
290
  const dt = useInject(DateTimeProvider);
270
291
 
292
+ useEffect(() => {
293
+ return () => {
294
+ if (debounceRef.current) clearTimeout(debounceRef.current);
295
+ };
296
+ }, []);
297
+
271
298
  useEffect(() => {
272
299
  if (props.submitOnInit) {
273
300
  form.submit();
@@ -358,9 +385,9 @@ const DataTable = <T extends object, Filters extends TObject>(
358
385
  </Text>
359
386
  {col.sortable && (
360
387
  <Flex c="dimmed">
361
- {sortDir === "asc" && <IconArrowUp size={ui.sizes.icon.sm} />}
362
- {sortDir === "desc" && <IconArrowDown size={ui.sizes.icon.sm} />}
363
- {sortDir === null && <IconArrowsSort size={ui.sizes.icon.sm} />}
388
+ {sortDir === "asc" && <IconArrowUp size={ui.sizes.icon.xs} />}
389
+ {sortDir === "desc" && <IconArrowDown size={ui.sizes.icon.xs} />}
390
+ {sortDir === null && <IconArrowsSort size={ui.sizes.icon.xs} />}
364
391
  </Flex>
365
392
  )}
366
393
  </Flex>
@@ -428,9 +455,21 @@ const DataTable = <T extends object, Filters extends TObject>(
428
455
  alepha,
429
456
  } as DataTableColumnContext<Filters>;
430
457
 
458
+ const content = col.value?.(item as T, ctx);
459
+
431
460
  return (
432
461
  <Table.Td key={key} style={col.fit ? FIT_STYLE : undefined}>
433
- {col.value?.(item as T, ctx)}
462
+ {col.action ? (
463
+ <ActionButton
464
+ td={"inherit"}
465
+ unstyled
466
+ {...col.action(item as T)}
467
+ >
468
+ {content}
469
+ </ActionButton>
470
+ ) : (
471
+ content
472
+ )}
434
473
  </Table.Td>
435
474
  );
436
475
  })}
@@ -453,7 +492,7 @@ const DataTable = <T extends object, Filters extends TObject>(
453
492
  onClick={(e) => e.stopPropagation()}
454
493
  >
455
494
  <ActionButton
456
- variant="subtle"
495
+ variant={"minimal"}
457
496
  size="xs"
458
497
  icon={IconDotsVertical}
459
498
  menu={{
@@ -471,7 +510,14 @@ const DataTable = <T extends object, Filters extends TObject>(
471
510
  ) : (
472
511
  (Icon as ReactNode)
473
512
  ),
474
- onClick: (action as any).onClick,
513
+ onClick: (action as any).onClick
514
+ ? async () => {
515
+ await (action as any).onClick();
516
+ if (!action.skipRefresh) {
517
+ await form.submit();
518
+ }
519
+ }
520
+ : undefined,
475
521
  color: action.color,
476
522
  };
477
523
  }),
@@ -538,8 +584,16 @@ const DataTable = <T extends object, Filters extends TObject>(
538
584
  )}
539
585
  </Flex>
540
586
 
541
- <Flex col rounded bordered elevated shadowed={"xs"}>
542
- <Flex className="overflow-auto">
587
+ <Flex
588
+ col
589
+ rounded
590
+ bordered
591
+ elevated
592
+ shadowed={"xs"}
593
+ flex={1}
594
+ style={{ minHeight: 0 }}
595
+ >
596
+ <Flex className="overflow-auto" flex={1} style={{ minHeight: 0 }} col>
543
597
  <Table
544
598
  aria-label="Data table"
545
599
  withRowBorders
@@ -547,10 +601,12 @@ const DataTable = <T extends object, Filters extends TObject>(
547
601
  {...props.tableProps}
548
602
  >
549
603
  <Table.Thead
604
+ bdrs={"md"}
550
605
  style={{
551
606
  position: "sticky",
552
607
  top: 0,
553
608
  zIndex: 1,
609
+ backgroundColor: "var(--alepha-elevated)",
554
610
  }}
555
611
  >
556
612
  <Table.Tr>
@@ -560,25 +616,27 @@ const DataTable = <T extends object, Filters extends TObject>(
560
616
  {props.rowActions && <Table.Th style={FIT_STYLE} />}
561
617
  </Table.Tr>
562
618
  </Table.Thead>
563
- <Table.Tbody
564
- style={{
565
- opacity: form.submitting ? 0.5 : 1,
566
- transition: "opacity 150ms ease",
567
- }}
568
- >
569
- {rows}
570
- {items.content.length === 0 && (
619
+ <Table.Tbody>
620
+ {!loaded || form.submitting ? (
621
+ <Table.Tr>
622
+ <Table.Td colSpan={totalColumns || 1} py="sm">
623
+ <Flex justify="center" p={"md"}>
624
+ <Loader size="sm" type="dots" />
625
+ </Flex>
626
+ </Table.Td>
627
+ </Table.Tr>
628
+ ) : rows.length === 0 ? (
571
629
  <Table.Tr>
572
- <Table.Td
573
- colSpan={totalColumns || 1}
574
- py="xl"
575
- style={{ textAlign: "center" }}
576
- >
577
- <Text c="dimmed" size="sm">
578
- {form.submitting ? "Loading…" : "No results"}
579
- </Text>
630
+ <Table.Td colSpan={totalColumns || 1} py="xl">
631
+ <Flex justify="center">
632
+ <Text c="dimmed" size="sm">
633
+ {props.emptyLabel ?? "No results"}
634
+ </Text>
635
+ </Flex>
580
636
  </Table.Td>
581
637
  </Table.Tr>
638
+ ) : (
639
+ rows
582
640
  )}
583
641
  </Table.Tbody>
584
642
  </Table>
@@ -590,8 +648,10 @@ const DataTable = <T extends object, Filters extends TObject>(
590
648
  <DataTablePagination
591
649
  page={page}
592
650
  size={size}
593
- totalPages={items.page?.totalPages ?? 1}
651
+ totalPages={items.page?.totalPages}
594
652
  totalElements={items.page?.totalElements}
653
+ isFirst={items.page?.isFirst}
654
+ isLast={items.page?.isLast}
595
655
  offset={items.page?.offset ?? 0}
596
656
  numberOfElements={items.content.length}
597
657
  onPageChange={(value) => {
@@ -1,5 +1,4 @@
1
- import { ui } from "@alepha/ui";
2
- import { Flex } from "@mantine/core";
1
+ import { Flex } from "@alepha/ui";
3
2
  import { type TObject, t } from "alepha";
4
3
  import type { FormModel } from "alepha/react/form";
5
4
  import { useMemo } from "react";
@@ -16,12 +15,9 @@ export interface DataTableFiltersProps {
16
15
  filterVisibility: FilterVisibility;
17
16
  }
18
17
 
19
- const DataTableFilters = ({
20
- schema,
21
- form,
22
- typeFormProps,
23
- filterVisibility,
24
- }: DataTableFiltersProps) => {
18
+ const DataTableFilters = (props: DataTableFiltersProps) => {
19
+ const { schema, form, typeFormProps, filterVisibility } = props;
20
+
25
21
  const visibleSchema = useMemo(() => {
26
22
  const visibleKeys = Object.keys(schema.properties).filter(
27
23
  (key) => filterVisibility[key] !== false,
@@ -47,9 +43,8 @@ const DataTableFilters = ({
47
43
  }
48
44
 
49
45
  return (
50
- <Flex w="100%" p="xs" m="xs" bdrs="md" bg={ui.colors.surface}>
46
+ <Flex surface flex={1} mt={-4} p="xs" m="xs" bdrs="md">
51
47
  <TypeForm
52
- size={"xs"}
53
48
  {...typeFormProps}
54
49
  skipSubmitButton
55
50
  fill
@@ -60,7 +55,7 @@ const DataTableFilters = ({
60
55
  sm: 2,
61
56
  md: 3,
62
57
  lg: 4,
63
- xl: 6,
58
+ xl: 5,
64
59
  }}
65
60
  />
66
61
  </Flex>
@@ -4,8 +4,10 @@ import { Pagination, Select } from "@mantine/core";
4
4
  export interface DataTablePaginationProps {
5
5
  page: number;
6
6
  size: string;
7
- totalPages: number;
7
+ totalPages?: number;
8
8
  totalElements?: number;
9
+ isFirst?: boolean;
10
+ isLast?: boolean;
9
11
  offset: number;
10
12
  numberOfElements: number;
11
13
  onPageChange: (page: number) => void;
@@ -17,6 +19,8 @@ const DataTablePagination = ({
17
19
  size,
18
20
  totalPages,
19
21
  totalElements,
22
+ isFirst,
23
+ isLast,
20
24
  offset,
21
25
  numberOfElements,
22
26
  onPageChange,
@@ -24,6 +28,7 @@ const DataTablePagination = ({
24
28
  }: DataTablePaginationProps) => {
25
29
  const from = numberOfElements > 0 ? offset + 1 : 0;
26
30
  const to = offset + numberOfElements;
31
+ const hasTotal = totalPages != null;
27
32
 
28
33
  return (
29
34
  <Flex
@@ -68,8 +73,9 @@ const DataTablePagination = ({
68
73
  <Flex>
69
74
  <Pagination
70
75
  size={"sm"}
71
- withEdges
72
- total={totalPages}
76
+ withEdges={hasTotal}
77
+ withPages={hasTotal}
78
+ total={hasTotal ? totalPages : isLast !== false ? page : page + 1}
73
79
  value={page}
74
80
  onChange={onPageChange}
75
81
  />
@@ -151,7 +151,7 @@ const DataTableToolbar = <T extends object, Filters extends TObject>({
151
151
  />
152
152
  {withExport && (
153
153
  <ActionButton
154
- variant="subtle"
154
+ variant={"minimal"}
155
155
  icon={IconDownload}
156
156
  menu={{
157
157
  items: [
@@ -177,7 +177,7 @@ const DataTableToolbar = <T extends object, Filters extends TObject>({
177
177
  {selectedItems.length} selected
178
178
  </Badge>
179
179
  <ActionButton
180
- variant="subtle"
180
+ variant={"minimal"}
181
181
  size="compact-sm"
182
182
  icon={IconX}
183
183
  onClick={onClearSelection}
@@ -214,7 +214,11 @@ const DataTableToolbar = <T extends object, Filters extends TObject>({
214
214
  props
215
215
  ),
216
216
  )}
217
- <ActionButton variant="subtle" icon={IconRefresh} onClick={onRefresh} />
217
+ <ActionButton
218
+ variant={"minimal"}
219
+ icon={IconRefresh}
220
+ onClick={onRefresh}
221
+ />
218
222
  </Flex>
219
223
  </Flex>
220
224
  );
@@ -74,7 +74,7 @@ const FilterPicker = ({
74
74
  <Popover.Target>
75
75
  <div>
76
76
  <ActionButton
77
- variant="subtle"
77
+ variant={"minimal"}
78
78
  icon={IconFilter}
79
79
  onClick={() => setOpened((o) => !o)}
80
80
  />
@@ -102,14 +102,14 @@ const FilterPicker = ({
102
102
  <Flex gap={4}>
103
103
  <ActionButton
104
104
  size="compact-xs"
105
- variant="subtle"
105
+ variant={"minimal"}
106
106
  onClick={handleShowAll}
107
107
  >
108
108
  All
109
109
  </ActionButton>
110
110
  <ActionButton
111
111
  size="compact-xs"
112
- variant="subtle"
112
+ variant={"minimal"}
113
113
  onClick={handleHideAll}
114
114
  >
115
115
  None
@@ -29,6 +29,11 @@ export type DataTableRowAction = ActionProps & {
29
29
  */
30
30
  label?: string;
31
31
  visible?: boolean;
32
+ /**
33
+ * When true, skip the automatic table refresh after a successful onClick.
34
+ * By default, the table re-fetches data after every row action completes.
35
+ */
36
+ skipRefresh?: boolean;
32
37
  };
33
38
 
34
39
  // -----------------------------------------------------------------------------
@@ -70,6 +75,11 @@ export interface DataTableColumn<T extends object, Filters extends TObject> {
70
75
  * Hide this column by default. Users can show it via the column picker.
71
76
  */
72
77
  defaultHidden?: boolean;
78
+ /**
79
+ * Wrap the cell content with an ActionButton. Defaults to `variant="unstyled"`.
80
+ * Receives the row item to generate per-row action props (e.g., dynamic href).
81
+ */
82
+ action?: (item: T) => ActionProps;
73
83
  }
74
84
 
75
85
  // -----------------------------------------------------------------------------
@@ -136,6 +146,20 @@ export interface DataTableProps<T extends object, Filters extends TObject> {
136
146
  form: FormModel<Filters>,
137
147
  ) => void;
138
148
 
149
+ /**
150
+ * Skip auto-submit when filter values change.
151
+ * When true, filters update form state but do not trigger a refetch.
152
+ * The user must manually refresh (e.g. via the toolbar refresh button).
153
+ */
154
+ skipSubmitOnChange?: boolean;
155
+
156
+ /**
157
+ * Debounce delay in milliseconds for filter auto-submit.
158
+ * Defaults to 300ms. Set to 0 to disable debounce.
159
+ * Ignored when skipSubmitOnChange is true.
160
+ */
161
+ debounce?: number;
162
+
139
163
  /**
140
164
  * Optional filters to apply to the data.
141
165
  */
@@ -206,6 +230,11 @@ export interface DataTableProps<T extends object, Filters extends TObject> {
206
230
  // Mantine Props
207
231
  // -------------------------------------------------------------------------------------------------------------------
208
232
 
233
+ /**
234
+ * Label shown when the table has no results. Defaults to "No results".
235
+ */
236
+ emptyLabel?: string;
237
+
209
238
  /**
210
239
  * Props to pass to the Mantine Table component.
211
240
  */
@@ -31,8 +31,8 @@ export const getDefaultIcon = (params: {
31
31
  isArray?: boolean;
32
32
  size?: IconSize;
33
33
  }): ReactElement => {
34
- const { type, format, name, isEnum, isArray, size = "sm" } = params;
35
- const iconSize = ui.sizes.icon[size];
34
+ const { type, format, name, isEnum, isArray, size = "xs" } = params;
35
+ const iconSize = ui.sizes.icon[size] - 4; // TODO: better mapping
36
36
 
37
37
  // Format-based icons (highest priority)
38
38
  if (format) {
@@ -121,7 +121,7 @@ export class DemoRouter {
121
121
  icon: IconForms,
122
122
  path: "/form",
123
123
  label: "Form",
124
- children: () => [this.demoTypeForm],
124
+ children: () => [this.demoTypeForm, this.demoControlSelect],
125
125
  });
126
126
 
127
127
  demoTypeForm = $page({
@@ -131,6 +131,13 @@ export class DemoRouter {
131
131
  lazy: () => import("./components/core/DemoTypeForm.tsx"),
132
132
  });
133
133
 
134
+ demoControlSelect = $page({
135
+ icon: IconForms,
136
+ path: "/control-select",
137
+ label: "ControlSelect",
138
+ lazy: () => import("./components/core/DemoControlSelect.tsx"),
139
+ });
140
+
134
141
  // Table Components
135
142
  demoTable = $page({
136
143
  icon: IconTable,
@@ -13,12 +13,14 @@ const DemoLayout = () => {
13
13
  return (
14
14
  <AlephaMantineProvider>
15
15
  <DashboardShell
16
+ fill
16
17
  appShellProps={{
17
18
  withBorder: false,
18
19
  bg: ui.colors.background,
19
20
  }}
20
21
  appShellHeaderProps={{
21
22
  bg: "transparent",
23
+ style: { backdropFilter: "blur(10px)" },
22
24
  }}
23
25
  appBarProps={{
24
26
  items: [
@@ -58,7 +60,10 @@ const DemoLayout = () => {
58
60
  },
59
61
  {
60
62
  ...router.node("demoForm"),
61
- children: [router.node("demoTypeForm")],
63
+ children: [
64
+ router.node("demoTypeForm"),
65
+ router.node("demoControlSelect"),
66
+ ],
62
67
  },
63
68
  {
64
69
  ...router.node("demoTable"),
@@ -70,7 +75,12 @@ const DemoLayout = () => {
70
75
  },
71
76
  {
72
77
  ...router.node("demoAuth"),
73
- children: [router.node("demoLogin"), router.node("demoRegister")],
78
+ children: [
79
+ router.node("demoLogin"),
80
+ router.node("demoRegister"),
81
+ router.node("demoResetPassword"),
82
+ router.node("demoVerifyEmail"),
83
+ ],
74
84
  },
75
85
  {
76
86
  position: "bottom",
@@ -1,9 +1,14 @@
1
1
  import { Login } from "@alepha/ui/auth";
2
2
  import { t } from "alepha";
3
- import type { RealmConfig } from "alepha/api/users";
3
+ import type { FieldRequirement, RealmConfig } from "alepha/api/users";
4
4
  import Showcase from "../shared/Showcase.tsx";
5
5
 
6
6
  const showcaseSchema = t.object({
7
+ variant: t.string({
8
+ title: "Variant",
9
+ default: "card",
10
+ enum: ["card", "split"],
11
+ }),
7
12
  showCredentials: t.boolean({
8
13
  title: "Credentials",
9
14
  default: true,
@@ -19,20 +24,20 @@ const showcaseSchema = t.object({
19
24
  default: false,
20
25
  $control: { switch: true },
21
26
  }),
22
- usernameEnabled: t.boolean({
23
- title: "Username Login",
24
- default: true,
25
- $control: { switch: true },
27
+ username: t.string({
28
+ title: "Username",
29
+ default: "optional",
30
+ enum: ["none", "optional", "required"],
26
31
  }),
27
- emailEnabled: t.boolean({
28
- title: "Email Login",
29
- default: true,
30
- $control: { switch: true },
32
+ email: t.string({
33
+ title: "Email",
34
+ default: "optional",
35
+ enum: ["none", "optional", "required"],
31
36
  }),
32
- phoneEnabled: t.boolean({
33
- title: "Phone Login",
34
- default: false,
35
- $control: { switch: true },
37
+ phoneNumber: t.string({
38
+ title: "Phone Number",
39
+ default: "none",
40
+ enum: ["none", "optional", "required"],
36
41
  }),
37
42
  registrationAllowed: t.boolean({
38
43
  title: "Show Sign Up",
@@ -55,9 +60,9 @@ const buildRealmConfig = (props: {
55
60
  showCredentials: boolean;
56
61
  showGoogleOAuth: boolean;
57
62
  showGithubOAuth: boolean;
58
- usernameEnabled: boolean;
59
- emailEnabled: boolean;
60
- phoneEnabled: boolean;
63
+ username: string;
64
+ email: string;
65
+ phoneNumber: string;
61
66
  registrationAllowed: boolean;
62
67
  resetPasswordAllowed: boolean;
63
68
  showBranding: boolean;
@@ -82,17 +87,13 @@ const buildRealmConfig = (props: {
82
87
  description: props.showBranding ? "Sign in to continue" : undefined,
83
88
  logoUrl: undefined,
84
89
  registrationAllowed: props.registrationAllowed,
85
- emailEnabled: props.emailEnabled,
86
- emailRequired: false,
87
- usernameEnabled: props.usernameEnabled,
90
+ email: props.email as FieldRequirement,
91
+ username: props.username as FieldRequirement,
88
92
  usernameRegExp: "^[a-zA-Z0-9_]{3,30}$",
89
- usernameRequired: false,
90
- phoneEnabled: props.phoneEnabled,
91
- phoneRequired: false,
93
+ phoneNumber: props.phoneNumber as FieldRequirement,
92
94
  verifyEmailRequired: false,
93
95
  verifyPhoneRequired: false,
94
- firstNameLastNameEnabled: false,
95
- firstNameLastNameRequired: false,
96
+ firstNameLastName: "none" as FieldRequirement,
96
97
  resetPasswordAllowed: props.resetPasswordAllowed,
97
98
  adminEmails: [],
98
99
  adminUsernames: [],
@@ -113,19 +114,25 @@ const DemoLogin = () => {
113
114
  title="Login"
114
115
  schema={showcaseSchema}
115
116
  initialValues={{
117
+ variant: "card",
116
118
  showCredentials: true,
117
119
  showGoogleOAuth: true,
118
120
  showGithubOAuth: false,
119
- usernameEnabled: true,
120
- emailEnabled: true,
121
- phoneEnabled: false,
121
+ username: "optional",
122
+ email: "optional",
123
+ phoneNumber: "none",
122
124
  registrationAllowed: true,
123
125
  resetPasswordAllowed: true,
124
126
  showBranding: true,
125
127
  }}
126
128
  columns={1}
127
129
  >
128
- {(props) => <Login realmConfig={buildRealmConfig(props)} />}
130
+ {(props) => (
131
+ <Login
132
+ realmConfig={buildRealmConfig(props)}
133
+ variant={props.variant as "card" | "split"}
134
+ />
135
+ )}
129
136
  </Showcase>
130
137
  );
131
138
  };