@ngrdt/menu 0.0.10 → 0.0.12

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.
@@ -1,5 +1,5 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, ElementRef, DestroyRef, Renderer2, ChangeDetectorRef, Component, ChangeDetectionStrategy, ViewChildren, ViewChild, Input, HostBinding, HostListener, EnvironmentInjector, booleanAttribute, Directive, ViewEncapsulation, numberAttribute, NgModule } from '@angular/core';
2
+ import { InjectionToken, inject, ElementRef, DestroyRef, Renderer2, ChangeDetectorRef, Component, ChangeDetectionStrategy, ViewChildren, ViewChild, Input, HostBinding, HostListener, EnvironmentInjector, booleanAttribute, numberAttribute, Directive, ViewEncapsulation, NgModule } from '@angular/core';
3
3
  import * as i2$1 from '@ngrdt/button';
4
4
  import { RDT_BUTTON_BASE_PROVIDER, RdtButtonOutletDirective } from '@ngrdt/button';
5
5
  import * as i1 from '@angular/common';
@@ -11,7 +11,7 @@ import * as i3 from '@ngrdt/router';
11
11
  import { RdtRouterService, RdtAnyRouteActiveDirective } from '@ngrdt/router';
12
12
  import * as i4 from '@ngrdt/shortcuts';
13
13
  import { RdtShortcutService, RdtShortcut, RdtKeyListenerDirective } from '@ngrdt/shortcuts';
14
- import { KB_CODE, RdtObjectUtils, RdtStringUtils } from '@ngrdt/utils';
14
+ import { RdtStringUtils, KB_CODE, RdtObjectUtils } from '@ngrdt/utils';
15
15
  import { delay, of, map, first, Subscription, fromEvent, throttleTime, animationFrameScheduler } from 'rxjs';
16
16
 
17
17
  var RdtMenuShortcutMode;
@@ -28,6 +28,78 @@ const DEFAULT_MENU_VERTICAL_DIR = 'down';
28
28
  const RDT_MENU_HORIZONTAL_DIR_PROVIDER = new InjectionToken('RDT_MENU_HORIZONTAL_DIR');
29
29
  const RDT_MENU_VERTICAL_DIR_PROVIDER = new InjectionToken('RDT_MENU_VERTICAL_DIR');
30
30
 
31
+ function parseMenuItems(items, injector, prefix = '') {
32
+ return items
33
+ .map((item) => {
34
+ let newPrefix;
35
+ if (item.dataTestId) {
36
+ newPrefix = item.dataTestId;
37
+ }
38
+ else if (prefix) {
39
+ newPrefix = RdtStringUtils.getDataTestId(item.label, prefix);
40
+ }
41
+ else {
42
+ newPrefix = RdtStringUtils.getDataTestId(item.label);
43
+ }
44
+ const newDataTestId = RdtStringUtils.getDataTestId(newPrefix, null, 'menu-item');
45
+ const res = {
46
+ label: item.label,
47
+ icon: item.icon,
48
+ shortcut: item.shortcut,
49
+ command: item.command,
50
+ visible: item.visible,
51
+ queryParams: item.queryParams,
52
+ requiredParent: item.requiredParent,
53
+ dataTestId: newDataTestId,
54
+ };
55
+ if (item.items) {
56
+ const childrenRes = res;
57
+ const parsedChildren = parseMenuItems(item.items, injector, newPrefix);
58
+ if (parsedChildren.length > 0) {
59
+ childrenRes.items = parsedChildren;
60
+ }
61
+ return childrenRes;
62
+ }
63
+ else if (item.routerLink) {
64
+ const linkRes = res;
65
+ linkRes.target = item.target ?? '_self';
66
+ if (item.routerLink) {
67
+ linkRes.routerLink = [item.routerLink.createAbsoluteUrl()];
68
+ if (!res.visible && item.routerLink.hasCanBeEnteredGuard) {
69
+ const canBeEntered = item.routerLink.canBeEntered.bind(item.routerLink);
70
+ linkRes.visible = () => canBeEntered(injector);
71
+ }
72
+ }
73
+ return linkRes;
74
+ }
75
+ else {
76
+ const linkRes = res;
77
+ if (item.externalLink) {
78
+ if (item.queryParams) {
79
+ linkRes.externalLink = RdtStringUtils.appendQueryParams(item.externalLink, item.queryParams);
80
+ }
81
+ else {
82
+ linkRes.externalLink = item.externalLink;
83
+ }
84
+ }
85
+ linkRes.target = item.target ?? '_blank';
86
+ return linkRes;
87
+ }
88
+ })
89
+ .filter((item) => !item.visible || item.visible())
90
+ .filter((item) => item.externalLink ||
91
+ item['routerLink'] ||
92
+ item.command ||
93
+ (item['items']?.length ?? 0) > 0);
94
+ }
95
+ var RdtMenuExpandSource;
96
+ (function (RdtMenuExpandSource) {
97
+ RdtMenuExpandSource[RdtMenuExpandSource["Click"] = 0] = "Click";
98
+ RdtMenuExpandSource[RdtMenuExpandSource["Hover"] = 1] = "Hover";
99
+ RdtMenuExpandSource[RdtMenuExpandSource["Shortcut"] = 2] = "Shortcut";
100
+ RdtMenuExpandSource[RdtMenuExpandSource["Focus"] = 3] = "Focus";
101
+ })(RdtMenuExpandSource || (RdtMenuExpandSource = {}));
102
+
31
103
  const INVISIBLE_CLASS = 'invisible';
32
104
  const FOCUS_VISIBLE = 'focus-visible';
