ngx-mat-menu-hover 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,39 @@
1
+ # mat-menu-hover - An Angular Material directive
2
+ This Angular directive provides functionality to handle hover menu behavior, allowing menus to open when hovered over and close when the mouse leaves.
3
+
4
+ ## Installation
5
+
6
+ npm install mat-menu-hover@latest
7
+
8
+ Since the directive is marked as standalone you can directly import it into a module.
9
+
10
+ import { NgModule } from '@angular/core';
11
+ import { HoverMenuDirective } from 'mat-menu-hover';
12
+
13
+ @NgModule({
14
+ declarations: [...],
15
+ imports: [
16
+ HoverMenuDirective
17
+ ],
18
+ exports: [...]
19
+ })
20
+ export class AppModule { }
21
+
22
+ ## Usage
23
+
24
+ <button mat-button [matMenuTriggerFor]="menu" matHoverMenu>Menu</button>
25
+ <mat-menu #menu="matMenu">
26
+ <!-- Menu content goes here -->
27
+ </mat-menu>
28
+
29
+ ## Optional inputs/outputs
30
+ |Keyword |Function |Note |
31
+ |------------|-----------------------------------|--------------|
32
+ |[closeDelay]|Adds a delay before the menu closed|Default = 50ms|
33
+ |(opened) |Emits if the menu is opened/closed | |
34
+
35
+ ## Known issues
36
+ - Currently it is not possible to nest menus. It will only work with single-level mat-menus.
37
+
38
+ ## License
39
+ This project is licensed under the MIT License - see the LICENSE file for details.
@@ -0,0 +1,83 @@
1
+ import { DestroyRef, Directive, EventEmitter, HostListener, Input, Output, Self, inject } from '@angular/core';
2
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
3
+ import { BehaviorSubject, filter, fromEvent, mergeMap, tap } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/material/menu";
6
+ /**
7
+ * Directive to handle hover menu behavior.
8
+ */
9
+ export class MatMenuHoverDirective {
10
+ onMouseEnter() {
11
+ this.openMenu();
12
+ // Get the menu element by ID and emit it to the observable
13
+ const element = document.querySelector(`#${this.menu.panelId}`);
14
+ if (element) {
15
+ this.menuElement$.next(element);
16
+ }
17
+ }
18
+ onMouseLeave() {
19
+ this.closeMenu();
20
+ }
21
+ constructor(matMenuTrigger) {
22
+ this.matMenuTrigger = matMenuTrigger;
23
+ this.destroyRef = inject(DestroyRef);
24
+ this.menuElement$ = new BehaviorSubject(null); // Observable for menu element
25
+ /**
26
+ * Delay (in milliseconds) before closing the menu after mouseleave.
27
+ */
28
+ this.closeDelay = 50; // Delay before closing the menu on mouseleave
29
+ /**
30
+ * Event emitter for notifying when the menu is opened.
31
+ */
32
+ this.opened = new EventEmitter();
33
+ }
34
+ ngOnInit() {
35
+ // Ensure MatMenuTrigger is present
36
+ if (!this.matMenuTrigger) {
37
+ console.error('There must be a MatMenuTrigger present.');
38
+ return;
39
+ }
40
+ // Assign the menu and disable backdrop
41
+ this.menu = this.matMenuTrigger.menu;
42
+ this.menu.hasBackdrop = false;
43
+ // Subscribe to mouseleave event on the menu element to close the menu
44
+ this.menuElement$.pipe(takeUntilDestroyed(this.destroyRef), filter(element => !!element), mergeMap(element => fromEvent(element, 'mouseleave')), tap(() => this.closeMenu()))
45
+ .subscribe();
46
+ // Subscribe to mouseenter event on the menu element to open the menu
47
+ this.menuElement$.pipe(takeUntilDestroyed(this.destroyRef), filter(element => !!element), mergeMap(element => fromEvent(element, 'mouseenter')), tap(() => this.openMenu()))
48
+ .subscribe();
49
+ }
50
+ closeMenu() {
51
+ this.closer = setTimeout(() => {
52
+ this.matMenuTrigger.closeMenu();
53
+ }, this.closeDelay);
54
+ }
55
+ openMenu() {
56
+ if (this.closer) {
57
+ clearTimeout(this.closer);
58
+ }
59
+ this.matMenuTrigger.openMenu();
60
+ }
61
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.1", ngImport: i0, type: MatMenuHoverDirective, deps: [{ token: i1.MatMenuTrigger, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
62
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.2.1", type: MatMenuHoverDirective, isStandalone: true, selector: "[matHoverMenu]", inputs: { closeDelay: "closeDelay" }, outputs: { opened: "opened" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, ngImport: i0 }); }
63
+ }
64
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.1", ngImport: i0, type: MatMenuHoverDirective, decorators: [{
65
+ type: Directive,
66
+ args: [{
67
+ selector: '[matHoverMenu]',
68
+ standalone: true
69
+ }]
70
+ }], ctorParameters: () => [{ type: i1.MatMenuTrigger, decorators: [{
71
+ type: Self
72
+ }] }], propDecorators: { closeDelay: [{
73
+ type: Input
74
+ }], opened: [{
75
+ type: Output
76
+ }], onMouseEnter: [{
77
+ type: HostListener,
78
+ args: ['mouseenter']
79
+ }], onMouseLeave: [{
80
+ type: HostListener,
81
+ args: ['mouseleave']
82
+ }] } });
83
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWF0LW1lbnUtaG92ZXIuZGlyZWN0aXZlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vcHJvamVjdHMvbWF0LW1lbnUtaG92ZXIvc3JjL2xpYi9tYXQtbWVudS1ob3Zlci5kaXJlY3RpdmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxTQUFTLEVBQUUsWUFBWSxFQUFFLFlBQVksRUFBRSxLQUFLLEVBQVUsTUFBTSxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDdkgsT0FBTyxFQUFFLGtCQUFrQixFQUFFLE1BQU0sNEJBQTRCLENBQUM7QUFFaEUsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLEVBQUUsU0FBUyxFQUFFLFFBQVEsRUFBRSxHQUFHLEVBQUUsTUFBTSxNQUFNLENBQUM7OztBQUV6RTs7R0FFRztBQUtILE1BQU0sT0FBTyxxQkFBcUI7SUFpQmhDLFlBQVk7UUFDVixJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7UUFFaEIsMkRBQTJEO1FBQzNELE1BQU0sT0FBTyxHQUFHLFFBQVEsQ0FBQyxhQUFhLENBQUMsSUFBSSxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFtQixDQUFDO1FBQ2xGLElBQUksT0FBTyxFQUFFLENBQUM7WUFDWixJQUFJLENBQUMsWUFBWSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsQyxDQUFDO0lBQ0gsQ0FBQztJQUdELFlBQVk7UUFDVixJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7SUFDbkIsQ0FBQztJQUVELFlBQTRCLGNBQThCO1FBQTlCLG1CQUFjLEdBQWQsY0FBYyxDQUFnQjtRQS9CbEQsZUFBVSxHQUFHLE1BQU0sQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUVoQyxpQkFBWSxHQUFHLElBQUksZUFBZSxDQUFpQixJQUFJLENBQUMsQ0FBQyxDQUFDLDhCQUE4QjtRQUdoRzs7VUFFRTtRQUNPLGVBQVUsR0FBRyxFQUFFLENBQUMsQ0FBQyw4Q0FBOEM7UUFFeEU7O1NBRUM7UUFDUyxXQUFNLEdBQUcsSUFBSSxZQUFZLEVBQVcsQ0FBQztJQWtCZSxDQUFDO0lBRS9ELFFBQVE7UUFDTixtQ0FBbUM7UUFDbkMsSUFBSSxDQUFDLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztZQUN6QixPQUFPLENBQUMsS0FBSyxDQUFDLHlDQUF5QyxDQUFDLENBQUM7WUFDekQsT0FBTztRQUNULENBQUM7UUFFRCx1Q0FBdUM7UUFDdkMsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQztRQUNyQyxJQUFJLENBQUMsSUFBSSxDQUFDLFdBQVcsR0FBRyxLQUFLLENBQUM7UUFFOUIsc0VBQXNFO1FBQ3RFLElBQUksQ0FBQyxZQUFZLENBQUMsSUFBSSxDQUNwQixrQkFBa0IsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEVBQ25DLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFDNUIsUUFBUSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsU0FBUyxDQUFDLE9BQU8sRUFBRSxZQUFZLENBQUMsQ0FBQyxFQUNyRCxHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQzVCO2FBQ0UsU0FBUyxFQUFFLENBQUM7UUFFZixxRUFBcUU7UUFDckUsSUFBSSxDQUFDLFlBQVksQ0FBQyxJQUFJLENBQ3BCLGtCQUFrQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsRUFDbkMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxFQUM1QixRQUFRLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxTQUFTLENBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQyxDQUFDLEVBQ3JELEdBQUcsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUMsQ0FDM0I7YUFDRSxTQUFTLEVBQUUsQ0FBQztJQUNqQixDQUFDO0lBRU8sU0FBUztRQUNmLElBQUksQ0FBQyxNQUFNLEdBQUcsVUFBVSxDQUFDLEdBQUcsRUFBRTtZQUM1QixJQUFJLENBQUMsY0FBYyxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2xDLENBQUMsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7SUFDdEIsQ0FBQztJQUVPLFFBQVE7UUFDZCxJQUFJLElBQUksQ0FBQyxNQUFNLEVBQUUsQ0FBQztZQUNoQixZQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxDQUFDO1FBQzVCLENBQUM7UUFFRCxJQUFJLENBQUMsY0FBYyxDQUFDLFFBQVEsRUFBRSxDQUFDO0lBQ2pDLENBQUM7OEdBNUVVLHFCQUFxQjtrR0FBckIscUJBQXFCOzsyRkFBckIscUJBQXFCO2tCQUpqQyxTQUFTO21CQUFDO29CQUNULFFBQVEsRUFBRSxnQkFBZ0I7b0JBQzFCLFVBQVUsRUFBRSxJQUFJO2lCQUNqQjs7MEJBaUNjLElBQUk7eUNBdkJSLFVBQVU7c0JBQWxCLEtBQUs7Z0JBS0ksTUFBTTtzQkFBZixNQUFNO2dCQUdQLFlBQVk7c0JBRFgsWUFBWTt1QkFBQyxZQUFZO2dCQVkxQixZQUFZO3NCQURYLFlBQVk7dUJBQUMsWUFBWSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IERlc3Ryb3lSZWYsIERpcmVjdGl2ZSwgRXZlbnRFbWl0dGVyLCBIb3N0TGlzdGVuZXIsIElucHV0LCBPbkluaXQsIE91dHB1dCwgU2VsZiwgaW5qZWN0IH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XHJcbmltcG9ydCB7IHRha2VVbnRpbERlc3Ryb3llZCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUvcnhqcy1pbnRlcm9wJztcclxuaW1wb3J0IHsgTWF0TWVudVBhbmVsLCBNYXRNZW51VHJpZ2dlciB9IGZyb20gJ0Bhbmd1bGFyL21hdGVyaWFsL21lbnUnO1xyXG5pbXBvcnQgeyBCZWhhdmlvclN1YmplY3QsIGZpbHRlciwgZnJvbUV2ZW50LCBtZXJnZU1hcCwgdGFwIH0gZnJvbSAncnhqcyc7XHJcblxyXG4vKipcclxuICogRGlyZWN0aXZlIHRvIGhhbmRsZSBob3ZlciBtZW51IGJlaGF2aW9yLlxyXG4gKi9cclxuQERpcmVjdGl2ZSh7XHJcbiAgc2VsZWN0b3I6ICdbbWF0SG92ZXJNZW51XScsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZVxyXG59KVxyXG5leHBvcnQgY2xhc3MgTWF0TWVudUhvdmVyRGlyZWN0aXZlIGltcGxlbWVudHMgT25Jbml0IHtcclxuICBwcml2YXRlIGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XHJcbiAgcHJpdmF0ZSBtZW51OiBNYXRNZW51UGFuZWw8YW55PjsgLy8gUmVmZXJlbmNlIHRvIHRoZSBNYXRNZW51UGFuZWxcclxuICBwcml2YXRlIG1lbnVFbGVtZW50JCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8SFRNTERpdkVsZW1lbnQ+KG51bGwpOyAvLyBPYnNlcnZhYmxlIGZvciBtZW51IGVsZW1lbnRcclxuICBwcml2YXRlIGNsb3NlcjogYW55O1xyXG5cclxuICAvKipcclxuICAqIERlbGF5IChpbiBtaWxsaXNlY29uZHMpIGJlZm9yZSBjbG9zaW5nIHRoZSBtZW51IGFmdGVyIG1vdXNlbGVhdmUuXHJcbiAgKi9cclxuICBASW5wdXQoKSBjbG9zZURlbGF5ID0gNTA7IC8vIERlbGF5IGJlZm9yZSBjbG9zaW5nIHRoZSBtZW51IG9uIG1vdXNlbGVhdmVcclxuXHJcbiAgLyoqXHJcbiAqIEV2ZW50IGVtaXR0ZXIgZm9yIG5vdGlmeWluZyB3aGVuIHRoZSBtZW51IGlzIG9wZW5lZC5cclxuICovXHJcbiAgQE91dHB1dCgpIG9wZW5lZCA9IG5ldyBFdmVudEVtaXR0ZXI8Ym9vbGVhbj4oKTtcclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignbW91c2VlbnRlcicpXHJcbiAgb25Nb3VzZUVudGVyKCk6IHZvaWQge1xyXG4gICAgdGhpcy5vcGVuTWVudSgpO1xyXG5cclxuICAgIC8vIEdldCB0aGUgbWVudSBlbGVtZW50IGJ5IElEIGFuZCBlbWl0IGl0IHRvIHRoZSBvYnNlcnZhYmxlXHJcbiAgICBjb25zdCBlbGVtZW50ID0gZG9jdW1lbnQucXVlcnlTZWxlY3RvcihgIyR7dGhpcy5tZW51LnBhbmVsSWR9YCkgYXMgSFRNTERpdkVsZW1lbnQ7XHJcbiAgICBpZiAoZWxlbWVudCkge1xyXG4gICAgICB0aGlzLm1lbnVFbGVtZW50JC5uZXh0KGVsZW1lbnQpO1xyXG4gICAgfVxyXG4gIH1cclxuXHJcbiAgQEhvc3RMaXN0ZW5lcignbW91c2VsZWF2ZScpXHJcbiAgb25Nb3VzZUxlYXZlKCk6IHZvaWQge1xyXG4gICAgdGhpcy5jbG9zZU1lbnUoKTtcclxuICB9XHJcblxyXG4gIGNvbnN0cnVjdG9yKEBTZWxmKCkgcHJpdmF0ZSBtYXRNZW51VHJpZ2dlcjogTWF0TWVudVRyaWdnZXIpIHsgfVxyXG5cclxuICBuZ09uSW5pdCgpOiB2b2lkIHtcclxuICAgIC8vIEVuc3VyZSBNYXRNZW51VHJpZ2dlciBpcyBwcmVzZW50XHJcbiAgICBpZiAoIXRoaXMubWF0TWVudVRyaWdnZXIpIHtcclxuICAgICAgY29uc29sZS5lcnJvcignVGhlcmUgbXVzdCBiZSBhIE1hdE1lbnVUcmlnZ2VyIHByZXNlbnQuJyk7XHJcbiAgICAgIHJldHVybjtcclxuICAgIH1cclxuXHJcbiAgICAvLyBBc3NpZ24gdGhlIG1lbnUgYW5kIGRpc2FibGUgYmFja2Ryb3BcclxuICAgIHRoaXMubWVudSA9IHRoaXMubWF0TWVudVRyaWdnZXIubWVudTtcclxuICAgIHRoaXMubWVudS5oYXNCYWNrZHJvcCA9IGZhbHNlO1xyXG5cclxuICAgIC8vIFN1YnNjcmliZSB0byBtb3VzZWxlYXZlIGV2ZW50IG9uIHRoZSBtZW51IGVsZW1lbnQgdG8gY2xvc2UgdGhlIG1lbnVcclxuICAgIHRoaXMubWVudUVsZW1lbnQkLnBpcGUoXHJcbiAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpLFxyXG4gICAgICBmaWx0ZXIoZWxlbWVudCA9PiAhIWVsZW1lbnQpLFxyXG4gICAgICBtZXJnZU1hcChlbGVtZW50ID0+IGZyb21FdmVudChlbGVtZW50LCAnbW91c2VsZWF2ZScpKSxcclxuICAgICAgdGFwKCgpID0+IHRoaXMuY2xvc2VNZW51KCkpXHJcbiAgICApXHJcbiAgICAgIC5zdWJzY3JpYmUoKTtcclxuXHJcbiAgICAvLyBTdWJzY3JpYmUgdG8gbW91c2VlbnRlciBldmVudCBvbiB0aGUgbWVudSBlbGVtZW50IHRvIG9wZW4gdGhlIG1lbnVcclxuICAgIHRoaXMubWVudUVsZW1lbnQkLnBpcGUoXHJcbiAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpLFxyXG4gICAgICBmaWx0ZXIoZWxlbWVudCA9PiAhIWVsZW1lbnQpLFxyXG4gICAgICBtZXJnZU1hcChlbGVtZW50ID0+IGZyb21FdmVudChlbGVtZW50LCAnbW91c2VlbnRlcicpKSxcclxuICAgICAgdGFwKCgpID0+IHRoaXMub3Blbk1lbnUoKSlcclxuICAgIClcclxuICAgICAgLnN1YnNjcmliZSgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBjbG9zZU1lbnUoKTogdm9pZCB7XHJcbiAgICB0aGlzLmNsb3NlciA9IHNldFRpbWVvdXQoKCkgPT4ge1xyXG4gICAgICB0aGlzLm1hdE1lbnVUcmlnZ2VyLmNsb3NlTWVudSgpO1xyXG4gICAgfSwgdGhpcy5jbG9zZURlbGF5KTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgb3Blbk1lbnUoKTogdm9pZCB7XHJcbiAgICBpZiAodGhpcy5jbG9zZXIpIHtcclxuICAgICAgY2xlYXJUaW1lb3V0KHRoaXMuY2xvc2VyKTtcclxuICAgIH1cclxuXHJcbiAgICB0aGlzLm1hdE1lbnVUcmlnZ2VyLm9wZW5NZW51KCk7XHJcbiAgfVxyXG59XHJcblxyXG4iXX0=
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './public-api';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibmd4LW1hdC1tZW51LWhvdmVyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vcHJvamVjdHMvbWF0LW1lbnUtaG92ZXIvc3JjL25neC1tYXQtbWVudS1ob3Zlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsY0FBYyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL3B1YmxpYy1hcGknO1xuIl19
@@ -0,0 +1,5 @@
1
+ /*
2
+ * Public API Surface of mat-menu-hover
3
+ */
4
+ export * from './lib/mat-menu-hover.directive';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHVibGljLWFwaS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3Byb2plY3RzL21hdC1tZW51LWhvdmVyL3NyYy9wdWJsaWMtYXBpLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOztHQUVHO0FBRUgsY0FBYyxnQ0FBZ0MsQ0FBQyIsInNvdXJjZXNDb250ZW50IjpbIi8qXHJcbiAqIFB1YmxpYyBBUEkgU3VyZmFjZSBvZiBtYXQtbWVudS1ob3ZlclxyXG4gKi9cclxuXHJcbmV4cG9ydCAqIGZyb20gJy4vbGliL21hdC1tZW51LWhvdmVyLmRpcmVjdGl2ZSc7XHJcblxyXG4iXX0=
@@ -0,0 +1,94 @@
1
+ import * as i0 from '@angular/core';
2
+ import { inject, DestroyRef, EventEmitter, Directive, Self, Input, Output, HostListener } from '@angular/core';
3
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
4
+ import { BehaviorSubject, filter, mergeMap, fromEvent, tap } from 'rxjs';
5
+ import * as i1 from '@angular/material/menu';
6
+
7
+ /**
8
+ * Directive to handle hover menu behavior.
9
+ */
10
+ class MatMenuHoverDirective {
11
+ onMouseEnter() {
12
+ this.openMenu();
13
+ // Get the menu element by ID and emit it to the observable
14
+ const element = document.querySelector(`#${this.menu.panelId}`);
15
+ if (element) {
16
+ this.menuElement$.next(element);
17
+ }
18
+ }
19
+ onMouseLeave() {
20
+ this.closeMenu();
21
+ }
22
+ constructor(matMenuTrigger) {
23
+ this.matMenuTrigger = matMenuTrigger;
24
+ this.destroyRef = inject(DestroyRef);
25
+ this.menuElement$ = new BehaviorSubject(null); // Observable for menu element
26
+ /**
27
+ * Delay (in milliseconds) before closing the menu after mouseleave.
28
+ */
29
+ this.closeDelay = 50; // Delay before closing the menu on mouseleave
30
+ /**
31
+ * Event emitter for notifying when the menu is opened.
32
+ */
33
+ this.opened = new EventEmitter();
34
+ }
35
+ ngOnInit() {
36
+ // Ensure MatMenuTrigger is present
37
+ if (!this.matMenuTrigger) {
38
+ console.error('There must be a MatMenuTrigger present.');
39
+ return;
40
+ }
41
+ // Assign the menu and disable backdrop
42
+ this.menu = this.matMenuTrigger.menu;
43
+ this.menu.hasBackdrop = false;
44
+ // Subscribe to mouseleave event on the menu element to close the menu
45
+ this.menuElement$.pipe(takeUntilDestroyed(this.destroyRef), filter(element => !!element), mergeMap(element => fromEvent(element, 'mouseleave')), tap(() => this.closeMenu()))
46
+ .subscribe();
47
+ // Subscribe to mouseenter event on the menu element to open the menu
48
+ this.menuElement$.pipe(takeUntilDestroyed(this.destroyRef), filter(element => !!element), mergeMap(element => fromEvent(element, 'mouseenter')), tap(() => this.openMenu()))
49
+ .subscribe();
50
+ }
51
+ closeMenu() {
52
+ this.closer = setTimeout(() => {
53
+ this.matMenuTrigger.closeMenu();
54
+ }, this.closeDelay);
55
+ }
56
+ openMenu() {
57
+ if (this.closer) {
58
+ clearTimeout(this.closer);
59
+ }
60
+ this.matMenuTrigger.openMenu();
61
+ }
62
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.2.1", ngImport: i0, type: MatMenuHoverDirective, deps: [{ token: i1.MatMenuTrigger, self: true }], target: i0.ɵɵFactoryTarget.Directive }); }
63
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.2.1", type: MatMenuHoverDirective, isStandalone: true, selector: "[matHoverMenu]", inputs: { closeDelay: "closeDelay" }, outputs: { opened: "opened" }, host: { listeners: { "mouseenter": "onMouseEnter()", "mouseleave": "onMouseLeave()" } }, ngImport: i0 }); }
64
+ }
65
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.2.1", ngImport: i0, type: MatMenuHoverDirective, decorators: [{
66
+ type: Directive,
67
+ args: [{
68
+ selector: '[matHoverMenu]',
69
+ standalone: true
70
+ }]
71
+ }], ctorParameters: () => [{ type: i1.MatMenuTrigger, decorators: [{
72
+ type: Self
73
+ }] }], propDecorators: { closeDelay: [{
74
+ type: Input
75
+ }], opened: [{
76
+ type: Output
77
+ }], onMouseEnter: [{
78
+ type: HostListener,
79
+ args: ['mouseenter']
80
+ }], onMouseLeave: [{
81
+ type: HostListener,
82
+ args: ['mouseleave']
83
+ }] } });
84
+
85
+ /*
86
+ * Public API Surface of mat-menu-hover
87
+ */
88
+
89
+ /**
90
+ * Generated bundle index. Do not edit.
91
+ */
92
+
93
+ export { MatMenuHoverDirective };
94
+ //# sourceMappingURL=ngx-mat-menu-hover.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ngx-mat-menu-hover.mjs","sources":["../../../projects/mat-menu-hover/src/lib/mat-menu-hover.directive.ts","../../../projects/mat-menu-hover/src/public-api.ts","../../../projects/mat-menu-hover/src/ngx-mat-menu-hover.ts"],"sourcesContent":["import { DestroyRef, Directive, EventEmitter, HostListener, Input, OnInit, Output, Self, inject } from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { MatMenuPanel, MatMenuTrigger } from '@angular/material/menu';\r\nimport { BehaviorSubject, filter, fromEvent, mergeMap, tap } from 'rxjs';\r\n\r\n/**\r\n * Directive to handle hover menu behavior.\r\n */\r\n@Directive({\r\n selector: '[matHoverMenu]',\r\n standalone: true\r\n})\r\nexport class MatMenuHoverDirective implements OnInit {\r\n private destroyRef = inject(DestroyRef);\r\n private menu: MatMenuPanel<any>; // Reference to the MatMenuPanel\r\n private menuElement$ = new BehaviorSubject<HTMLDivElement>(null); // Observable for menu element\r\n private closer: any;\r\n\r\n /**\r\n * Delay (in milliseconds) before closing the menu after mouseleave.\r\n */\r\n @Input() closeDelay = 50; // Delay before closing the menu on mouseleave\r\n\r\n /**\r\n * Event emitter for notifying when the menu is opened.\r\n */\r\n @Output() opened = new EventEmitter<boolean>();\r\n\r\n @HostListener('mouseenter')\r\n onMouseEnter(): void {\r\n this.openMenu();\r\n\r\n // Get the menu element by ID and emit it to the observable\r\n const element = document.querySelector(`#${this.menu.panelId}`) as HTMLDivElement;\r\n if (element) {\r\n this.menuElement$.next(element);\r\n }\r\n }\r\n\r\n @HostListener('mouseleave')\r\n onMouseLeave(): void {\r\n this.closeMenu();\r\n }\r\n\r\n constructor(@Self() private matMenuTrigger: MatMenuTrigger) { }\r\n\r\n ngOnInit(): void {\r\n // Ensure MatMenuTrigger is present\r\n if (!this.matMenuTrigger) {\r\n console.error('There must be a MatMenuTrigger present.');\r\n return;\r\n }\r\n\r\n // Assign the menu and disable backdrop\r\n this.menu = this.matMenuTrigger.menu;\r\n this.menu.hasBackdrop = false;\r\n\r\n // Subscribe to mouseleave event on the menu element to close the menu\r\n this.menuElement$.pipe(\r\n takeUntilDestroyed(this.destroyRef),\r\n filter(element => !!element),\r\n mergeMap(element => fromEvent(element, 'mouseleave')),\r\n tap(() => this.closeMenu())\r\n )\r\n .subscribe();\r\n\r\n // Subscribe to mouseenter event on the menu element to open the menu\r\n this.menuElement$.pipe(\r\n takeUntilDestroyed(this.destroyRef),\r\n filter(element => !!element),\r\n mergeMap(element => fromEvent(element, 'mouseenter')),\r\n tap(() => this.openMenu())\r\n )\r\n .subscribe();\r\n }\r\n\r\n private closeMenu(): void {\r\n this.closer = setTimeout(() => {\r\n this.matMenuTrigger.closeMenu();\r\n }, this.closeDelay);\r\n }\r\n\r\n private openMenu(): void {\r\n if (this.closer) {\r\n clearTimeout(this.closer);\r\n }\r\n\r\n this.matMenuTrigger.openMenu();\r\n }\r\n}\r\n\r\n","/*\r\n * Public API Surface of mat-menu-hover\r\n */\r\n\r\nexport * from './lib/mat-menu-hover.directive';\r\n\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
package/index.d.ts ADDED
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ /// <amd-module name="ngx-mat-menu-hover" />
5
+ export * from './public-api';
@@ -0,0 +1,29 @@
1
+ import { EventEmitter, OnInit } from '@angular/core';
2
+ import { MatMenuTrigger } from '@angular/material/menu';
3
+ import * as i0 from "@angular/core";
4
+ /**
5
+ * Directive to handle hover menu behavior.
6
+ */
7
+ export declare class MatMenuHoverDirective implements OnInit {
8
+ private matMenuTrigger;
9
+ private destroyRef;
10
+ private menu;
11
+ private menuElement$;
12
+ private closer;
13
+ /**
14
+ * Delay (in milliseconds) before closing the menu after mouseleave.
15
+ */
16
+ closeDelay: number;
17
+ /**
18
+ * Event emitter for notifying when the menu is opened.
19
+ */
20
+ opened: EventEmitter<boolean>;
21
+ onMouseEnter(): void;
22
+ onMouseLeave(): void;
23
+ constructor(matMenuTrigger: MatMenuTrigger);
24
+ ngOnInit(): void;
25
+ private closeMenu;
26
+ private openMenu;
27
+ static ɵfac: i0.ɵɵFactoryDeclaration<MatMenuHoverDirective, [{ self: true; }]>;
28
+ static ɵdir: i0.ɵɵDirectiveDeclaration<MatMenuHoverDirective, "[matHoverMenu]", never, { "closeDelay": { "alias": "closeDelay"; "required": false; }; }, { "opened": "opened"; }, never, never, true, never>;
29
+ }
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "ngx-mat-menu-hover",
3
+ "version": "1.0.0",
4
+ "peerDependencies": {
5
+ "@angular/common": "^17.2.0",
6
+ "@angular/core": "^17.2.0",
7
+ "@angular/material": "^17.2.0"
8
+ },
9
+ "dependencies": {
10
+ "tslib": "^2.3.0"
11
+ },
12
+ "sideEffects": false,
13
+ "module": "fesm2022/ngx-mat-menu-hover.mjs",
14
+ "typings": "index.d.ts",
15
+ "exports": {
16
+ "./package.json": {
17
+ "default": "./package.json"
18
+ },
19
+ ".": {
20
+ "types": "./index.d.ts",
21
+ "esm2022": "./esm2022/ngx-mat-menu-hover.mjs",
22
+ "esm": "./esm2022/ngx-mat-menu-hover.mjs",
23
+ "default": "./fesm2022/ngx-mat-menu-hover.mjs"
24
+ }
25
+ }
26
+ }
@@ -0,0 +1 @@
1
+ export * from './lib/mat-menu-hover.directive';