@ai-matrx/design-system 0.36.0 → 0.38.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 (47) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/dist/content-transfer.cjs +81 -17
  3. package/dist/content-transfer.cjs.map +1 -1
  4. package/dist/content-transfer.js +81 -17
  5. package/dist/content-transfer.js.map +1 -1
  6. package/dist/data-table/copy-helpers.d.cts +1 -1
  7. package/dist/data-table/copy-helpers.d.ts +1 -1
  8. package/dist/data-table/data-row-inspector.cjs +81 -17
  9. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  10. package/dist/data-table/data-row-inspector.js +83 -19
  11. package/dist/data-table/data-row-inspector.js.map +1 -1
  12. package/dist/data-table/data-row-window.cjs +81 -17
  13. package/dist/data-table/data-row-window.cjs.map +1 -1
  14. package/dist/data-table/data-row-window.js +83 -19
  15. package/dist/data-table/data-row-window.js.map +1 -1
  16. package/dist/data-table/filter-engine.d.cts +1 -1
  17. package/dist/data-table/filter-engine.d.ts +1 -1
  18. package/dist/data-table/host.d.cts +1 -1
  19. package/dist/data-table/host.d.ts +1 -1
  20. package/dist/data-table/index.cjs +127 -25
  21. package/dist/data-table/index.cjs.map +1 -1
  22. package/dist/data-table/index.d.cts +2 -2
  23. package/dist/data-table/index.d.ts +2 -2
  24. package/dist/data-table/index.js +223 -121
  25. package/dist/data-table/index.js.map +1 -1
  26. package/dist/data-table/infer-filter.d.cts +1 -1
  27. package/dist/data-table/infer-filter.d.ts +1 -1
  28. package/dist/data-table/layered-filters.d.cts +1 -1
  29. package/dist/data-table/layered-filters.d.ts +1 -1
  30. package/dist/data-table/query-control.d.cts +1 -1
  31. package/dist/data-table/query-control.d.ts +1 -1
  32. package/dist/data-table/types.cjs.map +1 -1
  33. package/dist/data-table/types.d.cts +1 -1
  34. package/dist/data-table/types.d.ts +1 -1
  35. package/dist/data-table/url-state.d.cts +1 -1
  36. package/dist/data-table/url-state.d.ts +1 -1
  37. package/dist/data-table/xlsx.d.cts +1 -1
  38. package/dist/data-table/xlsx.d.ts +1 -1
  39. package/dist/index.cjs +81 -17
  40. package/dist/index.cjs.map +1 -1
  41. package/dist/index.d.cts +21 -0
  42. package/dist/index.d.ts +21 -0
  43. package/dist/index.js +91 -27
  44. package/dist/index.js.map +1 -1
  45. package/dist/{types-Cxm5XK0L.d.ts → types-B8vwElPz.d.ts} +25 -1
  46. package/dist/{types-kiV-CAuZ.d.cts → types-BuMHbFjs.d.cts} +25 -1
  47. package/package.json +7 -7
@@ -9,8 +9,8 @@ import {
9
9
  useEffect as useEffect16,
10
10
  useId as useId2,
11
11
  useLayoutEffect as useLayoutEffect2,
12
- useMemo as useMemo8,
13
- useRef as useRef15,
12
+ useMemo as useMemo9,
13
+ useRef as useRef16,
14
14
  useState as useState22
15
15
  } from "react";
