@alepha/ui 0.10.7 → 0.11.1

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/index.js CHANGED
@@ -1,22 +1,223 @@
1
- import { n as Omnibar_default, t as AlephaMantineProvider_default } from "./AlephaMantineProvider-WfiC2EH6.js";
1
+ import { n as Omnibar_default, t as AlephaMantineProvider_default } from "./AlephaMantineProvider-DDbIijPF.js";
2
2
  import { $module, TypeBoxError } from "@alepha/core";
3
3
  import { $page, AlephaReact, useActive, useAlepha, useInject, useRouter } from "@alepha/react";
4
- import { notifications } from "@mantine/notifications";
5
- import { IconAlertTriangle, IconAt, IconCalendar, IconCheck, IconClock, IconColorPicker, IconFile, IconHash, IconInfoCircle, IconKey, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconSelector, IconSun, IconToggleLeft, IconX } from "@tabler/icons-react";
4
+ import { modals } from "@mantine/modals";
5
+ import { ActionIcon, Autocomplete, Badge, Box, Button, Center, Checkbox, ColorInput, FileInput, Flex, Flex as Flex$1, Grid, Group, Input, Loader, Menu, MultiSelect, NumberInput, Pagination, Paper, PasswordInput, ScrollArea, SegmentedControl, Select, Switch, Table, TagsInput, Text, TextInput, Textarea, Tooltip, UnstyledButton, useComputedColorScheme, useMantineColorScheme } from "@mantine/core";
6
6
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
7
- import { ActionIcon, Autocomplete, Button, ColorInput, FileInput, Flex, Flex as Flex$1, Grid, Input, MultiSelect, NumberInput, PasswordInput, SegmentedControl, Select, Stack, Switch, TagsInput, TextInput, Textarea, useComputedColorScheme, useMantineColorScheme } from "@mantine/core";
7
+ import { useCallback, useEffect, useMemo, useRef, useState } from "react";
8
+ import { notifications } from "@mantine/notifications";
9
+ import { IconAlertTriangle, IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconChevronUp, IconCircle, IconClock, IconColorPicker, IconColumns, IconDownload, IconFile, IconHash, IconInfoCircle, IconKey, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconRefresh, IconSearch, IconSelector, IconSun, IconToggleLeft, IconX } from "@tabler/icons-react";
8
10
  import { useFormState } from "@alepha/react-form";
9
- import { useEffect, useState } from "react";
10
11
  import { DateInput, DateTimePicker, TimeInput } from "@mantine/dates";
11
12
 
12
13
  //#region src/RootRouter.ts
13
14
  var RootRouter = class {
14
15
  root = $page({
15
16
  path: "/",
16
- lazy: () => import("./AlephaMantineProvider-EemOtraW.js")
17
+ lazy: () => import("./AlephaMantineProvider-pOu8hOzK.js")
17
18
  });
18
19
  };
19
20
 
21
+ //#endregion
22
+ //#region src/components/dialogs/AlertDialog.tsx
23
+ function AlertDialog({ options, onClose }) {
24
+ return /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text, {
25
+ mb: "md",
26
+ children: options.message
27
+ }), /* @__PURE__ */ jsx(Group, {
28
+ justify: "flex-end",
29
+ children: /* @__PURE__ */ jsx(Button, {
30
+ onClick: onClose,
31
+ children: options?.okLabel || "OK"
32
+ })
33
+ })] });
34
+ }
35
+
36
+ //#endregion
37
+ //#region src/components/dialogs/ConfirmDialog.tsx
38
+ function ConfirmDialog({ options, onConfirm }) {
39
+ return /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text, {
40
+ mb: "md",
41
+ children: options.message
42
+ }), /* @__PURE__ */ jsxs(Group, {
43
+ justify: "flex-end",
44
+ children: [/* @__PURE__ */ jsx(Button, {
45
+ variant: "subtle",
46
+ onClick: () => onConfirm(false),
47
+ children: options?.cancelLabel || "Cancel"
48
+ }), /* @__PURE__ */ jsx(Button, {
49
+ color: options?.confirmColor || "blue",
50
+ onClick: () => onConfirm(true),
51
+ children: options?.confirmLabel || "Confirm"
52
+ })]
53
+ })] });
54
+ }
55
+
56
+ //#endregion
57
+ //#region src/components/dialogs/PromptDialog.tsx
58
+ function PromptDialog({ options, onSubmit }) {
59
+ const [value, setValue] = useState(options?.defaultValue || "");
60
+ const inputRef = useRef(null);
61
+ useEffect(() => {
62
+ inputRef.current?.focus();
63
+ }, []);
64
+ const handleSubmit = () => {
65
+ if (!options?.required || value.trim()) onSubmit(value);
66
+ };
67
+ const handleKeyDown = (event) => {
68
+ if (event.key === "Enter") handleSubmit();
69
+ };
70
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
71
+ options?.message && /* @__PURE__ */ jsx(Text, {
72
+ mb: "md",
73
+ children: options.message
74
+ }),
75
+ /* @__PURE__ */ jsx(TextInput, {
76
+ ref: inputRef,
77
+ label: options?.label,
78
+ placeholder: options?.placeholder,
79
+ value,
80
+ onChange: (event) => setValue(event.currentTarget.value),
81
+ onKeyDown: handleKeyDown,
82
+ required: options?.required,
83
+ mb: "md"
84
+ }),
85
+ /* @__PURE__ */ jsxs(Group, {
86
+ justify: "flex-end",
87
+ children: [/* @__PURE__ */ jsx(Button, {
88
+ variant: "subtle",
89
+ onClick: () => onSubmit(null),
90
+ children: options?.cancelLabel || "Cancel"
91
+ }), /* @__PURE__ */ jsx(Button, {
92
+ onClick: handleSubmit,
93
+ disabled: options?.required && !value.trim(),
94
+ children: options?.submitLabel || "OK"
95
+ })]
96
+ })
97
+ ] });
98
+ }
99
+
100
+ //#endregion
101
+ //#region src/services/DialogService.tsx
102
+ var DialogService = class {
103
+ options = { default: {
104
+ centered: true,
105
+ withCloseButton: true,
106
+ size: "md",
107
+ overlayProps: {
108
+ backgroundOpacity: .55,
109
+ blur: 3
110
+ },
111
+ transitionProps: {
112
+ transition: "pop",
113
+ duration: 200
114
+ }
115
+ } };
116
+ /**
117
+ * Show an alert dialog with a message
118
+ */
119
+ alert(options) {
120
+ return new Promise((resolve) => {
121
+ const modalId = this.open({
122
+ ...options,
123
+ title: options?.title || "Alert",
124
+ content: /* @__PURE__ */ jsx(AlertDialog, {
125
+ options,
126
+ onClose: () => {
127
+ this.close(modalId);
128
+ resolve();
129
+ }
130
+ })
131
+ });
132
+ });
133
+ }
134
+ /**
135
+ * Show a confirmation dialog that returns a promise
136
+ */
137
+ confirm(options) {
138
+ return new Promise((resolve) => {
139
+ const modalId = this.open({
140
+ ...options,
141
+ title: options?.title || "Confirm",
142
+ closeOnClickOutside: false,
143
+ closeOnEscape: false,
144
+ content: /* @__PURE__ */ jsx(ConfirmDialog, {
145
+ options,
146
+ onConfirm: (confirmed) => {
147
+ this.close(modalId);
148
+ resolve(confirmed);
149
+ }
150
+ })
151
+ });
152
+ });
153
+ }
154
+ /**
155
+ * Show a prompt dialog to get user input
156
+ */
157
+ prompt(options) {
158
+ return new Promise((resolve) => {
159
+ const modalId = this.open({
160
+ ...options,
161
+ title: options?.title || "Input",
162
+ closeOnClickOutside: false,
163
+ closeOnEscape: false,
164
+ content: /* @__PURE__ */ jsx(PromptDialog, {
165
+ options,
166
+ onSubmit: (value) => {
167
+ this.close(modalId);
168
+ resolve(value);
169
+ }
170
+ })
171
+ });
172
+ });
173
+ }
174
+ /**
175
+ * Open a custom dialog with provided content
176
+ */
177
+ open(options) {
178
+ return modals.open({
179
+ ...this.options.default,
180
+ ...options,
181
+ children: options?.content || options?.message
182
+ });
183
+ }
184
+ /**
185
+ * Show a JSON editor/viewer dialog
186
+ */
187
+ json(data, options) {}
188
+ /**
189
+ * Show a form dialog for structured input
190
+ */
191
+ form(options) {
192
+ return Promise.resolve(null);
193
+ }
194
+ /**
195
+ * Close the currently open dialog or a specific dialog by ID
196
+ */
197
+ close(modalId) {
198
+ if (modalId) modals.close(modalId);
199
+ else modals.closeAll();
200
+ }
201
+ /**
202
+ * Show a loading/progress dialog with optional progress percentage
203
+ */
204
+ loading(options) {}
205
+ /**
206
+ * Show an image viewer/gallery dialog
207
+ */
208
+ image(src, options) {}
209
+ /**
210
+ * Show a table/data grid dialog for displaying tabular data
211
+ */
212
+ table(data, options) {}
213
+ /**
214
+ * Show a multi-step wizard dialog
215
+ */
216
+ wizard(steps, options) {
217
+ return Promise.resolve(null);
218
+ }
219
+ };
220
+
20
221
  //#endregion
