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.
Files changed (3) hide show
  1. package/README.md +303 -0
  2. package/dist/index.js +1470 -0
  3. 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