@keenmate/web-grid 1.0.0-rc15 → 1.0.1
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 +13 -6
- package/ai/INDEX.txt +360 -0
- package/ai/basic-setup.txt +165 -0
- package/ai/callbacks-events.txt +297 -0
- package/ai/columns.txt +486 -0
- package/ai/dropdown-editors.txt +504 -0
- package/ai/editing.txt +545 -0
- package/ai/fill-handle.txt +128 -0
- package/ai/frozen-columns.txt +142 -0
- package/ai/grid-modes.txt +267 -0
- package/ai/keyboard-navigation.txt +429 -0
- package/ai/public-methods.txt +231 -0
- package/ai/row-locking.txt +214 -0
- package/ai/selection.txt +403 -0
- package/ai/sorting-filtering-pagination.txt +375 -0
- package/ai/styling-theming.txt +291 -0
- package/ai/toolbar-actions.txt +475 -0
- package/ai/typescript-types.txt +498 -0
- package/ai/virtual-scroll.txt +146 -0
- package/dist/grid.d.ts +4 -0
- package/dist/modules/navigation/focus.d.ts +4 -0
- package/dist/modules/navigation/index.d.ts +1 -1
- package/dist/modules/toolbar/index.d.ts +1 -1
- package/dist/types.d.ts +3 -0
- package/dist/web-grid.js +2038 -1997
- package/dist/web-grid.umd.js +80 -79
- package/package.json +2 -1
- package/src/css/_cell-selection.css +5 -3
- package/src/css/_dark-mode.css +44 -7
- package/src/css/_dialogs.css +1 -1
- package/src/css/_freeze.css +10 -5
- package/src/css/_navigation.css +15 -8
- package/src/css/_selection.css +5 -3
- package/src/css/_variables.css +3 -0
|
@@ -0,0 +1,429 @@
|
|
|
1
|
+
KEYBOARD NAVIGATION AND SHORTCUTS
|
|
2
|
+
==================================
|
|
3
|
+
This document covers all keyboard interactions in @keenmate/web-grid:
|
|
4
|
+
cell navigation, editing triggers, row operations, custom shortcuts,
|
|
5
|
+
and the shortcuts help overlay.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
NAVIGATION KEYS
|
|
9
|
+
---------------
|
|
10
|
+
These keys work when a cell is focused but NOT in edit mode (navigate state).
|
|
11
|
+
Arrow keys move one cell at a time. Other keys jump farther.
|
|
12
|
+
|
|
13
|
+
Arrow Up Move focus one row up (same column)
|
|
14
|
+
Arrow Down Move focus one row down (same column)
|
|
15
|
+
Arrow Left Move focus one column left (same row)
|
|
16
|
+
Arrow Right Move focus one column right (same row)
|
|
17
|
+
|
|
18
|
+
Tab Move to next editable column. Wraps to first editable
|
|
19
|
+
column of next row when at the end of a row.
|
|
20
|
+
Shift+Tab Move to previous editable column. Wraps to last editable
|
|
21
|
+
column of previous row when at the start of a row.
|
|
22
|
+
|
|
23
|
+
Home Move to first column in the current row
|
|
24
|
+
End Move to last column in the current row
|
|
25
|
+
Ctrl+Home Move to first cell in the grid (row 0, column 0)
|
|
26
|
+
Ctrl+End Move to last cell in the grid (last row, last column)
|
|
27
|
+
|
|
28
|
+
PageUp Move up ~10 rows (same column)
|
|
29
|
+
PageDown Move down ~10 rows (same column)
|
|
30
|
+
Ctrl+PageUp Move to first row (same column)
|
|
31
|
+
Ctrl+PageDown Move to last row (same column)
|
|
32
|
+
|
|
33
|
+
Enter Move to next row (same column). If Tab was used before
|
|
34
|
+
Enter, the column resets to where Tab traversal started
|
|
35
|
+
(Excel-like behavior).
|
|
36
|
+
|
|
37
|
+
Ctrl+G Open "Go To Row" dialog for jumping to a specific row number
|
|
38
|
+
|
|
39
|
+
Tab traversal tracks a "start column." When you Tab across columns and then
|
|
40
|
+
press Enter, focus moves down to the next row at the column where you started
|
|
41
|
+
Tab traversal. Arrow keys reset this tracking.
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
EDITING KEYS
|
|
45
|
+
------------
|
|
46
|
+
These keys start or control cell editing. Behavior depends on the column's
|
|
47
|
+
editor type (text, number, checkbox, select, combobox, autocomplete, date,
|
|
48
|
+
custom) and the grid's editTrigger setting.
|
|
49
|
+
|
|
50
|
+
Enter Start editing for dropdown/date editors (if
|
|
51
|
+
shouldOpenDropdownOnEnter is true). For text/number
|
|
52
|
+
editors, Enter navigates down (does not start editing).
|
|
53
|
+
F2 Start editing the focused cell. For dropdown editors,
|
|
54
|
+
also opens the dropdown. For date editors, opens the
|
|
55
|
+
date picker. For custom editors, calls cellEditCallback.
|
|
56
|
+
Space Toggle checkbox value. For dropdown/date/custom editors,
|
|
57
|
+
starts editing and opens the respective picker/editor.
|
|
58
|
+
Escape If editing with dropdown/datepicker open: first press
|
|
59
|
+
closes the dropdown/datepicker. Second press cancels the
|
|
60
|
+
edit and returns to navigate mode. If no dropdown is open,
|
|
61
|
+
first press cancels the edit. If not editing, clears focus.
|
|
62
|
+
Delete Clear cell content (sets value to null) for editable cells.
|
|
63
|
+
Ctrl+C Copy focused cell value (or cell selection) to clipboard.
|
|
64
|
+
|
|
65
|
+
Any printable Start editing with that character as initial input. For
|
|
66
|
+
character text editors, the character replaces the cell value. For
|
|
67
|
+
combobox/autocomplete, it becomes the initial search query.
|
|
68
|
+
For number editors, only digits/dot/minus are accepted.
|
|
69
|
+
|
|
70
|
+
When a dropdown is open during editing:
|
|
71
|
+
Arrow Up/Down Navigate through dropdown options
|
|
72
|
+
PageUp/PageDown Jump ~10 options in the dropdown
|
|
73
|
+
Home/End Jump to first/last option (select/combobox only;
|
|
74
|
+
autocomplete lets the browser handle cursor movement)
|
|
75
|
+
Enter Select the highlighted option and commit
|
|
76
|
+
Tab Select the highlighted option and move to next cell
|
|
77
|
+
Escape Close dropdown (first press), cancel edit (second press)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
ROW OPERATION KEYS
|
|
81
|
+
------------------
|
|
82
|
+
These built-in keys operate on the currently focused row.
|
|
83
|
+
|
|
84
|
+
Ctrl+Delete Fire the onrowdelete callback and dispatch a 'rowdelete'
|
|
85
|
+
CustomEvent. Does NOT delete the row automatically.
|
|
86
|
+
The consumer must handle deletion in the callback.
|
|
87
|
+
|
|
88
|
+
grid.onrowdelete = ({ rowIndex, row }) => {
|
|
89
|
+
grid.items = grid.items.filter((_, i) => i !== rowIndex)
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
Row move operations (Ctrl+Up to move row up, Ctrl+Down to move row down)
|
|
93
|
+
are available as predefined toolbar items ('moveUp', 'moveDown'), not as
|
|
94
|
+
built-in keyboard shortcuts. To add them as keyboard shortcuts, use
|
|
95
|
+
rowShortcuts (see below).
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
ROW SHORTCUTS
|
|
99
|
+
-------------
|
|
100
|
+
rowShortcuts defines keyboard shortcuts that operate on a single focused row.
|
|
101
|
+
Each shortcut requires key, id, label, and action. The action receives a
|
|
102
|
+
context with the row data and position.
|
|
103
|
+
|
|
104
|
+
Type definition:
|
|
105
|
+
|
|
106
|
+
type RowShortcut<T> = {
|
|
107
|
+
key: string // Key combo string
|
|
108
|
+
id: string // Unique identifier
|
|
109
|
+
label: string // Display label for help overlay
|
|
110
|
+
action: (ctx: ShortcutContext<T>) => void // Handler function
|
|
111
|
+
disabled?: boolean | ((ctx) => boolean) // Optionally disable
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
type ShortcutContext<T> = {
|
|
115
|
+
row: T // The data object for the focused row
|
|
116
|
+
rowIndex: number // Index in displayItems
|
|
117
|
+
colIndex: number // Currently focused column index
|
|
118
|
+
column: Column<T> // Column definition at colIndex
|
|
119
|
+
cellValue: unknown // Raw value of the focused cell
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
Example:
|
|
123
|
+
|
|
124
|
+
grid.rowShortcuts = [
|
|
125
|
+
{
|
|
126
|
+
key: 'Delete',
|
|
127
|
+
id: 'delete-row',
|
|
128
|
+
label: 'Delete row',
|
|
129
|
+
action: (ctx) => {
|
|
130
|
+
grid.items = grid.items.filter((_, i) => i !== ctx.rowIndex)
|
|
131
|
+
}
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
key: 'Ctrl+D',
|
|
135
|
+
id: 'duplicate-row',
|
|
136
|
+
label: 'Duplicate row',
|
|
137
|
+
action: (ctx) => {
|
|
138
|
+
const copy = { ...ctx.row, id: Date.now() }
|
|
139
|
+
grid.items = [
|
|
140
|
+
...grid.items.slice(0, ctx.rowIndex + 1),
|
|
141
|
+
copy,
|
|
142
|
+
...grid.items.slice(ctx.rowIndex + 1)
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
},
|
|
146
|
+
{
|
|
147
|
+
key: 'Ctrl+Up',
|
|
148
|
+
id: 'move-up',
|
|
149
|
+
label: 'Move row up',
|
|
150
|
+
action: (ctx) => {
|
|
151
|
+
if (ctx.rowIndex === 0) return
|
|
152
|
+
const items = [...grid.items]
|
|
153
|
+
;[items[ctx.rowIndex - 1], items[ctx.rowIndex]] =
|
|
154
|
+
[items[ctx.rowIndex], items[ctx.rowIndex - 1]]
|
|
155
|
+
grid.items = items
|
|
156
|
+
}
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
key: 'Shift+F2',
|
|
160
|
+
id: 'edit-details',
|
|
161
|
+
label: 'Edit in modal',
|
|
162
|
+
disabled: (ctx) => ctx.row.locked,
|
|
163
|
+
action: (ctx) => openEditModal(ctx.row)
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
Shortcuts are checked before built-in key handlers. If a shortcut matches,
|
|
168
|
+
it consumes the event (preventDefault) and the built-in behavior is skipped.
|
|
169
|
+
|
|
170
|
+
Shortcuts also work on hovered rows when the row toolbar is visible. The grid
|
|
171
|
+
sets up document-level keydown listeners for the toolbar and inline toolbar
|
|
172
|
+
modes, so shortcuts fire even without cell focus.
|
|
173
|
+
|
|
174
|
+
|
|
175
|
+
RANGE SHORTCUTS
|
|
176
|
+
---------------
|
|
177
|
+
rangeShortcuts defines keyboard shortcuts that operate on multiple selected
|
|
178
|
+
rows or a selected cell range. They work with both row selection (clicking
|
|
179
|
+
row number column) and cell range selection (click+drag or Shift+click).
|
|
180
|
+
|
|
181
|
+
Type definition:
|
|
182
|
+
|
|
183
|
+
type RangeShortcut<T> = {
|
|
184
|
+
key: string // Key combo string
|
|
185
|
+
id: string // Unique identifier
|
|
186
|
+
label: string // Display label
|
|
187
|
+
action: (ctx: RangeShortcutContext<T>) => void // Handler function
|
|
188
|
+
disabled?: boolean | ((ctx) => boolean) // Optionally disable
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
type RangeShortcutContext<T> = {
|
|
192
|
+
// Always present (populated for row selection, empty arrays for cell range)
|
|
193
|
+
rows: T[] // Selected row data objects (display order)
|
|
194
|
+
rowIndices: number[] // Selected row indices (sorted ascending)
|
|
195
|
+
|
|
196
|
+
// Present only when a cell range is selected
|
|
197
|
+
cellRange?: CellRange // { startRowIndex, startColIndex, endRowIndex,
|
|
198
|
+
// endColIndex, startField, endField }
|
|
199
|
+
cells?: Array<{ // Individual cells in the selected range
|
|
200
|
+
row: T
|
|
201
|
+
rowIndex: number
|
|
202
|
+
colIndex: number
|
|
203
|
+
field: string
|
|
204
|
+
value: unknown
|
|
205
|
+
}>
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
Example:
|
|
209
|
+
|
|
210
|
+
grid.rangeShortcuts = [
|
|
211
|
+
{
|
|
212
|
+
key: 'Delete',
|
|
213
|
+
id: 'delete-selected',
|
|
214
|
+
label: 'Delete selected rows',
|
|
215
|
+
action: (ctx) => {
|
|
216
|
+
const indexSet = new Set(ctx.rowIndices)
|
|
217
|
+
grid.items = grid.items.filter((_, i) => !indexSet.has(i))
|
|
218
|
+
}
|
|
219
|
+
},
|
|
220
|
+
{
|
|
221
|
+
key: 'Ctrl+E',
|
|
222
|
+
id: 'export-selection',
|
|
223
|
+
label: 'Export selection',
|
|
224
|
+
action: (ctx) => {
|
|
225
|
+
if (ctx.cells) {
|
|
226
|
+
// Cell range selected - export cell data
|
|
227
|
+
exportCells(ctx.cells)
|
|
228
|
+
} else {
|
|
229
|
+
// Row selection - export full rows
|
|
230
|
+
exportRows(ctx.rows)
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
]
|
|
235
|
+
|
|
236
|
+
Range shortcuts are checked in two places:
|
|
237
|
+
1. On the focused cell's keydown handler (when rows are selected)
|
|
238
|
+
2. On the grid container's keydown handler (for cell range and row/column
|
|
239
|
+
selection when no individual cell has focus)
|
|
240
|
+
|
|
241
|
+
Built-in range keys (no rangeShortcuts needed):
|
|
242
|
+
Ctrl+C Copy selected rows/columns/cells to clipboard as TSV
|
|
243
|
+
Escape Clear the current selection
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
SHORTCUTS HELP OVERLAY
|
|
247
|
+
----------------------
|
|
248
|
+
When isShortcutsHelpVisible is true and rowShortcuts has entries, the grid
|
|
249
|
+
displays a small info icon. Hovering or focusing the icon reveals an overlay
|
|
250
|
+
listing all registered shortcuts with their key combinations and labels.
|
|
251
|
+
|
|
252
|
+
Properties:
|
|
253
|
+
|
|
254
|
+
isShortcutsHelpVisible boolean, default false
|
|
255
|
+
Show the shortcuts help icon
|
|
256
|
+
|
|
257
|
+
shortcutsHelpPosition 'top-right' (default) or 'top-left'
|
|
258
|
+
Where to place the icon in the grid
|
|
259
|
+
|
|
260
|
+
shortcutsHelpContentCallback () => string
|
|
261
|
+
Return custom HTML to display above the
|
|
262
|
+
shortcuts list in the overlay
|
|
263
|
+
|
|
264
|
+
Example:
|
|
265
|
+
|
|
266
|
+
grid.isShortcutsHelpVisible = true
|
|
267
|
+
grid.shortcutsHelpPosition = 'top-right'
|
|
268
|
+
|
|
269
|
+
grid.shortcutsHelpContentCallback = () => {
|
|
270
|
+
return '<p>Use these shortcuts when a row is focused:</p>'
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
KEY FORMAT
|
|
275
|
+
----------
|
|
276
|
+
Key combination strings use '+' as a separator between modifiers and the
|
|
277
|
+
main key. Case-insensitive for modifiers, case-insensitive matching for
|
|
278
|
+
letters.
|
|
279
|
+
|
|
280
|
+
Modifiers:
|
|
281
|
+
Ctrl (or Control)
|
|
282
|
+
Shift
|
|
283
|
+
Alt
|
|
284
|
+
Meta (or Cmd, Command)
|
|
285
|
+
|
|
286
|
+
Examples:
|
|
287
|
+
'Delete' Delete key alone
|
|
288
|
+
'Ctrl+D' Ctrl and D
|
|
289
|
+
'Ctrl+Alt+E' Ctrl, Alt, and E
|
|
290
|
+
'Shift+F2' Shift and F2
|
|
291
|
+
'Ctrl+Up' Ctrl and Arrow Up (use 'ArrowUp' for the key name)
|
|
292
|
+
'Ctrl+Shift+Z' Ctrl, Shift, and Z
|
|
293
|
+
|
|
294
|
+
Note: The key name in the combo is matched against KeyboardEvent.key. For
|
|
295
|
+
arrow keys, you can use either 'Up' or 'ArrowUp' since matching is done via
|
|
296
|
+
e.key.toLowerCase(). The parsed combo stores the key as provided; matching
|
|
297
|
+
compares lowercase versions.
|
|
298
|
+
|
|
299
|
+
Under the hood, parseKeyCombo() splits on '+', identifies modifiers (ctrl,
|
|
300
|
+
shift, alt, meta), and the remaining part becomes the key. matchesKeyCombo()
|
|
301
|
+
checks that all modifier flags match and the key matches (case-insensitive).
|
|
302
|
+
|
|
303
|
+
|
|
304
|
+
NAVIGATION BEHAVIOR BY EDIT MODE
|
|
305
|
+
---------------------------------
|
|
306
|
+
The editTrigger property (grid-level or per-column) changes how keyboard
|
|
307
|
+
navigation interacts with editing. There are five modes: navigate, always,
|
|
308
|
+
click, dblclick, and button.
|
|
309
|
+
|
|
310
|
+
NAVIGATE MODE (editTrigger: 'navigate')
|
|
311
|
+
This is the mode set by mode: 'excel'. Cells display values. Arrow keys
|
|
312
|
+
move between cells. Typing starts editing with the typed character. F2
|
|
313
|
+
starts editing. Enter/Tab commit edits and move focus.
|
|
314
|
+
|
|
315
|
+
When not editing:
|
|
316
|
+
- Arrow keys move focus between cells
|
|
317
|
+
- Tab/Shift+Tab move between editable cells only
|
|
318
|
+
- Enter moves down (or starts edit for dropdown if configured)
|
|
319
|
+
- F2 starts edit
|
|
320
|
+
- Space toggles checkbox / opens dropdown / opens datepicker
|
|
321
|
+
- Printable characters start edit with that character
|
|
322
|
+
- Delete clears cell value
|
|
323
|
+
|
|
324
|
+
When editing:
|
|
325
|
+
- Arrow Up/Down for text editors: commit and navigate (pipeline mode)
|
|
326
|
+
- Arrow Left/Right for text editors: cursor movement (native browser)
|
|
327
|
+
- Arrow Left/Right for dropdown editors: cancel edit and navigate
|
|
328
|
+
- Tab commits and moves to next editable cell
|
|
329
|
+
- Enter commits and moves down
|
|
330
|
+
- Escape cancels edit (two-phase if dropdown is open)
|
|
331
|
+
|
|
332
|
+
ALWAYS MODE (editTrigger: 'always')
|
|
333
|
+
This is the mode set by mode: 'input-matrix'. All cells render as editors
|
|
334
|
+
permanently. Focus moves between editor inputs directly.
|
|
335
|
+
|
|
336
|
+
- Tab/Shift+Tab commit current cell and move to next/previous editor
|
|
337
|
+
- Enter commits and moves to next row
|
|
338
|
+
- Arrow Up/Down commit and move up/down
|
|
339
|
+
- Arrow Left/Right are handled by the input (cursor movement) for text
|
|
340
|
+
editors; for dropdown editors, they navigate options when open
|
|
341
|
+
- Escape closes dropdown (first press) or clears focus (second press)
|
|
342
|
+
- The grid uses the action pipeline exclusively in this mode
|
|
343
|
+
|
|
344
|
+
CLICK MODE (editTrigger: 'click')
|
|
345
|
+
Single click on a cell starts editing. Keyboard navigation works the same
|
|
346
|
+
as navigate mode when not editing.
|
|
347
|
+
|
|
348
|
+
- Click starts editing immediately
|
|
349
|
+
- While not editing, all navigation keys work normally
|
|
350
|
+
- While editing, same behavior as navigate mode editing
|
|
351
|
+
|
|
352
|
+
DBLCLICK MODE (editTrigger: 'dblclick')
|
|
353
|
+
Double-click on a cell starts editing. This is the default editTrigger.
|
|
354
|
+
|
|
355
|
+
- Double-click starts editing
|
|
356
|
+
- While not editing, all navigation keys work normally
|
|
357
|
+
- While editing, same behavior as navigate mode editing
|
|
358
|
+
- In navigate mode, double-click also starts editing
|
|
359
|
+
|
|
360
|
+
BUTTON MODE (editTrigger: 'button')
|
|
361
|
+
Editing is only triggered by the edit button (isEditButtonVisible: true).
|
|
362
|
+
Keyboard navigation works but does not start editing.
|
|
363
|
+
|
|
364
|
+
READ-ONLY (isEditable: false or mode: 'read-only')
|
|
365
|
+
Navigation keys work normally (arrows, Tab, Home, End, PageUp, PageDown).
|
|
366
|
+
No editing keys function. Ctrl+C copies. Cell selection works if enabled.
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
EDITOR-SPECIFIC NAVIGATION
|
|
370
|
+
---------------------------
|
|
371
|
+
Different editor types handle keys differently during editing:
|
|
372
|
+
|
|
373
|
+
TEXT / NUMBER EDITORS:
|
|
374
|
+
- Arrow Left/Right: cursor movement within the input (native)
|
|
375
|
+
- Arrow Up/Down: commit edit and navigate (navigate/click/dblclick modes)
|
|
376
|
+
- Enter: commit and move down
|
|
377
|
+
- Tab: commit and move to next editable cell
|
|
378
|
+
- Escape: cancel edit
|
|
379
|
+
|
|
380
|
+
CHECKBOX EDITOR:
|
|
381
|
+
- Space: toggle checked state
|
|
382
|
+
- Arrow keys: consumed (noop) while in edit mode
|
|
383
|
+
- Enter: commit and move down
|
|
384
|
+
- Tab: commit and move to next cell
|
|
385
|
+
- isCheckboxAlwaysEditable: when true, Space toggles checkbox even in
|
|
386
|
+
navigate mode without entering edit state
|
|
387
|
+
|
|
388
|
+
SELECT / COMBOBOX / AUTOCOMPLETE EDITORS:
|
|
389
|
+
When dropdown is CLOSED:
|
|
390
|
+
- Arrow Left/Right: cancel edit and navigate to adjacent cell
|
|
391
|
+
(navigate mode only)
|
|
392
|
+
- Space/F2/Enter: open the dropdown
|
|
393
|
+
- Typing: for select, type-to-filter (keys accumulate as filter text,
|
|
394
|
+
Backspace removes last character)
|
|
395
|
+
|
|
396
|
+
When dropdown is OPEN:
|
|
397
|
+
- Arrow Up/Down: navigate through options (skip disabled)
|
|
398
|
+
- PageUp/PageDown: jump ~10 options
|
|
399
|
+
- Home/End: first/last option (select/combobox only)
|
|
400
|
+
- Enter: select highlighted option, commit, move down
|
|
401
|
+
- Tab: select highlighted option, commit, move to next cell
|
|
402
|
+
- Escape: close dropdown (first press); cancel edit (second press).
|
|
403
|
+
For combobox/autocomplete, first Escape restores original display
|
|
404
|
+
value if input was modified.
|
|
405
|
+
- Arrow Left/Right: for autocomplete, cursor movement in input.
|
|
406
|
+
For select/combobox, consumed (noop).
|
|
407
|
+
|
|
408
|
+
DATE EDITOR:
|
|
409
|
+
- When datepicker is open, Arrow/PageUp/PageDown/Home/End/Enter/Escape/Tab
|
|
410
|
+
are handled by the datepicker component, not the grid
|
|
411
|
+
- F2 or Space from navigate mode: start edit and open datepicker
|
|
412
|
+
- Enter from navigate mode: start edit and open datepicker
|
|
413
|
+
|
|
414
|
+
CUSTOM EDITOR:
|
|
415
|
+
- F2 or Space from navigate mode: start edit and call cellEditCallback
|
|
416
|
+
- The custom editor receives commit() and cancel() functions
|
|
417
|
+
- Grid does not handle keydown inside custom editors
|
|
418
|
+
|
|
419
|
+
|
|
420
|
+
CLIPBOARD KEYS
|
|
421
|
+
--------------
|
|
422
|
+
Ctrl+C Copy focused cell, selected rows, selected columns, or
|
|
423
|
+
cell range to clipboard as TSV (tab-separated values).
|
|
424
|
+
Compatible with Excel paste.
|
|
425
|
+
Ctrl+V Paste TSV data from clipboard into the grid starting at
|
|
426
|
+
the focused cell. Multi-cell paste supported.
|
|
427
|
+
|
|
428
|
+
shouldCopyWithHeaders (boolean, default false): when true, column headers
|
|
429
|
+
are included as the first row when copying cell selections.
|
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
PUBLIC METHODS
|
|
2
|
+
==============
|
|
3
|
+
@keenmate/web-grid - Complete reference for all public methods.
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
All methods are called on the <web-grid> DOM element:
|
|
7
|
+
const grid = document.getElementById('grid')
|
|
8
|
+
grid.focusCell(0, 1)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
----------------------------------------------------------------------
|
|
12
|
+
FOCUS AND EDITING
|
|
13
|
+
----------------------------------------------------------------------
|
|
14
|
+
|
|
15
|
+
focusCell(rowIndex: number, colIndex: number): void
|
|
16
|
+
Programmatically focus a cell. In navigate mode (editTrigger='navigate'),
|
|
17
|
+
this sets the blue focus border on the specified cell. Does not start
|
|
18
|
+
editing.
|
|
19
|
+
|
|
20
|
+
startEditing(rowIndex: number, colIndex: number): void
|
|
21
|
+
Programmatically start editing a cell. The cell must be editable
|
|
22
|
+
(column.isEditable = true, row not locked). Opens the appropriate
|
|
23
|
+
editor for the column's editor type.
|
|
24
|
+
|
|
25
|
+
openCustomEditor(rowIndex: number, colIndex: number): void
|
|
26
|
+
Open the custom editor for a cell with editor: 'custom'. Invokes the
|
|
27
|
+
column's cellEditCallback with { value, row, rowIndex, field, commit,
|
|
28
|
+
cancel }.
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
----------------------------------------------------------------------
|
|
32
|
+
DRAFT MANAGEMENT
|
|
33
|
+
----------------------------------------------------------------------
|
|
34
|
+
Drafts are uncommitted cell edits. When a user edits a cell, the new value
|
|
35
|
+
is stored in a draft row until committed. Invalid values remain in the
|
|
36
|
+
draft but are flagged with validation errors.
|
|
37
|
+
|
|
38
|
+
getRowDraft(rowIndex: number): T | undefined
|
|
39
|
+
Get the draft (edited but uncommitted values) for a row. Returns
|
|
40
|
+
undefined if the row has no draft.
|
|
41
|
+
|
|
42
|
+
hasRowDraft(rowIndex: number): boolean
|
|
43
|
+
Check if a row has any uncommitted changes.
|
|
44
|
+
|
|
45
|
+
discardRowDraft(rowIndex: number): void
|
|
46
|
+
Discard all draft changes for a specific row. Reverts cells to their
|
|
47
|
+
original values.
|
|
48
|
+
|
|
49
|
+
getDraftRowIndices(): number[]
|
|
50
|
+
Get indices of all rows that have drafts (uncommitted changes).
|
|
51
|
+
|
|
52
|
+
discardAllDrafts(): void
|
|
53
|
+
Discard all draft changes across all rows. Reverts every edited cell
|
|
54
|
+
to its original value.
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
----------------------------------------------------------------------
|
|
58
|
+
VALIDATION
|
|
59
|
+
----------------------------------------------------------------------
|
|
60
|
+
|
|
61
|
+
isCellInvalid(rowIndex: number, field: string): boolean
|
|
62
|
+
Check if a cell has a validation error (from beforeCommitCallback or
|
|
63
|
+
external invalidCells).
|
|
64
|
+
|
|
65
|
+
getCellValidationError(rowIndex: number, field: string): string | null
|
|
66
|
+
Get the validation error message for a cell. Returns null if the cell
|
|
67
|
+
is valid.
|
|
68
|
+
|
|
69
|
+
canEditCell(rowIndex: number, field: string): boolean
|
|
70
|
+
Check if a cell can be edited. Considers:
|
|
71
|
+
- Column isEditable setting
|
|
72
|
+
- Row locking state and lockedEditBehavior
|
|
73
|
+
- canEditLockedCallback result
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
----------------------------------------------------------------------
|
|
77
|
+
ROW IDENTIFICATION
|
|
78
|
+
----------------------------------------------------------------------
|
|
79
|
+
Requires idValueMember or idValueCallback to be configured.
|
|
80
|
+
|
|
81
|
+
getRowId(row: T): unknown | undefined
|
|
82
|
+
Get the unique ID of a row using the configured idValueMember or
|
|
83
|
+
idValueCallback.
|
|
84
|
+
|
|
85
|
+
findRowById(id: unknown): { row: T, index: number } | null
|
|
86
|
+
Find a row by its unique ID. Returns the row object and its current
|
|
87
|
+
index, or null if not found.
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
----------------------------------------------------------------------
|
|
91
|
+
ROW UPDATES
|
|
92
|
+
----------------------------------------------------------------------
|
|
93
|
+
For live data updates (WebSocket, polling). Requires row identification.
|
|
94
|
+
|
|
95
|
+
updateRowById(id: unknown, newData: Partial<T>): boolean
|
|
96
|
+
Merge partial data into an existing row. Only the provided properties
|
|
97
|
+
are updated; other properties remain unchanged. Returns true if the
|
|
98
|
+
row was found and updated.
|
|
99
|
+
|
|
100
|
+
grid.updateRowById(42, { status: 'approved', updatedAt: new Date() })
|
|
101
|
+
|
|
102
|
+
replaceRowById(id: unknown, newRow: T): boolean
|
|
103
|
+
Replace an entire row object by ID. Returns true if the row was found
|
|
104
|
+
and replaced.
|
|
105
|
+
|
|
106
|
+
grid.replaceRowById(42, newRowData)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
----------------------------------------------------------------------
|
|
110
|
+
ROW LOCKING
|
|
111
|
+
----------------------------------------------------------------------
|
|
112
|
+
Query methods accept either a row object or a row ID.
|
|
113
|
+
External lock methods require row identification (idValueMember or
|
|
114
|
+
idValueCallback).
|
|
115
|
+
|
|
116
|
+
isRowLocked(rowOrId: T | unknown): boolean
|
|
117
|
+
Check if a row is locked (from any source: property, callback, or
|
|
118
|
+
external).
|
|
119
|
+
|
|
120
|
+
getRowLockInfo(rowOrId: T | unknown): RowLockInfo | null
|
|
121
|
+
Get lock information for a row. Returns null if not locked.
|
|
122
|
+
|
|
123
|
+
lockRowById(id: unknown, lockerInfo?: RowLockInfo): boolean
|
|
124
|
+
Lock a row externally. Returns true if the row was found. Fires
|
|
125
|
+
onrowlockchange event.
|
|
126
|
+
|
|
127
|
+
grid.lockRowById(42, {
|
|
128
|
+
isLocked: true,
|
|
129
|
+
lockedBy: 'Jane',
|
|
130
|
+
lockedAt: new Date()
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
unlockRowById(id: unknown): boolean
|
|
134
|
+
Unlock an externally locked row. Returns true if the row was found
|
|
135
|
+
and was locked.
|
|
136
|
+
|
|
137
|
+
getExternalLocks(): Map<unknown, RowLockInfo>
|
|
138
|
+
Get all external locks as a Map keyed by row ID.
|
|
139
|
+
|
|
140
|
+
clearExternalLocks(): void
|
|
141
|
+
Remove all external locks at once.
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
----------------------------------------------------------------------
|
|
145
|
+
ROW SELECTION
|
|
146
|
+
----------------------------------------------------------------------
|
|
147
|
+
|
|
148
|
+
selectRow(rowIndex: number, mode?: 'replace' | 'toggle' | 'range'): void
|
|
149
|
+
Select a row.
|
|
150
|
+
'replace' (default): Clear existing selection, select this row
|
|
151
|
+
'toggle': Toggle this row's selection without affecting others
|
|
152
|
+
'range': Select all rows from last selected to this row
|
|
153
|
+
|
|
154
|
+
selectRowRange(fromIndex: number, toIndex: number): void
|
|
155
|
+
Select a contiguous range of rows (inclusive).
|
|
156
|
+
|
|
157
|
+
clearSelection(): void
|
|
158
|
+
Clear all row selections.
|
|
159
|
+
|
|
160
|
+
isRowSelected(rowIndex: number): boolean
|
|
161
|
+
Check if a specific row is selected.
|
|
162
|
+
|
|
163
|
+
getSelectedRowsData(): T[]
|
|
164
|
+
Get the data objects for all selected rows.
|
|
165
|
+
|
|
166
|
+
copySelectedRowsToClipboard(): Promise<boolean>
|
|
167
|
+
Copy selected rows as TSV (tab-separated values) to the clipboard.
|
|
168
|
+
Returns true if successful. TSV format is compatible with Excel paste.
|
|
169
|
+
|
|
170
|
+
|
|
171
|
+
----------------------------------------------------------------------
|
|
172
|
+
CELL SELECTION
|
|
173
|
+
----------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
selectCellRange(range: CellRange): void
|
|
176
|
+
Select a rectangular cell range programmatically.
|
|
177
|
+
CellRange: { startRowIndex, startColIndex, endRowIndex, endColIndex,
|
|
178
|
+
startField, endField }
|
|
179
|
+
|
|
180
|
+
clearCellSelection(): void
|
|
181
|
+
Clear the current cell range selection.
|
|
182
|
+
|
|
183
|
+
getSelectedCells(): Array<{ row: T, rowIndex: number, colIndex: number, field: string, value: unknown }>
|
|
184
|
+
Get data for all cells in the current selection.
|
|
185
|
+
|
|
186
|
+
copyCellSelectionToClipboard(): Promise<boolean>
|
|
187
|
+
Copy selected cells as TSV to clipboard. If shouldCopyWithHeaders is
|
|
188
|
+
true, column headers are included as the first row. Returns true if
|
|
189
|
+
successful.
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
----------------------------------------------------------------------
|
|
193
|
+
COLUMN WIDTH
|
|
194
|
+
----------------------------------------------------------------------
|
|
195
|
+
|
|
196
|
+
setColumnWidth(field: string, width: string): void
|
|
197
|
+
Set the width of a single column.
|
|
198
|
+
|
|
199
|
+
grid.setColumnWidth('name', '200px')
|
|
200
|
+
|
|
201
|
+
setColumnWidths(widths: ColumnWidthState[]): void
|
|
202
|
+
Set widths for multiple columns at once.
|
|
203
|
+
ColumnWidthState: { field: string, width: string }
|
|
204
|
+
|
|
205
|
+
grid.setColumnWidths([
|
|
206
|
+
{ field: 'name', width: '200px' },
|
|
207
|
+
{ field: 'email', width: '300px' }
|
|
208
|
+
])
|
|
209
|
+
|
|
210
|
+
getColumnWidthsState(): ColumnWidthState[]
|
|
211
|
+
Get current widths of all columns. Returns array of { field, width }.
|
|
212
|
+
Same format used by localStorage persistence and setColumnWidths.
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
----------------------------------------------------------------------
|
|
216
|
+
COLUMN ORDER
|
|
217
|
+
----------------------------------------------------------------------
|
|
218
|
+
|
|
219
|
+
setColumnOrder(order: ColumnOrderState[]): void
|
|
220
|
+
Set column display order.
|
|
221
|
+
ColumnOrderState: { field: string, order: number }
|
|
222
|
+
|
|
223
|
+
grid.setColumnOrder([
|
|
224
|
+
{ field: 'name', order: 0 },
|
|
225
|
+
{ field: 'email', order: 1 },
|
|
226
|
+
{ field: 'id', order: 2 }
|
|
227
|
+
])
|
|
228
|
+
|
|
229
|
+
getColumnOrderState(): ColumnOrderState[]
|
|
230
|
+
Get current column order. Returns array of { field, order }.
|
|
231
|
+
Same format used by localStorage persistence and setColumnOrder.
|