21
222
  //#region src/services/ToastService.tsx
22
223
  var ToastService = class {
@@ -72,17 +273,38 @@ var ToastService = class {
72
273
 
73
274
  //#endregion
74
275
  //#region src/components/Action.tsx
276
+ const renderMenuItem = (item, index) => {
277
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
278
+ if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
279
+ if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
280
+ trigger: "hover",
281
+ position: "right-start",
282
+ offset: 2,
283
+ children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Menu.Item, {
284
+ leftSection: item.icon,
285
+ rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
286
+ children: item.label
287
+ }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => renderMenuItem(child, childIndex)) })]
288
+ }, index);
289
+ return /* @__PURE__ */ jsx(Menu.Item, {
290
+ leftSection: item.icon,
291
+ onClick: item.onClick,
292
+ color: item.color,
293
+ children: item.label
294
+ }, index);
295
+ };
75
296
  const Action = (_props) => {
76
297
  const props = {
77
298
  variant: "subtle",
78
299
  ..._props
79
300
  };
301
+ const { tooltip, menu,...restProps } = props;
80
302
  if (props.leftSection && !props.children) {
81
- props.className ??= "mantine-Action-iconOnly";
82
- props.p ??= "xs";
303
+ restProps.className ??= "mantine-Action-iconOnly";
304
+ restProps.p ??= "xs";
83
305
  }
84
306
  if (props.textVisibleFrom) {
85
- const { children, textVisibleFrom, leftSection,...rest } = props;
307
+ const { children, textVisibleFrom, leftSection,...rest } = restProps;
86
308
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Flex$1, {
87
309
  w: "100%",
88
310
  visibleFrom: textVisibleFrom,
@@ -90,6 +312,8 @@ const Action = (_props) => {
90
312
  flex: 1,
91
313
  ...rest,
92
314
  leftSection,
315
+ tooltip,
316
+ menu,
93
317
  children
94
318
  })
95
319
  }), /* @__PURE__ */ jsx(Flex$1, {
@@ -98,32 +322,48 @@ const Action = (_props) => {
98
322
  children: /* @__PURE__ */ jsx(Action, {
99
323
  px: "xs",
100
324
  ...rest,
325
+ tooltip,
326
+ menu,
101
327
  children: leftSection
102
328
  })
103
329
  })] });
104
330
  }
