@dotglitch/ngx-common 1.1.35 → 1.1.36

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.
@@ -1,18 +1,18 @@
1
1
  import * as i0 from '@angular/core';
2
2
  import { TemplateRef, Component, Optional, Inject, Input, HostListener, Directive, InjectionToken, Pipe, Injectable, EventEmitter, isDevMode, ViewContainerRef, ViewChild, Output, NgModule, ViewEncapsulation, SecurityContext, ContentChild, ViewChildren } from '@angular/core';
3
- import * as i1 from '@angular/material/dialog';
3
+ import * as i1$1 from '@angular/material/dialog';
4
4
  import { MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog';
5
5
  import { NgTemplateOutlet, NgComponentOutlet, DOCUMENT, NgIf, NgForOf, DatePipe } from '@angular/common';
6
- import * as i1$1 from '@angular/platform-browser';
6
+ import * as i1 from '@angular/platform-browser';
7
7
  import { createApplication } from '@angular/platform-browser';
8
8
  import { firstValueFrom, debounceTime, of, Subject, BehaviorSubject } from 'rxjs';
9
- import { ulid } from 'ulidx';
10
9
  import * as i3$1 from '@angular/material/icon';
11
10
  import { MatIconModule } from '@angular/material/icon';
12
11
  import * as i5 from '@angular/material/progress-spinner';
13
12
  import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
14
13
  import * as i3 from '@angular/cdk/portal';
15
14
  import { ComponentPortal, PortalModule } from '@angular/cdk/portal';
15
+ import { ulid } from 'ulidx';
16
16
  import { createInstance, INDEXEDDB } from 'localforage';
17
17
  import * as i2 from '@angular/cdk/dialog';
18
18
  import { retry } from 'rxjs/operators';
@@ -165,39 +165,31 @@ const getPosition = (el, config = {}, bounds) => {
165
165
  };
166
166
 
167
167
  const zone$1 = new Zone(Zone.current, { name: "@dotglitch_menu", properties: {} });
168
- const calcTooltipBounds = async (template, data, matDialogConfig) => {
169
- const args = {
170
- data: data || {},
171
- template,
168
+ const calcMenuItemBounds = async (menuItems, dataObj) => {
169
+ const data = {
170
+ data: dataObj,
171
+ items: menuItems,
172
172
  config: {},
173
173
  selfCords: { left: "0px", top: "0px" },
174
174
  ownerCords: { x: 0, y: 0, width: 0, height: 0 },
175
175
  id: null
176
176
  };
177
- // dimensions should be in px... Might need to handle vw/v
178
- if (matDialogConfig?.width && matDialogConfig?.height) {
179
- return {
180
- width: parseInt(matDialogConfig.width),
181
- height: parseInt(matDialogConfig.height),
182
- top: 0,
183
- left: 0,
184
- right: 0,
185
- bottom: 0
186
- };
187
- }
177
+ return calcComponentBounds(MenuComponent, data);
178
+ };
179
+ const calcComponentBounds = async (component, data) => {
188
180
  return new Promise((res, rej) => {
189
181
  zone$1.run(async () => {
190
- // Forcibly bootstrap the ctx menu outside of the client application's zone.
191
182
  const app = await createApplication({
192
183
  providers: [
193
- { provide: MAT_DIALOG_DATA, useValue: args }
184
+ { provide: MAT_DIALOG_DATA, useValue: data }
194
185
  ]
195
186
  });
196
187
  const del = document.createElement("div");
188
+ del.classList.add("ngx-menu");
197
189
  del.style.position = "absolute";
198
190
  del.style.left = '-1000vw';
199
191
  document.body.append(del);
200
- const base = app.bootstrap(TooltipComponent, del);
192
+ const base = app.bootstrap(component, del);
201
193
  const { instance } = base;
202
194
  await firstValueFrom(app.isStable);
203
195
  const el = instance.viewContainer?.element?.nativeElement;
@@ -208,53 +200,121 @@ const calcTooltipBounds = async (template, data, matDialogConfig) => {
208
200
  });
209
201
  });
210
202
  };
211
- class TooltipComponent {
212
- constructor(viewContainer, _data, dialog, // optional only for the purpose of estimating dimensions
203
+ const $data = Symbol("data");
204
+ const $hover = Symbol("hover");
205
+ class MenuComponent {
206
+ constructor(viewContainer, sanitizer, _data, dialog, // optional only for the purpose of estimating dimensions
213
207
  dialogRef) {
214
208
  this.viewContainer = viewContainer;
209
+ this.sanitizer = sanitizer;
215
210
  this._data = _data;
216
211
  this.dialog = dialog;
217
212
  this.dialogRef = dialogRef;
213
+ this.overlayOverlap = 32;
214
+ this.hoverDelay = 400;
215
+ this.showDebugOverlay = false;
216
+ this.isLockedOpen = false;
218
217
  this.hasBootstrapped = false;
219
218
  this.pointerIsOnVoid = false;
220
- this.isLockedOpen = false;
221
- this.clientWidth = window.innerWidth;
222
- this.clientHeight = window.innerHeight;
219
+ this.pointerHasBeenOverMask = false;
220
+ this.parentIsNgxMenu = false;
223
221
  this.coverRectCords = {
224
222
  top: 0,
225
223
  left: 0,
226
224
  height: 0,
227
225
  width: 0
228
226
  };
227
+ // Check if there are any slashes or dots -- that will clearly exclude it from being a mat icon
228
+ this.matIconRx = /[\/\.]/i;
229
+ this.showIconColumn = true;
230
+ this.showShortcutColumn = true;
231
+ this.childDialogs = [];
229
232
  // Defaults are set before @Input() hooks evaluate
230
- this.data = this.data || this._data?.data || {};
231
- this.config = this.config || this._data?.config;
232
233
  this.dialog = this.dialog || this._data?.dialog;
233
- this.template = this.template || this._data?.template;
234
- this.ownerCords = this.ownerCords || this._data?.ownerCords;
235
- this.selfCords = this.selfCords || this._data?.selfCords;
236
- this.isLockedOpen = this._data?.isLockedOpen || this.config?.stayOpen;
234
+ this.data = this._data?.data;
235
+ this.ownerCords = this._data?.ownerCords;
236
+ this.selfCords = this._data?.selfCords;
237
+ this.items = this._data?.items;
238
+ this.config = this._data?.config;
239
+ this.id = this._data?.id;
240
+ this.parentItem = this._data?.parentItem;
241
+ this.parentContext = this._data?.parentContext;
242
+ this.isLockedOpen = this.isLockedOpen || this._data?.config?.['_isLockedOpen'];
243
+ this.parentIsNgxMenu = this._data?.parentIsNgxMenu;
244
+ this.targetBounds = this._data?.targetBounds;
245
+ this.template = _data.template;
246
+ this.templateType = this.template instanceof TemplateRef ? "template" : "component";
247
+ if (this.templateType == "component") {
248
+ this.componentPortal = new ComponentPortal(this.template);
249
+ }
237
250
  }
238
251
  ngOnInit() {
239
- const selfY = parseInt(this.selfCords.top.replace('px', ''));
240
- const selfX = parseInt(this.selfCords.left.replace('px', ''));
241
- this.coverRectCords = {
242
- top: this.ownerCords.y - selfY - 16,
243
- left: this.ownerCords.x - selfX - 16,
244
- height: this.ownerCords.height + 32,
245
- width: this.ownerCords.width + 32
246
- };
247
- if (this.template instanceof TemplateRef)
248
- this.isTemplate = true;
249
- else if (typeof this.template == "function")
250
- this.isTemplate = false;
251
- else
252
- throw new Error("Unrecognized template object provided.");
253
- // TODO: resolve the event hook with the .void element
252
+ this.items?.forEach(i => {
253
+ if (typeof i == "string")
254
+ return;
255
+ // Set defaults
256
+ i['_disabled'] = false;
257
+ i['_visible'] = true;
258
+ i['_context'] = (typeof i.context == "function")
259
+ ? i.context(this.data)
260
+ : i.context;
261
+ if (i.label)
262
+ try {
263
+ i['_formattedLabel'] = this.formatLabel(i.label);
264
+ }
265
+ catch (e) {
266
+ console.warn(e);
267
+ }
268
+ if (typeof i.isDisabled == "function")
269
+ try {
270
+ i['_disabled'] = i.isDisabled(this.data || {}, i['_context']);
271
+ }
272
+ catch (e) {
273
+ console.warn(e);
274
+ }
275
+ if (typeof i.isVisible == "function")
276
+ try {
277
+ i['_visible'] = i.isVisible(this.data || {}, i['_context']);
278
+ }
279
+ catch (e) {
280
+ console.warn(e);
281
+ }
282
+ if (typeof i.linkTemplate == "function")
283
+ try {
284
+ i['_link'] = i.linkTemplate(this.data || {}, i['_context']);
285
+ }
286
+ catch (e) {
287
+ console.warn(e);
288
+ }
289
+ if (typeof i.iconTemplate == "function")
290
+ try {
291
+ i['_icon'] = i.iconTemplate(this.data || {}, i['_context']);
292
+ }
293
+ catch (e) {
294
+ console.warn(e);
295
+ }
296
+ });
297
+ // Show the icon column if there are any items with an icon
298
+ this.showIconColumn = !!this.items?.find(i => typeof i == "object" &&
299
+ typeof i['icon'] == "string" &&
300
+ i['icon'].length > 2);
301
+ this.showShortcutColumn = !!this.items?.find(i => typeof i == "object" &&
302
+ typeof i['shortcut'] == "string" &&
303
+ i['shortcut'].length > 2);
304
+ if (this.ownerCords) {
305
+ const selfY = parseInt(this.selfCords.top?.replace('px', '') || '0');
306
+ const selfX = parseInt(this.selfCords.left?.replace('px', '') || '0');
307
+ this.coverRectCords = {
308
+ top: this.ownerCords.y - selfY - (this.overlayOverlap / 2),
309
+ left: this.ownerCords.x - selfX - (this.overlayOverlap / 2),
310
+ height: this.ownerCords.height + this.overlayOverlap,
311
+ width: this.ownerCords.width + this.overlayOverlap
312
+ };
313
+ }
314
+ if (this.config?.stayOpen)
315
+ this.isLockedOpen = true;
254
316
  setTimeout(() => {
255
317
  this.hasBootstrapped = true;
256
- if (this.pointerIsOnVoid && !this.isLockedOpen)
257
- this.dialogRef.close();
258
318
  }, 200);
259
319
  }
260
320
  ngAfterViewInit() {
@@ -269,367 +329,12 @@ class TooltipComponent {
269
329
  this.isLockedOpen = true;
270
330
  });
271
331
  }
272
- onKeyDown(evt) {
273
- if (this.config.freezeOnKeyCode) {
274
- if (evt.code == this.config.freezeOnKeyCode)
275
- this.isLockedOpen = true;
276
- }
277
- }
278
- onVoidPointerDown(evt) {
279
- if (!this.isLockedOpen) {
280
- const el = this.viewContainer.element.nativeElement;
281
- el.querySelector(".void").remove();
282
- setTimeout(() => {
283
- const clonedEvt = new PointerEvent("pointerdown", evt);
284
- const target = document.elementFromPoint(evt.clientX, evt.clientY);
285
- console.log("DEBUG EVENTS", { evt, clonedEvt });
286
- target.dispatchEvent(clonedEvt);
287
- }, 15);
288
- }
289
- this.closeOnVoid(true);
290
- }
291
- // If the void element gets stuck open, make wheel events pass through.
292
- onWheel(evt) {
293
- const el = this.viewContainer.element.nativeElement;
294
- el.style.display = "none";
295
- const target = document.elementFromPoint(evt.clientX, evt.clientY);
296
- el.style.display = "block";
297
- target.scroll({
298
- top: evt.deltaY + target.scrollTop,
299
- left: evt.deltaX + target.scrollLeft,
300
- behavior: "smooth"
301
- });
332
+ ngOnDestroy() {
333
+ //
334
+ this.childDialogs.forEach(d => d.close({ [$data]: true }));
302
335
  }
303
336
  /**
304
- * Close the tooltip if these actions occur
305
- */
306
- onClose() {
307
- if (!this.isLockedOpen)
308
- this.dialogRef?.close();
309
- this.clientWidth = window.innerWidth;
310
- this.clientHeight = window.innerHeight;
311
- }
312
- closeOnVoid(force = false) {
313
- if (!this.isLockedOpen || force)
314
- this.dialogRef.close();
315
- }
316
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TooltipComponent, deps: [{ token: i0.ViewContainerRef }, { token: MAT_DIALOG_DATA, optional: true }, { token: i1.MatDialog, optional: true }, { token: i1.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
317
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: TooltipComponent, isStandalone: true, selector: "ngx-tooltip", inputs: { data: "data", config: "config", ownerCords: "ownerCords", selfCords: "selfCords", template: "template" }, host: { listeners: { "window:keydown": "onKeyDown($event)", "window:resize": "onClose()", "window:blur": "onClose()", "pointerleave": "onClose()" } }, ngImport: i0, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords) {\n <!-- <div\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 (pointerdown)=\"onVoidPointerDown($event)\"\n ></div> -->\n\n <div class=\"void left\"\n [style.top]=\"'0px'\"\n [style.left]=\"'0px'\"\n [style.height]=\"'100%'\"\n [style.width]=\"(ownerCords.left) + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void top\"\n [style.top]=\"'0px'\"\n [style.left]=\"ownerCords.left + 'px'\"\n [style.height]=\"ownerCords.top + 'px'\"\n [style.width]=\"ownerCords.width + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void right\"\n [style.top]=\"'0px'\"\n [style.left]=\"(ownerCords.left + ownerCords.width) + 'px'\"\n [style.height]=\"'100%'\"\n [style.width]=\"(clientWidth - (ownerCords.left + ownerCords.width)) + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void\"\n [style.top]=\"(ownerCords.top + ownerCords.height) + 'px'\"\n [style.left]=\"ownerCords.left + 'px'\"\n [style.height]=\"(clientHeight - (ownerCords.top + ownerCords.height)) + 'px'\"\n [style.width]=\"ownerCords.width + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n\n<div\n #container\n class=\"container\"\n>\n @if (isTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"$any(template)\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'element': container,\n 'tooltip': this\n }\"\n ></ng-container>\n }\n @else {\n <ng-container\n [ngComponentOutlet]=\"$any(template)\"\n >\n </ng-container>\n }\n</div>\n", styles: ["::ng-deep .cdk-overlay-container .ngx-tooltip{--mdc-dialog-container-color: var(--ngx-tooltip-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__surface{overflow:visible;background-color:#0000}::ng-deep .cdk-overlay-container .context-menu-backdrop.cdk-overlay-backdrop-showing{opacity:0}::ng-deep .cdk-overlay-pane.ngx-tooltip .mat-dialog-container{padding:0}:host{min-width:2px;min-height:2px;display:block}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2;position:fixed}.container{width:100%;height:100%;background:var(--ngx-tooltip-background-color, #333);border-radius:6px;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }] }); }
318
- }
319
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TooltipComponent, decorators: [{
320
- type: Component,
321
- args: [{ selector: 'ngx-tooltip', imports: [
322
- NgTemplateOutlet,
323
- NgComponentOutlet
324
- ], standalone: true, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords) {\n <!-- <div\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 (pointerdown)=\"onVoidPointerDown($event)\"\n ></div> -->\n\n <div class=\"void left\"\n [style.top]=\"'0px'\"\n [style.left]=\"'0px'\"\n [style.height]=\"'100%'\"\n [style.width]=\"(ownerCords.left) + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void top\"\n [style.top]=\"'0px'\"\n [style.left]=\"ownerCords.left + 'px'\"\n [style.height]=\"ownerCords.top + 'px'\"\n [style.width]=\"ownerCords.width + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void right\"\n [style.top]=\"'0px'\"\n [style.left]=\"(ownerCords.left + ownerCords.width) + 'px'\"\n [style.height]=\"'100%'\"\n [style.width]=\"(clientWidth - (ownerCords.left + ownerCords.width)) + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void\"\n [style.top]=\"(ownerCords.top + ownerCords.height) + 'px'\"\n [style.left]=\"ownerCords.left + 'px'\"\n [style.height]=\"(clientHeight - (ownerCords.top + ownerCords.height)) + 'px'\"\n [style.width]=\"ownerCords.width + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n\n<div\n #container\n class=\"container\"\n>\n @if (isTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"$any(template)\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'element': container,\n 'tooltip': this\n }\"\n ></ng-container>\n }\n @else {\n <ng-container\n [ngComponentOutlet]=\"$any(template)\"\n >\n </ng-container>\n }\n</div>\n", styles: ["::ng-deep .cdk-overlay-container .ngx-tooltip{--mdc-dialog-container-color: var(--ngx-tooltip-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__surface{overflow:visible;background-color:#0000}::ng-deep .cdk-overlay-container .context-menu-backdrop.cdk-overlay-backdrop-showing{opacity:0}::ng-deep .cdk-overlay-pane.ngx-tooltip .mat-dialog-container{padding:0}:host{min-width:2px;min-height:2px;display:block}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2;position:fixed}.container{width:100%;height:100%;background:var(--ngx-tooltip-background-color, #333);border-radius:6px;overflow:hidden}\n"] }]
325
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: undefined, decorators: [{
326
- type: Optional
327
- }, {
328
- type: Inject,
329
- args: [MAT_DIALOG_DATA]
330
- }] }, { type: i1.MatDialog, decorators: [{
331
- type: Optional
332
- }] }, { type: i1.MatDialogRef, decorators: [{
333
- type: Optional
334
- }] }], propDecorators: { data: [{
335
- type: Input
336
- }], config: [{
337
- type: Input
338
- }], ownerCords: [{
339
- type: Input
340
- }], selfCords: [{
341
- type: Input
342
- }], template: [{
343
- type: Input
344
- }], onKeyDown: [{
345
- type: HostListener,
346
- args: ["window:keydown", ['$event']]
347
- }], onClose: [{
348
- type: HostListener,
349
- args: ["window:resize"]
350
- }, {
351
- type: HostListener,
352
- args: ["window:blur"]
353
- }, {
354
- type: HostListener,
355
- args: ["pointerleave"]
356
- }] } });
357
-
358
- class TooltipDirective {
359
- constructor(dialog, viewContainer) {
360
- this.dialog = dialog;
361
- this.viewContainer = viewContainer;
362
- /**
363
- * Configuration for opening the app menu
364
- */
365
- this.config = {};
366
- /**
367
- * Arbitrary data to pass into the template
368
- */
369
- this.data = {};
370
- this.isCursorOverTarget = false;
371
- this.dialogIsOpen = false;
372
- }
373
- ngAfterViewInit() {
374
- const el = this.viewContainer.element.nativeElement;
375
- this.config?.triggers?.forEach(t => {
376
- el.addEventListener(t, () => {
377
- if (t == "click")
378
- this.config.stayOpen = true;
379
- this.open();
380
- });
381
- });
382
- }
383
- async open() {
384
- if (!this.dialogIsOpen) {
385
- const el = this.viewContainer.element.nativeElement;
386
- this.dialogIsOpen = true;
387
- await openTooltip(this.dialog, this.template, this.data, el, this.config);
388
- this.dialogIsOpen = false;
389
- }
390
- }
391
- async onPointerEnter(evt) {
392
- // If the template is not a template ref, do nothing.
393
- if (!(this.template instanceof TemplateRef))
394
- return;
395
- if (Array.isArray(this.config?.triggers) && !this.config.triggers.includes("hover")) {
396
- return;
397
- }
398
- this.isCursorOverTarget = true;
399
- setTimeout(async () => {
400
- // If the cursor moved away in the time
401
- if (!this.isCursorOverTarget)
402
- return;
403
- this.open();
404
- }, this.config.delay ?? 250);
405
- }
406
- async onPointerLeave(evt) {
407
- this.isCursorOverTarget = false;
408
- }
409
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TooltipDirective, deps: [{ token: i1.MatDialog }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); }
410
- static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.1.2", type: TooltipDirective, isStandalone: true, selector: "[ngx-tooltip]", inputs: { template: ["ngx-tooltip", "template"], config: ["ngx-tooltip-config", "config"], data: ["ngx-tooltip-context", "data"] }, host: { listeners: { "pointerenter": "onPointerEnter($event)", "pointerleave": "onPointerLeave($event)" } }, providers: [
411
- MatDialog
412
- ], ngImport: i0 }); }
413
- }
414
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TooltipDirective, decorators: [{
415
- type: Directive,
416
- args: [{
417
- selector: '[ngx-tooltip]',
418
- providers: [
419
- MatDialog
420
- ],
421
- standalone: true
422
- }]
423
- }], ctorParameters: () => [{ type: i1.MatDialog }, { type: i0.ViewContainerRef }], propDecorators: { template: [{
424
- type: Input,
425
- args: ["ngx-tooltip"]
426
- }], config: [{
427
- type: Input,
428
- args: ["ngx-tooltip-config"]
429
- }], data: [{
430
- type: Input,
431
- args: ["ngx-tooltip-context"]
432
- }], onPointerEnter: [{
433
- type: HostListener,
434
- args: ['pointerenter', ['$event']]
435
- }], onPointerLeave: [{
436
- type: HostListener,
437
- args: ['pointerleave', ['$event']]
438
- }] } });
439
- // Helper to open the context menu without using the directive.
440
- const openTooltip = async (dialog, template, data, el, config, focusTrap = false, matPopupOptions) => {
441
- const rect = await calcTooltipBounds(template, data, matPopupOptions);
442
- const ownerCords = el.getBoundingClientRect();
443
- const cords = getPosition(el, config, rect);
444
- const specificId = ulid();
445
- return firstValueFrom(dialog.open(TooltipComponent, {
446
- autoFocus: focusTrap,
447
- restoreFocus: focusTrap,
448
- data: {
449
- dialog,
450
- data: data,
451
- template: template,
452
- config: config,
453
- matPopupOptions,
454
- ownerCords: ownerCords,
455
- selfCords: cords,
456
- id: specificId
457
- },
458
- panelClass: ["ngx-tooltip", 'ngx-' + specificId].concat(config?.customClass || []),
459
- position: cords,
460
- hasBackdrop: false,
461
- ...matPopupOptions
462
- })
463
- .afterClosed());
464
- };
465
-
466
- const zone = new Zone(Zone.current, { name: "@dotglitch_menu", properties: {} });
467
- const calcMenuItemBounds = async (menuItems, dataObj) => {
468
- const data = {
469
- data: dataObj,
470
- items: menuItems,
471
- config: {},
472
- selfCords: { left: "0px", top: "0px" },
473
- ownerCords: { x: 0, y: 0, width: 0, height: 0 },
474
- id: null
475
- };
476
- return calcComponentBounds(MenuComponent, data);
477
- };
478
- const calcComponentBounds = async (component, data) => {
479
- return new Promise((res, rej) => {
480
- zone.run(async () => {
481
- const app = await createApplication({
482
- providers: [
483
- { provide: MAT_DIALOG_DATA, useValue: data }
484
- ]
485
- });
486
- const del = document.createElement("div");
487
- del.style.position = "absolute";
488
- del.style.left = '-1000vw';
489
- document.body.append(del);
490
- const base = app.bootstrap(component, del);
491
- const { instance } = base;
492
- await firstValueFrom(app.isStable);
493
- const el = instance.viewContainer?.element?.nativeElement;
494
- const rect = el.getBoundingClientRect();
495
- app.destroy();
496
- del.remove();
497
- res(rect);
498
- });
499
- });
500
- };
501
- const $data = Symbol("data");
502
- const $hover = Symbol("hover");
503
- class MenuComponent {
504
- constructor(viewContainer, sanitizer, _data, dialog, // optional only for the purpose of estimating dimensions
505
- dialogRef) {
506
- this.viewContainer = viewContainer;
507
- this.sanitizer = sanitizer;
508
- this._data = _data;
509
- this.dialog = dialog;
510
- this.dialogRef = dialogRef;
511
- this.overlayOverlap = 32;
512
- this.hoverDelay = 400;
513
- this.showDebugOverlay = false;
514
- this.isLockedOpen = false;
515
- this.hasBootstrapped = false;
516
- this.pointerIsOnVoid = false;
517
- this.pointerHasBeenOverMask = false;
518
- this.parentIsNgxMenu = false;
519
- this.coverRectCords = {
520
- top: 0,
521
- left: 0,
522
- height: 0,
523
- width: 0
524
- };
525
- // Check if there are any slashes or dots -- that will clearly exclude it from being a mat icon
526
- this.matIconRx = /[\/\.]/i;
527
- this.showIconColumn = true;
528
- this.showShortcutColumn = true;
529
- this.childDialogs = [];
530
- // Defaults are set before @Input() hooks evaluate
531
- this.dialog = this.dialog || this._data?.dialog;
532
- this.data = this._data?.data;
533
- this.ownerCords = this._data?.ownerCords;
534
- this.selfCords = this._data?.selfCords;
535
- this.items = this._data?.items;
536
- this.config = this._data?.config;
537
- this.id = this._data?.id;
538
- this.parentItem = this._data?.parentItem;
539
- this.parentContext = this._data?.parentContext;
540
- this.isLockedOpen = this.isLockedOpen || this._data?.config?.['_isLockedOpen'];
541
- this.parentIsNgxMenu = this._data?.parentIsNgxMenu;
542
- this.template = _data.template;
543
- this.templateType = this.template instanceof TemplateRef ? "template" : "component";
544
- if (this.templateType == "component") {
545
- this.componentPortal = new ComponentPortal(this.template);
546
- }
547
- }
548
- ngOnInit() {
549
- this.items?.forEach(i => {
550
- if (typeof i == "string")
551
- return;
552
- // Set defaults
553
- i['_disabled'] = false;
554
- i['_visible'] = true;
555
- i['_context'] = (typeof i.context == "function")
556
- ? i.context(this.data)
557
- : i.context;
558
- if (i.label)
559
- try {
560
- i['_formattedLabel'] = this.formatLabel(i.label);
561
- }
562
- catch (e) {
563
- console.warn(e);
564
- }
565
- if (typeof i.isDisabled == "function")
566
- try {
567
- i['_disabled'] = i.isDisabled(this.data || {}, i['_context']);
568
- }
569
- catch (e) {
570
- console.warn(e);
571
- }
572
- if (typeof i.isVisible == "function")
573
- try {
574
- i['_visible'] = i.isVisible(this.data || {}, i['_context']);
575
- }
576
- catch (e) {
577
- console.warn(e);
578
- }
579
- if (typeof i.linkTemplate == "function")
580
- try {
581
- i['_link'] = i.linkTemplate(this.data || {}, i['_context']);
582
- }
583
- catch (e) {
584
- console.warn(e);
585
- }
586
- if (typeof i.iconTemplate == "function")
587
- try {
588
- i['_icon'] = i.iconTemplate(this.data || {}, i['_context']);
589
- }
590
- catch (e) {
591
- console.warn(e);
592
- }
593
- });
594
- // Show the icon column if there are any items with an icon
595
- this.showIconColumn = !!this.items?.find(i => typeof i == "object" &&
596
- typeof i['icon'] == "string" &&
597
- i['icon'].length > 2);
598
- this.showShortcutColumn = !!this.items?.find(i => typeof i == "object" &&
599
- typeof i['shortcut'] == "string" &&
600
- i['shortcut'].length > 2);
601
- if (this.ownerCords) {
602
- const selfY = parseInt(this.selfCords.top?.replace('px', '') || '0');
603
- const selfX = parseInt(this.selfCords.left?.replace('px', '') || '0');
604
- this.coverRectCords = {
605
- top: this.ownerCords.y - selfY - (this.overlayOverlap / 2),
606
- left: this.ownerCords.x - selfX - (this.overlayOverlap / 2),
607
- height: this.ownerCords.height + this.overlayOverlap,
608
- width: this.ownerCords.width + this.overlayOverlap
609
- };
610
- }
611
- setTimeout(() => {
612
- this.hasBootstrapped = true;
613
- }, 200);
614
- }
615
- ngAfterViewInit() {
616
- const el = this.viewContainer.element.nativeElement;
617
- el.addEventListener("keydown", evt => {
618
- this.isLockedOpen = true;
619
- });
620
- el.addEventListener("pointerdown", evt => {
621
- this.isLockedOpen = true;
622
- });
623
- el.addEventListener("touch", evt => {
624
- this.isLockedOpen = true;
625
- });
626
- }
627
- ngOnDestroy() {
628
- //
629
- this.childDialogs.forEach(d => d.close({ [$data]: true }));
630
- }
631
- /**
632
- *
337
+ *
633
338
  */
634
339
  async onMenuItemClick(item, row, keepOpen = false) {
635
340
  if (typeof item == 'string')
@@ -672,9 +377,10 @@ class MenuComponent {
672
377
  // right: null
673
378
  };
674
379
  // Set position coordinates
675
- const { width, height } = await (item.childTemplate
380
+ const targetBounds = await (item.childTemplate
676
381
  ? calcComponentBounds(MenuComponent, { template: item.childTemplate })
677
382
  : calcMenuItemBounds(item['_children'], this.data));
383
+ const { width, height } = targetBounds;
678
384
  if (bounds.y + height > window.innerHeight)
679
385
  cords.bottom = "0px";
680
386
  if (bounds.x + bounds.width + width > window.innerWidth)
@@ -703,7 +409,8 @@ class MenuComponent {
703
409
  items: item['_children'],
704
410
  template: item.childTemplate,
705
411
  config: config,
706
- parentIsNgxMenu: true
412
+ parentIsNgxMenu: true,
413
+ targetBounds
707
414
  }
708
415
  });
709
416
  let _s = dialogRef
@@ -757,7 +464,6 @@ class MenuComponent {
757
464
  }
758
465
  }
