@alepha/ui 0.11.3 → 0.11.5

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 (42) hide show
  1. package/dist/AlephaMantineProvider-Ba88lMeq.js +3 -0
  2. package/dist/AlephaMantineProvider-Be0DAazb.js +150 -0
  3. package/dist/AlephaMantineProvider-Be0DAazb.js.map +1 -0
  4. package/dist/index.d.ts +289 -225
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +650 -729
  7. package/dist/index.js.map +1 -1
  8. package/package.json +14 -12
  9. package/src/RootRouter.ts +1 -1
  10. package/src/components/buttons/ActionButton.tsx +542 -0
  11. package/src/components/buttons/BurgerButton.tsx +20 -0
  12. package/src/components/{DarkModeButton.tsx → buttons/DarkModeButton.tsx} +27 -14
  13. package/src/components/buttons/LanguageButton.tsx +28 -0
  14. package/src/components/buttons/OmnibarButton.tsx +32 -0
  15. package/src/components/buttons/ToggleSidebarButton.tsx +28 -0
  16. package/src/components/dialogs/AlertDialog.tsx +10 -10
  17. package/src/components/dialogs/ConfirmDialog.tsx +18 -18
  18. package/src/components/dialogs/PromptDialog.tsx +5 -3
  19. package/src/components/{Control.tsx → form/Control.tsx} +6 -3
  20. package/src/components/{ControlDate.tsx → form/ControlDate.tsx} +4 -1
  21. package/src/components/{ControlSelect.tsx → form/ControlSelect.tsx} +4 -1
  22. package/src/components/{TypeForm.tsx → form/TypeForm.tsx} +8 -6
  23. package/src/components/layout/AdminShell.tsx +97 -0
  24. package/src/components/{AlephaMantineProvider.tsx → layout/AlephaMantineProvider.tsx} +30 -10
  25. package/src/components/layout/AppBar.tsx +133 -0
  26. package/src/components/layout/Omnibar.tsx +43 -0
  27. package/src/components/layout/Sidebar.tsx +410 -0
  28. package/src/components/table/DataTable.tsx +63 -0
  29. package/src/constants/ui.ts +8 -0
  30. package/src/index.ts +89 -24
  31. package/src/services/DialogService.tsx +13 -32
  32. package/src/services/ToastService.tsx +16 -4
  33. package/src/utils/parseInput.ts +1 -1
  34. package/dist/AlephaMantineProvider-DDbIijPF.js +0 -96
  35. package/dist/AlephaMantineProvider-DDbIijPF.js.map +0 -1
  36. package/dist/AlephaMantineProvider-pOu8hOzK.js +0 -3
  37. package/src/components/Action.tsx +0 -345
  38. package/src/components/DataTable.css +0 -199
  39. package/src/components/DataTable.tsx +0 -724
  40. package/src/components/Omnibar.tsx +0 -77
  41. package/src/components/Sidebar.css +0 -217
  42. package/src/components/Sidebar.tsx +0 -255
@@ -29,7 +29,10 @@ export class ToastService {
29
29
  });
30
30
  }
31
31
 
