ng-primitives 0.44.0 → 0.45.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 (45) hide show
  1. package/combobox/combobox/combobox-state.d.ts +3 -2
  2. package/combobox/combobox/combobox.d.ts +9 -3
  3. package/combobox/combobox-button/combobox-button.d.ts +3 -2
  4. package/combobox/combobox-dropdown/combobox-dropdown.d.ts +52 -2
  5. package/combobox/combobox-input/combobox-input.d.ts +3 -2
  6. package/combobox/combobox-option/combobox-option.d.ts +3 -2
  7. package/combobox/combobox-portal/combobox-portal.d.ts +10 -21
  8. package/example-theme/index.css +1 -0
  9. package/fesm2022/ng-primitives-combobox.mjs +66 -87
  10. package/fesm2022/ng-primitives-combobox.mjs.map +1 -1
  11. package/fesm2022/ng-primitives-focus-trap.mjs +9 -1
  12. package/fesm2022/ng-primitives-focus-trap.mjs.map +1 -1
  13. package/fesm2022/ng-primitives-listbox.mjs +1 -1
  14. package/fesm2022/ng-primitives-listbox.mjs.map +1 -1
  15. package/fesm2022/ng-primitives-menu.mjs +382 -63
  16. package/fesm2022/ng-primitives-menu.mjs.map +1 -1
  17. package/fesm2022/ng-primitives-popover.mjs +66 -331
  18. package/fesm2022/ng-primitives-popover.mjs.map +1 -1
  19. package/fesm2022/ng-primitives-portal.mjs +360 -2
  20. package/fesm2022/ng-primitives-portal.mjs.map +1 -1
  21. package/fesm2022/ng-primitives-tooltip.mjs +56 -176
  22. package/fesm2022/ng-primitives-tooltip.mjs.map +1 -1
  23. package/focus-trap/focus-trap/focus-trap-state.d.ts +1 -0
  24. package/focus-trap/focus-trap/focus-trap.d.ts +5 -0
  25. package/menu/config/menu-config.d.ts +42 -0
  26. package/menu/index.d.ts +5 -1
  27. package/menu/menu/menu.d.ts +6 -2
  28. package/menu/menu-trigger/menu-trigger-state.d.ts +38 -0
  29. package/menu/menu-trigger/menu-trigger.d.ts +91 -13
  30. package/menu/submenu-trigger/submenu-trigger-state.d.ts +58 -0
  31. package/menu/submenu-trigger/submenu-trigger.d.ts +66 -10
  32. package/package.json +12 -12
  33. package/popover/index.d.ts +1 -2
  34. package/popover/popover/popover.d.ts +2 -43
  35. package/popover/popover-trigger/popover-trigger.d.ts +16 -106
  36. package/portal/index.d.ts +2 -0
  37. package/portal/overlay-token.d.ts +12 -0
  38. package/portal/overlay.d.ts +172 -0
  39. package/schematics/ng-generate/templates/combobox/combobox.__fileSuffix@dasherize__.ts.template +31 -0
  40. package/tooltip/index.d.ts +1 -1
  41. package/tooltip/tooltip/tooltip.d.ts +3 -25
  42. package/tooltip/tooltip-trigger/tooltip-trigger.d.ts +16 -63
  43. package/popover/popover/popover-token.d.ts +0 -10
  44. package/popover/utils/transform-origin.d.ts +0 -2
  45. package/tooltip/tooltip/tooltip-token.d.ts +0 -10
@@ -1,15 +1,47 @@
1
+ import { createOverlay, injectOverlay } from 'ng-primitives/portal';
2
+ export { injectOverlayContext as injectMenuContext } from 'ng-primitives/portal';
1
3
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, HostListener, Directive, Injector } from '@angular/core';
3
- import * as i1$1 from 'ng-primitives/button';
4
+ import { InjectionToken, inject, Injector, ViewContainerRef, input, booleanAttribute, numberAttribute, signal, computed, HostListener, Directive } from '@angular/core';
5
+ import * as i1 from 'ng-primitives/button';
4
6
  import { NgpButton } from 'ng-primitives/button';
