@cute-widgets/base 20.0.5 → 21.0.0

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 (168) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/fesm2022/cute-widgets-base-abstract.mjs +15 -15
  3. package/fesm2022/cute-widgets-base-abstract.mjs.map +1 -1
  4. package/fesm2022/cute-widgets-base-alert.mjs +10 -10
  5. package/fesm2022/cute-widgets-base-alert.mjs.map +1 -1
  6. package/fesm2022/cute-widgets-base-autocomplete.mjs +14 -14
  7. package/fesm2022/cute-widgets-base-autocomplete.mjs.map +1 -1
  8. package/fesm2022/cute-widgets-base-badge.mjs +46 -14
  9. package/fesm2022/cute-widgets-base-badge.mjs.map +1 -1
  10. package/fesm2022/cute-widgets-base-bottom-sheet.mjs +11 -11
  11. package/fesm2022/cute-widgets-base-bottom-sheet.mjs.map +1 -1
  12. package/fesm2022/cute-widgets-base-button-toggle.mjs +29 -12
  13. package/fesm2022/cute-widgets-base-button-toggle.mjs.map +1 -1
  14. package/fesm2022/cute-widgets-base-button.mjs +20 -20
  15. package/fesm2022/cute-widgets-base-button.mjs.map +1 -1
  16. package/fesm2022/cute-widgets-base-card.mjs +40 -40
  17. package/fesm2022/cute-widgets-base-card.mjs.map +1 -1
  18. package/fesm2022/cute-widgets-base-checkbox.mjs +28 -28
  19. package/fesm2022/cute-widgets-base-checkbox.mjs.map +1 -1
  20. package/fesm2022/cute-widgets-base-chips.mjs +49 -49
  21. package/fesm2022/cute-widgets-base-chips.mjs.map +1 -1
  22. package/fesm2022/cute-widgets-base-collapse.mjs +14 -14
  23. package/fesm2022/cute-widgets-base-collapse.mjs.map +1 -1
  24. package/fesm2022/cute-widgets-base-core-datetime.mjs +11 -11
  25. package/fesm2022/cute-widgets-base-core-datetime.mjs.map +1 -1
  26. package/fesm2022/cute-widgets-base-core-directives.mjs +21 -21
  27. package/fesm2022/cute-widgets-base-core-directives.mjs.map +1 -1
  28. package/fesm2022/cute-widgets-base-core-error.mjs +6 -6
  29. package/fesm2022/cute-widgets-base-core-error.mjs.map +1 -1
  30. package/fesm2022/cute-widgets-base-core-line.mjs +7 -7
  31. package/fesm2022/cute-widgets-base-core-line.mjs.map +1 -1
  32. package/fesm2022/cute-widgets-base-core-nav.mjs +30 -28
  33. package/fesm2022/cute-widgets-base-core-nav.mjs.map +1 -1
  34. package/fesm2022/cute-widgets-base-core-observers.mjs +16 -16
  35. package/fesm2022/cute-widgets-base-core-observers.mjs.map +1 -1
  36. package/fesm2022/cute-widgets-base-core-option.mjs +10 -10
  37. package/fesm2022/cute-widgets-base-core-option.mjs.map +1 -1
  38. package/fesm2022/cute-widgets-base-core-pipes.mjs +6 -6
  39. package/fesm2022/cute-widgets-base-core-pipes.mjs.map +1 -1
  40. package/fesm2022/cute-widgets-base-core-ripple.mjs +3 -3
  41. package/fesm2022/cute-widgets-base-core-ripple.mjs.map +1 -1
  42. package/fesm2022/cute-widgets-base-core-theming.mjs +6 -6
  43. package/fesm2022/cute-widgets-base-core-theming.mjs.map +1 -1
  44. package/fesm2022/cute-widgets-base-core-utils.mjs +3 -3
  45. package/fesm2022/cute-widgets-base-core-utils.mjs.map +1 -1
  46. package/fesm2022/cute-widgets-base-core.mjs +36 -36
  47. package/fesm2022/cute-widgets-base-core.mjs.map +1 -1
  48. package/fesm2022/cute-widgets-base-datepicker.mjs +100 -99
  49. package/fesm2022/cute-widgets-base-datepicker.mjs.map +1 -1
  50. package/fesm2022/cute-widgets-base-dialog.mjs +31 -31
  51. package/fesm2022/cute-widgets-base-dialog.mjs.map +1 -1
  52. package/fesm2022/cute-widgets-base-divider.mjs +7 -7
  53. package/fesm2022/cute-widgets-base-divider.mjs.map +1 -1
  54. package/fesm2022/cute-widgets-base-expansion.mjs +27 -27
  55. package/fesm2022/cute-widgets-base-expansion.mjs.map +1 -1
  56. package/fesm2022/cute-widgets-base-form-field.mjs +28 -28
  57. package/fesm2022/cute-widgets-base-form-field.mjs.map +1 -1
  58. package/fesm2022/cute-widgets-base-grid-list.mjs +22 -22
  59. package/fesm2022/cute-widgets-base-grid-list.mjs.map +1 -1
  60. package/fesm2022/cute-widgets-base-icon.mjs +10 -10
  61. package/fesm2022/cute-widgets-base-icon.mjs.map +1 -1
  62. package/fesm2022/cute-widgets-base-input.mjs +7 -7
  63. package/fesm2022/cute-widgets-base-input.mjs.map +1 -1
  64. package/fesm2022/cute-widgets-base-layout-container.mjs +10 -10
  65. package/fesm2022/cute-widgets-base-layout-container.mjs.map +1 -1
  66. package/fesm2022/cute-widgets-base-layout-stack.mjs +13 -13
  67. package/fesm2022/cute-widgets-base-layout-stack.mjs.map +1 -1
  68. package/fesm2022/cute-widgets-base-layout.mjs +23 -23
  69. package/fesm2022/cute-widgets-base-layout.mjs.map +1 -1
  70. package/fesm2022/cute-widgets-base-list.mjs +56 -56
  71. package/fesm2022/cute-widgets-base-list.mjs.map +1 -1
  72. package/fesm2022/cute-widgets-base-menu.mjs +579 -364
  73. package/fesm2022/cute-widgets-base-menu.mjs.map +1 -1
  74. package/fesm2022/cute-widgets-base-navbar.mjs +27 -27
  75. package/fesm2022/cute-widgets-base-navbar.mjs.map +1 -1
  76. package/fesm2022/cute-widgets-base-paginator.mjs +11 -11
  77. package/fesm2022/cute-widgets-base-paginator.mjs.map +1 -1
  78. package/fesm2022/cute-widgets-base-progress.mjs +10 -10
  79. package/fesm2022/cute-widgets-base-progress.mjs.map +1 -1
  80. package/fesm2022/cute-widgets-base-radio.mjs +11 -11
  81. package/fesm2022/cute-widgets-base-radio.mjs.map +1 -1
  82. package/fesm2022/cute-widgets-base-select.mjs +11 -11
  83. package/fesm2022/cute-widgets-base-select.mjs.map +1 -1
  84. package/fesm2022/cute-widgets-base-sidenav.mjs +26 -26
  85. package/fesm2022/cute-widgets-base-sidenav.mjs.map +1 -1
  86. package/fesm2022/cute-widgets-base-slider.mjs +10 -10
  87. package/fesm2022/cute-widgets-base-slider.mjs.map +1 -1
  88. package/fesm2022/cute-widgets-base-snack-bar.mjs +28 -28
  89. package/fesm2022/cute-widgets-base-snack-bar.mjs.map +1 -1
  90. package/fesm2022/cute-widgets-base-sort.mjs +13 -13
  91. package/fesm2022/cute-widgets-base-sort.mjs.map +1 -1
  92. package/fesm2022/cute-widgets-base-spinner.mjs +8 -8
  93. package/fesm2022/cute-widgets-base-spinner.mjs.map +1 -1
  94. package/fesm2022/cute-widgets-base-stepper.mjs +40 -40
  95. package/fesm2022/cute-widgets-base-stepper.mjs.map +1 -1
  96. package/fesm2022/cute-widgets-base-table.mjs +58 -66
  97. package/fesm2022/cute-widgets-base-table.mjs.map +1 -1
  98. package/fesm2022/cute-widgets-base-tabs.mjs +16 -16
  99. package/fesm2022/cute-widgets-base-tabs.mjs.map +1 -1
  100. package/fesm2022/cute-widgets-base-timepicker.mjs +34 -63
  101. package/fesm2022/cute-widgets-base-timepicker.mjs.map +1 -1
  102. package/fesm2022/cute-widgets-base-toolbar.mjs +13 -13
  103. package/fesm2022/cute-widgets-base-toolbar.mjs.map +1 -1
  104. package/fesm2022/cute-widgets-base-tooltip.mjs +10 -10
  105. package/fesm2022/cute-widgets-base-tooltip.mjs.map +1 -1
  106. package/fesm2022/cute-widgets-base-tree.mjs +25 -25
  107. package/fesm2022/cute-widgets-base-tree.mjs.map +1 -1
  108. package/fesm2022/cute-widgets-base.mjs +4 -4
  109. package/package.json +118 -118
  110. package/{abstract/index.d.ts → types/cute-widgets-base-abstract.d.ts} +1 -1
  111. package/{autocomplete/index.d.ts → types/cute-widgets-base-autocomplete.d.ts} +2 -2
  112. package/{badge/index.d.ts → types/cute-widgets-base-badge.d.ts} +6 -5
  113. package/{bottom-sheet/index.d.ts → types/cute-widgets-base-bottom-sheet.d.ts} +1 -1
  114. package/{button-toggle/index.d.ts → types/cute-widgets-base-button-toggle.d.ts} +7 -1
  115. package/{button/index.d.ts → types/cute-widgets-base-button.d.ts} +1 -1
  116. package/{checkbox/index.d.ts → types/cute-widgets-base-checkbox.d.ts} +1 -1
  117. package/{chips/index.d.ts → types/cute-widgets-base-chips.d.ts} +1 -1
  118. package/{core/nav/index.d.ts → types/cute-widgets-base-core-nav.d.ts} +2 -1
  119. package/{core/observers/index.d.ts → types/cute-widgets-base-core-observers.d.ts} +1 -1
  120. package/{core/option/index.d.ts → types/cute-widgets-base-core-option.d.ts} +1 -1
  121. package/{datepicker/index.d.ts → types/cute-widgets-base-datepicker.d.ts} +2 -2
  122. package/{expansion/index.d.ts → types/cute-widgets-base-expansion.d.ts} +4 -14
  123. package/{form-field/index.d.ts → types/cute-widgets-base-form-field.d.ts} +1 -1
  124. package/{icon/index.d.ts → types/cute-widgets-base-icon.d.ts} +1 -1
  125. package/{input/index.d.ts → types/cute-widgets-base-input.d.ts} +1 -1
  126. package/{menu/index.d.ts → types/cute-widgets-base-menu.d.ts} +202 -121
  127. package/{progress/index.d.ts → types/cute-widgets-base-progress.d.ts} +1 -1
  128. package/{radio/index.d.ts → types/cute-widgets-base-radio.d.ts} +2 -2
  129. package/{sidenav/index.d.ts → types/cute-widgets-base-sidenav.d.ts} +1 -1
  130. package/{snack-bar/index.d.ts → types/cute-widgets-base-snack-bar.d.ts} +1 -1
  131. package/{sort/index.d.ts → types/cute-widgets-base-sort.d.ts} +1 -1
  132. package/{table/index.d.ts → types/cute-widgets-base-table.d.ts} +1 -1
  133. package/{tree/index.d.ts → types/cute-widgets-base-tree.d.ts} +2 -2
  134. /package/{alert/index.d.ts → types/cute-widgets-base-alert.d.ts} +0 -0
  135. /package/{card/index.d.ts → types/cute-widgets-base-card.d.ts} +0 -0
  136. /package/{collapse/index.d.ts → types/cute-widgets-base-collapse.d.ts} +0 -0
  137. /package/{core/animation/index.d.ts → types/cute-widgets-base-core-animation.d.ts} +0 -0
  138. /package/{core/datetime/index.d.ts → types/cute-widgets-base-core-datetime.d.ts} +0 -0
  139. /package/{core/directives/index.d.ts → types/cute-widgets-base-core-directives.d.ts} +0 -0
  140. /package/{core/error/index.d.ts → types/cute-widgets-base-core-error.d.ts} +0 -0
  141. /package/{core/interfaces/index.d.ts → types/cute-widgets-base-core-interfaces.d.ts} +0 -0
  142. /package/{core/layout/index.d.ts → types/cute-widgets-base-core-layout.d.ts} +0 -0
  143. /package/{core/line/index.d.ts → types/cute-widgets-base-core-line.d.ts} +0 -0
  144. /package/{core/pipes/index.d.ts → types/cute-widgets-base-core-pipes.d.ts} +0 -0
  145. /package/{core/ripple/index.d.ts → types/cute-widgets-base-core-ripple.d.ts} +0 -0
  146. /package/{core/testing/index.d.ts → types/cute-widgets-base-core-testing.d.ts} +0 -0
  147. /package/{core/theming/index.d.ts → types/cute-widgets-base-core-theming.d.ts} +0 -0
  148. /package/{core/types/index.d.ts → types/cute-widgets-base-core-types.d.ts} +0 -0
  149. /package/{core/utils/index.d.ts → types/cute-widgets-base-core-utils.d.ts} +0 -0
  150. /package/{core/index.d.ts → types/cute-widgets-base-core.d.ts} +0 -0
  151. /package/{dialog/index.d.ts → types/cute-widgets-base-dialog.d.ts} +0 -0
  152. /package/{divider/index.d.ts → types/cute-widgets-base-divider.d.ts} +0 -0
  153. /package/{grid-list/index.d.ts → types/cute-widgets-base-grid-list.d.ts} +0 -0
  154. /package/{layout/container/index.d.ts → types/cute-widgets-base-layout-container.d.ts} +0 -0
  155. /package/{layout/stack/index.d.ts → types/cute-widgets-base-layout-stack.d.ts} +0 -0
  156. /package/{layout/index.d.ts → types/cute-widgets-base-layout.d.ts} +0 -0
  157. /package/{list/index.d.ts → types/cute-widgets-base-list.d.ts} +0 -0
  158. /package/{navbar/index.d.ts → types/cute-widgets-base-navbar.d.ts} +0 -0
  159. /package/{paginator/index.d.ts → types/cute-widgets-base-paginator.d.ts} +0 -0
  160. /package/{select/index.d.ts → types/cute-widgets-base-select.d.ts} +0 -0
  161. /package/{slider/index.d.ts → types/cute-widgets-base-slider.d.ts} +0 -0
  162. /package/{spinner/index.d.ts → types/cute-widgets-base-spinner.d.ts} +0 -0
  163. /package/{stepper/index.d.ts → types/cute-widgets-base-stepper.d.ts} +0 -0
  164. /package/{tabs/index.d.ts → types/cute-widgets-base-tabs.d.ts} +0 -0
  165. /package/{timepicker/index.d.ts → types/cute-widgets-base-timepicker.d.ts} +0 -0
  166. /package/{toolbar/index.d.ts → types/cute-widgets-base-toolbar.d.ts} +0 -0
  167. /package/{tooltip/index.d.ts → types/cute-widgets-base-tooltip.d.ts} +0 -0
  168. /package/{index.d.ts → types/cute-widgets-base.d.ts} +0 -0
