@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
package/dist/index.js CHANGED
@@ -1,61 +1,61 @@
1
- import { n as Omnibar_default, t as AlephaMantineProvider_default } from "./AlephaMantineProvider-DDbIijPF.js";
1
+ import { i as ToastService, n as Omnibar_default, r as useToast, t as AlephaMantineProvider_default } from "./AlephaMantineProvider-Be0DAazb.js";
2
2
  import { $module, TypeBoxError } from "@alepha/core";
3
- import { $page, AlephaReact, useActive, useAlepha, useInject, useRouter } from "@alepha/react";
3
+ import { AlephaReactForm, useFormState } from "@alepha/react-form";
4
+ import { AlephaReactHead } from "@alepha/react-head";
5
+ import { AlephaReactI18n, useI18n } from "@alepha/react-i18n";
6
+ import { $page, NestedView, useAction, useActive, useEvents, useInject, useRouter, useStore } from "@alepha/react";
4
7
  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";
8
+ import { AppShell, Autocomplete, Burger, Button, ColorInput, Divider, FileInput, Flex, Flex as Flex$1, Grid, Group, Input, Kbd, Menu, MultiSelect, NumberInput, PasswordInput, SegmentedControl, Select, Switch, Table, TagsInput, Text, Text as Text$1, TextInput, Textarea, ThemeIcon, Tooltip, useComputedColorScheme, useMantineColorScheme } from "@mantine/core";
6
9
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
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";
10
- import { useFormState } from "@alepha/react-form";
10
+ import { useCallback, useEffect, useRef, useState } from "react";
11
+ import { IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClock, IconColorPicker, IconFile, IconHash, IconKey, IconLanguage, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconSearch, IconSelector, IconSquareRounded, IconSun, IconToggleLeft } from "@tabler/icons-react";
12
+ import { spotlight } from "@mantine/spotlight";
11
13
  import { DateInput, DateTimePicker, TimeInput } from "@mantine/dates";
12
14
 
13
15
  //#region src/RootRouter.ts
14
16
  var RootRouter = class {
15
17
  root = $page({
16
18
  path: "/",
17
- lazy: () => import("./AlephaMantineProvider-pOu8hOzK.js")
19
+ lazy: () => import("./AlephaMantineProvider-Ba88lMeq.js")
18
20
  });
19
21
  };
20
22
 
21
23
  //#endregion
22
24
  //#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
- }
25
+ const AlertDialog = ({ options, onClose }) => /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text$1, {
26
+ mb: "md",
27
+ children: options.message
28
+ }), /* @__PURE__ */ jsx(Group, {
29
+ justify: "flex-end",
30
+ children: /* @__PURE__ */ jsx(Button, {
31
+ onClick: onClose,
32
+ children: options?.okLabel || "OK"
33
+ })
34
+ })] });
35
+ var AlertDialog_default = AlertDialog;
35
36
 
36
37
  //#endregion
37
38
  //#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