5
- import { injectElementRef } from 'ng-primitives/internal';
7
+ import { injectElementRef, provideExitAnimationManager } from 'ng-primitives/internal';
6
8
  import * as i2 from 'ng-primitives/roving-focus';
7
9
  import { NgpRovingFocusItem, provideRovingFocusGroup, NgpRovingFocusGroup } from 'ng-primitives/roving-focus';
8
10
  import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
9
- import * as i1 from 'ng-primitives/popover';
10
- import { injectPopoverTriggerState, NgpPopoverTrigger, NgpPopover } from 'ng-primitives/popover';
11
+ import { createStateToken, createStateProvider, createStateInjector, createState } from 'ng-primitives/state';
12
+ import * as i1$1 from 'ng-primitives/popover';
13
+ import { NgpPopover } from 'ng-primitives/popover';
11
14
  import { Subject } from 'rxjs';
12
15
 
16
+ const defaultMenuConfig = {
17
+ offset: 4,
18
+ placement: 'bottom-start',
19
+ flip: true,
20
+ container: null,
21
+ scrollBehavior: 'block',
22
+ };
23
+ const NgpMenuConfigToken = new InjectionToken('NgpMenuConfigToken');
24
+ /**
25
+ * Provide the default Menu configuration
26
+ * @param config The Menu configuration
27
+ * @returns The provider
28
+ */
29
+ function provideMenuConfig(config) {
30
+ return [
31
+ {
32
+ provide: NgpMenuConfigToken,
33
+ useValue: { ...defaultMenuConfig, ...config },
34
+ },
35
+ ];
36
+ }
37
+ /**
38
+ * Inject the Menu configuration
39
+ * @returns The global Menu configuration
40
+ */
41
+ function injectMenuConfig() {
42
+ return inject(NgpMenuConfigToken, { optional: true }) ?? defaultMenuConfig;
43
+ }
44
+
13
45
  const NgpMenuToken = new InjectionToken('NgpMenuToken');
