@ai-matrx/design-system 0.21.3 → 0.21.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.
Files changed (48) hide show
  1. package/dist/data-table/copy-helpers.d.cts +1 -1
  2. package/dist/data-table/copy-helpers.d.ts +1 -1
  3. package/dist/data-table/data-row-inspector.cjs +3 -0
  4. package/dist/data-table/data-row-inspector.cjs.map +1 -1
  5. package/dist/data-table/data-row-inspector.js +3 -0
  6. package/dist/data-table/data-row-inspector.js.map +1 -1
  7. package/dist/data-table/data-row-window.cjs +3 -0
  8. package/dist/data-table/data-row-window.cjs.map +1 -1
  9. package/dist/data-table/data-row-window.js +3 -0
  10. package/dist/data-table/data-row-window.js.map +1 -1
  11. package/dist/data-table/filter-engine.d.cts +1 -1
  12. package/dist/data-table/filter-engine.d.ts +1 -1
  13. package/dist/data-table/host.cjs +12 -1
  14. package/dist/data-table/host.cjs.map +1 -1
  15. package/dist/data-table/host.d.cts +19 -3
  16. package/dist/data-table/host.d.ts +19 -3
  17. package/dist/data-table/host.js +12 -1
  18. package/dist/data-table/host.js.map +1 -1
  19. package/dist/data-table/index.cjs +98 -34
  20. package/dist/data-table/index.cjs.map +1 -1
  21. package/dist/data-table/index.d.cts +5 -4
  22. package/dist/data-table/index.d.ts +5 -4
  23. package/dist/data-table/index.js +127 -63
  24. package/dist/data-table/index.js.map +1 -1
  25. package/dist/data-table/infer-filter.d.cts +1 -1
  26. package/dist/data-table/infer-filter.d.ts +1 -1
  27. package/dist/data-table/layered-filters.d.cts +1 -1
  28. package/dist/data-table/layered-filters.d.ts +1 -1
  29. package/dist/data-table/pagination.cjs +3 -0
  30. package/dist/data-table/pagination.cjs.map +1 -1
  31. package/dist/data-table/pagination.js +3 -0
  32. package/dist/data-table/pagination.js.map +1 -1
  33. package/dist/data-table/query-control.d.cts +1 -1
  34. package/dist/data-table/query-control.d.ts +1 -1
  35. package/dist/data-table/types.cjs.map +1 -1
  36. package/dist/data-table/types.d.cts +1 -1
  37. package/dist/data-table/types.d.ts +1 -1
  38. package/dist/data-table/url-state.d.cts +1 -1
  39. package/dist/data-table/url-state.d.ts +1 -1
  40. package/dist/data-table/uuid-cell.cjs +3 -0
  41. package/dist/data-table/uuid-cell.cjs.map +1 -1
  42. package/dist/data-table/uuid-cell.js +3 -0
  43. package/dist/data-table/uuid-cell.js.map +1 -1
  44. package/dist/data-table/xlsx.d.cts +1 -1
  45. package/dist/data-table/xlsx.d.ts +1 -1
  46. package/dist/{types-JFlsIv-0.d.ts → types-CbGNfo7r.d.ts} +10 -1
  47. package/dist/{types-BarjBFyG.d.cts → types-DRusLYrU.d.cts} +10 -1
  48. package/package.json +1 -1
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { g as MatrxDataTableProps, h as TableViewSnapshot } from '../types-BarjBFyG.cjs';
4
- export { A as AnyOfColumnSearch, i as CellEditType, j as CellEditsMap, e as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, M as MatrxColumnDef, f as MatrxDataTableCopyConfig, c as MatrxDataTableDensity, k as MatrxDataTableDetailConfig, l as MatrxDataTableEditConfig, m as MatrxDataTableEmptyState, n as MatrxDataTableFilterUi, o as MatrxDataTableHierarchyConfig, p as MatrxDataTableHierarchyMove, q as MatrxDataTableMobileCardControls, r as MatrxDataTableQueryControl, d as MatrxDataTableQueryState, s as MatrxDataTableRecordControls, t as MatrxDataTableSelectionConfig, u as MatrxDataTableSourceProcessing, v as MatrxDataTableToolbar, w as MatrxDataTableUrlStateConfig, x as MatrxDataTableWindowConfig, y as MatrxTablePagination, z as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, B as TableViewQuery, D as TextFilterMode, E as ToolbarFacet } from '../types-BarjBFyG.cjs';
3
+ import { h as MatrxDataTableProps, i as TableViewSnapshot, c as MatrxDataTableRecordControls } from '../types-DRusLYrU.cjs';
4
+ export { A as AnyOfColumnSearch, j as CellEditType, k as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, M as MatrxColumnDef, l as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, d as MatrxDataTableDensity, m as MatrxDataTableDetailConfig, n as MatrxDataTableEditConfig, o as MatrxDataTableEmptyState, p as MatrxDataTableFilterUi, q as MatrxDataTableHierarchyConfig, r as MatrxDataTableHierarchyMove, s as MatrxDataTableMobileCardControls, t as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, u as MatrxDataTableSelectionConfig, v as MatrxDataTableSourceProcessing, w as MatrxDataTableToolbar, x as MatrxDataTableUrlStateConfig, y as MatrxDataTableWindowConfig, z as MatrxTablePagination, B as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, D as TableViewQuery, E as TextFilterMode, F as ToolbarFacet } from '../types-DRusLYrU.cjs';
5
5
  export { MatrxDataTableHost, MatrxDataTableProvider, MatrxTableRowAlchemy, TableDoors, TableEntityRefProps, TableLinkProps, TablePeekProps, TableSidePanelProps, TableToolbarActionProps, TableWindowPanelProps, useMatrxDataTableHost, useMatrxTableRowAlchemy } from './host.cjs';
