@xcelsior/ui-spreadsheets 1.1.4 → 1.1.6
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/.turbo/turbo-build.log +14 -14
- package/.turbo/turbo-lint.log +73 -84
- package/CHANGELOG.md +8 -0
- package/dist/index.d.mts +51 -6
- package/dist/index.d.ts +51 -6
- package/dist/index.js +224 -193
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +123 -93
- package/dist/index.mjs.map +1 -1
- package/dist/styles/globals.css +6 -7
- package/dist/styles/globals.css.map +1 -1
- package/package.json +4 -4
- package/src/components/RowContextMenu.tsx +85 -0
- package/src/components/Spreadsheet.stories.tsx +80 -33
- package/src/components/Spreadsheet.tsx +20 -53
- package/src/hooks/useSpreadsheetHighlighting.ts +6 -2
- package/src/index.ts +2 -0
- package/src/types.ts +29 -4
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type React from 'react';
|
|
2
2
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
3
|
-
import { HiChevronDown, HiChevronRight
|
|
3
|
+
import { HiChevronDown, HiChevronRight } from 'react-icons/hi';
|
|
4
4
|
import { AiFillHighlight } from 'react-icons/ai';
|
|
5
5
|
import { FaComment, FaRegComment } from 'react-icons/fa';
|
|
6
6
|
import { cn } from '../utils';
|
|
@@ -13,6 +13,7 @@ import { ColorPickerPopover } from './ColorPickerPopover';
|
|
|
13
13
|
import { type SpreadsheetSettings, SpreadsheetSettingsModal } from './SpreadsheetSettingsModal';
|
|
14
14
|
import { AddCommentModal, ViewCommentsModal } from './CommentModals';
|
|
15
15
|
import { KeyboardShortcutsModal } from './KeyboardShortcutsModal';
|
|
16
|
+
import { RowContextMenu } from './RowContextMenu';
|
|
16
17
|
import { Pagination } from '@xcelsior/design-system';
|
|
17
18
|
import { useSpreadsheetFiltering } from '../hooks/useSpreadsheetFiltering';
|
|
18
19
|
import { useSpreadsheetHighlighting } from '../hooks/useSpreadsheetHighlighting';
|
|
@@ -25,7 +26,7 @@ import { useSpreadsheetComments } from '../hooks/useSpreadsheetComments';
|
|
|
25
26
|
import { useSpreadsheetUndoRedo } from '../hooks/useSpreadsheetUndoRedo';
|
|
26
27
|
import { useSpreadsheetKeyboardShortcuts } from '../hooks/useSpreadsheetKeyboardShortcuts';
|
|
27
28
|
import { useSpreadsheetSelection } from '../hooks/useSpreadsheetSelection';
|
|
28
|
-
import type { CellEdit,
|
|
29
|
+
import type { CellEdit, SpreadsheetProps } from '../types';
|
|
29
30
|
|
|
30
31
|
type SingleCellEdit = {
|
|
31
32
|
rowId: string | number;
|
|
@@ -84,8 +85,6 @@ export function Spreadsheet<T extends Record<string, any>>({
|
|
|
84
85
|
onFilterChange,
|
|
85
86
|
onRowClick,
|
|
86
87
|
onRowDoubleClick,
|
|
87
|
-
onRowClone,
|
|
88
|
-
onRowDelete,
|
|
89
88
|
onAddCellComment,
|
|
90
89
|
onToggleCommentResolved,
|
|
91
90
|
onRowHighlight,
|
|
@@ -110,6 +109,7 @@ export function Spreadsheet<T extends Record<string, any>>({
|
|
|
110
109
|
cellHighlights: externalCellHighlights,
|
|
111
110
|
cellComments: externalCellComments,
|
|
112
111
|
rowActions,
|
|
112
|
+
rowContextMenuItems,
|
|
113
113
|
toolbarMenuItems,
|
|
114
114
|
// Server-side mode props
|
|
115
115
|
serverSide = false,
|
|
@@ -627,22 +627,6 @@ export function Spreadsheet<T extends Record<string, any>>({
|
|
|
627
627
|
setEditingCell(null);
|
|
628
628
|
}, [setEditingCell]);
|
|
629
629
|
|
|
630
|
-
// Handle row clone/duplicate
|
|
631
|
-
const handleRowClone = useCallback(
|
|
632
|
-
(row: T, rowId: string | number) => {
|
|
633
|
-
onRowClone?.(row, rowId);
|
|
634
|
-
},
|
|
635
|
-
[onRowClone]
|
|
636
|
-
);
|
|
637
|
-
|
|
638
|
-
// Handle row delete
|
|
639
|
-
const handleRowDelete = useCallback(
|
|
640
|
-
(row: T, rowId: string | number) => {
|
|
641
|
-
onRowDelete?.(row, rowId);
|
|
642
|
-
},
|
|
643
|
-
[onRowDelete]
|
|
644
|
-
);
|
|
645
|
-
|
|
646
630
|
// Handle row index highlight (using unified column highlight with special ID)
|
|
647
631
|
const handleRowIndexHighlightClick = useCallback(() => {
|
|
648
632
|
setHighlightPickerColumn(ROW_INDEX_COLUMN_ID);
|
|
@@ -889,41 +873,24 @@ export function Spreadsheet<T extends Record<string, any>>({
|
|
|
889
873
|
}),
|
|
890
874
|
}}
|
|
891
875
|
>
|
|
892
|
-
<div className="relative flex items-center justify-center">
|
|
893
|
-
{/* Row number -
|
|
876
|
+
<div className="relative flex items-center justify-center w-full h-full">
|
|
877
|
+
{/* Row number - centered */}
|
|
894
878
|
<span>{displayIndex}</span>
|
|
895
879
|
|
|
896
|
-
{/* Action buttons - absolute
|
|
897
|
-
<div className="absolute
|
|
898
|
-
{/*
|
|
899
|
-
{
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
</button>
|
|
911
|
-
)}
|
|
912
|
-
|
|
913
|
-
{/* Delete Row */}
|
|
914
|
-
{onRowDelete && (
|
|
915
|
-
<button
|
|
916
|
-
type="button"
|
|
917
|
-
onClick={(e) => {
|
|
918
|
-
e.stopPropagation();
|
|
919
|
-
handleRowDelete(row, rowId);
|
|
920
|
-
}}
|
|
921
|
-
className="opacity-0 group-hover:opacity-100 transition-opacity p-0.5 bg-gray-100 hover:bg-red-100 rounded"
|
|
922
|
-
title="Delete row"
|
|
923
|
-
>
|
|
924
|
-
<HiTrash className="h-2.5 w-2.5 text-gray-500 hover:text-red-500" />
|
|
925
|
-
</button>
|
|
926
|
-
)}
|
|
880
|
+
{/* Action buttons - absolute overlay, spaced evenly */}
|
|
881
|
+
<div className="absolute inset-0 flex items-center justify-evenly">
|
|
882
|
+
{/* Context Menu (3-dot menu for row actions) */}
|
|
883
|
+
{rowContextMenuItems &&
|
|
884
|
+
rowContextMenuItems.length > 0 && (
|
|
885
|
+
<RowContextMenu
|
|
886
|
+
row={row}
|
|
887
|
+
rowId={rowId}
|
|
888
|
+
items={rowContextMenuItems}
|
|
889
|
+
compactMode={
|
|
890
|
+
effectiveCompactMode
|
|
891
|
+
}
|
|
892
|
+
/>
|
|
893
|
+
)}
|
|
927
894
|
|
|
928
895
|
{/* Highlight Row */}
|
|
929
896
|
{enableHighlighting && (
|
|
@@ -91,7 +91,9 @@ export function useSpreadsheetHighlighting({
|
|
|
91
91
|
const [rowHighlightsInternal, setRowHighlightsInternal] = useState<CellHighlight[]>([]);
|
|
92
92
|
|
|
93
93
|
// Column-level highlights (internal state, can be overridden by external)
|
|
94
|
-
const [columnHighlightsInternal, setColumnHighlightsInternal] = useState<
|
|
94
|
+
const [columnHighlightsInternal, setColumnHighlightsInternal] = useState<
|
|
95
|
+
Record<string, string>
|
|
96
|
+
>({});
|
|
95
97
|
|
|
96
98
|
// Picker states
|
|
97
99
|
const [highlightPickerRow, setHighlightPickerRow] = useState<string | number | null>(null);
|
|
@@ -127,7 +129,9 @@ export function useSpreadsheetHighlighting({
|
|
|
127
129
|
if (existing) {
|
|
128
130
|
if (color === null) {
|
|
129
131
|
// Remove highlight
|
|
130
|
-
return prev.filter(
|
|
132
|
+
return prev.filter(
|
|
133
|
+
(h) => !(h.rowId === rowId && h.columnId === columnId)
|
|
134
|
+
);
|
|
131
135
|
}
|
|
132
136
|
// Update color
|
|
133
137
|
return prev.map((h) =>
|
package/src/index.ts
CHANGED
|
@@ -7,6 +7,7 @@ export { SpreadsheetHeader } from './components/SpreadsheetHeader';
|
|
|
7
7
|
export { SpreadsheetFilterDropdown } from './components/SpreadsheetFilterDropdown';
|
|
8
8
|
export { SpreadsheetToolbar } from './components/SpreadsheetToolbar';
|
|
9
9
|
export { SpreadsheetSettingsModal } from './components/SpreadsheetSettingsModal';
|
|
10
|
+
export { RowContextMenu } from './components/RowContextMenu';
|
|
10
11
|
export type { SpreadsheetSettings } from './components/SpreadsheetSettingsModal';
|
|
11
12
|
|
|
12
13
|
// Types
|
|
@@ -31,5 +32,6 @@ export type {
|
|
|
31
32
|
SelectionEdge,
|
|
32
33
|
PaginationState,
|
|
33
34
|
RowAction,
|
|
35
|
+
RowContextMenuItem,
|
|
34
36
|
ToolbarMenuItem,
|
|
35
37
|
} from './types';
|
package/src/types.ts
CHANGED
|
@@ -296,6 +296,29 @@ export interface RowAction<T = any> {
|
|
|
296
296
|
className?: string;
|
|
297
297
|
}
|
|
298
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Row context menu item configuration
|
|
301
|
+
* Used for the 3-dot menu that appears on row hover
|
|
302
|
+
*/
|
|
303
|
+
export interface RowContextMenuItem<T = any> {
|
|
304
|
+
/** Unique identifier */
|
|
305
|
+
id: string;
|
|
306
|
+
/** Display label for the menu item */
|
|
307
|
+
label: string;
|
|
308
|
+
/** Icon component to display next to the label */
|
|
309
|
+
icon?: React.ReactNode;
|
|
310
|
+
/** Callback when menu item is clicked */
|
|
311
|
+
onClick: (row: T, rowId: string | number) => void;
|
|
312
|
+
/** Whether the menu item is visible */
|
|
313
|
+
visible?: (row: T) => boolean;
|
|
314
|
+
/** Whether the menu item is disabled */
|
|
315
|
+
disabled?: (row: T) => boolean;
|
|
316
|
+
/** Variant for styling (e.g., destructive for delete actions) */
|
|
317
|
+
variant?: 'default' | 'destructive';
|
|
318
|
+
/** Custom className */
|
|
319
|
+
className?: string;
|
|
320
|
+
}
|
|
321
|
+
|
|
299
322
|
/**
|
|
300
323
|
* Server-side pagination state for controlled pagination
|
|
301
324
|
*/
|
|
@@ -332,10 +355,6 @@ export interface SpreadsheetProps<T = any> {
|
|
|
332
355
|
onRowClick?: (row: T, rowIndex: number) => void;
|
|
333
356
|
/** Callback for row double click */
|
|
334
357
|
onRowDoubleClick?: (row: T, rowIndex: number) => void;
|
|
335
|
-
/** Callback when a row is cloned/duplicated */
|
|
336
|
-
onRowClone?: (row: T, rowId: string | number) => void;
|
|
337
|
-
/** Callback when a row is deleted */
|
|
338
|
-
onRowDelete?: (row: T, rowId: string | number) => void;
|
|
339
358
|
/** Callback when a cell comment is added */
|
|
340
359
|
onAddCellComment?: (rowId: string | number, columnId: string, comment: string) => void;
|
|
341
360
|
/** Callback when a comment's resolved status is toggled */
|
|
@@ -404,6 +423,12 @@ export interface SpreadsheetProps<T = any> {
|
|
|
404
423
|
cellComments?: CellComment[];
|
|
405
424
|
/** Custom row actions to display in the index column */
|
|
406
425
|
rowActions?: RowAction<T>[];
|
|
426
|
+
/**
|
|
427
|
+
* Context menu items to display in the 3-dot menu for each row.
|
|
428
|
+
* These appear in a dropdown when the user clicks the 3-dot icon on row hover.
|
|
429
|
+
* Use this for actions like clone, delete, view, edit, etc.
|
|
430
|
+
*/
|
|
431
|
+
rowContextMenuItems?: RowContextMenuItem<T>[];
|
|
407
432
|
/** Custom menu items to display in the toolbar's "More" dropdown menu */
|
|
408
433
|
toolbarMenuItems?: ToolbarMenuItem[];
|
|
409
434
|
|