react-glide-table 2.3.0 → 2.3.1

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/dist/compound.cjs CHANGED
@@ -2658,6 +2658,87 @@ function formatDefaultCellValue(value) {
2658
2658
  return String(value);
2659
2659
  }
2660
2660
 
2661
+ // src/components/ui/table/features/cell-selection/pasteData.ts
2662
+ function countLeadingEmptyCells(cells) {
2663
+ let depth = 0;
2664
+ while (depth < cells.length && cells[depth] === "") {
2665
+ depth += 1;
2666
+ }
2667
+ return depth;
2668
+ }
2669
+ function looksLikeSubtreeIndentation(leadingEmptyCounts) {
2670
+ if (leadingEmptyCounts.length === 0) return false;
2671
+ const firstDepth = leadingEmptyCounts[0] ?? 0;
2672
+ if (firstDepth !== 0) return false;
2673
+ return leadingEmptyCounts.some((depth) => depth > 0);
2674
+ }
2675
+ function parseClipboardTSVWithDepths(text) {
2676
+ if (!text) return { values: [], depths: [] };
2677
+ const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2678
+ const withoutTrailing = normalized.replace(/\n+$/, "");
2679
+ if (!withoutTrailing) return { values: [], depths: [] };
2680
+ const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
2681
+ const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
2682
+ const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
2683
+ const values = [];
2684
+ const depths = [];
2685
+ for (let index = 0; index < rows.length; index += 1) {
2686
+ const cells = rows[index] ?? [];
2687
+ const depth = leadingEmptyCounts[index] ?? 0;
2688
+ if (treatAsDepth) {
2689
+ values.push(cells.slice(depth));
2690
+ depths.push(depth);
2691
+ } else {
2692
+ values.push(cells);
2693
+ depths.push(0);
2694
+ }
2695
+ }
2696
+ return { values, depths };
2697
+ }
2698
+ function resolvePasteColumnIds(rows, startCol, width) {
2699
+ if (width <= 0) return [];
2700
+ const cells = rows[0]?.getVisibleCells() ?? [];
2701
+ const columnIds = [];
2702
+ for (let offset = 0; offset < width; offset += 1) {
2703
+ const cell = cells[startCol + offset];
2704
+ if (!cell) break;
2705
+ columnIds.push(cell.column.id);
2706
+ }
2707
+ return columnIds;
2708
+ }
2709
+ function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
2710
+ const { values, depths } = parseClipboardTSVWithDepths(text);
2711
+ if (values.length === 0) return null;
2712
+ const width = Math.max(...values.map((row) => row.length), 0);
2713
+ if (width === 0) return null;
2714
+ const columnIds = resolvePasteColumnIds(rows, startCol, width);
2715
+ if (columnIds.length === 0) return null;
2716
+ const rowIds = [];
2717
+ for (let offset = 0; offset < values.length; offset += 1) {
2718
+ const row = rows[startRow + offset];
2719
+ if (!row) break;
2720
+ rowIds.push(row.id);
2721
+ }
2722
+ const anchorRow = rows[endRow] ?? rows[startRow];
2723
+ return {
2724
+ mode,
2725
+ startRow,
2726
+ startCol,
2727
+ endRow,
2728
+ rowIds,
2729
+ anchorRowId: anchorRow?.id ?? "",
2730
+ columnIds,
2731
+ values,
2732
+ depths
2733
+ };
2734
+ }
2735
+ function isEditablePasteTarget(target) {
2736
+ if (!(target instanceof HTMLElement)) return false;
2737
+ const tag = target.tagName;
2738
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
2739
+ return Boolean(target.isContentEditable);
2740
+ }
2741
+
2661
2742
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
2662
2743
  var import_react7 = require("react");
2663
2744
 
@@ -3067,87 +3148,6 @@ function hasFillExtension(sourceBounds, fillBounds) {
3067
3148
  return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
3068
3149
  }
3069
3150
 
