@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.d.mts +7 -21
- package/dist/index.d.ts +7 -21
- package/dist/index.js +137 -121
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +98 -82
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
- package/src/components/CommentModals.tsx +33 -17
- package/src/components/Spreadsheet.tsx +12 -23
- package/src/components/SpreadsheetCell.tsx +37 -11
- package/src/hooks/useSpreadsheetComments.ts +6 -12
- package/src/types.ts +3 -3
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: () =>
|
|
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
|
|
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
|
-
|
|
295
|
-
|
|
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
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
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) =>
|
|
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:
|
|
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:
|
|
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
|
|
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)(
|
|
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
|
|
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,
|
|
2237
|
+
const [internalFilters, setInternalFilters] = (0, import_react11.useState)(
|
|
2209
2238
|
{}
|
|
2210
2239
|
);
|
|
2211
|
-
const [internalSortConfig, setInternalSortConfig] = (0,
|
|
2240
|
+
const [internalSortConfig, setInternalSortConfig] = (0, import_react11.useState)(
|
|
2212
2241
|
null
|
|
2213
2242
|
);
|
|
2214
|
-
const [activeFilterColumn, setActiveFilterColumn] = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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
|
|
2518
|
+
var import_react12 = require("react");
|
|
2490
2519
|
function useSpreadsheetComments({
|
|
2491
2520
|
externalCellComments,
|
|
2492
2521
|
onAddCellComment
|
|
2493
2522
|
} = {}) {
|
|
2494
|
-
const [cellCommentsInternal, setCellCommentsInternal] = (0,
|
|
2495
|
-
const [commentModalCell, setCommentModalCell] = (0,
|
|
2496
|
-
const [
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
2520
|
-
(rowId, columnId) => {
|
|
2521
|
-
if (!
|
|
2547
|
+
const handleAddCellComment = (0, import_react12.useCallback)(
|
|
2548
|
+
(rowId, columnId, text) => {
|
|
2549
|
+
if (!text.trim()) return;
|
|
2522
2550
|
if (onAddCellComment) {
|
|
2523
|
-
onAddCellComment(rowId, columnId,
|
|
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
|
|
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
|
-
[
|
|
2567
|
+
[onAddCellComment]
|
|
2541
2568
|
);
|
|
2542
|
-
const handleToggleCommentResolved = (0,
|
|
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
|
|
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,
|
|
2576
|
-
const [redoStack, setRedoStack] = (0,
|
|
2577
|
-
const [hasUnsavedChanges, setHasUnsavedChanges] = (0,
|
|
2578
|
-
const [saveStatus, setSaveStatus] = (0,
|
|
2579
|
-
const pushToUndoStack = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
2661
|
+
const markAsSaved = (0, import_react13.useCallback)(() => {
|
|
2637
2662
|
setHasUnsavedChanges(false);
|
|
2638
2663
|
setSaveStatus("saved");
|
|
2639
2664
|
}, []);
|
|
2640
|
-
const clearStacks = (0,
|
|
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
|
|
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,
|
|
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,
|
|
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,
|
|
2927
|
-
const [lastSelectedRow, setLastSelectedRow] = (0,
|
|
2928
|
-
const [focusedCell, setFocusedCell] = (0,
|
|
2929
|
-
const [editingCell, setEditingCell] = (0,
|
|
2930
|
-
const [
|
|
2931
|
-
const [
|
|
2932
|
-
const [
|
|
2933
|
-
const [
|
|
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,
|
|
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,
|
|
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,
|
|
2959
|
-
const [spreadsheetSettings, setSpreadsheetSettings] = (0,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
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,
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
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,
|
|
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,
|
|
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
|
-
|
|
3532
|
+
MemoizedSpreadsheetCell,
|
|
3513
3533
|
{
|
|
3514
|
-
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
|
-
|
|
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
|
}
|