@@ -1,19 +1,17 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, inject, ElementRef, DOCUMENT, ChangeDetectorRef, booleanAttribute, Input, ViewEncapsulation, ChangeDetectionStrategy, Component, TemplateRef, ApplicationRef, Injector, ViewContainerRef, Directive, isDevMode, QueryList, EventEmitter, afterNextRender, Output, ContentChild, ContentChildren, ViewChild, Inject, Optional, Self, NgModule } from '@angular/core';
3
- import * as i4 from '@angular/cdk/a11y';
2
+ import { InjectionToken, inject, ElementRef, DOCUMENT, ChangeDetectorRef, booleanAttribute, Input, ViewEncapsulation, ChangeDetectionStrategy, Component, TemplateRef, ApplicationRef, Injector, ViewContainerRef, Directive, isDevMode, QueryList, signal, EventEmitter, afterNextRender, Output, ContentChild, ContentChildren, ViewChild, NgZone, Renderer2, NgModule } from '@angular/core';
4
3
  import { FocusMonitor, FocusKeyManager, isFakeTouchstartFromScreenReader, isFakeMousedownFromScreenReader } from '@angular/cdk/a11y';
5
4
  import { UP_ARROW, DOWN_ARROW, RIGHT_ARROW, LEFT_ARROW, ESCAPE, hasModifierKey, ENTER, SPACE } from '@angular/cdk/keycodes';
6
- import { Subject, merge, Subscription, of, asapScheduler } from 'rxjs';
7
- import { startWith, switchMap, takeUntil, filter, take, delay } from 'rxjs/operators';
5
+ import { Subject, merge, Subscription, of } from 'rxjs';
6
+ import { startWith, switchMap, takeUntil, take, filter, skipWhile } from 'rxjs/operators';
8
7
  import { TemplatePortal, DomPortalOutlet } from '@angular/cdk/portal';
9
- import { trigger, state, transition, style, animate } from '@angular/animations';
8
+ import { _animationsDisabled } from '@cute-widgets/base/core';
10
9
  import * as i1 from '@angular/cdk/menu';
11
10
  import { CdkMenu } from '@angular/cdk/menu';
12
- import * as i1$1 from '@angular/cdk/overlay';
13
- import { Overlay, OverlayConfig } from '@angular/cdk/overlay';
14
- import { normalizePassiveListenerOptions } from '@angular/cdk/platform';
15
- import * as i3 from '@angular/cdk/bidi';
16
- import { CommonModule } from '@angular/common';
11
+ import { Directionality } from '@angular/cdk/bidi';
12
+ import { createRepositionScrollStrategy, createOverlayRef, OverlayConfig, createFlexibleConnectedPositionStrategy, ViewportRuler, ScrollDispatcher, OverlayModule } from '@angular/cdk/overlay';
13
+ import { _getEventTarget, _getShadowRoot } from '@angular/cdk/platform';
14
+ import { CdkScrollableModule } from '@angular/cdk/scrolling';
17
15
 
