@ai-matrx/design-system 0.48.16 → 0.49.3

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 (42) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +16 -0
  3. package/dist/data-table/copy-helpers.d.cts +1 -1
  4. package/dist/data-table/copy-helpers.d.ts +1 -1
  5. package/dist/data-table/filter-engine.d.cts +1 -1
  6. package/dist/data-table/filter-engine.d.ts +1 -1
  7. package/dist/data-table/host.d.cts +1 -1
  8. package/dist/data-table/host.d.ts +1 -1
  9. package/dist/data-table/index.cjs +215 -49
  10. package/dist/data-table/index.cjs.map +1 -1
  11. package/dist/data-table/index.d.cts +2 -2
  12. package/dist/data-table/index.d.ts +2 -2
  13. package/dist/data-table/index.js +215 -49
  14. package/dist/data-table/index.js.map +1 -1
  15. package/dist/data-table/infer-filter.d.cts +1 -1
  16. package/dist/data-table/infer-filter.d.ts +1 -1
  17. package/dist/data-table/layered-filters.d.cts +1 -1
  18. package/dist/data-table/layered-filters.d.ts +1 -1
  19. package/dist/data-table/pagination.cjs +23 -3
  20. package/dist/data-table/pagination.cjs.map +1 -1
  21. package/dist/data-table/pagination.d.cts +6 -1
  22. package/dist/data-table/pagination.d.ts +6 -1
  23. package/dist/data-table/pagination.js +23 -3
  24. package/dist/data-table/pagination.js.map +1 -1
  25. package/dist/data-table/query-control.d.cts +1 -1
  26. package/dist/data-table/query-control.d.ts +1 -1
  27. package/dist/data-table/types.cjs.map +1 -1
  28. package/dist/data-table/types.d.cts +1 -1
  29. package/dist/data-table/types.d.ts +1 -1
  30. package/dist/data-table/url-state.d.cts +1 -1
  31. package/dist/data-table/url-state.d.ts +1 -1
  32. package/dist/data-table/xlsx.d.cts +1 -1
  33. package/dist/data-table/xlsx.d.ts +1 -1
  34. package/dist/index.cjs +330 -325
  35. package/dist/index.cjs.map +1 -1
  36. package/dist/index.d.cts +11 -1
  37. package/dist/index.d.ts +11 -1
  38. package/dist/index.js +330 -325
  39. package/dist/index.js.map +1 -1
  40. package/dist/{types-bIcXnlYS.d.cts → types-ClxgLUFi.d.cts} +34 -1
  41. package/dist/{types-DVTNnzU5.d.ts → types-DlgTSJsC.d.ts} +34 -1
  42. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,8 +1,41 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.49.3
4
+ ### Unreleased
5
+ ### page-pass shared fix (2026-09-27): one dropdown chevron
6
+
7
+ - New export **`SelectChevron`** — THE trigger glyph for every dropdown (down chevron, 16px / 14px `sm`, muted). `SelectTrigger` and `CreatablePicker` draw it (the picker drew an up-down pair beside Selects' down chevron). Proof: `one-dropdown-chevron.test.tsx`, red on the previous picker.
8
+
9
+ ## 0.49.2
10
+
11
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
12
+ `git diff npm/design-system/v0.48.16..npm/design-system/v0.49.2 -- apps/shared/design-system`).
13
+ No source changes intended and no consumer action required.
14
+
15
+ ## 0.49.1
16
+
17
+ Automatic changed-only republish (docs/metadata drift since the last tag — see
18
+ `git diff npm/design-system/v0.48.16..npm/design-system/v0.49.1 -- apps/shared/design-system`).
19
+ No source changes intended and no consumer action required.
20
+
21
+ ## 0.49.0
22
+ <<<<<<< origin/main
23
+
24
+ - Added optional canonical table KPIs and aligned column totals through `summary`. Aggregates use filtered rows before pagination; source-provided totals carry their own declared scope. Loading, unavailable and retained stale results remain explicit. Existing `footerRows` behavior is preserved.
25
+ - Consumer action: pass metric callbacks and column-ID totals to `summary` where aggregates are useful. Desktop column resizing remains enabled by default.
26
+
27
+ ## 0.48.16
28
+ ### Unreleased
29
+ =======
30
+ >>>>>>> HEAD
31
+
32
+ - Added optional canonical table KPIs and aligned column totals through `summary`. Aggregates use filtered rows before pagination; source-provided totals carry their own declared scope. Loading, unavailable and retained stale results remain explicit. Existing `footerRows` behavior is preserved.
33
+ - Consumer action: pass metric callbacks and column-ID totals to `summary` where aggregates are useful. Desktop column resizing remains enabled by default.
34
+
3
35
  ## 0.48.16
