UNPKG

@dotglitch/ngx-ctx-menu

Version:

Angular context menu that works with templates

1 lines 69.4 kB
{"version":3,"file":"dotglitch-ngx-ctx-menu.mjs","sources":["../../src/lib/context-menu/context-menu.component.ts","../../src/lib/context-menu/context-menu.component.html","../../src/lib/utils.ts","../../src/lib/appmenu.directive.ts","../../src/lib/ctxmenu.directive.ts","../../src/lib/tooltip/tooltip.component.ts","../../src/lib/tooltip/tooltip.component.html","../../src/lib/tooltip.directive.ts","../../src/index.ts","../../src/dotglitch-ngx-ctx-menu.ts"],"sourcesContent":["import { CommonModule, NgForOf, NgIf, NgTemplateOutlet } from '@angular/common';\nimport { ChangeDetectorRef, Component, EventEmitter, HostListener, Inject, Input, OnInit, Optional, Output, TemplateRef, Type, ViewContainerRef } from '@angular/core';\nimport { DomSanitizer, createApplication } from '@angular/platform-browser';\nimport { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';\nimport { MatIconModule } from '@angular/material/icon';\nimport { MatProgressSpinnerModule } from '@angular/material/progress-spinner';\n\nimport { ContextMenuItem } from '../types';\nimport { NgxAppMenuDirective, NgxAppMenuOptions } from '../appmenu.directive';\nimport { ComponentPortal, PortalModule } from '@angular/cdk/portal';\nimport { firstValueFrom } from 'rxjs';\n\nexport const calcMenuItemBounds = async (menuItems: ContextMenuItem[], dataObj: any) => {\n const data = {\n data: dataObj,\n items: menuItems,\n config: {},\n id: null\n }\n\n return calcComponentBounds(ContextMenuComponent, data);\n}\n\nconst calcComponentBounds = async (component: Type<any>, data: any) => {\n // Forcibly bootstrap the ctx menu outside of the client application's zone.\n const app = await createApplication({\n providers: [\n { provide: MAT_DIALOG_DATA, useValue: data }\n ]\n });\n\n const del = document.createElement(\"div\");\n del.style.position = \"absolute\";\n del.style.left = '-1000vw';\n document.body.append(del);\n\n const base = app.bootstrap(component, del);\n const { instance } = base;\n\n await firstValueFrom(app.isStable);\n\n const el: HTMLElement = instance.viewContainer?.element?.nativeElement;\n\n const rect = el.getBoundingClientRect();\n app.destroy();\n del.remove();\n return rect;\n}\n\n@Component({\n selector: 'ngx-ctx-menu-template-container',\n template: `\n <ng-container *ngIf=\"templateType == 'template'; else portalOutlet\">\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{ '$implicit': data, dialog: dialogRef }\"\n />\n </ng-container>\n <ng-template #portalOutlet [cdkPortalOutlet]=\"componentPortal\" ></ng-template>\n`,\n imports: [ NgTemplateOutlet, PortalModule, NgIf ],\n standalone: true\n})\nclass TemplateWrapper {\n\n data: Object;\n template: TemplateRef<any>;\n\n templateType: \"template\" | \"component\"\n componentPortal: ComponentPortal<any>;\n\n constructor(\n @Optional() public dialogRef: MatDialogRef<any>,\n @Inject(MAT_DIALOG_DATA) private _data: any,\n public viewContainer: ViewContainerRef\n ) {\n this.data = _data.data;\n this.template = _data.template;\n\n // TODO: This is probably invalid\n this.templateType = this.template instanceof TemplateRef ? \"template\" : \"component\";\n\n if (this.templateType == \"component\") {\n this.componentPortal = new ComponentPortal(this.template as any);\n }\n }\n}\n\n@Component({\n selector: 'ngx-ctx-menu',\n templateUrl: './context-menu.component.html',\n styleUrls: ['./context-menu.component.scss'],\n imports: [\n NgIf,\n NgForOf,\n NgTemplateOutlet,\n MatIconModule,\n MatProgressSpinnerModule\n ],\n standalone: true\n})\nexport class ContextMenuComponent implements OnInit {\n @Input() public data: any;\n @Input() public parentCords: DOMRect;\n @Input() public items: ContextMenuItem[];\n @Input() public config: NgxAppMenuOptions;\n @Input() public id: string;\n\n @Output() closeSignal = new EventEmitter();\n\n selfCords: DOMRect;\n // Check if there are any slashes or dots -- that will clearly exclude it from being a mat icon\n public readonly matIconRx = /[\\/\\.]/i;\n showIconColumn = true;\n showShortcutColumn = true;\n\n constructor(\n public viewContainer: ViewContainerRef,\n public sanitizer: DomSanitizer,\n @Optional() @Inject(MAT_DIALOG_DATA) private _data: any,\n @Optional() public dialog: MatDialog, // optional only for the purpose of estimating dimensions\n @Optional() public dialogRef: MatDialogRef<any>,\n private changeDetector: ChangeDetectorRef\n ) {\n // Defaults are set before @Input() hooks evaluate\n this.data = this._data?.data;\n this.parentCords = this._data?.parentCords;\n this.items = this._data?.items;\n this.config = this._data?.config;\n this.id = this._data?.id;\n }\n\n ngOnInit() {\n this.items?.forEach(i => {\n if (typeof i == \"string\") return;\n\n // Set defaults\n i['_disabled'] = false;\n i['_visible'] = true;\n\n if (i.label)\n try { i['_formattedLabel'] = this.formatLabel(i.label); } catch (e) { console.warn(e) }\n\n if (typeof i.isDisabled == \"function\")\n try { i['_disabled'] = i.isDisabled(this.data || {}); } catch(e) { console.warn(e) }\n\n if (typeof i.isVisible == \"function\")\n try { i['_visible'] = i.isVisible(this.data || {}); } catch (e) { console.warn(e) }\n\n if (typeof i.linkTemplate == \"function\")\n try { i['_link'] = i.linkTemplate(this.data || {}); } catch (e) { console.warn(e) }\n });\n\n // Show the icon column if there are any items with an icon\n this.showIconColumn = !!this.items.find(i =>\n typeof i == \"object\" &&\n typeof i['icon'] == \"string\" &&\n i['icon'].length > 2\n );\n\n this.showShortcutColumn = !!this.items.find(i =>\n typeof i == \"object\" &&\n typeof i['shortcut'] == \"string\" &&\n i['shortcut'].length > 2\n );\n\n // setTimeout(() => {\n // this.closeOnLeave = true\n // }, 300);\n }\n\n ngAfterViewInit() {\n if (this.parentCords) {\n this.selfCords = this.viewContainer?.element?.nativeElement?.getBoundingClientRect();\n this.changeDetector.detectChanges();\n }\n }\n\n /**\n *\n * @param item\n * @param evt\n * @returns\n */\n async onMenuItemClick(item: ContextMenuItem, row: HTMLTableRowElement, hideBackdrop = false) {\n if (typeof item == 'string') return null;\n if (item.separator) return null;\n\n // If cache is enabled, only load if we don't have any children.\n const forceLoad = (item.cacheResolvedChildren ? !item.children : true);\n\n if (item.childrenResolver && forceLoad) {\n item['_isResolving'] = true;\n item.children = await item.childrenResolver(this.data);\n item['_isResolving'] = false;\n }\n\n if (!item.childTemplate && !item.children) {\n if (item.action) {\n item.action(this.data);\n this.close();\n }\n // If no action, this is simply a text item.\n\n return null;\n }\n\n // Need X pos, Y pos, width and height\n const bounds = row.getBoundingClientRect();\n\n const cords = {\n top: null,\n left: null,\n bottom: null,\n right: null\n };\n\n // Set position coordinates\n const { width, height } = await (item.childTemplate\n ? calcComponentBounds(TemplateWrapper, { template: item.childTemplate })\n : calcMenuItemBounds(item.children, this.data));\n\n if (bounds.y + height > window.innerHeight)\n cords.bottom = \"0px\";\n if (bounds.x + bounds.width + width > window.innerWidth)\n cords.left = ((bounds.x - width)) + \"px\";\n\n if (!cords.bottom) cords.top = bounds.y + \"px\";\n if (!cords.left) cords.left = bounds.x + bounds.width + \"px\";\n\n const component = item.children ? ContextMenuComponent : TemplateWrapper as any;\n\n const dialogRef = this.dialog.open(component, {\n position: cords,\n panelClass: [\"ngx-ctx-menu\", \"ngx-app-menu\"].concat(this.config?.customClass || []),\n backdropClass: \"ngx-ctx-menu-backdrop\",\n hasBackdrop: !hideBackdrop,\n data: {\n data: this.data,\n parentCords: this.viewContainer?.element?.nativeElement?.getBoundingClientRect(),\n items: item.children,\n template: item.childTemplate,\n config: this.config\n }\n });\n\n let _s = dialogRef\n .afterClosed()\n .subscribe((result) => {\n if (result != -1) {\n if (result && typeof item.action == 'function')\n item.action(result);\n\n this.close();\n }\n else {\n item['_selfclose'] = Date.now();\n }\n\n _s.unsubscribe();\n });\n\n return dialogRef;\n }\n\n /**\n *\n * @param label\n * @returns\n */\n formatLabel(label: string): string {\n return label.replace(/_([a-z0-9])_/i, (match, group) => `<u>${group}</u>`);\n }\n\n /**\n * Close the context menu under these circumstances\n */\n // @HostListener(\"window:resize\", ['event'])\n // @HostListener(\"window:blur\", ['event'])\n close() {\n this.closeSignal.emit();\n\n this.dialogRef?.close();\n }\n\n /**\n * Check if the dialog is clipping offscreen\n * if so, move it back into view.\n */\n @HostListener(\"window:resize\")\n private onResize() {\n const el = this.viewContainer?.element?.nativeElement as HTMLElement;\n if (!el) return;\n\n const { width, height, x, y } = el.getBoundingClientRect();\n\n const target = document.querySelector(\".ngx-ctx-menu,.ngx-app-menu\") as HTMLElement;\n if (!target) return;\n\n // Move back into view if we're clipping outside of the bottom\n if (y + height > window.innerHeight) {\n const newTop = (window.innerHeight - (height + (this.config.edgePadding || 12))) + \"px\";\n target.style['margin-top'] = newTop;\n }\n\n // Move back into view if we're clipping off the right\n if (x + width > window.innerWidth) {\n const newLeft = (window.innerWidth - (width + (this.config.edgePadding || 12))) + \"px\"\n target.style['margin-left'] = newLeft;\n }\n }\n\n // private hoveredItems: MatDialogRef<any>[];\n // async onHover(item, row: HTMLTableRowElement) {\n // this.hoveredItems.forEach(i => i.close(-1));\n\n // if (typeof item['_selfclose'] == 'number' && (Date.now() - item['_selfclose']) < 3*1000) return;\n\n // const hi = await this.onMenuItemClick(item, row, true);\n // this.hoveredItems.push(hi);\n\n // hi.afterClosed().toPromise().then(e => {\n // this.viewContainer.element.nativeElement.focus();\n // this.hoveredItems.splice(this.hoveredItems.findIndex(i => i == hi), 1);\n // })\n // }\n\n // closeOnLeave = false;\n // async onLeave() {\n // if (this.closeOnLeave) {\n // if (this.hoveredItems.length > 0) {\n // this.hoveredItems.forEach(i => i.close(-1));\n // this.hoveredItems.splice(0);\n // }\n // else {\n // this.closeSignal.next(-1);\n\n // this.dialogRef.close(-1);\n // }\n // }\n // }\n}\n","<table>\n <tbody>\n <ng-container *ngFor=\"let item of items\">\n <ng-container>\n\n <!-- A row with a click action -->\n <tr #row\n *ngIf=\"item != 'separator' && item.separator != true && item['_visible']\"\n [class.disabled]=\"item['_disabled']\"\n (click)=\"!item['_disabled'] && onMenuItemClick(item, row)\"\n [class.hover]=\"item['children'] && row['hover']\"\n (pointerenter)=\"row['hover'] = true;\"\n (pointerleave)=\"row['hover'] = false\"\n >\n <!-- (item['children']?.length > 0 || item['childTemplate']) && onHover(item, row); closeOnLeave=true -->\n <td class=\"icon\" *ngIf=\"showIconColumn\">\n <img *ngIf=\"matIconRx.test(item.icon); else matIcon\" [src]=\"item.icon\" />\n <ng-template #matIcon>\n <mat-icon [fontIcon]=\"item.icon\"></mat-icon>\n </ng-template>\n </td>\n\n <!-- 'Normal' action based item -->\n <ng-container>\n <td class=\"label\"\n [style.padding-left]=\"showIconColumn ? 0 : '16px'\"\n >\n <a\n [attr.target]=\"item.linkTarget\"\n [attr.href]=\"(item['_link'] || item.link) ? sanitizer.bypassSecurityTrustUrl(item['_link'] || item.link) : undefined\"\n >\n <ng-container\n *ngIf=\"$any(item.labelTemplate)?.prototype; else labelTemplate\"\n [ngTemplateOutlet]=\"$any(item).labelTemplate\"\n [ngTemplateOutletContext]=\"{ '$implicit': data, 'dialog': dialogRef }\"\n />\n\n <ng-template #labelTemplate>\n <ng-container *ngIf=\"!$any(item)?.labelTemplate\">\n <div [innerHTML]=\"item['_formattedLabel']\"></div>\n </ng-container>\n <ng-container *ngIf=\"$any(item)?.labelTemplate\">\n {{$any(item)?.labelTemplate(data || {})}}\n </ng-container>\n </ng-template>\n </a>\n </td>\n </ng-container>\n\n <td class=\"shortcut\" *ngIf=\"showShortcutColumn\">\n {{item.shortcutLabel}}\n </td>\n <td style=\"min-width: 16px\">\n <mat-icon *ngIf=\"\n (item.children && item.children.length > 0) ||\n item.childTemplate ||\n (item.childrenResolver && !item['_isResolving'])\n \"\n sytle=\"transform: translateY(2px)\"\n >\n chevron_right\n </mat-icon>\n\n <mat-progress-spinner *ngIf=\"item['_isResolving']\" mode=\"indeterminate\" [diameter]=\"20\" style=\"margin-right: 4px\"/>\n </td>\n </tr>\n\n <tr *ngIf=\"item != 'separator' && item.separator == true\" class=\"disabled separator\">\n <td class=\"center\" [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\">\n <span class=\"hr\">\n {{item['label'] || ''}}\n </span>\n </td>\n </tr>\n <tr *ngIf=\"item == 'separator'\" class=\"disabled separator\">\n <td [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\">\n <hr/>\n </td>\n </tr>\n </ng-container>\n </ng-container>\n </tbody>\n</table>\n\n<!-- <div *ngIf=\"true\" class=\"backdrop\"></div> -->\n<!-- <div\n *ngIf=\"parentCords && this.selfCords\"\n class=\"backdrop parent\"\n [style.top]=\"(parentCords.y - selfCords.y + 6) + 'px'\"\n [style.left]=\"(parentCords.x - selfCords.x + 12) + 'px'\"\n [style.width]=\"(parentCords.width) + 'px'\"\n [style.height]=\"(parentCords.height) + 'px'\"\n>\n</div> -->\n<!-- <ng-container *ngIf=\"parentCords && selfCords\">\n <div #top\n class=\"backdrop-outer\"\n [style.bottom]=\"(parentCords.y - selfCords.y)*-1 + parentCords.height + 'px'\"\n style=\"background: #f003;\"\n (pointerenter)=\"onLeave()\"\n ></div>\n <div #right\n class=\"backdrop-outer\"\n [style.left]=\"((parentCords.x - selfCords.x) + parentCords.width) + 'px'\"\n style=\"background: #0f03;\"\n (pointerenter)=\"onLeave()\"\n >\n <div>px: {{parentCords.x}}</div>\n <div>py: {{parentCords.y}}</div>\n <div>pw: {{parentCords.width}}</div>\n <div>ph: {{parentCords.height}}</div>\n <div>sx: {{selfCords.x}}</div>\n <div>sy: {{selfCords.y}}</div>\n <div>sw: {{selfCords.width}}</div>\n <div>sh: {{selfCords.height}}</div>\n </div>\n <div #bottom\n class=\"backdrop-outer\"\n [style.top]=\"((parentCords.y + parentCords.height - selfCords.y)) + 'px'\"\n style=\"background: #00f3;\"\n (pointerenter)=\"onLeave()\"\n ></div>\n <div #left\n class=\"backdrop-outer\"\n [style.right]=\"((parentCords.x - selfCords.x)*-1 + parentCords.width + 32) + 'px'\"\n style=\"background: #fff3;\"\n (pointerenter)=\"onLeave()\"\n ></div>\n</ng-container> -->\n","\n\nexport const getPosition = (el: HTMLElement | PointerEvent, config: any = {}, bounds: DOMRect) => {\n // Bounds of the popup owner\n const src: DOMRect = !!el['nodeName']\n ? (el as HTMLElement).getBoundingClientRect()\n : {\n // It's a pointer event, so we'll take the X and Y from the pointer.\n x: el['clientX'],\n y: el['clientY'],\n // Set a default tiny size, so we don't divide by zero.\n width: 0.0001,\n height: 0.0001\n } as DOMRect;\n\n // Popup bounds\n const { width, height } = bounds;\n\n const winh = window.innerHeight;\n const winw = window.innerWidth;\n\n const cords = {\n top: null,\n left: null\n };\n\n if (config?.position == \"left\" || config?.position == \"right\" || !config?.position) {\n switch (config?.alignment) {\n\n case \"end\": {\n // vertically bind to bottom\n cords.top = src.y + src.height - height;\n break;\n }\n case \"afterend\": {\n // vertically bind below bottom\n cords.top = src.y + src.height;\n break;\n }\n case \"beforestart\": {\n // vertically bind above top\n cords.top = src.y - height;\n break;\n }\n case \"start\": {\n // vertically bind to top\n cords.top = src.y;\n break;\n }\n case \"center\":\n default: {\n // vertically center\n cords.top = (src.y + (src.height / 2)) - (height / 2);\n break;\n }\n }\n\n // Apply bounds to prevent the dialog from being cut-off screen\n // Lower bound\n cords.top = Math.max(config?.edgePadding || 0, cords.top);\n // Upper bound\n cords.top = Math.min(winh - height, cords.top);\n\n if (config?.position == \"left\") {\n cords.left = src.x - (width + (config?.arrowSize || 0) + (config?.arrowPadding || 0));\n }\n if (config?.position == \"right\" || !config?.position) {\n cords.left = src.x + (src.width + (config?.arrowSize || 0) + (config?.arrowPadding || 0));\n }\n\n // Lower bound\n cords.left = Math.max(config?.edgePadding || 0, cords.left);\n // Upper bound\n cords.left = Math.min(winw - width, cords.left);\n }\n else if (config?.position == \"top\" || config?.position == \"bottom\") {\n switch (config?.alignment) {\n case \"end\": {\n // vertically bind to right\n cords.left = src.x + src.width - width;\n break;\n }\n case \"afterend\": {\n // vertically bind past right\n cords.left = src.x + src.width;\n break;\n }\n case \"beforestart\": {\n // vertically bind before left\n cords.left = src.x - width;\n break;\n }\n case \"start\": {\n // vertically bind to left\n cords.left = src.x;\n break;\n }\n case \"center\":\n default: {\n // vertically center\n cords.left = (src.x + (src.width / 2)) - (width / 2);\n break;\n }\n }\n\n // Apply bounds to prevent the dialog from being cut-off screen\n // Lower bound\n cords.left = Math.max(config?.edgePadding || 0, cords.left);\n // Upper bound\n cords.left = Math.min(winw - width, cords.left);\n\n\n if (config?.position == \"top\") {\n cords.top = src.y - (height + (config?.arrowSize || 0) + (config?.arrowPadding || 0));\n }\n if (config?.position == \"bottom\") {\n cords.top = src.y + (src.height + (config?.arrowSize || 0) + (config?.arrowPadding || 0));\n }\n\n // Lower bound\n cords.top = Math.max(config?.edgePadding || 0, cords.top);\n // Upper bound\n cords.top = Math.min(winh - height, cords.top);\n }\n\n // Assign unit\n cords.top = cords.top + 'px';\n cords.left = cords.left + 'px';\n\n return cords;\n}\n","import { Directive, Input, HostListener, ViewContainerRef, AfterViewInit } from '@angular/core';\nimport { MatDialog } from '@angular/material/dialog';\nimport { calcMenuItemBounds, ContextMenuComponent } from './context-menu/context-menu.component';\nimport { ContextMenuItem } from './types';\nimport { getPosition } from './utils';\n\nexport type NgxAppMenuTriggers = \"click\" | \"dblclick\" | \"hover\" | \"contextmenu\";\n\nexport type NgxAppMenuOptions = Partial<{\n /**\n * Position relative to the element the menu pops-up at.\n */\n position: \"top\" | \"right\" | \"bottom\" | \"left\",\n /**\n * How the popup is aligned relative to the element.\n */\n alignment: \"center\" | \"beforestart\" | \"start\" | \"end\" | \"afterend\",\n /**\n * @hidden\n * WIP:\n * Show an error from the dialog pointing to the element.\n */\n showArrow: boolean,\n /**\n * @hidden\n * WIP:\n * Size of the arrow.\n */\n arrowSize: number,\n /**\n * How much padding to add near the edges of the screen.\n */\n edgePadding: number,\n /**\n * Which event should trigger the app menu.\n */\n trigger: NgxAppMenuTriggers | NgxAppMenuTriggers[];\n /**\n * A list of custom classes to add to the dialog popups.\n */\n customClass: string[]\n}>;\n\n@Directive({\n selector: '[ngx-app-menu]',\n standalone: true\n})\nexport class NgxAppMenuDirective implements AfterViewInit {\n\n /**\n * The items that will be bound to the menu.\n */\n @Input(\"ngx-app-menu\") menuItems: ContextMenuItem[];\n\n /**\n * The data representing the item the context-menu was opened for.\n */\n @Input(\"ngx-app-menu-context\") data: any;\n\n /**\n * Configuration for opening the app menu\n */\n @Input(\"ngx-app-menu-config\") config: NgxAppMenuOptions = {};\n\n constructor(\n private dialog: MatDialog,\n private viewContainer: ViewContainerRef\n ) { }\n\n ngAfterViewInit() {\n const el = this.viewContainer.element.nativeElement as HTMLElement;\n\n if (!this.config?.trigger) {\n el.onclick = this.openDialog.bind(this);\n }\n else {\n const triggers = Array.isArray(this.config.trigger) ? this.config.trigger : [this.config.trigger];\n\n triggers.forEach(t => {\n if (t == \"contextmenu\") {\n el.addEventListener(t, (e) => {\n e.preventDefault();\n this.openDialog(e);\n });\n }\n else {\n el.addEventListener(t, this.openDialog.bind(this));\n }\n });\n }\n }\n\n // Needs to be public so we can manually open the dialog\n private async openDialog(evt: MouseEvent) {\n const el = this.viewContainer.element.nativeElement as HTMLElement;\n\n const cords = getPosition(el, this.config, await calcMenuItemBounds(this.menuItems, this.data));\n\n const specificId = crypto.randomUUID();\n\n el.classList.add(\"ngx-app-menu-open\");\n\n // Create the context menu\n let _s = this.dialog.open(ContextMenuComponent, {\n data: {\n data: this.data,\n items: this.menuItems,\n // dialog: this.dialog\n config: this.config,\n id: specificId\n },\n panelClass: [\"ngx-app-menu\", \"ngx-ctx-menu\", 'ngx-' + specificId].concat(this.config?.customClass || []),\n position: cords,\n backdropClass: \"ngx-app-menu-backdrop\"\n })\n .afterClosed() // What a stupid thing to make an observable.\n .subscribe(() => {\n _s.unsubscribe();\n\n el.classList.remove(\"ngx-app-menu-open\");\n })\n }\n}\n","import { Directive, Input, HostListener, TemplateRef, ViewContainerRef } from '@angular/core';\nimport { MAT_DIALOG_DATA, MatDialog, MAT_DIALOG_SCROLL_STRATEGY_PROVIDER } from '@angular/material/dialog';\nimport { calcMenuItemBounds, ContextMenuComponent } from './context-menu/context-menu.component';\nimport { ContextMenuItem } from './types';\nimport { NgxAppMenuOptions } from './appmenu.directive';\nimport { createApplication } from '@angular/platform-browser';\nimport { getPosition } from './utils';\n\n@Directive({\n selector: '[ngx-ctx-menu]',\n providers: [\n MatDialog\n ],\n standalone: true\n})\nexport class NgxContextMenuDirective {\n\n /**\n * The data representing the item the context-menu was opened for.\n */\n @Input(\"ngx-ctx-menu-context\") data: any;\n\n /**\n * The items that will be bound to the context menu.\n */\n @Input(\"ngx-ctx-menu\") menuItems: ContextMenuItem[];\n\n /**\n * Configuration for opening the app menu\n */\n @Input(\"ngx-ctx-menu-config\") config: NgxAppMenuOptions = {};\n\n constructor(\n private dialog: MatDialog,\n private viewContainer: ViewContainerRef\n ) { }\n\n // Needs to be public so we can manually open the dialog\n @HostListener('contextmenu', ['$event'])\n public async onContextMenu(evt: PointerEvent) {\n const el = this.viewContainer.element.nativeElement as HTMLElement;\n\n el.classList.add(\"ngx-app-menu-open\");\n\n return openContextMenu(this.dialog, this.menuItems, this.data, evt, this.config)\n .finally(() => {\n el.classList.remove(\"ngx-app-menu-open\");\n });\n }\n}\n\n// Helper to open the context menu without using the directive.\nexport const openContextMenu = async (dialog: MatDialog, menuItems: ContextMenuItem[], data: any, evt: PointerEvent, config: NgxAppMenuOptions = {}) => {\n evt.preventDefault();\n evt.stopPropagation();\n\n const cords = getPosition(evt, config, await calcMenuItemBounds(menuItems, data));\n const specificId = crypto.randomUUID();\n\n if (!config.alignment) config.alignment = \"start\";\n\n return new Promise(res => {\n dialog.open(ContextMenuComponent, {\n data: {\n data: data,\n items: menuItems,\n config: config,\n id: specificId\n },\n panelClass: [\"ngx-ctx-menu\", 'ngx-' + specificId].concat(config?.customClass || []),\n position: cords,\n backdropClass: \"ngx-ctx-menu-backdrop\"\n })\n .afterClosed()\n .subscribe(s => {\n res(s);\n })\n }) as Promise<any>;\n};\n","import { CommonModule } from '@angular/common';\nimport { Component, HostListener, Inject, Input, TemplateRef, Type, ViewContainerRef } from '@angular/core';\nimport { MatDialog, MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog';\nimport { NgxTooltipOptions } from '../tooltip.directive';\nimport { Optional } from '@angular/core';\nimport { createApplication } from '@angular/platform-browser';\nimport { firstValueFrom } from 'rxjs';\n\nexport const calcTooltipBounds = async (template: TemplateRef<any> | Type<any>, data) => {\n const args = {\n data: data || {},\n template,\n config: {},\n selfCords: { left: \"0px\", top: \"0px\" },\n ownerCords: { x: 0, y: 0, width: 0, height: 0 },\n id: null\n }\n // Forcibly bootstrap the ctx menu outside of the client application's zone.\n const app = await createApplication({\n providers: [\n { provide: MAT_DIALOG_DATA, useValue: args }\n ]\n });\n\n const del = document.createElement(\"div\");\n del.style.position = \"absolute\";\n del.style.left = '-1000vw';\n document.body.append(del);\n\n const base = app.bootstrap(TooltipComponent, del);\n const { instance } = base;\n\n await firstValueFrom(app.isStable);\n\n const el: HTMLElement = instance.viewContainer?.element?.nativeElement;\n\n const rect = el.getBoundingClientRect();\n app.destroy();\n del.remove();\n\n return rect;\n}\n\n\n@Component({\n selector: 'ngx-tooltip',\n templateUrl: './tooltip.component.html',\n styleUrls: ['./tooltip.component.scss'],\n imports: [\n // NgIf,\n // NgTemplateOutlet,\n // NgComponentOutlet,\n CommonModule,\n ],\n standalone: true\n})\nexport class TooltipComponent {\n @Input() data: any;\n @Input() config: NgxTooltipOptions;\n @Input() ownerCords: DOMRect;\n @Input() selfCords;\n @Input() template: TemplateRef<any> | Type<any>;\n\n isTemplate: boolean;\n hasBootstrapped = false;\n pointerIsOnVoid = false;\n\n coverRectCords = {\n top: 0,\n left: 0,\n height: 0,\n width: 0\n }\n\n constructor(\n public viewContainer: ViewContainerRef,\n @Optional() @Inject(MAT_DIALOG_DATA) private _data: any,\n @Optional() public dialog: MatDialog, // optional only for the purpose of estimating dimensions\n @Optional() public dialogRef: MatDialogRef<any>,\n ) {\n // Defaults are set before @Input() hooks evaluate\n this.data = this.data || this._data?.data || {};\n this.config = this.config || this._data?.config;\n this.template = this.template || this._data?.template;\n this.ownerCords = this.ownerCords || this._data?.ownerCords;\n this.selfCords = this.selfCords || this._data?.selfCords;\n }\n\n ngOnInit() {\n\n const selfY = parseInt(this.selfCords.top.replace('px', ''));\n const selfX = parseInt(this.selfCords.left.replace('px', ''));\n\n this.coverRectCords = {\n top: this.ownerCords.y - selfY - 16,\n left: this.ownerCords.x - selfX - 16,\n height: this.ownerCords.height + 32,\n width: this.ownerCords.width + 32\n }\n\n if (this.template instanceof TemplateRef)\n this.isTemplate = true;\n else if (typeof this.template == \"function\")\n this.isTemplate = false;\n else\n throw new Error(\"Unrecognized template object provided.\");\n\n // TODO: resolve the event hook with the .void element\n setTimeout(() => {\n this.hasBootstrapped = true;\n if (this.pointerIsOnVoid)\n this.dialogRef.close();\n }, 10);\n }\n\n /**\n * Close the tooltip if these actions occur\n */\n @HostListener(\"window:resize\")\n @HostListener(\"window:blur\")\n private onClose() {\n this.dialogRef?.close();\n }\n\n @HostListener(\"pointerleave\")\n private onPointerLeave() {\n\n this.dialogRef?.close();\n }\n}\n","<!-- Mouse event blocker for pointer leave -->\n<div\n *ngIf=\"coverRectCords\"\n class=\"owner-mask\"\n [style.top]=\"coverRectCords.top + 'px'\"\n [style.left]=\"coverRectCords.left + 'px'\"\n [style.height]=\"coverRectCords.height + 'px'\"\n [style.width]=\"coverRectCords.width + 'px'\"\n style=\"z-index: -1;\"\n></div>\n\n<div class=\"void\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && dialogRef.close()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && dialogRef.close()\"\n></div>\n\n<div class=\"container\">\n <ng-container\n *ngIf=\"isTemplate == false\"\n [ngComponentOutlet]=\"$any(template)\"\n >\n </ng-container>\n\n <ng-container\n *ngIf=\"isTemplate == true\"\n >\n <ng-container\n [ngTemplateOutlet]=\"$any(template)\"\n [ngTemplateOutletContext]=\"{ '$implicit': data }\"\n ></ng-container>\n </ng-container>\n</div>\n","import { Directive, Input, HostListener, TemplateRef, Type, ViewContainerRef } from '@angular/core';\nimport { MatDialog, MatDialogRef } from '@angular/material/dialog';\nimport { TooltipComponent, calcTooltipBounds } from './tooltip/tooltip.component';\nimport { getPosition } from './utils';\n\nexport type NgxTooltipOptions = Partial<{\n /**\n * Position relative to the element the menu pops-up at\n */\n position: \"top\" | \"right\" | \"bottom\" | \"left\",\n /**\n * How the popup is aligned relative to the element\n */\n alignment: \"center\" | \"beforestart\" | \"start\" | \"end\" | \"afterend\",\n /**\n * @hidden\n * WIP:\n * Show an error from the dialog pointing to the element\n */\n showArrow: boolean,\n /**\n * @hidden\n * WIP:\n * Size of the arrow.\n */\n arrowSize: number,\n /**\n * How much padding to add near the edges of the screen.\n */\n edgePadding: number,\n\n customClass: string[]\n}>;\n\n@Directive({\n selector: '[ngxTooltip],[ngx-tooltip]',\n providers: [\n MatDialog\n ],\n standalone: true\n})\nexport class NgxTooltipDirective {\n\n /**\n */\n @Input(\"ngxTooltip\")\n @Input(\"ngx-tooltip\") template: TemplateRef<any> | Type<any>;\n\n /**\n * Configuration for opening the app menu\n */\n @Input(\"ngxTooltipConfig\")\n @Input(\"ngx-tooltip-config\") config: NgxTooltipOptions = {};\n\n /**\n * Arbitrary data to pass into the template\n */\n @Input(\"ngxTooltipContext\")\n @Input(\"ngx-tooltip-context\") data: any = {};\n\n constructor(\n private dialog: MatDialog,\n private viewContainer: ViewContainerRef\n ) {\n }\n\n ngOnInit() {\n }\n\n private dialogInstance: MatDialogRef<any>;\n\n // Needs to be public so we can manually open the dialog\n @HostListener('pointerenter', ['$event'])\n public async onPointerEnter(evt: PointerEvent) {\n // If the template is not a template ref, do nothing.\n if (!(this.template instanceof TemplateRef))\n return;\n\n const el = this.viewContainer.element.nativeElement;\n this.dialogInstance = await openTooltip(this.dialog, this.template, this.data, el, this.config);\n }\n}\n\n// Helper to open the context menu without using the directive.\nexport const openTooltip = async (\n dialog: MatDialog,\n template: TemplateRef<any> | Type<any>,\n data: any,\n el: HTMLElement,\n config?: NgxTooltipOptions\n) => {\n\n const rect = await calcTooltipBounds(template, data);\n const ownerCords = el.getBoundingClientRect();\n const cords = getPosition(el, config, rect);\n const specificId = crypto.randomUUID();\n\n return new Promise(res => {\n dialog.open(TooltipComponent, {\n data: {\n data: data,\n template: template,\n config: config,\n ownerCords: ownerCords,\n selfCords: cords,\n id: specificId\n },\n panelClass: [\"ngx-tooltip\", 'ngx-' + specificId].concat(config?.customClass || []),\n position: cords,\n hasBackdrop: false\n })\n .afterClosed()\n .subscribe(s => {\n res(s);\n })\n }) as Promise<any>;\n};\n","/*\n * Public API Surface of ngx-ctx-menu\n */\n\nexport * from './lib/appmenu.directive';\nexport * from './lib/ctxmenu.directive';\nexport * from './lib/tooltip.directive';\nexport * from './lib/context-menu/context-menu.component';\nexport * from './lib/context-menu/context-menu.component';\nexport * from './lib/types';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './index';\n"],"names":["i2"],"mappings":"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