14
46
  /**
15
47
  * Inject the Menu directive instance
@@ -24,41 +56,185 @@ function provideMenu(type) {
24
56
  return { provide: NgpMenuToken, useExisting: type };
25
57
  }
26
58
 
59
+ /**
60
+ * The state token for the MenuTrigger primitive.
61
+ */
62
+ const NgpMenuTriggerStateToken = createStateToken('MenuTrigger');
63
+ /**
64
+ * Provides the MenuTrigger state.
65
+ */
66
+ const provideMenuTriggerState = createStateProvider(NgpMenuTriggerStateToken);
67
+ /**
68
+ * Injects the MenuTrigger state.
69
+ */
70
+ const injectMenuTriggerState = createStateInjector(NgpMenuTriggerStateToken);
71
+ /**
72
+ * The MenuTrigger state registration function.
73
+ */
74
+ const menuTriggerState = createState(NgpMenuTriggerStateToken);
75
+
76
+ /**
77
+ * The state token for the SubmenuTrigger primitive.
78
+ */
79
+ const NgpSubmenuTriggerStateToken = createStateToken('SubmenuTrigger');
80
+ /**
81
+ * Provides the SubmenuTrigger state.
82
+ */
83
+ const provideSubmenuTriggerState = createStateProvider(NgpSubmenuTriggerStateToken);
84
+ /**
85
+ * Injects the SubmenuTrigger state.
86
+ */
87
+ const injectSubmenuTriggerState = createStateInjector(NgpSubmenuTriggerStateToken);
88
+ /**
89
+ * The SubmenuTrigger state registration function.
90
+ */
91
+ const submenuTriggerState = createState(NgpSubmenuTriggerStateToken);
92
+
27
93
  class NgpSubmenuTrigger {
28
94
  constructor() {
29
- /** Access the popover trigger element. */
95
+ /**
96
+ * Access the menu trigger element.
97
+ */
30
98
  this.trigger = injectElementRef();
31
- /** Access the popover trigger state */
32
- this.popoverTrigger = injectPopoverTriggerState();
99
+ /**
100
+ * Access the injector.
101
+ */
102
+ this.injector = inject(Injector);
103
+ /**
104
+ * Access the view container reference.
105
+ */
106
+ this.viewContainerRef = inject(ViewContainerRef);
107
+ /** Access the menu trigger state */
108
+ this.menuTrigger = injectMenuTriggerState();
33
109
  /** Access the parent menu */
34
110
  this.parentMenu = inject(NgpMenuToken, { optional: true });
35
- // by default the popover opens below and to the center of the trigger,
111
+ /**
112
+ * Access the submenu template ref.
113
+ */
114
+ this.menu = input(undefined, {
115
+ alias: 'ngpSubmenuTrigger',
116
+ });
117
+ /**
118
+ * Define if the trigger should be disabled.
119
+ * @default false
120
+ */
121
+ this.disabled = input(false, {
122
+ alias: 'ngpMenuTriggerDisabled',
123
+ transform: booleanAttribute,
124
+ });
125
+ /**
126
+ * Define the placement of the menu relative to the trigger.
127
+ * @default 'right-start'
128
+ */
129
+ this.placement = input('right-start', {
130
+ alias: 'ngpMenuTriggerPlacement',
131
+ });
132
+ /**
133
+ * Define the offset of the menu relative to the trigger.
134
+ * @default 0
135
+ */
136
+ this.offset = input(0, {
137
+ alias: 'ngpMenuTriggerOffset',
138
+ transform: numberAttribute,
139
+ });
140
+ /**
141
+ * Define whether the menu should flip when there is not enough space for the menu.
142
+ * @default true
143
+ */
144
+ this.flip = input(true, {
145
+ alias: 'ngpMenuTriggerFlip',
146
+ transform: booleanAttribute,
147
+ });
148
+ /**
149
+ * The overlay that manages the menu
150
+ * @internal
151
+ */
152
+ this.overlay = signal(null);
153
+ /**
154
+ * The open state of the menu.
155
+ * @internal
156
+ */
157
+ this.open = computed(() => this.overlay()?.isOpen() ?? false);
158
+ /**
159
+ * Access the menu trigger state.
160
+ */
161
+ this.state = submenuTriggerState(this);
162
+ // by default the menu opens below and to the center of the trigger,
36
163
  // but as this is a submenu we want to default to opening to the right
37
164
  // and to the start
38
- this.popoverTrigger().placement.set('right-start');
165
+ this.menuTrigger().placement.set('right-start');
39
166
  this.parentMenu?.closeSubmenus.pipe(takeUntilDestroyed()).subscribe(element => {
40
167
  // if the element is not the trigger, we want to close the menu
41
168
  if (element === this.trigger.nativeElement) {
42
169
  return;
43
170
  }
44
- this.closeMenu('mouse');
171
+ this.hide('mouse');
45
172
  });
46
173
  }
174
+ toggle(event) {
175
+ // if the trigger is disabled then do not toggle the menu
176
+ if (this.state.disabled()) {
177
+ return;
178
+ }
179
+ // determine the origin of the event, 0 is keyboard, 1 is mouse
180
+ const origin = event.detail === 0 ? 'keyboard' : 'mouse';
181
+ // if the menu is open then hide it
182
+ if (this.open()) {
183
+ this.hide(origin);
184
+ }
185
+ else {
186
+ this.show();
187
+ }
188
+ }
47
189
  /**
48
- * @internal
190
+ * Show the menu.
49
191
  */
50
- openMenu(origin) {
51
- // if the menu is already open, we don't want to do anything
52
- if (this.popoverTrigger().open()) {
192
+ show() {
193
+ // If the trigger is disabled, don't show the menu
194
+ if (this.state.disabled()) {
53
195
  return;
54
196
  }
55
- this.popoverTrigger().show(origin);
197
+ // Create the overlay if it doesn't exist yet
198
+ if (!this.overlay()) {
199
+ this.createOverlay();
200
+ }
201
+ // Show the overlay
202
+ this.overlay()?.show();
56
203
  }
57
204
  /**
58
205
  * @internal
206
+ * Hide the menu.
207
+ */
208
+ hide(origin = 'program') {
209
+ // If the trigger is disabled or the menu is not open, do nothing
210
+ if (this.state.disabled() || !this.open()) {
211
+ return;
212
+ }
213
+ // Hide the overlay
214
+ this.overlay()?.hide({ origin });
215
+ }
216
+ /**
217
+ * Create the overlay that will contain the menu
59
218
  */
60
- closeMenu(origin) {
61
- this.popoverTrigger().hide(origin);
219
+ createOverlay() {
220
+ const menu = this.state.menu();
221
+ if (!menu) {
222
+ throw new Error('Menu must be either a TemplateRef or a ComponentType');
223
+ }
224
+ // Create config for the overlay
225
+ const config = {
226
+ content: menu,
227
+ triggerElement: this.trigger.nativeElement,
228
+ injector: this.injector,
229
+ placement: this.state.placement(),
230
+ offset: this.state.offset(),
231
+ flip: this.state.flip(),
232
+ closeOnOutsideClick: true,
233
+ closeOnEscape: true,
234
+ restoreFocus: true,
235
+ viewContainerRef: this.viewContainerRef,
236
+ };
237
+ this.overlay.set(createOverlay(config));
62
238
  }
63
239
  /**
64
240
  * If the user presses the right arrow key, we want to open the submenu
@@ -73,28 +249,29 @@ class NgpSubmenuTrigger {
73
249
  const isLeftArrow = event.key === 'ArrowLeft';
74
250
  if ((isRightArrow && !isRtl) || (isLeftArrow && isRtl)) {
75
251
  event.preventDefault();
76
- this.openMenu('keyboard');
252
+ this.show();
77
253
  }
78
254
  }
79
255
  /**
80
256
  * If the user hovers over the trigger, we want to open the submenu
81
257
  */
82
258
  showSubmenuOnHover() {
83
- this.openMenu('mouse');
259
+ this.show();
84
260
  }
85
261
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpSubmenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
86
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.11", type: NgpSubmenuTrigger, isStandalone: true, selector: "[ngpSubmenuTrigger]", host: { attributes: { "aria-haspopup": "true" }, listeners: { "keydown.ArrowRight": "showSubmenuOnArrow($event)", "keydown.ArrowLeft": "showSubmenuOnArrow($event)", "mouseenter": "showSubmenuOnHover()" } }, exportAs: ["ngpSubmenuTrigger"], hostDirectives: [{ directive: i1.NgpPopoverTrigger, inputs: ["ngpPopoverTrigger", "ngpSubmenuTrigger"] }], ngImport: i0 }); }
262
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.11", type: NgpSubmenuTrigger, isStandalone: true, selector: "[ngpSubmenuTrigger]", inputs: { menu: { classPropertyName: "menu", publicName: "ngpSubmenuTrigger", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpMenuTriggerDisabled", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "ngpMenuTriggerPlacement", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "ngpMenuTriggerOffset", isSignal: true, isRequired: false, transformFunction: null }, flip: { classPropertyName: "flip", publicName: "ngpMenuTriggerFlip", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-haspopup": "true" }, listeners: { "click": "toggle($event)", "keydown.ArrowRight": "showSubmenuOnArrow($event)", "keydown.ArrowLeft": "showSubmenuOnArrow($event)", "mouseenter": "showSubmenuOnHover()" }, properties: { "attr.aria-expanded": "open() ? \"true\" : \"false\"", "attr.data-open": "open() ? \"\" : null" } }, providers: [provideSubmenuTriggerState({ inherit: false }), provideExitAnimationManager()], exportAs: ["ngpSubmenuTrigger"], ngImport: i0 }); }
87
263
  }
