react-excel-lite 0.3.0 → 0.4.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/README.md +102 -25
- package/dist/components/excel-grid.d.ts +1 -1
- package/dist/components/excel-grid.d.ts.map +1 -1
- package/dist/components/grid-cell.d.ts +1 -1
- package/dist/components/grid-cell.d.ts.map +1 -1
- package/dist/react-excel-lite.js +344 -340
- package/dist/react-excel-lite.umd.cjs +2 -2
- package/dist/types.d.ts +4 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,17 +9,21 @@
|
|
|
9
9
|
A lightweight, Excel-like editable grid component for React.
|
|
10
10
|
|
|
11
11
|
## Demo
|
|
12
|
+
|
|
12
13
|
[react-excel-lite-demo](https://prkgnt.github.io/react-excel-lite/)
|
|
13
14
|
|
|
14
15
|
## Features
|
|
15
16
|
|
|
16
17
|
- Excel-like cell selection (click & drag)
|
|
18
|
+
- Keyboard navigation (Arrow keys to move, Shift+Arrow to extend selection)
|
|
17
19
|
- Copy/Paste support (Ctrl+C / Ctrl+V)
|
|
18
20
|
- Auto Fill with arithmetic sequence detection (drag fill handle)
|
|
19
|
-
- Grouped column headers with
|
|
20
|
-
-
|
|
21
|
-
-
|
|
21
|
+
- Grouped column headers with rowSpan support
|
|
22
|
+
- Grouped row headers with rowSpan support
|
|
23
|
+
- Click outside to clear selection
|
|
24
|
+
- Double-click or type to edit cells
|
|
22
25
|
- Expandable input field when editing (text overflow handling)
|
|
26
|
+
- Keyboard shortcuts (Delete/Backspace to clear)
|
|
23
27
|
- **Styling-agnostic**: Works with Tailwind CSS, CSS Modules, plain CSS, or any styling solution
|
|
24
28
|
- Zero external dependencies
|
|
25
29
|
|
|
@@ -48,15 +52,16 @@ function App() {
|
|
|
48
52
|
|
|
49
53
|
## Props
|
|
50
54
|
|
|
51
|
-
| Prop | Type
|
|
52
|
-
| ---------------- |
|
|
53
|
-
| `data` | `string[][]`
|
|
54
|
-
| `onChange` | `(data: string[][]) => void`
|
|
55
|
-
| `rowHeaders` | `HeaderGroup[]`
|
|
56
|
-
| `colHeaders` | `HeaderGroup[]`
|
|
57
|
-
| `className` | `string`
|
|
58
|
-
| `rowHeaderTitle` | `string`
|
|
59
|
-
| `styles` | `GridStyles`
|
|
55
|
+
| Prop | Type | Required | Description |
|
|
56
|
+
| ---------------- | ----------------------------------------- | -------- | ---------------------------------- |
|
|
57
|
+
| `data` | `string[][]` | Yes | 2D array of strings |
|
|
58
|
+
| `onChange` | `(data: string[][]) => void` | Yes | Callback when data changes |
|
|
59
|
+
| `rowHeaders` | `HeaderGroup[]` | No | Grouped row headers |
|
|
60
|
+
| `colHeaders` | `HeaderGroup[]` | No | Grouped column headers |
|
|
61
|
+
| `className` | `string` | No | CSS class for container |
|
|
62
|
+
| `rowHeaderTitle` | `string` | No | Title for row header column |
|
|
63
|
+
| `styles` | `GridStyles` | No | Style configuration object |
|
|
64
|
+
| `cellStyles` | `(coord: CellCoord) => string|undefined` | No | Function to style individual cells |
|
|
60
65
|
|
|
61
66
|
## With Headers
|
|
62
67
|
|
|
@@ -74,16 +79,18 @@ function App() {
|
|
|
74
79
|
const colHeaders: HeaderGroup[] = [
|
|
75
80
|
{
|
|
76
81
|
label: "Q1",
|
|
82
|
+
description: "First quarter",
|
|
77
83
|
headers: [
|
|
78
|
-
{ key: "jan", label: "Jan" },
|
|
79
|
-
{ key: "feb", label: "Feb" },
|
|
84
|
+
{ key: "jan", label: "Jan", description: "January" },
|
|
85
|
+
{ key: "feb", label: "Feb", description: "February" },
|
|
80
86
|
],
|
|
81
87
|
},
|
|
82
88
|
{
|
|
83
89
|
label: "Q2",
|
|
90
|
+
description: "Second quarter",
|
|
84
91
|
headers: [
|
|
85
|
-
{ key: "mar", label: "Mar" },
|
|
86
|
-
{ key: "apr", label: "Apr" },
|
|
92
|
+
{ key: "mar", label: "Mar", description: "March" },
|
|
93
|
+
{ key: "apr", label: "Apr", description: "April" },
|
|
87
94
|
],
|
|
88
95
|
},
|
|
89
96
|
];
|
|
@@ -91,6 +98,7 @@ function App() {
|
|
|
91
98
|
const rowHeaders: HeaderGroup[] = [
|
|
92
99
|
{
|
|
93
100
|
label: "Products",
|
|
101
|
+
description: "Product categories",
|
|
94
102
|
headers: [
|
|
95
103
|
{ key: "prodA", label: "Product A", description: "Main product line" },
|
|
96
104
|
{ key: "prodB", label: "Product B", description: "Secondary product" },
|
|
@@ -104,7 +112,7 @@ function App() {
|
|
|
104
112
|
onChange={setData}
|
|
105
113
|
colHeaders={colHeaders}
|
|
106
114
|
rowHeaders={rowHeaders}
|
|
107
|
-
rowHeaderTitle="
|
|
115
|
+
rowHeaderTitle="Category"
|
|
108
116
|
/>
|
|
109
117
|
);
|
|
110
118
|
}
|
|
@@ -262,14 +270,77 @@ Style individual row headers:
|
|
|
262
270
|
const rowHeaders: HeaderGroup[] = [
|
|
263
271
|
{
|
|
264
272
|
label: "Regions",
|
|
273
|
+
className: "bg-slate-700 text-white",
|
|
265
274
|
headers: [
|
|
266
|
-
{
|
|
267
|
-
|
|
275
|
+
{
|
|
276
|
+
key: "regionA",
|
|
277
|
+
label: "Region A",
|
|
278
|
+
className: "bg-slate-600 text-white",
|
|
279
|
+
},
|
|
280
|
+
{
|
|
281
|
+
key: "regionB",
|
|
282
|
+
label: "Region B",
|
|
283
|
+
className: "bg-slate-500 text-white",
|
|
284
|
+
},
|
|
268
285
|
],
|
|
269
286
|
},
|
|
270
287
|
];
|
|
271
288
|
```
|
|
272
289
|
|
|
290
|
+
### Styling Individual Cells
|
|
291
|
+
|
|
292
|
+
Use the `cellStyles` prop to apply styles to specific cells based on their coordinates:
|
|
293
|
+
|
|
294
|
+
```tsx
|
|
295
|
+
import { useCallback } from "react";
|
|
296
|
+
import type { CellCoord } from "react-excel-lite";
|
|
297
|
+
|
|
298
|
+
function App() {
|
|
299
|
+
const [data, setData] = useState([
|
|
300
|
+
["100", "200", "300"],
|
|
301
|
+
["400", "500", "600"],
|
|
302
|
+
["700", "800", "900"],
|
|
303
|
+
]);
|
|
304
|
+
|
|
305
|
+
// Memoize to prevent unnecessary re-renders
|
|
306
|
+
const cellStyles = useCallback((coord: CellCoord) => {
|
|
307
|
+
// Highlight first row
|
|
308
|
+
if (coord.row === 0) return "bg-yellow-100";
|
|
309
|
+
// Highlight specific cell
|
|
310
|
+
if (coord.row === 1 && coord.col === 1) return "bg-red-100 font-bold";
|
|
311
|
+
// Highlight cells with negative values (check data)
|
|
312
|
+
return undefined;
|
|
313
|
+
}, []);
|
|
314
|
+
|
|
315
|
+
return <ExcelGrid data={data} onChange={setData} cellStyles={cellStyles} />;
|
|
316
|
+
}
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
Common use cases:
|
|
320
|
+
|
|
321
|
+
- Highlight header rows or columns
|
|
322
|
+
- Show validation errors (e.g., red background for invalid cells)
|
|
323
|
+
- Conditional formatting based on cell values
|
|
324
|
+
- Alternating row colors
|
|
325
|
+
|
|
326
|
+
```tsx
|
|
327
|
+
// Alternating row colors
|
|
328
|
+
const cellStyles = useCallback((coord: CellCoord) => {
|
|
329
|
+
return coord.row % 2 === 0 ? "bg-gray-50" : "bg-white";
|
|
330
|
+
}, []);
|
|
331
|
+
|
|
332
|
+
// Value-based styling (check data in callback)
|
|
333
|
+
const cellStyles = useCallback(
|
|
334
|
+
(coord: CellCoord) => {
|
|
335
|
+
const value = Number(data[coord.row]?.[coord.col]);
|
|
336
|
+
if (value < 0) return "bg-red-100 text-red-700";
|
|
337
|
+
if (value > 1000) return "bg-green-100 text-green-700";
|
|
338
|
+
return undefined;
|
|
339
|
+
},
|
|
340
|
+
[data],
|
|
341
|
+
);
|
|
342
|
+
```
|
|
343
|
+
|
|
273
344
|
## Auto Fill (Arithmetic Sequence)
|
|
274
345
|
|
|
275
346
|
Select cells with a numeric pattern and drag the fill handle to auto-fill:
|
|
@@ -281,11 +352,16 @@ Select cells with a numeric pattern and drag the fill handle to auto-fill:
|
|
|
281
352
|
|
|
282
353
|
## Keyboard Shortcuts
|
|
283
354
|
|
|
284
|
-
| Shortcut | Action
|
|
285
|
-
| ---------------------- |
|
|
286
|
-
| `
|
|
287
|
-
| `
|
|
288
|
-
| `
|
|
355
|
+
| Shortcut | Action |
|
|
356
|
+
| ---------------------- | --------------------------------- |
|
|
357
|
+
| `Arrow Keys` | Move selection |
|
|
358
|
+
| `Shift + Arrow Keys` | Extend selection range |
|
|
359
|
+
| `Enter` | Enter edit mode (select all text) |
|
|
360
|
+
| `Any character` | Enter edit mode and start typing |
|
|
361
|
+
| `Escape` | Exit edit mode |
|
|
362
|
+
| `Ctrl+C` / `Cmd+C` | Copy selected cells |
|
|
363
|
+
| `Ctrl+V` / `Cmd+V` | Paste from clipboard |
|
|
364
|
+
| `Delete` / `Backspace` | Clear selected cells |
|
|
289
365
|
|
|
290
366
|
## Exports
|
|
291
367
|
|
|
@@ -297,7 +373,7 @@ Select cells with a numeric pattern and drag the fill handle to auto-fill:
|
|
|
297
373
|
### Hooks
|
|
298
374
|
|
|
299
375
|
- `useGridSelection` - Cell selection logic
|
|
300
|
-
- `useGridClipboard` - Copy/paste logic
|
|
376
|
+
- `useGridClipboard` - Copy/paste and keyboard navigation logic
|
|
301
377
|
- `useGridDragFill` - Fill handle logic
|
|
302
378
|
|
|
303
379
|
### Utilities
|
|
@@ -357,6 +433,7 @@ interface ExcelGridProps {
|
|
|
357
433
|
className?: string;
|
|
358
434
|
rowHeaderTitle?: string;
|
|
359
435
|
styles?: GridStyles;
|
|
436
|
+
cellStyles?: (coord: CellCoord) => string | undefined;
|
|
360
437
|
}
|
|
361
438
|
```
|
|
362
439
|
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { ExcelGridProps } from '../types';
|
|
2
|
-
export declare function ExcelGrid({ data, onChange, rowHeaders, colHeaders, className, rowHeaderTitle, styles, }: ExcelGridProps): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare function ExcelGrid({ data, onChange, rowHeaders, colHeaders, className, rowHeaderTitle, styles, cellStyles, }: ExcelGridProps): import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
//# sourceMappingURL=excel-grid.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"excel-grid.d.ts","sourceRoot":"","sources":["../../src/components/excel-grid.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,UAAU,CAAC;AAsE1D,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,cAAmB,EACnB,MAAM,
|
|
1
|
+
{"version":3,"file":"excel-grid.d.ts","sourceRoot":"","sources":["../../src/components/excel-grid.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,UAAU,CAAC;AAsE1D,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,cAAmB,EACnB,MAAM,EACN,UAAU,GACX,EAAE,cAAc,2CAmThB"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import { GridCellProps } from '../types';
|
|
2
|
-
export declare function GridCell({ coord, value, isSelected, isFillTarget, showFillHandle, onMouseDown, onMouseEnter, onChange, onFillHandleMouseDown, styles, }: GridCellProps): import("react/jsx-runtime").JSX.Element;
|
|
2
|
+
export declare function GridCell({ coord, value, isSelected, isFillTarget, showFillHandle, onMouseDown, onMouseEnter, onChange, onFillHandleMouseDown, styles, cellClassName, }: GridCellProps): import("react/jsx-runtime").JSX.Element;
|
|
3
3
|
//# sourceMappingURL=grid-cell.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"grid-cell.d.ts","sourceRoot":"","sources":["../../src/components/grid-cell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA8E9C,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,UAAU,EACV,YAAY,EACZ,cAAc,EACd,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,qBAAqB,EACrB,MAAM,
|
|
1
|
+
{"version":3,"file":"grid-cell.d.ts","sourceRoot":"","sources":["../../src/components/grid-cell.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA8E9C,wBAAgB,QAAQ,CAAC,EACvB,KAAK,EACL,KAAK,EACL,UAAU,EACV,YAAY,EACZ,cAAc,EACd,WAAW,EACX,YAAY,EACZ,QAAQ,EACR,qBAAqB,EACrB,MAAM,EACN,aAAa,GACd,EAAE,aAAa,2CA6Kf"}
|