105
331
  const renderAction = () => {
106
- if ("href" in props && props.href) return /* @__PURE__ */ jsx(ActionHref, {
107
- ...props,
108
- href: props.href,
109
- children: props.children
332
+ if ("href" in restProps && restProps.href) return /* @__PURE__ */ jsx(ActionHref, {
333
+ ...restProps,
334
+ href: restProps.href,
335
+ children: restProps.children
110
336
  });
111
- if ("onClick" in props && props.onClick) return /* @__PURE__ */ jsx(ActionClick, {
112
- ...props,
113
- onClick: props.onClick,
114
- children: props.children
337
+ if ("onClick" in restProps && restProps.onClick) return /* @__PURE__ */ jsx(ActionClick, {
338
+ ...restProps,
339
+ onClick: restProps.onClick,
340
+ children: restProps.children
115
341
  });
116
- if ("form" in props && props.form) return /* @__PURE__ */ jsx(ActionSubmit, {
117
- ...props,
118
- form: props.form,
119
- children: props.children
342
+ if ("form" in restProps && restProps.form) return /* @__PURE__ */ jsx(ActionSubmit, {
343
+ ...restProps,
344
+ form: restProps.form,
345
+ children: restProps.children
120
346
  });
121
347
  return /* @__PURE__ */ jsx(Button, {
122
- ...props,
123
- children: props.children
348
+ ...restProps,
349
+ children: restProps.children
124
350
  });
125
351
  };
126
- return renderAction();
352
+ let actionElement = renderAction();
353
+ if (menu) actionElement = /* @__PURE__ */ jsxs(Menu, {
354
+ position: menu.position || "bottom-start",
355
+ width: menu.width || 200,
356
+ shadow: menu.shadow || "md",
357
+ children: [/* @__PURE__ */ jsx(Menu.Target, { children: actionElement }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: menu.items.map((item, index) => renderMenuItem(item, index)) })]
358
+ });
359
+ if (tooltip) return /* @__PURE__ */ jsx(Tooltip, { ...typeof tooltip === "string" ? {
360
+ label: tooltip,
361
+ children: actionElement
362
+ } : {
363
+ ...tooltip,
364
+ children: actionElement
365
+ } });
366
+ return actionElement;
127
367
  };
128
368
  var Action_default = Action;
129
369
  /**
@@ -263,6 +503,44 @@ const prettyName = (name) => {
263
503
  return capitalize(name.replaceAll("/", ""));
264
504
  };
265
505
 
506
+ //#endregion
507
+ //#region src/utils/parseInput.ts
508
+ const parseInput = (props, form) => {
509
+ const disabled = false;
510
+ const id = props.input.props.id;
511
+ const label = props.title ?? ("title" in props.input.schema && typeof props.input.schema.title === "string" ? props.input.schema.title : void 0) ?? prettyName(props.input.path);
512
+ const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
513
+ const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
514
+ const icon = props.icon ?? getDefaultIcon({
515
+ type: props.input.schema && "type" in props.input.schema ? String(props.input.schema.type) : void 0,
516
+ format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
517
+ name: props.input.props.name,
518
+ isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
519
+ isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
520
+ });
521
+ const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
522
+ const required = props.input.required;
523
+ const schema = props.input.schema;
524
+ const inputProps = {
525
+ label,
526
+ description,
527
+ error,
528
+ required,
529
+ disabled
530
+ };
531
+ if ("minLength" in schema && typeof schema.minLength === "number") inputProps.minLength = schema.minLength;
532
+ if ("maxLength" in schema && typeof schema.maxLength === "number") inputProps.maxLength = schema.maxLength;
533
+ if ("minimum" in schema && typeof schema.minimum === "number") inputProps.minimum = schema.minimum;
534
+ if ("maximum" in schema && typeof schema.maximum === "number") inputProps.maximum = schema.maximum;
535
+ return {
536
+ id,
537
+ icon,
538
+ format,
539
+ schema: props.input.schema,
540
+ inputProps
541
+ };
542
+ };
543
+
266
544
  //#endregion
267
545
  //#region src/components/ControlDate.tsx
268
546
  /**
@@ -276,9 +554,8 @@ const prettyName = (name) => {
276
554
  * Automatically detects date formats from schema and renders appropriate picker.
277
555
  */
278
556
  const ControlDate = (props) => {
279
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
557
+ const { inputProps, id, icon, format } = parseInput(props, useFormState(props.input));
280
558
  if (!props.input?.props) return null;
281
- const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
282
559
  if (props.datetime || format === "date-time") {
283
560
  const dateTimePickerProps = typeof props.datetime === "object" ? props.datetime : {};
284
561
  return /* @__PURE__ */ jsx(DateTimePicker, {
@@ -339,7 +616,6 @@ var ControlDate_default = ControlDate;
339
616
  */
340
617
  const ControlSelect = (props) => {
341
618
  const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
342
- if (!props.input?.props) return null;
343
619
  const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
344
620
  let itemsEnum;
345
621
  if (isArray && "items" in props.input.schema && props.input.schema.items) {
@@ -347,6 +623,42 @@ const ControlSelect = (props) => {
347
623
  if ("enum" in items && Array.isArray(items.enum)) itemsEnum = items.enum;
348
624
  }
349
625
  const enumValues = props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum : [];
626
+ const [data, setData] = useState([]);
627
+ useEffect(() => {
628
+ if (!props.input?.props) return;
629
+ if (props.loader) props.loader().then(setData);
630
+ else setData(enumValues);
631
+ }, [props.input, props.loader]);
632
+ if (!props.input?.props) return null;
633
+ if (props.segmented) {
634
+ const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
635
+ return /* @__PURE__ */ jsx(Input.Wrapper, {
636
+ ...inputProps,
637
+ children: /* @__PURE__ */ jsx(Flex$1, {
638
+ mt: "calc(var(--mantine-spacing-xs) / 2)",
639
+ children: /* @__PURE__ */ jsx(SegmentedControl, {
640
+ disabled: inputProps.disabled,
641
+ defaultValue: String(props.input.props.defaultValue),
642
+ ...segmentedControlProps,
643
+ onChange: (value) => {
644
+ props.input.set(value);
645
+ },
646
+ data: data.slice(0, 10)
647
+ })
648
+ })
649
+ });
650
+ }
651
+ if (props.autocomplete) {
652
+ const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
653
+ return /* @__PURE__ */ jsx(Autocomplete, {
654
+ ...inputProps,
655
+ id,
656
+ leftSection: icon,
657
+ data,
658
+ ...props.input.props,
659
+ ...autocompleteProps
660
+ });
661
+ }
350
662
  if (isArray && !itemsEnum || props.tags) {
351
663
  const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
352
664
  return /* @__PURE__ */ jsx(TagsInput, {
@@ -378,10 +690,6 @@ const ControlSelect = (props) => {
378
690
  ...multiSelectProps
379
691
  });
380
692
  }
381
- const data = enumValues.map((value) => ({
382
- value,
383
- label: value
384
- }));
385
693
  const selectProps = typeof props.select === "object" ? props.select : {};
386
694
  return /* @__PURE__ */ jsx(Select, {
387
695
  ...inputProps,
@@ -417,10 +725,13 @@ var ControlSelect_default = ControlSelect;
417
725
  *
418
726
  * Automatically handles labels, descriptions, error messages, required state, and default icons.
419
727
  */
420
- const Control = (props) => {
421
- const { inputProps, id, icon } = parseInput(props, useFormState(props.input));
422
- if (!props.input?.props) return null;
423
- const format = props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0;
728
+ const Control = (_props) => {
729
+ const { inputProps, id, icon, format, schema } = parseInput(_props, useFormState(_props.input, ["error"]));
730
+ if (!_props.input?.props) return null;
731
+ const props = {
732
+ ..._props,
733
+ ...schema.$control
734
+ };
424
735
  if (props.custom) {
425
736
  const Custom = props.custom;
426
737
  return /* @__PURE__ */ jsx(Input.Wrapper, {
@@ -470,47 +781,18 @@ const Control = (props) => {
470
781
  ...colorInputProps
471
782
  });
472
783
  }
473
- if (props.segmented) {
474
- const segmentedControlProps = typeof props.segmented === "object" ? props.segmented : {};
475
- const data = segmentedControlProps.data ?? (props.input.schema && "enum" in props.input.schema && Array.isArray(props.input.schema.enum) ? props.input.schema.enum?.map((value) => ({
476
- value,
477
- label: value
478
- })) : []);
479
- return /* @__PURE__ */ jsx(Input.Wrapper, {
480
- ...inputProps,
481
- children: /* @__PURE__ */ jsx(Flex$1, {
482
- mt: "calc(var(--mantine-spacing-xs) / 2)",
483
- children: /* @__PURE__ */ jsx(SegmentedControl, {
484
- disabled: inputProps.disabled,
485
- defaultValue: String(props.input.props.defaultValue),
486
- ...segmentedControlProps,
487
- onChange: (value) => {
488
- props.input.set(value);
489
- },
490
- data
491
- })
492
- })
493
- });
494
- }
495
- if (props.autocomplete) {
496
- const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
497
- return /* @__PURE__ */ jsx(Autocomplete, {
498
- ...inputProps,
499
- id,
500
- leftSection: icon,
501
- ...props.input.props,
502
- ...autocompleteProps
503
- });
504
- }
505
784
  const isEnum = props.input.schema && "enum" in props.input.schema && props.input.schema.enum;
506
785
  const isArray = props.input.schema && "type" in props.input.schema && props.input.schema.type === "array";
507
- if (isEnum || isArray || props.select) return /* @__PURE__ */ jsx(ControlSelect_default, {
508
- input: props.input,
509
- title: props.title,
510
- description: props.description,
511
- icon,
512
- select: props.select
513
- });
786
+ if (isEnum || isArray || props.select) {
787
+ const opts = typeof props.select === "object" ? props.select : {};
788
+ return /* @__PURE__ */ jsx(ControlSelect_default, {
789
+ input: props.input,
790
+ title: props.title,
791
+ description: props.description,
792
+ icon,
793
+ ...opts
794
+ });
795
+ }
514
796
  if (props.input.schema && "type" in props.input.schema && props.input.schema.type === "boolean" || props.switch) {
515
797
  const switchProps = typeof props.switch === "object" ? props.switch : {};
516
798
  return /* @__PURE__ */ jsx(Switch, {
@@ -572,30 +854,6 @@ const Control = (props) => {
572
854
  });
573
855
  };
574
856
  var Control_default = Control;
575
- const parseInput = (props, form) => {
576
- const disabled = false;
577
- const id = props.input.props.id;
578
- const label = props.title ?? ("title" in props.input.schema && typeof props.input.schema.title === "string" ? props.input.schema.title : void 0) ?? prettyName(props.input.path);
579
- const description = props.description ?? ("description" in props.input.schema && typeof props.input.schema.description === "string" ? props.input.schema.description : void 0);
580
- const error = form.error && form.error instanceof TypeBoxError ? form.error.value.message : void 0;
581
- return {
582
- id,
583
- icon: props.icon ?? getDefaultIcon({
584
- type: props.input.schema && "type" in props.input.schema ? String(props.input.schema.type) : void 0,
585
- format: props.input.schema && "format" in props.input.schema && typeof props.input.schema.format === "string" ? props.input.schema.format : void 0,
586
- name: props.input.props.name,
587
- isEnum: props.input.schema && "enum" in props.input.schema && Boolean(props.input.schema.enum),
588
- isArray: props.input.schema && "type" in props.input.schema && props.input.schema.type === "array"
589
- }),
590
- inputProps: {
591
- label,
592
- description,
593
- error,
594
- required: props.input.required,
595
- disabled
596
- }
597
- };
598
- };
599
857
 
600
858
  //#endregion
601
859
  //#region src/components/DarkModeButton.tsx
@@ -603,10 +861,10 @@ const DarkModeButton = (props) => {
603
861
  const { setColorScheme } = useMantineColorScheme();
604
862
  const computedColorScheme = useComputedColorScheme("light");
605
863
  const [colorScheme, setColorScheme2] = useState("default");
864
+ const mode = props.mode ?? "minimal";
606
865
  useEffect(() => {
607
866
  setColorScheme2(computedColorScheme);
608
867
  }, [computedColorScheme]);
609
- const mode = props.mode ?? "minimal";
610
868
  const toggleColorScheme = () => {
611
869
  setColorScheme(computedColorScheme === "dark" ? "light" : "dark");
612
870
  };
@@ -636,11 +894,523 @@ const DarkModeButton = (props) => {
636
894
  variant: props.variant ?? "default",
637
895
  size: props.size ?? "lg",
638
896
  "aria-label": "Toggle color scheme",
639
- children: colorScheme === "dark" ? /* @__PURE__ */ jsx(IconSun, { size: 20 }) : /* @__PURE__ */ jsx(IconMoon, { size: 20 })
897
+ children: colorScheme === "dark" ? /* @__PURE__ */ jsx(IconSun, { size: 20 }) : colorScheme === "light" ? /* @__PURE__ */ jsx(IconMoon, { size: 20 }) : /* @__PURE__ */ jsx(Flex$1, { h: 20 })
640
898
  });
641
899
  };
642
900
  var DarkModeButton_default = DarkModeButton;
643
901
 
902
+ //#endregion
903
+ //#region src/components/DataTable.tsx
904
+ function getNestedValue(obj, path) {
905
+ return path.split(".").reduce((acc, part) => acc?.[part], obj);
906
+ }
907
+ function DataTable({ data = [], columns: initialColumns = [], loading = false, emptyMessage = "No data available", selectable = false, selectedRows = [], onRowSelect, sortable = false, sort, onSortChange, filterable = false, filters = [], onFiltersChange, filterPlaceholder = "Search...", paginate = false, page = 1, pageSize = 10, totalRecords, pageSizeOptions = [
908
+ 10,
909
+ 25,
910
+ 50,
911
+ 100
912
+ ], onPageChange, onPageSizeChange, rowActions, onRowClick, rowClassName, showHeader = true, showFooter = true, stickyHeader = false, striped = false, highlightOnHover = true, showToolbar = true, title, actions, showColumnToggle = true, showRefresh = false, onRefresh, showExport = false, onExport, height, minHeight, maxHeight,...tableProps }) {
913
+ const [hiddenColumns, setHiddenColumns] = useState(/* @__PURE__ */ new Set());
914
+ const [globalFilter, setGlobalFilter] = useState("");
915
+ const [internalPage, setInternalPage] = useState(page);
916
+ const [internalPageSize, setInternalPageSize] = useState(pageSize);
917
+ const [internalSort, setInternalSort] = useState(sort);
918
+ const [internalFilters, setInternalFilters] = useState(filters);
919
+ const [internalSelectedRows, setInternalSelectedRows] = useState(selectedRows);
920
+ const currentPage = onPageChange ? page : internalPage;
921
+ const currentPageSize = onPageSizeChange ? pageSize : internalPageSize;
922
+ const currentSort = onSortChange ? sort : internalSort;
923
+ const currentFilters = onFiltersChange ? filters : internalFilters;
924
+ const currentSelectedRows = onRowSelect ? selectedRows : internalSelectedRows;
925
+ const visibleColumns = useMemo(() => initialColumns.filter((col) => !col.hidden && !hiddenColumns.has(String(col.accessor))), [initialColumns, hiddenColumns]);
926
+ const processedData = useMemo(() => {
927
+ let result = [...data];
928
+ if (filterable && globalFilter) result = result.filter((row) => {
929
+ return visibleColumns.some((col) => {
930
+ const value = getNestedValue(row, String(col.accessor));
931
+ return String(value).toLowerCase().includes(globalFilter.toLowerCase());
932
+ });
933
+ });
934
+ if (filterable && currentFilters.length > 0) result = result.filter((row) => {
935
+ return currentFilters.every((filter) => {
936
+ const value = String(getNestedValue(row, filter.column)).toLowerCase();
937
+ const filterValue = filter.value.toLowerCase();
938
+ switch (filter.operator) {
939
+ case "equals": return value === filterValue;
940
+ case "startsWith": return value.startsWith(filterValue);
941
+ case "endsWith": return value.endsWith(filterValue);
942
+ default: return value.includes(filterValue);
943
+ }
944
+ });
945
+ });
946
+ if (sortable && currentSort?.direction) result.sort((a, b) => {
947
+ const aVal = getNestedValue(a, currentSort.column);
948
+ const bVal = getNestedValue(b, currentSort.column);
949
+ if (aVal === bVal) return 0;
950
+ if (aVal === null || aVal === void 0) return 1;
951
+ if (bVal === null || bVal === void 0) return -1;
952
+ const comparison = aVal < bVal ? -1 : 1;
953
+ return currentSort.direction === "asc" ? comparison : -comparison;
954
+ });
955
+ return result;
956
+ }, [
957
+ data,
958
+ visibleColumns,
959
+ filterable,
960
+ globalFilter,
961
+ currentFilters,
962
+ sortable,
963
+ currentSort
964
+ ]);
965
+ const paginatedData = useMemo(() => {
966
+ if (!paginate) return processedData;
967
+ const startIndex = (currentPage - 1) * currentPageSize;
968
+ return processedData.slice(startIndex, startIndex + currentPageSize);
969
+ }, [
970
+ processedData,
971
+ paginate,
972
+ currentPage,
973
+ currentPageSize
974
+ ]);
975
+ const totalPages = useMemo(() => {
976
+ const total = totalRecords ?? processedData.length;
977
+ return Math.ceil(total / currentPageSize);
978
+ }, [
979
+ totalRecords,
980
+ processedData.length,
981
+ currentPageSize
982
+ ]);
983
+ const handleSort = useCallback((column) => {
984
+ if (!sortable) return;
985
+ const newSort = {
986
+ column,
987
+ direction: currentSort?.column === column ? currentSort.direction === "asc" ? "desc" : currentSort.direction === "desc" ? null : "asc" : "asc"
988
+ };
989
+ if (onSortChange) onSortChange(newSort);
990
+ else setInternalSort(newSort);
991
+ }, [
992
+ sortable,
993
+ currentSort,
994
+ onSortChange
995
+ ]);
996
+ const handlePageChange = useCallback((newPage) => {
997
+ if (onPageChange) onPageChange(newPage);
998
+ else setInternalPage(newPage);
999
+ }, [onPageChange]);
1000
+ const handlePageSizeChange = useCallback((size) => {
1001
+ const newSize = Number(size) || currentPageSize;
1002
+ if (onPageSizeChange) {
1003
+ onPageSizeChange(newSize);
1004
+ onPageChange?.(1);
1005
+ } else {
1006
+ setInternalPageSize(newSize);
1007
+ setInternalPage(1);
1008
+ }
1009
+ }, [
1010
+ currentPageSize,
1011
+ onPageSizeChange,
1012
+ onPageChange
1013
+ ]);
1014
+ const handleSelectAll = useCallback((checked) => {
1015
+ const newSelection = checked ? paginatedData : [];
1016
+ if (onRowSelect) onRowSelect(newSelection);
1017
+ else setInternalSelectedRows(newSelection);
1018
+ }, [paginatedData, onRowSelect]);
1019
+ const handleSelectRow = useCallback((row, checked) => {
1020
+ const newSelection = checked ? [...currentSelectedRows, row] : currentSelectedRows.filter((r) => r !== row);
1021
+ if (onRowSelect) onRowSelect(newSelection);
1022
+ else setInternalSelectedRows(newSelection);
1023
+ }, [currentSelectedRows, onRowSelect]);
1024
+ const handleColumnToggle = useCallback((column) => {
1025
+ const newHidden = new Set(hiddenColumns);
1026
+ if (newHidden.has(column)) newHidden.delete(column);
1027
+ else newHidden.add(column);
1028
+ setHiddenColumns(newHidden);
1029
+ }, [hiddenColumns]);
1030
+ const isAllSelected = currentSelectedRows.length > 0 && currentSelectedRows.length === paginatedData.length;
1031
+ const isIndeterminate = currentSelectedRows.length > 0 && currentSelectedRows.length < paginatedData.length;
1032
+ const renderSortIcon = (column) => {
1033
+ if (!sortable) return null;
1034
+ if (currentSort?.column === column) {
1035
+ if (currentSort.direction === "asc") return /* @__PURE__ */ jsx(IconChevronUp, {
1036
+ className: "alepha-datatable-sort-icon",
1037
+ size: 16
1038
+ });
1039
+ if (currentSort.direction === "desc") return /* @__PURE__ */ jsx(IconChevronDown, {
1040
+ className: "alepha-datatable-sort-icon",
1041
+ size: 16
1042
+ });
1043
+ }
1044
+ return /* @__PURE__ */ jsx(IconChevronUp, {
1045
+ className: "alepha-datatable-sort-icon-inactive",
1046
+ size: 16
1047
+ });
1048
+ };
1049
+ const toolbar = showToolbar && (title || actions || filterable || showColumnToggle || showRefresh || showExport) && /* @__PURE__ */ jsx(Paper, {
1050
+ className: "alepha-datatable-toolbar",
1051
+ p: "md",
1052
+ mb: "sm",
1053
+ children: /* @__PURE__ */ jsxs(Flex$1, {
1054
+ justify: "space-between",
1055
+ align: "center",
1056
+ gap: "md",
1057
+ children: [/* @__PURE__ */ jsxs(Group, { children: [title && /* @__PURE__ */ jsx(Text, {
1058
+ size: "lg",
1059
+ fw: 600,
1060
+ children: title
1061
+ }), currentSelectedRows.length > 0 && /* @__PURE__ */ jsxs(Badge, {
1062
+ color: "blue",
1063
+ variant: "light",
1064
+ children: [currentSelectedRows.length, " selected"]
1065
+ })] }), /* @__PURE__ */ jsxs(Group, { children: [
1066
+ filterable && /* @__PURE__ */ jsx(TextInput, {
1067
+ placeholder: filterPlaceholder,
1068
+ value: globalFilter,
1069
+ onChange: (e) => setGlobalFilter(e.target.value),
1070
+ leftSection: /* @__PURE__ */ jsx(IconSearch, { size: 16 }),
1071
+ rightSection: globalFilter && /* @__PURE__ */ jsx(ActionIcon, {
1072
+ size: "xs",
1073
+ variant: "subtle",
1074
+ onClick: () => setGlobalFilter(""),
1075
+ children: /* @__PURE__ */ jsx(IconX, { size: 14 })
1076
+ }),
1077
+ className: "alepha-datatable-search-input"
1078
+ }),
1079
+ showColumnToggle && /* @__PURE__ */ jsxs(Menu, {
1080
+ position: "bottom-end",
1081
+ children: [/* @__PURE__ */ jsx(Menu.Target, { children: /* @__PURE__ */ jsx(Tooltip, {
1082
+ label: "Toggle columns",
1083
+ children: /* @__PURE__ */ jsx(ActionIcon, {
1084
+ variant: "subtle",
1085
+ children: /* @__PURE__ */ jsx(IconColumns, { size: 20 })
1086
+ })
1087
+ }) }), /* @__PURE__ */ jsxs(Menu.Dropdown, { children: [/* @__PURE__ */ jsx(Menu.Label, { children: "Visible columns" }), initialColumns.map((col) => /* @__PURE__ */ jsx(Menu.Item, {
1088
+ onClick: () => handleColumnToggle(String(col.accessor)),
1089
+ leftSection: /* @__PURE__ */ jsx(Checkbox, {
1090
+ checked: !hiddenColumns.has(String(col.accessor)) && !col.hidden,
1091
+ readOnly: true,
1092
+ size: "xs"
1093
+ }),
1094
+ children: col.title || String(col.accessor)
1095
+ }, String(col.accessor)))] })]
1096
+ }),
1097
+ showRefresh && /* @__PURE__ */ jsx(Tooltip, {
1098
+ label: "Refresh",
1099
+ children: /* @__PURE__ */ jsx(ActionIcon, {
1100
+ variant: "subtle",
1101
+ onClick: onRefresh,
1102
+ loading,
1103
+ children: /* @__PURE__ */ jsx(IconRefresh, { size: 20 })
1104
+ })
1105
+ }),
1106
+ showExport && /* @__PURE__ */ jsx(Tooltip, {
1107
+ label: "Export",
1108
+ children: /* @__PURE__ */ jsx(ActionIcon, {
1109
+ variant: "subtle",
1110
+ onClick: onExport,
1111
+ children: /* @__PURE__ */ jsx(IconDownload, { size: 20 })
1112
+ })
1113
+ }),
1114
+ actions
1115
+ ] })]
1116
+ })
1117
+ });
1118
+ const tableContent = /* @__PURE__ */ jsxs(Table, {
1119
+ striped,
1120
+ highlightOnHover,
1121
+ stickyHeader,
1122
+ className: "alepha-datatable-table",
1123
+ ...tableProps,
1124
+ children: [
1125
+ showHeader && /* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
1126
+ selectable && /* @__PURE__ */ jsx(Table.Th, {
1127
+ className: "alepha-datatable-checkbox-column",
1128
+ children: /* @__PURE__ */ jsx(Checkbox, {
1129
+ checked: isAllSelected,
1130
+ indeterminate: isIndeterminate,
1131
+ onChange: (e) => handleSelectAll(e.currentTarget.checked)
1132
+ })
1133
+ }),
1134
+ visibleColumns.map((column) => /* @__PURE__ */ jsx(Table.Th, {
1135
+ className: `alepha-datatable-th ${column.headerClassName || ""}`,
1136
+ style: {
1137
+ width: column.width,
1138
+ textAlign: column.align,
1139
+ cursor: column.sortable && sortable ? "pointer" : "default"
1140
+ },
1141
+ onClick: () => column.sortable && handleSort(String(column.accessor)),
1142
+ children: /* @__PURE__ */ jsxs(Group, {
1143
+ gap: "xs",
1144
+ justify: column.align === "center" ? "center" : column.align === "right" ? "flex-end" : "flex-start",
1145
+ children: [column.renderHeader ? column.renderHeader() : column.title || String(column.accessor), column.sortable && renderSortIcon(String(column.accessor))]
1146
+ })
1147
+ }, String(column.accessor))),
1148
+ rowActions && /* @__PURE__ */ jsx(Table.Th, {
1149
+ className: "alepha-datatable-actions-column",
1150
+ children: "Actions"
1151
+ })
1152
+ ] }) }),
1153
+ /* @__PURE__ */ jsx(Table.Tbody, { children: loading ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
1154
+ colSpan: visibleColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
1155
+ children: /* @__PURE__ */ jsx(Center, {
1156
+ py: "xl",
1157
+ children: /* @__PURE__ */ jsx(Loader, { size: "sm" })
1158
+ })
1159
+ }) }) : paginatedData.length === 0 ? /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
1160
+ colSpan: visibleColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
1161
+ children: /* @__PURE__ */ jsx(Center, {
1162
+ py: "xl",
1163
+ children: /* @__PURE__ */ jsx(Text, {
1164
+ c: "dimmed",
1165
+ children: emptyMessage
1166
+ })
1167
+ })
1168
+ }) }) : paginatedData.map((row, index) => {
1169
+ const isSelected = currentSelectedRows.includes(row);
1170
+ return /* @__PURE__ */ jsxs(Table.Tr, {
1171
+ className: `alepha-datatable-tr ${isSelected ? "alepha-datatable-selected" : ""} ${rowClassName?.(row, index) || ""}`,
1172
+ onClick: () => onRowClick?.(row, index),
1173
+ style: { cursor: onRowClick ? "pointer" : "default" },
1174
+ children: [
1175
+ selectable && /* @__PURE__ */ jsx(Table.Td, {
1176
+ className: "alepha-datatable-checkbox-column",
1177
+ children: /* @__PURE__ */ jsx(Checkbox, {
1178
+ checked: isSelected,
1179
+ onChange: (e) => handleSelectRow(row, e.currentTarget.checked),
1180
+ onClick: (e) => e.stopPropagation()
1181
+ })
1182
+ }),
1183
+ visibleColumns.map((column) => {
1184
+ const value = getNestedValue(row, String(column.accessor));
1185
+ return /* @__PURE__ */ jsx(Table.Td, {
1186
+ className: column.className,
1187
+ style: {
1188
+ textAlign: column.align,
1189
+ ...column.ellipsis && {
1190
+ maxWidth: column.width,
1191
+ overflow: "hidden",
1192
+ textOverflow: "ellipsis",
1193
+ whiteSpace: "nowrap"
1194
+ }
1195
+ },
1196
+ children: column.render ? column.render(value, row, index) : value
1197
+ }, String(column.accessor));
1198
+ }),
1199
+ rowActions && /* @__PURE__ */ jsx(Table.Td, {
1200
+ className: "alepha-datatable-actions-column",
1201
+ children: rowActions(row, index)
1202
+ })
1203
+ ]
1204
+ }, index);
1205
+ }) }),
1206
+ showFooter && paginate && /* @__PURE__ */ jsx(Table.Tfoot, { children: /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
1207
+ colSpan: visibleColumns.length + (selectable ? 1 : 0) + (rowActions ? 1 : 0),
1208
+ children: /* @__PURE__ */ jsxs(Flex$1, {
1209
+ justify: "space-between",
1210
+ align: "center",
1211
+ py: "xs",
1212
+ children: [/* @__PURE__ */ jsxs(Group, {
1213
+ gap: "xs",
1214
+ children: [/* @__PURE__ */ jsxs(Text, {
1215
+ size: "sm",
1216
+ c: "dimmed",
1217
+ children: [
1218
+ "Showing ",
1219
+ (currentPage - 1) * currentPageSize + 1,
1220
+ " to",
1221
+ " ",
1222
+ Math.min(currentPage * currentPageSize, totalRecords ?? processedData.length),
1223
+ " ",
1224
+ "of ",
1225
+ totalRecords ?? processedData.length,
1226
+ " records"
1227
+ ]
1228
+ }), /* @__PURE__ */ jsx(Select, {
1229
+ size: "xs",
1230
+ value: String(currentPageSize),
1231
+ onChange: handlePageSizeChange,
1232
+ data: pageSizeOptions.map((size) => ({
1233
+ value: String(size),
1234
+ label: `${size} / page`
1235
+ })),
1236
+ className: "alepha-datatable-page-size-select"
1237
+ })]
1238
+ }), /* @__PURE__ */ jsx(Pagination, {
1239
+ size: "sm",
1240
+ value: currentPage,
1241
+ onChange: handlePageChange,
1242
+ total: totalPages,
1243
+ siblings: 1,
1244
+ boundaries: 1
1245
+ })]
1246
+ })
1247
+ }) }) })
1248
+ ]
1249
+ });
1250
+ return /* @__PURE__ */ jsxs(Box, {
1251
+ className: "alepha-datatable-container",
1252
+ children: [toolbar, height || maxHeight ? /* @__PURE__ */ jsx(ScrollArea.Autosize, {
1253
+ mah: maxHeight,
1254
+ h: height,
1255
+ mih: minHeight,
1256
+ children: tableContent
1257
+ }) : tableContent]
1258
+ });
1259
+ }
1260
+
1261
+ //#endregion
1262
+ //#region src/components/Sidebar.tsx
1263
+ const Sidebar = ({ menu, defaultOpenIds = [], onItemClick, showSearchButton = false, onSearchClick }) => {
1264
+ const [openIds, setOpenIds] = useState(new Set(defaultOpenIds));
1265
+ const toggleOpen = (id) => {
1266
+ setOpenIds((prev) => {
1267
+ const newSet = new Set(prev);
1268
+ if (newSet.has(id)) newSet.delete(id);
1269
+ else newSet.add(id);
1270
+ return newSet;
1271
+ });
1272
+ };
1273
+ return /* @__PURE__ */ jsxs(Box, {
1274
+ component: "nav",
1275
+ className: "alepha-sidebar",
1276
+ children: [showSearchButton && /* @__PURE__ */ jsx(UnstyledButton, {
1277
+ className: "alepha-sidebar-search-button",
1278
+ onClick: onSearchClick,
1279
+ children: /* @__PURE__ */ jsxs(Box, {
1280
+ className: "alepha-sidebar-search-button-content",
1281
+ children: [/* @__PURE__ */ jsxs(Box, {
1282
+ className: "alepha-sidebar-search-button-left",
1283
+ children: [/* @__PURE__ */ jsx(IconSearch, { size: 16 }), /* @__PURE__ */ jsx("span", { children: "Search..." })]
1284
+ }), /* @__PURE__ */ jsx(Box, {
1285
+ className: "alepha-sidebar-search-button-shortcut",
1286
+ children: /* @__PURE__ */ jsx("kbd", { children: "⌘+K" })
1287
+ })]
1288
+ })
1289
+ }), menu.map((item) => /* @__PURE__ */ jsx(SidebarItem, {
1290
+ item,
1291
+ level: 0,
1292
+ openIds,
1293
+ onToggle: toggleOpen,
1294
+ onItemClick
1295
+ }, item.id))]
1296
+ });
1297
+ };
1298
+ const SidebarItem = (props) => {
1299
+ const { item, level } = props;
1300
+ if (level > 2) return null;
1301
+ if (item.href) return /* @__PURE__ */ jsx(SidebarItemHref, { ...props });
1302
+ return /* @__PURE__ */ jsx(SidebarItemButton, { ...props });
1303
+ };
1304
+ const SidebarItemHref = ({ item, level, openIds, onToggle, onItemClick }) => {
1305
+ const hasChildren = item.children && item.children.length > 0;
1306
+ const isOpen = openIds.has(item.id);
1307
+ const { isActive, anchorProps } = useActive({
1308
+ href: item.href,
1309
+ startWith: item.activeStartsWith
1310
+ });
1311
+ const handleItemClick = (e) => {
1312
+ if (hasChildren) {
1313
+ e.preventDefault();
1314
+ onToggle(item.id);
1315
+ }
1316
+ };
1317
+ return /* @__PURE__ */ jsxs(Box, {
1318
+ className: "alepha-sidebar-item-wrapper",
1319
+ children: [/* @__PURE__ */ jsx(UnstyledButton, {
1320
+ component: "a",
1321
+ ...anchorProps,
1322
+ className: `alepha-sidebar-item alepha-sidebar-level-${level} ${isActive ? "alepha-sidebar-item-active" : ""}`,
1323
+ onClick: hasChildren ? handleItemClick : anchorProps.onClick,
1324
+ children: /* @__PURE__ */ jsxs(Flex$1, {
1325
+ justify: "space-between",
1326
+ align: "center",
1327
+ w: "100%",
1328
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
1329
+ className: "alepha-sidebar-item-content",
1330
+ align: "center",
1331
+ gap: 10,
1332
+ children: [/* @__PURE__ */ jsx(Box, {
1333
+ className: "alepha-sidebar-item-icon",
1334
+ children: item.icon || /* @__PURE__ */ jsx(IconCircle, { size: 16 })
1335
+ }), /* @__PURE__ */ jsx(Box, {
1336
+ className: "alepha-sidebar-item-label",
1337
+ children: item.label
1338
+ })]
1339
+ }), hasChildren && /* @__PURE__ */ jsx(Box, {
1340
+ className: "alepha-sidebar-item-caret",
1341
+ children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 })
1342
+ })]
1343
+ })
1344
+ }), hasChildren && isOpen && /* @__PURE__ */ jsxs(Box, {
1345
+ className: "alepha-sidebar-children",
1346
+ "data-parent-level": level,
1347
+ children: [(level === 0 || level === 1) && /* @__PURE__ */ jsx(Box, { className: "alepha-sidebar-vertical-bar" }), /* @__PURE__ */ jsx(Box, {
1348
+ className: "alepha-sidebar-children-items",
1349
+ children: item.children.map((child) => /* @__PURE__ */ jsx(SidebarItem, {
1350
+ item: child,
1351
+ level: level + 1,
1352
+ openIds,
1353
+ onToggle,
1354
+ onItemClick
1355
+ }, child.id))
1356
+ })]
1357
+ })]
1358
+ });
1359
+ };
1360
+ const SidebarItemButton = ({ item, level, openIds, onToggle, onItemClick }) => {
1361
+ const hasChildren = item.children && item.children.length > 0;
1362
+ const isOpen = openIds.has(item.id);
1363
+ const handleItemClick = (e) => {
1364
+ e.preventDefault();
1365
+ if (hasChildren) onToggle(item.id);
1366
+ else {
1367
+ onItemClick?.(item);
1368
+ item.onClick?.();
1369
+ }
1370
+ };
1371
+ return /* @__PURE__ */ jsxs(Box, {
1372
+ className: "alepha-sidebar-item-wrapper",
1373
+ children: [/* @__PURE__ */ jsx(UnstyledButton, {
1374
+ component: "button",
1375
+ className: `alepha-sidebar-item alepha-sidebar-level-${level}`,
1376
+ onClick: handleItemClick,
1377
+ children: /* @__PURE__ */ jsxs(Flex$1, {
1378
+ justify: "space-between",
1379
+ align: "center",
1380
+ w: "100%",
1381
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
1382
+ className: "alepha-sidebar-item-content",
1383
+ align: "center",
1384
+ gap: 10,
1385
+ children: [/* @__PURE__ */ jsx(Box, {
1386
+ className: "alepha-sidebar-item-icon",
1387
+ children: item.icon || /* @__PURE__ */ jsx(IconCircle, { size: 16 })
1388
+ }), /* @__PURE__ */ jsx(Box, {
1389
+ className: "alepha-sidebar-item-label",
1390
+ children: item.label
1391
+ })]
1392
+ }), hasChildren && /* @__PURE__ */ jsx(Box, {
1393
+ className: "alepha-sidebar-item-caret",
1394
+ children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 })
1395
+ })]
1396
+ })
1397
+ }), hasChildren && isOpen && /* @__PURE__ */ jsxs(Box, {
1398
+ className: "alepha-sidebar-children",
1399
+ "data-parent-level": level,
1400
+ children: [(level === 0 || level === 1) && /* @__PURE__ */ jsx(Box, { className: "alepha-sidebar-vertical-bar" }), /* @__PURE__ */ jsx(Box, {
1401
+ className: "alepha-sidebar-children-items",
1402
+ children: item.children.map((child) => /* @__PURE__ */ jsx(SidebarItem, {
1403
+ item: child,
1404
+ level: level + 1,
1405
+ openIds,
1406
+ onToggle,
1407
+ onItemClick
1408
+ }, child.id))
1409
+ })]
1410
+ })]
1411
+ });
1412
+ };
1413
+
644
1414
  //#endregion