32
- public info(options: Partial<NotificationData>) {
32
+ public info(options: Partial<NotificationData> | string) {
33
+ if (typeof options === "string") {
34
+ options = { message: options };
35
+ }
33
36
  this.show({
34
37
  color: "blue",
35
38
  icon: <IconInfoCircle size={20} />,
@@ -39,7 +42,10 @@ export class ToastService {
39
42
  });
40
43
  }
41
44
 
42
- public success(options: Partial<NotificationData>) {
45
+ public success(options: Partial<NotificationData> | string) {
46
+ if (typeof options === "string") {
47
+ options = { message: options };
48
+ }
43
49
  this.show({
44
50
  color: "green",
45
51
  icon: <IconCheck size={16} />,
@@ -49,7 +55,10 @@ export class ToastService {
49
55
  });
50
56
  }
51
57
 
52
- public warning(options: Partial<NotificationData>) {
58
+ public warning(options: Partial<NotificationData> | string) {
59
+ if (typeof options === "string") {
60
+ options = { message: options };
61
+ }
53
62
  this.show({
54
63
  color: "yellow",
55
64
  icon: <IconAlertTriangle size={20} />,
@@ -59,7 +68,10 @@ export class ToastService {
59
68
  });
60
69
  }
61
70
 
62
- public danger(options: Partial<NotificationData>) {
71
+ public danger(options: Partial<NotificationData> | string) {
72
+ if (typeof options === "string") {
73
+ options = { message: options };
74
+ }
63
75
  this.show({
64
76
  color: "red",
65
77
  icon: <IconX size={20} />,
@@ -1,7 +1,7 @@
1
1
  import { type TObject, TypeBoxError } from "@alepha/core";
2
2
  import type { InputField } from "@alepha/react-form";
3
3
  import type { ReactNode } from "react";
4
- import type { ControlProps } from "../components/Control.tsx";
4
+ import type { ControlProps } from "../components/form/Control.tsx";
5
5
  import { getDefaultIcon } from "./icons.tsx";
6
6
  import { prettyName } from "./string.ts";
7
7
 
@@ -1,96 +0,0 @@
1
- import { NestedView, useRouterEvents } from "@alepha/react";
2
- import { ModalsProvider } from "@mantine/modals";
3
- import { ColorSchemeScript, MantineProvider } from "@mantine/core";
4
- import { Fragment, jsx, jsxs } from "react/jsx-runtime";
5
- import React from "react";
6
- import { Notifications } from "@mantine/notifications";
7
- import { IconDashboard, IconFileText, IconHome, IconSearch, IconSettings, IconUser } from "@tabler/icons-react";
8
- import { NavigationProgress, nprogress } from "@mantine/nprogress";
9
- import { Spotlight } from "@mantine/spotlight";
10
-
11
- //#region src/components/Omnibar.tsx
12
- const defaultActions = [
13
- {
14
- id: "home",
15
- label: "Home",
16
- description: "Go to home page",
17
- onClick: () => console.log("Home"),
18
- leftSection: /* @__PURE__ */ jsx(IconHome, { size: 20 })
19
- },
20
- {
21
- id: "dashboard",
22
- label: "Dashboard",
23
- description: "View your dashboard",
24
- onClick: () => console.log("Dashboard"),
25
- leftSection: /* @__PURE__ */ jsx(IconDashboard, { size: 20 })
26
- },
27
- {
28
- id: "documents",
29
- label: "Documents",
30
- description: "Browse all documents",
31
- onClick: () => console.log("Documents"),
32
- leftSection: /* @__PURE__ */ jsx(IconFileText, { size: 20 })
33
- },
34
- {
35
- id: "profile",
36
- label: "Profile",
37
- description: "View and edit your profile",
38
- onClick: () => console.log("Profile"),
39
- leftSection: /* @__PURE__ */ jsx(IconUser, { size: 20 })
40
- },
41
- {
42
- id: "settings",
43
- label: "Settings",
44
- description: "Manage application settings",
45
- onClick: () => console.log("Settings"),
46
- leftSection: /* @__PURE__ */ jsx(IconSettings, { size: 20 })
47
- }
48
- ];
49
- const Omnibar = (props) => {
50
- const actions = props.actions ?? defaultActions;
51
- const shortcut = props.shortcut ?? "mod+K";
52
- const searchPlaceholder = props.searchPlaceholder ?? "Search...";
53
- const nothingFound = props.nothingFound ?? "Nothing found...";
54
- return /* @__PURE__ */ jsx(Spotlight, {
55
- actions,
56
- shortcut,
57
- searchProps: {
58
- leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 20 }),
59
- placeholder: searchPlaceholder
60
- },
61
- nothingFound
62
- });
63
- };
64
- var Omnibar_default = Omnibar;
65
-
66
- //#endregion
67
- //#region src/components/AlephaMantineProvider.tsx
68
- const AlephaMantineProvider = (props) => {
69
- useRouterEvents({
70
- onBegin: () => {
71
- nprogress.start();
72
- },
73
- onEnd: () => {
74
- nprogress.complete();
75
- }
76
- });
77
- return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(ColorSchemeScript, {
78
- defaultColorScheme: props.mantine?.defaultColorScheme,
79
- ...props.colorSchemeScript
80
- }), /* @__PURE__ */ jsxs(MantineProvider, {
81
- ...props.mantine,
82
- children: [
83
- /* @__PURE__ */ jsx(Notifications, { ...props.notifications }),
84
- /* @__PURE__ */ jsx(NavigationProgress, { ...props.navigationProgress }),
85
- /* @__PURE__ */ jsxs(ModalsProvider, {
86
- ...props.modals,
87
- children: [/* @__PURE__ */ jsx(Omnibar_default, { ...props.omnibar }), props.children ?? /* @__PURE__ */ jsx(NestedView, {})]
88
- })
89
- ]
90
- })] });
91
- };
92
- var AlephaMantineProvider_default = AlephaMantineProvider;
93
-
94
- //#endregion
95
- export { Omnibar_default as n, AlephaMantineProvider_default as t };
96
- //# sourceMappingURL=AlephaMantineProvider-DDbIijPF.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AlephaMantineProvider-DDbIijPF.js","names":["defaultActions: SpotlightActionData[]","Omnibar"],"sources":["../src/components/Omnibar.tsx","../src/components/AlephaMantineProvider.tsx"],"sourcesContent":["import { Spotlight, type SpotlightActionData } from \"@mantine/spotlight\";\nimport {\n IconDashboard,\n IconFileText,\n IconHome,\n IconSearch,\n IconSettings,\n IconUser,\n} from \"@tabler/icons-react\";\n// biome-ignore lint/correctness/noUnusedImports: required\nimport React, { type ReactNode } from \"react\";\n\nexport interface OmnibarProps {\n actions?: SpotlightActionData[];\n shortcut?: string | string[];\n searchPlaceholder?: string;\n nothingFound?: ReactNode;\n}\n\nconst defaultActions: SpotlightActionData[] = [\n {\n id: \"home\",\n label: \"Home\",\n description: \"Go to home page\",\n onClick: () => console.log(\"Home\"),\n leftSection: <IconHome size={20} />,\n },\n {\n id: \"dashboard\",\n label: \"Dashboard\",\n description: \"View your dashboard\",\n onClick: () => console.log(\"Dashboard\"),\n leftSection: <IconDashboard size={20} />,\n },\n {\n id: \"documents\",\n label: \"Documents\",\n description: \"Browse all documents\",\n onClick: () => console.log(\"Documents\"),\n leftSection: <IconFileText size={20} />,\n },\n {\n id: \"profile\",\n label: \"Profile\",\n description: \"View and edit your profile\",\n onClick: () => console.log(\"Profile\"),\n leftSection: <IconUser size={20} />,\n },\n {\n id: \"settings\",\n label: \"Settings\",\n description: \"Manage application settings\",\n onClick: () => console.log(\"Settings\"),\n leftSection: <IconSettings size={20} />,\n },\n];\n\nconst Omnibar = (props: OmnibarProps) => {\n const actions = props.actions ?? defaultActions;\n const shortcut = props.shortcut ?? \"mod+K\";\n const searchPlaceholder = props.searchPlaceholder ?? \"Search...\";\n const nothingFound = props.nothingFound ?? \"Nothing found...\";\n\n return (\n <Spotlight\n actions={actions}\n shortcut={shortcut}\n searchProps={{\n leftSection: <IconSearch size={20} />,\n placeholder: searchPlaceholder,\n }}\n nothingFound={nothingFound}\n />\n );\n};\n\nexport default Omnibar;\n","import { NestedView, useRouterEvents } from \"@alepha/react\";\nimport type {\n ColorSchemeScriptProps,\n MantineProviderProps,\n} from \"@mantine/core\";\nimport { ColorSchemeScript, MantineProvider } from \"@mantine/core\";\nimport { ModalsProvider, type ModalsProviderProps } from \"@mantine/modals\";\nimport { Notifications, type NotificationsProps } from \"@mantine/notifications\";\nimport type { NavigationProgressProps } from \"@mantine/nprogress\";\nimport { NavigationProgress, nprogress } from \"@mantine/nprogress\";\nimport type { ReactNode } from \"react\";\nimport Omnibar, { type OmnibarProps } from \"./Omnibar\";\n\nexport interface AlephaMantineProviderProps {\n children?: ReactNode;\n mantine?: MantineProviderProps;\n colorSchemeScript?: ColorSchemeScriptProps;\n navigationProgress?: NavigationProgressProps;\n notifications?: NotificationsProps;\n modals?: ModalsProviderProps;\n omnibar?: OmnibarProps;\n}\n\nconst AlephaMantineProvider = (props: AlephaMantineProviderProps) => {\n useRouterEvents({\n onBegin: () => {\n nprogress.start();\n },\n onEnd: () => {\n nprogress.complete();\n },\n });\n\n return (\n <>\n <ColorSchemeScript\n defaultColorScheme={props.mantine?.defaultColorScheme}\n {...props.colorSchemeScript}\n />\n <MantineProvider {...props.mantine}>\n <Notifications {...props.notifications} />\n <NavigationProgress {...props.navigationProgress} />\n <ModalsProvider {...props.modals}>\n <Omnibar {...props.omnibar} />\n {props.children ?? <NestedView />}\n </ModalsProvider>\n </MantineProvider>\n </>\n );\n};\n\nexport default AlephaMantineProvider;\n"],"mappings":";;;;;;;;;;;AAmBA,MAAMA,iBAAwC;CAC5C;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,eAAe,QAAQ,IAAI,OAAO;EAClC,aAAa,oBAAC,YAAS,MAAM,KAAM;EACpC;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,eAAe,QAAQ,IAAI,YAAY;EACvC,aAAa,oBAAC,iBAAc,MAAM,KAAM;EACzC;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,eAAe,QAAQ,IAAI,YAAY;EACvC,aAAa,oBAAC,gBAAa,MAAM,KAAM;EACxC;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,eAAe,QAAQ,IAAI,UAAU;EACrC,aAAa,oBAAC,YAAS,MAAM,KAAM;EACpC;CACD;EACE,IAAI;EACJ,OAAO;EACP,aAAa;EACb,eAAe,QAAQ,IAAI,WAAW;EACtC,aAAa,oBAAC,gBAAa,MAAM,KAAM;EACxC;CACF;AAED,MAAM,WAAW,UAAwB;CACvC,MAAM,UAAU,MAAM,WAAW;CACjC,MAAM,WAAW,MAAM,YAAY;CACnC,MAAM,oBAAoB,MAAM,qBAAqB;CACrD,MAAM,eAAe,MAAM,gBAAgB;AAE3C,QACE,oBAAC;EACU;EACC;EACV,aAAa;GACX,aAAa,oBAAC,cAAW,MAAM,KAAM;GACrC,aAAa;GACd;EACa;GACd;;AAIN,sBAAe;;;;ACrDf,MAAM,yBAAyB,UAAsC;AACnE,iBAAgB;EACd,eAAe;AACb,aAAU,OAAO;;EAEnB,aAAa;AACX,aAAU,UAAU;;EAEvB,CAAC;AAEF,QACE,4CACE,oBAAC;EACC,oBAAoB,MAAM,SAAS;EACnC,GAAI,MAAM;GACV,EACF,qBAAC;EAAgB,GAAI,MAAM;;GACzB,oBAAC,iBAAc,GAAI,MAAM,gBAAiB;GAC1C,oBAAC,sBAAmB,GAAI,MAAM,qBAAsB;GACpD,qBAAC;IAAe,GAAI,MAAM;eACxB,oBAACC,mBAAQ,GAAI,MAAM,UAAW,EAC7B,MAAM,YAAY,oBAAC,eAAa;KAClB;;GACD,IACjB;;AAIP,oCAAe"}
@@ -1,3 +0,0 @@
1
- import { t as AlephaMantineProvider_default } from "./AlephaMantineProvider-DDbIijPF.js";
2
-
3
- export { AlephaMantineProvider_default as default };
@@ -1,345 +0,0 @@
1
- import {
2
- type RouterGoOptions,
3
- type UseActiveOptions,
4
- useActive,
5
- useAlepha,
6
- useRouter,
7
- } from "@alepha/react";
8
- import { type FormModel, useFormState } from "@alepha/react-form";
9
- import {
10
- Button,
11
- type ButtonProps,
12
- Flex,
13
- Menu,
14
- Tooltip,
15
- type TooltipProps,
16
- } from "@mantine/core";
17
- import { IconChevronRight } from "@tabler/icons-react";
18
- import { type ReactNode, useState } from "react";
19
-
20
- export interface ActionMenuItem {
21
- /**
22
- * Menu item type
23
- */
24
- type?: "item" | "divider" | "label";
25
-
26
- /**
27
- * Label text for the menu item
28
- */
29
- label?: string;
30
-
31
- /**
32
- * Icon element to display before the label
33
- */
34
- icon?: ReactNode;
35
-
36
- /**
37
- * Click handler for menu items
38
- */
39
- onClick?: () => void;
40
-
41
- /**
42
- * Color for the menu item (e.g., "red" for danger actions)
43
- */
44
- color?: string;
45
-
46
- /**
47
- * Nested submenu items
48
- */
49
- children?: ActionMenuItem[];
50
- }
51
-
52
- export interface ActionMenuConfig {
53
- /**
54
- * Array of menu items to display
55
- */
56
- items: ActionMenuItem[];
57
-
58
- /**
59
- * Menu position relative to the button
60
- */
61
- position?:
62
- | "bottom"
63
- | "bottom-start"
64
- | "bottom-end"
65
- | "top"
66
- | "top-start"
67
- | "top-end"
68
- | "left"
69
- | "right";
70
-
71
- /**
72
- * Menu width
73
- */
74
- width?: number | string;
75
-
76
- /**
77
- * Menu shadow
78
- */
79
- shadow?: "xs" | "sm" | "md" | "lg" | "xl";
80
- }
81
-
82
- export interface ActionCommonProps extends ButtonProps {
83
- children?: ReactNode;
84
- textVisibleFrom?: "xs" | "sm" | "md" | "lg" | "xl";
85
-
86
- /**
87
- * Tooltip to display on hover. Can be a string for simple tooltips
88
- * or a TooltipProps object for advanced configuration.
89
- */
90
- tooltip?: string | TooltipProps;
91
-
92
- /**
93
- * Menu configuration. When provided, the action will display a dropdown menu.
94
- */
95
- menu?: ActionMenuConfig;
96
-
97
- /**
98
- * If set, a confirmation dialog will be shown before performing the action.
99
- * If `true`, a default title and message will be used.
100
- * If a string, it will be used as the message with a default title.
101
- * If an object, it can contain `title` and `message` properties to customize the dialog.
102
- */
103
- confirm?: boolean | string | { title?: string; message: string };
104
- }
105
-
106
- export type ActionProps = ActionCommonProps &
107
- (ActiveHrefProps | ActionClickProps | ActionSubmitProps | {});
108
-
109
- // ---------------------------------------------------------------------------------------------------------------------
110
-
111
- // Helper function to render menu items recursively
112
- const renderMenuItem = (item: ActionMenuItem, index: number): ReactNode => {
113
- // Render divider
114
- if (item.type === "divider") {
115
- return <Menu.Divider key={index} />;
116
- }
117
-
118
- // Render label
119
- if (item.type === "label") {
120
- return <Menu.Label key={index}>{item.label}</Menu.Label>;
121
- }
122
-
123
- // Render submenu if has children
124
- if (item.children && item.children.length > 0) {
125
- return (
126
- <Menu key={index} trigger="hover" position="right-start" offset={2}>
127
- <Menu.Target>
128
- <Menu.Item
129
- leftSection={item.icon}
130
- rightSection={<IconChevronRight size={14} />}
131
- >
132
- {item.label}
133
- </Menu.Item>
134
- </Menu.Target>
135
- <Menu.Dropdown>
136
- {item.children.map((child, childIndex) =>
137
- renderMenuItem(child, childIndex),
138
- )}
139
- </Menu.Dropdown>
140
- </Menu>
141
- );
142
- }
143
-
144
- // Render regular menu item
145
- return (
146
- <Menu.Item
147
- key={index}
148
- leftSection={item.icon}
149
- onClick={item.onClick}
150
- color={item.color}
151
- >
152
- {item.label}
153
- </Menu.Item>
154
- );
155
- };
156
-
157
- const Action = (_props: ActionProps) => {
158
- const props = { variant: "subtle", ..._props };
159
- const { tooltip, menu, ...restProps } = props;
160
-
161
- if (props.leftSection && !props.children) {
162
- restProps.className ??= "mantine-Action-iconOnly";
163
- restProps.p ??= "xs";
164
- }
165
-
166
- if (props.textVisibleFrom) {
167
- const { children, textVisibleFrom, leftSection, ...rest } = restProps;
168
- return (
169
- <>
170
- <Flex w={"100%"} visibleFrom={textVisibleFrom}>
171
- <Action
172
- flex={1}
173
- {...rest}
174
- leftSection={leftSection}
175
- tooltip={tooltip}
176
- menu={menu}
177
- >
178
- {children}
179
- </Action>
180
- </Flex>
181
- <Flex w={"100%"} hiddenFrom={textVisibleFrom}>
182
- <Action px={"xs"} {...rest} tooltip={tooltip} menu={menu}>
183
- {leftSection}
184
- </Action>
185
- </Flex>
186
- </>
187
- );
188
- }
189
-
190
- const renderAction = () => {
191
- if ("href" in restProps && restProps.href) {
192
- return (
193
- <ActionHref {...restProps} href={restProps.href}>
194
- {restProps.children}
195
- </ActionHref>
196
- );
197
- }
198
-
199
- if ("onClick" in restProps && restProps.onClick) {
200
- return (
201
- <ActionClick {...restProps} onClick={restProps.onClick}>
202
- {restProps.children}
203
- </ActionClick>
204
- );
205
- }
206
-
207
- if ("form" in restProps && restProps.form) {
208
- return (
209
- <ActionSubmit {...restProps} form={restProps.form}>
210
- {restProps.children}
211
- </ActionSubmit>
212
- );
213
- }
214
-
215
- return <Button {...(restProps as any)}>{restProps.children}</Button>;
216
- };
217
-
218
- let actionElement = renderAction();
219
-
220
- // Wrap with Menu if provided
221
- if (menu) {
222
- actionElement = (
223
- <Menu
224
- position={menu.position || "bottom-start"}
225
- width={menu.width || 200}
226
- shadow={menu.shadow || "md"}
227
- >
228
- <Menu.Target>{actionElement}</Menu.Target>
229
- <Menu.Dropdown>
230
- {menu.items.map((item, index) => renderMenuItem(item, index))}
231
- </Menu.Dropdown>
232
- </Menu>
233
- );
234
- }
235
-
236
- // Wrap with Tooltip if provided
237
- if (tooltip) {
238
- const tooltipProps: TooltipProps =
239
- typeof tooltip === "string"
240
- ? { label: tooltip, children: actionElement }
241
- : { ...tooltip, children: actionElement };
242
-
243
- return <Tooltip {...tooltipProps} />;
244
- }
245
-
246
- return actionElement;
247
- };
248
-
249
- export default Action;
250
-
251
- // ---------------------------------------------------------------------------------------------------------------------
252
-
253
- export interface ActionSubmitProps extends ButtonProps {
254
- form: FormModel<any>;
255
- }
256
-
257
- /**
258
- * Action button that submits a form with loading and disabled state handling.
259
- */
260
- const ActionSubmit = (props: ActionSubmitProps) => {
261
- const { form, ...buttonProps } = props;
262
- const state = useFormState(form);
263
- return (
264
- <Button
265
- {...buttonProps}
266
- loading={state.loading}
267
- disabled={state.loading}
268
- type={"submit"}
269
- >
270
- {props.children}
271
- </Button>
272
- );
273
- };
274
-
275
- // ---------------------------------------------------------------------------------------------------------------------
276
-
277
- export interface ActionClickProps extends ButtonProps {
278
- onClick: (e: any) => any;
279
- }
280
-
281
- /**
282
- * Basic action button that handles click events with loading and error handling.
283
- */
284
- const ActionClick = (props: ActionClickProps) => {
285
- const [pending, setPending] = useState(false);
286
- const alepha = useAlepha();
287
-
288
- const onClick = async (e: any) => {
289
- setPending(true);
290
- try {
291
- await props.onClick(e);
292
- } catch (e) {
293
- console.error(e);
294
- await alepha.events.emit("form:submit:error", {
295
- id: "action",
296
- error: e as Error,
297
- });
298
- } finally {
299
- setPending(false);
300
- }
301
- };
302
-
303
- return (
304
- <Button
305
- {...props}
306
- disabled={pending || props.disabled}
307
- loading={pending}
308
- onClick={onClick}
309
- >
310
- {props.children}
311
- </Button>
312
- );
313
- };
314
-
315
- // ---------------------------------------------------------------------------------------------------------------------
316
-
317
- export interface ActiveHrefProps extends ButtonProps {
318
- href: string;
319
- active?: Partial<UseActiveOptions> | false;
320
- routerGoOptions?: RouterGoOptions;
321
- }
322
-
323
- /**
324
- * Action for navigation with active state support.
325
- */
326
- const ActionHref = (props: ActiveHrefProps) => {
327
- const { active: options, routerGoOptions, ...buttonProps } = props;
328
- const router = useRouter();
329
- const { isPending, isActive } = useActive(
330
- options ? { href: props.href, ...options } : { href: props.href },
331
- );
332
- const anchorProps = router.anchor(props.href, routerGoOptions);
333
-
334
- return (
335
- <Button
336
- component={"a"}
337
- loading={isPending}
338
- {...anchorProps}
339
- {...buttonProps}
340
- variant={isActive && options !== false ? "filled" : "subtle"}
341
- >
342
- {props.children}
343
- </Button>
344
- );
345
- };