@xcelsior/ui-spreadsheets 1.0.15 → 1.0.17
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 +3 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.js +68 -32
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +73 -37
- package/dist/index.mjs.map +1 -1
- package/dist/styles/globals.css +6 -0
- package/dist/styles/globals.css.map +1 -1
- package/package.json +1 -1
- package/src/components/RowIndexColumnHeader.tsx +11 -1
- package/src/components/Spreadsheet.tsx +35 -24
- package/src/components/SpreadsheetCell.tsx +3 -2
- package/src/components/SpreadsheetHeader.tsx +3 -2
- package/src/hooks/useSpreadsheetUndoRedo.ts +35 -8
- package/src/types.ts +2 -0
package/dist/index.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/components/Spreadsheet.tsx
|
|
2
|
-
import { useCallback as useCallback7, useEffect as useEffect6, useMemo as useMemo4, useRef as
|
|
2
|
+
import { useCallback as useCallback7, useEffect as useEffect6, useMemo as useMemo4, useRef as useRef5, useState as useState12 } from "react";
|
|
3
3
|
|
|
4
4
|
// ../../../node_modules/.pnpm/react-icons@4.12.0_react@18.3.1/node_modules/react-icons/lib/esm/iconBase.js
|
|
5
5
|
import React2 from "react";
|
|
@@ -153,7 +153,7 @@ function cn(...inputs) {
|
|
|
153
153
|
// src/components/SpreadsheetCell.tsx
|
|
154
154
|
import { useState, useRef, useEffect, memo } from "react";
|
|
155
155
|
import { jsx, jsxs } from "react/jsx-runtime";
|
|
156
|
-
var cellPaddingCompact = "px-1
|
|
156
|
+
var cellPaddingCompact = "px-1 py-px";
|
|
157
157
|
var cellPaddingNormal = "px-2 py-1";
|
|
158
158
|
var SpreadsheetCell = ({
|
|
159
159
|
value,
|
|
@@ -329,7 +329,8 @@ var SpreadsheetCell = ({
|
|
|
329
329
|
onKeyDown: handleCellKeyDown,
|
|
330
330
|
"data-cell-id": `${rowId}-${column.id}`,
|
|
331
331
|
className: cn(
|
|
332
|
-
"border border-gray-200
|
|
332
|
+
"border border-gray-200 group cursor-pointer transition-colors select-none",
|
|
333
|
+
compactMode ? "text-[10px]" : "text-xs",
|
|
333
334
|
cellPadding,
|
|
334
335
|
column.align === "right" && "text-right",
|
|
335
336
|
column.align === "center" && "text-center",
|
|
@@ -1148,7 +1149,7 @@ ColumnHeaderActions.displayName = "ColumnHeaderActions";
|
|
|
1148
1149
|
|
|
1149
1150
|
// src/components/SpreadsheetHeader.tsx
|
|
1150
1151
|
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1151
|
-
var cellPaddingCompact2 = "px-1
|
|
1152
|
+
var cellPaddingCompact2 = "px-1 py-0.5";
|
|
1152
1153
|
var cellPaddingNormal2 = "px-2 py-1.5";
|
|
1153
1154
|
var SpreadsheetHeader = ({
|
|
1154
1155
|
column,
|
|
@@ -1184,7 +1185,8 @@ var SpreadsheetHeader = ({
|
|
|
1184
1185
|
{
|
|
1185
1186
|
onClick: column.sortable ? onClick : void 0,
|
|
1186
1187
|
className: cn(
|
|
1187
|
-
"border border-gray-200
|
|
1188
|
+
"border border-gray-200 font-semibold text-gray-700 sticky group",
|
|
1189
|
+
compactMode ? "text-[10px]" : "text-xs",
|
|
1188
1190
|
cellPadding,
|
|
1189
1191
|
column.align === "right" && "text-right",
|
|
1190
1192
|
column.align === "center" && "text-center",
|
|
@@ -1354,6 +1356,8 @@ function useSpreadsheetPinning({
|
|
|
1354
1356
|
|
|
1355
1357
|
// src/components/RowIndexColumnHeader.tsx
|
|
1356
1358
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
1359
|
+
var cellPaddingCompact3 = "px-1 py-0.5";
|
|
1360
|
+
var cellPaddingNormal3 = "px-2 py-1.5";
|
|
1357
1361
|
function RowIndexColumnHeader({
|
|
1358
1362
|
enableHighlighting = false,
|
|
1359
1363
|
highlightColor,
|
|
@@ -1361,13 +1365,17 @@ function RowIndexColumnHeader({
|
|
|
1361
1365
|
onHighlightClick,
|
|
1362
1366
|
onPinClick,
|
|
1363
1367
|
hasColumnGroups = false,
|
|
1368
|
+
compactMode = false,
|
|
1364
1369
|
className
|
|
1365
1370
|
}) {
|
|
1371
|
+
const cellPadding = compactMode ? cellPaddingCompact3 : cellPaddingNormal3;
|
|
1366
1372
|
return /* @__PURE__ */ jsx6(
|
|
1367
1373
|
"th",
|
|
1368
1374
|
{
|
|
1369
1375
|
className: cn(
|
|
1370
|
-
"border border-gray-200
|
|
1376
|
+
"border border-gray-200 text-center font-bold text-gray-700 group",
|
|
1377
|
+
compactMode ? "text-[10px]" : "text-xs",
|
|
1378
|
+
cellPadding,
|
|
1371
1379
|
isPinned ? "z-30" : "z-20",
|
|
1372
1380
|
className
|
|
1373
1381
|
),
|
|
@@ -2601,16 +2609,19 @@ function useSpreadsheetComments({
|
|
|
2601
2609
|
}
|
|
2602
2610
|
|
|
2603
2611
|
// src/hooks/useSpreadsheetUndoRedo.ts
|
|
2604
|
-
import { useCallback as useCallback5, useState as useState9 } from "react";
|
|
2612
|
+
import { useCallback as useCallback5, useRef as useRef3, useState as useState9 } from "react";
|
|
2605
2613
|
function useSpreadsheetUndoRedo({
|
|
2606
2614
|
enabled = true,
|
|
2607
2615
|
maxStackSize = 50,
|
|
2608
|
-
autoSave = true
|
|
2616
|
+
autoSave = true,
|
|
2617
|
+
onSave
|
|
2609
2618
|
}) {
|
|
2610
2619
|
const [undoStack, setUndoStack] = useState9([]);
|
|
2611
2620
|
const [redoStack, setRedoStack] = useState9([]);
|
|
2612
2621
|
const [hasUnsavedChanges, setHasUnsavedChanges] = useState9(false);
|
|
2613
2622
|
const [saveStatus, setSaveStatus] = useState9("saved");
|
|
2623
|
+
const onSaveRef = useRef3(onSave);
|
|
2624
|
+
onSaveRef.current = onSave;
|
|
2614
2625
|
const pushToUndoStack = useCallback5(
|
|
2615
2626
|
(snapshot) => {
|
|
2616
2627
|
if (!enabled) return;
|
|
@@ -2651,19 +2662,36 @@ function useSpreadsheetUndoRedo({
|
|
|
2651
2662
|
});
|
|
2652
2663
|
return nextSnapshot;
|
|
2653
2664
|
}, [enabled, redoStack, maxStackSize]);
|
|
2654
|
-
const handleSave = useCallback5(() => {
|
|
2655
|
-
if (!hasUnsavedChanges) return;
|
|
2665
|
+
const handleSave = useCallback5(async () => {
|
|
2666
|
+
if (!hasUnsavedChanges && !autoSave) return;
|
|
2656
2667
|
setSaveStatus("saving");
|
|
2657
|
-
|
|
2668
|
+
try {
|
|
2669
|
+
if (onSaveRef.current) {
|
|
2670
|
+
await onSaveRef.current();
|
|
2671
|
+
}
|
|
2658
2672
|
setSaveStatus("saved");
|
|
2659
2673
|
setHasUnsavedChanges(false);
|
|
2660
|
-
}
|
|
2661
|
-
|
|
2674
|
+
} catch {
|
|
2675
|
+
setSaveStatus("error");
|
|
2676
|
+
}
|
|
2677
|
+
}, [hasUnsavedChanges, autoSave]);
|
|
2662
2678
|
const markAsChanged = useCallback5(() => {
|
|
2663
2679
|
setHasUnsavedChanges(true);
|
|
2664
2680
|
if (autoSave) {
|
|
2665
2681
|
setSaveStatus("saving");
|
|
2666
|
-
|
|
2682
|
+
if (onSaveRef.current) {
|
|
2683
|
+
Promise.resolve(onSaveRef.current()).then(() => {
|
|
2684
|
+
setSaveStatus("saved");
|
|
2685
|
+
setHasUnsavedChanges(false);
|
|
2686
|
+
}).catch(() => {
|
|
2687
|
+
setSaveStatus("error");
|
|
2688
|
+
});
|
|
2689
|
+
} else {
|
|
2690
|
+
setTimeout(() => {
|
|
2691
|
+
setSaveStatus("saved");
|
|
2692
|
+
setHasUnsavedChanges(false);
|
|
2693
|
+
}, 500);
|
|
2694
|
+
}
|
|
2667
2695
|
} else {
|
|
2668
2696
|
setSaveStatus("unsaved");
|
|
2669
2697
|
}
|
|
@@ -2859,7 +2887,7 @@ function useSpreadsheetKeyboardShortcuts({
|
|
|
2859
2887
|
}
|
|
2860
2888
|
|
|
2861
2889
|
// src/hooks/useSpreadsheetSelection.ts
|
|
2862
|
-
import { useCallback as useCallback6, useState as useState11, useRef as
|
|
2890
|
+
import { useCallback as useCallback6, useState as useState11, useRef as useRef4, useMemo as useMemo3 } from "react";
|
|
2863
2891
|
function useSpreadsheetSelection({
|
|
2864
2892
|
data,
|
|
2865
2893
|
columns,
|
|
@@ -2872,7 +2900,7 @@ function useSpreadsheetSelection({
|
|
|
2872
2900
|
const [selectedCellRange, setSelectedCellRangeState] = useState11(null);
|
|
2873
2901
|
const [isDragging, setIsDragging] = useState11(false);
|
|
2874
2902
|
const [clipboardData, setClipboardData] = useState11(null);
|
|
2875
|
-
const anchorCell =
|
|
2903
|
+
const anchorCell = useRef4(null);
|
|
2876
2904
|
const rowIndexMap = useMemo3(() => {
|
|
2877
2905
|
const map = /* @__PURE__ */ new Map();
|
|
2878
2906
|
data.forEach((row, index) => {
|
|
@@ -3315,6 +3343,7 @@ function Spreadsheet({
|
|
|
3315
3343
|
pageSizeOptions = [25, 50, 100, 200],
|
|
3316
3344
|
defaultZoom = 100,
|
|
3317
3345
|
autoSave = true,
|
|
3346
|
+
onSave,
|
|
3318
3347
|
compactMode = false,
|
|
3319
3348
|
isLoading = false,
|
|
3320
3349
|
className,
|
|
@@ -3399,6 +3428,19 @@ function Spreadsheet({
|
|
|
3399
3428
|
externalCellComments,
|
|
3400
3429
|
onAddCellComment
|
|
3401
3430
|
});
|
|
3431
|
+
const [showSettingsModal, setShowSettingsModal] = useState12(false);
|
|
3432
|
+
const [spreadsheetSettings, setSpreadsheetSettings] = useState12({
|
|
3433
|
+
defaultPinnedColumns: [],
|
|
3434
|
+
defaultSort: null,
|
|
3435
|
+
defaultPageSize,
|
|
3436
|
+
defaultZoom,
|
|
3437
|
+
autoSave,
|
|
3438
|
+
compactView: compactMode,
|
|
3439
|
+
showRowIndex,
|
|
3440
|
+
pinRowIndex: false,
|
|
3441
|
+
rowIndexHighlightColor: void 0
|
|
3442
|
+
});
|
|
3443
|
+
const effectiveAutoSave = spreadsheetSettings.autoSave ?? autoSave;
|
|
3402
3444
|
const {
|
|
3403
3445
|
canUndo,
|
|
3404
3446
|
canRedo,
|
|
@@ -3413,7 +3455,8 @@ function Spreadsheet({
|
|
|
3413
3455
|
markAsChanged
|
|
3414
3456
|
} = useSpreadsheetUndoRedo({
|
|
3415
3457
|
enabled: enableUndoRedo,
|
|
3416
|
-
autoSave
|
|
3458
|
+
autoSave: effectiveAutoSave,
|
|
3459
|
+
onSave
|
|
3417
3460
|
});
|
|
3418
3461
|
const [selectedRows, setSelectedRows] = useState12(/* @__PURE__ */ new Set());
|
|
3419
3462
|
const [lastSelectedRow, setLastSelectedRow] = useState12(null);
|
|
@@ -3444,18 +3487,6 @@ function Spreadsheet({
|
|
|
3444
3487
|
},
|
|
3445
3488
|
[controlledPageSize, controlledCurrentPage, onPageChange]
|
|
3446
3489
|
);
|
|
3447
|
-
const [showSettingsModal, setShowSettingsModal] = useState12(false);
|
|
3448
|
-
const [spreadsheetSettings, setSpreadsheetSettings] = useState12({
|
|
3449
|
-
defaultPinnedColumns: [],
|
|
3450
|
-
defaultSort: null,
|
|
3451
|
-
defaultPageSize,
|
|
3452
|
-
defaultZoom,
|
|
3453
|
-
autoSave,
|
|
3454
|
-
compactView: compactMode,
|
|
3455
|
-
showRowIndex,
|
|
3456
|
-
pinRowIndex: false,
|
|
3457
|
-
rowIndexHighlightColor: void 0
|
|
3458
|
-
});
|
|
3459
3490
|
useEffect6(() => {
|
|
3460
3491
|
setSpreadsheetSettings((prev) => ({
|
|
3461
3492
|
...prev,
|
|
@@ -3621,8 +3652,9 @@ function Spreadsheet({
|
|
|
3621
3652
|
enabled: true
|
|
3622
3653
|
});
|
|
3623
3654
|
const effectiveShowRowIndex = spreadsheetSettings.showRowIndex !== false;
|
|
3655
|
+
const effectiveCompactMode = spreadsheetSettings.compactView ?? compactMode;
|
|
3624
3656
|
const rowIndexHighlightColor = getColumnHighlight(ROW_INDEX_COLUMN_ID);
|
|
3625
|
-
const tableRef =
|
|
3657
|
+
const tableRef = useRef5(null);
|
|
3626
3658
|
const effectiveTotalItems = serverSide ? totalItems ?? data.length : filteredData.length;
|
|
3627
3659
|
const totalPages = Math.max(1, Math.ceil(effectiveTotalItems / pageSize));
|
|
3628
3660
|
useEffect6(() => {
|
|
@@ -3641,8 +3673,9 @@ function Spreadsheet({
|
|
|
3641
3673
|
const start = Math.min(currentIndex, lastIndex);
|
|
3642
3674
|
const end = Math.max(currentIndex, lastIndex);
|
|
3643
3675
|
const newSelection = new Set(selectedRows);
|
|
3644
|
-
|
|
3645
|
-
|
|
3676
|
+
const rangeRows = filteredData.slice(start, end + 1);
|
|
3677
|
+
for (const row of rangeRows) {
|
|
3678
|
+
newSelection.add(getRowId(row));
|
|
3646
3679
|
}
|
|
3647
3680
|
setSelectedRows(newSelection);
|
|
3648
3681
|
onSelectionChange?.(Array.from(newSelection));
|
|
@@ -3747,7 +3780,7 @@ function Spreadsheet({
|
|
|
3747
3780
|
selectedRowCount: selectedRows.size,
|
|
3748
3781
|
hasUnsavedChanges,
|
|
3749
3782
|
saveStatus,
|
|
3750
|
-
autoSave,
|
|
3783
|
+
autoSave: effectiveAutoSave,
|
|
3751
3784
|
hasActiveFilters,
|
|
3752
3785
|
onClearFilters: clearAllFilters,
|
|
3753
3786
|
onZoomIn: () => setZoom((z) => Math.min(z + 10, 200)),
|
|
@@ -3785,7 +3818,8 @@ function Spreadsheet({
|
|
|
3785
3818
|
isPinned: isRowIndexPinned,
|
|
3786
3819
|
onHighlightClick: handleRowIndexHighlightClick,
|
|
3787
3820
|
onPinClick: handleToggleRowIndexPin,
|
|
3788
|
-
hasColumnGroups: true
|
|
3821
|
+
hasColumnGroups: true,
|
|
3822
|
+
compactMode: effectiveCompactMode
|
|
3789
3823
|
}
|
|
3790
3824
|
),
|
|
3791
3825
|
columnGroups.map((group) => {
|
|
@@ -3828,7 +3862,8 @@ function Spreadsheet({
|
|
|
3828
3862
|
isPinned: isRowIndexPinned,
|
|
3829
3863
|
onHighlightClick: handleRowIndexHighlightClick,
|
|
3830
3864
|
onPinClick: handleToggleRowIndexPin,
|
|
3831
|
-
hasColumnGroups: false
|
|
3865
|
+
hasColumnGroups: false,
|
|
3866
|
+
compactMode: effectiveCompactMode
|
|
3832
3867
|
}
|
|
3833
3868
|
),
|
|
3834
3869
|
visibleColumns.map((column) => {
|
|
@@ -3843,7 +3878,7 @@ function Spreadsheet({
|
|
|
3843
3878
|
pinSide: getColumnPinSide(column.id),
|
|
3844
3879
|
leftOffset: isPinnedLeft ? getColumnLeftOffset(column.id) : 0,
|
|
3845
3880
|
highlightColor: getColumnHighlight(column.id),
|
|
3846
|
-
compactMode,
|
|
3881
|
+
compactMode: effectiveCompactMode,
|
|
3847
3882
|
onClick: () => handleSort(column.id),
|
|
3848
3883
|
onFilterClick: () => setActiveFilterColumn(
|
|
3849
3884
|
activeFilterColumn === column.id ? null : column.id
|
|
@@ -3905,6 +3940,7 @@ function Spreadsheet({
|
|
|
3905
3940
|
onClick: (e) => handleRowSelect(rowId, e),
|
|
3906
3941
|
className: cn(
|
|
3907
3942
|
"border border-gray-200 text-center font-semibold cursor-pointer group",
|
|
3943
|
+
effectiveCompactMode ? "text-[10px] px-1 py-px" : "text-xs px-2 py-1",
|
|
3908
3944
|
isRowIndexPinned ? "z-20" : "z-0",
|
|
3909
3945
|
isRowSelected && "bg-blue-100",
|
|
3910
3946
|
!isRowSelected && rowHighlight && "",
|
|
@@ -4076,7 +4112,7 @@ function Spreadsheet({
|
|
|
4076
4112
|
isRowSelected,
|
|
4077
4113
|
isRowHovered,
|
|
4078
4114
|
highlightColor: cellOrRowOrColumnHighlight,
|
|
4079
|
-
compactMode,
|
|
4115
|
+
compactMode: effectiveCompactMode,
|
|
4080
4116
|
isPinned: isColPinned,
|
|
4081
4117
|
pinSide: colPinSide,
|
|
4082
4118
|
leftOffset: getColumnLeftOffset(column.id),
|