@alepha/ui 0.10.7 → 0.11.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.
package/src/index.ts CHANGED
@@ -2,6 +2,7 @@ import { $module } from "@alepha/core";
2
2
  import { AlephaReact } from "@alepha/react";
3
3
  import type { ControlProps } from "./components/Control.tsx";
4
4
  import { RootRouter } from "./RootRouter.ts";
5
+ import { DialogService } from "./services/DialogService.tsx";
5
6
  import { ToastService } from "./services/ToastService.tsx";
6
7
 
7
8
  // ---------------------------------------------------------------------------------------------------------------------
@@ -13,10 +14,37 @@ export { default as Control } from "./components/Control.tsx";
13
14
  export { default as ControlDate } from "./components/ControlDate.tsx";
14
15
  export { default as ControlSelect } from "./components/ControlSelect.tsx";
15
16
  export { default as DarkModeButton } from "./components/DarkModeButton.tsx";
17
+ export type {
18
+ DataTableColumn,
19
+ DataTableFilter,
20
+ DataTableProps,
21
+ DataTableSort,
22
+ } from "./components/DataTable.tsx";
23
+ export { default as DataTable } from "./components/DataTable.tsx";
24
+ export { AlertDialog } from "./components/dialogs/AlertDialog.tsx";
25
+ export { ConfirmDialog } from "./components/dialogs/ConfirmDialog.tsx";
26
+ export { PromptDialog } from "./components/dialogs/PromptDialog.tsx";
16
27
  export { default as Omnibar } from "./components/Omnibar.tsx";
28
+ export type {
29
+ MenuItem,
30
+ SidebarItemProps,
31
+ SidebarProps,
32
+ } from "./components/Sidebar.tsx";
33
+ export { Sidebar, SidebarItem } from "./components/Sidebar.tsx";
17
34
  export { default as TypeForm } from "./components/TypeForm.tsx";
35
+ export { useDialog } from "./hooks/useDialog.ts";
18
36
  export { useToast } from "./hooks/useToast.ts";
19
37
  export * from "./RootRouter.ts";
38
+ export type {
39
+ AlertDialogOptions,
40
+ AlertDialogProps,
41
+ BaseDialogOptions,
42
+ ConfirmDialogOptions,
43
+ ConfirmDialogProps,
44
+ PromptDialogOptions,
45
+ PromptDialogProps,
46
+ } from "./services/DialogService.tsx";
47
+ export { DialogService } from "./services/DialogService.tsx";
20
48
  export { ToastService } from "./services/ToastService.tsx";
21
49
  export * from "./utils/icons.tsx";
22
50
  export * from "./utils/string.ts";
