@acorex/components 18.10.16 → 18.11.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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