4
36
  ### Unreleased
5
37
 
38
+ - **The pager never says "0 rows" over a failed read** (2026-09-27, seen live on `/administration/automation/scheduling/runs` with the runs read failing: body "Couldn't load runs", footer "0 rows"). When `read.status` is `"error"` and no rows are on screen, the footer shows "—" labelled "Row count unavailable"; while `read.status` is `"loading"` with no rows it shows no count. A failed refresh over kept rows still shows the real count (stale-while-error). A caller's `paginationLabelFormat` is not drawn in those states either. New optional pager prop `countUnavailable` (`GenericTablePagination`). Consumer action: none. Proof: `MatrxDataTable.read-outcome-pager.test.tsx`, 3 of 6 red on 0.48.15.
6
39
  - **The layout menu's promises, kept** (merged-grid review 2, fix lane E, 2026-09-27). (1) **Freeze holds with tick boxes:** the band waited forever for the selection column to be measured, which only happened after every column was resized; the selection column is now declared at `SELECTION_COLUMN_PX` (36) while a column is frozen, so the offset is known. On a phone the FIRST frozen column now stays too, capped at 40vw (`FROZEN_PHONE_*`); the rest of the band scrolls. (2) **Compact is compact:** a `rowHeight` below the density's own draws cells unpadded and row buttons at 24 px. (3) **`fitToWidth`** (new prop): every data column gets its proportional share of the measured container (`fit-columns.ts`), `table-layout: fixed`, never a sideways scroll (from `sm` up). (4) **`rowActionsHeader`** (new prop): controls drawn in the Actions header. Proof: `MatrxDataTable.layout-look.test.tsx`, 5 of 7 red on the previous table.
7
40
  - **A submenu opens beside its parent, not on top of it**: `DropdownMenuSubContent` and `ContextMenuSubContent` are portalled through the container seam — the parent's animation transform made it the containing block of the submenu's `position: fixed`. Proof: `menus.test.tsx`, red on the in-place submenu.
8
41
  - **The number filter box reads like its neighbours**: 12 px, not monospace 16 px (16 px only below `sm`, for iOS). Proof: `header-number-filter-and-clear-sort.test.tsx`.
package/README.md CHANGED
@@ -162,6 +162,22 @@ The gate validates declarations and exports against the packed tarball, installs
162
162
 
163
163
  ## Data tables
164
164
 
