@alepha/ui 0.16.2 → 0.17.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.
Files changed (175) hide show
  1. package/dist/admin/{AdminApiKeys-CoTOTfgU.js → AdminApiKeys-CF_qOO3u.js} +20 -20
  2. package/dist/admin/AdminApiKeys-CF_qOO3u.js.map +1 -0
  3. package/dist/admin/{AdminAudits-BmsxFbDa.js → AdminAudits-BQno3hZG.js} +7 -8
  4. package/dist/admin/AdminAudits-BQno3hZG.js.map +1 -0
  5. package/dist/admin/{AdminFiles-BBB8knca.js → AdminFiles-kvuUaASF.js} +3 -5
  6. package/dist/admin/{AdminFiles-BBB8knca.js.map → AdminFiles-kvuUaASF.js.map} +1 -1
  7. package/dist/admin/AdminJobDashboard-CrPxp0W1.js +485 -0
  8. package/dist/admin/AdminJobDashboard-CrPxp0W1.js.map +1 -0
  9. package/dist/admin/AdminJobExecutions-D-b4Zt7W.js +678 -0
  10. package/dist/admin/AdminJobExecutions-D-b4Zt7W.js.map +1 -0
  11. package/dist/admin/AdminJobRegistry-CNX5cpDx.js +301 -0
  12. package/dist/admin/AdminJobRegistry-CNX5cpDx.js.map +1 -0
  13. package/dist/admin/{AdminLayout-CsjvpeD1.js → AdminLayout-e-ZP5nWw.js} +1 -1
  14. package/dist/admin/{AdminLayout-CsjvpeD1.js.map → AdminLayout-e-ZP5nWw.js.map} +1 -1
  15. package/dist/admin/{AdminNotifications-LwR6RKrx.js → AdminNotifications-DeHJFf6W.js} +3 -5
  16. package/dist/admin/{AdminNotifications-LwR6RKrx.js.map → AdminNotifications-DeHJFf6W.js.map} +1 -1
  17. package/dist/admin/{AdminParameters-B_83Vie9.js → AdminParameters-iQE8o7a7.js} +43 -36
  18. package/dist/admin/AdminParameters-iQE8o7a7.js.map +1 -0
  19. package/dist/admin/{AdminSessions-CWnPosdd.js → AdminSessions-oKJCbd7w.js} +5 -7
  20. package/dist/admin/AdminSessions-oKJCbd7w.js.map +1 -0
  21. package/dist/admin/{AdminUserAudits-nHv636E_.js → AdminUserAudits-BNCEle_E.js} +6 -8
  22. package/dist/admin/AdminUserAudits-BNCEle_E.js.map +1 -0
  23. package/dist/admin/{AdminUserCreate-CjYD3Kjc.js → AdminUserCreate-CgqeFwCt.js} +6 -7
  24. package/dist/admin/AdminUserCreate-CgqeFwCt.js.map +1 -0
  25. package/dist/admin/{AdminUserDetails-Ccq-LsZ0.js → AdminUserDetails-DDe1A1GP.js} +30 -29
  26. package/dist/admin/AdminUserDetails-DDe1A1GP.js.map +1 -0
  27. package/dist/admin/{AdminUserLayout-7s41DiF_.js → AdminUserLayout-HAlobhWf.js} +18 -16
  28. package/dist/admin/AdminUserLayout-HAlobhWf.js.map +1 -0
  29. package/dist/admin/{AdminUserSessions-Ds3ODq_d.js → AdminUserSessions-Bq1LnVLf.js} +5 -7
  30. package/dist/admin/AdminUserSessions-Bq1LnVLf.js.map +1 -0
  31. package/dist/admin/{AdminUserSettings-CGh4gROo.js → AdminUserSettings-BRsBZoxV.js} +10 -10
  32. package/dist/admin/AdminUserSettings-BRsBZoxV.js.map +1 -0
  33. package/dist/admin/{AdminUsers-CvPiBzQK.js → AdminUsers-D71kIOSn.js} +6 -8
  34. package/dist/admin/AdminUsers-D71kIOSn.js.map +1 -0
  35. package/dist/admin/index.d.ts +7 -83
  36. package/dist/admin/index.d.ts.map +1 -1
  37. package/dist/admin/index.js +49 -70
  38. package/dist/admin/index.js.map +1 -1
  39. package/dist/auth/{Login-DS_OqA0G.js → Login-BS_FYTy0.js} +13 -8
  40. package/dist/auth/Login-BS_FYTy0.js.map +1 -0
  41. package/dist/auth/{Profile-Di7N7HZL.js → Profile-CjDsW378.js} +16 -10
  42. package/dist/auth/Profile-CjDsW378.js.map +1 -0
  43. package/dist/auth/{Register-BRR2_gux.js → Register-C5eqzAaD.js} +21 -12
  44. package/dist/auth/Register-C5eqzAaD.js.map +1 -0
  45. package/dist/auth/{ResetPassword-oQu72lod.js → ResetPassword-XifinVao.js} +14 -8
  46. package/dist/auth/ResetPassword-XifinVao.js.map +1 -0
  47. package/dist/auth/{VerifyEmail-DC6HPZjd.js → VerifyEmail-DTgbeJOO.js} +6 -4
  48. package/dist/auth/VerifyEmail-DTgbeJOO.js.map +1 -0
  49. package/dist/auth/index.d.ts +4 -0
  50. package/dist/auth/index.d.ts.map +1 -1
  51. package/dist/auth/index.js +15 -14
  52. package/dist/auth/index.js.map +1 -1
  53. package/dist/core/index.d.ts +37 -26
  54. package/dist/core/index.d.ts.map +1 -1
  55. package/dist/core/index.js +444 -193
  56. package/dist/core/index.js.map +1 -1
  57. package/dist/demo/DemoDataTable-lnBKWBf8.js +362 -0
  58. package/dist/demo/DemoDataTable-lnBKWBf8.js.map +1 -0
  59. package/dist/demo/{DemoHome-DpRrPlBC.js → DemoHome-CUMZsYaH.js} +6 -7
  60. package/dist/demo/DemoHome-CUMZsYaH.js.map +1 -0
  61. package/dist/demo/{DemoJsonViewer-zeucGKHV.js → DemoJsonViewer-_uokbGaW.js} +17 -19
  62. package/dist/demo/DemoJsonViewer-_uokbGaW.js.map +1 -0
  63. package/dist/demo/{DemoLayout-PhgbAAiQ.js → DemoLayout-DHVoacE6.js} +2 -4
  64. package/dist/demo/{DemoLayout-PhgbAAiQ.js.map → DemoLayout-DHVoacE6.js.map} +1 -1
  65. package/dist/demo/{DemoLogin-DSzP0Lkv.js → DemoLogin-DjJ9314c.js} +22 -17
  66. package/dist/demo/DemoLogin-DjJ9314c.js.map +1 -0
  67. package/dist/demo/{DemoRegister-DavFBsCz.js → DemoRegister-DzkJ5M83.js} +34 -25
  68. package/dist/demo/DemoRegister-DzkJ5M83.js.map +1 -0
  69. package/dist/demo/{DemoResetPassword-BS2rIAQK.js → DemoResetPassword-DWh4_BpQ.js} +27 -21
  70. package/dist/demo/DemoResetPassword-DWh4_BpQ.js.map +1 -0
  71. package/dist/demo/{DemoSidebar-zNkUmHRl.js → DemoSidebar-C1csnGhX.js} +2 -2
  72. package/dist/demo/{DemoSidebar-zNkUmHRl.js.map → DemoSidebar-C1csnGhX.js.map} +1 -1
  73. package/dist/demo/{DemoTypeForm-B9q7oT0b.js → DemoTypeForm-CWz6fJrJ.js} +2 -2
  74. package/dist/demo/{DemoTypeForm-B9q7oT0b.js.map → DemoTypeForm-CWz6fJrJ.js.map} +1 -1
  75. package/dist/demo/{DemoVerifyEmail-Bi4SdWz0.js → DemoVerifyEmail-DbU_tCj8.js} +13 -11
  76. package/dist/demo/DemoVerifyEmail-DbU_tCj8.js.map +1 -0
  77. package/dist/demo/{IconGoogle-CTeZyrek.js → IconGoogle-Ch1m3Uzl.js} +1 -1
  78. package/dist/demo/{IconGoogle-CTeZyrek.js.map → IconGoogle-Ch1m3Uzl.js.map} +1 -1
  79. package/dist/demo/{Showcase-C9btr_SJ.js → Showcase-BzoXNlCn.js} +10 -10
  80. package/dist/demo/Showcase-BzoXNlCn.js.map +1 -0
  81. package/dist/demo/index.d.ts +1 -68
  82. package/dist/demo/index.d.ts.map +1 -1
  83. package/dist/demo/index.js +11 -15
  84. package/dist/demo/index.js.map +1 -1
  85. package/dist/json/index.js +2 -2
  86. package/dist/json/index.js.map +1 -1
  87. package/package.json +9 -5
  88. package/src/admin/AdminRouter.ts +36 -5
  89. package/src/admin/components/audits/AdminAudits.tsx +5 -5
  90. package/src/admin/components/jobs/AdminJobDashboard.tsx +455 -0
  91. package/src/admin/components/jobs/AdminJobExecutions.tsx +693 -0
  92. package/src/admin/components/jobs/AdminJobRegistry.tsx +325 -0
  93. package/src/admin/components/keys/AdminApiKeys.tsx +28 -31
  94. package/src/admin/components/parameters/AdminParameters.tsx +3 -3
  95. package/src/admin/components/parameters/ParameterDetails.tsx +34 -29
  96. package/src/admin/components/parameters/ParameterEmptyState.tsx +5 -5
  97. package/src/admin/components/parameters/ParameterHistory.tsx +11 -19
  98. package/src/admin/components/parameters/ParameterTree.tsx +16 -18
  99. package/src/admin/components/sessions/AdminSessions.tsx +3 -3
  100. package/src/admin/components/shared/AdminResourceHeader.tsx +20 -16
  101. package/src/admin/components/users/AdminUserAudits.tsx +5 -5
  102. package/src/admin/components/users/AdminUserCreate.tsx +3 -3
  103. package/src/admin/components/users/AdminUserDetails.tsx +51 -53
  104. package/src/admin/components/users/AdminUserLayout.tsx +7 -7
  105. package/src/admin/components/users/AdminUserSessions.tsx +3 -3
  106. package/src/admin/components/users/AdminUserSettings.tsx +9 -9
  107. package/src/admin/components/users/AdminUsers.tsx +5 -5
  108. package/src/admin/components/verifications/AdminVerifications.tsx +3 -3
  109. package/src/admin/index.ts +0 -24
  110. package/src/auth/components/Login.tsx +13 -13
  111. package/src/auth/components/Profile.tsx +17 -26
  112. package/src/auth/components/Register.tsx +21 -31
  113. package/src/auth/components/ResetPassword.tsx +13 -22
  114. package/src/auth/components/VerifyEmail.tsx +5 -5
  115. package/src/auth/components/buttons/UserButton.tsx +14 -4
  116. package/src/core/components/buttons/ActionButton.tsx +9 -2
  117. package/src/core/components/data/ErrorViewer.tsx +15 -15
  118. package/src/core/components/dialogs/AlertDialog.tsx +3 -3
  119. package/src/core/components/dialogs/ConfirmDialog.tsx +3 -3
  120. package/src/core/components/dialogs/PromptDialog.tsx +3 -3
  121. package/src/core/components/form/Control.tsx +9 -0
  122. package/src/core/components/form/ControlArray.tsx +6 -7
  123. package/src/core/components/form/ControlObject.tsx +3 -3
  124. package/src/core/components/form/ControlQueryBuilder.tsx +20 -22
  125. package/src/core/components/form/ControlSelect.tsx +4 -0
  126. package/src/core/components/form/TypeForm.tsx +7 -0
  127. package/src/core/components/layout/Breadcrumb.tsx +6 -6
  128. package/src/core/components/layout/Omnibar.tsx +2 -1
  129. package/src/core/components/layout/Sidebar.tsx +5 -1
  130. package/src/core/components/table/ColumnPicker.tsx +47 -31
  131. package/src/core/components/table/DataTable.tsx +277 -201
  132. package/src/core/components/table/DataTableFilters.tsx +8 -0
  133. package/src/core/components/table/DataTableToolbar.tsx +98 -5
  134. package/src/core/components/table/FilterPicker.tsx +28 -26
  135. package/src/core/components/table/types.ts +52 -37
  136. package/src/core/components/table/useTableSelection.ts +83 -0
  137. package/src/core/styles.css +1 -0
  138. package/src/core/utils/parseInput.ts +1 -0
  139. package/src/demo/components/DemoHome.tsx +5 -5
  140. package/src/demo/components/core/DemoDataTable.tsx +209 -5
  141. package/src/demo/components/json/DemoJsonViewer.tsx +1 -1
  142. package/src/demo/components/shared/MacWindow.tsx +7 -7
  143. package/src/demo/components/shared/Showcase.tsx +3 -3
  144. package/src/demo/index.ts +0 -11
  145. package/src/json/components/JsonViewer.tsx +3 -3
  146. package/dist/admin/AdminApiKeys-CoTOTfgU.js.map +0 -1
  147. package/dist/admin/AdminAudits-BmsxFbDa.js.map +0 -1
  148. package/dist/admin/AdminJobs-C604joTz.js +0 -698
  149. package/dist/admin/AdminJobs-C604joTz.js.map +0 -1
  150. package/dist/admin/AdminParameters-B_83Vie9.js.map +0 -1
  151. package/dist/admin/AdminSessions-CWnPosdd.js.map +0 -1
  152. package/dist/admin/AdminUserAudits-nHv636E_.js.map +0 -1
  153. package/dist/admin/AdminUserCreate-CjYD3Kjc.js.map +0 -1
  154. package/dist/admin/AdminUserDetails-Ccq-LsZ0.js.map +0 -1
  155. package/dist/admin/AdminUserLayout-7s41DiF_.js.map +0 -1
  156. package/dist/admin/AdminUserSessions-Ds3ODq_d.js.map +0 -1
  157. package/dist/admin/AdminUserSettings-CGh4gROo.js.map +0 -1
  158. package/dist/admin/AdminUsers-CvPiBzQK.js.map +0 -1
  159. package/dist/admin/rolldown-runtime-CjeV3_4I.js +0 -18
  160. package/dist/auth/Login-DS_OqA0G.js.map +0 -1
  161. package/dist/auth/Profile-Di7N7HZL.js.map +0 -1
  162. package/dist/auth/Register-BRR2_gux.js.map +0 -1
  163. package/dist/auth/ResetPassword-oQu72lod.js.map +0 -1
  164. package/dist/auth/VerifyEmail-DC6HPZjd.js.map +0 -1
  165. package/dist/demo/DemoDataTable-DCsJq8v5.js +0 -149
  166. package/dist/demo/DemoDataTable-DCsJq8v5.js.map +0 -1
  167. package/dist/demo/DemoHome-DpRrPlBC.js.map +0 -1
  168. package/dist/demo/DemoJsonViewer-zeucGKHV.js.map +0 -1
  169. package/dist/demo/DemoLogin-DSzP0Lkv.js.map +0 -1
  170. package/dist/demo/DemoRegister-DavFBsCz.js.map +0 -1
  171. package/dist/demo/DemoResetPassword-BS2rIAQK.js.map +0 -1
  172. package/dist/demo/DemoVerifyEmail-Bi4SdWz0.js.map +0 -1
  173. package/dist/demo/Showcase-C9btr_SJ.js.map +0 -1
  174. package/dist/demo/rolldown-runtime-CjeV3_4I.js +0 -18
  175. package/src/admin/components/jobs/AdminJobs.tsx +0 -772