18
16
  /**
19
17
  * @license Apache-2.0
@@ -135,10 +133,10 @@ class CuteMenuItem {
135
133
  _hasFocus() {
136
134
  return this._document && this._document.activeElement === this._getHostElement();
137
135
  }
138
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
139
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "20.3.15", type: CuteMenuItem, isStandalone: true, selector: "[cute-menu-item]", inputs: { role: "role", disabled: ["disabled", "disabled", booleanAttribute], disableRipple: ["disableRipple", "disableRipple", booleanAttribute] }, host: { listeners: { "click": "_checkDisabled($event)", "mouseenter": "_handleMouseEnter()" }, properties: { "attr.role": "role", "class.active": "_highlighted", "class.cute-menu-item-submenu-trigger": "_triggersSubmenu", "attr.tabindex": "_getTabIndex()", "attr.aria-disabled": "disabled", "disabled": "disabled || null" }, classAttribute: "cute-menu-item" }, exportAs: ["cuteMenuItem"], ngImport: i0, template: "<ng-content select=\"cute-icon, i[class], [cuteMenuItemIcon]\"></ng-content>\r\n<span class=\"cute-menu-item-text\"><ng-content></ng-content></span>\r\n\r\n@if (_triggersSubmenu) {\r\n <svg class=\"cute-menu-item-submenu-icon\"\r\n viewBox=\"0 0 5 10\"\r\n focusable=\"false\"\r\n aria-hidden=\"true\">\r\n <polygon points=\"0,0 5,5 0,10\"/>\r\n </svg>\r\n}\r\n", styles: [".cute-menu-item{display:flex;position:relative;justify-content:flex-start;cursor:pointer;width:100%;text-align:start;text-overflow:ellipsis;text-decoration:none;box-sizing:border-box;font-size:inherit;margin:0;padding:.25rem 1rem;align-items:center;white-space:nowrap;overflow:hidden;-webkit-user-select:none;user-select:none;border:none;outline:none;background:none;pointer-events:auto}.cute-menu-item:hover,.cute-menu-item.active{outline:none;background-color:rgba(var(--bs-body-color-rgb),.04)}.cute-menu-item[disabled]{opacity:.38;color:var(--bs-body-color);cursor:default}.cute-menu-item[disabled]:hover,.cute-menu-item[disabled]:focus{outline:none;background-color:var(--bs-body-bg)}.cute-menu-item[disabled]:after{display:block;position:absolute;content:\"\";inset:0}.cute-menu-item:not([disabled]).cdk-keyboard-focused{background-color:rgba(var(--bs-body-color-rgb),.04)}.cute-menu-item>[role=img],.cute-menu-item i[class]{position:absolute;left:4px;width:24px;height:24px;line-height:24px;background-repeat:no-repeat;display:inline-block;fill:currentColor;text-align:center;overflow:hidden;-webkit-user-select:none;user-select:none;-webkit-font-smoothing:antialiased}[dir=rtl] .cute-menu-item>[role=img],[dir=rtl] .cute-menu-item i[class]{right:4px;left:auto}.cute-menu-item .cute-menu-item-text{margin-left:1rem}[dir=rtl] .cute-menu-item .cute-menu-item-text{margin-right:1rem;margin-left:auto}.cute-menu-item .cute-menu-item-submenu-icon{position:absolute;top:50%;right:12px;transform:translateY(-50%);width:5px;height:10px;fill:currentColor;opacity:.75}[dir=rtl] .cute-menu-item .cute-menu-item-submenu-icon{left:12px;right:auto;transform:translateY(-50%) rotate(180deg)}.cute-menu-item-submenu-trigger{padding-right:2rem}[dir=rtl] .cute-menu-item-submenu-trigger{padding-right:1rem;padding-left:2rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
136
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuItem, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
137
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.0", type: CuteMenuItem, isStandalone: true, selector: "[cute-menu-item]", inputs: { role: "role", disabled: ["disabled", "disabled", booleanAttribute], disableRipple: ["disableRipple", "disableRipple", booleanAttribute] }, host: { listeners: { "click": "_checkDisabled($event)", "mouseenter": "_handleMouseEnter()" }, properties: { "attr.role": "role", "class.active": "_highlighted", "class.cute-menu-item-submenu-trigger": "_triggersSubmenu", "attr.tabindex": "_getTabIndex()", "attr.aria-disabled": "disabled", "attr.disabled": "disabled || null" }, classAttribute: "cute-menu-item" }, exportAs: ["cuteMenuItem"], ngImport: i0, template: "<ng-content select=\"cute-icon, i[class], [cuteMenuItemIcon]\"></ng-content>\r\n<span class=\"cute-menu-item-text\"><ng-content></ng-content></span>\r\n\r\n@if (_triggersSubmenu) {\r\n <svg class=\"cute-menu-item-submenu-icon\"\r\n viewBox=\"0 0 5 10\"\r\n focusable=\"false\"\r\n aria-hidden=\"true\">\r\n <polygon points=\"0,0 5,5 0,10\"/>\r\n </svg>\r\n}\r\n", styles: [".cute-menu-item{display:flex;position:relative;justify-content:flex-start;cursor:pointer;width:100%;text-align:start;text-overflow:ellipsis;text-decoration:none;box-sizing:border-box;font-size:inherit;margin:0;padding:.25rem 1rem;align-items:center;white-space:nowrap;overflow:hidden;-webkit-user-select:none;user-select:none;border:none;outline:none;background:none;pointer-events:auto}.cute-menu-item:hover,.cute-menu-item.active{outline:none;background-color:rgba(var(--bs-body-color-rgb),.04)}.cute-menu-item[disabled]{opacity:.38;color:var(--bs-body-color);cursor:default}.cute-menu-item[disabled]:hover,.cute-menu-item[disabled]:focus{outline:none;background-color:var(--bs-body-bg)}.cute-menu-item[disabled]:after{display:block;position:absolute;content:\"\";inset:0}.cute-menu-item:not([disabled]).cdk-keyboard-focused{background-color:rgba(var(--bs-body-color-rgb),.04)}.cute-menu-item>[role=img],.cute-menu-item i[class]{position:absolute;left:4px;width:24px;height:24px;line-height:24px;background-repeat:no-repeat;display:inline-block;fill:currentColor;text-align:center;overflow:hidden;-webkit-user-select:none;user-select:none;-webkit-font-smoothing:antialiased}[dir=rtl] .cute-menu-item>[role=img],[dir=rtl] .cute-menu-item i[class]{right:4px;left:auto}.cute-menu-item .cute-menu-item-text{margin-left:1rem}[dir=rtl] .cute-menu-item .cute-menu-item-text{margin-right:1rem;margin-left:auto}.cute-menu-item .cute-menu-item-submenu-icon{position:absolute;top:50%;right:12px;transform:translateY(-50%);width:5px;height:10px;fill:currentColor;opacity:.75}[dir=rtl] .cute-menu-item .cute-menu-item-submenu-icon{left:12px;right:auto;transform:translateY(-50%) rotate(180deg)}.cute-menu-item-submenu-trigger{padding-right:2rem}[dir=rtl] .cute-menu-item-submenu-trigger{padding-right:1rem;padding-left:2rem}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
140
138
  }
141
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuItem, decorators: [{
139
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuItem, decorators: [{
142
140
  type: Component,
143
141
  args: [{ selector: '[cute-menu-item]', exportAs: 'cuteMenuItem', host: {
144
142
  '[attr.role]': 'role',
@@ -148,7 +146,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
148
146
  //'[class.disabled]': 'disabled',
149
147
  '[attr.tabindex]': '_getTabIndex()',
150
148
  '[attr.aria-disabled]': 'disabled',
151
- '[disabled]': 'disabled || null',
149
+ '[attr.disabled]': 'disabled || null',
152
150
  '(click)': '_checkDisabled($event)',
153
151
  '(mouseenter)': '_handleMouseEnter()',
154
152
  }, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, template: "<ng-content select=\"cute-icon, i[class], [cuteMenuItemIcon]\"></ng-content>\r\n<span class=\"cute-menu-item-text\"><ng-content></ng-content></span>\r\n\r\n@if (_triggersSubmenu) {\r\n <svg class=\"cute-menu-item-submenu-icon\"\r\n viewBox=\"0 0 5 10\"\r\n focusable=\"false\"\r\n aria-hidden=\"true\">\r\n <polygon points=\"0,0 5,5 0,10\"/>\r\n </svg>\r\n}\r\n", styles: [".cute-menu-item{display:flex;position:relative;justify-content:flex-start;cursor:pointer;width:100%;text-align:start;text-overflow:ellipsis;text-decoration:none;box-sizing:border-box;font-size:inherit;margin:0;padding:.25rem 1rem;align-items:center;white-space:nowrap;overflow:hidden;-webkit-user-select:none;user-select:none;border:none;outline:none;background:none;pointer-events:auto}.cute-menu-item:hover,.cute-menu-item.active{outline:none;background-color:rgba(var(--bs-body-color-rgb),.04)}.cute-menu-item[disabled]{opacity:.38;color:var(--bs-body-color);cursor:default}.cute-menu-item[disabled]:hover,.cute-menu-item[disabled]:focus{outline:none;background-color:var(--bs-body-bg)}.cute-menu-item[disabled]:after{display:block;position:absolute;content:\"\";inset:0}.cute-menu-item:not([disabled]).cdk-keyboard-focused{background-color:rgba(var(--bs-body-color-rgb),.04)}.cute-menu-item>[role=img],.cute-menu-item i[class]{position:absolute;left:4px;width:24px;height:24px;line-height:24px;background-repeat:no-repeat;display:inline-block;fill:currentColor;text-align:center;overflow:hidden;-webkit-user-select:none;user-select:none;-webkit-font-smoothing:antialiased}[dir=rtl] .cute-menu-item>[role=img],[dir=rtl] .cute-menu-item i[class]{right:4px;left:auto}.cute-menu-item .cute-menu-item-text{margin-left:1rem}[dir=rtl] .cute-menu-item .cute-menu-item-text{margin-right:1rem;margin-left:auto}.cute-menu-item .cute-menu-item-submenu-icon{position:absolute;top:50%;right:12px;transform:translateY(-50%);width:5px;height:10px;fill:currentColor;opacity:.75}[dir=rtl] .cute-menu-item .cute-menu-item-submenu-icon{left:12px;right:auto;transform:translateY(-50%) rotate(180deg)}.cute-menu-item-submenu-trigger{padding-right:2rem}[dir=rtl] .cute-menu-item-submenu-trigger{padding-right:1rem;padding-left:2rem}\n"] }]
@@ -265,10 +263,10 @@ class CuteMenuContent {
265
263
  this.detach();
266
264
  this._outlet?.dispose();
267
265
  }
268
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuContent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
269
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: CuteMenuContent, isStandalone: true, selector: "ng-template[cuteMenuContent]", providers: [{ provide: CUTE_MENU_CONTENT, useExisting: CuteMenuContent }], ngImport: i0 }); }
266
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuContent, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
267
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: CuteMenuContent, isStandalone: true, selector: "ng-template[cuteMenuContent]", providers: [{ provide: CUTE_MENU_CONTENT, useExisting: CuteMenuContent }], ngImport: i0 }); }
270
268
  }
271
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuContent, decorators: [{
269
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuContent, decorators: [{
272
270
  type: Directive,
273
271
  args: [{
274
272
  selector: 'ng-template[cuteMenuContent]',
@@ -277,70 +275,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
277
275
  }]
278
276
  }], ctorParameters: () => [] });
279
277
 
280
- /**
281
- * @license Apache-2.0
282
- *
283
- * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
284
- *
285
- * You may not use this file except in compliance with the License
286
- * that can be found at http://www.apache.org/licenses/LICENSE-2.0
287
- *
288
- * This code is a modification of the `@angular/material` original
289
- * code licensed under MIT-style License (https://angular.dev/license).
290
- */
291
- /**
292
- * Animations used by the cute-menu component.
293
- * Animation duration and timing values are based on:
294
- * https://material.io/guidelines/components/menus.html#menus-usage
295
- * @docs-private
296
- */
297
- const cuteMenuAnimations = {
298
- /**
299
- * This animation controls the menu panel's entry and exit from the page.
300
- *
301
- * When the menu panel is added to the DOM, it scales in and fades in its border.
302
- *
303
- * When the menu panel is removed from the DOM, it simply fades out after a brief
304
- * delay to display the ripple.
305
- */
306
- transformMenu: trigger('transformMenu', [
307
- state('void', style({
308
- opacity: 0,
309
- transform: 'scale(0.8)',
310
- })),
311
- transition('void => enter', animate('120ms cubic-bezier(0, 0, 0.2, 1)', style({
312
- opacity: 1,
313
- transform: 'scale(1)',
314
- }))),
315
- transition('* => void', animate('100ms 25ms linear', style({ opacity: 0 }))),
316
- ]),
317
- /**
318
- * This animation fades in the background color and content of the menu panel
319
- * after its containing element is scaled in.
320
- */
321
- fadeInItems: trigger('fadeInItems', [
322
- // TODO(crisbeto): this is inside the `transformMenu`
323
- // now. Remove next time we do breaking changes.
324
- state('showing', style({ opacity: 1 })),
325
- transition('void => *', [
326
- style({ opacity: 0 }),
327
- animate('400ms 100ms cubic-bezier(0.55, 0, 0.55, 0.2)'),
328
- ]),
329
- ]),
330
- };
331
- /**
332
- * @deprecated
333
- * @breaking-change 8.0.0
334
- * @docs-private
335
- */
336
- //export const fadeInItems = cuteMenuAnimations.fadeInItems;
337
- /**
338
- * @deprecated
339
- * @breaking-change 8.0.0
340
- * @docs-private
341
- */
342
- //export const transformMenu = cuteMenuAnimations.transformMenu;
343
-
344
278
  /**
345
279
  * @license Apache-2.0
346
280
  *
@@ -356,21 +290,17 @@ let menuPanelUid = 0;
356
290
  /** Injection token to be used to override the default options for `mat-menu`. */