6
6
  import { CopyControlProps } from './copy-types.cjs';
7
7
  export { AgentPayloadInput } from './copy-types.cjs';
@@ -71,9 +71,10 @@ declare function SavedViewsControl({ views, activeId, loading, error, dirty, onS
71
71
  declare function parseTableViewSnapshot(raw: unknown): TableViewSnapshot | null;
72
72
 
73
73
  /** Keeps Alchemy mounted beside row actions, never inside a transient host popup. */
74
- declare function MatrxTableRowAlchemyProvider({ copy, placement, children }: {
74
+ declare function MatrxTableRowAlchemyProvider({ copy, placement, controls, children }: {
75
75
  copy: CopyControlProps;
76
76
  placement: "inline" | "menu";
77
+ controls: MatrxDataTableRecordControls;
77
78
  children: ReactNode;
78
79
  }): React.JSX.Element;
79
80
 
@@ -95,4 +96,4 @@ interface TableViewTabsProps {
95
96
  /** One shared tab strip; hosts may own URL state without copying its UI. */
96
97
  declare function TableViewTabs({ tabs, activeId, onSelect, onAdd, onClose, onRename, related }: TableViewTabsProps): React.JSX.Element;
97
98
 
98
- export { MatrxDataTable, MatrxDataTableProps, MatrxTableRowAlchemyProvider, SavedViewsControl, type SavedViewsControlProps, TableTitleRow, type TableTitleRowProps, TableViewSnapshot, type TableViewTab, TableViewTabs, type TableViewTabsProps, parseTableViewSnapshot };
99
+ export { MatrxDataTable, MatrxDataTableProps, MatrxDataTableRecordControls, MatrxTableRowAlchemyProvider, SavedViewsControl, type SavedViewsControlProps, TableTitleRow, type TableTitleRowProps, TableViewSnapshot, type TableViewTab, TableViewTabs, type TableViewTabsProps, parseTableViewSnapshot };
@@ -1,7 +1,7 @@
1
1
  import * as React from 'react';
2
2
  import { ReactNode } from 'react';
3
- import { g as MatrxDataTableProps, h as TableViewSnapshot } from '../types-JFlsIv-0.js';
4
- export { A as AnyOfColumnSearch, i as CellEditType, j as CellEditsMap, e as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, M as MatrxColumnDef, f as MatrxDataTableCopyConfig, c as MatrxDataTableDensity, k as MatrxDataTableDetailConfig, l as MatrxDataTableEditConfig, m as MatrxDataTableEmptyState, n as MatrxDataTableFilterUi, o as MatrxDataTableHierarchyConfig, p as MatrxDataTableHierarchyMove, q as MatrxDataTableMobileCardControls, r as MatrxDataTableQueryControl, d as MatrxDataTableQueryState, s as MatrxDataTableRecordControls, t as MatrxDataTableSelectionConfig, u as MatrxDataTableSourceProcessing, v as MatrxDataTableToolbar, w as MatrxDataTableUrlStateConfig, x as MatrxDataTableWindowConfig, y as MatrxTablePagination, z as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, B as TableViewQuery, D as TextFilterMode, E as ToolbarFacet } from '../types-JFlsIv-0.js';
3
+ import { h as MatrxDataTableProps, i as TableViewSnapshot, c as MatrxDataTableRecordControls } from '../types-CbGNfo7r.js';
4
+ export { A as AnyOfColumnSearch, j as CellEditType, k as CellEditsMap, f as ColumnFilterKind, a as ColumnFilterValue, C as ColumnFiltersState, M as MatrxColumnDef, l as MatrxDataTableContextMenuConfig, g as MatrxDataTableCopyConfig, d as MatrxDataTableDensity, m as MatrxDataTableDetailConfig, n as MatrxDataTableEditConfig, o as MatrxDataTableEmptyState, p as MatrxDataTableFilterUi, q as MatrxDataTableHierarchyConfig, r as MatrxDataTableHierarchyMove, s as MatrxDataTableMobileCardControls, t as MatrxDataTableQueryControl, e as MatrxDataTableQueryState, u as MatrxDataTableSelectionConfig, v as MatrxDataTableSourceProcessing, w as MatrxDataTableToolbar, x as MatrxDataTableUrlStateConfig, y as MatrxDataTableWindowConfig, z as MatrxTablePagination, B as SortDirection, S as SortState, b as TableSavedViewsProps, T as TableSearchMatchMode, D as TableViewQuery, E as TextFilterMode, F as ToolbarFacet } from '../types-CbGNfo7r.js';
5
5
  export { MatrxDataTableHost, MatrxDataTableProvider, MatrxTableRowAlchemy, TableDoors, TableEntityRefProps, TableLinkProps, TablePeekProps, TableSidePanelProps, TableToolbarActionProps, TableWindowPanelProps, useMatrxDataTableHost, useMatrxTableRowAlchemy } from './host.js';
6
6
  import { CopyControlProps } from './copy-types.js';
7
7
  export { AgentPayloadInput } from './copy-types.js';
@@ -71,9 +71,10 @@ declare function SavedViewsControl({ views, activeId, loading, error, dirty, onS
71
71
  declare function parseTableViewSnapshot(raw: unknown): TableViewSnapshot | null;
72
72
 
73
73
  /** Keeps Alchemy mounted beside row actions, never inside a transient host popup. */
74
- declare function MatrxTableRowAlchemyProvider({ copy, placement, children }: {
74
+ declare function MatrxTableRowAlchemyProvider({ copy, placement, controls, children }: {
75
75
  copy: CopyControlProps;
76
76
  placement: "inline" | "menu";
77
+ controls: MatrxDataTableRecordControls;
77
78
  children: ReactNode;
78
79
  }): React.JSX.Element;
79
80
 
@@ -95,4 +96,4 @@ interface TableViewTabsProps {
95
96
  /** One shared tab strip; hosts may own URL state without copying its UI. */
96
97
  declare function TableViewTabs({ tabs, activeId, onSelect, onAdd, onClose, onRename, related }: TableViewTabsProps): React.JSX.Element;
97
98
 
98
- export { MatrxDataTable, MatrxDataTableProps, MatrxTableRowAlchemyProvider, SavedViewsControl, type SavedViewsControlProps, TableTitleRow, type TableTitleRowProps, TableViewSnapshot, type TableViewTab, TableViewTabs, type TableViewTabsProps, parseTableViewSnapshot };
99
+ export { MatrxDataTable, MatrxDataTableProps, MatrxDataTableRecordControls, MatrxTableRowAlchemyProvider, SavedViewsControl, type SavedViewsControlProps, TableTitleRow, type TableTitleRowProps, TableViewSnapshot, type TableViewTab, TableViewTabs, type TableViewTabsProps, parseTableViewSnapshot };
@@ -6,11 +6,11 @@ import {
6
6
  Fragment as Fragment6,
7
7
  isValidElement as isValidElement2,
8
8
  useCallback as useCallback6,
9
- useEffect as useEffect14,
9
+ useEffect as useEffect15,
10
10
  useId as useId2,
11
11
  useLayoutEffect as useLayoutEffect2,
12
12
  useMemo as useMemo7,
13
- useRef as useRef12,
13
+ useRef as useRef13,
14
14
  useState as useState21
15
15
  } from "react";
16
16
  import {
@@ -1886,6 +1886,12 @@ function MatrxTableRowAlchemyScope({ value, children }) {
1886
1886
  function useMatrxTableRowAlchemy() {
1887
1887
  return useContext4(RowAlchemyContext);
1888
1888
  }
1889
+ var ROW_CONTROLS_SLOT = /* @__PURE__ */ Symbol.for("ai-matrx.design-system.table-row-controls-context");
1890
+ var rowControlsRegistry = globalThis;
1891
+ var RowControlsContext = rowControlsRegistry[ROW_CONTROLS_SLOT] ??= createContext4(null);
1892
+ function MatrxTableRowControlsScope({ value, children }) {
1893
+ return /* @__PURE__ */ jsx18(RowControlsContext.Provider, { value, children });
1894
+ }
1889
1895
 
1890
1896
  // src/data-table/useTableNotice.tsx
1891
1897
  import { jsx as jsx19, jsxs as jsxs12 } from "react/jsx-runtime";
@@ -5592,7 +5598,7 @@ import {
5592
5598
  // src/data-table/RowAlchemyLauncher.tsx
5593
5599
  import { useEffect as useEffect8, useRef as useRef9, useState as useState13 } from "react";
5594
5600
  import { jsx as jsx29, jsxs as jsxs20 } from "react/jsx-runtime";
5595
- function MatrxTableRowAlchemyProvider({ copy, placement, children }) {
5601
+ function MatrxTableRowAlchemyProvider({ copy, placement, controls, children }) {
5596
5602
  const controller = useRef9(null);
5597
5603
  const { CopyControls } = useMatrxDataTableHost();
5598
5604
  const [active, setActive] = useState13(false);
@@ -5609,6 +5615,7 @@ function MatrxTableRowAlchemyProvider({ copy, placement, children }) {
5609
5615
  }, [active, placement]);
5610
5616
  const value = {
5611
5617
  copy,
5618
+ controls,
5612
5619
  placement,
5613
5620
  ready: active,
5614
5621
  activate: () => setActive(true),
@@ -7442,7 +7449,7 @@ function DirtySavePill({
7442
7449
  }
7443
7450
 
7444
7451
  // src/data-table/EditableTableCell.tsx
7445
- import { useState as useState19 } from "react";
7452
+ import { useEffect as useEffect14, useRef as useRef12, useState as useState19 } from "react";
7446
7453
  import { jsx as jsx38, jsxs as jsxs28 } from "react/jsx-runtime";
7447
7454
  function CellEditShell({
7448
7455
  href,
@@ -7489,9 +7496,13 @@ function EditableTableCell({
7489
7496
  onCommit,
7490
7497
  className,
7491
7498
  href,
7492
- editTrigger = "click"
7499
+ editTrigger = "click",
7500
+ editRequest
7493
7501
  }) {
7494
7502
  const [open, setOpen] = useState19(false);
7503
+ useEffect14(() => {
7504
+ if (editRequest !== void 0) setOpen(true);
7505
+ }, [editRequest]);
7495
7506
  const usePencil = Boolean(href) || editTrigger === "pencil";
7496
7507
  if (editType === "string") {
7497
7508
  return /* @__PURE__ */ jsx38(
@@ -7503,7 +7514,8 @@ function EditableTableCell({
7503
7514
  onCommit,
7504
7515
  ...className === void 0 ? {} : { className },
7505
7516
  ...href === void 0 ? {} : { href },
7506
- usePencil
7517
+ usePencil,
7518
+ ...editRequest === void 0 ? {} : { editRequest }
7507
7519
  }
7508
7520
  );
7509
7521
  }
@@ -7578,10 +7590,18 @@ function InlineStringEditor({
7578
7590
  onCommit,
7579
7591
  className,
7580
7592
  href,
7581
- usePencil
7593
+ usePencil,
7594
+ editRequest
7582
7595
  }) {
7583
7596
  const [editing, setEditing] = useState19(false);
7584
7597
  const [draft, setDraft] = useState19(value);
7598
+ const handledEditRequest = useRef12(void 0);
7599
+ useEffect14(() => {
7600
+ if (editRequest === void 0 || handledEditRequest.current === editRequest) return;
7601
+ handledEditRequest.current = editRequest;
7602
+ setDraft(value);
7603
+ setEditing(true);
7604
+ }, [editRequest, value]);
7585
7605
  if (!editing) {
7586
7606
  if (usePencil) {
7587
7607
  return /* @__PURE__ */ jsx38(
@@ -8505,7 +8525,7 @@ function MatrxDataTableWithUrlState({
8505
8525
  ...urlState.history === void 0 ? {} : { history: urlState.history },
8506
8526
  ...urlState.textHistory === void 0 ? {} : { textHistory: urlState.textHistory }
8507
8527
  });
8508
- useEffect14(() => {
8528
+ useEffect15(() => {
8509
8529
  if (activeUrlTableIds.has(urlState.id)) {
8510
8530
  throw new Error(
8511
8531
  `Duplicate MatrxDataTable urlState.id "${urlState.id}" on one page. Give every table a unique stable id.`
@@ -8575,6 +8595,9 @@ function MatrxDataTableWithUrlState({
8575
8595
  );
8576
8596
  }
8577
8597
  var COLUMN_REORDER_ACTIVATION_DISTANCE = 6;
8598
+ function TableContextPassthrough({ children }) {
8599
+ return /* @__PURE__ */ jsx41(Fragment7, { children });
8600
+ }
8578
8601
  function MatrxDataTableCore({
8579
8602
  data: suppliedData,
8580
8603
  columns,
@@ -8601,6 +8624,7 @@ function MatrxDataTableCore({
8601
8624
  detail,
8602
8625
  window: windowConfig,
8603
8626
  copy,
8627
+ contextMenu,
8604
8628
  rowCopyPlacement = "inline",
8605
8629
  edit,
8606
8630
  hierarchy,
@@ -8630,12 +8654,13 @@ function MatrxDataTableCore({
8630
8654
  }) {
8631
8655
  const appendQuery = query?.mode === "controlled-append" ? query : null;
8632
8656
  const appendQueryKey = appendQuery?.pagination.queryKey ?? null;
8633
- const committedAppendQueryKey = useRef12(appendQueryKey);
8657
+ const committedAppendQueryKey = useRef13(appendQueryKey);
8634
8658
  const appendSourceChanged = appendQuery !== null && committedAppendQueryKey.current !== appendQueryKey;
8635
8659
  const data = appendQuery ? appendQuery.pagination.rows : suppliedData;
8636
8660
  const isLoading = appendQuery ? appendQuery.pagination.loading : suppliedLoading;
8637
8661
  const isFetching = appendQuery ? appendQuery.pagination.isFetchingNextPage : suppliedFetching;
8638
8662
  const host = useMatrxDataTableHost();
8663
+ const ContextMenuBoundary = host.ContextMenuBoundary ?? TableContextPassthrough;
8639
8664
  const resolvedDensity = density ?? host.defaultDensity ?? "normal";
8640
8665
  const SavedViews = host.SavedViews;
8641
8666
  const Link = host.Link ?? DefaultTableLink;
@@ -8644,7 +8669,7 @@ function MatrxDataTableCore({
8644
8669
  const [savedViewError, setSavedViewError] = useState21(null);
8645
8670
  const [toolbarActionError, setToolbarActionError] = useState21(null);
8646
8671
  const [toolbarActionPending, setToolbarActionPending] = useState21({ refresh: false, add: false });
8647
- const toolbarActionPendingRef = useRef12({ refresh: false, add: false });
8672
+ const toolbarActionPendingRef = useRef13({ refresh: false, add: false });
8648
8673
  const CHECKBOX_TAP_AREA = "h-4 w-4 touch-manipulation";
8649
8674
  const mobileCardsClass = mobileCardsBreakpoint === "lg" ? "lg:hidden" : "sm:hidden";
8650
8675
  const tableWithCardsClass = mobileCardsBreakpoint === "lg" ? "max-lg:hidden" : "max-sm:hidden";
@@ -8782,8 +8807,10 @@ function MatrxDataTableCore({
8782
8807
  const [windowRowSnapshot, setWindowRowSnapshot] = useState21(null);
8783
8808
  const editScopeKey = appendQueryKey === null ? "\0local" : `append:${appendQueryKey}`;
8784
8809
  const [editsByScope, setEditsByScope] = useState21({});
8785
- const editRevisionRef = useRef12({});
8810
+ const editRevisionRef = useRef13({});
8786
8811
  const [savingByScope, setSavingByScope] = useState21({});
8812
+ const savingScopesRef = useRef13(/* @__PURE__ */ new Set());
8813
+ const [editRequest, setEditRequest] = useState21(null);
8787
8814
  const [confirmForeignDraftDiscard, setConfirmForeignDraftDiscard] = useState21(false);
8788
8815
  const edits = editsByScope[editScopeKey]?.values ?? {};
8789
8816
  const saving = (savingByScope[editScopeKey] ?? 0) > 0;
@@ -8851,7 +8878,7 @@ function MatrxDataTableCore({
8851
8878
  rows: Object.entries(draft.values).map(([rowId, columns2]) => ({ rowId, columns: columns2 }))
8852
8879
  }));
8853
8880
  const selection = appendSourceChanged && selectionConfig ? { ...selectionConfig, selectedIds: [] } : selectionConfig;
8854
- useEffect14(() => {
8881
+ useEffect15(() => {
8855
8882
  const previous = committedAppendQueryKey.current;
8856
8883
  committedAppendQueryKey.current = appendQueryKey;
8857
8884
  if (previous === null || appendQueryKey === null || previous === appendQueryKey) {
@@ -8869,13 +8896,13 @@ function MatrxDataTableCore({
8869
8896
  onWindowRowIdChange,
8870
8897
  selectionConfig
8871
8898
  ]);
8872
- const scrollRef = useRef12(null);
8873
- const tableRef = useRef12(null);
8874
- const tableHeaderRef = useRef12(null);
8875
- const cardsScrollRef = useRef12(null);
8899
+ const scrollRef = useRef13(null);
8900
+ const tableRef = useRef13(null);
8901
+ const tableHeaderRef = useRef13(null);
8902
+ const cardsScrollRef = useRef13(null);
8876
8903
  const [documentStickyHeader, setDocumentStickyHeader] = useState21(false);
8877
- const documentStickyHeaderRef = useRef12(false);
8878
- const previousAppendKeyForScrollReset = useRef12(appendQueryKey);
8904
+ const documentStickyHeaderRef = useRef13(false);
8905
+ const previousAppendKeyForScrollReset = useRef13(appendQueryKey);
8879
8906
  useLayoutEffect2(() => {
8880
8907
  const previous = previousAppendKeyForScrollReset.current;
8881
8908
  previousAppendKeyForScrollReset.current = appendQueryKey;
@@ -8901,7 +8928,7 @@ function MatrxDataTableCore({
8901
8928
  ...appendScrollPolicy?.mode === "scroll" && appendScrollPolicy.thresholdPx !== void 0 ? { thresholdPx: appendScrollPolicy.thresholdPx } : {},
8902
8929
  ...appendScrollPolicy?.mode === "scroll" && appendScrollPolicy.intentTimeoutMs !== void 0 ? { intentTimeoutMs: appendScrollPolicy.intentTimeoutMs } : {}
8903
8930
  });
8904
- const rootRef = useRef12(null);
8931
+ const rootRef = useRef13(null);
8905
8932
  useClippedContentGuard(rootRef, {
8906
8933
  label: typeof copy === "object" && copy.listLabel ? `Table: ${copy.listLabel}` : "MatrxDataTable"
8907
8934
  });
@@ -8921,7 +8948,7 @@ function MatrxDataTableCore({
8921
8948
  behavior: "smooth"
8922
8949
  });
8923
8950
  };
8924
- useEffect14(() => {
8951
+ useEffect15(() => {
8925
8952
  updateScrollHint();
8926
8953
  window.addEventListener("resize", updateScrollHint);
8927
8954
  const el = scrollRef.current;
@@ -9003,18 +9030,18 @@ function MatrxDataTableCore({
9003
9030
  () => normalizeColumnWidthsForColumns(columnState?.widths, columns)
9004
9031
  );
9005
9032
  const [fixedTableGeometry, setFixedTableGeometry] = useState21(null);
9006
- const knownColumnIds = useRef12(new Set(columns.map(columnId)));
9007
- const draggedColumnId = useRef12(null);
9008
- const columnDragActive = useRef12(false);
9009
- const columnDragRaf = useRef12(null);
9010
- const columnDragScrollDirection = useRef12(0);
9033
+ const knownColumnIds = useRef13(new Set(columns.map(columnId)));
9034
+ const draggedColumnId = useRef13(null);
9035
+ const columnDragActive = useRef13(false);
9036
+ const columnDragRaf = useRef13(null);
9037
+ const columnDragScrollDirection = useRef13(0);
9011
9038
  const [columnDragPreview, setColumnDragPreview] = useState21(null);
9012
9039
  const stopColumnDragScroll = useCallback6(() => {
9013
9040
  if (columnDragRaf.current !== null) cancelAnimationFrame(columnDragRaf.current);
9014
9041
  columnDragRaf.current = null;
9015
9042
  columnDragScrollDirection.current = 0;
9016
9043
  }, []);
9017
- useEffect14(() => () => {
9044
+ useEffect15(() => () => {
9018
9045
  columnDragActive.current = false;
9019
9046
  stopColumnDragScroll();
9020
9047
  }, [stopColumnDragScroll]);
@@ -9062,7 +9089,7 @@ function MatrxDataTableCore({
9062
9089
  () => normalizeColumnWidthsForColumns(columnState?.widths ?? columnWidths, columns),
9063
9090
  [columns, columnState?.widths, columnWidths]
9064
9091
  );
9065
- const resizeGestureSnapshotRef = useRef12(null);
9092
+ const resizeGestureSnapshotRef = useRef13(null);
9066
9093
  const measureVisibleColumnWidths = useCallback6(() => {
9067
9094
  const measured = {};
9068
9095
  const headers = tableRef.current ? Array.from(tableRef.current.querySelectorAll(
@@ -9135,7 +9162,7 @@ function MatrxDataTableCore({
9135
9162
  }
9136
9163
  setColumnWidths(normalized);
9137
9164
  }, [columnIds, columnState, columns, measureFixedTableGeometry, measureVisibleColumnWidths]);
9138
- useEffect14(() => {
9165
+ useEffect15(() => {
9139
9166
  const ids = columns.map(columnId);
9140
9167
  if (columnState) return;
9141
9168
  const previousIds = knownColumnIds.current;
@@ -9205,6 +9232,7 @@ function MatrxDataTableCore({
9205
9232
  [visibleColumns]
9206
9233
  );
9207
9234
  const tableCopySourceNamespace = useId2();
9235
+ const tableContextMenuInstanceId = useId2();
9208
9236
  const tableDndContextId = useId2();
9209
9237
  const defaultCopyTitle = toolbar?.title || "Table";
9210
9238
  const defaultCopy = useMemo7(() => ({
@@ -9320,8 +9348,8 @@ function MatrxDataTableCore({
9320
9348
  intelligentSearchEnabled,
9321
9349
  searchScope
9322
9350
  ]);
9323
- const lastNotifiedViewRows = useRef12(null);
9324
- useEffect14(() => {
9351
+ const lastNotifiedViewRows = useRef13(null);
9352
+ useEffect15(() => {
9325
9353
  if (!onViewChange) {
9326
9354
  lastNotifiedViewRows.current = null;
9327
9355
  return;
@@ -9330,7 +9358,7 @@ function MatrxDataTableCore({
9330
9358
  lastNotifiedViewRows.current = processed;
9331
9359
  if (changed) onViewChange(processed);
9332
9360
  }, [processed, onViewChange]);
9333
- useEffect14(() => {
9361
+ useEffect15(() => {
9334
9362
  if (controlledQuery) return;
9335
9363
  setInternalPage(1);
9336
9364
  }, [
@@ -9382,7 +9410,7 @@ function MatrxDataTableCore({
9382
9410
  const start = (safePage - 1) * effectivePageSize;
9383
9411
  return processed.slice(start, start + effectivePageSize);
9384
9412
  }, [processed, safePage, effectivePageSize, pageSize, remoteQuery, hidePagination, localProgressiveEnabled, progressiveRows.rows]);
9385
- useEffect14(() => {
9413
+ useEffect15(() => {
9386
9414
  if (!controlledQuery || controlledQuery.state.page === safePage) return;
9387
9415
  emitControlledQueryChange({ page: safePage });
9388
9416
  }, [controlledQuery, emitControlledQueryChange, safePage]);
@@ -9406,13 +9434,15 @@ function MatrxDataTableCore({
9406
9434
  const showToolbarCopy = effectiveCopy !== void 0 && effectiveCopy.showToolbar !== false;
9407
9435
  const renderRowActions = (row, controls) => {
9408
9436
  const actions = rowActions?.(row, controls);
9409
- if (!effectiveCopy || !showRowCopy) return actions;
9437
+ const scopedActions = /* @__PURE__ */ jsx41(MatrxTableRowControlsScope, { value: controls, children: actions });
9438
+ if (!effectiveCopy || !showRowCopy) return scopedActions;
9410
9439
  return /* @__PURE__ */ jsx41(
9411
9440
  MatrxTableRowAlchemyProvider,
9412
9441
  {
9413
9442
  copy: tableRowCopyProps(effectiveCopy, row, `${tableCopySourceNamespace}:row:${getRowId(row)}`, copy === void 0 ? declaredVisibleCopyColumns : void 0),
9414
9443
  placement: rowCopyInMenu ? "menu" : "inline",
9415
- children: actions
9444
+ controls,
9445
+ children: scopedActions
9416
9446
  }
9417
9447
  );
9418
9448
  };
@@ -9529,6 +9559,37 @@ function MatrxDataTableCore({
9529
9559
  return next;
9530
9560
  });
9531
9561
  };
9562
+ const beginRowEdit = (row) => {
9563
+ const column = visibleColumns.find(
9564
+ (candidate) => candidate.editable && (candidate.editableIf?.(row) ?? true)
9565
+ );
9566
+ if (!column) return;
9567
+ const field = column.accessorKey ? String(column.accessorKey) : columnId(column);
9568
+ setEditRequest((current) => ({
9569
+ rowId: getRowId(row),
9570
+ field,
9571
+ nonce: (current?.nonce ?? 0) + 1
9572
+ }));
9573
+ };
9574
+ const buildRecordControls = (row) => {
9575
+ const rowId = getRowId(row);
9576
+ const pending = edits[rowId];
9577
+ return {
9578
+ closeDetail: () => setSelectedId(null),
9579
+ openDetail: () => openDetail(row),
9580
+ openWindow: () => openWindow(row),
9581
+ closeWindow,
9582
+ hasPendingEdits: Boolean(pending),
9583
+ discardPendingEdits: () => discardRowEdits(rowId),
9584
+ ...pending ? { cancelEdits: () => discardRowEdits(rowId) } : {},
9585
+ ...pending && edit?.onSave && !edit.autoSave && !saving ? {
9586
+ saveEdits: () => handleSaveEdits(rowId)
9587
+ } : {},
9588
+ ...editEnabled && visibleColumns.some(
9589
+ (column) => column.editable && (column.editableIf?.(row) ?? true)
9590
+ ) ? { beginEdit: () => beginRowEdit(row) } : {}
9591
+ };
9592
+ };
9532
9593
  const hierarchyRows = hierarchy?.rows ?? data;
9533
9594
  const hierarchyGetParentId = hierarchy?.getParentId;
9534
9595
  const hierarchyIndex = useMemo7(() => {
@@ -9700,15 +9761,18 @@ function MatrxDataTableCore({
9700
9761
  }
9701
9762
  setDraggedRowId(null);
9702
9763
  };
9703
- const handleSaveEdits = async () => {
9764
+ const handleSaveEdits = async (rowId) => {
9704
9765
  if (!edit?.onSave || changeCount === 0) return;
9705
9766
  const scope = editScopeKey;
9767
+ if (savingScopesRef.current.has(scope)) return;
9706
9768
  const draft = editsByScope[scope];
9707
9769
  if (!draft) return;
9708
- const values = draft.values;
9709
- const revisions = draft.revisions;
9770
+ const values = rowId ? draft.values[rowId] ? { [rowId]: draft.values[rowId] } : {} : draft.values;
9771
+ if (Object.keys(values).length === 0) return;
9772
+ const revisions = rowId ? draft.revisions[rowId] ? { [rowId]: draft.revisions[rowId] } : {} : draft.revisions;
9710
9773
  const rows = appendQueryKey === null ? data : draft.rows;
9711
9774
  const save = edit.onSave;
9775
+ savingScopesRef.current.add(scope);
9712
9776
  startSaving(scope);
9713
9777
  try {
9714
9778
  await Promise.resolve().then(() => save(values, rows));
@@ -9716,16 +9780,16 @@ function MatrxDataTableCore({
9716
9780
  const currentDraft = current[scope];
9717
9781
  if (!currentDraft) return current;
9718
9782
  const nextValues = {};
9719
- for (const [rowId, rowValues] of Object.entries(currentDraft.values)) {
9720
- const savedRow = values[rowId];
9721
- const savedRevisions = revisions[rowId];
9722
- const currentRevisions = currentDraft.revisions[rowId];
9783
+ for (const [rowId2, rowValues] of Object.entries(currentDraft.values)) {
9784
+ const savedRow = values[rowId2];
9785
+ const savedRevisions = revisions[rowId2];
9786
+ const currentRevisions = currentDraft.revisions[rowId2];
9723
9787
  const remaining = Object.fromEntries(
9724
9788
  Object.entries(rowValues).filter(
9725
9789
  ([field]) => !Object.hasOwn(savedRow ?? {}, field) || currentRevisions?.[field] !== savedRevisions?.[field]
9726
9790
  )
9727
9791
  );
9728
- if (Object.keys(remaining).length > 0) nextValues[rowId] = remaining;
9792
+ if (Object.keys(remaining).length > 0) nextValues[rowId2] = remaining;
9729
9793
  }
9730
9794
  return { ...current, [scope]: { ...currentDraft, values: nextValues } };
9731
9795
  });
@@ -9735,6 +9799,7 @@ function MatrxDataTableCore({
9735
9799
  `Couldn't save: ${e instanceof Error ? e.message : String(e)}`
9736
9800
  );
9737
9801
  } finally {
9802
+ savingScopesRef.current.delete(scope);
9738
9803
  finishSaving(scope);
9739
9804
  }
9740
9805
  };
@@ -9742,6 +9807,17 @@ function MatrxDataTableCore({
9742
9807
  setEdits({});
9743
9808
  edit?.onCancel?.();
9744
9809
  };
9810
+ useEffect15(() => {
9811
+ if (!host.rowContextRegistry || !contextMenu && !host.createDefaultRowContext) return;
9812
+ return host.rowContextRegistry.register(tableContextMenuInstanceId, (rowId) => {
9813
+ const row = data.find((candidate) => getRowId(candidate) === rowId);
9814
+ if (!row) return null;
9815
+ const pending = edits[rowId];
9816
+ const displayRow = applyRowEdits(row, pending);
9817
+ const controls = buildRecordControls(displayRow);
9818
+ return contextMenu?.resolveRowContext(displayRow, controls) ?? host.createDefaultRowContext?.(displayRow, controls) ?? null;
9819
+ });
9820
+ }, [buildRecordControls, contextMenu, data, getRowId, host.createDefaultRowContext, host.rowContextRegistry, tableContextMenuInstanceId]);
9745
9821
  const showActionsCol = windowEnabled || Boolean(rowActions) || showInlineRowCopy;
9746
9822
  const selectedIdSet = useMemo7(
9747
9823
  () => new Set(selection?.selectedIds ?? []),
@@ -9759,7 +9835,7 @@ function MatrxDataTableCore({
9759
9835
  () => data.filter((row) => selectedIdSet.has(getRowId(row))),
9760
9836
  [data, selectedIdSet, getRowId]
9761
9837
  );
9762
- const lastToggledIndex = useRef12(null);
9838
+ const lastToggledIndex = useRef13(null);
9763
9839
  const setSelectedIds = (next) => selection?.onSelectedIdsChange([...next]);
9764
9840
  const toggleRowSelected = (index, shiftKey) => {
9765
9841
  if (!selection) return;
@@ -9822,7 +9898,8 @@ function MatrxDataTableCore({
9822
9898
  dirty: Boolean(rowEdits && field in rowEdits),
9823
9899
  onCommit: (next) => commitCell(id, field, next),
9824
9900
  ...href === void 0 ? {} : { href },
9825
- ...col.editTrigger === void 0 ? {} : { editTrigger: col.editTrigger }
9901
+ ...col.editTrigger === void 0 ? {} : { editTrigger: col.editTrigger },
9902
+ ...editRequest?.rowId === id && editRequest.field === field ? { editRequest: editRequest.nonce } : {}
9826
9903
  }
9827
9904
  );
9828
9905
  }
@@ -9932,7 +10009,7 @@ function MatrxDataTableCore({
9932
10009
  },
9933
10010
  [columns, commitColumnState, commitColumnWidths, controlledQuery, intelligentSearchEnabled, intelligentSearchScopes, toolbar]
9934
10011
  );
9935
- return /* @__PURE__ */ jsx41(TooltipProvider, { children: /* @__PURE__ */ jsxs31(
10012
+ return /* @__PURE__ */ jsx41(TooltipProvider, { children: /* @__PURE__ */ jsx41(ContextMenuBoundary, { label: tableId ?? "Data table", children: /* @__PURE__ */ jsxs31(
9936
10013
  DndContext,
9937
10014
  {
9938
10015
  id: tableDndContextId,
@@ -10030,6 +10107,7 @@ function MatrxDataTableCore({
10030
10107
  {
10031
10108
  ref: rootRef,
10032
10109
  "data-matrx-table": true,
10110
+ "data-matrx-table-id": tableContextMenuInstanceId,
10033
10111
  "data-matrx-table-implementation": "@ai-matrx/design-system",
10034
10112
  "data-matrx-table-density": resolvedDensity,
10035
10113
  "data-url-state-table": urlState?.id,
@@ -10416,7 +10494,7 @@ function MatrxDataTableCore({
10416
10494
  const id = getRowId(row);
10417
10495
  const displayRow = applyRowEdits(row, edits[id]);
10418
10496
  const selectable = selection?.isRowSelectable?.(row) ?? Boolean(selection);
10419
- return /* @__PURE__ */ jsx41(Fragment6, { children: mobileCards(displayRow, index, {
10497
+ return /* @__PURE__ */ jsx41("div", { "data-row-id": id, className: "contents", children: mobileCards(displayRow, index, {
10420
10498
  renderCell: (columnKey) => {
10421
10499
  const column = columns.find((candidate) => columnId(candidate) === columnKey);
10422
10500
  return column ? renderRecordCell(row, column, index) : null;
@@ -10449,14 +10527,7 @@ function MatrxDataTableCore({
10449
10527
  ...copy === void 0 ? { defaultColumns: declaredVisibleCopyColumns } : {}
10450
10528
  }
10451
10529
  ) : null,
10452
- renderRowActions(displayRow, {
10453
- closeDetail: () => setSelectedId(null),
10454
- openDetail: () => openDetail(displayRow),
10455
- openWindow: () => openWindow(displayRow),
10456
- closeWindow,
10457
- hasPendingEdits: Boolean(edits[id]),
10458
- discardPendingEdits: () => discardRowEdits(id)
10459
- })
10530
+ renderRowActions(displayRow, buildRecordControls(displayRow))
10460
10531
  ]
10461
10532
  }
10462
10533
  ) : null
@@ -10852,14 +10923,7 @@ function MatrxDataTableCore({
10852
10923
  ...copy === void 0 ? { defaultColumns: declaredVisibleCopyColumns } : {}
10853
10924
  }
10854
10925
  ) : null,
10855
- renderRowActions(displayRow, {
10856
- closeDetail: () => setSelectedId(null),
10857
- openDetail: () => openDetail(displayRow),
10858
- openWindow: () => openWindow(displayRow),
10859
- closeWindow,
10860
- hasPendingEdits: Boolean(rowEdits),
10861
- discardPendingEdits: () => discardRowEdits(id)
10862
- }),
10926
+ renderRowActions(displayRow, buildRecordControls(displayRow)),
10863
10927
  windowEnabled ? /* @__PURE__ */ jsxs31(Tooltip, { children: [
10864
10928
  /* @__PURE__ */ jsx41(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsx41(
10865
10929
  Button,
@@ -11347,7 +11411,7 @@ function MatrxDataTableCore({
11347
11411
  ) : null })
11348
11412
  ]
11349
11413
  }
11350
- ) });
11414
+ ) }) });
11351
11415
  }
11352
11416
  function HierarchyDragHandle({
11353
11417
  id,