165
+ Desktop columns are adjustable by default. Optional `summary` supplies KPI
166
+ metrics above the toolbar and totals aligned to column IDs below the rows.
167
+ Callbacks receive the filtered rows before pagination, plus `isFiltered` and
168
+ `coverage` (`all`, `loaded`, or `page`). The table labels that scope and never
169
+ calls aggregates for an empty loading or failed read. Retained stale rows are
170
+ labelled; unavailable aggregates remain visible. Use `summary.source` only for
171
+ caller-provided complete source totals; missing source values are never replaced
172
+ with an aggregate of the loaded page.
173
+
174
+ ```tsx
175
+ summary={{
176
+ metrics: [{ id: "amount", label: "Amount", value: ({ rows }) => rows.reduce((n, row) => n + row.amount, 0) }],
177
+ totals: { amount: ({ rows }) => rows.reduce((n, row) => n + row.amount, 0) },
178
+ }}
179
+ ```
180
+
165
181
  ```tsx
166
182
  import { MatrxDataTable } from "@ai-matrx/design-system/data-table";
167
183
  import { usePaginatedData } from "@ai-matrx/data/react";
@@ -1,5 +1,5 @@
1
1
  import { AgentPayloadInput } from './copy-types.cjs';
2
- import { g as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-bIcXnlYS.cjs';
2
+ import { g as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-ClxgLUFi.cjs';
3
3
  import '../content-transfer.cjs';
4
4
  import 'react';
5
5
  import '@ai-matrx/kit/content-transfer';
@@ -1,5 +1,5 @@
1
1
  import { AgentPayloadInput } from './copy-types.js';
2
- import { g as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-DVTNnzU5.js';
2
+ import { g as MatrxDataTableCopyConfig, M as MatrxColumnDef } from '../types-DlgTSJsC.js';
3
3
  import '../content-transfer.js';
4
4
  import 'react';
5
5
  import '@ai-matrx/kit/content-transfer';
@@ -1,4 +1,4 @@
1
- import { M as MatrxColumnDef, C as ColumnFiltersState, S as SortState, L as LayeredFilterRule, T as TableSearchMatchMode, a as ColumnFilterValue } from '../types-bIcXnlYS.cjs';
1
+ import { M as MatrxColumnDef, C as ColumnFiltersState, S as SortState, L as LayeredFilterRule, T as TableSearchMatchMode, a as ColumnFilterValue } from '../types-ClxgLUFi.cjs';
2
2
  import '../content-transfer.cjs';
3
3
  import 'react';
4
4
  import '@ai-matrx/kit/content-transfer';
@@ -1,4 +1,4 @@
1
- import { M as MatrxColumnDef, C as ColumnFiltersState, S as SortState, L as LayeredFilterRule, T as TableSearchMatchMode, a as ColumnFilterValue } from '../types-DVTNnzU5.js';
1
+ import { M as MatrxColumnDef, C as ColumnFiltersState, S as SortState, L as LayeredFilterRule, T as TableSearchMatchMode, a as ColumnFilterValue } from '../types-DlgTSJsC.js';
2
2
  import '../content-transfer.js';
3
3
  import 'react';
4
4
  import '@ai-matrx/kit/content-transfer';
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import { ComponentType, ReactNode, MouseEventHandler } from 'react';
3
3
  import { CopyControlProps } from './copy-types.cjs';
4
4
  export { AgentPayloadInput, AiCustomSource, AiVariant, CopyExportConfig } from './copy-types.cjs';
5
- import { b as TableSavedViewsProps, c as MatrxDataTableDensity, d as MatrxDataTableRecordControls } from '../types-bIcXnlYS.cjs';
5
+ import { b as TableSavedViewsProps, c as MatrxDataTableDensity, d as MatrxDataTableRecordControls } from '../types-ClxgLUFi.cjs';
6
6
  import { MatrxTableMenuTarget, MatrxTableMenuPayload, MatrxTableMenuSectionsResolver, MatrxTableMenuIconName } from './menu-targets.cjs';
7
7
  export { MatrxTableMenuItem, MatrxTableMenuSection } from './menu-targets.cjs';
8
8
  import '../content-transfer.cjs';
@@ -2,7 +2,7 @@ import * as React from 'react';
2
2
  import { ComponentType, ReactNode, MouseEventHandler } from 'react';
3
3
  import { CopyControlProps } from './copy-types.js';
4
4
  export { AgentPayloadInput, AiCustomSource, AiVariant, CopyExportConfig } from './copy-types.js';
5
- import { b as TableSavedViewsProps, c as MatrxDataTableDensity, d as MatrxDataTableRecordControls } from '../types-DVTNnzU5.js';
5
+ import { b as TableSavedViewsProps, c as MatrxDataTableDensity, d as MatrxDataTableRecordControls } from '../types-DlgTSJsC.js';
6
6
  import { MatrxTableMenuTarget, MatrxTableMenuPayload, MatrxTableMenuSectionsResolver, MatrxTableMenuIconName } from './menu-targets.js';
7
7
  export { MatrxTableMenuItem, MatrxTableMenuSection } from './menu-targets.js';
8
8
  import '../content-transfer.js';
@@ -35068,6 +35068,16 @@ var selectTriggerVariants = (0, import_class_variance_authority2.cva)(
35068
35068
  }
35069
35069
  }
35070
35070
  );
35071
+ function SelectChevron({ className, size = "default" }) {
35072
+ return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
35073
+ RadixChevronDownIcon,
35074
+ {
35075
+ "aria-hidden": "true",
35076
+ "data-select-chevron": "",
35077
+ className: cn(size === "sm" ? "h-3.5 w-3.5" : "h-4 w-4", "shrink-0 opacity-50", className)
35078
+ }
35079
+ );
35080
+ }
35071
35081
  var SelectTrigger = React8.forwardRef(({ className, children, hideArrow = false, size, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
35072
35082
  SelectPrimitive.Trigger,
35073
35083
  {
@@ -35076,7 +35086,7 @@ var SelectTrigger = React8.forwardRef(({ className, children, hideArrow = false,
35076
35086
  ...props,
35077
35087
  children: [
35078
35088
  children,
35079
- !hideArrow && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(RadixChevronDownIcon, { className: "h-4 w-4 shrink-0 opacity-50" }) })
35089
+ !hideArrow && /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectPrimitive.Icon, { asChild: true, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(SelectChevron, { size: size === "sm" ? "sm" : "default" }) })
35080
35090
  ]
35081
35091
  }
35082
35092
  ));
@@ -36503,7 +36513,8 @@ function GenericTablePagination({
36503
36513
  labelFormat,
36504
36514
  compact = false,
36505
36515
  hideEntriesInfo = false,
36506
- progressive
36516
+ progressive,
36517
+ countUnavailable
36507
36518
  }) {
36508
36519
  const host = useMatrxDataTableHost();
36509
36520
  const positivePageSizes = pageSizeOptions.filter((size) => size > 0);
@@ -36578,7 +36589,16 @@ function GenericTablePagination({
36578
36589
  "div",
36579
36590
  {
36580
36591
  className: cn("flex min-w-0 justify-center", infoContainerClassName),
36581
- children: showPageInfo && !hideEntriesInfo && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
36592
+ children: showPageInfo && !hideEntriesInfo && countUnavailable === "failed" ? /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
36593
+ "span",
36594
+ {
36595
+ role: "img",
36596
+ "aria-label": "Row count unavailable",
36597
+ title: "Row count unavailable",
36598
+ className: "truncate text-sm tabular-nums text-muted-foreground",
36599
+ children: /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { "aria-hidden": "true", children: "\u2014" })
36600
+ }
36601
+ ) : showPageInfo && !hideEntriesInfo && !countUnavailable && /* @__PURE__ */ (0, import_jsx_runtime23.jsxs)(import_jsx_runtime23.Fragment, { children: [
36582
36602
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)("span", { className: "truncate text-xs tabular-nums text-muted-foreground sm:hidden", children: labelFormat ? formatLabel(startItem, endItem, totalItems) : unknownTotal ? defaultLabelFormat(startItem, endItem, totalItems) : totalItems === 0 ? "0 rows" : progressive ? `${endItem}/${totalItems} ${progressive.loadedCount !== void 0 && progressive.loadedCount !== totalItems ? "matching" : "loaded"}` : `${startItem}\u2013${endItem} of ${totalItems}` }),
36583
36603
  /* @__PURE__ */ (0, import_jsx_runtime23.jsx)(
36584
36604
  "span",
@@ -48155,6 +48175,7 @@ function MatrxDataTableCore(coreProps) {
48155
48175
  selection: selectionConfig,
48156
48176
  rowActions,
48157
48177
  footerRows = [],
48178
+ summary,
48158
48179
  rowClassName,
48159
48180
  rowVersion,
48160
48181
  cellClassName,
@@ -48210,6 +48231,17 @@ function MatrxDataTableCore(coreProps) {
48210
48231
  const CHECKBOX_TAP_AREA = "h-4 w-4 touch-manipulation";
48211
48232
  const mobileCardsClass = mobileCardsBreakpoint === "lg" ? "lg:hidden" : "sm:hidden";
48212
48233
  const tableWithCardsClass = mobileCardsBreakpoint === "lg" ? "max-lg:hidden" : "max-sm:hidden";
48234
+ const cardsQuery = mobileCardsBreakpoint === "lg" ? "(max-width: 1023px)" : "(max-width: 639px)";
48235
+ const [cardsActive, setCardsActive] = (0, import_react22.useState)(null);
48236
+ (0, import_react22.useEffect)(() => {
48237
+ if (!mobileCards || typeof window === "undefined" || !window.matchMedia) return;
48238
+ const mql = window.matchMedia(cardsQuery);
48239
+ const read2 = () => setCardsActive(mql.matches);
48240
+ read2();
48241
+ mql.addEventListener?.("change", read2);
48242
+ return () => mql.removeEventListener?.("change", read2);
48243
+ }, [mobileCards, cardsQuery]);
48244
+ const inactiveProps = (active) => cardsActive === null || active ? {} : { inert: true, "aria-hidden": true };
48213
48245
  const controlledQuery = query?.mode === "controlled" || query?.mode === "controlled-local" || query?.mode === "controlled-append" ? query : null;
48214
48246
  const remoteQuery = query?.mode === "controlled" || query?.mode === "controlled-append" ? query : null;
48215
48247
  const sourceProcessing = query?.mode === "controlled" || query?.mode === "controlled-local" ? query.sourceProcessing : appendQuery?.sourceProcessing;
@@ -49524,6 +49556,48 @@ function MatrxDataTableCore(coreProps) {
49524
49556
  return def !== void 0 && f.value !== def;
49525
49557
  });
49526
49558
  const hasActiveFilters = activeFilterCount > 0 || Boolean(searchValue.trim()) || intelligentSearchEnabled && searchScope !== "all" || Boolean(anyOfValue.trim()) || completeLayeredFilterRules(layeredFilters).length > 0 || facetActive;
49559
+ const summaryIsFiltered = activeFilterCount > 0 || Boolean(searchValue.trim()) || Boolean(anyOfValue.trim()) || completeLayeredFilterRules(layeredFilters).length > 0 || facetActive;
49560
+ const summaryCoverage = remoteQuery?.mode === "controlled" ? "page" : appendQuery !== null || !allRowsAreLoaded ? "loaded" : "all";
49561
+ const summaryContext = {
49562
+ rows: processed,
49563
+ isFiltered: summaryIsFiltered,
49564
+ coverage: summaryCoverage
49565
+ };
49566
+ const summaryCanReadRows = !readView.failure && (!isLoading || data.length > 0);
49567
+ const summaryUsesSource = summary?.source !== void 0;
49568
+ const summaryCaption = (() => {
49569
+ if (summaryUsesSource) {
49570
+ const sourceCaption = summary?.source?.isFiltered ? "Filtered source totals" : "Source totals";
49571
+ return readView.stale ? `${sourceCaption} (stale)` : sourceCaption;
49572
+ }
49573
+ const base = summaryCoverage === "all" ? "rows" : summaryCoverage === "loaded" ? "loaded rows" : "current page";
49574
+ const caption = summaryIsFiltered ? `Filtered ${base}` : base === "rows" ? "All rows" : base[0].toUpperCase() + base.slice(1);
49575
+ return readView.stale ? `${caption} (stale)` : caption;
49576
+ })();
49577
+ const resolveSummaryValue = (sourceValue, callback) => {
49578
+ if (!summaryCanReadRows) {
49579
+ return readView.failure ? { value: "Unavailable", unavailable: true } : { value: "Loading", unavailable: false };
49580
+ }
49581
+ if (summaryUsesSource) {
49582
+ return sourceValue === void 0 ? { value: "Unavailable", unavailable: true } : { value: sourceValue, unavailable: false };
49583
+ }
49584
+ if (!callback) return { value: "Unavailable", unavailable: true };
49585
+ try {
49586
+ return { value: callback(summaryContext), unavailable: false };
49587
+ } catch {
49588
+ return { value: "Unavailable", unavailable: true };
49589
+ }
49590
+ };
49591
+ const summaryMetrics = summary?.metrics.map((metric) => ({
49592
+ id: metric.id,
49593
+ label: metric.label,
49594
+ ...resolveSummaryValue(summary.source?.metrics?.[metric.id], metric.value)
49595
+ })) ?? [];
49596
+ const summaryTotals = Object.entries(summary?.totals ?? {}).map(([id, value]) => ({
49597
+ id,
49598
+ ...resolveSummaryValue(summary?.source?.totals?.[id], value)
49599
+ }));
49600
+ const hasSummaryTotals = summaryTotals.length > 0;
49527
49601
  const changeCount = (0, import_react22.useMemo)(() => {
49528
49602
  let n2 = 0;
49529
49603
  for (const fields of Object.values(edits)) {
@@ -50425,7 +50499,16 @@ function MatrxDataTableCore(coreProps) {
50425
50499
  controlledQuery,
50426
50500
  emitControlledQueryChange
50427
50501
  ]);
50428
- const footerEpoch = useRenderEpoch([...chromeGeometry, footerRows]);
50502
+ const footerEpoch = useRenderEpoch([
50503
+ ...chromeGeometry,
50504
+ footerRows,
50505
+ summaryContext.rows,
50506
+ summaryContext.isFiltered,
50507
+ summaryContext.coverage,
50508
+ summaryCaption,
50509
+ summaryUsesSource,
50510
+ ...summaryTotals.flatMap((total) => [total.id, total.value, total.unavailable])
50511
+ ]);
50429
50512
  const paginationEpoch = useRenderEpoch([
50430
50513
  totalItems,
50431
50514
  sourceTotal,
@@ -50962,6 +51045,25 @@ function MatrxDataTableCore(coreProps) {
50962
51045
  notice,
50963
51046
  savedViewError ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ErrorBox, { className: "shrink-0 text-xs text-destructive", message: savedViewError, operation: "Save or apply a saved view", origin: "design-system/MatrxDataTable" }) : null,
50964
51047
  toolbarActionError ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ErrorBox, { className: "shrink-0 text-xs text-destructive", message: toolbarActionError, operation: "Run a table toolbar action", origin: "design-system/MatrxDataTable" }) : null,
51048
+ summaryMetrics.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
51049
+ "section",
51050
+ {
51051
+ "data-matrx-table-summary": true,
51052
+ "data-matrx-table-summary-scope": summaryUsesSource ? "source" : summaryCoverage,
51053
+ "aria-label": `Table summary: ${summaryCaption}`,
51054
+ className: "flex shrink-0 flex-wrap items-stretch gap-2",
51055
+ children: [
51056
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "flex items-center px-1 text-xs font-medium text-muted-foreground", children: summaryCaption }),
51057
+ summaryMetrics.map((metric) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "min-w-24 rounded-md border border-border bg-card px-3 py-2 shadow-xs", children: [
51058
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "text-xs text-muted-foreground", children: metric.label }),
51059
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("div", { className: "mt-0.5 text-sm font-semibold tabular-nums text-foreground", children: [
51060
+ metric.value,
51061
+ metric.unavailable ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ErrorBox, { as: "span", className: "sr-only", message: `${metric.label} is unavailable`, operation: "Summarize this table", origin: "design-system/MatrxDataTable" }) : null
51062
+ ] })
51063
+ ] }, metric.id))
51064
+ ]
51065
+ }
51066
+ ) : null,
50965
51067
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(MatrxTableChrome, { part: "toolbar", epoch: toolbarEpoch, render: () => placeToolbar(!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__ */ (0, import_jsx_runtime50.jsxs)(
50966
51068
  TableTitleRow,
50967
51069
  {
@@ -51298,6 +51400,7 @@ function MatrxDataTableCore(coreProps) {
51298
51400
  "div",
51299
51401
  {
51300
51402
  ref: cardsScrollRef,
51403
+ ...inactiveProps(cardsActive === true),
51301
51404
  "data-matrx-table-cards-scroll": true,
51302
51405
  "aria-busy": isLoading || isFetching,
51303
51406
  ...appendQuery === null ? {} : { style: { containerType: "inline-size" } },
@@ -51406,6 +51509,7 @@ function MatrxDataTableCore(coreProps) {
51406
51509
  "div",
51407
51510
  {
51408
51511
  ref: scrollRef,
51512
+ ...mobileCards ? inactiveProps(cardsActive === false) : {},
51409
51513
  "data-matrx-table-scroll": true,
51410
51514
  onScroll: updateScrollHint,
51411
51515
  ...spreadsheetEnabled ? {
@@ -51802,50 +51906,111 @@ function MatrxDataTableCore(coreProps) {
51802
51906
  }
51803
51907
  ) }) : null
51804
51908
  ] }),
51805
- /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(MatrxTableChrome, { part: "footer", epoch: footerEpoch, render: () => footerRows.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("tfoot", { className: "border-t-2 border-border bg-muted/50 font-semibold", children: footerRows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("tr", { children: [
51806
- selection ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("td", { className: "px-2 py-2" }) : null,
51807
- columnSpacers && columnSpacers.start > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
51808
- "td",
51809
- {
51810
- "aria-hidden": "true",
51811
- "data-matrx-table-column-spacer": "start",
51812
- className: "border-0 p-0",
51813
- style: { width: `${columnSpacers.start}px`, minWidth: `${columnSpacers.start}px` }
51814
- },
51815
- "matrx-column-spacer-start"
51816
- ) : null,
51817
- renderedColumns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
51818
- "td",
51819
- {
51820
- className: cn(
51821
- "px-2 py-2 align-middle",
51822
- (column.compact || resolveColumnMarker(column) !== void 0) && "px-1",
51823
- column.className,
51824
- column.align === "center" && "text-center",
51825
- column.align === "right" && "text-right"
51826
- ),
51827
- style: columnWidthVar(
51828
- resolveColumnMarker(column) && column.width === void 0 ? 40 : column.width,
51829
- windowedWidthFor(columnId(column), column.width),
51830
- columnId(column),
51831
- resizableColumns && column.resizable !== false
51832
- ),
51833
- children: renderCell(row, column, index)
51834
- },
51835
- columnId(column)
51836
- )),
51837
- columnSpacers && columnSpacers.end > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
51838
- "td",
51839
- {
51840
- "aria-hidden": "true",
51841
- "data-matrx-table-column-spacer": "end",
51842
- className: "border-0 p-0",
51843
- style: { width: `${columnSpacers.end}px`, minWidth: `${columnSpacers.end}px` }
51844
- },
51845
- "matrx-column-spacer-end"
51846
- ) : null,
51847
- showActionsCol ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("td", {}) : null
51848
- ] }, `footer-${index}`)) }) : null })
51909
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(MatrxTableChrome, { part: "footer", epoch: footerEpoch, render: () => footerRows.length > 0 || hasSummaryTotals ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("tfoot", { className: cn(
51910
+ "border-t-2 border-border bg-muted/50 font-semibold",
51911
+ hasSummaryTotals && "sticky bottom-0 z-10 bg-muted/95 backdrop-blur-sm"
51912
+ ), children: [
51913
+ hasSummaryTotals ? /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(import_jsx_runtime50.Fragment, { children: [
51914
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("tr", { "data-matrx-table-summary-total-caption": true, children: /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("td", { colSpan: renderedColSpan, className: "px-2 pt-2 text-xs font-medium text-muted-foreground", children: [
51915
+ summaryCaption,
51916
+ readView.stale ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("span", { className: "ml-1 text-amber-700 dark:text-amber-300", children: "Retained rows may be out of date." }) : null
51917
+ ] }) }),
51918
+ /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("tr", { "data-matrx-table-summary-totals": true, children: [
51919
+ selection ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("td", { className: "px-2 py-2" }) : null,
51920
+ columnSpacers && columnSpacers.start > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
51921
+ "td",
51922
+ {
51923
+ "aria-hidden": "true",
51924
+ "data-matrx-table-column-spacer": "start",
51925
+ className: "border-0 p-0",
51926
+ style: { width: `${columnSpacers.start}px`, minWidth: `${columnSpacers.start}px` }
51927
+ },
51928
+ "matrx-summary-column-spacer-start"
51929
+ ) : null,
51930
+ renderedColumns.map((column) => {
51931
+ const total = summaryTotals.find((candidate) => candidate.id === columnId(column));
51932
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(
51933
+ "td",
51934
+ {
51935
+ className: cn(
51936
+ "px-2 py-2 align-middle",
51937
+ (column.compact || resolveColumnMarker(column) !== void 0) && "px-1",
51938
+ column.className,
51939
+ column.align === "center" && "text-center",
51940
+ column.align === "right" && "text-right"
51941
+ ),
51942
+ style: columnWidthVar(
51943
+ resolveColumnMarker(column) && column.width === void 0 ? 40 : column.width,
51944
+ windowedWidthFor(columnId(column), column.width),
51945
+ columnId(column),
51946
+ resizableColumns && column.resizable !== false
51947
+ ),
51948
+ children: [
51949
+ total?.value,
51950
+ total?.unavailable ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(ErrorBox, { as: "span", className: "sr-only", message: `${columnId(column)} total is unavailable`, operation: "Total this column", origin: "design-system/MatrxDataTable" }) : null
51951
+ ]
51952
+ },
51953
+ columnId(column)
51954
+ );
51955
+ }),
51956
+ columnSpacers && columnSpacers.end > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
51957
+ "td",
51958
+ {
51959
+ "aria-hidden": "true",
51960
+ "data-matrx-table-column-spacer": "end",
51961
+ className: "border-0 p-0",
51962
+ style: { width: `${columnSpacers.end}px`, minWidth: `${columnSpacers.end}px` }
51963
+ },
51964
+ "matrx-summary-column-spacer-end"
51965
+ ) : null,
51966
+ showActionsCol ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("td", {}) : null
51967
+ ] })
51968
+ ] }) : null,
51969
+ footerRows.map((row, index) => /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)("tr", { children: [
51970
+ selection ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("td", { className: "px-2 py-2" }) : null,
51971
+ columnSpacers && columnSpacers.start > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
51972
+ "td",
51973
+ {
51974
+ "aria-hidden": "true",
51975
+ "data-matrx-table-column-spacer": "start",
51976
+ className: "border-0 p-0",
51977
+ style: { width: `${columnSpacers.start}px`, minWidth: `${columnSpacers.start}px` }
51978
+ },
51979
+ "matrx-column-spacer-start"
51980
+ ) : null,
51981
+ renderedColumns.map((column) => /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
51982
+ "td",
51983
+ {
51984
+ className: cn(
51985
+ "px-2 py-2 align-middle",
51986
+ (column.compact || resolveColumnMarker(column) !== void 0) && "px-1",
51987
+ column.className,
51988
+ column.align === "center" && "text-center",
51989
+ column.align === "right" && "text-right"
51990
+ ),
51991
+ style: columnWidthVar(
51992
+ resolveColumnMarker(column) && column.width === void 0 ? 40 : column.width,
51993
+ windowedWidthFor(columnId(column), column.width),
51994
+ columnId(column),
51995
+ resizableColumns && column.resizable !== false
51996
+ ),
51997
+ children: renderCell(row, column, index)
51998
+ },
51999
+ columnId(column)
52000
+ )),
52001
+ columnSpacers && columnSpacers.end > 0 ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
52002
+ "td",
52003
+ {
52004
+ "aria-hidden": "true",
52005
+ "data-matrx-table-column-spacer": "end",
52006
+ className: "border-0 p-0",
52007
+ style: { width: `${columnSpacers.end}px`, minWidth: `${columnSpacers.end}px` }
52008
+ },
52009
+ "matrx-column-spacer-end"
52010
+ ) : null,
52011
+ showActionsCol ? /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("td", {}) : null
52012
+ ] }, `footer-${index}`))
52013
+ ] }) : null })
51849
52014
  ]
51850
52015
  }
51851
52016
  )
@@ -52011,6 +52176,7 @@ function MatrxDataTableCore(coreProps) {
52011
52176
  GenericTablePagination,
52012
52177
  {
52013
52178
  totalItems,
52179
+ ...readView.failure ? { countUnavailable: "failed" } : read?.status === "loading" && data.length === 0 ? { countUnavailable: "loading" } : {},
52014
52180
  ...paginationLabelFormat ? { labelFormat: paginationLabelFormat } : sourceTotal === void 0 ? {} : { labelFormat: (start, end, total) => `${(0, import_format3.formatCount)(start)}\u2013${(0, import_format3.formatCount)(end)} of ${(0, import_format3.formatCount)(total)} matching \xB7 ${(0, import_format3.formatCount)(data.length)} / ${(0, import_format3.formatCount)(sourceTotal)} loaded` },
52015
52181
  ...localProgressiveEnabled ? { progressive: {
52016
52182
  shownCount: progressiveRows.shownCount,
@@ -52692,7 +52858,7 @@ var DropdownMenu = DropdownMenuPrimitive.Root;
52692
52858
  var DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
52693
52859
  var DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
52694
52860
  var MENU_SURFACE_CLASS = "z-[10001] min-w-[8rem] max-h-[var(--radix-dropdown-menu-content-available-height)] overflow-y-auto overflow-x-hidden overscroll-contain rounded-md border bg-popover p-1 text-popover-foreground";
52695
- var MENU_ITEM_CLASS = "relative flex cursor-default select-none items-center rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
52861
+ var MENU_ITEM_CLASS = "relative flex cursor-default select-none items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
52696
52862
  var MENU_INDICATOR_ITEM_CLASS = "relative flex cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none transition-colors focus:bg-accent focus:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50";
52697
52863
  var DropdownMenuSubTrigger = React22.forwardRef(({ className, inset, children, ...props }, ref) => /* @__PURE__ */ (0, import_jsx_runtime51.jsxs)(
52698
52864
  DropdownMenuPrimitive.SubTrigger,