@xcelsior/ui-spreadsheets 1.0.5 → 1.0.7

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/index.js CHANGED
@@ -31,7 +31,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  var index_exports = {};
32
32
  __export(index_exports, {
33
33
  Spreadsheet: () => Spreadsheet,
34
- SpreadsheetCell: () => SpreadsheetCell,
34
+ SpreadsheetCell: () => MemoizedSpreadsheetCell,
35
35
  SpreadsheetFilterDropdown: () => SpreadsheetFilterDropdown,
36
36
  SpreadsheetHeader: () => SpreadsheetHeader,
37
37
  SpreadsheetSettingsModal: () => SpreadsheetSettingsModal,
@@ -40,7 +40,7 @@ __export(index_exports, {
40
40
  module.exports = __toCommonJS(index_exports);
41
41
 
42
42
  // src/components/Spreadsheet.tsx
43
- var import_react14 = require("react");
43
+ var import_react15 = require("react");
44
44
 
45
45
  // ../../../node_modules/.pnpm/react-icons@4.12.0_react@18.3.1/node_modules/react-icons/lib/esm/iconBase.js
46
46
  var import_react2 = __toESM(require("react"));
@@ -253,12 +253,11 @@ var SpreadsheetCell = ({
253
253
  const handleKeyDown = (e) => {
254
254
  if (e.key === "Enter") {
255
255
  e.preventDefault();
256
- onConfirm?.();
256
+ onConfirm?.(localValue);
257
257
  } else if (e.key === "Escape") {
258
258
  e.preventDefault();
259
259
  e.stopPropagation();
260
260
  setLocalValue(value);
261
- onChange?.(value);
262
261
  onCancel?.();
263
262
  }
264
263
  };
@@ -291,12 +290,12 @@ var SpreadsheetCell = ({
291
290
  ref: selectRef,
292
291
  value: localValue ?? "",
293
292
  onChange: (e) => {
294
- setLocalValue(e.target.value);
295
- onChange?.(e.target.value);
296
- onConfirm?.();
293
+ const newValue = e.target.value;
294
+ setLocalValue(newValue);
295
+ onConfirm?.(newValue);
297
296
  },
298
297
  onKeyDown: handleKeyDown,
299
- onBlur: () => onConfirm?.(),
298
+ onBlur: () => onConfirm?.(localValue),
300
299
  className: cn(
301
300
  "w-full border border-gray-300 rounded text-xs focus:outline-none focus:ring-1 focus:ring-blue-500",
302
301
  compactMode ? "px-1 py-0.5" : "px-2 py-1"
@@ -315,10 +314,9 @@ var SpreadsheetCell = ({
315
314
  onChange: (e) => {
316
315
  const newValue = column.type === "number" ? e.target.value === "" ? "" : parseFloat(e.target.value) : e.target.value;
317
316
  setLocalValue(newValue);
318
- onChange?.(newValue);
319
317
  },
320
318
  onKeyDown: handleKeyDown,
321
- onBlur: () => onConfirm?.(),
319
+ onBlur: () => onConfirm?.(localValue),
322
320
  className: cn(
323
321
  "w-full border border-gray-300 rounded text-xs focus:outline-none focus:ring-1 focus:ring-blue-500 bg-yellow-50",
324
322
  compactMode ? "px-1 py-0.5" : "px-2 py-1"
@@ -328,7 +326,7 @@ var SpreadsheetCell = ({
328
326
  };
329
327
  const cellPadding = compactMode ? cellPaddingCompact : cellPaddingNormal;
330
328
  const handleCellKeyDown = (e) => {
331
- if (e.key === " ") {
329
+ if (e.key === " " && !isEditing) {
332
330
  e.preventDefault();
333
331
  onClick?.(e);
334
332
  }
@@ -458,6 +456,22 @@ var SpreadsheetCell = ({
458
456
  );
459
457
  };
460
458
  SpreadsheetCell.displayName = "SpreadsheetCell";
459
+ var MemoizedSpreadsheetCell = (0, import_react3.memo)(SpreadsheetCell, (prevProps, nextProps) => {
460
+ if (prevProps.isEditing !== nextProps.isEditing) return false;
461
+ if (prevProps.isFocused !== nextProps.isFocused) return false;
462
+ if (prevProps.value !== nextProps.value) return false;
463
+ if (prevProps.isRowSelected !== nextProps.isRowSelected) return false;
464
+ if (prevProps.isRowHovered !== nextProps.isRowHovered) return false;
465
+ if (prevProps.highlightColor !== nextProps.highlightColor) return false;
466
+ if (prevProps.hasComments !== nextProps.hasComments) return false;
467
+ if (prevProps.unresolvedCommentCount !== nextProps.unresolvedCommentCount) return false;
468
+ if (prevProps.isCopied !== nextProps.isCopied) return false;
469
+ if (prevProps.isPinned !== nextProps.isPinned) return false;
470
+ if (prevProps.leftOffset !== nextProps.leftOffset) return false;
471
+ if (prevProps.rightOffset !== nextProps.rightOffset) return false;
472
+ return true;
473
+ });
474
+ MemoizedSpreadsheetCell.displayName = "MemoizedSpreadsheetCell";
461
475
 
462
476
  // src/components/SpreadsheetFilterDropdown.tsx
463
477
  var import_react4 = require("react");
@@ -2019,16 +2033,26 @@ var SpreadsheetSettingsModal = ({
2019
2033
  SpreadsheetSettingsModal.displayName = "SpreadsheetSettingsModal";
2020
2034
 
2021
2035
  // src/components/CommentModals.tsx
2036
+ var import_react9 = require("react");
2022
2037
  var import_jsx_runtime9 = require("react/jsx-runtime");
2023
- function AddCommentModal({
2024
- isOpen,
2025
- commentText,
2026
- columnLabel,
2027
- onCommentTextChange,
2028
- onAdd,
2029
- onClose
2030
- }) {
2038
+ function AddCommentModal({ isOpen, columnLabel, onAdd, onClose }) {
2039
+ const [commentText, setCommentText] = (0, import_react9.useState)("");
2040
+ (0, import_react9.useEffect)(() => {
2041
+ if (!isOpen) {
2042
+ setCommentText("");
2043
+ }
2044
+ }, [isOpen]);
2031
2045
  if (!isOpen) return null;
2046
+ const handleAdd = () => {
2047
+ if (commentText.trim()) {
2048
+ onAdd(commentText);
2049
+ setCommentText("");
2050
+ }
2051
+ };
2052
+ const handleClose = () => {
2053
+ setCommentText("");
2054
+ onClose();
2055
+ };
2032
2056
  return /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { className: "fixed inset-0 z-50 flex items-center justify-center bg-black/50", children: /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "bg-white rounded-lg shadow-xl p-6 w-96 max-w-full mx-4", children: [
2033
2057
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("h3", { className: "text-lg font-semibold mb-4", children: [
2034
2058
  "Add Comment",
@@ -2038,9 +2062,14 @@ function AddCommentModal({
2038
2062
  "textarea",
2039
2063
  {
2040
2064
  value: commentText,
2041
- onChange: (e) => onCommentTextChange(e.target.value),
2065
+ onChange: (e) => setCommentText(e.target.value),
2066
+ onKeyDown: (e) => {
2067
+ e.stopPropagation();
2068
+ e.nativeEvent.stopImmediatePropagation();
2069
+ },
2042
2070
  placeholder: "Enter your comment...",
2043
- className: "w-full h-24 p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none"
2071
+ className: "w-full h-24 p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500 resize-none",
2072
+ autoFocus: true
2044
2073
  }
2045
2074
  ),
2046
2075
  /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { className: "flex justify-end gap-2 mt-4", children: [
@@ -2048,7 +2077,7 @@ function AddCommentModal({
2048
2077
  "button",
2049
2078
  {
2050
2079
  type: "button",
2051
- onClick: onClose,
2080
+ onClick: handleClose,
2052
2081
  className: "px-4 py-2 text-gray-600 hover:bg-gray-100 rounded-lg transition-colors",
2053
2082
  children: "Cancel"
2054
2083
  }
@@ -2057,7 +2086,7 @@ function AddCommentModal({
2057
2086
  "button",
2058
2087
  {
2059
2088
  type: "button",
2060
- onClick: onAdd,
2089
+ onClick: handleAdd,
2061
2090
  disabled: !commentText.trim(),
2062
2091
  className: "px-4 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700 disabled:opacity-50 disabled:cursor-not-allowed transition-colors",
2063
2092
  children: "Add Comment"
@@ -2140,7 +2169,7 @@ function ViewCommentsModal({
2140
2169
  ViewCommentsModal.displayName = "ViewCommentsModal";
2141
2170
 
2142
2171
  // src/components/KeyboardShortcutsModal.tsx
2143
- var import_react9 = __toESM(require("react"));
2172
+ var import_react10 = __toESM(require("react"));
2144
2173
  var import_jsx_runtime10 = require("react/jsx-runtime");
2145
2174
  function KeyboardShortcutsModal({
2146
2175
  isOpen,
@@ -2182,7 +2211,7 @@ function ShortcutSection({ title, children }) {
2182
2211
  function ShortcutRow({ label, keys }) {
2183
2212
  return /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)("div", { className: "flex items-center justify-between", children: [
2184
2213
  /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-gray-600 text-sm", children: label }),
2185
- /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-center gap-1", children: keys.map((key, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react9.default.Fragment, { children: [
2214
+ /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("div", { className: "flex items-center gap-1", children: keys.map((key, index) => /* @__PURE__ */ (0, import_jsx_runtime10.jsxs)(import_react10.default.Fragment, { children: [
2186
2215
  index > 0 && /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-gray-400", children: "+" }),
2187
2216
  key.includes("Click") ? /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("span", { className: "text-gray-500 text-xs", children: key }) : /* @__PURE__ */ (0, import_jsx_runtime10.jsx)("kbd", { className: "px-2 py-1 bg-gray-100 text-gray-800 rounded text-xs border border-gray-200", children: key })
2188
2217
  ] }, index)) })
@@ -2194,7 +2223,7 @@ KeyboardShortcutsModal.displayName = "KeyboardShortcutsModal";
2194
2223
  var import_design_system = require("@xcelsior/design-system");
2195
2224
 
2196
2225
  // src/hooks/useSpreadsheetFiltering.ts
2197
- var import_react10 = require("react");
2226
+ var import_react11 = require("react");
2198
2227
  var import_utils9 = require("@xcelsior/utils");
2199
2228
  function useSpreadsheetFiltering({
2200
2229
  data,
@@ -2205,16 +2234,16 @@ function useSpreadsheetFiltering({
2205
2234
  controlledFilters,
2206
2235
  controlledSortConfig
2207
2236
  }) {
2208
- const [internalFilters, setInternalFilters] = (0, import_react10.useState)(
2237
+ const [internalFilters, setInternalFilters] = (0, import_react11.useState)(
2209
2238
  {}
2210
2239
  );
2211
- const [internalSortConfig, setInternalSortConfig] = (0, import_react10.useState)(
2240
+ const [internalSortConfig, setInternalSortConfig] = (0, import_react11.useState)(
2212
2241
  null
2213
2242
  );
2214
- const [activeFilterColumn, setActiveFilterColumn] = (0, import_react10.useState)(null);
2243
+ const [activeFilterColumn, setActiveFilterColumn] = (0, import_react11.useState)(null);
2215
2244
  const filters = controlledFilters ?? internalFilters;
2216
2245
  const sortConfig = controlledSortConfig !== void 0 ? controlledSortConfig : internalSortConfig;
2217
- const applyTextCondition = (0, import_react10.useCallback)(
2246
+ const applyTextCondition = (0, import_react11.useCallback)(
2218
2247
  (value, condition) => {
2219
2248
  const strValue = String(value ?? "").toLowerCase();
2220
2249
  const filterValue = (condition.value ?? "").toLowerCase();
@@ -2241,7 +2270,7 @@ function useSpreadsheetFiltering({
2241
2270
  },
2242
2271
  []
2243
2272
  );
2244
- const applyNumberCondition = (0, import_react10.useCallback)(
2273
+ const applyNumberCondition = (0, import_react11.useCallback)(
2245
2274
  (value, condition) => {
2246
2275
  if (condition.operator === "isEmpty") return isBlankValue(value);
2247
2276
  if (condition.operator === "isNotEmpty") return !isBlankValue(value);
@@ -2270,7 +2299,7 @@ function useSpreadsheetFiltering({
2270
2299
  },
2271
2300
  []
2272
2301
  );
2273
- const applyDateCondition = (0, import_react10.useCallback)(
2302
+ const applyDateCondition = (0, import_react11.useCallback)(
2274
2303
  (value, condition) => {
2275
2304
  if (condition.operator === "isEmpty") return isBlankValue(value);
2276
2305
  if (condition.operator === "isNotEmpty") return !isBlankValue(value);
@@ -2342,7 +2371,7 @@ function useSpreadsheetFiltering({
2342
2371
  },
2343
2372
  []
2344
2373
  );
2345
- const buildFilterPredicate = (0, import_react10.useCallback)(
2374
+ const buildFilterPredicate = (0, import_react11.useCallback)(
2346
2375
  (column, filter) => {
2347
2376
  return (row) => {
2348
2377
  const value = column.getValue ? column.getValue(row) : row[column.id];
@@ -2376,7 +2405,7 @@ function useSpreadsheetFiltering({
2376
2405
  },
2377
2406
  [applyTextCondition, applyNumberCondition, applyDateCondition]
2378
2407
  );
2379
- const buildSortComparator = (0, import_react10.useCallback)(
2408
+ const buildSortComparator = (0, import_react11.useCallback)(
2380
2409
  (column, direction) => {
2381
2410
  return (a, b) => {
2382
2411
  const aValue = column?.getValue ? column.getValue(a) : a[sortConfig?.columnId];
@@ -2391,7 +2420,7 @@ function useSpreadsheetFiltering({
2391
2420
  },
2392
2421
  [sortConfig?.columnId]
2393
2422
  );
2394
- const filteredData = (0, import_react10.useMemo)(() => {
2423
+ const filteredData = (0, import_react11.useMemo)(() => {
2395
2424
  if (!data || !Array.isArray(data)) return import_utils9.LazyArray.empty();
2396
2425
  if (serverSide) {
2397
2426
  return import_utils9.LazyArray.from(data);
@@ -2414,7 +2443,7 @@ function useSpreadsheetFiltering({
2414
2443
  }
2415
2444
  return lazyResult;
2416
2445
  }, [data, filters, sortConfig, columns, serverSide, buildFilterPredicate, buildSortComparator]);
2417
- const handleFilterChange = (0, import_react10.useCallback)(
2446
+ const handleFilterChange = (0, import_react11.useCallback)(
2418
2447
  (columnId, filter) => {
2419
2448
  const newFilters = { ...filters };
2420
2449
  if (filter) {
@@ -2429,7 +2458,7 @@ function useSpreadsheetFiltering({
2429
2458
  },
2430
2459
  [filters, onFilterChange, controlledFilters]
2431
2460
  );
2432
- const handleSort = (0, import_react10.useCallback)(
2461
+ const handleSort = (0, import_react11.useCallback)(
2433
2462
  (columnId) => {
2434
2463
  let newSortConfig;
2435
2464
  if (sortConfig?.columnId === columnId) {
@@ -2448,13 +2477,13 @@ function useSpreadsheetFiltering({
2448
2477
  },
2449
2478
  [sortConfig, onSortChange, controlledSortConfig]
2450
2479
  );
2451
- const clearSort = (0, import_react10.useCallback)(() => {
2480
+ const clearSort = (0, import_react11.useCallback)(() => {
2452
2481
  if (controlledSortConfig === void 0) {
2453
2482
  setInternalSortConfig(null);
2454
2483
  }
2455
2484
  onSortChange?.(null);
2456
2485
  }, [onSortChange, controlledSortConfig]);
2457
- const setSortConfig = (0, import_react10.useCallback)(
2486
+ const setSortConfig = (0, import_react11.useCallback)(
2458
2487
  (config) => {
2459
2488
  if (controlledSortConfig === void 0) {
2460
2489
  setInternalSortConfig(config);
@@ -2463,7 +2492,7 @@ function useSpreadsheetFiltering({
2463
2492
  },
2464
2493
  [onSortChange, controlledSortConfig]
2465
2494
  );
2466
- const clearAllFilters = (0, import_react10.useCallback)(() => {
2495
+ const clearAllFilters = (0, import_react11.useCallback)(() => {
2467
2496
  if (controlledFilters === void 0) {
2468
2497
  setInternalFilters({});
2469
2498
  }
@@ -2486,23 +2515,22 @@ function useSpreadsheetFiltering({
2486
2515
  }
2487
2516
 
2488
2517
  // src/hooks/useSpreadsheetComments.ts
2489
- var import_react11 = require("react");
2518
+ var import_react12 = require("react");
2490
2519
  function useSpreadsheetComments({
2491
2520
  externalCellComments,
2492
2521
  onAddCellComment
2493
2522
  } = {}) {
2494
- const [cellCommentsInternal, setCellCommentsInternal] = (0, import_react11.useState)([]);
2495
- const [commentModalCell, setCommentModalCell] = (0, import_react11.useState)(null);
2496
- const [commentText, setCommentText] = (0, import_react11.useState)("");
2497
- const [viewCommentsCell, setViewCommentsCell] = (0, import_react11.useState)(null);
2523
+ const [cellCommentsInternal, setCellCommentsInternal] = (0, import_react12.useState)([]);
2524
+ const [commentModalCell, setCommentModalCell] = (0, import_react12.useState)(null);
2525
+ const [viewCommentsCell, setViewCommentsCell] = (0, import_react12.useState)(null);
2498
2526
  const cellComments = externalCellComments || cellCommentsInternal;
2499
- const getCellComments = (0, import_react11.useCallback)(
2527
+ const getCellComments = (0, import_react12.useCallback)(
2500
2528
  (rowId, columnId) => {
2501
2529
  return cellComments.filter((c) => c.rowId === rowId && c.columnId === columnId);
2502
2530
  },
2503
2531
  [cellComments]
2504
2532
  );
2505
- const getCellUnresolvedCommentCount = (0, import_react11.useCallback)(
2533
+ const getCellUnresolvedCommentCount = (0, import_react12.useCallback)(
2506
2534
  (rowId, columnId) => {
2507
2535
  return cellComments.filter(
2508
2536
  (c) => c.rowId === rowId && c.columnId === columnId && !c.resolved
@@ -2510,17 +2538,17 @@ function useSpreadsheetComments({
2510
2538
  },
2511
2539
  [cellComments]
2512
2540
  );
2513
- const cellHasComments = (0, import_react11.useCallback)(
2541
+ const cellHasComments = (0, import_react12.useCallback)(
2514
2542
  (rowId, columnId) => {
2515
2543
  return cellComments.some((c) => c.rowId === rowId && c.columnId === columnId);
2516
2544
  },
2517
2545
  [cellComments]
2518
2546
  );
2519
- const handleAddCellComment = (0, import_react11.useCallback)(
2520
- (rowId, columnId) => {
2521
- if (!commentText.trim()) return;
2547
+ const handleAddCellComment = (0, import_react12.useCallback)(
2548
+ (rowId, columnId, text) => {
2549
+ if (!text.trim()) return;
2522
2550
  if (onAddCellComment) {
2523
- onAddCellComment(rowId, columnId, commentText);
2551
+ onAddCellComment(rowId, columnId, text);
2524
2552
  } else {
2525
2553
  setCellCommentsInternal((prev) => [
2526
2554
  ...prev,
@@ -2528,18 +2556,17 @@ function useSpreadsheetComments({
2528
2556
  id: `comment-${Date.now()}`,
2529
2557
  rowId,
2530
2558
  columnId,
2531
- text: commentText,
2559
+ text,
2532
2560
  timestamp: /* @__PURE__ */ new Date(),
2533
2561
  resolved: false
2534
2562
  }
2535
2563
  ]);
2536
2564
  }
2537
- setCommentText("");
2538
2565
  setCommentModalCell(null);
2539
2566
  },
2540
- [commentText, onAddCellComment]
2567
+ [onAddCellComment]
2541
2568
  );
2542
- const handleToggleCommentResolved = (0, import_react11.useCallback)((commentId) => {
2569
+ const handleToggleCommentResolved = (0, import_react12.useCallback)((commentId) => {
2543
2570
  setCellCommentsInternal(
2544
2571
  (prev) => prev.map((c) => c.id === commentId ? { ...c, resolved: !c.resolved } : c)
2545
2572
  );
@@ -2552,8 +2579,6 @@ function useSpreadsheetComments({
2552
2579
  // Add comment modal state
2553
2580
  commentModalCell,
2554
2581
  setCommentModalCell,
2555
- commentText,
2556
- setCommentText,
2557
2582
  // View comments modal state
2558
2583
  viewCommentsCell,
2559
2584
  setViewCommentsCell,
@@ -2566,17 +2591,17 @@ function useSpreadsheetComments({
2566
2591
  }
2567
2592
 
2568
2593
  // src/hooks/useSpreadsheetUndoRedo.ts
2569
- var import_react12 = require("react");
2594
+ var import_react13 = require("react");
2570
2595
  function useSpreadsheetUndoRedo({
2571
2596
  enabled = true,
2572
2597
  maxStackSize = 50,
2573
2598
  autoSave = true
2574
2599
  }) {
2575
- const [undoStack, setUndoStack] = (0, import_react12.useState)([]);
2576
- const [redoStack, setRedoStack] = (0, import_react12.useState)([]);
2577
- const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react12.useState)(false);
2578
- const [saveStatus, setSaveStatus] = (0, import_react12.useState)("saved");
2579
- const pushToUndoStack = (0, import_react12.useCallback)(
2600
+ const [undoStack, setUndoStack] = (0, import_react13.useState)([]);
2601
+ const [redoStack, setRedoStack] = (0, import_react13.useState)([]);
2602
+ const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react13.useState)(false);
2603
+ const [saveStatus, setSaveStatus] = (0, import_react13.useState)("saved");
2604
+ const pushToUndoStack = (0, import_react13.useCallback)(
2580
2605
  (snapshot) => {
2581
2606
  if (!enabled) return;
2582
2607
  setUndoStack((prev) => {
@@ -2590,7 +2615,7 @@ function useSpreadsheetUndoRedo({
2590
2615
  },
2591
2616
  [enabled, maxStackSize]
2592
2617
  );
2593
- const handleUndo = (0, import_react12.useCallback)(() => {
2618
+ const handleUndo = (0, import_react13.useCallback)(() => {
2594
2619
  if (!enabled || undoStack.length === 0) return null;
2595
2620
  const previousSnapshot = undoStack[undoStack.length - 1];
2596
2621
  setUndoStack((prev) => prev.slice(0, -1));
@@ -2603,7 +2628,7 @@ function useSpreadsheetUndoRedo({
2603
2628
  });
2604
2629
  return previousSnapshot;
2605
2630
  }, [enabled, undoStack, maxStackSize]);
2606
- const handleRedo = (0, import_react12.useCallback)(() => {
2631
+ const handleRedo = (0, import_react13.useCallback)(() => {
2607
2632
  if (!enabled || redoStack.length === 0) return null;
2608
2633
  const nextSnapshot = redoStack[redoStack.length - 1];
2609
2634
  setRedoStack((prev) => prev.slice(0, -1));
@@ -2616,7 +2641,7 @@ function useSpreadsheetUndoRedo({
2616
2641
  });
2617
2642
  return nextSnapshot;
2618
2643
  }, [enabled, redoStack, maxStackSize]);
2619
- const handleSave = (0, import_react12.useCallback)(() => {
2644
+ const handleSave = (0, import_react13.useCallback)(() => {
2620
2645
  if (!hasUnsavedChanges) return;
2621
2646
  setSaveStatus("saving");
2622
2647
  setTimeout(() => {
@@ -2624,7 +2649,7 @@ function useSpreadsheetUndoRedo({
2624
2649
  setHasUnsavedChanges(false);
2625
2650
  }, 500);
2626
2651
  }, [hasUnsavedChanges]);
2627
- const markAsChanged = (0, import_react12.useCallback)(() => {
2652
+ const markAsChanged = (0, import_react13.useCallback)(() => {
2628
2653
  setHasUnsavedChanges(true);
2629
2654
  if (autoSave) {
2630
2655
  setSaveStatus("saving");
@@ -2633,11 +2658,11 @@ function useSpreadsheetUndoRedo({
2633
2658
  setSaveStatus("unsaved");
2634
2659
  }
2635
2660
  }, [autoSave]);
2636
- const markAsSaved = (0, import_react12.useCallback)(() => {
2661
+ const markAsSaved = (0, import_react13.useCallback)(() => {
2637
2662
  setHasUnsavedChanges(false);
2638
2663
  setSaveStatus("saved");
2639
2664
  }, []);
2640
- const clearStacks = (0, import_react12.useCallback)(() => {
2665
+ const clearStacks = (0, import_react13.useCallback)(() => {
2641
2666
  setUndoStack([]);
2642
2667
  setRedoStack([]);
2643
2668
  }, []);
@@ -2665,7 +2690,7 @@ function useSpreadsheetUndoRedo({
2665
2690
  }
2666
2691
 
2667
2692
  // src/hooks/useSpreadsheetKeyboardShortcuts.ts
2668
- var import_react13 = require("react");
2693
+ var import_react14 = require("react");
2669
2694
  function useSpreadsheetKeyboardShortcuts({
2670
2695
  onUndo,
2671
2696
  onRedo,
@@ -2677,10 +2702,10 @@ function useSpreadsheetKeyboardShortcuts({
2677
2702
  customShortcuts = [],
2678
2703
  enabled = true
2679
2704
  } = {}) {
2680
- const [showKeyboardShortcuts, setShowKeyboardShortcuts] = (0, import_react13.useState)(false);
2705
+ const [showKeyboardShortcuts, setShowKeyboardShortcuts] = (0, import_react14.useState)(false);
2681
2706
  const isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPod|iPad/.test(navigator.platform);
2682
2707
  const modifierKey = isMac ? "\u2318" : "Ctrl";
2683
- (0, import_react13.useEffect)(() => {
2708
+ (0, import_react14.useEffect)(() => {
2684
2709
  if (!enabled) return;
2685
2710
  const handleKeyDown = (event) => {
2686
2711
  if (event.key === "Escape") {
@@ -2897,8 +2922,6 @@ function Spreadsheet({
2897
2922
  cellHasComments,
2898
2923
  commentModalCell,
2899
2924
  setCommentModalCell,
2900
- commentText,
2901
- setCommentText,
2902
2925
  viewCommentsCell,
2903
2926
  setViewCommentsCell,
2904
2927
  handleAddCellComment,
@@ -2923,18 +2946,17 @@ function Spreadsheet({
2923
2946
  enabled: enableUndoRedo,
2924
2947
  autoSave
2925
2948
  });
2926
- const [selectedRows, setSelectedRows] = (0, import_react14.useState)(/* @__PURE__ */ new Set());
2927
- const [lastSelectedRow, setLastSelectedRow] = (0, import_react14.useState)(null);
2928
- const [focusedCell, setFocusedCell] = (0, import_react14.useState)(null);
2929
- const [editingCell, setEditingCell] = (0, import_react14.useState)(null);
2930
- const [editValue, setEditValue] = (0, import_react14.useState)("");
2931
- const [hoveredRow, setHoveredRow] = (0, import_react14.useState)(null);
2932
- const [internalCurrentPage, setInternalCurrentPage] = (0, import_react14.useState)(1);
2933
- const [internalPageSize, setInternalPageSize] = (0, import_react14.useState)(defaultPageSize);
2934
- const [zoom, setZoom] = (0, import_react14.useState)(defaultZoom);
2949
+ const [selectedRows, setSelectedRows] = (0, import_react15.useState)(/* @__PURE__ */ new Set());
2950
+ const [lastSelectedRow, setLastSelectedRow] = (0, import_react15.useState)(null);
2951
+ const [focusedCell, setFocusedCell] = (0, import_react15.useState)(null);
2952
+ const [editingCell, setEditingCell] = (0, import_react15.useState)(null);
2953
+ const [hoveredRow, setHoveredRow] = (0, import_react15.useState)(null);
2954
+ const [internalCurrentPage, setInternalCurrentPage] = (0, import_react15.useState)(1);
2955
+ const [internalPageSize, setInternalPageSize] = (0, import_react15.useState)(defaultPageSize);
2956
+ const [zoom, setZoom] = (0, import_react15.useState)(defaultZoom);
2935
2957
  const currentPage = controlledCurrentPage ?? internalCurrentPage;
2936
2958
  const pageSize = controlledPageSize ?? internalPageSize;
2937
- const handlePageChange = (0, import_react14.useCallback)(
2959
+ const handlePageChange = (0, import_react15.useCallback)(
2938
2960
  (newPage) => {
2939
2961
  if (controlledCurrentPage === void 0) {
2940
2962
  setInternalCurrentPage(newPage);
@@ -2943,7 +2965,7 @@ function Spreadsheet({
2943
2965
  },
2944
2966
  [controlledCurrentPage, onPageChange, pageSize]
2945
2967
  );
2946
- const handlePageSizeChange = (0, import_react14.useCallback)(
2968
+ const handlePageSizeChange = (0, import_react15.useCallback)(
2947
2969
  (newPageSize) => {
2948
2970
  if (controlledPageSize === void 0) {
2949
2971
  setInternalPageSize(newPageSize);
@@ -2955,8 +2977,8 @@ function Spreadsheet({
2955
2977
  },
2956
2978
  [controlledPageSize, controlledCurrentPage, onPageChange]
2957
2979
  );
2958
- const [showSettingsModal, setShowSettingsModal] = (0, import_react14.useState)(false);
2959
- const [spreadsheetSettings, setSpreadsheetSettings] = (0, import_react14.useState)({
2980
+ const [showSettingsModal, setShowSettingsModal] = (0, import_react15.useState)(false);
2981
+ const [spreadsheetSettings, setSpreadsheetSettings] = (0, import_react15.useState)({
2960
2982
  defaultPinnedColumns: [],
2961
2983
  defaultSort: null,
2962
2984
  defaultPageSize,
@@ -2967,13 +2989,13 @@ function Spreadsheet({
2967
2989
  pinRowIndex: false,
2968
2990
  rowIndexHighlightColor: void 0
2969
2991
  });
2970
- (0, import_react14.useEffect)(() => {
2992
+ (0, import_react15.useEffect)(() => {
2971
2993
  setSpreadsheetSettings((prev) => ({
2972
2994
  ...prev,
2973
2995
  defaultSort: sortConfig
2974
2996
  }));
2975
2997
  }, [sortConfig]);
2976
- const handleEscapeCallback = (0, import_react14.useCallback)(() => {
2998
+ const handleEscapeCallback = (0, import_react15.useCallback)(() => {
2977
2999
  if (commentModalCell !== null) {
2978
3000
  setCommentModalCell(null);
2979
3001
  } else if (viewCommentsCell !== null) {
@@ -3002,7 +3024,7 @@ function Spreadsheet({
3002
3024
  highlightPickerCell,
3003
3025
  setHighlightPickerCell
3004
3026
  ]);
3005
- const applyUndo = (0, import_react14.useCallback)(() => {
3027
+ const applyUndo = (0, import_react15.useCallback)(() => {
3006
3028
  const entry = popUndoEntry();
3007
3029
  if (!entry || !onCellEdit) return;
3008
3030
  if (entry.type === "cell-edit") {
@@ -3010,7 +3032,7 @@ function Spreadsheet({
3010
3032
  markAsChanged();
3011
3033
  }
3012
3034
  }, [popUndoEntry, onCellEdit, markAsChanged]);
3013
- const applyRedo = (0, import_react14.useCallback)(() => {
3035
+ const applyRedo = (0, import_react15.useCallback)(() => {
3014
3036
  const entry = popRedoEntry();
3015
3037
  if (!entry || !onCellEdit) return;
3016
3038
  if (entry.type === "cell-edit") {
@@ -3018,14 +3040,14 @@ function Spreadsheet({
3018
3040
  markAsChanged();
3019
3041
  }
3020
3042
  }, [popRedoEntry, onCellEdit, markAsChanged]);
3021
- const paginatedData = (0, import_react14.useMemo)(() => {
3043
+ const paginatedData = (0, import_react15.useMemo)(() => {
3022
3044
  if (serverSide) {
3023
3045
  return filteredData;
3024
3046
  }
3025
3047
  const startIndex = (currentPage - 1) * pageSize;
3026
3048
  return filteredData.slice(startIndex, startIndex + pageSize);
3027
3049
  }, [filteredData, currentPage, pageSize, serverSide]);
3028
- const handleNavigate = (0, import_react14.useCallback)(
3050
+ const handleNavigate = (0, import_react15.useCallback)(
3029
3051
  (direction) => {
3030
3052
  if (!focusedCell) return;
3031
3053
  const currentRowIndex = paginatedData.findIndex(
@@ -3068,15 +3090,13 @@ function Spreadsheet({
3068
3090
  },
3069
3091
  [focusedCell, paginatedData, visibleColumns, getRowId]
3070
3092
  );
3071
- const handleEnterEditMode = (0, import_react14.useCallback)(() => {
3093
+ const handleEnterEditMode = (0, import_react15.useCallback)(() => {
3072
3094
  if (!focusedCell) return;
3073
3095
  const column = (columns || []).find((c) => c.id === focusedCell.columnId);
3074
3096
  if (column?.editable && enableCellEditing) {
3075
3097
  const row = (data || []).find((r) => getRowId(r) === focusedCell.rowId);
3076
3098
  if (row) {
3077
- const value = column.getValue ? column.getValue(row) : row[focusedCell.columnId];
3078
3099
  setEditingCell({ rowId: focusedCell.rowId, columnId: focusedCell.columnId });
3079
- setEditValue(value);
3080
3100
  }
3081
3101
  }
3082
3102
  }, [focusedCell, columns, data, getRowId, enableCellEditing]);
@@ -3092,15 +3112,15 @@ function Spreadsheet({
3092
3112
  });
3093
3113
  const effectiveShowRowIndex = spreadsheetSettings.showRowIndex !== false;
3094
3114
  const rowIndexHighlightColor = getColumnHighlight(ROW_INDEX_COLUMN_ID);
3095
- const tableRef = (0, import_react14.useRef)(null);
3115
+ const tableRef = (0, import_react15.useRef)(null);
3096
3116
  const effectiveTotalItems = serverSide ? totalItems ?? data.length : filteredData.length;
3097
3117
  const totalPages = Math.max(1, Math.ceil(effectiveTotalItems / pageSize));
3098
- (0, import_react14.useEffect)(() => {
3118
+ (0, import_react15.useEffect)(() => {
3099
3119
  if (!serverSide && currentPage > totalPages) {
3100
3120
  setInternalCurrentPage(1);
3101
3121
  }
3102
3122
  }, [totalPages, currentPage, serverSide]);
3103
- const handleRowSelect = (0, import_react14.useCallback)(
3123
+ const handleRowSelect = (0, import_react15.useCallback)(
3104
3124
  (rowId, event) => {
3105
3125
  if (!enableRowSelection) return;
3106
3126
  event.stopPropagation();
@@ -3148,7 +3168,7 @@ function Spreadsheet({
3148
3168
  onSelectionChange
3149
3169
  ]
3150
3170
  );
3151
- const handleCellClick = (0, import_react14.useCallback)(
3171
+ const handleCellClick = (0, import_react15.useCallback)(
3152
3172
  (rowId, columnId, event) => {
3153
3173
  event.stopPropagation();
3154
3174
  setFocusedCell({ rowId, columnId });
@@ -3156,15 +3176,13 @@ function Spreadsheet({
3156
3176
  if (column?.editable && enableCellEditing) {
3157
3177
  const row = (data || []).find((r) => getRowId(r) === rowId);
3158
3178
  if (row) {
3159
- const value = column.getValue ? column.getValue(row) : row[columnId];
3160
3179
  setEditingCell({ rowId, columnId });
3161
- setEditValue(value);
3162
3180
  }
3163
3181
  }
3164
3182
  },
3165
3183
  [columns, data, getRowId, enableCellEditing]
3166
3184
  );
3167
- const handleCellChange = (0, import_react14.useCallback)(
3185
+ const handleCellChange = (0, import_react15.useCallback)(
3168
3186
  (rowId, columnId, newValue) => {
3169
3187
  const row = data.find((r) => getRowId(r) === rowId);
3170
3188
  const previousValue = row ? row[columnId] : void 0;
@@ -3185,23 +3203,25 @@ function Spreadsheet({
3185
3203
  },
3186
3204
  [data, getRowId, enableUndoRedo, onCellEdit, pushToUndoStack, markAsChanged]
3187
3205
  );
3188
- const handleConfirmEdit = (0, import_react14.useCallback)(() => {
3189
- if (editingCell) {
3190
- handleCellChange(editingCell.rowId, editingCell.columnId, editValue);
3191
- setEditingCell(null);
3192
- }
3193
- }, [editingCell, editValue, handleCellChange]);
3194
- const handleCancelEdit = (0, import_react14.useCallback)(() => {
3206
+ const handleConfirmEdit = (0, import_react15.useCallback)(
3207
+ (finalValue) => {
3208
+ if (editingCell && finalValue !== void 0) {
3209
+ handleCellChange(editingCell.rowId, editingCell.columnId, finalValue);
3210
+ setEditingCell(null);
3211
+ }
3212
+ },
3213
+ [editingCell, handleCellChange]
3214
+ );
3215
+ const handleCancelEdit = (0, import_react15.useCallback)(() => {
3195
3216
  setEditingCell(null);
3196
- setEditValue("");
3197
3217
  }, []);
3198
- const handleRowClone = (0, import_react14.useCallback)(
3218
+ const handleRowClone = (0, import_react15.useCallback)(
3199
3219
  (row, rowId) => {
3200
3220
  onRowClone?.(row, rowId);
3201
3221
  },
3202
3222
  [onRowClone]
3203
3223
  );
3204
- const handleRowIndexHighlightClick = (0, import_react14.useCallback)(() => {
3224
+ const handleRowIndexHighlightClick = (0, import_react15.useCallback)(() => {
3205
3225
  setHighlightPickerColumn(ROW_INDEX_COLUMN_ID);
3206
3226
  }, [setHighlightPickerColumn]);
3207
3227
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)("div", { className: cn("flex flex-col h-full bg-white", className), children: [
@@ -3509,9 +3529,9 @@ function Spreadsheet({
3509
3529
  const isColPinned = isColumnPinned(column.id);
3510
3530
  const colPinSide = getColumnPinSide(column.id);
3511
3531
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(
3512
- SpreadsheetCell,
3532
+ MemoizedSpreadsheetCell,
3513
3533
  {
3514
- value: isEditing ? editValue : value,
3534
+ value,
3515
3535
  column,
3516
3536
  row,
3517
3537
  rowIndex,
@@ -3528,7 +3548,6 @@ function Spreadsheet({
3528
3548
  pinSide: colPinSide,
3529
3549
  leftOffset: getColumnLeftOffset(column.id),
3530
3550
  onClick: (e) => handleCellClick(rowId, column.id, e),
3531
- onChange: (newValue) => setEditValue(newValue),
3532
3551
  onConfirm: handleConfirmEdit,
3533
3552
  onCancel: handleCancelEdit,
3534
3553
  onHighlight: enableHighlighting ? () => {
@@ -3584,12 +3603,9 @@ function Spreadsheet({
3584
3603
  AddCommentModal,
3585
3604
  {
3586
3605
  isOpen: commentModalCell !== null,
3587
- commentText,
3588
3606
  columnLabel: commentModalCell ? commentModalCell.columnId === ROW_INDEX_COLUMN_ID ? "Row #" : columns.find((c) => c.id === commentModalCell.columnId)?.label : void 0,
3589
- onCommentTextChange: setCommentText,
3590
- onAdd: () => commentModalCell !== null && handleAddCellComment(commentModalCell.rowId, commentModalCell.columnId),
3607
+ onAdd: (text) => commentModalCell !== null && handleAddCellComment(commentModalCell.rowId, commentModalCell.columnId, text),
3591
3608
  onClose: () => {
3592
- setCommentText("");
3593
3609
  setCommentModalCell(null);
3594
3610
  }
3595
3611
  }