88
264
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpSubmenuTrigger, decorators: [{
89
265
  type: Directive,
90
266
  args: [{
91
267
  selector: '[ngpSubmenuTrigger]',
92
268
  exportAs: 'ngpSubmenuTrigger',
93
- hostDirectives: [
94
- { directive: NgpPopoverTrigger, inputs: ['ngpPopoverTrigger:ngpSubmenuTrigger'] },
95
- ],
269
+ providers: [provideSubmenuTriggerState({ inherit: false }), provideExitAnimationManager()],
96
270
  host: {
97
271
  'aria-haspopup': 'true',
272
+ '[attr.aria-expanded]': 'open() ? "true" : "false"',
273
+ '[attr.data-open]': 'open() ? "" : null',
274
+ '(click)': 'toggle($event)',
98
275
  },
99
276
  }]
100
277
  }], ctorParameters: () => [], propDecorators: { showSubmenuOnArrow: [{
@@ -147,7 +324,7 @@ class NgpMenuItem {
147
324
  if ((isLeftArrow && !isRtl) || (isRightArrow && isRtl)) {
148
325
  event.preventDefault();
149
326
  if (trigger) {
150
- trigger.closeMenu('keyboard');
327
+ trigger.hide('keyboard');
151
328
  }
152
329
  }
153
330
  }
@@ -158,7 +335,7 @@ class NgpMenuItem {
158
335
  this.parentMenu?.closeSubmenus.next(this.elementRef.nativeElement);
159
336
  }
160
337
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
161
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.11", type: NgpMenuItem, isStandalone: true, selector: "[ngpMenuItem]", host: { attributes: { "role": "menuitem" }, listeners: { "click": "onClick($event)", "keydown.ArrowLeft": "handleArrowKey($event)", "keydown.ArrowRight": "handleArrowKey($event)", "mouseenter": "showSubmenuOnHover()" } }, exportAs: ["ngpMenuItem"], hostDirectives: [{ directive: i1$1.NgpButton, inputs: ["disabled", "ngpMenuItemDisabled"] }, { directive: i2.NgpRovingFocusItem }], ngImport: i0 }); }
338
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.11", type: NgpMenuItem, isStandalone: true, selector: "[ngpMenuItem]", host: { attributes: { "role": "menuitem" }, listeners: { "click": "onClick($event)", "keydown.ArrowLeft": "handleArrowKey($event)", "keydown.ArrowRight": "handleArrowKey($event)", "mouseenter": "showSubmenuOnHover()" } }, exportAs: ["ngpMenuItem"], hostDirectives: [{ directive: i1.NgpButton, inputs: ["disabled", "ngpMenuItemDisabled"] }, { directive: i2.NgpRovingFocusItem }], ngImport: i0 }); }
162
339
  }
163
340
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpMenuItem, decorators: [{
164
341
  type: Directive,
@@ -186,60 +363,195 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImpo
186
363
  */
187
364
  class NgpMenuTrigger {
188
365
  constructor() {
189
- /** Access the popover trigger state */
190
- this.state = injectPopoverTriggerState();
191
- /** Access any parent menus */
192
- this.parentMenu = inject(NgpMenuToken, { optional: true });
193
- // by default the popover opens below and to the center of the trigger,
194
- // but as this is a menu we want to default to opening below and to the start
195
- this.state().placement.set('bottom-start');
196
- // for menus we want to default to blocking the scroll behavior
197
- this.state().scrollBehavior.set('block');
366
+ /**
367
+ * Access the trigger element
368
+ */
369
+ this.trigger = injectElementRef();
370
+ /**
371
+ * Access the injector.
372
+ */
373
+ this.injector = inject(Injector);
374
+ /**
375
+ * Access the view container reference.
376
+ */
377
+ this.viewContainerRef = inject(ViewContainerRef);
378
+ /**
379
+ * Access the global menu configuration.
380
+ */
381
+ this.config = injectMenuConfig();
382
+ /**
383
+ * Access the menu template ref.
384
+ */
385
+ this.menu = input(undefined, {
386
+ alias: 'ngpMenuTrigger',
387
+ });
388
+ /**
389
+ * Define if the trigger should be disabled.
390
+ * @default false
391
+ */
392
+ this.disabled = input(false, {
393
+ alias: 'ngpMenuTriggerDisabled',
394
+ transform: booleanAttribute,
395
+ });
396
+ /**
397
+ * Define the placement of the menu relative to the trigger.
398
+ * @default 'bottom-start'
399
+ */
400
+ this.placement = input(this.config.placement, {
401
+ alias: 'ngpMenuTriggerPlacement',
402
+ });
403
+ /**
404
+ * Define the offset of the menu relative to the trigger.
405
+ * @default 0
406
+ */
407
+ this.offset = input(this.config.offset, {
408
+ alias: 'ngpMenuTriggerOffset',
409
+ transform: numberAttribute,
410
+ });
411
+ /**
412
+ * Define whether the menu should flip when there is not enough space for the menu.
413
+ * @default true
414
+ */
415
+ this.flip = input(this.config.flip, {
416
+ alias: 'ngpMenuTriggerFlip',
417
+ transform: booleanAttribute,
418
+ });
419
+ /**
420
+ * Define the container in which the menu should be attached.
421
+ * @default document.body
422
+ */
423
+ this.container = input(this.config.container, {
424
+ alias: 'ngpMenuTriggerContainer',
425
+ });
426
+ /**
427
+ * Defines how the menu behaves when the window is scrolled.
428
+ * @default 'block'
429
+ */
430
+ this.scrollBehavior = input(this.config.scrollBehavior, {
431
+ alias: 'ngpMenuTriggerScrollBehavior',
432
+ });
433
+ /**
434
+ * Provide context to the menu. This can be used to pass data to the menu content.
435
+ */
436
+ this.context = input(undefined, {
437
+ alias: 'ngpMenuTriggerContext',
438
+ });
439
+ /**
440
+ * The overlay that manages the menu
441
+ * @internal
442
+ */
443
+ this.overlay = signal(null);
444
+ /**
445
+ * The open state of the menu.
446
+ * @internal
447
+ */
448
+ this.open = computed(() => this.overlay()?.isOpen() ?? false);
449
+ /**
450
+ * The menu trigger state.
451
+ */
452
+ this.state = menuTriggerState(this);
453
+ }
454
+ ngOnDestroy() {
455
+ this.overlay()?.destroy();
456
+ }
457
+ toggle(event) {
458
+ // if the trigger is disabled then do not toggle the menu
459
+ if (this.state.disabled()) {
460
+ return;
461
+ }
462
+ // determine the origin of the event, 0 is keyboard, 1 is mouse
463
+ const origin = event.detail === 0 ? 'keyboard' : 'mouse';
464
+ // if the menu is open then hide it
465
+ if (this.open()) {
466
+ this.hide(origin);
467
+ }
468
+ else {
469
+ this.show();
470
+ }
198
471
  }
199
472
  /**
200
- * Close the menu and any parent menus
473
+ * Show the menu.
201
474
  */
202
- closeOnEscape() {
203
- this.parentMenu?.closeAllMenus('keyboard');
475
+ show() {
476
+ // If the trigger is disabled, don't show the menu
477
+ if (this.state.disabled()) {
478
+ return;
479
+ }
480
+ // Create the overlay if it doesn't exist yet
481
+ if (!this.overlay()) {
482
+ this.createOverlay();
483
+ }
484
+ // Show the overlay
485
+ this.overlay()?.show();
486
+ }
487
+ /**
488
+ * @internal
489
+ * Hide the menu.
490
+ */
491
+ hide(origin = 'program') {
492
+ // If the trigger is disabled or the menu is not open, do nothing
493
+ if (this.state.disabled() || !this.open()) {
494
+ return;
495
+ }
496
+ // Hide the overlay
497
+ this.overlay()?.hide({ origin });
498
+ }
499
+ /**
500
+ * Create the overlay that will contain the menu
501
+ */
502
+ createOverlay() {
503
+ const menu = this.state.menu();
504
+ if (!menu) {
505
+ throw new Error('Menu must be either a TemplateRef or a ComponentType');
506
+ }
507
+ // Create config for the overlay
508
+ const config = {
509
+ content: menu,
510
+ triggerElement: this.trigger.nativeElement,
511
+ viewContainerRef: this.viewContainerRef,
512
+ injector: this.injector,
513
+ context: this.state.context(),
514
+ container: this.state.container(),
515
+ placement: this.state.placement(),
516
+ offset: this.state.offset(),
517
+ flip: this.state.flip(),
518
+ closeOnOutsideClick: true,
519
+ closeOnEscape: true,
520
+ restoreFocus: true,
521
+ scrollBehaviour: this.state.scrollBehavior(),
522
+ };
523
+ this.overlay.set(createOverlay(config));
204
524
  }
205
525
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
206
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.11", type: NgpMenuTrigger, isStandalone: true, selector: "[ngpMenuTrigger]", host: { attributes: { "aria-haspopup": "true" }, listeners: { "document:keydown.escape": "closeOnEscape()" } }, exportAs: ["ngpMenuTrigger"], hostDirectives: [{ directive: i1.NgpPopoverTrigger, inputs: ["ngpPopoverTrigger", "ngpMenuTrigger", "ngpPopoverTriggerDisabled", "ngpMenuTriggerDisabled", "ngpPopoverTriggerPlacement", "ngpMenuTriggerPlacement", "ngpPopoverTriggerOffset", "ngpMenuTriggerOffset", "ngpPopoverTriggerShowDelay", "ngpMenuTriggerShowDelay", "ngpPopoverTriggerHideDelay", "ngpMenuTriggerHideDelay", "ngpPopoverTriggerFlip", "ngpMenuTriggerFlip", "ngpPopoverTriggerContainer", "ngpMenuTriggerContainer", "ngpPopoverTriggerScrollBehavior", "ngpMenuTriggerScrollBehavior"] }], ngImport: i0 }); }
526
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.11", type: NgpMenuTrigger, isStandalone: true, selector: "[ngpMenuTrigger]", inputs: { menu: { classPropertyName: "menu", publicName: "ngpMenuTrigger", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "ngpMenuTriggerDisabled", isSignal: true, isRequired: false, transformFunction: null }, placement: { classPropertyName: "placement", publicName: "ngpMenuTriggerPlacement", isSignal: true, isRequired: false, transformFunction: null }, offset: { classPropertyName: "offset", publicName: "ngpMenuTriggerOffset", isSignal: true, isRequired: false, transformFunction: null }, flip: { classPropertyName: "flip", publicName: "ngpMenuTriggerFlip", isSignal: true, isRequired: false, transformFunction: null }, container: { classPropertyName: "container", publicName: "ngpMenuTriggerContainer", isSignal: true, isRequired: false, transformFunction: null }, scrollBehavior: { classPropertyName: "scrollBehavior", publicName: "ngpMenuTriggerScrollBehavior", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "ngpMenuTriggerContext", isSignal: true, isRequired: false, transformFunction: null } }, host: { attributes: { "aria-haspopup": "true" }, listeners: { "click": "toggle($event)" }, properties: { "attr.aria-expanded": "open() ? \"true\" : \"false\"", "attr.data-open": "open() ? \"\" : null", "attr.data-placement": "state.placement()" } }, providers: [provideMenuTriggerState({ inherit: false }), provideExitAnimationManager()], exportAs: ["ngpMenuTrigger"], ngImport: i0 }); }
207
527
  }
