@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.d.mts
CHANGED
|
@@ -303,6 +303,8 @@ interface SpreadsheetProps<T = any> {
|
|
|
303
303
|
defaultZoom?: number;
|
|
304
304
|
/** Whether to auto-save changes */
|
|
305
305
|
autoSave?: boolean;
|
|
306
|
+
/** Callback when changes are saved (called for both auto-save and manual save) */
|
|
307
|
+
onSave?: () => void | Promise<void>;
|
|
306
308
|
/** Whether to use compact mode (smaller cells) */
|
|
307
309
|
compactMode?: boolean;
|
|
308
310
|
/** Loading state */
|
|
@@ -604,7 +606,7 @@ interface SpreadsheetColumnGroupHeaderProps {
|
|
|
604
606
|
* />
|
|
605
607
|
* ```
|
|
606
608
|
*/
|
|
607
|
-
declare function Spreadsheet<T extends Record<string, any>>({ data, columns, columnGroups, getRowId, onCellsEdit, onSelectionChange, onSortChange, onFilterChange, onRowClick, onRowDoubleClick, onRowClone, onRowDelete, onAddCellComment, onRowHighlight, showToolbar, showPagination, showRowIndex, enableRowSelection, enableCellEditing, enableComments, enableHighlighting, enableUndoRedo, defaultPageSize, pageSizeOptions, defaultZoom, autoSave, compactMode, isLoading, className, emptyMessage, rowHighlights: externalRowHighlights, cellComments: externalCellComments, rowActions, toolbarMenuItems, serverSide, totalItems, currentPage: controlledCurrentPage, pageSize: controlledPageSize, onPageChange, sortConfig: controlledSortConfig, filters: controlledFilters, }: SpreadsheetProps<T>): react_jsx_runtime.JSX.Element;
|
|
609
|
+
declare function Spreadsheet<T extends Record<string, any>>({ data, columns, columnGroups, getRowId, onCellsEdit, onSelectionChange, onSortChange, onFilterChange, onRowClick, onRowDoubleClick, onRowClone, onRowDelete, onAddCellComment, onRowHighlight, showToolbar, showPagination, showRowIndex, enableRowSelection, enableCellEditing, enableComments, enableHighlighting, enableUndoRedo, defaultPageSize, pageSizeOptions, defaultZoom, autoSave, onSave, compactMode, isLoading, className, emptyMessage, rowHighlights: externalRowHighlights, cellComments: externalCellComments, rowActions, toolbarMenuItems, serverSide, totalItems, currentPage: controlledCurrentPage, pageSize: controlledPageSize, onPageChange, sortConfig: controlledSortConfig, filters: controlledFilters, }: SpreadsheetProps<T>): react_jsx_runtime.JSX.Element;
|
|
608
610
|
declare namespace Spreadsheet {
|
|
609
611
|
var displayName: string;
|
|
610
612
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -303,6 +303,8 @@ interface SpreadsheetProps<T = any> {
|
|
|
303
303
|
defaultZoom?: number;
|
|
304
304
|
/** Whether to auto-save changes */
|
|
305
305
|
autoSave?: boolean;
|
|
306
|
+
/** Callback when changes are saved (called for both auto-save and manual save) */
|
|
307
|
+
onSave?: () => void | Promise<void>;
|
|
306
308
|
/** Whether to use compact mode (smaller cells) */
|
|
307
309
|
compactMode?: boolean;
|
|
308
310
|
/** Loading state */
|
|
@@ -604,7 +606,7 @@ interface SpreadsheetColumnGroupHeaderProps {
|
|
|
604
606
|
* />
|
|
605
607
|
* ```
|
|
606
608
|
*/
|
|
607
|
-
declare function Spreadsheet<T extends Record<string, any>>({ data, columns, columnGroups, getRowId, onCellsEdit, onSelectionChange, onSortChange, onFilterChange, onRowClick, onRowDoubleClick, onRowClone, onRowDelete, onAddCellComment, onRowHighlight, showToolbar, showPagination, showRowIndex, enableRowSelection, enableCellEditing, enableComments, enableHighlighting, enableUndoRedo, defaultPageSize, pageSizeOptions, defaultZoom, autoSave, compactMode, isLoading, className, emptyMessage, rowHighlights: externalRowHighlights, cellComments: externalCellComments, rowActions, toolbarMenuItems, serverSide, totalItems, currentPage: controlledCurrentPage, pageSize: controlledPageSize, onPageChange, sortConfig: controlledSortConfig, filters: controlledFilters, }: SpreadsheetProps<T>): react_jsx_runtime.JSX.Element;
|
|
609
|
+
declare function Spreadsheet<T extends Record<string, any>>({ data, columns, columnGroups, getRowId, onCellsEdit, onSelectionChange, onSortChange, onFilterChange, onRowClick, onRowDoubleClick, onRowClone, onRowDelete, onAddCellComment, onRowHighlight, showToolbar, showPagination, showRowIndex, enableRowSelection, enableCellEditing, enableComments, enableHighlighting, enableUndoRedo, defaultPageSize, pageSizeOptions, defaultZoom, autoSave, onSave, compactMode, isLoading, className, emptyMessage, rowHighlights: externalRowHighlights, cellComments: externalCellComments, rowActions, toolbarMenuItems, serverSide, totalItems, currentPage: controlledCurrentPage, pageSize: controlledPageSize, onPageChange, sortConfig: controlledSortConfig, filters: controlledFilters, }: SpreadsheetProps<T>): react_jsx_runtime.JSX.Element;
|
|
608
610
|
declare namespace Spreadsheet {
|
|
609
611
|
var displayName: string;
|
|
610
612
|
}
|
package/dist/index.js
CHANGED
|
@@ -194,7 +194,7 @@ function cn(...inputs) {
|
|
|
194
194
|
// src/components/SpreadsheetCell.tsx
|
|
195
195
|
var import_react3 = require("react");
|
|
196
196
|
var import_jsx_runtime = require("react/jsx-runtime");
|
|
197
|
-
var cellPaddingCompact = "px-1
|
|
197
|
+
var cellPaddingCompact = "px-1 py-px";
|
|
198
198
|
var cellPaddingNormal = "px-2 py-1";
|
|
199
199
|
var SpreadsheetCell = ({
|
|
200
200
|
value,
|
|
@@ -370,7 +370,8 @@ var SpreadsheetCell = ({
|
|
|
370
370
|
onKeyDown: handleCellKeyDown,
|
|
371
371
|
"data-cell-id": `${rowId}-${column.id}`,
|
|
372
372
|
className: cn(
|
|
373
|
-
"border border-gray-200
|
|
373
|
+
"border border-gray-200 group cursor-pointer transition-colors select-none",
|
|
374
|
+
compactMode ? "text-[10px]" : "text-xs",
|
|
374
375
|
cellPadding,
|
|
375
376
|
column.align === "right" && "text-right",
|
|
376
377
|
column.align === "center" && "text-center",
|
|
@@ -1189,7 +1190,7 @@ ColumnHeaderActions.displayName = "ColumnHeaderActions";
|
|
|
1189
1190
|
|
|
1190
1191
|
// src/components/SpreadsheetHeader.tsx
|
|
1191
1192
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
1192
|
-
var cellPaddingCompact2 = "px-1
|
|
1193
|
+
var cellPaddingCompact2 = "px-1 py-0.5";
|
|
1193
1194
|
var cellPaddingNormal2 = "px-2 py-1.5";
|
|
1194
1195
|
var SpreadsheetHeader = ({
|
|
1195
1196
|
column,
|
|
@@ -1225,7 +1226,8 @@ var SpreadsheetHeader = ({
|
|
|
1225
1226
|
{
|
|
1226
1227
|
onClick: column.sortable ? onClick : void 0,
|
|
1227
1228
|
className: cn(
|
|
1228
|
-
"border border-gray-200
|
|
1229
|
+
"border border-gray-200 font-semibold text-gray-700 sticky group",
|
|
1230
|
+
compactMode ? "text-[10px]" : "text-xs",
|
|
1229
1231
|
cellPadding,
|
|
1230
1232
|
column.align === "right" && "text-right",
|
|
1231
1233
|
column.align === "center" && "text-center",
|
|
@@ -1395,6 +1397,8 @@ function useSpreadsheetPinning({
|
|
|
1395
1397
|
|
|
1396
1398
|
// src/components/RowIndexColumnHeader.tsx
|
|
1397
1399
|
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
1400
|
+
var cellPaddingCompact3 = "px-1 py-0.5";
|
|
1401
|
+
var cellPaddingNormal3 = "px-2 py-1.5";
|
|
1398
1402
|
function RowIndexColumnHeader({
|
|
1399
1403
|
enableHighlighting = false,
|
|
1400
1404
|
highlightColor,
|
|
@@ -1402,13 +1406,17 @@ function RowIndexColumnHeader({
|
|
|
1402
1406
|
onHighlightClick,
|
|
1403
1407
|
onPinClick,
|
|
1404
1408
|
hasColumnGroups = false,
|
|
1409
|
+
compactMode = false,
|
|
1405
1410
|
className
|
|
1406
1411
|
}) {
|
|
1412
|
+
const cellPadding = compactMode ? cellPaddingCompact3 : cellPaddingNormal3;
|
|
1407
1413
|
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1408
1414
|
"th",
|
|
1409
1415
|
{
|
|
1410
1416
|
className: cn(
|
|
1411
|
-
"border border-gray-200
|
|
1417
|
+
"border border-gray-200 text-center font-bold text-gray-700 group",
|
|
1418
|
+
compactMode ? "text-[10px]" : "text-xs",
|
|
1419
|
+
cellPadding,
|
|
1412
1420
|
isPinned ? "z-30" : "z-20",
|
|
1413
1421
|
className
|
|
1414
1422
|
),
|
|
@@ -2646,12 +2654,15 @@ var import_react13 = require("react");
|
|
|
2646
2654
|
function useSpreadsheetUndoRedo({
|
|
2647
2655
|
enabled = true,
|
|
2648
2656
|
maxStackSize = 50,
|
|
2649
|
-
autoSave = true
|
|
2657
|
+
autoSave = true,
|
|
2658
|
+
onSave
|
|
2650
2659
|
}) {
|
|
2651
2660
|
const [undoStack, setUndoStack] = (0, import_react13.useState)([]);
|
|
2652
2661
|
const [redoStack, setRedoStack] = (0, import_react13.useState)([]);
|
|
2653
2662
|
const [hasUnsavedChanges, setHasUnsavedChanges] = (0, import_react13.useState)(false);
|
|
2654
2663
|
const [saveStatus, setSaveStatus] = (0, import_react13.useState)("saved");
|
|
2664
|
+
const onSaveRef = (0, import_react13.useRef)(onSave);
|
|
2665
|
+
onSaveRef.current = onSave;
|
|
2655
2666
|
const pushToUndoStack = (0, import_react13.useCallback)(
|
|
2656
2667
|
(snapshot) => {
|
|
2657
2668
|
if (!enabled) return;
|
|
@@ -2692,19 +2703,36 @@ function useSpreadsheetUndoRedo({
|
|
|
2692
2703
|
});
|
|
2693
2704
|
return nextSnapshot;
|
|
2694
2705
|
}, [enabled, redoStack, maxStackSize]);
|
|
2695
|
-
const handleSave = (0, import_react13.useCallback)(() => {
|
|
2696
|
-
if (!hasUnsavedChanges) return;
|
|
2706
|
+
const handleSave = (0, import_react13.useCallback)(async () => {
|
|
2707
|
+
if (!hasUnsavedChanges && !autoSave) return;
|
|
2697
2708
|
setSaveStatus("saving");
|
|
2698
|
-
|
|
2709
|
+
try {
|
|
2710
|
+
if (onSaveRef.current) {
|
|
2711
|
+
await onSaveRef.current();
|
|
2712
|
+
}
|
|
2699
2713
|
setSaveStatus("saved");
|
|
2700
2714
|
setHasUnsavedChanges(false);
|
|
2701
|
-
}
|
|
2702
|
-
|
|
2715
|
+
} catch {
|
|
2716
|
+
setSaveStatus("error");
|
|
2717
|
+
}
|
|
2718
|
+
}, [hasUnsavedChanges, autoSave]);
|
|
2703
2719
|
const markAsChanged = (0, import_react13.useCallback)(() => {
|
|
2704
2720
|
setHasUnsavedChanges(true);
|
|
2705
2721
|
if (autoSave) {
|
|
2706
2722
|
setSaveStatus("saving");
|
|
2707
|
-
|
|
2723
|
+
if (onSaveRef.current) {
|
|
2724
|
+
Promise.resolve(onSaveRef.current()).then(() => {
|
|
2725
|
+
setSaveStatus("saved");
|
|
2726
|
+
setHasUnsavedChanges(false);
|
|
2727
|
+
}).catch(() => {
|
|
2728
|
+
setSaveStatus("error");
|
|
2729
|
+
});
|
|
2730
|
+
} else {
|
|
2731
|
+
setTimeout(() => {
|
|
2732
|
+
setSaveStatus("saved");
|
|
2733
|
+
setHasUnsavedChanges(false);
|
|
2734
|
+
}, 500);
|
|
2735
|
+
}
|
|
2708
2736
|
} else {
|
|
2709
2737
|
setSaveStatus("unsaved");
|
|
2710
2738
|
}
|
|
@@ -3356,6 +3384,7 @@ function Spreadsheet({
|
|
|
3356
3384
|
pageSizeOptions = [25, 50, 100, 200],
|
|
3357
3385
|
defaultZoom = 100,
|
|
3358
3386
|
autoSave = true,
|
|
3387
|
+
onSave,
|
|
3359
3388
|
compactMode = false,
|
|
3360
3389
|
isLoading = false,
|
|
3361
3390
|
className,
|
|
@@ -3440,6 +3469,19 @@ function Spreadsheet({
|
|
|
3440
3469
|
externalCellComments,
|
|
3441
3470
|
onAddCellComment
|
|
3442
3471
|
});
|
|
3472
|
+
const [showSettingsModal, setShowSettingsModal] = (0, import_react16.useState)(false);
|
|
3473
|
+
const [spreadsheetSettings, setSpreadsheetSettings] = (0, import_react16.useState)({
|
|
3474
|
+
defaultPinnedColumns: [],
|
|
3475
|
+
defaultSort: null,
|
|
3476
|
+
defaultPageSize,
|
|
3477
|
+
defaultZoom,
|
|
3478
|
+
autoSave,
|
|
3479
|
+
compactView: compactMode,
|
|
3480
|
+
showRowIndex,
|
|
3481
|
+
pinRowIndex: false,
|
|
3482
|
+
rowIndexHighlightColor: void 0
|
|
3483
|
+
});
|
|
3484
|
+
const effectiveAutoSave = spreadsheetSettings.autoSave ?? autoSave;
|
|
3443
3485
|
const {
|
|
3444
3486
|
canUndo,
|
|
3445
3487
|
canRedo,
|
|
@@ -3454,7 +3496,8 @@ function Spreadsheet({
|
|
|
3454
3496
|
markAsChanged
|
|
3455
3497
|
} = useSpreadsheetUndoRedo({
|
|
3456
3498
|
enabled: enableUndoRedo,
|
|
3457
|
-
autoSave
|
|
3499
|
+
autoSave: effectiveAutoSave,
|
|
3500
|
+
onSave
|
|
3458
3501
|
});
|
|
3459
3502
|
const [selectedRows, setSelectedRows] = (0, import_react16.useState)(/* @__PURE__ */ new Set());
|
|
3460
3503
|
const [lastSelectedRow, setLastSelectedRow] = (0, import_react16.useState)(null);
|
|
@@ -3485,18 +3528,6 @@ function Spreadsheet({
|
|
|
3485
3528
|
},
|
|
3486
3529
|
[controlledPageSize, controlledCurrentPage, onPageChange]
|
|
3487
3530
|
);
|
|
3488
|
-
const [showSettingsModal, setShowSettingsModal] = (0, import_react16.useState)(false);
|
|
3489
|
-
const [spreadsheetSettings, setSpreadsheetSettings] = (0, import_react16.useState)({
|
|
3490
|
-
defaultPinnedColumns: [],
|
|
3491
|
-
defaultSort: null,
|
|
3492
|
-
defaultPageSize,
|
|
3493
|
-
defaultZoom,
|
|
3494
|
-
autoSave,
|
|
3495
|
-
compactView: compactMode,
|
|
3496
|
-
showRowIndex,
|
|
3497
|
-
pinRowIndex: false,
|
|
3498
|
-
rowIndexHighlightColor: void 0
|
|
3499
|
-
});
|
|
3500
3531
|
(0, import_react16.useEffect)(() => {
|
|
3501
3532
|
setSpreadsheetSettings((prev) => ({
|
|
3502
3533
|
...prev,
|
|
@@ -3662,6 +3693,7 @@ function Spreadsheet({
|
|
|
3662
3693
|
enabled: true
|
|
3663
3694
|
});
|
|
3664
3695
|
const effectiveShowRowIndex = spreadsheetSettings.showRowIndex !== false;
|
|
3696
|
+
const effectiveCompactMode = spreadsheetSettings.compactView ?? compactMode;
|
|
3665
3697
|
const rowIndexHighlightColor = getColumnHighlight(ROW_INDEX_COLUMN_ID);
|
|
3666
3698
|
const tableRef = (0, import_react16.useRef)(null);
|
|
3667
3699
|
const effectiveTotalItems = serverSide ? totalItems ?? data.length : filteredData.length;
|
|
@@ -3682,8 +3714,9 @@ function Spreadsheet({
|
|
|
3682
3714
|
const start = Math.min(currentIndex, lastIndex);
|
|
3683
3715
|
const end = Math.max(currentIndex, lastIndex);
|
|
3684
3716
|
const newSelection = new Set(selectedRows);
|
|
3685
|
-
|
|
3686
|
-
|
|
3717
|
+
const rangeRows = filteredData.slice(start, end + 1);
|
|
3718
|
+
for (const row of rangeRows) {
|
|
3719
|
+
newSelection.add(getRowId(row));
|
|
3687
3720
|
}
|
|
3688
3721
|
setSelectedRows(newSelection);
|
|
3689
3722
|
onSelectionChange?.(Array.from(newSelection));
|
|
@@ -3788,7 +3821,7 @@ function Spreadsheet({
|
|
|
3788
3821
|
selectedRowCount: selectedRows.size,
|
|
3789
3822
|
hasUnsavedChanges,
|
|
3790
3823
|
saveStatus,
|
|
3791
|
-
autoSave,
|
|
3824
|
+
autoSave: effectiveAutoSave,
|
|
3792
3825
|
hasActiveFilters,
|
|
3793
3826
|
onClearFilters: clearAllFilters,
|
|
3794
3827
|
onZoomIn: () => setZoom((z) => Math.min(z + 10, 200)),
|
|
@@ -3826,7 +3859,8 @@ function Spreadsheet({
|
|
|
3826
3859
|
isPinned: isRowIndexPinned,
|
|
3827
3860
|
onHighlightClick: handleRowIndexHighlightClick,
|
|
3828
3861
|
onPinClick: handleToggleRowIndexPin,
|
|
3829
|
-
hasColumnGroups: true
|
|
3862
|
+
hasColumnGroups: true,
|
|
3863
|
+
compactMode: effectiveCompactMode
|
|
3830
3864
|
}
|
|
3831
3865
|
),
|
|
3832
3866
|
columnGroups.map((group) => {
|
|
@@ -3869,7 +3903,8 @@ function Spreadsheet({
|
|
|
3869
3903
|
isPinned: isRowIndexPinned,
|
|
3870
3904
|
onHighlightClick: handleRowIndexHighlightClick,
|
|
3871
3905
|
onPinClick: handleToggleRowIndexPin,
|
|
3872
|
-
hasColumnGroups: false
|
|
3906
|
+
hasColumnGroups: false,
|
|
3907
|
+
compactMode: effectiveCompactMode
|
|
3873
3908
|
}
|
|
3874
3909
|
),
|
|
3875
3910
|
visibleColumns.map((column) => {
|
|
@@ -3884,7 +3919,7 @@ function Spreadsheet({
|
|
|
3884
3919
|
pinSide: getColumnPinSide(column.id),
|
|
3885
3920
|
leftOffset: isPinnedLeft ? getColumnLeftOffset(column.id) : 0,
|
|
3886
3921
|
highlightColor: getColumnHighlight(column.id),
|
|
3887
|
-
compactMode,
|
|
3922
|
+
compactMode: effectiveCompactMode,
|
|
3888
3923
|
onClick: () => handleSort(column.id),
|
|
3889
3924
|
onFilterClick: () => setActiveFilterColumn(
|
|
3890
3925
|
activeFilterColumn === column.id ? null : column.id
|
|
@@ -3946,6 +3981,7 @@ function Spreadsheet({
|
|
|
3946
3981
|
onClick: (e) => handleRowSelect(rowId, e),
|
|
3947
3982
|
className: cn(
|
|
3948
3983
|
"border border-gray-200 text-center font-semibold cursor-pointer group",
|
|
3984
|
+
effectiveCompactMode ? "text-[10px] px-1 py-px" : "text-xs px-2 py-1",
|
|
3949
3985
|
isRowIndexPinned ? "z-20" : "z-0",
|
|
3950
3986
|
isRowSelected && "bg-blue-100",
|
|
3951
3987
|
!isRowSelected && rowHighlight && "",
|
|
@@ -4117,7 +4153,7 @@ function Spreadsheet({
|
|
|
4117
4153
|
isRowSelected,
|
|
4118
4154
|
isRowHovered,
|
|
4119
4155
|
highlightColor: cellOrRowOrColumnHighlight,
|
|
4120
|
-
compactMode,
|
|
4156
|
+
compactMode: effectiveCompactMode,
|
|
4121
4157
|
isPinned: isColPinned,
|
|
4122
4158
|
pinSide: colPinSide,
|
|
4123
4159
|
leftOffset: getColumnLeftOffset(column.id),
|