Skip to content

Commit 358dc97

Browse files
committed
Add argument to onChange to know which rows were updated
1 parent 3775674 commit 358dc97

File tree

11 files changed

+369
-165
lines changed

11 files changed

+369
-165
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
# Change Log
22

3+
## 3.4.0
4+
> Date: 2021-12-23
5+
### Added
6+
- `onChange` now receives a second argument to track which rows were updated.
7+
38
## 3.3.9
49
> Date: 2021-12-07
510
### Fixed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-datasheet-grid",
3-
"version": "3.3.9",
3+
"version": "3.4.0",
44
"description": "An Excel-like React component to create beautiful spreadsheets.",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

src/components/DataSheetGrid.tsx

Lines changed: 101 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import {
1414
DataSheetGridRef,
1515
HeaderContextType,
1616
ListItemData,
17+
Operation,
1718
Selection,
1819
SelectionContextType,
1920
} from '../types'
@@ -316,11 +317,20 @@ export const DataSheetGrid = React.memo(
316317
setSelectionCell(null)
317318
setEditing(false)
318319

319-
onChange([
320-
...dataRef.current.slice(0, row + 1),
321-
...new Array(count).fill(0).map(createRow),
322-
...dataRef.current.slice(row + 1),
323-
])
320+
onChange(
321+
[
322+
...dataRef.current.slice(0, row + 1),
323+
...new Array(count).fill(0).map(createRow),
324+
...dataRef.current.slice(row + 1),
325+
],
326+
[
327+
{
328+
type: 'CREATE',
329+
fromRowIndex: row + 1,
330+
toRowIndex: row + 1 + count,
331+
},
332+
]
333+
)
324334
setActiveCell((a) => ({ col: a?.col || 0, row: row + count }))
325335
},
326336
[createRow, lockRows, onChange, setActiveCell, setSelectionCell]
@@ -332,15 +342,24 @@ export const DataSheetGrid = React.memo(
332342
return
333343
}
334344

335-
onChange([
336-
...dataRef.current.slice(0, rowMax + 1),
337-
...dataRef.current
338-
.slice(rowMin, rowMax + 1)
339-
.map((rowData, i) =>
340-
duplicateRow({ rowData, rowIndex: i + rowMin })
341-
),
342-
...dataRef.current.slice(rowMax + 1),
343-
])
345+
onChange(
346+
[
347+
...dataRef.current.slice(0, rowMax + 1),
348+
...dataRef.current
349+
.slice(rowMin, rowMax + 1)
350+
.map((rowData, i) =>
351+
duplicateRow({ rowData, rowIndex: i + rowMin })
352+
),
353+
...dataRef.current.slice(rowMax + 1),
354+
],
355+
[
356+
{
357+
type: 'CREATE',
358+
fromRowIndex: rowMax + 1,
359+
toRowIndex: rowMax + 2 + rowMax - rowMin,
360+
},
361+
]
362+
)
344363
setActiveCell({ col: 0, row: rowMax + 1 })
345364
setSelectionCell({
346365
col: columns.length - (hasStickyRightColumn ? 3 : 2),
@@ -430,11 +449,20 @@ export const DataSheetGrid = React.memo(
430449

431450
const setRowData = useCallback(
432451
(rowIndex: number, item: T) => {
433-
onChange([
434-
...dataRef.current?.slice(0, rowIndex),
435-
item,
436-
...dataRef.current?.slice(rowIndex + 1),
437-
])
452+
onChange(
453+
[
454+
...dataRef.current?.slice(0, rowIndex),
455+
item,
456+
...dataRef.current?.slice(rowIndex + 1),
457+
],
458+
[
459+
{
460+
type: 'UPDATE',
461+
fromRowIndex: rowIndex,
462+
toRowIndex: rowIndex + 1,
463+
},
464+
]
465+
)
438466
},
439467
[onChange]
440468
)
@@ -459,10 +487,19 @@ export const DataSheetGrid = React.memo(
459487
return a && { ...a, row }
460488
})
461489
setSelectionCell(null)
462-
onChange([
463-
...dataRef.current.slice(0, rowMin),
464-
...dataRef.current.slice(rowMax + 1),
465-
])
490+
onChange(
491+
[
492+
...dataRef.current.slice(0, rowMin),
493+
...dataRef.current.slice(rowMax + 1),
494+
],
495+
[
496+
{
497+
type: 'DELETE',
498+
fromRowIndex: rowMin,
499+
toRowIndex: rowMax + 1,
500+
},
501+
]
502+
)
466503
},
467504
[lockRows, onChange, setActiveCell, setSelectionCell]
468505
)
@@ -515,7 +552,13 @@ export const DataSheetGrid = React.memo(
515552
return
516553
}
517554

518-
onChange(newData)
555+
onChange(newData, [
556+
{
557+
type: 'UPDATE',
558+
fromRowIndex: min.row,
559+
toRowIndex: max.row + 1,
560+
},
561+
])
519562
},
520563
[
521564
activeCell,
@@ -666,7 +709,13 @@ export const DataSheetGrid = React.memo(
666709
}
667710
}
668711

