react-excel-lite 0.0.1 → 0.0.4
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/LICENSE +21 -0
- package/README.md +248 -0
- package/dist/components/excel-grid.d.ts +3 -0
- package/dist/components/excel-grid.d.ts.map +1 -0
- package/dist/components/grid-cell.d.ts +3 -0
- package/dist/components/grid-cell.d.ts.map +1 -0
- package/dist/hooks/use-grid-clipboard.d.ts +19 -0
- package/dist/hooks/use-grid-clipboard.d.ts.map +1 -0
- package/dist/hooks/use-grid-drag-fill.d.ts +21 -0
- package/dist/hooks/use-grid-drag-fill.d.ts.map +1 -0
- package/dist/hooks/use-grid-selection.d.ts +14 -0
- package/dist/hooks/use-grid-selection.d.ts.map +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/react-excel-lite.js +535 -1
- package/dist/react-excel-lite.umd.cjs +2 -1
- package/dist/types.d.ts +98 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/cn.d.ts +6 -0
- package/dist/utils/cn.d.ts.map +1 -0
- package/dist/utils/format-utils.d.ts +13 -0
- package/dist/utils/format-utils.d.ts.map +1 -0
- package/dist/utils/grid-utils.d.ts +34 -0
- package/dist/utils/grid-utils.d.ts.map +1 -0
- package/package.json +5 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 prkgnt
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
# react-excel-lite
|
|
2
|
+
|
|
3
|
+
[](https://github.com/prkgnt/react-excel-lite)
|
|
4
|
+
[](https://www.npmjs.org/package/react-excel-lite)
|
|
5
|
+
[](https://www.npmjs.org/package/react-excel-lite)
|
|
6
|
+
[](https://github.com/prkgnt/react-excel-lite/blob/main/LICENSE)
|
|
7
|
+
[](https://github.com/prkgnt/react-excel-lite/pulls)
|
|
8
|
+
|
|
9
|
+
A lightweight, Excel-like editable grid component for React.
|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- Excel-like cell selection (click & drag)
|
|
14
|
+
- Copy/Paste support (Ctrl+C / Ctrl+V)
|
|
15
|
+
- Auto Fill with arithmetic sequence detection (drag fill handle)
|
|
16
|
+
- Grouped column headers with custom styling
|
|
17
|
+
- Row headers with custom styling
|
|
18
|
+
- Keyboard shortcuts (Delete/Backspace to clear)
|
|
19
|
+
- Zero external dependencies
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install react-excel-lite
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```tsx
|
|
30
|
+
import { useState } from "react";
|
|
31
|
+
import { ExcelGrid } from "react-excel-lite";
|
|
32
|
+
|
|
33
|
+
function App() {
|
|
34
|
+
const [data, setData] = useState([
|
|
35
|
+
["100", "200", "300"],
|
|
36
|
+
["400", "500", "600"],
|
|
37
|
+
["700", "800", "900"],
|
|
38
|
+
]);
|
|
39
|
+
|
|
40
|
+
return <ExcelGrid data={data} onChange={setData} />;
|
|
41
|
+
}
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Props
|
|
45
|
+
|
|
46
|
+
| Prop | Type | Required | Description |
|
|
47
|
+
| ---------------- | ---------------------------- | -------- | --------------------------- |
|
|
48
|
+
| `data` | `string[][]` | Yes | 2D array of strings |
|
|
49
|
+
| `onChange` | `(data: string[][]) => void` | Yes | Callback when data changes |
|
|
50
|
+
| `rowHeaders` | `RowHeaderGroup[]` | No | Row header definitions |
|
|
51
|
+
| `colHeaders` | `ColHeaderGroup[]` | No | Grouped column headers |
|
|
52
|
+
| `className` | `string` | No | CSS class for container |
|
|
53
|
+
| `rowHeaderTitle` | `string` | No | Title for row header column |
|
|
54
|
+
| `styles` | `GridStyles` | No | Style configuration object |
|
|
55
|
+
|
|
56
|
+
## With Headers
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
import { useState } from "react";
|
|
60
|
+
import { ExcelGrid } from "react-excel-lite";
|
|
61
|
+
import type { ColHeaderGroup, RowHeaderGroup } from "react-excel-lite";
|
|
62
|
+
|
|
63
|
+
function App() {
|
|
64
|
+
const [data, setData] = useState([
|
|
65
|
+
["100", "200", "300", "400"],
|
|
66
|
+
["500", "600", "700", "800"],
|
|
67
|
+
]);
|
|
68
|
+
|
|
69
|
+
const colHeaders: ColHeaderGroup[] = [
|
|
70
|
+
{
|
|
71
|
+
label: "Q1",
|
|
72
|
+
headers: [
|
|
73
|
+
{ key: "jan", label: "Jan" },
|
|
74
|
+
{ key: "feb", label: "Feb" },
|
|
75
|
+
],
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
label: "Q2",
|
|
79
|
+
headers: [
|
|
80
|
+
{ key: "mar", label: "Mar" },
|
|
81
|
+
{ key: "apr", label: "Apr" },
|
|
82
|
+
],
|
|
83
|
+
},
|
|
84
|
+
];
|
|
85
|
+
|
|
86
|
+
const rowHeaders: RowHeaderGroup[] = [
|
|
87
|
+
{ key: "prodA", label: "Product A", description: "Main product line" },
|
|
88
|
+
{ key: "prodB", label: "Product B", description: "Secondary product" },
|
|
89
|
+
];
|
|
90
|
+
|
|
91
|
+
return (
|
|
92
|
+
<ExcelGrid
|
|
93
|
+
data={data}
|
|
94
|
+
onChange={setData}
|
|
95
|
+
colHeaders={colHeaders}
|
|
96
|
+
rowHeaders={rowHeaders}
|
|
97
|
+
rowHeaderTitle="Product"
|
|
98
|
+
/>
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Custom Styling
|
|
104
|
+
|
|
105
|
+
Use the `styles` prop to customize selection, fill handle, and header styles:
|
|
106
|
+
|
|
107
|
+
```tsx
|
|
108
|
+
import type { GridStyles } from "react-excel-lite";
|
|
109
|
+
|
|
110
|
+
const styles: GridStyles = {
|
|
111
|
+
cell: "text-sm",
|
|
112
|
+
selected: "bg-purple-100 ring-2 ring-inset ring-purple-500",
|
|
113
|
+
fillTarget: "bg-purple-50",
|
|
114
|
+
fillHandle: "bg-purple-500",
|
|
115
|
+
colGroup: "bg-purple-100 text-purple-700",
|
|
116
|
+
colHeader: "bg-purple-50",
|
|
117
|
+
rowHeader: "bg-slate-200",
|
|
118
|
+
};
|
|
119
|
+
|
|
120
|
+
<ExcelGrid data={data} onChange={setData} styles={styles} />;
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Style individual column headers and groups:
|
|
124
|
+
|
|
125
|
+
```tsx
|
|
126
|
+
const colHeaders: ColHeaderGroup[] = [
|
|
127
|
+
{
|
|
128
|
+
label: "Revenue",
|
|
129
|
+
className: "bg-green-100 text-green-700",
|
|
130
|
+
headers: [
|
|
131
|
+
{ key: "q1r", label: "Q1", className: "bg-green-50" },
|
|
132
|
+
{ key: "q2r", label: "Q2", className: "bg-green-50" },
|
|
133
|
+
],
|
|
134
|
+
},
|
|
135
|
+
];
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
Style individual row headers:
|
|
139
|
+
|
|
140
|
+
```tsx
|
|
141
|
+
const rowHeaders: RowHeaderGroup[] = [
|
|
142
|
+
{
|
|
143
|
+
key: "regionA",
|
|
144
|
+
label: "Region A",
|
|
145
|
+
className: "bg-slate-700 text-white",
|
|
146
|
+
},
|
|
147
|
+
];
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Auto Fill (Arithmetic Sequence)
|
|
151
|
+
|
|
152
|
+
Select cells with a numeric pattern and drag the fill handle to auto-fill:
|
|
153
|
+
|
|
154
|
+
- `1, 2, 3` → drag down → `4, 5, 6, 7, ...`
|
|
155
|
+
- `100, 200, 300` → drag down → `400, 500, 600, ...`
|
|
156
|
+
- `10, 8, 6` → drag down → `4, 2, 0, -2, ...`
|
|
157
|
+
- Text values → repeats the pattern
|
|
158
|
+
|
|
159
|
+
## Keyboard Shortcuts
|
|
160
|
+
|
|
161
|
+
| Shortcut | Action |
|
|
162
|
+
| ---------------------- | -------------------- |
|
|
163
|
+
| `Ctrl+C` / `Cmd+C` | Copy selected cells |
|
|
164
|
+
| `Ctrl+V` / `Cmd+V` | Paste from clipboard |
|
|
165
|
+
| `Delete` / `Backspace` | Clear selected cells |
|
|
166
|
+
|
|
167
|
+
## Exports
|
|
168
|
+
|
|
169
|
+
### Components
|
|
170
|
+
|
|
171
|
+
- `ExcelGrid` - Main grid component
|
|
172
|
+
- `GridCell` - Individual cell component
|
|
173
|
+
|
|
174
|
+
### Hooks
|
|
175
|
+
|
|
176
|
+
- `useGridSelection` - Cell selection logic
|
|
177
|
+
- `useGridClipboard` - Copy/paste logic
|
|
178
|
+
- `useGridDragFill` - Fill handle logic
|
|
179
|
+
|
|
180
|
+
### Utilities
|
|
181
|
+
|
|
182
|
+
- `cn` - Classname merge utility
|
|
183
|
+
- `coordToKey` - Convert coordinate to string key
|
|
184
|
+
- `keyToCoord` - Convert string key to coordinate
|
|
185
|
+
- `getCellsInRange` - Get all cells in a range
|
|
186
|
+
- `isCellInRange` - Check if cell is in range
|
|
187
|
+
- `parseTSV` - Parse TSV string to 2D array
|
|
188
|
+
- `toTSV` - Convert 2D array to TSV string
|
|
189
|
+
- `normalizeRange` - Normalize selection range
|
|
190
|
+
- `getFillTargetCells` - Get fill target cells
|
|
191
|
+
|
|
192
|
+
### Types
|
|
193
|
+
|
|
194
|
+
```ts
|
|
195
|
+
interface CellCoord {
|
|
196
|
+
row: number;
|
|
197
|
+
col: number;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
interface SelectionRange {
|
|
201
|
+
start: CellCoord | null;
|
|
202
|
+
end: CellCoord | null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
interface ColHeader {
|
|
206
|
+
key: string;
|
|
207
|
+
label: string;
|
|
208
|
+
description?: string;
|
|
209
|
+
className?: string;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
interface ColHeaderGroup {
|
|
213
|
+
label: string;
|
|
214
|
+
headers: ColHeader[];
|
|
215
|
+
className?: string;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
interface RowHeaderGroup {
|
|
219
|
+
key: string;
|
|
220
|
+
label: string;
|
|
221
|
+
description?: string;
|
|
222
|
+
className?: string;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
interface GridStyles {
|
|
226
|
+
cell?: string;
|
|
227
|
+
selected?: string;
|
|
228
|
+
fillTarget?: string;
|
|
229
|
+
fillHandle?: string;
|
|
230
|
+
colGroup?: string;
|
|
231
|
+
colHeader?: string;
|
|
232
|
+
rowHeader?: string;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
interface ExcelGridProps {
|
|
236
|
+
data: string[][];
|
|
237
|
+
onChange: (data: string[][]) => void;
|
|
238
|
+
rowHeaders?: RowHeaderGroup[];
|
|
239
|
+
colHeaders?: ColHeaderGroup[];
|
|
240
|
+
className?: string;
|
|
241
|
+
rowHeaderTitle?: string;
|
|
242
|
+
styles?: GridStyles;
|
|
243
|
+
}
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
## Styling
|
|
247
|
+
|
|
248
|
+
The component uses Tailwind CSS classes. Make sure Tailwind CSS is configured in your project, or override styles using the `styles` prop.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"excel-grid.d.ts","sourceRoot":"","sources":["../../src/components/excel-grid.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAa,MAAM,UAAU,CAAC;AAO1D,wBAAgB,SAAS,CAAC,EACxB,IAAI,EACJ,QAAQ,EACR,UAAU,EACV,UAAU,EACV,SAAS,EACT,cAAmB,EACnB,MAAM,GACP,EAAE,cAAc,2CAwPhB"}
|
|
@@ -0,0 +1,3 @@
|
|
|
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;
|
|
3
|
+
//# sourceMappingURL=grid-cell.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid-cell.d.ts","sourceRoot":"","sources":["../../src/components/grid-cell.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C,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,2CAmDf"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CellCoord, SelectionRange } from '../types';
|
|
2
|
+
interface UseGridClipboardProps {
|
|
3
|
+
selection: SelectionRange;
|
|
4
|
+
getValue: (coord: CellCoord) => string;
|
|
5
|
+
setValues: (updates: {
|
|
6
|
+
coord: CellCoord;
|
|
7
|
+
value: string;
|
|
8
|
+
}[]) => void;
|
|
9
|
+
rowCount: number;
|
|
10
|
+
colCount: number;
|
|
11
|
+
}
|
|
12
|
+
interface UseGridClipboardReturn {
|
|
13
|
+
handleCopy: () => Promise<void>;
|
|
14
|
+
handlePaste: () => Promise<void>;
|
|
15
|
+
handleKeyDown: (e: React.KeyboardEvent) => void;
|
|
16
|
+
}
|
|
17
|
+
export declare function useGridClipboard({ selection, getValue, setValues, rowCount, colCount, }: UseGridClipboardProps): UseGridClipboardReturn;
|
|
18
|
+
export {};
|
|
19
|
+
//# sourceMappingURL=use-grid-clipboard.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-grid-clipboard.d.ts","sourceRoot":"","sources":["../../src/hooks/use-grid-clipboard.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1D,UAAU,qBAAqB;IAC7B,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,MAAM,CAAC;IACvC,SAAS,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,IAAI,CAAC;IACpE,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,sBAAsB;IAC9B,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;CACjD;AAED,wBAAgB,gBAAgB,CAAC,EAC/B,SAAS,EACT,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,QAAQ,GACT,EAAE,qBAAqB,GAAG,sBAAsB,CAmHhD"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { CellCoord, SelectionRange } from '../types';
|
|
2
|
+
interface UseGridDragFillProps {
|
|
3
|
+
selection: SelectionRange;
|
|
4
|
+
getValue: (coord: CellCoord) => string;
|
|
5
|
+
setValues: (updates: {
|
|
6
|
+
coord: CellCoord;
|
|
7
|
+
value: string;
|
|
8
|
+
}[]) => void;
|
|
9
|
+
}
|
|
10
|
+
interface UseGridDragFillReturn {
|
|
11
|
+
fillSource: CellCoord | null;
|
|
12
|
+
fillTargets: CellCoord[];
|
|
13
|
+
isDraggingFill: boolean;
|
|
14
|
+
isFillTarget: (coord: CellCoord) => boolean;
|
|
15
|
+
handleFillHandleMouseDown: (sourceCoord: CellCoord) => void;
|
|
16
|
+
handleCellMouseEnterForFill: (coord: CellCoord) => void;
|
|
17
|
+
handleFillMouseUp: () => void;
|
|
18
|
+
}
|
|
19
|
+
export declare function useGridDragFill({ selection, getValue, setValues, }: UseGridDragFillProps): UseGridDragFillReturn;
|
|
20
|
+
export {};
|
|
21
|
+
//# sourceMappingURL=use-grid-drag-fill.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-grid-drag-fill.d.ts","sourceRoot":"","sources":["../../src/hooks/use-grid-drag-fill.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1D,UAAU,oBAAoB;IAC5B,SAAS,EAAE,cAAc,CAAC;IAC1B,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,MAAM,CAAC;IACvC,SAAS,EAAE,CAAC,OAAO,EAAE;QAAE,KAAK,EAAE,SAAS,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,KAAK,IAAI,CAAC;CACrE;AAED,UAAU,qBAAqB;IAC7B,UAAU,EAAE,SAAS,GAAG,IAAI,CAAC;IAC7B,WAAW,EAAE,SAAS,EAAE,CAAC;IACzB,cAAc,EAAE,OAAO,CAAC;IACxB,YAAY,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;IAC5C,yBAAyB,EAAE,CAAC,WAAW,EAAE,SAAS,KAAK,IAAI,CAAC;IAC5D,2BAA2B,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACxD,iBAAiB,EAAE,MAAM,IAAI,CAAC;CAC/B;AA8CD,wBAAgB,eAAe,CAAC,EAC9B,SAAS,EACT,QAAQ,EACR,SAAS,GACV,EAAE,oBAAoB,GAAG,qBAAqB,CAwM9C"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { CellCoord, SelectionRange } from '../types';
|
|
2
|
+
interface UseGridSelectionReturn {
|
|
3
|
+
selection: SelectionRange;
|
|
4
|
+
isSelecting: boolean;
|
|
5
|
+
isCellSelected: (coord: CellCoord) => boolean;
|
|
6
|
+
handleCellMouseDown: (coord: CellCoord) => void;
|
|
7
|
+
handleCellMouseEnter: (coord: CellCoord) => void;
|
|
8
|
+
handleMouseUp: () => void;
|
|
9
|
+
clearSelection: () => void;
|
|
10
|
+
setSelection: (range: SelectionRange) => void;
|
|
11
|
+
}
|
|
12
|
+
export declare function useGridSelection(): UseGridSelectionReturn;
|
|
13
|
+
export {};
|
|
14
|
+
//# sourceMappingURL=use-grid-selection.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-grid-selection.d.ts","sourceRoot":"","sources":["../../src/hooks/use-grid-selection.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAG1D,UAAU,sBAAsB;IAC9B,SAAS,EAAE,cAAc,CAAC;IAC1B,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC;IAC9C,mBAAmB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAChD,oBAAoB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACjD,aAAa,EAAE,MAAM,IAAI,CAAC;IAC1B,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,YAAY,EAAE,CAAC,KAAK,EAAE,cAAc,KAAK,IAAI,CAAC;CAC/C;AAED,wBAAgB,gBAAgB,IAAI,sBAAsB,CA8DzD"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,2 +1,10 @@
|
|
|
1
|
-
export {};
|
|
1
|
+
export { ExcelGrid } from './components/excel-grid';
|
|
2
|
+
export { GridCell } from './components/grid-cell';
|
|
3
|
+
export { useGridSelection } from './hooks/use-grid-selection';
|
|
4
|
+
export { useGridClipboard } from './hooks/use-grid-clipboard';
|
|
5
|
+
export { useGridDragFill } from './hooks/use-grid-drag-fill';
|
|
6
|
+
export { cn } from './utils/cn';
|
|
7
|
+
export { formatCurrency, parseCurrency } from './utils/format-utils';
|
|
8
|
+
export { coordToKey, keyToCoord, getCellsInRange, isCellInRange, parseTSV, toTSV, normalizeRange, getFillTargetCells, } from './utils/grid-utils';
|
|
9
|
+
export type { CellCoord, SelectionRange, ColHeader, ColHeaderGroup, RowHeaderGroup, GridStyles, ExcelGridProps, GridCellProps, } from './types';
|
|
2
10
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,QAAQ,EAAE,MAAM,wBAAwB,CAAC;AAGlD,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,gBAAgB,EAAE,MAAM,4BAA4B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAG7D,OAAO,EAAE,EAAE,EAAE,MAAM,YAAY,CAAC;AAChC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrE,OAAO,EACL,UAAU,EACV,UAAU,EACV,eAAe,EACf,aAAa,EACb,QAAQ,EACR,KAAK,EACL,cAAc,EACd,kBAAkB,GACnB,MAAM,oBAAoB,CAAC;AAG5B,YAAY,EACV,SAAS,EACT,cAAc,EACd,SAAS,EACT,cAAc,EACd,cAAc,EACd,UAAU,EACV,cAAc,EACd,aAAa,GACd,MAAM,SAAS,CAAC"}
|
package/dist/react-excel-lite.js
CHANGED
|
@@ -1 +1,535 @@
|
|
|
1
|
-
|
|
1
|
+
import { jsxs as j, jsx as E } from "react/jsx-runtime";
|
|
2
|
+
import { useState as L, useCallback as x, useEffect as $, useRef as _, useMemo as q } from "react";
|
|
3
|
+
function R(...n) {
|
|
4
|
+
return n.filter(Boolean).join(" ");
|
|
5
|
+
}
|
|
6
|
+
function on(n) {
|
|
7
|
+
return `${n.row}-${n.col}`;
|
|
8
|
+
}
|
|
9
|
+
function tn(n) {
|
|
10
|
+
const [o, e] = n.split("-").map(Number);
|
|
11
|
+
return { row: o, col: e };
|
|
12
|
+
}
|
|
13
|
+
function en(n, o) {
|
|
14
|
+
if (!n || !o) return n ? [n] : [];
|
|
15
|
+
const e = Math.min(n.row, o.row), s = Math.max(n.row, o.row), i = Math.min(n.col, o.col), b = Math.max(n.col, o.col), c = [];
|
|
16
|
+
for (let f = e; f <= s; f++)
|
|
17
|
+
for (let a = i; a <= b; a++)
|
|
18
|
+
c.push({ row: f, col: a });
|
|
19
|
+
return c;
|
|
20
|
+
}
|
|
21
|
+
function J(n, o) {
|
|
22
|
+
if (!o.start) return !1;
|
|
23
|
+
const e = o.end || o.start, s = Math.min(o.start.row, e.row), i = Math.max(o.start.row, e.row), b = Math.min(o.start.col, e.col), c = Math.max(o.start.col, e.col);
|
|
24
|
+
return n.row >= s && n.row <= i && n.col >= b && n.col <= c;
|
|
25
|
+
}
|
|
26
|
+
function O(n) {
|
|
27
|
+
return n.split(/\r?\n/).filter((o) => o.trim()).map((o) => o.split(" ").map((e) => e.trim()));
|
|
28
|
+
}
|
|
29
|
+
function Q(n) {
|
|
30
|
+
return n.map((o) => o.join(" ")).join(`
|
|
31
|
+
`);
|
|
32
|
+
}
|
|
33
|
+
function B(n) {
|
|
34
|
+
return !n.start || !n.end ? n : {
|
|
35
|
+
start: {
|
|
36
|
+
row: Math.min(n.start.row, n.end.row),
|
|
37
|
+
col: Math.min(n.start.col, n.end.col)
|
|
38
|
+
},
|
|
39
|
+
end: {
|
|
40
|
+
row: Math.max(n.start.row, n.end.row),
|
|
41
|
+
col: Math.max(n.start.col, n.end.col)
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
function ln(n, o) {
|
|
46
|
+
if (n.row === o.row && n.col === o.col)
|
|
47
|
+
return [];
|
|
48
|
+
const e = Math.min(n.row, o.row), s = Math.max(n.row, o.row), i = Math.min(n.col, o.col), b = Math.max(n.col, o.col), c = [];
|
|
49
|
+
for (let f = e; f <= s; f++)
|
|
50
|
+
for (let a = i; a <= b; a++)
|
|
51
|
+
f === n.row && a === n.col || c.push({ row: f, col: a });
|
|
52
|
+
return c;
|
|
53
|
+
}
|
|
54
|
+
function W() {
|
|
55
|
+
const [n, o] = L({
|
|
56
|
+
start: null,
|
|
57
|
+
end: null
|
|
58
|
+
}), [e, s] = L(!1), i = x((u) => {
|
|
59
|
+
o({ start: u, end: u }), s(!0);
|
|
60
|
+
}, []), b = x(
|
|
61
|
+
(u) => {
|
|
62
|
+
e && o((l) => ({ ...l, end: u }));
|
|
63
|
+
},
|
|
64
|
+
[e]
|
|
65
|
+
), c = x(() => {
|
|
66
|
+
s(!1);
|
|
67
|
+
}, []), f = x(() => {
|
|
68
|
+
o({ start: null, end: null }), s(!1);
|
|
69
|
+
}, []), a = x(
|
|
70
|
+
(u) => J(u, n),
|
|
71
|
+
[n]
|
|
72
|
+
);
|
|
73
|
+
return $(() => {
|
|
74
|
+
const u = () => {
|
|
75
|
+
e && s(!1);
|
|
76
|
+
};
|
|
77
|
+
return window.addEventListener("mouseup", u), () => window.removeEventListener("mouseup", u);
|
|
78
|
+
}, [e]), {
|
|
79
|
+
selection: n,
|
|
80
|
+
isSelecting: e,
|
|
81
|
+
isCellSelected: a,
|
|
82
|
+
handleCellMouseDown: i,
|
|
83
|
+
handleCellMouseEnter: b,
|
|
84
|
+
handleMouseUp: c,
|
|
85
|
+
clearSelection: f,
|
|
86
|
+
setSelection: o
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
function X({
|
|
90
|
+
selection: n,
|
|
91
|
+
getValue: o,
|
|
92
|
+
setValues: e,
|
|
93
|
+
rowCount: s,
|
|
94
|
+
colCount: i
|
|
95
|
+
}) {
|
|
96
|
+
const b = x(() => {
|
|
97
|
+
const l = B(n);
|
|
98
|
+
if (!l.start || !l.end) return [];
|
|
99
|
+
const y = [];
|
|
100
|
+
for (let C = l.start.row; C <= l.end.row; C++) {
|
|
101
|
+
const h = [];
|
|
102
|
+
for (let D = l.start.col; D <= l.end.col; D++)
|
|
103
|
+
h.push(o({ row: C, col: D }));
|
|
104
|
+
y.push(h);
|
|
105
|
+
}
|
|
106
|
+
return y;
|
|
107
|
+
}, [n, o]), c = x(async () => {
|
|
108
|
+
const l = b();
|
|
109
|
+
if (l.length === 0) return;
|
|
110
|
+
const y = Q(l);
|
|
111
|
+
try {
|
|
112
|
+
await navigator.clipboard.writeText(y);
|
|
113
|
+
} catch (C) {
|
|
114
|
+
console.error("Clipboard copy failed:", C);
|
|
115
|
+
}
|
|
116
|
+
}, [b]), f = x(async () => {
|
|
117
|
+
if (n.start)
|
|
118
|
+
try {
|
|
119
|
+
const l = await navigator.clipboard.readText(), y = O(l);
|
|
120
|
+
if (y.length === 0) return;
|
|
121
|
+
const C = n.start.row, h = n.start.col, D = [];
|
|
122
|
+
y.forEach((d, M) => {
|
|
123
|
+
const w = C + M;
|
|
124
|
+
w >= s || d.forEach((m, v) => {
|
|
125
|
+
const F = h + v;
|
|
126
|
+
F >= i || D.push({ coord: { row: w, col: F }, value: m });
|
|
127
|
+
});
|
|
128
|
+
}), D.length > 0 && e(D);
|
|
129
|
+
} catch (l) {
|
|
130
|
+
console.error("Clipboard paste failed:", l);
|
|
131
|
+
}
|
|
132
|
+
}, [n.start, e, s, i]), a = x(() => {
|
|
133
|
+
const l = B(n);
|
|
134
|
+
if (!l.start || !l.end) return;
|
|
135
|
+
const y = [];
|
|
136
|
+
for (let C = l.start.row; C <= l.end.row; C++)
|
|
137
|
+
for (let h = l.start.col; h <= l.end.col; h++)
|
|
138
|
+
y.push({ coord: { row: C, col: h }, value: "" });
|
|
139
|
+
y.length > 0 && e(y);
|
|
140
|
+
}, [n, e]), u = x(
|
|
141
|
+
(l) => {
|
|
142
|
+
(l.ctrlKey || l.metaKey) && l.key === "c" && (l.preventDefault(), c()), (l.ctrlKey || l.metaKey) && l.key === "v" && (l.preventDefault(), f()), (l.key === "Backspace" || l.key === "Delete") && (l.preventDefault(), a());
|
|
143
|
+
},
|
|
144
|
+
[c, f, a]
|
|
145
|
+
);
|
|
146
|
+
return {
|
|
147
|
+
handleCopy: c,
|
|
148
|
+
handlePaste: f,
|
|
149
|
+
handleKeyDown: u
|
|
150
|
+
};
|
|
151
|
+
}
|
|
152
|
+
function Y(n) {
|
|
153
|
+
if (n.trim() === "") return null;
|
|
154
|
+
const o = Number(n);
|
|
155
|
+
return isNaN(o) ? null : o;
|
|
156
|
+
}
|
|
157
|
+
function P(n) {
|
|
158
|
+
if (n.length === 0) return null;
|
|
159
|
+
const o = n.map(Y);
|
|
160
|
+
if (o.some((i) => i === null)) return null;
|
|
161
|
+
const e = o;
|
|
162
|
+
if (e.length === 1)
|
|
163
|
+
return { numbers: e, diff: 0 };
|
|
164
|
+
const s = e[1] - e[0];
|
|
165
|
+
for (let i = 2; i < e.length; i++)
|
|
166
|
+
if (e[i] - e[i - 1] !== s)
|
|
167
|
+
return { numbers: e, diff: 0 };
|
|
168
|
+
return { numbers: e, diff: s };
|
|
169
|
+
}
|
|
170
|
+
function Z({
|
|
171
|
+
selection: n,
|
|
172
|
+
getValue: o,
|
|
173
|
+
setValues: e
|
|
174
|
+
}) {
|
|
175
|
+
const [s, i] = L(null), [b, c] = L([]), [f, a] = L(!1), [u, l] = L(null), y = x((d) => {
|
|
176
|
+
i(d), a(!0), c([]), l(null);
|
|
177
|
+
}, []), C = x(
|
|
178
|
+
(d) => {
|
|
179
|
+
if (!f || !n.start) return;
|
|
180
|
+
const M = B(n);
|
|
181
|
+
if (!M.start || !M.end) return;
|
|
182
|
+
l(d);
|
|
183
|
+
const w = {
|
|
184
|
+
row: Math.min(M.start.row, d.row),
|
|
185
|
+
col: Math.min(M.start.col, d.col)
|
|
186
|
+
}, m = {
|
|
187
|
+
row: Math.max(M.end.row, d.row),
|
|
188
|
+
col: Math.max(M.end.col, d.col)
|
|
189
|
+
}, v = [];
|
|
190
|
+
for (let F = w.row; F <= m.row; F++)
|
|
191
|
+
for (let r = w.col; r <= m.col; r++)
|
|
192
|
+
F >= M.start.row && F <= M.end.row && r >= M.start.col && r <= M.end.col || v.push({ row: F, col: r });
|
|
193
|
+
c(v);
|
|
194
|
+
},
|
|
195
|
+
[f, n]
|
|
196
|
+
), h = x(() => {
|
|
197
|
+
if (!n.start || b.length === 0 || !u) {
|
|
198
|
+
i(null), c([]), a(!1), l(null);
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
const d = B(n);
|
|
202
|
+
if (!d.start || !d.end) {
|
|
203
|
+
i(null), c([]), a(!1), l(null);
|
|
204
|
+
return;
|
|
205
|
+
}
|
|
206
|
+
const M = [], w = d.start, m = d.end, v = m.row - w.row + 1, F = m.col - w.col + 1;
|
|
207
|
+
b.forEach((r) => {
|
|
208
|
+
let T, k;
|
|
209
|
+
if (r.row < w.row) {
|
|
210
|
+
const S = w.row - r.row;
|
|
211
|
+
T = m.row - (S - 1) % v;
|
|
212
|
+
} else if (r.row > m.row) {
|
|
213
|
+
const S = r.row - m.row;
|
|
214
|
+
T = w.row + (S - 1) % v;
|
|
215
|
+
} else
|
|
216
|
+
T = r.row;
|
|
217
|
+
if (r.col < w.col) {
|
|
218
|
+
const S = w.col - r.col;
|
|
219
|
+
k = m.col - (S - 1) % F;
|
|
220
|
+
} else if (r.col > m.col) {
|
|
221
|
+
const S = r.col - m.col;
|
|
222
|
+
k = w.col + (S - 1) % F;
|
|
223
|
+
} else
|
|
224
|
+
k = r.col;
|
|
225
|
+
let z = o({ row: T, col: k });
|
|
226
|
+
if (r.row !== T && r.col >= w.col && r.col <= m.col) {
|
|
227
|
+
const S = [];
|
|
228
|
+
for (let t = w.row; t <= m.row; t++)
|
|
229
|
+
S.push(o({ row: t, col: r.col }));
|
|
230
|
+
const g = P(S);
|
|
231
|
+
if (g && g.diff !== 0) {
|
|
232
|
+
if (r.row > m.row) {
|
|
233
|
+
const t = r.row - m.row;
|
|
234
|
+
z = String(g.numbers[g.numbers.length - 1] + g.diff * t);
|
|
235
|
+
} else if (r.row < w.row) {
|
|
236
|
+
const t = w.row - r.row;
|
|
237
|
+
z = String(g.numbers[0] - g.diff * t);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (r.col !== k && r.row >= w.row && r.row <= m.row) {
|
|
242
|
+
const S = [];
|
|
243
|
+
for (let t = w.col; t <= m.col; t++)
|
|
244
|
+
S.push(o({ row: r.row, col: t }));
|
|
245
|
+
const g = P(S);
|
|
246
|
+
if (g && g.diff !== 0) {
|
|
247
|
+
if (r.col > m.col) {
|
|
248
|
+
const t = r.col - m.col;
|
|
249
|
+
z = String(g.numbers[g.numbers.length - 1] + g.diff * t);
|
|
250
|
+
} else if (r.col < w.col) {
|
|
251
|
+
const t = w.col - r.col;
|
|
252
|
+
z = String(g.numbers[0] - g.diff * t);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
M.push({ coord: r, value: z });
|
|
257
|
+
}), M.length > 0 && e(M), i(null), c([]), a(!1), l(null);
|
|
258
|
+
}, [n, b, u, o, e]), D = x(
|
|
259
|
+
(d) => b.some(
|
|
260
|
+
(M) => M.row === d.row && M.col === d.col
|
|
261
|
+
),
|
|
262
|
+
[b]
|
|
263
|
+
);
|
|
264
|
+
return $(() => {
|
|
265
|
+
const d = () => {
|
|
266
|
+
f && h();
|
|
267
|
+
};
|
|
268
|
+
return window.addEventListener("mouseup", d), () => window.removeEventListener("mouseup", d);
|
|
269
|
+
}, [f, h]), {
|
|
270
|
+
fillSource: s,
|
|
271
|
+
fillTargets: b,
|
|
272
|
+
isDraggingFill: f,
|
|
273
|
+
isFillTarget: D,
|
|
274
|
+
handleFillHandleMouseDown: y,
|
|
275
|
+
handleCellMouseEnterForFill: C,
|
|
276
|
+
handleFillMouseUp: h
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function V({
|
|
280
|
+
coord: n,
|
|
281
|
+
value: o,
|
|
282
|
+
isSelected: e,
|
|
283
|
+
isFillTarget: s,
|
|
284
|
+
showFillHandle: i,
|
|
285
|
+
onMouseDown: b,
|
|
286
|
+
onMouseEnter: c,
|
|
287
|
+
onChange: f,
|
|
288
|
+
onFillHandleMouseDown: a,
|
|
289
|
+
styles: u
|
|
290
|
+
}) {
|
|
291
|
+
const l = (h) => {
|
|
292
|
+
f(n, h.target.value);
|
|
293
|
+
}, y = (h) => {
|
|
294
|
+
h.target.classList.contains("fill-handle") || b(n);
|
|
295
|
+
}, C = (h) => {
|
|
296
|
+
h.stopPropagation(), h.preventDefault(), a(n);
|
|
297
|
+
};
|
|
298
|
+
return /* @__PURE__ */ j(
|
|
299
|
+
"td",
|
|
300
|
+
{
|
|
301
|
+
className: R(
|
|
302
|
+
"relative border border-gray-300 p-0",
|
|
303
|
+
u?.cell,
|
|
304
|
+
e && (u?.selected ?? "bg-blue-100 ring-2 ring-inset ring-blue-500"),
|
|
305
|
+
s && (u?.fillTarget ?? "bg-blue-50")
|
|
306
|
+
),
|
|
307
|
+
onMouseDown: y,
|
|
308
|
+
onMouseEnter: () => c(n),
|
|
309
|
+
children: [
|
|
310
|
+
/* @__PURE__ */ E(
|
|
311
|
+
"input",
|
|
312
|
+
{
|
|
313
|
+
type: "text",
|
|
314
|
+
value: o,
|
|
315
|
+
onChange: l,
|
|
316
|
+
className: R(
|
|
317
|
+
"w-full h-full px-1 py-1 text-right text-xs bg-transparent outline-none cursor-cell",
|
|
318
|
+
e && "bg-transparent"
|
|
319
|
+
)
|
|
320
|
+
}
|
|
321
|
+
),
|
|
322
|
+
i && /* @__PURE__ */ E(
|
|
323
|
+
"div",
|
|
324
|
+
{
|
|
325
|
+
className: R(
|
|
326
|
+
"fill-handle absolute -bottom-0.5 -right-0.5 w-2 h-2 cursor-crosshair z-20",
|
|
327
|
+
u?.fillHandle ?? "bg-blue-500"
|
|
328
|
+
),
|
|
329
|
+
onMouseDown: C
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
]
|
|
333
|
+
}
|
|
334
|
+
);
|
|
335
|
+
}
|
|
336
|
+
function rn({
|
|
337
|
+
data: n,
|
|
338
|
+
onChange: o,
|
|
339
|
+
rowHeaders: e,
|
|
340
|
+
colHeaders: s,
|
|
341
|
+
className: i,
|
|
342
|
+
rowHeaderTitle: b = "",
|
|
343
|
+
styles: c
|
|
344
|
+
}) {
|
|
345
|
+
const f = _(null), a = n.length, u = q(() => s ? s.reduce(
|
|
346
|
+
(t, p) => t + p.headers.length,
|
|
347
|
+
0
|
|
348
|
+
) : n[0]?.length ?? 0, [s, n]), l = q(() => s ? s.flatMap((t) => t.headers) : [], [s]), y = x(
|
|
349
|
+
(t) => t.row < 0 || t.row >= a || t.col < 0 || t.col >= u ? "" : n[t.row]?.[t.col] ?? "",
|
|
350
|
+
[n, a, u]
|
|
351
|
+
), C = x(
|
|
352
|
+
(t, p) => {
|
|
353
|
+
const N = n.map(
|
|
354
|
+
(K, G) => G === t.row ? K.map(
|
|
355
|
+
(I, U) => U === t.col ? p : I
|
|
356
|
+
) : K
|
|
357
|
+
);
|
|
358
|
+
o(N);
|
|
359
|
+
},
|
|
360
|
+
[n, o]
|
|
361
|
+
), h = x(
|
|
362
|
+
(t) => {
|
|
363
|
+
if (t.length === 0) return;
|
|
364
|
+
const p = n.map((N) => [...N]);
|
|
365
|
+
t.forEach(({ coord: N, value: K }) => {
|
|
366
|
+
N.row >= 0 && N.row < a && N.col >= 0 && N.col < u && (p[N.row][N.col] = K);
|
|
367
|
+
}), o(p);
|
|
368
|
+
},
|
|
369
|
+
[n, o, a, u]
|
|
370
|
+
), {
|
|
371
|
+
selection: D,
|
|
372
|
+
isSelecting: d,
|
|
373
|
+
isCellSelected: M,
|
|
374
|
+
handleCellMouseDown: w,
|
|
375
|
+
handleCellMouseEnter: m
|
|
376
|
+
} = W(), { handleKeyDown: v } = X({
|
|
377
|
+
selection: D,
|
|
378
|
+
getValue: y,
|
|
379
|
+
setValues: h,
|
|
380
|
+
rowCount: a,
|
|
381
|
+
colCount: u
|
|
382
|
+
}), {
|
|
383
|
+
isDraggingFill: F,
|
|
384
|
+
isFillTarget: r,
|
|
385
|
+
handleFillHandleMouseDown: T,
|
|
386
|
+
handleCellMouseEnterForFill: k
|
|
387
|
+
} = Z({
|
|
388
|
+
selection: D,
|
|
389
|
+
getValue: y,
|
|
390
|
+
setValues: h
|
|
391
|
+
}), z = x(
|
|
392
|
+
(t) => {
|
|
393
|
+
F ? k(t) : d && m(t);
|
|
394
|
+
},
|
|
395
|
+
[
|
|
396
|
+
F,
|
|
397
|
+
d,
|
|
398
|
+
k,
|
|
399
|
+
m
|
|
400
|
+
]
|
|
401
|
+
), S = x(
|
|
402
|
+
(t, p) => {
|
|
403
|
+
C(t, p);
|
|
404
|
+
},
|
|
405
|
+
[C]
|
|
406
|
+
), g = x(
|
|
407
|
+
(t) => {
|
|
408
|
+
if (!D.start) return !1;
|
|
409
|
+
const p = B(D);
|
|
410
|
+
return !p.start || !p.end ? !1 : t.row === p.end.row && t.col === p.end.col;
|
|
411
|
+
},
|
|
412
|
+
[D]
|
|
413
|
+
);
|
|
414
|
+
return /* @__PURE__ */ E(
|
|
415
|
+
"div",
|
|
416
|
+
{
|
|
417
|
+
ref: f,
|
|
418
|
+
className: R("outline-none overflow-x-auto", i),
|
|
419
|
+
tabIndex: 0,
|
|
420
|
+
onKeyDown: v,
|
|
421
|
+
children: /* @__PURE__ */ j("table", { className: "border-collapse text-xs select-none", children: [
|
|
422
|
+
/* @__PURE__ */ j("thead", { children: [
|
|
423
|
+
s && /* @__PURE__ */ j("tr", { children: [
|
|
424
|
+
e && /* @__PURE__ */ E(
|
|
425
|
+
"th",
|
|
426
|
+
{
|
|
427
|
+
className: R(
|
|
428
|
+
"sticky left-0 z-10 bg-gray-100 border border-gray-300 px-2 py-1.5 text-center font-medium",
|
|
429
|
+
c?.rowHeader
|
|
430
|
+
),
|
|
431
|
+
children: b
|
|
432
|
+
}
|
|
433
|
+
),
|
|
434
|
+
s.map((t, p) => /* @__PURE__ */ E(
|
|
435
|
+
"th",
|
|
436
|
+
{
|
|
437
|
+
colSpan: t.headers.length,
|
|
438
|
+
className: R(
|
|
439
|
+
"bg-blue-100 border border-gray-300 px-1 py-1.5 text-center font-medium text-blue-700",
|
|
440
|
+
c?.colGroup,
|
|
441
|
+
t.className
|
|
442
|
+
),
|
|
443
|
+
children: t.label
|
|
444
|
+
},
|
|
445
|
+
p
|
|
446
|
+
))
|
|
447
|
+
] }),
|
|
448
|
+
s && /* @__PURE__ */ j("tr", { children: [
|
|
449
|
+
e && /* @__PURE__ */ E(
|
|
450
|
+
"th",
|
|
451
|
+
{
|
|
452
|
+
className: R(
|
|
453
|
+
"sticky left-0 z-10 bg-gray-100 border border-gray-300 px-2 py-1",
|
|
454
|
+
c?.rowHeader
|
|
455
|
+
)
|
|
456
|
+
}
|
|
457
|
+
),
|
|
458
|
+
l.map((t) => /* @__PURE__ */ E(
|
|
459
|
+
"th",
|
|
460
|
+
{
|
|
461
|
+
className: R(
|
|
462
|
+
"bg-gray-50 border border-gray-300 px-1 py-1 text-center font-medium text-[11px]",
|
|
463
|
+
c?.colHeader,
|
|
464
|
+
t.className
|
|
465
|
+
),
|
|
466
|
+
title: t.description,
|
|
467
|
+
children: t.label
|
|
468
|
+
},
|
|
469
|
+
t.key
|
|
470
|
+
))
|
|
471
|
+
] })
|
|
472
|
+
] }),
|
|
473
|
+
/* @__PURE__ */ E("tbody", { children: n.map((t, p) => /* @__PURE__ */ j("tr", { children: [
|
|
474
|
+
e && e[p] && /* @__PURE__ */ E(
|
|
475
|
+
"td",
|
|
476
|
+
{
|
|
477
|
+
className: R(
|
|
478
|
+
"sticky left-0 z-10 bg-gray-100 border border-gray-300 px-1 py-1.5 text-center font-medium",
|
|
479
|
+
c?.rowHeader,
|
|
480
|
+
e[p].className
|
|
481
|
+
),
|
|
482
|
+
title: e[p].description,
|
|
483
|
+
children: e[p].label
|
|
484
|
+
}
|
|
485
|
+
),
|
|
486
|
+
t.map((N, K) => {
|
|
487
|
+
const G = { row: p, col: K }, I = M(G), U = r(G), A = g(G);
|
|
488
|
+
return /* @__PURE__ */ E(
|
|
489
|
+
V,
|
|
490
|
+
{
|
|
491
|
+
coord: G,
|
|
492
|
+
value: y(G),
|
|
493
|
+
isSelected: I,
|
|
494
|
+
isFillTarget: U,
|
|
495
|
+
showFillHandle: A && !F,
|
|
496
|
+
onMouseDown: w,
|
|
497
|
+
onMouseEnter: z,
|
|
498
|
+
onChange: S,
|
|
499
|
+
onFillHandleMouseDown: T,
|
|
500
|
+
styles: c
|
|
501
|
+
},
|
|
502
|
+
K
|
|
503
|
+
);
|
|
504
|
+
})
|
|
505
|
+
] }, p)) })
|
|
506
|
+
] })
|
|
507
|
+
}
|
|
508
|
+
);
|
|
509
|
+
}
|
|
510
|
+
function sn(n) {
|
|
511
|
+
const o = typeof n == "string" ? parseFloat(n.replace(/,/g, "")) : n;
|
|
512
|
+
return isNaN(o) ? "0" : new Intl.NumberFormat("ko-KR").format(o);
|
|
513
|
+
}
|
|
514
|
+
function cn(n) {
|
|
515
|
+
const o = parseInt(n.replace(/,/g, ""), 10);
|
|
516
|
+
return isNaN(o) ? 0 : o;
|
|
517
|
+
}
|
|
518
|
+
export {
|
|
519
|
+
rn as ExcelGrid,
|
|
520
|
+
V as GridCell,
|
|
521
|
+
R as cn,
|
|
522
|
+
on as coordToKey,
|
|
523
|
+
sn as formatCurrency,
|
|
524
|
+
en as getCellsInRange,
|
|
525
|
+
ln as getFillTargetCells,
|
|
526
|
+
J as isCellInRange,
|
|
527
|
+
tn as keyToCoord,
|
|
528
|
+
B as normalizeRange,
|
|
529
|
+
cn as parseCurrency,
|
|
530
|
+
O as parseTSV,
|
|
531
|
+
Q as toTSV,
|
|
532
|
+
X as useGridClipboard,
|
|
533
|
+
Z as useGridDragFill,
|
|
534
|
+
W as useGridSelection
|
|
535
|
+
};
|
|
@@ -1 +1,2 @@
|
|
|
1
|
-
(function(
|
|
1
|
+
(function(m,g){typeof exports=="object"&&typeof module<"u"?g(exports,require("react/jsx-runtime"),require("react")):typeof define=="function"&&define.amd?define(["exports","react/jsx-runtime","react"],g):(m=typeof globalThis<"u"?globalThis:m||self,g(m.ReactExcelLite={},m.ReactJsxRuntime,m.React))})(this,(function(m,g,s){"use strict";function T(...l){return l.filter(Boolean).join(" ")}function _(l){return`${l.row}-${l.col}`}function Q(l){const[n,o]=l.split("-").map(Number);return{row:n,col:o}}function W(l,n){if(!l||!n)return l?[l]:[];const o=Math.min(l.row,n.row),c=Math.max(l.row,n.row),a=Math.min(l.col,n.col),y=Math.max(l.col,n.col),i=[];for(let w=o;w<=c;w++)for(let u=a;u<=y;u++)i.push({row:w,col:u});return i}function B(l,n){if(!n.start)return!1;const o=n.end||n.start,c=Math.min(n.start.row,o.row),a=Math.max(n.start.row,o.row),y=Math.min(n.start.col,o.col),i=Math.max(n.start.col,o.col);return l.row>=c&&l.row<=a&&l.col>=y&&l.col<=i}function U(l){return l.split(/\r?\n/).filter(n=>n.trim()).map(n=>n.split(" ").map(o=>o.trim()))}function P(l){return l.map(n=>n.join(" ")).join(`
|
|
2
|
+
`)}function I(l){return!l.start||!l.end?l:{start:{row:Math.min(l.start.row,l.end.row),col:Math.min(l.start.col,l.end.col)},end:{row:Math.max(l.start.row,l.end.row),col:Math.max(l.start.col,l.end.col)}}}function X(l,n){if(l.row===n.row&&l.col===n.col)return[];const o=Math.min(l.row,n.row),c=Math.max(l.row,n.row),a=Math.min(l.col,n.col),y=Math.max(l.col,n.col),i=[];for(let w=o;w<=c;w++)for(let u=a;u<=y;u++)w===l.row&&u===l.col||i.push({row:w,col:u});return i}function $(){const[l,n]=s.useState({start:null,end:null}),[o,c]=s.useState(!1),a=s.useCallback(f=>{n({start:f,end:f}),c(!0)},[]),y=s.useCallback(f=>{o&&n(t=>({...t,end:f}))},[o]),i=s.useCallback(()=>{c(!1)},[]),w=s.useCallback(()=>{n({start:null,end:null}),c(!1)},[]),u=s.useCallback(f=>B(f,l),[l]);return s.useEffect(()=>{const f=()=>{o&&c(!1)};return window.addEventListener("mouseup",f),()=>window.removeEventListener("mouseup",f)},[o]),{selection:l,isSelecting:o,isCellSelected:u,handleCellMouseDown:a,handleCellMouseEnter:y,handleMouseUp:i,clearSelection:w,setSelection:n}}function A({selection:l,getValue:n,setValues:o,rowCount:c,colCount:a}){const y=s.useCallback(()=>{const t=I(l);if(!t.start||!t.end)return[];const S=[];for(let k=t.start.row;k<=t.end.row;k++){const b=[];for(let D=t.start.col;D<=t.end.col;D++)b.push(n({row:k,col:D}));S.push(b)}return S},[l,n]),i=s.useCallback(async()=>{const t=y();if(t.length===0)return;const S=P(t);try{await navigator.clipboard.writeText(S)}catch(k){console.error("Clipboard copy failed:",k)}},[y]),w=s.useCallback(async()=>{if(l.start)try{const t=await navigator.clipboard.readText(),S=U(t);if(S.length===0)return;const k=l.start.row,b=l.start.col,D=[];S.forEach((p,M)=>{const d=k+M;d>=c||p.forEach((h,v)=>{const F=b+v;F>=a||D.push({coord:{row:d,col:F},value:h})})}),D.length>0&&o(D)}catch(t){console.error("Clipboard paste failed:",t)}},[l.start,o,c,a]),u=s.useCallback(()=>{const t=I(l);if(!t.start||!t.end)return;const S=[];for(let k=t.start.row;k<=t.end.row;k++)for(let b=t.start.col;b<=t.end.col;b++)S.push({coord:{row:k,col:b},value:""});S.length>0&&o(S)},[l,o]),f=s.useCallback(t=>{(t.ctrlKey||t.metaKey)&&t.key==="c"&&(t.preventDefault(),i()),(t.ctrlKey||t.metaKey)&&t.key==="v"&&(t.preventDefault(),w()),(t.key==="Backspace"||t.key==="Delete")&&(t.preventDefault(),u())},[i,w,u]);return{handleCopy:i,handlePaste:w,handleKeyDown:f}}function Y(l){if(l.trim()==="")return null;const n=Number(l);return isNaN(n)?null:n}function J(l){if(l.length===0)return null;const n=l.map(Y);if(n.some(a=>a===null))return null;const o=n;if(o.length===1)return{numbers:o,diff:0};const c=o[1]-o[0];for(let a=2;a<o.length;a++)if(o[a]-o[a-1]!==c)return{numbers:o,diff:0};return{numbers:o,diff:c}}function O({selection:l,getValue:n,setValues:o}){const[c,a]=s.useState(null),[y,i]=s.useState([]),[w,u]=s.useState(!1),[f,t]=s.useState(null),S=s.useCallback(p=>{a(p),u(!0),i([]),t(null)},[]),k=s.useCallback(p=>{if(!w||!l.start)return;const M=I(l);if(!M.start||!M.end)return;t(p);const d={row:Math.min(M.start.row,p.row),col:Math.min(M.start.col,p.col)},h={row:Math.max(M.end.row,p.row),col:Math.max(M.end.col,p.col)},v=[];for(let F=d.row;F<=h.row;F++)for(let r=d.col;r<=h.col;r++)F>=M.start.row&&F<=M.end.row&&r>=M.start.col&&r<=M.end.col||v.push({row:F,col:r});i(v)},[w,l]),b=s.useCallback(()=>{if(!l.start||y.length===0||!f){a(null),i([]),u(!1),t(null);return}const p=I(l);if(!p.start||!p.end){a(null),i([]),u(!1),t(null);return}const M=[],d=p.start,h=p.end,v=h.row-d.row+1,F=h.col-d.col+1;y.forEach(r=>{let G,z;if(r.row<d.row){const E=d.row-r.row;G=h.row-(E-1)%v}else if(r.row>h.row){const E=r.row-h.row;G=d.row+(E-1)%v}else G=r.row;if(r.col<d.col){const E=d.col-r.col;z=h.col-(E-1)%F}else if(r.col>h.col){const E=r.col-h.col;z=d.col+(E-1)%F}else z=r.col;let K=n({row:G,col:z});if(r.row!==G&&r.col>=d.col&&r.col<=h.col){const E=[];for(let e=d.row;e<=h.row;e++)E.push(n({row:e,col:r.col}));const x=J(E);if(x&&x.diff!==0){if(r.row>h.row){const e=r.row-h.row;K=String(x.numbers[x.numbers.length-1]+x.diff*e)}else if(r.row<d.row){const e=d.row-r.row;K=String(x.numbers[0]-x.diff*e)}}}if(r.col!==z&&r.row>=d.row&&r.row<=h.row){const E=[];for(let e=d.col;e<=h.col;e++)E.push(n({row:r.row,col:e}));const x=J(E);if(x&&x.diff!==0){if(r.col>h.col){const e=r.col-h.col;K=String(x.numbers[x.numbers.length-1]+x.diff*e)}else if(r.col<d.col){const e=d.col-r.col;K=String(x.numbers[0]-x.diff*e)}}}M.push({coord:r,value:K})}),M.length>0&&o(M),a(null),i([]),u(!1),t(null)},[l,y,f,n,o]),D=s.useCallback(p=>y.some(M=>M.row===p.row&&M.col===p.col),[y]);return s.useEffect(()=>{const p=()=>{w&&b()};return window.addEventListener("mouseup",p),()=>window.removeEventListener("mouseup",p)},[w,b]),{fillSource:c,fillTargets:y,isDraggingFill:w,isFillTarget:D,handleFillHandleMouseDown:S,handleCellMouseEnterForFill:k,handleFillMouseUp:b}}function V({coord:l,value:n,isSelected:o,isFillTarget:c,showFillHandle:a,onMouseDown:y,onMouseEnter:i,onChange:w,onFillHandleMouseDown:u,styles:f}){const t=b=>{w(l,b.target.value)},S=b=>{b.target.classList.contains("fill-handle")||y(l)},k=b=>{b.stopPropagation(),b.preventDefault(),u(l)};return g.jsxs("td",{className:T("relative border border-gray-300 p-0",f?.cell,o&&(f?.selected??"bg-blue-100 ring-2 ring-inset ring-blue-500"),c&&(f?.fillTarget??"bg-blue-50")),onMouseDown:S,onMouseEnter:()=>i(l),children:[g.jsx("input",{type:"text",value:n,onChange:t,className:T("w-full h-full px-1 py-1 text-right text-xs bg-transparent outline-none cursor-cell",o&&"bg-transparent")}),a&&g.jsx("div",{className:T("fill-handle absolute -bottom-0.5 -right-0.5 w-2 h-2 cursor-crosshair z-20",f?.fillHandle??"bg-blue-500"),onMouseDown:k})]})}function Z({data:l,onChange:n,rowHeaders:o,colHeaders:c,className:a,rowHeaderTitle:y="",styles:i}){const w=s.useRef(null),u=l.length,f=s.useMemo(()=>c?c.reduce((e,C)=>e+C.headers.length,0):l[0]?.length??0,[c,l]),t=s.useMemo(()=>c?c.flatMap(e=>e.headers):[],[c]),S=s.useCallback(e=>e.row<0||e.row>=u||e.col<0||e.col>=f?"":l[e.row]?.[e.col]??"",[l,u,f]),k=s.useCallback((e,C)=>{const N=l.map((R,j)=>j===e.row?R.map((L,q)=>q===e.col?C:L):R);n(N)},[l,n]),b=s.useCallback(e=>{if(e.length===0)return;const C=l.map(N=>[...N]);e.forEach(({coord:N,value:R})=>{N.row>=0&&N.row<u&&N.col>=0&&N.col<f&&(C[N.row][N.col]=R)}),n(C)},[l,n,u,f]),{selection:D,isSelecting:p,isCellSelected:M,handleCellMouseDown:d,handleCellMouseEnter:h}=$(),{handleKeyDown:v}=A({selection:D,getValue:S,setValues:b,rowCount:u,colCount:f}),{isDraggingFill:F,isFillTarget:r,handleFillHandleMouseDown:G,handleCellMouseEnterForFill:z}=O({selection:D,getValue:S,setValues:b}),K=s.useCallback(e=>{F?z(e):p&&h(e)},[F,p,z,h]),E=s.useCallback((e,C)=>{k(e,C)},[k]),x=s.useCallback(e=>{if(!D.start)return!1;const C=I(D);return!C.start||!C.end?!1:e.row===C.end.row&&e.col===C.end.col},[D]);return g.jsx("div",{ref:w,className:T("outline-none overflow-x-auto",a),tabIndex:0,onKeyDown:v,children:g.jsxs("table",{className:"border-collapse text-xs select-none",children:[g.jsxs("thead",{children:[c&&g.jsxs("tr",{children:[o&&g.jsx("th",{className:T("sticky left-0 z-10 bg-gray-100 border border-gray-300 px-2 py-1.5 text-center font-medium",i?.rowHeader),children:y}),c.map((e,C)=>g.jsx("th",{colSpan:e.headers.length,className:T("bg-blue-100 border border-gray-300 px-1 py-1.5 text-center font-medium text-blue-700",i?.colGroup,e.className),children:e.label},C))]}),c&&g.jsxs("tr",{children:[o&&g.jsx("th",{className:T("sticky left-0 z-10 bg-gray-100 border border-gray-300 px-2 py-1",i?.rowHeader)}),t.map(e=>g.jsx("th",{className:T("bg-gray-50 border border-gray-300 px-1 py-1 text-center font-medium text-[11px]",i?.colHeader,e.className),title:e.description,children:e.label},e.key))]})]}),g.jsx("tbody",{children:l.map((e,C)=>g.jsxs("tr",{children:[o&&o[C]&&g.jsx("td",{className:T("sticky left-0 z-10 bg-gray-100 border border-gray-300 px-1 py-1.5 text-center font-medium",i?.rowHeader,o[C].className),title:o[C].description,children:o[C].label}),e.map((N,R)=>{const j={row:C,col:R},L=M(j),q=r(j),nl=x(j);return g.jsx(V,{coord:j,value:S(j),isSelected:L,isFillTarget:q,showFillHandle:nl&&!F,onMouseDown:d,onMouseEnter:K,onChange:E,onFillHandleMouseDown:G,styles:i},R)})]},C))})]})})}function H(l){const n=typeof l=="string"?parseFloat(l.replace(/,/g,"")):l;return isNaN(n)?"0":new Intl.NumberFormat("ko-KR").format(n)}function ll(l){const n=parseInt(l.replace(/,/g,""),10);return isNaN(n)?0:n}m.ExcelGrid=Z,m.GridCell=V,m.cn=T,m.coordToKey=_,m.formatCurrency=H,m.getCellsInRange=W,m.getFillTargetCells=X,m.isCellInRange=B,m.keyToCoord=Q,m.normalizeRange=I,m.parseCurrency=ll,m.parseTSV=U,m.toTSV=P,m.useGridClipboard=A,m.useGridDragFill=O,m.useGridSelection=$,Object.defineProperty(m,Symbol.toStringTag,{value:"Module"})}));
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cell coordinate
|
|
3
|
+
*/
|
|
4
|
+
export interface CellCoord {
|
|
5
|
+
row: number;
|
|
6
|
+
col: number;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Selection range
|
|
10
|
+
*/
|
|
11
|
+
export interface SelectionRange {
|
|
12
|
+
start: CellCoord | null;
|
|
13
|
+
end: CellCoord | null;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Column header definition
|
|
17
|
+
*/
|
|
18
|
+
export interface ColHeader {
|
|
19
|
+
key: string;
|
|
20
|
+
label: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
/** Custom class name for this header cell */
|
|
23
|
+
className?: string;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Column header group
|
|
27
|
+
*/
|
|
28
|
+
export interface ColHeaderGroup {
|
|
29
|
+
label: string;
|
|
30
|
+
headers: ColHeader[];
|
|
31
|
+
/** Custom class name for this group header */
|
|
32
|
+
className?: string;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Row header group
|
|
36
|
+
*/
|
|
37
|
+
export interface RowHeaderGroup {
|
|
38
|
+
key: string;
|
|
39
|
+
label: string;
|
|
40
|
+
description?: string;
|
|
41
|
+
/** Custom class name for this row header */
|
|
42
|
+
className?: string;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Grid styles configuration
|
|
46
|
+
*/
|
|
47
|
+
export interface GridStyles {
|
|
48
|
+
/** Data cell style */
|
|
49
|
+
cell?: string;
|
|
50
|
+
/** Selected cell style */
|
|
51
|
+
selected?: string;
|
|
52
|
+
/** Fill target cell style (when dragging fill handle) */
|
|
53
|
+
fillTarget?: string;
|
|
54
|
+
/** Fill handle style (bottom-right corner handle) */
|
|
55
|
+
fillHandle?: string;
|
|
56
|
+
/** Column group header style */
|
|
57
|
+
colGroup?: string;
|
|
58
|
+
/** Column header style */
|
|
59
|
+
colHeader?: string;
|
|
60
|
+
/** Row header style */
|
|
61
|
+
rowHeader?: string;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Grid Props
|
|
65
|
+
*/
|
|
66
|
+
export interface ExcelGridProps {
|
|
67
|
+
/** 2D string array data */
|
|
68
|
+
data: string[][];
|
|
69
|
+
/** Data change callback */
|
|
70
|
+
onChange: (data: string[][]) => void;
|
|
71
|
+
/** Row header definitions (overridable per row) */
|
|
72
|
+
rowHeaders?: RowHeaderGroup[];
|
|
73
|
+
/** Column header group definitions */
|
|
74
|
+
colHeaders?: ColHeaderGroup[];
|
|
75
|
+
/** Additional class name for container */
|
|
76
|
+
className?: string;
|
|
77
|
+
/** Row header column title */
|
|
78
|
+
rowHeaderTitle?: string;
|
|
79
|
+
/** Style configuration */
|
|
80
|
+
styles?: GridStyles;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Cell component Props
|
|
84
|
+
*/
|
|
85
|
+
export interface GridCellProps {
|
|
86
|
+
coord: CellCoord;
|
|
87
|
+
value: string;
|
|
88
|
+
isSelected: boolean;
|
|
89
|
+
isFillTarget: boolean;
|
|
90
|
+
showFillHandle: boolean;
|
|
91
|
+
onMouseDown: (coord: CellCoord) => void;
|
|
92
|
+
onMouseEnter: (coord: CellCoord) => void;
|
|
93
|
+
onChange: (coord: CellCoord, value: string) => void;
|
|
94
|
+
onFillHandleMouseDown: (coord: CellCoord) => void;
|
|
95
|
+
/** Cell styles */
|
|
96
|
+
styles?: Pick<GridStyles, "cell" | "selected" | "fillTarget" | "fillHandle">;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,SAAS,GAAG,IAAI,CAAC;IACxB,GAAG,EAAE,SAAS,GAAG,IAAI,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6CAA6C;IAC7C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,SAAS,EAAE,CAAC;IACrB,8CAA8C;IAC9C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,4CAA4C;IAC5C,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,sBAAsB;IACtB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,0BAA0B;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,yDAAyD;IACzD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0BAA0B;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uBAAuB;IACvB,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,2BAA2B;IAC3B,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC;IACjB,2BAA2B;IAC3B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,KAAK,IAAI,CAAC;IACrC,mDAAmD;IACnD,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,sCAAsC;IACtC,UAAU,CAAC,EAAE,cAAc,EAAE,CAAC;IAC9B,0CAA0C;IAC1C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8BAA8B;IAC9B,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,0BAA0B;IAC1B,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,SAAS,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,cAAc,EAAE,OAAO,CAAC;IACxB,WAAW,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IACzC,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACpD,qBAAqB,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAC;IAClD,kBAAkB;IAClB,MAAM,CAAC,EAAE,IAAI,CAAC,UAAU,EAAE,MAAM,GAAG,UAAU,GAAG,YAAY,GAAG,YAAY,CAAC,CAAC;CAC9E"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cn.d.ts","sourceRoot":"","sources":["../../src/utils/cn.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,wBAAgB,EAAE,CAChB,GAAG,OAAO,EAAE,CAAC,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,IAAI,CAAC,EAAE,GAClD,MAAM,CAER"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Format number with thousand separators
|
|
3
|
+
* @param value Number to format
|
|
4
|
+
* @returns Formatted string (e.g., 1000000 -> "1,000,000")
|
|
5
|
+
*/
|
|
6
|
+
export declare function formatCurrency(value: number | string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Parse string with thousand separators to number
|
|
9
|
+
* @param value String to parse
|
|
10
|
+
* @returns Number (e.g., "1,000,000" -> 1000000)
|
|
11
|
+
*/
|
|
12
|
+
export declare function parseCurrency(value: string): number;
|
|
13
|
+
//# sourceMappingURL=format-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-utils.d.ts","sourceRoot":"","sources":["../../src/utils/format-utils.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAK7D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAGnD"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { CellCoord, SelectionRange } from '../types';
|
|
2
|
+
/**
|
|
3
|
+
* Convert coordinate to string key
|
|
4
|
+
*/
|
|
5
|
+
export declare function coordToKey(coord: CellCoord): string;
|
|
6
|
+
/**
|
|
7
|
+
* Convert string key to coordinate
|
|
8
|
+
*/
|
|
9
|
+
export declare function keyToCoord(key: string): CellCoord;
|
|
10
|
+
/**
|
|
11
|
+
* Get all cell coordinates between two coordinates
|
|
12
|
+
*/
|
|
13
|
+
export declare function getCellsInRange(start: CellCoord | null, end: CellCoord | null): CellCoord[];
|
|
14
|
+
/**
|
|
15
|
+
* Check if cell is within selection range
|
|
16
|
+
*/
|
|
17
|
+
export declare function isCellInRange(coord: CellCoord, range: SelectionRange): boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Parse TSV (Tab-Separated Values) string - supports Excel copy
|
|
20
|
+
*/
|
|
21
|
+
export declare function parseTSV(text: string): string[][];
|
|
22
|
+
/**
|
|
23
|
+
* Convert 2D array to TSV string
|
|
24
|
+
*/
|
|
25
|
+
export declare function toTSV(data: string[][]): string;
|
|
26
|
+
/**
|
|
27
|
+
* Normalize selection range (start is always top-left)
|
|
28
|
+
*/
|
|
29
|
+
export declare function normalizeRange(range: SelectionRange): SelectionRange;
|
|
30
|
+
/**
|
|
31
|
+
* Calculate fill target cells (2D area support - excludes source cell)
|
|
32
|
+
*/
|
|
33
|
+
export declare function getFillTargetCells(source: CellCoord, target: CellCoord): CellCoord[];
|
|
34
|
+
//# sourceMappingURL=grid-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"grid-utils.d.ts","sourceRoot":"","sources":["../../src/utils/grid-utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAE1D;;GAEG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,SAAS,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAGjD;AAED;;GAEG;AACH,wBAAgB,eAAe,CAC7B,KAAK,EAAE,SAAS,GAAG,IAAI,EACvB,GAAG,EAAE,SAAS,GAAG,IAAI,GACpB,SAAS,EAAE,CAeb;AAED;;GAEG;AACH,wBAAgB,aAAa,CAC3B,KAAK,EAAE,SAAS,EAChB,KAAK,EAAE,cAAc,GACpB,OAAO,CAeT;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,EAAE,CAKjD;AAED;;GAEG;AACH,wBAAgB,KAAK,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,MAAM,CAE9C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,cAAc,GAAG,cAAc,CAapE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,SAAS,EACjB,MAAM,EAAE,SAAS,GAChB,SAAS,EAAE,CAsBb"}
|
package/package.json
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-excel-lite",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "0.0.4",
|
|
4
|
+
"description": "A lightweight, Excel-like editable grid component for React with cell selection, copy/paste, auto-fill with arithmetic sequence detection, and customizable styling.",
|
|
5
|
+
"license": "MIT",
|
|
5
6
|
"type": "module",
|
|
6
7
|
"main": "./dist/react-excel-lite.umd.cjs",
|
|
7
8
|
"module": "./dist/react-excel-lite.js",
|
|
@@ -22,7 +23,8 @@
|
|
|
22
23
|
},
|
|
23
24
|
"peerDependencies": {
|
|
24
25
|
"react": ">=18.0.0",
|
|
25
|
-
"react-dom": ">=18.0.0"
|
|
26
|
+
"react-dom": ">=18.0.0",
|
|
27
|
+
"tailwindcss": ">=3.0.0"
|
|
26
28
|
},
|
|
27
29
|
"devDependencies": {
|
|
28
30
|
"@vitejs/plugin-react": "^5.1.1",
|