645
1415
  //#region src/components/TypeForm.tsx
646
1416
  /**
@@ -669,7 +1439,7 @@ var DarkModeButton_default = DarkModeButton;
669
1439
  * ```
670
1440
  */
671
1441
  const TypeForm = (props) => {
672
- const { form, columns = 1, children, controlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps } = props;
1442
+ const { form, columns = 3, children, controlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps } = props;
673
1443
  if (!form.options?.schema?.properties) return null;
674
1444
  const supportedFields = Object.keys(form.options.schema.properties).filter((fieldName) => {
675
1445
  const field = form.input[fieldName];
@@ -684,7 +1454,7 @@ const TypeForm = (props) => {
684
1454
  const colSpan = typeof columns === "number" ? {
685
1455
  xs: 12,
686
1456
  sm: 6,
687
- lg: 12 / 3
1457
+ lg: 12 / columns
688
1458
  } : {
689
1459
  base: columns.base ? 12 / columns.base : void 0,
690
1460
  xs: columns.xs ? 12 / columns.xs : 12,
@@ -707,20 +1477,41 @@ const TypeForm = (props) => {
707
1477
  }, fieldName);
708
1478
  }) });
709
1479
  };
710
- const content = /* @__PURE__ */ jsxs(Stack, { children: [renderFields(), !skipSubmitButton && /* @__PURE__ */ jsx(Action_default, {
711
- form,
712
- ...submitButtonProps,
713
- children: submitButtonProps?.children ?? "Submit"
714
- })] });
1480
+ const content = /* @__PURE__ */ jsxs(Flex$1, {
1481
+ direction: "column",
1482
+ gap: "sm",
1483
+ children: [renderFields(), !skipSubmitButton && /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(Action_default, {
1484
+ form,
1485
+ ...submitButtonProps,
1486
+ children: submitButtonProps?.children ?? "Submit"
1487
+ }), /* @__PURE__ */ jsx("button", {
1488
+ type: "reset",
1489
+ children: "Reset"
1490
+ })] })]
1491
+ });
715
1492
  if (skipFormElement) return content;
