@eifi1/ui-kit 0.46.1 → 0.48.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (216) hide show
  1. package/README.md +8 -6
  2. package/dist/admin/admin-sections.d.ts +8 -0
  3. package/dist/admin/admin-sections.js +2 -1
  4. package/dist/admin/admin-sections.js.map +1 -1
  5. package/dist/auth/verify-email.d.ts +9 -1
  6. package/dist/auth/verify-email.js +22 -13
  7. package/dist/auth/verify-email.js.map +1 -1
  8. package/dist/components/alert-banner.d.ts +29 -1
  9. package/dist/components/alert-banner.js +84 -7
  10. package/dist/components/alert-banner.js.map +1 -1
  11. package/dist/components/button-look.d.ts +4 -0
  12. package/dist/components/button-look.js +2 -0
  13. package/dist/components/button-look.js.map +1 -1
  14. package/dist/components/combobox-core.js +5 -1
  15. package/dist/components/combobox-core.js.map +1 -1
  16. package/dist/components/data-table-column-settings.d.ts +6 -1
  17. package/dist/components/data-table-column-settings.js +12 -2
  18. package/dist/components/data-table-column-settings.js.map +1 -1
  19. package/dist/components/data-table-fit.d.ts +44 -0
  20. package/dist/components/data-table-fit.js +103 -0
  21. package/dist/components/data-table-fit.js.map +1 -0
  22. package/dist/components/data-table-groups.d.ts +95 -0
  23. package/dist/components/data-table-groups.js +165 -0
  24. package/dist/components/data-table-groups.js.map +1 -0
  25. package/dist/components/data-table-head.js +3 -1
  26. package/dist/components/data-table-head.js.map +1 -1
  27. package/dist/components/data-table-labels.d.ts +7 -0
  28. package/dist/components/data-table-labels.js +3 -0
  29. package/dist/components/data-table-labels.js.map +1 -1
  30. package/dist/components/data-table-leading-row.d.ts +17 -0
  31. package/dist/components/data-table-leading-row.js +41 -0
  32. package/dist/components/data-table-leading-row.js.map +1 -0
  33. package/dist/components/data-table-resize.js +1 -1
  34. package/dist/components/data-table-resize.js.map +1 -1
  35. package/dist/components/data-table.d.ts +78 -2
  36. package/dist/components/data-table.js +355 -247
  37. package/dist/components/data-table.js.map +1 -1
  38. package/dist/components/disclosure.d.ts +3 -1
  39. package/dist/components/disclosure.js +10 -4
  40. package/dist/components/disclosure.js.map +1 -1
  41. package/dist/components/dropdown.js +8 -1
  42. package/dist/components/dropdown.js.map +1 -1
  43. package/dist/components/floating-panel.d.ts +14 -1
  44. package/dist/components/floating-panel.js +7 -2
  45. package/dist/components/floating-panel.js.map +1 -1
  46. package/dist/components/hover-menu.js +5 -1
  47. package/dist/components/hover-menu.js.map +1 -1
  48. package/dist/components/icon-button.js +2 -1
  49. package/dist/components/icon-button.js.map +1 -1
  50. package/dist/components/popover.js +5 -1
  51. package/dist/components/popover.js.map +1 -1
  52. package/dist/components/row-actions.d.ts +25 -0
  53. package/dist/components/row-actions.js +13 -3
  54. package/dist/components/row-actions.js.map +1 -1
  55. package/dist/components/table-skeleton.d.ts +35 -0
  56. package/dist/components/table-skeleton.js +75 -0
  57. package/dist/components/table-skeleton.js.map +1 -0
  58. package/dist/components/tabs.d.ts +22 -16
  59. package/dist/components/tabs.js +47 -31
  60. package/dist/components/tabs.js.map +1 -1
  61. package/dist/components/ui-labels.js +1 -1
  62. package/dist/components/ui-labels.js.map +1 -1
  63. package/dist/components/use-table-state.d.ts +8 -7
  64. package/dist/components/use-table-state.js +37 -3
  65. package/dist/components/use-table-state.js.map +1 -1
  66. package/dist/data-table.d.ts +1 -0
  67. package/dist/data-table.js.map +1 -1
  68. package/dist/eslint/index.js +1 -1
  69. package/dist/feedback/feedback-attachment-download.d.ts +19 -0
  70. package/dist/feedback/feedback-attachment-download.js +59 -0
  71. package/dist/feedback/feedback-attachment-download.js.map +1 -0
  72. package/dist/feedback/feedback-comment-thread.d.ts +17 -6
  73. package/dist/feedback/feedback-comment-thread.js +21 -2
  74. package/dist/feedback/feedback-comment-thread.js.map +1 -1
  75. package/dist/feedback/feedback-entry-file.d.ts +61 -0
  76. package/dist/feedback/feedback-entry-file.js +76 -0
  77. package/dist/feedback/feedback-entry-file.js.map +1 -0
  78. package/dist/feedback/feedback-public-list.d.ts +18 -5
  79. package/dist/feedback/feedback-public-list.js +8 -0
  80. package/dist/feedback/feedback-public-list.js.map +1 -1
  81. package/dist/feedback/feedback-public-types.d.ts +7 -2
  82. package/dist/feedback/feedback-replies.d.ts +26 -9
  83. package/dist/feedback/feedback-replies.js +20 -10
  84. package/dist/feedback/feedback-replies.js.map +1 -1
  85. package/dist/feedback/feedback-row-detail-labels.js +0 -1
  86. package/dist/feedback/feedback-row-detail-labels.js.map +1 -1
  87. package/dist/feedback/feedback-row-detail.d.ts +23 -10
  88. package/dist/feedback/feedback-row-detail.js +10 -54
  89. package/dist/feedback/feedback-row-detail.js.map +1 -1
  90. package/dist/feedback/feedback-table.d.ts +5 -0
  91. package/dist/feedback/feedback-table.js +30 -7
  92. package/dist/feedback/feedback-table.js.map +1 -1
  93. package/dist/feedback.d.ts +1 -0
  94. package/dist/feedback.js +1 -0
  95. package/dist/feedback.js.map +1 -1
  96. package/dist/hooks/use-dismiss.d.ts +30 -1
  97. package/dist/hooks/use-dismiss.js +30 -2
  98. package/dist/hooks/use-dismiss.js.map +1 -1
  99. package/dist/i18n/german.js +7 -7
  100. package/dist/i18n/german.js.map +1 -1
  101. package/dist/i18n/kit-labels.d.ts +4 -0
  102. package/dist/i18n/kit-labels.js.map +1 -1
  103. package/dist/i18n/locales/en.js +7 -7
  104. package/dist/i18n/locales/en.js.map +2 -2
  105. package/dist/i18n/locales/es.js +7 -7
  106. package/dist/i18n/locales/es.js.map +1 -1
  107. package/dist/i18n/locales/fr.js +7 -7
  108. package/dist/i18n/locales/fr.js.map +1 -1
  109. package/dist/i18n/locales/hu.js +7 -7
  110. package/dist/i18n/locales/hu.js.map +1 -1
  111. package/dist/i18n/locales/it.js +7 -7
  112. package/dist/i18n/locales/it.js.map +1 -1
  113. package/dist/i18n/locales/zh.js +7 -7
  114. package/dist/i18n/locales/zh.js.map +1 -1
  115. package/dist/i18n/review.js +0 -1
  116. package/dist/i18n/review.js.map +1 -1
  117. package/dist/i18n/shared-labels.js +3 -1
  118. package/dist/i18n/shared-labels.js.map +1 -1
  119. package/dist/index.d.ts +4 -4
  120. package/dist/index.js +13 -4
  121. package/dist/index.js.map +1 -1
  122. package/dist/lib/float-clearance.d.ts +8 -0
  123. package/dist/lib/float-clearance.js +29 -0
  124. package/dist/lib/float-clearance.js.map +1 -0
  125. package/dist/notifications/device-zone-report.d.ts +1 -1
  126. package/dist/notifications/device-zone-report.js.map +1 -1
  127. package/dist/notifications/notification-types.d.ts +0 -3
  128. package/dist/notifications/notifications-labels.d.ts +2 -15
  129. package/dist/notifications/notifications-labels.js +0 -4
  130. package/dist/notifications/notifications-labels.js.map +1 -1
  131. package/dist/notifications/quiet-hours-setting.d.ts +3 -8
  132. package/dist/notifications/quiet-hours-setting.js +8 -3
  133. package/dist/notifications/quiet-hours-setting.js.map +1 -1
  134. package/dist/settings/settings-catalogue.d.ts +10 -0
  135. package/dist/settings/settings-catalogue.js.map +1 -1
  136. package/dist/settings/settings-layout.js +10 -3
  137. package/dist/settings/settings-layout.js.map +1 -1
  138. package/dist/shell/app-shell.d.ts +5 -0
  139. package/dist/shell/app-shell.js +5 -3
  140. package/dist/shell/app-shell.js.map +1 -1
  141. package/dist/shell/option-switcher-menu.d.ts +2 -0
  142. package/dist/shell/option-switcher-menu.js +6 -2
  143. package/dist/shell/option-switcher-menu.js.map +1 -1
  144. package/dist/shell/topbar-action-menu.js +2 -1
  145. package/dist/shell/topbar-action-menu.js.map +1 -1
  146. package/dist/shell/topbar-controls.js +5 -3
  147. package/dist/shell/topbar-controls.js.map +1 -1
  148. package/dist/theme/theme-store.d.ts +4 -4
  149. package/dist/theme/theme-store.js +1 -0
  150. package/dist/theme/theme-store.js.map +1 -1
  151. package/dist/tour/tour.js +1 -0
  152. package/dist/tour/tour.js.map +1 -1
  153. package/package.json +2 -2
  154. package/src/admin/admin-sections.tsx +8 -0
  155. package/src/auth/verify-email.tsx +34 -9
  156. package/src/components/alert-banner.tsx +131 -7
  157. package/src/components/button-look.ts +6 -0
  158. package/src/components/combobox-core.tsx +7 -1
  159. package/src/components/data-table-column-settings.tsx +23 -2
  160. package/src/components/data-table-fit.ts +187 -0
  161. package/src/components/data-table-groups.tsx +275 -0
  162. package/src/components/data-table-head.tsx +4 -1
  163. package/src/components/data-table-labels.ts +13 -0
  164. package/src/components/data-table-leading-row.tsx +55 -0
  165. package/src/components/data-table-resize.ts +2 -1
  166. package/src/components/data-table.tsx +274 -45
  167. package/src/components/disclosure.tsx +22 -5
  168. package/src/components/dropdown.tsx +11 -1
  169. package/src/components/floating-panel.tsx +24 -1
  170. package/src/components/hover-menu.tsx +6 -1
  171. package/src/components/icon-button.tsx +3 -3
  172. package/src/components/popover.tsx +7 -1
  173. package/src/components/row-actions.tsx +42 -3
  174. package/src/components/table-skeleton.tsx +133 -0
  175. package/src/components/tabs.tsx +102 -50
  176. package/src/components/ui-labels.ts +1 -1
  177. package/src/components/use-table-state.ts +54 -3
  178. package/src/data-table.ts +2 -0
  179. package/src/feedback/feedback-attachment-download.tsx +77 -0
  180. package/src/feedback/feedback-comment-thread.tsx +42 -7
  181. package/src/feedback/feedback-entry-file.tsx +150 -0
  182. package/src/feedback/feedback-public-list.tsx +25 -4
  183. package/src/feedback/feedback-public-types.ts +7 -2
  184. package/src/feedback/feedback-replies.tsx +46 -19
  185. package/src/feedback/feedback-row-detail-labels.ts +0 -1
  186. package/src/feedback/feedback-row-detail.tsx +35 -86
  187. package/src/feedback/feedback-table.tsx +33 -1
  188. package/src/feedback.ts +1 -0
  189. package/src/hooks/use-dismiss.ts +65 -3
  190. package/src/i18n/german.ts +6 -6
  191. package/src/i18n/kit-labels.tsx +4 -0
  192. package/src/i18n/locales/es.ts +6 -6
  193. package/src/i18n/locales/fr.ts +6 -6
  194. package/src/i18n/locales/hu.ts +6 -6
  195. package/src/i18n/locales/it.ts +6 -6
  196. package/src/i18n/locales/zh.ts +6 -6
  197. package/src/i18n/review.ts +0 -1
  198. package/src/i18n/shared-labels.ts +2 -0
  199. package/src/index.ts +13 -3
  200. package/src/lib/float-clearance.ts +54 -0
  201. package/src/notifications/device-zone-report.ts +1 -1
  202. package/src/notifications/notification-types.ts +0 -3
  203. package/src/notifications/notifications-labels.ts +2 -19
  204. package/src/notifications/quiet-hours-setting.tsx +16 -11
  205. package/src/settings/settings-catalogue.ts +10 -0
  206. package/src/settings/settings-layout.tsx +18 -4
  207. package/src/shell/app-shell.tsx +17 -3
  208. package/src/shell/option-switcher-menu.tsx +16 -4
  209. package/src/shell/topbar-action-menu.tsx +22 -10
  210. package/src/shell/topbar-controls.tsx +18 -12
  211. package/src/theme/theme-store.ts +13 -5
  212. package/src/tour/tour.tsx +5 -0
  213. package/dist/notifications/time-zone-select.d.ts +0 -54
  214. package/dist/notifications/time-zone-select.js +0 -71
  215. package/dist/notifications/time-zone-select.js.map +0 -1
  216. package/src/notifications/time-zone-select.tsx +0 -125
