@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/composites/confirm-dialog.d.ts +6 -0
- package/dist/composites/data-table-filter-bar.d.ts +14 -1
- package/dist/composites/data-table-filter.d.ts +23 -0
- package/dist/composites/data-table-pager.d.ts +8 -0
- package/dist/composites/data-table-pagination.d.ts +31 -0
- package/dist/composites/data-table-selection.d.ts +15 -0
- package/dist/composites/data-table.d.ts +31 -2
- package/dist/composites/index.d.ts +9 -4
- package/dist/composites/use-data-table-filter.d.ts +9 -0
- package/dist/index.cjs +275 -32
- package/dist/index.js +271 -33
- package/dist/lib/tailwind-variants.d.ts +1 -1
- package/package.json +1 -1
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-
|
|
15038
|
-
warning: { button: "bg-
|
|
15039
|
-
default: { button: "bg-primary hover:bg-primary/90 text-
|
|
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-
|
|
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 [
|
|
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.
|
|
35463
|
-
className
|
|
35464
|
-
children:
|
|
35465
|
-
|
|
35466
|
-
rowIndex,
|
|
35467
|
-
|
|
35468
|
-
|
|
35469
|
-
|
|
35470
|
-
|
|
35471
|
-
|
|
35472
|
-
|
|
35473
|
-
|
|
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:
|
|
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: () =>
|
|
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:
|
|
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:
|
|
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
|
-
|
|
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
|
|
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
|
|
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;
|