@@ -32,11 +60,11 @@ declare module "typebox" {
32
60
  // ---------------------------------------------------------------------------------------------------------------------
33
61
 
34
62
  /**
35
- *
63
+ * Mantine
36
64
  *
37
65
  * @module alepha.ui
38
66
  */
39
67
  export const AlephaUI = $module({
40
68
  name: "alepha.ui",
41
- services: [AlephaReact, ToastService, RootRouter],
69
+ services: [AlephaReact, DialogService, ToastService, RootRouter],
42
70
  });
@@ -0,0 +1,207 @@
1
+ import type { ModalProps } from "@mantine/core";
2
+ import { modals } from "@mantine/modals";
3
+ import type { ReactNode } from "react";
4
+ import { AlertDialog } from "../components/dialogs/AlertDialog";
5
+ import { ConfirmDialog } from "../components/dialogs/ConfirmDialog";
6
+ import { PromptDialog } from "../components/dialogs/PromptDialog";
7
+
8
+ // Base interfaces
9
+ export interface BaseDialogOptions extends Partial<ModalProps> {
10
+ title?: ReactNode;
11
+ message?: ReactNode;
12
+ content?: any; // weird typing for mantine modals content
13
+ }
14
+
15
+ export interface AlertDialogOptions extends BaseDialogOptions {
16
+ okLabel?: string;
17
+ }
18
+
19
+ export interface ConfirmDialogOptions extends BaseDialogOptions {
20
+ confirmLabel?: string;
21
+ cancelLabel?: string;
22
+ confirmColor?: string;
23
+ }
24
+
25
+ export interface PromptDialogOptions extends BaseDialogOptions {
26
+ placeholder?: string;
27
+ defaultValue?: string;
28
+ label?: string;
29
+ required?: boolean;
30
+ submitLabel?: string;
31
+ cancelLabel?: string;
32
+ }
33
+
34
+ // Component prop interfaces
35
+ export interface AlertDialogProps {
36
+ options?: AlertDialogOptions;
37
+ onClose: () => void;
38
+ }
39
+
40
+ export interface ConfirmDialogProps {
41
+ options?: ConfirmDialogOptions;
42
+ onConfirm: (confirmed: boolean) => void;
43
+ }
44
+
45
+ export interface PromptDialogProps {
46
+ options?: PromptDialogOptions;
47
+ onSubmit: (value: string | null) => void;
48
+ }
49
+
50
+ export interface DialogServiceOptions {
51
+ default?: Partial<BaseDialogOptions>;
52
+ }
53
+
54
+ export class DialogService {
55
+ public readonly options: DialogServiceOptions = {
56
+ default: {
57
+ centered: true,
58
+ withCloseButton: true,
59
+ size: "md",
60
+ overlayProps: {
61
+ backgroundOpacity: 0.55,
62
+ blur: 3,
63
+ },
64
+ transitionProps: {
65
+ transition: "pop",
66
+ duration: 200,
67
+ },
68
+ },
69
+ };
70
+
71
+ /**
72
+ * Show an alert dialog with a message
73
+ */
74
+ public alert(options?: AlertDialogOptions): Promise<void> {
75
+ return new Promise((resolve) => {
76
+ const modalId = this.open({
77
+ ...options,
78
+ title: options?.title || "Alert",
79
+ content: (
80
+ <AlertDialog
81
+ options={options}
82
+ onClose={() => {
83
+ this.close(modalId);
84
+ resolve();
85
+ }}
86
+ />
87
+ ),
88
+ });
89
+ });
90
+ }
91
+
92
+ /**
93
+ * Show a confirmation dialog that returns a promise
94
+ */
95
+ public confirm(options?: ConfirmDialogOptions): Promise<boolean> {
96
+ return new Promise((resolve) => {
97
+ const modalId = this.open({
98
+ ...options,
99
+ title: options?.title || "Confirm",
100
+ closeOnClickOutside: false,
101
+ closeOnEscape: false,
102
+ content: (
103
+ <ConfirmDialog
104
+ options={options}
105
+ onConfirm={(confirmed) => {
106
+ this.close(modalId);
107
+ resolve(confirmed);
108
+ }}
109
+ />
110
+ ),
111
+ });
112
+ });
113
+ }
114
+
115
+ /**
116
+ * Show a prompt dialog to get user input
117
+ */
118
+ public prompt(options?: PromptDialogOptions): Promise<string | null> {
119
+ return new Promise((resolve) => {
120
+ const modalId = this.open({
121
+ ...options,
122
+ title: options?.title || "Input",
123
+ closeOnClickOutside: false,
124
+ closeOnEscape: false,
125
+ content: (
126
+ <PromptDialog
127
+ options={options}
128
+ onSubmit={(value) => {
129
+ this.close(modalId);
130
+ resolve(value);
131
+ }}
132
+ />
133
+ ),
134
+ });
135
+ });
136
+ }
137
+
138
+ /**
139
+ * Open a custom dialog with provided content
140
+ */
141
+ public open(options?: BaseDialogOptions): string {
142
+ const modalId = modals.open({
143
+ ...this.options.default,
144
+ ...options,
145
+ children: options?.content || options?.message,
146
+ });
147
+ return modalId;
148
+ }
149
+
150
+ /**
151
+ * Show a JSON editor/viewer dialog
152
+ */
153
+ public json(data?: any, options?: BaseDialogOptions): void {
154
+ // Implementation to be added
155
+ }
156
+
157
+ /**
158
+ * Show a form dialog for structured input
159
+ */
160
+ public form(options?: BaseDialogOptions): Promise<any> {
161
+ // Implementation to be added
162
+ return Promise.resolve(null);
163
+ }
164
+
165
+ /**
166
+ * Close the currently open dialog or a specific dialog by ID
167
+ */
168
+ public close(modalId?: string): void {
169
+ if (modalId) {
170
+ modals.close(modalId);
171
+ } else {
172
+ modals.closeAll();
173
+ }
174
+ }
175
+
176
+ /**
177
+ * Show a loading/progress dialog with optional progress percentage
178
+ */
179
+ public loading(options?: BaseDialogOptions & { progress?: number }): void {
180
+ // Implementation to be added
181
+ }
182
+
183
+ /**
184
+ * Show an image viewer/gallery dialog
185
+ */
186
+ public image(src: string | string[], options?: BaseDialogOptions): void {
187
+ // Implementation to be added
188
+ }
189
+
190
+ /**
191
+ * Show a table/data grid dialog for displaying tabular data
192
+ */
193
+ public table(
194
+ data: any[],
195
+ options?: BaseDialogOptions & { columns?: any[] },
196
+ ): void {
197
+ // Implementation to be added
198
+ }
199
+
200
+ /**
201
+ * Show a multi-step wizard dialog
202
+ */
203
+ public wizard(steps: any[], options?: BaseDialogOptions): Promise<any> {
204
+ // Implementation to be added
205
+ return Promise.resolve(null);
206
+ }
207
+ }
@@ -0,0 +1,125 @@
1
+ import { type TObject, TypeBoxError } from "@alepha/core";
2
+ import type { InputField } from "@alepha/react-form";
3
+ import type { ReactNode } from "react";
4
+ import type { ControlProps } from "../components/Control.tsx";
5
+ import { getDefaultIcon } from "./icons.tsx";
6
+ import { prettyName } from "./string.ts";
7
+
8
+ export const parseInput = (
9
+ props: GenericControlProps,
10
+ form: {
11
+ error?: Error;
12
+ },
13
+ ): ControlInput => {
14
+ const disabled = false; // form.loading;
15
+ const id = props.input.props.id;
16
+ const label =
17
+ props.title ??
18
+ ("title" in props.input.schema &&
19
+ typeof props.input.schema.title === "string"
20
+ ? props.input.schema.title
21
+ : undefined) ??
22
+ prettyName(props.input.path);
23
+ const description =
24
+ props.description ??
25
+ ("description" in props.input.schema &&
26
+ typeof props.input.schema.description === "string"
27
+ ? props.input.schema.description
28
+ : undefined);
29
+ const error =
30
+ form.error && form.error instanceof TypeBoxError
31
+ ? form.error.value.message
32
+ : undefined;
33
+
34
+ // Auto-generate icon if not provided
35
+ const icon =
36
+ props.icon ??
37
+ getDefaultIcon({
38
+ type:
39
+ props.input.schema && "type" in props.input.schema
40
+ ? String(props.input.schema.type)
41
+ : undefined,
42
+ format:
43
+ props.input.schema &&
44
+ "format" in props.input.schema &&
45
+ typeof props.input.schema.format === "string"
46
+ ? props.input.schema.format
47
+ : undefined,
48
+ name: props.input.props.name,
49
+ isEnum:
50
+ props.input.schema &&
51
+ "enum" in props.input.schema &&
52
+ Boolean(props.input.schema.enum),
53
+ isArray:
54
+ props.input.schema &&
55
+ "type" in props.input.schema &&
56
+ props.input.schema.type === "array",
57
+ });
58
+
59
+ const format =
60
+ props.input.schema &&
61
+ "format" in props.input.schema &&
62
+ typeof props.input.schema.format === "string"
63
+ ? props.input.schema.format
64
+ : undefined;
65
+
66
+ const required = props.input.required;
67
+ const schema = props.input.schema as TObject & { $control?: ControlProps };
68
+
69
+ const inputProps: InputProps = {
70
+ label,
71
+ description,
72
+ error,
73
+ required,
74
+ disabled,
75
+ };
76
+
77
+ if ("minLength" in schema && typeof schema.minLength === "number") {
78
+ inputProps.minLength = schema.minLength;
79
+ }
80
+ if ("maxLength" in schema && typeof schema.maxLength === "number") {
81
+ inputProps.maxLength = schema.maxLength;
82
+ }
83
+ if ("minimum" in schema && typeof schema.minimum === "number") {
84
+ inputProps.minimum = schema.minimum;
85
+ }
86
+ if ("maximum" in schema && typeof schema.maximum === "number") {
87
+ inputProps.maximum = schema.maximum;
88
+ }
89
+
90
+ return {
91
+ id,
92
+ icon,
93
+ format,
94
+ schema: props.input.schema as TObject & { $control?: ControlProps },
95
+ inputProps,
96
+ };
97
+ };
98
+
99
+ export interface GenericControlProps {
100
+ input: InputField;
101
+ title?: string;
102
+ description?: string;
103
+ icon?: ReactNode;
104
+ }
105
+
106
+ export interface ControlInput {
107
+ id?: string;
108
+ icon: ReactNode;
109
+ format?: string;
110
+ schema: TObject & { $control?: ControlProps };
111
+ inputProps: InputProps;
112
+ }
113
+
114
+ export interface InputProps {
115
+ label: string;
116
+ description?: string;
117
+ error?: string;
118
+ required: boolean;
119
+ disabled: boolean;
120
+
121
+ minLength?: number;
122
+ maxLength?: number;
123
+ minimum?: number;
124
+ maximum?: number;
125
+ }
@@ -1,3 +0,0 @@
1
- import { t as AlephaMantineProvider_default } from "./AlephaMantineProvider-WfiC2EH6.js";
2
-
3
- export { AlephaMantineProvider_default as default };
@@ -1 +0,0 @@
1
- {"version":3,"file":"AlephaMantineProvider-WfiC2EH6.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\";\nimport 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":";;;;;;;;;;AAkBA,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;;;;ACpDf,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"}