@acorex/components 18.10.16 → 18.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. package/action-sheet/lib/action-sheet.class.d.ts +8 -0
  2. package/common/index.d.ts +1 -0
  3. package/common/lib/types/base/component.types.d.ts +8 -0
  4. package/common/lib/types/base/events.types.d.ts +21 -0
  5. package/common/lib/types/base/index.d.ts +2 -0
  6. package/esm2022/action-sheet/lib/action-sheet.class.mjs +1 -1
  7. package/esm2022/action-sheet/lib/action-sheet.component.mjs +3 -3
  8. package/esm2022/common/index.mjs +2 -1
  9. package/esm2022/common/lib/classes/events.class.mjs +1 -1
  10. package/esm2022/common/lib/components/base-component.class.mjs +1 -1
  11. package/esm2022/common/lib/types/base/component.types.mjs +27 -0
  12. package/esm2022/common/lib/types/base/events.types.mjs +19 -0
  13. package/esm2022/common/lib/types/base/index.mjs +3 -0
  14. package/esm2022/menu/index.mjs +4 -4
  15. package/esm2022/menu/lib/context-menu.component.mjs +232 -0
  16. package/esm2022/menu/lib/menu-item.component.mjs +310 -0
  17. package/esm2022/menu/lib/menu.component.mjs +27 -33
  18. package/esm2022/menu/lib/menu.module.mjs +7 -7
  19. package/esm2022/menu/lib/menu.service.mjs +10 -8
  20. package/esm2022/menu/lib/menu.types.mjs +14 -0
  21. package/fesm2022/acorex-components-action-sheet.mjs +2 -2
  22. package/fesm2022/acorex-components-action-sheet.mjs.map +1 -1
  23. package/fesm2022/acorex-components-common.mjs +47 -3
  24. package/fesm2022/acorex-components-common.mjs.map +1 -1
  25. package/fesm2022/acorex-components-menu.mjs +536 -161
  26. package/fesm2022/acorex-components-menu.mjs.map +1 -1
  27. package/menu/index.d.ts +3 -3
  28. package/menu/lib/context-menu.component.d.ts +52 -0
  29. package/menu/lib/menu-item.component.d.ts +60 -0
  30. package/menu/lib/menu.component.d.ts +10 -11
  31. package/menu/lib/menu.module.d.ts +9 -9
  32. package/menu/lib/menu.service.d.ts +14 -3
  33. package/menu/lib/menu.types.d.ts +38 -0
  34. package/package.json +43 -43
  35. package/esm2022/menu/lib/class/popover.class.mjs +0 -2
  36. package/esm2022/menu/lib/class/root-menu.class.mjs +0 -8
  37. package/esm2022/menu/lib/menu-item/menu-item.component.mjs +0 -160
  38. package/menu/lib/class/popover.class.d.ts +0 -2
  39. package/menu/lib/class/root-menu.class.d.ts +0 -7
  40. package/menu/lib/menu-item/menu-item.component.d.ts +0 -81
@@ -1,254 +1,629 @@
1
+ import { NXClickEvent, NXComponent, NXEvent } from '@acorex/components/common';
1
2
  import * as i0 from '@angular/core';
2
- import { signal, Injectable, inject, input, output, afterNextRender, Component, ViewEncapsulation, ViewChild, ContentChildren, HostBinding, HostListener, NgModule } from '@angular/core';
3
- import { MXInteractiveComponent, MXBaseComponent } from '@acorex/components/common';
4
- import * as i1 from '@acorex/components/popover';
5
- import { AXPopoverComponent, AXPopoverModule } from '@acorex/components/popover';
6
- import { BehaviorSubject } from 'rxjs';
7
- import { AXButtonModule } from '@acorex/components/button';
3
+ import { Injectable, signal, inject, Renderer2, computed, output, input, afterNextRender, Component, ViewEncapsulation, ChangeDetectionStrategy, HostListener, HostBinding, NgModule } from '@angular/core';
4
+ import { Subject } from 'rxjs';
5
+ import { AXUnsubscriber, AXHtmlUtil } from '@acorex/core/utils';
6
+ import { cloneDeep } from 'lodash-es';
7
+ import { isBrowser } from '@acorex/core/platform';
8
+ import * as i1 from '@angular/common';
9
+ import { CommonModule } from '@angular/common';
10
+ import * as i2 from '@acorex/components/decorators';
8
11
  import { AXDecoratorModule } from '@acorex/components/decorators';
9
12
  import { AXLoadingModule } from '@acorex/components/loading';
13
+ import { AXPopoverModule } from '@acorex/components/popover';
10
14
  import { AXTranslationModule } from '@acorex/core/translation';
11
15
  import { OverlayModule } from '@angular/cdk/overlay';
12
- import { CommonModule } from '@angular/common';
13
16
 
14
17
  class AXRootMenu {
18
+ }
19
+ class AXMenuItemComponentBase {
20
+ }
21
+ class AXMenuItem {
22
+ }
23
+ class AXMenuItemClickBaseEvent extends NXClickEvent {
15
24
  constructor() {
16
- this.orientation = signal('horizontal');
17
- this.openOn = signal('toggle');
25
+ super(...arguments);
26
+ this.canceled = false;
18
27
  }
19
28
  }
20
29
 
21
30
  class AXMenuService {
22
31
  constructor() {
23
- this.activeMenus$ = new BehaviorSubject([]);
32
+ this.closeAll$ = new Subject();
33
+ this.open$ = new Subject();
34
+ this.close$ = new Subject();
35
+ this.closeExcept$ = new Subject();
36
+ this.openContextMenu$ = new Subject();
37
+ this.closeAllContextMenu$ = new Subject();
24
38
  }
25
39
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
26
- static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuService, providedIn: 'root' }); }
40
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuService }); }
27
41
  }
28
42
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuService, decorators: [{
29
- type: Injectable,
30
- args: [{
31
- providedIn: 'root',
32
- }]
43
+ type: Injectable
33
44
  }] });
34
45
 
35
46
  /**
36
47
  * Represents a menu item component used within an `ax-menu`.
37
48
  * @category Components
38
49
  */
