@angular/aria 21.0.0-next.9 → 21.0.0-rc.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.
Files changed (49) hide show
  1. package/_adev_assets/aria-accordion.json +373 -0
  2. package/_adev_assets/aria-combobox.json +383 -0
  3. package/_adev_assets/aria-grid.json +647 -0
  4. package/_adev_assets/aria-listbox.json +511 -0
  5. package/_adev_assets/aria-menu.json +852 -0
  6. package/_adev_assets/aria-tabs.json +987 -0
  7. package/_adev_assets/aria-toolbar.json +696 -0
  8. package/_adev_assets/aria-tree.json +1071 -0
  9. package/fesm2022/_widget-chunk.mjs +949 -0
  10. package/fesm2022/_widget-chunk.mjs.map +1 -0
  11. package/fesm2022/accordion.mjs +372 -174
  12. package/fesm2022/accordion.mjs.map +1 -1
  13. package/fesm2022/aria.mjs +1 -2
  14. package/fesm2022/aria.mjs.map +1 -1
  15. package/fesm2022/combobox.mjs +308 -116
  16. package/fesm2022/combobox.mjs.map +1 -1
  17. package/fesm2022/grid.mjs +566 -0
  18. package/fesm2022/grid.mjs.map +1 -0
  19. package/fesm2022/listbox.mjs +384 -184
  20. package/fesm2022/listbox.mjs.map +1 -1
  21. package/fesm2022/menu.mjs +591 -0
  22. package/fesm2022/menu.mjs.map +1 -0
  23. package/fesm2022/private.mjs +2338 -0
  24. package/fesm2022/private.mjs.map +1 -0
  25. package/fesm2022/tabs.mjs +484 -276
  26. package/fesm2022/tabs.mjs.map +1 -1
  27. package/fesm2022/toolbar.mjs +366 -200
  28. package/fesm2022/toolbar.mjs.map +1 -1
  29. package/fesm2022/tree.mjs +515 -267
  30. package/fesm2022/tree.mjs.map +1 -1
  31. package/package.json +12 -12
  32. package/types/_grid-chunk.d.ts +608 -0
  33. package/types/accordion.d.ts +8 -8
  34. package/types/combobox.d.ts +20 -7
  35. package/types/grid.d.ts +120 -0
  36. package/types/listbox.d.ts +9 -7
  37. package/types/menu.d.ts +170 -0
  38. package/types/{ui-patterns.d.ts → private.d.ts} +555 -433
  39. package/types/tabs.d.ts +8 -8
  40. package/types/toolbar.d.ts +31 -28
  41. package/types/tree.d.ts +11 -9
  42. package/fesm2022/deferred-content.mjs +0 -60
  43. package/fesm2022/deferred-content.mjs.map +0 -1
  44. package/fesm2022/radio-group.mjs +0 -197
  45. package/fesm2022/radio-group.mjs.map +0 -1
  46. package/fesm2022/ui-patterns.mjs +0 -2504
  47. package/fesm2022/ui-patterns.mjs.map +0 -1
  48. package/types/deferred-content.d.ts +0 -38
  49. package/types/radio-group.d.ts +0 -82