@@ -3,9 +3,9 @@ import { AlephaReactForm, FormValidationError, useForm, useFormState } from "ale
3
3
  import { $head, AlephaReactHead } from "alepha/react/head";
4
4
  import { AlephaReactI18n, useI18n } from "alepha/react/i18n";
5
5
  import { $cookie } from "alepha/server/cookies";
6
- import { ActionIcon, Anchor, AppShell, Autocomplete, Badge, Box, Burger, Button, Card, Checkbox, Collapse, ColorInput, ColorSchemeScript, Container, CopyButton, Divider, Fieldset, FileInput, Flex, Flex as Flex$1, Grid, Group, Image, Input, Kbd, MantineProvider, Menu, MultiSelect, NumberInput, Pagination, PasswordInput, Popover, ScrollArea, SegmentedControl, Select, Slider, Stack, Switch, Table, TagsInput, Text, Text as Text$1, TextInput, Textarea, ThemeIcon, Tooltip, UnstyledButton, useMantineColorScheme, useMantineTheme } from "@mantine/core";
6
+ import { ActionIcon, Anchor, AppShell, Autocomplete, Badge, Burger, Button, Card, Checkbox, Collapse, ColorInput, ColorSchemeScript, Container, CopyButton, Divider, Drawer, Fieldset, FileInput, Flex, Flex as Flex$1, Grid, Image, Input, Kbd, MantineProvider, Menu, MultiSelect, NumberInput, Pagination, PasswordInput, Popover, ScrollArea, SegmentedControl, Select, Slider, Switch, Table, TagsInput, Text, Text as Text$1, TextInput, Textarea, ThemeIcon, Tooltip, UnstyledButton, useMantineColorScheme, useMantineTheme } from "@mantine/core";
7
7
  import { ModalsProvider, modals } from "@mantine/modals";
8
- import { IconAlertTriangle, IconArrowDown, IconArrowLeft, IconArrowUp, IconArrowsSort, IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClock, IconColorPicker, IconColumns, IconCopy, IconFile, IconFilter, IconGripVertical, IconHash, IconInfoCircle, IconInfoTriangle, IconKey, IconLanguage, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightCollapse, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconPlus, IconRefresh, IconSearch, IconSelector, IconSquareRounded, IconSun, IconToggleLeft, IconTrash, IconX } from "@tabler/icons-react";
8
+ import { IconAlertTriangle, IconArrowDown, IconArrowLeft, IconArrowUp, IconArrowsSort, IconAt, IconCalendar, IconCheck, IconChevronDown, IconChevronRight, IconClipboard, IconClock, IconColorPicker, IconColumns, IconCopy, IconDownload, IconFile, IconFilter, IconGripVertical, IconHash, IconInfoCircle, IconInfoTriangle, IconKey, IconLanguage, IconLayoutSidebarLeftCollapse, IconLayoutSidebarRightCollapse, IconLetterCase, IconLink, IconList, IconMail, IconMoon, IconPalette, IconPhone, IconPlus, IconRefresh, IconSearch, IconSelector, IconSquareRounded, IconSun, IconToggleLeft, IconTrash, IconX } from "@tabler/icons-react";
9
9
  import { Children, Fragment, createElement, isValidElement, useCallback, useEffect, useMemo, useRef, useState } from "react";
10
10
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
11
11
  import { Notifications, notifications } from "@mantine/notifications";
@@ -13,8 +13,9 @@ import { $page, Link, NestedView, useActive, useRouter, useRouterState } from "a
13
13
  import { NavigationProgress, nprogress } from "@mantine/nprogress";
14
14
  import { ClientOnly, useAction, useAlepha, useEvents, useInject, useStore } from "alepha/react";
15
15
  import { Spotlight, spotlight } from "@mantine/spotlight";
16
+ import { currentUserAtom } from "alepha/security";
16
17
  import { ui as ui$1 } from "@alepha/ui";