39
- class AXMenuItemComponent extends MXInteractiveComponent {
40
- /** @ignore */
50
+ class AXMenuItemComponent extends NXComponent {
41
51
  constructor() {
42
52
  super();
53
+ this.isOpen = signal(false);
54
+ this.hasSubItems = signal(false);
55
+ this.isFirstLevel = signal(false);
56
+ this.root = inject(AXRootMenu);
43
57
  this.service = inject(AXMenuService);
44
- /**
45
- * Injects the `AXMenuService` for managing menu interactions.
46
- */
47
- this.menuService = inject(AXMenuService);
48
- /**
49
- * The vertical offset for positioning, initialized to 0.
50
- */
51
- this.offsetY = signal(0);
52
- /**
53
- * The horizontal offset for positioning, initialized to 0.
54
- */
55
- this.offsetX = signal(0);
56
- /**
57
- * The text content, initialized to an empty string.
58
- */
59
- // text = input<string>();
60
- /**
61
- * Indicates whether the item is active.
62
- */
63
- this.active = input();
64
- /**
65
- * Emitted when the active state changes.
66
- */
67
- this.activeChange = output();
68
- /**
69
- * Emitted when the element is clicked.
70
- */
58
+ this.scrollableParents = [];
59
+ this.unsuscriber = inject(AXUnsubscriber);
60
+ this.renderer = inject(Renderer2);
61
+ this.arrowIcon = computed(() => {
62
+ const isRtl = AXHtmlUtil.isRtl(this.nativeElement);
63
+ return this.root.orientation() == 'horizontal' && this.isFirstLevel() ?
64
+ "ax-icon-chevron-down" :
65
+ isRtl ? "ax-icon-chevron-left" : "ax-icon-chevron-right";
66
+ });
71
67
  this.onClick = output();
72
- /**
73
- * Indicates whether the component is a root menu item.
74
- * @defaultValue false
75
- */
76
- this.isRoot = false;
77
- /**
78
- * Injects the root menu service.
79
- */
80
- this.rootMenu = inject(AXRootMenu);
81
- this.arrowState = input(true);
68
+ this.name = input();
69
+ this.data = input();
70
+ this.disabled = input();
71
+ this.color = input();
72
+ //
82
73
  afterNextRender(() => {
83
- this.children.forEach((c) => {
84
- c.parent = this;
85
- });
86
- this.offsetY.set(this.isRoot ? 8 : 0);
87
- this.offsetX.set(this.isRoot ? 0 : 4);
88
- this.getPlacement();
74
+ this.detectSubItems();
75
+ this.observeMutations();
76
+ this.bindScrollEvents();
77
+ });
78
+ //
79
+ this.service.closeAll$
80
+ .pipe(this.unsuscriber.takeUntilDestroy)
81
+ .subscribe(() => this.close());
82
+ this.service.open$
83
+ .pipe(this.unsuscriber.takeUntilDestroy)
84
+ .subscribe((item) => {
85
+ if (this === item) {
86
+ this.isOpen.set(true);
87
+ this.calculatePosition();
88
+ }
89
+ });
90
+ //
91
+ this.service.close$
92
+ .pipe(this.unsuscriber.takeUntilDestroy)
93
+ .subscribe(item => {
94
+ if (this == item) {
95
+ this.isOpen.set(false);
96
+ }
97
+ });
98
+ //
99
+ this.service.closeExcept$
100
+ .pipe(this.unsuscriber.takeUntilDestroy)
101
+ .subscribe((item) => {
102
+ this.closeExcept(item);
89
103
  });
90
104
  }
105
+ closeExcept(item) {
106
+ const list = [item];
107
+ //
108
+ let parent = item.parent;
109
+ while (parent != null) {
110
+ list.push(parent);
111
+ parent = parent.parent;
112
+ }
113
+ //
114
+ if (!list.includes(this)) {
115
+ this.close();
116
+ }
117
+ }
118
+ observeMutations() {
119
+ this.mutationObserver = new MutationObserver(() => {
120
+ this.detectSubItems();
121
+ });
122
+ // Start observing changes in child elements
123
+ this.mutationObserver.observe(this.nativeElement, {
124
+ childList: true,
125
+ subtree: true,
126
+ });
127
+ }
128
+ getText() {
129
+ return this.nativeElement.querySelector('ax-text')?.innerText;
130
+ }
91
131
  /**
92
- * Closes the popover if it is open.
93
- */
132
+ * Manually detect all `ax-menu-item` elements and check if this menu item has sub-items.
133
+ */
134
+ detectSubItems() {
135
+ //
136
+ const parentEl = this.nativeElement.parentElement?.parentElement;
137
+ this.parent = parentEl?.tagName == "AX-MENU-ITEM" ? parentEl?.["__axContext__"] : null;
138
+ //
139
+ const tag = this.nativeElement.parentElement?.tagName;
140
+ this.isFirstLevel.set(tag == "AX-MENU" || tag == "AX-CONTEXT-MENU");
141
+ const subItems = this.nativeElement.querySelectorAll('ax-menu-item');
142
+ if (subItems.length > 0) {
143
+ this.hasSubItems.set(true);
144
+ }
145
+ else {
146
+ this.hasSubItems.set(false);
147
+ }
148
+ }
149
+ open() {
150
+ this.service.closeExcept$.next(this);
151
+ if (!this.disabled() && this.hasSubItems()) {
152
+ this.service.open$.next(this);
153
+ }
154
+ }
94
155
  close() {
95
- this.popover?.close();
156
+ this.service.close$.next(this);
157
+ }
158
+ /**
159
+ * Calculate the position of the submenu to avoid it going out of the viewport.
160
+ */
161
+ calculatePosition() {
162
+ const submenu = this.nativeElement.querySelector('.ax-menu-items');
163
+ if (!submenu)
164
+ return;
165
+ const submenuRect = submenu.getBoundingClientRect();
166
+ const itemRect = this.nativeElement.getBoundingClientRect();
167
+ const windowWidth = window.innerWidth;
168
+ const windowHeight = window.innerHeight;
169
+ const isRtl = AXHtmlUtil.isRtl(this.nativeElement);
170
+ let top = null;
171
+ let left = null;
172
+ // For first-level menu items
173
+ if (this.isFirstLevel() && this.root.orientation() === 'horizontal') {
174
+ top = itemRect.bottom + submenuRect.height > windowHeight
175
+ ? itemRect.top - submenuRect.height // Open upwards
176
+ : itemRect.bottom; // Open downwards
177
+ if (isRtl) {
178
+ // RTL: Align to the right of the parent item
179
+ left = itemRect.right - submenuRect.width < 0
180
+ ? itemRect.left // Align to the left if not enough space on the right
181
+ : itemRect.right - submenuRect.width; // Open to the left in RTL
182
+ }
183
+ else {
184
+ // LTR: Align to the left of the parent item
185
+ left = itemRect.left + submenuRect.width > windowWidth
186
+ ? itemRect.right - submenuRect.width // Align to the right edge in LTR
187
+ : itemRect.left; // Open to the left
188
+ }
189
+ }
190
+ else {
191
+ // For nested submenus
192
+ if (isRtl) {
193
+ // RTL: Nested submenu opens to the left
194
+ left = itemRect.left - submenuRect.width < 0
195
+ ? itemRect.right // Align to the right if not enough space on the left
196
+ : itemRect.left - submenuRect.width; // Open to the left in RTL
197
+ }
198
+ else {
199
+ // LTR: Nested submenu opens to the right
200
+ left = itemRect.right + submenuRect.width > windowWidth
201
+ ? itemRect.left - submenuRect.width // Open to the left if not enough space
202
+ : itemRect.right; // Open to the right in LTR
203
+ }
204
+ // Adjust top position (align vertically with parent)
205
+ top = itemRect.top + submenuRect.height > windowHeight
206
+ ? itemRect.top - (itemRect.bottom + submenuRect.height - windowHeight) // Adjust upwards
207
+ : itemRect.top; // Align with the parent item
208
+ }
209
+ // Apply calculated styles for RTL/LTR
210
+ this.renderer.setStyle(submenu, 'left', `${left}px`);
211
+ this.renderer.setStyle(submenu, 'top', `${top}px`);
212
+ this.renderer.setStyle(submenu, 'position', 'fixed'); // Fixed position relative to the viewport
213
+ }
214
+ handleClick(e) {
215
+ e.stopPropagation();
216
+ if (this.disabled())
217
+ return;
218
+ //
219
+ const event = {
220
+ sender: this,
221
+ nativeEvent: e,
222
+ canceled: false,
223
+ item: {
224
+ name: this.name(),
225
+ text: this.getText(),
226
+ data: this.data()
227
+ }
228
+ };
229
+ //
230
+ this.onClick.emit(event);
231
+ this.root.onItemClick.emit({ ...event, ...{ sender: this.root } });
232
+ //
233
+ if (this.hasSubItems() && !event.canceled) {
234
+ this.open();
235
+ }
236
+ else if (!event.canceled) {
237
+ this.service.closeAll$.next();
238
+ this.service.closeAllContextMenu$.next({ sender: this.root });
239
+ }
240
+ }
241
+ handleMouseEnter(event) {
242
+ event.stopPropagation();
243
+ // Cancel the close delay if the mouse re-enters the element
244
+ if (this.mouseLeaveTimeout) {
245
+ clearTimeout(this.mouseLeaveTimeout);
246
+ this.mouseLeaveTimeout = null; // Reset the timeout
247
+ }
248
+ if (!this.isFirstLevel() || this.root.openOn() == 'hover') {
249
+ this.open();
250
+ }
251
+ }
252
+ handleMouseLeave(event) {
253
+ event.stopPropagation();
254
+ if (this.hasSubItems() && this.root.closeOn() === 'leave') {
255
+ // Clear any previous timeout to avoid multiple triggers
256
+ if (this.mouseLeaveTimeout) {
257
+ clearTimeout(this.mouseLeaveTimeout);
258
+ }
259
+ // Set a delay before closing the submenu
260
+ this.mouseLeaveTimeout = setTimeout(() => {
261
+ this.close();
262
+ }, 500); // Adjust the delay (500ms in this case) as per your requirement
263
+ }
264
+ }
265
+ onWindowEvent() {
266
+ this.service.closeAll$.next(); // Close all menus on scroll or resize
267
+ }
268
+ /**
269
+ * Close all menus if clicking outside the root menu and all sub-items.
270
+ */
271
+ onClickOutside(event) {
272
+ const hostElement = this.root.nativeElement;
273
+ if (!hostElement.contains(event.target)) {
274
+ this.service.closeAll$.next(); // Close all menus if click is outside the root and sub-items
275
+ }
276
+ }
277
+ ngOnDestroy() {
278
+ this.removeScrollEvents();
279
+ }
280
+ bindScrollEvents() {
281
+ this.scrollableParents = AXHtmlUtil.getScrollableParents(this.nativeElement);
282
+ this.scrollableParents.forEach((parent) => {
283
+ parent.addEventListener('scroll', this.onContainerScroll.bind(this));
284
+ });
285
+ }
286
+ // Remove scroll event listeners
287
+ removeScrollEvents() {
288
+ this.scrollableParents.forEach((parent) => {
289
+ parent.removeEventListener('scroll', this.onContainerScroll.bind(this));
290
+ });
291
+ }
292
+ /**
293
+ * Handler for scroll events (window or scrollable parent containers)
294
+ */
295
+ onContainerScroll() {
296
+ this.service.closeAll$.next(); // Close all menus on scroll
297
+ }
298
+ /** @ignore */
299
+ get __hostClass() {
300
+ const list = ['ax-el-interactive', 'ax-action-item'];
301
+ if (this.disabled()) {
302
+ list.push('ax-state-disabled');
303
+ }
304
+ if (this.color()) {
305
+ list.push(`ax-el-${this.color()}-blank`);
306
+ }
307
+ return list;
308
+ }
309
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
310
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.0", type: AXMenuItemComponent, selector: "ax-menu-item", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: true, isRequired: false, transformFunction: null }, color: { classPropertyName: "color", publicName: "color", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onClick: "onClick" }, host: { listeners: { "click": "handleClick($event)", "mouseenter": "handleMouseEnter($event)", "mouseleave": "handleMouseLeave($event)", "window:scroll": "onWindowEvent($event)", "window:resize": "onWindowEvent($event)", "document:click": "onClickOutside($event)" }, properties: { "class": "this.__hostClass" } }, providers: [
311
+ {
312
+ provide: AXMenuItemComponentBase,
313
+ useExisting: AXMenuItemComponent
314
+ },
315
+ AXUnsubscriber
316
+ ], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-action-item-prefix\">\n <ng-content select=\"ax-prefix\"></ng-content>\n <ng-content select=\"ax-text\"></ng-content>\n</div>\n<div class=\"ax-action-item-suffix\">\n <ng-content select=\"ax-suffix\"></ng-content>\n @if (hasSubItems()) {\n <i class=\"ax-icon ax-icon-solid {{ arrowIcon() }} ax-menu-item-child-icon\"></i>\n }\n</div>\n<div class=\"ax-menu-items ax-action-list ax-action-list-vertical\" [class.ax-state-open]=\"isOpen()\">\n <ng-content select=\"ax-menu-item,ax-title,ng-container\"></ng-content>\n</div>", changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
317
+ }
318
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuItemComponent, decorators: [{
319
+ type: Component,
320
+ args: [{ selector: 'ax-menu-item', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
321
+ {
322
+ provide: AXMenuItemComponentBase,
323
+ useExisting: AXMenuItemComponent
324
+ },
325
+ AXUnsubscriber
326
+ ], template: "<div class=\"ax-action-item-prefix\">\n <ng-content select=\"ax-prefix\"></ng-content>\n <ng-content select=\"ax-text\"></ng-content>\n</div>\n<div class=\"ax-action-item-suffix\">\n <ng-content select=\"ax-suffix\"></ng-content>\n @if (hasSubItems()) {\n <i class=\"ax-icon ax-icon-solid {{ arrowIcon() }} ax-menu-item-child-icon\"></i>\n }\n</div>\n<div class=\"ax-menu-items ax-action-list ax-action-list-vertical\" [class.ax-state-open]=\"isOpen()\">\n <ng-content select=\"ax-menu-item,ax-title,ng-container\"></ng-content>\n</div>" }]
327
+ }], ctorParameters: () => [], propDecorators: { handleClick: [{
328
+ type: HostListener,
329
+ args: ["click", ['$event']]
330
+ }], handleMouseEnter: [{
331
+ type: HostListener,
332
+ args: ["mouseenter", ['$event']]
333
+ }], handleMouseLeave: [{
334
+ type: HostListener,
335
+ args: ["mouseleave", ['$event']]
336
+ }], onWindowEvent: [{
337
+ type: HostListener,
338
+ args: ['window:scroll', ['$event']]
339
+ }, {
340
+ type: HostListener,
341
+ args: ['window:resize', ['$event']]
342
+ }], onClickOutside: [{
343
+ type: HostListener,
344
+ args: ['document:click', ['$event']]
345
+ }], __hostClass: [{
346
+ type: HostBinding,
347
+ args: ['class']
348
+ }] } });
349
+
350
+ class AXContextMenuOpeningEvent extends NXEvent {
351
+ constructor() {
352
+ super(...arguments);
353
+ this.canceled = false;
96
354
  }
355
+ }
356
+ /**
357
+ * Represents a menu component that displays context menu.
358
+ * @category Components
359
+ */
360
+ class AXContextMenuComponent extends NXComponent {
361
+ // Constructor (Dependency Injection)
97
362
  /** @ignore */
98
- _handleOnOpened() {
99
- this.parent.children.forEach((c) => {
100
- if (c != this) {
101
- c.close();
363
+ constructor() {
364
+ super();
365
+ // Inputs and Outputs
366
+ this.orientation = input('vertical');
367
+ this.openOn = input('hover');
368
+ this.closeOn = input('click');
369
+ this.orginalItems = input([], { alias: "items" });
370
+ this.target = input();
371
+ this.onItemClick = output();
372
+ this.onOpening = output();
373
+ // Injected Services
374
+ this.service = inject(AXMenuService);
375
+ this.renderer = inject(Renderer2);
376
+ this.items = signal([]);
377
+ //
378
+ afterNextRender(() => {
379
+ this.bindContextEvent();
380
+ });
381
+ this.service.closeAllContextMenu$.subscribe(() => {
382
+ this.service.closeAll$.next();
383
+ this.close();
384
+ });
385
+ this.service.openContextMenu$.subscribe((e) => {
386
+ if (e.sender == this) {
387
+ this.internalShowAt(e.point);
102
388
  }
103
389
  });
104
- if (this.children.length) {
105
- this.menuService.activeMenus$.next(this.menuService.activeMenus$.getValue().concat(this));
390
+ }
391
+ // Lifecycle Hooks
392
+ ngOnDestroy() {
393
+ if (isBrowser()) {
394
+ this.removeContextEvent();
106
395
  }
107
396
  }
397
+ // Public Methods
398
+ showAt(point) {
399
+ const sender = this;
400
+ this.service.closeAllContextMenu$.next({ sender });
401
+ this.service.openContextMenu$.next({ sender, point });
402
+ }
403
+ close() {
404
+ this.nativeElement.classList.remove('ax-state-open');
405
+ this.removeBackdrop();
406
+ }
407
+ // Private Methods (Internal Logic)
108
408
  /** @ignore */
109
- _handleOnClosed() {
110
- this.children.forEach((c) => {
111
- c.close();
409
+ getTargetElements() {
410
+ const elements = typeof this.target() == 'string' ?
411
+ Array.from(document.querySelectorAll(this.target())) :
412
+ Array.isArray(this.target()) ?
413
+ this.target() :
414
+ [this.target()];
415
+ return elements;
416
+ }
417
+ /** @ignore */
418
+ bindContextEvent() {
419
+ this.getTargetElements().forEach((e) => {
420
+ e.addEventListener('contextmenu', this.handleContextMenu.bind(this));
112
421
  });
113
422
  }
114
- /**
115
- * Returns the icon based on the orientation of the root menu.
116
- */
117
- getIcon() {
118
- if (this.rootMenu.orientation() === 'vertical') {
119
- return 'ax-icon-chevron-right';
423
+ /** @ignore */
424
+ removeContextEvent() {
425
+ this.getTargetElements().forEach((e) => {
426
+ e.removeEventListener('contextmenu', this.handleContextMenu.bind(this));
427
+ });
428
+ }
429
+ /** @ignore */
430
+ handleContextMenu(e) {
431
+ e.preventDefault();
432
+ e.stopPropagation();
433
+ //
434
+ const elementsUnderMouse = document.elementsFromPoint(e.x, e.y);
435
+ const targetElements = this.getTargetElements();
436
+ const targetElement = targetElements.find(target => elementsUnderMouse.includes(target));
437
+ //
438
+ const event = {
439
+ sender: this,
440
+ canceled: false,
441
+ targetElement: targetElement,
442
+ items: cloneDeep(this.orginalItems()),
443
+ };
444
+ this.onOpening.emit(event);
445
+ this.items.set(event.items);
446
+ //
447
+ if (!event.canceled) {
448
+ this.showAt({ x: e.clientX, y: e.clientY });
449
+ }
450
+ }
451
+ /** @ignore */
452
+ internalShowAt(point) {
453
+ const elementRef = this.nativeElement;
454
+ elementRef.classList.add('ax-state-open');
455
+ const itemRect = elementRef.getBoundingClientRect();
456
+ const windowWidth = window.innerWidth;
457
+ const windowHeight = window.innerHeight;
458
+ // Detect RTL (Right-To-Left) mode
459
+ const isRtl = AXHtmlUtil.isRtl(elementRef);
460
+ let left;
461
+ if (isRtl) {
462
+ left = point.x - itemRect.width;
463
+ if (left < 0) {
464
+ left = point.x;
465
+ }
120
466
  }
121
467
  else {
122
- return 'ax-icon-chevron-down';
468
+ left = point.x;
469
+ if (left + itemRect.width > windowWidth) {
470
+ left = point.x - itemRect.width;
471
+ }
123
472
  }
124
- }
125
- /**
126
- * Determines the placement based on the root menu's orientation: 'bottom-start' for horizontal root, 'end-top' otherwise.
127
- */
128
- getPlacement() {
129
- switch (this.rootMenu.orientation()) {
130
- case 'horizontal':
131
- if (this.isRoot) {
132
- return 'bottom-start';
133
- }
134
- else {
135
- return 'end-top';
136
- }
137
- break;
138
- case 'vertical':
139
- if (this.isRoot) {
140
- return 'end-top';
141
- }
142
- else {
143
- return 'end-top';
144
- }
145
- break;
146
- default:
147
- return 'bottom-start';
473
+ const bottom = point.y + itemRect.height;
474
+ let top;
475
+ if (bottom > windowHeight) {
476
+ top = point.y - itemRect.height;
477
+ if (top < 0) {
478
+ top = 0;
479
+ }
480
+ }
481
+ else {
482
+ top = point.y;
148
483
  }
484
+ this.renderer.setStyle(elementRef, 'left', `${left}px`);
485
+ this.renderer.setStyle(elementRef, 'top', `${top}px`);
486
+ this.renderer.setStyle(elementRef, 'position', 'fixed');
487
+ this.createBackdrop();
149
488
  }
150
489
  /** @ignore */
151
- get __hostClass() {
152
- return [`${this.disabled ? 'ax-state-disabled' : ''}`, `${this.active() ? 'ax-state-active' : ''}`];
490
+ createBackdrop() {
491
+ this.backdropElement = this.renderer.createElement('div');
492
+ this.renderer.setStyle(this.backdropElement, 'position', 'fixed');
493
+ this.renderer.setStyle(this.backdropElement, 'top', '0');
494
+ this.renderer.setStyle(this.backdropElement, 'left', '0');
495
+ this.renderer.setStyle(this.backdropElement, 'width', '100%');
496
+ this.renderer.setStyle(this.backdropElement, 'height', '100%');
497
+ this.renderer.setStyle(this.backdropElement, 'z-index', '999'); // Ensure it's below the context menu
498
+ this.renderer.setStyle(this.backdropElement, 'background', 'transparent');
499
+ const l1 = this.renderer.listen(this.backdropElement, 'click', () => {
500
+ this.close();
501
+ l1();
502
+ });
503
+ const l2 = this.renderer.listen(this.backdropElement, 'wheel', () => {
504
+ this.close();
505
+ l2();
506
+ });
507
+ const l3 = this.renderer.listen(this.backdropElement, 'contextmenu', (e) => {
508
+ this.close();
509
+ // Get all elements under the mouse pointer
510
+ const elementsUnderMouse = document.elementsFromPoint(e.x, e.y);
511
+ const targetElements = this.getTargetElements();
512
+ if (targetElements.some(target => elementsUnderMouse.includes(target))) {
513
+ e.preventDefault();
514
+ setTimeout(() => {
515
+ //this.internalShowAt({ x: e.x, y: e.y });
516
+ this.handleContextMenu(e);
517
+ });
518
+ }
519
+ l3();
520
+ });
521
+ document.body.appendChild(this.backdropElement);
153
522
  }
154
523
  /** @ignore */
155
- __hostClick(e) {
156
- if (!this.disabled) {
157
- this.onClick.emit({
158
- component: this,
159
- htmlElement: this.getHostElement(),
160
- nativeEvent: e,
161
- });
162
- if (!this.children.length) {
163
- this.menuService.activeMenus$.subscribe((c) => c.forEach((x) => x.close())).unsubscribe();
164
- this.menuService.activeMenus$.next([]);
524
+ removeBackdrop() {
525
+ if (this.backdropElement) {
526
+ if (this.backdropElement.parentNode) {
527
+ this.backdropElement.parentNode.removeChild(this.backdropElement);
165
528
  }
529
+ this.backdropElement = null;
166
530
  }
167
531
  }
168
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuItemComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
169
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.0", type: AXMenuItemComponent, selector: "ax-menu-item", inputs: { disabled: { classPropertyName: "disabled", publicName: "disabled", isSignal: false, isRequired: false, transformFunction: null }, active: { classPropertyName: "active", publicName: "active", isSignal: true, isRequired: false, transformFunction: null }, arrowState: { classPropertyName: "arrowState", publicName: "arrowState", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { activeChange: "activeChange", onClick: "onClick" }, host: { attributes: { "ngSkipHydration": "true" }, listeners: { "click": "__hostClick($event)" }, properties: { "class": "this.__hostClass" } }, queries: [{ propertyName: "children", predicate: AXMenuItemComponent }], viewQueries: [{ propertyName: "popover", first: true, predicate: AXPopoverComponent, descendants: true }], usesInheritance: true, ngImport: i0, template: "<div class=\"ax-menu-item-start-side\">\n <ng-content select=\"ax-prefix\"></ng-content>\n <ng-content select=\"ax-text\"></ng-content>\n <ng-content></ng-content>\n</div>\n<ng-content select=\"ax-suffix\"></ng-content>\n@if (children.length && arrowState()) {\n <i class=\"ax-icon ax-icon-solid {{ getIcon() }} ax-menu-item-child-icon\"></i>\n}\n\n<ax-popover\n #popover\n [closeOn]=\"'clickOut'\"\n [openOn]=\"rootMenu.openOn()\"\n [target]=\"getHostElement()\"\n [offsetY]=\"offsetY()\"\n [offsetX]=\"offsetX()\"\n [placement]=\"getPlacement()\"\n (onOpened)=\"_handleOnOpened()\"\n (onClosed)=\"_handleOnClosed()\"\n>\n <div class=\"ax-menu-item-children ax-parent-{{ this.rootMenu.orientation() }}\">\n <ng-content select=\"ax-menu-item\"></ng-content>\n </div>\n</ax-popover>\n", dependencies: [{ kind: "component", type: i1.AXPopoverComponent, selector: "ax-popover", inputs: ["offsetX", "offsetY", "target", "placement", "content", "openOn", "closeOn", "hasBackdrop", "openAfter", "closeAfter", "backdropClass", "adaptivityEnabled"], outputs: ["onOpened", "onClosed"] }], encapsulation: i0.ViewEncapsulation.None }); }
532
+ // Host Listeners (UI Interaction Handling)
533
+ /** @ignore */
534
+ onWindowEvent() {
535
+ const sender = this;
536
+ this.service.closeAllContextMenu$.next({ sender: sender }); // Close all menus on scroll or resize
537
+ }
538
+ /** @ignore */
539
+ get __hostClass() {
540
+ return ['ax-menu-container', `ax-orientation-${this.orientation()}`, 'ax-action-list', 'ax-action-list-vertical'];
541
+ }
542
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXContextMenuComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
543
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.0", type: AXContextMenuComponent, selector: "ax-context-menu", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, openOn: { classPropertyName: "openOn", publicName: "openOn", isSignal: true, isRequired: false, transformFunction: null }, closeOn: { classPropertyName: "closeOn", publicName: "closeOn", isSignal: true, isRequired: false, transformFunction: null }, orginalItems: { classPropertyName: "orginalItems", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, target: { classPropertyName: "target", publicName: "target", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onItemClick: "onItemClick", onOpening: "onOpening" }, host: { listeners: { "window:scroll": "onWindowEvent($event)", "window:resize": "onWindowEvent($event)" }, properties: { "class": "this.__hostClass" } }, providers: [
544
+ AXMenuService,
545
+ {
546
+ provide: AXRootMenu,
547
+ useExisting: AXContextMenuComponent
548
+ }
549
+ ], usesInheritance: true, ngImport: i0, template: "<ng-content select=\"ax-menu-item,ax-title,ng-container\"></ng-content>\n\n<ng-container *ngFor=\"let node of items()\" [ngTemplateOutlet]=\"Recursion\"\n [ngTemplateOutletContext]=\"{ $implicit: node }\">\n</ng-container>\n<ng-template #Recursion let-item>\n @if(item.group?.title)\n {\n <ax-title>{{item.group?.title}}</ax-title>\n }\n <ax-menu-item [name]=\"item.name\" [data]=\"item.data\" [disabled]=\"item.disabled\" [color]=\"item.color\">\n <ax-prefix>\n @if(item.icon)\n {\n <ax-icon [icon]=\"item.icon\">\n </ax-icon>\n }\n </ax-prefix>\n @if(item.text)\n {\n <ax-text>{{ item.text }}</ax-text>\n }\n @if(item.suffix)\n {\n <ax-suffix>\n <ax-text>{{ item.suffix.text }}</ax-text>\n </ax-suffix>\n }\n <ng-container *ngFor=\"let child of item.items\" [ngTemplateOutlet]=\"Recursion\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"></ng-container>\n </ax-menu-item>\n @if(item.break)\n {\n <ax-divider></ax-divider>\n }\n</ng-template>", styles: ["ax-context-menu,ax-menu{width:100%;color:inherit;display:flex;width:max-content}ax-context-menu.ax-menu-container,ax-context-menu .ax-menu-items,ax-menu.ax-menu-container,ax-menu .ax-menu-items{padding-block:.5rem;display:flex;opacity:0;visibility:hidden;transition:opacity .3s;width:max-content;min-width:12rem;height:max-content;position:fixed;flex-direction:column;border-radius:0;border-width:1px;border-color:rgba(var(--ax-color-border-default));background-color:rgba(var(--ax-color-surface));--ax-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--ax-shadow-colored: 0 4px 6px -1px var(--ax-shadow-color), 0 2px 4px -2px var(--ax-shadow-color);box-shadow:var(--ax-ring-offset-shadow, 0 0 rgba(0, 0, 0, 0)),var(--ax-ring-shadow, 0 0 rgba(0, 0, 0, 0)),var(--ax-shadow);border-radius:var(--ax-rounded-border-default);z-index:9999}ax-context-menu.ax-menu-container.ax-state-open,ax-context-menu .ax-menu-items.ax-state-open,ax-menu.ax-menu-container.ax-state-open,ax-menu .ax-menu-items.ax-state-open{opacity:1;visibility:visible}ax-context-menu.ax-action-list-horizontal{padding-inline:1rem}ax-menu.ax-action-list-horizontal{min-width:12rem;gap:.875rem}ax-menu.ax-action-list-horizontal>ax-menu-item{font-weight:500}ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-prefix{padding-inline-start:0!important}ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-suffix:not(ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-suffix:empty){padding-inline-end:0!important;margin-inline-start:0!important}ax-menu.ax-action-list-horizontal>ax-menu-item:hover{background-color:transparent!important}ax-menu.ax-action-list-horizontal>ax-menu-item:hover>.ax-action-item-prefix{color:rgba(var(--ax-color-primary-500))}ax-menu.ax-action-list-horizontal>ax-menu-item:hover>.ax-action-item-suffix{color:rgba(var(--ax-color-primary-500))}ax-menu.ax-action-list-vertical{width:max-content;min-width:12rem}ax-menu.ax-action-list-vertical>ax-menu-item{font-weight:500}ax-menu>ax-menu-item{padding-block:.5rem}ax-menu>ax-menu-item:hover:not(ax-menu>ax-menu-item:hover.ax-state-disabled)>ax-icon,ax-menu>ax-menu-item:hover:not(ax-menu>ax-menu-item:hover.ax-state-disabled)>ax-text{color:rgba(var(--ax-color-primary-500))}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-sub-title, ax-placeholder, ax-overlay" }, { kind: "component", type: AXMenuItemComponent, selector: "ax-menu-item", inputs: ["name", "data", "disabled", "color"], outputs: ["onClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
170
550
  }
171
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuItemComponent, decorators: [{
551
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXContextMenuComponent, decorators: [{
172
552
  type: Component,
173
- args: [{ selector: 'ax-menu-item', inputs: ['disabled'], host: { ngSkipHydration: 'true' }, encapsulation: ViewEncapsulation.None, template: "<div class=\"ax-menu-item-start-side\">\n <ng-content select=\"ax-prefix\"></ng-content>\n <ng-content select=\"ax-text\"></ng-content>\n <ng-content></ng-content>\n</div>\n<ng-content select=\"ax-suffix\"></ng-content>\n@if (children.length && arrowState()) {\n <i class=\"ax-icon ax-icon-solid {{ getIcon() }} ax-menu-item-child-icon\"></i>\n}\n\n<ax-popover\n #popover\n [closeOn]=\"'clickOut'\"\n [openOn]=\"rootMenu.openOn()\"\n [target]=\"getHostElement()\"\n [offsetY]=\"offsetY()\"\n [offsetX]=\"offsetX()\"\n [placement]=\"getPlacement()\"\n (onOpened)=\"_handleOnOpened()\"\n (onClosed)=\"_handleOnClosed()\"\n>\n <div class=\"ax-menu-item-children ax-parent-{{ this.rootMenu.orientation() }}\">\n <ng-content select=\"ax-menu-item\"></ng-content>\n </div>\n</ax-popover>\n" }]
174
- }], ctorParameters: () => [], propDecorators: { popover: [{
175
- type: ViewChild,
176
- args: [AXPopoverComponent]
177
- }], children: [{
178
- type: ContentChildren,
179
- args: [AXMenuItemComponent]
553
+ args: [{ selector: 'ax-context-menu', changeDetection: ChangeDetectionStrategy.OnPush, encapsulation: ViewEncapsulation.None, providers: [
554
+ AXMenuService,
555
+ {
556
+ provide: AXRootMenu,
557
+ useExisting: AXContextMenuComponent
558
+ }
559
+ ], template: "<ng-content select=\"ax-menu-item,ax-title,ng-container\"></ng-content>\n\n<ng-container *ngFor=\"let node of items()\" [ngTemplateOutlet]=\"Recursion\"\n [ngTemplateOutletContext]=\"{ $implicit: node }\">\n</ng-container>\n<ng-template #Recursion let-item>\n @if(item.group?.title)\n {\n <ax-title>{{item.group?.title}}</ax-title>\n }\n <ax-menu-item [name]=\"item.name\" [data]=\"item.data\" [disabled]=\"item.disabled\" [color]=\"item.color\">\n <ax-prefix>\n @if(item.icon)\n {\n <ax-icon [icon]=\"item.icon\">\n </ax-icon>\n }\n </ax-prefix>\n @if(item.text)\n {\n <ax-text>{{ item.text }}</ax-text>\n }\n @if(item.suffix)\n {\n <ax-suffix>\n <ax-text>{{ item.suffix.text }}</ax-text>\n </ax-suffix>\n }\n <ng-container *ngFor=\"let child of item.items\" [ngTemplateOutlet]=\"Recursion\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"></ng-container>\n </ax-menu-item>\n @if(item.break)\n {\n <ax-divider></ax-divider>\n }\n</ng-template>", styles: ["ax-context-menu,ax-menu{width:100%;color:inherit;display:flex;width:max-content}ax-context-menu.ax-menu-container,ax-context-menu .ax-menu-items,ax-menu.ax-menu-container,ax-menu .ax-menu-items{padding-block:.5rem;display:flex;opacity:0;visibility:hidden;transition:opacity .3s;width:max-content;min-width:12rem;height:max-content;position:fixed;flex-direction:column;border-radius:0;border-width:1px;border-color:rgba(var(--ax-color-border-default));background-color:rgba(var(--ax-color-surface));--ax-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--ax-shadow-colored: 0 4px 6px -1px var(--ax-shadow-color), 0 2px 4px -2px var(--ax-shadow-color);box-shadow:var(--ax-ring-offset-shadow, 0 0 rgba(0, 0, 0, 0)),var(--ax-ring-shadow, 0 0 rgba(0, 0, 0, 0)),var(--ax-shadow);border-radius:var(--ax-rounded-border-default);z-index:9999}ax-context-menu.ax-menu-container.ax-state-open,ax-context-menu .ax-menu-items.ax-state-open,ax-menu.ax-menu-container.ax-state-open,ax-menu .ax-menu-items.ax-state-open{opacity:1;visibility:visible}ax-context-menu.ax-action-list-horizontal{padding-inline:1rem}ax-menu.ax-action-list-horizontal{min-width:12rem;gap:.875rem}ax-menu.ax-action-list-horizontal>ax-menu-item{font-weight:500}ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-prefix{padding-inline-start:0!important}ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-suffix:not(ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-suffix:empty){padding-inline-end:0!important;margin-inline-start:0!important}ax-menu.ax-action-list-horizontal>ax-menu-item:hover{background-color:transparent!important}ax-menu.ax-action-list-horizontal>ax-menu-item:hover>.ax-action-item-prefix{color:rgba(var(--ax-color-primary-500))}ax-menu.ax-action-list-horizontal>ax-menu-item:hover>.ax-action-item-suffix{color:rgba(var(--ax-color-primary-500))}ax-menu.ax-action-list-vertical{width:max-content;min-width:12rem}ax-menu.ax-action-list-vertical>ax-menu-item{font-weight:500}ax-menu>ax-menu-item{padding-block:.5rem}ax-menu>ax-menu-item:hover:not(ax-menu>ax-menu-item:hover.ax-state-disabled)>ax-icon,ax-menu>ax-menu-item:hover:not(ax-menu>ax-menu-item:hover.ax-state-disabled)>ax-text{color:rgba(var(--ax-color-primary-500))}\n"] }]
560
+ }], ctorParameters: () => [], propDecorators: { onWindowEvent: [{
561
+ type: HostListener,
562
+ args: ['window:scroll', ['$event']]
563
+ }, {
564
+ type: HostListener,
565
+ args: ['window:resize', ['$event']]
180
566
  }], __hostClass: [{
181
567
  type: HostBinding,
182
568
  args: ['class']
183
- }], __hostClick: [{
184
- type: HostListener,
185
- args: ['click', ['$event']]
186
569
  }] } });
187
570
 
188
571
  /**
189
572
  * Represents a menu component that displays menu items.
190
573
  * @category Components
191
574
  */
192
- class AXMenuComponent extends MXBaseComponent {
575
+ class AXMenuComponent extends NXComponent {
193
576
  constructor() {
194
577
  super(...arguments);
195
578
  this.orientation = input('horizontal');
196
- this.openOn = input('toggle');
579
+ this.openOn = input('hover');
580
+ this.closeOn = input('leave');
197
581
  this.service = inject(AXMenuService);
198
- }
199
- /** @ignore */
200
- ngAfterViewInit() {
201
- this.children.forEach((c) => {
202
- c.isRoot = true;
203
- c.parent = this;
204
- });
582
+ this.onItemClick = output();
583
+ this.items = input([]);
205
584
  }
206
585
  /** @ignore */
207
586
  get __hostClass() {
208
- return `ax-orientation-${this.orientation()}`;
587
+ return `ax-action-list-${this.orientation()} ax-action-list`;
588
+ }
589
+ close() {
590
+ this.service.closeAll$.next();
209
591
  }
210
592
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
211
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "18.2.0", type: AXMenuComponent, selector: "ax-menu", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, openOn: { classPropertyName: "openOn", publicName: "openOn", isSignal: true, isRequired: false, transformFunction: null } }, host: { properties: { "class": "this.__hostClass" } }, providers: [
593
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "18.2.0", type: AXMenuComponent, selector: "ax-menu", inputs: { orientation: { classPropertyName: "orientation", publicName: "orientation", isSignal: true, isRequired: false, transformFunction: null }, openOn: { classPropertyName: "openOn", publicName: "openOn", isSignal: true, isRequired: false, transformFunction: null }, closeOn: { classPropertyName: "closeOn", publicName: "closeOn", isSignal: true, isRequired: false, transformFunction: null }, items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onItemClick: "onItemClick" }, host: { properties: { "class": "this.__hostClass" } }, providers: [
594
+ AXMenuService,
212
595
  {
213
596
  provide: AXRootMenu,
214
- useExisting: AXMenuComponent,
215
- },
216
- {
217
- provide: AXMenuService,
218
- },
219
- ], queries: [{ propertyName: "children", predicate: AXMenuItemComponent }], usesInheritance: true, ngImport: i0, template: ` <ng-content select="ax-menu-item,ng-container"></ng-content>`, isInline: true, styles: ["ax-menu{width:100%;font-size:.875rem;line-height:1.25rem;color:inherit;position:relative}ax-menu.ax-orientation-horizontal{display:flex}ax-menu.ax-orientation-horizontal ax-menu-item:not(ax-menu.ax-orientation-horizontal ax-menu-item:last-child){margin-inline-end:1rem}ax-menu.ax-orientation-vertical{display:flex;flex-direction:column}ax-menu.ax-orientation-vertical ax-menu-item{justify-content:space-between}ax-menu.ax-orientation-vertical ax-menu-item:not(ax-menu.ax-orientation-vertical ax-menu-item:last-child){margin-bottom:1rem}ax-menu ax-menu-item:hover:not(ax-menu ax-menu-item:hover.ax-state-disabled){color:rgba(var(--ax-color-primary-500))}ax-menu-item{position:relative;display:flex;align-items:center;gap:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;justify-content:space-between;color:rgba(var(--ax-color-text-default))}ax-menu-item .ax-menu-item-text{white-space:nowrap}ax-menu-item:not(ax-menu-item.ax-state-disabled){cursor:pointer}ax-menu-item .ax-menu-item-start-side{display:flex;align-items:center;gap:.5rem}ax-menu-item.ax-state-disabled{cursor:not-allowed;opacity:.5}ax-menu-item.ax-state-selected{color:rgba(var(--ax-color-primary-500))}ax-menu-item .ax-menu-item-child-icon{width:fit-content;line-height:1;font-size:10px}ax-menu-item ax-popover{position:absolute}.ax-menu-item-children{padding-top:.5rem;padding-bottom:.5rem}.ax-menu-item-children:not(.ax-menu-item-children:empty){display:flex;min-width:12rem;flex-direction:column;border-radius:var(--ax-rounded-border-default);border-width:1px;border-color:rgba(var(--ax-color-border-default));background-color:rgba(var(--ax-color-surface))}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item{padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover:not(.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover.ax-state-disabled){background-color:rgba(var(--ax-color-on-surface))}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover:not(.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover.ax-state-disabled) ax-prefix,.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover:not(.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover.ax-state-disabled) ax-suffix{opacity:1}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item ax-prefix,.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item ax-suffix{opacity:.75}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item .ax-menu-item-text{flex:1 1 0%}html[dir=rtl] .ax-parent-horizontal .ax-menu-item-child-icon{transform:rotate(-90deg)}html[dir=rtl] .ax-parent-horizontal .ax-menu-item-child-icon:before{-moz-transform:scale(1,-1);-webkit-transform:scale(1,-1);-o-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scaleY(-1)}.ax-parent-horizontal .ax-menu-item-child-icon{transform:rotate(-90deg)}\n"], encapsulation: i0.ViewEncapsulation.None }); }
597
+ useExisting: AXMenuComponent
598
+ }
599
+ ], usesInheritance: true, ngImport: i0, template: "<ng-content select=\"ax-menu-item,ax-title,ng-container\"></ng-content>\n\n<ng-container *ngFor=\"let node of items()\" [ngTemplateOutlet]=\"Recursion\"\n [ngTemplateOutletContext]=\"{ $implicit: node }\">\n</ng-container>\n<ng-template #Recursion let-item>\n @if(item.group?.title)\n {\n <ax-title>{{item.group?.title}}</ax-title>\n }\n <ax-menu-item [name]=\"item.name\" [data]=\"item.data\" [disabled]=\"item.disabled\" [color]=\"item.color\">\n <ax-prefix>\n @if(item.icon)\n {\n <ax-icon [icon]=\"item.icon\">\n </ax-icon>\n }\n </ax-prefix>\n @if(item.text)\n {\n <ax-text>{{ item.text }}</ax-text>\n }\n @if(item.suffix)\n {\n <ax-suffix>\n <ax-text>{{ item.suffix.text }}</ax-text>\n </ax-suffix>\n }\n <ng-container *ngFor=\"let child of item.items\" [ngTemplateOutlet]=\"Recursion\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"></ng-container>\n </ax-menu-item>\n @if(item.break)\n {\n <ax-divider></ax-divider>\n }\n</ng-template>", styles: ["ax-context-menu,ax-menu{width:100%;color:inherit;display:flex;width:max-content}ax-context-menu.ax-menu-container,ax-context-menu .ax-menu-items,ax-menu.ax-menu-container,ax-menu .ax-menu-items{padding-block:.5rem;display:flex;opacity:0;visibility:hidden;transition:opacity .3s;width:max-content;min-width:12rem;height:max-content;position:fixed;flex-direction:column;border-radius:0;border-width:1px;border-color:rgba(var(--ax-color-border-default));background-color:rgba(var(--ax-color-surface));--ax-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--ax-shadow-colored: 0 4px 6px -1px var(--ax-shadow-color), 0 2px 4px -2px var(--ax-shadow-color);box-shadow:var(--ax-ring-offset-shadow, 0 0 rgba(0, 0, 0, 0)),var(--ax-ring-shadow, 0 0 rgba(0, 0, 0, 0)),var(--ax-shadow);border-radius:var(--ax-rounded-border-default);z-index:9999}ax-context-menu.ax-menu-container.ax-state-open,ax-context-menu .ax-menu-items.ax-state-open,ax-menu.ax-menu-container.ax-state-open,ax-menu .ax-menu-items.ax-state-open{opacity:1;visibility:visible}ax-context-menu.ax-action-list-horizontal{padding-inline:1rem}ax-menu.ax-action-list-horizontal{min-width:12rem;gap:.875rem}ax-menu.ax-action-list-horizontal>ax-menu-item{font-weight:500}ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-prefix{padding-inline-start:0!important}ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-suffix:not(ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-suffix:empty){padding-inline-end:0!important;margin-inline-start:0!important}ax-menu.ax-action-list-horizontal>ax-menu-item:hover{background-color:transparent!important}ax-menu.ax-action-list-horizontal>ax-menu-item:hover>.ax-action-item-prefix{color:rgba(var(--ax-color-primary-500))}ax-menu.ax-action-list-horizontal>ax-menu-item:hover>.ax-action-item-suffix{color:rgba(var(--ax-color-primary-500))}ax-menu.ax-action-list-vertical{width:max-content;min-width:12rem}ax-menu.ax-action-list-vertical>ax-menu-item{font-weight:500}ax-menu>ax-menu-item{padding-block:.5rem}ax-menu>ax-menu-item:hover:not(ax-menu>ax-menu-item:hover.ax-state-disabled)>ax-icon,ax-menu>ax-menu-item:hover:not(ax-menu>ax-menu-item:hover.ax-state-disabled)>ax-text{color:rgba(var(--ax-color-primary-500))}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "component", type: i2.AXDecoratorIconComponent, selector: "ax-icon", inputs: ["icon"] }, { kind: "component", type: i2.AXDecoratorGenericComponent, selector: "ax-footer, ax-header, ax-content, ax-divider, ax-form-hint, ax-prefix, ax-suffix, ax-text, ax-title, ax-sub-title, ax-placeholder, ax-overlay" }, { kind: "component", type: AXMenuItemComponent, selector: "ax-menu-item", inputs: ["name", "data", "disabled", "color"], outputs: ["onClick"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None }); }
220
600
  }
221
601
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuComponent, decorators: [{
222
602
  type: Component,
223
- args: [{ selector: 'ax-menu', template: ` <ng-content select="ax-menu-item,ng-container"></ng-content>`, encapsulation: ViewEncapsulation.None, providers: [
603
+ args: [{ selector: 'ax-menu', encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, providers: [
604
+ AXMenuService,
224
605
  {
225
606
  provide: AXRootMenu,
226
- useExisting: AXMenuComponent,
227
- },
228
- {
229
- provide: AXMenuService,
230
- },
231
- ], styles: ["ax-menu{width:100%;font-size:.875rem;line-height:1.25rem;color:inherit;position:relative}ax-menu.ax-orientation-horizontal{display:flex}ax-menu.ax-orientation-horizontal ax-menu-item:not(ax-menu.ax-orientation-horizontal ax-menu-item:last-child){margin-inline-end:1rem}ax-menu.ax-orientation-vertical{display:flex;flex-direction:column}ax-menu.ax-orientation-vertical ax-menu-item{justify-content:space-between}ax-menu.ax-orientation-vertical ax-menu-item:not(ax-menu.ax-orientation-vertical ax-menu-item:last-child){margin-bottom:1rem}ax-menu ax-menu-item:hover:not(ax-menu ax-menu-item:hover.ax-state-disabled){color:rgba(var(--ax-color-primary-500))}ax-menu-item{position:relative;display:flex;align-items:center;gap:.5rem;font-size:.875rem;line-height:1.25rem;font-weight:500;transition-property:color,background-color,border-color,text-decoration-color,fill,stroke;transition-timing-function:cubic-bezier(.4,0,.2,1);transition-duration:.15s;justify-content:space-between;color:rgba(var(--ax-color-text-default))}ax-menu-item .ax-menu-item-text{white-space:nowrap}ax-menu-item:not(ax-menu-item.ax-state-disabled){cursor:pointer}ax-menu-item .ax-menu-item-start-side{display:flex;align-items:center;gap:.5rem}ax-menu-item.ax-state-disabled{cursor:not-allowed;opacity:.5}ax-menu-item.ax-state-selected{color:rgba(var(--ax-color-primary-500))}ax-menu-item .ax-menu-item-child-icon{width:fit-content;line-height:1;font-size:10px}ax-menu-item ax-popover{position:absolute}.ax-menu-item-children{padding-top:.5rem;padding-bottom:.5rem}.ax-menu-item-children:not(.ax-menu-item-children:empty){display:flex;min-width:12rem;flex-direction:column;border-radius:var(--ax-rounded-border-default);border-width:1px;border-color:rgba(var(--ax-color-border-default));background-color:rgba(var(--ax-color-surface))}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item{padding:.5rem 1rem;font-size:.875rem;line-height:1.25rem}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover:not(.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover.ax-state-disabled){background-color:rgba(var(--ax-color-on-surface))}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover:not(.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover.ax-state-disabled) ax-prefix,.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover:not(.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item:hover.ax-state-disabled) ax-suffix{opacity:1}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item ax-prefix,.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item ax-suffix{opacity:.75}.ax-menu-item-children:not(.ax-menu-item-children:empty) ax-menu-item .ax-menu-item-text{flex:1 1 0%}html[dir=rtl] .ax-parent-horizontal .ax-menu-item-child-icon{transform:rotate(-90deg)}html[dir=rtl] .ax-parent-horizontal .ax-menu-item-child-icon:before{-moz-transform:scale(1,-1);-webkit-transform:scale(1,-1);-o-transform:scale(1,-1);-ms-transform:scale(1,-1);transform:scaleY(-1)}.ax-parent-horizontal .ax-menu-item-child-icon{transform:rotate(-90deg)}\n"] }]
232
- }], propDecorators: { children: [{
233
- type: ContentChildren,
234
- args: [AXMenuItemComponent]
235
- }], __hostClass: [{
607
+ useExisting: AXMenuComponent
608
+ }
609
+ ], template: "<ng-content select=\"ax-menu-item,ax-title,ng-container\"></ng-content>\n\n<ng-container *ngFor=\"let node of items()\" [ngTemplateOutlet]=\"Recursion\"\n [ngTemplateOutletContext]=\"{ $implicit: node }\">\n</ng-container>\n<ng-template #Recursion let-item>\n @if(item.group?.title)\n {\n <ax-title>{{item.group?.title}}</ax-title>\n }\n <ax-menu-item [name]=\"item.name\" [data]=\"item.data\" [disabled]=\"item.disabled\" [color]=\"item.color\">\n <ax-prefix>\n @if(item.icon)\n {\n <ax-icon [icon]=\"item.icon\">\n </ax-icon>\n }\n </ax-prefix>\n @if(item.text)\n {\n <ax-text>{{ item.text }}</ax-text>\n }\n @if(item.suffix)\n {\n <ax-suffix>\n <ax-text>{{ item.suffix.text }}</ax-text>\n </ax-suffix>\n }\n <ng-container *ngFor=\"let child of item.items\" [ngTemplateOutlet]=\"Recursion\"\n [ngTemplateOutletContext]=\"{ $implicit: child }\"></ng-container>\n </ax-menu-item>\n @if(item.break)\n {\n <ax-divider></ax-divider>\n }\n</ng-template>", styles: ["ax-context-menu,ax-menu{width:100%;color:inherit;display:flex;width:max-content}ax-context-menu.ax-menu-container,ax-context-menu .ax-menu-items,ax-menu.ax-menu-container,ax-menu .ax-menu-items{padding-block:.5rem;display:flex;opacity:0;visibility:hidden;transition:opacity .3s;width:max-content;min-width:12rem;height:max-content;position:fixed;flex-direction:column;border-radius:0;border-width:1px;border-color:rgba(var(--ax-color-border-default));background-color:rgba(var(--ax-color-surface));--ax-shadow: 0 4px 6px -1px rgb(0 0 0 / .1), 0 2px 4px -2px rgb(0 0 0 / .1);--ax-shadow-colored: 0 4px 6px -1px var(--ax-shadow-color), 0 2px 4px -2px var(--ax-shadow-color);box-shadow:var(--ax-ring-offset-shadow, 0 0 rgba(0, 0, 0, 0)),var(--ax-ring-shadow, 0 0 rgba(0, 0, 0, 0)),var(--ax-shadow);border-radius:var(--ax-rounded-border-default);z-index:9999}ax-context-menu.ax-menu-container.ax-state-open,ax-context-menu .ax-menu-items.ax-state-open,ax-menu.ax-menu-container.ax-state-open,ax-menu .ax-menu-items.ax-state-open{opacity:1;visibility:visible}ax-context-menu.ax-action-list-horizontal{padding-inline:1rem}ax-menu.ax-action-list-horizontal{min-width:12rem;gap:.875rem}ax-menu.ax-action-list-horizontal>ax-menu-item{font-weight:500}ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-prefix{padding-inline-start:0!important}ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-suffix:not(ax-menu.ax-action-list-horizontal>ax-menu-item>.ax-action-item-suffix:empty){padding-inline-end:0!important;margin-inline-start:0!important}ax-menu.ax-action-list-horizontal>ax-menu-item:hover{background-color:transparent!important}ax-menu.ax-action-list-horizontal>ax-menu-item:hover>.ax-action-item-prefix{color:rgba(var(--ax-color-primary-500))}ax-menu.ax-action-list-horizontal>ax-menu-item:hover>.ax-action-item-suffix{color:rgba(var(--ax-color-primary-500))}ax-menu.ax-action-list-vertical{width:max-content;min-width:12rem}ax-menu.ax-action-list-vertical>ax-menu-item{font-weight:500}ax-menu>ax-menu-item{padding-block:.5rem}ax-menu>ax-menu-item:hover:not(ax-menu>ax-menu-item:hover.ax-state-disabled)>ax-icon,ax-menu>ax-menu-item:hover:not(ax-menu>ax-menu-item:hover.ax-state-disabled)>ax-text{color:rgba(var(--ax-color-primary-500))}\n"] }]
610
+ }], propDecorators: { __hostClass: [{
236
611
  type: HostBinding,
237
612
  args: ['class']
238
613
  }] } });
239
614
 
240
- const COMPONENT = [AXMenuItemComponent, AXMenuComponent];
615
+ const COMPONENT = [AXMenuItemComponent, AXMenuComponent, AXContextMenuComponent];
241
616
  const MODULES = [AXDecoratorModule, AXLoadingModule, AXTranslationModule, OverlayModule, AXPopoverModule];
242
617
  class AXMenuModule {
243
618
  static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule }); }
244
- static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.0", ngImport: i0, type: AXMenuModule, declarations: [AXMenuItemComponent, AXMenuComponent], imports: [CommonModule, AXDecoratorModule, AXLoadingModule, AXTranslationModule, OverlayModule, AXPopoverModule, AXButtonModule], exports: [AXMenuItemComponent, AXMenuComponent] }); }
245
- static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuModule, imports: [CommonModule, MODULES, AXButtonModule] }); }
619
+ static { this.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "18.2.0", ngImport: i0, type: AXMenuModule, declarations: [AXMenuItemComponent, AXMenuComponent, AXContextMenuComponent], imports: [CommonModule, AXDecoratorModule, AXLoadingModule, AXTranslationModule, OverlayModule, AXPopoverModule], exports: [AXMenuItemComponent, AXMenuComponent, AXContextMenuComponent] }); }
620
+ static { this.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuModule, imports: [CommonModule, MODULES] }); }
246
621
  }
247
622
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImport: i0, type: AXMenuModule, decorators: [{
248
623
  type: NgModule,
249
624
  args: [{
250
625
  declarations: [...COMPONENT],
251
- imports: [CommonModule, ...MODULES, AXButtonModule],
626
+ imports: [CommonModule, ...MODULES],
252
627
  exports: [...COMPONENT],
253
628
  providers: [],
254
629
  }]
@@ -258,5 +633,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.0", ngImpor
258
633
  * Generated bundle index. Do not edit.
259
634
  */
260
635
 
261
- export { AXMenuComponent, AXMenuItemComponent, AXMenuModule, AXMenuService, AXRootMenu };
636
+ export { AXContextMenuComponent, AXContextMenuOpeningEvent, AXMenuComponent, AXMenuItem, AXMenuItemClickBaseEvent, AXMenuItemComponent, AXMenuItemComponentBase, AXMenuModule, AXMenuService, AXRootMenu };
262
637
  //# sourceMappingURL=acorex-components-menu.mjs.map