@angular/aria 21.0.3 → 21.1.0-next.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 (56) hide show
  1. package/_adev_assets/aria-accordion.json +743 -0
  2. package/_adev_assets/aria-combobox.json +603 -0
  3. package/_adev_assets/aria-grid.json +893 -0
  4. package/_adev_assets/aria-listbox.json +540 -0
  5. package/_adev_assets/aria-menu.json +1049 -0
  6. package/_adev_assets/aria-tabs.json +880 -0
  7. package/_adev_assets/aria-toolbar.json +545 -0
  8. package/_adev_assets/aria-tree.json +853 -0
  9. package/fesm2022/_widget-chunk.mjs +246 -4
  10. package/fesm2022/_widget-chunk.mjs.map +1 -1
  11. package/fesm2022/accordion.mjs +4 -17
  12. package/fesm2022/accordion.mjs.map +1 -1
  13. package/fesm2022/aria.mjs +1 -1
  14. package/fesm2022/aria.mjs.map +1 -1
  15. package/fesm2022/combobox.mjs +120 -96
  16. package/fesm2022/combobox.mjs.map +1 -1
  17. package/fesm2022/grid.mjs +201 -225
  18. package/fesm2022/grid.mjs.map +1 -1
  19. package/fesm2022/listbox.mjs +161 -173
  20. package/fesm2022/listbox.mjs.map +1 -1
  21. package/fesm2022/menu.mjs +238 -256
  22. package/fesm2022/menu.mjs.map +1 -1
  23. package/fesm2022/private.mjs +932 -7
  24. package/fesm2022/private.mjs.map +1 -1
  25. package/fesm2022/tabs.mjs +168 -182
  26. package/fesm2022/tabs.mjs.map +1 -1
  27. package/fesm2022/toolbar.mjs +3 -15
  28. package/fesm2022/toolbar.mjs.map +1 -1
  29. package/fesm2022/tree.mjs +2 -4
  30. package/fesm2022/tree.mjs.map +1 -1
  31. package/package.json +3 -3
  32. package/types/_grid-chunk.d.ts +210 -3
  33. package/types/accordion.d.ts +49 -52
  34. package/types/combobox.d.ts +111 -25
  35. package/types/grid.d.ts +32 -37
  36. package/types/listbox.d.ts +5 -8
  37. package/types/menu.d.ts +113 -113
  38. package/types/private.d.ts +498 -10
  39. package/types/tabs.d.ts +84 -89
  40. package/types/toolbar.d.ts +66 -69
  41. package/types/tree.d.ts +103 -106
  42. package/fesm2022/_combobox-chunk.mjs +0 -425
  43. package/fesm2022/_combobox-chunk.mjs.map +0 -1
  44. package/fesm2022/_combobox-listbox-chunk.mjs +0 -522
  45. package/fesm2022/_combobox-listbox-chunk.mjs.map +0 -1
  46. package/fesm2022/_combobox-popup-chunk.mjs +0 -46
  47. package/fesm2022/_combobox-popup-chunk.mjs.map +0 -1
  48. package/fesm2022/_list-navigation-chunk.mjs +0 -116
  49. package/fesm2022/_list-navigation-chunk.mjs.map +0 -1
  50. package/fesm2022/_pointer-event-manager-chunk.mjs +0 -134
  51. package/fesm2022/_pointer-event-manager-chunk.mjs.map +0 -1
  52. package/types/_combobox-chunk.d.ts +0 -98
  53. package/types/_combobox-chunk.d2.ts +0 -193
  54. package/types/_list-chunk.d.ts +0 -212
  55. package/types/_list-navigation-chunk.d.ts +0 -212
  56. package/types/_listbox-chunk.d.ts +0 -106
@@ -1,12 +1,937 @@
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';
4
1
  import * as i0 from '@angular/core';
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';
2
+ import { signal, computed, model, Directive, inject, TemplateRef, ViewContainerRef, afterRenderEffect } from '@angular/core';
3
+ import { PointerEventManager, KeyboardEventManager, ListFocus, ListNavigation, Modifier } from './_widget-chunk.mjs';
8
4
  export { GridCellPattern, GridCellWidgetPattern, GridPattern, GridRowPattern } from './_widget-chunk.mjs';
9
5
 
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
+
10
935
  class MenuPattern {
11
936
  inputs;
12
937
  id;
@@ -1402,5 +2327,5 @@ i0.ɵɵngDeclareClassMetadata({
1402
2327
  ctorParameters: () => []
1403
2328
  });
1404
2329
 
1405
- export { AccordionGroupPattern, AccordionPanelPattern, AccordionTriggerPattern, ComboboxTreePattern, DeferredContent, DeferredContentAware, MenuBarPattern, MenuItemPattern, MenuPattern, MenuTriggerPattern, TabListPattern, TabPanelPattern, TabPattern, ToolbarPattern, ToolbarWidgetGroupPattern, ToolbarWidgetPattern, TreeItemPattern, TreePattern, convertGetterSetterToWritableSignalLike };
2330
+ 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 };
1406
2331
  //# sourceMappingURL=private.mjs.map