@camstack/ui-library 1.2.254 → 1.2.256

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -15034,13 +15034,12 @@ function usePrompt() {
15034
15034
  return useDialogContext$1().prompt;
15035
15035
  }
15036
15036
  var VARIANT_STYLES$2 = {
15037
- danger: { button: "bg-red-500 hover:bg-red-600 text-white" },
15038
- warning: { button: "bg-orange-500 hover:bg-orange-600 text-white" },
15039
- default: { button: "bg-primary hover:bg-primary/90 text-white" }
15037
+ danger: { button: "bg-danger hover:bg-danger/90 text-primary-foreground" },
15038
+ warning: { button: "bg-warning hover:bg-warning/90 text-primary-foreground" },
15039
+ default: { button: "bg-primary hover:bg-primary/90 text-primary-foreground" }
15040
15040
  };
15041
15041
  var CANCEL_CLASS = "px-3 py-1.5 text-xs font-medium rounded-md border border-border text-foreground-subtle hover:text-foreground hover:bg-surface-hover transition-colors";
15042
15042
  function variantOf(state) {
15043
- if (state.kind === "prompt") return "default";
15044
15043
  return state.options.variant ?? "default";
15045
15044
  }
15046
15045
  /**
@@ -15259,7 +15258,7 @@ function PromptBody({ options, value, error, inputRef, onChange }) {
15259
15258
  const inputId = "camstack-dialog-input";
15260
15259
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(react_jsx_runtime.Fragment, { children: [
15261
15260
  options.message !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
15262
- className: "mt-2 text-xs text-foreground-subtle leading-relaxed",
15261
+ className: "mt-2 max-h-48 overflow-y-auto text-xs text-foreground-subtle leading-relaxed whitespace-pre-line",
15263
15262
  children: options.message
15264
15263
  }),
15265
15264
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("label", {
@@ -15283,7 +15282,7 @@ function PromptBody({ options, value, error, inputRef, onChange }) {
15283
15282
  className: "mt-1 w-full rounded-md border border-border bg-surface px-2 py-1.5 text-xs text-foreground outline-none focus:border-primary"
15284
15283
  }),
15285
15284
  error !== null && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("p", {
15286
- className: "mt-1.5 text-[11px] text-red-400",
15285
+ className: "mt-1.5 text-[11px] text-danger",
15287
15286
  children: error
15288
15287
  })
15289
15288
  ] });
@@ -35266,6 +35265,147 @@ function resolveTableLayout({ mode, columnCount, isNarrow }) {
35266
35265
  return columnCount >= 4 ? "cards" : "table";
35267
35266
  }
35268
35267
  //#endregion
35268
+ //#region src/composites/data-table-pager.tsx
35269
+ /**
35270
+ * The pager under a paginated {@link DataTable}: the range ("26–50 of 167")
35271
+ * and previous / next. A `<nav>` named after its table, because two paged
35272
+ * tables on one page are otherwise two identical landmarks.
35273
+ *
35274
+ * The range is a polite live region: a screen-reader user who pressed "Next"
35275
+ * hears where they landed without having to hunt for it.
35276
+ */
35277
+ function DataTablePager({ page, labels, onPageChange }) {
35278
+ const atStart = page.page === 0;
35279
+ const atEnd = page.page >= page.pageCount - 1;
35280
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("nav", {
35281
+ "aria-label": labels.navLabel,
35282
+ className: "flex items-center justify-end gap-2 pt-2",
35283
+ children: [
35284
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
35285
+ "aria-live": "polite",
35286
+ className: "text-[11px] tabular-nums text-foreground-subtle",
35287
+ children: labels.range(page.from, page.to, page.total)
35288
+ }),
35289
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconButton, {
35290
+ type: "button",
35291
+ variant: "outline",
35292
+ size: "sm",
35293
+ icon: ChevronLeft,
35294
+ "aria-label": labels.previous,
35295
+ title: labels.previous,
35296
+ disabled: atStart,
35297
+ onClick: () => onPageChange(page.page - 1)
35298
+ }),
35299
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)(IconButton, {
35300
+ type: "button",
35301
+ variant: "outline",
35302
+ size: "sm",
35303
+ icon: ChevronRight,
35304
+ "aria-label": labels.next,
35305
+ title: labels.next,
35306
+ disabled: atEnd,
35307
+ onClick: () => onPageChange(page.page + 1)
35308
+ })
35309
+ ]
35310
+ });
35311
+ }
35312
+ //#endregion
35313
+ //#region src/composites/data-table-pagination.ts
35314
+ function paginateRows(rows, page, pageSize) {
35315
+ const size = Math.max(1, Math.floor(pageSize));
35316
+ const total = rows.length;
35317
+ const pageCount = Math.max(1, Math.ceil(total / size));
35318
+ const clamped = Math.min(Math.max(0, Math.floor(page)), pageCount - 1);
35319
+ const start = clamped * size;
35320
+ const pageRows = rows.slice(start, start + size);
35321
+ return {
35322
+ pageRows,
35323
+ page: clamped,
35324
+ pageCount,
35325
+ from: pageRows.length === 0 ? 0 : start + 1,
35326
+ to: start + pageRows.length,
35327
+ total
35328
+ };
35329
+ }
35330
+ var DEFAULT_PAGINATION_LABELS = {
35331
+ navLabel: "Table pages",
35332
+ previous: "Previous page",
35333
+ next: "Next page",
35334
+ range: (from, to, total) => `${from}–${to} of ${total}`
35335
+ };
35336
+ //#endregion
35337
+ //#region src/composites/data-table-selection.tsx
35338
+ /**
35339
+ * Row selection for {@link DataTable}, as a synthetic leading column.
35340
+ *
35341
+ * A column, not a second rendering path: the table and the card layout both
35342
+ * already know how to draw columns, so selection works in both without a
35343
+ * branch of its own (in cards, the unlabelled column lands in the card's
35344
+ * footer strip with the other controls).
35345
+ *
35346
+ * Rules a bulk action relies on — pinned in `data-table-paging-selection.test`:
35347
+ * - the header box acts on the selectable rows of the page ON SCREEN only;
35348
+ * - a row `isSelectable` rejects has no box and is never added;
35349
+ * - keys of rows that are not on screen survive a page-level toggle.
35350
+ */
35351
+ var SELECTION_COLUMN_KEY = "__select";
35352
+ var CHECKBOX = "cursor-pointer align-middle";
35353
+ function PageCheckbox({ checked, indeterminate, disabled, label, onToggle }) {
35354
+ const ref = (0, react$1.useRef)(null);
35355
+ (0, react$1.useEffect)(() => {
35356
+ if (ref.current !== null) ref.current.indeterminate = indeterminate;
35357
+ }, [indeterminate]);
35358
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Checkbox, {
35359
+ ref,
35360
+ "aria-label": label,
35361
+ checked,
35362
+ disabled,
35363
+ onChange: onToggle,
35364
+ className: CHECKBOX
35365
+ });
35366
+ }
35367
+ /** The selection column for the rows currently on screen. */
35368
+ function selectionColumn(selection, pageRows, keyOf) {
35369
+ const selectable = selection.isSelectable ?? (() => true);
35370
+ const pageKeys = pageRows.filter(selectable).map(keyOf);
35371
+ const onPage = pageKeys.filter((k) => selection.selected.has(k)).length;
35372
+ const allOnPage = pageKeys.length > 0 && onPage === pageKeys.length;
35373
+ const togglePage = () => {
35374
+ const next = new Set(selection.selected);
35375
+ for (const key of pageKeys) if (allOnPage) next.delete(key);
35376
+ else next.add(key);
35377
+ selection.onChange(next);
35378
+ };
35379
+ const toggleRow = (key) => {
35380
+ const next = new Set(selection.selected);
35381
+ if (next.has(key)) next.delete(key);
35382
+ else next.add(key);
35383
+ selection.onChange(next);
35384
+ };
35385
+ return {
35386
+ key: SELECTION_COLUMN_KEY,
35387
+ width: "w-8",
35388
+ headerRender: () => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(PageCheckbox, {
35389
+ checked: allOnPage,
35390
+ indeterminate: onPage > 0 && !allOnPage,
35391
+ disabled: pageKeys.length === 0,
35392
+ label: selection.pageLabel,
35393
+ onToggle: togglePage
35394
+ }),
35395
+ render: (row) => {
35396
+ if (!selectable(row)) return null;
35397
+ const key = keyOf(row);
35398
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(Checkbox, {
35399
+ "aria-label": selection.rowLabel(row),
35400
+ checked: selection.selected.has(key),
35401
+ onChange: () => toggleRow(key),
35402
+ onClick: (e) => e.stopPropagation(),
35403
+ className: CHECKBOX
35404
+ });
35405
+ }
35406
+ };
35407
+ }
35408
+ //#endregion
35269
35409
  //#region src/composites/setting-row.tsx
