@ai-matrx/design-system 0.17.3 → 0.17.4

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.17.4 — 2026-09-12
4
+
5
+ `MatrxDataTable` now renders next-page progress as a sticky 64px row inside
6
+ the desktop table and mobile-card scrollers. It remains visible at the current
7
+ scroll bottom without moving the user; the footer retains counts, errors, and
8
+ controls without duplicating the active spinner/status.
9
+
10
+ ### Consumer action
11
+
12
+ Update to 0.17.4 for in-body append progress. No query, pagination, or API
13
+ changes are required.
14
+
3
15
  ## 0.17.3 — 2026-09-12
4
16
 
5
17
  `MatrxDataTable` now keeps a fixed-height append status area at the bottom of
@@ -6511,6 +6511,7 @@ function MatrxDataTableCore({
6511
6511
  ref: cardsScrollRef,
6512
6512
  "data-matrx-table-cards-scroll": true,
6513
6513
  "aria-busy": isLoading || isFetching,
6514
+ ...appendQuery === null ? {} : { style: { containerType: "inline-size" } },
6514
6515
  className: cn(
6515
6516
  "flex h-full min-h-0 flex-col gap-2 overflow-y-auto rounded-md border border-border bg-card p-2",
6516
6517
  mobileCardsClass
@@ -6580,7 +6581,26 @@ function MatrxDataTableCore({
6580
6581
  }
6581
6582
  ) : null
6582
6583
  }) }, id);
6583
- })
6584
+ }),
6585
+ appendQuery !== null && isFetching && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6586
+ "div",
6587
+ {
6588
+ "data-matrx-table-append-loading-card": true,
6589
+ role: "status",
6590
+ "aria-live": "polite",
6591
+ className: "sticky bottom-0 z-20 flex h-16 w-full max-w-[100cqw] shrink-0 items-center justify-center gap-2 rounded-md border border-border bg-card/95 px-3 text-sm font-medium text-foreground shadow-sm backdrop-blur-sm",
6592
+ children: [
6593
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6594
+ Loader2,
6595
+ {
6596
+ "aria-hidden": "true",
6597
+ className: "h-5 w-5 shrink-0 animate-spin text-primary motion-reduce:animate-none"
6598
+ }
6599
+ ),
6600
+ "Loading more rows\u2026"
6601
+ ]
6602
+ }
6603
+ ) : null
6584
6604
  ]
6585
6605
  }
6586
6606
  ) : null,
@@ -6591,6 +6611,7 @@ function MatrxDataTableCore({
6591
6611
  "data-matrx-table-scroll": true,
6592
6612
  onScroll: updateScrollHint,
6593
6613
  "aria-busy": isLoading || isFetching,
6614
+ ...appendQuery === null ? {} : { style: { containerType: "inline-size" } },
6594
6615
  className: cn(
6595
6616
  "relative h-full w-full overflow-auto rounded-md border border-border bg-card",
6596
6617
  mobileCards && tableWithCardsClass,
@@ -6712,214 +6733,241 @@ function MatrxDataTableCore({
6712
6733
  }),
6713
6734
  showActionsCol && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("th", { className: "h-9 w-28 px-2 text-right align-middle text-xs font-semibold uppercase tracking-wide text-muted-foreground", children: "Actions" })
6714
6735
  ] }) }),
6715
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tbody", { children: isLoading ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("tr", { className: "border-b border-border/60", children: [
6716
- selection ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-2 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Skeleton, { className: "h-3.5 w-3.5" }) }) : null,
6717
- visibleColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6736
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("tbody", { children: [
6737
+ isLoading ? Array.from({ length: 6 }).map((_, i) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("tr", { className: "border-b border-border/60", children: [
6738
+ selection ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-2 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Skeleton, { className: "h-3.5 w-3.5" }) }) : null,
6739
+ visibleColumns.map((col) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6740
+ "td",
6741
+ {
6742
+ className: cn(
6743
+ "py-2",
6744
+ col.compact ? "px-1" : "px-2",
6745
+ col.mobileHidden && "max-sm:hidden"
6746
+ ),
6747
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Skeleton, { className: "h-5 w-full" })
6748
+ },
6749
+ columnId(col)
6750
+ )),
6751
+ showActionsCol && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-2 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Skeleton, { className: "ml-auto h-5 w-10" }) })
6752
+ ] }, `sk-${i}`)) : paginated.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6718
6753
  "td",