208
528
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpMenuTrigger, decorators: [{
209
529
  type: Directive,
210
530
  args: [{
211
531
  selector: '[ngpMenuTrigger]',
212
532
  exportAs: 'ngpMenuTrigger',
213
- hostDirectives: [
214
- {
215
- directive: NgpPopoverTrigger,
216
- inputs: [
217
- 'ngpPopoverTrigger:ngpMenuTrigger',
218
- 'ngpPopoverTriggerDisabled:ngpMenuTriggerDisabled',
219
- 'ngpPopoverTriggerPlacement:ngpMenuTriggerPlacement',
220
- 'ngpPopoverTriggerOffset:ngpMenuTriggerOffset',
221
- 'ngpPopoverTriggerShowDelay:ngpMenuTriggerShowDelay',
222
- 'ngpPopoverTriggerHideDelay:ngpMenuTriggerHideDelay',
223
- 'ngpPopoverTriggerFlip:ngpMenuTriggerFlip',
224
- 'ngpPopoverTriggerContainer:ngpMenuTriggerContainer',
225
- 'ngpPopoverTriggerScrollBehavior:ngpMenuTriggerScrollBehavior',
226
- ],
227
- },
228
- ],
533
+ providers: [provideMenuTriggerState({ inherit: false }), provideExitAnimationManager()],
229
534
  host: {
230
535
  'aria-haspopup': 'true',
231
- '(document:keydown.escape)': 'closeOnEscape()',
536
+ '[attr.aria-expanded]': 'open() ? "true" : "false"',
537
+ '[attr.data-open]': 'open() ? "" : null',
538
+ '[attr.data-placement]': 'state.placement()',
539
+ '(click)': 'toggle($event)',
232
540
  },
233
541
  }]
234
- }], ctorParameters: () => [] });
542
+ }] });
235
543
 
