@angular/aria 21.0.2 → 21.0.4

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 (81) hide show
  1. package/fesm2022/_accordion-chunk.mjs +108 -0
  2. package/fesm2022/_accordion-chunk.mjs.map +1 -0
  3. package/fesm2022/_combobox-chunk.mjs +425 -0
  4. package/fesm2022/_combobox-chunk.mjs.map +1 -0
  5. package/fesm2022/_combobox-listbox-chunk.mjs +240 -0
  6. package/fesm2022/_combobox-listbox-chunk.mjs.map +1 -0
  7. package/fesm2022/_combobox-tree-chunk.mjs +331 -0
  8. package/fesm2022/_combobox-tree-chunk.mjs.map +1 -0
  9. package/fesm2022/_deferred-content-chunk.mjs +124 -0
  10. package/fesm2022/_deferred-content-chunk.mjs.map +1 -0
  11. package/fesm2022/_expansion-chunk.mjs +41 -0
  12. package/fesm2022/_expansion-chunk.mjs.map +1 -0
  13. package/fesm2022/_list-chunk.mjs +287 -0
  14. package/fesm2022/_list-chunk.mjs.map +1 -0
  15. package/fesm2022/_list-navigation-chunk.mjs +116 -0
  16. package/fesm2022/_list-navigation-chunk.mjs.map +1 -0
  17. package/fesm2022/_menu-chunk.mjs +515 -0
  18. package/fesm2022/_menu-chunk.mjs.map +1 -0
  19. package/fesm2022/_pointer-event-manager-chunk.mjs +54 -0
  20. package/fesm2022/_pointer-event-manager-chunk.mjs.map +1 -0
  21. package/fesm2022/_signal-like-chunk.mjs +118 -0
  22. package/fesm2022/_signal-like-chunk.mjs.map +1 -0
  23. package/fesm2022/_tabs-chunk.mjs +159 -0
  24. package/fesm2022/_tabs-chunk.mjs.map +1 -0
  25. package/fesm2022/_toolbar-widget-group-chunk.mjs +148 -0
  26. package/fesm2022/_toolbar-widget-group-chunk.mjs.map +1 -0
  27. package/fesm2022/_widget-chunk.mjs +5 -246
  28. package/fesm2022/_widget-chunk.mjs.map +1 -1
  29. package/fesm2022/accordion.mjs +73 -55
  30. package/fesm2022/accordion.mjs.map +1 -1
  31. package/fesm2022/aria.mjs +1 -1
  32. package/fesm2022/aria.mjs.map +1 -1
  33. package/fesm2022/combobox.mjs +166 -153
  34. package/fesm2022/combobox.mjs.map +1 -1
  35. package/fesm2022/grid.mjs +287 -261
  36. package/fesm2022/grid.mjs.map +1 -1
  37. package/fesm2022/listbox.mjs +211 -197
  38. package/fesm2022/listbox.mjs.map +1 -1
  39. package/fesm2022/menu.mjs +308 -286
  40. package/fesm2022/menu.mjs.map +1 -1
  41. package/fesm2022/private.mjs +15 -2329
  42. package/fesm2022/private.mjs.map +1 -1
  43. package/fesm2022/tabs.mjs +221 -199
  44. package/fesm2022/tabs.mjs.map +1 -1
  45. package/fesm2022/toolbar.mjs +64 -48
  46. package/fesm2022/toolbar.mjs.map +1 -1
  47. package/fesm2022/tree.mjs +54 -44
  48. package/fesm2022/tree.mjs.map +1 -1
  49. package/package.json +2 -2
  50. package/types/_accordion-chunk.d.ts +100 -0
  51. package/types/_combobox-chunk.d.ts +194 -0
  52. package/types/_deferred-content-chunk.d.ts +42 -0
  53. package/types/_expansion-chunk.d.ts +40 -0
  54. package/types/_grid-chunk.d.ts +43 -250
  55. package/types/_keyboard-event-manager-chunk.d.ts +68 -0
  56. package/types/_list-chunk.d.ts +211 -0
  57. package/types/_list-navigation-chunk.d.ts +119 -0
  58. package/types/_listbox-chunk.d.ts +107 -0
  59. package/types/_menu-chunk.d.ts +267 -0
  60. package/types/_pointer-event-manager-chunk.d.ts +34 -0
  61. package/types/_tabs-chunk.d.ts +153 -0
  62. package/types/_toolbar-chunk.d.ts +124 -0
  63. package/types/_tree-chunk.d.ts +185 -0
  64. package/types/accordion.d.ts +65 -54
  65. package/types/aria.d.ts +1 -1
  66. package/types/combobox.d.ts +86 -56
  67. package/types/grid.d.ts +47 -32
  68. package/types/listbox.d.ts +22 -7
  69. package/types/menu.d.ts +135 -117
  70. package/types/private.d.ts +28 -1376
  71. package/types/tabs.d.ts +109 -88
  72. package/types/toolbar.d.ts +77 -66
  73. package/types/tree.d.ts +118 -104
  74. package/_adev_assets/aria-accordion.json +0 -743
  75. package/_adev_assets/aria-combobox.json +0 -603
  76. package/_adev_assets/aria-grid.json +0 -893
  77. package/_adev_assets/aria-listbox.json +0 -540
  78. package/_adev_assets/aria-menu.json +0 -1049
  79. package/_adev_assets/aria-tabs.json +0 -880
  80. package/_adev_assets/aria-toolbar.json +0 -545
  81. package/_adev_assets/aria-tree.json +0 -853
