@alepha/ui 0.16.1 → 0.17.0

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 (218) hide show
  1. package/dist/admin/{AdminApiKeys-GMORg-1l.js → AdminApiKeys-CF_qOO3u.js} +20 -19
  2. package/dist/admin/AdminApiKeys-CF_qOO3u.js.map +1 -0
  3. package/dist/admin/{AdminAudits-pkWrjq1Z.js → AdminAudits-BQno3hZG.js} +7 -7
  4. package/dist/admin/AdminAudits-BQno3hZG.js.map +1 -0
  5. package/dist/admin/{AdminFiles-WeQbsCsl.js → AdminFiles-kvuUaASF.js} +3 -4
  6. package/dist/admin/{AdminFiles-WeQbsCsl.js.map → AdminFiles-kvuUaASF.js.map} +1 -1
  7. package/dist/admin/AdminJobDashboard-CrPxp0W1.js +485 -0
  8. package/dist/admin/AdminJobDashboard-CrPxp0W1.js.map +1 -0
  9. package/dist/admin/AdminJobExecutions-D-b4Zt7W.js +678 -0
  10. package/dist/admin/AdminJobExecutions-D-b4Zt7W.js.map +1 -0
  11. package/dist/admin/AdminJobRegistry-CNX5cpDx.js +301 -0
  12. package/dist/admin/AdminJobRegistry-CNX5cpDx.js.map +1 -0
  13. package/dist/admin/{AdminLayout-BqZiXx4H.js → AdminLayout-e-ZP5nWw.js} +6 -9
  14. package/dist/admin/AdminLayout-e-ZP5nWw.js.map +1 -0
  15. package/dist/admin/{AdminNotifications-Ds5Un0NJ.js → AdminNotifications-DeHJFf6W.js} +3 -4
  16. package/dist/admin/{AdminNotifications-Ds5Un0NJ.js.map → AdminNotifications-DeHJFf6W.js.map} +1 -1
  17. package/dist/admin/AdminParameters-iQE8o7a7.js +774 -0
  18. package/dist/admin/AdminParameters-iQE8o7a7.js.map +1 -0
  19. package/dist/admin/{AdminSessions-DzIOxM3b.js → AdminSessions-oKJCbd7w.js} +5 -6
  20. package/dist/admin/AdminSessions-oKJCbd7w.js.map +1 -0
  21. package/dist/admin/{AdminUserAudits-CiUPN2BC.js → AdminUserAudits-BNCEle_E.js} +6 -7
  22. package/dist/admin/AdminUserAudits-BNCEle_E.js.map +1 -0
  23. package/dist/admin/{AdminUserCreate-BwQKr4xE.js → AdminUserCreate-CgqeFwCt.js} +6 -6
  24. package/dist/admin/AdminUserCreate-CgqeFwCt.js.map +1 -0
  25. package/dist/admin/{AdminUserDetails-uqtC5aJ1.js → AdminUserDetails-DDe1A1GP.js} +30 -28
  26. package/dist/admin/AdminUserDetails-DDe1A1GP.js.map +1 -0
  27. package/dist/admin/{AdminUserLayout-CiPay35T.js → AdminUserLayout-HAlobhWf.js} +20 -19
  28. package/dist/admin/AdminUserLayout-HAlobhWf.js.map +1 -0
  29. package/dist/admin/{AdminUserSessions-DAE8Nf1F.js → AdminUserSessions-Bq1LnVLf.js} +5 -6
  30. package/dist/admin/AdminUserSessions-Bq1LnVLf.js.map +1 -0
  31. package/dist/admin/{AdminUserSettings-EbahaV2a.js → AdminUserSettings-BRsBZoxV.js} +10 -9
  32. package/dist/admin/AdminUserSettings-BRsBZoxV.js.map +1 -0
  33. package/dist/admin/{AdminUsers-Dcjh0KNW.js → AdminUsers-D71kIOSn.js} +6 -7
  34. package/dist/admin/AdminUsers-D71kIOSn.js.map +1 -0
  35. package/dist/admin/index.d.ts +21 -85
  36. package/dist/admin/index.d.ts.map +1 -1
  37. package/dist/admin/index.js +66 -88
  38. package/dist/admin/index.js.map +1 -1
  39. package/dist/auth/{AuthLayout-Dj5K4SIN.js → AuthLayout-CdJcrPs4.js} +2 -3
  40. package/dist/auth/{AuthLayout-Dj5K4SIN.js.map → AuthLayout-CdJcrPs4.js.map} +1 -1
  41. package/dist/{demo/IconGoogle-CbBF8Hqq.js → auth/IconGoogle-Bm18QD2q.js} +2 -4
  42. package/dist/auth/{IconGoogle-DpSlPZ1u.js.map → IconGoogle-Bm18QD2q.js.map} +1 -1
  43. package/dist/auth/{Login-BBqTosqZ.js → Login-BS_FYTy0.js} +19 -13
  44. package/dist/auth/Login-BS_FYTy0.js.map +1 -0
  45. package/dist/auth/{Profile-Bxj8Nwom.js → Profile-CjDsW378.js} +17 -12
  46. package/dist/auth/Profile-CjDsW378.js.map +1 -0
  47. package/dist/auth/{Register-Ce675Crg.js → Register-C5eqzAaD.js} +27 -17
  48. package/dist/auth/Register-C5eqzAaD.js.map +1 -0
  49. package/dist/auth/{ResetPassword-DWdt7c40.js → ResetPassword-XifinVao.js} +17 -10
  50. package/dist/auth/ResetPassword-XifinVao.js.map +1 -0
  51. package/dist/auth/{VerifyEmail-CI4JwByV.js → VerifyEmail-DTgbeJOO.js} +9 -6
  52. package/dist/auth/VerifyEmail-DTgbeJOO.js.map +1 -0
  53. package/dist/auth/index.d.ts +18 -14
  54. package/dist/auth/index.d.ts.map +1 -1
  55. package/dist/auth/index.js +19 -18
  56. package/dist/auth/index.js.map +1 -1
  57. package/dist/auth/rolldown-runtime-CjeV3_4I.js +18 -0
  58. package/dist/core/index.d.ts +182 -92
  59. package/dist/core/index.d.ts.map +1 -1
  60. package/dist/core/index.js +789 -476
  61. package/dist/core/index.js.map +1 -1
  62. package/dist/demo/DemoDataTable-lnBKWBf8.js +362 -0
  63. package/dist/demo/DemoDataTable-lnBKWBf8.js.map +1 -0
  64. package/dist/demo/{DemoHome-Cce2bWmg.js → DemoHome-CUMZsYaH.js} +6 -6
  65. package/dist/demo/DemoHome-CUMZsYaH.js.map +1 -0
  66. package/dist/demo/{DemoJsonViewer-Dgdk3Txb.js → DemoJsonViewer-_uokbGaW.js} +18 -19
  67. package/dist/demo/DemoJsonViewer-_uokbGaW.js.map +1 -0
  68. package/dist/demo/{DemoLayout-B20TEuhV.js → DemoLayout-DHVoacE6.js} +4 -5
  69. package/dist/demo/DemoLayout-DHVoacE6.js.map +1 -0
  70. package/dist/demo/{DemoLogin-CvCG2WVh.js → DemoLogin-DjJ9314c.js} +27 -24
  71. package/dist/demo/DemoLogin-DjJ9314c.js.map +1 -0
  72. package/dist/demo/{DemoRegister-CmeHbOAs.js → DemoRegister-DzkJ5M83.js} +39 -32
  73. package/dist/demo/DemoRegister-DzkJ5M83.js.map +1 -0
  74. package/dist/demo/{DemoResetPassword-CKO5iA_6.js → DemoResetPassword-DWh4_BpQ.js} +30 -26
  75. package/dist/demo/DemoResetPassword-DWh4_BpQ.js.map +1 -0
  76. package/dist/demo/{DemoSidebar-MVmQKfMt.js → DemoSidebar-C1csnGhX.js} +4 -5
  77. package/dist/demo/DemoSidebar-C1csnGhX.js.map +1 -0
  78. package/dist/demo/{DemoTypeForm-w-qtfRlC.js → DemoTypeForm-CWz6fJrJ.js} +4 -5
  79. package/dist/demo/DemoTypeForm-CWz6fJrJ.js.map +1 -0
  80. package/dist/demo/{DemoVerifyEmail-C8FFJT5A.js → DemoVerifyEmail-DbU_tCj8.js} +16 -16
  81. package/dist/demo/DemoVerifyEmail-DbU_tCj8.js.map +1 -0
  82. package/dist/{auth/IconGoogle-DpSlPZ1u.js → demo/IconGoogle-Ch1m3Uzl.js} +2 -4
  83. package/dist/demo/{IconGoogle-CbBF8Hqq.js.map → IconGoogle-Ch1m3Uzl.js.map} +1 -1
  84. package/dist/demo/{Showcase-CQrMWars.js → Showcase-BzoXNlCn.js} +11 -13
  85. package/dist/demo/Showcase-BzoXNlCn.js.map +1 -0
  86. package/dist/demo/index.d.ts +3 -70
  87. package/dist/demo/index.d.ts.map +1 -1
  88. package/dist/demo/index.js +11 -15
  89. package/dist/demo/index.js.map +1 -1
  90. package/dist/json/index.js +2 -2
  91. package/dist/json/index.js.map +1 -1
  92. package/package.json +11 -5
  93. package/src/admin/AdminRouter.ts +51 -29
  94. package/src/admin/components/AdminLayout.tsx +6 -9
  95. package/src/admin/components/audits/AdminAudits.tsx +5 -5
  96. package/src/admin/components/jobs/AdminJobDashboard.tsx +455 -0
  97. package/src/admin/components/jobs/AdminJobExecutions.tsx +693 -0
  98. package/src/admin/components/jobs/AdminJobRegistry.tsx +325 -0
  99. package/src/admin/components/keys/AdminApiKeys.tsx +28 -31
  100. package/src/admin/components/parameters/AdminParameters.tsx +156 -78
  101. package/src/admin/components/parameters/ParameterDetails.tsx +173 -108
  102. package/src/admin/components/parameters/ParameterEmptyState.tsx +27 -0
  103. package/src/admin/components/parameters/ParameterHistory.tsx +22 -35
  104. package/src/admin/components/parameters/ParameterTree.tsx +283 -109
  105. package/src/admin/components/parameters/types.ts +3 -3
  106. package/src/admin/components/sessions/AdminSessions.tsx +3 -3
  107. package/src/admin/components/shared/AdminResourceHeader.tsx +20 -16
  108. package/src/admin/components/users/AdminUserAudits.tsx +5 -5
  109. package/src/admin/components/users/AdminUserCreate.tsx +3 -3
  110. package/src/admin/components/users/AdminUserDetails.tsx +51 -53
  111. package/src/admin/components/users/AdminUserLayout.tsx +7 -7
  112. package/src/admin/components/users/AdminUserSessions.tsx +3 -3
  113. package/src/admin/components/users/AdminUserSettings.tsx +9 -9
  114. package/src/admin/components/users/AdminUsers.tsx +5 -5
  115. package/src/admin/components/verifications/AdminVerifications.tsx +3 -3
  116. package/src/admin/index.ts +0 -24
  117. package/src/admin/primitives/$uiAdmin.ts +2 -2
  118. package/src/auth/AuthRouter.ts +1 -0
  119. package/src/auth/components/Login.tsx +13 -13
  120. package/src/auth/components/Profile.tsx +17 -26
  121. package/src/auth/components/Register.tsx +21 -31
  122. package/src/auth/components/ResetPassword.tsx +13 -22
  123. package/src/auth/components/VerifyEmail.tsx +5 -5
  124. package/src/auth/components/buttons/UserButton.tsx +14 -4
  125. package/src/core/components/buttons/ActionButton.tsx +13 -17
  126. package/src/core/components/buttons/DarkModeButton.tsx +8 -4
  127. package/src/core/components/buttons/ToggleSidebarButton.tsx +3 -5
  128. package/src/core/components/data/ErrorViewer.tsx +15 -15
  129. package/src/core/components/dialogs/AlertDialog.tsx +3 -3
  130. package/src/core/components/dialogs/ConfirmDialog.tsx +3 -3
  131. package/src/core/components/dialogs/PromptDialog.tsx +3 -3
  132. package/src/core/components/form/Control.tsx +19 -32
  133. package/src/core/components/form/ControlArray.tsx +206 -96
  134. package/src/core/components/form/ControlObject.tsx +3 -3
  135. package/src/core/components/form/ControlQueryBuilder.tsx +20 -22
  136. package/src/core/components/form/ControlSelect.tsx +4 -0
  137. package/src/core/components/form/TypeForm.browser.spec.tsx +727 -0
  138. package/src/core/components/form/TypeForm.tsx +7 -0
  139. package/src/core/components/layout/AlephaMantineProvider.tsx +1 -0
  140. package/src/core/components/layout/Breadcrumb.tsx +91 -0
  141. package/src/core/components/layout/{AdminShell.tsx → DashboardShell.tsx} +77 -32
  142. package/src/core/components/layout/Omnibar.tsx +2 -1
  143. package/src/core/components/layout/Sidebar.tsx +63 -19
  144. package/src/core/components/table/ColumnPicker.tsx +47 -31
  145. package/src/core/components/table/DataTable.tsx +277 -201
  146. package/src/core/components/table/DataTableFilters.tsx +8 -0
  147. package/src/core/components/table/DataTableToolbar.tsx +98 -5
  148. package/src/core/components/table/FilterPicker.tsx +28 -26
  149. package/src/core/components/table/types.ts +52 -37
  150. package/src/core/components/table/useTableSelection.ts +83 -0
  151. package/src/core/constants/ui.ts +1 -1
  152. package/src/core/helpers/renderIcon.tsx +5 -2
  153. package/src/core/index.ts +9 -5
  154. package/src/core/styles.css +8 -7
  155. package/src/core/utils/parseInput.ts +1 -0
  156. package/src/core/utils/string.ts +28 -4
  157. package/src/demo/components/DemoHome.tsx +5 -5
  158. package/src/demo/components/DemoLayout.tsx +6 -2
  159. package/src/demo/components/core/DemoDataTable.tsx +209 -5
  160. package/src/demo/components/json/DemoJsonViewer.tsx +1 -1
  161. package/src/demo/components/shared/MacWindow.tsx +7 -7
  162. package/src/demo/components/shared/Showcase.tsx +3 -3
  163. package/src/demo/index.ts +0 -11
  164. package/src/json/components/JsonViewer.tsx +3 -3
  165. package/dist/admin/AdminApiKeys-DsmGnHNh.js +0 -3
  166. package/dist/admin/AdminApiKeys-GMORg-1l.js.map +0 -1
  167. package/dist/admin/AdminAudits-8SM96viT.js +0 -3
  168. package/dist/admin/AdminAudits-pkWrjq1Z.js.map +0 -1
  169. package/dist/admin/AdminFiles-B56ocq4H.js +0 -3
  170. package/dist/admin/AdminJobs-B-q9iGO3.js +0 -697
  171. package/dist/admin/AdminJobs-B-q9iGO3.js.map +0 -1
  172. package/dist/admin/AdminJobs-CED1syCn.js +0 -3
  173. package/dist/admin/AdminLayout-BqZiXx4H.js.map +0 -1
  174. package/dist/admin/AdminNotifications-B0B1rdc4.js +0 -3
  175. package/dist/admin/AdminParameters-BU3lATdJ.js +0 -3
  176. package/dist/admin/AdminParameters-CfDUpc78.js +0 -575
  177. package/dist/admin/AdminParameters-CfDUpc78.js.map +0 -1
  178. package/dist/admin/AdminSessions-BDGK2MS6.js +0 -3
  179. package/dist/admin/AdminSessions-DzIOxM3b.js.map +0 -1
  180. package/dist/admin/AdminUserAudits-CiUPN2BC.js.map +0 -1
  181. package/dist/admin/AdminUserAudits-Cj79gENT.js +0 -3
  182. package/dist/admin/AdminUserCreate-BwQKr4xE.js.map +0 -1
  183. package/dist/admin/AdminUserCreate-Cq-mUmBs.js +0 -3
  184. package/dist/admin/AdminUserDetails-DRjVAPFd.js +0 -3
  185. package/dist/admin/AdminUserDetails-uqtC5aJ1.js.map +0 -1
  186. package/dist/admin/AdminUserLayout-CGzmHHby.js +0 -3
  187. package/dist/admin/AdminUserLayout-CiPay35T.js.map +0 -1
  188. package/dist/admin/AdminUserSessions-DAE8Nf1F.js.map +0 -1
  189. package/dist/admin/AdminUserSessions-DcdzuNZ9.js +0 -3
  190. package/dist/admin/AdminUserSettings-D7V6-ceX.js +0 -3
  191. package/dist/admin/AdminUserSettings-EbahaV2a.js.map +0 -1
  192. package/dist/admin/AdminUsers-D9nyzGqQ.js +0 -3
  193. package/dist/admin/AdminUsers-Dcjh0KNW.js.map +0 -1
  194. package/dist/auth/Login-BBqTosqZ.js.map +0 -1
  195. package/dist/auth/Login-CoU63mMR.js +0 -4
  196. package/dist/auth/Profile-Bxj8Nwom.js.map +0 -1
  197. package/dist/auth/Register-BV_oa_AK.js +0 -4
  198. package/dist/auth/Register-Ce675Crg.js.map +0 -1
  199. package/dist/auth/ResetPassword-D5wC8GAA.js +0 -3
  200. package/dist/auth/ResetPassword-DWdt7c40.js.map +0 -1
  201. package/dist/auth/VerifyEmail-CI4JwByV.js.map +0 -1
  202. package/dist/auth/VerifyEmail-DAfqVm5s.js +0 -3
  203. package/dist/demo/DemoDataTable-CguplbR7.js +0 -150
  204. package/dist/demo/DemoDataTable-CguplbR7.js.map +0 -1
  205. package/dist/demo/DemoHome-Cce2bWmg.js.map +0 -1
  206. package/dist/demo/DemoHome-DC9qkMNe.js +0 -3
  207. package/dist/demo/DemoJsonViewer-DIssGVlJ.js +0 -4
  208. package/dist/demo/DemoJsonViewer-Dgdk3Txb.js.map +0 -1
  209. package/dist/demo/DemoLayout-B20TEuhV.js.map +0 -1
  210. package/dist/demo/DemoLayout-DSRyf4qJ.js +0 -3
  211. package/dist/demo/DemoLogin-CvCG2WVh.js.map +0 -1
  212. package/dist/demo/DemoRegister-CmeHbOAs.js.map +0 -1
  213. package/dist/demo/DemoResetPassword-CKO5iA_6.js.map +0 -1
  214. package/dist/demo/DemoSidebar-MVmQKfMt.js.map +0 -1
  215. package/dist/demo/DemoTypeForm-w-qtfRlC.js.map +0 -1
  216. package/dist/demo/DemoVerifyEmail-C8FFJT5A.js.map +0 -1
  217. package/dist/demo/Showcase-CQrMWars.js.map +0 -1
  218. package/src/admin/components/jobs/AdminJobs.tsx +0 -772