35270
35410
  function SettingRow({ label, children, actions, elements = "plain", className, valueClassName }) {
35271
35411
  const LabelTag = elements === "description" ? "dt" : "span";
@@ -35437,9 +35577,19 @@ var ALIGN_CLASS = {
35437
35577
  right: "text-right",
35438
35578
  center: "text-center"
35439
35579
  };
35440
- function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyMessage, className, bordered = true, rowClassName, mobileMode = "scroll", maxBodyHeight, defaultSort }) {
35580
+ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyMessage, className, bordered = true, rowClassName, mobileMode = "scroll", maxBodyHeight, defaultSort, sort: sortProp, onSortChange, pageSize, page: pageProp, onPageChange, paginationLabels = DEFAULT_PAGINATION_LABELS, selection }) {
35441
35581
  const isNarrow = useIsMobile();
35442
- const [sort, setSort] = (0, react$1.useState)(defaultSort ?? null);
35582
+ const [innerSort, setInnerSort] = (0, react$1.useState)(defaultSort ?? null);
35583
+ const [innerPage, setInnerPage] = (0, react$1.useState)(0);
35584
+ const sort = sortProp !== void 0 ? sortProp : innerSort;
35585
+ const changeSort = (next) => {
35586
+ if (sortProp === void 0) setInnerSort(next);
35587
+ onSortChange?.(next);
35588
+ };
35589
+ const changePage = (next) => {
35590
+ if (pageProp === void 0) setInnerPage(next);
35591
+ onPageChange?.(next);
35592
+ };
35443
35593
  const layout = resolveTableLayout({
35444
35594
  mode: mobileMode,
35445
35595
  columnCount: columns.length,
@@ -35454,36 +35604,48 @@ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyM
35454
35604
  sortValue
35455
35605
  ]);
35456
35606
  const activeSort = sortedColumn === void 0 ? null : sort;
35607
+ const paged = pageSize === void 0 ? null : paginateRows(displayRows, pageProp ?? innerPage, pageSize);
35608
+ const pageRows = paged === null ? displayRows : paged.pageRows;
35609
+ const pager = paged !== null && paged.pageCount > 1 ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTablePager, {
35610
+ page: paged,
35611
+ labels: paginationLabels,
35612
+ onPageChange: changePage
35613
+ }) : null;
35614
+ const keyOf = (row) => String(rowKey ? rowKey(row, rows.indexOf(row)) : rows.indexOf(row));
35615
+ const shownColumns = selection === void 0 ? columns : [selectionColumn(selection, pageRows, keyOf), ...columns];
35457
35616
  if (rows.length === 0 && emptyMessage) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