3070
- // src/components/ui/table/features/cell-selection/pasteData.ts
3071
- function countLeadingEmptyCells(cells) {
3072
- let depth = 0;
3073
- while (depth < cells.length && cells[depth] === "") {
3074
- depth += 1;
3075
- }
3076
- return depth;
3077
- }
3078
- function looksLikeSubtreeIndentation(leadingEmptyCounts) {
3079
- if (leadingEmptyCounts.length === 0) return false;
3080
- const firstDepth = leadingEmptyCounts[0] ?? 0;
3081
- if (firstDepth !== 0) return false;
3082
- return leadingEmptyCounts.some((depth) => depth > 0);
3083
- }
3084
- function parseClipboardTSVWithDepths(text) {
3085
- if (!text) return { values: [], depths: [] };
3086
- const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
3087
- const withoutTrailing = normalized.replace(/\n+$/, "");
3088
- if (!withoutTrailing) return { values: [], depths: [] };
3089
- const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
3090
- const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
3091
- const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
3092
- const values = [];
3093
- const depths = [];
3094
- for (let index = 0; index < rows.length; index += 1) {
3095
- const cells = rows[index] ?? [];
3096
- const depth = leadingEmptyCounts[index] ?? 0;
3097
- if (treatAsDepth) {
3098
- values.push(cells.slice(depth));
3099
- depths.push(depth);
3100
- } else {
3101
- values.push(cells);
3102
- depths.push(0);
3103
- }
3104
- }
3105
- return { values, depths };
3106
- }
3107
- function resolvePasteColumnIds(rows, startCol, width) {
3108
- if (width <= 0) return [];
3109
- const cells = rows[0]?.getVisibleCells() ?? [];
3110
- const columnIds = [];
3111
- for (let offset = 0; offset < width; offset += 1) {
3112
- const cell = cells[startCol + offset];
3113
- if (!cell) break;
3114
- columnIds.push(cell.column.id);
3115
- }
3116
- return columnIds;
3117
- }
3118
- function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
3119
- const { values, depths } = parseClipboardTSVWithDepths(text);
3120
- if (values.length === 0) return null;
3121
- const width = Math.max(...values.map((row) => row.length), 0);
3122
- if (width === 0) return null;
3123
- const columnIds = resolvePasteColumnIds(rows, startCol, width);
3124
- if (columnIds.length === 0) return null;
3125
- const rowIds = [];
3126
- for (let offset = 0; offset < values.length; offset += 1) {
3127
- const row = rows[startRow + offset];
3128
- if (!row) break;
3129
- rowIds.push(row.id);
3130
- }
3131
- const anchorRow = rows[endRow] ?? rows[startRow];
3132
- return {
3133
- mode,
3134
- startRow,
3135
- startCol,
3136
- endRow,
3137
- rowIds,
3138
- anchorRowId: anchorRow?.id ?? "",
3139
- columnIds,
3140
- values,
3141
- depths
3142
- };
3143
- }
3144
- function isEditablePasteTarget(target) {
3145
- if (!(target instanceof HTMLElement)) return false;
3146
- const tag = target.tagName;
3147
- if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
3148
- return Boolean(target.isContentEditable);
3149
- }
3150
-
3151
3151
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
3152
3152
  function useCellSelection({
3153
3153
  data,
@@ -3229,11 +3229,19 @@ function useCellSelection({
3229
3229
  },
3230
3230
  [enabled]
3231
3231
  );
3232
+ const clearSelection = (0, import_react7.useCallback)(() => {
3233
+ const prev = dragStateRef.current;
3234
+ if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
3235
+ return;
3236
+ }
3237
+ dragStateRef.current = INITIAL_DRAG_STATE;
3238
+ setDragState(INITIAL_DRAG_STATE);
3239
+ }, []);
3232
3240
  (0, import_react7.useEffect)(() => {
3233
3241
  if (!enabled) {
3234
- setDragState(INITIAL_DRAG_STATE);
3242
+ clearSelection();
3235
3243
  }
3236
- }, [enabled]);
3244
+ }, [clearSelection, enabled]);
3237
3245
  (0, import_react7.useEffect)(() => {
3238
3246
  if (!enabled) return;
3239
3247
  const handleKeyDown = (e) => {
@@ -3447,6 +3455,7 @@ function useCellSelection({
3447
3455
  handleCellMouseDown,
3448
3456
  handleCellMouseEnter,
3449
3457
  handleFillHandleMouseDown,
3458
+ clearSelection,
3450
3459
  copySelection
3451
3460
  };
3452
3461
  }
@@ -4038,6 +4047,7 @@ function useGlideTable(options) {
4038
4047
  handleCellMouseDown,
4039
4048
  handleCellMouseEnter,
4040
4049
  handleFillHandleMouseDown,
4050
+ clearSelection: clearCellSelection,
4041
4051
  copySelection
4042
4052
  } = useCellSelection({
4043
4053
  data: tableData,
@@ -4053,6 +4063,42 @@ function useGlideTable(options) {
4053
4063
  cellRendererRegistry,
4054
4064
  rootRef
4055
4065
  });
4066
+ const clearRowSelection = (0, import_react9.useCallback)(() => {
4067
+ if (rowSelectionMode === "none") return;
4068
+ const hasSelection = Object.values(rowSelection).some(Boolean);
4069
+ if (!hasSelection) return;
4070
+ if (onRowSelectionChange) {
4071
+ onRowSelectionChange(() => ({}));
4072
+ return;
4073
+ }
4074
+ setInternalRowSelection({});
4075
+ }, [onRowSelectionChange, rowSelection, rowSelectionMode]);
4076
+ (0, import_react9.useEffect)(() => {
4077
+ const clearAllSelections = () => {
4078
+ clearCellSelection();
4079
+ clearRowSelection();
4080
+ };
4081
+ const handleKeyDown = (event) => {
4082
+ if (event.key !== "Escape") return;
4083
+ if (event.defaultPrevented) return;
4084
+ if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
4085
+ return;
4086
+ }
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;
4093
+ clearAllSelections();
4094
+ };
4095
+ window.addEventListener("keydown", handleKeyDown);
4096
+ document.addEventListener("mousedown", handleMouseDown);
4097
+ return () => {
4098
+ window.removeEventListener("keydown", handleKeyDown);
4099
+ document.removeEventListener("mousedown", handleMouseDown);
4100
+ };
4101
+ }, [clearCellSelection, clearRowSelection]);
4056
4102
  const {
4057
4103
  editingCell,
4058
4104
  draftValue,
package/dist/compound.js CHANGED
@@ -2646,6 +2646,87 @@ function formatDefaultCellValue(value) {
2646
2646
  return String(value);
2647
2647
  }
2648
2648
 
2649
+ // src/components/ui/table/features/cell-selection/pasteData.ts
2650
+ function countLeadingEmptyCells(cells) {
2651
+ let depth = 0;
2652
+ while (depth < cells.length && cells[depth] === "") {
2653
+ depth += 1;
2654
+ }
2655
+ return depth;
2656
+ }
2657
+ function looksLikeSubtreeIndentation(leadingEmptyCounts) {
2658
+ if (leadingEmptyCounts.length === 0) return false;
2659
+ const firstDepth = leadingEmptyCounts[0] ?? 0;
2660
+ if (firstDepth !== 0) return false;
2661
+ return leadingEmptyCounts.some((depth) => depth > 0);
2662
+ }
2663
+ function parseClipboardTSVWithDepths(text) {
2664
+ if (!text) return { values: [], depths: [] };
2665
+ const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
2666
+ const withoutTrailing = normalized.replace(/\n+$/, "");
2667
+ if (!withoutTrailing) return { values: [], depths: [] };
2668
+ const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
2669
+ const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
2670
+ const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
2671
+ const values = [];
2672
+ const depths = [];
2673
+ for (let index = 0; index < rows.length; index += 1) {
2674
+ const cells = rows[index] ?? [];
2675
+ const depth = leadingEmptyCounts[index] ?? 0;
2676
+ if (treatAsDepth) {
2677
+ values.push(cells.slice(depth));
2678
+ depths.push(depth);
2679
+ } else {
2680
+ values.push(cells);
2681
+ depths.push(0);
2682
+ }
2683
+ }
2684
+ return { values, depths };
2685
+ }
2686
+ function resolvePasteColumnIds(rows, startCol, width) {
2687
+ if (width <= 0) return [];
2688
+ const cells = rows[0]?.getVisibleCells() ?? [];
2689
+ const columnIds = [];
2690
+ for (let offset = 0; offset < width; offset += 1) {
2691
+ const cell = cells[startCol + offset];
2692
+ if (!cell) break;
2693
+ columnIds.push(cell.column.id);
2694
+ }
2695
+ return columnIds;
2696
+ }
2697
+ function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
2698
+ const { values, depths } = parseClipboardTSVWithDepths(text);
2699
+ if (values.length === 0) return null;
2700
+ const width = Math.max(...values.map((row) => row.length), 0);
2701
+ if (width === 0) return null;
2702
+ const columnIds = resolvePasteColumnIds(rows, startCol, width);
2703
+ if (columnIds.length === 0) return null;
2704
+ const rowIds = [];
2705
+ for (let offset = 0; offset < values.length; offset += 1) {
2706
+ const row = rows[startRow + offset];
2707
+ if (!row) break;
2708
+ rowIds.push(row.id);
2709
+ }
2710
+ const anchorRow = rows[endRow] ?? rows[startRow];
2711
+ return {
2712
+ mode,
2713
+ startRow,
2714
+ startCol,
2715
+ endRow,
2716
+ rowIds,
2717
+ anchorRowId: anchorRow?.id ?? "",
2718
+ columnIds,
2719
+ values,
2720
+ depths
2721
+ };
2722
+ }
2723
+ function isEditablePasteTarget(target) {
2724
+ if (!(target instanceof HTMLElement)) return false;
2725
+ const tag = target.tagName;
2726
+ if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
2727
+ return Boolean(target.isContentEditable);
2728
+ }
2729
+
2649
2730
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
2650
2731
  import { useCallback as useCallback3, useEffect as useEffect5, useRef as useRef5, useState as useState3 } from "react";
2651
2732
 
@@ -3055,87 +3136,6 @@ function hasFillExtension(sourceBounds, fillBounds) {
3055
3136
  return fillBounds.startRow < sourceBounds.startRow || fillBounds.endRow > sourceBounds.endRow || fillBounds.startCol < sourceBounds.startCol || fillBounds.endCol > sourceBounds.endCol;
3056
3137
  }
3057
3138
 
3058
- // src/components/ui/table/features/cell-selection/pasteData.ts
3059
- function countLeadingEmptyCells(cells) {
3060
- let depth = 0;
3061
- while (depth < cells.length && cells[depth] === "") {
3062
- depth += 1;
3063
- }
3064
- return depth;
3065
- }
3066
- function looksLikeSubtreeIndentation(leadingEmptyCounts) {
3067
- if (leadingEmptyCounts.length === 0) return false;
3068
- const firstDepth = leadingEmptyCounts[0] ?? 0;
3069
- if (firstDepth !== 0) return false;
3070
- return leadingEmptyCounts.some((depth) => depth > 0);
3071
- }
3072
- function parseClipboardTSVWithDepths(text) {
3073
- if (!text) return { values: [], depths: [] };
3074
- const normalized = text.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
3075
- const withoutTrailing = normalized.replace(/\n+$/, "");
3076
- if (!withoutTrailing) return { values: [], depths: [] };
3077
- const rows = withoutTrailing.split("\n").map((line) => line.split(" "));
3078
- const leadingEmptyCounts = rows.map(countLeadingEmptyCells);
3079
- const treatAsDepth = looksLikeSubtreeIndentation(leadingEmptyCounts);
3080
- const values = [];
3081
- const depths = [];
3082
- for (let index = 0; index < rows.length; index += 1) {
3083
- const cells = rows[index] ?? [];
3084
- const depth = leadingEmptyCounts[index] ?? 0;
3085
- if (treatAsDepth) {
3086
- values.push(cells.slice(depth));
3087
- depths.push(depth);
3088
- } else {
3089
- values.push(cells);
3090
- depths.push(0);
3091
- }
3092
- }
3093
- return { values, depths };
3094
- }
3095
- function resolvePasteColumnIds(rows, startCol, width) {
3096
- if (width <= 0) return [];
3097
- const cells = rows[0]?.getVisibleCells() ?? [];
3098
- const columnIds = [];
3099
- for (let offset = 0; offset < width; offset += 1) {
3100
- const cell = cells[startCol + offset];
3101
- if (!cell) break;
3102
- columnIds.push(cell.column.id);
3103
- }
3104
- return columnIds;
3105
- }
3106
- function buildRowsPastePayload(rows, startRow, startCol, text, mode, endRow = startRow) {
3107
- const { values, depths } = parseClipboardTSVWithDepths(text);
3108
- if (values.length === 0) return null;
3109
- const width = Math.max(...values.map((row) => row.length), 0);
3110
- if (width === 0) return null;
3111
- const columnIds = resolvePasteColumnIds(rows, startCol, width);
3112
- if (columnIds.length === 0) return null;
3113
- const rowIds = [];
3114
- for (let offset = 0; offset < values.length; offset += 1) {
3115
- const row = rows[startRow + offset];
3116
- if (!row) break;
3117
- rowIds.push(row.id);
3118
- }
3119
- const anchorRow = rows[endRow] ?? rows[startRow];
3120
- return {
3121
- mode,
3122
- startRow,
3123
- startCol,
3124
- endRow,
3125
- rowIds,
3126
- anchorRowId: anchorRow?.id ?? "",
3127
- columnIds,
3128
- values,
3129
- depths
3130
- };
3131
- }
3132
- function isEditablePasteTarget(target) {
3133
- if (!(target instanceof HTMLElement)) return false;
3134
- const tag = target.tagName;
3135
- if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT") return true;
3136
- return Boolean(target.isContentEditable);
3137
- }
3138
-
3139
3139
  // src/components/ui/table/features/cell-selection/useCellSelection.ts
3140
3140
  function useCellSelection({
3141
3141
  data,
@@ -3217,11 +3217,19 @@ function useCellSelection({
3217
3217
  },
3218
3218
  [enabled]
3219
3219
  );
3220
+ const clearSelection = useCallback3(() => {
3221
+ const prev = dragStateRef.current;
3222
+ if (prev.start === null && prev.end === null && !prev.isSelecting && !prev.isFillDragging) {
3223
+ return;
3224
+ }
3225
+ dragStateRef.current = INITIAL_DRAG_STATE;
3226
+ setDragState(INITIAL_DRAG_STATE);
3227
+ }, []);
3220
3228
  useEffect5(() => {
3221
3229
  if (!enabled) {
3222
- setDragState(INITIAL_DRAG_STATE);
3230
+ clearSelection();
3223
3231
  }
3224
- }, [enabled]);
3232
+ }, [clearSelection, enabled]);
3225
3233
  useEffect5(() => {
3226
3234
  if (!enabled) return;
3227
3235
  const handleKeyDown = (e) => {
@@ -3435,6 +3443,7 @@ function useCellSelection({
3435
3443
  handleCellMouseDown,
3436
3444
  handleCellMouseEnter,
3437
3445
  handleFillHandleMouseDown,
3446
+ clearSelection,
3438
3447
  copySelection
3439
3448
  };
3440
3449
  }
@@ -4033,6 +4042,7 @@ function useGlideTable(options) {
4033
4042
  handleCellMouseDown,
4034
4043
  handleCellMouseEnter,
4035
4044
  handleFillHandleMouseDown,
4045
+ clearSelection: clearCellSelection,
4036
4046
  copySelection
4037
4047
  } = useCellSelection({
4038
4048
  data: tableData,
@@ -4048,6 +4058,42 @@ function useGlideTable(options) {
4048
4058
  cellRendererRegistry,
4049
4059
  rootRef
4050
4060
  });
4061
+ const clearRowSelection = useCallback5(() => {
4062
+ if (rowSelectionMode === "none") return;
4063
+ const hasSelection = Object.values(rowSelection).some(Boolean);
4064
+ if (!hasSelection) return;
4065
+ if (onRowSelectionChange) {
4066
+ onRowSelectionChange(() => ({}));
4067
+ return;
4068
+ }
4069
+ setInternalRowSelection({});
4070
+ }, [onRowSelectionChange, rowSelection, rowSelectionMode]);
4071
+ useEffect7(() => {
4072
+ const clearAllSelections = () => {
4073
+ clearCellSelection();
4074
+ clearRowSelection();
4075
+ };
4076
+ const handleKeyDown = (event) => {
4077
+ if (event.key !== "Escape") return;
4078
+ if (event.defaultPrevented) return;
4079
+ if (isEditablePasteTarget(event.target) || isEditablePasteTarget(document.activeElement)) {
4080
+ return;
4081
+ }
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;
4088
+ clearAllSelections();
4089
+ };
4090
+ window.addEventListener("keydown", handleKeyDown);
4091
+ document.addEventListener("mousedown", handleMouseDown);
4092
+ return () => {
4093
+ window.removeEventListener("keydown", handleKeyDown);
4094
+ document.removeEventListener("mousedown", handleMouseDown);
4095
+ };
4096
+ }, [clearCellSelection, clearRowSelection]);
4051
4097
  const {
4052
4098
  editingCell,
4053
4099
  draftValue,