@angular/aria 21.0.0-rc.0 → 21.0.0-rc.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/_adev_assets/aria-accordion.json +443 -59
- package/_adev_assets/aria-combobox.json +345 -37
- package/_adev_assets/aria-grid.json +408 -71
- package/_adev_assets/aria-listbox.json +115 -35
- package/_adev_assets/aria-menu.json +492 -167
- package/_adev_assets/aria-tabs.json +272 -88
- package/_adev_assets/aria-toolbar.json +151 -133
- package/_adev_assets/aria-tree.json +182 -35
- package/fesm2022/_widget-chunk.mjs +643 -190
- package/fesm2022/_widget-chunk.mjs.map +1 -1
- package/fesm2022/accordion.mjs +129 -77
- package/fesm2022/accordion.mjs.map +1 -1
- package/fesm2022/aria.mjs +1 -1
- package/fesm2022/aria.mjs.map +1 -1
- package/fesm2022/combobox.mjs +140 -27
- package/fesm2022/combobox.mjs.map +1 -1
- package/fesm2022/grid.mjs +254 -68
- package/fesm2022/grid.mjs.map +1 -1
- package/fesm2022/listbox.mjs +54 -44
- package/fesm2022/listbox.mjs.map +1 -1
- package/fesm2022/menu.mjs +270 -108
- package/fesm2022/menu.mjs.map +1 -1
- package/fesm2022/private.mjs +752 -785
- package/fesm2022/private.mjs.map +1 -1
- package/fesm2022/tabs.mjs +101 -71
- package/fesm2022/tabs.mjs.map +1 -1
- package/fesm2022/toolbar.mjs +87 -64
- package/fesm2022/toolbar.mjs.map +1 -1
- package/fesm2022/tree.mjs +105 -60
- package/fesm2022/tree.mjs.map +1 -1
- package/package.json +2 -10
- package/types/_grid-chunk.d.ts +326 -83
- package/types/accordion.d.ts +134 -35
- package/types/combobox.d.ts +146 -13
- package/types/grid.d.ts +159 -32
- package/types/listbox.d.ts +59 -28
- package/types/menu.d.ts +151 -55
- package/types/private.d.ts +449 -567
- package/types/tabs.d.ts +121 -41
- package/types/toolbar.d.ts +74 -51
- package/types/tree.d.ts +116 -45
- package/_adev_assets/aria-radio-group.json +0 -389
- package/fesm2022/deferred-content.mjs +0 -99
- package/fesm2022/deferred-content.mjs.map +0 -1
- package/fesm2022/radio-group.mjs +0 -338
- package/fesm2022/radio-group.mjs.map +0 -1
- package/types/deferred-content.d.ts +0 -38
- package/types/radio-group.d.ts +0 -84
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { signal, computed, linkedSignal, untracked } from '@angular/core';
|
|
2
2
|
|
|
3
3
|
var Modifier;
|
|
4
4
|
(function (Modifier) {
|
|
@@ -46,23 +46,28 @@ class KeyboardEventManager extends EventManager {
|
|
|
46
46
|
const {
|
|
47
47
|
modifiers,
|
|
48
48
|
key,
|
|
49
|
-
handler
|
|
49
|
+
handler,
|
|
50
|
+
options
|
|
50
51
|
} = this._normalizeInputs(...args);
|
|
51
52
|
this.configs.push({
|
|
52
53
|
handler: handler,
|
|
53
54
|
matcher: event => this._isMatch(event, key, modifiers),
|
|
54
|
-
...this.options
|
|
55
|
+
...this.options,
|
|
56
|
+
...options
|
|
55
57
|
});
|
|
56
58
|
return this;
|
|
57
59
|
}
|
|
58
60
|
_normalizeInputs(...args) {
|
|
59
|
-
const
|
|
60
|
-
const
|
|
61
|
-
const
|
|
61
|
+
const withModifiers = Array.isArray(args[0]) || args[0] in Modifier;
|
|
62
|
+
const modifiers = withModifiers ? args[0] : Modifier.None;
|
|
63
|
+
const key = withModifiers ? args[1] : args[0];
|
|
64
|
+
const handler = withModifiers ? args[2] : args[1];
|
|
65
|
+
const options = withModifiers ? args[3] : args[2];
|
|
62
66
|
return {
|
|
63
67
|
key: key,
|
|
64
68
|
handler: handler,
|
|
65
|
-
modifiers: modifiers
|
|
69
|
+
modifiers: modifiers,
|
|
70
|
+
options: options ?? {}
|
|
66
71
|
};
|
|
67
72
|
}
|
|
68
73
|
_isMatch(event, key, modifiers) {
|
|
@@ -127,10 +132,121 @@ class PointerEventManager extends EventManager {
|
|
|
127
132
|
}
|
|
128
133
|
}
|
|
129
134
|
|
|
135
|
+
class ListFocus {
|
|
136
|
+
inputs;
|
|
137
|
+
prevActiveItem = signal(undefined);
|
|
138
|
+
prevActiveIndex = computed(() => {
|
|
139
|
+
return this.prevActiveItem() ? this.inputs.items().indexOf(this.prevActiveItem()) : -1;
|
|
140
|
+
});
|
|
141
|
+
activeIndex = computed(() => {
|
|
142
|
+
return this.inputs.activeItem() ? this.inputs.items().indexOf(this.inputs.activeItem()) : -1;
|
|
143
|
+
});
|
|
144
|
+
constructor(inputs) {
|
|
145
|
+
this.inputs = inputs;
|
|
146
|
+
}
|
|
147
|
+
isListDisabled() {
|
|
148
|
+
return this.inputs.disabled() || this.inputs.items().every(i => i.disabled());
|
|
149
|
+
}
|
|
150
|
+
getActiveDescendant() {
|
|
151
|
+
if (this.isListDisabled()) {
|
|
152
|
+
return undefined;
|
|
153
|
+
}
|
|
154
|
+
if (this.inputs.focusMode() === 'roving') {
|
|
155
|
+
return undefined;
|
|
156
|
+
}
|
|
157
|
+
return this.inputs.activeItem()?.id() ?? undefined;
|
|
158
|
+
}
|
|
159
|
+
getListTabIndex() {
|
|
160
|
+
if (this.isListDisabled()) {
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
return this.inputs.focusMode() === 'activedescendant' ? 0 : -1;
|
|
164
|
+
}
|
|
165
|
+
getItemTabIndex(item) {
|
|
166
|
+
if (this.isListDisabled()) {
|
|
167
|
+
return -1;
|
|
168
|
+
}
|
|
169
|
+
if (this.inputs.focusMode() === 'activedescendant') {
|
|
170
|
+
return -1;
|
|
171
|
+
}
|
|
172
|
+
return this.inputs.activeItem() === item ? 0 : -1;
|
|
173
|
+
}
|
|
174
|
+
focus(item, opts) {
|
|
175
|
+
if (this.isListDisabled() || !this.isFocusable(item)) {
|
|
176
|
+
return false;
|
|
177
|
+
}
|
|
178
|
+
this.prevActiveItem.set(this.inputs.activeItem());
|
|
179
|
+
this.inputs.activeItem.set(item);
|
|
180
|
+
if (opts?.focusElement || opts?.focusElement === undefined) {
|
|
181
|
+
this.inputs.focusMode() === 'roving' ? item.element()?.focus() : this.inputs.element()?.focus();
|
|
182
|
+
}
|
|
183
|
+
return true;
|
|
184
|
+
}
|
|
185
|
+
isFocusable(item) {
|
|
186
|
+
return !item.disabled() || this.inputs.softDisabled();
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
class ListNavigation {
|
|
191
|
+
inputs;
|
|
192
|
+
constructor(inputs) {
|
|
193
|
+
this.inputs = inputs;
|
|
194
|
+
}
|
|
195
|
+
goto(item, opts) {
|
|
196
|
+
return item ? this.inputs.focusManager.focus(item, opts) : false;
|
|
197
|
+
}
|
|
198
|
+
next(opts) {
|
|
199
|
+
return this._advance(1, opts);
|
|
200
|
+
}
|
|
201
|
+
peekNext() {
|
|
202
|
+
return this._peek(1);
|
|
203
|
+
}
|
|
204
|
+
prev(opts) {
|
|
205
|
+
return this._advance(-1, opts);
|
|
206
|
+
}
|
|
207
|
+
peekPrev() {
|
|
208
|
+
return this._peek(-1);
|
|
209
|
+
}
|
|
210
|
+
first(opts) {
|
|
211
|
+
const item = this.peekFirst();
|
|
212
|
+
return item ? this.goto(item, opts) : false;
|
|
213
|
+
}
|
|
214
|
+
last(opts) {
|
|
215
|
+
const item = this.peekLast();
|
|
216
|
+
return item ? this.goto(item, opts) : false;
|
|
217
|
+
}
|
|
218
|
+
peekFirst(items = this.inputs.items()) {
|
|
219
|
+
return items.find(i => this.inputs.focusManager.isFocusable(i));
|
|
220
|
+
}
|
|
221
|
+
peekLast(items = this.inputs.items()) {
|
|
222
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
223
|
+
if (this.inputs.focusManager.isFocusable(items[i])) {
|
|
224
|
+
return items[i];
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
_advance(delta, opts) {
|
|
230
|
+
const item = this._peek(delta);
|
|
231
|
+
return item ? this.goto(item, opts) : false;
|
|
232
|
+
}
|
|
233
|
+
_peek(delta) {
|
|
234
|
+
const items = this.inputs.items();
|
|
235
|
+
const itemCount = items.length;
|
|
236
|
+
const startIndex = this.inputs.focusManager.activeIndex();
|
|
237
|
+
const step = i => this.inputs.wrap() ? (i + delta + itemCount) % itemCount : i + delta;
|
|
238
|
+
for (let i = step(startIndex); i !== startIndex && i < itemCount && i >= 0; i = step(i)) {
|
|
239
|
+
if (this.inputs.focusManager.isFocusable(items[i])) {
|
|
240
|
+
return items[i];
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
|
|
130
247
|
class GridData {
|
|
131
248
|
inputs;
|
|
132
249
|
cells;
|
|
133
|
-
rowCount = computed(() => this.cells().length);
|
|
134
250
|
maxRowCount = computed(() => Math.max(...this._rowCountByCol().values(), 0));
|
|
135
251
|
maxColCount = computed(() => Math.max(...this._colCountsByRow().values(), 0));
|
|
136
252
|
_coordsMap = computed(() => {
|
|
@@ -220,6 +336,9 @@ class GridData {
|
|
|
220
336
|
this.inputs = inputs;
|
|
221
337
|
this.cells = this.inputs.cells;
|
|
222
338
|
}
|
|
339
|
+
hasCell(cell) {
|
|
340
|
+
return this._coordsMap().has(cell);
|
|
341
|
+
}
|
|
223
342
|
getCell(rowCol) {
|
|
224
343
|
return this._cellMap().get(`${rowCol.row}:${rowCol.col}`);
|
|
225
344
|
}
|
|
@@ -280,7 +399,7 @@ class GridFocus {
|
|
|
280
399
|
constructor(inputs) {
|
|
281
400
|
this.inputs = inputs;
|
|
282
401
|
}
|
|
283
|
-
|
|
402
|
+
getCellTabIndex(cell) {
|
|
284
403
|
if (this.gridDisabled()) {
|
|
285
404
|
return -1;
|
|
286
405
|
}
|
|
@@ -290,7 +409,7 @@ class GridFocus {
|
|
|
290
409
|
return this.activeCell() === cell ? 0 : -1;
|
|
291
410
|
}
|
|
292
411
|
isFocusable(cell) {
|
|
293
|
-
return !cell.disabled() ||
|
|
412
|
+
return this.inputs.grid.hasCell(cell) && (!cell.disabled() || this.inputs.softDisabled());
|
|
294
413
|
}
|
|
295
414
|
focusCell(cell) {
|
|
296
415
|
if (this.gridDisabled()) {
|
|
@@ -349,37 +468,38 @@ class GridNavigation {
|
|
|
349
468
|
gotoCoords(coords) {
|
|
350
469
|
return this.inputs.gridFocus.focusCoordinates(coords);
|
|
351
470
|
}
|
|
352
|
-
peek(direction, fromCoords, wrap) {
|
|
471
|
+
peek(direction, fromCoords, wrap, allowDisabled) {
|
|
353
472
|
wrap = wrap ?? (direction.row !== undefined ? this.inputs.rowWrap() : this.inputs.colWrap());
|
|
354
|
-
return this._peekDirectional(direction, fromCoords, wrap);
|
|
473
|
+
return this._peekDirectional(direction, fromCoords, wrap, allowDisabled);
|
|
355
474
|
}
|
|
356
475
|
advance(direction) {
|
|
357
476
|
const nextCoords = this.peek(direction, this.inputs.gridFocus.activeCoords());
|
|
358
477
|
return !!nextCoords && this.gotoCoords(nextCoords);
|
|
359
478
|
}
|
|
360
|
-
peekFirst(row) {
|
|
479
|
+
peekFirst(row, allowDisabled) {
|
|
361
480
|
const fromCoords = {
|
|
362
481
|
row: row ?? 0,
|
|
363
482
|
col: -1
|
|
364
483
|
};
|
|
365
|
-
return row === undefined ? this._peekDirectional(direction.Right, fromCoords, 'continuous') : this._peekDirectional(direction.Right, fromCoords, 'nowrap');
|
|
484
|
+
return row === undefined ? this._peekDirectional(direction.Right, fromCoords, 'continuous', allowDisabled) : this._peekDirectional(direction.Right, fromCoords, 'nowrap', allowDisabled);
|
|
366
485
|
}
|
|
367
486
|
first(row) {
|
|
368
487
|
const nextCoords = this.peekFirst(row);
|
|
369
488
|
return !!nextCoords && this.gotoCoords(nextCoords);
|
|
370
489
|
}
|
|
371
|
-
peekLast(row) {
|
|
490
|
+
peekLast(row, allowDisabled) {
|
|
372
491
|
const fromCoords = {
|
|
373
492
|
row: row ?? this.inputs.grid.maxRowCount() - 1,
|
|
374
493
|
col: this.inputs.grid.maxColCount()
|
|
375
494
|
};
|
|
376
|
-
return row === undefined ? this._peekDirectional(direction.Left, fromCoords, 'continuous') : this._peekDirectional(direction.Left, fromCoords, 'nowrap');
|
|
495
|
+
return row === undefined ? this._peekDirectional(direction.Left, fromCoords, 'continuous', allowDisabled) : this._peekDirectional(direction.Left, fromCoords, 'nowrap', allowDisabled);
|
|
377
496
|
}
|
|
378
497
|
last(row) {
|
|
379
498
|
const nextCoords = this.peekLast(row);
|
|
380
499
|
return !!nextCoords && this.gotoCoords(nextCoords);
|
|
381
500
|
}
|
|
382
|
-
_peekDirectional(delta, fromCoords, wrap) {
|
|
501
|
+
_peekDirectional(delta, fromCoords, wrap, allowDisabled = false) {
|
|
502
|
+
if (this.inputs.gridFocus.gridDisabled()) return undefined;
|
|
383
503
|
const fromCell = this.inputs.grid.getCell(fromCoords);
|
|
384
504
|
const maxRowCount = this.inputs.grid.maxRowCount();
|
|
385
505
|
const maxColCount = this.inputs.grid.maxColCount();
|
|
@@ -390,11 +510,13 @@ class GridNavigation {
|
|
|
390
510
|
};
|
|
391
511
|
for (let step = 0; step < this._maxSteps(); step++) {
|
|
392
512
|
const isWrapping = nextCoords.col + colDelta < 0 || nextCoords.col + colDelta >= maxColCount || nextCoords.row + rowDelta < 0 || nextCoords.row + rowDelta >= maxRowCount;
|
|
393
|
-
if (wrap === 'nowrap' && isWrapping) return;
|
|
513
|
+
if (wrap === 'nowrap' && isWrapping) return undefined;
|
|
394
514
|
if (wrap === 'continuous') {
|
|
395
515
|
const generalDelta = delta.row ?? delta.col;
|
|
396
516
|
const rowStep = isWrapping ? generalDelta : rowDelta;
|
|
397
517
|
const colStep = isWrapping ? generalDelta : colDelta;
|
|
518
|
+
const bothWrapping = nextCoords.row + rowStep >= maxRowCount && nextCoords.col + colStep >= maxColCount || nextCoords.row + rowStep < 0 && nextCoords.col + colStep < 0;
|
|
519
|
+
if (bothWrapping) return undefined;
|
|
398
520
|
nextCoords = {
|
|
399
521
|
row: (nextCoords.row + rowStep + maxRowCount) % maxRowCount,
|
|
400
522
|
col: (nextCoords.col + colStep + maxColCount) % maxColCount
|
|
@@ -406,11 +528,17 @@ class GridNavigation {
|
|
|
406
528
|
col: (nextCoords.col + colDelta + maxColCount) % maxColCount
|
|
407
529
|
};
|
|
408
530
|
}
|
|
531
|
+
if (wrap === 'nowrap') {
|
|
532
|
+
nextCoords = {
|
|
533
|
+
row: nextCoords.row + rowDelta,
|
|
534
|
+
col: nextCoords.col + colDelta
|
|
535
|
+
};
|
|
536
|
+
}
|
|
409
537
|
if (nextCoords.row === fromCoords.row && nextCoords.col === fromCoords.col) {
|
|
410
538
|
return undefined;
|
|
411
539
|
}
|
|
412
540
|
const nextCell = this.inputs.grid.getCell(nextCoords);
|
|
413
|
-
if (nextCell !== undefined && nextCell !== fromCell && this.inputs.gridFocus.isFocusable(nextCell)) {
|
|
541
|
+
if (nextCell !== undefined && nextCell !== fromCell && (allowDisabled || this.inputs.gridFocus.isFocusable(nextCell))) {
|
|
414
542
|
return nextCoords;
|
|
415
543
|
}
|
|
416
544
|
}
|
|
@@ -420,45 +548,45 @@ class GridNavigation {
|
|
|
420
548
|
|
|
421
549
|
class GridSelection {
|
|
422
550
|
inputs;
|
|
551
|
+
_undoList = signal([]);
|
|
423
552
|
constructor(inputs) {
|
|
424
553
|
this.inputs = inputs;
|
|
425
554
|
}
|
|
426
|
-
|
|
427
|
-
for (const cell of this.
|
|
428
|
-
cell.selected.set(
|
|
555
|
+
undo() {
|
|
556
|
+
for (const [cell, oldState] of this._undoList()) {
|
|
557
|
+
cell.selected.set(oldState);
|
|
429
558
|
}
|
|
559
|
+
this._undoList.set([]);
|
|
560
|
+
}
|
|
561
|
+
select(fromCoords, toCoords) {
|
|
562
|
+
this._updateState(fromCoords, toCoords ?? fromCoords, () => true);
|
|
430
563
|
}
|
|
431
564
|
deselect(fromCoords, toCoords) {
|
|
432
|
-
|
|
433
|
-
cell.selected.set(false);
|
|
434
|
-
}
|
|
565
|
+
this._updateState(fromCoords, toCoords ?? fromCoords, () => false);
|
|
435
566
|
}
|
|
436
567
|
toggle(fromCoords, toCoords) {
|
|
437
|
-
|
|
438
|
-
cell.selected.update(state => !state);
|
|
439
|
-
}
|
|
568
|
+
this._updateState(fromCoords, toCoords ?? fromCoords, oldState => !oldState);
|
|
440
569
|
}
|
|
441
570
|
selectAll() {
|
|
442
|
-
|
|
571
|
+
this._updateState({
|
|
443
572
|
row: 0,
|
|
444
573
|
col: 0
|
|
445
574
|
}, {
|
|
446
575
|
row: this.inputs.grid.maxRowCount(),
|
|
447
576
|
col: this.inputs.grid.maxColCount()
|
|
448
|
-
}))
|
|
449
|
-
cell.selected.set(true);
|
|
450
|
-
}
|
|
577
|
+
}, () => true);
|
|
451
578
|
}
|
|
452
579
|
deselectAll() {
|
|
453
|
-
|
|
580
|
+
this._updateState({
|
|
454
581
|
row: 0,
|
|
455
582
|
col: 0
|
|
456
583
|
}, {
|
|
457
584
|
row: this.inputs.grid.maxRowCount(),
|
|
458
585
|
col: this.inputs.grid.maxColCount()
|
|
459
|
-
}))
|
|
460
|
-
|
|
461
|
-
|
|
586
|
+
}, () => false);
|
|
587
|
+
}
|
|
588
|
+
isSelectable(cell) {
|
|
589
|
+
return cell.selectable() && !cell.disabled();
|
|
462
590
|
}
|
|
463
591
|
*_validCells(fromCoords, toCoords) {
|
|
464
592
|
const startRow = Math.min(fromCoords.row, toCoords.row);
|
|
@@ -473,14 +601,22 @@ class GridSelection {
|
|
|
473
601
|
col
|
|
474
602
|
});
|
|
475
603
|
if (cell === undefined) continue;
|
|
476
|
-
if (!
|
|
477
|
-
if (cell.disabled()) continue;
|
|
604
|
+
if (!this.isSelectable(cell)) continue;
|
|
478
605
|
if (visited.has(cell)) continue;
|
|
479
606
|
visited.add(cell);
|
|
480
607
|
yield cell;
|
|
481
608
|
}
|
|
482
609
|
}
|
|
483
610
|
}
|
|
611
|
+
_updateState(fromCoords, toCoords, stateFn) {
|
|
612
|
+
const undoList = [];
|
|
613
|
+
for (const cell of this._validCells(fromCoords, toCoords)) {
|
|
614
|
+
const oldState = cell.selected();
|
|
615
|
+
undoList.push([cell, oldState]);
|
|
616
|
+
cell.selected.set(stateFn(oldState));
|
|
617
|
+
}
|
|
618
|
+
this._undoList.set(undoList);
|
|
619
|
+
}
|
|
484
620
|
}
|
|
485
621
|
|
|
486
622
|
class Grid {
|
|
@@ -490,9 +626,12 @@ class Grid {
|
|
|
490
626
|
navigationBehavior;
|
|
491
627
|
selectionBehavior;
|
|
492
628
|
selectionAnchor = linkedSignal(() => this.focusBehavior.activeCoords());
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
629
|
+
selectionAnchorCell = computed(() => this.data.getCell(this.selectionAnchor()));
|
|
630
|
+
selectionStabled = signal(true);
|
|
631
|
+
allSelected = computed(() => this.data.cells().flat().filter(c => this.selectionBehavior.isSelectable(c)).every(c => c.selected()));
|
|
632
|
+
gridTabIndex = () => this.focusBehavior.gridTabIndex();
|
|
633
|
+
gridDisabled = () => this.focusBehavior.gridDisabled();
|
|
634
|
+
activeDescendant = () => this.focusBehavior.activeDescendant();
|
|
496
635
|
constructor(inputs) {
|
|
497
636
|
this.inputs = inputs;
|
|
498
637
|
this.data = new GridData(inputs);
|
|
@@ -520,51 +659,33 @@ class Grid {
|
|
|
520
659
|
return index !== undefined ? index + 1 : undefined;
|
|
521
660
|
}
|
|
522
661
|
cellTabIndex(cell) {
|
|
523
|
-
return this.focusBehavior.
|
|
524
|
-
}
|
|
525
|
-
up() {
|
|
526
|
-
return this.navigationBehavior.advance(direction.Up);
|
|
527
|
-
}
|
|
528
|
-
rangeSelectUp() {
|
|
529
|
-
const coords = this.navigationBehavior.peek(direction.Up, this.selectionAnchor());
|
|
530
|
-
if (coords === undefined) return;
|
|
531
|
-
this._rangeSelectCoords(coords);
|
|
532
|
-
}
|
|
533
|
-
down() {
|
|
534
|
-
return this.navigationBehavior.advance(direction.Down);
|
|
662
|
+
return this.focusBehavior.getCellTabIndex(cell);
|
|
535
663
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
if (coords === undefined) return;
|
|
539
|
-
this._rangeSelectCoords(coords);
|
|
664
|
+
up(opts = {}) {
|
|
665
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peek(direction.Up, this.selectionAnchor(), 'nowrap', true)) : this.navigationBehavior.advance(direction.Up), opts);
|
|
540
666
|
}
|
|
541
|
-
|
|
542
|
-
return this.navigationBehavior.advance(direction.
|
|
667
|
+
down(opts = {}) {
|
|
668
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peek(direction.Down, this.selectionAnchor(), 'nowrap', true)) : this.navigationBehavior.advance(direction.Down), opts);
|
|
543
669
|
}
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
if (coords === undefined) return;
|
|
547
|
-
this._rangeSelectCoords(coords);
|
|
670
|
+
left(opts = {}) {
|
|
671
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peek(direction.Left, this.selectionAnchor(), 'nowrap', true)) : this.navigationBehavior.advance(direction.Left), opts);
|
|
548
672
|
}
|
|
549
|
-
right() {
|
|
550
|
-
return this.navigationBehavior.advance(direction.Right);
|
|
673
|
+
right(opts = {}) {
|
|
674
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peek(direction.Right, this.selectionAnchor(), 'nowrap', true)) : this.navigationBehavior.advance(direction.Right), opts);
|
|
551
675
|
}
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
if (coords === undefined) return;
|
|
555
|
-
this._rangeSelectCoords(coords);
|
|
676
|
+
first(opts = {}) {
|
|
677
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peekFirst(undefined, true)) : this.navigationBehavior.first(), opts);
|
|
556
678
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
firstInRow() {
|
|
561
|
-
return this.navigationBehavior.first(this.focusBehavior.activeCoords().row);
|
|
679
|
+
firstInRow(opts = {}) {
|
|
680
|
+
const row = this.focusBehavior.activeCoords().row;
|
|
681
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peekFirst(row, true)) : this.navigationBehavior.first(row), opts);
|
|
562
682
|
}
|
|
563
|
-
last() {
|
|
564
|
-
return this.navigationBehavior.last();
|
|
683
|
+
last(opts = {}) {
|
|
684
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peekLast(undefined, true)) : this.navigationBehavior.last(), opts);
|
|
565
685
|
}
|
|
566
|
-
lastInRow() {
|
|
567
|
-
|
|
686
|
+
lastInRow(opts = {}) {
|
|
687
|
+
const row = this.focusBehavior.activeCoords().row;
|
|
688
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peekLast(row, true)) : this.navigationBehavior.last(row), opts);
|
|
568
689
|
}
|
|
569
690
|
selectRow() {
|
|
570
691
|
const row = this.focusBehavior.activeCoords().row;
|
|
@@ -588,50 +709,48 @@ class Grid {
|
|
|
588
709
|
col
|
|
589
710
|
});
|
|
590
711
|
}
|
|
591
|
-
|
|
592
|
-
this.selectionBehavior.
|
|
712
|
+
select() {
|
|
713
|
+
this.selectionBehavior.select(this.focusBehavior.activeCoords());
|
|
593
714
|
}
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
if (coords === undefined) return;
|
|
605
|
-
this._rangeSelectCoords(coords);
|
|
606
|
-
}
|
|
607
|
-
_rangeSelectCoords(coords) {
|
|
608
|
-
const activeCell = this.focusBehavior.activeCell();
|
|
609
|
-
const anchorCell = this.data.getCell(coords);
|
|
610
|
-
if (activeCell === undefined || anchorCell === undefined) {
|
|
715
|
+
deselect() {
|
|
716
|
+
this.selectionBehavior.deselect(this.focusBehavior.activeCoords());
|
|
717
|
+
}
|
|
718
|
+
toggle() {
|
|
719
|
+
this.selectionBehavior.toggle(this.focusBehavior.activeCoords());
|
|
720
|
+
}
|
|
721
|
+
toggleOne() {
|
|
722
|
+
const selected = !!this.focusBehavior.activeCell()?.selected();
|
|
723
|
+
if (selected) {
|
|
724
|
+
this.deselect();
|
|
611
725
|
return;
|
|
612
726
|
}
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
const toCoords = {
|
|
621
|
-
row: Math.max(...allRows),
|
|
622
|
-
col: Math.max(...allCols)
|
|
623
|
-
};
|
|
727
|
+
this.deselectAll();
|
|
728
|
+
this.select();
|
|
729
|
+
}
|
|
730
|
+
selectAll() {
|
|
731
|
+
this.selectionBehavior.selectAll();
|
|
732
|
+
}
|
|
733
|
+
deselectAll() {
|
|
624
734
|
this.selectionBehavior.deselectAll();
|
|
625
|
-
|
|
626
|
-
|
|
735
|
+
}
|
|
736
|
+
gotoCell(cell, opts = {}) {
|
|
737
|
+
return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.data.getCoords(cell)) : this.navigationBehavior.gotoCell(cell), opts);
|
|
738
|
+
}
|
|
739
|
+
setDefaultState() {
|
|
740
|
+
const focusableSelectedCell = this.data.cells().flat().filter(c => this.focusBehavior.isFocusable(c)).find(c => c.selected());
|
|
741
|
+
if (focusableSelectedCell !== undefined) {
|
|
742
|
+
this.focusBehavior.focusCell(focusableSelectedCell);
|
|
743
|
+
return true;
|
|
744
|
+
}
|
|
745
|
+
const firstFocusableCoords = this.navigationBehavior.peekFirst();
|
|
746
|
+
if (firstFocusableCoords !== undefined) {
|
|
747
|
+
return this.focusBehavior.focusCoordinates(firstFocusableCoords);
|
|
748
|
+
}
|
|
749
|
+
return false;
|
|
627
750
|
}
|
|
628
751
|
resetState() {
|
|
629
752
|
if (this.focusBehavior.stateEmpty()) {
|
|
630
|
-
|
|
631
|
-
if (firstFocusableCoords === undefined) {
|
|
632
|
-
return false;
|
|
633
|
-
}
|
|
634
|
-
return this.focusBehavior.focusCoordinates(firstFocusableCoords);
|
|
753
|
+
return this.setDefaultState();
|
|
635
754
|
}
|
|
636
755
|
if (this.focusBehavior.stateStale()) {
|
|
637
756
|
if (this.focusBehavior.focusCell(this.focusBehavior.activeCell())) {
|
|
@@ -646,6 +765,67 @@ class Grid {
|
|
|
646
765
|
}
|
|
647
766
|
return false;
|
|
648
767
|
}
|
|
768
|
+
_updateSelectionAnchor(peekFn) {
|
|
769
|
+
const coords = peekFn();
|
|
770
|
+
const success = coords !== undefined;
|
|
771
|
+
if (!success) return false;
|
|
772
|
+
this.selectionAnchor.set(coords);
|
|
773
|
+
return success;
|
|
774
|
+
}
|
|
775
|
+
_updateRangeSelection() {
|
|
776
|
+
if (!this.selectionStabled()) {
|
|
777
|
+
this.selectionBehavior.undo();
|
|
778
|
+
}
|
|
779
|
+
this.selectionBehavior.select(...this._getSelectionCoords(this.focusBehavior.activeCoords(), this.selectionAnchor()));
|
|
780
|
+
}
|
|
781
|
+
_getSelectionCoords(startCoords, endCoords) {
|
|
782
|
+
const startCell = this.data.getCell(startCoords);
|
|
783
|
+
const endCell = this.data.getCell(endCoords);
|
|
784
|
+
const allCoords = [...this.data.getAllCoords(startCell), ...this.data.getAllCoords(endCell)];
|
|
785
|
+
const allRows = allCoords.map(c => c.row);
|
|
786
|
+
const allCols = allCoords.map(c => c.col);
|
|
787
|
+
const fromCoords = {
|
|
788
|
+
row: Math.min(...allRows),
|
|
789
|
+
col: Math.min(...allCols)
|
|
790
|
+
};
|
|
791
|
+
const toCoords = {
|
|
792
|
+
row: Math.max(...allRows),
|
|
793
|
+
col: Math.max(...allCols)
|
|
794
|
+
};
|
|
795
|
+
return [fromCoords, toCoords];
|
|
796
|
+
}
|
|
797
|
+
_navigateWithSelection(op, opts = {}) {
|
|
798
|
+
const success = op();
|
|
799
|
+
if (!success) return false;
|
|
800
|
+
if (opts.anchor) {
|
|
801
|
+
this._updateRangeSelection();
|
|
802
|
+
this.selectionStabled.set(false);
|
|
803
|
+
return success;
|
|
804
|
+
}
|
|
805
|
+
this.selectionStabled.set(true);
|
|
806
|
+
if (opts.select) {
|
|
807
|
+
this.select();
|
|
808
|
+
return success;
|
|
809
|
+
}
|
|
810
|
+
if (opts.selectOne) {
|
|
811
|
+
this.deselectAll();
|
|
812
|
+
this.select();
|
|
813
|
+
return success;
|
|
814
|
+
}
|
|
815
|
+
if (opts.toggle) {
|
|
816
|
+
this.toggle();
|
|
817
|
+
return success;
|
|
818
|
+
}
|
|
819
|
+
if (opts.toggleOne) {
|
|
820
|
+
const selected = !!this.focusBehavior.activeCell()?.selected();
|
|
821
|
+
this.deselectAll();
|
|
822
|
+
if (!selected) {
|
|
823
|
+
this.select();
|
|
824
|
+
}
|
|
825
|
+
return success;
|
|
826
|
+
}
|
|
827
|
+
return success;
|
|
828
|
+
}
|
|
649
829
|
}
|
|
650
830
|
|
|
651
831
|
class GridPattern {
|
|
@@ -656,53 +836,111 @@ class GridPattern {
|
|
|
656
836
|
disabled = computed(() => this.gridBehavior.gridDisabled());
|
|
657
837
|
activeDescendant = computed(() => this.gridBehavior.activeDescendant());
|
|
658
838
|
activeCell = computed(() => this.gridBehavior.focusBehavior.activeCell());
|
|
659
|
-
|
|
839
|
+
anchorCell = computed(() => this.inputs.enableSelection() && this.inputs.multi() ? this.gridBehavior.selectionAnchorCell() : undefined);
|
|
840
|
+
pauseNavigation = computed(() => this.gridBehavior.data.cells().flat().reduce((res, c) => res || c.isActivated(), false));
|
|
660
841
|
isFocused = signal(false);
|
|
842
|
+
hasBeenFocused = signal(false);
|
|
661
843
|
dragging = signal(false);
|
|
844
|
+
prevColKey = computed(() => this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft');
|
|
845
|
+
nextColKey = computed(() => this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight');
|
|
662
846
|
keydown = computed(() => {
|
|
663
847
|
const manager = new KeyboardEventManager();
|
|
664
848
|
if (this.pauseNavigation()) {
|
|
665
849
|
return manager;
|
|
666
850
|
}
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
851
|
+
const opts = {
|
|
852
|
+
selectOne: this.inputs.enableSelection() && this.inputs.selectionMode() === 'follow'
|
|
853
|
+
};
|
|
854
|
+
manager.on('ArrowUp', () => this.gridBehavior.up(opts)).on('ArrowDown', () => this.gridBehavior.down(opts)).on(this.prevColKey(), () => this.gridBehavior.left(opts)).on(this.nextColKey(), () => this.gridBehavior.right(opts)).on('Home', () => this.gridBehavior.firstInRow(opts)).on('End', () => this.gridBehavior.lastInRow(opts)).on([Modifier.Ctrl], 'Home', () => this.gridBehavior.first(opts)).on([Modifier.Ctrl], 'End', () => this.gridBehavior.last(opts));
|
|
855
|
+
if (this.inputs.enableSelection() && this.inputs.selectionMode() === 'explicit') {
|
|
856
|
+
manager.on(/Enter| /, () => this.inputs.multi() ? this.gridBehavior.toggle() : this.gridBehavior.toggleOne());
|
|
857
|
+
}
|
|
858
|
+
if (this.inputs.enableSelection() && this.inputs.enableRangeSelection()) {
|
|
859
|
+
manager.on(Modifier.Shift, 'ArrowUp', () => this.gridBehavior.up({
|
|
860
|
+
anchor: true
|
|
861
|
+
})).on(Modifier.Shift, 'ArrowDown', () => this.gridBehavior.down({
|
|
862
|
+
anchor: true
|
|
863
|
+
})).on(Modifier.Shift, this.prevColKey(), () => this.gridBehavior.left({
|
|
864
|
+
anchor: true
|
|
865
|
+
})).on(Modifier.Shift, this.nextColKey(), () => this.gridBehavior.right({
|
|
866
|
+
anchor: true
|
|
867
|
+
})).on(Modifier.Shift, 'Home', () => this.gridBehavior.firstInRow({
|
|
868
|
+
anchor: true
|
|
869
|
+
})).on(Modifier.Shift, 'End', () => this.gridBehavior.lastInRow({
|
|
870
|
+
anchor: true
|
|
871
|
+
})).on([Modifier.Ctrl | Modifier.Shift], 'Home', () => this.gridBehavior.first({
|
|
872
|
+
anchor: true
|
|
873
|
+
})).on([Modifier.Ctrl | Modifier.Shift], 'End', () => this.gridBehavior.last({
|
|
874
|
+
anchor: true
|
|
875
|
+
})).on([Modifier.Ctrl, Modifier.Meta], 'A', () => {
|
|
876
|
+
if (this.gridBehavior.allSelected()) {
|
|
877
|
+
this.gridBehavior.deselectAll();
|
|
878
|
+
} else {
|
|
879
|
+
this.gridBehavior.selectAll();
|
|
880
|
+
}
|
|
881
|
+
}).on([Modifier.Shift], ' ', () => this.gridBehavior.selectRow()).on([Modifier.Ctrl, Modifier.Meta], ' ', () => this.gridBehavior.selectCol());
|
|
670
882
|
}
|
|
671
883
|
return manager;
|
|
672
884
|
});
|
|
673
885
|
pointerdown = computed(() => {
|
|
674
886
|
const manager = new PointerEventManager();
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
if (!cell) return;
|
|
678
|
-
this.gridBehavior.gotoCell(cell);
|
|
679
|
-
if (this.inputs.enableSelection()) {
|
|
680
|
-
this.dragging.set(true);
|
|
681
|
-
}
|
|
682
|
-
});
|
|
683
|
-
if (this.inputs.enableSelection()) {
|
|
684
|
-
manager.on([Modifier.Ctrl, Modifier.Meta], e => {
|
|
887
|
+
if (!this.inputs.enableSelection()) {
|
|
888
|
+
manager.on(e => {
|
|
685
889
|
const cell = this.inputs.getCell(e.target);
|
|
686
|
-
if (!cell) return;
|
|
687
|
-
this.gridBehavior.
|
|
688
|
-
})
|
|
890
|
+
if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return;
|
|
891
|
+
this.gridBehavior.gotoCell(cell);
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
if (this.inputs.enableSelection()) {
|
|
895
|
+
manager.on(e => {
|
|
689
896
|
const cell = this.inputs.getCell(e.target);
|
|
690
|
-
if (!cell) return;
|
|
691
|
-
this.gridBehavior.
|
|
692
|
-
|
|
897
|
+
if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return;
|
|
898
|
+
this.gridBehavior.gotoCell(cell, {
|
|
899
|
+
selectOne: this.inputs.selectionMode() === 'follow',
|
|
900
|
+
toggleOne: this.inputs.selectionMode() === 'explicit' && !this.inputs.multi(),
|
|
901
|
+
toggle: this.inputs.selectionMode() === 'explicit' && this.inputs.multi()
|
|
902
|
+
});
|
|
903
|
+
if (this.inputs.multi() && this.inputs.enableRangeSelection()) {
|
|
904
|
+
this.dragging.set(true);
|
|
905
|
+
}
|
|
693
906
|
});
|
|
907
|
+
if (this.inputs.multi()) {
|
|
908
|
+
manager.on([Modifier.Ctrl, Modifier.Meta], e => {
|
|
909
|
+
const cell = this.inputs.getCell(e.target);
|
|
910
|
+
if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return;
|
|
911
|
+
this.gridBehavior.gotoCell(cell, {
|
|
912
|
+
toggle: true
|
|
913
|
+
});
|
|
914
|
+
if (this.inputs.enableRangeSelection()) {
|
|
915
|
+
this.dragging.set(true);
|
|
916
|
+
}
|
|
917
|
+
});
|
|
918
|
+
if (this.inputs.enableRangeSelection()) {
|
|
919
|
+
manager.on(Modifier.Shift, e => {
|
|
920
|
+
const cell = this.inputs.getCell(e.target);
|
|
921
|
+
if (!cell) return;
|
|
922
|
+
this.gridBehavior.gotoCell(cell, {
|
|
923
|
+
anchor: true
|
|
924
|
+
});
|
|
925
|
+
this.dragging.set(true);
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
}
|
|
694
929
|
}
|
|
695
930
|
return manager;
|
|
696
931
|
});
|
|
697
932
|
pointerup = computed(() => {
|
|
698
933
|
const manager = new PointerEventManager();
|
|
699
|
-
if (this.inputs.enableSelection()) {
|
|
700
|
-
manager.on([Modifier.Shift, Modifier.None], () => {
|
|
934
|
+
if (this.inputs.enableSelection() && this.inputs.enableRangeSelection()) {
|
|
935
|
+
manager.on([Modifier.Shift, Modifier.Ctrl, Modifier.Meta, Modifier.None], () => {
|
|
701
936
|
this.dragging.set(false);
|
|
702
937
|
});
|
|
703
938
|
}
|
|
704
939
|
return manager;
|
|
705
940
|
});
|
|
941
|
+
_maybeDeletion = signal(false);
|
|
942
|
+
_deletion = signal(false);
|
|
943
|
+
_stateStale = signal(false);
|
|
706
944
|
constructor(inputs) {
|
|
707
945
|
this.inputs = inputs;
|
|
708
946
|
this.gridBehavior = new Grid({
|
|
@@ -711,65 +949,100 @@ class GridPattern {
|
|
|
711
949
|
});
|
|
712
950
|
}
|
|
713
951
|
onKeydown(event) {
|
|
714
|
-
if (
|
|
715
|
-
|
|
716
|
-
|
|
952
|
+
if (this.disabled()) return;
|
|
953
|
+
this.activeCell()?.onKeydown(event);
|
|
954
|
+
this.keydown().handle(event);
|
|
717
955
|
}
|
|
718
956
|
onPointerdown(event) {
|
|
719
|
-
if (
|
|
720
|
-
|
|
721
|
-
}
|
|
957
|
+
if (this.disabled()) return;
|
|
958
|
+
this.pointerdown().handle(event);
|
|
722
959
|
}
|
|
723
960
|
onPointermove(event) {
|
|
724
|
-
if (this.disabled())
|
|
725
|
-
|
|
726
|
-
|
|
961
|
+
if (this.disabled() || !this.inputs.enableSelection() || !this.inputs.enableRangeSelection() || !this.dragging()) {
|
|
962
|
+
return;
|
|
963
|
+
}
|
|
727
964
|
const cell = this.inputs.getCell(event.target);
|
|
728
|
-
if (
|
|
729
|
-
|
|
965
|
+
if (cell !== undefined) {
|
|
966
|
+
this.gridBehavior.gotoCell(cell, {
|
|
967
|
+
anchor: true
|
|
968
|
+
});
|
|
969
|
+
}
|
|
730
970
|
}
|
|
731
971
|
onPointerup(event) {
|
|
732
|
-
if (
|
|
733
|
-
|
|
734
|
-
}
|
|
972
|
+
if (this.disabled()) return;
|
|
973
|
+
this.pointerup().handle(event);
|
|
735
974
|
}
|
|
736
975
|
onFocusIn(event) {
|
|
737
976
|
this.isFocused.set(true);
|
|
977
|
+
this.hasBeenFocused.set(true);
|
|
978
|
+
if (this.dragging()) return;
|
|
738
979
|
const cell = this.inputs.getCell(event.target);
|
|
739
|
-
if (!cell) return;
|
|
740
|
-
|
|
980
|
+
if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return;
|
|
981
|
+
cell.onFocusIn(event);
|
|
982
|
+
if (cell !== this.activeCell()) {
|
|
983
|
+
this.gridBehavior.gotoCell(cell);
|
|
984
|
+
}
|
|
741
985
|
}
|
|
742
|
-
_maybeDeletion = signal(false);
|
|
743
986
|
onFocusOut(event) {
|
|
744
|
-
const
|
|
745
|
-
const
|
|
746
|
-
|
|
987
|
+
const blurTarget = event.target;
|
|
988
|
+
const cell = this.inputs.getCell(blurTarget);
|
|
989
|
+
cell?.onFocusOut(event);
|
|
990
|
+
const focusTarget = event.relatedTarget;
|
|
991
|
+
if (this.inputs.element().contains(focusTarget)) return;
|
|
992
|
+
if (focusTarget === null) {
|
|
747
993
|
this._maybeDeletion.set(true);
|
|
748
994
|
}
|
|
749
|
-
if (parentEl.contains(targetEl)) return;
|
|
750
995
|
this.isFocused.set(false);
|
|
751
996
|
}
|
|
752
|
-
|
|
997
|
+
setDefaultStateEffect() {
|
|
998
|
+
if (this.hasBeenFocused()) return;
|
|
999
|
+
this.gridBehavior.setDefaultState();
|
|
1000
|
+
}
|
|
753
1001
|
resetStateEffect() {
|
|
754
1002
|
const hasReset = this.gridBehavior.resetState();
|
|
755
|
-
if (hasReset
|
|
756
|
-
this.
|
|
1003
|
+
if (hasReset) {
|
|
1004
|
+
if (this._maybeDeletion()) {
|
|
1005
|
+
this._deletion.set(true);
|
|
1006
|
+
} else {
|
|
1007
|
+
this._stateStale.set(true);
|
|
1008
|
+
}
|
|
757
1009
|
}
|
|
758
|
-
|
|
759
|
-
|
|
1010
|
+
this._maybeDeletion.set(false);
|
|
1011
|
+
}
|
|
1012
|
+
resetFocusEffect() {
|
|
1013
|
+
const stateStale = this._stateStale();
|
|
1014
|
+
if (!stateStale) return;
|
|
1015
|
+
const isFocused = untracked(() => this.isFocused());
|
|
1016
|
+
const isRoving = untracked(() => this.inputs.focusMode() === 'roving');
|
|
1017
|
+
const activeCell = untracked(() => this.activeCell());
|
|
1018
|
+
if (isRoving && activeCell !== undefined && isFocused) {
|
|
1019
|
+
if (!activeCell.isFocused()) {
|
|
1020
|
+
activeCell.focus();
|
|
1021
|
+
}
|
|
760
1022
|
}
|
|
1023
|
+
this._stateStale.set(false);
|
|
761
1024
|
}
|
|
762
|
-
|
|
763
|
-
const activeCell = this.activeCell();
|
|
764
|
-
const hasFocus = this.isFocused();
|
|
1025
|
+
restoreFocusEffect() {
|
|
765
1026
|
const deletion = this._deletion();
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
1027
|
+
if (!deletion) return;
|
|
1028
|
+
const isRoving = untracked(() => this.inputs.focusMode() === 'roving');
|
|
1029
|
+
const activeCell = untracked(() => this.activeCell());
|
|
1030
|
+
if (isRoving && activeCell !== undefined) {
|
|
1031
|
+
if (!activeCell.isFocused()) {
|
|
1032
|
+
activeCell.focus();
|
|
771
1033
|
}
|
|
772
1034
|
}
|
|
1035
|
+
this._deletion.set(false);
|
|
1036
|
+
}
|
|
1037
|
+
focusEffect() {
|
|
1038
|
+
const activeCell = this.activeCell();
|
|
1039
|
+
const gridFocused = untracked(() => this.isFocused());
|
|
1040
|
+
if (activeCell === undefined || !gridFocused) return;
|
|
1041
|
+
const isRoving = untracked(() => this.inputs.focusMode() === 'roving');
|
|
1042
|
+
const cellFocused = untracked(() => activeCell.isFocused());
|
|
1043
|
+
if (isRoving && !cellFocused) {
|
|
1044
|
+
activeCell.focus();
|
|
1045
|
+
}
|
|
773
1046
|
}
|
|
774
1047
|
}
|
|
775
1048
|
|
|
@@ -784,44 +1057,224 @@ class GridRowPattern {
|
|
|
784
1057
|
|
|
785
1058
|
class GridCellPattern {
|
|
786
1059
|
inputs;
|
|
787
|
-
id;
|
|
788
|
-
|
|
1060
|
+
id = () => this.inputs.id();
|
|
1061
|
+
element = () => this.inputs.element();
|
|
1062
|
+
isFocused = signal(false);
|
|
789
1063
|
selected;
|
|
790
|
-
selectable;
|
|
791
|
-
|
|
792
|
-
|
|
1064
|
+
selectable = () => this.inputs.selectable();
|
|
1065
|
+
disabled = () => this.inputs.disabled();
|
|
1066
|
+
rowSpan = () => this.inputs.rowSpan();
|
|
1067
|
+
colSpan = () => this.inputs.colSpan();
|
|
1068
|
+
active = computed(() => this.inputs.grid().activeCell() === this);
|
|
1069
|
+
anchor = computed(() => this.inputs.grid().anchorCell() === this ? true : undefined);
|
|
793
1070
|
ariaSelected = computed(() => this.inputs.grid().inputs.enableSelection() && this.selectable() ? this.selected() : undefined);
|
|
794
1071
|
ariaRowIndex = computed(() => this.inputs.row().rowIndex() ?? this.inputs.rowIndex() ?? this.inputs.grid().gridBehavior.rowIndex(this));
|
|
795
1072
|
ariaColIndex = computed(() => this.inputs.colIndex() ?? this.inputs.grid().gridBehavior.colIndex(this));
|
|
796
|
-
element = computed(() => this.inputs.widget()?.element() ?? this.inputs.element());
|
|
797
|
-
active = computed(() => this.inputs.grid().activeCell() === this);
|
|
798
1073
|
_tabIndex = computed(() => this.inputs.grid().gridBehavior.cellTabIndex(this));
|
|
799
|
-
tabIndex = computed(() =>
|
|
800
|
-
|
|
1074
|
+
tabIndex = computed(() => {
|
|
1075
|
+
if (this.singleWidgetMode() || this.navigationActivated()) {
|
|
1076
|
+
return -1;
|
|
1077
|
+
}
|
|
1078
|
+
return this._tabIndex();
|
|
1079
|
+
});
|
|
1080
|
+
singleWidgetMode = computed(() => this.inputs.widgets().length === 1);
|
|
1081
|
+
multiWidgetMode = computed(() => this.inputs.widgets().length > 1);
|
|
1082
|
+
navigationDisabled = computed(() => !this.multiWidgetMode() || !this.active() || this.inputs.disabled());
|
|
1083
|
+
focusBehavior;
|
|
1084
|
+
navigationBehavior;
|
|
1085
|
+
activeWidget = linkedSignal(() => this.inputs.widgets().length > 0 ? this.inputs.widgets()[0] : undefined);
|
|
1086
|
+
navigationActivated = signal(false);
|
|
1087
|
+
widgetActivated = computed(() => this.inputs.widgets().some(w => w.isActivated()));
|
|
1088
|
+
isActivated = computed(() => this.navigationActivated() || this.widgetActivated());
|
|
1089
|
+
prevKey = computed(() => {
|
|
1090
|
+
if (this.inputs.orientation() === 'vertical') {
|
|
1091
|
+
return 'ArrowUp';
|
|
1092
|
+
}
|
|
1093
|
+
return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
|
|
1094
|
+
});
|
|
1095
|
+
nextKey = computed(() => {
|
|
1096
|
+
if (this.inputs.orientation() === 'vertical') {
|
|
1097
|
+
return 'ArrowDown';
|
|
1098
|
+
}
|
|
1099
|
+
return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight';
|
|
1100
|
+
});
|
|
1101
|
+
keydown = computed(() => {
|
|
1102
|
+
const manager = new KeyboardEventManager();
|
|
1103
|
+
if (!this.navigationActivated()) {
|
|
1104
|
+
manager.on('Enter', () => this.startNavigation());
|
|
1105
|
+
return manager;
|
|
1106
|
+
}
|
|
1107
|
+
manager.on('Escape', () => this.stopNavigation()).on(this.prevKey(), () => this._advance(() => this.navigationBehavior.prev({
|
|
1108
|
+
focusElement: false
|
|
1109
|
+
}))).on(this.nextKey(), () => this._advance(() => this.navigationBehavior.next({
|
|
1110
|
+
focusElement: false
|
|
1111
|
+
}))).on('Home', () => this._advance(() => this.navigationBehavior.next({
|
|
1112
|
+
focusElement: false
|
|
1113
|
+
}))).on('End', () => this._advance(() => this.navigationBehavior.next({
|
|
1114
|
+
focusElement: false
|
|
1115
|
+
})));
|
|
1116
|
+
return manager;
|
|
1117
|
+
});
|
|
801
1118
|
constructor(inputs) {
|
|
802
1119
|
this.inputs = inputs;
|
|
803
|
-
this.id = inputs.id;
|
|
804
|
-
this.disabled = inputs.disabled;
|
|
805
|
-
this.rowSpan = inputs.rowSpan;
|
|
806
|
-
this.colSpan = inputs.colSpan;
|
|
807
1120
|
this.selected = inputs.selected;
|
|
808
|
-
|
|
1121
|
+
const listNavigationInputs = {
|
|
1122
|
+
...inputs,
|
|
1123
|
+
items: inputs.widgets,
|
|
1124
|
+
activeItem: this.activeWidget,
|
|
1125
|
+
disabled: this.navigationDisabled,
|
|
1126
|
+
focusMode: () => 'roving',
|
|
1127
|
+
softDisabled: () => true
|
|
1128
|
+
};
|
|
1129
|
+
this.focusBehavior = new ListFocus(listNavigationInputs);
|
|
1130
|
+
this.navigationBehavior = new ListNavigation({
|
|
1131
|
+
...listNavigationInputs,
|
|
1132
|
+
focusManager: this.focusBehavior
|
|
1133
|
+
});
|
|
1134
|
+
}
|
|
1135
|
+
onKeydown(event) {
|
|
1136
|
+
if (this.disabled() || this.inputs.widgets().length === 0) return;
|
|
1137
|
+
if (this.singleWidgetMode()) {
|
|
1138
|
+
this.activeWidget().onKeydown(event);
|
|
1139
|
+
return;
|
|
1140
|
+
}
|
|
1141
|
+
if (!this.navigationActivated()) {
|
|
1142
|
+
this.keydown().handle(event);
|
|
1143
|
+
return;
|
|
1144
|
+
}
|
|
1145
|
+
const widgetActivated = this.widgetActivated();
|
|
1146
|
+
this.activeWidget().onKeydown(event);
|
|
1147
|
+
if (!widgetActivated) {
|
|
1148
|
+
this.keydown().handle(event);
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
onFocusIn(event) {
|
|
1152
|
+
this.isFocused.set(true);
|
|
1153
|
+
const focusTarget = event.target;
|
|
1154
|
+
const widget = this.inputs.getWidget(focusTarget);
|
|
1155
|
+
if (!widget) return;
|
|
1156
|
+
widget.onFocusIn(event);
|
|
1157
|
+
if (widget !== this.activeWidget()) {
|
|
1158
|
+
this.navigationBehavior.goto(widget, {
|
|
1159
|
+
focusElement: false
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
if (this.multiWidgetMode()) {
|
|
1163
|
+
this.navigationActivated.set(true);
|
|
1164
|
+
}
|
|
1165
|
+
}
|
|
1166
|
+
onFocusOut(event) {
|
|
1167
|
+
const blurTarget = event.target;
|
|
1168
|
+
const widget = this.inputs.getWidget(blurTarget);
|
|
1169
|
+
widget?.onFocusOut(event);
|
|
1170
|
+
const focusTarget = event.relatedTarget;
|
|
1171
|
+
if (this.element().contains(focusTarget)) return;
|
|
1172
|
+
this.isFocused.set(false);
|
|
1173
|
+
this.navigationActivated.set(false);
|
|
1174
|
+
}
|
|
1175
|
+
focus() {
|
|
1176
|
+
if (this.singleWidgetMode()) {
|
|
1177
|
+
this.activeWidget()?.focus();
|
|
1178
|
+
} else {
|
|
1179
|
+
this.element().focus();
|
|
1180
|
+
}
|
|
809
1181
|
}
|
|
810
1182
|
widgetTabIndex() {
|
|
811
|
-
|
|
1183
|
+
if (this.singleWidgetMode()) {
|
|
1184
|
+
return this._tabIndex();
|
|
1185
|
+
}
|
|
1186
|
+
return this.navigationActivated() ? 0 : -1;
|
|
1187
|
+
}
|
|
1188
|
+
startNavigation() {
|
|
1189
|
+
if (this.navigationActivated()) return;
|
|
1190
|
+
this.navigationActivated.set(true);
|
|
1191
|
+
this.navigationBehavior.first();
|
|
1192
|
+
}
|
|
1193
|
+
stopNavigation() {
|
|
1194
|
+
if (!this.navigationActivated()) return;
|
|
1195
|
+
this.navigationActivated.set(false);
|
|
1196
|
+
this.element().focus();
|
|
1197
|
+
}
|
|
1198
|
+
_advance(op) {
|
|
1199
|
+
const success = op();
|
|
1200
|
+
if (success) {
|
|
1201
|
+
this.activeWidget()?.focus();
|
|
1202
|
+
}
|
|
812
1203
|
}
|
|
813
1204
|
}
|
|
814
1205
|
|
|
815
1206
|
class GridCellWidgetPattern {
|
|
816
1207
|
inputs;
|
|
817
|
-
|
|
1208
|
+
id = () => this.inputs.id();
|
|
1209
|
+
element = () => this.inputs.element();
|
|
1210
|
+
widgetHost = computed(() => this.inputs.focusTarget() ?? this.element());
|
|
1211
|
+
index = computed(() => this.inputs.cell().inputs.widgets().indexOf(this));
|
|
1212
|
+
disabled = computed(() => this.inputs.disabled() || this.inputs.cell().disabled());
|
|
818
1213
|
tabIndex = computed(() => this.inputs.cell().widgetTabIndex());
|
|
819
|
-
active = computed(() => this.inputs.cell().
|
|
1214
|
+
active = computed(() => this.inputs.cell().activeWidget() === this);
|
|
1215
|
+
isActivated = signal(false);
|
|
1216
|
+
lastActivateEvent = signal(undefined);
|
|
1217
|
+
lastDeactivateEvent = signal(undefined);
|
|
1218
|
+
keydown = computed(() => {
|
|
1219
|
+
const manager = new KeyboardEventManager();
|
|
1220
|
+
if (this.inputs.widgetType() === 'simple') {
|
|
1221
|
+
return manager;
|
|
1222
|
+
}
|
|
1223
|
+
if (this.isActivated()) {
|
|
1224
|
+
manager.on('Escape', e => {
|
|
1225
|
+
this.deactivate(e);
|
|
1226
|
+
this.focus();
|
|
1227
|
+
});
|
|
1228
|
+
if (this.inputs.widgetType() === 'editable') {
|
|
1229
|
+
manager.on('Enter', e => {
|
|
1230
|
+
this.deactivate(e);
|
|
1231
|
+
this.focus();
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
return manager;
|
|
1235
|
+
}
|
|
1236
|
+
manager.on('Enter', e => this.activate(e));
|
|
1237
|
+
if (this.inputs.widgetType() === 'editable') {
|
|
1238
|
+
manager.on([Modifier.Shift, Modifier.None], /^[a-zA-Z0-9]$/, e => this.activate(e), {
|
|
1239
|
+
preventDefault: false
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
return manager;
|
|
1243
|
+
});
|
|
820
1244
|
constructor(inputs) {
|
|
821
1245
|
this.inputs = inputs;
|
|
822
|
-
|
|
1246
|
+
}
|
|
1247
|
+
onKeydown(event) {
|
|
1248
|
+
if (this.disabled()) return;
|
|
1249
|
+
this.keydown().handle(event);
|
|
1250
|
+
}
|
|
1251
|
+
onFocusIn(event) {
|
|
1252
|
+
if (this.inputs.widgetType() === 'simple') return;
|
|
1253
|
+
const focusTarget = event.target;
|
|
1254
|
+
if (this.widgetHost().contains(focusTarget) && this.widgetHost() !== focusTarget) {
|
|
1255
|
+
this.activate(event);
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
onFocusOut(event) {
|
|
1259
|
+
const focusTarget = event.relatedTarget;
|
|
1260
|
+
if (this.widgetHost().contains(focusTarget)) return;
|
|
1261
|
+
this.deactivate(event);
|
|
1262
|
+
}
|
|
1263
|
+
focus() {
|
|
1264
|
+
this.widgetHost().focus();
|
|
1265
|
+
}
|
|
1266
|
+
activate(event) {
|
|
1267
|
+
if (this.isActivated()) return;
|
|
1268
|
+
if (this.inputs.widgetType() === 'simple') return;
|
|
1269
|
+
this.isActivated.set(true);
|
|
1270
|
+
this.lastActivateEvent.set(event);
|
|
1271
|
+
}
|
|
1272
|
+
deactivate(event) {
|
|
1273
|
+
if (!this.isActivated()) return;
|
|
1274
|
+
this.isActivated.set(false);
|
|
1275
|
+
this.lastDeactivateEvent.set(event);
|
|
823
1276
|
}
|
|
824
1277
|
}
|
|
825
1278
|
|
|
826
|
-
export { GridCellPattern, GridCellWidgetPattern, GridPattern, GridRowPattern, KeyboardEventManager, Modifier, PointerEventManager };
|
|
1279
|
+
export { GridCellPattern, GridCellWidgetPattern, GridPattern, GridRowPattern, KeyboardEventManager, ListFocus, ListNavigation, Modifier, PointerEventManager };
|
|
827
1280
|
//# sourceMappingURL=_widget-chunk.mjs.map
|