16
16
  import {
@@ -1490,7 +1490,8 @@ var Dialog = ({
1490
1490
  children,
1491
1491
  ...props
1492
1492
  }) => {
1493
- const modal = props.modal ?? true;
1493
+ const isMobile = useIsMobile();
1494
+ const modal = props.modal ?? isMobile;
1494
1495
  return /* @__PURE__ */ jsx15(RadixDialogModalProvider, { modal, children: /* @__PURE__ */ jsx15(DialogPrimitive.Root, { ...props, modal, children }) });
1495
1496
  };
1496
1497
  Dialog.displayName = "Dialog";
@@ -1536,6 +1537,11 @@ DialogContentPrimitive.displayName = "DialogContentPrimitive";
1536
1537
  var DIALOG_DESKTOP_CLASSES = "matrx-dialog-card fixed inset-0 z-[10000] m-auto grid h-fit min-w-0 w-full max-w-lg gap-4 max-h-[85dvh] overflow-y-auto overscroll-contain [--dialog-pad:1.5rem] overflow-x-clip border bg-background p-6 shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full sm:rounded-lg";
1537
1538
  var DIALOG_MOBILE_SHEET_CLASSES = "matrx-mobile-sheet matrx-dialog-card fixed inset-x-0 bottom-0 left-0 right-0 top-auto z-[10000] flex min-w-0 flex-col w-full max-w-full max-h-[90dvh] gap-4 [--dialog-pad:1rem] overflow-x-clip border-t bg-background p-4 pb-safe shadow-lg [overflow-wrap:anywhere] [&>*]:min-w-0 [&>*]:max-w-full rounded-t-2xl rounded-b-none overflow-y-auto overscroll-contain";
1538
1539
  var DIALOG_MOBILE_SHEET_OVERRIDE = "inset-x-0 bottom-0 left-0 right-0 top-auto translate-none w-full max-w-full max-h-[90dvh] rounded-b-none rounded-t-2xl overflow-y-auto";
1540
+ var DialogWindowHandleContext = React10.createContext(null);
1541
+ var WINDOW_KEEP_VISIBLE = 80;
1542
+ function isInteractiveTarget(target) {
1543
+ return target instanceof Element && Boolean(target.closest("button, a, input, textarea, select, [role='button'], [contenteditable='true']"));
1544
+ }
1539
1545
  var DialogContent = React10.forwardRef(
1540
1546
  ({
1541
1547
  className,
@@ -1544,15 +1550,50 @@ var DialogContent = React10.forwardRef(
1544
1550
  animated = true,
1545
1551
  showCloseButton = true,
1546
1552
  container,
1553
+ dismissOnOutsideClick = false,
1554
+ onInteractOutside,
1555
+ onEscapeKeyDown,
1556
+ style,
1547
1557
  ...props
1548
1558
  }, ref) => {
1549
1559
  const isMobile = useIsMobile();
1550
1560
  const isModal = useRadixDialogModal();
1551
1561
  const injectedContainer = usePortalContainer(container);
1552
1562
  const asSheet = mobileSheet && isMobile;
1563
+ const windowed = !isModal && !asSheet;
1553
1564
  const [containerEl, setContainerEl] = React10.useState(
1554
1565
  null
1555
1566
  );
1567
+ const [offset, setOffset] = React10.useState({ x: 0, y: 0 });
1568
+ const dragRef = React10.useRef(null);
1569
+ const handle = React10.useMemo(() => {
1570
+ if (!windowed) return null;
1571
+ const clamp = (value, limit) => Math.max(-limit, Math.min(limit, value));
1572
+ return {
1573
+ onPointerDown: (event) => {
1574
+ if (event.button !== 0 || isInteractiveTarget(event.target)) return;
1575
+ dragRef.current = { x: event.clientX, y: event.clientY, baseX: offset.x, baseY: offset.y };
1576
+ event.currentTarget.setPointerCapture?.(event.pointerId);
1577
+ },
1578
+ onPointerMove: (event) => {
1579
+ const start = dragRef.current;
1580
+ if (!start) return;
1581
+ setOffset({
1582
+ x: clamp(start.baseX + event.clientX - start.x, window.innerWidth / 2 - WINDOW_KEEP_VISIBLE / 2),
1583
+ y: clamp(start.baseY + event.clientY - start.y, window.innerHeight / 2 - WINDOW_KEEP_VISIBLE / 2)
1584
+ });
1585
+ },
1586
+ onPointerUp: (event) => {
1587
+ if (!dragRef.current) return;
1588
+ dragRef.current = null;
1589
+ event.currentTarget.releasePointerCapture?.(event.pointerId);
1590
+ },
1591
+ onPointerCancel: () => {
1592
+ dragRef.current = null;
1593
+ },
1594
+ onDoubleClick: () => setOffset({ x: 0, y: 0 })
1595
+ };
1596
+ }, [windowed, offset.x, offset.y]);
1556
1597
  const mergedRef = React10.useCallback(
1557
1598
  (node) => {
1558
1599
  setContainerEl(node);
@@ -1580,19 +1621,33 @@ var DialogContent = React10.forwardRef(
1580
1621
  // can sit beside a host's floating window manager (which starts at
1581
1622
  // z=1000); staying below that boundary makes a newly focused window
1582
1623
  // usable without coupling the two systems.
1583
- !isModal && "z-[900]"
1624
+ !isModal && "z-[900]",
1625
+ // Without an overlay the card needs its own separation from the page.
1626
+ windowed && "shadow-2xl ring-1 ring-border/60"
1584
1627
  ),
1628
+ style: windowed && (offset.x !== 0 || offset.y !== 0) ? { ...style, translate: `${offset.x}px ${offset.y}px` } : style,
1629
+ onInteractOutside: (event) => {
1630
+ onInteractOutside?.(event);
1631
+ if (windowed && !dismissOnOutsideClick) event.preventDefault();
1632
+ },
1633
+ onEscapeKeyDown: (event) => {
1634
+ onEscapeKeyDown?.(event);
1635
+ const pressedIn = event.target instanceof Node && event.target !== document.body ? event.target : document.activeElement;
1636
+ if (windowed && containerEl && !(pressedIn && containerEl.contains(pressedIn))) {
1637
+ event.preventDefault();
1638
+ }
1639
+ },
1585
1640
  ...hasDescription ? {} : { "aria-describedby": void 0 },
1586
1641
  ...props,
1587
1642
  children: [
1588
1643
  hasTitle ? null : /* @__PURE__ */ jsx15(VisuallyHidden.Root, { children: /* @__PURE__ */ jsx15(DialogPrimitive.Title, { children: "Dialog" }) }),
1589
- /* @__PURE__ */ jsx15(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ jsx15(
1644
+ /* @__PURE__ */ jsx15(DialogContainerContext.Provider, { value: containerEl, children: /* @__PURE__ */ jsx15(DialogWindowHandleContext.Provider, { value: handle, children: /* @__PURE__ */ jsx15(
1590
1645
  PortalContainerProvider,
1591
1646
  {
1592
1647
  container: containerEl ?? injectedContainer ?? null,
1593
1648
  children
1594
1649
  }
1595
- ) }),
1650
+ ) }) }),
1596
1651
  showCloseButton ? /* @__PURE__ */ jsxs9(
1597
1652
  DialogPrimitive.Close,
1598
1653
  {
@@ -1615,19 +1670,28 @@ DialogContent.displayName = DialogPrimitive.Content.displayName;
1615
1670
  var DialogHeader = ({
1616
1671
  className,
1617
1672
  ...props
1618
- }) => /* @__PURE__ */ jsx15(
1619
- "div",
1620
- {
1621
- "data-slot": "dialog-header",
1622
- className: cn(
1623
- // DialogContent owns an absolute close control. Reserve its hit area in
1624
- // every header so trailing actions never render underneath it.
1625
- "flex flex-col space-y-1.5 pr-12 text-center sm:text-left",
1626
- className
1627
- ),
1628
- ...props
1629
- }
1630
- );
1673
+ }) => {
1674
+ const handle = React10.useContext(DialogWindowHandleContext);
1675
+ return /* @__PURE__ */ jsx15(
1676
+ "div",
1677
+ {
1678
+ "data-slot": "dialog-header",
1679
+ ...handle ? {
1680
+ ...handle,
1681
+ "data-window-handle": "",
1682
+ title: "Drag to move \xB7 double-click to recenter"
1683
+ } : {},
1684
+ className: cn(
1685
+ // DialogContent owns an absolute close control. Reserve its hit area in
1686
+ // every header so trailing actions never render underneath it.
1687
+ "flex flex-col space-y-1.5 pr-12 text-center sm:text-left",
1688
+ handle && "cursor-grab select-none active:cursor-grabbing",
1689
+ className
1690
+ ),
1691
+ ...props
1692
+ }
1693
+ );
1694
+ };
1631
1695
  DialogHeader.displayName = "DialogHeader";
1632
1696
  var DialogFooter = ({
1633
1697
  className,
@@ -5614,7 +5678,7 @@ function useClippedContentGuard(ref, options) {
5614
5678
  }
5615
5679
 
5616
5680
  // src/data-table/url-state.ts
5617
- import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo4, useRef as useRef8, useState as useState12 } from "react";
5681
+ import { useCallback as useCallback4, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef9, useState as useState12 } from "react";
5618
5682
  import {
5619
5683
  commitUrlParams,
5620
5684
  useUrlSearchParams
@@ -5694,7 +5758,7 @@ function useTableUrlState(options) {
5694
5758
  [defaultPageSize, defaultSortDirection, defaultSortId, key]
5695
5759
  );
5696
5760
  const state = readState(searchParams);
5697
- const lastTextWriteAt = useRef8(0);
5761
+ const lastTextWriteAt = useRef9(0);
5698
5762
  const [debouncedSearch, setDebouncedSearch] = useState12(state.search);
5699
5763
  useEffect7(() => {
5700
5764
  if (state.search === debouncedSearch) return;
@@ -5789,7 +5853,7 @@ function useTableUrlState(options) {
5789
5853
  writeState(next);
5790
5854
  setDebouncedSearch("");
5791
5855
  }, [defaultPageSize, defaultSortDirection, defaultSortId, writeState]);
5792
- const queryState = useMemo4(
5856
+ const queryState = useMemo5(
5793
5857
  () => state.search === debouncedSearch ? state : { ...state, search: debouncedSearch, page: 1 },
5794
5858
  [state, debouncedSearch]
5795
5859
  );
@@ -5804,10 +5868,10 @@ import {
5804
5868
  } from "@ai-matrx/kit/url-state";
5805
5869
 
5806
5870
  // src/data-table/RowAlchemyLauncher.tsx
5807
- import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef9, useState as useState13 } from "react";
5871
+ import { useCallback as useCallback5, useEffect as useEffect8, useRef as useRef10, useState as useState13 } from "react";
5808
5872
  import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
5809
5873
  function MatrxTableRowAlchemyProvider({ copy, placement, controls, children }) {
5810
- const controller = useRef9(null);
5874
+ const controller = useRef10(null);
5811
5875
  const { CopyControls } = useMatrxDataTableHost();
5812
5876
  const [active, setActive] = useState13(false);
5813
5877
  const [fallback, setFallback] = useState13(false);
@@ -5849,8 +5913,8 @@ function MatrxTableRowAlchemyProvider({ copy, placement, controls, children }) {
5849
5913
  import {
5850
5914
  forwardRef as forwardRef12,
5851
5915
  useEffect as useEffect9,
5852
- useMemo as useMemo5,
5853
- useRef as useRef10,
5916
+ useMemo as useMemo6,
5917
+ useRef as useRef11,
5854
5918
  useState as useState14
5855
5919
  } from "react";
5856
5920
  import { useDraggable } from "@dnd-kit/core";
@@ -6192,7 +6256,7 @@ function ColumnHeaderCell({
6192
6256
  setPendingNegation(filterValue?.negated ?? false);
6193
6257
  }
6194
6258
  }, [filterOpen, filterValue]);
6195
- const notifyOpen = useRef10(onFilterOpen);
6259
+ const notifyOpen = useRef11(onFilterOpen);
6196
6260
  notifyOpen.current = onFilterOpen;
6197
6261
  useEffect9(() => {
6198
6262
  if (filterOpen) notifyOpen.current?.();
@@ -6679,7 +6743,7 @@ function FacetChecklist({
6679
6743
  const [query, setQuery] = useState14("");
6680
6744
  const selected = value?.kind === "select" ? value.values ?? (value.value && value.value !== "__all__" ? [value.value] : []) : [];
6681
6745
  const selectedSet = new Set(selected);
6682
- const rows = useMemo5(() => {
6746
+ const rows = useMemo6(() => {
6683
6747
  if (!facets) return [];
6684
6748
  const listed = facets.values.map((entry) => ({
6685
6749
  value: entry.value,
@@ -6849,7 +6913,7 @@ function SearchableSelectFilter({
6849
6913
  allowCustom = false
6850
6914
  }) {
6851
6915
  const [query, setQuery] = useState14("");
6852
- const filtered = useMemo5(() => {
6916
+ const filtered = useMemo6(() => {
6853
6917
  const q = query.trim().toLowerCase();
6854
6918
  if (!q) return options;
6855
6919
  return options.filter(
@@ -7035,7 +7099,7 @@ function parseOptionalNumber(raw) {
7035
7099
  import {
7036
7100
  useCallback as useCallback6,
7037
7101
  useEffect as useEffect10,
7038
- useRef as useRef11,
7102
+ useRef as useRef12,
7039
7103
  useState as useState15
7040
7104
  } from "react";
7041
7105
 
@@ -7079,11 +7143,11 @@ function ColumnResizeHandle({
7079
7143
  onResizeCancel,
7080
7144
  onResizeCommit
7081
7145
  }) {
7082
- const handleRef = useRef11(null);
7083
- const activeResizeRef = useRef11(null);
7084
- const previewRafRef = useRef11(null);
7085
- const queuedWidthRef = useRef11(null);
7086
- const keyboardWidthRef = useRef11(null);
7146
+ const handleRef = useRef12(null);
7147
+ const activeResizeRef = useRef12(null);
7148
+ const previewRafRef = useRef12(null);
7149
+ const queuedWidthRef = useRef12(null);
7150
+ const keyboardWidthRef = useRef12(null);
7087
7151
  const [announcedWidth, setAnnouncedWidth] = useState15(null);
7088
7152
  const bounds = resolveColumnResizeBounds(minWidth, maxWidth);
7089
7153
  const cssVar = columnResizeCssVar(columnId2);
@@ -7672,7 +7736,7 @@ function scrollOffsetForIndex(input) {
7672
7736
  }
7673
7737
 
7674
7738
  // src/data-table/useSpreadsheetGrid.ts
7675
- import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo6, useRef as useRef12, useState as useState16 } from "react";
7739
+ import { useCallback as useCallback7, useEffect as useEffect11, useMemo as useMemo7, useRef as useRef13, useState as useState16 } from "react";
7676
7740
 
7677
7741
  // src/data-table/grid-selection.ts
7678
7742
  function rangeBounds(range, rowIds, fieldNames) {
@@ -8383,11 +8447,11 @@ function useSpreadsheetGrid(options) {
8383
8447
  const [range, setRange] = useState16(null);
8384
8448
  const [fillTarget, setFillTarget] = useState16(null);
8385
8449
  const [stack, setStack] = useState16(() => createUndoStack(options?.undoDepth ?? 100));
8386
- const draggingRef = useRef12(null);
8387
- const optionsRef = useRef12(options);
8450
+ const draggingRef = useRef13(null);
8451
+ const optionsRef = useRef13(options);
8388
8452
  optionsRef.current = options;
8389
8453
  const rowIds = options?.rowIds ?? [];
8390
- const columnIds = useMemo6(
8454
+ const columnIds = useMemo7(
8391
8455
  () => options ? options.columnIds.filter((id) => id !== "") : [],
8392
8456
  [options]
8393
8457
  );
@@ -8398,16 +8462,16 @@ function useSpreadsheetGrid(options) {
8398
8462
  const alive = rowSet.has(range.anchor.rowId) && rowSet.has(range.focus.rowId) && colSet.has(range.anchor.fieldName) && colSet.has(range.focus.fieldName);
8399
8463
  if (!alive) setRange(null);
8400
8464
  }, [range, rowIds, columnIds]);
8401
- const bounds = useMemo6(
8465
+ const bounds = useMemo7(
8402
8466
  () => range ? rangeBounds(range, rowIds, columnIds) : null,
8403
8467
  [range, rowIds, columnIds]
8404
8468
  );
8405
- const rowIndexById = useMemo6(() => {
8469
+ const rowIndexById = useMemo7(() => {
8406
8470
  const map = /* @__PURE__ */ new Map();
8407
8471
  for (let i = 0; i < rowIds.length; i += 1) map.set(rowIds[i], i);
8408
8472
  return map;
8409
8473
  }, [rowIds]);
8410
- const columnIndexById = useMemo6(() => {
8474
+ const columnIndexById = useMemo7(() => {
8411
8475
  const map = /* @__PURE__ */ new Map();
8412
8476
  for (let i = 0; i < columnIds.length; i += 1) map.set(columnIds[i], i);
8413
8477
  return map;
@@ -8791,9 +8855,9 @@ function useSpreadsheetGrid(options) {
8791
8855
  },
8792
8856
  []
8793
8857
  );
8794
- const fillTargetRef = useRef12(null);
8858
+ const fillTargetRef = useRef13(null);
8795
8859
  fillTargetRef.current = fillTarget;
8796
- const boundsRef = useRef12(null);
8860
+ const boundsRef = useRef13(null);
8797
8861
  boundsRef.current = bounds;
8798
8862
  useEffect11(() => {
8799
8863
  if (!options) return;
@@ -8988,7 +9052,7 @@ function rankTableSearchRows(rows, columns, query, options = {}, extraText) {
8988
9052
  }
8989
9053
 
8990
9054
  // src/data-table/ColumnManager.tsx
8991
- import { useEffect as useEffect12, useMemo as useMemo7, useState as useState17 } from "react";
9055
+ import { useEffect as useEffect12, useMemo as useMemo8, useState as useState17 } from "react";
8992
9056
  import { useDndMonitor, useDraggable as useDraggable2, useDroppable } from "@dnd-kit/core";
8993
9057
  import { jsx as jsx33, jsxs as jsxs23 } from "react/jsx-runtime";
8994
9058
  function ColumnManager({
@@ -8999,7 +9063,7 @@ function ColumnManager({
8999
9063
  hidden,
9000
9064
  onApply
9001
9065
  }) {
9002
- const byId = useMemo7(
9066
+ const byId = useMemo8(
9003
9067
  () => new Map(columns.map((column) => [columnId(column), column])),
9004
9068
  [columns]
9005
9069
  );
@@ -9541,7 +9605,7 @@ function parseTableViewSnapshot(raw) {
9541
9605
  // src/data-table/MatrxUuidCell.tsx
9542
9606
  import {
9543
9607
  useEffect as useEffect13,
9544
- useRef as useRef13,
9608
+ useRef as useRef14,
9545
9609
  useState as useState18
9546
9610
  } from "react";
9547
9611
  import { jsx as jsx34, jsxs as jsxs24 } from "react/jsx-runtime";
@@ -9586,7 +9650,7 @@ function MatrxUuidCell({
9586
9650
  const [copied, setCopied] = useState18(false);
9587
9651
  const [opening, setOpening] = useState18(false);
9588
9652
  const [peekOpen, setPeekOpen] = useState18(false);
9589
- const timer = useRef13(null);
9653
+ const timer = useRef14(null);
9590
9654
  useEffect13(
9591
9655
  () => () => {
9592
9656
  if (timer.current) clearTimeout(timer.current);
@@ -10820,7 +10884,7 @@ function DirtySavePill({
10820
10884
  }
10821
10885
 
10822
10886
  // src/data-table/EditableTableCell.tsx
10823
- import { useEffect as useEffect15, useRef as useRef14, useState as useState20 } from "react";
10887
+ import { useEffect as useEffect15, useRef as useRef15, useState as useState20 } from "react";
10824
10888
  import { jsx as jsx39, jsxs as jsxs29 } from "react/jsx-runtime";
10825
10889
  function CellRefusal({ reason }) {
10826
10890
  return /* @__PURE__ */ jsx39(
@@ -10994,8 +11058,8 @@ function InlineStringEditor({
10994
11058
  const [editing, setEditing] = useState20(false);
10995
11059
  const [draft, setDraft] = useState20(value);
10996
11060
  const [refusal, setRefusal] = useState20(null);
10997
- const handledEditRequest = useRef14(void 0);
10998
- const seedRef = useRef14(editSeed);
11061
+ const handledEditRequest = useRef15(void 0);
11062
+ const seedRef = useRef15(editSeed);
10999
11063
  seedRef.current = editSeed;
11000
11064
  useEffect15(() => {
11001
11065
  if (editRequest === void 0 || handledEditRequest.current === editRequest) return;
@@ -12079,6 +12143,7 @@ function MatrxDataTableCore({
12079
12143
  toolbar,
12080
12144
  hideToolbar = false,
12081
12145
  hidePagination = false,
12146
+ paginationLabelFormat,
12082
12147
  filterUi,
12083
12148
  detail,
12084
12149
  expandedDetail,
@@ -12123,7 +12188,7 @@ function MatrxDataTableCore({
12123
12188
  }) {
12124
12189
  const appendQuery = query?.mode === "controlled-append" ? query : null;
12125
12190
  const appendQueryKey = appendQuery?.pagination.queryKey ?? null;
12126
- const committedAppendQueryKey = useRef15(appendQueryKey);
12191
+ const committedAppendQueryKey = useRef16(appendQueryKey);
12127
12192
  const appendSourceChanged = appendQuery !== null && committedAppendQueryKey.current !== appendQueryKey;
12128
12193
  const data = (appendQuery ? appendQuery.pagination.rows : suppliedData) ?? [];
12129
12194
  const isLoading = appendQuery ? appendQuery.pagination.loading : suppliedLoading;
@@ -12138,7 +12203,7 @@ function MatrxDataTableCore({
12138
12203
  const [savedViewError, setSavedViewError] = useState22(null);
12139
12204
  const [toolbarActionError, setToolbarActionError] = useState22(null);
12140
12205
  const [toolbarActionPending, setToolbarActionPending] = useState22({ refresh: false, add: false });
12141
- const toolbarActionPendingRef = useRef15({ refresh: false, add: false });
12206
+ const toolbarActionPendingRef = useRef16({ refresh: false, add: false });
12142
12207
  const CHECKBOX_TAP_AREA = "h-4 w-4 touch-manipulation";
12143
12208
  const mobileCardsClass = mobileCardsBreakpoint === "lg" ? "lg:hidden" : "sm:hidden";
12144
12209
  const tableWithCardsClass = mobileCardsBreakpoint === "lg" ? "max-lg:hidden" : "max-sm:hidden";
@@ -12276,9 +12341,9 @@ function MatrxDataTableCore({
12276
12341
  const [windowRowSnapshot, setWindowRowSnapshot] = useState22(null);
12277
12342
  const editScopeKey = appendQueryKey === null ? "\0local" : `append:${appendQueryKey}`;
12278
12343
  const [editsByScope, setEditsByScope] = useState22({});
12279
- const editRevisionRef = useRef15({});
12344
+ const editRevisionRef = useRef16({});
12280
12345
  const [savingByScope, setSavingByScope] = useState22({});
12281
- const savingScopesRef = useRef15(/* @__PURE__ */ new Set());
12346
+ const savingScopesRef = useRef16(/* @__PURE__ */ new Set());
12282
12347
  const [editRequest, setEditRequest] = useState22(null);
12283
12348
  const [confirmForeignDraftDiscard, setConfirmForeignDraftDiscard] = useState22(false);
12284
12349
  const edits = editsByScope[editScopeKey]?.values ?? {};
@@ -12365,13 +12430,13 @@ function MatrxDataTableCore({
12365
12430
  onWindowRowIdChange,
12366
12431
  selectionConfig
12367
12432
  ]);
12368
- const scrollRef = useRef15(null);
12369
- const tableRef = useRef15(null);
12370
- const tableHeaderRef = useRef15(null);
12371
- const cardsScrollRef = useRef15(null);
12433
+ const scrollRef = useRef16(null);
12434
+ const tableRef = useRef16(null);
12435
+ const tableHeaderRef = useRef16(null);
12436
+ const cardsScrollRef = useRef16(null);
12372
12437
  const [documentStickyHeader, setDocumentStickyHeader] = useState22(false);
12373
- const documentStickyHeaderRef = useRef15(false);
12374
- const previousAppendKeyForScrollReset = useRef15(appendQueryKey);
12438
+ const documentStickyHeaderRef = useRef16(false);
12439
+ const previousAppendKeyForScrollReset = useRef16(appendQueryKey);
12375
12440
  useLayoutEffect2(() => {
12376
12441
  const previous = previousAppendKeyForScrollReset.current;
12377
12442
  previousAppendKeyForScrollReset.current = appendQueryKey;
@@ -12397,7 +12462,7 @@ function MatrxDataTableCore({
12397
12462
  ...appendScrollPolicy?.mode === "scroll" && appendScrollPolicy.thresholdPx !== void 0 ? { thresholdPx: appendScrollPolicy.thresholdPx } : {},
12398
12463
  ...appendScrollPolicy?.mode === "scroll" && appendScrollPolicy.intentTimeoutMs !== void 0 ? { intentTimeoutMs: appendScrollPolicy.intentTimeoutMs } : {}
12399
12464
  });
12400
- const rootRef = useRef15(null);
12465
+ const rootRef = useRef16(null);
12401
12466
  useClippedContentGuard(rootRef, {
12402
12467
  label: typeof copy === "object" && copy.listLabel ? `Table: ${copy.listLabel}` : "MatrxDataTable"
12403
12468
  });
@@ -12499,11 +12564,11 @@ function MatrxDataTableCore({
12499
12564
  () => normalizeColumnWidthsForColumns(columnState?.widths, columns)
12500
12565
  );
12501
12566
  const [fixedTableGeometry, setFixedTableGeometry] = useState22(null);
12502
- const knownColumnIds = useRef15(new Set(columns.map(columnId)));
12503
- const draggedColumnId = useRef15(null);
12504
- const columnDragActive = useRef15(false);
12505
- const columnDragRaf = useRef15(null);
12506
- const columnDragScrollDirection = useRef15(0);
12567
+ const knownColumnIds = useRef16(new Set(columns.map(columnId)));
12568
+ const draggedColumnId = useRef16(null);
12569
+ const columnDragActive = useRef16(false);
12570
+ const columnDragRaf = useRef16(null);
12571
+ const columnDragScrollDirection = useRef16(0);
12507
12572
  const [columnDragPreview, setColumnDragPreview] = useState22(null);
12508
12573
  const stopColumnDragScroll = useCallback8(() => {
12509
12574
  if (columnDragRaf.current !== null) cancelAnimationFrame(columnDragRaf.current);
@@ -12551,14 +12616,14 @@ function MatrxDataTableCore({
12551
12616
  const [internalColumnManagerOpen, setInternalColumnManagerOpen] = useState22(false);
12552
12617
  const columnManagerOpen = controlledColumnManager?.open ?? internalColumnManagerOpen;
12553
12618
  const setColumnManagerOpen = controlledColumnManager?.onOpenChange ?? setInternalColumnManagerOpen;
12554
- const columnIds = useMemo8(() => columns.map(columnId), [columns]);
12555
- const effectiveColumnOrder = useMemo8(() => columnState ? [...columnState.order.filter((id, index, values) => columnIds.includes(id) && values.indexOf(id) === index), ...columnIds.filter((id) => !columnState.order.includes(id))] : columnOrder, [columnIds, columnOrder, columnState]);
12556
- const effectiveHiddenColumnIds = useMemo8(() => columnState ? new Set(columnState.hidden.filter((id) => columnIds.includes(id))) : hiddenColumnIds, [columnIds, columnState, hiddenColumnIds]);
12557
- const effectiveColumnWidths = useMemo8(
12619
+ const columnIds = useMemo9(() => columns.map(columnId), [columns]);
12620
+ const effectiveColumnOrder = useMemo9(() => columnState ? [...columnState.order.filter((id, index, values) => columnIds.includes(id) && values.indexOf(id) === index), ...columnIds.filter((id) => !columnState.order.includes(id))] : columnOrder, [columnIds, columnOrder, columnState]);
12621
+ const effectiveHiddenColumnIds = useMemo9(() => columnState ? new Set(columnState.hidden.filter((id) => columnIds.includes(id))) : hiddenColumnIds, [columnIds, columnState, hiddenColumnIds]);
12622
+ const effectiveColumnWidths = useMemo9(
12558
12623
  () => normalizeColumnWidthsForColumns(columnState?.widths ?? columnWidths, columns),
12559
12624
  [columns, columnState?.widths, columnWidths]
12560
12625
  );
12561
- const resizeGestureSnapshotRef = useRef15(null);
12626
+ const resizeGestureSnapshotRef = useRef16(null);
12562
12627
  const measureVisibleColumnWidths = useCallback8(() => {
12563
12628
  const measured = {};
12564
12629
  const headers = tableRef.current ? Array.from(tableRef.current.querySelectorAll(
@@ -12660,12 +12725,12 @@ function MatrxDataTableCore({
12660
12725
  tableRef.current?.style.removeProperty(columnResizeCssVar(id));
12661
12726
  }
12662
12727
  });
12663
- const previewColumnOrder = useMemo8(
12728
+ const previewColumnOrder = useMemo9(
12664
12729
  () => projectColumnDragOrder(effectiveColumnOrder, columnDragPreview),
12665
12730
  [columnDragPreview, effectiveColumnOrder]
12666
12731
  );
12667
12732
  useColumnReorderAnimation(tableRef, previewColumnOrder.join("\0"), columnDragPreview !== null);
12668
- const visibleColumns = useMemo8(() => {
12733
+ const visibleColumns = useMemo9(() => {
12669
12734
  const byId = new Map(columns.map((column) => [columnId(column), column]));
12670
12735
  return previewColumnOrder.map((id) => byId.get(id)).filter(
12671
12736
  (column) => column !== void 0 && !effectiveHiddenColumnIds.has(columnId(column))
@@ -12701,7 +12766,7 @@ function MatrxDataTableCore({
12701
12766
  setFixedTableGeometry(geometry);
12702
12767
  }, [resolvedDensity, measureFixedTableGeometry, usesMeasuredFixedLayout]);
12703
12768
  const fixedLayoutActive = usesMeasuredFixedLayout && fixedTableGeometry !== null;
12704
- const frozenColumns = useMemo8(() => {
12769
+ const frozenColumns = useMemo9(() => {
12705
12770
  if (!visibleColumns.some((column) => column.frozen)) return NO_FROZEN_COLUMNS;
12706
12771
  const ids = visibleColumns.map(columnId);
12707
12772
  const byId = new Map(visibleColumns.map((column) => [columnId(column), column]));
@@ -12749,7 +12814,7 @@ function MatrxDataTableCore({
12749
12814
  const color = cellTintColor(row, id, colId);
12750
12815
  return color ? CELL_TINT_CLASS[color] : void 0;
12751
12816
  };
12752
- const declaredVisibleCopyColumns = useMemo8(
12817
+ const declaredVisibleCopyColumns = useMemo9(
12753
12818
  () => visibleColumns.filter((column) => column.accessorFn !== void 0 || column.accessorKey !== void 0),
12754
12819
  [visibleColumns]
12755
12820
  );
@@ -12757,7 +12822,7 @@ function MatrxDataTableCore({
12757
12822
  const tableContextMenuInstanceId = useId2();
12758
12823
  const tableDndContextId = useId2();
12759
12824
  const defaultCopyTitle = toolbar?.title || "Table";
12760
- const defaultCopy = useMemo8(() => ({
12825
+ const defaultCopy = useMemo9(() => ({
12761
12826
  label: defaultCopyTitle,
12762
12827
  listLabel: defaultCopyTitle,
12763
12828
  location: defaultCopyTitle,
@@ -12792,7 +12857,7 @@ function MatrxDataTableCore({
12792
12857
  serializer: (shaped) => buildViewAgentInput(effectiveCopy, shaped, data, { scope: "custom" })
12793
12858
  }))
12794
12859
  ] : [];
12795
- const filterMeta = useMemo8(() => {
12860
+ const filterMeta = useMemo9(() => {
12796
12861
  const meta = /* @__PURE__ */ new Map();
12797
12862
  for (const col of visibleColumns) {
12798
12863
  const id = columnId(col);
@@ -12800,14 +12865,14 @@ function MatrxDataTableCore({
12800
12865
  }
12801
12866
  return meta;
12802
12867
  }, [visibleColumns, data, remoteQuery]);
12803
- const intelligentSearchScopes = useMemo8(
12868
+ const intelligentSearchScopes = useMemo9(
12804
12869
  () => resolveTableSearchScopes(data, columns, {
12805
12870
  ...toolbar?.intelligentSearch?.roles === void 0 ? {} : { roles: toolbar.intelligentSearch.roles },
12806
12871
  ...toolbar?.intelligentSearch?.scopes === void 0 ? {} : { scopes: toolbar.intelligentSearch.scopes }
12807
12872
  }),
12808
12873
  [columns, data, toolbar?.intelligentSearch?.roles, toolbar?.intelligentSearch?.scopes]
12809
12874
  );
12810
- const processed = useMemo8(() => {
12875
+ const processed = useMemo9(() => {
12811
12876
  if (remoteQuery && !appendUsesLocalProcessing) return data;
12812
12877
  if (processLocalRows) {
12813
12878
  return processLocalRows(data, {
@@ -12870,7 +12935,7 @@ function MatrxDataTableCore({
12870
12935
  intelligentSearchEnabled,
12871
12936
  searchScope
12872
12937
  ]);
12873
- const lastNotifiedViewRows = useRef15(null);
12938
+ const lastNotifiedViewRows = useRef16(null);
12874
12939
  useEffect16(() => {
12875
12940
  if (!onViewChange) {
12876
12941
  lastNotifiedViewRows.current = null;
@@ -12924,7 +12989,7 @@ function MatrxDataTableCore({
12924
12989
  numberedPageHasMore: !hidePagination && !isLoading && !isFetching && processed.length > 0 && safePage < pageCount && (remoteQuery?.mode === "controlled" || !remoteQuery && localPagination?.mode === "numbered"),
12925
12990
  onPageAdvance: setPage
12926
12991
  });
12927
- const paginated = useMemo8(() => {
12992
+ const paginated = useMemo9(() => {
12928
12993
  if (remoteQuery) return processed;
12929
12994
  if (hidePagination) return processed;
12930
12995
  if (localProgressiveEnabled) return [...progressiveRows.rows];
@@ -12942,7 +13007,7 @@ function MatrxDataTableCore({
12942
13007
  },
12943
13008
  [grouping]
12944
13009
  );
12945
- const groups = useMemo8(() => {
13010
+ const groups = useMemo9(() => {
12946
13011
  if (!grouping || !groupingColumnId) return null;
12947
13012
  const groupColumn = columns.find((col) => columnId(col) === groupingColumnId);
12948
13013
  if (!groupColumn) return null;
@@ -12961,7 +13026,7 @@ function MatrxDataTableCore({
12961
13026
  ...grouping.emptyLabel ? { emptyLabel: grouping.emptyLabel } : {}
12962
13027
  });
12963
13028
  }, [grouping, groupingColumnId, columns, paginated]);
12964
- const groupableColumns = useMemo8(() => {
13029
+ const groupableColumns = useMemo9(() => {
12965
13030
  const allowed = grouping?.groupableColumnIds;
12966
13031
  return visibleColumns.filter((col) => {
12967
13032
  const id = columnId(col);
@@ -12969,7 +13034,7 @@ function MatrxDataTableCore({
12969
13034
  return col.accessorKey !== void 0 || col.accessorFn !== void 0;
12970
13035
  });
12971
13036
  }, [visibleColumns, grouping?.groupableColumnIds]);
12972
- const groupedRenderRows = useMemo8(
13037
+ const groupedRenderRows = useMemo9(
12973
13038
  () => groups ? flattenGroups(groups, collapsedGroups) : null,
12974
13039
  [groups, collapsedGroups]
12975
13040
  );
@@ -12979,7 +13044,7 @@ function MatrxDataTableCore({
12979
13044
  const bodyEntryCount = groupedRenderRows ? groupedRenderRows.length : paginated.length;
12980
13045
  const virtualizeActive = virtualizeConfig !== null && virtualizeConfig.enabled !== false && bodyEntryCount > virtualThreshold && !hierarchy && expandedDetail === void 0;
12981
13046
  const columnWindowWidth = virtualizeConfig?.columnWidth ?? 160;
12982
- const frozenRunLength = useMemo8(() => {
13047
+ const frozenRunLength = useMemo9(() => {
12983
13048
  let run = 0;
12984
13049
  for (const col of visibleColumns) {
12985
13050
  if (frozenColumns.offsets[columnId(col)] === void 0) break;
@@ -12990,7 +13055,7 @@ function MatrxDataTableCore({
12990
13055
  const columnVirtualizeActive = virtualizeConfig !== null && virtualizeConfig.enabled !== false && virtualizeConfig.columns === true && visibleColumns.length - frozenRunLength > 30 && !hierarchy && mobileCards === void 0;
12991
13056
  const [rowWindow, setRowWindow] = useState22(null);
12992
13057
  const [columnWindow, setColumnWindow] = useState22(null);
12993
- const windowInputs = useRef15({
13058
+ const windowInputs = useRef16({
12994
13059
  virtualizeActive: false,
12995
13060
  bodyEntryCount: 0,
12996
13061
  virtualRowHeight: 40,
@@ -13031,7 +13096,7 @@ function MatrxDataTableCore({
13031
13096
  setRowWindow((prev) => sameWindow(prev, nextRow) ? prev : nextRow);
13032
13097
  setColumnWindow((prev) => sameWindow(prev, nextColumn) ? prev : nextColumn);
13033
13098
  }, []);
13034
- const effectiveRowWindow = useMemo8(() => {
13099
+ const effectiveRowWindow = useMemo9(() => {
13035
13100
  if (!virtualizeActive) return null;
13036
13101
  if (rowWindow && rowWindow.end <= bodyEntryCount) return rowWindow;
13037
13102
  return computeWindow({
@@ -13042,7 +13107,7 @@ function MatrxDataTableCore({
13042
13107
  overscan: virtualizeConfig?.overscan ?? 8
13043
13108
  });
13044
13109
  }, [virtualizeActive, rowWindow, bodyEntryCount, virtualRowHeight, virtualizeConfig?.overscan]);
13045
- const effectiveColumnWindow = useMemo8(() => {
13110
+ const effectiveColumnWindow = useMemo9(() => {
13046
13111
  if (!columnVirtualizeActive) return null;
13047
13112
  if (columnWindow && columnWindow.end <= visibleColumns.length) return columnWindow;
13048
13113
  return computeWindow({
@@ -13095,7 +13160,7 @@ function MatrxDataTableCore({
13095
13160
  observer?.disconnect();
13096
13161
  };
13097
13162
  }, [metricsWanted, recomputeWindows]);
13098
- const renderedColumns = useMemo8(
13163
+ const renderedColumns = useMemo9(
13099
13164
  () => effectiveColumnWindow ? [
13100
13165
  ...visibleColumns.slice(0, frozenRunLength),
13101
13166
  ...visibleColumns.slice(effectiveColumnWindow.start, effectiveColumnWindow.end)
@@ -13112,10 +13177,10 @@ function MatrxDataTableCore({
13112
13177
  },
13113
13178
  [effectiveColumnWindow, effectiveColumnWidths, frozenColumns, columnWindowWidth]
13114
13179
  );
13115
- const coverageResult = useMemo8(() => {
13180
+ const coverageResult = useMemo9(() => {
13116
13181
  if (!coverage) return null;
13117
13182
  return describeCoverage({
13118
- loaded: data.length,
13183
+ loaded: coverage.loaded ?? data.length,
13119
13184
  ...coverage.matched === void 0 ? {} : { matched: coverage.matched },
13120
13185
  ...coverage.total === void 0 ? {} : { total: coverage.total },
13121
13186
  ...coverage.cap === void 0 ? {} : { cap: coverage.cap },
@@ -13123,7 +13188,7 @@ function MatrxDataTableCore({
13123
13188
  ...coverage.noun === void 0 ? {} : { noun: coverage.noun }
13124
13189
  });
13125
13190
  }, [coverage, data.length]);
13126
- const bodyEntries = useMemo8(() => {
13191
+ const bodyEntries = useMemo9(() => {
13127
13192
  const from = effectiveRowWindow ? effectiveRowWindow.start : 0;
13128
13193
  const to = effectiveRowWindow ? effectiveRowWindow.end : void 0;
13129
13194
  const windowed = groupedRenderRows ? groupedRenderRows.slice(from, to).map(
@@ -13140,22 +13205,22 @@ function MatrxDataTableCore({
13140
13205
  windowed.push({ kind: "spacer", height: effectiveRowWindow.padEnd, place: "end" });
13141
13206
  return windowed;
13142
13207
  }, [groupedRenderRows, collapsedGroups, paginated, effectiveRowWindow]);
13143
- const getRowIdRef = useRef15(getRowId);
13208
+ const getRowIdRef = useRef16(getRowId);
13144
13209
  getRowIdRef.current = getRowId;
13145
- const spreadsheetRowIds = useMemo8(
13210
+ const spreadsheetRowIds = useMemo9(
13146
13211
  () => paginated.map((row) => getRowIdRef.current(row)),
13147
13212
  [paginated]
13148
13213
  );
13149
- const spreadsheetColumnIds = useMemo8(
13214
+ const spreadsheetColumnIds = useMemo9(
13150
13215
  () => visibleColumns.map((col) => columnId(col)),
13151
13216
  [visibleColumns]
13152
13217
  );
13153
- const spreadsheetRowById = useMemo8(() => {
13218
+ const spreadsheetRowById = useMemo9(() => {
13154
13219
  const map = /* @__PURE__ */ new Map();
13155
13220
  for (const row of paginated) map.set(getRowIdRef.current(row), row);
13156
13221
  return map;
13157
13222
  }, [paginated]);
13158
- const spreadsheetColumnById = useMemo8(() => {
13223
+ const spreadsheetColumnById = useMemo9(() => {
13159
13224
  const map = /* @__PURE__ */ new Map();
13160
13225
  for (const col of visibleColumns) map.set(columnId(col), col);
13161
13226
  return map;
@@ -13188,9 +13253,9 @@ function MatrxDataTableCore({
13188
13253
  ...spreadsheet.onPastePlan ? { onPastePlan: spreadsheet.onPastePlan } : {}
13189
13254
  } : null
13190
13255
  );
13191
- const sheetRef = useRef15(sheet);
13256
+ const sheetRef = useRef16(sheet);
13192
13257
  sheetRef.current = sheet;
13193
- const searchValueRef = useRef15(searchValue);
13258
+ const searchValueRef = useRef16(searchValue);
13194
13259
  searchValueRef.current = searchValue;
13195
13260
  const facetsEnabled = Boolean(facets && facets.enabled !== false);
13196
13261
  const [facetState, setFacetState] = useState22({});
@@ -13202,9 +13267,9 @@ function MatrxDataTableCore({
13202
13267
  },
13203
13268
  [facets, visibleColumns]
13204
13269
  );
13205
- const facetInputsRef = useRef15({ data, facets, facetReadCell });
13270
+ const facetInputsRef = useRef16({ data, facets, facetReadCell });
13206
13271
  facetInputsRef.current = { data, facets, facetReadCell };
13207
- const facetRequestRef = useRef15(/* @__PURE__ */ new Map());
13272
+ const facetRequestRef = useRef16(/* @__PURE__ */ new Map());
13208
13273
  const requestFacets = useCallback8((colId) => {
13209
13274
  const { data: rows, facets: config, facetReadCell: readCell } = facetInputsRef.current;
13210
13275
  if (!config || config.enabled === false) return;
@@ -13273,11 +13338,11 @@ function MatrxDataTableCore({
13273
13338
  if (!controlledQuery || controlledQuery.state.page === safePage) return;
13274
13339
  emitControlledQueryChange({ page: safePage });
13275
13340
  }, [controlledQuery, emitControlledQueryChange, safePage]);
13276
- const selectedRow = useMemo8(() => {
13341
+ const selectedRow = useMemo9(() => {
13277
13342
  if (!selectedId) return null;
13278
13343
  return data.find((r) => getRowId(r) === selectedId) ?? null;
13279
13344
  }, [data, selectedId, getRowId]);
13280
- const windowRow = useMemo8(() => {
13345
+ const windowRow = useMemo9(() => {
13281
13346
  if (!windowRowId) return null;
13282
13347
  return data.find((r) => getRowId(r) === windowRowId) ?? (windowRowSnapshot && windowRowSnapshot.queryKey === appendQueryKey && getRowId(windowRowSnapshot.row) === windowRowId ? windowRowSnapshot.row : null);
13283
13348
  }, [data, windowRowId, windowRowSnapshot, getRowId, appendQueryKey]);
@@ -13312,7 +13377,7 @@ function MatrxDataTableCore({
13312
13377
  return def !== void 0 && f.value !== def;
13313
13378
  });
13314
13379
  const hasActiveFilters = activeFilterCount > 0 || Boolean(searchValue.trim()) || intelligentSearchEnabled && searchScope !== "all" || Boolean(anyOfValue.trim()) || completeLayeredFilterRules(layeredFilters).length > 0 || facetActive;
13315
- const changeCount = useMemo8(() => {
13380
+ const changeCount = useMemo9(() => {
13316
13381
  let n2 = 0;
13317
13382
  for (const fields of Object.values(edits)) {
13318
13383
  n2 += Object.keys(fields).length;
@@ -13491,7 +13556,7 @@ function MatrxDataTableCore({
13491
13556
  }));
13492
13557
  return true;
13493
13558
  };
13494
- const requestCellEditRef = useRef15(requestCellEdit);
13559
+ const requestCellEditRef = useRef16(requestCellEdit);
13495
13560
  requestCellEditRef.current = requestCellEdit;
13496
13561
  const buildRecordControls = (row) => {
13497
13562
  const rowId = getRowId(row);
@@ -13518,7 +13583,7 @@ function MatrxDataTableCore({
13518
13583
  };
13519
13584
  const hierarchyRows = hierarchy?.rows ?? data;
13520
13585
  const hierarchyGetParentId = hierarchy?.getParentId;
13521
- const hierarchyIndex = useMemo8(() => {
13586
+ const hierarchyIndex = useMemo9(() => {
13522
13587
  if (!hierarchyGetParentId) return null;
13523
13588
  const byId = /* @__PURE__ */ new Map();
13524
13589
  const parentById = /* @__PURE__ */ new Map();
@@ -13550,7 +13615,7 @@ function MatrxDataTableCore({
13550
13615
  return { byId, parentById, depthById };
13551
13616
  }, [hierarchyGetParentId, hierarchyRows, getRowId]);
13552
13617
  const draggedRow = draggedRowId && hierarchyIndex ? hierarchyIndex.byId.get(draggedRowId) : void 0;
13553
- const hierarchyBlockedIds = useMemo8(() => {
13618
+ const hierarchyBlockedIds = useMemo9(() => {
13554
13619
  if (!draggedRowId || !hierarchyIndex) return null;
13555
13620
  const childrenById = /* @__PURE__ */ new Map();
13556
13621
  for (const [id, parentId] of hierarchyIndex.parentById) {
@@ -13796,7 +13861,7 @@ function MatrxDataTableCore({
13796
13861
  }
13797
13862
  }
13798
13863
  };
13799
- const resolveMenuLevelRef = useRef15(resolveMenuLevel);
13864
+ const resolveMenuLevelRef = useRef16(resolveMenuLevel);
13800
13865
  resolveMenuLevelRef.current = resolveMenuLevel;
13801
13866
  useEffect16(() => {
13802
13867
  if (!host.rowContextRegistry) return;
@@ -13806,7 +13871,7 @@ function MatrxDataTableCore({
13806
13871
  );
13807
13872
  }, [host.rowContextRegistry, tableContextMenuInstanceId]);
13808
13873
  const showActionsCol = windowEnabled || Boolean(rowActions) || showInlineRowCopy;
13809
- const selectedIdSet = useMemo8(
13874
+ const selectedIdSet = useMemo9(
13810
13875
  () => new Set(selection?.selectedIds ?? []),
13811
13876
  [selection?.selectedIds]
13812
13877
  );
@@ -13818,11 +13883,11 @@ function MatrxDataTableCore({
13818
13883
  );
13819
13884
  const allOnPageSelected = selectableRows.length > 0 && selectedOnPage.length === selectableRows.length;
13820
13885
  const someOnPageSelected = selectedOnPage.length > 0 && !allOnPageSelected;
13821
- const selectedRows = useMemo8(
13886
+ const selectedRows = useMemo9(
13822
13887
  () => data.filter((row) => selectedIdSet.has(getRowId(row))),
13823
13888
  [data, selectedIdSet, getRowId]
13824
13889
  );
13825
- const lastToggledIndex = useRef15(null);
13890
+ const lastToggledIndex = useRef16(null);
13826
13891
  const setSelectedIds = (next) => selection?.onSelectedIdsChange([...next]);
13827
13892
  const toggleRowSelected = (index, shiftKey) => {
13828
13893
  if (!selection) return;
@@ -13904,7 +13969,7 @@ function MatrxDataTableCore({
13904
13969
  }
13905
13970
  return href ? /* @__PURE__ */ jsx42(Link, { href, onClick: (event) => event.stopPropagation(), className: "block w-full min-w-0 rounded outline-none focus-visible:ring-2 focus-visible:ring-ring", children: display }) : display;
13906
13971
  };
13907
- const currentViewSnapshot = useMemo8(
13972
+ const currentViewSnapshot = useMemo9(
13908
13973
  () => ({
13909
13974
  __kind: "matrx-table-view",
13910
13975
  version: 1,
@@ -13939,7 +14004,7 @@ function MatrxDataTableCore({
13939
14004
  sort
13940
14005
  ]
13941
14006
  );
13942
- const declaredDefaultViewSnapshot = useMemo8(
14007
+ const declaredDefaultViewSnapshot = useMemo9(
13943
14008
  () => defaultViewSnapshot ?? {
13944
14009
  __kind: "matrx-table-view",
13945
14010
  version: 1,
@@ -14118,11 +14183,12 @@ function MatrxDataTableCore({
14118
14183
  notice,
14119
14184
  savedViewError ? /* @__PURE__ */ jsx42("p", { role: "alert", className: "shrink-0 text-xs text-destructive", children: savedViewError }) : null,
14120
14185
  toolbarActionError ? /* @__PURE__ */ jsx42("p", { role: "alert", className: "shrink-0 text-xs text-destructive", children: toolbarActionError }) : null,
14121
- !hideToolbar && (viewTabs || toolbar?.title || showSearch || toolbar?.anyOf || toolbar?.layeredFilters || toolbar?.facets && toolbar.facets.length > 0 || toolbar?.leading || toolbar?.actions || toolbar?.refresh || toolbar?.add || tableId && SavedViews || hasActiveFilters || showToolbarCopy || columns.length > 0) && /* @__PURE__ */ jsxs32(
14186
+ !hideToolbar && (viewTabs || toolbar?.title || toolbar?.titleCount || showSearch || toolbar?.customSearch || toolbar?.anyOf || toolbar?.layeredFilters || toolbar?.facets && toolbar.facets.length > 0 || toolbar?.leading || toolbar?.actions || toolbar?.refresh || toolbar?.add || tableId && SavedViews || hasActiveFilters || showToolbarCopy || columns.length > 0) && /* @__PURE__ */ jsxs32(
14122
14187
  TableTitleRow,
14123
14188
  {
14124
14189
  tabs: viewTabs ? /* @__PURE__ */ jsx42(TableViewWorkspace, { snapshot: currentViewSnapshot, onApply: applySavedView, related: relatedTableActions }, tableId ?? "table") : void 0,
14125
14190
  ...toolbar?.title === void 0 ? {} : { title: toolbar.title },
14191
+ ...toolbar?.titleCount === void 0 ? {} : { count: toolbar.titleCount },
14126
14192
  context: tableId && SavedViews ? /* @__PURE__ */ jsx42("span", { "data-matrx-table-view-control": true, children: /* @__PURE__ */ jsx42(
14127
14193
  SavedViews,
14128
14194
  {
@@ -14132,7 +14198,7 @@ function MatrxDataTableCore({
14132
14198
  onApply: applySavedView
14133
14199
  }
14134
14200
  ) }) : void 0,
14135
- search: showSearch ? intelligentSearchEnabled ? /* @__PURE__ */ jsx42(
14201
+ search: toolbar?.customSearch ?? (showSearch ? intelligentSearchEnabled ? /* @__PURE__ */ jsx42(
14136
14202
  TableSearch,
14137
14203
  {
14138
14204
  value: searchValue,
@@ -14203,7 +14269,7 @@ function MatrxDataTableCore({
14203
14269
  ] }) : null
14204
14270
  ]
14205
14271
  }
14206
- ) : null,
14272
+ ) : null),
14207
14273
  children: [
14208
14274
  toolbar?.layeredFilters ? /* @__PURE__ */ jsx42(
14209
14275
  LayeredFilterBuilder,
@@ -14857,6 +14923,7 @@ function MatrxDataTableCore({
14857
14923
  leadingCols,
14858
14924
  showActionsCol,
14859
14925
  rowNoun: grouping?.rowNoun ?? "row",
14926
+ ...grouping?.renderLabel ? { renderLabel: grouping.renderLabel } : {},
14860
14927
  onToggle: () => setCollapsedGroups(toggleGroupCollapsed(collapsedGroups, entry.group.key))
14861
14928
  },
14862
14929
  `matrx-group-${entry.group.key}`
@@ -15030,7 +15097,7 @@ function MatrxDataTableCore({
15030
15097
  "div",
15031
15098
  {
15032
15099
  className: cn(
15033
- colIdx === 0 && hierarchy && "flex min-w-0 items-center"
15100
+ colIdx === 0 && (hierarchy || canExpandRow(row)) && "flex min-w-0 items-center"
15034
15101
  ),
15035
15102
  children: [
15036
15103
  colIdx === 0 && hierarchy ? /* @__PURE__ */ jsx42(
@@ -15041,6 +15108,40 @@ function MatrxDataTableCore({
15041
15108
  disabled: !(hierarchy.canReparent?.(row) ?? true)
15042
15109
  }
15043
15110
  ) : null,
15111
+ colIdx === 0 && canExpandRow(row) ? /* @__PURE__ */ jsxs32(Tooltip, { children: [
15112
+ /* @__PURE__ */ jsx42(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx42(
15113
+ Button,
15114
+ {
15115
+ type: "button",
15116
+ variant: "ghost",
15117
+ size: "icon",
15118
+ "data-matrx-table-expand-toggle": true,
15119
+ className: "mr-1 h-7 w-7 shrink-0 text-muted-foreground hover:text-foreground [&_svg]:size-4",
15120
+ "aria-label": isRowExpanded(row) ? "Collapse row details" : "Expand row details",
15121
+ "aria-expanded": isRowExpanded(row),
15122
+ onClick: (event) => {
15123
+ event.stopPropagation();
15124
+ toggleExpanded(row);
15125
+ },
15126
+ onKeyDown: (event) => {
15127
+ if (event.key !== "Enter" && event.key !== " ") return;
15128
+ event.preventDefault();
15129
+ event.stopPropagation();
15130
+ toggleExpanded(row);
15131
+ },
15132
+ children: /* @__PURE__ */ jsx42(
15133
+ ChevronRight,
15134
+ {
15135
+ className: cn(
15136
+ "transition-transform",
15137
+ isRowExpanded(row) && "rotate-90"
15138
+ )
15139
+ }
15140
+ )
15141
+ }
15142
+ ) }),
15143
+ /* @__PURE__ */ jsx42(TooltipContent, { children: isRowExpanded(row) ? "Collapse details" : "Expand details" })
15144
+ ] }) : null,
15044
15145
  /* @__PURE__ */ jsx42(
15045
15146
  "div",
15046
15147
  {
@@ -15383,7 +15484,7 @@ function MatrxDataTableCore({
15383
15484
  GenericTablePagination,
15384
15485
  {
15385
15486
  totalItems,
15386
- ...sourceTotal === void 0 ? {} : { labelFormat: (start, end, total) => `${formatCount3(start)}\u2013${formatCount3(end)} of ${formatCount3(total)} matching \xB7 ${formatCount3(data.length)} / ${formatCount3(sourceTotal)} loaded` },
15487
+ ...paginationLabelFormat ? { labelFormat: paginationLabelFormat } : sourceTotal === void 0 ? {} : { labelFormat: (start, end, total) => `${formatCount3(start)}\u2013${formatCount3(end)} of ${formatCount3(total)} matching \xB7 ${formatCount3(data.length)} / ${formatCount3(sourceTotal)} loaded` },
15387
15488
  ...localProgressiveEnabled ? { progressive: {
15388
15489
  shownCount: progressiveRows.shownCount,
15389
15490
  loadedCount: data.length,
@@ -15901,6 +16002,7 @@ function TableGroupHeaderRow({
15901
16002
  leadingCols,
15902
16003
  showActionsCol,
15903
16004
  rowNoun,
16005
+ renderLabel,
15904
16006
  onToggle
15905
16007
  }) {
15906
16008
  const count = group.rows.length;
@@ -15931,7 +16033,7 @@ function TableGroupHeaderRow({
15931
16033
  children: collapsed ? /* @__PURE__ */ jsx42(ChevronRight, { className: "h-4 w-4" }) : /* @__PURE__ */ jsx42(ChevronDown, { className: "h-4 w-4" })
15932
16034
  }
15933
16035
  ),
15934
- /* @__PURE__ */ jsx42("span", { className: "truncate text-sm font-semibold text-foreground", children: group.label }),
16036
+ renderLabel ? renderLabel(group) : /* @__PURE__ */ jsx42("span", { className: "truncate text-sm font-semibold text-foreground", children: group.label }),
15935
16037
  /* @__PURE__ */ jsx42("span", { className: "whitespace-nowrap text-xs text-muted-foreground", children: summary })
15936
16038
  ] }) }, id);
15937
16039
  }
@@ -16277,7 +16379,7 @@ function SavedViewsControl({
16277
16379
  ] })
16278
16380
  ] }),
16279
16381
  dirty ? /* @__PURE__ */ jsx44("span", { id: unsavedChangesId, className: "sr-only", children: "This table view has unsaved changes. Open the view menu to save or update it." }) : null,
16280
- visibleError ? /* @__PURE__ */ jsx44("p", { role: "alert", className: "basis-full break-words text-xs text-destructive", children: visibleError }) : null,
16382
+ visibleError && !saveOpen ? /* @__PURE__ */ jsx44("p", { role: "alert", className: "basis-full break-words text-xs text-destructive", children: visibleError }) : null,
16281
16383
  /* @__PURE__ */ jsx44(Dialog, { open: saveOpen, onOpenChange: setSaveOpen, children: /* @__PURE__ */ jsxs34(DialogContent, { children: [
16282
16384
  /* @__PURE__ */ jsx44(DialogHeader, { children: /* @__PURE__ */ jsx44(DialogTitle, { children: "Save current view" }) }),
16283
16385
  visibleError ? /* @__PURE__ */ jsx44("p", { role: "alert", className: "text-sm text-destructive", children: visibleError }) : null,