@@ -1,7 +1,7 @@
1
1
  "use client";
2
- import { jsx, jsxs } from "react/jsx-runtime";
2
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
3
3
  import { createElement } from "react";
4
- import { Fragment, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
4
+ import { Fragment as Fragment2, useEffect, useId, useLayoutEffect, useMemo, useRef, useState } from "react";
5
5
  import { Card } from "./card.js";
6
6
  import { Spinner } from "./spinner.js";
7
7
  import { isTableOwnColumn, useRowActionColumn } from "./data-table-row-actions.js";
@@ -19,6 +19,14 @@ import {
19
19
  } from "./data-table-shared.js";
20
20
  import { MobileFilters, MobileRow, MobileSelectBar, MobileSort, StackedFields } from "./data-table-mobile.js";
21
21
  import { DataTableHead } from "./data-table-head.js";
22
+ import { DataTableLeadingRow } from "./data-table-leading-row.js";
23
+ import {
24
+ DataTableGroupBand,
25
+ DataTableLoadMoreFooter,
26
+ groupLevels,
27
+ groupRows,
28
+ useGroupBandTops
29
+ } from "./data-table-groups.js";
22
30
  import { ColumnSettingsPanel } from "./data-table-column-settings.js";
23
31
  import { useLargeText } from "../hooks/use-large-text.js";
24
32
  import { cn } from "../lib/cn.js";
@@ -42,10 +50,12 @@ const DEFAULT_DATA_TABLE_SORT_LABELS = {
42
50
  const flipDir = (d) => d === "asc" ? "desc" : "asc";
43
51
  function moveRowFocus(from, key) {
44
52
  if (!(key in ROW_NAV_KEYS)) return false;
45
- const body = from.parentElement;
46
- if (!body) return false;
47
- const rows = Array.from(body.children).filter(
48
- (el) => el instanceof HTMLElement && el.hasAttribute("data-row-nav")
53
+ const table = from.closest("table");
54
+ if (!table) return false;
55
+ const rows = Array.from(table.tBodies).flatMap(
56
+ (body) => Array.from(body.children).filter(
57
+ (el) => el instanceof HTMLElement && el.hasAttribute("data-row-nav")
58
+ )
49
59
  );
50
60
  const i = rows.indexOf(from);
51
61
  const target = key === "ArrowDown" ? rows[i + 1] : key === "ArrowUp" ? rows[i - 1] : key === "Home" ? rows[0] : key === "End" ? rows[rows.length - 1] : void 0;
@@ -55,6 +65,7 @@ function moveRowFocus(from, key) {
55
65
  const ROW_NAV_KEYS = { ArrowDown: 1, ArrowUp: 1, Home: 1, End: 1 };
56
66
  import { DEFAULT_PERSIST_PREFIX, useTableState } from "./use-table-state.js";
57
67
  import { useMobileReveal } from "./use-mobile-reveal.js";
68
+ import { GROW_CELL_CLASS, GROW_PEER_CELL_CLASS, useColumnFit } from "./data-table-fit.js";
58
69
  function DataTable({
59
70
  rows,
60
71
  columns: columnsProp,
@@ -94,6 +105,9 @@ function DataTable({
94
105
  mobileSwipeActions,
95
106
  desktopSwipeActions,
96
107
  leadingRow,
108
+ leadingRowSticky = false,
109
+ groupBy,
110
+ loadMore,
97
111
  density = "comfortable",
98
112
  sortCycle = "tri",
99
113
  chrome = "full",
@@ -160,7 +174,13 @@ function DataTable({
160
174
  // Ignored in `serverPagination` mode, where the owner's is the page size.
161
175
  pageSizeProp: isServer ? void 0 : pageSizeProp
162
176
  });
163
- const widths = useMemo(() => resizable ? storedWidths : {}, [resizable, storedWidths]);
177
+ const widths = useMemo(() => {
178
+ if (!resizable) return {};
179
+ const grow = columns.find((c) => c.grow)?.key;
180
+ if (!grow || !(grow in storedWidths)) return storedWidths;
181
+ const { [grow]: _ignored, ...rest } = storedWidths;
182
+ return rest;
183
+ }, [resizable, storedWidths, columns]);
164
184
  const hiddenCols = useMemo(
165
185
  () => columnSettings ? storedHiddenCols : /* @__PURE__ */ new Set(),
166
186
  [columnSettings, storedHiddenCols]
@@ -221,7 +241,7 @@ function DataTable({
221
241
  });
222
242
  return copy;
223
243
  }, [filtered, sorts, columnSig, isServer]);
224
- const unpaged = !isServer && !paginated;
244
+ const unpaged = !isServer && (!paginated || !!loadMore);
225
245
  const effectivePageSize = isServer ? serverPagination.pageSize : unpaged || pageSize === Infinity ? sorted.length || 1 : pageSize;
226
246
  const paginationTotal = isServer ? serverPagination.total : sorted.length;
227
247
  const paginationPageSize = isServer ? serverPagination.pageSize : pageSize;
@@ -297,17 +317,26 @@ function DataTable({
297
317
  else setPage(p);
298
318
  announce(labels.pageChanged(p + 1, totalPages));
299
319
  };
320
+ const { autoHidden, keep: keepColumn } = useColumnFit({
321
+ columns,
322
+ hiddenCols,
323
+ headRefs,
324
+ scroller: () => desktopScroller.current,
325
+ enabled: !usePhoneLayout()
326
+ });
300
327
  const visibleColumns = useMemo(
301
- () => columns.filter((c) => !hiddenCols.has(c.key)),
302
- [columns, hiddenCols]
328
+ () => columns.filter((c) => !hiddenCols.has(c.key) && !autoHidden.has(c.key)),
329
+ [columns, hiddenCols, autoHidden]
303
330
  );
331
+ const growDrawn = visibleColumns.some((c) => c.grow);
304
332
  const linkColumn = rowHref ? visibleColumns.find((c) => c.mobilePrimary && !c.noRowLink) ?? visibleColumns.find((c) => !c.noRowLink) : void 0;
305
333
  const { startResize, moveResize, finishResize, autoSizeAll } = useColumnResize({
306
334
  headRefs,
307
335
  widths,
308
336
  setWidths,
309
337
  columns,
310
- hiddenCols
338
+ // The columns left out for width have no header to measure either.
339
+ hiddenCols: autoHidden.size > 0 ? /* @__PURE__ */ new Set([...hiddenCols, ...autoHidden]) : hiddenCols
311
340
  });
312
341
  const visibleCount = visibleColumns.length;
313
342
  const totalCount = columns.length;
@@ -323,6 +352,15 @@ function DataTable({
323
352
  const columnsCountLabel = labels.columnsCount(visibleCount - ownVisible, totalCount - ownColumns);
324
353
  const isMdUp = !usePhoneLayout();
325
354
  const desktopScroller = useRef(null);
355
+ const levels = groupLevels(groupBy);
356
+ const measuresVisibleWidth = isMdUp && (!!expandedRow || levels.length > 0 || !!loadMore);
357
+ useEffect(() => {
358
+ const el = desktopScroller.current;
359
+ if (!measuresVisibleWidth || !el || typeof ResizeObserver === "undefined") return;
360
+ const ro = new ResizeObserver(() => el.style.setProperty("--dt-visible-w", `${el.clientWidth}px`));
361
+ ro.observe(el);
362
+ return () => ro.disconnect();
363
+ }, [measuresVisibleWidth]);
326
364
  const edgeFadeProps = useEdgeFade(desktopScroller, edgeFade && isMdUp);
327
365
  const mobileColumns = visibleColumns.filter((c) => !c.mobileHidden);
328
366
  const mobilePrimaryCol = mobileColumns.find((c) => c.mobilePrimary) ?? mobileColumns[0] ?? null;
@@ -428,8 +466,17 @@ function DataTable({
428
466
  },
429
467
  rowKey(row)
430
468
  );
431
- const mobileGroups = mobileGroupBy ? mobileSlice.reduce((acc, row) => {
432
- const key = mobileGroupBy(row);
469
+ const tableRef = useRef(null);
470
+ const desktopGroups = isMdUp && levels.length > 0 ? groupRows(slice, levels) : null;
471
+ const bandTops = useGroupBandTops(
472
+ tableRef,
473
+ !!desktopGroups,
474
+ `${levels.length}:${leadingRowSticky && !!leadingRow}:${desktopGroups?.[0]?.key ?? ""}`
475
+ );
476
+ const mobileLevel = typeof mobileGroupBy === "function" ? null : mobileGroupBy ?? null;
477
+ const mobileKey = typeof mobileGroupBy === "function" ? mobileGroupBy : mobileGroupBy?.key;
478
+ const mobileGroups = mobileKey ? mobileSlice.reduce((acc, row) => {
479
+ const key = mobileKey(row);
433
480
  const last = acc[acc.length - 1];
434
481
  if (last && last.key === key) last.rows.push(row);
435
482
  else acc.push({ key, rows: [row] });
@@ -544,8 +591,11 @@ function DataTable({
544
591
  ),
545
592
  "aria-busy": isLoading || void 0,
546
593
  children: [
547
- mobileGroups ? mobileGroups.map((g) => /* @__PURE__ */ jsxs(Fragment, { children: [
548
- /* @__PURE__ */ jsx("li", { className: "sticky top-0 z-10 bg-surface-2 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted backdrop-blur", children: mobileGroupLabel ? mobileGroupLabel(g.key) : g.key }),
594
+ mobileGroups ? mobileGroups.map((g) => /* @__PURE__ */ jsxs(Fragment2, { children: [
595
+ /* @__PURE__ */ jsxs("li", { className: "sticky top-0 z-10 flex flex-wrap items-baseline justify-between gap-x-3 bg-surface-2 px-4 py-1.5 text-xs font-semibold uppercase tracking-wide text-muted backdrop-blur", children: [
596
+ /* @__PURE__ */ jsx("span", { className: "min-w-0", children: mobileGroupLabel ? mobileGroupLabel(g.key) : mobileLevel?.label ? mobileLevel.label(g.key, g.rows) : g.key }),
597
+ mobileLevel?.end && /* @__PURE__ */ jsx("span", { className: "ms-auto tabular-nums", children: mobileLevel.end(g.key, g.rows) })
598
+ ] }),
549
599
  g.rows.map(renderMobileRow)
550
600
  ] }, `hb-group:${g.key}`)) : mobileSlice.map(renderMobileRow),
551
601
  mobileSlice.length === 0 && /* @__PURE__ */ jsx(
@@ -565,6 +615,16 @@ function DataTable({
565
615
  className: "px-4 py-4 text-center text-xs text-placeholder",
566
616
  children: /* @__PURE__ */ jsx("bdi", { children: labels.loading })
567
617
  }
618
+ ),
619
+ loadMore && !canRevealMoreMobile && /* @__PURE__ */ jsx(
620
+ DataTableLoadMoreFooter,
621
+ {
622
+ as: "li",
623
+ loadMore,
624
+ rowCount: sorted.length,
625
+ labels,
626
+ compact
627
+ }
568
628
  )
569
629
  ]
570
630
  }
@@ -588,7 +648,7 @@ function DataTable({
588
648
  "grid grid-cols-[auto_1fr] gap-x-3",
589
649
  compact ? "gap-y-0.5 text-xs" : "gap-y-1 text-sm"
590
650
  ),
591
- children: mobileColumns.filter((c) => c.footer).map((col) => /* @__PURE__ */ jsxs(Fragment, { children: [
651
+ children: mobileColumns.filter((c) => c.footer).map((col) => /* @__PURE__ */ jsxs(Fragment2, { children: [
592
652
  /* @__PURE__ */ jsx("dt", { className: "self-center text-xs uppercase tracking-wide text-muted", children: col.header }),
593
653
  /* @__PURE__ */ jsx("dd", { className: "min-w-0 self-center font-semibold text-primary", children: footerValue(col) })
594
654
  ] }, col.key))
@@ -597,7 +657,7 @@ function DataTable({
597
657
  ]
598
658
  }
599
659
  ),
600
- isServer && /* @__PURE__ */ jsx(
660
+ isServer && !loadMore && /* @__PURE__ */ jsx(
601
661
  Pagination,
602
662
  {
603
663
  page: safePage,
@@ -625,7 +685,7 @@ function DataTable({
625
685
  ] }),
626
686
  isMdUp && /* @__PURE__ */ jsxs("div", { className: cn("flex", fillHeight && "flex-1"), children: [
627
687
  /* @__PURE__ */ jsxs("div", { className: cn("relative min-w-0 flex-1", fillHeight && "flex flex-col"), children: [
628
- /* @__PURE__ */ jsx(
688
+ /* @__PURE__ */ jsxs(
629
689
  "div",
630
690
  {
631
691
  ref: desktopScroller,
@@ -633,248 +693,294 @@ function DataTable({
633
693
  className: cn("overflow-auto [scrollbar-gutter:stable]", fillHeight && "min-h-0 grow basis-48"),
634
694
  ...edgeFadeProps,
635
695
  style: fillHeight ? edgeFadeProps.style : { ...edgeFadeProps.style, maxHeight: maxBodyHeight },
636
- children: /* @__PURE__ */ jsxs(
637
- "table",
638
- {
639
- className: cn("w-full", compact ? "text-xs" : "text-sm"),
640
- "aria-label": labels.table,
641
- "aria-busy": isLoading || void 0,
642
- children: [
643
- /* @__PURE__ */ jsx(
644
- DataTableHead,
645
- {
646
- visibleColumns,
647
- selection,
648
- compact,
649
- labels,
650
- locale,
651
- isServer,
652
- hasSortCallback: !!onSortsChange,
653
- hasFilterCallback: !!onFiltersChange,
654
- sorts,
655
- filters,
656
- selectOptionsByKey,
657
- multiSort,
658
- resizable,
659
- widths,
660
- setWidths,
661
- headRefs,
662
- toggleSort,
663
- setFilterValue,
664
- clearFilter,
665
- startResize,
666
- moveResize,
667
- finishResize
668
- }
669
- ),
670
- /* @__PURE__ */ jsxs(
671
- "tbody",
672
- {
673
- className: cn(isLoading && slice.length > 0 && "opacity-60 transition-opacity"),
674
- children: [
675
- leadingRow && /* @__PURE__ */ jsx("tr", { className: "border-t border-subtle", children: /* @__PURE__ */ jsx("td", { colSpan: totalColSpan, className: "p-0", children: leadingRow }) }),
676
- slice.map((row, rowIndex) => {
677
- const expanded = isExpanded?.(row) ?? false;
678
- const expansion = expanded ? expandedRow?.(row) : null;
679
- const rowInteractive = !!onRowClick || !!selection;
680
- const href = rowHref?.(row);
681
- const key = rowKey(row);
682
- const detailId = `${detailIdBase}-${rowIndex}`;
683
- const disclosure = rowsFocusable && expandedRow ? /* @__PURE__ */ jsx(
684
- "button",
696
+ children: [
697
+ /* @__PURE__ */ jsxs(
698
+ "table",
699
+ {
700
+ ref: tableRef,
701
+ className: cn("w-full", compact ? "text-xs" : "text-sm"),
702
+ "data-fit-grow": growDrawn ? "" : void 0,
703
+ "aria-label": labels.table,
704
+ "aria-busy": isLoading || void 0,
705
+ children: [
706
+ /* @__PURE__ */ jsx(
707
+ DataTableHead,
708
+ {
709
+ visibleColumns,
710
+ selection,
711
+ compact,
712
+ labels,
713
+ locale,
714
+ isServer,
715
+ hasSortCallback: !!onSortsChange,
716
+ hasFilterCallback: !!onFiltersChange,
717
+ sorts,
718
+ filters,
719
+ selectOptionsByKey,
720
+ multiSort,
721
+ resizable,
722
+ widths,
723
+ setWidths,
724
+ headRefs,
725
+ toggleSort,
726
+ setFilterValue,
727
+ clearFilter,
728
+ startResize,
729
+ moveResize,
730
+ finishResize
731
+ }
732
+ ),
733
+ (() => {
734
+ const bodyClass = cn(isLoading && slice.length > 0 && "opacity-60 transition-opacity");
735
+ const leading = leadingRow ? /* @__PURE__ */ jsx(DataTableLeadingRow, { colSpan: totalColSpan, sticky: leadingRowSticky, children: leadingRow }) : null;
736
+ const renderRow = (row, rowIndex) => {
737
+ const expanded = isExpanded?.(row) ?? false;
738
+ const expansion = expanded ? expandedRow?.(row) : null;
739
+ const rowInteractive = !!onRowClick || !!selection;
740
+ const href = rowHref?.(row);
741
+ const key = rowKey(row);
742
+ const detailId = `${detailIdBase}-${rowIndex}`;
743
+ const disclosure = rowsFocusable && expandedRow ? /* @__PURE__ */ jsx(
744
+ "button",
745
+ {
746
+ type: "button",
747
+ tabIndex: -1,
748
+ className: "sr-only-fixed",
749
+ "aria-label": labels.rowDetails,
750
+ "aria-expanded": expanded,
751
+ "aria-controls": expansion ? detailId : void 0,
752
+ onClick: () => onRowClick(row)
753
+ }
754
+ ) : null;
755
+ return /* @__PURE__ */ jsxs(Fragment2, { children: [
756
+ /* @__PURE__ */ jsxs(
757
+ "tr",
685
758
  {
686
- type: "button",
687
- tabIndex: -1,
688
- className: "sr-only-fixed",
689
- "aria-label": labels.rowDetails,
690
- "aria-expanded": expanded,
691
- "aria-controls": expansion ? detailId : void 0,
692
- onClick: () => onRowClick(row)
693
- }
694
- ) : null;
695
- return /* @__PURE__ */ jsxs(Fragment, { children: [
696
- /* @__PURE__ */ jsxs(
697
- "tr",
698
- {
699
- ...cleanAttrs(rowAttributes?.(row)),
700
- "data-row-nav": rowsFocusable ? "" : void 0,
701
- tabIndex: rowsFocusable ? key === tabRowKey ? 0 : -1 : void 0,
702
- onFocus: rowsFocusable ? (e) => {
703
- if (e.target === e.currentTarget) setFocusRowKey(key);
704
- } : void 0,
705
- onKeyDown: rowsFocusable ? (e) => {
706
- if (e.target !== e.currentTarget) return;
707
- if (e.altKey || e.ctrlKey || e.metaKey) return;
708
- if (e.key === "Enter" || e.key === " ") {
709
- e.preventDefault();
710
- onRowClick(row);
759
+ ...cleanAttrs(rowAttributes?.(row)),
760
+ "data-row-nav": rowsFocusable ? "" : void 0,
761
+ tabIndex: rowsFocusable ? key === tabRowKey ? 0 : -1 : void 0,
762
+ onFocus: rowsFocusable ? (e) => {
763
+ if (e.target === e.currentTarget) setFocusRowKey(key);
764
+ } : void 0,
765
+ onKeyDown: rowsFocusable ? (e) => {
766
+ if (e.target !== e.currentTarget) return;
767
+ if (e.altKey || e.ctrlKey || e.metaKey) return;
768
+ if (e.key === "Enter" || e.key === " ") {
769
+ e.preventDefault();
770
+ onRowClick(row);
771
+ return;
772
+ }
773
+ if (e.shiftKey) return;
774
+ if (moveRowFocus(e.currentTarget, e.key)) e.preventDefault();
775
+ } : void 0,
776
+ className: cn(
777
+ "border-t border-subtle",
778
+ rowInteractive && "cursor-pointer hover:bg-hover",
779
+ // The kit's focus frame width (§5, `--focus-ring-width`), drawn as an
780
+ // OUTLINE rather than FOCUS_RING's box-shadow: a shadow on a `<tr>`
781
+ // is not painted by every engine, an outline is.
782
+ rowsFocusable && "focus-visible:bg-hover focus-visible:outline-focus focus-visible:-outline-offset-2 focus-visible:outline-brand",
783
+ rowClassName?.(row)
784
+ ),
785
+ onClick: rowInteractive ? (e) => {
786
+ if (fromOwnControl(e.target, e.currentTarget)) return;
787
+ if (fromOutside(e.target, e.currentTarget)) return;
788
+ if (selection && canSelect(row)) {
789
+ if (e.shiftKey) {
790
+ window.getSelection?.()?.removeAllRanges();
791
+ if (selectRange(rowIndex)) return;
792
+ selectionAnchor.current = rowKey(row);
793
+ selection.onToggle(row, !selection.isSelected(row));
711
794
  return;
712
795
  }
713
- if (e.shiftKey) return;
714
- if (moveRowFocus(e.currentTarget, e.key)) e.preventDefault();
715
- } : void 0,
716
- className: cn(
717
- "border-t border-subtle",
718
- rowInteractive && "cursor-pointer hover:bg-hover",
719
- // The kit's focus frame width (§5, `--focus-ring-width`), drawn as an
720
- // OUTLINE rather than FOCUS_RING's box-shadow: a shadow on a `<tr>`
721
- // is not painted by every engine, an outline is.
722
- rowsFocusable && "focus-visible:bg-hover focus-visible:outline-focus focus-visible:-outline-offset-2 focus-visible:outline-brand",
723
- rowClassName?.(row)
724
- ),
725
- onClick: rowInteractive ? (e) => {
726
- if (fromOwnControl(e.target, e.currentTarget)) return;
727
- if (fromOutside(e.target, e.currentTarget)) return;
728
- if (selection && canSelect(row)) {
729
- if (e.shiftKey) {
730
- window.getSelection?.()?.removeAllRanges();
731
- if (selectRange(rowIndex)) return;
732
- selectionAnchor.current = rowKey(row);
733
- selection.onToggle(row, !selection.isSelected(row));
734
- return;
735
- }
736
- if (e.metaKey || e.ctrlKey) {
737
- selectionAnchor.current = rowKey(row);
738
- selection.onToggle(row, !selection.isSelected(row));
739
- return;
740
- }
796
+ if (e.metaKey || e.ctrlKey) {
797
+ selectionAnchor.current = rowKey(row);
798
+ selection.onToggle(row, !selection.isSelected(row));
799
+ return;
741
800
  }
742
- onRowClick?.(row);
743
- } : void 0,
744
- children: [
745
- selection && /* @__PURE__ */ jsx(
801
+ }
802
+ onRowClick?.(row);
803
+ } : void 0,
804
+ children: [
805
+ selection && /* @__PURE__ */ jsx(
806
+ "td",
807
+ {
808
+ className: cn("align-top", compact ? "w-8 px-2 py-1" : "w-10 px-3 py-2"),
809
+ onClick: (e) => e.stopPropagation(),
810
+ children: canSelect(row) && /* @__PURE__ */ jsx(
811
+ "input",
812
+ {
813
+ type: "checkbox",
814
+ className: cn("accent-indigo-600", compact ? "size-3.5" : "size-4"),
815
+ checked: selection.isSelected(row),
816
+ onClick: (e) => {
817
+ if (e.shiftKey && selectRange(rowIndex)) {
818
+ e.preventDefault();
819
+ rangeClick.current = e.nativeEvent;
820
+ }
821
+ },
822
+ onChange: (e) => {
823
+ if (rangeClick.current && e.nativeEvent === rangeClick.current) {
824
+ rangeClick.current = null;
825
+ return;
826
+ }
827
+ selectionAnchor.current = rowKey(row);
828
+ selection.onToggle(row, e.target.checked);
829
+ },
830
+ "aria-label": labels.selectRow
831
+ }
832
+ )
833
+ }
834
+ ),
835
+ visibleColumns.map((col, colIndex) => {
836
+ const width = widths[col.key];
837
+ const own = splitCellProps(col.cellProps?.(row));
838
+ const pinned = width ? { width, minWidth: width, maxWidth: width } : void 0;
839
+ return /* @__PURE__ */ createElement(
746
840
  "td",
747
841
  {
748
- className: cn("align-top", compact ? "w-8 px-2 py-1" : "w-10 px-3 py-2"),
749
- onClick: (e) => e.stopPropagation(),
750
- children: canSelect(row) && /* @__PURE__ */ jsx(
751
- "input",
752
- {
753
- type: "checkbox",
754
- className: cn("accent-indigo-600", compact ? "size-3.5" : "size-4"),
755
- checked: selection.isSelected(row),
756
- onClick: (e) => {
757
- if (e.shiftKey && selectRange(rowIndex)) {
758
- e.preventDefault();
759
- rangeClick.current = e.nativeEvent;
760
- }
761
- },
762
- onChange: (e) => {
763
- if (rangeClick.current && e.nativeEvent === rangeClick.current) {
764
- rangeClick.current = null;
765
- return;
766
- }
767
- selectionAnchor.current = rowKey(row);
768
- selection.onToggle(row, e.target.checked);
769
- },
770
- "aria-label": labels.selectRow
771
- }
842
+ ...own.attrs,
843
+ key: col.key,
844
+ "data-col": col.key,
845
+ style: own.style || pinned ? { ...own.style, ...pinned } : void 0,
846
+ className: cn(
847
+ "align-top",
848
+ compact ? "px-2 py-1" : "px-3 py-2",
849
+ width && "overflow-hidden text-ellipsis",
850
+ col.grow ? GROW_CELL_CLASS : growDrawn && GROW_PEER_CELL_CLASS,
851
+ logicalAlign(own.className),
852
+ logicalAlign(col.className)
772
853
  )
773
- }
774
- ),
775
- visibleColumns.map((col, colIndex) => {
776
- const width = widths[col.key];
777
- const own = splitCellProps(col.cellProps?.(row));
778
- const pinned = width ? { width, minWidth: width, maxWidth: width } : void 0;
779
- return /* @__PURE__ */ createElement(
780
- "td",
781
- {
782
- ...own.attrs,
783
- key: col.key,
784
- "data-col": col.key,
785
- style: own.style || pinned ? { ...own.style, ...pinned } : void 0,
786
- className: cn(
787
- "align-top",
788
- compact ? "px-2 py-1" : "px-3 py-2",
789
- width && "overflow-hidden text-ellipsis",
790
- logicalAlign(own.className),
791
- logicalAlign(col.className)
792
- )
793
- },
794
- colIndex === 0 && disclosure,
795
- col === linkColumn && href ? (
796
- // No `onActivate`: the click is left to bubble to the
797
- // <tr> handler above, which already owns expand-vs-select.
798
- // Calling it here as well would toggle the row twice.
799
- /* @__PURE__ */ jsx(RowLink, { href, className: "block", "data-row-link": "", children: col.cell(row) })
800
- ) : col.cell(row)
801
- );
802
- })
803
- ]
804
- }
805
- ),
806
- expansion && /* @__PURE__ */ jsx("tr", { id: disclosure ? detailId : void 0, className: "bg-surface-2 border-t border-subtle", children: /* @__PURE__ */ jsx("td", { colSpan: totalColSpan, className: "p-0", children: /* @__PURE__ */ jsx("div", { className: cn("w-0 min-w-full", compact ? "px-2 py-2" : "px-3 py-3"), children: expansion }) }) })
807
- ] }, key);
808
- }),
809
- slice.length === 0 && /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
810
- "td",
811
- {
812
- colSpan: totalColSpan,
813
- className: cn("text-center text-muted", compact ? "px-2 py-2" : "px-3 py-4"),
814
- children: isLoading ? /* @__PURE__ */ jsx(LoadingText, { label: labels.loading }) : empty ?? labels.empty
815
- }
816
- ) })
817
- ]
818
- }
819
- ),
820
- showFooter && // Sticky to the scroller's bottom edge for the same reason the header is
821
- // sticky to its top: the body scrolls inside a bounded wrapper, and a
822
- // total that scrolls away with the last row is a total nobody sees on a
823
- // 25-row page. Each cell carries its own background and its own `sticky`,
824
- // as the header's do — `position: sticky` on a `<tfoot>` is not reliable.
825
- /* @__PURE__ */ jsx(
826
- "tfoot",
827
- {
828
- "data-table-footer": "",
829
- className: cn(
830
- "font-semibold text-primary",
831
- isLoading && "opacity-60 transition-opacity"
832
- ),
833
- children: /* @__PURE__ */ jsxs("tr", { children: [
834
- selection && /* @__PURE__ */ jsx(
835
- "td",
836
- {
837
- className: cn(
838
- FOOTER_CELL,
839
- compact ? "w-8 px-2 py-1" : "w-10 px-3 py-2"
840
- )
841
- }
854
+ },
855
+ colIndex === 0 && disclosure,
856
+ col === linkColumn && href ? (
857
+ // No `onActivate`: the click is left to bubble to the
858
+ // <tr> handler above, which already owns expand-vs-select.
859
+ // Calling it here as well would toggle the row twice.
860
+ /* @__PURE__ */ jsx(RowLink, { href, className: "block", "data-row-link": "", children: col.cell(row) })
861
+ ) : col.cell(row)
862
+ );
863
+ })
864
+ ]
865
+ }
866
+ ),
867
+ expansion && /* @__PURE__ */ jsx("tr", { id: disclosure ? detailId : void 0, className: "bg-surface-2 border-t border-subtle", children: /* @__PURE__ */ jsx("td", { colSpan: totalColSpan, className: "p-0", children: /* @__PURE__ */ jsx("div", { className: "w-0 min-w-full", children: /* @__PURE__ */ jsx(
868
+ "div",
869
+ {
870
+ className: cn(
871
+ "sticky start-0 w-[var(--dt-visible-w,100%)] max-w-full",
872
+ compact ? "px-2 py-2" : "px-3 py-3"
873
+ ),
874
+ children: expansion
875
+ }
876
+ ) }) }) })
877
+ ] }, key);
878
+ };
879
+ const emptyRow = slice.length === 0 ? /* @__PURE__ */ jsx("tr", { children: /* @__PURE__ */ jsx(
880
+ "td",
881
+ {
882
+ colSpan: totalColSpan,
883
+ className: cn("text-center text-muted", compact ? "px-2 py-2" : "px-3 py-4"),
884
+ children: isLoading ? /* @__PURE__ */ jsx(LoadingText, { label: labels.loading }) : empty ?? labels.empty
885
+ }
886
+ ) }) : null;
887
+ if (!desktopGroups) {
888
+ return /* @__PURE__ */ jsxs("tbody", { className: bodyClass, children: [
889
+ leading,
890
+ slice.map(renderRow),
891
+ emptyRow
892
+ ] });
893
+ }
894
+ const band = (level, def, g) => /* @__PURE__ */ jsx(
895
+ DataTableGroupBand,
896
+ {
897
+ level,
898
+ colSpan: totalColSpan,
899
+ top: level === 1 ? bandTops[0] : bandTops[1],
900
+ compact,
901
+ label: def.label ? def.label(g.key, g.rows) : g.key,
902
+ end: def.end?.(g.key, g.rows)
903
+ }
904
+ );
905
+ const rowsOf = (g) => g.rows.map((r, i) => renderRow(r, g.start + i));
906
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
907
+ (leading || emptyRow) && /* @__PURE__ */ jsxs("tbody", { className: bodyClass, children: [
908
+ leading,
909
+ emptyRow
910
+ ] }),
911
+ desktopGroups.map(
912
+ (g1) => g1.children ? g1.children.map((g2, j) => /* @__PURE__ */ jsxs("tbody", { className: bodyClass, children: [
913
+ j === 0 && band(1, levels[0], g1),
914
+ band(2, levels[1], g2),
915
+ rowsOf(g2)
916
+ ] }, `g:${g1.key}:${g2.key}:${g2.start}`)) : /* @__PURE__ */ jsxs("tbody", { className: bodyClass, children: [
917
+ band(1, levels[0], g1),
918
+ rowsOf(g1)
919
+ ] }, `g:${g1.key}:${g1.start}`)
920
+ )
921
+ ] });
922
+ })(),
923
+ showFooter && // Sticky to the scroller's bottom edge for the same reason the header is
924
+ // sticky to its top: the body scrolls inside a bounded wrapper, and a
925
+ // total that scrolls away with the last row is a total nobody sees on a
926
+ // 25-row page. Each cell carries its own background and its own `sticky`,
927
+ // as the header's do — `position: sticky` on a `<tfoot>` is not reliable.
928
+ /* @__PURE__ */ jsx(
929
+ "tfoot",
930
+ {
931
+ "data-table-footer": "",
932
+ className: cn(
933
+ "font-semibold text-primary",
934
+ isLoading && "opacity-60 transition-opacity"
842
935
  ),
843
- visibleColumns.map((col) => {
844
- const width = widths[col.key];
845
- const pinned = width ? { width, minWidth: width, maxWidth: width } : void 0;
846
- const isLabel = col === footerLabelCol;
847
- const Cell = isLabel ? "th" : "td";
848
- return /* @__PURE__ */ jsx(
849
- Cell,
936
+ children: /* @__PURE__ */ jsxs("tr", { children: [
937
+ selection && /* @__PURE__ */ jsx(
938
+ "td",
850
939
  {
851
- "data-col": col.key,
852
- scope: isLabel ? "row" : void 0,
853
- style: pinned,
854
940
  className: cn(
855
941
  FOOTER_CELL,
856
- "align-top",
857
- compact ? "px-2 py-1" : "px-3 py-2",
858
- width && "overflow-hidden text-ellipsis",
859
- // A `<th>` centres by default; the label reads from the start
860
- // like the cells above it, unless the column says otherwise.
861
- isLabel && "text-start",
862
- logicalAlign(col.className)
863
- ),
864
- children: col.footer ? footerValue(col) : isLabel ? footerLabel : null
865
- },
866
- col.key
867
- );
868
- })
869
- ] })
870
- }
871
- )
872
- ]
873
- }
874
- )
942
+ compact ? "w-8 px-2 py-1" : "w-10 px-3 py-2"
943
+ )
944
+ }
945
+ ),
946
+ visibleColumns.map((col) => {
947
+ const width = widths[col.key];
948
+ const pinned = width ? { width, minWidth: width, maxWidth: width } : void 0;
949
+ const isLabel = col === footerLabelCol;
950
+ const Cell = isLabel ? "th" : "td";
951
+ return /* @__PURE__ */ jsx(
952
+ Cell,
953
+ {
954
+ "data-col": col.key,
955
+ scope: isLabel ? "row" : void 0,
956
+ style: pinned,
957
+ className: cn(
958
+ FOOTER_CELL,
959
+ "align-top",
960
+ compact ? "px-2 py-1" : "px-3 py-2",
961
+ width && "overflow-hidden text-ellipsis",
962
+ // A `<th>` centres by default; the label reads from the start
963
+ // like the cells above it, unless the column says otherwise.
964
+ isLabel && "text-start",
965
+ col.grow ? GROW_CELL_CLASS : growDrawn && GROW_PEER_CELL_CLASS,
966
+ logicalAlign(col.className)
967
+ ),
968
+ children: col.footer ? footerValue(col) : isLabel ? footerLabel : null
969
+ },
970
+ col.key
971
+ );
972
+ })
973
+ ] })
974
+ }
975
+ )
976
+ ]
977
+ }
978
+ ),
979
+ loadMore && /* @__PURE__ */ jsx(DataTableLoadMoreFooter, { loadMore, rowCount: sorted.length, labels, compact })
980
+ ]
875
981
  }
876
982
  ),
877
- !unpaged && /* @__PURE__ */ jsx(
983
+ !unpaged && !loadMore && /* @__PURE__ */ jsx(
878
984
  Pagination,
879
985
  {
880
986
  page: safePage,
@@ -899,6 +1005,8 @@ function DataTable({
899
1005
  columns,
900
1006
  hiddenCols,
901
1007
  setHiddenCols,
1008
+ autoHidden,
1009
+ keepColumn,
902
1010
  showSettings,
903
1011
  setShowSettings,
904
1012
  columnsCountLabel,