17
- import { useDebouncedCallback, useOs } from "@mantine/hooks";
18
+ import { useOs } from "@mantine/hooks";
18
19
  import { DateInput, DateTimePicker, TimeInput } from "@mantine/dates";
19
20
  import { parseQueryString } from "alepha/orm";
20
21
  import { DateTimeProvider } from "alepha/datetime";
@@ -267,10 +268,10 @@ const ErrorViewer = ({ error, showStack = true, copyable = true, size = "sm" })
267
268
  if (isError) return `${errorName}: ${errorMessage}${errorStack ? `\n\n${errorStack}` : ""}`;
268
269
  return String(error);
269
270
  };
270
- return /* @__PURE__ */ jsxs(Box, {
271
+ return /* @__PURE__ */ jsxs(Flex$1, {
271
272
  pos: "relative",
272
273
  w: "100%",
273
- children: [copyable && /* @__PURE__ */ jsx(Box, {
274
+ children: [copyable && /* @__PURE__ */ jsx(Flex$1, {
274
275
  pos: "absolute",
275
276
  top: 0,
276
277
  right: 0,
@@ -288,9 +289,9 @@ const ErrorViewer = ({ error, showStack = true, copyable = true, size = "sm" })
288
289
  })
289
290
  })
290
291
  })
291
- }), /* @__PURE__ */ jsxs(Box, {
292
+ }), /* @__PURE__ */ jsxs(Flex$1, {
292
293
  pt: copyable ? 30 : 0,
293
- children: [/* @__PURE__ */ jsxs(Box, {
294
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
294
295
  style: {
295
296
  display: "flex",
296
297
  alignItems: "flex-start",
@@ -310,9 +311,9 @@ const ErrorViewer = ({ error, showStack = true, copyable = true, size = "sm" })
310
311
  style: { wordBreak: "break-word" },
311
312
  children: errorMessage
312
313
  })]
313
- }), showStack && stackLines.length > 1 && /* @__PURE__ */ jsxs(Box, {
314
+ }), showStack && stackLines.length > 1 && /* @__PURE__ */ jsxs(Flex$1, {
314
315
  mt: "sm",
315
- children: [/* @__PURE__ */ jsxs(Box, {
316
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
316
317
  style: {
317
318
  display: "flex",
318
319
  alignItems: "center",
@@ -337,7 +338,7 @@ const ErrorViewer = ({ error, showStack = true, copyable = true, size = "sm" })
337
338
  })]
338
339
  }), /* @__PURE__ */ jsx(Collapse, {
339
340
  in: stackExpanded,
340
- children: /* @__PURE__ */ jsx(Box, {
341
+ children: /* @__PURE__ */ jsx(Flex$1, {
341
342
  mt: "xs",
342
343
  pl: "md",
343
344
  style: { borderLeft: "1px solid var(--mantine-color-default-border)" },
@@ -363,7 +364,7 @@ const ErrorViewer = ({ error, showStack = true, copyable = true, size = "sm" })
363
364
  const AlertDialog = ({ options, onClose }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [options?.message && /* @__PURE__ */ jsx(Text$1, {
364
365
  mb: "md",
365
366
  children: options.message
366
- }), /* @__PURE__ */ jsx(Group, {
367
+ }), /* @__PURE__ */ jsx(Flex$1, {
367
368
  justify: "flex-end",
368
369
  children: /* @__PURE__ */ jsx(Button, {
369
370
  onClick: onClose,
@@ -376,7 +377,7 @@ const AlertDialog = ({ options, onClose }) => /* @__PURE__ */ jsxs(Fragment$1, {
376
377
  const ConfirmDialog = ({ options, onConfirm }) => /* @__PURE__ */ jsxs(Fragment$1, { children: [options?.message && /* @__PURE__ */ jsx(Text$1, {
377
378
  mb: "md",
378
379
  children: options.message
379
- }), /* @__PURE__ */ jsxs(Group, {
380
+ }), /* @__PURE__ */ jsxs(Flex$1, {
380
381
  justify: "flex-end",
381
382
  children: [/* @__PURE__ */ jsx(Button, {
382
383
  variant: "subtle",
@@ -418,7 +419,7 @@ const PromptDialog = ({ options, onSubmit }) => {
418
419
  required: options?.required,
419
420
  mb: "md"
420
421
  }),
421
- /* @__PURE__ */ jsxs(Group, {
422
+ /* @__PURE__ */ jsxs(Flex$1, {
422
423
  justify: "flex-end",
423
424
  children: [/* @__PURE__ */ jsx(Button, {
424
425
  variant: "subtle",
@@ -700,7 +701,7 @@ const Omnibar = (props) => {
700
701
  const searchPlaceholder = props.searchPlaceholder ?? "Search...";
701
702
  const nothingFound = props.nothingFound ?? "Nothing found...";
702
703
  const router = useRouter();
703
- const [user] = useStore("alepha.server.request.user");
704
+ const [user] = useStore(currentUserAtom);
704
705
  return /* @__PURE__ */ jsx(Spotlight, {
705
706
  actions: useMemo(() => router.concretePages.filter((page) => {
706
707
  if (page.can && !page.can()) return false;
@@ -1008,10 +1009,11 @@ const ActionHookButton = (props) => {
1008
1009
  * </ActionButton>
1009
1010
  * ```
1010
1011
  */
1011
- const ActionClickButton = (props) => {
1012
+ const ActionClickButton = ({ preventDefault, ...props }) => {
1012
1013
  const action = useAction({ handler: async (e) => {
1014
+ if (preventDefault) e.preventDefault();
1013
1015
  await props.onClick(e);
1014
- } }, [props.onClick]);
1016
+ } }, [props.onClick, preventDefault]);
1015
1017
  return /* @__PURE__ */ jsx(Button, {
1016
1018
  ...props,
1017
1019
  disabled: action.loading || props.disabled,
@@ -1537,7 +1539,8 @@ const ControlArray = (props) => {
1537
1539
  const colSpan = 12 / columns;
1538
1540
  const objectItemSchema = isObjectItem ? itemSchema : null;
1539
1541
  const fieldNames = objectItemSchema ? Object.keys(objectItemSchema.properties) : [];
1540
- const renderItems = () => /* @__PURE__ */ jsxs(Stack, {
1542
+ const renderItems = () => /* @__PURE__ */ jsxs(Flex$1, {
1543
+ direction: "column",
1541
1544
  gap: "sm",
1542
1545
  children: [items.map((item, index) => /* @__PURE__ */ jsxs(Flex$1, {
1543
1546
  gap: "sm",
@@ -1613,7 +1616,8 @@ const ControlArray = (props) => {
1613
1616
  children: [/* @__PURE__ */ jsx(IconPlus, { size: 14 }), props.addLabel ?? "Add"]
1614
1617
  })]
1615
1618
  });
1616
- if (props.variant === "plain") return /* @__PURE__ */ jsxs(Stack, {
1619
+ if (props.variant === "plain") return /* @__PURE__ */ jsxs(Flex$1, {
1620
+ direction: "column",
1617
1621
  gap: "xs",
1618
1622
  children: [
1619
1623
  inputProps.label && /* @__PURE__ */ jsx(Text$1, {
@@ -1636,7 +1640,8 @@ const ControlArray = (props) => {
1636
1640
  });
1637
1641
  return /* @__PURE__ */ jsx(Fieldset, {
1638
1642
  legend: inputProps.label,
1639
- children: /* @__PURE__ */ jsxs(Stack, {
1643
+ children: /* @__PURE__ */ jsxs(Flex$1, {
1644
+ direction: "column",
1640
1645
  gap: "xs",
1641
1646
  children: [
1642
1647
  inputProps.description && /* @__PURE__ */ jsx(Text$1, {
@@ -1827,7 +1832,8 @@ const ControlObject = (props) => {
1827
1832
  if (props.variant === "plain") return renderFields();
1828
1833
  return /* @__PURE__ */ jsx(Fieldset, {
1829
1834
  legend: inputProps.label,
1830
- children: /* @__PURE__ */ jsxs(Stack, {
1835
+ children: /* @__PURE__ */ jsxs(Flex$1, {
1836
+ direction: "column",
1831
1837
  gap: "xs",
1832
1838
  children: [
1833
1839
  inputProps.description && /* @__PURE__ */ jsx(Text$1, {
@@ -2051,7 +2057,7 @@ const ControlQueryBuilder = ({ schema, value = "", onChange, placeholder = "Ente
2051
2057
  });
2052
2058
  };
2053
2059
  function QueryHelp({ fields, onInsert }) {
2054
- return /* @__PURE__ */ jsxs(Group, {
2060
+ return /* @__PURE__ */ jsxs(Flex$1, {
2055
2061
  gap: "md",
2056
2062
  align: "flex-start",
2057
2063
  wrap: "nowrap",
@@ -2059,19 +2065,22 @@ function QueryHelp({ fields, onInsert }) {
2059
2065
  p: "sm",
2060
2066
  bdrs: "sm",
2061
2067
  children: [
2062
- /* @__PURE__ */ jsxs(Stack, {
2068
+ /* @__PURE__ */ jsxs(Flex$1, {
2069
+ direction: "column",
2063
2070
  gap: "md",
2064
2071
  style: { flex: 1 },
2065
2072
  children: [
2066
- /* @__PURE__ */ jsxs(Stack, {
2073
+ /* @__PURE__ */ jsxs(Flex$1, {
2074
+ direction: "column",
2067
2075
  gap: "xs",
2068
2076
  children: [/* @__PURE__ */ jsx(Text$1, {
2069
2077
  size: "sm",
2070
2078
  fw: 600,
2071
2079
  children: "Operators"
2072
- }), /* @__PURE__ */ jsx(Stack, {
2080
+ }), /* @__PURE__ */ jsx(Flex$1, {
2081
+ direction: "column",
2073
2082
  gap: 4,
2074
- children: Object.entries(OPERATOR_INFO).map(([key, info]) => /* @__PURE__ */ jsxs(Group, {
2083
+ children: Object.entries(OPERATOR_INFO).map(([key, info]) => /* @__PURE__ */ jsxs(Flex$1, {
2075
2084
  gap: "xs",
2076
2085
  wrap: "nowrap",
2077
2086
  children: [/* @__PURE__ */ jsx(ActionButton, {
@@ -2093,15 +2102,17 @@ function QueryHelp({ fields, onInsert }) {
2093
2102
  })]
2094
2103
  }),
2095
2104
  /* @__PURE__ */ jsx(Divider, {}),
2096
- /* @__PURE__ */ jsxs(Stack, {
2105
+ /* @__PURE__ */ jsxs(Flex$1, {
2106
+ direction: "column",
2097
2107
  gap: "xs",
2098
2108
  children: [/* @__PURE__ */ jsx(Text$1, {
2099
2109
  size: "sm",
2100
2110
  fw: 600,
2101
2111
  children: "Logic"
2102
- }), /* @__PURE__ */ jsxs(Stack, {
2112
+ }), /* @__PURE__ */ jsxs(Flex$1, {
2113
+ direction: "column",
2103
2114
  gap: 4,
2104
- children: [/* @__PURE__ */ jsxs(Group, {
2115
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
2105
2116
  gap: "xs",
2106
2117
  wrap: "nowrap",
2107
2118
  children: [/* @__PURE__ */ jsx(ActionButton, {
@@ -2118,7 +2129,7 @@ function QueryHelp({ fields, onInsert }) {
2118
2129
  c: "dimmed",
2119
2130
  children: "AND"
2120
2131
  })]
2121
- }), /* @__PURE__ */ jsxs(Group, {
2132
+ }), /* @__PURE__ */ jsxs(Flex$1, {
2122
2133
  gap: "xs",
2123
2134
  wrap: "nowrap",
2124
2135
  children: [/* @__PURE__ */ jsx(ActionButton, {
@@ -2184,7 +2195,7 @@ function QueryHelp({ fields, onInsert }) {
2184
2195
  c: "dimmed",
2185
2196
  lineClamp: 1,
2186
2197
  children: field.description || field.type
2187
- }), field.enum && /* @__PURE__ */ jsx(Group, {
2198
+ }), field.enum && /* @__PURE__ */ jsx(Flex$1, {
2188
2199
  gap: 0,
2189
2200
  wrap: "wrap",
2190
2201
  children: field.enum.map((enumValue) => /* @__PURE__ */ jsx(ActionButton, {
@@ -2260,6 +2271,7 @@ const ControlSelect = (props) => {
2260
2271
  const autocompleteProps = typeof props.autocomplete === "object" ? props.autocomplete : {};
2261
2272
  return /* @__PURE__ */ jsx(Autocomplete, {
2262
2273
  ...inputProps,
2274
+ size: props.size,
2263
2275
  id,
2264
2276
  leftSection: icon,
2265
2277
  data,
@@ -2271,6 +2283,7 @@ const ControlSelect = (props) => {
2271
2283
  const tagsInputProps = typeof props.tags === "object" ? props.tags : {};
2272
2284
  return /* @__PURE__ */ jsx(TagsInput, {
2273
2285
  ...inputProps,
2286
+ size: props.size,
2274
2287
  id,
2275
2288
  leftSection: icon,
2276
2289
  defaultValue: Array.isArray(props.input.props.defaultValue) ? props.input.props.defaultValue : [],
@@ -2288,6 +2301,7 @@ const ControlSelect = (props) => {
2288
2301
  const multiSelectProps = typeof props.multi === "object" ? props.multi : {};
2289
2302
  return /* @__PURE__ */ jsx(MultiSelect, {
2290
2303
  ...inputProps,
2304
+ size: props.size,
2291
2305
  id,
2292
2306
  leftSection: icon,
2293
2307
  data,
@@ -2301,6 +2315,7 @@ const ControlSelect = (props) => {
2301
2315
  const selectProps = typeof props.select === "object" ? props.select : {};
2302
2316
  return /* @__PURE__ */ jsx(Select, {
2303
2317
  ...inputProps,
2318
+ size: props.size,
2304
2319
  id,
2305
2320
  leftSection: icon,
2306
2321
  data,
@@ -2393,6 +2408,7 @@ const Control = (_props) => {
2393
2408
  const controlNumberProps = typeof props.number === "object" ? props.number : {};
2394
2409
  if (props.slider) controlNumberProps.sliderProps ??= {};
2395
2410
  return /* @__PURE__ */ jsx(ControlNumber, {
2411
+ size: props.size,
2396
2412
  input: props.input,
2397
2413
  title: props.title,
2398
2414
  description: props.description,
@@ -2404,6 +2420,7 @@ const Control = (_props) => {
2404
2420
  const fileInputProps = typeof props.file === "object" ? props.file : {};
2405
2421
  return /* @__PURE__ */ jsx(FileInput, {
2406
2422
  ...inputProps,
2423
+ size: props.size,
2407
2424
  id,
2408
2425
  leftSection: icon,
2409
2426
  onChange: (file) => {
@@ -2416,6 +2433,7 @@ const Control = (_props) => {
2416
2433
  const colorInputProps = typeof props.color === "object" ? props.color : {};
2417
2434
  return /* @__PURE__ */ jsx(ColorInput, {
2418
2435
  ...inputProps,
2436
+ size: props.size,
2419
2437
  id,
2420
2438
  leftSection: icon,
2421
2439
  ...props.input.props,
@@ -2426,6 +2444,7 @@ const Control = (_props) => {
2426
2444
  const opts = typeof props.select === "object" ? props.select : {};
2427
2445
  if (props.segmented) opts.segmented ??= {};
2428
2446
  return /* @__PURE__ */ jsx(ControlSelect, {
2447
+ size: props.size,
2429
2448
  input: props.input,
2430
2449
  title: props.title,
2431
2450
  description: props.description,
@@ -2437,6 +2456,7 @@ const Control = (_props) => {
2437
2456
  const switchProps = typeof props.switch === "object" ? props.switch : {};
2438
2457
  return /* @__PURE__ */ jsx(Switch, {
2439
2458
  ...inputProps,
2459
+ size: props.size,
2440
2460
  id,
2441
2461
  color: "blue",
2442
2462
  defaultChecked: props.input.props.defaultValue,
@@ -2450,6 +2470,7 @@ const Control = (_props) => {
2450
2470
  const passwordInputProps = typeof props.password === "object" ? props.password : {};
2451
2471
  return /* @__PURE__ */ jsx(PasswordInput, {
2452
2472
  ...inputProps,
2473
+ size: props.size,
2453
2474
  id,
2454
2475
  leftSection: icon,
2455
2476
  ...props.input.props,
@@ -2460,6 +2481,7 @@ const Control = (_props) => {
2460
2481
  const textAreaProps = typeof props.area === "object" ? props.area : {};
2461
2482
  return /* @__PURE__ */ jsx(Textarea, {
2462
2483
  ...inputProps,
2484
+ size: props.size,
2463
2485
  id,
2464
2486
  leftSection: icon,
2465
2487
  ...props.input.props,
@@ -2467,6 +2489,7 @@ const Control = (_props) => {
2467
2489
  });
2468
2490
  }
2469
2491
  if (props.date || props.datetime || props.time || format === "date" || format === "date-time" || format === "time") return /* @__PURE__ */ jsx(ControlDate, {
2492
+ size: props.size,
2470
2493
  input: props.input,
2471
2494
  title: props.title,
2472
2495
  description: props.description,
@@ -2488,6 +2511,7 @@ const Control = (_props) => {
2488
2511
  };
2489
2512
  return /* @__PURE__ */ jsx(TextInput, {
2490
2513
  ...inputProps,
2514
+ size: props.size,
2491
2515
  id,
2492
2516
  leftSection: icon,
2493
2517
  type: getInputType(),
@@ -2546,7 +2570,7 @@ const Control = (_props) => {
2546
2570
  * ```
2547
2571
  */
2548
2572
  const TypeForm = (props) => {
2549
- const { form, columns = 3, children, controlProps, fieldControlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps, fill = true } = props;
2573
+ const { form, columns = 3, children, controlProps, fieldControlProps, skipFormElement = false, skipSubmitButton = false, submitButtonProps, fill = true, size } = props;
2550
2574
  const schema = props.schema || form.options.schema;
2551
2575
  if (!schema?.properties) return null;
2552
2576
  const supportedFields = Object.keys(schema.properties);
@@ -2575,6 +2599,7 @@ const TypeForm = (props) => {
2575
2599
  ...controlProps,
2576
2600
  ...fieldControlProps?.[fieldName]
2577
2601
  };
2602
+ if (size) mergedControlProps.size = size;
2578
2603
  return /* @__PURE__ */ jsx(Grid.Col, {
2579
2604
  span,
2580
2605
  children: /* @__PURE__ */ jsx(Control, {
@@ -2777,10 +2802,10 @@ const Breadcrumb = ({ home = "Home", separator, size = "xs", ...groupProps }) =>
2777
2802
  size: 12,
2778
2803
  color: "#9ca3af"
2779
2804
  });
2780
- return /* @__PURE__ */ jsx(Group, {
2805
+ return /* @__PURE__ */ jsx(Flex$1, {
2781
2806
  gap: 4,
2782
2807
  ...groupProps,
2783
- children: crumbs.map((crumb, i) => /* @__PURE__ */ jsxs(Group, {
2808
+ children: crumbs.map((crumb, i) => /* @__PURE__ */ jsxs(Flex$1, {
2784
2809
  gap: 4,
2785
2810
  children: [i > 0 && sep, i < crumbs.length - 1 ? /* @__PURE__ */ jsx(Anchor, {
2786
2811
  component: Link,
@@ -2945,7 +2970,10 @@ const SidebarItem = (props) => {
2945
2970
  href: props.item.href,
2946
2971
  target: props.item.target,
2947
2972
  size: props.item.theme?.size ?? props.theme.button?.size ?? (level === 0 ? "sm" : "xs"),
2948
- tooltip: item.description,
2973
+ tooltip: item.description ? {
2974
+ label: item.description,
2975
+ position: "right"
2976
+ } : void 0,
2949
2977
  color: "gray",
2950
2978
  variant: "subtle",
2951
2979
  variantActive: "default",
@@ -3276,11 +3304,19 @@ const DataTableFilters = ({ schema, form, typeFormProps, filterVisibility }) =>
3276
3304
  bg: ui.colors.surface,
3277
3305
  style: { borderBottom: "1px solid var(--alepha-border)" },
3278
3306
  children: /* @__PURE__ */ jsx(TypeForm, {
3307
+ size: "xs",
3279
3308
  ...typeFormProps,
3280
3309
  skipSubmitButton: true,
3281
3310
  fill: true,
3282
3311
  form,
3283
- schema: visibleSchema
3312
+ schema: visibleSchema,
3313
+ columns: {
3314
+ base: 1,
3315
+ sm: 2,
3316
+ md: 3,
3317
+ lg: 4,
3318
+ xl: 6
3319
+ }
3284
3320
  })
3285
3321
  });
3286
3322
  };
@@ -3332,6 +3368,10 @@ const DataTablePagination = ({ page, size, totalPages, onPageChange, onSizeChang
3332
3368
  });
3333
3369
  };
3334
3370
 
3371
+ //#endregion
3372
+ //#region ../../src/core/components/table/types.ts
3373
+ const DEFAULT_MAX_VISIBLE_COLUMNS = 8;
3374
+
3335
3375
  //#endregion
3336
3376
  //#region ../../src/core/components/table/ColumnPicker.tsx
3337
3377
  const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
@@ -3343,11 +3383,16 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3343
3383
  [key]: true
3344
3384
  }), {}));
3345
3385
  };
3346
- const handleHideAll = () => {
3347
- onVisibilityChange(columnEntries.reduce((acc, [key]) => ({
3348
- ...acc,
3349
- [key]: false
3350
- }), {}));
3386
+ const handleDefault = () => {
3387
+ let count = 0;
3388
+ onVisibilityChange(columnEntries.reduce((acc, [key, col]) => {
3389
+ if (col.defaultHidden) acc[key] = false;
3390
+ else if (count < DEFAULT_MAX_VISIBLE_COLUMNS) {
3391
+ acc[key] = true;
3392
+ count++;
3393
+ } else acc[key] = false;
3394
+ return acc;
3395
+ }, {}));
3351
3396
  };
3352
3397
  const handleToggle = (key, checked) => {
3353
3398
  onVisibilityChange({
@@ -3369,20 +3414,22 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3369
3414
  duration: 200,
3370
3415
  timingFunction: "ease"
3371
3416
  },
3372
- children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(ActionButton, {
3417
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
3373
3418
  variant: "subtle",
3374
- icon: IconColumns
3375
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3419
+ icon: IconColumns,
3420
+ onClick: () => setOpened((o) => !o)
3421
+ }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3376
3422
  bg: "transparent",
3377
3423
  p: "xs",
3378
3424
  bd: `1px solid ${ui.colors.border}`,
3379
3425
  style: { backdropFilter: "blur(20px)" },
3380
- children: /* @__PURE__ */ jsxs(Stack, {
3426
+ children: /* @__PURE__ */ jsxs(Flex$1, {
3427
+ direction: "column",
3381
3428
  gap: "xs",
3382
3429
  bg: ui.colors.surface,
3383
3430
  p: "sm",
3384
3431
  bdrs: "sm",
3385
- children: [/* @__PURE__ */ jsxs(Group, {
3432
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
3386
3433
  justify: "space-between",
3387
3434
  children: [/* @__PURE__ */ jsxs(Text$1, {
3388
3435
  size: "sm",
@@ -3394,26 +3441,27 @@ const ColumnPicker = ({ columns, visibility, onVisibilityChange }) => {
3394
3441
  columnEntries.length,
3395
3442
  ")"
3396
3443
  ]
3397
- }), /* @__PURE__ */ jsxs(Group, {
3444
+ }), /* @__PURE__ */ jsxs(Flex$1, {
3398
3445
  gap: 4,
3399
- children: [/* @__PURE__ */ jsx(Button, {
3446
+ children: [/* @__PURE__ */ jsx(ActionButton, {
3400
3447
  size: "compact-xs",
3401
3448
  variant: "subtle",
3402
3449
  onClick: handleShowAll,
3403
3450
  children: "All"
3404
- }), /* @__PURE__ */ jsx(Button, {
3451
+ }), /* @__PURE__ */ jsx(ActionButton, {
3405
3452
  size: "compact-xs",
3406
3453
  variant: "subtle",
3407
- onClick: handleHideAll,
3408
- children: "None"
3454
+ onClick: handleDefault,
3455
+ children: "Default"
3409
3456
  })]
3410
3457
  })]
3411
3458
  }), /* @__PURE__ */ jsx(ScrollArea.Autosize, {
3412
3459
  mah: 300,
3413
- children: /* @__PURE__ */ jsx(Stack, {
3460
+ children: /* @__PURE__ */ jsx(Flex$1, {
3461
+ direction: "column",
3414
3462
  gap: 4,
3415
3463
  children: columnEntries.map(([key, col]) => /* @__PURE__ */ jsx(Checkbox, {
3416
- label: col.label,
3464
+ label: col.label || key,
3417
3465
  checked: visibility[key] !== false,
3418
3466
  onChange: (e) => handleToggle(key, e.currentTarget.checked),
3419
3467
  size: "sm"
@@ -3453,7 +3501,7 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3453
3501
  [key]: checked
3454
3502
  });
3455
3503
  };
3456
- const visibleCount = filterKeys.filter((key) => visibility[key] !== false).length;
3504
+ const visibleCount = filterKeys.filter((key) => visibility[key]).length;
3457
3505
  return /* @__PURE__ */ jsxs(Popover, {
3458
3506
  width: 280,
3459
3507
  position: "bottom-start",
@@ -3467,20 +3515,22 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3467
3515
  duration: 200,
3468
3516
  timingFunction: "ease"
3469
3517
  },
3470
- children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx(ActionButton, {
3518
+ children: [/* @__PURE__ */ jsx(Popover.Target, { children: /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(ActionButton, {
3471
3519
  variant: "subtle",
3472
- icon: IconFilter
3473
- }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3520
+ icon: IconFilter,
3521
+ onClick: () => setOpened((o) => !o)
3522
+ }) }) }), /* @__PURE__ */ jsx(Popover.Dropdown, {
3474
3523
  bg: "transparent",
3475
3524
  p: "xs",
3476
3525
  bd: `1px solid ${ui.colors.border}`,
3477
3526
  style: { backdropFilter: "blur(20px)" },
3478
- children: /* @__PURE__ */ jsxs(Stack, {
3527
+ children: /* @__PURE__ */ jsxs(Flex$1, {
3528
+ direction: "column",
3479
3529
  gap: "xs",
3480
3530
  bg: ui.colors.surface,
3481
3531
  p: "sm",
3482
3532
  bdrs: "sm",
3483
- children: [/* @__PURE__ */ jsxs(Group, {
3533
+ children: [/* @__PURE__ */ jsxs(Flex$1, {
3484
3534
  justify: "space-between",
3485
3535
  children: [/* @__PURE__ */ jsxs(Text$1, {
3486
3536
  size: "sm",
@@ -3492,14 +3542,14 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3492
3542
  filterKeys.length,
3493
3543
  ")"
3494
3544
  ]
3495
- }), /* @__PURE__ */ jsxs(Group, {
3545
+ }), /* @__PURE__ */ jsxs(Flex$1, {
3496
3546
  gap: 4,
3497
- children: [/* @__PURE__ */ jsx(Button, {
3547
+ children: [/* @__PURE__ */ jsx(ActionButton, {
3498
3548
  size: "compact-xs",
3499
3549
  variant: "subtle",
3500
3550
  onClick: handleShowAll,
3501
3551
  children: "All"
3502
- }), /* @__PURE__ */ jsx(Button, {
3552
+ }), /* @__PURE__ */ jsx(ActionButton, {
3503
3553
  size: "compact-xs",
3504
3554
  variant: "subtle",
3505
3555
  onClick: handleHideAll,
@@ -3508,11 +3558,12 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3508
3558
  })]
3509
3559
  }), /* @__PURE__ */ jsx(ScrollArea.Autosize, {
3510
3560
  mah: 300,
3511
- children: /* @__PURE__ */ jsx(Stack, {
3561
+ children: /* @__PURE__ */ jsx(Flex$1, {
3562
+ direction: "column",
3512
3563
  gap: 4,
3513
3564
  children: filterKeys.map((key) => /* @__PURE__ */ jsx(Checkbox, {
3514
3565
  label: getFieldLabel(schema, key),
3515
- checked: visibility[key] !== false,
3566
+ checked: visibility[key] === true,
3516
3567
  onChange: (e) => handleToggle(key, e.currentTarget.checked),
3517
3568
  size: "sm"
3518
3569
  }, key))
@@ -3525,8 +3576,50 @@ const FilterPicker = ({ schema, visibility, onVisibilityChange }) => {
3525
3576
 
3526
3577
  //#endregion
3527
3578
  //#region ../../src/core/components/table/DataTableToolbar.tsx
3528
- const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility, onColumnVisibilityChange, onFilterVisibilityChange, actions, onRefresh, selectedItems = [], checkboxActions, onClearSelection }) => {
3579
+ const escapeCsvField = (value) => {
3580
+ if (value.includes(",") || value.includes("\"") || value.includes("\n")) return `"${value.replace(/"/g, "\"\"")}"`;
3581
+ return value;
3582
+ };
3583
+ const extractText = (node) => {
3584
+ if (node == null || typeof node === "boolean") return "";
3585
+ if (typeof node === "string" || typeof node === "number") return String(node);
3586
+ if (Array.isArray(node)) return node.map(extractText).join("");
3587
+ if (typeof node === "object" && "props" in node) return extractText(node.props.children);
3588
+ return "";
3589
+ };
3590
+ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility, onColumnVisibilityChange, onFilterVisibilityChange, actions, onRefresh, items, withExport, selectedItems = [], checkboxActions, onClearSelection }) => {
3529
3591
  const hasSelection = selectedItems.length > 0;
3592
+ const exportableColumns = useCallback(() => {
3593
+ return Object.entries(columns).filter(([key, col]) => !col.actions && columnVisibility[key] !== false);
3594
+ }, [columns, columnVisibility]);
3595
+ const buildRows = useCallback(() => {
3596
+ const cols = exportableColumns();
3597
+ return items.map((item) => cols.map(([_key, col]) => {
3598
+ if (!col.value) return "";
3599
+ return extractText(col.value(item, {}));
3600
+ }));
3601
+ }, [items, exportableColumns]);
3602
+ const buildCsv = useCallback(() => {
3603
+ const header = exportableColumns().map(([_key, col]) => escapeCsvField(col.label));
3604
+ const rows = buildRows().map((row) => row.map(escapeCsvField));
3605
+ return [header.join(","), ...rows.map((r) => r.join(","))].join("\n");
3606
+ }, [exportableColumns, buildRows]);
3607
+ const exportCsv = useCallback(() => {
3608
+ const csv = buildCsv();
3609
+ const blob = new Blob([csv], { type: "text/csv;charset=utf-8;" });
3610
+ const url = URL.createObjectURL(blob);
3611
+ const a = document.createElement("a");
3612
+ a.href = url;
3613
+ a.download = "export.csv";
3614
+ a.click();
3615
+ URL.revokeObjectURL(url);
3616
+ }, [buildCsv]);
3617
+ const exportClipboard = useCallback(async () => {
3618
+ const header = exportableColumns().map(([_key, col]) => col.label);
3619
+ const rows = buildRows();
3620
+ const text = [header.join(" "), ...rows.map((r) => r.join(" "))].join("\n");
3621
+ await navigator.clipboard.writeText(text);
3622
+ }, [exportableColumns, buildRows]);
3530
3623
  const handleCheckboxAction = async (action) => {
3531
3624
  const ctx = {
3532
3625
  selectedItems,
@@ -3552,6 +3645,19 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3552
3645
  visibility: columnVisibility,
3553
3646
  onVisibilityChange: onColumnVisibilityChange
3554
3647
  }),
3648
+ withExport && /* @__PURE__ */ jsx(ActionButton, {
3649
+ variant: "subtle",
3650
+ icon: IconDownload,
3651
+ menu: { items: [{
3652
+ label: "Export as CSV",
3653
+ icon: /* @__PURE__ */ jsx(IconDownload, { size: 14 }),
3654
+ onClick: exportCsv
3655
+ }, {
3656
+ label: "Copy to clipboard",
3657
+ icon: /* @__PURE__ */ jsx(IconClipboard, { size: 14 }),
3658
+ onClick: exportClipboard
3659
+ }] }
3660
+ }),
3555
3661
  hasSelection && /* @__PURE__ */ jsxs(Fragment$1, { children: [
3556
3662
  /* @__PURE__ */ jsx(Divider, {
3557
3663
  orientation: "vertical",
@@ -3587,18 +3693,80 @@ const DataTableToolbar = ({ columns, filters, columnVisibility, filterVisibility
3587
3693
  ...props,
3588
3694
  children: props.label
3589
3695
  }, index) : props), /* @__PURE__ */ jsx(ActionButton, {
3696
+ variant: "subtle",
3590
3697
  icon: IconRefresh,
3591
- onClick: onRefresh,
3592
- children: "Refresh"
3698
+ onClick: onRefresh
3593
3699
  })]
3594
3700
  })
3595
3701
  ]
3596
3702
  });
3597
3703
  };
3598
3704
 
3705
+ //#endregion
3706
+ //#region ../../src/core/components/table/useTableSelection.ts
3707
+ const useTableSelection = (items, getItemKey, enabled) => {
3708
+ const [selectedKeys, setSelectedKeys] = useState(/* @__PURE__ */ new Set());
3709
+ const selectedItems = useMemo(() => {
3710
+ if (!enabled) return [];
3711
+ return items.filter((item) => selectedKeys.has(getItemKey(item)));
3712
+ }, [
3713
+ items,
3714
+ selectedKeys,
3715
+ getItemKey,
3716
+ enabled
3717
+ ]);
3718
+ const allSelected = useMemo(() => {
3719
+ if (items.length === 0) return false;
3720
+ return items.every((item) => selectedKeys.has(getItemKey(item)));
3721
+ }, [
3722
+ items,
3723
+ selectedKeys,
3724
+ getItemKey
3725
+ ]);
3726
+ return {
3727
+ selectedItems,
3728
+ allSelected,
3729
+ someSelected: useMemo(() => {
3730
+ if (items.length === 0) return false;
3731
+ const count = items.filter((item) => selectedKeys.has(getItemKey(item))).length;
3732
+ return count > 0 && count < items.length;
3733
+ }, [
3734
+ items,
3735
+ selectedKeys,
3736
+ getItemKey
3737
+ ]),
3738
+ toggleItem: useCallback((item) => {
3739
+ const key = getItemKey(item);
3740
+ setSelectedKeys((prev) => {
3741
+ const next = new Set(prev);
3742
+ if (next.has(key)) next.delete(key);
3743
+ else next.add(key);
3744
+ return next;
3745
+ });
3746
+ }, [getItemKey]),
3747
+ toggleAll: useCallback(() => {
3748
+ if (allSelected) setSelectedKeys((prev) => {
3749
+ const next = new Set(prev);
3750
+ for (const item of items) next.delete(getItemKey(item));
3751
+ return next;
3752
+ });
3753
+ else setSelectedKeys((prev) => {
3754
+ const next = new Set(prev);
3755
+ for (const item of items) next.add(getItemKey(item));
3756
+ return next;
3757
+ });
3758
+ }, [
3759
+ allSelected,
3760
+ items,
3761
+ getItemKey
3762
+ ]),
3763
+ clear: useCallback(() => setSelectedKeys(/* @__PURE__ */ new Set()), []),
3764
+ isSelected: useCallback((item) => selectedKeys.has(getItemKey(item)), [selectedKeys, getItemKey])
3765
+ };
3766
+ };
3767
+
3599
3768
  //#endregion
3600
3769
  //#region ../../src/core/components/table/DataTable.tsx
3601
- const DEFAULT_VISIBLE_COLUMN_COUNT = 10;
3602
3770
  /**
3603
3771
  * Parse the sort string to get direction for a specific field.
3604
3772
  * Alepha convention: 'field' = ASC, '-field' = DESC
@@ -3623,6 +3791,15 @@ const toggleSort = (sortString, field) => {
3623
3791
  else if (current === "asc") parts.unshift(`-${field}`);
3624
3792
  return parts.length > 0 ? parts.join(",") : void 0;
3625
3793
  };
3794
+ const toAriaSort = (dir) => {
3795
+ if (dir === "asc") return "ascending";
3796
+ if (dir === "desc") return "descending";
3797
+ return "none";
3798
+ };
3799
+ const FIT_STYLE = {
3800
+ width: 1,
3801
+ whiteSpace: "nowrap"
3802
+ };
3626
3803
  const DataTable = (props) => {
3627
3804
  const [items, setItems] = useState(typeof props.items === "function" ? { content: [] } : props.items);
3628
3805
  const defaultSize = props.infinityScroll ? 100 : props.defaultSize || 10;
@@ -3630,31 +3807,27 @@ const DataTable = (props) => {
3630
3807
  const [size, setSize] = useState(String(defaultSize));
3631
3808
  const [currentPage, setCurrentPage] = useState(0);
3632
3809
  const alepha = useInject(Alepha);
3810
+ const sentinelRef = useRef(null);
3633
3811
  const [columnVisibility, setColumnVisibility] = useState(() => {
3634
- if (props.defaultColumnVisibility) return props.defaultColumnVisibility;
3635
- const columnKeys = Object.keys(props.columns);
3636
- const maxVisible = props.defaultVisibleColumnCount ?? DEFAULT_VISIBLE_COLUMN_COUNT;
3637
- return columnKeys.reduce((acc, key, index) => ({
3638
- ...acc,
3639
- [key]: index < maxVisible
3640
- }), {});
3812
+ const entries = Object.entries(props.columns);
3813
+ let visibleCount = 0;
3814
+ return entries.reduce((acc, [key, col]) => {
3815
+ if (col.defaultHidden) acc[key] = false;
3816
+ else if (visibleCount < DEFAULT_MAX_VISIBLE_COLUMNS) {
3817
+ acc[key] = true;
3818
+ visibleCount++;
3819
+ } else acc[key] = false;
3820
+ return acc;
3821
+ }, {});
3641
3822
  });
3642
3823
  const [filterVisibility, setFilterVisibility] = useState(() => {
3643
- if (props.defaultFilterVisibility) return props.defaultFilterVisibility;
3644
3824
  if (!props.filters?.properties) return {};
3825
+ const defaults = new Set(props.defaultFilters ?? []);
3645
3826
  return Object.keys(props.filters.properties).reduce((acc, key) => ({
3646
3827
  ...acc,
3647
- [key]: true
3828
+ [key]: defaults.has(key)
3648
3829
  }), {});
3649
3830
  });
3650
- const handleColumnVisibilityChange = (visibility) => {
3651
- setColumnVisibility(visibility);
3652
- props.onColumnVisibilityChange?.(visibility);
3653
- };
3654
- const handleFilterVisibilityChange = (visibility) => {
3655
- setFilterVisibility(visibility);
3656
- props.onFilterVisibilityChange?.(visibility);
3657
- };
3658
3831
  const visibleColumns = useMemo(() => {
3659
3832
  return Object.entries(props.columns).filter(([key]) => columnVisibility[key] !== false);
3660
3833
  }, [props.columns, columnVisibility]);
@@ -3665,64 +3838,38 @@ const DataTable = (props) => {
3665
3838
  form.input.sort.set(newSort);
3666
3839
  form.input.page.set(0);
3667
3840
  };
3668
- const [selectedKeys, setSelectedKeys] = useState(/* @__PURE__ */ new Set());
3669
3841
  const getItemKey = useCallback((item) => {
3670
3842
  if (props.getItemKey) return props.getItemKey(item);
3843
+ if ("id" in item) return String(item.id);
3671
3844
  return JSON.stringify(item);
3672
3845
  }, [props.getItemKey]);
3673
- const selectedItems = useMemo(() => {
3674
- if (!props.withCheckbox) return [];
3675
- return items.content.filter((item) => selectedKeys.has(getItemKey(item)));
3676
- }, [
3677
- items.content,
3678
- selectedKeys,
3679
- getItemKey,
3680
- props.withCheckbox
3681
- ]);
3682
- const allSelected = useMemo(() => {
3683
- if (items.content.length === 0) return false;
3684
- return items.content.every((item) => selectedKeys.has(getItemKey(item)));
3685
- }, [
3686
- items.content,
3687
- selectedKeys,
3688
- getItemKey
3689
- ]);
3690
- const someSelected = useMemo(() => {
3691
- if (items.content.length === 0) return false;
3692
- const selectedCount = items.content.filter((item) => selectedKeys.has(getItemKey(item))).length;
3693
- return selectedCount > 0 && selectedCount < items.content.length;
3694
- }, [
3695
- items.content,
3696
- selectedKeys,
3697
- getItemKey
3698
- ]);
3699
- const toggleItemSelection = useCallback((item) => {
3700
- const key = getItemKey(item);
3701
- setSelectedKeys((prev) => {
3846
+ const selection = useTableSelection(items.content, getItemKey, props.withCheckbox ?? false);
3847
+ const panelConfig = useMemo(() => {
3848
+ if (!props.panel) return null;
3849
+ if (typeof props.panel === "function") return {
3850
+ render: props.panel,
3851
+ can: void 0
3852
+ };
3853
+ return props.panel;
3854
+ }, [props.panel]);
3855
+ const [drawerItem, setDrawerItem] = useState(null);
3856
+ const drawerConfig = useMemo(() => {
3857
+ if (!props.drawer) return null;
3858
+ if (typeof props.drawer === "function") return {
3859
+ render: props.drawer,
3860
+ can: void 0,
3861
+ props: void 0
3862
+ };
3863
+ return props.drawer;
3864
+ }, [props.drawer]);
3865
+ const [expandedKeys, setExpandedKeys] = useState(/* @__PURE__ */ new Set());
3866
+ const toggleExpand = useCallback((key) => {
3867
+ setExpandedKeys((prev) => {
3702
3868
  const next = new Set(prev);
3703
3869
  if (next.has(key)) next.delete(key);
3704
3870
  else next.add(key);
3705
3871
  return next;
3706
3872
  });
3707
- }, [getItemKey]);
3708
- const toggleAllSelection = useCallback(() => {
3709
- if (allSelected) setSelectedKeys((prev) => {
3710
- const next = new Set(prev);
3711
- for (const item of items.content) next.delete(getItemKey(item));
3712
- return next;
3713
- });
3714
- else setSelectedKeys((prev) => {
3715
- const next = new Set(prev);
3716
- for (const item of items.content) next.add(getItemKey(item));
3717
- return next;
3718
- });
3719
- }, [
3720
- allSelected,
3721
- items.content,
3722
- getItemKey
3723
- ]);
3724
- const clearSelection = useCallback(() => {
3725
- setSelectedKeys(/* @__PURE__ */ new Set());
3726
3873
  }, []);
3727
3874
  const form = useForm({
3728
3875
  schema: t.object({
@@ -3744,7 +3891,7 @@ const DataTable = (props) => {
3744
3891
  },
3745
3892
  onReset: async () => {
3746
3893
  setPage(1);
3747
- setSize("10");
3894
+ setSize(String(defaultSize));
3748
3895
  await form.submit();
3749
3896
  },
3750
3897
  onChange: async (key, value) => {
@@ -3761,7 +3908,6 @@ const DataTable = (props) => {
3761
3908
  props.onFilterChange?.(key, value, form);
3762
3909
  }
3763
3910
  }, [items]);
3764
- useDebouncedCallback(() => form.submit(), { delay: 800 });
3765
3911
  const dt = useInject(DateTimeProvider);
3766
3912
  useEffect(() => {
3767
3913
  if (props.submitOnInit) form.submit();
@@ -3777,18 +3923,15 @@ const DataTable = (props) => {
3777
3923
  }, [props.items]);
3778
3924
  useEffect(() => {
3779
3925
  if (!props.infinityScroll || typeof props.items !== "function") return;
3780
- const handleScroll = () => {
3781
- if (form.submitting) return;
3782
- const scrollTop = window.scrollY;
3783
- const windowHeight = window.innerHeight;
3784
- const docHeight = document.documentElement.scrollHeight;
3785
- if (scrollTop + windowHeight >= docHeight - 300) {
3786
- const totalPages = items.page?.totalPages ?? 1;
3787
- if (currentPage + 1 < totalPages) form.input.page.set(currentPage + 1);
3788
- }
3789
- };
3790
- window.addEventListener("scroll", handleScroll);
3791
- return () => window.removeEventListener("scroll", handleScroll);
3926
+ const sentinel = sentinelRef.current;
3927
+ if (!sentinel) return;
3928
+ const observer = new IntersectionObserver((entries) => {
3929
+ if (!entries[0].isIntersecting || form.submitting) return;
3930
+ const totalPages = items.page?.totalPages ?? 1;
3931
+ if (currentPage + 1 < totalPages) form.input.page.set(currentPage + 1);
3932
+ }, { rootMargin: "300px" });
3933
+ observer.observe(sentinel);
3934
+ return () => observer.disconnect();
3792
3935
  }, [
3793
3936
  props.infinityScroll,
3794
3937
  form.submitting,
@@ -3796,63 +3939,134 @@ const DataTable = (props) => {
3796
3939
  currentPage,
3797
3940
  form
3798
3941
  ]);
3942
+ const totalColumns = visibleColumns.length + (panelConfig ? 1 : 0) + (props.withCheckbox ? 1 : 0);
3799
3943
  const checkboxHeader = props.withCheckbox ? /* @__PURE__ */ jsx(Table.Th, {
3800
3944
  style: { width: 40 },
3801
3945
  children: /* @__PURE__ */ jsx(Checkbox, {
3802
- checked: allSelected,
3803
- indeterminate: someSelected,
3804
- onChange: toggleAllSelection,
3946
+ checked: selection.allSelected,
3947
+ indeterminate: selection.someSelected,
3948
+ onChange: selection.toggleAll,
3805
3949
  "aria-label": "Select all"
3806
3950
  })
3807
3951
  }) : null;
3808
3952
  const head = visibleColumns.map(([key, col]) => {
3809
3953
  const sortField = col.sortKey || key;
3810
3954
  const sortDir = col.sortable ? getSortDirection(sortString, sortField) : null;
3811
- const headerContent = /* @__PURE__ */ jsxs(Flex$1, {
3812
- align: "center",
3813
- gap: 4,
3814
- children: [/* @__PURE__ */ jsx(Text$1, {
3815
- size: "xs",
3816
- children: col.label
3817
- }), col.sortable && /* @__PURE__ */ jsxs(Flex$1, {
3818
- c: "dimmed",
3819
- children: [
3820
- sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.sm }),
3821
- sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.sm }),
3822
- sortDir === null && /* @__PURE__ */ jsx(IconArrowsSort, { size: ui.sizes.icon.sm })
3823
- ]
3824
- })]
3825
- });
3826
3955
  return /* @__PURE__ */ jsx(Table.Th, {
3956
+ onClick: col.sortable ? () => handleSortClick(key, col.sortKey) : void 0,
3957
+ "aria-sort": col.sortable ? toAriaSort(sortDir) : void 0,
3827
3958
  style: {
3828
- ...col.fit ? {} : {},
3829
- ...col.sortable ? { cursor: "pointer" } : {}
3959
+ ...col.fit ? FIT_STYLE : {},
3960
+ ...col.sortable ? {
3961
+ cursor: "pointer",
3962
+ userSelect: "none"
3963
+ } : {}
3830
3964
  },
3831
- children: col.sortable ? /* @__PURE__ */ jsx(UnstyledButton, {
3832
- onClick: () => handleSortClick(key, col.sortKey),
3833
- children: headerContent
3834
- }) : headerContent
3965
+ children: /* @__PURE__ */ jsxs(Flex$1, {
3966
+ align: "center",
3967
+ gap: 4,
3968
+ children: [/* @__PURE__ */ jsx(Text$1, {
3969
+ size: "xs",
3970
+ children: col.label
3971
+ }), col.sortable && /* @__PURE__ */ jsxs(Flex$1, {
3972
+ c: "dimmed",
3973
+ children: [
3974
+ sortDir === "asc" && /* @__PURE__ */ jsx(IconArrowUp, { size: ui.sizes.icon.sm }),
3975
+ sortDir === "desc" && /* @__PURE__ */ jsx(IconArrowDown, { size: ui.sizes.icon.sm }),
3976
+ sortDir === null && /* @__PURE__ */ jsx(IconArrowsSort, { size: ui.sizes.icon.sm })
3977
+ ]
3978
+ })]
3979
+ })
3835
3980
  }, key);
3836
3981
  });
3837
- const rows = items.content.map((item, index) => {
3982
+ const rows = items.content.flatMap((item, index) => {
3838
3983
  const trProps = props.tableTrProps ? props.tableTrProps(item) : {};
3839
3984
  const itemKey = getItemKey(item);
3840
- const isSelected = selectedKeys.has(itemKey);
3841
- return /* @__PURE__ */ jsxs(Table.Tr, {
3985
+ const isSelected = selection.isSelected(item);
3986
+ const showPanel = panelConfig && (panelConfig.can ? panelConfig.can(item) : true);
3987
+ const isExpanded = expandedKeys.has(itemKey);
3988
+ const canOpenDrawer = drawerConfig && (drawerConfig.can ? drawerConfig.can(item) : true);
3989
+ const elements = [/* @__PURE__ */ jsxs(Table.Tr, {
3842
3990
  ...trProps,
3843
- children: [props.withCheckbox && /* @__PURE__ */ jsx(Table.Td, {
3844
- style: { width: 40 },
3845
- children: /* @__PURE__ */ jsx(Checkbox, {
3846
- checked: isSelected,
3847
- onChange: () => toggleItemSelection(item),
3848
- "aria-label": "Select row"
3991
+ style: {
3992
+ ...canOpenDrawer ? { cursor: "pointer" } : {},
3993
+ ...trProps.style ?? {}
3994
+ },
3995
+ onClick: (e) => {
3996
+ if (canOpenDrawer) setDrawerItem(item);
3997
+ trProps.onClick?.(e);
3998
+ },
3999
+ children: [
4000
+ panelConfig && /* @__PURE__ */ jsx(Table.Td, {
4001
+ style: {
4002
+ width: 36,
4003
+ textAlign: "center"
4004
+ },
4005
+ py: 2,
4006
+ px: 0,
4007
+ children: showPanel && /* @__PURE__ */ jsx(UnstyledButton, {
4008
+ onClick: (e) => {
4009
+ e.stopPropagation();
4010
+ toggleExpand(itemKey);
4011
+ },
4012
+ style: { display: "inline-flex" },
4013
+ children: /* @__PURE__ */ jsx(Flex$1, {
4014
+ c: "dimmed",
4015
+ align: "center",
4016
+ justify: "center",
4017
+ children: isExpanded ? /* @__PURE__ */ jsx(IconChevronDown, { size: ui.sizes.icon.sm }) : /* @__PURE__ */ jsx(IconChevronRight, { size: ui.sizes.icon.sm })
4018
+ })
4019
+ })
4020
+ }),
4021
+ props.withCheckbox && /* @__PURE__ */ jsx(Table.Td, {
4022
+ style: { width: 40 },
4023
+ onClick: (e) => e.stopPropagation(),
4024
+ children: /* @__PURE__ */ jsx(Checkbox, {
4025
+ checked: isSelected,
4026
+ onChange: () => selection.toggleItem(item),
4027
+ "aria-label": "Select row"
4028
+ })
4029
+ }),
4030
+ visibleColumns.map(([key, col]) => {
4031
+ const ctx = {
4032
+ index,
4033
+ form,
4034
+ alepha
4035
+ };
4036
+ if (col.actions) {
4037
+ const rowActions = col.actions(item, ctx).filter((a) => a.visible !== false);
4038
+ return /* @__PURE__ */ jsx(Table.Td, {
4039
+ py: 2,
4040
+ px: 4,
4041
+ style: col.fit ? FIT_STYLE : void 0,
4042
+ onClick: (e) => e.stopPropagation(),
4043
+ children: /* @__PURE__ */ jsx(Flex$1, {
4044
+ gap: 4,
4045
+ children: rowActions.map(({ visible: _, ...actionProps }, i) => /* @__PURE__ */ jsx(ActionButton, {
4046
+ variant: "subtle",
4047
+ size: "xs",
4048
+ preventDefault: true,
4049
+ h: 20,
4050
+ ...actionProps
4051
+ }, i))
4052
+ })
4053
+ }, key);
4054
+ }
4055
+ return /* @__PURE__ */ jsx(Table.Td, {
4056
+ py: 2,
4057
+ px: 4,
4058
+ style: col.fit ? FIT_STYLE : void 0,
4059
+ children: col.value?.(item, ctx)
4060
+ }, key);
3849
4061
  })
3850
- }), visibleColumns.map(([key, col]) => /* @__PURE__ */ jsx(Table.Td, { children: col.value(item, {
3851
- index,
3852
- form,
3853
- alepha
3854
- }) }, key))]
3855
- }, itemKey);
4062
+ ]
4063
+ }, itemKey)];
4064
+ if (panelConfig && showPanel && isExpanded) elements.push(/* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
4065
+ colSpan: totalColumns,
4066
+ p: 0,
4067
+ children: panelConfig.render(item)
4068
+ }) }, `${itemKey}-panel`));
4069
+ return elements;
3856
4070
  });
3857
4071
  const filterSchema = useMemo(() => {
3858
4072
  if (!props.filters) return null;
@@ -3865,9 +4079,7 @@ const DataTable = (props) => {
3865
4079
  return /* @__PURE__ */ jsxs(Flex$1, {
3866
4080
  flex: 1,
3867
4081
  p: 0,
3868
- bg: "var(--alepha-elevated)",
3869
4082
  bdrs: "sm",
3870
- bd: "1px solid var(--alepha-border)",
3871
4083
  direction: "column",
3872
4084
  children: [
3873
4085
  /* @__PURE__ */ jsx(DataTableToolbar, {
@@ -3875,13 +4087,15 @@ const DataTable = (props) => {
3875
4087
  filters: props.filters,
3876
4088
  columnVisibility,
3877
4089
  filterVisibility,
3878
- onColumnVisibilityChange: handleColumnVisibilityChange,
3879
- onFilterVisibilityChange: handleFilterVisibilityChange,
4090
+ onColumnVisibilityChange: setColumnVisibility,
4091
+ onFilterVisibilityChange: setFilterVisibility,
3880
4092
  actions: props.actions,
3881
4093
  onRefresh: () => form.submit(),
3882
- selectedItems,
4094
+ items: items.content,
4095
+ withExport: props.withExport,
4096
+ selectedItems: selection.selectedItems,
3883
4097
  checkboxActions: props.checkboxActions,
3884
- onClearSelection: clearSelection
4098
+ onClearSelection: selection.clear
3885
4099
  }),
3886
4100
  filterSchema && props.filters && /* @__PURE__ */ jsx(DataTableFilters, {
3887
4101
  schema: filterSchema,
@@ -3892,12 +4106,41 @@ const DataTable = (props) => {
3892
4106
  /* @__PURE__ */ jsx(Flex$1, {
3893
4107
  className: "overflow-auto",
3894
4108
  children: /* @__PURE__ */ jsxs(Table, {
4109
+ "aria-label": "Data table",
3895
4110
  withColumnBorders: true,
3896
4111
  withRowBorders: true,
3897
4112
  ...props.tableProps,
3898
- children: [/* @__PURE__ */ jsx(Table.Thead, { children: /* @__PURE__ */ jsxs(Table.Tr, { children: [checkboxHeader, head] }) }), /* @__PURE__ */ jsx(Table.Tbody, { children: rows })]
4113
+ children: [/* @__PURE__ */ jsx(Table.Thead, {
4114
+ style: {
4115
+ position: "sticky",
4116
+ top: 0,
4117
+ zIndex: 1,
4118
+ backgroundColor: "var(--mantine-color-body)"
4119
+ },
4120
+ children: /* @__PURE__ */ jsxs(Table.Tr, { children: [
4121
+ panelConfig && /* @__PURE__ */ jsx(Table.Th, { style: { width: 36 } }),
4122
+ checkboxHeader,
4123
+ head
4124
+ ] })
4125
+ }), /* @__PURE__ */ jsxs(Table.Tbody, {
4126
+ style: {
4127
+ opacity: form.submitting ? .5 : 1,
4128
+ transition: "opacity 150ms ease"
4129
+ },
4130
+ children: [rows, items.content.length === 0 && /* @__PURE__ */ jsx(Table.Tr, { children: /* @__PURE__ */ jsx(Table.Td, {
4131
+ colSpan: totalColumns || 1,
4132
+ py: "xl",
4133
+ style: { textAlign: "center" },
4134
+ children: /* @__PURE__ */ jsx(Text$1, {
4135
+ c: "dimmed",
4136
+ size: "sm",
4137
+ children: form.submitting ? "Loading…" : "No results"
4138
+ })
4139
+ }) })]
4140
+ })]
3899
4141
  })
3900
4142
  }),
4143
+ props.infinityScroll && /* @__PURE__ */ jsx("div", { ref: sentinelRef }),
3901
4144
  !props.infinityScroll && /* @__PURE__ */ jsx(DataTablePagination, {
3902
4145
  page,
3903
4146
  size,
@@ -3908,6 +4151,14 @@ const DataTable = (props) => {
3908
4151
  onSizeChange: (value) => {
3909
4152
  form.input.size.set(value);
3910
4153
  }
4154
+ }),
4155
+ drawerConfig && /* @__PURE__ */ jsx(Drawer, {
4156
+ opened: drawerItem !== null,
4157
+ onClose: () => setDrawerItem(null),
4158
+ position: "right",
4159
+ size: "xl",
4160
+ ...drawerConfig.props,
4161
+ children: drawerItem && drawerConfig.render(drawerItem)
3911
4162
  })
3912
4163
  ]
3913
4164
  });