@@ -1,11 +1,11 @@
1
- import type { AdminShellProps } from "@alepha/ui";
1
+ import type { DashboardShellProps } from "@alepha/ui";
2
2
  import { $context } from "alepha";
3
3
  import { AdminRouter } from "../AdminRouter.ts";
4
4
 
5
5
  /**
6
6
  * Register Admin UI components and get the AdminRouter instance.
7
7
  */
8
- export const $uiAdmin = (optsFn?: (a: AdminRouter) => AdminShellProps) => {
8
+ export const $uiAdmin = (optsFn?: (a: AdminRouter) => DashboardShellProps) => {
9
9
  const { alepha } = $context();
10
10
  const adminRouter = alepha.inject(AdminRouter);
11
11
 
@@ -27,6 +27,7 @@ export class AuthRouter {
27
27
  protected readonly auth = $inject(ReactAuth);
28
28
 
29
29
  authLayout = $page({
30
+ label: "Auth",
30
31
  path: "/auth",
31
32
  lazy: () => import("./components/AuthLayout.tsx"),
32
33
  children: () => [
@@ -1,5 +1,5 @@
1
1
  import { ActionButton, Control, capitalize } from "@alepha/ui";
2
- import { Card, Flex, Group, Image, Stack, Text, Title } from "@mantine/core";
2
+ import { Card, Flex, Image, Text, Title } from "@mantine/core";
3
3
  import { IconLock, IconUser } from "@tabler/icons-react";
4
4
  import { AlephaError, t } from "alepha";
5
5
  import type { RealmConfig } from "alepha/api/users";
@@ -115,14 +115,14 @@ const Login = (props: LoginProps) => {
115
115
 
116
116
  return (
117
117
  <Flex flex={1} justify={"center"} align={"center"}>
118
- <Stack gap={"sm"} w={360}>
118
+ <Flex direction="column" gap={"sm"} w={360}>
119
119
  <Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
120
- <Stack gap={"md"}>
120
+ <Flex direction="column" gap={"md"}>
121
121
  {/* Realm branding */}
122
122
  {(settings.logoUrl ||
123
123
  settings.displayName ||
124
124
  settings.description) && (
125
- <Stack gap={"xs"} align="center" mb="xs">
125
+ <Flex direction="column" gap={"xs"} align="center" mb="xs">
126
126
  {settings.logoUrl && (
127
127
  <Image
128
128
  src={settings.logoUrl}
@@ -142,14 +142,14 @@ const Login = (props: LoginProps) => {
142
142
  {settings.description}
143
143
  </Text>
144
144
  )}
145
- </Stack>
145
+ </Flex>
146
146
  )}
147
147
 
148
148
  {/* Credentials login form */}
149
149
  {credentialsProvider && (
150
150
  <>
151
151
  <form {...form.props}>
152
- <Stack flex={1} gap={"md"}>
152
+ <Flex direction="column" flex={1} gap={"md"}>
153
153
  <Control
154
154
  title={identifierTitle}
155
155
  input={form.input.identifier}
@@ -169,7 +169,7 @@ const Login = (props: LoginProps) => {
169
169
  <ActionButton variant={"filled"} form={form}>
170
170
  {tr("loginSignIn")}
171
171
  </ActionButton>
172
- </Stack>
172
+ </Flex>
173
173
  </form>
174
174
  {settings.resetPasswordAllowed && (
175
175
  <Text size="sm" ta="center">
@@ -188,18 +188,18 @@ const Login = (props: LoginProps) => {
188
188
 
189
189
  {/* OR divider - only when both credentials AND external methods exist */}
190
190
  {showOrDivider && (
191
- <Group align="center" justify="center" gap={"md"}>
191
+ <Flex align="center" justify="center" gap={"md"}>
192
192
  <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
193
193
  <Text size="xs" c={"dimmed"}>
194
194
  {tr("loginOr")}
195
195
  </Text>
196
196
  <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
197
- </Group>
197
+ </Flex>
198
198
  )}
199
199
 
200
200
  {/* External login methods */}
201
201
  {externalLoginMethods.length > 0 && (
202
- <Stack gap={"sm"}>
202
+ <Flex direction="column" gap={"sm"}>
203
203
  {externalLoginMethods.map((method) => (
204
204
  <ActionButton
205
205
  variant={"default"}
@@ -217,7 +217,7 @@ const Login = (props: LoginProps) => {
217
217
  })}
218
218
  </ActionButton>
219
219
  ))}
220
- </Stack>
220
+ </Flex>
221
221
  )}
222
222
 
223
223
  {/* Registration link */}
@@ -234,12 +234,12 @@ const Login = (props: LoginProps) => {
234
234
  </ActionButton>
235
235
  </Text>
236
236
  )}
237
- </Stack>
237
+ </Flex>
238
238
  </Card>
239
239
  <ActionButton variant={"subtle"} href={"/"}>
240
240
  {tr("loginCancel")}
241
241
  </ActionButton>
242
- </Stack>
242
+ </Flex>
243
243
  </Flex>
244
244
  );
245
245
  };
@@ -1,14 +1,5 @@
1
1
  import { ActionButton } from "@alepha/ui";
2
- import {
3
- Avatar,
4
- Badge,
5
- Card,
6
- Flex,
7
- Group,
8
- Stack,
9
- Text,
10
- Title,
11
- } from "@mantine/core";
2
+ import { Avatar, Badge, Card, Flex, Text, Title } from "@mantine/core";
12
3
  import {
13
4
  IconAt,
14
5
  IconCalendar,
@@ -35,9 +26,9 @@ const Profile = () => {
35
26
 
36
27
  return (
37
28
  <Flex flex={1} justify="center" align="center">
38
- <Stack gap="md" w={400}>
29
+ <Flex direction="column" gap="md" w={400}>
39
30
  <Card withBorder p="xl" bg="var(--alepha-elevated)">
40
- <Stack gap="lg">
31
+ <Flex direction="column" gap="lg">
41
32
  {/* Avatar and name */}
42
33
  <Flex direction="column" align="center" gap="md">
43
34
  <Avatar
@@ -48,18 +39,18 @@ const Profile = () => {
48
39
  >
49
40
  {!picture && <IconUser size={48} />}
50
41
  </Avatar>
51
- <Stack gap={4} align="center">
42
+ <Flex direction="column" gap={4} align="center">
52
43
  <Title order={3}>{displayName}</Title>
53
44
  {email && username && (
54
45
  <Text size="sm" c="dimmed">
55
46
  @{username}
56
47
  </Text>
57
48
  )}
58
- </Stack>
49
+ </Flex>
59
50
  </Flex>
60
51
 
61
52
  {/* User details */}
62
- <Stack gap="sm">
53
+ <Flex direction="column" gap="sm">
63
54
  {email && (
64
55
  <ProfileField icon={<IconAt size={18} />} label="Email">
65
56
  {email}
@@ -83,13 +74,13 @@ const Profile = () => {
83
74
  {/* Roles */}
84
75
  {roles && roles.length > 0 && (
85
76
  <ProfileField icon={<IconShield size={18} />} label="Roles">
86
- <Group gap="xs">
77
+ <Flex gap="xs">
87
78
  {roles.map((role) => (
88
79
  <Badge key={role} size="sm" variant="light">
89
80
  {role}
90
81
  </Badge>
91
82
  ))}
92
- </Group>
83
+ </Flex>
93
84
  </ProfileField>
94
85
  )}
95
86
 
@@ -99,19 +90,19 @@ const Profile = () => {
99
90
  icon={<IconCalendar size={18} />}
100
91
  label="Organizations"
101
92
  >
102
- <Group gap="xs">
93
+ <Flex gap="xs">
103
94
  {organizations.map((org) => (
104
95
  <Badge key={org} size="sm" variant="outline">
105
96
  {org}
106
97
  </Badge>
107
98
  ))}
108
- </Group>
99
+ </Flex>
109
100
  </ProfileField>
110
101
  )}
111
- </Stack>
102
+ </Flex>
112
103
 
113
104
  {/* Actions */}
114
- <Stack gap="sm" mt="md">
105
+ <Flex direction="column" gap="sm" mt="md">
115
106
  <ActionButton
116
107
  variant="light"
117
108
  color="red"
@@ -120,14 +111,14 @@ const Profile = () => {
120
111
  >
121
112
  Sign out
122
113
  </ActionButton>
123
- </Stack>
124
- </Stack>
114
+ </Flex>
115
+ </Flex>
125
116
  </Card>
126
117
 
127
118
  <ActionButton variant="subtle" href="/">
128
119
  Back to home
129
120
  </ActionButton>
130
- </Stack>
121
+ </Flex>
131
122
  </Flex>
132
123
  );
133
124
  };
@@ -144,12 +135,12 @@ const ProfileField = ({ icon, label, children }: ProfileFieldProps) => {
144
135
  <Flex c="dimmed" mt={2}>
145
136
  {icon}
146
137
  </Flex>
147
- <Stack gap={2} flex={1}>
138
+ <Flex direction="column" gap={2} flex={1}>
148
139
  <Text size="xs" c="dimmed" tt="uppercase" fw={500}>
149
140
  {label}
150
141
  </Text>
151
142
  <Text size="sm">{children}</Text>
152
- </Stack>
143
+ </Flex>
153
144
  </Flex>
154
145
  );
155
146
  };
@@ -1,15 +1,5 @@
1
1
  import { ActionButton, Control, capitalize } from "@alepha/ui";
2
- import {
3
- Alert,
4
- Card,
5
- Flex,
6
- Group,
7
- Image,
8
- PinInput,
9
- Stack,
10
- Text,
11
- Title,
12
- } from "@mantine/core";
2
+ import { Alert, Card, Flex, Image, PinInput, Text, Title } from "@mantine/core";
13
3
  import {
14
4
  IconAlertCircle,
15
5
  IconLock,
@@ -222,9 +212,9 @@ const Register = (props: RegisterProps) => {
222
212
  if (registrationState.phase === "verification" && registrationState.intent) {
223
213
  return (
224
214
  <Flex flex={1} justify={"center"} align={"center"}>
225
- <Stack gap={"sm"} w={360}>
215
+ <Flex direction="column" gap={"sm"} w={360}>
226
216
  <Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
227
- <Stack gap={"md"}>
217
+ <Flex direction="column" gap={"md"}>
228
218
  <Text size="lg" fw={500} ta="center">
229
219
  {tr("registerVerifyTitle") ?? "Verify your account"}
230
220
  </Text>
@@ -240,7 +230,7 @@ const Register = (props: RegisterProps) => {
240
230
  )}
241
231
 
242
232
  {registrationState.intent.expectEmailVerification && (
243
- <Stack gap={"xs"}>
233
+ <Flex direction="column" gap={"xs"}>
244
234
  <Text size="sm" fw={500}>
245
235
  {tr("registerEmailCode")}
246
236
  </Text>
@@ -254,11 +244,11 @@ const Register = (props: RegisterProps) => {
254
244
  aria-label="Email verification code"
255
245
  />
256
246
  </Flex>
257
- </Stack>
247
+ </Flex>
258
248
  )}
259
249
 
260
250
  {registrationState.intent.expectPhoneVerification && (
261
- <Stack gap={"xs"}>
251
+ <Flex direction="column" gap={"xs"}>
262
252
  <Text size="sm" fw={500}>
263
253
  {tr("registerPhoneCode")}
264
254
  </Text>
@@ -272,7 +262,7 @@ const Register = (props: RegisterProps) => {
272
262
  aria-label="Phone verification code"
273
263
  />
274
264
  </Flex>
275
- </Stack>
265
+ </Flex>
276
266
  )}
277
267
 
278
268
  <ActionButton
@@ -292,9 +282,9 @@ const Register = (props: RegisterProps) => {
292
282
  >
293
283
  {tr("registerVerifyBack") ?? "Back to registration"}
294
284
  </ActionButton>
295
- </Stack>
285
+ </Flex>
296
286
  </Card>
297
- </Stack>
287
+ </Flex>
298
288
  </Flex>
299
289
  );
300
290
  }
@@ -309,14 +299,14 @@ const Register = (props: RegisterProps) => {
309
299
  // Registration form phase UI
310
300
  return (
311
301
  <Flex flex={1} justify={"center"} align={"center"}>
312
- <Stack gap={"sm"} w={360}>
302
+ <Flex direction="column" gap={"sm"} w={360}>
313
303
  <Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
314
- <Stack gap={"md"}>
304
+ <Flex direction="column" gap={"md"}>
315
305
  {/* Realm branding */}
316
306
  {(settings.logoUrl ||
317
307
  settings.displayName ||
318
308
  settings.description) && (
319
- <Stack gap={"xs"} align="center" mb="xs">
309
+ <Flex direction="column" gap={"xs"} align="center" mb="xs">
320
310
  {settings.logoUrl && (
321
311
  <Image
322
312
  src={settings.logoUrl}
@@ -336,7 +326,7 @@ const Register = (props: RegisterProps) => {
336
326
  {settings.description}
337
327
  </Text>
338
328
  )}
339
- </Stack>
329
+ </Flex>
340
330
  )}
341
331
 
342
332
  {!isRegistrationAllowed ? (
@@ -361,7 +351,7 @@ const Register = (props: RegisterProps) => {
361
351
  {/* Credentials registration form */}
362
352
  {credentialsProvider && (
363
353
  <form {...form.props}>
364
- <Stack flex={1} gap={"md"}>
354
+ <Flex direction="column" flex={1} gap={"md"}>
365
355
  {settings.usernameEnabled !== false &&
366
356
  form.input.username && (
367
357
  <Control
@@ -417,24 +407,24 @@ const Register = (props: RegisterProps) => {
417
407
  >
418
408
  {tr("registerCreateAccount")}
419
409
  </ActionButton>
420
- </Stack>
410
+ </Flex>
421
411
  </form>
422
412
  )}
423
413
 
424
414
  {/* OR divider - only when both credentials AND external methods exist */}
425
415
  {showOrDivider && (
426
- <Group align="center" justify="center" gap={"md"}>
416
+ <Flex align="center" justify="center" gap={"md"}>
427
417
  <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
428
418
  <Text size="xs" c="dimmed">
429
419
  {tr("registerOr")}
430
420
  </Text>
431
421
  <Flex flex={1} h={"1px"} bg={"var(--alepha-border)"} />
432
- </Group>
422
+ </Flex>
433
423
  )}
434
424
 
435
425
  {/* External login methods */}
436
426
  {externalMethods.length > 0 && (
437
- <Stack gap={"sm"}>
427
+ <Flex direction="column" gap={"sm"}>
438
428
  {externalMethods.map((method) => (
439
429
  <ActionButton
440
430
  variant={"default"}
@@ -452,7 +442,7 @@ const Register = (props: RegisterProps) => {
452
442
  })}
453
443
  </ActionButton>
454
444
  ))}
455
- </Stack>
445
+ </Flex>
456
446
  )}
457
447
 
458
448
  {/* Sign in link */}
@@ -469,12 +459,12 @@ const Register = (props: RegisterProps) => {
469
459
  </Text>
470
460
  </>
471
461
  )}
472
- </Stack>
462
+ </Flex>
473
463
  </Card>
474
464
  <ActionButton variant={"subtle"} href={redirect}>
475
465
  {tr("registerCancel")}
476
466
  </ActionButton>
477
- </Stack>
467
+ </Flex>
478
468
  </Flex>
479
469
  );
480
470
  };
@@ -1,14 +1,5 @@
1
1
  import { ActionButton, Control } from "@alepha/ui";
2
- import {
3
- Alert,
4
- Card,
5
- Flex,
6
- Image,
7
- PinInput,
8
- Stack,
9
- Text,
10
- Title,
11
- } from "@mantine/core";
2
+ import { Alert, Card, Flex, Image, PinInput, Text, Title } from "@mantine/core";
12
3
  import {
13
4
  IconAlertCircle,
14
5
  IconCheck,
@@ -139,14 +130,14 @@ const ResetPassword = (props: ResetPasswordProps) => {
139
130
 
140
131
  return (
141
132
  <Flex flex={1} justify={"center"} align={"center"}>
142
- <Stack gap={"sm"} w={360}>
133
+ <Flex direction="column" gap={"sm"} w={360}>
143
134
  <Card withBorder p={"lg"} bg={"var(--alepha-elevated)"}>
144
- <Stack gap={"md"}>
135
+ <Flex direction="column" gap={"md"}>
145
136
  {/* Realm branding */}
146
137
  {(settings.logoUrl ||
147
138
  settings.displayName ||
148
139
  settings.description) && (
149
- <Stack gap={"xs"} align="center" mb="xs">
140
+ <Flex direction="column" gap={"xs"} align="center" mb="xs">
150
141
  {settings.logoUrl && (
151
142
  <Image
152
143
  src={settings.logoUrl}
@@ -166,7 +157,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
166
157
  {settings.description}
167
158
  </Text>
168
159
  )}
169
- </Stack>
160
+ </Flex>
170
161
  )}
171
162
 
172
163
  {error && (
@@ -194,7 +185,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
194
185
  </>
195
186
  ) : resetState.step === "email" ? (
196
187
  <form {...emailForm.props}>
197
- <Stack flex={1} gap={"md"}>
188
+ <Flex direction="column" flex={1} gap={"md"}>
198
189
  <Text size="lg" fw={500} ta="center">
199
190
  {tr("resetPasswordTitle")}
200
191
  </Text>
@@ -217,10 +208,10 @@ const ResetPassword = (props: ResetPasswordProps) => {
217
208
  >
218
209
  {tr("resetPasswordSendCode")}
219
210
  </ActionButton>
220
- </Stack>
211
+ </Flex>
221
212
  </form>
222
213
  ) : resetState.step === "code" ? (
223
- <Stack gap={"md"}>
214
+ <Flex direction="column" gap={"md"}>
224
215
  <Text size="lg" fw={500} ta="center">
225
216
  {tr("resetPasswordTitle")}
226
217
  </Text>
@@ -247,10 +238,10 @@ const ResetPassword = (props: ResetPasswordProps) => {
247
238
  >
248
239
  {tr("resetPasswordResendCode")}
249
240
  </ActionButton>
250
- </Stack>
241
+ </Flex>
251
242
  ) : resetState.step === "password" ? (
252
243
  <form {...passwordForm.props}>
253
- <Stack flex={1} gap={"md"}>
244
+ <Flex direction="column" flex={1} gap={"md"}>
254
245
  <Text size="lg" fw={500} ta="center">
255
246
  {tr("resetPasswordTitle")}
256
247
  </Text>
@@ -277,7 +268,7 @@ const ResetPassword = (props: ResetPasswordProps) => {
277
268
  <ActionButton form={passwordForm}>
278
269
  {tr("resetPasswordSetNewPassword")}
279
270
  </ActionButton>
280
- </Stack>
271
+ </Flex>
281
272
  </form>
282
273
  ) : (
283
274
  <>
@@ -293,12 +284,12 @@ const ResetPassword = (props: ResetPasswordProps) => {
293
284
  </ActionButton>
294
285
  </>
295
286
  )}
296
- </Stack>
287
+ </Flex>
297
288
  </Card>
298
289
  <ActionButton variant={"subtle"} href={redirect}>
299
290
  {tr("resetPasswordCancel")}
300
291
  </ActionButton>
301
- </Stack>
292
+ </Flex>
302
293
  </Flex>
303
294
  );
304
295
  };
@@ -1,5 +1,5 @@
1
1
  import { ActionButton } from "@alepha/ui";
2
- import { Alert, Card, Flex, Loader, Stack, Text } from "@mantine/core";
2
+ import { Alert, Card, Flex, Loader, Text } from "@mantine/core";
3
3
  import { IconAlertCircle, IconCheck, IconMailCheck } from "@tabler/icons-react";
4
4
  import type { UserController } from "alepha/api/users";
5
5
  import { useClient } from "alepha/react";
@@ -49,9 +49,9 @@ const VerifyEmail = (_props: VerifyEmailProps) => {
49
49
 
50
50
  return (
51
51
  <Flex flex={1} justify="center" align="center">
52
- <Stack gap="sm" w={400}>
52
+ <Flex direction="column" gap="sm" w={400}>
53
53
  <Card withBorder p="lg" bg="var(--alepha-elevated)">
54
- <Stack gap="md" align="center">
54
+ <Flex direction="column" gap="md" align="center">
55
55
  {step === "verifying" && (
56
56
  <>
57
57
  <Loader size="lg" />
@@ -93,9 +93,9 @@ const VerifyEmail = (_props: VerifyEmailProps) => {
93
93
  </ActionButton>
94
94
  </>
95
95
  )}
96
- </Stack>
96
+ </Flex>
97
97
  </Card>
98
- </Stack>
98
+ </Flex>
99
99
  </Flex>
100
100
  );
101
101
  };
@@ -31,6 +31,11 @@ export interface UserButtonProps
31
31
  */
32
32
  logoutLabel?: string;
33
33
 
34
+ /**
35
+ * Custom label for the login button when user is not authenticated
36
+ */
37
+ loginLabel?: string;
38
+
34
39
  /**
35
40
  * Menu configuration overrides
36
41
  */
@@ -51,6 +56,7 @@ const UserButton = (props: UserButtonProps) => {
51
56
  const {
52
57
  menuItems = [],
53
58
  logoutLabel = "Sign out",
59
+ loginLabel,
54
60
  menuConfig,
55
61
  showLogoutDivider = menuItems.length > 0,
56
62
  icon,
@@ -79,9 +85,11 @@ const UserButton = (props: UserButtonProps) => {
79
85
  return (
80
86
  <ActionButton
81
87
  {...buttonProps}
82
- icon={IconLogin2}
88
+ icon={icon === null ? undefined : (icon ?? IconLogin2)}
83
89
  href={authRouter.path("login")}
84
- />
90
+ >
91
+ {loginLabel ?? children}
92
+ </ActionButton>
85
93
  );
86
94
  }
87
95
 
@@ -132,12 +140,14 @@ const UserButton = (props: UserButtonProps) => {
132
140
  });
133
141
 
134
142
  // Use leftSection for Avatar (JSX element), icon prop for component types
135
- const hasAvatar = !icon && auth.user.picture;
143
+ const hasAvatar = icon === undefined && auth.user.picture;
136
144
 
137
145
  return (
138
146
  <ActionButton
139
147
  {...buttonProps}
140
- icon={hasAvatar ? undefined : (icon ?? IconUser)}
148
+ icon={
149
+ hasAvatar ? undefined : icon === null ? undefined : (icon ?? IconUser)
150
+ }
141
151
  leftSection={
142
152
  hasAvatar ? (
143
153
  <Avatar
@@ -243,17 +243,14 @@ const ActionButton = (_props: ActionProps) => {
243
243
  const props = { ..._props };
244
244
  const { tooltip, menu, icon, ...restProps } = props;
245
245
 
246
- if (props.variant === "subtle") {
247
- restProps.c ??= "var(--mantine-color-text)";
246
+ if (props.variant === "subtle" || props.variant === "outline") {
248
247
  restProps.color ??= "gray";
249
248
  }
250
249
 
251
250
  if (props.intent) {
252
251
  if (props.intent === "none") {
253
- restProps.c ??= "var(--mantine-color-text)";
254
252
  restProps.color ??= "gray";
255
253
  } else if (props.intent === "primary") {
256
- restProps.c ??= "white";
257
254
  restProps.color ??= theme.primaryColor;
258
255
  } else if (props.intent === "success") {
259
256
  restProps.c ??= "white";
@@ -262,7 +259,6 @@ const ActionButton = (_props: ActionProps) => {
262
259
  restProps.c ??= "white";
263
260
  restProps.color ??= "red";
264
261
  } else if (props.intent === "warning") {
265
- restProps.c ??= "var(--mantine-color-text)";
266
262
  restProps.color ??= "yellow";
267
263
  } else if (props.intent === "info") {
268
264
  restProps.c ??= "white";
@@ -271,18 +267,11 @@ const ActionButton = (_props: ActionProps) => {
271
267
  }
272
268
 
273
269
  if (props.icon) {
270
+ const sizes = ui.sizes.icon as Record<string, number>;
274
271
  const icon = isComponentType(props.icon) ? (
275
- <props.icon size={ui.sizes.icon.md} />
272
+ <props.icon size={sizes[props.size || "md"]} />
276
273
  ) : (
277
- <ThemeIcon
278
- w={24} // TODO: make size configurable
279
- variant={"transparent"}
280
- size={"sm"}
281
- c={"var(--mantine-color-text)"}
282
- {...props.themeIconProps}
283
- >
284
- {props.icon as ReactNode}
285
- </ThemeIcon>
274
+ <span>{props.icon as ReactNode}</span>
286
275
  );
287
276
 
288
277
  if (!props.children) {
@@ -508,6 +497,7 @@ const ActionHookButton = (props: ActionHookButtonProps) => {
508
497
 
509
498
  export interface ActionClickButtonProps extends ButtonProps {
510
499
  onClick: (e: any) => any;
500
+ preventDefault?: boolean;
511
501
  }
512
502
 
513
503
  /**
@@ -520,14 +510,20 @@ export interface ActionClickButtonProps extends ButtonProps {
520
510
  * </ActionButton>
521
511
  * ```
522
512
  */
523
- const ActionClickButton = (props: ActionClickButtonProps) => {
513
+ const ActionClickButton = ({
514
+ preventDefault,
515
+ ...props
516
+ }: ActionClickButtonProps) => {
524
517
  const action = useAction(
525
518
  {
526
519
  handler: async (e: any) => {
520
+ if (preventDefault) {
521
+ e.preventDefault();
522
+ }
527
523
  await props.onClick(e);
528
524
  },
529
525
  },
530
- [props.onClick],
526
+ [props.onClick, preventDefault],
531
527
  );
532
528
 
533
529
  return (