236
544
  /**
237
545
  * The `NgpMenu` is a container for menu items.
238
546
  */
239
547
  class NgpMenu {
240
548
  constructor() {
241
- /** Access the popover trigger state */
242
- this.popover = injectPopoverTriggerState();
549
+ /**
550
+ * Access the overlay.
551
+ */
552
+ this.overlay = injectOverlay();
553
+ /** Access the menu trigger state */
554
+ this.menuTrigger = injectMenuTriggerState();
243
555
  /** Access any parent menus */
244
556
  this.parentMenu = inject(NgpMenuToken, { optional: true, skipSelf: true });
245
557
  /** @internal Whether we should close submenus */
@@ -247,15 +559,15 @@ class NgpMenu {
247
559
  }
248
560
  /** Close the menu and any parent menus */
249
561
  closeAllMenus(origin) {
250
- this.popover().hide(origin);
562
+ this.menuTrigger().hide(origin);
251
563
  this.parentMenu?.closeAllMenus(origin);
252
564
  }
253
565
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpMenu, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
254
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.11", type: NgpMenu, isStandalone: true, selector: "[ngpMenu]", providers: [
566
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.11", type: NgpMenu, isStandalone: true, selector: "[ngpMenu]", host: { attributes: { "role": "menu" }, properties: { "style.left.px": "overlay.position().x", "style.top.px": "overlay.position().y", "style.--ngp-menu-trigger-width.px": "overlay.triggerWidth()", "style.--ngp-menu-transform-origin": "overlay.transformOrigin()" } }, providers: [
255
567
  // ensure we don't inherit the focus group from the parent menu if there is one
256
568
  provideRovingFocusGroup(NgpRovingFocusGroup, { inherit: false }),
257
569
  provideMenu(NgpMenu),
258
- ], exportAs: ["ngpMenu"], hostDirectives: [{ directive: i1.NgpPopover }, { directive: i2.NgpRovingFocusGroup }], ngImport: i0 }); }
570
+ ], exportAs: ["ngpMenu"], hostDirectives: [{ directive: i1$1.NgpPopover }, { directive: i2.NgpRovingFocusGroup }], ngImport: i0 }); }
259
571
  }
