@mikestools/usetable 0.0.1 → 0.0.2

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
@@ -1,519 +1,586 @@
1
- # @mikestools/usetable
2
-
3
- The most comprehensive Vue 3 table composable with 20+ advanced features. Pure DOM wrapper with reactive data layer for complete table manipulation.
4
-
5
- ## Features
6
-
7
- - đŸŽ¯ **Composable-First** - Pure Vue 3 Composition API, no components
8
- - đŸ“Ļ **TypeScript First** - Full type safety with IntelliSense
9
- - 🔗 **DOM-First Architecture** - HTML table is source of truth
10
- - ✨ **20+ Advanced Features** - All-in-one solution
11
-
12
- > **Note:** Data is read from DOM `textContent`, so values are strings. Use `Number()` when working with numeric data.
13
-
14
- ### Complete Feature Set
15
-
16
- | Feature | Description |
17
- |---------------------------|-------------------------------------------|
18
- | 🔀 **Sorting** | Column sorting with state tracking |
19
- | 🔍 **Filtering** | Row filtering with predicates |
20
- | â†Šī¸ **Undo/Redo** | Full history tracking with rollback |
21
- | đŸŽ¯ **Cell Focus** | Keyboard navigation between cells |
22
- | đŸ‘ī¸ **Column Visibility** | Show/hide columns dynamically |
23
- | â†•ī¸ **Reordering** | Move rows and columns programmatically |
24
- | 📋 **Clipboard** | Copy/paste with Excel-compatible format |
25
- | 📌 **Row State** | Expand/collapse and pin rows |
26
- | đŸˇī¸ **Metadata** | Custom data on cells, rows, columns |
27
- | â˜‘ī¸ **Selection** | Row and cell selection with range support |
28
- | 🔔 **Events** | Granular change callbacks |
29
- | ⚡ **Batch Updates** | Efficient bulk operations |
30
- | âŗ **Async Data** | Loading states and async fetching |
31
- | 🧊 **Frozen Columns** | Pin columns to left/right |
32
- | 🔄 **Transactions** | Batch operations with automatic rollback |
33
- | ✅ **Validation** | Cell, row, column validation |
34
- | 📊 **Aggregation** | Sum, average, min, max, count |
35
- | 📄 **Pagination** | Client-side pagination |
36
- | đŸ“Ĩ **Import/Export** | CSV and JSON format support |
37
- | 🧩 **HTML Elements** | Rich cell content support |
38
-
39
- ## Installation
40
-
41
- ```bash
42
- npm install @mikestools/usetable vue
43
- ```
44
-
45
- ## Quick Start
46
-
47
- ```typescript
48
- import { ref, onMounted } from 'vue'
49
- import { useTable } from '@mikestools/usetable'
50
-
51
- const tableRef = ref<HTMLTableElement>()
52
-
53
- onMounted(() => {
54
- const element = tableRef.value
55
- if (!element) return
56
-
57
- const table = useTable(ref(element))
58
-
59
- // Set up table structure
60
- table.setHeaders(['Name', 'Department', 'Salary'])
61
- table.setData([
62
- ['Alice Johnson', 'Engineering', 85000],
63
- ['Bob Smith', 'Marketing', 72000],
64
- ['Carol Williams', 'Sales', 68000]
65
- ])
66
-
67
- // Add a row
68
- table.addRow(['David Brown', 'Engineering', 92000])
69
-
70
- // Update a cell
71
- table.setCell(0, 2, 90000)
72
-
73
- // Use aggregation
74
- const totalSalary = table.sum(2)
75
- console.log('Total:', totalSalary)
76
-
77
- // Enable inline editing
78
- const cleanup = table.enableEditing()
79
- })
80
- ```
81
-
82
- ```vue
83
- <template>
84
- <table ref="tableRef" class="table"></table>
85
- </template>
86
- ```
87
-
88
- ## API Reference
89
-
90
- ### Core Properties
91
-
92
- | Property | Type | Description |
93
- |----------------------|-----------------------------------|-----------------------------------|
94
- | `element` | `Readonly<Ref<HTMLTableElement>>` | The underlying table element |
95
- | `data` | `Ref<unknown[][]>` | Reactive 2D array of body data |
96
- | `headers` | `Ref<string[]>` | Reactive array of headers |
97
- | `rowCount` | `Readonly<Ref<number>>` | Number of data rows |
98
- | `columnCount` | `Readonly<Ref<number>>` | Number of columns |
99
- | `selectedRows` | `Ref<Set<number>>` | Selected row indices |
100
- | `selectedCells` | `Ref<Set<string>>` | Selected cell keys |
101
- | `sortState` | `SortState` | Current sort column and direction |
102
- | `filterState` | `FilterState` | Current filter state |
103
- | `focusedCell` | `Ref<{row, column} \| null>` | Currently focused cell |
104
- | `visibleColumnCount` | `Readonly<Ref<number>>` | Count of visible columns |
105
- | `dirtyState` | `Ref<boolean>` | Whether table has unsaved changes |
106
- | `expandedRows` | `Ref<Set<number>>` | Expanded row indices |
107
- | `pinnedTopRows` | `Ref<Set<number>>` | Rows pinned to top |
108
- | `pinnedBottomRows` | `Ref<Set<number>>` | Rows pinned to bottom |
109
- | `tableLoading` | `Ref<boolean>` | Loading state |
110
-
111
- ### Data Methods
112
-
113
- #### Setup
114
- ```typescript
115
- table.setHeaders(['Name', 'Age', 'Email'])
116
- table.setData([['Alice', 30, 'alice@email.com'], ...])
117
- table.setFooter(['Total', '', count])
118
- table.setCaption('User List')
119
- ```
120
-
121
- #### Row Operations
122
- ```typescript
123
- table.addRow(['value1', 'value2', ...], index?)
124
- table.addRowWithAttributes(['value1', ...], { class: 'highlight' })
125
- table.removeRow(index) // -1 for last row
126
- table.updateRow(index, ['newValue1', ...])
127
- table.getRowData(index) // Returns copy
128
- table.setRowData(index, ['value1', ...])
129
- ```
130
-
131
- #### Cell Operations
132
- ```typescript
133
- table.getCell(rowIndex, columnIndex)
134
- table.setCell(rowIndex, columnIndex, value)
135
- table.setCellWithAttributes(rowIndex, columnIndex, value, { class: 'active' })
136
- table.updateCell(rowIndex, columnIndex, { value, attributes })
137
- table.getCellRange(rowStart, rowEnd, columnStart, columnEnd)
138
- table.setCellRange(rowStart, columnStart, [[data]])
139
- ```
140
-
141
- #### Column Operations
142
- ```typescript
143
- table.addColumn('Header', ['data1', 'data2', ...], index?)
144
- table.removeColumn(index)
145
- table.getColumnData(index)
146
- table.setColumnData(index, ['value1', 'value2', ...])
147
- ```
148
-
149
- ### Advanced Features
150
-
151
- #### Transactions
152
- ```typescript
153
- // Batch operations with automatic rollback on error
154
- table.transaction(() => {
155
- table.addRow(['New', 'Row', 'Data'])
156
- table.setCell(0, 0, 'Updated')
157
- // If any operation fails, all changes are reverted
158
- })
159
-
160
- // Async transactions
161
- await table.transaction(async () => {
162
- const data = await fetchData()
163
- table.setData(data)
164
- })
165
- ```
166
-
167
- #### Validation
168
- ```typescript
169
- const result = table.validateAll((value, rowIndex, columnIndex) => {
170
- if (columnIndex === 0 && !value) return 'Name required'
171
- if (columnIndex === 2 && isNaN(Number(value))) return 'Must be number'
172
- return null // Valid
173
- })
174
-
175
- if (!result.valid) {
176
- result.errors.forEach(error => {
177
- console.log(`Row ${error.row}, Column ${error.column}: ${error.message}`)
178
- })
179
- }
180
- ```
181
-
182
- #### Aggregation
183
- ```typescript
184
- const total = table.sum(colIndex) // Returns number (auto-converts)
185
- const avg = table.average(colIndex) // Returns number
186
- const min = table.min(colIndex) // Returns string from DOM
187
- const max = table.max(colIndex) // Returns string from DOM
188
- const count = table.count(colIndex, predicate?)
189
- const custom = table.aggregate(colIndex, { initial, reducer })
190
-
191
- // Convert min/max when needed
192
- const maxSalary = Number(table.max(2))
193
- ```
194
-
195
- #### Transformation
196
- ```typescript
197
- table.transformColumn(columnIndex, (value, rowIndex) => {
198
- return Number(value) * 1.1 // 10% increase
199
- })
200
-
201
- table.transformRow(rowIndex, (value, columnIndex) => {
202
- return String(value).toUpperCase()
203
- })
204
-
205
- table.transformCells((value, rowIndex, columnIndex) => {
206
- return columnIndex === 2 ? Number(value).toFixed(2) : value
207
- })
208
- ```
209
-
210
- #### Computed Columns
211
- ```typescript
212
- table.addComputedColumn({
213
- label: 'Total',
214
- computeFunction: (row) => Number(row[1]) * Number(row[2]),
215
- index: 3 // Optional, defaults to end
216
- })
217
-
218
- table.removeComputedColumn(3)
219
- ```
220
-
221
- #### Grouping
222
- ```typescript
223
- const grouped = table.groupBy(row => row[1]) // Group by column 1
224
- // Returns: Map<string, number[]> - key to row indices
225
- ```
226
-
227
- #### Pagination
228
- ```typescript
229
- table.paginate({ pageSize: 10, currentPage: 1 })
230
-
231
- // Navigation
232
- table.nextPage()
233
- table.previousPage()
234
- table.goToPage(5)
235
- ```
236
-
237
- #### Virtual Scrolling
238
- ```typescript
239
- table.enableVirtualScrolling({
240
- rowHeight: 40,
241
- containerHeight: 400
242
- })
243
-
244
- table.disableVirtualScrolling()
245
- ```
246
-
247
- #### Import/Export
248
- ```typescript
249
- // Export
250
- const csv = table.exportToCSV()
251
- const json = table.exportToJSON()
252
-
253
- // Import
254
- table.importFromCSV(csvString)
255
- table.importFromJSON(jsonString)
256
- table.importFromArray([['row1col1', ...], ['row2col1', ...]])
257
- ```
258
-
259
- #### Search
260
- ```typescript
261
- const results = table.search('query', { caseSensitive: false })
262
- // Returns: [{ row, column, value }, ...]
263
-
264
- const columnResults = table.searchColumn(0, 'query')
265
- ```
266
-
267
- #### Selection
268
- ```typescript
269
- table.selectRow(rowIndex)
270
- table.deselectRow(rowIndex)
271
- table.toggleRowSelection(rowIndex)
272
- table.selectCell(rowIndex, columnIndex)
273
- table.clearSelection()
274
-
275
- // Check state
276
- table.isRowSelected(rowIndex)
277
- table.selectedRows.value // Set<number>
278
- table.selectedCells.value // Set<string>
279
- ```
280
-
281
- #### Inline Editing
282
- ```typescript
283
- const cleanup = table.enableEditing()
284
- // Double-click to edit, Enter to save, Escape to cancel
285
-
286
- // Disable when done
287
- cleanup()
288
- ```
289
-
290
- #### DOM Sync
291
- ```typescript
292
- // Sync pre-existing HTML table to data layer
293
- table.sync()
294
-
295
- // Now table.headers and table.data contain DOM content
296
- ```
297
-
298
- #### Data Change Subscription
299
- ```typescript
300
- const unsubscribe = table.onDataChange((newData) => {
301
- console.log('Data changed:', newData)
302
- // Save to server, localStorage, etc.
303
- })
304
-
305
- // Stop watching
306
- unsubscribe()
307
- ```
308
-
309
- ### Types
310
-
311
- ```typescript
312
- // Cell configuration
313
- interface CellConfig {
314
- value: unknown
315
- attributes?: ElementAttributes
316
- columnSpan?: number
317
- rowSpan?: number
318
- }
319
-
320
- // Element attributes
321
- interface ElementAttributes {
322
- class?: string | string[] | Record<string, boolean>
323
- style?: string | Record<string, string | number>
324
- id?: string
325
- title?: string
326
- // ... all HTML attributes, ARIA, data-*, events
327
- }
328
-
329
- // Computed column configuration
330
- interface ComputedColumnConfig {
331
- computeFunction: (row: unknown[]) => unknown
332
- label: string
333
- index?: number
334
- }
335
-
336
- // Validation
337
- interface ValidationResult {
338
- valid: boolean
339
- errors: ValidationError[]
340
- }
341
-
342
- interface ValidationError {
343
- row: number
344
- column: number
345
- message: string
346
- }
347
-
348
- // Search
349
- interface SearchResult {
350
- row: number
351
- column: number
352
- value: unknown
353
- }
354
-
355
- // Sort state
356
- interface SortState {
357
- columnIndex: Readonly<Ref<number | null>>
358
- ascending: Readonly<Ref<boolean>>
359
- descending: Readonly<Ref<boolean>>
360
- }
361
-
362
- // Filter state
363
- interface FilterState {
364
- isFiltered: Readonly<Ref<boolean>>
365
- filteredRowCount: Readonly<Ref<number>>
366
- filteredIndices: Readonly<Ref<number[]>>
367
- }
368
- ```
369
-
370
- ### Sorting API
371
-
372
- ```typescript
373
- table.sortColumnAscending(columnIndex)
374
- table.sortColumnDescending(columnIndex)
375
- table.sortColumnAscendingWith(columnIndex, comparator)
376
- table.sortColumnDescendingWith(columnIndex, comparator)
377
- table.clearColumnSort()
378
-
379
- // Check state
380
- table.isSorted()
381
- table.isSortedAscending()
382
- table.isSortedDescending()
383
- table.getSortedColumnIndex()
384
-
385
- // Reactive state
386
- table.sortState.columnIndex.value
387
- table.sortState.ascending.value
388
- ```
389
-
390
- ### Filtering API
391
-
392
- ```typescript
393
- table.filterRows(predicate)
394
- table.filterColumn(columnIndex, predicate)
395
- table.filterColumnByValue(columnIndex, value)
396
- table.filterColumnByValues(columnIndex, values)
397
- table.clearFilters()
398
-
399
- // Check state
400
- table.getFilteredRowIndices()
401
- table.filterState.isFiltered.value
402
- ```
403
-
404
- ### Undo/Redo API
405
-
406
- ```typescript
407
- table.undo()
408
- table.redo()
409
- table.canUndo()
410
- table.canRedo()
411
- table.clearHistory()
412
- table.setHistoryLimit(100)
413
- ```
414
-
415
- ### Cell Focus API
416
-
417
- ```typescript
418
- table.focusCell(rowIndex, columnIndex)
419
- table.clearCellFocus()
420
- table.getFocusedCell()
421
- table.moveFocusUp()
422
- table.moveFocusDown()
423
- table.moveFocusLeft()
424
- table.moveFocusRight()
425
- table.enableKeyboardNavigation()
426
- ```
427
-
428
- ### Column Visibility API
429
-
430
- ```typescript
431
- table.hideColumn(columnIndex)
432
- table.showColumn(columnIndex)
433
- table.toggleColumnVisibility(columnIndex)
434
- table.isColumnVisible(columnIndex)
435
- table.getVisibleColumnIndices()
436
- table.getHiddenColumnIndices()
437
- ```
438
-
439
- ### Reordering API
440
-
441
- ```typescript
442
- table.moveRow(fromIndex, toIndex)
443
- table.moveRowUp(index)
444
- table.moveRowDown(index)
445
- table.moveRowToTop(index)
446
- table.moveRowToBottom(index)
447
- table.swapRows(index1, index2)
448
- table.moveColumn(fromIndex, toIndex)
449
- table.swapColumns(index1, index2)
450
- ```
451
-
452
- ### Clipboard API
453
-
454
- ```typescript
455
- table.copyCell(rowIndex, columnIndex)
456
- table.copyRow(rowIndex)
457
- table.copyColumn(columnIndex)
458
- table.copyCellRange(startRow, startCol, endRow, endCol)
459
- table.copySelectedCells()
460
- table.copySelectedRows()
461
- table.pasteAtCell(rowIndex, columnIndex, data)
462
- ```
463
-
464
- ### Row State API
465
-
466
- ```typescript
467
- table.expandRow(index)
468
- table.collapseRow(index)
469
- table.toggleRowExpansion(index)
470
- table.pinRowTop(index)
471
- table.pinRowBottom(index)
472
- table.unpinRow(index)
473
- table.unpinAllRows()
474
- ```
475
-
476
- ### Metadata API
477
-
478
- ```typescript
479
- table.setCellMeta(row, col, key, value)
480
- table.getCellMeta(row, col, key)
481
- table.setRowMeta(index, key, value)
482
- table.getRowMeta(index, key)
483
- table.setColumnMeta(index, key, value)
484
- table.getColumnMeta(index, key)
485
- ```
486
-
487
- ## Examples
488
-
489
- The showcase includes 21 interactive examples:
490
-
491
- 1. **Basic Setup** - Headers, data, caption, row manipulation
492
- 2. **Inline Editing** - Double-click to edit with data sync
493
- 3. **Sorting** - Column sorting with state tracking
494
- 4. **Search & Filter** - Search and filter with predicates
495
- 5. **Selection** - Row/cell selection with range support
496
- 6. **Cell Navigation** - Keyboard navigation between cells
497
- 7. **Column Visibility** - Show/hide columns
498
- 8. **Reordering** - Move rows and columns
499
- 9. **Undo/Redo** - History tracking with rollback
500
- 10. **Clipboard** - Copy/paste operations
501
- 11. **Row State** - Expand/collapse and pin rows
502
- 12. **Aggregation** - Sum, average, computed columns
503
- 13. **Validation** - Per-cell validation rules
504
- 14. **Pagination** - Page through large datasets
505
- 15. **Import/Export** - CSV and JSON support
506
- 16. **Styling** - Dynamic classes and attributes
507
- 17. **Transactions** - Batch operations with rollback
508
- 18. **Grouping** - Group rows by values
509
- 19. **Footer & Totals** - Summary rows
510
- 20. **HTML Elements** - Rich content in cells
511
- 21. **Pre-existing Sync** - Connect to existing tables
512
-
513
- ## Browser Support
514
-
515
- Works in all modern browsers that support ES2020+.
516
-
517
- ## License
518
-
519
- MIT Š Mike Garcia
1
+ # @mikestools/usetable
2
+
3
+ The most comprehensive Vue 3 table composable with 20+ advanced features. Pure DOM wrapper with reactive data layer for complete table manipulation.
4
+
5
+ ## Features
6
+
7
+ - đŸŽ¯ **Composable-First** - Pure Vue 3 Composition API, no components
8
+ - đŸ“Ļ **TypeScript First** - Full type safety with IntelliSense
9
+ - 🔗 **DOM-First Architecture** - HTML table is source of truth
10
+ - ✨ **20+ Advanced Features** - All-in-one solution
11
+
12
+ > **Note:** Data is read from DOM `textContent`, so values are strings. Use `Number()` when working with numeric data.
13
+
14
+ ### Complete Feature Set
15
+
16
+ | Feature | Description |
17
+ |---------------------------|-------------------------------------------|
18
+ | đŸ—„ī¸ **Record-Based Data** | Work with typed records by ID |
19
+ | 🔀 **Sorting** | Column sorting with state tracking |
20
+ | 🔍 **Filtering** | Row filtering with predicates |
21
+ | â†Šī¸ **Undo/Redo** | Full history tracking with rollback |
22
+ | đŸŽ¯ **Cell Focus** | Keyboard navigation between cells |
23
+ | đŸ‘ī¸ **Column Visibility** | Show/hide columns dynamically |
24
+ | â†•ī¸ **Reordering** | Move rows and columns programmatically |
25
+ | 📋 **Clipboard** | Copy/paste with Excel-compatible format |
26
+ | 📌 **Row State** | Expand/collapse and pin rows |
27
+ | đŸˇī¸ **Metadata** | Custom data on cells, rows, columns |
28
+ | â˜‘ī¸ **Selection** | Row and cell selection with range support |
29
+ | 🔔 **Events** | Granular change callbacks |
30
+ | ⚡ **Batch Updates** | Efficient bulk operations |
31
+ | âŗ **Async Data** | Loading states and async fetching |
32
+ | 🧊 **Frozen Columns** | Pin columns to left/right |
33
+ | 🔄 **Transactions** | Batch operations with automatic rollback |
34
+ | ✅ **Validation** | Cell, row, column validation |
35
+ | 📊 **Aggregation** | Sum, average, min, max, count |
36
+ | 📄 **Pagination** | Client-side pagination |
37
+ | đŸ“Ĩ **Import/Export** | CSV and JSON format support |
38
+ | 🧩 **HTML Elements** | Rich cell content support |
39
+
40
+ ## Installation
41
+
42
+ ```bash
43
+ npm install @mikestools/usetable vue
44
+ ```
45
+
46
+ ## Quick Start
47
+
48
+ ```typescript
49
+ import { ref, onMounted } from 'vue'
50
+ import { useTable } from '@mikestools/usetable'
51
+
52
+ const tableRef = ref<HTMLTableElement>()
53
+
54
+ onMounted(() => {
55
+ const element = tableRef.value
56
+ if (!element) return
57
+
58
+ const table = useTable(ref(element))
59
+
60
+ // Set up table structure
61
+ table.setHeaders(['Name', 'Department', 'Salary'])
62
+ table.setData([
63
+ ['Alice Johnson', 'Engineering', 85000],
64
+ ['Bob Smith', 'Marketing', 72000],
65
+ ['Carol Williams', 'Sales', 68000]
66
+ ])
67
+
68
+ // Add a row
69
+ table.addRow(['David Brown', 'Engineering', 92000])
70
+
71
+ // Update a cell
72
+ table.setCell(0, 2, 90000)
73
+
74
+ // Use aggregation
75
+ const totalSalary = table.sum(2)
76
+ console.log('Total:', totalSalary)
77
+
78
+ // Enable inline editing
79
+ const cleanup = table.enableEditing()
80
+ })
81
+ ```
82
+
83
+ ```vue
84
+ <template>
85
+ <table ref="tableRef" class="table"></table>
86
+ </template>
87
+ ```
88
+
89
+ ## API Reference
90
+
91
+ ### Core Properties
92
+
93
+ | Property | Type | Description |
94
+ |----------------------|-----------------------------------|-----------------------------------|
95
+ | `element` | `Readonly<Ref<HTMLTableElement>>` | The underlying table element |
96
+ | `data` | `Ref<unknown[][]>` | Reactive 2D array of body data |
97
+ | `headers` | `Ref<string[]>` | Reactive array of headers |
98
+ | `rowCount` | `Readonly<Ref<number>>` | Number of data rows |
99
+ | `columnCount` | `Readonly<Ref<number>>` | Number of columns |
100
+ | `selectedRows` | `Ref<Set<number>>` | Selected row indices |
101
+ | `selectedCells` | `Ref<Set<string>>` | Selected cell keys |
102
+ | `sortState` | `SortState` | Current sort column and direction |
103
+ | `filterState` | `FilterState` | Current filter state |
104
+ | `focusedCell` | `Ref<{row, column} \| null>` | Currently focused cell |
105
+ | `visibleColumnCount` | `Readonly<Ref<number>>` | Count of visible columns |
106
+ | `dirtyState` | `Ref<boolean>` | Whether table has unsaved changes |
107
+ | `expandedRows` | `Ref<Set<number>>` | Expanded row indices |
108
+ | `pinnedTopRows` | `Ref<Set<number>>` | Rows pinned to top |
109
+ | `pinnedBottomRows` | `Ref<Set<number>>` | Rows pinned to bottom |
110
+ | `tableLoading` | `Ref<boolean>` | Loading state |
111
+
112
+ ### Data Methods
113
+
114
+ #### Setup
115
+ ```typescript
116
+ table.setHeaders(['Name', 'Age', 'Email'])
117
+ table.setData([['Alice', 30, 'alice@email.com'], ...])
118
+ table.setFooter(['Total', '', count])
119
+ table.setCaption('User List')
120
+ ```
121
+
122
+ #### Row Operations
123
+ ```typescript
124
+ table.addRow(['value1', 'value2', ...], index?)
125
+ table.addRowWithAttributes(['value1', ...], { class: 'highlight' })
126
+ table.removeRow(index) // -1 for last row
127
+ table.updateRow(index, ['newValue1', ...])
128
+ table.getRowData(index) // Returns copy
129
+ table.setRowData(index, ['value1', ...])
130
+ ```
131
+
132
+ #### Cell Operations
133
+ ```typescript
134
+ table.getCell(rowIndex, columnIndex)
135
+ table.setCell(rowIndex, columnIndex, value)
136
+ table.setCellWithAttributes(rowIndex, columnIndex, value, { class: 'active' })
137
+ table.updateCell(rowIndex, columnIndex, { value, attributes })
138
+ table.getCellRange(rowStart, rowEnd, columnStart, columnEnd)
139
+ table.setCellRange(rowStart, columnStart, [[data]])
140
+ ```
141
+
142
+ #### Column Operations
143
+ ```typescript
144
+ table.addColumn('Header', ['data1', 'data2', ...], index?)
145
+ table.removeColumn(index)
146
+ table.getColumnData(index)
147
+ table.setColumnData(index, ['value1', 'value2', ...])
148
+ ```
149
+
150
+ ### Advanced Features
151
+
152
+ #### Transactions
153
+ ```typescript
154
+ // Batch operations with automatic rollback on error
155
+ table.transaction(() => {
156
+ table.addRow(['New', 'Row', 'Data'])
157
+ table.setCell(0, 0, 'Updated')
158
+ // If any operation fails, all changes are reverted
159
+ })
160
+
161
+ // Async transactions
162
+ await table.transaction(async () => {
163
+ const data = await fetchData()
164
+ table.setData(data)
165
+ })
166
+ ```
167
+
168
+ #### Validation
169
+ ```typescript
170
+ const result = table.validateAll((value, rowIndex, columnIndex) => {
171
+ if (columnIndex === 0 && !value) return 'Name required'
172
+ if (columnIndex === 2 && isNaN(Number(value))) return 'Must be number'
173
+ return null // Valid
174
+ })
175
+
176
+ if (!result.valid) {
177
+ result.errors.forEach(error => {
178
+ console.log(`Row ${error.row}, Column ${error.column}: ${error.message}`)
179
+ })
180
+ }
181
+ ```
182
+
183
+ #### Aggregation
184
+ ```typescript
185
+ const total = table.sum(colIndex) // Returns number (auto-converts)
186
+ const avg = table.average(colIndex) // Returns number
187
+ const min = table.min(colIndex) // Returns string from DOM
188
+ const max = table.max(colIndex) // Returns string from DOM
189
+ const count = table.count(colIndex, predicate?)
190
+ const custom = table.aggregate(colIndex, { initial, reducer })
191
+
192
+ // Convert min/max when needed
193
+ const maxSalary = Number(table.max(2))
194
+ ```
195
+
196
+ #### Transformation
197
+ ```typescript
198
+ table.transformColumn(columnIndex, (value, rowIndex) => {
199
+ return Number(value) * 1.1 // 10% increase
200
+ })
201
+
202
+ table.transformRow(rowIndex, (value, columnIndex) => {
203
+ return String(value).toUpperCase()
204
+ })
205
+
206
+ table.transformCells((value, rowIndex, columnIndex) => {
207
+ return columnIndex === 2 ? Number(value).toFixed(2) : value
208
+ })
209
+ ```
210
+
211
+ #### Computed Columns
212
+ ```typescript
213
+ table.addComputedColumn({
214
+ label: 'Total',
215
+ computeFunction: (row) => Number(row[1]) * Number(row[2]),
216
+ index: 3 // Optional, defaults to end
217
+ })
218
+
219
+ table.removeComputedColumn(3)
220
+ ```
221
+
222
+ #### Grouping
223
+ ```typescript
224
+ const grouped = table.groupBy(row => row[1]) // Group by column 1
225
+ // Returns: Map<string, number[]> - key to row indices
226
+ ```
227
+
228
+ #### Pagination
229
+ ```typescript
230
+ table.paginate({ pageSize: 10, currentPage: 1 })
231
+
232
+ // Navigation
233
+ table.nextPage()
234
+ table.previousPage()
235
+ table.goToPage(5)
236
+ ```
237
+
238
+ #### Virtual Scrolling
239
+ ```typescript
240
+ table.enableVirtualScrolling({
241
+ rowHeight: 40,
242
+ containerHeight: 400
243
+ })
244
+
245
+ table.disableVirtualScrolling()
246
+ ```
247
+
248
+ #### Import/Export
249
+ ```typescript
250
+ // Export
251
+ const csv = table.exportToCSV()
252
+ const json = table.exportToJSON()
253
+
254
+ // Import
255
+ table.importFromCSV(csvString)
256
+ table.importFromJSON(jsonString)
257
+ table.importFromArray([['row1col1', ...], ['row2col1', ...]])
258
+ ```
259
+
260
+ #### Search
261
+ ```typescript
262
+ const results = table.search('query', { caseSensitive: false })
263
+ // Returns: [{ row, column, value }, ...]
264
+
265
+ const columnResults = table.searchColumn(0, 'query')
266
+ ```
267
+
268
+ #### Selection
269
+ ```typescript
270
+ table.selectRow(rowIndex)
271
+ table.deselectRow(rowIndex)
272
+ table.toggleRowSelection(rowIndex)
273
+ table.selectCell(rowIndex, columnIndex)
274
+ table.clearSelection()
275
+
276
+ // Check state
277
+ table.isRowSelected(rowIndex)
278
+ table.selectedRows.value // Set<number>
279
+ table.selectedCells.value // Set<string>
280
+ ```
281
+
282
+ #### Inline Editing
283
+ ```typescript
284
+ const cleanup = table.enableEditing()
285
+ // Double-click to edit, Enter to save, Escape to cancel
286
+
287
+ // Disable when done
288
+ cleanup()
289
+ ```
290
+
291
+ #### DOM Sync
292
+ ```typescript
293
+ // Sync pre-existing HTML table to data layer
294
+ table.sync()
295
+
296
+ // Now table.headers and table.data contain DOM content
297
+ ```
298
+
299
+ #### Data Change Subscription
300
+ ```typescript
301
+ const unsubscribe = table.onDataChange((newData) => {
302
+ console.log('Data changed:', newData)
303
+ // Save to server, localStorage, etc.
304
+ })
305
+
306
+ // Stop watching
307
+ unsubscribe()
308
+ ```
309
+
310
+ ### Types
311
+
312
+ ```typescript
313
+ // Cell configuration
314
+ interface CellConfig {
315
+ value: unknown
316
+ attributes?: ElementAttributes
317
+ columnSpan?: number
318
+ rowSpan?: number
319
+ }
320
+
321
+ // Element attributes
322
+ interface ElementAttributes {
323
+ class?: string | string[] | Record<string, boolean>
324
+ style?: string | Record<string, string | number>
325
+ id?: string
326
+ title?: string
327
+ // ... all HTML attributes, ARIA, data-*, events
328
+ }
329
+
330
+ // Computed column configuration
331
+ interface ComputedColumnConfig {
332
+ computeFunction: (row: unknown[]) => unknown
333
+ label: string
334
+ index?: number
335
+ }
336
+
337
+ // Validation
338
+ interface ValidationResult {
339
+ valid: boolean
340
+ errors: ValidationError[]
341
+ }
342
+
343
+ interface ValidationError {
344
+ row: number
345
+ column: number
346
+ message: string
347
+ }
348
+
349
+ // Search
350
+ interface SearchResult {
351
+ row: number
352
+ column: number
353
+ value: unknown
354
+ }
355
+
356
+ // Sort state
357
+ interface SortState {
358
+ columnIndex: Readonly<Ref<number | null>>
359
+ ascending: Readonly<Ref<boolean>>
360
+ descending: Readonly<Ref<boolean>>
361
+ }
362
+
363
+ // Filter state
364
+ interface FilterState {
365
+ isFiltered: Readonly<Ref<boolean>>
366
+ filteredRowCount: Readonly<Ref<number>>
367
+ filteredIndices: Readonly<Ref<number[]>>
368
+ }
369
+
370
+ // Base record type
371
+ interface BaseRecord {
372
+ readonly id: string
373
+ }
374
+
375
+ // Column definition for records
376
+ interface RecordColumnDef<T extends BaseRecord> {
377
+ field: string | ((record: T) => unknown)
378
+ header: string
379
+ format?: (value: unknown, record: T) => string
380
+ parse?: (value: string, record: T) => unknown
381
+ editable?: boolean
382
+ width?: string | number
383
+ defaultValue?: unknown
384
+ }
385
+ ```
386
+
387
+ ### Record-Based Data API
388
+
389
+ Work with typed records instead of raw arrays:
390
+
391
+ ```typescript
392
+ import type { RecordColumnDef } from '@mikestools/usetable'
393
+
394
+ interface User {
395
+ id: string
396
+ name: string
397
+ email: string
398
+ age: number
399
+ }
400
+
401
+ const columns: RecordColumnDef<User>[] = [
402
+ { field: 'id', header: 'ID' },
403
+ { field: 'name', header: 'Name' },
404
+ { field: 'email', header: 'Email' },
405
+ { field: 'age', header: 'Age' },
406
+ ]
407
+
408
+ // Configure table for records
409
+ table.setRecordColumns(columns)
410
+ table.setRecords([
411
+ { id: 'user-1', name: 'Alice', email: 'alice@example.com', age: 30 },
412
+ { id: 'user-2', name: 'Bob', email: 'bob@example.com', age: 25 },
413
+ ])
414
+
415
+ // CRUD operations
416
+ const newId = table.addRecord({ name: 'Carol', email: 'carol@example.com', age: 28 })
417
+ table.updateRecord<User>('user-1', { age: 31 })
418
+ table.removeRecord('user-2')
419
+ const user = table.getRecordById<User>('user-1')
420
+
421
+ // Selection by ID
422
+ table.selectRecords(['user-1', 'user-3'])
423
+ const selectedIds = table.getSelectedRecordIds()
424
+ const selectedRecords = table.getSelectedRecords<User>()
425
+
426
+ // Change notifications
427
+ table.onRecordChange<User>((id, record, type) => {
428
+ console.log(`${type}: ${id}`) // 'add' | 'update' | 'remove'
429
+ })
430
+
431
+ // Export/Import
432
+ const json = table.exportRecordsToJSON()
433
+ table.importRecordsFromJSON(json)
434
+ ```
435
+
436
+ ### Sorting API
437
+
438
+ ```typescript
439
+ table.sortColumnAscending(columnIndex)
440
+ table.sortColumnDescending(columnIndex)
441
+ table.sortColumnAscendingWith(columnIndex, comparator)
442
+ table.sortColumnDescendingWith(columnIndex, comparator)
443
+ table.clearColumnSort()
444
+
445
+ // Check state
446
+ table.isSorted()
447
+ table.isSortedAscending()
448
+ table.isSortedDescending()
449
+ table.getSortedColumnIndex()
450
+
451
+ // Reactive state
452
+ table.sortState.columnIndex.value
453
+ table.sortState.ascending.value
454
+ ```
455
+
456
+ ### Filtering API
457
+
458
+ ```typescript
459
+ table.filterRows(predicate)
460
+ table.filterColumn(columnIndex, predicate)
461
+ table.filterColumnByValue(columnIndex, value)
462
+ table.filterColumnByValues(columnIndex, values)
463
+ table.clearFilters()
464
+
465
+ // Check state
466
+ table.getFilteredRowIndices()
467
+ table.filterState.isFiltered.value
468
+ ```
469
+
470
+ ### Undo/Redo API
471
+
472
+ ```typescript
473
+ table.undo()
474
+ table.redo()
475
+ table.canUndo()
476
+ table.canRedo()
477
+ table.clearHistory()
478
+ table.setHistoryLimit(100)
479
+ ```
480
+
481
+ ### Cell Focus API
482
+
483
+ ```typescript
484
+ table.focusCell(rowIndex, columnIndex)
485
+ table.clearCellFocus()
486
+ table.getFocusedCell()
487
+ table.moveFocusUp()
488
+ table.moveFocusDown()
489
+ table.moveFocusLeft()
490
+ table.moveFocusRight()
491
+ table.enableKeyboardNavigation()
492
+ ```
493
+
494
+ ### Column Visibility API
495
+
496
+ ```typescript
497
+ table.hideColumn(columnIndex)
498
+ table.showColumn(columnIndex)
499
+ table.toggleColumnVisibility(columnIndex)
500
+ table.isColumnVisible(columnIndex)
501
+ table.getVisibleColumnIndices()
502
+ table.getHiddenColumnIndices()
503
+ ```
504
+
505
+ ### Reordering API
506
+
507
+ ```typescript
508
+ table.moveRow(fromIndex, toIndex)
509
+ table.moveRowUp(index)
510
+ table.moveRowDown(index)
511
+ table.moveRowToTop(index)
512
+ table.moveRowToBottom(index)
513
+ table.swapRows(index1, index2)
514
+ table.moveColumn(fromIndex, toIndex)
515
+ table.swapColumns(index1, index2)
516
+ ```
517
+
518
+ ### Clipboard API
519
+
520
+ ```typescript
521
+ table.copyCell(rowIndex, columnIndex)
522
+ table.copyRow(rowIndex)
523
+ table.copyColumn(columnIndex)
524
+ table.copyCellRange(startRow, startCol, endRow, endCol)
525
+ table.copySelectedCells()
526
+ table.copySelectedRows()
527
+ table.pasteAtCell(rowIndex, columnIndex, data)
528
+ ```
529
+
530
+ ### Row State API
531
+
532
+ ```typescript
533
+ table.expandRow(index)
534
+ table.collapseRow(index)
535
+ table.toggleRowExpansion(index)
536
+ table.pinRowTop(index)
537
+ table.pinRowBottom(index)
538
+ table.unpinRow(index)
539
+ table.unpinAllRows()
540
+ ```
541
+
542
+ ### Metadata API
543
+
544
+ ```typescript
545
+ table.setCellMeta(row, col, key, value)
546
+ table.getCellMeta(row, col, key)
547
+ table.setRowMeta(index, key, value)
548
+ table.getRowMeta(index, key)
549
+ table.setColumnMeta(index, key, value)
550
+ table.getColumnMeta(index, key)
551
+ ```
552
+
553
+ ## Examples
554
+
555
+ The showcase includes 22 interactive examples:
556
+
557
+ 1. **Basic Setup** - Headers, data, caption, row manipulation
558
+ 2. **Record-Based Data** - Work with typed records by ID
559
+ 3. **Inline Editing** - Double-click to edit with data sync
560
+ 4. **Sorting** - Column sorting with state tracking
561
+ 5. **Search & Filter** - Search and filter with predicates
562
+ 6. **Selection** - Row/cell selection with range support
563
+ 7. **Cell Navigation** - Keyboard navigation between cells
564
+ 8. **Column Visibility** - Show/hide columns
565
+ 9. **Reordering** - Move rows and columns
566
+ 10. **Undo/Redo** - History tracking with rollback
567
+ 11. **Clipboard** - Copy/paste operations
568
+ 12. **Row State** - Expand/collapse and pin rows
569
+ 13. **Aggregation** - Sum, average, computed columns
570
+ 14. **Validation** - Per-cell validation rules
571
+ 15. **Pagination** - Page through large datasets
572
+ 16. **Import/Export** - CSV and JSON support
573
+ 17. **Styling** - Dynamic classes and attributes
574
+ 18. **Transactions** - Batch operations with rollback
575
+ 19. **Grouping** - Group rows by values
576
+ 20. **Footer & Totals** - Summary rows
577
+ 21. **HTML Elements** - Rich content in cells
578
+ 22. **Pre-existing Sync** - Connect to existing tables
579
+
580
+ ## Browser Support
581
+
582
+ Works in all modern browsers that support ES2020+.
583
+
584
+ ## License
585
+
586
+ MIT Š Mike Garcia