716
1493
  return /* @__PURE__ */ jsx("form", {
717
- onSubmit: form.onSubmit,
718
- noValidate: true,
1494
+ ...form.props,
719
1495
  children: content
720
1496
  });
721
1497
  };
722
1498
  var TypeForm_default = TypeForm;
723
1499
 
1500
+ //#endregion
1501
+ //#region src/hooks/useDialog.ts
1502
+ /**
1503
+ * Use this hook to access the Dialog Service for showing various dialog types.
1504
+ *
1505
+ * @example
1506
+ * const dialog = useDialog();
1507
+ * await dialog.alert({ title: "Alert", message: "This is an alert message" });
1508
+ * const confirmed = await dialog.confirm({ title: "Confirm", message: "Are you sure?" });
1509
+ * const input = await dialog.prompt({ title: "Input", message: "Enter your name:" });
1510
+ */
1511
+ const useDialog = () => {
1512
+ return useInject(DialogService);
1513
+ };
1514
+
724
1515
  //#endregion
725
1516
  //#region src/hooks/useToast.ts
726
1517
  /**
@@ -738,7 +1529,7 @@ const useToast = () => {
738
1529
  //#endregion
739
1530
  //#region src/index.ts
740
1531
  /**
741
- *
1532
+ * Mantine
742
1533
  *
743
1534
  * @module alepha.ui
744
1535
  */