260
572
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImport: i0, type: NgpMenu, decorators: [{
261
573
  type: Directive,
@@ -268,6 +580,13 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImpo
268
580
  provideRovingFocusGroup(NgpRovingFocusGroup, { inherit: false }),
269
581
  provideMenu(NgpMenu),
270
582
  ],
583
+ host: {
584
+ role: 'menu',
585
+ '[style.left.px]': 'overlay.position().x',
586
+ '[style.top.px]': 'overlay.position().y',
587
+ '[style.--ngp-menu-trigger-width.px]': 'overlay.triggerWidth()',
588
+ '[style.--ngp-menu-transform-origin]': 'overlay.transformOrigin()',
589
+ },
271
590
  }]
272
591
  }] });
273
592
 
@@ -275,5 +594,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.11", ngImpo
275
594
  * Generated bundle index. Do not edit.
276
595
  */
277
596
 
278
- export { NgpMenu, NgpMenuItem, NgpMenuToken, NgpMenuTrigger, NgpSubmenuTrigger, injectMenu };
597
+ export { NgpMenu, NgpMenuItem, NgpMenuToken, NgpMenuTrigger, NgpSubmenuTrigger, injectMenu, injectMenuTriggerState, injectSubmenuTriggerState, provideMenuConfig, provideMenuTriggerState, provideSubmenuTriggerState };
279
598
  //# sourceMappingURL=ng-primitives-menu.mjs.map