@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.
- package/dist/AlephaMantineProvider-Ba88lMeq.js +3 -0
- package/dist/AlephaMantineProvider-Be0DAazb.js +150 -0
- package/dist/AlephaMantineProvider-Be0DAazb.js.map +1 -0
- package/dist/index.d.ts +289 -225
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +650 -729
- package/dist/index.js.map +1 -1
- package/package.json +14 -12
- package/src/RootRouter.ts +1 -1
- package/src/components/buttons/ActionButton.tsx +542 -0
- package/src/components/buttons/BurgerButton.tsx +20 -0
- package/src/components/{DarkModeButton.tsx → buttons/DarkModeButton.tsx} +27 -14
- package/src/components/buttons/LanguageButton.tsx +28 -0
- package/src/components/buttons/OmnibarButton.tsx +32 -0
- package/src/components/buttons/ToggleSidebarButton.tsx +28 -0
- package/src/components/dialogs/AlertDialog.tsx +10 -10
- package/src/components/dialogs/ConfirmDialog.tsx +18 -18
- package/src/components/dialogs/PromptDialog.tsx +5 -3
- package/src/components/{Control.tsx → form/Control.tsx} +6 -3
- package/src/components/{ControlDate.tsx → form/ControlDate.tsx} +4 -1
- package/src/components/{ControlSelect.tsx → form/ControlSelect.tsx} +4 -1
- package/src/components/{TypeForm.tsx → form/TypeForm.tsx} +8 -6
- package/src/components/layout/AdminShell.tsx +97 -0
- package/src/components/{AlephaMantineProvider.tsx → layout/AlephaMantineProvider.tsx} +30 -10
- package/src/components/layout/AppBar.tsx +133 -0
- package/src/components/layout/Omnibar.tsx +43 -0
- package/src/components/layout/Sidebar.tsx +410 -0
- package/src/components/table/DataTable.tsx +63 -0
- package/src/constants/ui.ts +8 -0
- package/src/index.ts +89 -24
- package/src/services/DialogService.tsx +13 -32
- package/src/services/ToastService.tsx +16 -4
- package/src/utils/parseInput.ts +1 -1
- package/dist/AlephaMantineProvider-DDbIijPF.js +0 -96
- package/dist/AlephaMantineProvider-DDbIijPF.js.map +0 -1
- package/dist/AlephaMantineProvider-pOu8hOzK.js +0 -3
- package/src/components/Action.tsx +0 -345
- package/src/components/DataTable.css +0 -199
- package/src/components/DataTable.tsx +0 -724
- package/src/components/Omnibar.tsx +0 -77
- package/src/components/Sidebar.css +0 -217
- 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} />,
|
package/src/utils/parseInput.ts
CHANGED
|
@@ -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,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
|
-
};
|