@@ -746,11 +1537,12 @@ const AlephaUI = $module({
746
1537
  name: "alepha.ui",
747
1538
  services: [
748
1539
  AlephaReact,
1540
+ DialogService,
749
1541
  ToastService,
750
1542
  RootRouter
751
1543
  ]
752
1544
  });
753
1545
 
754
1546
  //#endregion
755
- export { Action_default as Action, AlephaMantineProvider_default as AlephaMantineProvider, AlephaUI, Control_default as Control, ControlDate_default as ControlDate, ControlSelect_default as ControlSelect, DarkModeButton_default as DarkModeButton, Flex, ICON_SIZES, Omnibar_default as Omnibar, RootRouter, ToastService, TypeForm_default as TypeForm, capitalize, getDefaultIcon, prettyName, useToast };
1547
+ export { Action_default as Action, AlephaMantineProvider_default as AlephaMantineProvider, AlephaUI, AlertDialog, ConfirmDialog, Control_default as Control, ControlDate_default as ControlDate, ControlSelect_default as ControlSelect, DarkModeButton_default as DarkModeButton, DataTable, DialogService, Flex, ICON_SIZES, Omnibar_default as Omnibar, PromptDialog, RootRouter, Sidebar, SidebarItem, ToastService, TypeForm_default as TypeForm, capitalize, getDefaultIcon, prettyName, useDialog, useToast };
756
1548
  //# sourceMappingURL=index.js.map