Skip to content

Commit 843a2d1

Browse files
fix readonly issues #8 (tests pending) (#37)
* fix readonly issues #8 * format * merge cell fix * version * test fixes * test fixes and merge * version * format
1 parent 5f07a1a commit 843a2d1

File tree

10 files changed

+81
-27
lines changed

10 files changed

+81
-27
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# React-spread-sheet-excel
22
React spread sheet excel is a high-performance React component for building Excel-like spreadsheets with advanced features.
33

4-
A **simple very light weight(<200KB)** component to Render large lists of input boxes in the table using React JS, Render a table with a large number of rows and columns.
4+
A **simple very light weight(<300KB)** component to Render large lists of input boxes in the table using React JS, Render a table with a large number of rows and columns.
55
Able to render 100000+ input boxes in react, A quick solution for web based spreadsheet or excel.
66

77
[![npm version](https://badge.fury.io/js/react-spread-sheet-excel.svg)](https://badge.fury.io/js/react-spread-sheet-excel) ![Downloads](https://img.shields.io/npm/dm/react-spread-sheet-excel.svg)

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "react-spread-sheet-excel",
3-
"version": "3.1.6",
3+
"version": "3.1.7",
44
"description": "A quick example of rendering large number of input boxes in table using React JS, React Spread-sheet (Excel sheet)",
55
"keywords": [
66
"React spreadsheet",

src/lib/list/__tests__/index.test.tsx

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { store } from "../../store";
66
import { generateDummyContent } from "../utils";
77
import { changeData, selectCellsDrag, selectOneCell } from "../../reducer";
88
import { mockAllIsIntersecting } from "react-intersection-observer/test-utils";
9+
import { wait } from "@testing-library/user-event/dist/cjs/utils/index.js";
910

1011
describe("index tests", () => {
1112
afterEach(() => {
@@ -368,7 +369,9 @@ describe("index tests", () => {
368369
});
369370
test("merge cells", async () => {
370371
const user = userEvent.setup();
371-
render(<List data={generateDummyContent(10, 2)} autoAddAdditionalRows={false} />);
372+
const { container } = render(
373+
<List data={generateDummyContent(10, 2)} autoAddAdditionalRows={false} />,
374+
);
372375
mockAllIsIntersecting(true);
373376
expect(screen.getAllByRole("textbox").length).toBe(21); //one common input from tools
374377
await user.click(screen.getByTestId(`${0}-${0}`));
@@ -386,6 +389,6 @@ describe("index tests", () => {
386389
expect(screen.getAllByRole("textbox").length).toBe(18); //one common input from tools
387390
fireEvent.contextMenu(screen.getByTestId(`0-0`));
388391
fireEvent.click(screen.getByText("Merge cells"));
389-
expect(screen.getAllByRole("textbox").length).toBe(18); //one common input from tools
392+
expect(screen.getAllByRole("textbox").length).toBe(18); //why this is 21 !!!!
390393
});
391394
});

src/lib/list/cell.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,15 +17,15 @@ const Cell = (props: Prop) => {
1717

1818
const colSpan = useAppSelector(store, (state) => {
1919
let val = state.data[props.i][props.j];
20-
if (inView && val.colSpan && val.rowSpan) {
20+
if (val.colSpan && val.rowSpan) {
2121
return val.colSpan;
2222
}
2323
return 1;
2424
});
2525

2626
const rowSpan = useAppSelector(store, (state) => {
2727
let val = state.data[props.i][props.j];
28-
if (inView && val.colSpan && val.rowSpan) {
28+
if (val.colSpan && val.rowSpan) {
2929
return val.rowSpan;
3030
}
3131
return 1;

src/lib/list/index.tsx

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,8 @@ const List = (props: Props) => {
141141
ctrlKey: any;
142142
metaKey: any;
143143
}) => {
144+
if (readonly) return;
145+
144146
if (e.code === "KeyA" && (e.ctrlKey || e.metaKey)) {
145147
dispatch(selectAllCells);
146148
}
@@ -207,8 +209,10 @@ const List = (props: Props) => {
207209
};
208210

209211
const handleContextMenu = (e: React.MouseEvent) => {
210-
e.preventDefault();
211-
setContextMenu({ x: e.clientX, y: e.clientY });
212+
if (!readonly) {
213+
e.preventDefault();
214+
setContextMenu({ x: e.clientX, y: e.clientY });
215+
}
212216
};
213217

214218
return (
@@ -226,7 +230,7 @@ const List = (props: Props) => {
226230
<table onContextMenu={handleContextMenu}>
227231
{!hideXAxisHeader ? (
228232
<thead>
229-
<SheetXAxis resize={resize} headerValues={headerValues} />
233+
<SheetXAxis resize={resize} headerValues={headerValues} readOnly={readonly} />
230234
</thead>
231235
) : (
232236
""

src/lib/list/readonlycell.tsx

Lines changed: 42 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,56 @@
11
import React from "react";
22
import { store, useAppSelector } from "../store";
3+
import { getCalculatedVal } from "./utils";
34

45
interface Prop {
56
i: number;
67
j: number;
8+
headerValues?: string[];
79
}
810
const ReadOnlyCell = (props: Prop) => {
9-
const value = useAppSelector(store, (state) => state.data[props.i][props.j].value);
10-
return (
11-
<td>
12-
<div className="input input-dummy" data-testid={`read-only-${props.i}-${props.j}`}>
11+
const value = useAppSelector(store, (state) => {
12+
let val = state.data[props.i][props.j].value;
13+
if (val && val.toString().trim().startsWith("=")) {
14+
return getCalculatedVal(val, state.data, props.headerValues);
15+
}
16+
return val;
17+
});
18+
const colSpan = useAppSelector(store, (state) => {
19+
let val = state.data[props.i][props.j];
20+
if (val.colSpan && val.rowSpan) {
21+
return val.colSpan;
22+
}
23+
return 1;
24+
});
25+
26+
const rowSpan = useAppSelector(store, (state) => {
27+
let val = state.data[props.i][props.j];
28+
if (val.colSpan && val.rowSpan) {
29+
return val.rowSpan;
30+
}
31+
return 1;
32+
});
33+
34+
const skip = useAppSelector(store, (state) => {
35+
return state.data[props.i][props.j].skip;
36+
});
37+
38+
const styles = useAppSelector(store, (state) => {
39+
return state.data[props.i][props.j].styles;
40+
});
41+
42+
return !skip ? (
43+
<td colSpan={colSpan} rowSpan={rowSpan}>
44+
<div
45+
className="input input-dummy"
46+
data-testid={`read-only-${props.i}-${props.j}`}
47+
style={styles}
48+
>
1349
{value}
1450
</div>
1551
</td>
52+
) : (
53+
<></>
1654
);
1755
};
1856

src/lib/list/row.tsx

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ const Row = (props: Prop) => {
1717
for (let j = 0; j < itemLength; j++) {
1818
items.push(
1919
props.readonly ? (
20-
<ReadOnlyCell key={`${i}-${j}-ReadOnly`} i={i} j={j} />
20+
<ReadOnlyCell key={`${i}-${j}-ReadOnly`} i={i} j={j} headerValues={props.headerValues} />
2121
) : (
2222
<Cell
2323
key={`${i}-${j}`}
@@ -37,9 +37,10 @@ const Row = (props: Prop) => {
3737
data-testid={`${i}-sheet-y-axis`}
3838
tabIndex={1}
3939
onMouseDown={(e) => {
40-
store.dispatch(selectHorizontalCells, {
41-
payload: { i: i, ctrlPressed: e.metaKey || e.ctrlKey },
42-
});
40+
!props.readonly &&
41+
store.dispatch(selectHorizontalCells, {
42+
payload: { i: i, ctrlPressed: e.metaKey || e.ctrlKey },
43+
});
4344
}}
4445
>
4546
{i + 1}

src/lib/list/sheet-x-axis.tsx

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,10 @@ import { selectAllCells, selectVerticalCells } from "../reducer";
66
interface Props {
77
resize?: boolean;
88
headerValues?: string[];
9+
readOnly: boolean | undefined;
910
}
1011

11-
const SheetXAxis = ({ resize, headerValues }: Props) => {
12+
const SheetXAxis = ({ resize, headerValues, readOnly }: Props) => {
1213
const { dispatch } = store;
1314
const itemLength = useAppSelector(store, (state) => state.data[0].length);
1415
const items: any = [];
@@ -25,12 +26,14 @@ const SheetXAxis = ({ resize, headerValues }: Props) => {
2526
data-testid={`${i}-x-axis`}
2627
tabIndex={0}
2728
onMouseDown={(e) => {
28-
if (i === 0) {
29-
dispatch(selectAllCells);
30-
} else
31-
dispatch(selectVerticalCells, {
32-
payload: { j: i - 1, ctrlPressed: e.metaKey || e.ctrlKey },
33-
});
29+
if (!readOnly) {
30+
if (i === 0) {
31+
dispatch(selectAllCells);
32+
} else
33+
dispatch(selectVerticalCells, {
34+
payload: { j: i - 1, ctrlPressed: e.metaKey || e.ctrlKey },
35+
});
36+
}
3437
}}
3538
>
3639
{resize && i > 0 ? (

src/lib/reducer.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -351,11 +351,11 @@ const actions: DispatcherActions = {
351351
j++
352352
) {
353353
undo.push({ i: i, j: j, data: { ...state.data[i][j] } });
354-
data[i][j].skip = undefined;
354+
delete data[i][j].skip;
355355
}
356356
}
357-
data[cellForMerge[0]][cellForMerge[1]].rowSpan = undefined;
358-
data[cellForMerge[0]][cellForMerge[1]].colSpan = undefined;
357+
delete data[cellForMerge[0]][cellForMerge[1]].rowSpan;
358+
delete data[cellForMerge[0]][cellForMerge[1]].colSpan;
359359
} else if (state.selected.length > 1) {
360360
state.selected.forEach((p, i) => {
361361
undo.push({ i: p[0], j: p[1], data: { ...state.data[p[0]][p[1]] } });

todo.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ Multiple selection with cntrl key
2525
Readonly should disable all updates and support merged cells
2626

2727
Tool tip for tools
28+
29+
30+
merge cells - skip
31+
32+
event delegation in javascript table

0 commit comments

Comments
 (0)