@@ -0,0 +1,949 @@
1
+ import { computed, signal, linkedSignal } from '@angular/core';
2
+
3
+ var Modifier;
4
+ (function (Modifier) {
5
+ Modifier[Modifier["None"] = 0] = "None";
6
+ Modifier[Modifier["Ctrl"] = 1] = "Ctrl";
7
+ Modifier[Modifier["Shift"] = 2] = "Shift";
8
+ Modifier[Modifier["Alt"] = 4] = "Alt";
9
+ Modifier[Modifier["Meta"] = 8] = "Meta";
10
+ Modifier["Any"] = "Any";
11
+ })(Modifier || (Modifier = {}));
12
+ class EventManager {
13
+ configs = [];
14
+ handle(event) {
15
+ for (const config of this.configs) {
16
+ if (config.matcher(event)) {
17
+ config.handler(event);
18
+ if (config.preventDefault) {
19
+ event.preventDefault();
20
+ }
21
+ if (config.stopPropagation) {
22
+ event.stopPropagation();
23
+ }
24
+ }
25
+ }
26
+ }
27
+ }
28
+ function getModifiers(event) {
29
+ return (+event.ctrlKey && Modifier.Ctrl) | (+event.shiftKey && Modifier.Shift) | (+event.altKey && Modifier.Alt) | (+event.metaKey && Modifier.Meta);
30
+ }
31
+ function hasModifiers(event, modifiers) {
32
+ const eventModifiers = getModifiers(event);
33
+ const modifiersList = Array.isArray(modifiers) ? modifiers : [modifiers];
34
+ if (modifiersList.includes(Modifier.Any)) {
35
+ return true;
36
+ }
37
+ return modifiersList.some(modifiers => eventModifiers === modifiers);
38
+ }
39
+
40
+ class KeyboardEventManager extends EventManager {
41
+ options = {
42
+ preventDefault: true,
43
+ stopPropagation: true
44
+ };
45
+ on(...args) {
46
+ const {
47
+ modifiers,
48
+ key,
49
+ handler,
50
+ options
51
+ } = this._normalizeInputs(...args);
52
+ this.configs.push({
53
+ handler: handler,
54
+ matcher: event => this._isMatch(event, key, modifiers),
55
+ ...this.options,
56
+ ...options
57
+ });
58
+ return this;
59
+ }
60
+ _normalizeInputs(...args) {
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];
66
+ return {
67
+ key: key,
68
+ handler: handler,
69
+ modifiers: modifiers,
70
+ options: options ?? {}
71
+ };
72
+ }
73
+ _isMatch(event, key, modifiers) {
74
+ if (!hasModifiers(event, modifiers)) {
75
+ return false;
76
+ }
77
+ if (key instanceof RegExp) {
78
+ return key.test(event.key);
79
+ }
80
+ const keyStr = typeof key === 'string' ? key : key();
81
+ return keyStr.toLowerCase() === event.key.toLowerCase();
82
+ }
83
+ }
84
+
85
+ var MouseButton;
86
+ (function (MouseButton) {
87
+ MouseButton[MouseButton["Main"] = 0] = "Main";
88
+ MouseButton[MouseButton["Auxiliary"] = 1] = "Auxiliary";
89
+ MouseButton[MouseButton["Secondary"] = 2] = "Secondary";
90
+ })(MouseButton || (MouseButton = {}));
91
+ class PointerEventManager extends EventManager {
92
+ options = {
93
+ preventDefault: false,
94
+ stopPropagation: false
95
+ };
96
+ on(...args) {
97
+ const {
98
+ button,
99
+ handler,
100
+ modifiers
101
+ } = this._normalizeInputs(...args);
102
+ this.configs.push({
103
+ handler,
104
+ matcher: event => this._isMatch(event, button, modifiers),
105
+ ...this.options
106
+ });
107
+ return this;
108
+ }
109
+ _normalizeInputs(...args) {
110
+ if (args.length === 3) {
111
+ return {
112
+ button: args[0],
113
+ modifiers: args[1],
114
+ handler: args[2]
115
+ };
116
+ }
117
+ if (args.length === 2) {
118
+ return {
119
+ button: MouseButton.Main,
120
+ modifiers: args[0],
121
+ handler: args[1]
122
+ };
123
+ }
124
+ return {
125
+ button: MouseButton.Main,
126
+ modifiers: Modifier.None,
127
+ handler: args[0]
128
+ };
129
+ }
130
+ _isMatch(event, button, modifiers) {
131
+ return button === (event.button ?? 0) && hasModifiers(event, modifiers);
132
+ }
133
+ }
134
+
135
+ class GridData {
136
+ inputs;
137
+ cells;
138
+ maxRowCount = computed(() => Math.max(...this._rowCountByCol().values(), 0));
139
+ maxColCount = computed(() => Math.max(...this._colCountsByRow().values(), 0));
140
+ _coordsMap = computed(() => {
141
+ const coordsMap = new Map();
142
+ const visitedCoords = new Set();
143
+ for (let rowIndex = 0; rowIndex < this.cells().length; rowIndex++) {
144
+ let colIndex = 0;
145
+ const row = this.cells()[rowIndex];
146
+ for (const cell of row) {
147
+ while (visitedCoords.has(`${rowIndex}:${colIndex}`)) {
148
+ colIndex++;
149
+ }
150
+ const rowspan = cell.rowSpan();
151
+ const colspan = cell.colSpan();
152
+ const spanCoords = [];
153
+ for (let rowOffset = 0; rowOffset < rowspan; rowOffset++) {
154
+ const row = rowIndex + rowOffset;
155
+ for (let colOffset = 0; colOffset < colspan; colOffset++) {
156
+ const col = colIndex + colOffset;
157
+ visitedCoords.add(`${row}:${col}`);
158
+ spanCoords.push({
159
+ row,
160
+ col
161
+ });
162
+ }
163
+ }
164
+ coordsMap.set(cell, {
165
+ coords: spanCoords[0],
166
+ spanCoords
167
+ });
168
+ colIndex += colspan;
169
+ }
170
+ }
171
+ return coordsMap;
172
+ });
173
+ _cellMap = computed(() => {
174
+ const cellMap = new Map();
175
+ for (const [cell, {
176
+ spanCoords
177
+ }] of this._coordsMap().entries()) {
178
+ for (const {
179
+ row,
180
+ col
181
+ } of spanCoords) {
182
+ cellMap.set(`${row}:${col}`, cell);
183
+ }
184
+ }
185
+ return cellMap;
186
+ });
187
+ _colCountsByRow = computed(() => {
188
+ const colCountByRow = new Map();
189
+ for (const [_, {
190
+ spanCoords
191
+ }] of this._coordsMap().entries()) {
192
+ for (const {
193
+ row,
194
+ col
195
+ } of spanCoords) {
196
+ const colCount = colCountByRow.get(row);
197
+ const newColCount = col + 1;
198
+ if (colCount === undefined || colCount < newColCount) {
199
+ colCountByRow.set(row, newColCount);
200
+ }
201
+ }
202
+ }
203
+ return colCountByRow;
204
+ });
205
+ _rowCountByCol = computed(() => {
206
+ const rowCountByCol = new Map();
207
+ for (const [_, {
208
+ spanCoords
209
+ }] of this._coordsMap().entries()) {
210
+ for (const {
211
+ row,
212
+ col
213
+ } of spanCoords) {
214
+ const rowCount = rowCountByCol.get(col);
215
+ const newRowCount = row + 1;
216
+ if (rowCount === undefined || rowCount < newRowCount) {
217
+ rowCountByCol.set(col, newRowCount);
218
+ }
219
+ }
220
+ }
221
+ return rowCountByCol;
222
+ });
223
+ constructor(inputs) {
224
+ this.inputs = inputs;
225
+ this.cells = this.inputs.cells;
226
+ }
227
+ getCell(rowCol) {
228
+ return this._cellMap().get(`${rowCol.row}:${rowCol.col}`);
229
+ }
230
+ getCoords(cell) {
231
+ return this._coordsMap().get(cell)?.coords;
232
+ }
233
+ getAllCoords(cell) {
234
+ return this._coordsMap().get(cell)?.spanCoords;
235
+ }
236
+ getRowCount(col) {
237
+ return this._rowCountByCol().get(col);
238
+ }
239
+ getColCount(row) {
240
+ return this._colCountsByRow().get(row);
241
+ }
242
+ }
243
+
244
+ class GridFocus {
245
+ inputs;
246
+ activeCell = signal(undefined);
247
+ activeCoords = signal({
248
+ row: -1,
249
+ col: -1
250
+ });
251
+ stateEmpty = computed(() => this.activeCell() === undefined || this.activeCoords().row === -1 && this.activeCoords().col === -1);
252
+ stateStale = computed(() => {
253
+ if (this.stateEmpty()) {
254
+ return true;
255
+ }
256
+ const activeCell = this.activeCell();
257
+ const activeCellCoords = this.inputs.grid.getCoords(activeCell);
258
+ const activeCoords = this.activeCoords();
259
+ const activeCoordsCell = this.inputs.grid.getCell(activeCoords);
260
+ const activeCellNotValid = activeCellCoords === undefined;
261
+ const activeCellMismatch = activeCell !== activeCoordsCell;
262
+ return activeCellNotValid || activeCellMismatch;
263
+ });
264
+ activeDescendant = computed(() => {
265
+ if (this.gridDisabled() || this.inputs.focusMode() === 'roving') {
266
+ return undefined;
267
+ }
268
+ const currentActiveCell = this.activeCell();
269
+ return currentActiveCell ? currentActiveCell.id() : undefined;
270
+ });
271
+ gridDisabled = computed(() => {
272
+ if (this.inputs.disabled()) {
273
+ return true;
274
+ }
275
+ const gridCells = this.inputs.grid.cells();
276
+ return gridCells.length === 0 || gridCells.every(row => row.every(cell => cell.disabled()));
277
+ });
278
+ gridTabIndex = computed(() => {
279
+ if (this.gridDisabled()) {
280
+ return 0;
281
+ }
282
+ return this.inputs.focusMode() === 'activedescendant' ? 0 : -1;
283
+ });
284
+ constructor(inputs) {
285
+ this.inputs = inputs;
286
+ }
287
+ getCellTabIndex(cell) {
288
+ if (this.gridDisabled()) {
289
+ return -1;
290
+ }
291
+ if (this.inputs.focusMode() === 'activedescendant') {
292
+ return -1;
293
+ }
294
+ return this.activeCell() === cell ? 0 : -1;
295
+ }
296
+ isFocusable(cell) {
297
+ return !cell.disabled() || this.inputs.softDisabled();
298
+ }
299
+ focusCell(cell) {
300
+ if (this.gridDisabled()) {
301
+ return false;
302
+ }
303
+ if (!this.isFocusable(cell)) {
304
+ return false;
305
+ }
306
+ if (this.inputs.grid.getCoords(cell) === undefined) {
307
+ return false;
308
+ }
309
+ this.activeCoords.set(this.inputs.grid.getCoords(cell));
310
+ this.activeCell.set(cell);
311
+ return true;
312
+ }
313
+ focusCoordinates(coords) {
314
+ if (this.gridDisabled()) {
315
+ return false;
316
+ }
317
+ const cell = this.inputs.grid.getCell(coords);
318
+ if (!cell || !this.isFocusable(cell)) {
319
+ return false;
320
+ }
321
+ if (this.inputs.grid.getCell(coords) === undefined) {
322
+ return false;
323
+ }
324
+ this.activeCoords.set(coords);
325
+ this.activeCell.set(this.inputs.grid.getCell(coords));
326
+ return true;
327
+ }
328
+ }
329
+
330
+ const direction = {
331
+ Up: {
332
+ row: -1
333
+ },
334
+ Down: {
335
+ row: 1
336
+ },
337
+ Left: {
338
+ col: -1
339
+ },
340
+ Right: {
341
+ col: 1
342
+ }
343
+ };
344
+ class GridNavigation {
345
+ inputs;
346
+ _maxSteps = computed(() => this.inputs.grid.maxRowCount() * this.inputs.grid.maxColCount());
347
+ constructor(inputs) {
348
+ this.inputs = inputs;
349
+ }
350
+ gotoCell(cell) {
351
+ return this.inputs.gridFocus.focusCell(cell);
352
+ }
353
+ gotoCoords(coords) {
354
+ return this.inputs.gridFocus.focusCoordinates(coords);
355
+ }
356
+ peek(direction, fromCoords, wrap, allowDisabled) {
357
+ wrap = wrap ?? (direction.row !== undefined ? this.inputs.rowWrap() : this.inputs.colWrap());
358
+ return this._peekDirectional(direction, fromCoords, wrap, allowDisabled);
359
+ }
360
+ advance(direction) {
361
+ const nextCoords = this.peek(direction, this.inputs.gridFocus.activeCoords());
362
+ return !!nextCoords && this.gotoCoords(nextCoords);
363
+ }
364
+ peekFirst(row, allowDisabled) {
365
+ const fromCoords = {
366
+ row: row ?? 0,
367
+ col: -1
368
+ };
369
+ return row === undefined ? this._peekDirectional(direction.Right, fromCoords, 'continuous', allowDisabled) : this._peekDirectional(direction.Right, fromCoords, 'nowrap', allowDisabled);
370
+ }
371
+ first(row) {
372
+ const nextCoords = this.peekFirst(row);
373
+ return !!nextCoords && this.gotoCoords(nextCoords);
374
+ }
375
+ peekLast(row, allowDisabled) {
376
+ const fromCoords = {
377
+ row: row ?? this.inputs.grid.maxRowCount() - 1,
378
+ col: this.inputs.grid.maxColCount()
379
+ };
380
+ return row === undefined ? this._peekDirectional(direction.Left, fromCoords, 'continuous', allowDisabled) : this._peekDirectional(direction.Left, fromCoords, 'nowrap', allowDisabled);
381
+ }
382
+ last(row) {
383
+ const nextCoords = this.peekLast(row);
384
+ return !!nextCoords && this.gotoCoords(nextCoords);
385
+ }
386
+ _peekDirectional(delta, fromCoords, wrap, allowDisabled = false) {
387
+ if (this.inputs.gridFocus.gridDisabled()) return undefined;
388
+ const fromCell = this.inputs.grid.getCell(fromCoords);
389
+ const maxRowCount = this.inputs.grid.maxRowCount();
390
+ const maxColCount = this.inputs.grid.maxColCount();
391
+ const rowDelta = delta.row ?? 0;
392
+ const colDelta = delta.col ?? 0;
393
+ let nextCoords = {
394
+ ...fromCoords
395
+ };
396
+ for (let step = 0; step < this._maxSteps(); step++) {
397
+ const isWrapping = nextCoords.col + colDelta < 0 || nextCoords.col + colDelta >= maxColCount || nextCoords.row + rowDelta < 0 || nextCoords.row + rowDelta >= maxRowCount;
398
+ if (wrap === 'nowrap' && isWrapping) return;
399
+ if (wrap === 'continuous') {
400
+ const generalDelta = delta.row ?? delta.col;
401
+ const rowStep = isWrapping ? generalDelta : rowDelta;
402
+ const colStep = isWrapping ? generalDelta : colDelta;
403
+ nextCoords = {
404
+ row: (nextCoords.row + rowStep + maxRowCount) % maxRowCount,
405
+ col: (nextCoords.col + colStep + maxColCount) % maxColCount
406
+ };
407
+ }
408
+ if (wrap === 'loop') {
409
+ nextCoords = {
410
+ row: (nextCoords.row + rowDelta + maxRowCount) % maxRowCount,
411
+ col: (nextCoords.col + colDelta + maxColCount) % maxColCount
412
+ };
413
+ }
414
+ if (wrap === 'nowrap') {
415
+ nextCoords = {
416
+ row: nextCoords.row + rowDelta,
417
+ col: nextCoords.col + colDelta
418
+ };
419
+ }
420
+ if (nextCoords.row === fromCoords.row && nextCoords.col === fromCoords.col) {
421
+ return undefined;
422
+ }
423
+ const nextCell = this.inputs.grid.getCell(nextCoords);
424
+ if (nextCell !== undefined && nextCell !== fromCell && (allowDisabled || this.inputs.gridFocus.isFocusable(nextCell))) {
425
+ return nextCoords;
426
+ }
427
+ }
428
+ return undefined;
429
+ }
430
+ }
431
+
432
+ class GridSelection {
433
+ inputs;
434
+ _undoList = signal([]);
435
+ constructor(inputs) {
436
+ this.inputs = inputs;
437
+ }
438
+ undo() {
439
+ for (const [cell, oldState] of this._undoList()) {
440
+ cell.selected.set(oldState);
441
+ }
442
+ this._undoList.set([]);
443
+ }
444
+ select(fromCoords, toCoords) {
445
+ this._updateState(fromCoords, toCoords ?? fromCoords, () => true);
446
+ }
447
+ deselect(fromCoords, toCoords) {
448
+ this._updateState(fromCoords, toCoords ?? fromCoords, () => false);
449
+ }
450
+ toggle(fromCoords, toCoords) {
451
+ this._updateState(fromCoords, toCoords ?? fromCoords, oldState => !oldState);
452
+ }
453
+ selectAll() {
454
+ this._updateState({
455
+ row: 0,
456
+ col: 0
457
+ }, {
458
+ row: this.inputs.grid.maxRowCount(),
459
+ col: this.inputs.grid.maxColCount()
460
+ }, () => true);
461
+ }
462
+ deselectAll() {
463
+ this._updateState({
464
+ row: 0,
465
+ col: 0
466
+ }, {
467
+ row: this.inputs.grid.maxRowCount(),
468
+ col: this.inputs.grid.maxColCount()
469
+ }, () => false);
470
+ }
471
+ isSelectable(cell) {
472
+ return cell.selectable() && !cell.disabled();
473
+ }
474
+ *_validCells(fromCoords, toCoords) {
475
+ const startRow = Math.min(fromCoords.row, toCoords.row);
476
+ const startCol = Math.min(fromCoords.col, toCoords.col);
477
+ const endRow = Math.max(fromCoords.row, toCoords.row);
478
+ const endCol = Math.max(fromCoords.col, toCoords.col);
479
+ const visited = new Set();
480
+ for (let row = startRow; row < endRow + 1; row++) {
481
+ for (let col = startCol; col < endCol + 1; col++) {
482
+ const cell = this.inputs.grid.getCell({
483
+ row,
484
+ col
485
+ });
486
+ if (cell === undefined) continue;
487
+ if (!this.isSelectable(cell)) continue;
488
+ if (visited.has(cell)) continue;
489
+ visited.add(cell);
490
+ yield cell;
491
+ }
492
+ }
493
+ }
494
+ _updateState(fromCoords, toCoords, stateFn) {
495
+ const undoList = [];
496
+ for (const cell of this._validCells(fromCoords, toCoords)) {
497
+ const oldState = cell.selected();
498
+ undoList.push([cell, oldState]);
499
+ cell.selected.set(stateFn(oldState));
500
+ }
501
+ this._undoList.set(undoList);
502
+ }
503
+ }
504
+
505
+ class Grid {
506
+ inputs;
507
+ data;
508
+ focusBehavior;
509
+ navigationBehavior;
510
+ selectionBehavior;
511
+ selectionAnchor = linkedSignal(() => this.focusBehavior.activeCoords());
512
+ selectionAnchorCell = computed(() => this.data.getCell(this.selectionAnchor()));
513
+ selectionStabled = signal(true);
514
+ allSelected = computed(() => this.data.cells().flat().filter(c => this.selectionBehavior.isSelectable(c)).every(c => c.selected()));
515
+ gridTabIndex = () => this.focusBehavior.gridTabIndex();
516
+ gridDisabled = () => this.focusBehavior.gridDisabled();
517
+ activeDescendant = () => this.focusBehavior.activeDescendant();
518
+ constructor(inputs) {
519
+ this.inputs = inputs;
520
+ this.data = new GridData(inputs);
521
+ this.focusBehavior = new GridFocus({
522
+ ...inputs,
523
+ grid: this.data
524
+ });
525
+ this.navigationBehavior = new GridNavigation({
526
+ ...inputs,
527
+ grid: this.data,
528
+ gridFocus: this.focusBehavior
529
+ });
530
+ this.selectionBehavior = new GridSelection({
531
+ ...inputs,
532
+ grid: this.data,
533
+ gridFocus: this.focusBehavior
534
+ });
535
+ }
536
+ rowIndex(cell) {
537
+ const index = this.data.getCoords(cell)?.row;
538
+ return index !== undefined ? index + 1 : undefined;
539
+ }
540
+ colIndex(cell) {
541
+ const index = this.data.getCoords(cell)?.col;
542
+ return index !== undefined ? index + 1 : undefined;
543
+ }
544
+ cellTabIndex(cell) {
545
+ return this.focusBehavior.getCellTabIndex(cell);
546
+ }
547
+ up(opts = {}) {
548
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peek(direction.Up, this.selectionAnchor(), 'nowrap', true)) : this.navigationBehavior.advance(direction.Up), opts);
549
+ }
550
+ down(opts = {}) {
551
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peek(direction.Down, this.selectionAnchor(), 'nowrap', true)) : this.navigationBehavior.advance(direction.Down), opts);
552
+ }
553
+ left(opts = {}) {
554
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peek(direction.Left, this.selectionAnchor(), 'nowrap', true)) : this.navigationBehavior.advance(direction.Left), opts);
555
+ }
556
+ right(opts = {}) {
557
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peek(direction.Right, this.selectionAnchor(), 'nowrap', true)) : this.navigationBehavior.advance(direction.Right), opts);
558
+ }
559
+ first(opts = {}) {
560
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peekFirst(undefined, true)) : this.navigationBehavior.first(), opts);
561
+ }
562
+ firstInRow(opts = {}) {
563
+ const row = this.focusBehavior.activeCoords().row;
564
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peekFirst(row, true)) : this.navigationBehavior.first(row), opts);
565
+ }
566
+ last(opts = {}) {
567
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peekLast(undefined, true)) : this.navigationBehavior.last(), opts);
568
+ }
569
+ lastInRow(opts = {}) {
570
+ const row = this.focusBehavior.activeCoords().row;
571
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.navigationBehavior.peekLast(row, true)) : this.navigationBehavior.last(row), opts);
572
+ }
573
+ selectRow() {
574
+ const row = this.focusBehavior.activeCoords().row;
575
+ this.selectionBehavior.deselectAll();
576
+ this.selectionBehavior.select({
577
+ row,
578
+ col: 0
579
+ }, {
580
+ row,
581
+ col: this.data.maxColCount()
582
+ });
583
+ }
584
+ selectCol() {
585
+ const col = this.focusBehavior.activeCoords().col;
586
+ this.selectionBehavior.deselectAll();
587
+ this.selectionBehavior.select({
588
+ row: 0,
589
+ col
590
+ }, {
591
+ row: this.data.maxRowCount(),
592
+ col
593
+ });
594
+ }
595
+ select() {
596
+ this.selectionBehavior.select(this.focusBehavior.activeCoords());
597
+ }
598
+ deselect() {
599
+ this.selectionBehavior.deselect(this.focusBehavior.activeCoords());
600
+ }
601
+ toggle() {
602
+ this.selectionBehavior.toggle(this.focusBehavior.activeCoords());
603
+ }
604
+ toggleOne() {
605
+ const selected = !!this.focusBehavior.activeCell()?.selected();
606
+ if (selected) {
607
+ this.deselect();
608
+ return;
609
+ }
610
+ this.deselectAll();
611
+ this.select();
612
+ }
613
+ selectAll() {
614
+ this.selectionBehavior.selectAll();
615
+ }
616
+ deselectAll() {
617
+ this.selectionBehavior.deselectAll();
618
+ }
619
+ gotoCell(cell, opts = {}) {
620
+ return this._navigateWithSelection(() => opts.anchor ? this._updateSelectionAnchor(() => this.data.getCoords(cell)) : this.navigationBehavior.gotoCell(cell), opts);
621
+ }
622
+ setDefaultState() {
623
+ const focusableSelectedCell = this.data.cells().flat().filter(c => this.focusBehavior.isFocusable(c)).find(c => c.selected());
624
+ if (focusableSelectedCell !== undefined) {
625
+ this.focusBehavior.focusCell(focusableSelectedCell);
626
+ return true;
627
+ }
628
+ const firstFocusableCoords = this.navigationBehavior.peekFirst();
629
+ if (firstFocusableCoords !== undefined) {
630
+ return this.focusBehavior.focusCoordinates(firstFocusableCoords);
631
+ }
632
+ return false;
633
+ }
634
+ resetState() {
635
+ if (this.focusBehavior.stateEmpty()) {
636
+ return this.setDefaultState();
637
+ }
638
+ if (this.focusBehavior.stateStale()) {
639
+ if (this.focusBehavior.focusCell(this.focusBehavior.activeCell())) {
640
+ return true;
641
+ }
642
+ if (this.focusBehavior.focusCoordinates(this.focusBehavior.activeCoords())) {
643
+ return true;
644
+ }
645
+ if (this.focusBehavior.focusCoordinates(this.navigationBehavior.peekFirst())) {
646
+ return true;
647
+ }
648
+ }
649
+ return false;
650
+ }
651
+ _updateSelectionAnchor(peekFn) {
652
+ const coords = peekFn();
653
+ const success = coords !== undefined;
654
+ if (!success) return false;
655
+ this.selectionAnchor.set(coords);
656
+ return success;
657
+ }
658
+ _updateRangeSelection() {
659
+ if (!this.selectionStabled()) {
660
+ this.selectionBehavior.undo();
661
+ }
662
+ this.selectionBehavior.select(...this._getSelectionCoords(this.focusBehavior.activeCoords(), this.selectionAnchor()));
663
+ }
664
+ _getSelectionCoords(startCoords, endCoords) {
665
+ const startCell = this.data.getCell(startCoords);
666
+ const endCell = this.data.getCell(endCoords);
667
+ const allCoords = [...this.data.getAllCoords(startCell), ...this.data.getAllCoords(endCell)];
668
+ const allRows = allCoords.map(c => c.row);
669
+ const allCols = allCoords.map(c => c.col);
670
+ const fromCoords = {
671
+ row: Math.min(...allRows),
672
+ col: Math.min(...allCols)
673
+ };
674
+ const toCoords = {
675
+ row: Math.max(...allRows),
676
+ col: Math.max(...allCols)
677
+ };
678
+ return [fromCoords, toCoords];
679
+ }
680
+ _navigateWithSelection(op, opts = {}) {
681
+ const success = op();
682
+ if (!success) return false;
683
+ if (opts.anchor) {
684
+ this._updateRangeSelection();
685
+ this.selectionStabled.set(false);
686
+ return success;
687
+ }
688
+ this.selectionStabled.set(true);
689
+ if (opts.select) {
690
+ this.select();
691
+ return success;
692
+ }
693
+ if (opts.selectOne) {
694
+ this.deselectAll();
695
+ this.select();
696
+ return success;
697
+ }
698
+ if (opts.toggle) {
699
+ this.toggle();
700
+ return success;
701
+ }
702
+ if (opts.toggleOne) {
703
+ const selected = !!this.focusBehavior.activeCell()?.selected();
704
+ this.deselectAll();
705
+ if (!selected) {
706
+ this.select();
707
+ }
708
+ return success;
709
+ }
710
+ return success;
711
+ }
712
+ }
713
+
714
+ class GridPattern {
715
+ inputs;
716
+ gridBehavior;
717
+ cells = computed(() => this.gridBehavior.data.cells());
718
+ tabIndex = computed(() => this.gridBehavior.gridTabIndex());
719
+ disabled = computed(() => this.gridBehavior.gridDisabled());
720
+ activeDescendant = computed(() => this.gridBehavior.activeDescendant());
721
+ activeCell = computed(() => this.gridBehavior.focusBehavior.activeCell());
722
+ anchorCell = computed(() => this.inputs.enableSelection() && this.inputs.multi() ? this.gridBehavior.selectionAnchorCell() : undefined);
723
+ pauseNavigation = computed(() => this.gridBehavior.data.cells().flat().reduce((res, c) => res || c.widgetActivated(), false));
724
+ isFocused = signal(false);
725
+ hasBeenFocused = signal(false);
726
+ dragging = signal(false);
727
+ prevColKey = computed(() => this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft');
728
+ nextColKey = computed(() => this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight');
729
+ keydown = computed(() => {
730
+ const manager = new KeyboardEventManager();
731
+ if (this.pauseNavigation()) {
732
+ return manager;
733
+ }
734
+ const opts = {
735
+ selectOne: this.inputs.enableSelection() && this.inputs.selectionMode() === 'follow'
736
+ };
737
+ 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));
738
+ if (this.inputs.enableSelection() && this.inputs.selectionMode() === 'explicit') {
739
+ manager.on('Enter', () => this.inputs.multi() ? this.gridBehavior.toggle() : this.gridBehavior.toggleOne()).on(' ', () => this.inputs.multi() ? this.gridBehavior.toggle() : this.gridBehavior.toggleOne());
740
+ }
741
+ if (this.inputs.enableSelection() && this.inputs.enableRangeSelection()) {
742
+ manager.on(Modifier.Shift, 'ArrowUp', () => this.gridBehavior.up({
743
+ anchor: true
744
+ })).on(Modifier.Shift, 'ArrowDown', () => this.gridBehavior.down({
745
+ anchor: true
746
+ })).on(Modifier.Shift, this.prevColKey(), () => this.gridBehavior.left({
747
+ anchor: true
748
+ })).on(Modifier.Shift, this.nextColKey(), () => this.gridBehavior.right({
749
+ anchor: true
750
+ })).on(Modifier.Shift, 'Home', () => this.gridBehavior.firstInRow({
751
+ anchor: true
752
+ })).on(Modifier.Shift, 'End', () => this.gridBehavior.lastInRow({
753
+ anchor: true
754
+ })).on([Modifier.Ctrl | Modifier.Shift], 'Home', () => this.gridBehavior.first({
755
+ anchor: true
756
+ })).on([Modifier.Ctrl | Modifier.Shift], 'End', () => this.gridBehavior.last({
757
+ anchor: true
758
+ })).on([Modifier.Ctrl, Modifier.Meta], 'A', () => {
759
+ if (this.gridBehavior.allSelected()) {
760
+ this.gridBehavior.deselectAll();
761
+ } else {
762
+ this.gridBehavior.selectAll();
763
+ }
764
+ }).on([Modifier.Shift], ' ', () => this.gridBehavior.selectRow()).on([Modifier.Ctrl, Modifier.Meta], ' ', () => this.gridBehavior.selectCol());
765
+ }
766
+ return manager;
767
+ });
768
+ pointerdown = computed(() => {
769
+ const manager = new PointerEventManager();
770
+ if (!this.inputs.enableSelection()) {
771
+ manager.on(e => {
772
+ const cell = this.inputs.getCell(e.target);
773
+ if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return;
774
+ this.gridBehavior.gotoCell(cell);
775
+ });
776
+ }
777
+ if (this.inputs.enableSelection()) {
778
+ manager.on(e => {
779
+ const cell = this.inputs.getCell(e.target);
780
+ if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return;
781
+ this.gridBehavior.gotoCell(cell, {
782
+ selectOne: this.inputs.selectionMode() === 'follow',
783
+ toggleOne: this.inputs.selectionMode() === 'explicit' && !this.inputs.multi(),
784
+ toggle: this.inputs.selectionMode() === 'explicit' && this.inputs.multi()
785
+ });
786
+ if (this.inputs.multi() && this.inputs.enableRangeSelection()) {
787
+ this.dragging.set(true);
788
+ }
789
+ });
790
+ if (this.inputs.multi()) {
791
+ manager.on([Modifier.Ctrl, Modifier.Meta], e => {
792
+ const cell = this.inputs.getCell(e.target);
793
+ if (!cell || !this.gridBehavior.focusBehavior.isFocusable(cell)) return;
794
+ this.gridBehavior.gotoCell(cell, {
795
+ toggle: true
796
+ });
797
+ if (this.inputs.enableRangeSelection()) {
798
+ this.dragging.set(true);
799
+ }
800
+ });
801
+ if (this.inputs.enableRangeSelection()) {
802
+ manager.on(Modifier.Shift, e => {
803
+ const cell = this.inputs.getCell(e.target);
804
+ if (!cell) return;
805
+ this.gridBehavior.gotoCell(cell, {
806
+ anchor: true
807
+ });
808
+ this.dragging.set(true);
809
+ });
810
+ }
811
+ }
812
+ }
813
+ return manager;
814
+ });
815
+ pointerup = computed(() => {
816
+ const manager = new PointerEventManager();
817
+ if (this.inputs.enableSelection() && this.inputs.enableRangeSelection()) {
818
+ manager.on([Modifier.Shift, Modifier.Ctrl, Modifier.Meta, Modifier.None], () => {
819
+ this.dragging.set(false);
820
+ });
821
+ }
822
+ return manager;
823
+ });
824
+ _maybeDeletion = signal(false);
825
+ _deletion = signal(false);
826
+ constructor(inputs) {
827
+ this.inputs = inputs;
828
+ this.gridBehavior = new Grid({
829
+ ...inputs,
830
+ cells: computed(() => this.inputs.rows().map(row => row.inputs.cells()))
831
+ });
832
+ }
833
+ onKeydown(event) {
834
+ if (!this.disabled()) {
835
+ this.keydown().handle(event);
836
+ }
837
+ }
838
+ onPointerdown(event) {
839
+ if (!this.disabled()) {
840
+ this.pointerdown().handle(event);
841
+ }
842
+ }
843
+ onPointermove(event) {
844
+ if (this.disabled()) return;
845
+ if (!this.inputs.enableSelection()) return;
846
+ if (!this.inputs.enableRangeSelection()) return;
847
+ if (!this.dragging()) return;
848
+ const cell = this.inputs.getCell(event.target);
849
+ if (!cell) return;
850
+ this.gridBehavior.gotoCell(cell, {
851
+ anchor: true
852
+ });
853
+ }
854
+ onPointerup(event) {
855
+ if (!this.disabled()) {
856
+ this.pointerup().handle(event);
857
+ }
858
+ }
859
+ onFocusIn() {
860
+ this.isFocused.set(true);
861
+ this.hasBeenFocused.set(true);
862
+ }
863
+ onFocusOut(event) {
864
+ const parentEl = this.inputs.element();
865
+ const targetEl = event.relatedTarget;
866
+ if (targetEl === null) {
867
+ this._maybeDeletion.set(true);
868
+ }
869
+ if (parentEl.contains(targetEl)) return;
870
+ this.isFocused.set(false);
871
+ }
872
+ setDefaultStateEffect() {
873
+ if (this.hasBeenFocused()) return;
874
+ this.gridBehavior.setDefaultState();
875
+ }
876
+ resetStateEffect() {
877
+ const hasReset = this.gridBehavior.resetState();
878
+ if (hasReset && this._maybeDeletion()) {
879
+ this._deletion.set(true);
880
+ }
881
+ this._maybeDeletion.set(false);
882
+ }
883
+ focusEffect() {
884
+ const activeCell = this.activeCell();
885
+ const hasFocus = this.isFocused();
886
+ const deletion = this._deletion();
887
+ const isRoving = this.inputs.focusMode() === 'roving';
888
+ if (activeCell !== undefined && isRoving && (hasFocus || deletion)) {
889
+ activeCell.element().focus();
890
+ if (deletion) {
891
+ this._deletion.set(false);
892
+ }
893
+ }
894
+ }
895
+ }
896
+
897
+ class GridRowPattern {
898
+ inputs;
899
+ rowIndex;
900
+ constructor(inputs) {
901
+ this.inputs = inputs;
902
+ this.rowIndex = inputs.rowIndex;
903
+ }
904
+ }
905
+
906
+ class GridCellPattern {
907
+ inputs;
908
+ id;
909
+ disabled;
910
+ selected;
911
+ selectable;
912
+ rowSpan;
913
+ colSpan;
914
+ ariaSelected = computed(() => this.inputs.grid().inputs.enableSelection() && this.selectable() ? this.selected() : undefined);
915
+ ariaRowIndex = computed(() => this.inputs.row().rowIndex() ?? this.inputs.rowIndex() ?? this.inputs.grid().gridBehavior.rowIndex(this));
916
+ ariaColIndex = computed(() => this.inputs.colIndex() ?? this.inputs.grid().gridBehavior.colIndex(this));
917
+ element = computed(() => this.inputs.widget()?.element() ?? this.inputs.element());
918
+ active = computed(() => this.inputs.grid().activeCell() === this);
919
+ anchor = computed(() => this.inputs.grid().anchorCell() === this ? true : undefined);
920
+ _tabIndex = computed(() => this.inputs.grid().gridBehavior.cellTabIndex(this));
921
+ tabIndex = computed(() => this.inputs.widget() !== undefined ? -1 : this._tabIndex());
922
+ widgetActivated = computed(() => this.inputs.widget()?.inputs.activate() ?? false);
923
+ constructor(inputs) {
924
+ this.inputs = inputs;
925
+ this.id = inputs.id;
926
+ this.disabled = inputs.disabled;
927
+ this.rowSpan = inputs.rowSpan;
928
+ this.colSpan = inputs.colSpan;
929
+ this.selected = inputs.selected;
930
+ this.selectable = inputs.selectable;
931
+ }
932
+ widgetTabIndex() {
933
+ return this._tabIndex();
934
+ }
935
+ }
936
+
937
+ class GridCellWidgetPattern {
938
+ inputs;
939
+ element;
940
+ tabIndex = computed(() => this.inputs.cell().widgetTabIndex());
941
+ active = computed(() => this.inputs.cell().active());
942
+ constructor(inputs) {
943
+ this.inputs = inputs;
944
+ this.element = inputs.element;
945
+ }
946
+ }
947
+
948
+ export { GridCellPattern, GridCellWidgetPattern, GridPattern, GridRowPattern, KeyboardEventManager, Modifier, PointerEventManager };
949
+ //# sourceMappingURL=_widget-chunk.mjs.map