759
466
  startHoverTimer(item, row) {
760
- this.childDialogs.forEach(cd => cd.close());
761
467
  // Invert check to make the logic simpler
762
468
  // TL;DR: if (any) of these are true, we will do the hover action
763
469
  if (!(Array.isArray(item.children) && item.children.length > 0 ||
@@ -768,6 +474,7 @@ class MenuComponent {
768
474
  item[$hover] = setTimeout(() => {
769
475
  delete item[$hover];
770
476
  if (!this.pointerIsOnVoid) {
477
+ this.childDialogs.forEach(cd => cd.close());
771
478
  row['_open'] = true;
772
479
  this.onMenuItemClick(item, row);
773
480
  }
@@ -777,6 +484,14 @@ class MenuComponent {
777
484
  item[$hover] && clearTimeout(item[$hover]);
778
485
  delete item[$hover];
779
486
  }
487
+ startCloseTimer() {
488
+ this.closeTimer = setTimeout(() => {
489
+ this.closeOnVoid();
490
+ }, 500);
491
+ }
492
+ stopCloseTimer() {
493
+ clearTimeout(this.closeTimer);
494
+ }
780
495
  /**
781
496
  * Check if the dialog is clipping offscreen
782
497
  * if so, move it back into view.
@@ -812,8 +527,8 @@ class MenuComponent {
812
527
  behavior: "smooth"
813
528
  });
814
529
  }
815
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: MenuComponent, deps: [{ token: i0.ViewContainerRef }, { token: i1$1.DomSanitizer }, { token: MAT_DIALOG_DATA, optional: true }, { token: i1.MatDialog, optional: true }, { token: i1.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
816
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: MenuComponent, isStandalone: true, selector: "ngx-menu", inputs: { data: "data", items: "items", config: "config", id: "id", overlayOverlap: "overlayOverlap", hoverDelay: "hoverDelay", showDebugOverlay: "showDebugOverlay", ownerCords: "ownerCords", selfCords: "selfCords", parentItem: "parentItem", parentContext: "parentContext", isLockedOpen: "isLockedOpen" }, host: { listeners: { "window:resize": "onResize()" } }, ngImport: i0, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords && !parentIsNgxMenu) {\n <div\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.background]=\"showDebugOverlay ? '#f004' : '#0000'\"\n style=\"z-index: -1\"\n (pointerenter)=\"pointerHasBeenOverMask=true\"\n (pointermove)=\"pointerHasBeenOverMask=true\"\n (click)=\"isLockedOpen = true\"\n ></div>\n}\n\n@if (!parentIsNgxMenu) {\n <div class=\"void\"\n [style.background]=\"showDebugOverlay ? '#00f4' : '#0000'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && !isLockedOpen && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && closeOnVoid(true)\"\n (pointermove)=\"hasBootstrapped && !isLockedOpen && closeOnVoid()\"\n (click)=\"closeOnVoid(true)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n@if (!template) {\n <table>\n <tbody>\n @for (item of items; track item) {\n <!-- A row with a click action -->\n @if (item != 'separator' && item.separator != true && item['_visible']) {\n <tr #row\n [class.disabled]=\"item['_disabled']\"\n (click)=\"!item['_disabled'] && onMenuItemClick(item, row, true)\"\n [class.hover]=\"row['hover']\"\n [class.open]=\"row['_open']\"\n (pointerenter)=\"row['hover'] = true; startHoverTimer(item, row)\"\n (pointerleave)=\"row['hover'] = false; stopHoverTimer(item)\"\n >\n\n @if (showIconColumn) {\n <td class=\"icon\">\n @if (matIconRx.test(item['_icon'] ?? item.icon)) {\n <img [src]=\"item['_icon'] ?? item.icon\"/>\n }\n @else {\n <mat-icon\n [fontIcon]=\"item['_icon'] ?? item.icon\"\n [style.color]=\"item.iconColor\"\n />\n }\n </td>\n }\n\n <!-- 'Normal' action based item -->\n <td class=\"label\"\n [style.padding-left]=\"showIconColumn ? 0 : '16px'\"\n >\n <a\n #anchor\n [attr.target]=\"item.linkTarget\"\n [attr.href]=\"(item['_link'] || item.link) ? sanitizer.bypassSecurityTrustUrl(item['_link'] || item.link) : undefined\"\n >\n @if ($any(item.labelTemplate)?.prototype) {\n <ng-container\n [ngTemplateOutlet]=\"$any(item).labelTemplate\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': item['_context'],\n 'item': item,\n 'element': anchor,\n 'menu': this\n }\"\n />\n }\n @else {\n @if ($any(item)?.labelTemplate) {\n {{$any(item)?.labelTemplate(data || {})}}\n }\n @else {\n <div [innerHTML]=\"item['_formattedLabel']\"></div>\n }\n }\n </a>\n </td>\n\n @if (showShortcutColumn) {\n <td class=\"shortcut\">\n {{item.shortcutLabel}}\n </td>\n }\n\n <td style=\"min-width: 16px\">\n @if ((\n (item['children']?.length > 0) ||\n (item['_children']?.length > 0) ||\n item.childTemplate ||\n item.children?.['call'] ||\n item.childrenResolver\n ) &&\n !item['_isResolving']\n ) {\n <mat-icon\n style=\"transform: translateY(2px)\"\n >\n chevron_right\n </mat-icon>\n }\n\n @if (item['_isResolving']) {\n <mat-progress-spinner\n mode=\"indeterminate\"\n [diameter]=\"20\"\n style=\"margin-right: 4px\"\n />\n }\n </td>\n </tr>\n }\n @else if (item != 'separator' && item.separator == true) {\n <!-- Separator with label -->\n <tr\n class=\"disabled separator\"\n >\n <td\n class=\"center\"\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <span class=\"hr\">\n {{item['label'] || ''}}\n </span>\n </td>\n </tr>\n }\n @else if (item == 'separator') {\n <!-- Separator -->\n <tr\n class=\"disabled separator\"\n >\n <td\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <hr/>\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n}\n@else {\n @if (templateType == 'template') {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': parentContext,\n 'item': parentItem,\n 'element': this.viewContainer?.element?.nativeElement,\n 'menu': this\n }\"\n />\n }\n @else {\n <ng-container\n [cdkPortalOutlet]=\"componentPortal\"\n />\n }\n}\n\n@if (showDebugOverlay) {\n <div>\n <div>hbs: {{hasBootstrapped}}</div>\n <div>pov: {{pointerIsOnVoid}}</div>\n <div>ilo: {{isLockedOpen}}</div>\n <div>hbom: {{pointerHasBeenOverMask}}</div>\n\n <div>type: {{templateType}}</div>\n </div>\n}\n", styles: ["::ng-deep .cdk-overlay-container .ngx-menu{--mdc-dialog-container-color: var(--ngx-menu-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-pane.ngx-menu .mat-mdc-dialog-surface{overflow:visible}:host{-webkit-user-select:none;user-select:none;z-index:1;position:relative;display:block}table{border-spacing:0;border-radius:5px;padding:4px 0}tr{color:var(--ngx-menu-text-color, #ccc);font-size:var(--ngx-menu-font-size, 14px);cursor:pointer;transition:background-color 75ms ease,color 75ms ease}tr:not(.disabled).hover,tr:not(.disabled).open{background-color:var(--ngx-menu-hover-background-color, #94ebeb);color:var(--ngx-menu-hover-text-color, #000)}tr:not(.disabled).hover a,tr:not(.disabled).open a{color:var(--ngx-menu-hover-text-color, #000)}tr:not(.separator){height:36px}tr.disabled .label{color:var(--ngx-menu-disabled-text-color, #919191)}tr .center{text-align:center}tr a{outline:0;display:flex;align-items:center;gap:10px;justify-content:space-between;height:100%;width:100%}tr .label{min-width:100px}tr img{max-width:100%;max-height:100%;aspect-ratio:1}.hr{height:1px;text-align:center;position:relative}.hr:before,.hr:after{content:\"\";background:var(--ngx-menu-separator-color, #2a2a2a);display:block;position:absolute;top:0;bottom:0;height:1px;margin:auto;width:300px}.hr:before{right:calc(100% + 4px)}.hr:after{left:calc(100% + 4px)}hr{background:var(--ngx-menu-separator-color, #2a2a2a);border:0;height:1px;margin:0}.icon{width:24px;height:24px;padding-left:10px}.icon mat-icon{transform:translateY(2px)}.shortcut{color:var(--ngx-menu-shortcut-text-color, #848484);text-align:end;padding-right:10px;padding-left:12px}.label{height:var(--ngx-menu-item-height, 30px)}td{vertical-align:middle}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i3.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
530
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: MenuComponent, deps: [{ token: i0.ViewContainerRef }, { token: i1.DomSanitizer }, { token: MAT_DIALOG_DATA, optional: true }, { token: i1$1.MatDialog, optional: true }, { token: i1$1.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
531
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: MenuComponent, isStandalone: true, selector: "ngx-menu", inputs: { data: "data", items: "items", config: "config", id: "id", overlayOverlap: "overlayOverlap", hoverDelay: "hoverDelay", showDebugOverlay: "showDebugOverlay", targetBounds: "targetBounds", ownerCords: "ownerCords", selfCords: "selfCords", parentItem: "parentItem", parentContext: "parentContext", isLockedOpen: "isLockedOpen" }, host: { listeners: { "window:resize": "onResize()" }, properties: { "attr.tx": "targetBounds?.x", "attr.ty": "targetBounds?.y", "attr.th": "targetBounds?.height", "attr.tw": "targetBounds?.width" } }, ngImport: i0, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords && !parentIsNgxMenu) {\n <div\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.background]=\"showDebugOverlay ? '#f004' : '#0000'\"\n style=\"z-index: -1\"\n (pointerenter)=\"pointerHasBeenOverMask=true;startCloseTimer()\"\n (pointerleave)=\"stopCloseTimer()\"\n (pointermove)=\"pointerHasBeenOverMask=true\"\n (click)=\"isLockedOpen = true\"\n ></div>\n}\n\n@if (!parentIsNgxMenu) {\n <div class=\"void\"\n [style.background]=\"showDebugOverlay ? '#00f4' : '#0000'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && !isLockedOpen && startCloseTimer()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && closeOnVoid(true)\"\n (pointermove)=\"hasBootstrapped && !isLockedOpen && startCloseTimer()\"\n (click)=\"closeOnVoid(true)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n@if (!template) {\n <table (pointerenter)=\"stopCloseTimer()\">\n <tbody>\n @for (item of items; track item) {\n <!-- A row with a click action -->\n @if (item != 'separator' && item.separator != true && item['_visible']) {\n <tr #row\n [class.disabled]=\"item['_disabled']\"\n (click)=\"!item['_disabled'] && onMenuItemClick(item, row, true)\"\n [class.hover]=\"row['hover']\"\n [class.open]=\"row['_open']\"\n (pointerenter)=\"row['hover'] = true; startHoverTimer(item, row)\"\n (pointerleave)=\"row['hover'] = false; stopHoverTimer(item)\"\n >\n\n @if (showIconColumn) {\n <td class=\"icon\">\n @if (matIconRx.test(item['_icon'] ?? item.icon)) {\n <img [src]=\"item['_icon'] ?? item.icon\"/>\n }\n @else {\n <mat-icon\n [fontIcon]=\"item['_icon'] ?? item.icon\"\n [style.color]=\"item.iconColor\"\n />\n }\n </td>\n }\n\n <!-- 'Normal' action based item -->\n <td class=\"label\"\n [style.padding-left]=\"showIconColumn ? 0 : '16px'\"\n >\n <a\n #anchor\n [attr.target]=\"item.linkTarget\"\n [attr.href]=\"(item['_link'] || item.link) ? sanitizer.bypassSecurityTrustUrl(item['_link'] || item.link) : undefined\"\n >\n @if ($any(item.labelTemplate)?.prototype) {\n <ng-container\n [ngTemplateOutlet]=\"$any(item).labelTemplate\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': item['_context'],\n 'item': item,\n 'element': anchor,\n 'menu': this\n }\"\n />\n }\n @else {\n @if ($any(item)?.labelTemplate) {\n {{$any(item)?.labelTemplate(data || {})}}\n }\n @else {\n <div [innerHTML]=\"item['_formattedLabel']\"></div>\n }\n }\n </a>\n </td>\n\n @if (showShortcutColumn) {\n <td class=\"shortcut\">\n {{item.shortcutLabel}}\n </td>\n }\n\n <td style=\"min-width: 16px\">\n @if ((\n (item['children']?.length > 0) ||\n (item['_children']?.length > 0) ||\n item.childTemplate ||\n item.children?.['call'] ||\n item.childrenResolver\n ) &&\n !item['_isResolving']\n ) {\n <mat-icon\n style=\"transform: translateY(2px)\"\n >\n chevron_right\n </mat-icon>\n }\n\n @if (item['_isResolving']) {\n <mat-progress-spinner\n mode=\"indeterminate\"\n [diameter]=\"20\"\n style=\"margin-right: 4px\"\n />\n }\n </td>\n </tr>\n }\n @else if (item != 'separator' && item.separator == true) {\n <!-- Separator with label -->\n <tr\n class=\"disabled separator\"\n >\n <td\n class=\"center\"\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <span class=\"hr\">\n {{item['label'] || ''}}\n </span>\n </td>\n </tr>\n }\n @else if (item == 'separator') {\n <!-- Separator -->\n <tr\n class=\"disabled separator\"\n >\n <td\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <hr/>\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n}\n@else {\n @if (templateType == 'template') {\n <div style=\"display: contents;\" (pointerenter)=\"stopCloseTimer()\">\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': parentContext,\n 'item': parentItem,\n 'element': this.viewContainer?.element?.nativeElement,\n 'menu': this\n }\"\n />\n </div>\n }\n @else {\n <div style=\"display: contents;\" (pointerenter)=\"stopCloseTimer()\">\n <ng-container\n [cdkPortalOutlet]=\"componentPortal\"\n />\n </div>\n }\n}\n\n@if (showDebugOverlay) {\n <div>\n <div>hbs: {{hasBootstrapped}}</div>\n <div>pov: {{pointerIsOnVoid}}</div>\n <div>ilo: {{isLockedOpen}}</div>\n <div>hbom: {{pointerHasBeenOverMask}}</div>\n\n <div>type: {{templateType}}</div>\n </div>\n}\n", styles: ["::ng-deep .cdk-overlay-container .ngx-menu{--mdc-dialog-container-color: var(--ngx-menu-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-pane.ngx-menu .mat-mdc-dialog-surface{overflow:visible}:host{-webkit-user-select:none;user-select:none;z-index:1;position:relative;display:block}table{border-spacing:0;border-radius:5px;padding:4px 0}tr{color:var(--ngx-menu-text-color, #ccc);font-size:var(--ngx-menu-font-size, 14px);cursor:pointer;transition:background-color 75ms ease,color 75ms ease}tr:not(.disabled).hover,tr:not(.disabled).open{background-color:var(--ngx-menu-hover-background-color, #94ebeb);color:var(--ngx-menu-hover-text-color, #000)}tr:not(.disabled).hover a,tr:not(.disabled).open a{color:var(--ngx-menu-hover-text-color, #000)}tr:not(.separator){height:36px}tr.disabled .label{color:var(--ngx-menu-disabled-text-color, #919191)}tr .center{text-align:center}tr a{outline:0;display:flex;align-items:center;gap:10px;justify-content:space-between;height:100%;width:100%}tr .label{min-width:100px}tr img{max-width:100%;max-height:100%;aspect-ratio:1}.hr{height:1px;text-align:center;position:relative}.hr:before,.hr:after{content:\"\";background:var(--ngx-menu-separator-color, #2a2a2a);display:block;position:absolute;top:0;bottom:0;height:1px;margin:auto;width:300px}.hr:before{right:calc(100% + 4px)}.hr:after{left:calc(100% + 4px)}hr{background:var(--ngx-menu-separator-color, #2a2a2a);border:0;height:1px;margin:0}.icon{width:24px;height:24px;padding-left:10px}.icon mat-icon{transform:translateY(2px)}.shortcut{color:var(--ngx-menu-shortcut-text-color, #848484);text-align:end;padding-right:10px;padding-left:12px}.label{height:var(--ngx-menu-item-height, 30px)}td{vertical-align:middle}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "ngmodule", type: PortalModule }, { kind: "directive", type: i3.CdkPortalOutlet, selector: "[cdkPortalOutlet]", inputs: ["cdkPortalOutlet"], outputs: ["attached"], exportAs: ["cdkPortalOutlet"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i5.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
817
532
  }
818
533
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: MenuComponent, decorators: [{
819
534
  type: Component,
@@ -823,15 +538,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
823
538
  MatIconModule,
824
539
  MatProgressSpinnerModule,
825
540
  TooltipDirective
826
- ], standalone: true, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords && !parentIsNgxMenu) {\n <div\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.background]=\"showDebugOverlay ? '#f004' : '#0000'\"\n style=\"z-index: -1\"\n (pointerenter)=\"pointerHasBeenOverMask=true\"\n (pointermove)=\"pointerHasBeenOverMask=true\"\n (click)=\"isLockedOpen = true\"\n ></div>\n}\n\n@if (!parentIsNgxMenu) {\n <div class=\"void\"\n [style.background]=\"showDebugOverlay ? '#00f4' : '#0000'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && !isLockedOpen && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && closeOnVoid(true)\"\n (pointermove)=\"hasBootstrapped && !isLockedOpen && closeOnVoid()\"\n (click)=\"closeOnVoid(true)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n@if (!template) {\n <table>\n <tbody>\n @for (item of items; track item) {\n <!-- A row with a click action -->\n @if (item != 'separator' && item.separator != true && item['_visible']) {\n <tr #row\n [class.disabled]=\"item['_disabled']\"\n (click)=\"!item['_disabled'] && onMenuItemClick(item, row, true)\"\n [class.hover]=\"row['hover']\"\n [class.open]=\"row['_open']\"\n (pointerenter)=\"row['hover'] = true; startHoverTimer(item, row)\"\n (pointerleave)=\"row['hover'] = false; stopHoverTimer(item)\"\n >\n\n @if (showIconColumn) {\n <td class=\"icon\">\n @if (matIconRx.test(item['_icon'] ?? item.icon)) {\n <img [src]=\"item['_icon'] ?? item.icon\"/>\n }\n @else {\n <mat-icon\n [fontIcon]=\"item['_icon'] ?? item.icon\"\n [style.color]=\"item.iconColor\"\n />\n }\n </td>\n }\n\n <!-- 'Normal' action based item -->\n <td class=\"label\"\n [style.padding-left]=\"showIconColumn ? 0 : '16px'\"\n >\n <a\n #anchor\n [attr.target]=\"item.linkTarget\"\n [attr.href]=\"(item['_link'] || item.link) ? sanitizer.bypassSecurityTrustUrl(item['_link'] || item.link) : undefined\"\n >\n @if ($any(item.labelTemplate)?.prototype) {\n <ng-container\n [ngTemplateOutlet]=\"$any(item).labelTemplate\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': item['_context'],\n 'item': item,\n 'element': anchor,\n 'menu': this\n }\"\n />\n }\n @else {\n @if ($any(item)?.labelTemplate) {\n {{$any(item)?.labelTemplate(data || {})}}\n }\n @else {\n <div [innerHTML]=\"item['_formattedLabel']\"></div>\n }\n }\n </a>\n </td>\n\n @if (showShortcutColumn) {\n <td class=\"shortcut\">\n {{item.shortcutLabel}}\n </td>\n }\n\n <td style=\"min-width: 16px\">\n @if ((\n (item['children']?.length > 0) ||\n (item['_children']?.length > 0) ||\n item.childTemplate ||\n item.children?.['call'] ||\n item.childrenResolver\n ) &&\n !item['_isResolving']\n ) {\n <mat-icon\n style=\"transform: translateY(2px)\"\n >\n chevron_right\n </mat-icon>\n }\n\n @if (item['_isResolving']) {\n <mat-progress-spinner\n mode=\"indeterminate\"\n [diameter]=\"20\"\n style=\"margin-right: 4px\"\n />\n }\n </td>\n </tr>\n }\n @else if (item != 'separator' && item.separator == true) {\n <!-- Separator with label -->\n <tr\n class=\"disabled separator\"\n >\n <td\n class=\"center\"\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <span class=\"hr\">\n {{item['label'] || ''}}\n </span>\n </td>\n </tr>\n }\n @else if (item == 'separator') {\n <!-- Separator -->\n <tr\n class=\"disabled separator\"\n >\n <td\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <hr/>\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n}\n@else {\n @if (templateType == 'template') {\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': parentContext,\n 'item': parentItem,\n 'element': this.viewContainer?.element?.nativeElement,\n 'menu': this\n }\"\n />\n }\n @else {\n <ng-container\n [cdkPortalOutlet]=\"componentPortal\"\n />\n }\n}\n\n@if (showDebugOverlay) {\n <div>\n <div>hbs: {{hasBootstrapped}}</div>\n <div>pov: {{pointerIsOnVoid}}</div>\n <div>ilo: {{isLockedOpen}}</div>\n <div>hbom: {{pointerHasBeenOverMask}}</div>\n\n <div>type: {{templateType}}</div>\n </div>\n}\n", styles: ["::ng-deep .cdk-overlay-container .ngx-menu{--mdc-dialog-container-color: var(--ngx-menu-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-pane.ngx-menu .mat-mdc-dialog-surface{overflow:visible}:host{-webkit-user-select:none;user-select:none;z-index:1;position:relative;display:block}table{border-spacing:0;border-radius:5px;padding:4px 0}tr{color:var(--ngx-menu-text-color, #ccc);font-size:var(--ngx-menu-font-size, 14px);cursor:pointer;transition:background-color 75ms ease,color 75ms ease}tr:not(.disabled).hover,tr:not(.disabled).open{background-color:var(--ngx-menu-hover-background-color, #94ebeb);color:var(--ngx-menu-hover-text-color, #000)}tr:not(.disabled).hover a,tr:not(.disabled).open a{color:var(--ngx-menu-hover-text-color, #000)}tr:not(.separator){height:36px}tr.disabled .label{color:var(--ngx-menu-disabled-text-color, #919191)}tr .center{text-align:center}tr a{outline:0;display:flex;align-items:center;gap:10px;justify-content:space-between;height:100%;width:100%}tr .label{min-width:100px}tr img{max-width:100%;max-height:100%;aspect-ratio:1}.hr{height:1px;text-align:center;position:relative}.hr:before,.hr:after{content:\"\";background:var(--ngx-menu-separator-color, #2a2a2a);display:block;position:absolute;top:0;bottom:0;height:1px;margin:auto;width:300px}.hr:before{right:calc(100% + 4px)}.hr:after{left:calc(100% + 4px)}hr{background:var(--ngx-menu-separator-color, #2a2a2a);border:0;height:1px;margin:0}.icon{width:24px;height:24px;padding-left:10px}.icon mat-icon{transform:translateY(2px)}.shortcut{color:var(--ngx-menu-shortcut-text-color, #848484);text-align:end;padding-right:10px;padding-left:12px}.label{height:var(--ngx-menu-item-height, 30px)}td{vertical-align:middle}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2}\n"] }]
827
- }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i1$1.DomSanitizer }, { type: undefined, decorators: [{
541
+ ], standalone: true, host: {
542
+ "[attr.tx]": "targetBounds?.x",
543
+ "[attr.ty]": "targetBounds?.y",
544
+ "[attr.th]": "targetBounds?.height",
545
+ "[attr.tw]": "targetBounds?.width",
546
+ }, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords && !parentIsNgxMenu) {\n <div\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.background]=\"showDebugOverlay ? '#f004' : '#0000'\"\n style=\"z-index: -1\"\n (pointerenter)=\"pointerHasBeenOverMask=true;startCloseTimer()\"\n (pointerleave)=\"stopCloseTimer()\"\n (pointermove)=\"pointerHasBeenOverMask=true\"\n (click)=\"isLockedOpen = true\"\n ></div>\n}\n\n@if (!parentIsNgxMenu) {\n <div class=\"void\"\n [style.background]=\"showDebugOverlay ? '#00f4' : '#0000'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && !isLockedOpen && startCloseTimer()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"hasBootstrapped && closeOnVoid(true)\"\n (pointermove)=\"hasBootstrapped && !isLockedOpen && startCloseTimer()\"\n (click)=\"closeOnVoid(true)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n@if (!template) {\n <table (pointerenter)=\"stopCloseTimer()\">\n <tbody>\n @for (item of items; track item) {\n <!-- A row with a click action -->\n @if (item != 'separator' && item.separator != true && item['_visible']) {\n <tr #row\n [class.disabled]=\"item['_disabled']\"\n (click)=\"!item['_disabled'] && onMenuItemClick(item, row, true)\"\n [class.hover]=\"row['hover']\"\n [class.open]=\"row['_open']\"\n (pointerenter)=\"row['hover'] = true; startHoverTimer(item, row)\"\n (pointerleave)=\"row['hover'] = false; stopHoverTimer(item)\"\n >\n\n @if (showIconColumn) {\n <td class=\"icon\">\n @if (matIconRx.test(item['_icon'] ?? item.icon)) {\n <img [src]=\"item['_icon'] ?? item.icon\"/>\n }\n @else {\n <mat-icon\n [fontIcon]=\"item['_icon'] ?? item.icon\"\n [style.color]=\"item.iconColor\"\n />\n }\n </td>\n }\n\n <!-- 'Normal' action based item -->\n <td class=\"label\"\n [style.padding-left]=\"showIconColumn ? 0 : '16px'\"\n >\n <a\n #anchor\n [attr.target]=\"item.linkTarget\"\n [attr.href]=\"(item['_link'] || item.link) ? sanitizer.bypassSecurityTrustUrl(item['_link'] || item.link) : undefined\"\n >\n @if ($any(item.labelTemplate)?.prototype) {\n <ng-container\n [ngTemplateOutlet]=\"$any(item).labelTemplate\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': item['_context'],\n 'item': item,\n 'element': anchor,\n 'menu': this\n }\"\n />\n }\n @else {\n @if ($any(item)?.labelTemplate) {\n {{$any(item)?.labelTemplate(data || {})}}\n }\n @else {\n <div [innerHTML]=\"item['_formattedLabel']\"></div>\n }\n }\n </a>\n </td>\n\n @if (showShortcutColumn) {\n <td class=\"shortcut\">\n {{item.shortcutLabel}}\n </td>\n }\n\n <td style=\"min-width: 16px\">\n @if ((\n (item['children']?.length > 0) ||\n (item['_children']?.length > 0) ||\n item.childTemplate ||\n item.children?.['call'] ||\n item.childrenResolver\n ) &&\n !item['_isResolving']\n ) {\n <mat-icon\n style=\"transform: translateY(2px)\"\n >\n chevron_right\n </mat-icon>\n }\n\n @if (item['_isResolving']) {\n <mat-progress-spinner\n mode=\"indeterminate\"\n [diameter]=\"20\"\n style=\"margin-right: 4px\"\n />\n }\n </td>\n </tr>\n }\n @else if (item != 'separator' && item.separator == true) {\n <!-- Separator with label -->\n <tr\n class=\"disabled separator\"\n >\n <td\n class=\"center\"\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <span class=\"hr\">\n {{item['label'] || ''}}\n </span>\n </td>\n </tr>\n }\n @else if (item == 'separator') {\n <!-- Separator -->\n <tr\n class=\"disabled separator\"\n >\n <td\n [attr.colspan]=\"2 + (showIconColumn ? 1 : 0) + (showShortcutColumn ? 1 : 0)\"\n >\n <hr/>\n </td>\n </tr>\n }\n }\n </tbody>\n </table>\n}\n@else {\n @if (templateType == 'template') {\n <div style=\"display: contents;\" (pointerenter)=\"stopCloseTimer()\">\n <ng-container\n [ngTemplateOutlet]=\"template\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'context': parentContext,\n 'item': parentItem,\n 'element': this.viewContainer?.element?.nativeElement,\n 'menu': this\n }\"\n />\n </div>\n }\n @else {\n <div style=\"display: contents;\" (pointerenter)=\"stopCloseTimer()\">\n <ng-container\n [cdkPortalOutlet]=\"componentPortal\"\n />\n </div>\n }\n}\n\n@if (showDebugOverlay) {\n <div>\n <div>hbs: {{hasBootstrapped}}</div>\n <div>pov: {{pointerIsOnVoid}}</div>\n <div>ilo: {{isLockedOpen}}</div>\n <div>hbom: {{pointerHasBeenOverMask}}</div>\n\n <div>type: {{templateType}}</div>\n </div>\n}\n", styles: ["::ng-deep .cdk-overlay-container .ngx-menu{--mdc-dialog-container-color: var(--ngx-menu-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-menu .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-pane.ngx-menu .mat-mdc-dialog-surface{overflow:visible}:host{-webkit-user-select:none;user-select:none;z-index:1;position:relative;display:block}table{border-spacing:0;border-radius:5px;padding:4px 0}tr{color:var(--ngx-menu-text-color, #ccc);font-size:var(--ngx-menu-font-size, 14px);cursor:pointer;transition:background-color 75ms ease,color 75ms ease}tr:not(.disabled).hover,tr:not(.disabled).open{background-color:var(--ngx-menu-hover-background-color, #94ebeb);color:var(--ngx-menu-hover-text-color, #000)}tr:not(.disabled).hover a,tr:not(.disabled).open a{color:var(--ngx-menu-hover-text-color, #000)}tr:not(.separator){height:36px}tr.disabled .label{color:var(--ngx-menu-disabled-text-color, #919191)}tr .center{text-align:center}tr a{outline:0;display:flex;align-items:center;gap:10px;justify-content:space-between;height:100%;width:100%}tr .label{min-width:100px}tr img{max-width:100%;max-height:100%;aspect-ratio:1}.hr{height:1px;text-align:center;position:relative}.hr:before,.hr:after{content:\"\";background:var(--ngx-menu-separator-color, #2a2a2a);display:block;position:absolute;top:0;bottom:0;height:1px;margin:auto;width:300px}.hr:before{right:calc(100% + 4px)}.hr:after{left:calc(100% + 4px)}hr{background:var(--ngx-menu-separator-color, #2a2a2a);border:0;height:1px;margin:0}.icon{width:24px;height:24px;padding-left:10px}.icon mat-icon{transform:translateY(2px)}.shortcut{color:var(--ngx-menu-shortcut-text-color, #848484);text-align:end;padding-right:10px;padding-left:12px}.label{height:var(--ngx-menu-item-height, 30px)}td{vertical-align:middle}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2}\n"] }]
547
+ }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: i1.DomSanitizer }, { type: undefined, decorators: [{
828
548
  type: Optional
829
549
  }, {
830
550
  type: Inject,
831
551
  args: [MAT_DIALOG_DATA]
832
- }] }, { type: i1.MatDialog, decorators: [{
552
+ }] }, { type: i1$1.MatDialog, decorators: [{
833
553
  type: Optional
834
- }] }, { type: i1.MatDialogRef, decorators: [{
554
+ }] }, { type: i1$1.MatDialogRef, decorators: [{
835
555
  type: Optional
836
556
  }] }], propDecorators: { data: [{
837
557
  type: Input
@@ -847,6 +567,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
847
567
  type: Input
848
568
  }], showDebugOverlay: [{
849
569
  type: Input
570
+ }], targetBounds: [{
571
+ type: Input
850
572
  }], ownerCords: [{
851
573
  type: Input
852
574
  }], selfCords: [{
@@ -862,12 +584,353 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
862
584
  args: ["window:resize"]
863
585
  }] } });
864
586
 
865
- class MenuDirective {
866
- constructor(dialog, viewContainer) {
867
- this.dialog = dialog;
868
- this.viewContainer = viewContainer;
869
- /**
870
- * Configuration for opening the app menu
587
+ const zone = new Zone(Zone.current, { name: "@dotglitch_menu", properties: {} });
588
+ const calcTooltipBounds = async (template, data, matDialogConfig) => {
589
+ const args = {
590
+ data: data || {},
591
+ template,
592
+ config: {},
593
+ selfCords: { left: "0px", top: "0px" },
594
+ ownerCords: { x: 0, y: 0, width: 0, height: 0 },
595
+ id: null
596
+ };
597
+ // dimensions should be in px... Might need to handle vw/v
598
+ if (matDialogConfig?.width && matDialogConfig?.height) {
599
+ return {
600
+ width: parseInt(matDialogConfig.width),
601
+ height: parseInt(matDialogConfig.height),
602
+ top: 0,
603
+ left: 0,
604
+ right: 0,
605
+ bottom: 0
606
+ };
607
+ }
608
+ return new Promise((res, rej) => {
609
+ zone.run(async () => {
610
+ // Forcibly bootstrap the ctx menu outside of the client application's zone.
611
+ const app = await createApplication({
612
+ providers: [
613
+ { provide: MAT_DIALOG_DATA, useValue: args }
614
+ ]
615
+ });
616
+ const del = document.createElement("div");
617
+ del.style.position = "absolute";
618
+ del.style.left = '-1000vw';
619
+ document.body.append(del);
620
+ const base = app.bootstrap(TooltipComponent, del);
621
+ const { instance } = base;
622
+ await firstValueFrom(app.isStable);
623
+ const el = instance.viewContainer?.element?.nativeElement;
624
+ const rect = el.getBoundingClientRect();
625
+ app.destroy();
626
+ del.remove();
627
+ res(rect);
628
+ });
629
+ });
630
+ };
631
+ class TooltipComponent {
632
+ constructor(viewContainer, _data, dialog, // optional only for the purpose of estimating dimensions
633
+ dialogRef) {
634
+ this.viewContainer = viewContainer;
635
+ this._data = _data;
636
+ this.dialog = dialog;
637
+ this.dialogRef = dialogRef;
638
+ this.isTemplate = false;
639
+ this.isMenu = false;
640
+ this.hasBootstrapped = false;
641
+ this.pointerIsOnVoid = false;
642
+ this.isLockedOpen = false;
643
+ this.clientWidth = window.innerWidth;
644
+ this.clientHeight = window.innerHeight;
645
+ this.coverRectCords = {
646
+ top: 0,
647
+ left: 0,
648
+ height: 0,
649
+ width: 0
650
+ };
651
+ // Defaults are set before @Input() hooks evaluate
652
+ this.data = this.data || this._data?.data || {};
653
+ this.config = this.config || this._data?.config;
654
+ this.dialog = this.dialog || this._data?.dialog;
655
+ this.template = this.template || this._data?.template;
656
+ this.ownerCords = this.ownerCords || this._data?.ownerCords;
657
+ this.selfCords = this.selfCords || this._data?.selfCords;
658
+ this.isLockedOpen = this._data?.isLockedOpen || this.config?.stayOpen;
659
+ }
660
+ ngOnInit() {
661
+ const selfY = parseInt(this.selfCords.top.replace('px', ''));
662
+ const selfX = parseInt(this.selfCords.left.replace('px', ''));
663
+ this.coverRectCords = {
664
+ top: this.ownerCords.y - selfY - 16,
665
+ left: this.ownerCords.x - selfX - 16,
666
+ height: this.ownerCords.height + 32,
667
+ width: this.ownerCords.width + 32
668
+ };
669
+ if (Array.isArray(this.template))
670
+ this.isMenu = true;
671
+ else if (this.template instanceof TemplateRef)
672
+ this.isTemplate = true;
673
+ else if (typeof this.template == "function")
674
+ this.isTemplate = false;
675
+ else
676
+ throw new Error("Unrecognized template object provided.");
677
+ // TODO: resolve the event hook with the .void element
678
+ setTimeout(() => {
679
+ this.hasBootstrapped = true;
680
+ if (this.pointerIsOnVoid && !this.isLockedOpen)
681
+ this.dialogRef.close();
682
+ }, 200);
683
+ }
684
+ ngAfterViewInit() {
685
+ const el = this.viewContainer.element.nativeElement;
686
+ el.addEventListener("keydown", evt => {
687
+ this.isLockedOpen = true;
688
+ });
689
+ el.addEventListener("pointerdown", evt => {
690
+ this.isLockedOpen = true;
691
+ });
692
+ el.addEventListener("touch", evt => {
693
+ this.isLockedOpen = true;
694
+ });
695
+ }
696
+ onKeyDown(evt) {
697
+ if (this.config?.freezeOnKeyCode) {
698
+ if (evt.code == this.config.freezeOnKeyCode)
699
+ this.isLockedOpen = true;
700
+ }
701
+ }
702
+ onVoidPointerDown(evt) {
703
+ if (!this.isLockedOpen) {
704
+ const el = this.viewContainer.element.nativeElement;
705
+ el.querySelector(".void").remove();
706
+ setTimeout(() => {
707
+ const clonedEvt = new PointerEvent("pointerdown", evt);
708
+ const target = document.elementFromPoint(evt.clientX, evt.clientY);
709
+ console.log("DEBUG EVENTS", { evt, clonedEvt });
710
+ target.dispatchEvent(clonedEvt);
711
+ }, 15);
712
+ }
713
+ this.closeOnVoid(true);
714
+ }
715
+ // If the void element gets stuck open, make wheel events pass through.
716
+ onWheel(evt) {
717
+ const el = this.viewContainer.element.nativeElement;
718
+ el.style.display = "none";
719
+ const target = document.elementFromPoint(evt.clientX, evt.clientY);
720
+ el.style.display = "block";
721
+ target.scroll({
722
+ top: evt.deltaY + target.scrollTop,
723
+ left: evt.deltaX + target.scrollLeft,
724
+ behavior: "smooth"
725
+ });
726
+ }
727
+ /**
728
+ * Close the tooltip if these actions occur
729
+ */
730
+ onClose() {
731
+ if (!this.isLockedOpen)
732
+ this.dialogRef?.close();
733
+ this.clientWidth = window.innerWidth;
734
+ this.clientHeight = window.innerHeight;
735
+ }
736
+ closeOnVoid(force = false) {
737
+ if (!this.isLockedOpen || force)
738
+ this.dialogRef.close();
739
+ }
740
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TooltipComponent, deps: [{ token: i0.ViewContainerRef }, { token: MAT_DIALOG_DATA, optional: true }, { token: i1$1.MatDialog, optional: true }, { token: i1$1.MatDialogRef, optional: true }], target: i0.ɵɵFactoryTarget.Component }); }
741
+ static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: TooltipComponent, isStandalone: true, selector: "ngx-tooltip", inputs: { data: "data", config: "config", ownerCords: "ownerCords", selfCords: "selfCords", template: "template" }, host: { listeners: { "window:keydown": "onKeyDown($event)", "window:resize": "onClose()", "window:blur": "onClose()", "pointerleave": "onClose()" } }, ngImport: i0, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords) {\n <!-- <div\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 (pointerdown)=\"onVoidPointerDown($event)\"\n ></div> -->\n\n <div class=\"void left\"\n [style.top]=\"'0px'\"\n [style.left]=\"'0px'\"\n [style.height]=\"'100%'\"\n [style.width]=\"(ownerCords.left) + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void top\"\n [style.top]=\"'0px'\"\n [style.left]=\"ownerCords.left + 'px'\"\n [style.height]=\"ownerCords.top + 'px'\"\n [style.width]=\"ownerCords.width + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void right\"\n [style.top]=\"'0px'\"\n [style.left]=\"(ownerCords.left + ownerCords.width) + 'px'\"\n [style.height]=\"'100%'\"\n [style.width]=\"(clientWidth - (ownerCords.left + ownerCords.width)) + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void\"\n [style.top]=\"(ownerCords.top + ownerCords.height) + 'px'\"\n [style.left]=\"ownerCords.left + 'px'\"\n [style.height]=\"(clientHeight - (ownerCords.top + ownerCords.height)) + 'px'\"\n [style.width]=\"ownerCords.width + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n\n<div\n #container\n class=\"container\"\n>\n @if (isMenu) {\n <ngx-menu\n [config]=\"config\"\n [data]=\"data\"\n [ownerCords]=\"ownerCords\"\n [selfCords]=\"selfCords\"\n [items]=\"$any(template)\"\n [isLockedOpen]=\"config.stayOpen\"\n />\n }\n @else if (isTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"$any(template)\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'element': container,\n 'tooltip': this\n }\"\n ></ng-container>\n }\n @else {\n <ng-container\n [ngComponentOutlet]=\"$any(template)\"\n >\n </ng-container>\n }\n</div>\n", styles: ["::ng-deep .cdk-overlay-container .ngx-tooltip{--mdc-dialog-container-color: var(--ngx-tooltip-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__surface{overflow:visible;background-color:#0000}::ng-deep .cdk-overlay-container .context-menu-backdrop.cdk-overlay-backdrop-showing{opacity:0}::ng-deep .cdk-overlay-pane.ngx-tooltip .mat-dialog-container{padding:0}:host{min-width:2px;min-height:2px;display:block}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2;position:fixed}.container{width:100%;height:100%;background:var(--ngx-tooltip-background-color, #333);border-radius:6px;overflow:hidden}\n"], dependencies: [{ kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }, { kind: "directive", type: NgComponentOutlet, selector: "[ngComponentOutlet]", inputs: ["ngComponentOutlet", "ngComponentOutletInputs", "ngComponentOutletInjector", "ngComponentOutletContent", "ngComponentOutletNgModule", "ngComponentOutletNgModuleFactory"] }, { kind: "component", type: MenuComponent, selector: "ngx-menu", inputs: ["data", "items", "config", "id", "overlayOverlap", "hoverDelay", "showDebugOverlay", "targetBounds", "ownerCords", "selfCords", "parentItem", "parentContext", "isLockedOpen"] }] }); }
742
+ }
743
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TooltipComponent, decorators: [{
744
+ type: Component,
745
+ args: [{ selector: 'ngx-tooltip', imports: [
746
+ NgTemplateOutlet,
747
+ NgComponentOutlet,
748
+ MenuComponent
749
+ ], standalone: true, template: "<!-- Mouse event blocker for pointer leave -->\n@if (coverRectCords) {\n <!-- <div\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 (pointerdown)=\"onVoidPointerDown($event)\"\n ></div> -->\n\n <div class=\"void left\"\n [style.top]=\"'0px'\"\n [style.left]=\"'0px'\"\n [style.height]=\"'100%'\"\n [style.width]=\"(ownerCords.left) + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void top\"\n [style.top]=\"'0px'\"\n [style.left]=\"ownerCords.left + 'px'\"\n [style.height]=\"ownerCords.top + 'px'\"\n [style.width]=\"ownerCords.width + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void right\"\n [style.top]=\"'0px'\"\n [style.left]=\"(ownerCords.left + ownerCords.width) + 'px'\"\n [style.height]=\"'100%'\"\n [style.width]=\"(clientWidth - (ownerCords.left + ownerCords.width)) + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n <div class=\"void\"\n [style.top]=\"(ownerCords.top + ownerCords.height) + 'px'\"\n [style.left]=\"ownerCords.left + 'px'\"\n [style.height]=\"(clientHeight - (ownerCords.top + ownerCords.height)) + 'px'\"\n [style.width]=\"ownerCords.width + 'px'\"\n (pointerenter)=\"pointerIsOnVoid = true; hasBootstrapped && closeOnVoid()\"\n (pointerleave)=\"pointerIsOnVoid = false\"\n (pointerdown)=\"onVoidPointerDown($event)\"\n (wheel)=\"onWheel($event)\"\n ></div>\n}\n\n\n<div\n #container\n class=\"container\"\n>\n @if (isMenu) {\n <ngx-menu\n [config]=\"config\"\n [data]=\"data\"\n [ownerCords]=\"ownerCords\"\n [selfCords]=\"selfCords\"\n [items]=\"$any(template)\"\n [isLockedOpen]=\"config.stayOpen\"\n />\n }\n @else if (isTemplate) {\n <ng-container\n [ngTemplateOutlet]=\"$any(template)\"\n [ngTemplateOutletContext]=\"{\n '$implicit': data,\n 'dialog': dialogRef,\n 'element': container,\n 'tooltip': this\n }\"\n ></ng-container>\n }\n @else {\n <ng-container\n [ngComponentOutlet]=\"$any(template)\"\n >\n </ng-container>\n }\n</div>\n", styles: ["::ng-deep .cdk-overlay-container .ngx-tooltip{--mdc-dialog-container-color: var(--ngx-tooltip-background-color, #2f2f2f)}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__container{transform-origin:top left}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog--open .mdc-dialog__container{transform:none}::ng-deep .cdk-overlay-container .ngx-tooltip .mdc-dialog__surface{overflow:visible;background-color:#0000}::ng-deep .cdk-overlay-container .context-menu-backdrop.cdk-overlay-backdrop-showing{opacity:0}::ng-deep .cdk-overlay-pane.ngx-tooltip .mat-dialog-container{padding:0}:host{min-width:2px;min-height:2px;display:block}.void,.owner-mask{position:absolute}.void{top:-100vh;right:-100vw;bottom:-100vh;left:-100vw;z-index:-2;position:fixed}.container{width:100%;height:100%;background:var(--ngx-tooltip-background-color, #333);border-radius:6px;overflow:hidden}\n"] }]
750
+ }], ctorParameters: () => [{ type: i0.ViewContainerRef }, { type: undefined, decorators: [{
751
+ type: Optional
752
+ }, {
753
+ type: Inject,
754
+ args: [MAT_DIALOG_DATA]
755
+ }] }, { type: i1$1.MatDialog, decorators: [{
756
+ type: Optional
757
+ }] }, { type: i1$1.MatDialogRef, decorators: [{
758
+ type: Optional
759
+ }] }], propDecorators: { data: [{
760
+ type: Input
761
+ }], config: [{
762
+ type: Input
763
+ }], ownerCords: [{
764
+ type: Input
765
+ }], selfCords: [{
766
+ type: Input
767
+ }], template: [{
768
+ type: Input
769
+ }], onKeyDown: [{
770
+ type: HostListener,
771
+ args: ["window:keydown", ['$event']]
772
+ }], onClose: [{
773
+ type: HostListener,
774
+ args: ["window:resize"]
775
+ }, {
776
+ type: HostListener,
777
+ args: ["window:blur"]
778
+ }, {
779
+ type: HostListener,
780
+ args: ["pointerleave"]
781
+ }] } });
782
+
783
+ class TooltipDirective {
784
+ constructor(dialog, viewContainer) {
785
+ this.dialog = dialog;
786
+ this.viewContainer = viewContainer;
787
+ /**
788
+ * Configuration for opening the app menu
789
+ */
790
+ this.config = {};
791
+ /**
792
+ * Arbitrary data to pass into the template
793
+ */
794
+ this.data = {};
795
+ this.isCursorOverTarget = false;
796
+ this.dialogIsOpen = false;
797
+ }
798
+ ngAfterViewInit() {
799
+ const el = this.viewContainer.element.nativeElement;
800
+ this.config?.triggers?.forEach(t => {
801
+ el.addEventListener(t, () => {
802
+ if (t == "click")
803
+ this.config.stayOpen = true;
804
+ this.open();
805
+ });
806
+ });
807
+ }
808
+ async open() {
809
+ if (!this.dialogIsOpen) {
810
+ const el = this.viewContainer.element.nativeElement;
811
+ this.dialogIsOpen = true;
812
+ await openTooltip(this.dialog, this.template, this.data, el, this.config);
813
+ this.dialogIsOpen = false;
814
+ }
815
+ }
816
+ async onPointerEnter(evt) {
817
+ // If the template is not a template ref, do nothing.
818
+ if (!(this.template instanceof TemplateRef))
819
+ return;
820
+ if (Array.isArray(this.config?.triggers) && !this.config.triggers.includes("hover")) {
821
+ return;
822
+ }
823
+ this.isCursorOverTarget = true;
824
+ setTimeout(async () => {
825
+ // If the cursor moved away in the time
826
+ if (!this.isCursorOverTarget)
827
+ return;
828
+ this.open();
829
+ }, this.config.delay ?? 250);
830
+ }
831
+ async onPointerLeave(evt) {
832
+ this.isCursorOverTarget = false;
833
+ }
834
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TooltipDirective, deps: [{ token: i1$1.MatDialog }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); }
835
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.1.2", type: TooltipDirective, isStandalone: true, selector: "[ngx-tooltip]", inputs: { template: ["ngx-tooltip", "template"], config: ["ngx-tooltip-config", "config"], data: ["ngx-tooltip-context", "data"] }, host: { listeners: { "pointerenter": "onPointerEnter($event)", "pointerleave": "onPointerLeave($event)" } }, providers: [
836
+ MatDialog
837
+ ], ngImport: i0 }); }
838
+ }
839
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: TooltipDirective, decorators: [{
840
+ type: Directive,
841
+ args: [{
842
+ selector: '[ngx-tooltip]',
843
+ providers: [
844
+ MatDialog
845
+ ],
846
+ standalone: true
847
+ }]
848
+ }], ctorParameters: () => [{ type: i1$1.MatDialog }, { type: i0.ViewContainerRef }], propDecorators: { template: [{
849
+ type: Input,
850
+ args: ["ngx-tooltip"]
851
+ }], config: [{
852
+ type: Input,
853
+ args: ["ngx-tooltip-config"]
854
+ }], data: [{
855
+ type: Input,
856
+ args: ["ngx-tooltip-context"]
857
+ }], onPointerEnter: [{
858
+ type: HostListener,
859
+ args: ['pointerenter', ['$event']]
860
+ }], onPointerLeave: [{
861
+ type: HostListener,
862
+ args: ['pointerleave', ['$event']]
863
+ }] } });
864
+ // Helper to open the context menu without using the directive.
865
+ const openTooltip = async (dialog, template, data, el, config, focusTrap = false, matPopupOptions) => {
866
+ const component = Array.isArray(template) ? MenuComponent : template;
867
+ const rect = await calcTooltipBounds(component, data, matPopupOptions);
868
+ const ownerCords = el.getBoundingClientRect();
869
+ const cords = getPosition(el, config, rect);
870
+ const specificId = ulid();
871
+ return firstValueFrom(dialog.open(TooltipComponent, {
872
+ autoFocus: focusTrap,
873
+ restoreFocus: focusTrap,
874
+ data: {
875
+ dialog,
876
+ data: data,
877
+ template: template,
878
+ config: config,
879
+ matPopupOptions,
880
+ ownerCords: ownerCords,
881
+ selfCords: cords,
882
+ id: specificId
883
+ },
884
+ panelClass: ["ngx-tooltip", 'ngx-' + specificId].concat(config?.customClass || []),
885
+ position: cords,
886
+ hasBackdrop: false,
887
+ ...matPopupOptions
888
+ })
889
+ .afterClosed());
890
+ };
891
+ class DropdownDirective extends TooltipDirective {
892
+ constructor() {
893
+ super(...arguments);
894
+ /**
895
+ * Configuration for opening the app menu
896
+ */
897
+ this._config = {};
898
+ }
899
+ ngOnInit() {
900
+ // Set default values
901
+ this._config.position = this._config.position ?? "bottom";
902
+ this._config.alignment = this._config.alignment ?? "start";
903
+ this._config.stayOpen = this._config.stayOpen ?? true;
904
+ this.config = this._config;
905
+ }
906
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DropdownDirective, deps: null, target: i0.ɵɵFactoryTarget.Directive }); }
907
+ static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.1.2", type: DropdownDirective, isStandalone: true, selector: "[ngx-dropdown],[ngx-dropdown-config]", inputs: { template: ["ngx-dropdown", "template"], _config: ["ngx-dropdown-config", "_config"] }, providers: [
908
+ MatDialog
909
+ ], usesInheritance: true, ngImport: i0 }); }
910
+ }
911
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DropdownDirective, decorators: [{
912
+ type: Directive,
913
+ args: [{
914
+ selector: '[ngx-dropdown],[ngx-dropdown-config]',
915
+ providers: [
916
+ MatDialog
917
+ ],
918
+ standalone: true
919
+ }]
920
+ }], propDecorators: { template: [{
921
+ type: Input,
922
+ args: ["ngx-dropdown"]
923
+ }], _config: [{
924
+ type: Input,
925
+ args: ["ngx-dropdown-config"]
926
+ }] } });
927
+
928
+ class MenuDirective {
929
+ constructor(dialog, viewContainer) {
930
+ this.dialog = dialog;
931
+ this.viewContainer = viewContainer;
932
+ /**
933
+ * Configuration for opening the app menu
871
934
  */
872
935
  this.config = {};
873
936
  }
@@ -919,7 +982,7 @@ class MenuDirective {
919
982
  throw ex;
920
983
  });