35458
35617
  className: `rounded-lg ${bordered ? "border border-border" : ""} bg-surface px-3 py-4 text-xs text-foreground-subtle text-center ${className ?? ""}`,
35459
35618
  children: emptyMessage
35460
35619
  });
35461
35620
  if (rows.length === 0) return null;
35462
- if (layout === "cards") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
35463
- className: `space-y-2 ${scrolls ? `${maxBodyHeight} overflow-y-auto` : ""} ${className ?? ""}`,
35464
- children: displayRows.map((row, rowIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableCard, {
35465
- row,
35466
- rowIndex,
35467
- columns,
35468
- bordered,
35469
- onRowClick,
35470
- rowClassName
35471
- }, rowKey ? rowKey(row, rowIndex) : rowIndex))
35472
- });
35473
- return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
35621
+ if (layout === "cards") return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
35622
+ className,
35623
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
35624
+ className: `space-y-2 ${scrolls ? `${maxBodyHeight} overflow-y-auto` : ""}`,
35625
+ children: pageRows.map((row, rowIndex) => /* @__PURE__ */ (0, react_jsx_runtime.jsx)(DataTableCard, {
35626
+ row,
35627
+ rowIndex,
35628
+ columns: shownColumns,
35629
+ bordered,
35630
+ onRowClick,
35631
+ rowClassName
35632
+ }, rowKey ? rowKey(row, rowIndex) : rowIndex))
35633
+ }), pager]
35634
+ });
35635
+ const table = /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
35474
35636
  className: [
35475
35637
  "rounded-lg",
35476
35638
  bordered ? "border border-border" : "",
35477
35639
  "bg-surface overflow-x-auto",
35478
35640
  scrolls ? `${maxBodyHeight} overflow-y-auto` : "",
35479
- className ?? ""
35641
+ pager === null ? className ?? "" : ""
35480
35642
  ].filter(Boolean).join(" "),
