@angular/aria 21.0.1 → 21.0.3

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 (56) hide show
  1. package/fesm2022/_combobox-chunk.mjs +425 -0
  2. package/fesm2022/_combobox-chunk.mjs.map +1 -0
  3. package/fesm2022/_combobox-listbox-chunk.mjs +522 -0
  4. package/fesm2022/_combobox-listbox-chunk.mjs.map +1 -0
  5. package/fesm2022/_combobox-popup-chunk.mjs +46 -0
  6. package/fesm2022/_combobox-popup-chunk.mjs.map +1 -0
  7. package/fesm2022/_list-navigation-chunk.mjs +116 -0
  8. package/fesm2022/_list-navigation-chunk.mjs.map +1 -0
  9. package/fesm2022/_pointer-event-manager-chunk.mjs +134 -0
  10. package/fesm2022/_pointer-event-manager-chunk.mjs.map +1 -0
  11. package/fesm2022/_widget-chunk.mjs +4 -246
  12. package/fesm2022/_widget-chunk.mjs.map +1 -1
  13. package/fesm2022/accordion.mjs +17 -4
  14. package/fesm2022/accordion.mjs.map +1 -1
  15. package/fesm2022/aria.mjs +1 -1
  16. package/fesm2022/aria.mjs.map +1 -1
  17. package/fesm2022/combobox.mjs +96 -120
  18. package/fesm2022/combobox.mjs.map +1 -1
  19. package/fesm2022/grid.mjs +225 -201
  20. package/fesm2022/grid.mjs.map +1 -1
  21. package/fesm2022/listbox.mjs +173 -161
  22. package/fesm2022/listbox.mjs.map +1 -1
  23. package/fesm2022/menu.mjs +256 -238
  24. package/fesm2022/menu.mjs.map +1 -1
  25. package/fesm2022/private.mjs +9 -932
  26. package/fesm2022/private.mjs.map +1 -1
  27. package/fesm2022/tabs.mjs +182 -168
  28. package/fesm2022/tabs.mjs.map +1 -1
  29. package/fesm2022/toolbar.mjs +15 -3
  30. package/fesm2022/toolbar.mjs.map +1 -1
  31. package/fesm2022/tree.mjs +4 -2
  32. package/fesm2022/tree.mjs.map +1 -1
  33. package/package.json +2 -2
  34. package/types/_combobox-chunk.d.ts +98 -0
  35. package/types/_combobox-chunk.d2.ts +193 -0
  36. package/types/_grid-chunk.d.ts +3 -210
  37. package/types/_list-chunk.d.ts +212 -0
  38. package/types/_list-navigation-chunk.d.ts +212 -0
  39. package/types/_listbox-chunk.d.ts +106 -0
  40. package/types/accordion.d.ts +52 -49
  41. package/types/combobox.d.ts +25 -111
  42. package/types/grid.d.ts +37 -32
  43. package/types/listbox.d.ts +8 -5
  44. package/types/menu.d.ts +113 -113
  45. package/types/private.d.ts +12 -498
  46. package/types/tabs.d.ts +89 -84
  47. package/types/toolbar.d.ts +69 -66
  48. package/types/tree.d.ts +106 -103
  49. package/_adev_assets/aria-accordion.json +0 -743
  50. package/_adev_assets/aria-combobox.json +0 -607
  51. package/_adev_assets/aria-grid.json +0 -901
  52. package/_adev_assets/aria-listbox.json +0 -544
  53. package/_adev_assets/aria-menu.json +0 -1049
  54. package/_adev_assets/aria-tabs.json +0 -880
  55. package/_adev_assets/aria-toolbar.json +0 -545
  56. package/_adev_assets/aria-tree.json +0 -861
@@ -1,937 +1,12 @@
1
+ export { ComboboxDialogPattern, ComboboxPattern } from './_combobox-chunk.mjs';
2
+ import { List } from './_combobox-listbox-chunk.mjs';
3
+ export { ComboboxListboxPattern, ListboxPattern, OptionPattern } from './_combobox-listbox-chunk.mjs';
1
4
  import * as i0 from '@angular/core';
2
- import { signal, computed, model, Directive, inject, TemplateRef, ViewContainerRef, afterRenderEffect } from '@angular/core';
3
- import { PointerEventManager, KeyboardEventManager, ListFocus, ListNavigation, Modifier } from './_widget-chunk.mjs';
5
+ import { computed, signal, model, Directive, inject, TemplateRef, ViewContainerRef, afterRenderEffect } from '@angular/core';
6
+ import { KeyboardEventManager, PointerEventManager, Modifier } from './_pointer-event-manager-chunk.mjs';
7
+ import { ListFocus, ListNavigation } from './_list-navigation-chunk.mjs';
4
8
  export { GridCellPattern, GridCellWidgetPattern, GridPattern, GridRowPattern } from './_widget-chunk.mjs';
5
9
 