357
291
  const CUTE_MENU_DEFAULT_OPTIONS = new InjectionToken('cute-menu-default-options', {
358
292
  providedIn: 'root',
359
- factory: CUTE_MENU_DEFAULT_OPTIONS_FACTORY,
360
- });
361
- /**
362
- * @docs-private
363
- * @deprecated No longer used, will be removed.
364
- * @breaking-change 21.0.0
365
- */
366
- function CUTE_MENU_DEFAULT_OPTIONS_FACTORY() {
367
- return {
293
+ factory: () => ({
368
294
  overlapTrigger: false,
369
295
  xPosition: 'after',
370
296
  yPosition: 'below',
371
297
  backdropClass: 'cdk-overlay-transparent-backdrop',
372
- };
373
- }
298
+ }),
299
+ });
300
+ /** Name of the enter animation `@keyframes`. */
301
+ const ENTER_ANIMATION = '_cute-menu-enter';
302
+ /** Name of the exit animation `@keyframes`. */
303
+ const EXIT_ANIMATION = '_cute-menu-exit';
374
304
  class CuteMenu {
375
305
  /** Position of the menu in the X axis. */
376
306
  get xPosition() { return this._xPosition; }
@@ -393,7 +323,7 @@ class CuteMenu {
393
323
  this.setPositionClasses();
394
324
  }
395
325
  /**
396
- * This method takes classes set on the host mat-menu element and applies them on the
326
+ * This method takes classes set on the host cute-menu element and applies them on the
397
327
  * menu template that displays in the overlay container. Otherwise, it's difficult
398
328
  * to style the containing menu from outside the component.
399
329
  * @param classes list of class names
@@ -421,14 +351,17 @@ class CuteMenu {
421
351
  this._injector = inject(Injector);
422
352
  this._elevationPrefix = 'shadow';
423
353
  this._baseElevation = 1;
354
+ this._animationsDisabled = _animationsDisabled();
355
+ /** Only the direct descendant menu items. */
356
+ this._directDescendantItems = new QueryList();
424
357
  /** Config object to be passed into the menu's ngClass */
425
358
  this._classList = {};
426
359
  /** Current state of the panel animation. */
427
360
  this._panelAnimationState = 'void';
428
- /** Only the direct descendant menu items. */
429
- this._directDescendantItems = new QueryList();
430
361
  /** Emits whenever an animation on the menu completes. */
431
362
  this._animationDone = new Subject();
363
+ /** Whether the menu is animating. */
364
+ this._isAnimating = signal(false, ...(ngDevMode ? [{ debugName: "_isAnimating" }] : []));
432
365
  /** Event emitted when the menu is closed. */
433
366
  this.closed = new EventEmitter();
434
367
  this.panelId = `cute-menu-panel-${menuPanelUid++}`;
@@ -597,8 +530,8 @@ class CuteMenu {
597
530
  /**
598
531
  * Adds classes to the menu panel based on its position. Can be used by
599
532
  * consumers to add specific styling based on the position.
600
- * @param posX Position of the menu along the x axis.
601
- * @param posY Position of the menu along the y axis.
533
+ * @param posX Position of the menu along the x-axis.
534
+ * @param posY Position of the menu along the y-axis.
602
535
  */
603
536
  setPositionClasses(posX = this.xPosition, posY = this.yPosition) {
604
537
  const classes = this._classList;
@@ -608,32 +541,52 @@ class CuteMenu {
608
541
  classes['cute-menu-below'] = posY === 'below';
609
542
  this._changeDetectorRef.markForCheck();
610
543
  }
611
- /** Starts the entered animation. */
612
- _startAnimation() {
613
- // @breaking-change 8.0.0 Combine with _resetAnimation.
614
- this._panelAnimationState = 'enter';
544
+ /** Callback that is invoked when the panel animation completes. */
545
+ _onAnimationDone(state) {
546
+ const isExit = state === EXIT_ANIMATION;
547
+ if (isExit || state === ENTER_ANIMATION) {
548
+ if (isExit) {
549
+ clearTimeout(this._exitFallbackTimeout);
550
+ this._exitFallbackTimeout = undefined;
551
+ }
552
+ this._animationDone.next(isExit ? 'void' : 'enter');
553
+ this._isAnimating.set(false);
554
+ }
615
555
  }
616
- /** Resets the panel animation to its initial state. */
617
- _resetAnimation() {
618
- // @breaking-change 8.0.0 Combine with _startAnimation.
619
- this._panelAnimationState = 'void';
556
+ _onAnimationStart(state) {
557
+ if (state === ENTER_ANIMATION || state === EXIT_ANIMATION) {
558
+ this._isAnimating.set(true);
559
+ }
620
560
  }
621
- /** Callback that is invoked when the panel animation completes. */
622
- _onAnimationDone(event) {
623
- this._animationDone.next(event);
624
- this._isAnimating = false;
625
- }
626
- _onAnimationStart(event) {
627
- this._isAnimating = true;
628
- // Scroll the content element to the top as soon as the animation starts. This is necessary,
629
- // because we move focus to the first item while it's still being animated, which can throw
630
- // the browser off when it determines the scroll position. Alternatively, we can move focus
631
- // when the animation is done, however, moving focus asynchronously will interrupt screen
632
- // readers which are in the process of reading out the menu already. We take the `element`
633
- // from the `event` since we can't use a `ViewChild` to access the pane.
634
- if (event.toState === 'enter' && this._keyManager?.activeItemIndex === 0) {
635
- event.element.scrollTop = 0;
561
+ _setIsOpen(isOpen) {
562
+ this._panelAnimationState = isOpen ? 'enter' : 'void';
563
+ if (isOpen) {
564
+ if (this._keyManager?.activeItemIndex === 0) {
565
+ // Scroll the content element to the top as soon as the animation starts. This is necessary,
566
+ // because we move focus to the first item while it's still being animated, which can throw
567
+ // the browser off when it determines the scroll position. Alternatively we can move focus
568
+ // when the animation is done, however moving focus asynchronously will interrupt screen
569
+ // readers which are in the process of reading out the menu already. We take the `element`
570
+ // from the `event` since we can't use a `ViewChild` to access the pane.
571
+ const menuPanel = this._resolvePanel();
572
+ if (menuPanel) {
573
+ menuPanel.scrollTop = 0;
574
+ }
575
+ }
636
576
  }
577
+ else if (!this._animationsDisabled) {
578
+ // Some apps do `* { animation: none !important; }` in tests which will prevent the
579
+ // `animationend` event from firing. Since the exit animation is loading-bearing for
580
+ // removing the content from the DOM, add a fallback timer.
581
+ this._exitFallbackTimeout = setTimeout(() => this._onAnimationDone(EXIT_ANIMATION), 200);
582
+ }
583
+ // Animation events won't fire when animations are disabled so we simulate them.
584
+ if (this._animationsDisabled) {
585
+ setTimeout(() => {
586
+ this._onAnimationDone(isOpen ? ENTER_ANIMATION : EXIT_ANIMATION);
587
+ });
588
+ }
589
+ this._changeDetectorRef.markForCheck();
637
590
  }
638
591
  /**
639
592
  * Sets up a stream that will keep track of any newly-added menu items and will update the list
@@ -653,7 +606,7 @@ class CuteMenu {
653
606
  _resolvePanel() {
654
607
  let menuPanel = null;
655
608
  if (this._directDescendantItems.length) {
656
- // Because the `mat-menuPanel` is at the DOM insertion point, not inside the overlay, we don't
609
+ // Because the `cute-menuPanel` is at the DOM insertion point, not inside the overlay, we don't
657
610
  // have a nice way of getting a hold of the menuPanel panel. We can't use a `ViewChild` either
658
611
  // because the panel is inside an `ng-template`. We work around it by starting from one of
659
612
  // the items and walking up the DOM.
@@ -661,18 +614,21 @@ class CuteMenu {
661
614
  }
662
615
  return menuPanel;
663
616
  }
664
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
665
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "20.3.15", type: CuteMenu, isStandalone: true, selector: "cute-menu", inputs: { backdropClass: "backdropClass", ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: ["aria-labelledby", "ariaLabelledby"], ariaDescribedby: ["aria-describedby", "ariaDescribedby"], xPosition: "xPosition", yPosition: "yPosition", overlapTrigger: ["overlapTrigger", "overlapTrigger", booleanAttribute], hasBackdrop: ["hasBackdrop", "hasBackdrop", (value) => (value == null ? null : booleanAttribute(value))], panelClass: ["class", "panelClass"] }, outputs: { closed: "closed" }, host: { properties: { "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null" }, classAttribute: "cute-menu" }, providers: [{ provide: CUTE_MENU_PANEL, useExisting: CuteMenu }], queries: [{ propertyName: "lazyContent", first: true, predicate: CUTE_MENU_CONTENT, descendants: true }, { propertyName: "_allItems", predicate: CuteMenuItem, descendants: true }, { propertyName: "items", predicate: CuteMenuItem }], viewQueries: [{ propertyName: "templateRef", first: true, predicate: TemplateRef, descendants: true }], exportAs: ["cuteMenu"], hostDirectives: [{ directive: i1.CdkMenu }], ngImport: i0, template: "<ng-template>\r\n <div\r\n class=\"cute-menu-panel\"\r\n [id]=\"panelId\"\r\n [class]=\"_classList\"\r\n (keydown)=\"_handleKeydown($event)\"\r\n (click)=\"onClick($event)\"\r\n [@transformMenu]=\"_panelAnimationState\"\r\n (@transformMenu.start)=\"_onAnimationStart($event)\"\r\n (@transformMenu.done)=\"_onAnimationDone($event)\"\r\n tabindex=\"-1\"\r\n role=\"menu\"\r\n [attr.aria-label]=\"ariaLabel || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\r\n [attr.aria-describedby]=\"ariaDescribedby || null\">\r\n <div class=\"cute-menu-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [".cute-menu{display:block}.cute-menu-panel{min-width:112px;max-width:280px;overflow:hidden;-webkit-overflow-scrolling:touch;box-sizing:border-box;outline:0;will-change:transform,opacity}.cute-menu-panel .cute-menu-content{display:block;width:100%;padding:.5rem 0;font-size:1rem;color:var(--bs-body-color);text-align:start;list-style:none;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color-translucent);border-radius:var(--bs-border-radius)}.cute-menu-panel .cute-menu-content [role=separator]{margin:.5rem 0!important;max-height:1px}\n"], animations: [cuteMenuAnimations.transformMenu, cuteMenuAnimations.fadeInItems], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
617
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
618
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "16.1.0", version: "21.2.0", type: CuteMenu, isStandalone: true, selector: "cute-menu", inputs: { backdropClass: "backdropClass", ariaLabel: ["aria-label", "ariaLabel"], ariaLabelledby: ["aria-labelledby", "ariaLabelledby"], ariaDescribedby: ["aria-describedby", "ariaDescribedby"], xPosition: "xPosition", yPosition: "yPosition", overlapTrigger: ["overlapTrigger", "overlapTrigger", booleanAttribute], hasBackdrop: ["hasBackdrop", "hasBackdrop", (value) => (value == null ? null : booleanAttribute(value))], panelClass: ["class", "panelClass"] }, outputs: { closed: "closed" }, host: { properties: { "attr.aria-label": "null", "attr.aria-labelledby": "null", "attr.aria-describedby": "null" }, classAttribute: "cute-menu" }, providers: [{ provide: CUTE_MENU_PANEL, useExisting: CuteMenu }], queries: [{ propertyName: "lazyContent", first: true, predicate: CUTE_MENU_CONTENT, descendants: true }, { propertyName: "_allItems", predicate: CuteMenuItem, descendants: true }, { propertyName: "items", predicate: CuteMenuItem }], viewQueries: [{ propertyName: "templateRef", first: true, predicate: TemplateRef, descendants: true }], exportAs: ["cuteMenu"], hostDirectives: [{ directive: i1.CdkMenu }], ngImport: i0, template: "<ng-template>\r\n <div\r\n class=\"cute-menu-panel shadow\"\r\n [id]=\"panelId\"\r\n [class]=\"_classList\"\r\n [class.cute-menu-panel-animations-disabled]=\"_animationsDisabled\"\r\n [class.cute-menu-panel-exit-animation]=\"_panelAnimationState === 'void'\"\r\n [class.cute-menu-panel-animating]=\"_isAnimating()\"\r\n (click)=\"onClick($event)\"\r\n (animationstart)=\"_onAnimationStart($event.animationName)\"\r\n (animationend)=\"_onAnimationDone($event.animationName)\"\r\n (animationcancel)=\"_onAnimationDone($event.animationName)\"\r\n tabindex=\"-1\"\r\n role=\"menu\"\r\n [attr.aria-label]=\"ariaLabel || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\r\n [attr.aria-describedby]=\"ariaDescribedby || null\">\r\n <div class=\"cute-menu-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [".cute-menu{display:none}.cute-menu-panel{min-width:112px;max-width:280px;overflow:hidden;box-sizing:border-box;outline:0;animation:_cute-menu-enter .12s cubic-bezier(0,0,.2,1);will-change:transform,opacity}.cute-menu-panel.cute-menu-panel-exit-animation{animation:_cute-menu-exit .1s 25ms linear forwards}.cute-menu-panel.cute-menu-panel-animations-disabled{animation:none}.cute-menu-panel.cute-menu-panel-animating{pointer-events:none}.cute-menu-panel.cute-menu-panel-animating:has(.cute-menu-content:empty){display:none}@media(forced-colors:active){.cute-menu-panel{outline:solid 1px}}.cute-menu-panel .cute-menu-content{display:block;width:100%;padding:.5rem 0;font-size:1rem;color:var(--bs-body-color);text-align:start;list-style:none;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color-translucent);border-radius:var(--bs-border-radius)}.cute-menu-panel .cute-menu-content [role=separator]{margin:.5rem 0!important;max-height:1px}@keyframes _cute-menu-enter{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:none}}@keyframes _cute-menu-exit{0%{opacity:1}to{opacity:0}}\n"], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
666
619
  }
667
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenu, decorators: [{
620
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenu, decorators: [{
668
621
  type: Component,
669
622
  args: [{ selector: 'cute-menu', exportAs: 'cuteMenu', host: {
670
623
  'class': 'cute-menu',
671
624
  '[attr.aria-label]': 'null',
672
625
  '[attr.aria-labelledby]': 'null',
673
626
  '[attr.aria-describedby]': 'null',
674
- }, animations: [cuteMenuAnimations.transformMenu, cuteMenuAnimations.fadeInItems], providers: [{ provide: CUTE_MENU_PANEL, useExisting: CuteMenu }], standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, hostDirectives: [CdkMenu], template: "<ng-template>\r\n <div\r\n class=\"cute-menu-panel\"\r\n [id]=\"panelId\"\r\n [class]=\"_classList\"\r\n (keydown)=\"_handleKeydown($event)\"\r\n (click)=\"onClick($event)\"\r\n [@transformMenu]=\"_panelAnimationState\"\r\n (@transformMenu.start)=\"_onAnimationStart($event)\"\r\n (@transformMenu.done)=\"_onAnimationDone($event)\"\r\n tabindex=\"-1\"\r\n role=\"menu\"\r\n [attr.aria-label]=\"ariaLabel || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\r\n [attr.aria-describedby]=\"ariaDescribedby || null\">\r\n <div class=\"cute-menu-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [".cute-menu{display:block}.cute-menu-panel{min-width:112px;max-width:280px;overflow:hidden;-webkit-overflow-scrolling:touch;box-sizing:border-box;outline:0;will-change:transform,opacity}.cute-menu-panel .cute-menu-content{display:block;width:100%;padding:.5rem 0;font-size:1rem;color:var(--bs-body-color);text-align:start;list-style:none;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color-translucent);border-radius:var(--bs-border-radius)}.cute-menu-panel .cute-menu-content [role=separator]{margin:.5rem 0!important;max-height:1px}\n"] }]
675
- }], ctorParameters: () => [], propDecorators: { backdropClass: [{
627
+ }, providers: [{ provide: CUTE_MENU_PANEL, useExisting: CuteMenu }], changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, hostDirectives: [CdkMenu], template: "<ng-template>\r\n <div\r\n class=\"cute-menu-panel shadow\"\r\n [id]=\"panelId\"\r\n [class]=\"_classList\"\r\n [class.cute-menu-panel-animations-disabled]=\"_animationsDisabled\"\r\n [class.cute-menu-panel-exit-animation]=\"_panelAnimationState === 'void'\"\r\n [class.cute-menu-panel-animating]=\"_isAnimating()\"\r\n (click)=\"onClick($event)\"\r\n (animationstart)=\"_onAnimationStart($event.animationName)\"\r\n (animationend)=\"_onAnimationDone($event.animationName)\"\r\n (animationcancel)=\"_onAnimationDone($event.animationName)\"\r\n tabindex=\"-1\"\r\n role=\"menu\"\r\n [attr.aria-label]=\"ariaLabel || null\"\r\n [attr.aria-labelledby]=\"ariaLabelledby || null\"\r\n [attr.aria-describedby]=\"ariaDescribedby || null\">\r\n <div class=\"cute-menu-content\">\r\n <ng-content></ng-content>\r\n </div>\r\n </div>\r\n</ng-template>\r\n", styles: [".cute-menu{display:none}.cute-menu-panel{min-width:112px;max-width:280px;overflow:hidden;box-sizing:border-box;outline:0;animation:_cute-menu-enter .12s cubic-bezier(0,0,.2,1);will-change:transform,opacity}.cute-menu-panel.cute-menu-panel-exit-animation{animation:_cute-menu-exit .1s 25ms linear forwards}.cute-menu-panel.cute-menu-panel-animations-disabled{animation:none}.cute-menu-panel.cute-menu-panel-animating{pointer-events:none}.cute-menu-panel.cute-menu-panel-animating:has(.cute-menu-content:empty){display:none}@media(forced-colors:active){.cute-menu-panel{outline:solid 1px}}.cute-menu-panel .cute-menu-content{display:block;width:100%;padding:.5rem 0;font-size:1rem;color:var(--bs-body-color);text-align:start;list-style:none;background-color:var(--bs-body-bg);border:var(--bs-border-width) solid var(--bs-border-color-translucent);border-radius:var(--bs-border-radius)}.cute-menu-panel .cute-menu-content [role=separator]{margin:.5rem 0!important;max-height:1px}@keyframes _cute-menu-enter{0%{opacity:0;transform:scale(.8)}to{opacity:1;transform:none}}@keyframes _cute-menu-exit{0%{opacity:1}to{opacity:0}}\n"] }]
628
+ }], ctorParameters: () => [], propDecorators: { _allItems: [{
629
+ type: ContentChildren,
630
+ args: [CuteMenuItem, { descendants: true }]
631
+ }], backdropClass: [{
676
632
  type: Input
677
633
  }], ariaLabel: [{
678
634
  type: Input,
@@ -696,9 +652,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
696
652
  }], templateRef: [{
697
653
  type: ViewChild,
698
654
  args: [TemplateRef]
699
- }], _allItems: [{
700
- type: ContentChildren,
701
- args: [CuteMenuItem, { descendants: true }]
702
655
  }], items: [{
703
656
  type: ContentChildren,
704
657
  args: [CuteMenuItem, { descendants: false }]
@@ -736,31 +689,37 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
736
689
  * code licensed under MIT-style License (https://angular.dev/license).
737
690
  */
738
691
  /** Injection token that determines the scroll handling while the menu is open. */
739
- const CUTE_MENU_SCROLL_STRATEGY = new InjectionToken('cute-menu-scroll-strategy');
740
- /** @docs-private */
741
- function CUTE_MENU_SCROLL_STRATEGY_FACTORY(overlay) {
742
- return () => overlay.scrollStrategies.reposition();
743
- }
744
- /** @docs-private */
745
- const CUTE_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER = {
746
- provide: CUTE_MENU_SCROLL_STRATEGY,
747
- deps: [Overlay],
748
- useFactory: CUTE_MENU_SCROLL_STRATEGY_FACTORY,
749
- };
750
- /** Options for binding a passive event listener. */
751
- const passiveEventListenerOptions = normalizePassiveListenerOptions({ passive: true });
692
+ const CUTE_MENU_SCROLL_STRATEGY = new InjectionToken('cute-menu-scroll-strategy', {
693
+ providedIn: 'root',
694
+ factory: () => {
695
+ const injector = inject(Injector);
696
+ return () => createRepositionScrollStrategy(injector);
697
+ },
698
+ });
699
+ /**
700
+ * Default top padding of the menu panel.
701
+ * @deprecated No longer being used. Will be removed.
702
+ * @breaking-change 15.0.0
703
+ */
704
+ const MENU_PANEL_TOP_PADDING = 8;
705
+ /** Mapping between menu panels and the last trigger that opened them. */
706
+ const PANELS_TO_TRIGGERS = new WeakMap();
752
707
  /** Directive applied to an element that should trigger a `cute-menu`. */
753
- class CuteMenuTrigger {
754
- /** References the menu instance that the trigger is associated with. */
755
- get menu() { return this._menu; }
756
- set menu(menu) {
757
- if (menu === this._menu) {
708
+ class CuteMenuTriggerBase {
709
+ /** Element reference that can be used in class compositions. */
710
+ get elementRef() { return this._element; }
711
+ /** Menu currently assigned to the trigger. */
712
+ get _menu() {
713
+ return this._menuInternal;
714
+ }
715
+ set _menu(menu) {
716
+ if (menu === this._menuInternal) {
758
717
  return;
759
718
  }
760
- this._menu = menu;
719
+ this._menuInternal = menu;
761
720
  this._menuCloseSubscription.unsubscribe();
762
721
  if (menu) {
763
- if (menu === this._parentCuteMenu && isDevMode()) {
722
+ if (menu === this._parentCuteMenu && (typeof ngDevMode === 'undefined' || ngDevMode)) {
764
723
  throwCuteMenuRecursiveError();
765
724
  }
766
725
  this._menuCloseSubscription = menu.closed.subscribe((reason) => {
@@ -771,65 +730,42 @@ class CuteMenuTrigger {
771
730
  }
772
731
  });
773
732
  }
774
- this._menuItemInstance?._setTriggersSubmenu(this.triggersSubmenu());
775
- }
776
- constructor(_overlay, _element, _viewContainerRef, scrollStrategy, parentMenu,
777
- // `CuteMenuTrigger` is commonly used in combination with a `CuteMenuItem`.
778
- // tslint:disable-next-line: lightweight-tokens
779
- _menuItemInstance, _dir, _focusMonitor, _ngZone) {
780
- this._overlay = _overlay;
781
- this._element = _element;
782
- this._viewContainerRef = _viewContainerRef;
783
- this._menuItemInstance = _menuItemInstance;
784
- this._dir = _dir;
785
- this._focusMonitor = _focusMonitor;
786
- this._ngZone = _ngZone;
787
- this._portal = null;
733
+ this._menuItemInstance?._setTriggersSubmenu(this._triggersSubmenu());
734
+ }
735
+ constructor(_canHaveBackdrop) {
736
+ this._canHaveBackdrop = _canHaveBackdrop;
737
+ this._element = inject(ElementRef);
738
+ this._viewContainerRef = inject(ViewContainerRef);
739
+ this._menuItemInstance = inject(CuteMenuItem, { optional: true, self: true });
740
+ this._dir = inject(Directionality, { optional: true });
741
+ this._focusMonitor = inject(FocusMonitor);
742
+ this._ngZone = inject(NgZone);
743
+ this._injector = inject(Injector);
744
+ this._scrollStrategy = inject(CUTE_MENU_SCROLL_STRATEGY);
745
+ this._changeDetectorRef = inject(ChangeDetectorRef);
746
+ this._animationsDisabled = _animationsDisabled();
788
747
  this._overlayRef = null;
789
748
  this._menuOpen = false;
790
749
  this._closingActionsSubscription = Subscription.EMPTY;
791
- this._hoverSubscription = Subscription.EMPTY;
792
750
  this._menuCloseSubscription = Subscription.EMPTY;
793
- this._changeDetectorRef = inject(ChangeDetectorRef);
794
- /**
795
- * Handles touch start events on the trigger.
796
- * Needs to be an arrow function, so we can easily use addEventListener and removeEventListener.
797
- */
798
- this._handleTouchStart = (event) => {
799
- if (!isFakeTouchstartFromScreenReader(event)) {
800
- this._openedBy = 'touch';
801
- }
802
- };
803
- // Tracking input type is necessary, so it's possible to only autofocus
751
+ // Tracking input type is necessary so it's possible to only auto-focus
804
752
  // the first item of the list when the menu is opened via the keyboard
805
753
  this._openedBy = undefined;
806
- this._menu = null;
807
- /**
808
- * Whether focus should be restored when the menu is closed.
809
- * Note that disabling this option can have accessibility implications, and
810
- * it's up to you to manage focus if you decide to turn it off.
811
- */
812
- this.restoreFocus = true;
813
- /** Event emitted when the associated menu is opened. */
814
- this.menuOpened = new EventEmitter();
815
- /** Event emitted when the associated menu is closed. */
816
- this.menuClosed = new EventEmitter();
817
- this._scrollStrategy = scrollStrategy;
754
+ this._menuInternal = null;
755
+ const parentMenu = inject(CUTE_MENU_PANEL, { optional: true });
818
756
  this._parentCuteMenu = parentMenu instanceof CuteMenu ? parentMenu : undefined;
819
- _element.nativeElement.addEventListener('touchstart', this._handleTouchStart, passiveEventListenerOptions);
820
- }
821
- ngAfterContentInit() {
822
- this._handleHover();
823
757
  }
824
758
  ngOnDestroy() {
759
+ if (this._menu && this._ownsMenu(this._menu)) {
760
+ PANELS_TO_TRIGGERS.delete(this._menu);
761
+ }
762
+ this._pendingRemoval?.unsubscribe();
763
+ this._menuCloseSubscription.unsubscribe();
764
+ this._closingActionsSubscription.unsubscribe();
825
765
  if (this._overlayRef) {
826
766
  this._overlayRef.dispose();
827
767
  this._overlayRef = null;
828
768
  }
829
- this._element.nativeElement.removeEventListener('touchstart', this._handleTouchStart, passiveEventListenerOptions);
830
- this._menuCloseSubscription.unsubscribe();
831
- this._closingActionsSubscription.unsubscribe();
832
- this._hoverSubscription.unsubscribe();
833
769
  }
834
770
  /** Whether the menu is open. */
835
771
  get menuOpen() {
@@ -839,53 +775,69 @@ class CuteMenuTrigger {
839
775
  get dir() {
840
776
  return this._dir && this._dir.value === 'rtl' ? 'rtl' : 'ltr';
841
777
  }
842
- get elementRef() {
843
- return this._element;
844
- }
845
- /** Whether the menu triggers a submenu or a top-level one. */
846
- triggersSubmenu() {
847
- return !!(this._menuItemInstance && this._parentCuteMenu && this.menu);
778
+ /** Whether the menu triggers a sub-menu or a top-level one. */
779
+ _triggersSubmenu() {
780
+ return !!(this._menuItemInstance && this._parentCuteMenu && this._menu);
848
781
  }
849
- /** Toggles the menu between the open and closed states. */
850
- toggleMenu() {
851
- return this._menuOpen ? this.closeMenu() : this.openMenu();
782
+ _closeMenu() {
783
+ this._menu?.closed.emit();
852
784
  }
853
- /** Opens the menu. */
854
- openMenu() {
855
- const menu = this.menu;
785
+ /** Internal method to open menu providing option to auto focus on first item. */
786
+ _openMenu(autoFocus) {
787
+ if (this._triggerIsAriaDisabled()) {
788
+ return;
789
+ }
790
+ const menu = this._menu;
856
791
  if (this._menuOpen || !menu) {
857
792
  return;
858
793
  }
794
+ this._pendingRemoval?.unsubscribe();
795
+ const previousTrigger = PANELS_TO_TRIGGERS.get(menu);
796
+ PANELS_TO_TRIGGERS.set(menu, this);
797
+ // If the same menu is currently attached to another trigger,
798
+ // we need to close it so it doesn't end up in a broken state.
799
+ if (previousTrigger && previousTrigger !== this) {
800
+ previousTrigger._closeMenu();
801
+ }
859
802
  const overlayRef = this._createOverlay(menu);
860
803
  const overlayConfig = overlayRef.getConfig();
861
804
  const positionStrategy = overlayConfig.positionStrategy;
862
805
  this._setPosition(menu, positionStrategy);
863
- overlayConfig.hasBackdrop =
864
- menu.hasBackdrop == null ? !this.triggersSubmenu() : menu.hasBackdrop;
865
- overlayRef.attach(this._getPortal(menu));
866
- if (menu.lazyContent) {
867
- menu.lazyContent.attach(this.menuData);
806
+ if (this._canHaveBackdrop) {
807
+ overlayConfig.hasBackdrop =
808
+ menu.hasBackdrop == null ? !this._triggersSubmenu() : menu.hasBackdrop;
809
+ }
810
+ else {
811
+ overlayConfig.hasBackdrop = false;
812
+ }
813
+ // We need the `hasAttached` check for the case where the user kicked off a removal animation,
814
+ // but re-entered the menu. Re-attaching the same portal will trigger an error otherwise.
815
+ if (!overlayRef.hasAttached()) {
816
+ overlayRef.attach(this._getPortal(menu));
817
+ menu.lazyContent?.attach(this.menuData);
868
818
  }
869
- this._closingActionsSubscription = this._menuClosingActions().subscribe(() => this.closeMenu());
870
- this._initMenu(menu);
819
+ this._closingActionsSubscription = this._menuClosingActions().subscribe(() => this._closeMenu());
820
+ menu.parentMenu = this._triggersSubmenu() ? this._parentCuteMenu : undefined;
821
+ menu.direction = this.dir;
822
+ //this._setMenuElevation(menu);
823
+ if (autoFocus) {
824
+ menu.focusFirstItem(this._openedBy || 'program');
825
+ }
826
+ this._setIsMenuOpen(true);
871
827
  if (menu instanceof CuteMenu) {
872
- menu._startAnimation();
828
+ menu._setIsOpen(true);
873
829
  menu._directDescendantItems.changes.pipe(takeUntil(menu.closed)).subscribe(() => {
874
- // Re-adjust the position without locking when the number of items
830
+ // Re-adjust the position without locking when the amount of items
875
831
  // changes so that the overlay is allowed to pick a new optimal position.
876
832
  positionStrategy.withLockedPosition(false).reapplyLastPosition();
877
833
  positionStrategy.withLockedPosition(true);
878
834
  });
879
835
  }
880
836
  }
881
- /** Closes the menu. */
882
- closeMenu() {
883
- this.menu?.closed.emit();
884
- }
885
837
  /**
886
838
  * Focuses the menu trigger.
887
839
  * @param origin Source of the menu trigger's focus.
888
- * @param options Focus options
840
+ * @param options Optional focus options.
889
841
  */
890
842
  focus(origin, options) {
891
843
  if (this._focusMonitor && origin) {
@@ -895,61 +847,47 @@ class CuteMenuTrigger {
895
847
  this._element.nativeElement.focus(options);
896
848
  }
897
849
  }
898
- /**
899
- * Updates the position of the menu to ensure that it fits all options within the viewport.
900
- */
901
- updatePosition() {
902
- this._overlayRef?.updatePosition();
903
- }
904
850
  /** Closes the menu and does the necessary cleanup. */
905
851
  _destroyMenu(reason) {
906
- if (!this._overlayRef || !this.menuOpen) {
852
+ const overlayRef = this._overlayRef;
853
+ const menu = this._menu;
854
+ if (!overlayRef || !this.menuOpen) {
907
855
  return;
908
856
  }
909
- const menu = this.menu;
910
857
  this._closingActionsSubscription.unsubscribe();
911
- this._overlayRef.detach();
858
+ this._pendingRemoval?.unsubscribe();
859
+ // Note that we don't wait for the animation to finish if another trigger took
860
+ // over the menu, because the panel will end up empty which looks glitchy.
861
+ if (menu instanceof CuteMenu && this._ownsMenu(menu)) {
862
+ this._pendingRemoval = menu._animationDone.pipe(take(1)).subscribe(() => {
863
+ overlayRef.detach();
864
+ // Only detach the lazy content if no other trigger took over the menu, otherwise we may
865
+ // detach something we no longer own. Note that we don't use `this._ownsMenu` here,
866
+ // because the current trigger relinquishes ownership as soon as the closing sequence
867
+ // is kicked off whereas the animation takes some time to play out.
868
+ if (!PANELS_TO_TRIGGERS.has(menu)) {
869
+ menu.lazyContent?.detach();
870
+ }
871
+ });
872
+ menu._setIsOpen(false);
873
+ }
874
+ else {
875
+ overlayRef.detach();
876
+ menu?.lazyContent?.detach();
877
+ }
878
+ if (menu && this._ownsMenu(menu)) {
879
+ PANELS_TO_TRIGGERS.delete(menu);
880
+ }
912
881
  // Always restore focus if the user is navigating using the keyboard or the menu was opened
913
882
  // programmatically. We don't restore for non-root triggers, because it can prevent focus
914
883
  // from making it back to the root trigger when closing a long chain of menus by clicking
915
884
  // on the backdrop.
916
- if (this.restoreFocus && (reason === 'keydown' || !this._openedBy || !this.triggersSubmenu())) {
885
+ if (this.restoreFocus &&
886
+ (reason === 'keydown' || !this._openedBy || !this._triggersSubmenu())) {
917
887
  this.focus(this._openedBy);
918
888
  }
919
889
  this._openedBy = undefined;
920
- if (menu instanceof CuteMenu) {
921
- menu._resetAnimation();
922
- if (menu.lazyContent) {
923
- // Wait for the exit animation to finish before detaching the content.
924
- menu._animationDone
925
- .pipe(filter(event => event.toState === 'void'), take(1),
926
- // Interrupt if the content got re-attached.
927
- takeUntil(menu.lazyContent._attached))
928
- .subscribe({
929
- next: () => menu.lazyContent.detach(),
930
- // No matter whether the content got re-attached, reset the menu.
931
- complete: () => this._setIsMenuOpen(false),
932
- });
933
- }
934
- else {
935
- this._setIsMenuOpen(false);
936
- }
937
- }
938
- else {
939
- this._setIsMenuOpen(false);
940
- menu?.lazyContent?.detach();
941
- }
942
- }
943
- /**
944
- * This method sets the menu state to open and focuses the first item if
945
- * the menu was opened via the keyboard.
946
- */
947
- _initMenu(menu) {
948
- menu.parentMenu = this.triggersSubmenu() ? this._parentCuteMenu : undefined;
949
- menu.direction = this.dir;
950
- this._setMenuElevation(menu);
951
- menu.focusFirstItem(this._openedBy || 'program');
952
- this._setIsMenuOpen(true);
890
+ this._setIsMenuOpen(false);
953
891
  }
954
892
  /** Updates the menu elevation based on the amount of parent menus that it has. */
955
893
  _setMenuElevation(menu) {
@@ -968,7 +906,7 @@ class CuteMenuTrigger {
968
906
  if (isOpen !== this._menuOpen) {
969
907
  this._menuOpen = isOpen;
970
908
  this._menuOpen ? this.menuOpened.emit() : this.menuClosed.emit();
971
- if (this.triggersSubmenu()) {
909
+ if (this._triggersSubmenu()) {
972
910
  this._menuItemInstance._setHighlighted(isOpen);
973
911
  }
974
912
  this._changeDetectorRef.markForCheck();
@@ -982,11 +920,12 @@ class CuteMenuTrigger {
982
920
  if (!this._overlayRef) {
983
921
  const config = this._getOverlayConfig(menu);
984
922
  this._subscribeToPositions(menu, config.positionStrategy);
985
- this._overlayRef = this._overlay.create(config);
986
- // Consume the `keydownEvents` in order to prevent them from going to another overlay.
987
- // Ideally we'd also have our keyboard event logic in here, however doing so will
988
- // break anybody that may have implemented the `CuteMenuPanel` themselves.
989
- this._overlayRef.keydownEvents().subscribe();
923
+ this._overlayRef = createOverlayRef(this._injector, config);
924
+ this._overlayRef.keydownEvents().subscribe(event => {
925
+ if (this._menu instanceof CuteMenu) {
926
+ this._menu._handleKeydown(event);
927
+ }
928
+ });
990
929
  }
991
930
  return this._overlayRef;
992
931
  }
@@ -996,16 +935,15 @@ class CuteMenuTrigger {
996
935
  */
997
936
  _getOverlayConfig(menu) {
998
937
  return new OverlayConfig({
999
- positionStrategy: this._overlay
1000
- .position()
1001
- .flexibleConnectedTo(this._element)
938
+ positionStrategy: createFlexibleConnectedPositionStrategy(this._injector, this._getOverlayOrigin())
1002
939
  .withLockedPosition()
1003
940
  .withGrowAfterOpen()
1004
941
  .withTransformOriginOn('.cute-menu-panel'),
1005
942
  backdropClass: menu.backdropClass || 'cdk-overlay-transparent-backdrop',
1006
943
  panelClass: menu.overlayPanelClass,
1007
944
  scrollStrategy: this._scrollStrategy(),
1008
- direction: this._dir,
945
+ direction: this._dir || 'ltr',
946
+ disableAnimations: this._animationsDisabled,
1009
947
  });
1010
948
  }
1011
949
  /**
@@ -1016,34 +954,28 @@ class CuteMenuTrigger {
1016
954
  _subscribeToPositions(menu, position) {
1017
955
  if (menu.setPositionClasses) {
1018
956
  position.positionChanges.subscribe(change => {
1019
- const posX = change.connectionPair.overlayX === 'start' ? 'after' : 'before';
1020
- const posY = change.connectionPair.overlayY === 'top' ? 'below' : 'above';
1021
- // @breaking-change 15.0.0 Remove null check for `ngZone`.
1022
- // `positionChanges` fires outside of the `ngZone` and `setPositionClasses` might be
1023
- // updating something in the view, so we need to bring it back in.
1024
- if (this._ngZone) {
1025
- this._ngZone.run(() => menu.setPositionClasses(posX, posY));
1026
- }
1027
- else {
957
+ this._ngZone.run(() => {
958
+ const posX = change.connectionPair.overlayX === 'start' ? 'after' : 'before';
959
+ const posY = change.connectionPair.overlayY === 'top' ? 'below' : 'above';
1028
960
  menu.setPositionClasses(posX, posY);
1029
- }
961
+ });
1030
962
  });
1031
963
  }
1032
964
  }
1033
965
  /**
1034
966
  * Sets the appropriate positions on a position strategy
1035
967
  * so the overlay connects with the trigger correctly.
1036
- * @param menu Menu panel
1037
- * @param positionStrategy Strategy whose position is to update.
968
+ * @param menu Menu panel.
969
+ * @param positionStrategy Strategy whose position to update.
1038
970
  */
1039
971
  _setPosition(menu, positionStrategy) {
1040
972
  let [originX, originFallbackX] = menu.xPosition === 'before' ? ['end', 'start'] : ['start', 'end'];
1041
973
  let [overlayY, overlayFallbackY] = menu.yPosition === 'above' ? ['bottom', 'top'] : ['top', 'bottom'];
1042
974
  let [originY, originFallbackY] = [overlayY, overlayFallbackY];
1043
975
  let [overlayX, overlayFallbackX] = [originX, originFallbackX];
1044
- let offsetY = 0;
1045
- if (this.triggersSubmenu()) {
1046
- // When the menu is a submenu, it should always align itself
976
+ let offsetY = 4; //0;
977
+ if (this._triggersSubmenu()) {
978
+ // When the menu is a sub-menu, it should always align itself
1047
979
  // to the edges of the trigger, instead of overlapping it.
1048
980
  overlayFallbackX = originX = menu.xPosition === 'before' ? 'start' : 'end';
1049
981
  originFallbackX = overlayX = originX === 'end' ? 'start' : 'end';
@@ -1056,7 +988,6 @@ class CuteMenuTrigger {
1056
988
  }
1057
989
  }
1058
990
  else if (!menu.overlapTrigger) {
1059
- offsetY = 4;
1060
991
  originY = overlayY === 'top' ? 'bottom' : 'top';
1061
992
  originFallbackY = overlayFallbackY === 'top' ? 'bottom' : 'top';
1062
993
  }
@@ -1081,13 +1012,147 @@ class CuteMenuTrigger {
1081
1012
  }
1082
1013
  /** Returns a stream that emits whenever an action that should close the menu occurs. */
1083
1014
  _menuClosingActions() {
1084
- const backdrop = this._overlayRef.backdropClick();
1015
+ const outsideClicks = this._getOutsideClickStream(this._overlayRef);
1085
1016
  const detachments = this._overlayRef.detachments();
1086
1017
  const parentClose = this._parentCuteMenu ? this._parentCuteMenu.closed : of();
1087
1018
  const hover = this._parentCuteMenu
1088
- ? this._parentCuteMenu._hovered().pipe(filter(active => active !== this._menuItemInstance), filter(() => this._menuOpen))
1019
+ ? this._parentCuteMenu
1020
+ ._hovered()
1021
+ .pipe(filter(active => this._menuOpen && active !== this._menuItemInstance))
1089
1022
  : of();
1090
- return merge(backdrop, parentClose, hover, detachments);
1023
+ return merge(outsideClicks, parentClose, hover, detachments);
1024
+ }
1025
+ /** Gets the portal that should be attached to the overlay. */
1026
+ _getPortal(menu) {
1027
+ // Note that we can avoid this check by keeping the portal on the menu panel.
1028
+ // While it would be cleaner, we'd have to introduce another required method on
1029
+ // `CuteMenuPanel`, making it harder to consume.
1030
+ if (!this._portal || this._portal.templateRef !== menu.templateRef) {
1031
+ this._portal = new TemplatePortal(menu.templateRef, this._viewContainerRef);
1032
+ }
1033
+ return this._portal;
1034
+ }
1035
+ /**
1036
+ * Determines whether the trigger owns a specific menu panel, at the current point in time.
1037
+ * This allows us to distinguish the case where the same panel is passed into multiple triggers
1038
+ * and multiple are open at a time.
1039
+ */
1040
+ _ownsMenu(menu) {
1041
+ return PANELS_TO_TRIGGERS.get(menu) === this;
1042
+ }
1043
+ /**
1044
+ * Detect if the trigger element is aria-disabled, indicating it should behave as
1045
+ * disabled and not open the menu.
1046
+ */
1047
+ _triggerIsAriaDisabled() {
1048
+ return booleanAttribute(this._element.nativeElement.getAttribute('aria-disabled'));
1049
+ }
1050
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuTriggerBase, deps: "invalid", target: i0.ɵɵFactoryTarget.Directive }); }
1051
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: CuteMenuTriggerBase, isStandalone: true, ngImport: i0 }); }
1052
+ }
1053
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuTriggerBase, decorators: [{
1054
+ type: Directive
1055
+ }], ctorParameters: () => [{ type: undefined }] });
1056
+
1057
+ /**
1058
+ * @license Apache-2.0
1059
+ *
1060
+ * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
1061
+ *
1062
+ * You may not use this file except in compliance with the License
1063
+ * that can be found at http://www.apache.org/licenses/LICENSE-2.0
1064
+ *
1065
+ * This code is a modification of the `@angular/material` original
1066
+ * code licensed under MIT-style License (https://angular.dev/license).
1067
+ */
1068
+ /** Directive applied to an element that should trigger a `mat-menu`. */
1069
+ class CuteMenuTrigger extends CuteMenuTriggerBase {
1070
+ /**
1071
+ * @deprecated
1072
+ * @breaking-change 8.0.0
1073
+ */
1074
+ get _deprecatedCuteMenuTriggerFor() {
1075
+ return this.menu;
1076
+ }
1077
+ set _deprecatedCuteMenuTriggerFor(v) {
1078
+ this.menu = v;
1079
+ }
1080
+ /** References the menu instance that the trigger is associated with. */
1081
+ get menu() {
1082
+ return this._menu;
1083
+ }
1084
+ set menu(menu) {
1085
+ this._menu = menu;
1086
+ }
1087
+ constructor() {
1088
+ super(true);
1089
+ this._hoverSubscription = Subscription.EMPTY;
1090
+ /**
1091
+ * Whether focus should be restored when the menu is closed.
1092
+ * Note that disabling this option can have accessibility implications
1093
+ * and it's up to you to manage focus, if you decide to turn it off.
1094
+ */
1095
+ this.restoreFocus = true;
1096
+ /** Event emitted when the associated menu is opened. */
1097
+ this.menuOpened = new EventEmitter();
1098
+ /**
1099
+ * Event emitted when the associated menu is opened.
1100
+ * @deprecated Switch to `menuOpened` instead
1101
+ * @breaking-change 8.0.0
1102
+ */
1103
+ // tslint:disable-next-line:no-output-on-prefix
1104
+ this.onMenuOpen = this.menuOpened;
1105
+ /** Event emitted when the associated menu is closed. */
1106
+ this.menuClosed = new EventEmitter();
1107
+ /**
1108
+ * Event emitted when the associated menu is closed.
1109
+ * @deprecated Switch to `menuClosed` instead
1110
+ * @breaking-change 8.0.0
1111
+ */
1112
+ // tslint:disable-next-line:no-output-on-prefix
1113
+ this.onMenuClose = this.menuClosed;
1114
+ const renderer = inject(Renderer2);
1115
+ this._cleanupTouchstart = renderer.listen(this._element.nativeElement, 'touchstart', (event) => {
1116
+ if (!isFakeTouchstartFromScreenReader(event)) {
1117
+ this._openedBy = 'touch';
1118
+ }
1119
+ }, { passive: true });
1120
+ }
1121
+ /** Whether the menu triggers a sub-menu or a top-level one. */
1122
+ triggersSubmenu() {
1123
+ return super._triggersSubmenu();
1124
+ }
1125
+ /** Toggles the menu between the open and closed states. */
1126
+ toggleMenu() {
1127
+ return this.menuOpen ? this.closeMenu() : this.openMenu();
1128
+ }
1129
+ /** Opens the menu. */
1130
+ openMenu() {
1131
+ this._openMenu(true);
1132
+ }
1133
+ /** Closes the menu. */
1134
+ closeMenu() {
1135
+ this._closeMenu();
1136
+ }
1137
+ /**
1138
+ * Updates the position of the menu to ensure that it fits all options within the viewport.
1139
+ */
1140
+ updatePosition() {
1141
+ this._overlayRef?.updatePosition();
1142
+ }
1143
+ ngAfterContentInit() {
1144
+ this._handleHover();
1145
+ }
1146
+ ngOnDestroy() {
1147
+ super.ngOnDestroy();
1148
+ this._cleanupTouchstart();
1149
+ this._hoverSubscription.unsubscribe();
1150
+ }
1151
+ _getOverlayOrigin() {
1152
+ return this._element;
1153
+ }
1154
+ _getOutsideClickStream(overlayRef) {
1155
+ return overlayRef.backdropClick();
1091
1156
  }
1092
1157
  /** Handles mouse presses on the trigger. */
1093
1158
  _handleMousedown(event) {
@@ -1095,7 +1160,7 @@ class CuteMenuTrigger {
1095
1160
  // Since right or middle button clicks won't trigger the `click` event,
1096
1161
  // we shouldn't consider the menu as opened by mouse in those cases.
1097
1162
  this._openedBy = event.button === 0 ? 'mouse' : undefined;
1098
- // Since clicking on the trigger won't close the menu if it opens a submenu,
1163
+ // Since clicking on the trigger won't close the menu if it opens a sub-menu,
1099
1164
  // we should prevent focus from moving onto it via click to avoid the
1100
1165
  // highlight from lingering on the menu item.
1101
1166
  if (this.triggersSubmenu()) {
@@ -1131,76 +1196,43 @@ class CuteMenuTrigger {
1131
1196
  /** Handles the cases where the user hovers over the trigger. */
1132
1197
  _handleHover() {
1133
1198
  // Subscribe to changes in the hovered item in order to toggle the panel.
1134
- if (!this.triggersSubmenu() || !this._parentCuteMenu) {
1135
- return;
1136
- }
1137
- this._hoverSubscription = this._parentCuteMenu
1138
- ._hovered()
1139
- // Since we might have multiple competing triggers for the same menu (e.g. a sub-menu
1140
- // with different data and triggers), we have to delay it by a tick to ensure that
1141
- // it won't be closed immediately after it is opened.
1142
- .pipe(filter(active => active === this._menuItemInstance && !active.disabled), delay(0, asapScheduler))
1143
- .subscribe(() => {
1144
- this._openedBy = 'mouse';
1145
- // If the same menu is used between multiple triggers, it might still be animating
1146
- // while the new trigger tries to re-open it. Wait for the animation to finish
1147
- // before doing so. Also interrupt if the user moves to another item.
1148
- if (this.menu instanceof CuteMenu && this.menu._isAnimating) {
1149
- // We need the `delay(0)` here in order to avoid
1150
- // 'changed after checked' errors in some cases. See #12194.
1151
- this.menu._animationDone
1152
- .pipe(take(1), delay(0, asapScheduler), takeUntil(this._parentCuteMenu._hovered()))
1153
- .subscribe(() => this.openMenu());
1154
- }
1155
- else {
1156
- this.openMenu();
1157
- }
1158
- });
1159
- }
1160
- /** Gets the portal that should be attached to the overlay. */
1161
- _getPortal(menu) {
1162
- // Note that we can avoid this check by keeping the portal on the menu panel.
1163
- // While it would be cleaner, we'd have to introduce another required method on
1164
- // `CuteMenuPanel`, making it harder to consume.
1165
- if (!this._portal || this._portal.templateRef !== menu.templateRef) {
1166
- this._portal = new TemplatePortal(menu.templateRef, this._viewContainerRef);
1199
+ if (this.triggersSubmenu() && this._parentCuteMenu) {
1200
+ this._hoverSubscription = this._parentCuteMenu._hovered().subscribe(active => {
1201
+ if (active === this._menuItemInstance &&
1202
+ !active.disabled &&
1203
+ // Ignore hover events if the parent menu is in the process of being closed (see #31956).
1204
+ this._parentCuteMenu?._panelAnimationState !== 'void') {
1205
+ this._openedBy = 'mouse';
1206
+ // Open the menu, but do NOT auto-focus on first item when just hovering.
1207
+ // When VoiceOver is enabled, this is particularly confusing as the focus will
1208
+ // cause another hover event, and continue opening sub-menus without interaction.
1209
+ this._openMenu(false);
1210
+ }
1211
+ });
1167
1212
  }
1168
- return this._portal;
1169
1213
  }
1170
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuTrigger, deps: [{ token: i1$1.Overlay }, { token: i0.ElementRef }, { token: i0.ViewContainerRef }, { token: CUTE_MENU_SCROLL_STRATEGY }, { token: CUTE_MENU_PANEL, optional: true }, { token: CuteMenuItem, optional: true, self: true }, { token: i3.Directionality, optional: true }, { token: i4.FocusMonitor }, { token: i0.NgZone }], target: i0.ɵɵFactoryTarget.Directive }); }
1171
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "20.3.15", type: CuteMenuTrigger, isStandalone: true, selector: "[cuteMenuTriggerFor]", inputs: { menu: ["cuteMenuTriggerFor", "menu"], menuData: ["cuteMenuTriggerData", "menuData"], restoreFocus: ["cuteMenuTriggerRestoreFocus", "restoreFocus"] }, outputs: { menuOpened: "menuOpened", menuClosed: "menuClosed" }, host: { listeners: { "click": "_handleClick($event)", "mousedown": "_handleMousedown($event)", "keydown": "_handleKeydown($event)" }, properties: { "attr.aria-haspopup": "menu ? \"menu\" : null", "attr.aria-expanded": "menuOpen", "attr.aria-controls": "menuOpen ? menu.panelId : null" }, classAttribute: "cute-menu-trigger" }, exportAs: ["cuteMenuTrigger"], ngImport: i0 }); }
1214
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1215
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "21.2.0", type: CuteMenuTrigger, isStandalone: true, selector: "[cute-menu-trigger-for], [cuteMenuTriggerFor]", inputs: { _deprecatedCuteMenuTriggerFor: ["cute-menu-trigger-for", "_deprecatedCuteMenuTriggerFor"], menu: ["cuteMenuTriggerFor", "menu"], menuData: ["cuteMenuTriggerData", "menuData"], restoreFocus: ["cuteMenuTriggerRestoreFocus", "restoreFocus"] }, outputs: { menuOpened: "menuOpened", onMenuOpen: "onMenuOpen", menuClosed: "menuClosed", onMenuClose: "onMenuClose" }, host: { listeners: { "click": "_handleClick($event)", "mousedown": "_handleMousedown($event)", "keydown": "_handleKeydown($event)" }, properties: { "attr.aria-haspopup": "menu ? \"menu\" : null", "attr.aria-expanded": "menuOpen", "attr.aria-controls": "menuOpen ? menu?.panelId : null" }, classAttribute: "cute-menu-trigger" }, exportAs: ["cuteMenuTrigger"], usesInheritance: true, ngImport: i0 }); }
1172
1216
  }
1173
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuTrigger, decorators: [{
1217
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuTrigger, decorators: [{
1174
1218
  type: Directive,
1175
1219
  args: [{
1176
- selector: `[cuteMenuTriggerFor]`,
1177
- exportAs: 'cuteMenuTrigger',
1220
+ selector: '[cute-menu-trigger-for], [cuteMenuTriggerFor]',
1178
1221
  host: {
1179
1222
  'class': 'cute-menu-trigger',
1180
1223
  '[attr.aria-haspopup]': 'menu ? "menu" : null',
1181
1224
  '[attr.aria-expanded]': 'menuOpen',
1182
- '[attr.aria-controls]': 'menuOpen ? menu.panelId : null',
1225
+ '[attr.aria-controls]': 'menuOpen ? menu?.panelId : null',
1183
1226
  '(click)': '_handleClick($event)',
1184
1227
  '(mousedown)': '_handleMousedown($event)',
1185
1228
  '(keydown)': '_handleKeydown($event)',
1186
1229
  },
1187
- standalone: true,
1230
+ exportAs: 'cuteMenuTrigger',
1188
1231
  }]
1189
- }], ctorParameters: () => [{ type: i1$1.Overlay }, { type: i0.ElementRef }, { type: i0.ViewContainerRef }, { type: undefined, decorators: [{
1190
- type: Inject,
1191
- args: [CUTE_MENU_SCROLL_STRATEGY]
1192
- }] }, { type: undefined, decorators: [{
1193
- type: Inject,
1194
- args: [CUTE_MENU_PANEL]
1195
- }, {
1196
- type: Optional
1197
- }] }, { type: CuteMenuItem, decorators: [{
1198
- type: Optional
1199
- }, {
1200
- type: Self
1201
- }] }, { type: i3.Directionality, decorators: [{
1202
- type: Optional
1203
- }] }, { type: i4.FocusMonitor }, { type: i0.NgZone }], propDecorators: { menu: [{
1232
+ }], ctorParameters: () => [], propDecorators: { _deprecatedCuteMenuTriggerFor: [{
1233
+ type: Input,
1234
+ args: ['cute-menu-trigger-for']
1235
+ }], menu: [{
1204
1236
  type: Input,
1205
1237
  args: ['cuteMenuTriggerFor']
1206
1238
  }], menuData: [{
@@ -1211,6 +1243,191 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1211
1243
  args: ['cuteMenuTriggerRestoreFocus']
1212
1244
  }], menuOpened: [{
1213
1245
  type: Output
1246
+ }], onMenuOpen: [{
1247
+ type: Output
1248
+ }], menuClosed: [{
1249
+ type: Output
1250
+ }], onMenuClose: [{
1251
+ type: Output
1252
+ }] } });
1253
+
1254
+ /**
1255
+ * @license Apache-2.0
1256
+ *
1257
+ * Copyright (c) 2025 CuteWidgets Team. All Rights Reserved.
1258
+ *
1259
+ * You may not use this file except in compliance with the License
1260
+ * that can be found at http://www.apache.org/licenses/LICENSE-2.0
1261
+ *
1262
+ * This code is a modification of the `@angular/material` original
1263
+ * code licensed under MIT-style License (https://angular.dev/license).
1264
+ */
1265
+ /**
1266
+ * Trigger that opens a menu whenever the user right-clicks within its host element.
1267
+ */
1268
+ class CuteContextMenuTrigger extends CuteMenuTriggerBase {
1269
+ /** References the menu instance that the trigger is associated with. */
1270
+ get menu() {
1271
+ return this._menu;
1272
+ }
1273
+ set menu(menu) {
1274
+ this._menu = menu;
1275
+ }
1276
+ constructor() {
1277
+ super(false);
1278
+ this._point = { x: 0, y: 0, initialX: 0, initialY: 0, initialScrollX: 0, initialScrollY: 0 };
1279
+ this._triggerPressedControl = false;
1280
+ this._document = inject(DOCUMENT);
1281
+ this._viewportRuler = inject(ViewportRuler);
1282
+ this._scrollDispatcher = inject(ScrollDispatcher);
1283
+ /**
1284
+ * Whether focus should be restored when the menu is closed.
1285
+ * Note that disabling this option can have accessibility implications
1286
+ * and it's up to you to manage focus, if you decide to turn it off.
1287
+ */
1288
+ this.restoreFocus = true;
1289
+ /** Whether the context menu is disabled. */
1290
+ this.disabled = false;
1291
+ /** Event emitted when the associated menu is opened. */
1292
+ this.menuOpened = new EventEmitter();
1293
+ /** Event emitted when the associated menu is closed. */
1294
+ this.menuClosed = new EventEmitter();
1295
+ }
1296
+ ngOnDestroy() {
1297
+ super.ngOnDestroy();
1298
+ this._scrollSubscription?.unsubscribe();
1299
+ }
1300
+ /** Handler for `contextmenu` events. */
1301
+ _handleContextMenuEvent(event) {
1302
+ if (!this.disabled) {
1303
+ event.preventDefault();
1304
+ // If the menu is already open, only update its position.
1305
+ if (this.menuOpen) {
1306
+ this._initializePoint(event.clientX, event.clientY);
1307
+ this._updatePosition();
1308
+ }
1309
+ else {
1310
+ this._openContextMenu(event);
1311
+ }
1312
+ }
1313
+ }
1314
+ _destroyMenu(reason) {
1315
+ super._destroyMenu(reason);
1316
+ this._scrollSubscription?.unsubscribe();
1317
+ }
1318
+ _getOverlayOrigin() {
1319
+ return this._point;
1320
+ }
1321
+ _getOutsideClickStream(overlayRef) {
1322
+ return overlayRef.outsidePointerEvents().pipe(skipWhile((event, index) => {
1323
+ if (event.type === 'contextmenu') {
1324
+ // Do not close when attempting to open a context menu within the trigger.
1325
+ return this._isWithinMenuOrTrigger(_getEventTarget(event));
1326
+ }
1327
+ else if (event.type === 'auxclick') {
1328
+ // Skip the first `auxclick` since it happens at
1329
+ // the same time as the event that opens the menu.
1330
+ if (index === 0) {
1331
+ return true;
1332
+ }
1333
+ // Do not close on `auxclick` within the menu since we want to reposition the menu
1334
+ // instead. Note that we have to resolve the clicked element using its position,
1335
+ // rather than `event.target`, because the `target` is set to the `body`.
1336
+ this._rootNode ??= _getShadowRoot(this._element.nativeElement) || this._document;
1337
+ return this._isWithinMenuOrTrigger(this._rootNode.elementFromPoint(event.clientX, event.clientY));
1338
+ }
1339
+ // Using a mouse, the `contextmenu` event can fire either when pressing the right button
1340
+ // or left button + control. Most browsers won't dispatch a `click` event right after
1341
+ // a `contextmenu` event triggered by left button + control, but Safari will (see #27832).
1342
+ // This closes the menu immediately. To work around it, we check that both the triggering
1343
+ // event and the current outside click event both had the control key pressed, and that
1344
+ // that this is the first outside click event.
1345
+ return this._triggerPressedControl && index === 0 && event.ctrlKey;
1346
+ }));
1347
+ }
1348
+ /** Checks whether an element is within the trigger or the opened overlay. */
1349
+ _isWithinMenuOrTrigger(target) {
1350
+ if (!target) {
1351
+ return false;
1352
+ }
1353
+ const element = this._element.nativeElement;
1354
+ if (target === element || element.contains(target)) {
1355
+ return true;
1356
+ }
1357
+ const overlay = this._overlayRef?.hostElement;
1358
+ return overlay === target || !!overlay?.contains(target);
1359
+ }
1360
+ /** Opens the context menu. */
1361
+ _openContextMenu(event) {
1362
+ // A context menu can be triggered via a mouse right click or a keyboard shortcut.
1363
+ if (event.button === 2) {
1364
+ this._openedBy = 'mouse';
1365
+ }
1366
+ else {
1367
+ this._openedBy = event.button === 0 ? 'keyboard' : undefined;
1368
+ }
1369
+ this._initializePoint(event.clientX, event.clientY);
1370
+ this._triggerPressedControl = event.ctrlKey;
1371
+ super._openMenu(true);
1372
+ this._scrollSubscription?.unsubscribe();
1373
+ this._scrollSubscription = this._scrollDispatcher.scrolled(0).subscribe(() => {
1374
+ // When passing a point to the connected position strategy, the position
1375
+ // won't update as the user is scrolling so we have to do it manually.
1376
+ const position = this._viewportRuler.getViewportScrollPosition();
1377
+ const point = this._point;
1378
+ point.y = point.initialY + (point.initialScrollY - position.top);
1379
+ point.x = point.initialX + (point.initialScrollX - position.left);
1380
+ this._updatePosition();
1381
+ });
1382
+ }
1383
+ /** Initializes the point representing the origin relative to which the menu will be rendered. */
1384
+ _initializePoint(x, y) {
1385
+ const scrollPosition = this._viewportRuler.getViewportScrollPosition();
1386
+ const point = this._point;
1387
+ point.x = point.initialX = x;
1388
+ point.y = point.initialY = y;
1389
+ point.initialScrollX = scrollPosition.left;
1390
+ point.initialScrollY = scrollPosition.top;
1391
+ }
1392
+ /** Refreshes the position of the overlay. */
1393
+ _updatePosition() {
1394
+ const overlayRef = this._overlayRef;
1395
+ if (overlayRef) {
1396
+ const positionStrategy = overlayRef.getConfig()
1397
+ .positionStrategy;
1398
+ positionStrategy.setOrigin(this._point);
1399
+ overlayRef.updatePosition();
1400
+ }
1401
+ }
1402
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteContextMenuTrigger, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
1403
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "16.1.0", version: "21.2.0", type: CuteContextMenuTrigger, isStandalone: true, selector: "[cuteContextMenuTriggerFor]", inputs: { menu: ["cuteContextMenuTriggerFor", "menu"], menuData: ["cuteContextMenuTriggerData", "menuData"], restoreFocus: ["cuteContextMenuTriggerRestoreFocus", "restoreFocus"], disabled: ["cuteContextMenuTriggerDisabled", "disabled", booleanAttribute] }, outputs: { menuOpened: "menuOpened", menuClosed: "menuClosed" }, host: { listeners: { "contextmenu": "_handleContextMenuEvent($event)" }, properties: { "class.cute-context-menu-trigger-disabled": "disabled", "attr.aria-controls": "menuOpen ? menu?.panelId : null" }, classAttribute: "cute-context-menu-trigger" }, exportAs: ["cuteContextMenuTrigger"], usesInheritance: true, ngImport: i0 }); }
1404
+ }
1405
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteContextMenuTrigger, decorators: [{
1406
+ type: Directive,
1407
+ args: [{
1408
+ selector: '[cuteContextMenuTriggerFor]',
1409
+ host: {
1410
+ 'class': 'cute-context-menu-trigger',
1411
+ '[class.cute-context-menu-trigger-disabled]': 'disabled',
1412
+ '[attr.aria-controls]': 'menuOpen ? menu?.panelId : null',
1413
+ '(contextmenu)': '_handleContextMenuEvent($event)',
1414
+ },
1415
+ exportAs: 'cuteContextMenuTrigger',
1416
+ }]
1417
+ }], ctorParameters: () => [], propDecorators: { menu: [{
1418
+ type: Input,
1419
+ args: [{ alias: 'cuteContextMenuTriggerFor', required: true }]
1420
+ }], menuData: [{
1421
+ type: Input,
1422
+ args: ['cuteContextMenuTriggerData']
1423
+ }], restoreFocus: [{
1424
+ type: Input,
1425
+ args: ['cuteContextMenuTriggerRestoreFocus']
1426
+ }], disabled: [{
1427
+ type: Input,
1428
+ args: [{ alias: 'cuteContextMenuTriggerDisabled', transform: booleanAttribute }]
1429
+ }], menuOpened: [{
1430
+ type: Output
1214
1431
  }], menuClosed: [{
1215
1432
  type: Output
1216
1433
  }] } });
@@ -1224,32 +1441,30 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1224
1441
  * that can be found at http://www.apache.org/licenses/LICENSE-2.0
1225
1442
  */
1226
1443
  const TYPES = [
1227
- CommonModule,
1228
1444
  CuteMenu,
1229
1445
  CuteMenuItem,
1230
1446
  CuteMenuContent,
1231
1447
  CuteMenuTrigger,
1448
+ CuteContextMenuTrigger,
1232
1449
  ];
1233
1450
  class CuteMenuModule {
1234
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1235
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuModule, imports: [CommonModule, CommonModule,
1236
- CuteMenu,
1451
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
1452
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuModule, imports: [OverlayModule, CuteMenu,
1237
1453
  CuteMenuItem,
1238
1454
  CuteMenuContent,
1239
- CuteMenuTrigger], exports: [CommonModule,
1240
- CuteMenu,
1455
+ CuteMenuTrigger,
1456
+ CuteContextMenuTrigger], exports: [CdkScrollableModule, CuteMenu,
1241
1457
  CuteMenuItem,
1242
1458
  CuteMenuContent,
1243
- CuteMenuTrigger] }); }
1244
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuModule, providers: [CUTE_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER], imports: [CommonModule, CommonModule, CommonModule] }); }
1459
+ CuteMenuTrigger,
1460
+ CuteContextMenuTrigger] }); }
1461
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuModule, imports: [OverlayModule, CdkScrollableModule] }); }
1245
1462
  }