35481
35643
  children: /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("table", {
35482
35644
  className: `w-full text-xs ${scrolls ? "border-separate border-spacing-0" : ""}`,
35483
35645
  style: { minWidth: `${minWidthPx}px` },
35484
35646
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("thead", {
35485
35647
  className: "bg-surface",
35486
- children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", { children: columns.map((col) => {
35648
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", { children: shownColumns.map((col) => {
35487
35649
  const align = col.align ?? "left";
35488
35650
  const nowrap = col.nowrap ?? true;
35489
35651
  const sortable = col.sortValue !== void 0;
@@ -35502,21 +35664,22 @@ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyM
35502
35664
  label: col.headerRender ? col.headerRender() : col.header,
35503
35665
  active: isSorted,
35504
35666
  dir: isSorted && activeSort !== null ? activeSort.dir : "asc",
35505
- onSort: () => setSort((prev) => nextTableSort(prev, col.key))
35667
+ onSort: () => changeSort(nextTableSort(sort, col.key))
35506
35668
  }) : col.headerRender ? col.headerRender() : col.header
35507
35669
  }, col.key);
35508
35670
  }) })
35509
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: displayRows.map((row, rowIndex) => {
35671
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tbody", { children: pageRows.map((row, rowIndex) => {
35510
35672
  const key = rowKey ? rowKey(row, rowIndex) : rowIndex;
35511
35673
  const extra = rowClassName?.(row, rowIndex) ?? "";
35512
35674
  const interactive = onRowClick !== void 0;
35513
35675
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("tr", {
35514
35676
  onClick: interactive ? () => onRowClick(row, rowIndex) : void 0,
35515
35677
  className: [interactive ? "cursor-pointer hover:bg-primary/5" : "hover:bg-primary/5", extra].filter(Boolean).join(" "),
35516
- children: columns.map((col) => {
35678
+ children: shownColumns.map((col) => {
35517
35679
  const align = col.align ?? "left";
35518
35680
  const nowrap = col.nowrap ?? true;
35519
35681
  return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("td", {
35682
+ "data-cell": col.key,
35520
35683
  className: [
35521
35684
  "px-3 py-2 text-foreground border-b border-border",
35522
35685
  ALIGN_CLASS[align],
@@ -35529,6 +35692,11 @@ function DataTable({ columns, rows, rowKey, onRowClick, minWidthPx = 480, emptyM
35529
35692
  }) })]
35530
35693
  })
35531
35694
  });
35695
+ if (pager === null) return table;
35696
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
35697
+ className,
35698
+ children: [table, pager]
35699
+ });
35532
35700
  }
35533
35701
  /**
35534
35702
  * One row as a card. Columns that carry a plain-text `header` become labelled
@@ -37789,8 +37957,28 @@ function dataTableFacets(rows, facetValue) {
37789
37957
  count
37790
37958
  })).toSorted((a, b) => b.count - a.count || a.value.localeCompare(b.value));
37791
37959
  }
37960
+ /** One chip row per configured group, each derived like {@link dataTableFacets}. */
37961
+ function dataTableFacetGroups(rows, groups) {
37962
+ return (groups ?? []).map((group) => ({
37963
+ id: group.id,
37964
+ facets: dataTableFacets(rows, group.value)
37965
+ }));
37966
+ }
37792
37967
  function isDataTableFilterActive(state) {
37793
- return state.search.trim() !== "" || state.facets.length > 0;
37968
+ const anyGroup = Object.values(state.groups ?? {}).some((values) => values.length > 0);
37969
+ return state.search.trim() !== "" || state.facets.length > 0 || anyGroup;
37970
+ }
37971
+ /** A new state with `value` added to, or removed from, group `groupId`. */
37972
+ function toggleDataTableGroupFacet(state, groupId, value) {
37973
+ const current = state.groups?.[groupId] ?? [];
37974
+ const next = current.includes(value) ? current.filter((v) => v !== value) : [...current, value];
37975
+ return {
37976
+ ...state,
37977
+ groups: {
37978
+ ...state.groups,
37979
+ [groupId]: next
37980
+ }
37981
+ };
37794
37982
  }
37795
37983
  /** A new state with `value` added to, or removed from, the selected facets. */
37796
37984
  function toggleDataTableFacet(state, value) {
@@ -37810,8 +37998,17 @@ function filterDataTableRows(rows, state, config) {
37810
37998
  const facetValue = config.facetValue;
37811
37999
  const present = new Set(dataTableFacets(rows, facetValue).map((f) => f.value));
37812
38000
  const selected = new Set(state.facets.filter((v) => present.has(v)));
38001
+ const groupGates = (config.facetGroups ?? []).flatMap((group) => {
38002
+ const presentInGroup = new Set(dataTableFacets(rows, group.value).map((f) => f.value));
38003
+ const chosen = new Set((state.groups?.[group.id] ?? []).filter((v) => presentInGroup.has(v)));
38004
+ return chosen.size === 0 ? [] : [{
38005
+ value: group.value,
38006
+ chosen
38007
+ }];
38008
+ });
37813
38009
  return rows.filter((row) => {
37814
38010
  if (selected.size > 0 && facetValue !== void 0 && !selected.has(facetValue(row))) return false;
38011
+ if (groupGates.some((gate) => !gate.chosen.has(gate.value(row)))) return false;
37815
38012
  if (needle !== "" && !config.searchText(row).some((text) => fuzzyMatch(needle, text))) return false;
37816
38013
  return true;
37817
38014
  });
@@ -37830,8 +38027,8 @@ function filterDataTableRows(rows, state, config) {
37830
38027
  */
37831
38028
  var CHIP_ON = "rounded-full border border-primary bg-primary/10 px-2 py-0.5 text-[10px] text-foreground";
37832
38029
  var CHIP_OFF = "rounded-full border border-border px-2 py-0.5 text-[10px] text-foreground-muted hover:bg-surface-hover";
37833
- function DataTableFilterBar({ state, facets, labels, onSearch, onToggleFacet, onClear, facetLabel }) {
37834
- const active = state.search.trim() !== "" || state.facets.length > 0;
38030
+ function DataTableFilterBar({ state, facets, labels, onSearch, onToggleFacet, onClear, facetLabel, groups = [], onToggleGroupFacet }) {
38031
+ const active = isDataTableFilterActive(state);
37835
38032
  const showFacets = facets.length > 1;
37836
38033
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
37837
38034
  className: "flex flex-wrap items-center gap-2",
@@ -37869,6 +38066,32 @@ function DataTableFilterBar({ state, facets, labels, onSearch, onToggleFacet, on
37869
38066
  }, facet.value);
37870
38067
  })
37871
38068
  }),
38069
+ groups.filter((group) => group.facets.length > 1).map((group) => /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
38070
+ role: "group",
38071
+ "aria-label": group.label,
38072
+ className: "flex flex-wrap items-center gap-1",
38073
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
38074
+ "aria-hidden": true,
38075
+ className: "text-[10px] uppercase tracking-wide text-foreground-subtle",
38076
+ children: group.label
38077
+ }), group.facets.map((facet) => {
38078
+ const pressed = group.selected.includes(facet.value);
38079
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
38080
+ type: "button",
38081
+ onClick: () => onToggleGroupFacet?.(group.id, facet.value),
38082
+ "aria-pressed": pressed,
38083
+ className: pressed ? CHIP_ON : CHIP_OFF,
38084
+ children: [
38085
+ group.facetLabel ? group.facetLabel(facet.value) : facet.value,
38086
+ " ",
38087
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
38088
+ className: "text-foreground-subtle tabular-nums",
38089
+ children: facet.count
38090
+ })
38091
+ ]
38092
+ }, facet.value);
38093
+ })]
38094
+ }, group.id)),
37872
38095
  active && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("button", {
37873
38096
  type: "button",
37874
38097
  onClick: onClear,
@@ -37900,22 +38123,37 @@ function useDataTableFilter(rows, config) {
37900
38123
  const toggleFacet = (0, react$1.useCallback)((value) => {
37901
38124
  setState((prev) => toggleDataTableFacet(prev, value));
37902
38125
  }, []);
38126
+ const toggleGroupFacet = (0, react$1.useCallback)((groupId, value) => {
38127
+ setState((prev) => toggleDataTableGroupFacet(prev, groupId, value));
38128
+ }, []);
37903
38129
  const clear = (0, react$1.useCallback)(() => setState(EMPTY_DATA_TABLE_FILTER), []);
37904
- const { searchText, facetValue } = config;
38130
+ const { searchText, facetValue, facetGroups } = config;
38131
+ const facets = (0, react$1.useMemo)(() => dataTableFacets(rows, facetValue), [rows, facetValue]);
37905
38132
  return {
37906
38133
  state,
37907
38134
  setSearch,
37908
38135
  toggleFacet,
38136
+ toggleGroupFacet,
38137
+ groups: (0, react$1.useMemo)(() => dataTableFacetGroups(rows, facetGroups).map((group) => ({
38138
+ ...group,
38139
+ selected: state.groups?.[group.id] ?? []
38140
+ })), [
38141
+ rows,
38142
+ facetGroups,
38143
+ state.groups
38144
+ ]),
37909
38145
  clear,
37910
- facets: (0, react$1.useMemo)(() => dataTableFacets(rows, facetValue), [rows, facetValue]),
38146
+ facets,
37911
38147
  rows: (0, react$1.useMemo)(() => filterDataTableRows(rows, state, {
37912
38148
  searchText,
37913
- facetValue
38149
+ facetValue,
38150
+ facetGroups
37914
38151
  }), [
37915
38152
  rows,
37916
38153
  state,
37917
38154
  searchText,
37918
- facetValue
38155
+ facetValue,
38156
+ facetGroups
37919
38157
  ]),
37920
38158
  active: isDataTableFilterActive(state)
37921
38159
  };
@@ -61843,6 +62081,7 @@ exports.CoverInlineControl = CoverInlineControl;
61843
62081
  exports.CoverPanel = CoverPanel;
61844
62082
  exports.CustomFieldRenderersProvider = CustomFieldRenderersProvider;
61845
62083
  exports.DEFAULT_COLOR = DEFAULT_COLOR;
62084
+ exports.DEFAULT_PAGINATION_LABELS = DEFAULT_PAGINATION_LABELS;
61846
62085
  exports.DEVICE_COLUMNS = DEVICE_COLUMNS;
61847
62086
  exports.DEVICE_EXPORT_PAGE_SIZE_KEY = DEVICE_EXPORT_PAGE_SIZE_KEY;
61848
62087
  exports.DEVICE_LIST_PAGE_SIZE_KEY = DEVICE_LIST_PAGE_SIZE_KEY;
@@ -61854,6 +62093,7 @@ exports.DEVICE_TYPE_META = DEVICE_TYPE_META;
61854
62093
  exports.DISPLAY_ICON_REGISTRY = DISPLAY_ICON_REGISTRY;
61855
62094
  exports.DataTable = DataTable;
61856
62095
  exports.DataTableFilterBar = DataTableFilterBar;
62096
+ exports.DataTablePager = DataTablePager;
61857
62097
  exports.DetectionCanvas = DetectionCanvas;
61858
62098
  exports.DetectionOverlay = DetectionOverlay;
61859
62099
  exports.DetectionResultTree = DetectionResultTree;
@@ -62154,6 +62394,7 @@ exports.createSharedContext = createSharedContext;
62154
62394
  exports.createTheme = require_theme_index.createTheme$1;
62155
62395
  exports.cursorFractionFor = cursorFractionFor;
62156
62396
  exports.darkColors = require_theme_index.darkColors$1;
62397
+ exports.dataTableFacetGroups = dataTableFacetGroups;
62157
62398
  exports.dataTableFacets = dataTableFacets;
62158
62399
  exports.defaultOfField = defaultOfField;
62159
62400
  exports.defaultTheme = require_theme_index.defaultTheme$1;
@@ -62237,6 +62478,7 @@ exports.orphanDeviceLabel = orphanDeviceLabel;
62237
62478
  exports.overrideEntityIdFromLink = overrideEntityIdFromLink;
62238
62479
  exports.pageRows = pageRows;
62239
62480
  exports.pageSizeLabel = pageSizeLabel;
62481
+ exports.paginateRows = paginateRows;
62240
62482
  exports.parentDetailOf = parentDetailOf;
62241
62483
  exports.parseIceCandidate = parseIceCandidate;
62242
62484
  exports.parsePickerGroupBy = parsePickerGroupBy;
@@ -62309,6 +62551,7 @@ exports.tankAlert = tankAlert;
62309
62551
  exports.themeToCss = require_theme_index.themeToCss$1;
62310
62552
  exports.toStationaryOverlayBox = toStationaryOverlayBox;
62311
62553
  exports.toggleDataTableFacet = toggleDataTableFacet;
62554
+ exports.toggleDataTableGroupFacet = toggleDataTableGroupFacet;
62312
62555
  exports.togglePickerDevice = togglePickerDevice;
62313
62556
  exports.togglePickerKey = togglePickerKey;
62314
62557
  exports.trainingRefusalText = trainingRefusalText;