react-glide-table 2.3.1 → 2.3.2

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/README.md CHANGED
@@ -75,6 +75,7 @@ export function Products({ data }: { data: Product[] }) {
75
75
  | `className` / column `className` / `headerClassName` | Extra class hooks |
76
76
  | `labels` / `summary` / `toolbar` | Copy and slot nodes |
77
77
  | `Column.render` / `ColumnDef.cell` | Cell content custom render (prefer `update` via context) |
78
+ | `Column.copyValue` | Clipboard: `"display"` (default) / `"value"` / `"omit"` / `(ctx) => string` |
78
79
  | `Column.kind` / `cellRenderers` | Built-in or custom cell kinds (override / add via registry) |
79
80
 
80
81
  Row/cell **state** is exposed as `data-*` attributes for Tailwind variants:
@@ -240,6 +241,32 @@ Cell selection ships with clipboard shortcuts. The table parses TSV and emits st
240
241
 
241
242
  Subtree copy encodes relative tree depth as leading tabs in the TSV so paste can rebuild parent/child nesting via `payload.depths`. Depth is only inferred when the clipboard looks like subtree indentation (first row unindented, at least one later row indented). Otherwise leading empty cells are kept as real values (e.g. Excel/Sheets blank first column) and `depths` stay `0`.
242
243
 
244
+ Per-column `copyValue` controls what lands on the clipboard when a custom `render` / `kind` is present:
245
+
246
+ - (default) / `"display"` — text from the rendered cell (buttons stay empty)
247
+ - `"value"` — raw accessor / field value (e.g. a count behind a button)
248
+ - `"omit"` — drop the column from the TSV entirely (neighbors shift left; same-table paste may misalign)
249
+ - `(ctx) => string` — fully custom clipboard string
250
+
251
+ ```tsx
252
+ <ProductTable.Column
253
+ field="partCount"
254
+ copyValue="value"
255
+ render={({ value }) => <button type="button">{value}개 보기</button>}
256
+ >
257
+ Part No
258
+ </ProductTable.Column>
259
+
260
+ <ProductTable.Column
261
+ field="actions"
262
+ virtual
263
+ copyValue="omit"
264
+ render={() => <button type="button">Edit</button>}
265
+ >
266
+ Actions
267
+ </ProductTable.Column>
268
+ ```
269
+
243
270
  ```tsx
244
271
  import type { RowsPastePayload } from "react-glide-table/compound";
245
272
 
package/dist/compound.cjs CHANGED
@@ -2742,6 +2742,39 @@ function isEditablePasteTarget(target) {
2742
2742
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
2743
2743
  var import_react7 = require("react");
2744
2744
 
2745
+ // src/components/ui/table/features/cell-selection/activeCellSelectionOwner.ts
2746
+ var activeOwner = null;
2747
+ var clearByOwner = /* @__PURE__ */ new Map();
2748
+ function createCellSelectionOwner() {
2749
+ return /* @__PURE__ */ Symbol("cell-selection-owner");
2750
+ }
2751
+ function registerCellSelectionOwner(owner, clearSelection) {
2752
+ clearByOwner.set(owner, clearSelection);
2753
+ return () => {
2754
+ clearByOwner.delete(owner);
2755
+ if (activeOwner === owner) {
2756
+ activeOwner = null;
2757
+ }
2758
+ };
2759
+ }
2760
+ function claimCellSelectionOwner(owner) {
2761
+ if (activeOwner === owner) return;
2762
+ activeOwner = owner;
2763
+ for (const [id, clearSelection] of clearByOwner) {
2764
+ if (id !== owner) {
2765
+ clearSelection();
2766
+ }
2767
+ }
2768
+ }
2769
+ function isActiveCellSelectionOwner(owner) {
2770
+ return activeOwner === owner;
2771
+ }
2772
+ function releaseCellSelectionOwner(owner) {
2773
+ if (activeOwner === owner) {
2774
+ activeOwner = null;
2775
+ }
2776
+ }
2777
+
2745
2778
  // src/components/ui/table/features/cell-selection/copyData.ts
2746
2779
  var import_react6 = require("react");
2747
2780
  function isReactNodeIterable(node) {
@@ -2914,19 +2947,31 @@ function extractRenderedCopyText(node, value, cellPosition, root) {
2914
2947
  function formatCopyCellText(rowData, columnDef, columnId, visibleRow, fallbackIndex, sourceCell, cellPosition, options) {
2915
2948
  const meta = columnDef.meta;
2916
2949
  const value = sourceCell ? sourceCell.getValue() : readRowColumnValue(rowData, columnDef);
2950
+ const row = visibleRow ?? createCopyRenderRow(rowData, fallbackIndex);
2951
+ const ctx = {
2952
+ value,
2953
+ row,
2954
+ index: row.index,
2955
+ columnId,
2956
+ cellProps: meta?.cellProps,
2957
+ update: () => {
2958
+ }
2959
+ };
2960
+ const copyValue = meta?.copyValue;
2961
+ if (typeof copyValue === "function") {
2962
+ try {
2963
+ return sanitizeClipboardCell(copyValue(ctx));
2964
+ } catch {
2965
+ return formatCellValue(value);
2966
+ }
2967
+ }
2968
+ if (copyValue === "value") {
2969
+ return formatCellValue(value);
2970
+ }
2917
2971
  const cellRender = meta?.cellRender;
2918
2972
  if (typeof cellRender === "function") {
2919
2973
  try {
2920
- const row = visibleRow ?? createCopyRenderRow(rowData, fallbackIndex);
2921
- const node = cellRender({
2922
- value,
2923
- row,
2924
- index: row.index,
2925
- columnId,
2926
- cellProps: meta?.cellProps,
2927
- update: () => {
2928
- }
2929
- });
2974
+ const node = cellRender(ctx);
2930
2975
  return extractRenderedCopyText(node, value, cellPosition, options?.root);
2931
2976
  } catch {
2932
2977
  return formatCellValue(value);
@@ -2934,16 +2979,6 @@ function formatCopyCellText(rowData, columnDef, columnId, visibleRow, fallbackIn
2934
2979
  }
2935
2980
  if (options?.registry && meta?.kind && isPrimitiveCopyValue(value)) {
2936
2981
  try {
2937
- const row = visibleRow ?? createCopyRenderRow(rowData, fallbackIndex);
2938
- const ctx = {
2939
- value,
2940
- row,
2941
- index: row.index,
2942
- columnId,
2943
- cellProps: meta.cellProps,
2944
- update: () => {
2945
- }
2946
- };
2947
2982
  const renderer = resolveCellRenderer(options.registry, meta.kind, ctx);
2948
2983
  if (renderer) {
2949
2984
  const node = renderer.render(ctx);
@@ -3050,11 +3085,16 @@ function serializeCopyRowsToTSV(copyRows, visibleRows, bounds, depths, options)
3050
3085
  const resolvedDepths = depths && depths.length === copyRows.length ? depths : copyRows.map((row) => getRowDepth(row));
3051
3086
  const minDepth = Math.min(...resolvedDepths);
3052
3087
  const visibleRowByOriginal = buildVisibleRowLookup(visibleRows);
3088
+ const copyableColumns = columnCells.flatMap((templateCell, colOffset) => {
3089
+ const meta = templateCell.column.columnDef.meta;
3090
+ if (meta?.copyValue === "omit") return [];
3091
+ return [{ templateCell, colOffset }];
3092
+ });
3053
3093
  return copyRows.map((rowData, index) => {
3054
3094
  const relativeDepth = Math.max(0, (resolvedDepths[index] ?? 0) - minDepth);
3055
3095
  const visibleRow = visibleRowByOriginal.get(rowData);
3056
3096
  const matchingCells = visibleRow?.getVisibleCells().slice(startCol, endCol + 1);
3057
- const line = columnCells.map((templateCell, colOffset) => {
3097
+ const line = copyableColumns.map(({ templateCell, colOffset }) => {
3058
3098
  const sourceCell = matchingCells?.[colOffset];
3059
3099
  const column = sourceCell?.column ?? templateCell.column;
3060
3100
  return formatCopyCellText(
@@ -3163,6 +3203,7 @@ function useCellSelection({
3163
3203
  cellRendererRegistry,
3164
3204
  rootRef
3165
3205
  }) {
3206
+ const ownerRef = (0, import_react7.useRef)(createCellSelectionOwner());
3166
3207
  const [dragState, setDragState] = (0, import_react7.useState)(INITIAL_DRAG_STATE);
3167
3208
  const pendingPasteModeRef = (0, import_react7.useRef)(null);
3168
3209
  const dragStateRef = (0, import_react7.useRef)(dragState);
@@ -3174,6 +3215,7 @@ function useCellSelection({
3174
3215
  const handleCellMouseDown = (0, import_react7.useCallback)(
3175
3216
  (rowIndex, colIndex, options) => {
3176
3217
  if (!enabled) return;
3218
+ claimCellSelectionOwner(ownerRef.current);
3177
3219
  setDragState((prev) => {
3178
3220
  if (options?.shiftKey && prev.start) {
3179
3221
  return {
@@ -3215,6 +3257,7 @@ function useCellSelection({
3215
3257
  const handleFillHandleMouseDown = (0, import_react7.useCallback)(
3216
3258
  (rowIndex, colIndex) => {
3217
3259
  if (!enabled) return;
3260
+ claimCellSelectionOwner(ownerRef.current);
3218
3261
  setDragState((prev) => {
3219
3262
  const bounds = getCellSelectionBounds(prev.start, prev.end);
3220
3263
  if (!bounds) return prev;
@@ -3234,6 +3277,7 @@ function useCellSelection({
3234
3277
  if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
3235
3278
  return;
3236
3279
  }
3280
+ releaseCellSelectionOwner(ownerRef.current);
3237
3281
  dragStateRef.current = INITIAL_DRAG_STATE;
3238
3282
  setDragState(INITIAL_DRAG_STATE);
3239
3283
  }, []);
@@ -3242,9 +3286,13 @@ function useCellSelection({
3242
3286
  clearSelection();
3243
3287
  }
3244
3288
  }, [clearSelection, enabled]);
3289
+ (0, import_react7.useEffect)(() => {
3290
+ return registerCellSelectionOwner(ownerRef.current, clearSelection);
3291
+ }, [clearSelection]);
3245
3292
  (0, import_react7.useEffect)(() => {
3246
3293
  if (!enabled) return;
3247
3294
  const handleKeyDown = (e) => {
3295
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3248
3296
  if (e.ctrlKey || e.metaKey || e.altKey) return;
3249
3297
  if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
3250
3298
  return;
@@ -3310,6 +3358,7 @@ function useCellSelection({
3310
3358
  (0, import_react7.useEffect)(() => {
3311
3359
  if (!enabled) return;
3312
3360
  const handleKeyDown = (e) => {
3361
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3313
3362
  if (!activeSelectionBounds) return;
3314
3363
  if (!(e.ctrlKey || e.metaKey)) return;
3315
3364
  if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
@@ -3346,6 +3395,7 @@ function useCellSelection({
3346
3395
  const pasteHandledRef = { current: false };
3347
3396
  const ignoreNextPasteRef = { current: false };
3348
3397
  const handleKeyDown = (e) => {
3398
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3349
3399
  if (!activeSelectionBounds) return;
3350
3400
  if (!(e.ctrlKey || e.metaKey)) return;
3351
3401
  if (e.key.toLowerCase() !== "v") return;
@@ -3366,6 +3416,7 @@ function useCellSelection({
3366
3416
  const text = await navigator.clipboard.readText();
3367
3417
  if (pasteHandledRef.current) return;
3368
3418
  if (pendingPasteModeRef.current !== mode) return;
3419
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3369
3420
  if (!text) return;
3370
3421
  pasteHandledRef.current = true;
3371
3422
  emitRowsPaste(text, mode);
@@ -3375,6 +3426,7 @@ function useCellSelection({
3375
3426
  })();
3376
3427
  };
3377
3428
  const handlePaste = (e) => {
3429
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3378
3430
  if (!activeSelectionBounds) return;
3379
3431
  if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
3380
3432
  return;
@@ -3460,6 +3512,25 @@ function useCellSelection({
3460
3512
  };
3461
3513
  }
3462
3514
 
3515
+ // src/components/ui/table/features/selection-dismiss/isOutsideDismissTarget.ts
3516
+ var OVERLAY_DISMISS_IGNORE_SELECTOR = [
3517
+ '[role="dialog"]',
3518
+ '[role="alertdialog"]',
3519
+ '[role="menu"]',
3520
+ '[role="listbox"]',
3521
+ '[role="tooltip"]',
3522
+ '[aria-modal="true"]',
3523
+ "[data-radix-portal]",
3524
+ "[data-radix-popper-content-wrapper]",
3525
+ "[data-floating-ui-portal]",
3526
+ "[data-table-ignore-outside-dismiss]"
3527
+ ].join(",");
3528
+ function isOverlayDismissIgnoreTarget(target) {
3529
+ const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
3530
+ if (!element) return false;
3531
+ return element.closest(OVERLAY_DISMISS_IGNORE_SELECTOR) !== null;
3532
+ }
3533
+
3463
3534
  // src/components/ui/table/features/inline-search/useInlineSearch.ts
3464
3535
  var import_react8 = require("react");
3465
3536
  var EMPTY_MATCH_KEYS = /* @__PURE__ */ new Set();
@@ -4084,19 +4155,14 @@ function useGlideTable(options) {
4084
4155
  if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
4085
4156
  return;
4086
4157
  }
4087
- clearAllSelections();
4088
- };
4089
- const handleMouseDown = (event) => {
4090
- const root = rootRef.current;
4091
- if (!root) return;
4092
- if (event.target instanceof Node && root.contains(event.target)) return;
4158
+ if (isOverlayDismissIgnoreTarget(event.target) || isOverlayDismissIgnoreTarget(document.activeElement)) {
4159
+ return;
4160
+ }
4093
4161
  clearAllSelections();
4094
4162
  };
4095
4163
  window.addEventListener("keydown", handleKeyDown);
4096
- document.addEventListener("mousedown", handleMouseDown);
4097
4164
  return () => {
4098
4165
  window.removeEventListener("keydown", handleKeyDown);
4099
- document.removeEventListener("mousedown", handleMouseDown);
4100
4166
  };
4101
4167
  }, [clearCellSelection, clearRowSelection]);
4102
4168
  const {
@@ -4971,7 +5037,8 @@ function buildColumnDef(props, sort, onSort) {
4971
5037
  cellProps,
4972
5038
  className,
4973
5039
  headerClassName,
4974
- render
5040
+ render,
5041
+ copyValue
4975
5042
  } = props;
4976
5043
  return {
4977
5044
  id: field,
@@ -5005,6 +5072,7 @@ function buildColumnDef(props, sort, onSort) {
5005
5072
  kind,
5006
5073
  cellProps,
5007
5074
  cellRender: render,
5075
+ copyValue,
5008
5076
  frozen,
5009
5077
  reorderable,
5010
5078
  width,
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ReactElement } from 'react';
3
- import { l as DataTableProps, r as TableColumnProps, T as TableColumnGroupProps, s as TableProps } from './types-DdeVn-9s.cjs';
4
- export { B as BuiltinCellKind, C as CellKind, a as CellRenderContext, b as CellRenderFn, c as CellRenderer, f as ColumnFreezeMeta, h as ColumnFreezeSide, i as DataTableClassNames, k as DataTableLabels, m as DataTableScrollSlotProps, n as DataTableSlots, P as PasteMode, R as RowSelectionMode, o as RowsPastePayload, p as SearchResultItem } from './types-DdeVn-9s.cjs';
3
+ import { m as DataTableProps, s as TableColumnProps, T as TableColumnGroupProps, t as TableProps } from './types-hf2ruVdu.cjs';
4
+ export { B as BuiltinCellKind, C as CellKind, a as CellRenderContext, b as CellRenderFn, c as CellRenderer, d as ColumnCopyValue, g as ColumnFreezeMeta, i as ColumnFreezeSide, j as DataTableClassNames, l as DataTableLabels, n as DataTableScrollSlotProps, o as DataTableSlots, P as PasteMode, R as RowSelectionMode, p as RowsPastePayload, q as SearchResultItem } from './types-hf2ruVdu.cjs';
5
5
  export { ColumnDef, ColumnOrderState, ColumnResizeMode, ColumnSizingState, RowSelectionState } from '@tanstack/react-table';
6
6
 
7
7
  /**
@@ -1,7 +1,7 @@
1
1
  import * as react from 'react';
2
2
  import { ReactNode, ReactElement } from 'react';
3
- import { l as DataTableProps, r as TableColumnProps, T as TableColumnGroupProps, s as TableProps } from './types-DdeVn-9s.js';
4
- export { B as BuiltinCellKind, C as CellKind, a as CellRenderContext, b as CellRenderFn, c as CellRenderer, f as ColumnFreezeMeta, h as ColumnFreezeSide, i as DataTableClassNames, k as DataTableLabels, m as DataTableScrollSlotProps, n as DataTableSlots, P as PasteMode, R as RowSelectionMode, o as RowsPastePayload, p as SearchResultItem } from './types-DdeVn-9s.js';
3
+ import { m as DataTableProps, s as TableColumnProps, T as TableColumnGroupProps, t as TableProps } from './types-hf2ruVdu.js';
4
+ export { B as BuiltinCellKind, C as CellKind, a as CellRenderContext, b as CellRenderFn, c as CellRenderer, d as ColumnCopyValue, g as ColumnFreezeMeta, i as ColumnFreezeSide, j as DataTableClassNames, l as DataTableLabels, n as DataTableScrollSlotProps, o as DataTableSlots, P as PasteMode, R as RowSelectionMode, p as RowsPastePayload, q as SearchResultItem } from './types-hf2ruVdu.js';
5
5
  export { ColumnDef, ColumnOrderState, ColumnResizeMode, ColumnSizingState, RowSelectionState } from '@tanstack/react-table';
6
6
 
7
7
  /**
package/dist/compound.js CHANGED
@@ -2730,6 +2730,39 @@ function isEditablePasteTarget(target) {
2730
2730
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
2731
2731
  import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef5, useState as useState3 } from "react";
2732
2732
 
2733
+ // src/components/ui/table/features/cell-selection/activeCellSelectionOwner.ts
2734
+ var activeOwner = null;
2735
+ var clearByOwner = /* @__PURE__ */ new Map();
2736
+ function createCellSelectionOwner() {
2737
+ return /* @__PURE__ */ Symbol("cell-selection-owner");
2738
+ }
2739
+ function registerCellSelectionOwner(owner, clearSelection) {
2740
+ clearByOwner.set(owner, clearSelection);
2741
+ return () => {
2742
+ clearByOwner.delete(owner);
2743
+ if (activeOwner === owner) {
2744
+ activeOwner = null;
2745
+ }
2746
+ };
2747
+ }
2748
+ function claimCellSelectionOwner(owner) {
2749
+ if (activeOwner === owner) return;
2750
+ activeOwner = owner;
2751
+ for (const [id, clearSelection] of clearByOwner) {
2752
+ if (id !== owner) {
2753
+ clearSelection();
2754
+ }
2755
+ }
2756
+ }
2757
+ function isActiveCellSelectionOwner(owner) {
2758
+ return activeOwner === owner;
2759
+ }
2760
+ function releaseCellSelectionOwner(owner) {
2761
+ if (activeOwner === owner) {
2762
+ activeOwner = null;
2763
+ }
2764
+ }
2765
+
2733
2766
  // src/components/ui/table/features/cell-selection/copyData.ts
2734
2767
  import { isValidElement } from "react";
2735
2768
  function isReactNodeIterable(node) {
@@ -2902,19 +2935,31 @@ function extractRenderedCopyText(node, value, cellPosition, root) {
2902
2935
  function formatCopyCellText(rowData, columnDef, columnId, visibleRow, fallbackIndex, sourceCell, cellPosition, options) {
2903
2936
  const meta = columnDef.meta;
2904
2937
  const value = sourceCell ? sourceCell.getValue() : readRowColumnValue(rowData, columnDef);
2938
+ const row = visibleRow ?? createCopyRenderRow(rowData, fallbackIndex);
2939
+ const ctx = {
2940
+ value,
2941
+ row,
2942
+ index: row.index,
2943
+ columnId,
2944
+ cellProps: meta?.cellProps,
2945
+ update: () => {
2946
+ }
2947
+ };
2948
+ const copyValue = meta?.copyValue;
2949
+ if (typeof copyValue === "function") {
2950
+ try {
2951
+ return sanitizeClipboardCell(copyValue(ctx));
2952
+ } catch {
2953
+ return formatCellValue(value);
2954
+ }
2955
+ }
2956
+ if (copyValue === "value") {
2957
+ return formatCellValue(value);
2958
+ }
2905
2959
  const cellRender = meta?.cellRender;
2906
2960
  if (typeof cellRender === "function") {
2907
2961
  try {
2908
- const row = visibleRow ?? createCopyRenderRow(rowData, fallbackIndex);
2909
- const node = cellRender({
2910
- value,
2911
- row,
2912
- index: row.index,
2913
- columnId,
2914
- cellProps: meta?.cellProps,
2915
- update: () => {
2916
- }
2917
- });
2962
+ const node = cellRender(ctx);
2918
2963
  return extractRenderedCopyText(node, value, cellPosition, options?.root);
2919
2964
  } catch {
2920
2965
  return formatCellValue(value);
@@ -2922,16 +2967,6 @@ function formatCopyCellText(rowData, columnDef, columnId, visibleRow, fallbackIn
2922
2967
  }
2923
2968
  if (options?.registry && meta?.kind && isPrimitiveCopyValue(value)) {
2924
2969
  try {
2925
- const row = visibleRow ?? createCopyRenderRow(rowData, fallbackIndex);
2926
- const ctx = {
2927
- value,
2928
- row,
2929
- index: row.index,
2930
- columnId,
2931
- cellProps: meta.cellProps,
2932
- update: () => {
2933
- }
2934
- };
2935
2970
  const renderer = resolveCellRenderer(options.registry, meta.kind, ctx);
2936
2971
  if (renderer) {
2937
2972
  const node = renderer.render(ctx);
@@ -3038,11 +3073,16 @@ function serializeCopyRowsToTSV(copyRows, visibleRows, bounds, depths, options)
3038
3073
  const resolvedDepths = depths && depths.length === copyRows.length ? depths : copyRows.map((row) => getRowDepth(row));
3039
3074
  const minDepth = Math.min(...resolvedDepths);
3040
3075
  const visibleRowByOriginal = buildVisibleRowLookup(visibleRows);
3076
+ const copyableColumns = columnCells.flatMap((templateCell, colOffset) => {
3077
+ const meta = templateCell.column.columnDef.meta;
3078
+ if (meta?.copyValue === "omit") return [];
3079
+ return [{ templateCell, colOffset }];
3080
+ });
3041
3081
  return copyRows.map((rowData, index) => {
3042
3082
  const relativeDepth = Math.max(0, (resolvedDepths[index] ?? 0) - minDepth);
3043
3083
  const visibleRow = visibleRowByOriginal.get(rowData);
3044
3084
  const matchingCells = visibleRow?.getVisibleCells().slice(startCol, endCol + 1);
3045
- const line = columnCells.map((templateCell, colOffset) => {
3085
+ const line = copyableColumns.map(({ templateCell, colOffset }) => {
3046
3086
  const sourceCell = matchingCells?.[colOffset];
3047
3087
  const column = sourceCell?.column ?? templateCell.column;
3048
3088
  return formatCopyCellText(
@@ -3151,6 +3191,7 @@ function useCellSelection({
3151
3191
  cellRendererRegistry,
3152
3192
  rootRef
3153
3193
  }) {
3194
+ const ownerRef = useRef5(createCellSelectionOwner());
3154
3195
  const [dragState, setDragState] = useState3(INITIAL_DRAG_STATE);
3155
3196
  const pendingPasteModeRef = useRef5(null);
3156
3197
  const dragStateRef = useRef5(dragState);
@@ -3162,6 +3203,7 @@ function useCellSelection({
3162
3203
  const handleCellMouseDown = useCallback3(
3163
3204
  (rowIndex, colIndex, options) => {
3164
3205
  if (!enabled) return;
3206
+ claimCellSelectionOwner(ownerRef.current);
3165
3207
  setDragState((prev) => {
3166
3208
  if (options?.shiftKey && prev.start) {
3167
3209
  return {
@@ -3203,6 +3245,7 @@ function useCellSelection({
3203
3245
  const handleFillHandleMouseDown = useCallback3(
3204
3246
  (rowIndex, colIndex) => {
3205
3247
  if (!enabled) return;
3248
+ claimCellSelectionOwner(ownerRef.current);
3206
3249
  setDragState((prev) => {
3207
3250
  const bounds = getCellSelectionBounds(prev.start, prev.end);
3208
3251
  if (!bounds) return prev;
@@ -3222,6 +3265,7 @@ function useCellSelection({
3222
3265
  if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
3223
3266
  return;
3224
3267
  }
3268
+ releaseCellSelectionOwner(ownerRef.current);
3225
3269
  dragStateRef.current = INITIAL_DRAG_STATE;
3226
3270
  setDragState(INITIAL_DRAG_STATE);
3227
3271
  }, []);
@@ -3230,9 +3274,13 @@ function useCellSelection({
3230
3274
  clearSelection();
3231
3275
  }
3232
3276
  }, [clearSelection, enabled]);
3277
+ useEffect5(() => {
3278
+ return registerCellSelectionOwner(ownerRef.current, clearSelection);
3279
+ }, [clearSelection]);
3233
3280
  useEffect5(() => {
3234
3281
  if (!enabled) return;
3235
3282
  const handleKeyDown = (e) => {
3283
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3236
3284
  if (e.ctrlKey || e.metaKey || e.altKey) return;
3237
3285
  if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
3238
3286
  return;
@@ -3298,6 +3346,7 @@ function useCellSelection({
3298
3346
  useEffect5(() => {
3299
3347
  if (!enabled) return;
3300
3348
  const handleKeyDown = (e) => {
3349
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3301
3350
  if (!activeSelectionBounds) return;
3302
3351
  if (!(e.ctrlKey || e.metaKey)) return;
3303
3352
  if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
@@ -3334,6 +3383,7 @@ function useCellSelection({
3334
3383
  const pasteHandledRef = { current: false };
3335
3384
  const ignoreNextPasteRef = { current: false };
3336
3385
  const handleKeyDown = (e) => {
3386
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3337
3387
  if (!activeSelectionBounds) return;
3338
3388
  if (!(e.ctrlKey || e.metaKey)) return;
3339
3389
  if (e.key.toLowerCase() !== "v") return;
@@ -3354,6 +3404,7 @@ function useCellSelection({
3354
3404
  const text = await navigator.clipboard.readText();
3355
3405
  if (pasteHandledRef.current) return;
3356
3406
  if (pendingPasteModeRef.current !== mode) return;
3407
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3357
3408
  if (!text) return;
3358
3409
  pasteHandledRef.current = true;
3359
3410
  emitRowsPaste(text, mode);
@@ -3363,6 +3414,7 @@ function useCellSelection({
3363
3414
  })();
3364
3415
  };
3365
3416
  const handlePaste = (e) => {
3417
+ if (!isActiveCellSelectionOwner(ownerRef.current)) return;
3366
3418
  if (!activeSelectionBounds) return;
3367
3419
  if (isEditablePasteTarget(e.target) || isEditablePasteTarget(document.activeElement)) {
3368
3420
  return;
@@ -3448,6 +3500,25 @@ function useCellSelection({
3448
3500
  };
3449
3501
  }
3450
3502
 
3503
+ // src/components/ui/table/features/selection-dismiss/isOutsideDismissTarget.ts
3504
+ var OVERLAY_DISMISS_IGNORE_SELECTOR = [
3505
+ '[role="dialog"]',
3506
+ '[role="alertdialog"]',
3507
+ '[role="menu"]',
3508
+ '[role="listbox"]',
3509
+ '[role="tooltip"]',
3510
+ '[aria-modal="true"]',
3511
+ "[data-radix-portal]",
3512
+ "[data-radix-popper-content-wrapper]",
3513
+ "[data-floating-ui-portal]",
3514
+ "[data-table-ignore-outside-dismiss]"
3515
+ ].join(",");
3516
+ function isOverlayDismissIgnoreTarget(target) {
3517
+ const element = target instanceof Element ? target : target instanceof Node ? target.parentElement : null;
3518
+ if (!element) return false;
3519
+ return element.closest(OVERLAY_DISMISS_IGNORE_SELECTOR) !== null;
3520
+ }
3521
+
3451
3522
  // src/components/ui/table/features/inline-search/useInlineSearch.ts
3452
3523
  import {
3453
3524
  useCallback as useCallback4,
@@ -4079,19 +4150,14 @@ function useGlideTable(options) {
4079
4150
  if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
4080
4151
  return;
4081
4152
  }
4082
- clearAllSelections();
4083
- };
4084
- const handleMouseDown = (event) => {
4085
- const root = rootRef.current;
4086
- if (!root) return;
4087
- if (event.target instanceof Node && root.contains(event.target)) return;
4153
+ if (isOverlayDismissIgnoreTarget(event.target) || isOverlayDismissIgnoreTarget(document.activeElement)) {
4154
+ return;
4155
+ }
4088
4156
  clearAllSelections();
4089
4157
  };
4090
4158
  window.addEventListener("keydown", handleKeyDown);
4091
- document.addEventListener("mousedown", handleMouseDown);
4092
4159
  return () => {
4093
4160
  window.removeEventListener("keydown", handleKeyDown);
4094
- document.removeEventListener("mousedown", handleMouseDown);
4095
4161
  };
4096
4162
  }, [clearCellSelection, clearRowSelection]);
4097
4163
  const {
@@ -4966,7 +5032,8 @@ function buildColumnDef(props, sort, onSort) {
4966
5032
  cellProps,
4967
5033
  className,
4968
5034
  headerClassName,
4969
- render
5035
+ render,
5036
+ copyValue
4970
5037
  } = props;
4971
5038
  return {
4972
5039
  id: field,
@@ -5000,6 +5067,7 @@ function buildColumnDef(props, sort, onSort) {
5000
5067
  kind,
5001
5068
  cellProps,
5002
5069
  cellRender: render,
5070
+ copyValue,
5003
5071
  frozen,
5004
5072
  reorderable,
5005
5073
  width,