1246
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImport: i0, type: CuteMenuModule, decorators: [{
1463
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.0", ngImport: i0, type: CuteMenuModule, decorators: [{
1247
1464
  type: NgModule,
1248
1465
  args: [{
1249
- imports: [CommonModule, ...TYPES],
1250
- exports: TYPES,
1251
- declarations: [],
1252
- providers: [CUTE_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER],
1466
+ imports: [OverlayModule, ...TYPES],
1467
+ exports: [CdkScrollableModule, ...TYPES],
1253
1468
  }]
1254
1469
  }] });
1255
1470
 
@@ -1257,5 +1472,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.15", ngImpo
1257
1472
  * Generated bundle index. Do not edit.
1258
1473
  */
1259
1474
 
1260
- export { CUTE_MENU_CONTENT, CUTE_MENU_DEFAULT_OPTIONS, CUTE_MENU_DEFAULT_OPTIONS_FACTORY, CUTE_MENU_SCROLL_STRATEGY, CUTE_MENU_SCROLL_STRATEGY_FACTORY, CUTE_MENU_SCROLL_STRATEGY_FACTORY_PROVIDER, CuteMenu, CuteMenuContent, CuteMenuItem, CuteMenuModule, CuteMenuTrigger };
1475
+ export { CUTE_MENU_CONTENT, CUTE_MENU_DEFAULT_OPTIONS, CUTE_MENU_PANEL, CUTE_MENU_SCROLL_STRATEGY, CuteContextMenuTrigger, CuteMenu, CuteMenuContent, CuteMenuItem, CuteMenuModule, CuteMenuTrigger, MENU_PANEL_TOP_PADDING };
1261
1476
  //# sourceMappingURL=cute-widgets-base-menu.mjs.map