- }
39
+ const ConfirmDialog = ({ options, onConfirm }) => /* @__PURE__ */ jsxs(Fragment, { children: [options?.message && /* @__PURE__ */ jsx(Text$1, {
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
+ var ConfirmDialog_default = ConfirmDialog;
55
55
 
56
56
  //#endregion
57
57
  //#region src/components/dialogs/PromptDialog.tsx
58
- function PromptDialog({ options, onSubmit }) {
58
+ const PromptDialog = ({ options, onSubmit }) => {
59
59
  const [value, setValue] = useState(options?.defaultValue || "");
60
60
  const inputRef = useRef(null);
61
61
  useEffect(() => {
@@ -68,7 +68,7 @@ function PromptDialog({ options, onSubmit }) {
68
68
  if (event.key === "Enter") handleSubmit();
69
69
  };
70
70
  return /* @__PURE__ */ jsxs(Fragment, { children: [
71
- options?.message && /* @__PURE__ */ jsx(Text, {
71
+ options?.message && /* @__PURE__ */ jsx(Text$1, {
72
72
  mb: "md",
73
73
  children: options.message
74
74
  }),
@@ -95,7 +95,8 @@ function PromptDialog({ options, onSubmit }) {
95
95
  })]
96
96
  })
97
97
  ] });
98
- }
98
+ };
99
+ var PromptDialog_default = PromptDialog;
99
100
 
100
101
  //#endregion
101
102
  //#region src/services/DialogService.tsx
@@ -121,7 +122,7 @@ var DialogService = class {
121
122
  const modalId = this.open({
122
123
  ...options,
123
124
  title: options?.title || "Alert",
124
- content: /* @__PURE__ */ jsx(AlertDialog, {
125
+ content: /* @__PURE__ */ jsx(AlertDialog_default, {
125
126
  options,
126
127
  onClose: () => {
127
128
  this.close(modalId);
@@ -141,7 +142,7 @@ var DialogService = class {
141
142
  title: options?.title || "Confirm",
142
143
  closeOnClickOutside: false,
143
144
  closeOnEscape: false,
144
- content: /* @__PURE__ */ jsx(ConfirmDialog, {
145
+ content: /* @__PURE__ */ jsx(ConfirmDialog_default, {
145
146
  options,
146
147
  onConfirm: (confirmed) => {
147
148
  this.close(modalId);
@@ -161,7 +162,7 @@ var DialogService = class {
161
162
  title: options?.title || "Input",
162
163
  closeOnClickOutside: false,
163
164
  closeOnEscape: false,
164
- content: /* @__PURE__ */ jsx(PromptDialog, {
165
+ content: /* @__PURE__ */ jsx(PromptDialog_default, {
165
166
  options,
166
167
  onSubmit: (value) => {
167
168
  this.close(modalId);
@@ -182,6 +183,13 @@ var DialogService = class {
182
183
  });
183
184
  }
184
185
  /**
186
+ * Close the currently open dialog or a specific dialog by ID
187
+ */
188
+ close(modalId) {
189
+ if (modalId) modals.close(modalId);
190
+ else modals.closeAll();
191
+ }
192
+ /**
185
193
  * Show a JSON editor/viewer dialog
186
194
  */
187
195
  json(data, options) {}
@@ -192,13 +200,6 @@ var DialogService = class {
192
200
  return Promise.resolve(null);
193
201
  }
194
202
  /**
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
203
  * Show a loading/progress dialog with optional progress percentage
203
204
  */
204
205
  loading(options) {}
@@ -206,74 +207,16 @@ var DialogService = class {
206
207
  * Show an image viewer/gallery dialog
207
208
  */
208
209
  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
-
221
- //#endregion
222
- //#region src/services/ToastService.tsx
223
- var ToastService = class {
224
- raw = notifications;
225
- options = { default: {
226
- autoClose: 5e3,
227
- withCloseButton: true,
228
- position: "top-center"
229
- } };
230
- show(options) {
231
- notifications.show({
232
- ...this.options.default,
233
- ...options
234
- });
235
- }
236
- info(options) {
237
- this.show({
238
- color: "blue",
239
- icon: /* @__PURE__ */ jsx(IconInfoCircle, { size: 20 }),
240
- title: "Info",
241
- message: "Information notification",
242
- ...options
243
- });
244
- }
245
- success(options) {
246
- this.show({
247
- color: "green",
248
- icon: /* @__PURE__ */ jsx(IconCheck, { size: 16 }),
249
- title: "Success",
250
- message: "Operation completed successfully",
251
- ...options
252
- });
253
- }
254
- warning(options) {
255
- this.show({
256
- color: "yellow",
257
- icon: /* @__PURE__ */ jsx(IconAlertTriangle, { size: 20 }),
258
- title: "Warning",
259
- message: "Please review this warning",
260
- ...options
261
- });
262
- }
263
- danger(options) {
264
- this.show({
265
- color: "red",
266
- icon: /* @__PURE__ */ jsx(IconX, { size: 20 }),
267
- title: "Error",
268
- message: "An error occurred",
269
- ...options
270
- });
271
- }
272
210
  };
273
211
 
274
212
  //#endregion
275
- //#region src/components/Action.tsx
276
- const renderMenuItem = (item, index) => {
213
+ //#region src/components/buttons/ActionButton.tsx
214
+ const ActionMenuItem = (props) => {
215
+ const { item, index } = props;
216
+ const router = useRouter();
217
+ const action = useAction({ handler: async (e) => {
218
+ await item.onClick?.();
219
+ } }, [item.onClick]);
277
220
  if (item.type === "divider") return /* @__PURE__ */ jsx(Menu.Divider, {}, index);
278
221
  if (item.type === "label") return /* @__PURE__ */ jsx(Menu.Label, { children: item.label }, index);
279
222
  if (item.children && item.children.length > 0) return /* @__PURE__ */ jsxs(Menu, {
@@ -284,21 +227,47 @@ const renderMenuItem = (item, index) => {
284
227
  leftSection: item.icon,
285
228
  rightSection: /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }),
286
229
  children: item.label
287
- }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => renderMenuItem(child, childIndex)) })]
230
+ }) }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: item.children.map((child, childIndex) => /* @__PURE__ */ jsx(ActionMenuItem, {
231
+ item: child,
232
+ index: childIndex
233
+ }, childIndex)) })]
288
234
  }, index);
235
+ const menuItemProps = {};
236
+ if (props.item.onClick) menuItemProps.onClick = action.run;
237
+ else if (props.item.href) Object.assign(menuItemProps, router.anchor(props.item.href));
289
238
  return /* @__PURE__ */ jsx(Menu.Item, {
290
239
  leftSection: item.icon,
291
240
  onClick: item.onClick,
292
241
  color: item.color,
242
+ rightSection: item.active ? /* @__PURE__ */ jsx(ThemeIcon, {
243
+ size: "xs",
244
+ variant: "transparent",
245
+ children: /* @__PURE__ */ jsx(IconCheck, {})
246
+ }) : void 0,
247
+ ...menuItemProps,
293
248
  children: item.label
294
249
  }, index);
295
250
  };
296
- const Action = (_props) => {
251
+ const ActionButton = (_props) => {
297
252
  const props = {
298
253
  variant: "subtle",
299
254
  ..._props
300
255
  };
301
- const { tooltip, menu,...restProps } = props;
256
+ const { tooltip, menu, icon,...restProps } = props;
257
+ if (props.icon) {
258
+ const icon$1 = /* @__PURE__ */ jsx(ThemeIcon, {
259
+ w: 24,
260
+ variant: "transparent",
261
+ size: "sm",
262
+ c: "var(--mantine-color-text)",
263
+ ...props.themeIconProps,
264
+ children: props.icon
265
+ });
266
+ if (!props.children) {
267
+ restProps.children = icon$1;
268
+ restProps.p ??= "xs";
269
+ } else restProps.leftSection = icon$1;
270
+ }
302
271
  if (props.leftSection && !props.children) {
303
272
  restProps.className ??= "mantine-Action-iconOnly";
304
273
  restProps.p ??= "xs";
@@ -308,7 +277,7 @@ const Action = (_props) => {
308
277
  return /* @__PURE__ */ jsxs(Fragment, { children: [/* @__PURE__ */ jsx(Flex$1, {
309
278
  w: "100%",
310
279
  visibleFrom: textVisibleFrom,
311
- children: /* @__PURE__ */ jsx(Action, {
280
+ children: /* @__PURE__ */ jsx(ActionButton, {
312
281
  flex: 1,
313
282
  ...rest,
314
283
  leftSection,
@@ -319,7 +288,7 @@ const Action = (_props) => {
319
288
  }), /* @__PURE__ */ jsx(Flex$1, {
320
289
  w: "100%",
321
290
  hiddenFrom: textVisibleFrom,
322
- children: /* @__PURE__ */ jsx(Action, {
291
+ children: /* @__PURE__ */ jsx(ActionButton, {
323
292
  px: "xs",
324
293
  ...rest,
325
294
  tooltip,
@@ -329,17 +298,31 @@ const Action = (_props) => {
329
298
  })] });
330
299
  }
331
300
  const renderAction = () => {
332
- if ("href" in restProps && restProps.href) return /* @__PURE__ */ jsx(ActionHref, {
301
+ if ("href" in restProps && restProps.href) {
302
+ if (restProps.href.startsWith("http")) return /* @__PURE__ */ jsx(ActionHrefButton, {
303
+ ...restProps,
304
+ href: restProps.href,
305
+ children: restProps.children
306
+ });
307
+ return /* @__PURE__ */ jsx(ActionNavigationButton, {
308
+ ...restProps,
309
+ href: restProps.href,
310
+ children: restProps.children
311
+ });
312
+ }
313
+ delete restProps.classNameActive;
314
+ delete restProps.variantActive;
315
+ if ("action" in restProps && restProps.action) return /* @__PURE__ */ jsx(ActionHookButton, {
333
316
  ...restProps,
334
- href: restProps.href,
317
+ action: restProps.action,
335
318
  children: restProps.children
336
319
  });
337
- if ("onClick" in restProps && restProps.onClick) return /* @__PURE__ */ jsx(ActionClick, {
320
+ if ("onClick" in restProps && restProps.onClick) return /* @__PURE__ */ jsx(ActionClickButton, {
338
321
  ...restProps,
339
322
  onClick: restProps.onClick,
340
323
  children: restProps.children
341
324
  });
342
- if ("form" in restProps && restProps.form) return /* @__PURE__ */ jsx(ActionSubmit, {
325
+ if ("form" in restProps && restProps.form) return /* @__PURE__ */ jsx(ActionSubmitButton, {
343
326
  ...restProps,
344
327
  form: restProps.form,
345
328
  children: restProps.children
@@ -354,7 +337,15 @@ const Action = (_props) => {
354
337
  position: menu.position || "bottom-start",
355
338
  width: menu.width || 200,
356
339
  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)) })]
340
+ trigger: menu.on === "hover" ? "hover" : "click",
341
+ ...menu.menuProps,
342
+ children: [/* @__PURE__ */ jsx(Menu.Target, {
343
+ ...menu.targetProps,
344
+ children: actionElement
345
+ }), /* @__PURE__ */ jsx(Menu.Dropdown, { children: menu.items.map((item, index) => /* @__PURE__ */ jsx(ActionMenuItem, {
346
+ item,
347
+ index
348
+ }, index)) })]
358
349
  });
359
350
  if (tooltip) return /* @__PURE__ */ jsx(Tooltip, { ...typeof tooltip === "string" ? {
360
351
  label: tooltip,
@@ -365,11 +356,11 @@ const Action = (_props) => {
365
356
  } });
366
357
  return actionElement;
367
358
  };
368
- var Action_default = Action;
359
+ var ActionButton_default = ActionButton;
369
360
  /**
370
361
  * Action button that submits a form with loading and disabled state handling.
371
362
  */
372
- const ActionSubmit = (props) => {
363
+ const ActionSubmitButton = (props) => {
373
364
  const { form,...buttonProps } = props;
374
365
  const state = useFormState(form);
375
366
  return /* @__PURE__ */ jsx(Button, {
@@ -381,53 +372,168 @@ const ActionSubmit = (props) => {
381
372
  });
382
373
  };
383
374
  /**
375
+ * Action button that integrates with useAction hook return value.
376
+ * Automatically handles loading state and executes the action on click.
377
+ *
378
+ * @example
379
+ * ```tsx
380
+ * const saveAction = useAction({
381
+ * handler: async (data) => {
382
+ * await api.save(data);
383
+ * }
384
+ * }, []);
385
+ *
386
+ * <ActionButton action={saveAction}>
387
+ * Save
388
+ * </ActionButton>
389
+ * ```
390
+ */
391
+ const ActionHookButton = (props) => {
392
+ const { action,...buttonProps } = props;
393
+ return /* @__PURE__ */ jsx(Button, {
394
+ ...buttonProps,
395
+ disabled: action.loading || props.disabled,
396
+ loading: action.loading,
397
+ onClick: () => action.run(),
398
+ children: props.children
399
+ });
400
+ };
401
+ /**
384
402
  * Basic action button that handles click events with loading and error handling.
403
+ *
404
+ * @example
405
+ * ```tsx
406
+ * <ActionButton onClick={() => api.doSomething()}>
407
+ * Do Something
408
+ * </ActionButton>
409
+ * ```
385
410
  */
386
- const ActionClick = (props) => {
387
- const [pending, setPending] = useState(false);
388
- const alepha = useAlepha();
389
- const onClick = async (e) => {
390
- setPending(true);
391
- try {
392
- await props.onClick(e);
393
- } catch (e$1) {
394
- console.error(e$1);
395
- await alepha.events.emit("form:submit:error", {
396
- id: "action",
397
- error: e$1
398
- });
399
- } finally {
400
- setPending(false);
401
- }
402
- };
411
+ const ActionClickButton = (props) => {
412
+ const action = useAction({ handler: async (e) => {
413
+ await props.onClick(e);
414
+ } }, [props.onClick]);
403
415
  return /* @__PURE__ */ jsx(Button, {
404
416
  ...props,
405
- disabled: pending || props.disabled,
406
- loading: pending,
407
- onClick,
417
+ disabled: action.loading || props.disabled,
418
+ loading: action.loading,
419
+ onClick: action.run,
408
420
  children: props.children
409
421
  });
410
422
  };
411
423
  /**
412
424
  * Action for navigation with active state support.
413
425
  */
414
- const ActionHref = (props) => {
415
- const { active: options, routerGoOptions,...buttonProps } = props;
426
+ const ActionNavigationButton = (props) => {
427
+ const { active: options, classNameActive, variantActive, routerGoOptions,...buttonProps } = props;
416
428
  const router = useRouter();
417
429
  const { isPending, isActive } = useActive(options ? {
418
430
  href: props.href,
419
431
  ...options
420
432
  } : { href: props.href });
433
+ const anchorProps = router.anchor(props.href, routerGoOptions);
434
+ const className = buttonProps.className || "";
435
+ if (isActive && options !== false && classNameActive) buttonProps.className = `${className} ${classNameActive}`.trim();
421
436
  return /* @__PURE__ */ jsx(Button, {
422
437
  component: "a",
423
438
  loading: isPending,
424
- ...router.anchor(props.href, routerGoOptions),
425
439
  ...buttonProps,
426
- variant: isActive && options !== false ? "filled" : "subtle",
440
+ ...anchorProps,
441
+ variant: isActive && options !== false ? variantActive ?? "filled" : buttonProps.variant ?? "subtle",
442
+ children: props.children
443
+ });
444
+ };
445
+ const ActionHrefButton = (props) => {
446
+ const { active: options, classNameActive, variantActive, routerGoOptions, target,...buttonProps } = props;
447
+ return /* @__PURE__ */ jsx(Button, {
448
+ component: "a",
449
+ target,
450
+ ...buttonProps,
427
451
  children: props.children
428
452
  });
429
453
  };
430
454
 
455
+ //#endregion
456
+ //#region src/components/buttons/DarkModeButton.tsx
457
+ const DarkModeButton = (props) => {
458
+ const { setColorScheme } = useMantineColorScheme();
459
+ const computedColorScheme = useComputedColorScheme("light");
460
+ const [colorScheme, setColorScheme2] = useState("default");
461
+ const mode = props.mode ?? "minimal";
462
+ useEffect(() => {
463
+ setColorScheme2(computedColorScheme);
464
+ }, [computedColorScheme]);
465
+ const toggleColorScheme = () => {
466
+ setColorScheme(computedColorScheme === "dark" ? "light" : "dark");
467
+ };
468
+ if (mode === "segmented") return /* @__PURE__ */ jsx(SegmentedControl, {
469
+ value: colorScheme,
470
+ onChange: (value) => setColorScheme(value),
471
+ data: [{
472
+ value: "light",
473
+ label: /* @__PURE__ */ jsx(Flex$1, {
474
+ h: 20,
475
+ align: "center",
476
+ justify: "center",
477
+ children: /* @__PURE__ */ jsx(IconSun, { size: 16 })
478
+ })
479
+ }, {
480
+ value: "dark",
481
+ label: /* @__PURE__ */ jsx(Flex$1, {
482
+ h: 20,
483
+ align: "center",
484
+ justify: "center",
485
+ children: /* @__PURE__ */ jsx(IconMoon, { size: 16 })
486
+ })
487
+ }],
488
+ w: props.fullWidth ? "100%" : void 0,
489
+ ...props.segmentedProps
490
+ });
491
+ return /* @__PURE__ */ jsx(ActionButton_default, {
492
+ onClick: toggleColorScheme,
493
+ variant: props.variant ?? "outline",
494
+ size: props.size ?? "sm",
495
+ "aria-label": "Toggle color scheme",
496
+ px: "xs",
497
+ fullWidth: props.fullWidth ?? false,
498
+ icon: colorScheme === "dark" ? /* @__PURE__ */ jsx(IconSun, { size: 20 }) : colorScheme === "light" ? /* @__PURE__ */ jsx(IconMoon, { size: 20 }) : /* @__PURE__ */ jsx(Flex$1, {
499
+ h: 20,
500
+ w: 20
501
+ }),
502
+ ...props.actionProps
503
+ });
504
+ };
505
+ var DarkModeButton_default = DarkModeButton;
506
+
507
+ //#endregion
508
+ //#region src/components/buttons/OmnibarButton.tsx
509
+ const OmnibarButton = (props) => {
510
+ return /* @__PURE__ */ jsx(ActionButton_default, {
511
+ variant: "outline",
512
+ miw: 256,
513
+ onClick: spotlight.open,
514
+ justify: "space-between",
515
+ rightSection: /* @__PURE__ */ jsx(Kbd, {
516
+ size: "sm",
517
+ children: "⌘+K"
518
+ }),
519
+ radius: "md",
520
+ ...props.actionProps,
521
+ children: /* @__PURE__ */ jsxs(Flex$1, {
522
+ align: "center",
523
+ gap: "xs",
524
+ children: [/* @__PURE__ */ jsx(IconSearch, {
525
+ size: 16,
526
+ color: "gray"
527
+ }), /* @__PURE__ */ jsx(Text$1, {
528
+ size: "xs",
529
+ c: "dimmed",
530
+ children: "Search..."
531
+ })]
532
+ })
533
+ });
534
+ };
535
+ var OmnibarButton_default = OmnibarButton;
536
+
431
537
  //#endregion
432
538
  //#region src/utils/icons.tsx
433
539
  /**
@@ -542,7 +648,7 @@ const parseInput = (props, form) => {
542
648
  };
543
649
 
544
650
  //#endregion
545
- //#region src/components/ControlDate.tsx
651
+ //#region src/components/form/ControlDate.tsx
546
652
  /**
547
653
  * ControlDate component for handling date, datetime, and time inputs.
548
654
  *
@@ -600,7 +706,7 @@ const ControlDate = (props) => {
600
706
  var ControlDate_default = ControlDate;
601
707
 
602
708
  //#endregion
603
- //#region src/components/ControlSelect.tsx
709
+ //#region src/components/form/ControlSelect.tsx
604
710
  /**
605
711
  * ControlSelect component for handling Select, MultiSelect, and TagsInput.
606
712
  *
@@ -703,7 +809,7 @@ const ControlSelect = (props) => {
703
809
  var ControlSelect_default = ControlSelect;
704
810
 
705
811
  //#endregion
706
- //#region src/components/Control.tsx
812
+ //#region src/components/form/Control.tsx
707
813
  /**
708
814
  * Generic form control that renders the appropriate input based on the schema and props.
709
815
  *
@@ -856,563 +962,7 @@ const Control = (_props) => {
856
962
  var Control_default = Control;
857
963
 
858
964
  //#endregion
859
- //#region src/components/DarkModeButton.tsx
860
- const DarkModeButton = (props) => {
861
- const { setColorScheme } = useMantineColorScheme();
862
- const computedColorScheme = useComputedColorScheme("light");
863
- const [colorScheme, setColorScheme2] = useState("default");
864
- const mode = props.mode ?? "minimal";
865
- useEffect(() => {
866
- setColorScheme2(computedColorScheme);
867
- }, [computedColorScheme]);
868
- const toggleColorScheme = () => {
869
- setColorScheme(computedColorScheme === "dark" ? "light" : "dark");
870
- };
871
- if (mode === "segmented") return /* @__PURE__ */ jsx(SegmentedControl, {
872
- value: colorScheme,
873
- onChange: (value) => setColorScheme(value),
874
- data: [{
875
- value: "light",
876
- label: /* @__PURE__ */ jsx(Flex$1, {
877
- h: 20,
878
- align: "center",
879
- justify: "center",
880
- children: /* @__PURE__ */ jsx(IconSun, { size: 16 })
881
- })
882
- }, {
883
- value: "dark",
884
- label: /* @__PURE__ */ jsx(Flex$1, {
885
- h: 20,
886
- align: "center",
887
- justify: "center",
888
- children: /* @__PURE__ */ jsx(IconMoon, { size: 16 })
889
- })
890
- }]
891
- });
892
- return /* @__PURE__ */ jsx(ActionIcon, {
893
- onClick: toggleColorScheme,
894
- variant: props.variant ?? "default",
895
- size: props.size ?? "lg",
896
- "aria-label": "Toggle color scheme",
897
- children: colorScheme === "dark" ? /* @__PURE__ */ jsx(IconSun, { size: 20 }) : colorScheme === "light" ? /* @__PURE__ */ jsx(IconMoon, { size: 20 }) : /* @__PURE__ */ jsx(Flex$1, { h: 20 })
898
- });
899
- };
900
- var DarkModeButton_default = DarkModeButton;
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
-
1414
- //#endregion
1415
- //#region src/components/TypeForm.tsx
965
+ //#region src/components/form/TypeForm.tsx
1416
966
  /**
1417
967
  * TypeForm component that automatically renders all form inputs based on schema.
1418
968
  * Uses the Control component to render individual fields and Mantine Grid for responsive layout.
@@ -1480,7 +1030,7 @@ const TypeForm = (props) => {
1480
1030
  const content = /* @__PURE__ */ jsxs(Flex$1, {
1481
1031
  direction: "column",
1482
1032
  gap: "sm",
1483
- children: [renderFields(), !skipSubmitButton && /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(Action_default, {
1033
+ children: [renderFields(), !skipSubmitButton && /* @__PURE__ */ jsxs(Flex$1, { children: [/* @__PURE__ */ jsx(ActionButton_default, {
1484
1034
  form,
1485
1035
  ...submitButtonProps,
1486
1036
  children: submitButtonProps?.children ?? "Submit"
@@ -1497,6 +1047,385 @@ const TypeForm = (props) => {
1497
1047
  };
1498
1048
  var TypeForm_default = TypeForm;
1499
1049
 
1050
+ //#endregion
1051
+ //#region src/constants/ui.ts
1052
+ const ui = { colors: {
1053
+ transparent: "transparent",
1054
+ background: "var(--alepha-background)",
1055
+ surface: "var(--alepha-surface)",
1056
+ elevated: "var(--alepha-elevated)"
1057
+ } };
1058
+
1059
+ //#endregion
1060
+ //#region src/components/buttons/BurgerButton.tsx
1061
+ const BurgerButton = (props) => {
1062
+ const [opened, setOpened] = useStore("alepha.ui.sidebar.opened");
1063
+ return /* @__PURE__ */ jsx(Burger, {
1064
+ opened,
1065
+ onClick: () => setOpened(!opened),
1066
+ hiddenFrom: "sm",
1067
+ size: "sm",
1068
+ ...props
1069
+ });
1070
+ };
1071
+ var BurgerButton_default = BurgerButton;
1072
+
1073
+ //#endregion
1074
+ //#region src/components/buttons/LanguageButton.tsx
1075
+ const LanguageButton = (props) => {
1076
+ const i18n = useI18n();
1077
+ return /* @__PURE__ */ jsx(ActionButton_default, {
1078
+ icon: /* @__PURE__ */ jsx(IconLanguage, {}),
1079
+ variant: "outline",
1080
+ menu: { items: i18n.languages.map((lang) => ({
1081
+ label: i18n.tr(lang),
1082
+ onClick: () => i18n.setLang(lang),
1083
+ active: i18n.lang === lang
1084
+ })) },
1085
+ ...props.actionProps
1086
+ });
1087
+ };
1088
+ var LanguageButton_default = LanguageButton;
1089
+
1090
+ //#endregion
1091
+ //#region src/components/layout/AppBar.tsx
1092
+ const AppBar = (props) => {
1093
+ const { items = [] } = props;
1094
+ const renderItem = (item, index) => {
1095
+ if ("type" in item) {
1096
+ if (item.type === "burger") return /* @__PURE__ */ jsx(BurgerButton_default, {}, index);
1097
+ if (item.type === "dark") return /* @__PURE__ */ jsx(DarkModeButton_default, { ...item.props }, index);
1098
+ if (item.type === "search") return /* @__PURE__ */ jsx(OmnibarButton_default, { ...item.props }, index);
1099
+ if (item.type === "lang") return /* @__PURE__ */ jsx(LanguageButton_default, { ...item.props }, index);
1100
+ if (item.type === "spacer") return /* @__PURE__ */ jsx(Flex$1, { w: 16 }, index);
1101
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Divider, { orientation: "vertical" }, index);
1102
+ }
1103
+ if ("element" in item) return item.element;
1104
+ return null;
1105
+ };
1106
+ const leftItems = items.filter((item) => item.position === "left");
1107
+ const centerItems = items.filter((item) => item.position === "center");
1108
+ const rightItems = items.filter((item) => item.position === "right");
1109
+ return /* @__PURE__ */ jsxs(Flex$1, {
1110
+ h: "100%",
1111
+ align: "center",
1112
+ px: "md",
1113
+ justify: "space-between",
1114
+ ...props.flexProps,
1115
+ children: [
1116
+ /* @__PURE__ */ jsx(Flex$1, {
1117
+ flex: 1,
1118
+ children: leftItems.map((item, index) => /* @__PURE__ */ jsx(Flex$1, {
1119
+ ml: index === 0 ? 0 : "md",
1120
+ align: "center",
1121
+ children: renderItem(item, index)
1122
+ }, index))
1123
+ }),
1124
+ /* @__PURE__ */ jsx(Flex$1, { children: centerItems.map((item, index) => /* @__PURE__ */ jsx(Flex$1, {
1125
+ mx: "md",
1126
+ align: "center",
1127
+ children: renderItem(item, index)
1128
+ }, index)) }),
1129
+ /* @__PURE__ */ jsx(Flex$1, {
1130
+ flex: 1,
1131
+ gap: "md",
1132
+ align: "center",
1133
+ justify: "end",
1134
+ children: rightItems.map((item, index) => /* @__PURE__ */ jsx(Flex$1, {
1135
+ ml: index === 0 ? 0 : "md",
1136
+ align: "center",
1137
+ children: renderItem(item, index)
1138
+ }, index))
1139
+ })
1140
+ ]
1141
+ });
1142
+ };
1143
+ var AppBar_default = AppBar;
1144
+
1145
+ //#endregion
1146
+ //#region src/components/layout/Sidebar.tsx
1147
+ const Sidebar = (props) => {
1148
+ const router = useRouter();
1149
+ const { top = [], bottom = [], onItemClick } = props;
1150
+ const renderNode = (item, key) => {
1151
+ if ("type" in item) {
1152
+ if (item.type === "spacer") return /* @__PURE__ */ jsx(Flex$1, { h: 16 }, key);
1153
+ if (item.type === "divider") return /* @__PURE__ */ jsx(Flex$1, {
1154
+ h: 1,
1155
+ bg: "var(--alepha-border)",
1156
+ my: "md",
1157
+ mx: "sm"
1158
+ }, key);
1159
+ if (item.type === "search") return /* @__PURE__ */ jsx(OmnibarButton_default, { collapsed: props.collapsed }, key);
1160
+ if (item.type === "section") {
1161
+ if (props.collapsed) return;
1162
+ return /* @__PURE__ */ jsx(Text$1, {
1163
+ size: "xs",
1164
+ c: "dimmed",
1165
+ mt: "md",
1166
+ mb: "xs",
1167
+ mx: "sm",
1168
+ tt: "uppercase",
1169
+ fw: "bold",
1170
+ children: item.label
1171
+ }, key);
1172
+ }
1173
+ }
1174
+ if ("element" in item) return /* @__PURE__ */ jsx(Flex$1, { children: item.element }, key);
1175
+ if (props.collapsed) return /* @__PURE__ */ jsx(SidebarCollapsedItem, {
1176
+ item,
1177
+ level: 0,
1178
+ onItemClick,
1179
+ theme: props.theme ?? {}
1180
+ }, key);
1181
+ return /* @__PURE__ */ jsx(SidebarItem, {
1182
+ item,
1183
+ level: 0,
1184
+ onItemClick,
1185
+ theme: props.theme ?? {}
1186
+ }, key);
1187
+ };
1188
+ const padding = "md";
1189
+ const gap = props.gap;
1190
+ const menu = props.menu ?? router.concretePages.map((page) => ({
1191
+ label: page.label ?? page.name,
1192
+ description: page.description,
1193
+ icon: page.icon,
1194
+ href: page.path
1195
+ }));
1196
+ return /* @__PURE__ */ jsxs(Flex$1, {
1197
+ flex: 1,
1198
+ py: padding,
1199
+ direction: "column",
1200
+ className: "overflow-auto",
1201
+ ...props.flexProps,
1202
+ children: [
1203
+ /* @__PURE__ */ jsxs(Flex$1, {
1204
+ gap,
1205
+ px: padding,
1206
+ direction: "column",
1207
+ children: [top.map((item, index) => renderNode(item, index)), menu.filter((it) => it.position === "top").map((item, index) => renderNode(item, index + top.length))]
1208
+ }),
1209
+ /* @__PURE__ */ jsx(Flex$1, {
1210
+ gap,
1211
+ px: padding,
1212
+ direction: "column",
1213
+ flex: 1,
1214
+ className: "overflow-auto",
1215
+ children: menu.filter((it) => !it.position).map((item, index) => renderNode(item, index))
1216
+ }),
1217
+ /* @__PURE__ */ jsxs(Flex$1, {
1218
+ gap,
1219
+ px: padding,
1220
+ direction: "column",
1221
+ children: [bottom.map((item, index) => renderNode(item, index)), menu.filter((it) => it.position === "bottom").map((item, index) => renderNode(item, index + bottom.length))]
1222
+ })
1223
+ ]
1224
+ });
1225
+ };
1226
+ const SidebarItem = (props) => {
1227
+ const { item, level } = props;
1228
+ const maxLevel = 2;
1229
+ const router = useRouter();
1230
+ const isActive = useCallback((item$1) => {
1231
+ if (!item$1.children) return false;
1232
+ for (const child of item$1.children) {
1233
+ if (child.href) {
1234
+ if (router.isActive(child.href)) return true;
1235
+ }
1236
+ if (isActive(child)) return true;
1237
+ }
1238
+ return false;
1239
+ }, []);
1240
+ const [isOpen, setIsOpen] = useState(isActive(item));
1241
+ useEvents({ "react:transition:end": () => {
1242
+ if (isActive(item)) setIsOpen(true);
1243
+ } }, []);
1244
+ if (level > maxLevel) return null;
1245
+ const handleItemClick = (e) => {
1246
+ e.preventDefault();
1247
+ if (item.children && item.children.length > 0) setIsOpen(!isOpen);
1248
+ else {
1249
+ props.onItemClick?.(item);
1250
+ item.onClick?.();
1251
+ }
1252
+ };
1253
+ return /* @__PURE__ */ jsxs(Flex$1, {
1254
+ direction: "column",
1255
+ ps: level === 0 ? 0 : 32,
1256
+ pos: "relative",
1257
+ children: [/* @__PURE__ */ jsx(ActionButton_default, {
1258
+ w: "100%",
1259
+ justify: "space-between",
1260
+ href: props.item.href,
1261
+ variant: "subtle",
1262
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
1263
+ variantActive: "default",
1264
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
1265
+ onClick: handleItemClick,
1266
+ leftSection: /* @__PURE__ */ jsxs(Flex$1, {
1267
+ w: "100%",
1268
+ align: "center",
1269
+ gap: "sm",
1270
+ children: [item.icon && /* @__PURE__ */ jsx(ThemeIcon, {
1271
+ size: level === 0 ? "sm" : "xs",
1272
+ variant: "transparent",
1273
+ children: item.icon
1274
+ }), /* @__PURE__ */ jsxs(Flex$1, {
1275
+ direction: "column",
1276
+ children: [/* @__PURE__ */ jsx(Flex$1, { children: item.label }), item.description && /* @__PURE__ */ jsx(Text$1, {
1277
+ size: "xs",
1278
+ c: "dimmed",
1279
+ children: item.description
1280
+ })]
1281
+ })]
1282
+ }),
1283
+ rightSection: item.children ? /* @__PURE__ */ jsx(Flex$1, { children: isOpen ? /* @__PURE__ */ jsx(IconChevronDown, { size: 14 }) : /* @__PURE__ */ jsx(IconChevronRight, { size: 14 }) }) : props.item.rightSection,
1284
+ ...props.item.actionProps
1285
+ }), item.children && isOpen && /* @__PURE__ */ jsxs(Flex$1, {
1286
+ direction: "column",
1287
+ "data-parent-level": level,
1288
+ children: [/* @__PURE__ */ jsx(Flex$1, { style: {
1289
+ position: "absolute",
1290
+ width: 1,
1291
+ background: "linear-gradient(to bottom, transparent, var(--alepha-border), transparent)",
1292
+ top: 48,
1293
+ left: 20 + 32 * level,
1294
+ bottom: 16
1295
+ } }), item.children.map((child, index) => /* @__PURE__ */ jsx(SidebarItem, {
1296
+ item: child,
1297
+ level: level + 1,
1298
+ onItemClick: props.onItemClick,
1299
+ theme: props.theme
1300
+ }, index))]
1301
+ })]
1302
+ });
1303
+ };
1304
+ const SidebarCollapsedItem = (props) => {
1305
+ const { item, level } = props;
1306
+ const router = useRouter();
1307
+ const isActive = useCallback((item$1) => {
1308
+ if (!item$1.children) return false;
1309
+ for (const child of item$1.children) {
1310
+ if (child.href) {
1311
+ if (router.isActive(child.href)) return true;
1312
+ }
1313
+ if (isActive(child)) return true;
1314
+ }
1315
+ return false;
1316
+ }, []);
1317
+ const [isOpen, setIsOpen] = useState(isActive(item));
1318
+ const handleItemClick = (e) => {
1319
+ e.preventDefault();
1320
+ if (item.children && item.children.length > 0) setIsOpen(!isOpen);
1321
+ else {
1322
+ props.onItemClick?.(item);
1323
+ item.onClick?.();
1324
+ }
1325
+ };
1326
+ return /* @__PURE__ */ jsx(ActionButton_default, {
1327
+ variant: "subtle",
1328
+ size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
1329
+ variantActive: "default",
1330
+ radius: props.item.theme?.radius ?? props.theme.button?.radius ?? "md",
1331
+ onClick: handleItemClick,
1332
+ icon: item.icon ?? /* @__PURE__ */ jsx(IconSquareRounded, {}),
1333
+ href: props.item.href,
1334
+ menu: item.children ? {
1335
+ position: "right",
1336
+ on: "hover",
1337
+ items: item.children.map((child) => ({
1338
+ label: child.label,
1339
+ href: child.href,
1340
+ icon: child.icon,
1341
+ children: child.children
1342
+ }))
1343
+ } : void 0,
1344
+ ...props.item.actionProps
1345
+ });
1346
+ };
1347
+
1348
+ //#endregion
1349
+ //#region src/components/layout/AdminShell.tsx
1350
+ const AdminShell = (props) => {
1351
+ const [opened, setOpened] = useStore("alepha.ui.sidebar.opened");
1352
+ const [collapsed] = useStore("alepha.ui.sidebar.collapsed", props.sidebarProps?.collapsed);
1353
+ useEvents({ "react:transition:begin": () => {
1354
+ setOpened(false);
1355
+ } }, []);
1356
+ const defaultAppBarItems = [{
1357
+ position: "left",
1358
+ type: "burger"
1359
+ }];
1360
+ return /* @__PURE__ */ jsxs(AppShell, {
1361
+ padding: "md",
1362
+ header: { height: 60 },
1363
+ navbar: props.sidebarProps !== void 0 ? {
1364
+ width: collapsed ? { base: 72 } : { base: 300 },
1365
+ breakpoint: "sm",
1366
+ collapsed: { mobile: !opened }
1367
+ } : void 0,
1368
+ footer: props.footer ? { height: 60 } : void 0,
1369
+ ...props.appShellProps,
1370
+ children: [
1371
+ /* @__PURE__ */ jsx(AppShell.Header, {
1372
+ bg: ui.colors.surface,
1373
+ ...props.appShellHeaderProps,
1374
+ children: props.header ?? /* @__PURE__ */ jsx(AppBar_default, {
1375
+ items: defaultAppBarItems,
1376
+ ...props.appBarProps
1377
+ })
1378
+ }),
1379
+ props.sidebarProps !== void 0 && /* @__PURE__ */ jsx(AppShell.Navbar, {
1380
+ bg: ui.colors.surface,
1381
+ ...props.appShellNavbarProps,
1382
+ children: /* @__PURE__ */ jsx(Sidebar, {
1383
+ collapsed,
1384
+ ...props.sidebarProps
1385
+ })
1386
+ }),
1387
+ /* @__PURE__ */ jsx(AppShell.Main, {
1388
+ ...props.appShellMainProps,
1389
+ children: props.children ?? /* @__PURE__ */ jsx(NestedView, {})
1390
+ }),
1391
+ props.footer && /* @__PURE__ */ jsx(AppShell.Footer, {
1392
+ bg: ui.colors.surface,
1393
+ ...props.appShellFooterProps,
1394
+ children: props.footer
1395
+ })
1396
+ ]
1397
+ });
1398
+ };
1399
+ var AdminShell_default = AdminShell;
1400
+
1401
+ //#endregion
1402
+ //#region src/components/table/DataTable.tsx
1403
+ const DataTable = (props) => {
1404
+ const [items, setItems] = useState(typeof props.items === "function" ? [] : props.items);
1405
+ useEffect(() => {
1406
+ if (typeof props.items !== "function") setItems(props.items);
1407
+ }, [props.items]);
1408
+ const head = Object.entries(props.columns).map(([key, col]) => /* @__PURE__ */ jsx(Table.Th, { children: /* @__PURE__ */ jsx(ActionButton_default, {
1409
+ justify: "space-between",
1410
+ radius: 0,
1411
+ fullWidth: true,
1412
+ size: "xs",
1413
+ children: col.label
1414
+ }) }, key));
1415
+ const rows = items.map((item, index) => {
1416
+ const trProps = props.tableTrProps ? props.tableTrProps(item) : {};
1417
+ return /* @__PURE__ */ jsx(Table.Tr, {
1418
+ ...trProps,
1419
+ children: Object.entries(props.columns).map(([key, col]) => /* @__PURE__ */ jsx(Table.Td, { children: col.value(item) }, key))
1420
+ }, JSON.stringify(item));
1421
+ });
1422
+ return /* @__PURE__ */ jsxs(Table, {
1423
+ ...props.tableProps,
1424
+ children: [/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsx(Table.Tr, { children: head }) }), /* @__PURE__ */ jsx(Table.Tbody, { children: rows })]
1425
+ });
1426
+ };
1427
+ var DataTable_default = DataTable;
1428
+
1500
1429
  //#endregion
1501
1430
  //#region src/hooks/useDialog.ts
1502
1431
  /**
@@ -1512,20 +1441,6 @@ const useDialog = () => {
1512
1441
  return useInject(DialogService);
1513
1442
  };
1514
1443
 
1515
- //#endregion
1516
- //#region src/hooks/useToast.ts
1517
- /**
1518
- * Use this hook to access the Toast Service for showing notifications.
1519
- *
1520
- * @example
1521
- * const toast = useToast();
1522
- * toast.success({ message: "Operation completed successfully!" });
1523
- * toast.error({ title: "Error", message: "Something went wrong" });
1524
- */
1525
- const useToast = () => {
1526
- return useInject(ToastService);
1527
- };
1528
-
1529
1444
  //#endregion
1530
1445
  //#region src/index.ts
1531
1446
  /**
@@ -1536,13 +1451,19 @@ const useToast = () => {
1536
1451
  const AlephaUI = $module({
1537
1452
  name: "alepha.ui",
1538
1453
  services: [
1539
- AlephaReact,
1540
1454
  DialogService,
1541
1455
  ToastService,
1542
1456
  RootRouter
1543
- ]
1457
+ ],
1458
+ register: (alepha) => {
1459
+ alepha.with(AlephaReactI18n);
1460
+ alepha.with(AlephaReactHead);
1461
+ alepha.with(AlephaReactForm);
1462
+ alepha.with(DialogService);
1463
+ alepha.with(ToastService);
1464
+ }
1544
1465
  });
1545
1466
 
1546
1467
  //#endregion
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 };
1468
+ export { ActionButton_default as ActionButton, AdminShell_default as AdminShell, AlephaMantineProvider_default as AlephaMantineProvider, AlephaUI, AlertDialog_default as AlertDialog, AppBar_default as AppBar, ConfirmDialog_default as ConfirmDialog, Control_default as Control, ControlDate_default as ControlDate, ControlSelect_default as ControlSelect, DarkModeButton_default as DarkModeButton, DataTable_default as DataTable, DialogService, Flex, ICON_SIZES, Omnibar_default as Omnibar, OmnibarButton_default as OmnibarButton, PromptDialog_default as PromptDialog, RootRouter, Sidebar, Text, ToastService, TypeForm_default as TypeForm, capitalize, getDefaultIcon, prettyName, ui, useDialog, useToast };
1548
1469
  //# sourceMappingURL=index.js.map