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 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 custom styling
20
- - Row headers with custom styling
21
- - Keyboard shortcuts (Delete/Backspace to clear)
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 | Required | Description |
52
- | ---------------- | ---------------------------- | -------- | --------------------------- |
53
- | `data` | `string[][]` | Yes | 2D array of strings |
54
- | `onChange` | `(data: string[][]) => void` | Yes | Callback when data changes |
55
- | `rowHeaders` | `HeaderGroup[]` | No | Row header definitions |
56
- | `colHeaders` | `HeaderGroup[]` | No | Grouped column headers |
57
- | `className` | `string` | No | CSS class for container |
58
- | `rowHeaderTitle` | `string` | No | Title for row header column |
59
- | `styles` | `GridStyles` | No | Style configuration object |
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="Product"
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
- { key: "regionA", label: "Region A", className: "bg-slate-700 text-white" },
267
- { key: "regionB", label: "Region B", className: "bg-slate-600 text-white" },
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
- | `Ctrl+C` / `Cmd+C` | Copy selected cells |
287
- | `Ctrl+V` / `Cmd+V` | Paste from clipboard |
288
- | `Delete` / `Backspace` | Clear selected cells |
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,GACP,EAAE,cAAc,2CAiThB"}
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,GACP,EAAE,aAAa,2CA4Kf"}
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"}