@@ -0,0 +1,116 @@
1
+ import { signal, computed } from './_signal-like-chunk.mjs';
2
+
3
+ class ListFocus {
4
+ inputs;
5
+ prevActiveItem = signal(undefined);
6
+ prevActiveIndex = computed(() => {
7
+ return this.prevActiveItem() ? this.inputs.items().indexOf(this.prevActiveItem()) : -1;
8
+ });
9
+ activeIndex = computed(() => {
10
+ return this.inputs.activeItem() ? this.inputs.items().indexOf(this.inputs.activeItem()) : -1;
11
+ });
12
+ constructor(inputs) {
13
+ this.inputs = inputs;
14
+ }
15
+ isListDisabled() {
16
+ return this.inputs.disabled() || this.inputs.items().every(i => i.disabled());
17
+ }
18
+ getActiveDescendant() {
19
+ if (this.isListDisabled()) {
20
+ return undefined;
21
+ }
22
+ if (this.inputs.focusMode() === 'roving') {
23
+ return undefined;
24
+ }
25
+ return this.inputs.activeItem()?.id() ?? undefined;
26
+ }
27
+ getListTabIndex() {
28
+ if (this.isListDisabled()) {
29
+ return 0;
30
+ }
31
+ return this.inputs.focusMode() === 'activedescendant' ? 0 : -1;
32
+ }
33
+ getItemTabIndex(item) {
34
+ if (this.isListDisabled()) {
35
+ return -1;
36
+ }
37
+ if (this.inputs.focusMode() === 'activedescendant') {
38
+ return -1;
39
+ }
40
+ return this.inputs.activeItem() === item ? 0 : -1;
41
+ }
42
+ focus(item, opts) {
43
+ if (this.isListDisabled() || !this.isFocusable(item)) {
44
+ return false;
45
+ }
46
+ this.prevActiveItem.set(this.inputs.activeItem());
47
+ this.inputs.activeItem.set(item);
48
+ if (opts?.focusElement || opts?.focusElement === undefined) {
49
+ this.inputs.focusMode() === 'roving' ? item.element()?.focus() : this.inputs.element()?.focus();
50
+ }
51
+ return true;
52
+ }
53
+ isFocusable(item) {
54
+ return !item.disabled() || this.inputs.softDisabled();
55
+ }
56
+ }
57
+
58
+ class ListNavigation {
59
+ inputs;
60
+ constructor(inputs) {
61
+ this.inputs = inputs;
62
+ }
63
+ goto(item, opts) {
64
+ return item ? this.inputs.focusManager.focus(item, opts) : false;
65
+ }
66
+ next(opts) {
67
+ return this._advance(1, opts);
68
+ }
69
+ peekNext() {
70
+ return this._peek(1);
71
+ }
72
+ prev(opts) {
73
+ return this._advance(-1, opts);
74
+ }
75
+ peekPrev() {
76
+ return this._peek(-1);
77
+ }
78
+ first(opts) {
79
+ const item = this.peekFirst();
80
+ return item ? this.goto(item, opts) : false;
81
+ }
82
+ last(opts) {
83
+ const item = this.peekLast();
84
+ return item ? this.goto(item, opts) : false;
85
+ }
86
+ peekFirst(items = this.inputs.items()) {
87
+ return items.find(i => this.inputs.focusManager.isFocusable(i));
88
+ }
89
+ peekLast(items = this.inputs.items()) {
90
+ for (let i = items.length - 1; i >= 0; i--) {
91
+ if (this.inputs.focusManager.isFocusable(items[i])) {
92
+ return items[i];
93
+ }
94
+ }
95
+ return;
96
+ }
97
+ _advance(delta, opts) {
98
+ const item = this._peek(delta);
99
+ return item ? this.goto(item, opts) : false;
100
+ }
101
+ _peek(delta) {
102
+ const items = this.inputs.items();
103
+ const itemCount = items.length;
104
+ const startIndex = this.inputs.focusManager.activeIndex();
105
+ const step = i => this.inputs.wrap() ? (i + delta + itemCount) % itemCount : i + delta;
106
+ for (let i = step(startIndex); i !== startIndex && i < itemCount && i >= 0; i = step(i)) {
107
+ if (this.inputs.focusManager.isFocusable(items[i])) {
108
+ return items[i];
109
+ }
110
+ }
111
+ return;
112
+ }
113
+ }
114
+
115
+ export { ListFocus, ListNavigation };
116
+ //# sourceMappingURL=_list-navigation-chunk.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_list-navigation-chunk.mjs","sources":["../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/src/aria/private/behaviors/list-focus/list-focus.ts","../../../../../darwin_arm64-fastbuild-ST-fdfa778d11ba/bin/src/aria/private/behaviors/list-navigation/list-navigation.ts"],"sourcesContent":["/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {computed, signal, SignalLike, WritableSignalLike} from '../signal-like/signal-like';\n\n/** Represents an item in a collection, such as a listbox option, than may receive focus. */\nexport interface ListFocusItem {\n /** A unique identifier for the item. */\n id: SignalLike<string>;\n\n /** The html element that should receive focus. */\n element: SignalLike<HTMLElement | undefined>;\n\n /** Whether an item is disabled. */\n disabled: SignalLike<boolean>;\n\n /** The index of the item in the list. */\n index: SignalLike<number>;\n}\n\n/** Represents the required inputs for a collection that contains focusable items. */\nexport interface ListFocusInputs<T extends ListFocusItem> {\n /** The focus strategy used by the list. */\n focusMode: SignalLike<'roving' | 'activedescendant'>;\n\n /** Whether the list is disabled. */\n disabled: SignalLike<boolean>;\n\n /** The items in the list. */\n items: SignalLike<T[]>;\n\n /** The active item. */\n activeItem: WritableSignalLike<T | undefined>;\n\n /** Whether disabled items in the list should be focusable. */\n softDisabled: SignalLike<boolean>;\n\n element: SignalLike<HTMLElement | undefined>;\n}\n\n/** Controls focus for a list of items. */\nexport class ListFocus<T extends ListFocusItem> {\n /** The last item that was active. */\n prevActiveItem = signal<T | undefined>(undefined);\n\n /** The index of the last item that was active. */\n prevActiveIndex = computed(() => {\n return this.prevActiveItem() ? this.inputs.items().indexOf(this.prevActiveItem()!) : -1;\n });\n\n /** The current active index in the list. */\n activeIndex = computed(() => {\n return this.inputs.activeItem() ? this.inputs.items().indexOf(this.inputs.activeItem()!) : -1;\n });\n\n constructor(readonly inputs: ListFocusInputs<T>) {}\n\n /** Whether the list is in a disabled state. */\n isListDisabled(): boolean {\n return this.inputs.disabled() || this.inputs.items().every(i => i.disabled());\n }\n\n /** The id of the current active item. */\n getActiveDescendant(): string | undefined {\n if (this.isListDisabled()) {\n return undefined;\n }\n if (this.inputs.focusMode() === 'roving') {\n return undefined;\n }\n return this.inputs.activeItem()?.id() ?? undefined;\n }\n\n /** The tab index for the list. */\n getListTabIndex(): -1 | 0 {\n if (this.isListDisabled()) {\n return 0;\n }\n return this.inputs.focusMode() === 'activedescendant' ? 0 : -1;\n }\n\n /** Returns the tab index for the given item. */\n getItemTabIndex(item: T): -1 | 0 {\n if (this.isListDisabled()) {\n return -1;\n }\n if (this.inputs.focusMode() === 'activedescendant') {\n return -1;\n }\n return this.inputs.activeItem() === item ? 0 : -1;\n }\n\n /** Moves focus to the given item if it is focusable. */\n focus(item: T, opts?: {focusElement?: boolean}): boolean {\n if (this.isListDisabled() || !this.isFocusable(item)) {\n return false;\n }\n\n this.prevActiveItem.set(this.inputs.activeItem());\n this.inputs.activeItem.set(item);\n\n if (opts?.focusElement || opts?.focusElement === undefined) {\n this.inputs.focusMode() === 'roving'\n ? item.element()?.focus()\n : this.inputs.element()?.focus();\n }\n\n return true;\n }\n\n /** Returns true if the given item can be navigated to. */\n isFocusable(item: T): boolean {\n return !item.disabled() || this.inputs.softDisabled();\n }\n}\n","/**\n * @license\n * Copyright Google LLC All Rights Reserved.\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://angular.dev/license\n */\n\nimport {SignalLike} from '../signal-like/signal-like';\nimport {ListFocus, ListFocusInputs, ListFocusItem} from '../list-focus/list-focus';\n\n/** Represents an item in a collection, such as a listbox option, than can be navigated to. */\nexport interface ListNavigationItem extends ListFocusItem {}\n\n/** Represents the required inputs for a collection that has navigable items. */\nexport interface ListNavigationInputs<T extends ListNavigationItem> extends ListFocusInputs<T> {\n /** Whether focus should wrap when navigating. */\n wrap: SignalLike<boolean>;\n\n /** Whether the list is vertically or horizontally oriented. */\n orientation: SignalLike<'vertical' | 'horizontal'>;\n\n /** The direction that text is read based on the users locale. */\n textDirection: SignalLike<'rtl' | 'ltr'>;\n}\n\n/** Controls navigation for a list of items. */\nexport class ListNavigation<T extends ListNavigationItem> {\n constructor(readonly inputs: ListNavigationInputs<T> & {focusManager: ListFocus<T>}) {}\n\n /** Navigates to the given item. */\n goto(item?: T, opts?: {focusElement?: boolean}): boolean {\n return item ? this.inputs.focusManager.focus(item, opts) : false;\n }\n\n /** Navigates to the next item in the list. */\n next(opts?: {focusElement?: boolean}): boolean {\n return this._advance(1, opts);\n }\n\n /** Peeks the next item in the list. */\n peekNext(): T | undefined {\n return this._peek(1);\n }\n\n /** Navigates to the previous item in the list. */\n prev(opts?: {focusElement?: boolean}): boolean {\n return this._advance(-1, opts);\n }\n\n /** Peeks the previous item in the list. */\n peekPrev(): T | undefined {\n return this._peek(-1);\n }\n\n /** Navigates to the first item in the list. */\n first(opts?: {focusElement?: boolean}): boolean {\n const item = this.peekFirst();\n return item ? this.goto(item, opts) : false;\n }\n\n /** Navigates to the last item in the list. */\n last(opts?: {focusElement?: boolean}): boolean {\n const item = this.peekLast();\n return item ? this.goto(item, opts) : false;\n }\n\n /** Gets the first focusable item from the given list of items. */\n peekFirst(items: T[] = this.inputs.items()): T | undefined {\n return items.find(i => this.inputs.focusManager.isFocusable(i));\n }\n\n /** Gets the last focusable item from the given list of items. */\n peekLast(items: T[] = this.inputs.items()): T | undefined {\n for (let i = items.length - 1; i >= 0; i--) {\n if (this.inputs.focusManager.isFocusable(items[i])) {\n return items[i];\n }\n }\n return;\n }\n\n /** Advances to the next or previous focusable item in the list based on the given delta. */\n private _advance(delta: 1 | -1, opts?: {focusElement?: boolean}): boolean {\n const item = this._peek(delta);\n return item ? this.goto(item, opts) : false;\n }\n\n /** Peeks the next or previous focusable item in the list based on the given delta. */\n private _peek(delta: 1 | -1): T | undefined {\n const items = this.inputs.items();\n const itemCount = items.length;\n const startIndex = this.inputs.focusManager.activeIndex();\n const step = (i: number) =>\n this.inputs.wrap() ? (i + delta + itemCount) % itemCount : i + delta;\n\n // If wrapping is enabled, this loop ultimately terminates when `i` gets back to `startIndex`\n // in the case that all options are disabled. If wrapping is disabled, the loop terminates\n // when the index goes out of bounds.\n for (let i = step(startIndex); i !== startIndex && i < itemCount && i >= 0; i = step(i)) {\n if (this.inputs.focusManager.isFocusable(items[i])) {\n return items[i];\n }\n }\n\n return;\n }\n}\n"],"names":["ListFocus","inputs","prevActiveItem","signal","undefined","prevActiveIndex","computed","items","indexOf","activeIndex","activeItem","constructor","isListDisabled","disabled","every","i","getActiveDescendant","focusMode","id","getListTabIndex","getItemTabIndex","item","focus","opts","isFocusable","set","focusElement","element","softDisabled","ListNavigation","goto","focusManager","next","_advance","peekNext","_peek","prev","peekPrev","first","peekFirst","last","peekLast","find","length","delta","itemCount","startIndex","step","wrap"],"mappings":";;MA8CaA,SAAS,CAAA;EAcCC,MAAA;AAZrBC,EAAAA,cAAc,GAAGC,MAAM,CAAgBC,SAAS,CAAC;EAGjDC,eAAe,GAAGC,QAAQ,CAAC,MAAK;IAC9B,OAAO,IAAI,CAACJ,cAAc,EAAE,GAAG,IAAI,CAACD,MAAM,CAACM,KAAK,EAAE,CAACC,OAAO,CAAC,IAAI,CAACN,cAAc,EAAG,CAAC,GAAG,CAAC,CAAC;AACzF,GAAC,CAAC;EAGFO,WAAW,GAAGH,QAAQ,CAAC,MAAK;AAC1B,IAAA,OAAO,IAAI,CAACL,MAAM,CAACS,UAAU,EAAE,GAAG,IAAI,CAACT,MAAM,CAACM,KAAK,EAAE,CAACC,OAAO,CAAC,IAAI,CAACP,MAAM,CAACS,UAAU,EAAG,CAAC,GAAG,CAAC,CAAC;AAC/F,GAAC,CAAC;EAEFC,WAAAA,CAAqBV,MAA0B,EAAA;IAA1B,IAAM,CAAAA,MAAA,GAANA,MAAM;AAAuB;AAGlDW,EAAAA,cAAcA,GAAA;IACZ,OAAO,IAAI,CAACX,MAAM,CAACY,QAAQ,EAAE,IAAI,IAAI,CAACZ,MAAM,CAACM,KAAK,EAAE,CAACO,KAAK,CAACC,CAAC,IAAIA,CAAC,CAACF,QAAQ,EAAE,CAAC;AAC/E;AAGAG,EAAAA,mBAAmBA,GAAA;AACjB,IAAA,IAAI,IAAI,CAACJ,cAAc,EAAE,EAAE;AACzB,MAAA,OAAOR,SAAS;AAClB;IACA,IAAI,IAAI,CAACH,MAAM,CAACgB,SAAS,EAAE,KAAK,QAAQ,EAAE;AACxC,MAAA,OAAOb,SAAS;AAClB;AACA,IAAA,OAAO,IAAI,CAACH,MAAM,CAACS,UAAU,EAAE,EAAEQ,EAAE,EAAE,IAAId,SAAS;AACpD;AAGAe,EAAAA,eAAeA,GAAA;AACb,IAAA,IAAI,IAAI,CAACP,cAAc,EAAE,EAAE;AACzB,MAAA,OAAO,CAAC;AACV;AACA,IAAA,OAAO,IAAI,CAACX,MAAM,CAACgB,SAAS,EAAE,KAAK,kBAAkB,GAAG,CAAC,GAAG,CAAC,CAAC;AAChE;EAGAG,eAAeA,CAACC,IAAO,EAAA;AACrB,IAAA,IAAI,IAAI,CAACT,cAAc,EAAE,EAAE;AACzB,MAAA,OAAO,CAAC,CAAC;AACX;IACA,IAAI,IAAI,CAACX,MAAM,CAACgB,SAAS,EAAE,KAAK,kBAAkB,EAAE;AAClD,MAAA,OAAO,CAAC,CAAC;AACX;AACA,IAAA,OAAO,IAAI,CAAChB,MAAM,CAACS,UAAU,EAAE,KAAKW,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC;AACnD;AAGAC,EAAAA,KAAKA,CAACD,IAAO,EAAEE,IAA+B,EAAA;AAC5C,IAAA,IAAI,IAAI,CAACX,cAAc,EAAE,IAAI,CAAC,IAAI,CAACY,WAAW,CAACH,IAAI,CAAC,EAAE;AACpD,MAAA,OAAO,KAAK;AACd;AAEA,IAAA,IAAI,CAACnB,cAAc,CAACuB,GAAG,CAAC,IAAI,CAACxB,MAAM,CAACS,UAAU,EAAE,CAAC;IACjD,IAAI,CAACT,MAAM,CAACS,UAAU,CAACe,GAAG,CAACJ,IAAI,CAAC;IAEhC,IAAIE,IAAI,EAAEG,YAAY,IAAIH,IAAI,EAAEG,YAAY,KAAKtB,SAAS,EAAE;AAC1D,MAAA,IAAI,CAACH,MAAM,CAACgB,SAAS,EAAE,KAAK,QAAQ,GAChCI,IAAI,CAACM,OAAO,EAAE,EAAEL,KAAK,EAAE,GACvB,IAAI,CAACrB,MAAM,CAAC0B,OAAO,EAAE,EAAEL,KAAK,EAAE;AACpC;AAEA,IAAA,OAAO,IAAI;AACb;EAGAE,WAAWA,CAACH,IAAO,EAAA;AACjB,IAAA,OAAO,CAACA,IAAI,CAACR,QAAQ,EAAE,IAAI,IAAI,CAACZ,MAAM,CAAC2B,YAAY,EAAE;AACvD;AACD;;MC5FYC,cAAc,CAAA;EACJ5B,MAAA;EAArBU,WAAAA,CAAqBV,MAA8D,EAAA;IAA9D,IAAM,CAAAA,MAAA,GAANA,MAAM;AAA2D;AAGtF6B,EAAAA,IAAIA,CAACT,IAAQ,EAAEE,IAA+B,EAAA;AAC5C,IAAA,OAAOF,IAAI,GAAG,IAAI,CAACpB,MAAM,CAAC8B,YAAY,CAACT,KAAK,CAACD,IAAI,EAAEE,IAAI,CAAC,GAAG,KAAK;AAClE;EAGAS,IAAIA,CAACT,IAA+B,EAAA;AAClC,IAAA,OAAO,IAAI,CAACU,QAAQ,CAAC,CAAC,EAAEV,IAAI,CAAC;AAC/B;AAGAW,EAAAA,QAAQA,GAAA;AACN,IAAA,OAAO,IAAI,CAACC,KAAK,CAAC,CAAC,CAAC;AACtB;EAGAC,IAAIA,CAACb,IAA+B,EAAA;IAClC,OAAO,IAAI,CAACU,QAAQ,CAAC,CAAC,CAAC,EAAEV,IAAI,CAAC;AAChC;AAGAc,EAAAA,QAAQA,GAAA;AACN,IAAA,OAAO,IAAI,CAACF,KAAK,CAAC,CAAC,CAAC,CAAC;AACvB;EAGAG,KAAKA,CAACf,IAA+B,EAAA;AACnC,IAAA,MAAMF,IAAI,GAAG,IAAI,CAACkB,SAAS,EAAE;IAC7B,OAAOlB,IAAI,GAAG,IAAI,CAACS,IAAI,CAACT,IAAI,EAAEE,IAAI,CAAC,GAAG,KAAK;AAC7C;EAGAiB,IAAIA,CAACjB,IAA+B,EAAA;AAClC,IAAA,MAAMF,IAAI,GAAG,IAAI,CAACoB,QAAQ,EAAE;IAC5B,OAAOpB,IAAI,GAAG,IAAI,CAACS,IAAI,CAACT,IAAI,EAAEE,IAAI,CAAC,GAAG,KAAK;AAC7C;EAGAgB,SAASA,CAAChC,KAAa,GAAA,IAAI,CAACN,MAAM,CAACM,KAAK,EAAE,EAAA;AACxC,IAAA,OAAOA,KAAK,CAACmC,IAAI,CAAC3B,CAAC,IAAI,IAAI,CAACd,MAAM,CAAC8B,YAAY,CAACP,WAAW,CAACT,CAAC,CAAC,CAAC;AACjE;EAGA0B,QAAQA,CAAClC,KAAa,GAAA,IAAI,CAACN,MAAM,CAACM,KAAK,EAAE,EAAA;AACvC,IAAA,KAAK,IAAIQ,CAAC,GAAGR,KAAK,CAACoC,MAAM,GAAG,CAAC,EAAE5B,CAAC,IAAI,CAAC,EAAEA,CAAC,EAAE,EAAE;AAC1C,MAAA,IAAI,IAAI,CAACd,MAAM,CAAC8B,YAAY,CAACP,WAAW,CAACjB,KAAK,CAACQ,CAAC,CAAC,CAAC,EAAE;QAClD,OAAOR,KAAK,CAACQ,CAAC,CAAC;AACjB;AACF;AACA,IAAA;AACF;AAGQkB,EAAAA,QAAQA,CAACW,KAAa,EAAErB,IAA+B,EAAA;AAC7D,IAAA,MAAMF,IAAI,GAAG,IAAI,CAACc,KAAK,CAACS,KAAK,CAAC;IAC9B,OAAOvB,IAAI,GAAG,IAAI,CAACS,IAAI,CAACT,IAAI,EAAEE,IAAI,CAAC,GAAG,KAAK;AAC7C;EAGQY,KAAKA,CAACS,KAAa,EAAA;IACzB,MAAMrC,KAAK,GAAG,IAAI,CAACN,MAAM,CAACM,KAAK,EAAE;AACjC,IAAA,MAAMsC,SAAS,GAAGtC,KAAK,CAACoC,MAAM;IAC9B,MAAMG,UAAU,GAAG,IAAI,CAAC7C,MAAM,CAAC8B,YAAY,CAACtB,WAAW,EAAE;IACzD,MAAMsC,IAAI,GAAIhC,CAAS,IACrB,IAAI,CAACd,MAAM,CAAC+C,IAAI,EAAE,GAAG,CAACjC,CAAC,GAAG6B,KAAK,GAAGC,SAAS,IAAIA,SAAS,GAAG9B,CAAC,GAAG6B,KAAK;IAKtE,KAAK,IAAI7B,CAAC,GAAGgC,IAAI,CAACD,UAAU,CAAC,EAAE/B,CAAC,KAAK+B,UAAU,IAAI/B,CAAC,GAAG8B,SAAS,IAAI9B,CAAC,IAAI,CAAC,EAAEA,CAAC,GAAGgC,IAAI,CAAChC,CAAC,CAAC,EAAE;AACvF,MAAA,IAAI,IAAI,CAACd,MAAM,CAAC8B,YAAY,CAACP,WAAW,CAACjB,KAAK,CAACQ,CAAC,CAAC,CAAC,EAAE;QAClD,OAAOR,KAAK,CAACQ,CAAC,CAAC;AACjB;AACF;AAEA,IAAA;AACF;AACD;;;;"}
@@ -0,0 +1,515 @@
1
+ import { computed, signal, KeyboardEventManager } from './_signal-like-chunk.mjs';
2
+ import { List } from './_list-chunk.mjs';
3
+
4
+ class MenuPattern {
5
+ inputs;
6
+ id;
7
+ role = () => 'menu';
8
+ disabled = () => this.inputs.disabled();
9
+ visible = computed(() => this.inputs.parent() ? !!this.inputs.parent()?.expanded() : true);
10
+ listBehavior;
11
+ isFocused = signal(false);
12
+ hasBeenFocused = signal(false);
13
+ hasBeenHovered = signal(false);
14
+ _openTimeout;
15
+ _closeTimeout;
16
+ tabIndex = () => this.listBehavior.tabIndex();
17
+ shouldFocus = computed(() => {
18
+ const root = this.root();
19
+ if (root instanceof MenuTriggerPattern) {
20
+ return true;
21
+ }
22
+ if (root instanceof MenuBarPattern || root instanceof MenuPattern) {
23
+ return root.isFocused();
24
+ }
25
+ return false;
26
+ });
27
+ _expandKey = computed(() => {
28
+ return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight';
29
+ });
30
+ _collapseKey = computed(() => {
31
+ return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
32
+ });
33
+ dynamicSpaceKey = computed(() => this.listBehavior.isTyping() ? '' : ' ');
34
+ typeaheadRegexp = /^.$/;
35
+ root = computed(() => {
36
+ const parent = this.inputs.parent();
37
+ if (!parent) {
38
+ return this;
39
+ }
40
+ if (parent instanceof MenuTriggerPattern) {
41
+ return parent;
42
+ }
43
+ const grandparent = parent.inputs.parent();
44
+ if (grandparent instanceof MenuBarPattern) {
45
+ return grandparent;
46
+ }
47
+ return grandparent?.root();
48
+ });
49
+ keydownManager = computed(() => {
50
+ return new KeyboardEventManager().on('ArrowDown', () => this.next()).on('ArrowUp', () => this.prev()).on('Home', () => this.first()).on('End', () => this.last()).on('Enter', () => this.trigger()).on('Escape', () => this.closeAll()).on(this._expandKey, () => this.expand()).on(this._collapseKey, () => this.collapse()).on(this.dynamicSpaceKey, () => this.trigger()).on(this.typeaheadRegexp, e => this.listBehavior.search(e.key));
51
+ });
52
+ constructor(inputs) {
53
+ this.inputs = inputs;
54
+ this.id = inputs.id;
55
+ this.listBehavior = new List({
56
+ ...inputs,
57
+ values: signal([])
58
+ });
59
+ }
60
+ setDefaultState() {
61
+ if (!this.inputs.parent()) {
62
+ this.listBehavior.goto(this.inputs.items()[0], {
63
+ focusElement: false
64
+ });
65
+ }
66
+ }
67
+ onKeydown(event) {
68
+ this.keydownManager().handle(event);
69
+ }
70
+ onMouseOver(event) {
71
+ if (!this.visible()) {
72
+ return;
73
+ }
74
+ this.hasBeenHovered.set(true);
75
+ const item = this.inputs.items().find(i => i.element()?.contains(event.target));
76
+ if (!item) {
77
+ return;
78
+ }
79
+ const parent = this.inputs.parent();
80
+ const activeItem = this?.inputs.activeItem();
81
+ if (parent instanceof MenuItemPattern) {
82
+ const grandparent = parent.inputs.parent();
83
+ if (grandparent instanceof MenuPattern) {
84
+ grandparent._clearTimeouts();
85
+ grandparent.listBehavior.goto(parent, {
86
+ focusElement: false
87
+ });
88
+ }
89
+ }
90
+ if (activeItem && activeItem !== item) {
91
+ this._closeItem(activeItem);
92
+ }
93
+ if (item.expanded()) {
94
+ this._clearCloseTimeout();
95
+ }
96
+ this._openItem(item);
97
+ this.listBehavior.goto(item, {
98
+ focusElement: this.shouldFocus()
99
+ });
100
+ }
101
+ _closeItem(item) {
102
+ this._clearOpenTimeout();
103
+ if (!this._closeTimeout) {
104
+ this._closeTimeout = setTimeout(() => {
105
+ item.close();
106
+ this._closeTimeout = undefined;
107
+ }, this.inputs.expansionDelay());
108
+ }
109
+ }
110
+ _openItem(item) {
111
+ this._clearOpenTimeout();
112
+ this._openTimeout = setTimeout(() => {
113
+ item.open();
114
+ this._openTimeout = undefined;
115
+ }, this.inputs.expansionDelay());
116
+ }
117
+ onMouseOut(event) {
118
+ this._clearOpenTimeout();
119
+ if (this.isFocused()) {
120
+ return;
121
+ }
122
+ const root = this.root();
123
+ const parent = this.inputs.parent();
124
+ const relatedTarget = event.relatedTarget;
125
+ if (!root || !parent || parent instanceof MenuTriggerPattern) {
126
+ return;
127
+ }
128
+ const grandparent = parent.inputs.parent();
129
+ if (!grandparent || grandparent instanceof MenuBarPattern) {
130
+ return;
131
+ }
132
+ if (!grandparent.inputs.element()?.contains(relatedTarget)) {
133
+ parent.close();
134
+ }
135
+ }
136
+ onClick(event) {
137
+ const relatedTarget = event.target;
138
+ const item = this.inputs.items().find(i => i.element()?.contains(relatedTarget));
139
+ if (item) {
140
+ item.open();
141
+ this.listBehavior.goto(item);
142
+ this.submit(item);
143
+ }
144
+ }
145
+ onFocusIn() {
146
+ this.isFocused.set(true);
147
+ this.hasBeenFocused.set(true);
148
+ }
149
+ onFocusOut(event) {
150
+ const parent = this.inputs.parent();
151
+ const parentEl = parent?.inputs.element();
152
+ const relatedTarget = event.relatedTarget;
153
+ if (!relatedTarget) {
154
+ this.isFocused.set(false);
155
+ this.inputs.parent()?.close({
156
+ refocus: true
157
+ });
158
+ }
159
+ if (parent instanceof MenuItemPattern) {
160
+ const grandparent = parent.inputs.parent();
161
+ const siblings = grandparent?.inputs.items().filter(i => i !== parent);
162
+ const item = siblings?.find(i => i.element()?.contains(relatedTarget));
163
+ if (item) {
164
+ return;
165
+ }
166
+ }
167
+ if (this.visible() && !parentEl?.contains(relatedTarget) && !this.inputs.element()?.contains(relatedTarget)) {
168
+ this.isFocused.set(false);
169
+ this.inputs.parent()?.close();
170
+ }
171
+ }
172
+ prev() {
173
+ this.inputs.activeItem()?.close();
174
+ this.listBehavior.prev();
175
+ }
176
+ next() {
177
+ this.inputs.activeItem()?.close();
178
+ this.listBehavior.next();
179
+ }
180
+ first() {
181
+ this.inputs.activeItem()?.close();
182
+ this.listBehavior.first();
183
+ }
184
+ last() {
185
+ this.inputs.activeItem()?.close();
186
+ this.listBehavior.last();
187
+ }
188
+ trigger() {
189
+ this.inputs.activeItem()?.hasPopup() ? this.inputs.activeItem()?.open({
190
+ first: true
191
+ }) : this.submit();
192
+ }
193
+ submit(item = this.inputs.activeItem()) {
194
+ const root = this.root();
195
+ if (item && !item.disabled()) {
196
+ const isMenu = root instanceof MenuPattern;
197
+ const isMenuBar = root instanceof MenuBarPattern;
198
+ const isMenuTrigger = root instanceof MenuTriggerPattern;
199
+ if (!item.submenu() && isMenuTrigger) {
200
+ root.close({
201
+ refocus: true
202
+ });
203
+ }
204
+ if (!item.submenu() && isMenuBar) {
205
+ root.close();
206
+ root?.inputs.onSelect?.(item.value());
207
+ }
208
+ if (!item.submenu() && isMenu) {
209
+ root.inputs.activeItem()?.close({
210
+ refocus: true
211
+ });
212
+ root?.inputs.onSelect?.(item.value());
213
+ }
214
+ }
215
+ }
216
+ collapse() {
217
+ const root = this.root();
218
+ const parent = this.inputs.parent();
219
+ if (parent instanceof MenuItemPattern && !(parent.inputs.parent() instanceof MenuBarPattern)) {
220
+ parent.close({
221
+ refocus: true
222
+ });
223
+ } else if (root instanceof MenuBarPattern) {
224
+ root.prev();
225
+ }
226
+ }
227
+ expand() {
228
+ const root = this.root();
229
+ const activeItem = this.inputs.activeItem();
230
+ if (activeItem?.submenu()) {
231
+ activeItem.open({
232
+ first: true
233
+ });
234
+ } else if (root instanceof MenuBarPattern) {
235
+ root.next();
236
+ }
237
+ }
238
+ close() {
239
+ this.inputs.parent()?.close();
240
+ }
241
+ closeAll() {
242
+ const root = this.root();
243
+ if (root instanceof MenuTriggerPattern) {
244
+ root.close({
245
+ refocus: true
246
+ });
247
+ }
248
+ if (root instanceof MenuBarPattern) {
249
+ root.close();
250
+ }
251
+ if (root instanceof MenuPattern) {
252
+ root.inputs.activeItem()?.close({
253
+ refocus: true
254
+ });
255
+ }
256
+ }
257
+ _clearTimeouts() {
258
+ this._clearOpenTimeout();
259
+ this._clearCloseTimeout();
260
+ }
261
+ _clearOpenTimeout() {
262
+ if (this._openTimeout) {
263
+ clearTimeout(this._openTimeout);
264
+ this._openTimeout = undefined;
265
+ }
266
+ }
267
+ _clearCloseTimeout() {
268
+ if (this._closeTimeout) {
269
+ clearTimeout(this._closeTimeout);
270
+ this._closeTimeout = undefined;
271
+ }
272
+ }
273
+ }
274
+ class MenuBarPattern {
275
+ inputs;
276
+ listBehavior;
277
+ tabIndex = () => this.listBehavior.tabIndex();
278
+ _nextKey = computed(() => {
279
+ return this.inputs.textDirection() === 'rtl' ? 'ArrowLeft' : 'ArrowRight';
280
+ });
281
+ _previousKey = computed(() => {
282
+ return this.inputs.textDirection() === 'rtl' ? 'ArrowRight' : 'ArrowLeft';
283
+ });
284
+ dynamicSpaceKey = computed(() => this.listBehavior.isTyping() ? '' : ' ');
285
+ typeaheadRegexp = /^.$/;
286
+ isFocused = signal(false);
287
+ hasBeenFocused = signal(false);
288
+ disabled = () => this.inputs.disabled();
289
+ keydownManager = computed(() => {
290
+ return new KeyboardEventManager().on(this._nextKey, () => this.next()).on(this._previousKey, () => this.prev()).on('End', () => this.listBehavior.last()).on('Home', () => this.listBehavior.first()).on('Enter', () => this.inputs.activeItem()?.open({
291
+ first: true
292
+ })).on('ArrowUp', () => this.inputs.activeItem()?.open({
293
+ last: true
294
+ })).on('ArrowDown', () => this.inputs.activeItem()?.open({
295
+ first: true
296
+ })).on(this.dynamicSpaceKey, () => this.inputs.activeItem()?.open({
297
+ first: true
298
+ })).on(this.typeaheadRegexp, e => this.listBehavior.search(e.key));
299
+ });
300
+ constructor(inputs) {
301
+ this.inputs = inputs;
302
+ this.listBehavior = new List(inputs);
303
+ }
304
+ setDefaultState() {
305
+ this.inputs.activeItem.set(this.inputs.items()[0]);
306
+ }
307
+ onKeydown(event) {
308
+ this.keydownManager().handle(event);
309
+ }
310
+ onClick(event) {
311
+ const item = this.inputs.items().find(i => i.element()?.contains(event.target));
312
+ if (!item) {
313
+ return;
314
+ }
315
+ this.goto(item);
316
+ item.expanded() ? item.close() : item.open();
317
+ }
318
+ onMouseOver(event) {
319
+ const item = this.inputs.items().find(i => i.element()?.contains(event.target));
320
+ if (item) {
321
+ this.goto(item, {
322
+ focusElement: this.isFocused()
323
+ });
324
+ }
325
+ }
326
+ onFocusIn() {
327
+ this.isFocused.set(true);
328
+ this.hasBeenFocused.set(true);
329
+ }
330
+ onFocusOut(event) {
331
+ const relatedTarget = event.relatedTarget;
332
+ if (!this.inputs.element()?.contains(relatedTarget)) {
333
+ this.isFocused.set(false);
334
+ this.close();
335
+ }
336
+ }
337
+ goto(item, opts) {
338
+ const prevItem = this.inputs.activeItem();
339
+ this.listBehavior.goto(item, opts);
340
+ if (prevItem?.expanded()) {
341
+ prevItem?.close();
342
+ this.inputs.activeItem()?.open();
343
+ }
344
+ if (item === prevItem) {
345
+ if (item.expanded() && item.submenu()?.inputs.activeItem()) {
346
+ item.submenu()?.inputs.activeItem()?.close();
347
+ item.submenu()?.listBehavior.unfocus();
348
+ }
349
+ }
350
+ }
351
+ next() {
352
+ const prevItem = this.inputs.activeItem();
353
+ this.listBehavior.next();
354
+ if (prevItem?.expanded()) {
355
+ prevItem?.close();
356
+ this.inputs.activeItem()?.open({
357
+ first: true
358
+ });
359
+ }
360
+ }
361
+ prev() {
362
+ const prevItem = this.inputs.activeItem();
363
+ this.listBehavior.prev();
364
+ if (prevItem?.expanded()) {
365
+ prevItem?.close();
366
+ this.inputs.activeItem()?.open({
367
+ first: true
368
+ });
369
+ }
370
+ }
371
+ close() {
372
+ this.inputs.activeItem()?.close({
373
+ refocus: this.isFocused()
374
+ });
375
+ }
376
+ }
377
+ class MenuTriggerPattern {
378
+ inputs;
379
+ expanded = signal(false);
380
+ hasBeenFocused = signal(false);
381
+ role = () => 'button';
382
+ hasPopup = () => true;
383
+ menu;
384
+ tabIndex = computed(() => this.expanded() && this.menu()?.inputs.activeItem() ? -1 : 0);
385
+ disabled = () => this.inputs.disabled();
386
+ keydownManager = computed(() => {
387
+ return new KeyboardEventManager().on(' ', () => this.open({
388
+ first: true
389
+ })).on('Enter', () => this.open({
390
+ first: true
391
+ })).on('ArrowDown', () => this.open({
392
+ first: true
393
+ })).on('ArrowUp', () => this.open({
394
+ last: true
395
+ })).on('Escape', () => this.close({
396
+ refocus: true
397
+ }));
398
+ });
399
+ constructor(inputs) {
400
+ this.inputs = inputs;
401
+ this.menu = this.inputs.menu;
402
+ }
403
+ onKeydown(event) {
404
+ if (!this.inputs.disabled()) {
405
+ this.keydownManager().handle(event);
406
+ }
407
+ }
408
+ onClick() {
409
+ if (!this.inputs.disabled()) {
410
+ this.expanded() ? this.close() : this.open({
411
+ first: true
412
+ });
413
+ }
414
+ }
415
+ onFocusIn() {
416
+ this.hasBeenFocused.set(true);
417
+ }
418
+ onFocusOut(event) {
419
+ const element = this.inputs.element();
420
+ const relatedTarget = event.relatedTarget;
421
+ if (this.expanded() && !element?.contains(relatedTarget) && !this.inputs.menu()?.inputs.element()?.contains(relatedTarget)) {
422
+ this.close();
423
+ }
424
+ }
425
+ open(opts) {
426
+ this.expanded.set(true);
427
+ if (opts?.first) {
428
+ this.inputs.menu()?.first();
429
+ } else if (opts?.last) {
430
+ this.inputs.menu()?.last();
431
+ }
432
+ }
433
+ close(opts = {}) {
434
+ this.expanded.set(false);
435
+ this.menu()?.listBehavior.unfocus();
436
+ if (opts.refocus) {
437
+ this.inputs.element()?.focus();
438
+ }
439
+ let menuitems = this.inputs.menu()?.inputs.items() ?? [];
440
+ while (menuitems.length) {
441
+ const menuitem = menuitems.pop();
442
+ menuitem?._expanded.set(false);
443
+ menuitem?.inputs.parent()?.listBehavior.unfocus();
444
+ menuitems = menuitems.concat(menuitem?.submenu()?.inputs.items() ?? []);
445
+ }
446
+ }
447
+ }
448
+ class MenuItemPattern {
449
+ inputs;
450
+ value;
451
+ id;
452
+ disabled = () => this.inputs.parent()?.disabled() || this.inputs.disabled();
453
+ searchTerm;
454
+ element;
455
+ active = computed(() => this.inputs.parent()?.inputs.activeItem() === this);
456
+ hasBeenFocused = signal(false);
457
+ tabIndex = computed(() => {
458
+ if (this.submenu() && this.submenu()?.inputs.activeItem()) {
459
+ return -1;
460
+ }
461
+ return this.inputs.parent()?.listBehavior.getItemTabindex(this) ?? -1;
462
+ });
463
+ index = computed(() => this.inputs.parent()?.inputs.items().indexOf(this) ?? -1);
464
+ expanded = computed(() => this.submenu() ? this._expanded() : null);
465
+ _expanded = signal(false);
466
+ controls = signal(undefined);
467
+ role = () => 'menuitem';
468
+ hasPopup = computed(() => !!this.submenu());
469
+ submenu;
470
+ selectable;
471
+ constructor(inputs) {
472
+ this.inputs = inputs;
473
+ this.id = inputs.id;
474
+ this.value = inputs.value;
475
+ this.element = inputs.element;
476
+ this.submenu = this.inputs.submenu;
477
+ this.searchTerm = inputs.searchTerm;
478
+ this.selectable = computed(() => !this.submenu());
479
+ }
480
+ open(opts) {
481
+ if (this.disabled()) {
482
+ return;
483
+ }
484
+ this._expanded.set(true);
485
+ if (opts?.first) {
486
+ this.submenu()?.first();
487
+ }
488
+ if (opts?.last) {
489
+ this.submenu()?.last();
490
+ }
491
+ }
492
+ close(opts = {}) {
493
+ this._expanded.set(false);
494
+ if (opts.refocus) {
495
+ this.inputs.parent()?.listBehavior.goto(this);
496
+ }
497
+ let menuitems = this.inputs.submenu()?.inputs.items() ?? [];
498
+ while (menuitems.length) {
499
+ const menuitem = menuitems.pop();
500
+ menuitem?._expanded.set(false);
501
+ menuitem?.inputs.parent()?.listBehavior.unfocus();
502
+ menuitems = menuitems.concat(menuitem?.submenu()?.inputs.items() ?? []);
503
+ const parent = menuitem?.inputs.parent();
504
+ if (parent instanceof MenuPattern) {
505
+ parent._clearTimeouts();
506
+ }
507
+ }
508
+ }
509
+ onFocusIn() {
510
+ this.hasBeenFocused.set(true);
511
+ }
512
+ }
513
+
514
+ export { MenuBarPattern, MenuItemPattern, MenuPattern, MenuTriggerPattern };
515
+ //# sourceMappingURL=_menu-chunk.mjs.map