y11n-spreadsheet 0.1.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 +303 -0
- package/dist/index.js +1470 -0
- package/package.json +49 -0
package/README.md
ADDED
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
# y11n-spreadsheet
|
|
2
|
+
|
|
3
|
+
An accessible spreadsheet web component built with [Lit 3.0](https://lit.dev). Implements the [WAI-ARIA grid pattern](https://www.w3.org/WAI/ARIA/apg/patterns/grid/) with virtual rendering, a formula engine, undo/redo, and clipboard support.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Full keyboard navigation (arrows, Tab, Enter, Escape, Ctrl+A)
|
|
8
|
+
- Copy/cut/paste with TSV clipboard format
|
|
9
|
+
- Undo/redo with Ctrl+Z / Ctrl+Shift+Z
|
|
10
|
+
- Formula engine with 20+ built-in functions and custom function support
|
|
11
|
+
- Arrow key cell reference insertion during formula editing
|
|
12
|
+
- Virtual rendering for large datasets (1000+ rows)
|
|
13
|
+
- Dual-mode formula bar (raw / formatted)
|
|
14
|
+
- Read-only mode
|
|
15
|
+
- CSS custom properties for theming
|
|
16
|
+
- Shadow DOM encapsulation
|
|
17
|
+
- Screen reader support with ARIA live regions
|
|
18
|
+
|
|
19
|
+
## Install
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm install y11n-spreadsheet
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Lit is a peer dependency:
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install lit
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Quick start
|
|
32
|
+
|
|
33
|
+
```html
|
|
34
|
+
<script type="module">
|
|
35
|
+
import 'y11n-spreadsheet';
|
|
36
|
+
</script>
|
|
37
|
+
|
|
38
|
+
<y11n-spreadsheet rows="50" cols="10"></y11n-spreadsheet>
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
## Usage
|
|
42
|
+
|
|
43
|
+
### Basic grid with data
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
import 'y11n-spreadsheet';
|
|
47
|
+
import { cellKey } from 'y11n-spreadsheet';
|
|
48
|
+
|
|
49
|
+
const sheet = document.querySelector('y11n-spreadsheet');
|
|
50
|
+
|
|
51
|
+
const data = new Map();
|
|
52
|
+
data.set(cellKey(0, 0), { rawValue: 'Name', displayValue: 'Name', type: 'text' });
|
|
53
|
+
data.set(cellKey(0, 1), { rawValue: 'Score', displayValue: 'Score', type: 'text' });
|
|
54
|
+
data.set(cellKey(1, 0), { rawValue: 'Alice', displayValue: 'Alice', type: 'text' });
|
|
55
|
+
data.set(cellKey(1, 1), { rawValue: '95', displayValue: '95', type: 'number' });
|
|
56
|
+
data.set(cellKey(2, 1), { rawValue: '=SUM(B1:B2)', displayValue: '95', type: 'number' });
|
|
57
|
+
|
|
58
|
+
sheet.setData(data);
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Properties
|
|
62
|
+
|
|
63
|
+
| Property | Attribute | Type | Default | Description |
|
|
64
|
+
|----------|-----------|------|---------|-------------|
|
|
65
|
+
| `rows` | `rows` | `number` | `100` | Number of rows |
|
|
66
|
+
| `cols` | `cols` | `number` | `26` | Number of columns |
|
|
67
|
+
| `data` | - | `GridData` | `new Map()` | Sparse cell data (`Map<string, CellData>`) |
|
|
68
|
+
| `readOnly` | `read-only` | `boolean` | `false` | Disables editing |
|
|
69
|
+
| `functions` | - | `Record<string, FormulaFunction>` | `{}` | Custom formula functions |
|
|
70
|
+
|
|
71
|
+
### Methods
|
|
72
|
+
|
|
73
|
+
```js
|
|
74
|
+
sheet.getData() // Returns a copy of the grid data
|
|
75
|
+
sheet.setData(data) // Replaces grid data (clears undo/redo)
|
|
76
|
+
sheet.registerFunction('DOUBLE', (ctx, val) => Number(val) * 2)
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Events
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
// Single cell edited
|
|
83
|
+
sheet.addEventListener('cell-change', (e) => {
|
|
84
|
+
console.log(e.detail.cellId, e.detail.value, e.detail.oldValue);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
// Selection moved
|
|
88
|
+
sheet.addEventListener('selection-change', (e) => {
|
|
89
|
+
console.log(e.detail.range); // { start: { row, col }, end: { row, col } }
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// Bulk operation (paste, cut, clear, undo, redo)
|
|
93
|
+
sheet.addEventListener('data-change', (e) => {
|
|
94
|
+
console.log(e.detail.updates, e.detail.source, e.detail.operation);
|
|
95
|
+
});
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### Formula engine
|
|
99
|
+
|
|
100
|
+
Formulas start with `=`. Supported syntax:
|
|
101
|
+
|
|
102
|
+
**Operators**: `+`, `-`, `*`, `/`, `&` (concat), `=`, `<>`, `<`, `>`, `<=`, `>=`
|
|
103
|
+
|
|
104
|
+
**Cell references**: `A1`, `B2:D10` (ranges)
|
|
105
|
+
|
|
106
|
+
**Built-in functions**:
|
|
107
|
+
|
|
108
|
+
| Category | Functions |
|
|
109
|
+
|----------|-----------|
|
|
110
|
+
| Aggregates | `SUM`, `AVERAGE`, `MIN`, `MAX`, `COUNT`, `COUNTA` |
|
|
111
|
+
| Conditional | `IF(condition, trueVal, falseVal)` |
|
|
112
|
+
| Math | `ABS`, `ROUND` |
|
|
113
|
+
| String | `CONCAT`, `UPPER`, `LOWER`, `LEN`, `TRIM` |
|
|
114
|
+
|
|
115
|
+
**Custom functions**:
|
|
116
|
+
|
|
117
|
+
```js
|
|
118
|
+
sheet.registerFunction('TAX', (ctx, amount, rate) => {
|
|
119
|
+
return Number(amount) * Number(rate);
|
|
120
|
+
});
|
|
121
|
+
// Use in cells: =TAX(B1, 0.2)
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The `ctx` argument provides `getCellValue(ref)` and `getRangeValues(start, end)` for reading other cells.
|
|
125
|
+
|
|
126
|
+
### Theming
|
|
127
|
+
|
|
128
|
+
Style the component using CSS custom properties:
|
|
129
|
+
|
|
130
|
+
```css
|
|
131
|
+
y11n-spreadsheet {
|
|
132
|
+
--ls-font-family: 'Inter', system-ui;
|
|
133
|
+
--ls-font-size: 14px;
|
|
134
|
+
--ls-cell-width: 120px;
|
|
135
|
+
--ls-cell-height: 32px;
|
|
136
|
+
--ls-header-bg: #f8f9fa;
|
|
137
|
+
--ls-border-color: #dee2e6;
|
|
138
|
+
--ls-selection-border: 2px solid #0d6efd;
|
|
139
|
+
--ls-selection-bg: rgba(13, 110, 253, 0.08);
|
|
140
|
+
--ls-text-color: #212529;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
<details>
|
|
145
|
+
<summary>All CSS custom properties</summary>
|
|
146
|
+
|
|
147
|
+
| Property | Default | Description |
|
|
148
|
+
|----------|---------|-------------|
|
|
149
|
+
| `--ls-font-family` | `system-ui` | Font family |
|
|
150
|
+
| `--ls-font-size` | `13px` | Base font size |
|
|
151
|
+
| `--ls-text-color` | `#333` | Cell text color |
|
|
152
|
+
| `--ls-cell-width` | `100px` | Column width |
|
|
153
|
+
| `--ls-cell-height` | `28px` | Row height |
|
|
154
|
+
| `--ls-header-bg` | `#f3f3f3` | Header background |
|
|
155
|
+
| `--ls-border-color` | `#e0e0e0` | Cell border color |
|
|
156
|
+
| `--ls-selection-border` | `2px solid #1a73e8` | Selection outline |
|
|
157
|
+
| `--ls-selection-bg` | `rgba(26, 115, 232, 0.1)` | Selection fill |
|
|
158
|
+
| `--ls-focus-ring` | `2px solid #1a73e8` | Focus indicator |
|
|
159
|
+
| `--ls-editor-bg` | `#fff` | Inline editor background |
|
|
160
|
+
| `--ls-editor-shadow` | `0 2px 6px rgba(0,0,0,0.2)` | Editor drop shadow |
|
|
161
|
+
| `--ls-formula-bar-bg` | `#f8fafc` | Formula bar background |
|
|
162
|
+
| `--ls-formula-ref-bg` | `#fff` | Formula bar input background |
|
|
163
|
+
| `--ls-formula-mode-active-bg` | `#dbeafe` | Active mode toggle background |
|
|
164
|
+
| `--ls-ref-highlight-border` | `#1a73e8` | Reference highlight border |
|
|
165
|
+
| `--ls-ref-highlight-bg` | `rgba(26, 115, 232, 0.15)` | Reference highlight fill |
|
|
166
|
+
|
|
167
|
+
</details>
|
|
168
|
+
|
|
169
|
+
The inline editor is exposed as a CSS part:
|
|
170
|
+
|
|
171
|
+
```css
|
|
172
|
+
y11n-spreadsheet::part(editor) {
|
|
173
|
+
font-weight: bold;
|
|
174
|
+
}
|
|
175
|
+
```
|
|
176
|
+
|
|
177
|
+
### Keyboard shortcuts
|
|
178
|
+
|
|
179
|
+
| Key | Action |
|
|
180
|
+
|-----|--------|
|
|
181
|
+
| Arrow keys | Move active cell |
|
|
182
|
+
| Shift + Arrow | Extend selection |
|
|
183
|
+
| Tab / Shift+Tab | Move right / left |
|
|
184
|
+
| Enter | Start editing / commit edit |
|
|
185
|
+
| Escape | Cancel edit / clear selection |
|
|
186
|
+
| Delete, Backspace | Clear selected cells |
|
|
187
|
+
| Ctrl+A | Select all |
|
|
188
|
+
| Ctrl+C / X / V | Copy / Cut / Paste |
|
|
189
|
+
| Ctrl+Z | Undo |
|
|
190
|
+
| Ctrl+Shift+Z | Redo |
|
|
191
|
+
| Any printable character | Start editing with that character |
|
|
192
|
+
|
|
193
|
+
During formula editing, arrow keys insert cell references instead of navigating.
|
|
194
|
+
|
|
195
|
+
## Types
|
|
196
|
+
|
|
197
|
+
All types are exported for TypeScript consumers:
|
|
198
|
+
|
|
199
|
+
```ts
|
|
200
|
+
import type {
|
|
201
|
+
CellData, // { rawValue, displayValue, type, style? }
|
|
202
|
+
CellCoord, // { row, col }
|
|
203
|
+
GridData, // Map<string, CellData>
|
|
204
|
+
SelectionRange, // { start: CellCoord, end: CellCoord }
|
|
205
|
+
FormulaContext, // { getCellValue, getRangeValues }
|
|
206
|
+
FormulaFunction, // (ctx: FormulaContext, ...args: unknown[]) => unknown
|
|
207
|
+
CellChangeDetail,
|
|
208
|
+
SelectionChangeDetail,
|
|
209
|
+
DataChangeDetail,
|
|
210
|
+
} from 'y11n-spreadsheet';
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Utility functions for coordinate conversion:
|
|
214
|
+
|
|
215
|
+
```ts
|
|
216
|
+
import { cellKey, parseKey, colToLetter, letterToCol, refToCoord, coordToRef } from 'y11n-spreadsheet';
|
|
217
|
+
|
|
218
|
+
cellKey(0, 0) // "0:0"
|
|
219
|
+
parseKey("0:0") // { row: 0, col: 0 }
|
|
220
|
+
colToLetter(0) // "A"
|
|
221
|
+
letterToCol("AA") // 26
|
|
222
|
+
refToCoord("B3") // { row: 2, col: 1 }
|
|
223
|
+
coordToRef({row:0, col:0}) // "A1"
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Exports
|
|
227
|
+
|
|
228
|
+
The package also exports internal modules if you need them standalone:
|
|
229
|
+
|
|
230
|
+
```ts
|
|
231
|
+
import { FormulaEngine } from 'y11n-spreadsheet';
|
|
232
|
+
import { SelectionManager } from 'y11n-spreadsheet';
|
|
233
|
+
import { ClipboardManager } from 'y11n-spreadsheet';
|
|
234
|
+
import { Y11nFormulaBar } from 'y11n-spreadsheet';
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## Contributing
|
|
240
|
+
|
|
241
|
+
### Prerequisites
|
|
242
|
+
|
|
243
|
+
- Node.js 22+
|
|
244
|
+
- npm
|
|
245
|
+
|
|
246
|
+
### Setup
|
|
247
|
+
|
|
248
|
+
```bash
|
|
249
|
+
git clone <repo-url>
|
|
250
|
+
cd accessible-spreadsheet-component
|
|
251
|
+
npm install
|
|
252
|
+
npx playwright install # for E2E tests
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### Development
|
|
256
|
+
|
|
257
|
+
```bash
|
|
258
|
+
npm run dev # Vite dev server at http://localhost:5173
|
|
259
|
+
npm run storybook # Storybook at http://localhost:6006
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
The `index.html` at the project root has a test harness. Storybook has detailed interactive examples covering all features.
|
|
263
|
+
|
|
264
|
+
### Testing
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
npm test # Unit tests (Vitest)
|
|
268
|
+
npm run test:watch # Unit tests in watch mode
|
|
269
|
+
npm run test:e2e # E2E tests headless (Playwright)
|
|
270
|
+
npm run test:e2e:headed # E2E tests in visible browser
|
|
271
|
+
npm run test:e2e:ui # E2E tests with Playwright UI
|
|
272
|
+
npm run typecheck # TypeScript type checking
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Project structure
|
|
276
|
+
|
|
277
|
+
```
|
|
278
|
+
src/
|
|
279
|
+
index.ts # Barrel exports
|
|
280
|
+
types.ts # Types & coordinate utilities
|
|
281
|
+
y11n-spreadsheet.ts # Main component
|
|
282
|
+
components/y11n-formula-bar.ts # Formula bar sub-component
|
|
283
|
+
controllers/
|
|
284
|
+
selection-manager.ts # Selection state (Lit ReactiveController)
|
|
285
|
+
clipboard-manager.ts # Clipboard operations (TSV format)
|
|
286
|
+
engine/
|
|
287
|
+
formula-engine.ts # Recursive descent formula parser
|
|
288
|
+
__tests__/ # Unit tests colocated with source
|
|
289
|
+
e2e/ # Playwright E2E tests
|
|
290
|
+
stories/ # Storybook stories
|
|
291
|
+
```
|
|
292
|
+
|
|
293
|
+
### Build
|
|
294
|
+
|
|
295
|
+
```bash
|
|
296
|
+
npm run build # Outputs ES module to dist/
|
|
297
|
+
```
|
|
298
|
+
|
|
299
|
+
The build externalizes `lit` as a peer dependency and produces `dist/index.js` with TypeScript declarations and source maps.
|
|
300
|
+
|
|
301
|
+
## License
|
|
302
|
+
|
|
303
|
+
MIT
|