33
105
  function getChildRoutesMapRec(item, map) {
@@ -160,7 +232,7 @@ class RdtMenuOverlayComponent {
160
232
  keyActions = {
161
233
  [KB_CODE.ARROW.UP]: (index) => this.focusPrevItem(index),
162
234
  [KB_CODE.ARROW.DOWN]: (index) => this.focusNextItem(index),
163
- [KB_CODE.ARROW.RIGHT]: (index) => this.openSubmenu(index, 'first'),
235
+ [KB_CODE.ARROW.RIGHT]: (index) => this.openSubmenu(index, 'first', RdtMenuExpandSource.Shortcut),
164
236
  [KB_CODE.ARROW.LEFT]: () => this.closeSelf(),
165
237
  [KB_CODE.HOME]: () => this.focusItem(0),
166
238
  [KB_CODE.END]: () => this.focusItem(this.item.items.length - 1),
@@ -168,6 +240,17 @@ class RdtMenuOverlayComponent {
168
240
  [KB_CODE.ENTER]: (index) => this.invokeItemClickByIndex(index),
169
241
  [KB_CODE.SPACEBAR]: (index) => this.invokeItemClickByIndex(index),
170
242
  };
243
+ get selfExpandSrc() {
244
+ if (this.expanded) {
245
+ if (this.parentMenu) {
246
+ return this.parentMenu.expandedChild?.src;
247
+ }
248
+ else {
249
+ return this.topLevelMenu.expandedChild?.src;
250
+ }
251
+ }
252
+ return undefined;
253
+ }
171
254
  ngOnInit() {
172
255
  this.setClasses();
173
256
  this.listenTabKeyPress();
@@ -274,25 +357,25 @@ class RdtMenuOverlayComponent {
274
357
  }
275
358
  onItemPointerEnter(item) {
276
359
  if (this.topLevelMenu.openOnHover &&
277
- this.expandedChild !== item &&
278
- menuItemHasChildren(item)) {
360
+ this.expandedChild?.src !== RdtMenuExpandSource.Click) {
279
361
  this.autofocusSubmenuItem = null;
280
- this.expandedChild = item;
281
- }
282
- }
283
- onItemPointerLeave(item) {
284
- if (this.topLevelMenu.openOnHover &&
285
- this.expandedChild === item &&
286
- menuItemHasChildren(item)) {
287
- this.autofocusSubmenuItem = null;
288
- this.expandedChild = null;
362
+ if (menuItemHasChildren(item)) {
363
+ this.expandedChild = { item, src: RdtMenuExpandSource.Hover };
364
+ this.expanded = true;
365
+ }
366
+ else {
367
+ //console.log('expanded child', this.expandedChild);
368
+ this.expandedChild = null;
369
+ }
289
370
  }
290
371
  }
291
372
  onItemClick(item) {
292
373
  const hasChildren = menuItemHasChildren(item);
293
- if (hasChildren && this.expandedChild !== item) {
374
+ if ((hasChildren && this.expandedChild?.item !== item) ||
375
+ (this.topLevelMenu.openOnHover &&
376
+ this.expandedChild?.src === RdtMenuExpandSource.Hover)) {
294
377
  this.autofocusSubmenuItem = null;
295
- this.expandedChild = item;
378
+ this.expandedChild = { item, src: RdtMenuExpandSource.Click };
296
379
  }
297
380
  else {
298
381
  this.expandedChild = null;
@@ -318,7 +401,7 @@ class RdtMenuOverlayComponent {
318
401
  }
319
402
  closeSubmenus(focusExpanded = false) {
320
403
  if (focusExpanded && this.expandedChild) {
321
- this.focusItem(this.expandedChild);
404
+ this.focusItem(this.expandedChild.item);
322
405
  }
323
406
  this.expandedChild = null;
324
407
  this.cd.markForCheck();
@@ -329,7 +412,7 @@ class RdtMenuOverlayComponent {
329
412
  this.autofocusSubmenuItem = null;
330
413
  this.autofocusItem = null;
331
414
  if (children.length > 0) {
332
- this.expandAndGetChild(thisItem)
415
+ this.expandAndGetChild(thisItem, RdtMenuExpandSource.Focus)
333
416
  .pipe(delay(1))
334
417
  .subscribe((overlay) => {
335
418
  overlay.focusItemRecursively(children);
@@ -346,11 +429,11 @@ class RdtMenuOverlayComponent {
346
429
  setTimeout(() => this.focusItem(thisItem), 1);
347
430
  }
348
431
  }
349
- expandAndGetChild(item) {
432
+ expandAndGetChild(item, src) {
350
433
  if (this.item.items.indexOf(item) < 0) {
351
434
  throw new Error('Attempting to expand item that is not child item of this.item');
352
435
  }
353
- this.expandedChild = item;
436
+ this.expandedChild = { item, src };
354
437
  this.cd.markForCheck();
355
438
  const child = this.children.find((child) => child.item === item);
356
439
  if (child) {
@@ -381,6 +464,8 @@ class RdtMenuOverlayComponent {
381
464
  }
382
465
  }
383
466
  onTabKeyPress(event) {
467
+ console.log('tab key pressed', event);
468
+ setTimeout(() => console.log('active element', this.document.activeElement), 300);
384
469
  // Do not prevent default to correctly switch to previous element
385
470
  event.originalEvent.stopPropagation();
386
471
  // Wait for document.activeElement to switch to new element
@@ -430,10 +515,10 @@ class RdtMenuOverlayComponent {
430
515
  const prev = (itemIndex - 1 + this.item.items.length) % this.item.items.length;
431
516
  this.focusItem(prev);
432
517
  }
433
- openSubmenu(itemIndex, visibleFocus) {
518
+ openSubmenu(itemIndex, visibleFocus, src) {
434
519
  if (itemIndex < this.item.items.length &&
435
520
  menuItemHasChildren(this.item.items[itemIndex])) {
436
- this.expandedChild = this.item.items[itemIndex];
521
+ this.expandedChild = { item: this.item.items[itemIndex], src };
437
522
  this.autofocusSubmenuItem = visibleFocus;
438
523
  }
439
524
  }
@@ -446,7 +531,7 @@ class RdtMenuOverlayComponent {
446
531
  }
447
532
  }
448
533
  checkActiveElement(event) {
449
- if (this.topLevelMenu.closeOnFocusOut) {
534
+ if (this.topLevelMenu.closeOnFocusOut && !this.topLevelMenu.openOnHover) {
450
535
  const thisEl = this.elRef.nativeElement;
451
536
  const target = event.relatedTarget;
452
537
  if (!(target instanceof HTMLElement) || !thisEl.contains(target)) {
@@ -632,11 +717,11 @@ class RdtMenuOverlayComponent {
632
717
  .subscribe((event) => this.onTabKeyPress(event));
633
718
  }
634
719
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RdtMenuOverlayComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
635
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.7", type: RdtMenuOverlayComponent, selector: "rdt-menu-overlay", inputs: { item: "item", level: "level", preferredHorizontalDir: "preferredHorizontalDir", preferredVerticalDir: "preferredVerticalDir", expanded: "expanded", autofocusItem: "autofocusItem", anchorElement: "anchorElement" }, host: { listeners: { "window:focusout": "checkActiveElement($event)" }, properties: { "class.expanded": "this.expanded", "attr.role": "this.roleAttr", "attr.tabindex": "this.tabindexAttr", "style.z-index": "this.zIndex" } }, viewQueries: [{ propertyName: "menuItemContainer", first: true, predicate: ["menuItemContainer"], descendants: true }, { propertyName: "children", predicate: RdtMenuOverlayComponent, descendants: true }, { propertyName: "focusableElements", predicate: ["focusableItem"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ul class=\"menu-item-container\" role=\"presentation\" #menuItemContainer>\r\n <li\r\n *ngFor=\"let item of item.items; let i = index\"\r\n role=\"presentation\"\r\n class=\"menu-item\"\r\n (rdtKeyListener)=\"onKeyDown(i, $event)\"\r\n rdtAnyRouteActive=\"menu-item-route-active\"\r\n [watchedRoutes]=\"getChildRoutes(item)\"\r\n (pointerleave)=\"onItemPointerLeave(item)\"\r\n #anchorEl\r\n >\r\n <ng-container *ngIf=\"!item.routerLink && !item.externalLink\">\r\n <button\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n (pointerenter)=\"onItemPointerEnter(item)\"\r\n [attr.aria-haspopup]=\"item.items ? 'menu' : null\"\r\n [attr.aria-expanded]=\"item === expandedChild\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n {{ item.label }}\r\n\r\n <div class=\"menu-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO:\r\n <rdt-icon\r\n *ngIf=\"item.items\"\r\n name=\"chevron_right\"\r\n class=\"menu-item-icon\"\r\n />\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-item-icon\"\r\n />\r\n -->\r\n <span class=\"menu-item-icon\" *ngIf=\"item.items\">&gt;</span>\r\n </div>\r\n </button>\r\n </ng-container>\r\n\r\n <ng-template #linkBody let-item>\r\n {{ item.label }}\r\n\r\n <div class=\"menu-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO:\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-item-icon\"\r\n />\r\n --></div>\r\n </ng-template>\r\n\r\n <ng-container *ngIf=\"item.routerLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [routerLink]=\"item.routerLink\"\r\n [queryParams]=\"item.queryParams\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"item.externalLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [href]=\"item.externalLink\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <!-- Child menus exist only if this menu is expanded. -->\r\n <!-- Only one invisible level is always attached to DOM, the rest does not exist. -->\r\n <rdt-menu-overlay\r\n *ngIf=\"item.items && expanded\"\r\n [item]=\"$any(item)\"\r\n [expanded]=\"item === expandedChild\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"horizontalDir?.dir!\"\r\n [preferredVerticalDir]=\"verticalDir?.dir!\"\r\n [level]=\"level + 1\"\r\n [anchorElement]=\"anchorEl\"\r\n />\r\n </li>\r\n</ul>\r\n", styles: [":host{visibility:hidden;position:fixed;min-width:var(--rdt-menu-min-width);box-shadow:var(--rdt-menu-box-shadow);border-radius:var(--rdt-menu-border-radius);max-height:calc(100vh - var(--rdt-menu-margin-top, 0px) - var(--rdt-menu-margin-bottom, 0px));overflow-y:auto}:host.expanded{visibility:visible}.menu-item-container{list-style-type:none;padding:var(--rdt-menu-padding-horizontal-padding) 0;border-radius:var(--rdt-menu-border-radius);background-color:var(--rdt-menu-item-background)}.menu-item{cursor:pointer;position:relative;box-sizing:border-box}.menu-item.menu-item-route-active>.menu-item-content{background-color:var(--rdt-menu-item-background-route-active)}.menu-item-content{display:flex;align-items:center;padding:var(--rdt-menu-item-padding);width:100%;background-color:var(--rdt-menu-item-background);color:var(--rdt-menu-item-text-color)}.menu-item-content:hover{background-color:var(--rdt-menu-item-background-hover)}.menu-item-content.focus-visible:focus,.menu-item-content:focus-visible{background-color:var(--rdt-menu-item-background-focus);outline:none}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3.RdtAnyRouteActiveDirective, selector: "[rdtAnyRouteActive]", inputs: ["anyRouteActive", "watchedRoutes", "anyRouteActiveOptions", "ariaCurrentWhenActive"] }, { kind: "directive", type: i4.RdtKeyListenerDirective, selector: "[rdtKeyListener]", outputs: ["rdtKeyListener"] }, { kind: "component", type: RdtMenuOverlayComponent, selector: "rdt-menu-overlay", inputs: ["item", "level", "preferredHorizontalDir", "preferredVerticalDir", "expanded", "autofocusItem", "anchorElement"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
720
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.7", type: RdtMenuOverlayComponent, selector: "rdt-menu-overlay", inputs: { item: "item", level: "level", preferredHorizontalDir: "preferredHorizontalDir", preferredVerticalDir: "preferredVerticalDir", expanded: "expanded", autofocusItem: "autofocusItem", anchorElement: "anchorElement" }, host: { listeners: { "window:focusout": "checkActiveElement($event)" }, properties: { "class.expanded": "this.expanded", "attr.role": "this.roleAttr", "attr.tabindex": "this.tabindexAttr", "style.z-index": "this.zIndex" } }, viewQueries: [{ propertyName: "menuItemContainer", first: true, predicate: ["menuItemContainer"], descendants: true }, { propertyName: "children", predicate: RdtMenuOverlayComponent, descendants: true }, { propertyName: "focusableElements", predicate: ["focusableItem"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "<ul class=\"menu-item-container\" role=\"presentation\" #menuItemContainer>\r\n <li\r\n *ngFor=\"let item of item.items; let i = index\"\r\n role=\"presentation\"\r\n class=\"menu-item\"\r\n (rdtKeyListener)=\"onKeyDown(i, $event)\"\r\n (pointerenter)=\"onItemPointerEnter(item)\"\r\n rdtAnyRouteActive=\"menu-item-route-active\"\r\n [watchedRoutes]=\"getChildRoutes(item)\"\r\n #anchorEl\r\n >\r\n <ng-container *ngIf=\"!item.routerLink && !item.externalLink\">\r\n <button\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [attr.aria-haspopup]=\"item.items ? 'menu' : null\"\r\n [attr.aria-expanded]=\"item === expandedChild?.item\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n {{ item.label }}\r\n\r\n <div class=\"menu-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO:\r\n <rdt-icon\r\n *ngIf=\"item.items\"\r\n name=\"chevron_right\"\r\n class=\"menu-item-icon\"\r\n />\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-item-icon\"\r\n />\r\n -->\r\n <span class=\"menu-item-icon\" *ngIf=\"item.items\">&gt;</span>\r\n </div>\r\n </button>\r\n </ng-container>\r\n\r\n <ng-template #linkBody let-item>\r\n {{ item.label }}\r\n\r\n <div class=\"menu-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO:\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-item-icon\"\r\n />\r\n --></div>\r\n </ng-template>\r\n\r\n <ng-container *ngIf=\"item.routerLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [routerLink]=\"item.routerLink\"\r\n [queryParams]=\"item.queryParams\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"item.externalLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [href]=\"item.externalLink\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <!-- Child menus exist only if this menu is expanded. -->\r\n <!-- Only one invisible level is always attached to DOM, the rest does not exist. -->\r\n <rdt-menu-overlay\r\n *ngIf=\"item.items && expanded\"\r\n [item]=\"$any(item)\"\r\n [expanded]=\"item === expandedChild?.item\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"horizontalDir?.dir!\"\r\n [preferredVerticalDir]=\"verticalDir?.dir!\"\r\n [level]=\"level + 1\"\r\n [anchorElement]=\"anchorEl\"\r\n />\r\n </li>\r\n</ul>\r\n", styles: [":host{visibility:hidden;position:fixed;min-width:var(--rdt-menu-min-width);box-shadow:var(--rdt-menu-box-shadow);border-radius:var(--rdt-menu-border-radius);overflow-x:hidden;overflow-y:auto;max-height:calc(100vh - var(--rdt-menu-margin-top, 0px) - var(--rdt-menu-margin-bottom, 0px))}:host.expanded{visibility:visible}.menu-item-container{list-style-type:none;padding:var(--rdt-menu-padding-horizontal-padding) 0;border-radius:var(--rdt-menu-border-radius);background-color:var(--rdt-menu-item-background);overflow-y:auto}.menu-item{cursor:pointer;position:relative;box-sizing:border-box}.menu-item.menu-item-route-active>.menu-item-content{background-color:var(--rdt-menu-item-background-route-active)}.menu-item-content{display:flex;align-items:center;padding:var(--rdt-menu-item-padding);width:100%;background-color:var(--rdt-menu-item-background);color:var(--rdt-menu-item-text-color)}.menu-item-content:hover{background-color:var(--rdt-menu-item-background-hover)}.menu-item-content.focus-visible:focus,.menu-item-content:focus-visible{background-color:var(--rdt-menu-item-background-focus);outline:none}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3.RdtAnyRouteActiveDirective, selector: "[rdtAnyRouteActive]", inputs: ["anyRouteActive", "watchedRoutes", "anyRouteActiveOptions", "ariaCurrentWhenActive"] }, { kind: "directive", type: i4.RdtKeyListenerDirective, selector: "[rdtKeyListener]", outputs: ["rdtKeyListener"] }, { kind: "component", type: RdtMenuOverlayComponent, selector: "rdt-menu-overlay", inputs: ["item", "level", "preferredHorizontalDir", "preferredVerticalDir", "expanded", "autofocusItem", "anchorElement"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
636
721
  }
637
722
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RdtMenuOverlayComponent, decorators: [{
638
723
  type: Component,
639
- args: [{ selector: 'rdt-menu-overlay', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ul class=\"menu-item-container\" role=\"presentation\" #menuItemContainer>\r\n <li\r\n *ngFor=\"let item of item.items; let i = index\"\r\n role=\"presentation\"\r\n class=\"menu-item\"\r\n (rdtKeyListener)=\"onKeyDown(i, $event)\"\r\n rdtAnyRouteActive=\"menu-item-route-active\"\r\n [watchedRoutes]=\"getChildRoutes(item)\"\r\n (pointerleave)=\"onItemPointerLeave(item)\"\r\n #anchorEl\r\n >\r\n <ng-container *ngIf=\"!item.routerLink && !item.externalLink\">\r\n <button\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n (pointerenter)=\"onItemPointerEnter(item)\"\r\n [attr.aria-haspopup]=\"item.items ? 'menu' : null\"\r\n [attr.aria-expanded]=\"item === expandedChild\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n {{ item.label }}\r\n\r\n <div class=\"menu-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO:\r\n <rdt-icon\r\n *ngIf=\"item.items\"\r\n name=\"chevron_right\"\r\n class=\"menu-item-icon\"\r\n />\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-item-icon\"\r\n />\r\n -->\r\n <span class=\"menu-item-icon\" *ngIf=\"item.items\">&gt;</span>\r\n </div>\r\n </button>\r\n </ng-container>\r\n\r\n <ng-template #linkBody let-item>\r\n {{ item.label }}\r\n\r\n <div class=\"menu-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO:\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-item-icon\"\r\n />\r\n --></div>\r\n </ng-template>\r\n\r\n <ng-container *ngIf=\"item.routerLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [routerLink]=\"item.routerLink\"\r\n [queryParams]=\"item.queryParams\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"item.externalLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [href]=\"item.externalLink\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <!-- Child menus exist only if this menu is expanded. -->\r\n <!-- Only one invisible level is always attached to DOM, the rest does not exist. -->\r\n <rdt-menu-overlay\r\n *ngIf=\"item.items && expanded\"\r\n [item]=\"$any(item)\"\r\n [expanded]=\"item === expandedChild\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"horizontalDir?.dir!\"\r\n [preferredVerticalDir]=\"verticalDir?.dir!\"\r\n [level]=\"level + 1\"\r\n [anchorElement]=\"anchorEl\"\r\n />\r\n </li>\r\n</ul>\r\n", styles: [":host{visibility:hidden;position:fixed;min-width:var(--rdt-menu-min-width);box-shadow:var(--rdt-menu-box-shadow);border-radius:var(--rdt-menu-border-radius);max-height:calc(100vh - var(--rdt-menu-margin-top, 0px) - var(--rdt-menu-margin-bottom, 0px));overflow-y:auto}:host.expanded{visibility:visible}.menu-item-container{list-style-type:none;padding:var(--rdt-menu-padding-horizontal-padding) 0;border-radius:var(--rdt-menu-border-radius);background-color:var(--rdt-menu-item-background)}.menu-item{cursor:pointer;position:relative;box-sizing:border-box}.menu-item.menu-item-route-active>.menu-item-content{background-color:var(--rdt-menu-item-background-route-active)}.menu-item-content{display:flex;align-items:center;padding:var(--rdt-menu-item-padding);width:100%;background-color:var(--rdt-menu-item-background);color:var(--rdt-menu-item-text-color)}.menu-item-content:hover{background-color:var(--rdt-menu-item-background-hover)}.menu-item-content.focus-visible:focus,.menu-item-content:focus-visible{background-color:var(--rdt-menu-item-background-focus);outline:none}\n"] }]
724
+ args: [{ selector: 'rdt-menu-overlay', changeDetection: ChangeDetectionStrategy.OnPush, template: "<ul class=\"menu-item-container\" role=\"presentation\" #menuItemContainer>\r\n <li\r\n *ngFor=\"let item of item.items; let i = index\"\r\n role=\"presentation\"\r\n class=\"menu-item\"\r\n (rdtKeyListener)=\"onKeyDown(i, $event)\"\r\n (pointerenter)=\"onItemPointerEnter(item)\"\r\n rdtAnyRouteActive=\"menu-item-route-active\"\r\n [watchedRoutes]=\"getChildRoutes(item)\"\r\n #anchorEl\r\n >\r\n <ng-container *ngIf=\"!item.routerLink && !item.externalLink\">\r\n <button\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [attr.aria-haspopup]=\"item.items ? 'menu' : null\"\r\n [attr.aria-expanded]=\"item === expandedChild?.item\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n {{ item.label }}\r\n\r\n <div class=\"menu-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO:\r\n <rdt-icon\r\n *ngIf=\"item.items\"\r\n name=\"chevron_right\"\r\n class=\"menu-item-icon\"\r\n />\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-item-icon\"\r\n />\r\n -->\r\n <span class=\"menu-item-icon\" *ngIf=\"item.items\">&gt;</span>\r\n </div>\r\n </button>\r\n </ng-container>\r\n\r\n <ng-template #linkBody let-item>\r\n {{ item.label }}\r\n\r\n <div class=\"menu-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO:\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-item-icon\"\r\n />\r\n --></div>\r\n </ng-template>\r\n\r\n <ng-container *ngIf=\"item.routerLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [routerLink]=\"item.routerLink\"\r\n [queryParams]=\"item.queryParams\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"item.externalLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [href]=\"item.externalLink\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <!-- Child menus exist only if this menu is expanded. -->\r\n <!-- Only one invisible level is always attached to DOM, the rest does not exist. -->\r\n <rdt-menu-overlay\r\n *ngIf=\"item.items && expanded\"\r\n [item]=\"$any(item)\"\r\n [expanded]=\"item === expandedChild?.item\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"horizontalDir?.dir!\"\r\n [preferredVerticalDir]=\"verticalDir?.dir!\"\r\n [level]=\"level + 1\"\r\n [anchorElement]=\"anchorEl\"\r\n />\r\n </li>\r\n</ul>\r\n", styles: [":host{visibility:hidden;position:fixed;min-width:var(--rdt-menu-min-width);box-shadow:var(--rdt-menu-box-shadow);border-radius:var(--rdt-menu-border-radius);overflow-x:hidden;overflow-y:auto;max-height:calc(100vh - var(--rdt-menu-margin-top, 0px) - var(--rdt-menu-margin-bottom, 0px))}:host.expanded{visibility:visible}.menu-item-container{list-style-type:none;padding:var(--rdt-menu-padding-horizontal-padding) 0;border-radius:var(--rdt-menu-border-radius);background-color:var(--rdt-menu-item-background);overflow-y:auto}.menu-item{cursor:pointer;position:relative;box-sizing:border-box}.menu-item.menu-item-route-active>.menu-item-content{background-color:var(--rdt-menu-item-background-route-active)}.menu-item-content{display:flex;align-items:center;padding:var(--rdt-menu-item-padding);width:100%;background-color:var(--rdt-menu-item-background);color:var(--rdt-menu-item-text-color)}.menu-item-content:hover{background-color:var(--rdt-menu-item-background-hover)}.menu-item-content.focus-visible:focus,.menu-item-content:focus-visible{background-color:var(--rdt-menu-item-background-focus);outline:none}\n"] }]
640
725
  }], propDecorators: { children: [{
641
726
  type: ViewChildren,
642
727
  args: [RdtMenuOverlayComponent]
@@ -687,6 +772,7 @@ class RdtMenuBaseComponent {
687
772
  shortcutMode = RdtMenuShortcutMode.OPEN_SUBMENU;
688
773
  closeOnFocusOut = true;
689
774
  openOnHover = false;
775
+ hitboxMargin = 10;
690
776
  cd = inject(ChangeDetectorRef);
691
777
  destroyRef = inject(DestroyRef);
692
778
  rdtRouter = inject(RdtRouterService);
@@ -698,8 +784,9 @@ class RdtMenuBaseComponent {
698
784
  injector = inject(EnvironmentInjector);
699
785
  children;
700
786
  focusableElements;
787
+ buttonContainer;
701
788
  classes = 'rdt-menu-base';
702
- expanded = null;
789
+ expandedChild = null;
703
790
  autofocusSubmenuItem = null;
704
791
  parsedItems;
705
792
  get clientSize() {
@@ -710,6 +797,10 @@ class RdtMenuBaseComponent {
710
797
  return this._bodyMargin;
711
798
  }
712
799
  _bodyMargin;
800
+ get buttonContainerRect() {
801
+ return this._buttonContainerRect;
802
+ }
803
+ _buttonContainerRect;
713
804
  allParsedItems;
714
805
  childRoutesMap = new Map();
715
806
  shortcutSub = new Subscription();
@@ -717,8 +808,8 @@ class RdtMenuBaseComponent {
717
808
  keyActions = {
718
809
  [KB_CODE.ARROW.LEFT]: (index) => this.focusPrevItem(index),
719
810
  [KB_CODE.ARROW.RIGHT]: (index) => this.focusNextItem(index),
720
- [KB_CODE.ARROW.DOWN]: (index) => this.openSubmenu(index, 'first'),
721
- [KB_CODE.ARROW.UP]: (index) => this.openSubmenu(index, 'last'),
811
+ [KB_CODE.ARROW.DOWN]: (index) => this.openSubmenu(index, 'first', RdtMenuExpandSource.Shortcut),
812
+ [KB_CODE.ARROW.UP]: (index) => this.openSubmenu(index, 'last', RdtMenuExpandSource.Shortcut),
722
813
  [KB_CODE.HOME]: () => this.focusItem(0),
723
814
  [KB_CODE.END]: () => this.focusItem(this.parsedItems.length - 1),
724
815
  [KB_CODE.ENTER]: (index) => this.invokeItemClickByIndex(index),
@@ -753,19 +844,21 @@ class RdtMenuBaseComponent {
753
844
  });
754
845
  }
755
846
  closeSubmenus(focusExpanded = false) {
756
- if (focusExpanded && this.expanded) {
757
- this.focusItem(this.expanded);
847
+ if (focusExpanded && this.expandedChild) {
848
+ this.focusItem(this.expandedChild.item);
758
849
  }
759
- this.expanded = null;
850
+ this.expandedChild = null;
760
851
  this.cd.markForCheck();
761
852
  }
762
853
  onItemClick(item) {
763
- if (menuItemHasChildren(item) && this.expanded !== item) {
854
+ if ((menuItemHasChildren(item) && this.expandedChild?.item !== item) ||
855
+ (this.openOnHover &&
856
+ this.expandedChild?.src === RdtMenuExpandSource.Hover)) {
764
857
  this.autofocusSubmenuItem = null;
765
- this.expanded = item;
858
+ this.expandedChild = { item, src: RdtMenuExpandSource.Click };
766
859
  }
767
860
  else {
768
- this.expanded = null;
861
+ this.expandedChild = null;
769
862
  }
770
863
  if (typeof item.command === 'function') {
771
864
  item.command();
@@ -773,15 +866,13 @@ class RdtMenuBaseComponent {
773
866
  }
774
867
  onItemPointerEnter(item) {
775
868
  if (this.openOnHover &&
776
- this.expanded !== item &&
777
- menuItemHasChildren(item)) {
869
+ menuItemHasChildren(item) &&
870
+ this.expandedChild?.src !== RdtMenuExpandSource.Click) {
778
871
  this.autofocusSubmenuItem = null;
779
- this.expanded = item;
872
+ this.expandedChild = { item, src: RdtMenuExpandSource.Hover };
780
873
  }
781
- }
782
- onItemPointerLeave(item) {
783
- if (this.openOnHover && this.expanded === item) {
784
- this.expanded = null;
874
+ else {
875
+ this.expandedChild = null;
785
876
  }
786
877
  }
787
878
  onKeyDown(itemIndex, event) {
@@ -870,12 +961,12 @@ class RdtMenuBaseComponent {
870
961
  }
871
962
  this.invokeItemClick(item);
872
963
  }
873
- openSubmenu(itemIndex, visibleFocus) {
964
+ openSubmenu(itemIndex, visibleFocus, src) {
874
965
  if (itemIndex < this.parsedItems.length &&
875
966
  menuItemHasChildren(this.parsedItems[itemIndex])) {
876
967
  const item = this.parsedItems[itemIndex];
877
968
  this.autofocusSubmenuItem = visibleFocus;
878
- this.expanded = item;
969
+ this.expandedChild = { item, src };
879
970
  }
880
971
  }
881
972
  focusItem(item) {
@@ -909,13 +1000,26 @@ class RdtMenuBaseComponent {
909
1000
  elRef.nativeElement.focus();
910
1001
  }
911
1002
  }
1003
+ onPointerMove(event) {
1004
+ if (this.openOnHover && this.expandedChild) {
1005
+ const hitboxes = this.getHitboxes();
1006
+ const isInside = hitboxes.some((hitbox) => this.isPointerInsideHitbox(hitbox.rect, event));
1007
+ for (let i = hitboxes.length - 1; i >= 0; i--) {
1008
+ const hitbox = hitboxes[i];
1009
+ if (!hitbox.fixed && !isInside) {
1010
+ hitbox.close();
1011
+ break;
1012
+ }
1013
+ }
1014
+ }
1015
+ }
912
1016
  // Closes menu if user navigates outside it using Tab.
913
1017
  checkActiveElement(event) {
914
- if (this.closeOnFocusOut) {
1018
+ if (this.closeOnFocusOut && !this.openOnHover) {
915
1019
  const thisEl = this.elRef.nativeElement;
916
1020
  const target = event.relatedTarget;
917
1021
  if (!(target instanceof HTMLElement) || !thisEl.contains(target)) {
918
- this.expanded = null;
1022
+ this.expandedChild = null;
919
1023
  }
920
1024
  }
921
1025
  }
@@ -927,6 +1031,7 @@ class RdtMenuBaseComponent {
927
1031
  }
928
1032
  }
929
1033
  measure() {
1034
+ this.measureButtonContainer();
930
1035
  this.measureClientSize();
931
1036
  this.readMargin();
932
1037
  }
@@ -949,6 +1054,15 @@ class RdtMenuBaseComponent {
949
1054
  height: this.document.body.clientHeight,
950
1055
  };
951
1056
  }
1057
+ measureButtonContainer() {
1058
+ const el = this.buttonContainer?.nativeElement;
1059
+ if (el) {
1060
+ this._buttonContainerRect = el.getBoundingClientRect();
1061
+ }
1062
+ else {
1063
+ this._buttonContainerRect = undefined;
1064
+ }
1065
+ }
952
1066
  listenWindowResize() {
953
1067
  fromEvent(window, 'resize')
954
1068
  .pipe(throttleTime(0, animationFrameScheduler, { trailing: true }), takeUntilDestroyed(this.destroyRef))
@@ -992,10 +1106,10 @@ class RdtMenuBaseComponent {
992
1106
  }
993
1107
  }
994
1108
  else {
995
- this.activateItemRecursively(path);
1109
+ this.activateItemRecursively(path, RdtMenuExpandSource.Shortcut);
996
1110
  }
997
1111
  }
998
- activateItemRecursively(path) {
1112
+ activateItemRecursively(path, src) {
999
1113
  const children = [...path];
1000
1114
  if (this.shortcutMode === RdtMenuShortcutMode.OPEN_SUBMENU) {
1001
1115
  const last = children[children.length - 1];
@@ -1005,17 +1119,55 @@ class RdtMenuBaseComponent {
1005
1119
  }
1006
1120
  const thisItem = children.shift();
1007
1121
  if (children.length > 0) {
1008
- this.expanded = thisItem;
1122
+ this.expandedChild = { item: thisItem, src };
1009
1123
  const overlay = this.children.find((child) => child.item === thisItem);
1010
1124
  overlay.focusItemRecursively(children);
1011
1125
  }
1012
1126
  else {
1013
- this.expanded = null;
1127
+ this.expandedChild = null;
1014
1128
  this.focusItem(thisItem);
1015
1129
  }
1016
1130
  }
1131
+ isPointerInsideHitbox(hitbox, event) {
1132
+ const rect = hitbox;
1133
+ const x = event.clientX;
1134
+ const y = event.clientY;
1135
+ return (x >= rect.left - this.hitboxMargin &&
1136
+ x <= rect.right + this.hitboxMargin &&
1137
+ y >= rect.top - this.hitboxMargin &&
1138
+ y <= rect.bottom + this.hitboxMargin);
1139
+ }
1140
+ getHitboxes() {
1141
+ const boxes = this.getOpenMenuBoundingBoxes();
1142
+ const buttonContainerRect = this.buttonContainerRect;
1143
+ if (buttonContainerRect) {
1144
+ boxes.push({ rect: buttonContainerRect, fixed: true, close: () => { } });
1145
+ }
1146
+ return boxes;
1147
+ }
1148
+ getOpenMenuBoundingBoxes() {
1149
+ const boxes = [];
1150
+ this.children.forEach((overlay) => {
1151
+ this.getOpenMenuBoundingBoxesRec(overlay, boxes);
1152
+ });
1153
+ return boxes;
1154
+ }
1155
+ getOpenMenuBoundingBoxesRec(overlay, boxes) {
1156
+ if (overlay.expanded) {
1157
+ let someByClick = false;
1158
+ overlay.children.forEach((child) => (someByClick ||= this.getOpenMenuBoundingBoxesRec(child, boxes)));
1159
+ const fixed = someByClick || overlay.selfExpandSrc === RdtMenuExpandSource.Click;
1160
+ boxes.push({
1161
+ rect: overlay.box,
1162
+ fixed: fixed,
1163
+ close: () => overlay.closeSelf(),
1164
+ });
1165
+ return fixed;
1166
+ }
1167
+ return false;
1168
+ }
1017
1169
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RdtMenuBaseComponent, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1018
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "18.2.7", type: RdtMenuBaseComponent, inputs: { preferredVerticalDir: "preferredVerticalDir", preferredHorizontalDir: "preferredHorizontalDir", shortcutMode: "shortcutMode", closeOnFocusOut: ["closeOnFocusOut", "closeOnFocusOut", booleanAttribute], openOnHover: ["openOnHover", "openOnHover", booleanAttribute] }, host: { listeners: { "window:focusout": "checkActiveElement($event)", "document:click": "onDocumentClick($event)" }, properties: { "class": "this.classes" } }, viewQueries: [{ propertyName: "children", predicate: RdtMenuOverlayComponent, descendants: true }, { propertyName: "focusableElements", predicate: ["focusableItem"], descendants: true }], usesOnChanges: true, ngImport: i0 });
1170
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "18.2.7", type: RdtMenuBaseComponent, inputs: { preferredVerticalDir: "preferredVerticalDir", preferredHorizontalDir: "preferredHorizontalDir", shortcutMode: "shortcutMode", closeOnFocusOut: ["closeOnFocusOut", "closeOnFocusOut", booleanAttribute], openOnHover: ["openOnHover", "openOnHover", booleanAttribute], hitboxMargin: ["hitboxMargin", "hitboxMargin", numberAttribute] }, host: { listeners: { "window:pointermove": "onPointerMove($event)", "window:focusout": "checkActiveElement($event)", "document:click": "onDocumentClick($event)" }, properties: { "class": "this.classes" } }, viewQueries: [{ propertyName: "buttonContainer", first: true, predicate: ["buttonContainer"], descendants: true, static: true }, { propertyName: "children", predicate: RdtMenuOverlayComponent, descendants: true }, { propertyName: "focusableElements", predicate: ["focusableItem"], descendants: true }], usesOnChanges: true, ngImport: i0 });
1019
1171
  }
1020
1172
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RdtMenuBaseComponent, decorators: [{
1021
1173
  type: Directive
@@ -1031,15 +1183,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImpor
1031
1183
  }], openOnHover: [{
1032
1184
  type: Input,
1033
1185
  args: [{ transform: booleanAttribute }]
1186
+ }], hitboxMargin: [{
1187
+ type: Input,
1188
+ args: [{ transform: numberAttribute }]
1034
1189
  }], children: [{
1035
1190
  type: ViewChildren,
1036
1191
  args: [RdtMenuOverlayComponent]
1037
1192
  }], focusableElements: [{
1038
1193
  type: ViewChildren,
1039
1194
  args: ['focusableItem']
1195
+ }], buttonContainer: [{
1196
+ type: ViewChild,
1197
+ args: ['buttonContainer', { static: true }]
1040
1198
  }], classes: [{
1041
1199
  type: HostBinding,
1042
1200
  args: ['class']
1201
+ }], onPointerMove: [{
1202
+ type: HostListener,
1203
+ args: ['window:pointermove', ['$event']]
1043
1204
  }], checkActiveElement: [{
1044
1205
  type: HostListener,
1045
1206
  args: ['window:focusout', ['$event']]
@@ -1048,71 +1209,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImpor
1048
1209
  args: ['document:click', ['$event']]
1049
1210
  }] } });
1050
1211
 
1051
- function parseMenuItems(items, injector, prefix = '') {
1052
- return items
1053
- .map((item) => {
1054
- let newPrefix;
1055
- if (item.dataTestId) {
1056
- newPrefix = item.dataTestId;
1057
- }
1058
- else if (prefix) {
1059
- newPrefix = RdtStringUtils.getDataTestId(item.label, prefix);
1060
- }
1061
- else {
1062
- newPrefix = RdtStringUtils.getDataTestId(item.label);
1063
- }
1064
- const newDataTestId = RdtStringUtils.getDataTestId(newPrefix, null, 'menu-item');
1065
- const res = {
1066
- label: item.label,
1067
- icon: item.icon,
1068
- shortcut: item.shortcut,
1069
- command: item.command,
1070
- visible: item.visible,
1071
- queryParams: item.queryParams,
1072
- requiredParent: item.requiredParent,
1073
- dataTestId: newDataTestId,
1074
- };
1075
- if (item.items) {
1076
- const childrenRes = res;
1077
- const parsedChildren = parseMenuItems(item.items, injector, newPrefix);
1078
- if (parsedChildren.length > 0) {
1079
- childrenRes.items = parsedChildren;
1080
- }
1081
- return childrenRes;
1082
- }
1083
- else if (item.routerLink) {
1084
- const linkRes = res;
1085
- linkRes.target = item.target ?? '_self';
1086
- if (item.routerLink) {
1087
- linkRes.routerLink = [item.routerLink.createAbsoluteUrl()];
1088
- if (!res.visible && item.routerLink.hasCanBeEnteredGuard) {
1089
- const canBeEntered = item.routerLink.canBeEntered.bind(item.routerLink);
1090
- linkRes.visible = () => canBeEntered(injector);
1091
- }
1092
- }
1093
- return linkRes;
1094
- }
1095
- else {
1096
- const linkRes = res;
1097
- if (item.externalLink) {
1098
- if (item.queryParams) {
1099
- linkRes.externalLink = RdtStringUtils.appendQueryParams(item.externalLink, item.queryParams);
1100
- }
1101
- else {
1102
- linkRes.externalLink = item.externalLink;
1103
- }
1104
- }
1105
- linkRes.target = item.target ?? '_blank';
1106
- return linkRes;
1107
- }
1108
- })
1109
- .filter((item) => !item.visible || item.visible())
1110
- .filter((item) => item.externalLink ||
1111
- item['routerLink'] ||
1112
- item.command ||
1113
- (item['items']?.length ?? 0) > 0);
1114
- }
1115
-
1116
1212
  class RdtMenuComponent extends RdtMenuBaseComponent {
1117
1213
  buttonClass = inject(RDT_BUTTON_BASE_PROVIDER);
1118
1214
  dataTestId = '';
@@ -1125,9 +1221,6 @@ class RdtMenuComponent extends RdtMenuBaseComponent {
1125
1221
  this.filterItems();
1126
1222
  }
1127
1223
  _item;
1128
- onPointerLeave() {
1129
- this.onItemPointerLeave(this.parsedItem);
1130
- }
1131
1224
  get parsedItem() {
1132
1225
  return this.parsedItems[0];
1133
1226
  }
@@ -1140,7 +1233,7 @@ class RdtMenuComponent extends RdtMenuBaseComponent {
1140
1233
  aria: {
1141
1234
  role: 'menuitem',
1142
1235
  'aria-haspopup': 'menu',
1143
- 'aria-expanded': this.expanded === this.parsedItem,
1236
+ 'aria-expanded': this.expandedChild?.item === this.parsedItem,
1144
1237
  },
1145
1238
  };
1146
1239
  }
@@ -1148,12 +1241,12 @@ class RdtMenuComponent extends RdtMenuBaseComponent {
1148
1241
  this.onItemClick(this.parsedItem);
1149
1242
  }
1150
1243
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RdtMenuComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1151
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.7", type: RdtMenuComponent, selector: "rdt-menu", inputs: { dataTestId: "dataTestId", item: "item" }, host: { listeners: { "pointerleave": "onPointerLeave()" } }, providers: [
1244
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "18.2.7", type: RdtMenuComponent, selector: "rdt-menu", inputs: { dataTestId: "dataTestId", item: "item" }, providers: [
1152
1245
  {
1153
1246
  provide: RdtMenuBaseComponent,
1154
1247
  useExisting: RdtMenuComponent,
1155
1248
  },
1156
- ], usesInheritance: true, ngImport: i0, template: "<div\r\n class=\"menu-button-container\"\r\n (pointerenter)=\"onItemPointerEnter(parsedItem)\"\r\n>\r\n <ng-template\r\n rdtButtonOutlet\r\n [inputs]=\"buttonInputs\"\r\n (click$)=\"toggle()\"\r\n #outlet=\"rdtButtonOutlet\"\r\n />\r\n</div>\r\n\r\n<rdt-menu-overlay\r\n *ngIf=\"parsedItem\"\r\n [anchorElement]=\"outlet.instance?.anchorElement\"\r\n [item]=\"$any(parsedItem)\"\r\n [expanded]=\"expanded === parsedItem\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"preferredHorizontalDir\"\r\n [preferredVerticalDir]=\"preferredVerticalDir\"\r\n [level]=\"0\"\r\n/>\r\n", styles: ["rdt-menu{display:block;position:relative}rdt-menu .menu-button-container{display:inline-block}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.RdtButtonOutletDirective, selector: "[rdtButtonOutlet]", inputs: ["inputs"], outputs: ["click$"], exportAs: ["rdtButtonOutlet"] }, { kind: "component", type: RdtMenuOverlayComponent, selector: "rdt-menu-overlay", inputs: ["item", "level", "preferredHorizontalDir", "preferredVerticalDir", "expanded", "autofocusItem", "anchorElement"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1249
+ ], usesInheritance: true, ngImport: i0, template: "<div\r\n class=\"menu-button-container\"\r\n (pointerenter)=\"onItemPointerEnter(parsedItem)\"\r\n #buttonContainer\r\n>\r\n <ng-template\r\n rdtButtonOutlet\r\n [inputs]=\"buttonInputs\"\r\n (click$)=\"toggle()\"\r\n #outlet=\"rdtButtonOutlet\"\r\n #focusableItem\r\n />\r\n</div>\r\n\r\n<rdt-menu-overlay\r\n *ngIf=\"parsedItem\"\r\n [anchorElement]=\"outlet.instance?.anchorElement\"\r\n [item]=\"$any(parsedItem)\"\r\n [expanded]=\"expandedChild?.item === parsedItem\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"preferredHorizontalDir\"\r\n [preferredVerticalDir]=\"preferredVerticalDir\"\r\n [level]=\"0\"\r\n/>\r\n", styles: ["a.menu-bar-item-content,a.menu-item-content,button.menu-bar-item-content,button.menu-item-content{white-space:nowrap;appearance:none;border:none;text-decoration:none}.menu-item-right-content,.menu-bar-item-right-content{margin-left:auto;display:flex;align-items:center}.menu-item-shortcut,.menu-bar-item-shortcut{margin-left:2rem}.menu-item-icon,.menu-bar-item-icon{margin-left:.5rem;font-size:1.2rem}.dp3-menu-base ul{margin-bottom:0}.rdt-menu-root{margin-left:0}.rdt-menu-root.rdt-overlay-down{margin-top:var(--rdt-menu-overlay-margin-y)}.rdt-menu-root.rdt-overlay-up{margin-top:calc(-1 * var(--rdt-menu-overlay-margin-y))}.rdt-menu-sub.rdt-overlay-left{margin-left:calc(-1 * var(--rdt-menu-overlay-margin-x))}.rdt-menu-sub.rdt-overlay-right{margin-left:var(--rdt-menu-overlay-margin-x)}rdt-menu{display:block;position:relative}rdt-menu .menu-button-container{display:inline-block}\n"], dependencies: [{ kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2$1.RdtButtonOutletDirective, selector: "[rdtButtonOutlet]", inputs: ["inputs"], outputs: ["click$"], exportAs: ["rdtButtonOutlet"] }, { kind: "component", type: RdtMenuOverlayComponent, selector: "rdt-menu-overlay", inputs: ["item", "level", "preferredHorizontalDir", "preferredVerticalDir", "expanded", "autofocusItem", "anchorElement"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1157
1250
  }
1158
1251
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RdtMenuComponent, decorators: [{
1159
1252
  type: Component,
@@ -1162,15 +1255,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImpor
1162
1255
  provide: RdtMenuBaseComponent,
1163
1256
  useExisting: RdtMenuComponent,
1164
1257
  },
1165
- ], template: "<div\r\n class=\"menu-button-container\"\r\n (pointerenter)=\"onItemPointerEnter(parsedItem)\"\r\n>\r\n <ng-template\r\n rdtButtonOutlet\r\n [inputs]=\"buttonInputs\"\r\n (click$)=\"toggle()\"\r\n #outlet=\"rdtButtonOutlet\"\r\n />\r\n</div>\r\n\r\n<rdt-menu-overlay\r\n *ngIf=\"parsedItem\"\r\n [anchorElement]=\"outlet.instance?.anchorElement\"\r\n [item]=\"$any(parsedItem)\"\r\n [expanded]=\"expanded === parsedItem\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"preferredHorizontalDir\"\r\n [preferredVerticalDir]=\"preferredVerticalDir\"\r\n [level]=\"0\"\r\n/>\r\n", styles: ["rdt-menu{display:block;position:relative}rdt-menu .menu-button-container{display:inline-block}\n"] }]
1258
+ ], template: "<div\r\n class=\"menu-button-container\"\r\n (pointerenter)=\"onItemPointerEnter(parsedItem)\"\r\n #buttonContainer\r\n>\r\n <ng-template\r\n rdtButtonOutlet\r\n [inputs]=\"buttonInputs\"\r\n (click$)=\"toggle()\"\r\n #outlet=\"rdtButtonOutlet\"\r\n #focusableItem\r\n />\r\n</div>\r\n\r\n<rdt-menu-overlay\r\n *ngIf=\"parsedItem\"\r\n [anchorElement]=\"outlet.instance?.anchorElement\"\r\n [item]=\"$any(parsedItem)\"\r\n [expanded]=\"expandedChild?.item === parsedItem\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"preferredHorizontalDir\"\r\n [preferredVerticalDir]=\"preferredVerticalDir\"\r\n [level]=\"0\"\r\n/>\r\n", styles: ["a.menu-bar-item-content,a.menu-item-content,button.menu-bar-item-content,button.menu-item-content{white-space:nowrap;appearance:none;border:none;text-decoration:none}.menu-item-right-content,.menu-bar-item-right-content{margin-left:auto;display:flex;align-items:center}.menu-item-shortcut,.menu-bar-item-shortcut{margin-left:2rem}.menu-item-icon,.menu-bar-item-icon{margin-left:.5rem;font-size:1.2rem}.dp3-menu-base ul{margin-bottom:0}.rdt-menu-root{margin-left:0}.rdt-menu-root.rdt-overlay-down{margin-top:var(--rdt-menu-overlay-margin-y)}.rdt-menu-root.rdt-overlay-up{margin-top:calc(-1 * var(--rdt-menu-overlay-margin-y))}.rdt-menu-sub.rdt-overlay-left{margin-left:calc(-1 * var(--rdt-menu-overlay-margin-x))}.rdt-menu-sub.rdt-overlay-right{margin-left:var(--rdt-menu-overlay-margin-x)}rdt-menu{display:block;position:relative}rdt-menu .menu-button-container{display:inline-block}\n"] }]
1166
1259
  }], propDecorators: { dataTestId: [{
1167
1260
  type: Input
1168
1261
  }], item: [{
1169
1262
  type: Input,
1170
1263
  args: [{ required: true }]
1171
- }], onPointerLeave: [{
1172
- type: HostListener,
1173
- args: ['pointerleave']
1174
1264
  }] } });
1175
1265
 
1176
1266
  class RdtMenuBarComponent extends RdtMenuBaseComponent {
@@ -1187,12 +1277,12 @@ class RdtMenuBarComponent extends RdtMenuBaseComponent {
1187
1277
  footerHeight = 0;
1188
1278
  roleAttr = 'menubar';
1189
1279
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RdtMenuBarComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1190
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "18.2.7", type: RdtMenuBarComponent, selector: "rdt-menu-bar", inputs: { items: "items", headerHeight: ["headerHeight", "headerHeight", numberAttribute], footerHeight: ["footerHeight", "footerHeight", numberAttribute] }, host: { properties: { "attr.role": "this.roleAttr" } }, providers: [
1280
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.7", type: RdtMenuBarComponent, selector: "rdt-menu-bar", inputs: { items: "items", headerHeight: ["headerHeight", "headerHeight", numberAttribute], footerHeight: ["footerHeight", "footerHeight", numberAttribute] }, host: { properties: { "attr.role": "this.roleAttr" } }, providers: [
1191
1281
  {
1192
1282
  provide: RdtMenuBaseComponent,
1193
1283
  useExisting: RdtMenuBarComponent,
1194
1284
  },
1195
- ], usesInheritance: true, ngImport: i0, template: "<ul class=\"menu-bar-item-container\" role=\"presentation\">\r\n <li\r\n *ngFor=\"let item of parsedItems; let i = index\"\r\n class=\"menu-bar-item\"\r\n role=\"presentation\"\r\n rdtAnyRouteActive=\"menu-bar-item-route-active\"\r\n [watchedRoutes]=\"getChildRoutes(item)\"\r\n (rdtKeyListener)=\"onKeyDown(i, $event)\"\r\n #anchorEl\r\n >\r\n <ng-container *ngIf=\"!item.routerLink && !item.externalLink\">\r\n <button\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n (pointerenter)=\"onItemPointerEnter(item)\"\r\n (pointerleave)=\"onItemPointerLeave(item)\"\r\n [attr.aria-haspopup]=\"item.items ? 'menu' : null\"\r\n [attr.aria-expanded]=\"item === expanded\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n {{ item.label }}\r\n\r\n <div class=\"menu-bar-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO\r\n <rdt-icon\r\n *ngIf=\"item.items\"\r\n name=\"expand_more\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n -->\r\n <span class=\"menu-bar-item-icon\" *ngIf=\"item.items\">v</span>\r\n </div>\r\n </button>\r\n </ng-container>\r\n\r\n <ng-template #linkBody let-item>\r\n {{ item.label }}\r\n\r\n <div class=\"menu-bar-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!--\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n --></div>\r\n </ng-template>\r\n\r\n <ng-container *ngIf=\"item.routerLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [routerLink]=\"item.routerLink\"\r\n [target]=\"item.target!\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"item.externalLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [href]=\"item.externalLink\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <rdt-menu-overlay\r\n *ngIf=\"item.items\"\r\n [item]=\"$any(item)\"\r\n [expanded]=\"item === expanded\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"preferredHorizontalDir\"\r\n [preferredVerticalDir]=\"preferredVerticalDir\"\r\n [level]=\"0\"\r\n [anchorElement]=\"anchorEl\"\r\n />\r\n </li>\r\n</ul>\r\n", styles: ["a.menu-bar-item-content,a.menu-item-content,button.menu-bar-item-content,button.menu-item-content{white-space:nowrap;appearance:none;border:none;text-decoration:none}.menu-item-right-content,.menu-bar-item-right-content{margin-left:auto;display:flex;align-items:center}.menu-item-shortcut,.menu-bar-item-shortcut{margin-left:2rem}.menu-item-icon,.menu-bar-item-icon{margin-left:.5rem;font-size:1.2rem}.dp3-menu-base ul{margin-bottom:0}rdt-menu-bar{-webkit-user-select:none;user-select:none;pointer-events:none;padding:var(--sub-menu-padding)}.menu-bar-item-container{display:flex;list-style-type:none;margin-bottom:0;padding-left:0}.menu-bar-item{cursor:pointer;pointer-events:all;color:var(--white);margin:0 .5rem;position:relative;display:flex;align-items:center;justify-content:center}.menu-bar-item.menu-bar-item-route-active .menu-bar-item-content{background-color:var(--rdt-menu-bar-item-background-route-active)}.menu-bar-item[aria-expanded=true] .menu-bar-item-content{background-color:var(--rdt-menu-bar-item-background-expanded)}.menu-bar-item-content{display:flex;align-items:center;padding:var(--rdt-menu-bar-item-padding);color:inherit!important;border-radius:var(--rdt-menu-bar-item-border-radius);overflow:hidden;background-color:var(--rdt-menu-bar-item-background)}.menu-bar-item-content:hover{background-color:var(--rdt-menu-bar-item-background-hover)}.menu-bar-item-content.focus-visible:focus,.menu-bar-item-content:focus-visible{outline:none;background-color:var(--rdt-menu-bar-item-background-focus)}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3.RdtAnyRouteActiveDirective, selector: "[rdtAnyRouteActive]", inputs: ["anyRouteActive", "watchedRoutes", "anyRouteActiveOptions", "ariaCurrentWhenActive"] }, { kind: "directive", type: i4.RdtKeyListenerDirective, selector: "[rdtKeyListener]", outputs: ["rdtKeyListener"] }, { kind: "component", type: RdtMenuOverlayComponent, selector: "rdt-menu-overlay", inputs: ["item", "level", "preferredHorizontalDir", "preferredVerticalDir", "expanded", "autofocusItem", "anchorElement"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1285
+ ], usesInheritance: true, ngImport: i0, template: "<ul class=\"menu-bar-item-container\" role=\"presentation\" #buttonContainer>\r\n @for(item of parsedItems; track item; let i = $index) {\r\n <li\r\n class=\"menu-bar-item\"\r\n role=\"presentation\"\r\n rdtAnyRouteActive=\"menu-bar-item-route-active\"\r\n [watchedRoutes]=\"getChildRoutes(item)\"\r\n (rdtKeyListener)=\"onKeyDown(i, $event)\"\r\n #anchorEl\r\n >\r\n @if(!item.routerLink && !item.externalLink) {\r\n <button\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n (pointerenter)=\"onItemPointerEnter(item)\"\r\n [attr.aria-haspopup]=\"item.items ? 'menu' : null\"\r\n [attr.aria-expanded]=\"item === expandedChild?.item\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n {{ item.label }}\r\n\r\n <div class=\"menu-bar-item-right-content\">\r\n @if(item.shortcut) {\r\n <span class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n }\r\n <!-- TODO\r\n <rdt-icon\r\n *ngIf=\"item.items\"\r\n name=\"expand_more\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n -->\r\n @if(item.items) {\r\n <span class=\"menu-bar-item-icon\">v</span>\r\n }\r\n </div>\r\n </button>\r\n }\r\n\r\n <ng-template #linkBody let-item>\r\n {{ item.label }}\r\n\r\n <div class=\"menu-bar-item-right-content\">\r\n @if(item.shortcut) {\r\n <span class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n }\r\n <!--\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n --></div>\r\n </ng-template>\r\n\r\n @if(item.routerLink) {\r\n <a\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [routerLink]=\"item.routerLink\"\r\n [target]=\"item.target!\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n } @if(item.externalLink) {\r\n <a\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [href]=\"item.externalLink\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n } @if (item.items) {\r\n <rdt-menu-overlay\r\n [item]=\"$any(item)\"\r\n [expanded]=\"item === expandedChild?.item\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"preferredHorizontalDir\"\r\n [preferredVerticalDir]=\"preferredVerticalDir\"\r\n [level]=\"0\"\r\n [anchorElement]=\"anchorEl\"\r\n />\r\n }\r\n </li>\r\n }\r\n</ul>\r\n", styles: ["a.menu-bar-item-content,a.menu-item-content,button.menu-bar-item-content,button.menu-item-content{white-space:nowrap;appearance:none;border:none;text-decoration:none}.menu-item-right-content,.menu-bar-item-right-content{margin-left:auto;display:flex;align-items:center}.menu-item-shortcut,.menu-bar-item-shortcut{margin-left:2rem}.menu-item-icon,.menu-bar-item-icon{margin-left:.5rem;font-size:1.2rem}.dp3-menu-base ul{margin-bottom:0}.rdt-menu-root{margin-left:0}.rdt-menu-root.rdt-overlay-down{margin-top:var(--rdt-menu-overlay-margin-y)}.rdt-menu-root.rdt-overlay-up{margin-top:calc(-1 * var(--rdt-menu-overlay-margin-y))}.rdt-menu-sub.rdt-overlay-left{margin-left:calc(-1 * var(--rdt-menu-overlay-margin-x))}.rdt-menu-sub.rdt-overlay-right{margin-left:var(--rdt-menu-overlay-margin-x)}rdt-menu-bar{-webkit-user-select:none;user-select:none;pointer-events:none;padding:var(--sub-menu-padding)}.menu-bar-item-container{display:flex;list-style-type:none;margin-bottom:0;padding-left:0}.menu-bar-item{cursor:pointer;pointer-events:all;color:var(--white);margin:0 .5rem;position:relative;display:flex;align-items:center;justify-content:center}.menu-bar-item.menu-bar-item-route-active .menu-bar-item-content{background-color:var(--rdt-menu-bar-item-background-route-active)}.menu-bar-item[aria-expanded=true] .menu-bar-item-content{background-color:var(--rdt-menu-bar-item-background-expanded)}.menu-bar-item-content{display:flex;align-items:center;padding:var(--rdt-menu-bar-item-padding);color:inherit!important;border-radius:var(--rdt-menu-bar-item-border-radius);overflow:hidden;background-color:var(--rdt-menu-bar-item-background)}.menu-bar-item-content:hover{background-color:var(--rdt-menu-bar-item-background-hover)}.menu-bar-item-content.focus-visible:focus,.menu-bar-item-content:focus-visible{outline:none;background-color:var(--rdt-menu-bar-item-background-focus)}\n"], dependencies: [{ kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: i2.RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: i3.RdtAnyRouteActiveDirective, selector: "[rdtAnyRouteActive]", inputs: ["anyRouteActive", "watchedRoutes", "anyRouteActiveOptions", "ariaCurrentWhenActive"] }, { kind: "directive", type: i4.RdtKeyListenerDirective, selector: "[rdtKeyListener]", outputs: ["rdtKeyListener"] }, { kind: "component", type: RdtMenuOverlayComponent, selector: "rdt-menu-overlay", inputs: ["item", "level", "preferredHorizontalDir", "preferredVerticalDir", "expanded", "autofocusItem", "anchorElement"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1196
1286
  }
1197
1287
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImport: i0, type: RdtMenuBarComponent, decorators: [{
1198
1288
  type: Component,
@@ -1201,7 +1291,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.7", ngImpor
1201
1291
  provide: RdtMenuBaseComponent,
1202
1292
  useExisting: RdtMenuBarComponent,
1203
1293
  },
1204
- ], template: "<ul class=\"menu-bar-item-container\" role=\"presentation\">\r\n <li\r\n *ngFor=\"let item of parsedItems; let i = index\"\r\n class=\"menu-bar-item\"\r\n role=\"presentation\"\r\n rdtAnyRouteActive=\"menu-bar-item-route-active\"\r\n [watchedRoutes]=\"getChildRoutes(item)\"\r\n (rdtKeyListener)=\"onKeyDown(i, $event)\"\r\n #anchorEl\r\n >\r\n <ng-container *ngIf=\"!item.routerLink && !item.externalLink\">\r\n <button\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n (pointerenter)=\"onItemPointerEnter(item)\"\r\n (pointerleave)=\"onItemPointerLeave(item)\"\r\n [attr.aria-haspopup]=\"item.items ? 'menu' : null\"\r\n [attr.aria-expanded]=\"item === expanded\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n {{ item.label }}\r\n\r\n <div class=\"menu-bar-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!-- TODO\r\n <rdt-icon\r\n *ngIf=\"item.items\"\r\n name=\"expand_more\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n -->\r\n <span class=\"menu-bar-item-icon\" *ngIf=\"item.items\">v</span>\r\n </div>\r\n </button>\r\n </ng-container>\r\n\r\n <ng-template #linkBody let-item>\r\n {{ item.label }}\r\n\r\n <div class=\"menu-bar-item-right-content\">\r\n <span *ngIf=\"item.shortcut\" class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n <!--\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n --></div>\r\n </ng-template>\r\n\r\n <ng-container *ngIf=\"item.routerLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [routerLink]=\"item.routerLink\"\r\n [target]=\"item.target!\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <ng-container *ngIf=\"item.externalLink\">\r\n <a\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [href]=\"item.externalLink\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n </ng-container>\r\n\r\n <rdt-menu-overlay\r\n *ngIf=\"item.items\"\r\n [item]=\"$any(item)\"\r\n [expanded]=\"item === expanded\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"preferredHorizontalDir\"\r\n [preferredVerticalDir]=\"preferredVerticalDir\"\r\n [level]=\"0\"\r\n [anchorElement]=\"anchorEl\"\r\n />\r\n </li>\r\n</ul>\r\n", styles: ["a.menu-bar-item-content,a.menu-item-content,button.menu-bar-item-content,button.menu-item-content{white-space:nowrap;appearance:none;border:none;text-decoration:none}.menu-item-right-content,.menu-bar-item-right-content{margin-left:auto;display:flex;align-items:center}.menu-item-shortcut,.menu-bar-item-shortcut{margin-left:2rem}.menu-item-icon,.menu-bar-item-icon{margin-left:.5rem;font-size:1.2rem}.dp3-menu-base ul{margin-bottom:0}rdt-menu-bar{-webkit-user-select:none;user-select:none;pointer-events:none;padding:var(--sub-menu-padding)}.menu-bar-item-container{display:flex;list-style-type:none;margin-bottom:0;padding-left:0}.menu-bar-item{cursor:pointer;pointer-events:all;color:var(--white);margin:0 .5rem;position:relative;display:flex;align-items:center;justify-content:center}.menu-bar-item.menu-bar-item-route-active .menu-bar-item-content{background-color:var(--rdt-menu-bar-item-background-route-active)}.menu-bar-item[aria-expanded=true] .menu-bar-item-content{background-color:var(--rdt-menu-bar-item-background-expanded)}.menu-bar-item-content{display:flex;align-items:center;padding:var(--rdt-menu-bar-item-padding);color:inherit!important;border-radius:var(--rdt-menu-bar-item-border-radius);overflow:hidden;background-color:var(--rdt-menu-bar-item-background)}.menu-bar-item-content:hover{background-color:var(--rdt-menu-bar-item-background-hover)}.menu-bar-item-content.focus-visible:focus,.menu-bar-item-content:focus-visible{outline:none;background-color:var(--rdt-menu-bar-item-background-focus)}\n"] }]
1294
+ ], template: "<ul class=\"menu-bar-item-container\" role=\"presentation\" #buttonContainer>\r\n @for(item of parsedItems; track item; let i = $index) {\r\n <li\r\n class=\"menu-bar-item\"\r\n role=\"presentation\"\r\n rdtAnyRouteActive=\"menu-bar-item-route-active\"\r\n [watchedRoutes]=\"getChildRoutes(item)\"\r\n (rdtKeyListener)=\"onKeyDown(i, $event)\"\r\n #anchorEl\r\n >\r\n @if(!item.routerLink && !item.externalLink) {\r\n <button\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n (pointerenter)=\"onItemPointerEnter(item)\"\r\n [attr.aria-haspopup]=\"item.items ? 'menu' : null\"\r\n [attr.aria-expanded]=\"item === expandedChild?.item\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n {{ item.label }}\r\n\r\n <div class=\"menu-bar-item-right-content\">\r\n @if(item.shortcut) {\r\n <span class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n }\r\n <!-- TODO\r\n <rdt-icon\r\n *ngIf=\"item.items\"\r\n name=\"expand_more\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n -->\r\n @if(item.items) {\r\n <span class=\"menu-bar-item-icon\">v</span>\r\n }\r\n </div>\r\n </button>\r\n }\r\n\r\n <ng-template #linkBody let-item>\r\n {{ item.label }}\r\n\r\n <div class=\"menu-bar-item-right-content\">\r\n @if(item.shortcut) {\r\n <span class=\"menu-item-shortcut\">\r\n {{ item.shortcut.label }}\r\n </span>\r\n }\r\n <!--\r\n <rdt-icon\r\n *ngIf=\"item.icon\"\r\n [name]=\"item.icon\"\r\n class=\"menu-bar-item-icon\"\r\n inverted\r\n />\r\n --></div>\r\n </ng-template>\r\n\r\n @if(item.routerLink) {\r\n <a\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [routerLink]=\"item.routerLink\"\r\n [target]=\"item.target!\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n } @if(item.externalLink) {\r\n <a\r\n #focusableItem\r\n class=\"menu-bar-item-content\"\r\n role=\"menuitem\"\r\n (click)=\"onItemClick(item)\"\r\n [href]=\"item.externalLink\"\r\n [target]=\"item.target\"\r\n [attr.tabindex]=\"0\"\r\n [attr.data-testid]=\"item.dataTestId\"\r\n >\r\n <ng-container\r\n *ngTemplateOutlet=\"linkBody; context: { $implicit: item }\"\r\n />\r\n </a>\r\n } @if (item.items) {\r\n <rdt-menu-overlay\r\n [item]=\"$any(item)\"\r\n [expanded]=\"item === expandedChild?.item\"\r\n [autofocusItem]=\"autofocusSubmenuItem\"\r\n [preferredHorizontalDir]=\"preferredHorizontalDir\"\r\n [preferredVerticalDir]=\"preferredVerticalDir\"\r\n [level]=\"0\"\r\n [anchorElement]=\"anchorEl\"\r\n />\r\n }\r\n </li>\r\n }\r\n</ul>\r\n", styles: ["a.menu-bar-item-content,a.menu-item-content,button.menu-bar-item-content,button.menu-item-content{white-space:nowrap;appearance:none;border:none;text-decoration:none}.menu-item-right-content,.menu-bar-item-right-content{margin-left:auto;display:flex;align-items:center}.menu-item-shortcut,.menu-bar-item-shortcut{margin-left:2rem}.menu-item-icon,.menu-bar-item-icon{margin-left:.5rem;font-size:1.2rem}.dp3-menu-base ul{margin-bottom:0}.rdt-menu-root{margin-left:0}.rdt-menu-root.rdt-overlay-down{margin-top:var(--rdt-menu-overlay-margin-y)}.rdt-menu-root.rdt-overlay-up{margin-top:calc(-1 * var(--rdt-menu-overlay-margin-y))}.rdt-menu-sub.rdt-overlay-left{margin-left:calc(-1 * var(--rdt-menu-overlay-margin-x))}.rdt-menu-sub.rdt-overlay-right{margin-left:var(--rdt-menu-overlay-margin-x)}rdt-menu-bar{-webkit-user-select:none;user-select:none;pointer-events:none;padding:var(--sub-menu-padding)}.menu-bar-item-container{display:flex;list-style-type:none;margin-bottom:0;padding-left:0}.menu-bar-item{cursor:pointer;pointer-events:all;color:var(--white);margin:0 .5rem;position:relative;display:flex;align-items:center;justify-content:center}.menu-bar-item.menu-bar-item-route-active .menu-bar-item-content{background-color:var(--rdt-menu-bar-item-background-route-active)}.menu-bar-item[aria-expanded=true] .menu-bar-item-content{background-color:var(--rdt-menu-bar-item-background-expanded)}.menu-bar-item-content{display:flex;align-items:center;padding:var(--rdt-menu-bar-item-padding);color:inherit!important;border-radius:var(--rdt-menu-bar-item-border-radius);overflow:hidden;background-color:var(--rdt-menu-bar-item-background)}.menu-bar-item-content:hover{background-color:var(--rdt-menu-bar-item-background-hover)}.menu-bar-item-content.focus-visible:focus,.menu-bar-item-content:focus-visible{outline:none;background-color:var(--rdt-menu-bar-item-background-focus)}\n"] }]
1205
1295
  }], propDecorators: { items: [{
1206
1296
  type: Input
1207
1297
  }], headerHeight: [{