6719
6754
  {
6720
- className: cn(
6721
- "py-2",
6722
- col.compact ? "px-1" : "px-2",
6723
- col.mobileHidden && "max-sm:hidden"
6724
- ),
6725
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Skeleton, { className: "h-5 w-full" })
6726
- },
6727
- columnId(col)
6728
- )),
6729
- showActionsCol && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-2 py-2", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(Skeleton, { className: "ml-auto h-5 w-10" }) })
6730
- ] }, `sk-${i}`)) : paginated.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tr", { children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6731
- "td",
6732
- {
6733
- colSpan: visibleColumns.length + leadingCols + (showActionsCol ? 1 : 0),
6734
- className: "px-4 py-12 text-center",
6735
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "mx-auto flex max-w-sm flex-col items-center gap-2", children: [
6736
- emptyState?.icon,
6737
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-sm font-medium text-foreground", children: emptyState?.title ?? "No rows" }),
6738
- emptyState?.description ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyState.description }) : null,
6739
- emptyState?.action
6740
- ] })
6741
- }
6742
- ) }) : paginated.map((row, index) => {
6743
- const id = getRowId(row);
6744
- const isSelected = selectedId === id;
6745
- const rowEdits = edits[id];
6746
- const displayRow = applyRowEdits(row, rowEdits);
6747
- const isChecked = selectedIdSet.has(id);
6748
- const rowNode = /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6749
- "tr",
6750
- {
6751
- "data-row-id": id,
6752
- "data-state": isSelected ? "selected" : void 0,
6753
- onClick: (e) => {
6754
- if (e.target.closest("a")) return;
6755
- openRow(row);
6756
- },
6757
- className: cn(
6758
- // Keep the mobile row opaque while the complete row scrolls
6759
- // horizontally. The translucent zebra/hover tints remain
6760
- // desktop-only so densely layered mobile content stays crisp.
6761
- "border-b border-border/60 bg-card transition-colors",
6762
- (detailEnabled || Boolean(onRowOpen)) && "cursor-pointer sm:hover:bg-muted/50",
6763
- isSelected && "bg-muted",
6764
- isChecked && "bg-primary/5",
6765
- highlightedIndex === index && "bg-muted ring-1 ring-inset ring-primary/60",
6766
- rowClassName?.(row, index),
6767
- draggedRowId === id && "opacity-40",
6768
- zebra && index % 2 === 1 && !isSelected && !isChecked && "sm:bg-muted/20"
6769
- ),
6770
- children: [
6771
- selection ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6772
- "td",
6773
- {
6774
- className: "px-2 py-1.5 align-middle lg:py-0.5",
6775
- onClick: (e) => e.stopPropagation(),
6776
- children: selection.isRowSelectable?.(row) ?? true ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6777
- Checkbox,
6778
- {
6779
- className: CHECKBOX_TAP_AREA,
6780
- checked: isChecked,
6781
- "aria-label": `Select this ${selectionNoun}`,
6782
- onClick: (e) => toggleRowSelected(index, e.shiftKey)
6783
- }
6784
- ) : null
6785
- }
6786
- ) : null,
6787
- visibleColumns.map((col, colIdx) => {
6788
- const field = col.accessorKey ? String(col.accessorKey) : columnId(col);
6789
- const display = renderCell(displayRow, col, index);
6790
- const editable = Boolean(
6791
- editEnabled && col.editable && (col.editableIf?.(row) ?? true)
6792
- );
6793
- const dirty = Boolean(
6794
- rowEdits && field in rowEdits
6795
- );
6796
- const cellHref = col.href?.(row) ?? void 0;
6797
- return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6755
+ colSpan: visibleColumns.length + leadingCols + (showActionsCol ? 1 : 0),
6756
+ className: "px-4 py-12 text-center",
6757
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "mx-auto flex max-w-sm flex-col items-center gap-2", children: [
6758
+ emptyState?.icon,
6759
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-sm font-medium text-foreground", children: emptyState?.title ?? "No rows" }),
6760
+ emptyState?.description ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "text-xs text-muted-foreground", children: emptyState.description }) : null,
6761
+ emptyState?.action
6762
+ ] })
6763
+ }
6764
+ ) }) : paginated.map((row, index) => {
6765
+ const id = getRowId(row);
6766
+ const isSelected = selectedId === id;
6767
+ const rowEdits = edits[id];
6768
+ const displayRow = applyRowEdits(row, rowEdits);
6769
+ const isChecked = selectedIdSet.has(id);
6770
+ const rowNode = /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6771
+ "tr",
6772
+ {
6773
+ "data-row-id": id,
6774
+ "data-state": isSelected ? "selected" : void 0,
6775
+ onClick: (e) => {
6776
+ if (e.target.closest("a")) return;
6777
+ openRow(row);
6778
+ },
6779
+ className: cn(
6780
+ // Keep the mobile row opaque while the complete row scrolls
6781
+ // horizontally. The translucent zebra/hover tints remain
6782
+ // desktop-only so densely layered mobile content stays crisp.
6783
+ "border-b border-border/60 bg-card transition-colors",
6784
+ (detailEnabled || Boolean(onRowOpen)) && "cursor-pointer sm:hover:bg-muted/50",
6785
+ isSelected && "bg-muted",
6786
+ isChecked && "bg-primary/5",
6787
+ highlightedIndex === index && "bg-muted ring-1 ring-inset ring-primary/60",
6788
+ rowClassName?.(row, index),
6789
+ draggedRowId === id && "opacity-40",
6790
+ zebra && index % 2 === 1 && !isSelected && !isChecked && "sm:bg-muted/20"
6791
+ ),
6792
+ children: [
6793
+ selection ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6798
6794
  "td",
6799
6795
  {
6800
- className: cn(
6801
- "py-1.5 align-middle lg:py-0.5",
6802
- col.compact ? "px-1" : "px-2",
6803
- // nowrap (NOT truncate — truncate clips the cell and
6804
- // defeats w-max, killing the horizontal scroll).
6805
- "max-sm:whitespace-nowrap",
6806
- col.mobileHidden && "max-sm:hidden",
6807
- col.width !== void 0 && "sm:w-[var(--matrx-col-w)] sm:min-w-[var(--matrx-col-w)] sm:max-w-[var(--matrx-col-w)]",
6808
- col.className,
6809
- col.align === "center" && "text-center",
6810
- col.align === "right" && "text-right"
6811
- ),
6812
- style: columnWidthVar(col.width),
6813
- children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6814
- "div",
6796
+ className: "px-2 py-1.5 align-middle lg:py-0.5",
6797
+ onClick: (e) => e.stopPropagation(),
6798
+ children: selection.isRowSelectable?.(row) ?? true ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6799
+ Checkbox,
6815
6800
  {
6816
- className: cn(
6817
- colIdx === 0 && hierarchy && "flex min-w-0 items-center"
6818
- ),
6819
- children: [
6820
- colIdx === 0 && hierarchy ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6821
- HierarchyDragHandle,
6822
- {
6823
- id,
6824
- label: hierarchy.itemLabel?.(row) ?? "row",
6825
- disabled: !(hierarchy.canReparent?.(row) ?? true)
6826
- }
6827
- ) : null,
6828
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6829
- "div",
6830
- {
6831
- "data-matrx-cell-content": true,
6832
- className: "min-w-0 max-w-full flex-1 whitespace-normal break-words [overflow-wrap:anywhere] sm:[&_*]:min-w-0 sm:[&_*]:max-w-full sm:[&_*]:whitespace-normal sm:[&_*]:[overflow-wrap:anywhere] sm:[&_[data-matrx-cell-control]]:w-max sm:[&_[data-matrx-cell-control]]:min-w-max sm:[&_[data-matrx-cell-control]]:max-w-none sm:[&_[data-matrx-cell-control]]:whitespace-nowrap sm:[&_[data-matrx-cell-control]]:[overflow-wrap:normal] sm:[&_[data-matrx-cell-control]_*]:whitespace-nowrap sm:[&_[data-matrx-cell-control]_*]:[overflow-wrap:normal]",
6833
- children: editable && col.editable ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6834
- EditableTableCell,
6835
- {
6836
- value: rowEdits && field in rowEdits ? rowEdits[field] : getCellValue(row, col),
6837
- editType: col.editable,
6838
- ...col.editOptions === void 0 ? {} : { editOptions: col.editOptions },
6839
- display,
6840
- dirty,
6841
- onCommit: (next) => commitCell(id, field, next),
6842
- ...cellHref === void 0 ? {} : { href: cellHref },
6843
- ...col.editTrigger === void 0 ? {} : { editTrigger: col.editTrigger }
6844
- }
6845
- ) : cellHref ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6846
- Link,
6847
- {
6848
- href: cellHref,
6849
- onClick: (e) => e.stopPropagation(),
6850
- className: "block w-full min-w-0 rounded outline-none focus-visible:ring-2 focus-visible:ring-ring",
6851
- children: display
6852
- }
6853
- ) : display
6854
- }
6855
- )
6856
- ]
6857
- }
6858
- )
6859
- },
6860
- columnId(col)
6861
- );
6862
- }),
6863
- showActionsCol && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-2 py-1.5 text-right align-middle lg:py-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6864
- "div",
6865
- {
6866
- className: "inline-flex items-center justify-end gap-0.5",
6867
- onClick: (e) => e.stopPropagation(),
6868
- children: [
6869
- showRowCopy && copy ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6870
- TableRowCopyControl,
6871
- {
6872
- size: "xs",
6873
- copy,
6874
- row: displayRow
6875
- }
6876
- ) : null,
6877
- rowActions?.(displayRow, {
6878
- closeDetail: () => setSelectedId(null),
6879
- openDetail: () => openDetail(displayRow),
6880
- openWindow: () => openWindow(displayRow),
6881
- closeWindow,
6882
- hasPendingEdits: Boolean(rowEdits),
6883
- discardPendingEdits: () => discardRowEdits(id)
6884
- }),
6885
- windowEnabled ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6886
- Button,
6887
- {
6888
- type: "button",
6889
- variant: "ghost",
6890
- size: "icon",
6891
- className: "h-11 w-11 text-muted-foreground hover:text-foreground lg:h-5 lg:w-5 [&_svg]:size-3",
6892
- "aria-label": opensWindowOnRowClick ? "Open in side panel" : "Open in window",
6893
- title: opensWindowOnRowClick ? "Open in side panel" : "Open in window",
6894
- onClick: (e) => {
6895
- e.stopPropagation();
6896
- if (opensWindowOnRowClick) {
6897
- openDetail(row);
6898
- } else {
6899
- openWindow(row);
6900
- }
6901
- },
6902
- children: opensWindowOnRowClick ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(PanelRightOpen, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(PanelRight, { className: "h-3.5 w-3.5" })
6801
+ className: CHECKBOX_TAP_AREA,
6802
+ checked: isChecked,
6803
+ "aria-label": `Select this ${selectionNoun}`,
6804
+ onClick: (e) => toggleRowSelected(index, e.shiftKey)
6903
6805
  }
6904
6806
  ) : null
6905
- ]
6906
- }
6907
- ) })
6908
- ]
6909
- },
6910
- id
6911
- );
6912
- const wrappedRow = rowWrapper ? rowWrapper(row, rowNode) : rowNode;
6913
- return hierarchy ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6914
- HierarchyDroppableRow,
6807
+ }
6808
+ ) : null,
6809
+ visibleColumns.map((col, colIdx) => {
6810
+ const field = col.accessorKey ? String(col.accessorKey) : columnId(col);
6811
+ const display = renderCell(displayRow, col, index);
6812
+ const editable = Boolean(
6813
+ editEnabled && col.editable && (col.editableIf?.(row) ?? true)
6814
+ );
6815
+ const dirty = Boolean(
6816
+ rowEdits && field in rowEdits
6817
+ );
6818
+ const cellHref = col.href?.(row) ?? void 0;
6819
+ return /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6820
+ "td",
6821
+ {
6822
+ className: cn(
6823
+ "py-1.5 align-middle lg:py-0.5",
6824
+ col.compact ? "px-1" : "px-2",
6825
+ // nowrap (NOT truncate — truncate clips the cell and
6826
+ // defeats w-max, killing the horizontal scroll).
6827
+ "max-sm:whitespace-nowrap",
6828
+ col.mobileHidden && "max-sm:hidden",
6829
+ col.width !== void 0 && "sm:w-[var(--matrx-col-w)] sm:min-w-[var(--matrx-col-w)] sm:max-w-[var(--matrx-col-w)]",
6830
+ col.className,
6831
+ col.align === "center" && "text-center",
6832
+ col.align === "right" && "text-right"
6833
+ ),
6834
+ style: columnWidthVar(col.width),
6835
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6836
+ "div",
6837
+ {
6838
+ className: cn(
6839
+ colIdx === 0 && hierarchy && "flex min-w-0 items-center"
6840
+ ),
6841
+ children: [
6842
+ colIdx === 0 && hierarchy ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6843
+ HierarchyDragHandle,
6844
+ {
6845
+ id,
6846
+ label: hierarchy.itemLabel?.(row) ?? "row",
6847
+ disabled: !(hierarchy.canReparent?.(row) ?? true)
6848
+ }
6849
+ ) : null,
6850
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6851
+ "div",
6852
+ {
6853
+ "data-matrx-cell-content": true,
6854
+ className: "min-w-0 max-w-full flex-1 whitespace-normal break-words [overflow-wrap:anywhere] sm:[&_*]:min-w-0 sm:[&_*]:max-w-full sm:[&_*]:whitespace-normal sm:[&_*]:[overflow-wrap:anywhere] sm:[&_[data-matrx-cell-control]]:w-max sm:[&_[data-matrx-cell-control]]:min-w-max sm:[&_[data-matrx-cell-control]]:max-w-none sm:[&_[data-matrx-cell-control]]:whitespace-nowrap sm:[&_[data-matrx-cell-control]]:[overflow-wrap:normal] sm:[&_[data-matrx-cell-control]_*]:whitespace-nowrap sm:[&_[data-matrx-cell-control]_*]:[overflow-wrap:normal]",
6855
+ children: editable && col.editable ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6856
+ EditableTableCell,
6857
+ {
6858
+ value: rowEdits && field in rowEdits ? rowEdits[field] : getCellValue(row, col),
6859
+ editType: col.editable,
6860
+ ...col.editOptions === void 0 ? {} : { editOptions: col.editOptions },
6861
+ display,
6862
+ dirty,
6863
+ onCommit: (next) => commitCell(id, field, next),
6864
+ ...cellHref === void 0 ? {} : { href: cellHref },
6865
+ ...col.editTrigger === void 0 ? {} : { editTrigger: col.editTrigger }
6866
+ }
6867
+ ) : cellHref ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6868
+ Link,
6869
+ {
6870
+ href: cellHref,
6871
+ onClick: (e) => e.stopPropagation(),
6872
+ className: "block w-full min-w-0 rounded outline-none focus-visible:ring-2 focus-visible:ring-ring",
6873
+ children: display
6874
+ }
6875
+ ) : display
6876
+ }
6877
+ )
6878
+ ]
6879
+ }
6880
+ )
6881
+ },
6882
+ columnId(col)
6883
+ );
6884
+ }),
6885
+ showActionsCol && /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-2 py-1.5 text-right align-middle lg:py-0.5", children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6886
+ "div",
6887
+ {
6888
+ className: "inline-flex items-center justify-end gap-0.5",
6889
+ onClick: (e) => e.stopPropagation(),
6890
+ children: [
6891
+ showRowCopy && copy ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6892
+ TableRowCopyControl,
6893
+ {
6894
+ size: "xs",
6895
+ copy,
6896
+ row: displayRow
6897
+ }
6898
+ ) : null,
6899
+ rowActions?.(displayRow, {
6900
+ closeDetail: () => setSelectedId(null),
6901
+ openDetail: () => openDetail(displayRow),
6902
+ openWindow: () => openWindow(displayRow),
6903
+ closeWindow,
6904
+ hasPendingEdits: Boolean(rowEdits),
6905
+ discardPendingEdits: () => discardRowEdits(id)
6906
+ }),
6907
+ windowEnabled ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6908
+ Button,
6909
+ {
6910
+ type: "button",
6911
+ variant: "ghost",
6912
+ size: "icon",
6913
+ className: "h-11 w-11 text-muted-foreground hover:text-foreground lg:h-5 lg:w-5 [&_svg]:size-3",
6914
+ "aria-label": opensWindowOnRowClick ? "Open in side panel" : "Open in window",
6915
+ title: opensWindowOnRowClick ? "Open in side panel" : "Open in window",
6916
+ onClick: (e) => {
6917
+ e.stopPropagation();
6918
+ if (opensWindowOnRowClick) {
6919
+ openDetail(row);
6920
+ } else {
6921
+ openWindow(row);
6922
+ }
6923
+ },
6924
+ children: opensWindowOnRowClick ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(PanelRightOpen, { className: "h-3.5 w-3.5" }) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(PanelRight, { className: "h-3.5 w-3.5" })
6925
+ }
6926
+ ) : null
6927
+ ]
6928
+ }
6929
+ ) })
6930
+ ]
6931
+ },
6932
+ id
6933
+ );
6934
+ const wrappedRow = rowWrapper ? rowWrapper(row, rowNode) : rowNode;
6935
+ return hierarchy ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6936
+ HierarchyDroppableRow,
6937
+ {
6938
+ id,
6939
+ disabled: !canDropOn(row),
6940
+ children: wrappedRow
6941
+ },
6942
+ id
6943
+ ) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react14.Fragment, { children: wrappedRow }, id);
6944
+ }),
6945
+ appendQuery !== null && isFetching && !isLoading ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tr", { "data-matrx-table-append-loading-row": true, children: /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6946
+ "td",
6915
6947
  {
6916
- id,
6917
- disabled: !canDropOn(row),
6918
- children: wrappedRow
6919
- },
6920
- id
6921
- ) : /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(import_react14.Fragment, { children: wrappedRow }, id);
6922
- }) }),
6948
+ colSpan: visibleColumns.length + leadingCols + (showActionsCol ? 1 : 0),
6949
+ className: "sticky bottom-0 z-20 h-16 border-y border-border bg-card/95 px-0 py-0 text-left shadow-sm backdrop-blur-sm",
6950
+ children: /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6951
+ "div",
6952
+ {
6953
+ role: "status",
6954
+ "aria-live": "polite",
6955
+ className: "sticky left-0 flex h-16 w-fit max-w-[100cqw] items-center justify-center gap-2 px-3 text-sm font-medium text-foreground",
6956
+ children: [
6957
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6958
+ Loader2,
6959
+ {
6960
+ "aria-hidden": "true",
6961
+ className: "h-5 w-5 shrink-0 animate-spin text-primary motion-reduce:animate-none"
6962
+ }
6963
+ ),
6964
+ "Loading more rows\u2026"
6965
+ ]
6966
+ }
6967
+ )
6968
+ }
6969
+ ) }) : null
6970
+ ] }),
6923
6971
  footerRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("tfoot", { className: "border-t-2 border-border bg-muted/50 font-semibold", children: footerRows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("tr", { children: [
6924
6972
  selection ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("td", { className: "px-2 py-2" }) : null,
6925
6973
  visibleColumns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
@@ -6982,11 +7030,10 @@ function MatrxDataTableCore({
6982
7030
  /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)(
6983
7031
  "div",
6984
7032
  {
6985
- role: "status",
6986
- "aria-live": "polite",
7033
+ ...isFetching && !isLoading ? {} : { role: "status", "aria-live": "polite" },
6987
7034
  className: "flex min-w-0 flex-1 items-center gap-2 text-xs text-muted-foreground",
6988
7035
  children: [
6989
- isLoading || isFetching ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
7036
+ isLoading ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)(
6990
7037
  Loader2,
6991
7038
  {
6992
7039
  "data-matrx-table-append-loader": true,
@@ -6995,7 +7042,7 @@ function MatrxDataTableCore({
6995
7042
  }
6996
7043
  ) : null,
6997
7044
  /* @__PURE__ */ (0, import_jsx_runtime32.jsxs)("div", { className: "min-w-0", children: [
6998
- /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "break-words font-medium text-foreground", children: isFetching ? "Loading more rows\u2026" : isLoading ? "Loading rows\u2026" : `${data.length.toLocaleString()} loaded${appendQuery.pagination.totalItems === void 0 ? "" : ` of ${appendQuery.pagination.totalItems.toLocaleString()}`}` }),
7045
+ /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { className: "break-words font-medium text-foreground", children: isLoading ? "Loading rows\u2026" : `${data.length.toLocaleString()} loaded${appendQuery.pagination.totalItems === void 0 ? "" : ` of ${appendQuery.pagination.totalItems.toLocaleString()}`}` }),
6999
7046
  scrollPagination.error ? /* @__PURE__ */ (0, import_jsx_runtime32.jsx)("p", { role: "alert", className: "break-words text-destructive", children: scrollPagination.error.message }) : null
7000
7047
  ] })
7001
7048
  ]