@xcelsior/ui-spreadsheets 1.0.18 → 1.1.0
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 +25 -17
- package/dist/index.d.ts +25 -17
- package/dist/index.js +62 -124
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +62 -124
- package/dist/index.mjs.map +1 -1
- package/dist/styles/globals.css +14 -49
- package/dist/styles/globals.css.map +1 -1
- package/package.json +1 -1
- package/src/components/Spreadsheet.stories.tsx +0 -26
- package/src/components/Spreadsheet.tsx +190 -210
- package/src/components/SpreadsheetCell.tsx +7 -7
- package/src/components/SpreadsheetSettingsModal.tsx +3 -110
- package/src/hooks/index.ts +0 -2
- package/src/hooks/useSpreadsheetHighlighting.ts +0 -3
- package/src/hooks/useSpreadsheetPinning.ts +31 -4
- package/src/types.ts +24 -10
|
@@ -18,12 +18,6 @@ export interface SpreadsheetSettings {
|
|
|
18
18
|
autoSave?: boolean;
|
|
19
19
|
/** Whether compact view is enabled */
|
|
20
20
|
compactView?: boolean;
|
|
21
|
-
/** Whether to show row index column */
|
|
22
|
-
showRowIndex?: boolean;
|
|
23
|
-
/** Whether row index column is pinned */
|
|
24
|
-
pinRowIndex?: boolean;
|
|
25
|
-
/** Row index column highlight color */
|
|
26
|
-
rowIndexHighlightColor?: string;
|
|
27
21
|
}
|
|
28
22
|
|
|
29
23
|
export interface SpreadsheetSettingsModalProps {
|
|
@@ -50,9 +44,6 @@ const DEFAULT_SETTINGS: SpreadsheetSettings = {
|
|
|
50
44
|
defaultZoom: 100,
|
|
51
45
|
autoSave: true,
|
|
52
46
|
compactView: false,
|
|
53
|
-
showRowIndex: true,
|
|
54
|
-
pinRowIndex: false,
|
|
55
|
-
rowIndexHighlightColor: undefined,
|
|
56
47
|
};
|
|
57
48
|
|
|
58
49
|
/**
|
|
@@ -221,17 +212,12 @@ export const SpreadsheetSettingsModal: React.FC<SpreadsheetSettingsModalProps> =
|
|
|
221
212
|
Select which columns should be pinned to the left by default.
|
|
222
213
|
</p>
|
|
223
214
|
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-2">
|
|
224
|
-
{/* Row Index Column
|
|
215
|
+
{/* Row Index Column */}
|
|
225
216
|
<button
|
|
226
217
|
type="button"
|
|
227
|
-
onClick={() =>
|
|
228
|
-
setLocalSettings({
|
|
229
|
-
...localSettings,
|
|
230
|
-
pinRowIndex: !localSettings.pinRowIndex,
|
|
231
|
-
})
|
|
232
|
-
}
|
|
218
|
+
onClick={() => togglePinnedColumn('__row_index__')}
|
|
233
219
|
className={`flex items-center gap-2 p-3 rounded-lg border transition-colors text-left ${
|
|
234
|
-
localSettings.
|
|
220
|
+
localSettings.defaultPinnedColumns.includes('__row_index__')
|
|
235
221
|
? 'bg-blue-50 border-blue-300 text-blue-700'
|
|
236
222
|
: 'bg-gray-50 border-gray-200 text-gray-700 hover:border-blue-300'
|
|
237
223
|
}`}
|
|
@@ -263,69 +249,6 @@ export const SpreadsheetSettingsModal: React.FC<SpreadsheetSettingsModalProps> =
|
|
|
263
249
|
);
|
|
264
250
|
})}
|
|
265
251
|
</div>
|
|
266
|
-
|
|
267
|
-
{/* Row Index Highlight */}
|
|
268
|
-
<div className="mt-6 p-4 bg-amber-50 border border-amber-200 rounded-lg">
|
|
269
|
-
<p className="text-sm font-semibold text-gray-900 mb-3">
|
|
270
|
-
Row Index Column Highlight
|
|
271
|
-
</p>
|
|
272
|
-
<p className="text-sm text-gray-600 mb-3">
|
|
273
|
-
Apply a highlight color to the # (row index) column to make it
|
|
274
|
-
stand out.
|
|
275
|
-
</p>
|
|
276
|
-
<div className="flex items-center gap-2 flex-wrap">
|
|
277
|
-
{[
|
|
278
|
-
'#fef3c7',
|
|
279
|
-
'#dbeafe',
|
|
280
|
-
'#dcfce7',
|
|
281
|
-
'#fce7f3',
|
|
282
|
-
'#f3e8ff',
|
|
283
|
-
'#e0e7ff',
|
|
284
|
-
'#fed7d7',
|
|
285
|
-
'#c6f6d5',
|
|
286
|
-
].map((color) => (
|
|
287
|
-
<button
|
|
288
|
-
key={color}
|
|
289
|
-
type="button"
|
|
290
|
-
onClick={() =>
|
|
291
|
-
setLocalSettings({
|
|
292
|
-
...localSettings,
|
|
293
|
-
rowIndexHighlightColor:
|
|
294
|
-
localSettings.rowIndexHighlightColor ===
|
|
295
|
-
color
|
|
296
|
-
? undefined
|
|
297
|
-
: color,
|
|
298
|
-
})
|
|
299
|
-
}
|
|
300
|
-
className={`w-8 h-8 rounded-lg border-2 transition-all ${
|
|
301
|
-
localSettings.rowIndexHighlightColor === color
|
|
302
|
-
? 'border-blue-600 scale-110 ring-2 ring-blue-300'
|
|
303
|
-
: 'border-gray-300 hover:border-gray-400'
|
|
304
|
-
}`}
|
|
305
|
-
style={{ backgroundColor: color }}
|
|
306
|
-
title={
|
|
307
|
-
localSettings.rowIndexHighlightColor === color
|
|
308
|
-
? 'Remove highlight'
|
|
309
|
-
: 'Apply highlight'
|
|
310
|
-
}
|
|
311
|
-
/>
|
|
312
|
-
))}
|
|
313
|
-
{localSettings.rowIndexHighlightColor && (
|
|
314
|
-
<button
|
|
315
|
-
type="button"
|
|
316
|
-
onClick={() =>
|
|
317
|
-
setLocalSettings({
|
|
318
|
-
...localSettings,
|
|
319
|
-
rowIndexHighlightColor: undefined,
|
|
320
|
-
})
|
|
321
|
-
}
|
|
322
|
-
className="text-sm text-red-600 hover:text-red-700 ml-2 px-2 py-1 rounded hover:bg-red-50"
|
|
323
|
-
>
|
|
324
|
-
Clear
|
|
325
|
-
</button>
|
|
326
|
-
)}
|
|
327
|
-
</div>
|
|
328
|
-
</div>
|
|
329
252
|
</div>
|
|
330
253
|
)}
|
|
331
254
|
|
|
@@ -393,36 +316,6 @@ export const SpreadsheetSettingsModal: React.FC<SpreadsheetSettingsModalProps> =
|
|
|
393
316
|
Customize the display and behavior of the spreadsheet.
|
|
394
317
|
</p>
|
|
395
318
|
|
|
396
|
-
{/* Row Index Options */}
|
|
397
|
-
<div className="p-4 bg-blue-50 border border-blue-200 rounded-lg">
|
|
398
|
-
<p className="text-sm font-semibold text-gray-900 mb-3">
|
|
399
|
-
Row Index Column
|
|
400
|
-
</p>
|
|
401
|
-
<div className="space-y-3">
|
|
402
|
-
{/* Show Row Index */}
|
|
403
|
-
<label className="flex items-center gap-3 cursor-pointer">
|
|
404
|
-
<input
|
|
405
|
-
type="checkbox"
|
|
406
|
-
checked={localSettings.showRowIndex !== false}
|
|
407
|
-
onChange={(e) =>
|
|
408
|
-
setLocalSettings({
|
|
409
|
-
...localSettings,
|
|
410
|
-
showRowIndex: e.target.checked,
|
|
411
|
-
})
|
|
412
|
-
}
|
|
413
|
-
className="w-4 h-4 cursor-pointer rounded border-gray-300 text-blue-600 focus:ring-blue-500"
|
|
414
|
-
/>
|
|
415
|
-
<span className="text-sm text-gray-700">
|
|
416
|
-
Show row index (#) column
|
|
417
|
-
</span>
|
|
418
|
-
</label>
|
|
419
|
-
<p className="text-xs text-gray-500 ml-7">
|
|
420
|
-
Tip: Use the "Pinned Columns" tab to pin and highlight the
|
|
421
|
-
row index column.
|
|
422
|
-
</p>
|
|
423
|
-
</div>
|
|
424
|
-
</div>
|
|
425
|
-
|
|
426
319
|
{/* Page Size */}
|
|
427
320
|
<div>
|
|
428
321
|
<label className="block text-sm font-medium text-gray-900 mb-2">
|
package/src/hooks/index.ts
CHANGED
|
@@ -7,7 +7,6 @@ export {
|
|
|
7
7
|
export {
|
|
8
8
|
useSpreadsheetHighlighting,
|
|
9
9
|
HIGHLIGHT_COLORS,
|
|
10
|
-
ROW_INDEX_COLUMN_ID,
|
|
11
10
|
type UseSpreadsheetHighlightingOptions,
|
|
12
11
|
type UseSpreadsheetHighlightingReturn,
|
|
13
12
|
} from './useSpreadsheetHighlighting';
|
|
@@ -15,7 +14,6 @@ export {
|
|
|
15
14
|
export {
|
|
16
15
|
useSpreadsheetPinning,
|
|
17
16
|
ROW_INDEX_COLUMN_WIDTH,
|
|
18
|
-
ROW_INDEX_COLUMN_ID as PINNING_ROW_INDEX_COLUMN_ID,
|
|
19
17
|
type UseSpreadsheetPinningOptions,
|
|
20
18
|
type UseSpreadsheetPinningReturn,
|
|
21
19
|
} from './useSpreadsheetPinning';
|
|
@@ -68,9 +68,6 @@ export interface UseSpreadsheetHighlightingReturn {
|
|
|
68
68
|
clearAllHighlights: () => void;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
// Special column ID for row index
|
|
72
|
-
export const ROW_INDEX_COLUMN_ID = '__row_index__';
|
|
73
|
-
|
|
74
71
|
export function useSpreadsheetHighlighting({
|
|
75
72
|
externalRowHighlights,
|
|
76
73
|
onRowHighlight,
|
|
@@ -3,7 +3,7 @@ import type { SpreadsheetColumn, SpreadsheetColumnGroup } from '../types';
|
|
|
3
3
|
|
|
4
4
|
// Special column ID for row index
|
|
5
5
|
export const ROW_INDEX_COLUMN_ID = '__row_index__';
|
|
6
|
-
export const ROW_INDEX_COLUMN_WIDTH =
|
|
6
|
+
export const ROW_INDEX_COLUMN_WIDTH = 80;
|
|
7
7
|
|
|
8
8
|
export interface UseSpreadsheetPinningOptions<T> {
|
|
9
9
|
columns: SpreadsheetColumn<T>[];
|
|
@@ -28,6 +28,8 @@ export interface UseSpreadsheetPinningReturn<T> {
|
|
|
28
28
|
handleTogglePin: (columnId: string) => void;
|
|
29
29
|
handleToggleRowIndexPin: () => void;
|
|
30
30
|
handleToggleGroupCollapse: (groupId: string) => void;
|
|
31
|
+
setPinnedColumnsFromIds: (columnIds: string[]) => void;
|
|
32
|
+
setRowIndexPinned: (pinned: boolean) => void;
|
|
31
33
|
|
|
32
34
|
// Offset calculations
|
|
33
35
|
getColumnLeftOffset: (columnId: string) => number;
|
|
@@ -45,16 +47,21 @@ export function useSpreadsheetPinning<T>({
|
|
|
45
47
|
defaultPinnedColumns = [],
|
|
46
48
|
defaultPinRowIndex = false,
|
|
47
49
|
}: UseSpreadsheetPinningOptions<T>): UseSpreadsheetPinningReturn<T> {
|
|
48
|
-
// Initialize pinned columns from defaults
|
|
50
|
+
// Initialize pinned columns from defaults (excluding row index which is handled separately)
|
|
49
51
|
const [pinnedColumns, setPinnedColumns] = useState<Map<string, 'left' | 'right'>>(() => {
|
|
50
52
|
const map = new Map<string, 'left' | 'right'>();
|
|
51
53
|
defaultPinnedColumns.forEach((col) => {
|
|
52
|
-
|
|
54
|
+
if (col !== ROW_INDEX_COLUMN_ID) {
|
|
55
|
+
map.set(col, 'left');
|
|
56
|
+
}
|
|
53
57
|
});
|
|
54
58
|
return map;
|
|
55
59
|
});
|
|
56
60
|
|
|
57
|
-
|
|
61
|
+
// Check if row index should be pinned from either defaultPinRowIndex or defaultPinnedColumns
|
|
62
|
+
const [isRowIndexPinned, setIsRowIndexPinned] = useState(
|
|
63
|
+
defaultPinRowIndex || defaultPinnedColumns.includes(ROW_INDEX_COLUMN_ID)
|
|
64
|
+
);
|
|
58
65
|
const [collapsedGroups, setCollapsedGroups] = useState<Set<string>>(new Set());
|
|
59
66
|
|
|
60
67
|
// Toggle column pin
|
|
@@ -75,6 +82,24 @@ export function useSpreadsheetPinning<T>({
|
|
|
75
82
|
setIsRowIndexPinned((prev) => !prev);
|
|
76
83
|
}, []);
|
|
77
84
|
|
|
85
|
+
// Set pinned columns from an array of column IDs
|
|
86
|
+
const setPinnedColumnsFromIds = useCallback((columnIds: string[]) => {
|
|
87
|
+
const map = new Map<string, 'left' | 'right'>();
|
|
88
|
+
columnIds.forEach((col) => {
|
|
89
|
+
if (col !== ROW_INDEX_COLUMN_ID) {
|
|
90
|
+
map.set(col, 'left');
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
setPinnedColumns(map);
|
|
94
|
+
// Also update row index pinned state
|
|
95
|
+
setIsRowIndexPinned(columnIds.includes(ROW_INDEX_COLUMN_ID));
|
|
96
|
+
}, []);
|
|
97
|
+
|
|
98
|
+
// Set row index pinned state directly
|
|
99
|
+
const setRowIndexPinned = useCallback((pinned: boolean) => {
|
|
100
|
+
setIsRowIndexPinned(pinned);
|
|
101
|
+
}, []);
|
|
102
|
+
|
|
78
103
|
// Toggle group collapse
|
|
79
104
|
const handleToggleGroupCollapse = useCallback((groupId: string) => {
|
|
80
105
|
setCollapsedGroups((prev) => {
|
|
@@ -195,6 +220,8 @@ export function useSpreadsheetPinning<T>({
|
|
|
195
220
|
handleTogglePin,
|
|
196
221
|
handleToggleRowIndexPin,
|
|
197
222
|
handleToggleGroupCollapse,
|
|
223
|
+
setPinnedColumnsFromIds,
|
|
224
|
+
setRowIndexPinned,
|
|
198
225
|
getColumnLeftOffset,
|
|
199
226
|
getRowIndexLeftOffset,
|
|
200
227
|
isColumnPinned,
|
package/src/types.ts
CHANGED
|
@@ -344,8 +344,6 @@ export interface SpreadsheetProps<T = any> {
|
|
|
344
344
|
showToolbar?: boolean;
|
|
345
345
|
/** Whether to show pagination */
|
|
346
346
|
showPagination?: boolean;
|
|
347
|
-
/** Whether to show row index column (#) */
|
|
348
|
-
showRowIndex?: boolean;
|
|
349
347
|
/** Whether to enable row selection */
|
|
350
348
|
enableRowSelection?: boolean;
|
|
351
349
|
/** Whether to enable cell editing */
|
|
@@ -356,18 +354,34 @@ export interface SpreadsheetProps<T = any> {
|
|
|
356
354
|
enableHighlighting?: boolean;
|
|
357
355
|
/** Whether to enable undo/redo */
|
|
358
356
|
enableUndoRedo?: boolean;
|
|
359
|
-
/** Initial page size */
|
|
360
|
-
defaultPageSize?: number;
|
|
361
357
|
/** Available page size options */
|
|
362
358
|
pageSizeOptions?: number[];
|
|
363
|
-
/** Initial zoom level */
|
|
364
|
-
defaultZoom?: number;
|
|
365
|
-
/** Whether to auto-save changes */
|
|
366
|
-
autoSave?: boolean;
|
|
367
359
|
/** Callback when changes are saved (called for both auto-save and manual save) */
|
|
368
360
|
onSave?: () => void | Promise<void>;
|
|
369
|
-
/**
|
|
370
|
-
|
|
361
|
+
/** Initial settings (optional). All settings can be changed by user in the settings modal. */
|
|
362
|
+
settings?: {
|
|
363
|
+
/** Default pinned column IDs */
|
|
364
|
+
defaultPinnedColumns?: string[];
|
|
365
|
+
/** Default sort configuration */
|
|
366
|
+
defaultSort?: SpreadsheetSortConfig | null;
|
|
367
|
+
/** Default page size */
|
|
368
|
+
defaultPageSize?: number;
|
|
369
|
+
/** Default zoom level */
|
|
370
|
+
defaultZoom?: number;
|
|
371
|
+
/** Whether auto-save is enabled */
|
|
372
|
+
autoSave?: boolean;
|
|
373
|
+
/** Whether compact view is enabled */
|
|
374
|
+
compactView?: boolean;
|
|
375
|
+
};
|
|
376
|
+
/** Callback when spreadsheet settings are changed by the user */
|
|
377
|
+
onSettingsChange?: (settings: {
|
|
378
|
+
compactView?: boolean;
|
|
379
|
+
autoSave?: boolean;
|
|
380
|
+
defaultPageSize?: number;
|
|
381
|
+
defaultZoom?: number;
|
|
382
|
+
defaultPinnedColumns?: string[];
|
|
383
|
+
defaultSort?: SpreadsheetSortConfig | null;
|
|
384
|
+
}) => void;
|
|
371
385
|
/** Loading state */
|
|
372
386
|
isLoading?: boolean;
|
|
373
387
|
/** Custom className */
|