6
- class ComboboxPattern {
7
- inputs;
8
- expanded = signal(false);
9
- disabled = () => this.inputs.disabled();
10
- activeDescendant = computed(() => {
11
- const popupControls = this.inputs.popupControls();
12
- if (popupControls instanceof ComboboxDialogPattern) {
13
- return null;
14
- }
15
- return popupControls?.activeId() ?? null;
16
- });
17
- highlightedItem = signal(undefined);
18
- isDeleting = false;
19
- isFocused = signal(false);
20
- hasBeenFocused = signal(false);
21
- expandKey = computed(() => this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight');
22
- collapseKey = computed(() => this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft');
23
- popupId = computed(() => this.inputs.popupControls()?.id() || null);
24
- autocomplete = computed(() => this.inputs.filterMode() === 'highlight' ? 'both' : 'list');
25
- hasPopup = computed(() => this.inputs.popupControls()?.role() || null);
26
- readonly = computed(() => this.inputs.readonly() || this.inputs.disabled() || null);
27
- listControls = () => {
28
- const popupControls = this.inputs.popupControls();
29
- if (popupControls instanceof ComboboxDialogPattern) {
30
- return null;
31
- }
32
- return popupControls;
33
- };
34
- treeControls = () => {
35
- const popupControls = this.inputs.popupControls();
36
- if (popupControls?.role() === 'tree') {
37
- return popupControls;
38
- }
39
- return null;
40
- };
41
- keydown = computed(() => {
42
- const manager = new KeyboardEventManager();
43
- const popupControls = this.inputs.popupControls();
44
- if (!popupControls) {
45
- return manager;
46
- }
47
- if (popupControls instanceof ComboboxDialogPattern) {
48
- if (!this.expanded()) {
49
- manager.on('ArrowUp', () => this.open()).on('ArrowDown', () => this.open());
50
- if (this.readonly()) {
51
- manager.on('Enter', () => this.open()).on(' ', () => this.open());
52
- }
53
- }
54
- return manager;
55
- }
56
- if (!this.inputs.alwaysExpanded()) {
57
- manager.on('Escape', () => this.close({
58
- reset: !this.readonly()
59
- }));
60
- }
61
- if (!this.expanded()) {
62
- manager.on('ArrowDown', () => this.open({
63
- first: true
64
- })).on('ArrowUp', () => this.open({
65
- last: true
66
- }));
67
- if (this.readonly()) {
68
- manager.on('Enter', () => this.open({
69
- selected: true
70
- })).on(' ', () => this.open({
71
- selected: true
72
- }));
73
- }
74
- return manager;
75
- }
76
- manager.on('ArrowDown', () => this.next()).on('ArrowUp', () => this.prev()).on('Home', () => this.first()).on('End', () => this.last());
77
- if (this.readonly()) {
78
- manager.on(' ', () => this.select({
79
- commit: true,
80
- close: !popupControls.multi()
81
- }));
82
- }
83
- if (popupControls.role() === 'listbox') {
84
- manager.on('Enter', () => {
85
- this.select({
86
- commit: true,
87
- close: !popupControls.multi()
88
- });
89
- });
90
- }
91
- const treeControls = this.treeControls();
92
- if (treeControls?.isItemSelectable()) {
93
- manager.on('Enter', () => this.select({
94
- commit: true,
95
- close: true
96
- }));
97
- }
98
- if (treeControls?.isItemExpandable()) {
99
- manager.on(this.expandKey(), () => this.expandItem()).on(this.collapseKey(), () => this.collapseItem());
100
- if (!treeControls.isItemSelectable()) {
101
- manager.on('Enter', () => this.expandItem());
102
- }
103
- }
104
- if (treeControls?.isItemCollapsible()) {
105
- manager.on(this.collapseKey(), () => this.collapseItem());
106
- }
107
- return manager;
108
- });
109
- click = computed(() => new PointerEventManager().on(e => {
110
- if (e.target === this.inputs.inputEl()) {
111
- if (this.readonly()) {
112
- this.expanded() ? this.close() : this.open({
113
- selected: true
114
- });
115
- }
116
- }
117
- const controls = this.inputs.popupControls();
118
- if (controls instanceof ComboboxDialogPattern) {
119
- return;
120
- }
121
- const item = controls?.getItem(e);
122
- if (item) {
123
- if (controls?.role() === 'tree') {
124
- const treeControls = controls;
125
- if (treeControls.isItemExpandable(item) && !treeControls.isItemSelectable(item)) {
126
- treeControls.toggleExpansion(item);
127
- this.inputs.inputEl()?.focus();
128
- return;
129
- }
130
- }
131
- this.select({
132
- item,
133
- commit: true,
134
- close: !controls?.multi()
135
- });
136
- this.inputs.inputEl()?.focus();
137
- }
138
- }));
139
- constructor(inputs) {
140
- this.inputs = inputs;
141
- }
142
- onKeydown(event) {
143
- if (!this.inputs.disabled()) {
144
- this.keydown().handle(event);
145
- }
146
- }
147
- onClick(event) {
148
- if (!this.inputs.disabled()) {
149
- this.click().handle(event);
150
- }
151
- }
152
- onInput(event) {
153
- if (this.inputs.disabled() || this.inputs.readonly()) {
154
- return;
155
- }
156
- const inputEl = this.inputs.inputEl();
157
- if (!inputEl) {
158
- return;
159
- }
160
- const popupControls = this.inputs.popupControls();
161
- if (popupControls instanceof ComboboxDialogPattern) {
162
- return;
163
- }
164
- this.open();
165
- this.inputs.inputValue?.set(inputEl.value);
166
- this.isDeleting = event instanceof InputEvent && !!event.inputType.match(/^delete/);
167
- if (this.inputs.filterMode() === 'highlight' && !this.isDeleting) {
168
- this.highlight();
169
- }
170
- }
171
- onFocusIn() {
172
- if (this.inputs.alwaysExpanded() && !this.hasBeenFocused()) {
173
- const firstSelectedItem = this.listControls()?.getSelectedItems()[0];
174
- firstSelectedItem ? this.listControls()?.focus(firstSelectedItem) : this.first();
175
- }
176
- this.isFocused.set(true);
177
- this.hasBeenFocused.set(true);
178
- }
179
- onFocusOut(event) {
180
- if (this.inputs.disabled()) {
181
- return;
182
- }
183
- const popupControls = this.inputs.popupControls();
184
- if (popupControls instanceof ComboboxDialogPattern) {
185
- return;
186
- }
187
- if (!(event.relatedTarget instanceof HTMLElement) || !this.inputs.containerEl()?.contains(event.relatedTarget)) {
188
- this.isFocused.set(false);
189
- if (this.readonly()) {
190
- this.close();
191
- return;
192
- }
193
- if (this.inputs.filterMode() !== 'manual') {
194
- this.commit();
195
- } else {
196
- const item = popupControls?.items().find(i => i.searchTerm() === this.inputs.inputEl()?.value);
197
- if (item) {
198
- this.select({
199
- item
200
- });
201
- }
202
- }
203
- this.close();
204
- }
205
- }
206
- firstMatch = computed(() => {
207
- if (this.listControls()?.role() === 'listbox') {
208
- return this.listControls()?.items()[0];
209
- }
210
- return this.listControls()?.items().find(i => i.value() === this.inputs.firstMatch());
211
- });
212
- onFilter() {
213
- if (this.readonly()) {
214
- return;
215
- }
216
- const popupControls = this.inputs.popupControls();
217
- if (popupControls instanceof ComboboxDialogPattern) {
218
- return;
219
- }
220
- const isInitialRender = !this.inputs.inputValue?.().length && !this.isDeleting;
221
- if (isInitialRender) {
222
- return;
223
- }
224
- if (!this.isFocused()) {
225
- return;
226
- }
227
- if (this.inputs.popupControls()?.role() === 'tree') {
228
- const treeControls = this.inputs.popupControls();
229
- this.inputs.inputValue?.().length ? treeControls.expandAll() : treeControls.collapseAll();
230
- }
231
- const item = this.firstMatch();
232
- if (!item) {
233
- popupControls?.clearSelection();
234
- popupControls?.unfocus();
235
- return;
236
- }
237
- popupControls?.focus(item);
238
- if (this.inputs.filterMode() !== 'manual') {
239
- this.select({
240
- item
241
- });
242
- }
243
- if (this.inputs.filterMode() === 'highlight' && !this.isDeleting) {
244
- this.highlight();
245
- }
246
- }
247
- highlight() {
248
- const inputEl = this.inputs.inputEl();
249
- const selectedItems = this.listControls()?.getSelectedItems();
250
- const item = selectedItems?.[0];
251
- if (!inputEl || !item) {
252
- return;
253
- }
254
- const isHighlightable = item.searchTerm().toLowerCase().startsWith(this.inputs.inputValue().toLowerCase());
255
- if (isHighlightable) {
256
- inputEl.value = this.inputs.inputValue() + item.searchTerm().slice(this.inputs.inputValue().length);
257
- inputEl.setSelectionRange(this.inputs.inputValue().length, item.searchTerm().length);
258
- this.highlightedItem.set(item);
259
- }
260
- }
261
- close(opts) {
262
- const popupControls = this.inputs.popupControls();
263
- if (this.inputs.alwaysExpanded()) {
264
- return;
265
- }
266
- if (popupControls instanceof ComboboxDialogPattern) {
267
- this.expanded.set(false);
268
- return;
269
- }
270
- if (this.readonly()) {
271
- this.expanded.set(false);
272
- popupControls?.unfocus();
273
- return;
274
- }
275
- if (!opts?.reset) {
276
- if (this.inputs.filterMode() === 'manual') {
277
- if (!this.listControls()?.items().some(i => i.searchTerm() === this.inputs.inputEl()?.value)) {
278
- this.listControls()?.clearSelection();
279
- }
280
- }
281
- this.expanded.set(false);
282
- popupControls?.unfocus();
283
- return;
284
- }
285
- if (!this.expanded()) {
286
- this.inputs.inputValue?.set('');
287
- popupControls?.clearSelection();
288
- const inputEl = this.inputs.inputEl();
289
- if (inputEl) {
290
- inputEl.value = '';
291
- }
292
- } else if (this.expanded()) {
293
- this.expanded.set(false);
294
- const selectedItem = popupControls?.getSelectedItems()?.[0];
295
- if (selectedItem?.searchTerm() !== this.inputs.inputValue()) {
296
- popupControls?.clearSelection();
297
- }
298
- return;
299
- }
300
- this.close();
301
- if (!this.readonly()) {
302
- popupControls?.clearSelection();
303
- }
304
- }
305
- open(nav) {
306
- this.expanded.set(true);
307
- const popupControls = this.inputs.popupControls();
308
- if (popupControls instanceof ComboboxDialogPattern) {
309
- return;
310
- }
311
- const inputEl = this.inputs.inputEl();
312
- if (inputEl && this.inputs.filterMode() === 'highlight') {
313
- const isHighlighting = inputEl.selectionStart !== inputEl.value.length;
314
- this.inputs.inputValue?.set(inputEl.value.slice(0, inputEl.selectionStart || 0));
315
- if (!isHighlighting) {
316
- this.highlightedItem.set(undefined);
317
- }
318
- }
319
- if (nav?.first) {
320
- this.first();
321
- }
322
- if (nav?.last) {
323
- this.last();
324
- }
325
- if (nav?.selected) {
326
- const selectedItem = popupControls?.items().find(i => popupControls?.getSelectedItems().includes(i));
327
- if (selectedItem) {
328
- popupControls?.focus(selectedItem);
329
- }
330
- }
331
- }
332
- next() {
333
- this._navigate(() => this.listControls()?.next());
334
- }
335
- prev() {
336
- this._navigate(() => this.listControls()?.prev());
337
- }
338
- first() {
339
- this._navigate(() => this.listControls()?.first());
340
- }
341
- last() {
342
- this._navigate(() => this.listControls()?.last());
343
- }
344
- collapseItem() {
345
- const controls = this.inputs.popupControls();
346
- this._navigate(() => controls?.collapseItem());
347
- }
348
- expandItem() {
349
- const controls = this.inputs.popupControls();
350
- this._navigate(() => controls?.expandItem());
351
- }
352
- select(opts = {}) {
353
- const controls = this.listControls();
354
- if (opts.item) {
355
- controls?.focus(opts.item, {
356
- focusElement: false
357
- });
358
- }
359
- controls?.multi() ? controls.toggle(opts.item) : controls?.select(opts.item);
360
- if (opts.commit) {
361
- this.commit();
362
- }
363
- if (opts.close) {
364
- this.close();
365
- }
366
- }
367
- commit() {
368
- const inputEl = this.inputs.inputEl();
369
- const selectedItems = this.listControls()?.getSelectedItems();
370
- if (!inputEl) {
371
- return;
372
- }
373
- inputEl.value = selectedItems?.map(i => i.searchTerm()).join(', ') || '';
374
- this.inputs.inputValue?.set(inputEl.value);
375
- if (this.inputs.filterMode() === 'highlight' && !this.readonly()) {
376
- const length = inputEl.value.length;
377
- inputEl.setSelectionRange(length, length);
378
- }
379
- }
380
- _navigate(operation) {
381
- operation();
382
- if (this.inputs.filterMode() !== 'manual') {
383
- this.select();
384
- }
385
- if (this.inputs.filterMode() === 'highlight') {
386
- const selectedItem = this.listControls()?.getSelectedItems()[0];
387
- if (!selectedItem) {
388
- return;
389
- }
390
- if (selectedItem === this.highlightedItem()) {
391
- this.highlight();
392
- } else {
393
- const inputEl = this.inputs.inputEl();
394
- inputEl.value = selectedItem?.searchTerm();
395
- }
396
- }
397
- }
398
- }
399
- class ComboboxDialogPattern {
400
- inputs;
401
- id = () => this.inputs.id();
402
- role = () => 'dialog';
403
- keydown = computed(() => {
404
- return new KeyboardEventManager().on('Escape', () => this.inputs.combobox.close());
405
- });
406
- constructor(inputs) {
407
- this.inputs = inputs;
408
- }
409
- onKeydown(event) {
410
- this.keydown().handle(event);
411
- }
412
- onClick(event) {
413
- if (event.target === this.inputs.element()) {
414
- this.inputs.combobox.close();
415
- }
416
- }
417
- }
418
-
419
- class ListSelection {
420
- inputs;
421
- rangeStartIndex = signal(0);
422
- rangeEndIndex = signal(0);
423
- selectedItems = computed(() => this.inputs.items().filter(item => this.inputs.values().includes(item.value())));
424
- constructor(inputs) {
425
- this.inputs = inputs;
426
- }
427
- select(item, opts = {
428
- anchor: true
429
- }) {
430
- item = item ?? this.inputs.focusManager.inputs.activeItem();
431
- if (!item || item.disabled() || !item.selectable() || this.inputs.values().includes(item.value())) {
432
- return;
433
- }
434
- if (!this.inputs.multi()) {
435
- this.deselectAll();
436
- }
437
- const index = this.inputs.items().findIndex(i => i === item);
438
- if (opts.anchor) {
439
- this.beginRangeSelection(index);
440
- }
441
- this.inputs.values.update(values => values.concat(item.value()));
442
- }
443
- deselect(item) {
444
- item = item ?? this.inputs.focusManager.inputs.activeItem();
445
- if (item && !item.disabled() && item.selectable()) {
446
- this.inputs.values.update(values => values.filter(value => value !== item.value()));
447
- }
448
- }
449
- toggle(item) {
450
- item = item ?? this.inputs.focusManager.inputs.activeItem();
451
- if (item) {
452
- this.inputs.values().includes(item.value()) ? this.deselect(item) : this.select(item);
453
- }
454
- }
455
- toggleOne() {
456
- const item = this.inputs.focusManager.inputs.activeItem();
457
- if (item) {
458
- this.inputs.values().includes(item.value()) ? this.deselect() : this.selectOne();
459
- }
460
- }
461
- selectAll() {
462
- if (!this.inputs.multi()) {
463
- return;
464
- }
465
- for (const item of this.inputs.items()) {
466
- this.select(item, {
467
- anchor: false
468
- });
469
- }
470
- this.beginRangeSelection();
471
- }
472
- deselectAll() {
473
- for (const value of this.inputs.values()) {
474
- const item = this.inputs.items().find(i => i.value() === value);
475
- item ? this.deselect(item) : this.inputs.values.update(values => values.filter(v => v !== value));
476
- }
477
- }
478
- toggleAll() {
479
- const selectableValues = this.inputs.items().filter(i => !i.disabled() && i.selectable()).map(i => i.value());
480
- selectableValues.every(i => this.inputs.values().includes(i)) ? this.deselectAll() : this.selectAll();
481
- }
482
- selectOne() {
483
- const item = this.inputs.focusManager.inputs.activeItem();
484
- if (item && (item.disabled() || !item.selectable())) {
485
- return;
486
- }
487
- this.deselectAll();
488
- if (this.inputs.values().length > 0 && !this.inputs.multi()) {
489
- return;
490
- }
491
- this.select();
492
- }
493
- selectRange(opts = {
494
- anchor: true
495
- }) {
496
- const isStartOfRange = this.inputs.focusManager.prevActiveIndex() === this.rangeStartIndex();
497
- if (isStartOfRange && opts.anchor) {
498
- this.beginRangeSelection(this.inputs.focusManager.prevActiveIndex());
499
- }
500
- const itemsInRange = this._getItemsFromIndex(this.rangeStartIndex());
501
- const itemsOutOfRange = this._getItemsFromIndex(this.rangeEndIndex()).filter(i => !itemsInRange.includes(i));
502
- for (const item of itemsOutOfRange) {
503
- this.deselect(item);
504
- }
505
- for (const item of itemsInRange) {
506
- this.select(item, {
507
- anchor: false
508
- });
509
- }
510
- if (itemsInRange.length) {
511
- const item = itemsInRange.pop();
512
- const index = this.inputs.items().findIndex(i => i === item);
513
- this.rangeEndIndex.set(index);
514
- }
515
- }
516
- beginRangeSelection(index = this.inputs.focusManager.activeIndex()) {
517
- this.rangeStartIndex.set(index);
518
- this.rangeEndIndex.set(index);
519
- }
520
- _getItemsFromIndex(index) {
521
- if (index === -1) {
522
- return [];
523
- }
524
- const upper = Math.max(this.inputs.focusManager.activeIndex(), index);
525
- const lower = Math.min(this.inputs.focusManager.activeIndex(), index);
526
- const items = [];
527
- for (let i = lower; i <= upper; i++) {
528
- items.push(this.inputs.items()[i]);
529
- }
530
- if (this.inputs.focusManager.activeIndex() < index) {
531
- return items.reverse();
532
- }
533
- return items;
534
- }
535
- }
536
-
537
- class ListTypeahead {
538
- inputs;
539
- timeout;
540
- focusManager;
541
- isTyping = computed(() => this._query().length > 0);
542
- _query = signal('');
543
- _startIndex = signal(undefined);
544
- constructor(inputs) {
545
- this.inputs = inputs;
546
- this.focusManager = inputs.focusManager;
547
- }
548
- search(char) {
549
- if (char.length !== 1) {
550
- return false;
551
- }
552
- if (!this.isTyping() && char === ' ') {
553
- return false;
554
- }
555
- if (this._startIndex() === undefined) {
556
- this._startIndex.set(this.focusManager.activeIndex());
557
- }
558
- clearTimeout(this.timeout);
559
- this._query.update(q => q + char.toLowerCase());
560
- const item = this._getItem();
561
- if (item) {
562
- this.focusManager.focus(item);
563
- }
564
- this.timeout = setTimeout(() => {
565
- this._query.set('');
566
- this._startIndex.set(undefined);
567
- }, this.inputs.typeaheadDelay());
568
- return true;
569
- }
570
- _getItem() {
571
- let items = this.focusManager.inputs.items();
572
- const after = items.slice(this._startIndex() + 1);
573
- const before = items.slice(0, this._startIndex());
574
- items = after.concat(before);
575
- items.push(this.inputs.items()[this._startIndex()]);
576
- const focusableItems = [];
577
- for (const item of items) {
578
- if (this.focusManager.isFocusable(item)) {
579
- focusableItems.push(item);
580
- }
581
- }
582
- return focusableItems.find(i => i.searchTerm().toLowerCase().startsWith(this._query()));
583
- }
584
- }
585
-
586
- class List {
587
- inputs;
588
- navigationBehavior;
589
- selectionBehavior;
590
- typeaheadBehavior;
591
- focusBehavior;
592
- disabled = computed(() => this.focusBehavior.isListDisabled());
593
- activeDescendant = computed(() => this.focusBehavior.getActiveDescendant());
594
- tabIndex = computed(() => this.focusBehavior.getListTabIndex());
595
- activeIndex = computed(() => this.focusBehavior.activeIndex());
596
- _anchorIndex = signal(0);
597
- _wrap = signal(true);
598
- constructor(inputs) {
599
- this.inputs = inputs;
600
- this.focusBehavior = new ListFocus(inputs);
601
- this.selectionBehavior = new ListSelection({
602
- ...inputs,
603
- focusManager: this.focusBehavior
604
- });
605
- this.typeaheadBehavior = new ListTypeahead({
606
- ...inputs,
607
- focusManager: this.focusBehavior
608
- });
609
- this.navigationBehavior = new ListNavigation({
610
- ...inputs,
611
- focusManager: this.focusBehavior,
612
- wrap: computed(() => this._wrap() && this.inputs.wrap())
613
- });
614
- }
615
- getItemTabindex(item) {
616
- return this.focusBehavior.getItemTabIndex(item);
617
- }
618
- first(opts) {
619
- this._navigate(opts, () => this.navigationBehavior.first(opts));
620
- }
621
- last(opts) {
622
- this._navigate(opts, () => this.navigationBehavior.last(opts));
623
- }
624
- next(opts) {
625
- this._navigate(opts, () => this.navigationBehavior.next(opts));
626
- }
627
- prev(opts) {
628
- this._navigate(opts, () => this.navigationBehavior.prev(opts));
629
- }
630
- goto(item, opts) {
631
- this._navigate(opts, () => this.navigationBehavior.goto(item, opts));
632
- }
633
- unfocus() {
634
- this.inputs.activeItem.set(undefined);
635
- }
636
- anchor(index) {
637
- this._anchorIndex.set(index);
638
- }
639
- search(char, opts) {
640
- this._navigate(opts, () => this.typeaheadBehavior.search(char));
641
- }
642
- isTyping() {
643
- return this.typeaheadBehavior.isTyping();
644
- }
645
- select(item) {
646
- this.selectionBehavior.select(item);
647
- }
648
- selectOne() {
649
- this.selectionBehavior.selectOne();
650
- }
651
- deselect(item) {
652
- this.selectionBehavior.deselect(item);
653
- }
654
- deselectAll() {
655
- this.selectionBehavior.deselectAll();
656
- }
657
- toggle(item) {
658
- this.selectionBehavior.toggle(item);
659
- }
660
- toggleOne() {
661
- this.selectionBehavior.toggleOne();
662
- }
663
- toggleAll() {
664
- this.selectionBehavior.toggleAll();
665
- }
666
- isFocusable(item) {
667
- return this.focusBehavior.isFocusable(item);
668
- }
669
- updateSelection(opts = {
670
- anchor: true
671
- }) {
672
- if (opts.toggle) {
673
- this.selectionBehavior.toggle();
674
- }
675
- if (opts.select) {
676
- this.selectionBehavior.select();
677
- }
678
- if (opts.selectOne) {
679
- this.selectionBehavior.selectOne();
680
- }
681
- if (opts.selectRange) {
682
- this.selectionBehavior.selectRange();
683
- }
684
- if (!opts.anchor) {
685
- this.anchor(this.selectionBehavior.rangeStartIndex());
686
- }
687
- }
688
- _navigate(opts = {}, operation) {
689
- if (opts?.selectRange) {
690
- this._wrap.set(false);
691
- this.selectionBehavior.rangeStartIndex.set(this._anchorIndex());
692
- }
693
- const moved = operation();
694
- if (moved) {
695
- this.updateSelection(opts);
696
- }
697
- this._wrap.set(true);
698
- }
699
- }
700
-
701
- class ListboxPattern {
702
- inputs;
703
- listBehavior;
704
- orientation;
705
- disabled = computed(() => this.listBehavior.disabled());
706
- readonly;
707
- tabIndex = computed(() => this.listBehavior.tabIndex());
708
- activeDescendant = computed(() => this.listBehavior.activeDescendant());
709
- multi;
710
- setsize = computed(() => this.inputs.items().length);
711
- followFocus = computed(() => this.inputs.selectionMode() === 'follow');
712
- wrap = signal(true);
713
- prevKey = computed(() => {
714
- if (this.inputs.orientation() === 'vertical') {
715
- return 'ArrowUp';
716
- }
717
- return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
718
- });
719
- nextKey = computed(() => {
720
- if (this.inputs.orientation() === 'vertical') {
721
- return 'ArrowDown';
722
- }
723
- return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight';
724
- });
725
- dynamicSpaceKey = computed(() => this.listBehavior.isTyping() ? '' : ' ');
726
- typeaheadRegexp = /^.$/;
727
- keydown = computed(() => {
728
- const manager = new KeyboardEventManager();
729
- if (this.readonly()) {
730
- return manager.on(this.prevKey, () => this.listBehavior.prev()).on(this.nextKey, () => this.listBehavior.next()).on('Home', () => this.listBehavior.first()).on('End', () => this.listBehavior.last()).on(this.typeaheadRegexp, e => this.listBehavior.search(e.key));
731
- }
732
- if (!this.followFocus()) {
733
- manager.on(this.prevKey, () => this.listBehavior.prev()).on(this.nextKey, () => this.listBehavior.next()).on('Home', () => this.listBehavior.first()).on('End', () => this.listBehavior.last()).on(this.typeaheadRegexp, e => this.listBehavior.search(e.key));
734
- }
735
- if (this.followFocus()) {
736
- manager.on(this.prevKey, () => this.listBehavior.prev({
737
- selectOne: true
738
- })).on(this.nextKey, () => this.listBehavior.next({
739
- selectOne: true
740
- })).on('Home', () => this.listBehavior.first({
741
- selectOne: true
742
- })).on('End', () => this.listBehavior.last({
743
- selectOne: true
744
- })).on(this.typeaheadRegexp, e => this.listBehavior.search(e.key, {
745
- selectOne: true
746
- }));
747
- }
748
- if (this.inputs.multi()) {
749
- manager.on(Modifier.Any, 'Shift', () => this.listBehavior.anchor(this.listBehavior.activeIndex())).on(Modifier.Shift, this.prevKey, () => this.listBehavior.prev({
750
- selectRange: true
751
- })).on(Modifier.Shift, this.nextKey, () => this.listBehavior.next({
752
- selectRange: true
753
- })).on([Modifier.Ctrl | Modifier.Shift, Modifier.Meta | Modifier.Shift], 'Home', () => this.listBehavior.first({
754
- selectRange: true,
755
- anchor: false
756
- })).on([Modifier.Ctrl | Modifier.Shift, Modifier.Meta | Modifier.Shift], 'End', () => this.listBehavior.last({
757
- selectRange: true,
758
- anchor: false
759
- })).on(Modifier.Shift, 'Enter', () => this.listBehavior.updateSelection({
760
- selectRange: true,
761
- anchor: false
762
- })).on(Modifier.Shift, this.dynamicSpaceKey, () => this.listBehavior.updateSelection({
763
- selectRange: true,
764
- anchor: false
765
- }));
766
- }
767
- if (!this.followFocus() && this.inputs.multi()) {
768
- manager.on(this.dynamicSpaceKey, () => this.listBehavior.toggle()).on('Enter', () => this.listBehavior.toggle()).on([Modifier.Ctrl, Modifier.Meta], 'A', () => this.listBehavior.toggleAll());
769
- }
770
- if (!this.followFocus() && !this.inputs.multi()) {
771
- manager.on(this.dynamicSpaceKey, () => this.listBehavior.toggleOne());
772
- manager.on('Enter', () => this.listBehavior.toggleOne());
773
- }
774
- if (this.inputs.multi() && this.followFocus()) {
775
- manager.on([Modifier.Ctrl, Modifier.Meta], this.prevKey, () => this.listBehavior.prev()).on([Modifier.Ctrl, Modifier.Meta], this.nextKey, () => this.listBehavior.next()).on([Modifier.Ctrl, Modifier.Meta], ' ', () => this.listBehavior.toggle()).on([Modifier.Ctrl, Modifier.Meta], 'Enter', () => this.listBehavior.toggle()).on([Modifier.Ctrl, Modifier.Meta], 'Home', () => this.listBehavior.first()).on([Modifier.Ctrl, Modifier.Meta], 'End', () => this.listBehavior.last()).on([Modifier.Ctrl, Modifier.Meta], 'A', () => {
776
- this.listBehavior.toggleAll();
777
- this.listBehavior.select();
778
- });
779
- }
780
- return manager;
781
- });
782
- pointerdown = computed(() => {
783
- const manager = new PointerEventManager();
784
- if (this.readonly()) {
785
- return manager.on(e => this.listBehavior.goto(this._getItem(e)));
786
- }
787
- if (this.multi()) {
788
- manager.on(Modifier.Shift, e => this.listBehavior.goto(this._getItem(e), {
789
- selectRange: true
790
- }));
791
- }
792
- if (!this.multi() && this.followFocus()) {
793
- return manager.on(e => this.listBehavior.goto(this._getItem(e), {
794
- selectOne: true
795
- }));
796
- }
797
- if (!this.multi() && !this.followFocus()) {
798
- return manager.on(e => this.listBehavior.goto(this._getItem(e), {
799
- toggle: true
800
- }));
801
- }
802
- if (this.multi() && this.followFocus()) {
803
- return manager.on(e => this.listBehavior.goto(this._getItem(e), {
804
- selectOne: true
805
- })).on(Modifier.Ctrl, e => this.listBehavior.goto(this._getItem(e), {
806
- toggle: true
807
- }));
808
- }
809
- if (this.multi() && !this.followFocus()) {
810
- return manager.on(e => this.listBehavior.goto(this._getItem(e), {
811
- toggle: true
812
- }));
813
- }
814
- return manager;
815
- });
816
- constructor(inputs) {
817
- this.inputs = inputs;
818
- this.readonly = inputs.readonly;
819
- this.orientation = inputs.orientation;
820
- this.multi = inputs.multi;
821
- this.listBehavior = new List(inputs);
822
- }
823
- validate() {
824
- const violations = [];
825
- if (!this.inputs.multi() && this.inputs.values().length > 1) {
826
- violations.push(`A single-select listbox should not have multiple selected options. Selected options: ${this.inputs.values().join(', ')}`);
827
- }
828
- return violations;
829
- }
830
- onKeydown(event) {
831
- if (!this.disabled()) {
832
- this.keydown().handle(event);
833
- }
834
- }
835
- onPointerdown(event) {
836
- if (!this.disabled()) {
837
- this.pointerdown().handle(event);
838
- }
839
- }
840
- setDefaultState() {
841
- let firstItem = null;
842
- for (const item of this.inputs.items()) {
843
- if (this.listBehavior.isFocusable(item)) {
844
- if (!firstItem) {
845
- firstItem = item;
846
- }
847
- if (item.selected()) {
848
- this.inputs.activeItem.set(item);
849
- return;
850
- }
851
- }
852
- }
853
- if (firstItem) {
854
- this.inputs.activeItem.set(firstItem);
855
- }
856
- }
857
- _getItem(e) {
858
- if (!(e.target instanceof HTMLElement)) {
859
- return;
860
- }
861
- const element = e.target.closest('[role="option"]');
862
- return this.inputs.items().find(i => i.element() === element);
863
- }
864
- }
865
-
866
- class OptionPattern {
867
- id;
868
- value;
869
- index = computed(() => this.listbox()?.inputs.items().indexOf(this) ?? -1);
870
- active = computed(() => this.listbox()?.inputs.activeItem() === this);
871
- selected = computed(() => this.listbox()?.inputs.values().includes(this.value()));
872
- selectable = () => true;
873
- disabled;
874
- searchTerm;
875
- listbox;
876
- tabIndex = computed(() => this.listbox()?.listBehavior.getItemTabindex(this));
877
- element;
878
- constructor(args) {
879
- this.id = args.id;
880
- this.value = args.value;
881
- this.listbox = args.listbox;
882
- this.element = args.element;
883
- this.disabled = args.disabled;
884
- this.searchTerm = args.searchTerm;
885
- }
886
- }
887
-
888
- class ComboboxListboxPattern extends ListboxPattern {
889
- inputs;
890
- id = computed(() => this.inputs.id());
891
- role = computed(() => 'listbox');
892
- activeId = computed(() => this.listBehavior.activeDescendant());
893
- items = computed(() => this.inputs.items());
894
- tabIndex = () => -1;
895
- multi = computed(() => {
896
- return this.inputs.combobox()?.readonly() ? this.inputs.multi() : false;
897
- });
898
- constructor(inputs) {
899
- if (inputs.combobox()) {
900
- inputs.focusMode = () => 'activedescendant';
901
- inputs.element = inputs.combobox().inputs.inputEl;
902
- }
903
- super(inputs);
904
- this.inputs = inputs;
905
- }
906
- onKeydown(_) {}
907
- onPointerdown(_) {}
908
- setDefaultState() {}
909
- focus = (item, opts) => {
910
- this.listBehavior.goto(item, opts);
911
- };
912
- getActiveItem = () => this.inputs.activeItem();
913
- next = () => this.listBehavior.next();
914
- prev = () => this.listBehavior.prev();
915
- last = () => this.listBehavior.last();
916
- first = () => this.listBehavior.first();
917
- unfocus = () => this.listBehavior.unfocus();
918
- select = item => this.listBehavior.select(item);
919
- toggle = item => this.listBehavior.toggle(item);
920
- clearSelection = () => this.listBehavior.deselectAll();
921
- getItem = e => this._getItem(e);
922
- getSelectedItems = () => {
923
- const items = [];
924
- for (const value of this.inputs.values()) {
925
- const item = this.items().find(i => i.value() === value);
926
- if (item) {
927
- items.push(item);
928
- }
929
- }
930
- return items;
931
- };
932
- setValue = value => this.inputs.values.set(value ? [value] : []);
933
- }
934
-
935
10
  class MenuPattern {
936
11
  inputs;
937
12
  id;
@@ -941,6 +16,7 @@ class MenuPattern {
941
16
  listBehavior;
942
17
  isFocused = signal(false);
943
18
  hasBeenFocused = signal(false);
19
+ hasBeenHovered = signal(false);
944
20
  _openTimeout;
945
21
  _closeTimeout;
946
22
  tabIndex = () => this.listBehavior.tabIndex();
@@ -1001,6 +77,7 @@ class MenuPattern {
1001
77
  if (!this.visible()) {
1002
78
  return;
1003
79
  }
80
+ this.hasBeenHovered.set(true);
1004
81
  const item = this.inputs.items().find(i => i.element()?.contains(event.target));
1005
82
  if (!item) {
1006
83
  return;
@@ -2325,5 +1402,5 @@ i0.ɵɵngDeclareClassMetadata({
2325
1402
  ctorParameters: () => []
2326
1403
  });
2327
1404
 
2328
- export { AccordionGroupPattern, AccordionPanelPattern, AccordionTriggerPattern, ComboboxDialogPattern, ComboboxListboxPattern, ComboboxPattern, ComboboxTreePattern, DeferredContent, DeferredContentAware, ListboxPattern, MenuBarPattern, MenuItemPattern, MenuPattern, MenuTriggerPattern, OptionPattern, TabListPattern, TabPanelPattern, TabPattern, ToolbarPattern, ToolbarWidgetGroupPattern, ToolbarWidgetPattern, TreeItemPattern, TreePattern, convertGetterSetterToWritableSignalLike };
1405
+ export { AccordionGroupPattern, AccordionPanelPattern, AccordionTriggerPattern, ComboboxTreePattern, DeferredContent, DeferredContentAware, MenuBarPattern, MenuItemPattern, MenuPattern, MenuTriggerPattern, TabListPattern, TabPanelPattern, TabPattern, ToolbarPattern, ToolbarWidgetGroupPattern, ToolbarWidgetPattern, TreeItemPattern, TreePattern, convertGetterSetterToWritableSignalLike };
2329
1406
  //# sourceMappingURL=private.mjs.map