669-
onChange(newData)
712+
onChange(newData, [
713+
{
714+
type: 'UPDATE',
715+
fromRowIndex: min.row,
716+
toRowIndex: max.row + 1,
717+
},
718+
])
670719
setActiveCell({ col: min.col, row: min.row })
671720
setSelectionCell({
672721
col: Math.min(
@@ -723,7 +772,26 @@ export const DataSheetGrid = React.memo(
723772
}
724773
}
725774

726-
onChange(newData)
775+
const operations: Operation[] = [
776+
{
777+
type: 'UPDATE',
778+
fromRowIndex: min.row,
779+
toRowIndex:
780+
min.row +
781+
pasteData.length -
782+
(!lockRows && missingRows > 0 ? missingRows : 0),
783+
},
784+
]
785+
786+
if (missingRows > 0 && !lockRows) {
787+
operations.push({
788+
type: 'CREATE',
789+
fromRowIndex: min.row + pasteData.length - missingRows,
790+
toRowIndex: min.row + pasteData.length,
791+
})
792+
}
793+
794+
onChange(newData, operations)
727795
setActiveCell({ col: min.col, row: min.row })
728796
setSelectionCell({
729797
col: Math.min(
@@ -1009,7 +1077,13 @@ export const DataSheetGrid = React.memo(
10091077
}
10101078
}
10111079

1012-
onChange(newData)
1080+
onChange(newData, [
1081+
{
1082+
type: 'UPDATE',
1083+
fromRowIndex: max.row + 1,
1084+
toRowIndex: max.row + 1 + expandSelectionRowsCount,
1085+
},
1086+
])
10131087
setExpandSelectionRowsCount(0)
10141088
setActiveCell({
10151089
col: Math.min(

src/types.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,11 +141,17 @@ export type ContextMenuComponentProps = {
141141
close: () => void
142142
}
143143

144+
export type Operation = {
145+
type: 'UPDATE' | 'DELETE' | 'CREATE'
146+
fromRowIndex: number
147+
toRowIndex: number
148+
}
149+
144150
export type DataSheetGridProps<T> = {
145151
value?: T[]
146152
style?: React.CSSProperties
147153
className?: string
148-
onChange?: (value: T[]) => void
154+
onChange?: (value: T[], operations: Operation[]) => void
149155
columns?: Partial<Column<T, any>>[]
150156
gutterColumn?: SimpleColumn<T, any> | false
151157
stickyRightColumn?: SimpleColumn<T, any>

tests/addRows.test.tsx

Lines changed: 42 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -38,21 +38,24 @@ test('Add single row', () => {
3838

3939
userEvent.click(screen.getByText('Add'))
4040

41-
expect(onChange).toHaveBeenCalledWith([
42-
{
43-
id: 1,
44-
firstName: 'Elon',
45-
lastName: 'Musk',
46-
},
47-
{
48-
id: 2,
49-
firstName: 'Jeff',
50-
lastName: 'Bezos',
51-
},
52-
{
53-
id: 3,
54-
},
55-
])
41+
expect(onChange).toHaveBeenCalledWith(
42+
[
43+
{
44+
id: 1,
45+
firstName: 'Elon',
46+
lastName: 'Musk',
47+
},
48+
{
49+
id: 2,
50+
firstName: 'Jeff',
51+
lastName: 'Bezos',
52+
},
53+
{
54+
id: 3,
55+
},
56+
],
57+
[{ type: 'CREATE', fromRowIndex: 2, toRowIndex: 3 }]
58+
)
5659
})
5760

5861
test('No add button when rows are locked', () => {
@@ -85,27 +88,30 @@ test('Add multiple rows', () => {
8588
userEvent.type(screen.getByRole('spinbutton'), '{selectall}3')
8689
userEvent.click(screen.getByText('Add'))
8790

88-
expect(onChange).toHaveBeenCalledWith([
89-
{
90-
id: 1,
91-
firstName: 'Elon',
92-
lastName: 'Musk',
93-
},
94-
{
95-
id: 2,
96-
firstName: 'Jeff',
97-
lastName: 'Bezos',
98-
},
99-
{
100-
id: 3,
101-
},
102-
{
103-
id: 4,
104-
},
105-
{
106-
id: 5,
107-
},
108-
])
91+
expect(onChange).toHaveBeenCalledWith(
92+
[
93+
{
94+
id: 1,
95+
firstName: 'Elon',
96+
lastName: 'Musk',
97+
},
98+
{
99+
id: 2,
100+
firstName: 'Jeff',
101+
lastName: 'Bezos',
102+
},
103+
{
104+
id: 3,
105+
},
106+
{
107+
id: 4,
108+
},
109+
{
110+
id: 5,
111+
},
112+
],
113+
[{ type: 'CREATE', fromRowIndex: 2, toRowIndex: 5 }]
114+
)
109115

110116
expect(ref.current.activeCell).toEqual({
111117
col: 0,

tests/copy.test.tsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,11 @@ test('Cut multiple cells', async () => {
109109
'text/html': '<table><tr><td>Elon</td></tr><tr><td>Jeff</td></tr></table>',
110110
'text/plain': 'Elon\nJeff',
111111
})
112-
expect(onChange).toHaveBeenCalledWith([
113-
{ firstName: null, lastName: 'Musk' },
114-
{ firstName: null, lastName: 'Bezos' },
115-
])
112+
expect(onChange).toHaveBeenCalledWith(
113+
[
114+
{ firstName: null, lastName: 'Musk' },
115+
{ firstName: null, lastName: 'Bezos' },
116+
],
117+
[{ type: 'UPDATE', fromRowIndex: 0, toRowIndex: 2 }]
118+
)
116119
})

0 commit comments

Comments
 (0)