921
984
  }
922
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: MenuDirective, deps: [{ token: i1.MatDialog }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); }
985
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: MenuDirective, deps: [{ token: i1$1.MatDialog }, { token: i0.ViewContainerRef }], target: i0.ɵɵFactoryTarget.Directive }); }
923
986
  static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "17.1.2", type: MenuDirective, isStandalone: true, selector: "[ngx-contextmenu],[ngx-menu]", inputs: { data: ["ngx-menu-context", "data"], ctxMenuItems: ["ngx-contextmenu", "ctxMenuItems"], menuItems: ["ngx-menu", "menuItems"], config: ["ngx-menu-config", "config"] }, providers: [
924
987
  MatDialog
925
988
  ], ngImport: i0 }); }
@@ -933,7 +996,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
933
996
  ],
934
997
  standalone: true
935
998
  }]
936
- }], ctorParameters: () => [{ type: i1.MatDialog }, { type: i0.ViewContainerRef }], propDecorators: { data: [{
999
+ }], ctorParameters: () => [{ type: i1$1.MatDialog }, { type: i0.ViewContainerRef }], propDecorators: { data: [{
937
1000
  type: Input,
938
1001
  args: ["ngx-menu-context"]
939
1002
  }], ctxMenuItems: [{
@@ -954,7 +1017,8 @@ const openMenu = async (dialog, menuItems, data, evt, config = {}, el) => {
954
1017
  // Apply defaults.
955
1018
  if (!config.alignment)
956
1019
  config.alignment = "start";
957
- const cords = getPosition(el || evt, config, await calcMenuItemBounds(menuItems, data));
1020
+ const initialBounds = await calcMenuItemBounds(menuItems, data);
1021
+ const cords = getPosition(el || evt, config, initialBounds);
958
1022
  const specificId = ulid();
959
1023
  return firstValueFrom(dialog.open(MenuComponent, {
960
1024
  data: {
@@ -964,7 +1028,8 @@ const openMenu = async (dialog, menuItems, data, evt, config = {}, el) => {
964
1028
  selfCords: cords,
965
1029
  items: menuItems,
966
1030
  config: config,
967
- id: specificId
1031
+ id: specificId,
1032
+ targetBounds: initialBounds
968
1033
  },
969
1034
  panelClass: ["ngx-menu", 'ngx-' + specificId].concat(config?.customClass || []),
970
1035
  position: cords,
@@ -1126,7 +1191,7 @@ class HtmlBypass {
1126
1191
  transform(url) {
1127
1192
  return this.sanitizer.bypassSecurityTrustHtml(url);
1128
1193
  }
1129
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: HtmlBypass, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1194
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: HtmlBypass, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1130
1195
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.1.2", ngImport: i0, type: HtmlBypass, isStandalone: true, name: "htmlbypass" }); }
1131
1196
  }
1132
1197
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: HtmlBypass, decorators: [{
@@ -1135,7 +1200,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
1135
1200
  name: 'htmlbypass',
1136
1201
  standalone: true
1137
1202
  }]
1138
- }], ctorParameters: () => [{ type: i1$1.DomSanitizer }] });
1203
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }] });
1139
1204
 
1140
1205
  /**
1141
1206
  * Url Sanitizer pipe.
@@ -1150,7 +1215,7 @@ class ResourceBypass {
1150
1215
  transform(url) {
1151
1216
  return this.sanitizer.bypassSecurityTrustResourceUrl(url);
1152
1217
  }
1153
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ResourceBypass, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1218
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ResourceBypass, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1154
1219
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.1.2", ngImport: i0, type: ResourceBypass, isStandalone: true, name: "resourcebypass" }); }
1155
1220
  }
1156
1221
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ResourceBypass, decorators: [{
@@ -1159,7 +1224,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
1159
1224
  name: 'resourcebypass',
1160
1225
  standalone: true
1161
1226
  }]
1162
- }], ctorParameters: () => [{ type: i1$1.DomSanitizer }] });
1227
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }] });
1163
1228
 
1164
1229
  /**
1165
1230
  * Url Sanitizer pipe.
@@ -1174,7 +1239,7 @@ class ScriptBypass {
1174
1239
  transform(url) {
1175
1240
  return this.sanitizer.bypassSecurityTrustScript(url);
1176
1241
  }
1177
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ScriptBypass, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1242
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ScriptBypass, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1178
1243
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.1.2", ngImport: i0, type: ScriptBypass, isStandalone: true, name: "scriptbypass" }); }
1179
1244
  }
1180
1245
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: ScriptBypass, decorators: [{
@@ -1183,7 +1248,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
1183
1248
  name: 'scriptbypass',
1184
1249
  standalone: true
1185
1250
  }]
1186
- }], ctorParameters: () => [{ type: i1$1.DomSanitizer }] });
1251
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }] });
1187
1252
 
1188
1253
  /**
1189
1254
  * Url Sanitizer pipe.
@@ -1198,7 +1263,7 @@ class StyleBypass {
1198
1263
  transform(url) {
1199
1264
  return this.sanitizer.bypassSecurityTrustStyle(url);
1200
1265
  }
1201
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: StyleBypass, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1266
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: StyleBypass, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1202
1267
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.1.2", ngImport: i0, type: StyleBypass, isStandalone: true, name: "stylebypass" }); }
1203
1268
  }
1204
1269
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: StyleBypass, decorators: [{
@@ -1207,7 +1272,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
1207
1272
  name: 'stylebypass',
1208
1273
  standalone: true
1209
1274
  }]
1210
- }], ctorParameters: () => [{ type: i1$1.DomSanitizer }] });
1275
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }] });
1211
1276
 
1212
1277
  /**
1213
1278
  * Url Sanitizer pipe.
@@ -1222,7 +1287,7 @@ class UrlBypass {
1222
1287
  transform(url) {
1223
1288
  return this.sanitizer.bypassSecurityTrustUrl(url);
1224
1289
  }
1225
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UrlBypass, deps: [{ token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1290
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UrlBypass, deps: [{ token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Pipe }); }
1226
1291
  static { this.ɵpipe = i0.ɵɵngDeclarePipe({ minVersion: "14.0.0", version: "17.1.2", ngImport: i0, type: UrlBypass, isStandalone: true, name: "urlbypass" }); }
1227
1292
  }
1228
1293
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: UrlBypass, decorators: [{
@@ -1231,7 +1296,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
1231
1296
  name: 'urlbypass',
1232
1297
  standalone: true
1233
1298
  }]
1234
- }], ctorParameters: () => [{ type: i1$1.DomSanitizer }] });
1299
+ }], ctorParameters: () => [{ type: i1.DomSanitizer }] });
1235
1300
 
1236
1301
  const sleep = ms => new Promise(r => setTimeout(r, ms));
1237
1302
  /**
@@ -2138,7 +2203,7 @@ class DialogService {
2138
2203
  clearDialog() {
2139
2204
  this.dialogs.forEach(dialog => dialog.close());
2140
2205
  }
2141
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DialogService, deps: [{ token: i1.MatDialog }, { token: LazyLoaderService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2206
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DialogService, deps: [{ token: i1$1.MatDialog }, { token: LazyLoaderService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2142
2207
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DialogService, providedIn: 'root' }); }
2143
2208
  }
2144
2209
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: DialogService, decorators: [{
@@ -2146,7 +2211,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
2146
2211
  args: [{
2147
2212
  providedIn: 'root'
2148
2213
  }]
2149
- }], ctorParameters: () => [{ type: i1.MatDialog }, { type: LazyLoaderService }] });
2214
+ }], ctorParameters: () => [{ type: i1$1.MatDialog }, { type: LazyLoaderService }] });
2150
2215
 
2151
2216
  // Total number of _retries_ if there is a 429 response code.
2152
2217
  const retryCount = 2;
@@ -2702,7 +2767,7 @@ class CommandPaletteComponent {
2702
2767
  this.dialog.close();
2703
2768
  }
2704
2769
  }
2705
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: CommandPaletteComponent, deps: [{ token: CommandPaletteService }, { token: i1.MatDialogRef }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component }); }
2770
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: CommandPaletteComponent, deps: [{ token: CommandPaletteService }, { token: i1$1.MatDialogRef }, { token: i0.ElementRef }, { token: i0.ChangeDetectorRef }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component }); }
2706
2771
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: CommandPaletteComponent, isStandalone: true, selector: "ngx-command-palette", inputs: { contextElement: "contextElement" }, host: { listeners: { "click": "textInput.nativeElement.focus()", "window:blur": "onBlur()", "window:resize": "onBlur()" } }, viewQueries: [{ propertyName: "scrollbar", first: true, predicate: NgScrollbar, descendants: true }, { propertyName: "textInput", first: true, predicate: ["textinput"], descendants: true }], ngImport: i0, template: "<mat-form-field style=\"width: 100%; padding: 8px 8px 0 8px\">\n <ngx-commandpalette-breadcrumb\n [breadcrumbs]=\"breadcrumbs\"\n />\n <input\n #textinput\n matInput\n type=\"text\"\n [value]=\"queryString\"\n (keydown)=\"onKeyDown($event)\"\n >\n</mat-form-field>\n\n@if (filteredCommands.length == 0) {\n <div class=\"commands\">\n <div class=\"command selected\">\n <div class=\"label\">No matching results.</div>\n </div>\n </div>\n}\n@else {\n <div\n class=\"commands\"\n [style.flex]=\"(filteredCommands.length * rowHeight) + 'px'\"\n [class.shadow]=\"scrollbar?.viewport?.scrollTop > 2\"\n >\n <ng-scrollbar #scrollbar>\n <cdk-virtual-scroll-viewport [itemSize]=\"rowHeight\" scrollViewport [minBufferPx]=\"150\">\n <div\n *cdkVirtualFor=\"let command of filteredCommands; let index = index\"\n class=\"command\"\n [style.height]=\"rowHeight + 'px'\"\n [class.selected]=\"index==activeIndex\"\n [class.has-icon]=\"command.icon\"\n [attr.index]=\"index\"\n (click)=\"executeCommand(command)\"\n >\n @if (command.icon) {\n <div class=\"icon\">\n @if (!MAT_ICON_REGEX.test(command.icon)) {\n <mat-icon [fontIcon]=\"command.icon\"></mat-icon>\n }\n @else {\n <img [src]=\"command.icon\"/>\n }\n </div>\n }\n\n <div\n class=\"label\"\n [innerHTML]=\"command['_renderedLabel'] || command.label || command.description\"\n ></div>\n\n @if (command['_renderedHint'] || command.hint) {\n <div\n class=\"hint\"\n [innerHTML]=\"command['_renderedHint'] || command.hint\"\n ></div>\n }\n <div style=\"flex: 1\"></div>\n\n <div>\n @for (shortcut of (command.shortcutKey?.find ? command.shortcutKey : [command.shortcutKey]); track shortcut) {\n @if (shortcut) {\n <ngx-commandpalette-shortcut [shortcut]=\"shortcut\"/>\n }\n }\n </div>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-scrollbar>\n </div>\n}\n\n", styles: [":host{display:flex;flex-direction:column;width:860px;max-height:460px;border:1px solid #484848;border-radius:6px;background-color:#222;-webkit-user-select:none;user-select:none;overflow:hidden;--text-color: #ccc;--transition: .25s ease}.commands{max-height:100%;overflow:hidden;position:relative;padding:0 6px}.commands .command{display:flex;padding-left:16px;padding-right:32px;align-items:center;border-radius:3px;justify-content:space-between;color:var(--text-color);font-size:15.5px;background-color:#0000}.commands .command:hover{background-color:#2a2d2e}.commands .command.selected{background-color:#04395e}.commands .command.has-icon{padding-left:8px}.commands .command .label ::ng-deep b{color:#2196f3}.commands .command .icon{width:38px;height:100%;display:flex;align-items:center;justify-content:center}.commands .command img{max-height:100%;padding:4px}.commands .command .hint{margin-left:12px;opacity:.75}.commands.shadow:after{box-shadow:#000 0 6px 6px -6px inset}.commands:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:6px;box-shadow:#0000 0 6px 6px -6px inset;transition:box-shadow .3s ease}ng-scrollbar.ng-scrollbar{--scrollbar-padding: 0px;--scrollbar-size: 14px;--scrollbar-border-radius: 0;--scrollbar-thumb-color: #4440;--scrollbar-thumb-transition: height ease-out .15s, width ease-out .15s, background-color ease 1.2s;animation:fadeScrollbar 1.2s ease}ng-scrollbar.ng-scrollbar:hover{--scrollbar-thumb-color: #444f}@keyframes fadeScrollbar{0%{--scrollbar-thumb-color: #444f}to{--scrollbar-thumb-color: #4440}}cdk-virtual-scroll-viewport{height:100%;padding-bottom:6px}:host ::ng-deep .mdc-text-field--no-label:not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mat-mdc-form-field-infix{padding:2px 0 4px}:host ::ng-deep .mat-mdc-form-field-infix{min-height:32px;display:flex}:host ::ng-deep .mat-mdc-text-field-wrapper{margin-bottom:8px;padding:0 12px}:host ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}::ng-deep .light app-command-palette{border:1px solid #e5e5e5;background-color:#f8f8f8;--text-color: #262626}::ng-deep .light app-command-palette .commands .command:hover{background-color:#f2f2f2}::ng-deep .light app-command-palette .commands .command.selected{background-color:#e8e8e8}\n"], dependencies: [{ kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i4$1.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i6.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i6.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i6.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }, { kind: "ngmodule", type: NgScrollbarModule }, { kind: "component", type: i7.NgScrollbar, selector: "ng-scrollbar", inputs: ["disabled", "sensorDisabled", "pointerEventsDisabled", "viewportPropagateMouseMove", "autoHeightDisabled", "autoWidthDisabled", "viewClass", "trackClass", "thumbClass", "minThumbSize", "trackClickScrollDuration", "pointerEventsMethod", "track", "visibility", "appearance", "position", "sensorDebounce", "scrollAuditTime"], outputs: ["updated"], exportAs: ["ngScrollbar"] }, { kind: "directive", type: i7.ScrollViewport, selector: "[scrollViewport]" }, { kind: "component", type: ShortcutComponent, selector: "ngx-commandpalette-shortcut", inputs: ["shortcut"] }, { kind: "component", type: BreadcrumbComponent, selector: "ngx-commandpalette-breadcrumb", inputs: ["breadcrumbs"] }] }); }
2707
2772
  }
2708
2773
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: CommandPaletteComponent, decorators: [{
@@ -2717,7 +2782,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
2717
2782
  ShortcutComponent,
2718
2783
  BreadcrumbComponent
2719
2784
  ], standalone: true, template: "<mat-form-field style=\"width: 100%; padding: 8px 8px 0 8px\">\n <ngx-commandpalette-breadcrumb\n [breadcrumbs]=\"breadcrumbs\"\n />\n <input\n #textinput\n matInput\n type=\"text\"\n [value]=\"queryString\"\n (keydown)=\"onKeyDown($event)\"\n >\n</mat-form-field>\n\n@if (filteredCommands.length == 0) {\n <div class=\"commands\">\n <div class=\"command selected\">\n <div class=\"label\">No matching results.</div>\n </div>\n </div>\n}\n@else {\n <div\n class=\"commands\"\n [style.flex]=\"(filteredCommands.length * rowHeight) + 'px'\"\n [class.shadow]=\"scrollbar?.viewport?.scrollTop > 2\"\n >\n <ng-scrollbar #scrollbar>\n <cdk-virtual-scroll-viewport [itemSize]=\"rowHeight\" scrollViewport [minBufferPx]=\"150\">\n <div\n *cdkVirtualFor=\"let command of filteredCommands; let index = index\"\n class=\"command\"\n [style.height]=\"rowHeight + 'px'\"\n [class.selected]=\"index==activeIndex\"\n [class.has-icon]=\"command.icon\"\n [attr.index]=\"index\"\n (click)=\"executeCommand(command)\"\n >\n @if (command.icon) {\n <div class=\"icon\">\n @if (!MAT_ICON_REGEX.test(command.icon)) {\n <mat-icon [fontIcon]=\"command.icon\"></mat-icon>\n }\n @else {\n <img [src]=\"command.icon\"/>\n }\n </div>\n }\n\n <div\n class=\"label\"\n [innerHTML]=\"command['_renderedLabel'] || command.label || command.description\"\n ></div>\n\n @if (command['_renderedHint'] || command.hint) {\n <div\n class=\"hint\"\n [innerHTML]=\"command['_renderedHint'] || command.hint\"\n ></div>\n }\n <div style=\"flex: 1\"></div>\n\n <div>\n @for (shortcut of (command.shortcutKey?.find ? command.shortcutKey : [command.shortcutKey]); track shortcut) {\n @if (shortcut) {\n <ngx-commandpalette-shortcut [shortcut]=\"shortcut\"/>\n }\n }\n </div>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-scrollbar>\n </div>\n}\n\n", styles: [":host{display:flex;flex-direction:column;width:860px;max-height:460px;border:1px solid #484848;border-radius:6px;background-color:#222;-webkit-user-select:none;user-select:none;overflow:hidden;--text-color: #ccc;--transition: .25s ease}.commands{max-height:100%;overflow:hidden;position:relative;padding:0 6px}.commands .command{display:flex;padding-left:16px;padding-right:32px;align-items:center;border-radius:3px;justify-content:space-between;color:var(--text-color);font-size:15.5px;background-color:#0000}.commands .command:hover{background-color:#2a2d2e}.commands .command.selected{background-color:#04395e}.commands .command.has-icon{padding-left:8px}.commands .command .label ::ng-deep b{color:#2196f3}.commands .command .icon{width:38px;height:100%;display:flex;align-items:center;justify-content:center}.commands .command img{max-height:100%;padding:4px}.commands .command .hint{margin-left:12px;opacity:.75}.commands.shadow:after{box-shadow:#000 0 6px 6px -6px inset}.commands:after{content:\"\";position:absolute;top:0;left:0;width:100%;height:6px;box-shadow:#0000 0 6px 6px -6px inset;transition:box-shadow .3s ease}ng-scrollbar.ng-scrollbar{--scrollbar-padding: 0px;--scrollbar-size: 14px;--scrollbar-border-radius: 0;--scrollbar-thumb-color: #4440;--scrollbar-thumb-transition: height ease-out .15s, width ease-out .15s, background-color ease 1.2s;animation:fadeScrollbar 1.2s ease}ng-scrollbar.ng-scrollbar:hover{--scrollbar-thumb-color: #444f}@keyframes fadeScrollbar{0%{--scrollbar-thumb-color: #444f}to{--scrollbar-thumb-color: #4440}}cdk-virtual-scroll-viewport{height:100%;padding-bottom:6px}:host ::ng-deep .mdc-text-field--no-label:not(.mdc-text-field--outlined):not(.mdc-text-field--textarea) .mat-mdc-form-field-infix{padding:2px 0 4px}:host ::ng-deep .mat-mdc-form-field-infix{min-height:32px;display:flex}:host ::ng-deep .mat-mdc-text-field-wrapper{margin-bottom:8px;padding:0 12px}:host ::ng-deep .mat-mdc-form-field-subscript-wrapper{display:none}::ng-deep .light app-command-palette{border:1px solid #e5e5e5;background-color:#f8f8f8;--text-color: #262626}::ng-deep .light app-command-palette .commands .command:hover{background-color:#f2f2f2}::ng-deep .light app-command-palette .commands .command.selected{background-color:#e8e8e8}\n"] }]
2720
- }], ctorParameters: () => [{ type: CommandPaletteService }, { type: i1.MatDialogRef }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
2785
+ }], ctorParameters: () => [{ type: CommandPaletteService }, { type: i1$1.MatDialogRef }, { type: i0.ElementRef }, { type: i0.ChangeDetectorRef }, { type: undefined, decorators: [{
2721
2786
  type: Inject,
2722
2787
  args: [MAT_DIALOG_DATA]
2723
2788
  }] }], propDecorators: { scrollbar: [{
@@ -2929,7 +2994,7 @@ class CommandPaletteService {
2929
2994
  getRegisteredCommands(element = document.body) {
2930
2995
  return this.getCommandBlocks(element).map(c => c.actions).flat();
2931
2996
  }
2932
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: CommandPaletteService, deps: [{ token: i1.MatDialog }, { token: LazyLoaderService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2997
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: CommandPaletteService, deps: [{ token: i1$1.MatDialog }, { token: LazyLoaderService }], target: i0.ɵɵFactoryTarget.Injectable }); }
2933
2998
  static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: CommandPaletteService, providedIn: 'root' }); }
2934
2999
  }
2935
3000
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: CommandPaletteService, decorators: [{
@@ -2937,7 +3002,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
2937
3002
  args: [{
2938
3003
  providedIn: 'root'
2939
3004
  }]
2940
- }], ctorParameters: () => [{ type: i1.MatDialog }, { type: LazyLoaderService }] });
3005
+ }], ctorParameters: () => [{ type: i1$1.MatDialog }, { type: LazyLoaderService }] });
2941
3006
 
2942
3007
  class LazyLoaderModule {
2943
3008
  static forRoot(config) {
@@ -9946,7 +10011,7 @@ class FileGridComponent {
9946
10011
  inputs: { path: data?.path || this.path, name: data?.name || '', config: this.config }
9947
10012
  }).then(r => this.loadFolder());
9948
10013
  }
9949
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: FileGridComponent, deps: [{ token: Fetch }, { token: KeyboardService }, { token: DialogService }, { token: i1.MatDialog }, { token: FilemanagerComponent }, { token: i0.ChangeDetectorRef }, { token: i1$1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
10014
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: FileGridComponent, deps: [{ token: Fetch }, { token: KeyboardService }, { token: DialogService }, { token: i1$1.MatDialog }, { token: FilemanagerComponent }, { token: i0.ChangeDetectorRef }, { token: i1.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component }); }
9950
10015
  static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.1.2", type: FileGridComponent, isStandalone: true, selector: "app-file-grid", inputs: { path: "path", config: "config", showHiddenFiles: "showHiddenFiles", viewMode: "viewMode", gridSize: "gridSize", tab: "tab", selection: "selection", value: "value", sortOrder: "sortOrder" }, outputs: { pathChange: "pathChange", fileSelect: "fileSelect", fileDblClick: "fileDblClick", folderSelect: "folderSelect", folderDblClick: "folderDblClick", newTab: "newTab", loadFiles: "loadFiles", selectionChange: "selectionChange", valueChange: "valueChange" }, viewQueries: [{ propertyName: "filesRef", first: true, predicate: ["fileViewport"], descendants: true }, { propertyName: "tabulator", first: true, predicate: TabulatorComponent, descendants: true }, { propertyName: "renameTemplate", first: true, predicate: ["renameTemplate"], descendants: true, read: TemplateRef }], ngImport: i0, template: "@if (showLoader) {\n <mat-progress-bar [class.hide]=\"hideLoader\" mode=\"query\"/>\n}\n\n<div\n style=\"display: contents\"\n [style.--filemanager-fileicon-backdrop]=\"'url(' + iconResolver.path + '/pop/generic.svg)'\"\n (dragstart)=\"userIsDraggingFile = true\"\n (dragend)=\"userIsDraggingFile = false\"\n (dragover)=\"draggingOver = true\"\n (dragleave)=\"draggingOver = false\"\n (ondrop)=\"onDrop($event)\"\n>\n\n @if (failedLoad) {\n <div style=\"display: flex; align-items: center; justify-content: center; height: 100%\">\n <div style=\"max-width: 400px; display: flex; flex-direction: column; align-items: center; justify-content: center;\">\n <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->\n <svg\n fill=\"var(--text-color)\"\n width=\"200px\"\n viewBox=\"0 0 600.525 600.525\"\n >\n <path d=\"M57.375,138.656L43.031,95.146c-23.428,8.128-40.162,29.166-42.553,54.028l45.9,3.825C46.856,146.306,51.16,140.568,57.375,138.656z\" />\n <rect y=\"288.309\" width=\"45.9\" height=\"45.901\" />\n <path d=\"M554.625,446.091c0,3.346-0.956,6.215-2.868,9.084l38.25,25.34c6.693-10.039,10.04-21.992,10.04-34.424V423.14h-45.899v22.951H554.625z\" />\n <rect x=\"456.609\" y=\"146.306\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"485.297\" y=\"462.825\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"393.497\" y=\"462.825\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"364.81\" y=\"146.306\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"118.097\" y=\"462.825\" width=\"45.9\" height=\"45.9\" />\n <rect y=\"380.108\" width=\"45.9\" height=\"45.9\" />\n <rect y=\"196.509\" width=\"45.9\" height=\"45.9\" />\n <path d=\"M330.385,143.437c-2.391-1.434-3.825-2.391-4.304-2.869l-28.209-29.166c-1.913-1.913-4.303-3.825-6.694-5.737l-27.253,36.815c0.478,0.478,0.956,0.956,0.956,0.956s37.772,34.425,44.465,41.119L330.385,143.437z\" />\n <rect x=\"554.625\" y=\"239.541\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"301.697\" y=\"462.825\" width=\"45.899\" height=\"45.9\" />\n <path d=\"M559.885,146.306h-10.997v47.812h5.737h45.9v-7.172C600.525,164.475,582.356,146.306,559.885,146.306z\" />\n <rect x=\"187.425\" y=\"91.8\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"554.625\" y=\"331.341\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"95.625\" y=\"91.8\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"209.897\" y=\"462.825\" width=\"45.9\" height=\"45.9\" />\n <path d=\"M49.247,456.132l-36.337,27.73c11.953,15.777,30.122,24.863,49.725,24.863h9.562v-45.9h-9.562C57.375,462.825,52.594,460.435,49.247,456.132z\" />\n </svg>\n\n <h3>Sorry about that.</h3>\n <p>\n Our servers aren't doing their thing right now.\n You can try again later or contact an administrator about this.\n </p>\n <hr style=\"width: 100%; opacity: .5;\"/>\n <p>\n Error:\n <span style=\"color: var(--mat-tab-header-active-focus-label-text-color)\">{{error.status}}</span>\n <br/>\n @if (error.error?.message) {\n Message: {{error.error?.message}}\n }\n </p>\n </div>\n </div>\n }\n @else {\n <!-- <ng-container *ngIf=\"draggingOver\"></ng-container> -->\n <!-- Grid mode -->\n @if (viewMode == 'grid') {\n <ng-scrollbar\n class=\"grid content-area {{gridSize}} {{config.imageSize || 'normal'}}\"\n [class.selectionMode]=\"config.mode == 'focusFiles'\"\n [class.showDropArea]=\"draggingOver\"\n style=\"height: 100%; width: 100%\"\n track=\"vertical\"\n pointerEventsMethod=\"scrollbar\"\n [ngx-contextmenu]=\"folderContextMenu\"\n >\n <div class=\"resize-observer\" #fileViewport></div>\n <cdk-virtual-scroll-viewport\n itemSize=\"150\"\n scrollViewport\n (click)=\"selection = []; selectionText = ''\"\n >\n <div class=\"row\" *cdkVirtualFor=\"let row of sortedFolders\">\n @for (item of row; track item) {\n <div class=\"file\"\n [class.selected]=\"selection.includes(item)\"\n [class.generic]=\"item['_icon'].needsBackdrop\"\n [ngx-contextmenu]=\"fileContextMenu\"\n [ngx-menu-context]=\"item\"\n >\n @if (config.mode == 'focusFiles' && item.kind == 'file') {\n <mat-checkbox\n #checkbox\n [checked]=\"item['_value']\"\n (change)=\"onToggle(item, $event)\"\n />\n }\n <div\n style=\"display: contents\"\n (click)=\"onSelect(item, $event)\"\n (dblclick)=\"onItemClick(item)\"\n (dragstart)=\"onDragStart($event, item)\"\n >\n <img [src]=\"item['_icon'].path\"/>\n <p>{{item['vanityName'] || item.name}}</p>\n </div>\n </div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-scrollbar>\n }\n\n <!-- List mode -->\n @if (viewMode == 'list') {\n <div\n class=\"content-area\"\n style=\"width: 100%; height: 100%\"\n [class.showDropArea]=\"draggingOver\"\n [ngx-contextmenu]=\"folderContextMenu\"\n >\n <app-tabulator\n [dataSource]=\"directoryContents\"\n [columns]=\"[\n { field: 'name', title: 'Name', formatter: nameCellFormatter },\n { field: '_size', title: 'Size' },\n { field: '_ctime', title: 'Created' },\n { field: '_mtime', title: 'Modified' },\n ]\"\n [options]=\"{\n rowHeight: 32\n }\"\n (rowClick)=\"onRowClick($event)\"\n (rowDblClick)=\"onItemClick($event.data)\"\n (rowContext)=\"onRowCtx($event)\"\n />\n </div>\n }\n }\n</div>\n\n@if (selectionText?.trim()?.length > 0) {\n <div class=\"select-hint\">\n {{selectionText}}\n </div>\n}\n\n<div class=\"controls\">\n <button\n mat-flat-button\n class=\"upload-button\"\n (click)=\"onCreateFolder()\"\n >\n <mat-icon>create_new_folder</mat-icon>\n New Folder\n </button>\n <button\n mat-flat-button\n class=\"upload-button\"\n (click)=\"onUploadFile()\"\n >\n <mat-icon>upload_file</mat-icon>\n Upload\n </button>\n</div>\n", styles: [":host{display:block;height:100%;width:100%;overflow:hidden}.resize-observer{position:absolute;inset:0}.grid .row{flex:1;display:grid;grid-template-columns:repeat(auto-fill,80px);justify-content:space-between;grid-gap:20px;grid-auto-rows:min-content;padding:10px;margin-right:10px}.grid .file{width:80px;z-index:1;position:relative;transition:opacity 50ms ease-in-out;display:flex;flex-direction:column;align-items:center;text-align:center}.grid .file.selected p{background-color:#8ad9d9;color:#000}.grid .file.generic:before{content:\" \";position:absolute;background:var(--filemanager-fileicon-backdrop);background-repeat:no-repeat;width:100%;height:100%;z-index:-1;left:0}.grid .file.generic img{height:44px;width:44px;margin-top:28px;margin-bottom:8px}.grid .file img{-webkit-user-select:none;user-select:none}.grid .file p{height:50px;width:100%;margin:0;padding:2px;font-size:14px;line-height:16px;border-radius:4px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;text-overflow:ellipsis;overflow-wrap:break-word;transition:background-color 50ms ease-in-out,color 50ms ease-in-out}.grid .file mat-checkbox{position:absolute;left:-32px;top:-16px}:host ::ng-deep .small .file{width:46px}:host ::ng-deep .grid.selectionMode .row{padding-left:30px}:host ::ng-deep .grid.selectionMode .cdk-virtual-scroll-content-wrapper{padding-top:10px}:host ::ng-deep .tabulator .tabulator-row .tabulator-cell:not(:first-of-type){padding-top:9px}.list .row{flex:1;display:flex;align-items:center;padding:5px 10px;height:42px}.list .row p{margin:0}.list .row:hover{background-color:var(--filemanager-row-hover-background-color, #343434)}.list .row.selected p{background-color:#8ad9d9;color:#000;border-radius:5px;padding:0 4px}.list .row.odd{background-color:var(--filemanager-row-alt-background-color, #323232)}.controls{position:absolute;bottom:12px;right:12px;display:flex;gap:12px}.select-hint{position:absolute;font-size:14px;bottom:0;right:0;background-color:#000a;padding:2px 10px;border:1px solid black;border-top-right-radius:5px;border-bottom:none;border-right:none;z-index:9999}.select-hint:hover{display:none}.content-area{border:4px dashed rgba(0,0,0,0)}.showDropArea{border:4px dashed var(--theme-primary, rgba(128, 128, 128, .8));transition:border-color .25s ease}:host ::ng-deep ng-scrollbar.ng-scrollbar{box-sizing:border-box!important;--scrollbar-thumb-color: #666;min-height:200px;min-width:200px}mat-progress-bar{--mdc-linear-progress-track-height: 2px;position:absolute;top:0;left:0;width:100%;animation:dropIn .2s ease;transition:position .2s ease;z-index:100}mat-progress-bar.hide{top:-2px}@keyframes dropIn{0%{top:-2px}to{top:0}}\n"], dependencies: [{ kind: "ngmodule", type: MatTabsModule }, { kind: "ngmodule", type: NgScrollbarModule }, { kind: "component", type: i7.NgScrollbar, selector: "ng-scrollbar", inputs: ["disabled", "sensorDisabled", "pointerEventsDisabled", "viewportPropagateMouseMove", "autoHeightDisabled", "autoWidthDisabled", "viewClass", "trackClass", "thumbClass", "minThumbSize", "trackClickScrollDuration", "pointerEventsMethod", "track", "visibility", "appearance", "position", "sensorDebounce", "scrollAuditTime"], outputs: ["updated"], exportAs: ["ngScrollbar"] }, { kind: "directive", type: i7.ScrollViewport, selector: "[scrollViewport]" }, { kind: "ngmodule", type: MatInputModule }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i6$1.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatProgressBarModule }, { kind: "component", type: i7$1.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i3$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i9.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", exportAs: ["matButton"] }, { kind: "component", type: TabulatorComponent, selector: "app-tabulator", inputs: ["dataSource", "columns", "key", "options"], outputs: ["cellClick", "cellDblClick", "rowClick", "rowContext", "rowDblClick"] }, { kind: "directive", type: MenuDirective, selector: "[ngx-contextmenu],[ngx-menu]", inputs: ["ngx-menu-context", "ngx-contextmenu", "ngx-menu", "ngx-menu-config"] }, { kind: "ngmodule", type: ScrollingModule }, { kind: "directive", type: i6.CdkFixedSizeVirtualScroll, selector: "cdk-virtual-scroll-viewport[itemSize]", inputs: ["itemSize", "minBufferPx", "maxBufferPx"] }, { kind: "directive", type: i6.CdkVirtualForOf, selector: "[cdkVirtualFor][cdkVirtualForOf]", inputs: ["cdkVirtualForOf", "cdkVirtualForTrackBy", "cdkVirtualForTemplate", "cdkVirtualForTemplateCacheSize"] }, { kind: "component", type: i6.CdkVirtualScrollViewport, selector: "cdk-virtual-scroll-viewport", inputs: ["orientation", "appendOnly"], outputs: ["scrolledIndexChange"] }] }); }
9951
10016
  }
9952
10017
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImport: i0, type: FileGridComponent, decorators: [{
@@ -9966,7 +10031,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
9966
10031
  MenuDirective,
9967
10032
  ScrollingModule
9968
10033
  ], standalone: true, template: "@if (showLoader) {\n <mat-progress-bar [class.hide]=\"hideLoader\" mode=\"query\"/>\n}\n\n<div\n style=\"display: contents\"\n [style.--filemanager-fileicon-backdrop]=\"'url(' + iconResolver.path + '/pop/generic.svg)'\"\n (dragstart)=\"userIsDraggingFile = true\"\n (dragend)=\"userIsDraggingFile = false\"\n (dragover)=\"draggingOver = true\"\n (dragleave)=\"draggingOver = false\"\n (ondrop)=\"onDrop($event)\"\n>\n\n @if (failedLoad) {\n <div style=\"display: flex; align-items: center; justify-content: center; height: 100%\">\n <div style=\"max-width: 400px; display: flex; flex-direction: column; align-items: center; justify-content: center;\">\n <!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->\n <svg\n fill=\"var(--text-color)\"\n width=\"200px\"\n viewBox=\"0 0 600.525 600.525\"\n >\n <path d=\"M57.375,138.656L43.031,95.146c-23.428,8.128-40.162,29.166-42.553,54.028l45.9,3.825C46.856,146.306,51.16,140.568,57.375,138.656z\" />\n <rect y=\"288.309\" width=\"45.9\" height=\"45.901\" />\n <path d=\"M554.625,446.091c0,3.346-0.956,6.215-2.868,9.084l38.25,25.34c6.693-10.039,10.04-21.992,10.04-34.424V423.14h-45.899v22.951H554.625z\" />\n <rect x=\"456.609\" y=\"146.306\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"485.297\" y=\"462.825\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"393.497\" y=\"462.825\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"364.81\" y=\"146.306\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"118.097\" y=\"462.825\" width=\"45.9\" height=\"45.9\" />\n <rect y=\"380.108\" width=\"45.9\" height=\"45.9\" />\n <rect y=\"196.509\" width=\"45.9\" height=\"45.9\" />\n <path d=\"M330.385,143.437c-2.391-1.434-3.825-2.391-4.304-2.869l-28.209-29.166c-1.913-1.913-4.303-3.825-6.694-5.737l-27.253,36.815c0.478,0.478,0.956,0.956,0.956,0.956s37.772,34.425,44.465,41.119L330.385,143.437z\" />\n <rect x=\"554.625\" y=\"239.541\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"301.697\" y=\"462.825\" width=\"45.899\" height=\"45.9\" />\n <path d=\"M559.885,146.306h-10.997v47.812h5.737h45.9v-7.172C600.525,164.475,582.356,146.306,559.885,146.306z\" />\n <rect x=\"187.425\" y=\"91.8\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"554.625\" y=\"331.341\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"95.625\" y=\"91.8\" width=\"45.9\" height=\"45.9\" />\n <rect x=\"209.897\" y=\"462.825\" width=\"45.9\" height=\"45.9\" />\n <path d=\"M49.247,456.132l-36.337,27.73c11.953,15.777,30.122,24.863,49.725,24.863h9.562v-45.9h-9.562C57.375,462.825,52.594,460.435,49.247,456.132z\" />\n </svg>\n\n <h3>Sorry about that.</h3>\n <p>\n Our servers aren't doing their thing right now.\n You can try again later or contact an administrator about this.\n </p>\n <hr style=\"width: 100%; opacity: .5;\"/>\n <p>\n Error:\n <span style=\"color: var(--mat-tab-header-active-focus-label-text-color)\">{{error.status}}</span>\n <br/>\n @if (error.error?.message) {\n Message: {{error.error?.message}}\n }\n </p>\n </div>\n </div>\n }\n @else {\n <!-- <ng-container *ngIf=\"draggingOver\"></ng-container> -->\n <!-- Grid mode -->\n @if (viewMode == 'grid') {\n <ng-scrollbar\n class=\"grid content-area {{gridSize}} {{config.imageSize || 'normal'}}\"\n [class.selectionMode]=\"config.mode == 'focusFiles'\"\n [class.showDropArea]=\"draggingOver\"\n style=\"height: 100%; width: 100%\"\n track=\"vertical\"\n pointerEventsMethod=\"scrollbar\"\n [ngx-contextmenu]=\"folderContextMenu\"\n >\n <div class=\"resize-observer\" #fileViewport></div>\n <cdk-virtual-scroll-viewport\n itemSize=\"150\"\n scrollViewport\n (click)=\"selection = []; selectionText = ''\"\n >\n <div class=\"row\" *cdkVirtualFor=\"let row of sortedFolders\">\n @for (item of row; track item) {\n <div class=\"file\"\n [class.selected]=\"selection.includes(item)\"\n [class.generic]=\"item['_icon'].needsBackdrop\"\n [ngx-contextmenu]=\"fileContextMenu\"\n [ngx-menu-context]=\"item\"\n >\n @if (config.mode == 'focusFiles' && item.kind == 'file') {\n <mat-checkbox\n #checkbox\n [checked]=\"item['_value']\"\n (change)=\"onToggle(item, $event)\"\n />\n }\n <div\n style=\"display: contents\"\n (click)=\"onSelect(item, $event)\"\n (dblclick)=\"onItemClick(item)\"\n (dragstart)=\"onDragStart($event, item)\"\n >\n <img [src]=\"item['_icon'].path\"/>\n <p>{{item['vanityName'] || item.name}}</p>\n </div>\n </div>\n }\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-scrollbar>\n }\n\n <!-- List mode -->\n @if (viewMode == 'list') {\n <div\n class=\"content-area\"\n style=\"width: 100%; height: 100%\"\n [class.showDropArea]=\"draggingOver\"\n [ngx-contextmenu]=\"folderContextMenu\"\n >\n <app-tabulator\n [dataSource]=\"directoryContents\"\n [columns]=\"[\n { field: 'name', title: 'Name', formatter: nameCellFormatter },\n { field: '_size', title: 'Size' },\n { field: '_ctime', title: 'Created' },\n { field: '_mtime', title: 'Modified' },\n ]\"\n [options]=\"{\n rowHeight: 32\n }\"\n (rowClick)=\"onRowClick($event)\"\n (rowDblClick)=\"onItemClick($event.data)\"\n (rowContext)=\"onRowCtx($event)\"\n />\n </div>\n }\n }\n</div>\n\n@if (selectionText?.trim()?.length > 0) {\n <div class=\"select-hint\">\n {{selectionText}}\n </div>\n}\n\n<div class=\"controls\">\n <button\n mat-flat-button\n class=\"upload-button\"\n (click)=\"onCreateFolder()\"\n >\n <mat-icon>create_new_folder</mat-icon>\n New Folder\n </button>\n <button\n mat-flat-button\n class=\"upload-button\"\n (click)=\"onUploadFile()\"\n >\n <mat-icon>upload_file</mat-icon>\n Upload\n </button>\n</div>\n", styles: [":host{display:block;height:100%;width:100%;overflow:hidden}.resize-observer{position:absolute;inset:0}.grid .row{flex:1;display:grid;grid-template-columns:repeat(auto-fill,80px);justify-content:space-between;grid-gap:20px;grid-auto-rows:min-content;padding:10px;margin-right:10px}.grid .file{width:80px;z-index:1;position:relative;transition:opacity 50ms ease-in-out;display:flex;flex-direction:column;align-items:center;text-align:center}.grid .file.selected p{background-color:#8ad9d9;color:#000}.grid .file.generic:before{content:\" \";position:absolute;background:var(--filemanager-fileicon-backdrop);background-repeat:no-repeat;width:100%;height:100%;z-index:-1;left:0}.grid .file.generic img{height:44px;width:44px;margin-top:28px;margin-bottom:8px}.grid .file img{-webkit-user-select:none;user-select:none}.grid .file p{height:50px;width:100%;margin:0;padding:2px;font-size:14px;line-height:16px;border-radius:4px;overflow:hidden;display:-webkit-box;-webkit-line-clamp:3;-webkit-box-orient:vertical;text-overflow:ellipsis;overflow-wrap:break-word;transition:background-color 50ms ease-in-out,color 50ms ease-in-out}.grid .file mat-checkbox{position:absolute;left:-32px;top:-16px}:host ::ng-deep .small .file{width:46px}:host ::ng-deep .grid.selectionMode .row{padding-left:30px}:host ::ng-deep .grid.selectionMode .cdk-virtual-scroll-content-wrapper{padding-top:10px}:host ::ng-deep .tabulator .tabulator-row .tabulator-cell:not(:first-of-type){padding-top:9px}.list .row{flex:1;display:flex;align-items:center;padding:5px 10px;height:42px}.list .row p{margin:0}.list .row:hover{background-color:var(--filemanager-row-hover-background-color, #343434)}.list .row.selected p{background-color:#8ad9d9;color:#000;border-radius:5px;padding:0 4px}.list .row.odd{background-color:var(--filemanager-row-alt-background-color, #323232)}.controls{position:absolute;bottom:12px;right:12px;display:flex;gap:12px}.select-hint{position:absolute;font-size:14px;bottom:0;right:0;background-color:#000a;padding:2px 10px;border:1px solid black;border-top-right-radius:5px;border-bottom:none;border-right:none;z-index:9999}.select-hint:hover{display:none}.content-area{border:4px dashed rgba(0,0,0,0)}.showDropArea{border:4px dashed var(--theme-primary, rgba(128, 128, 128, .8));transition:border-color .25s ease}:host ::ng-deep ng-scrollbar.ng-scrollbar{box-sizing:border-box!important;--scrollbar-thumb-color: #666;min-height:200px;min-width:200px}mat-progress-bar{--mdc-linear-progress-track-height: 2px;position:absolute;top:0;left:0;width:100%;animation:dropIn .2s ease;transition:position .2s ease;z-index:100}mat-progress-bar.hide{top:-2px}@keyframes dropIn{0%{top:-2px}to{top:0}}\n"] }]
9969
- }], ctorParameters: () => [{ type: Fetch }, { type: KeyboardService }, { type: DialogService }, { type: i1.MatDialog }, { type: FilemanagerComponent }, { type: i0.ChangeDetectorRef }, { type: i1$1.DomSanitizer }], propDecorators: { filesRef: [{
10034
+ }], ctorParameters: () => [{ type: Fetch }, { type: KeyboardService }, { type: DialogService }, { type: i1$1.MatDialog }, { type: FilemanagerComponent }, { type: i0.ChangeDetectorRef }, { type: i1.DomSanitizer }], propDecorators: { filesRef: [{
9970
10035
  type: ViewChild,
9971
10036
  args: ["fileViewport"]
9972
10037
  }], tabulator: [{
@@ -10317,7 +10382,7 @@ class FilemanagerComponent {
10317
10382
  lazyLoader.registerComponent({
10318
10383
  id: "folder-rename",
10319
10384
  group: "@dotglitch/ngx-web-components",
10320
- load: () => import('./dotglitch-ngx-common-folder-rename.component-xUdQXmcY.mjs')
10385
+ load: () => import('./dotglitch-ngx-common-folder-rename.component-6j7OjwOo.mjs')
10321
10386
  });
10322
10387
  this.iconResolver = new IconResolver(libConfig.assetPath);
10323
10388
  }
@@ -11598,5 +11663,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.1.2", ngImpor
11598
11663
  * Generated bundle index. Do not edit.
11599
11664
  */
11600
11665
 
11601
- export { CommandPaletteService, ComponentResolveStrategy, ConsoleLogger, DependencyService, DialogService, DynamicHTMLComponent, DynamicHTMLOptions, DynamicHTMLRenderer, Fetch, FileService, FilemanagerComponent, HtmlBypass, InstallMonacoUMD, KeyboardService, LazyLoaderComponent, LazyLoaderModule, LazyLoaderService, LogIcon, MenuComponent, MenuDirective, NGX_DYNAMIC_CONFIG, NGX_IMAGE_CACHE_CONFIG, NGX_LAZY_LOADER_CONFIG, NGX_WEB_COMPONENTS_CONFIG, NavigationService, NgxDynamicHTMLModule, NgxImageCacheDirective, OnMount, ParallaxCardComponent, ReactMagicWrapperComponent, ResourceBypass, ScriptBypass, StyleBypass, TabulatorComponent, ThemeService, TooltipDirective, UrlBypass, VscodeComponent, calcMenuItemBounds, openMenu, openTooltip };
11666
+ export { CommandPaletteService, ComponentResolveStrategy, ConsoleLogger, DependencyService, DialogService, DropdownDirective, DynamicHTMLComponent, DynamicHTMLOptions, DynamicHTMLRenderer, Fetch, FileService, FilemanagerComponent, HtmlBypass, InstallMonacoUMD, KeyboardService, LazyLoaderComponent, LazyLoaderModule, LazyLoaderService, LogIcon, MenuComponent, MenuDirective, NGX_DYNAMIC_CONFIG, NGX_IMAGE_CACHE_CONFIG, NGX_LAZY_LOADER_CONFIG, NGX_WEB_COMPONENTS_CONFIG, NavigationService, NgxDynamicHTMLModule, NgxImageCacheDirective, OnMount, ParallaxCardComponent, ReactMagicWrapperComponent, ResourceBypass, ScriptBypass, StyleBypass, TabulatorComponent, ThemeService, TooltipDirective, UrlBypass, VscodeComponent, calcMenuItemBounds, openMenu, openTooltip };
11602
11667
  //# sourceMappingURL=dotglitch-ngx-common.mjs.map