nath-angular-ui 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, ElementRef, model, input, output, contentChild, TemplateRef, viewChild, signal, computed, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, Service, Pipe, InjectionToken, Injector, EnvironmentInjector, ApplicationRef, createEnvironmentInjector, createComponent, Injectable, Renderer2, viewChildren, SecurityContext, untracked, HostListener, ViewChild, booleanAttribute, Directive, contentChildren, ViewContainerRef } from '@angular/core';
2
+ import { inject, ElementRef, model, input, output, contentChild, TemplateRef, viewChild, signal, computed, effect, ViewEncapsulation, ChangeDetectionStrategy, Component, Service, Pipe, InjectionToken, Injector, EnvironmentInjector, ApplicationRef, createEnvironmentInjector, createComponent, Injectable, Renderer2, DestroyRef, viewChildren, SecurityContext, untracked, HostListener, ViewChild, booleanAttribute, Directive, contentChildren, ViewContainerRef } from '@angular/core';
3
3
  import * as i1 from '@angular/common';
4
4
  import { CommonModule, NgTemplateOutlet, DOCUMENT, NgStyle, NgClass, KeyValuePipe } from '@angular/common';
5
5
  import * as i2 from '@angular/cdk/overlay';
6
6
  import { OverlayModule } from '@angular/cdk/overlay';
7
- import { LucideX, LucideChevronDown, isLucideIconComponent, LucideDynamicIcon, LucideHouse, LucideMinimize2, LucideMaximize2, LucideEye, LucideLoaderCircle, LucideSquare, LucideSquareCheck, LucideInbox, LucideChevronRight, LucideChevronsRight, LucideChevronLeft, LucideChevronsLeft, LucideCircle, LucideArrowUp, LucideArrowDown, LucideArrowUp01, LucideArrowDown01, LucideArrowUpAZ, LucideArrowDownAZ, LucideMoon, LucideSun, LucideCircleCheck, LucideCircleAlert, LucideInfo, LucideTriangleAlert } from '@lucide/angular';
7
+ import { LucideX, LucideChevronDown, isLucideIconComponent, LucideDynamicIcon, LucideHouse, LucideMinimize2, LucideMaximize2, LucideEye, LucideLoaderCircle, LucideMenu, LucideSquare, LucideSquareCheck, LucideInbox, LucideChevronRight, LucideChevronsRight, LucideChevronLeft, LucideChevronsLeft, LucideCircle, LucideArrowUp, LucideArrowDown, LucideArrowUp01, LucideArrowDown01, LucideArrowUpAZ, LucideArrowDownAZ, LucideMoon, LucideSun, LucideCircleCheck, LucideCircleAlert, LucideInfo, LucideTriangleAlert } from '@lucide/angular';
8
8
  import * as i1$1 from '@angular/router';
9
9
  import { RouterModule, Router, NavigationEnd, RouterLink, RouterLinkActive } from '@angular/router';
10
10
  import * as i1$2 from '@angular/forms';
@@ -305,7 +305,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
305
305
  args: [{ selector: 'nath-boolean-control', imports: [CommonModule, LucideDynamicIcon], encapsulation: ViewEncapsulation.None, template: "@if (mode() === 'checkbox') {\r\n <div class=\"nath-boolean-checkbox-container\">\r\n <label\r\n class=\"nath-boolean-checkbox-label\"\r\n [class.nath-boolean-disabled]=\"disabled()\"\r\n [class]=\"styleClass()\"\r\n >\r\n <input\r\n #checkboxElement\r\n type=\"checkbox\"\r\n [checked]=\"value() === true\"\r\n (change)=\"toggle()\"\r\n [id]=\"inputId()\"\r\n [disabled]=\"disabled()\"\r\n />\r\n @if (label()) {\r\n <span>\r\n {{ label() }}\r\n </span>\r\n }\r\n </label>\r\n </div>\r\n}\r\n\r\n@if (mode() === 'switch') {\r\n <label\r\n class=\"nath-boolean-switch-label\"\r\n [class.nath-boolean-disabled]=\"disabled()\"\r\n [class]=\"styleClass()\"\r\n >\r\n <div class=\"nath-boolean-switch-wrapper\">\r\n <input\r\n type=\"checkbox\"\r\n [checked]=\"value() === true\"\r\n (change)=\"toggle()\"\r\n class=\"nath-boolean-switch-input\"\r\n [id]=\"inputId()\"\r\n [disabled]=\"disabled()\"\r\n />\r\n <div\r\n class=\"nath-boolean-switch-track\"\r\n [class.is-null]=\"value() === null\"\r\n [class.nath-boolean-disabled]=\"disabled()\"\r\n >\r\n @if (icon()) {\r\n <div\r\n class=\"nath-boolean-switch-handle-content\"\r\n [class.is-off]=\"value() === false\"\r\n [class.is-null]=\"value() === null\"\r\n [class.is-on]=\"value() === true\"\r\n >\r\n @if (isLucideIconComponent(icon()!)) {\r\n <svg [lucideIcon]=\"icon()!\" />\r\n } @else {\r\n <i [ngClass]=\"[icon()!]\"></i>\r\n }\r\n </div>\r\n }\r\n </div>\r\n </div>\r\n @if (label()) {\r\n <span>\r\n {{ label() }}\r\n </span>\r\n }\r\n </label>\r\n}\r\n\r\n@if (mode() === 'toggle') {\r\n <button\r\n type=\"button\"\r\n (click)=\"toggle()\"\r\n class=\"nath-boolean-toggle-button\"\r\n [class]=\"styleClass()\"\r\n [id]=\"inputId()\"\r\n [disabled]=\"disabled()\"\r\n >\r\n <span class=\"nath-boolean-toggle-content\" [ngClass]=\"toggleButtonClasses()\">\r\n @if (icon()) {\r\n @if (isLucideIconComponent(icon()!)) {\r\n <svg [lucideIcon]=\"icon()!\" />\r\n } @else {\r\n <i [ngClass]=\"[icon()!]\"></i>\r\n }\r\n }\r\n {{ label() || fallbackButtonLabel() }}\r\n </span>\r\n </button>\r\n}\r\n", styles: ["nath-boolean-control,.nath-boolean-theme{--nath-boolean-gap: .75rem;--nath-boolean-disabled-opacity: .5;--nath-boolean-transition: all .2s ease-in-out;--nath-switch-width: 3.5rem;--nath-switch-height: 2rem;--nath-switch-bg-off: var(--color-zinc-300, oklch(87.1% .006 286.286));--nath-switch-bg-on: var(--color-primary-500, #8e9ba5);--nath-switch-bg-null: var(--color-zinc-300, oklch(87.1% .006 286.286));--nath-switch-handle-bg: var(--color-zinc-400, oklch(70.5% .015 286.067));--nath-switch-handle-bg-on: var(--color-zinc-900, oklch(14.1% .005 285.823));--nath-switch-handle-size: 1.75rem;--nath-switch-handle-offset: 2px;--nath-switch-focus-ring: 1px solid var(--color-zinc-900, oklch(14.1% .005 285.823));--nath-toggle-bg-null: var(--color-zinc-400, oklch(70.5% .015 286.067));--nath-toggle-text-null: var(--color-zinc-900, oklch(14.1% .005 285.823));--nath-toggle-bg-on: var(--color-zinc-50, oklch(98.4% .001 286.375));--nath-toggle-text-on: var(--color-zinc-900, oklch(14.1% .005 285.823));--nath-toggle-bg-off: transparent;--nath-toggle-text-off: inherit;--nath-toggle-padding: .25rem;--nath-toggle-inner-padding: .25rem .375rem;--nath-toggle-border-radius: .375rem;--nath-toggle-button-bg: var(--color-slate-300, oklch(92% .004 286.32));--nath-toggle-button-text: var(--color-slate-800, oklch(27.8% .033 256.848));--nath-toggle-button-hover-bg: var(--color-slate-300, oklch(92% .004 286.32));display:block}.dark nath-boolean-control,.dark .nath-boolean-theme{--nath-switch-bg-off: var(--color-zinc-700, oklch(37% .013 285.805));--nath-switch-bg-null: var(--color-zinc-600, oklch(44.2% .017 285.786));--nath-switch-focus-ring: 1px solid var(--color-zinc-50, oklch(98.4% .001 286.375));--nath-toggle-bg-on: var(--color-zinc-50, oklch(98.4% .001 286.375));--nath-toggle-text-on: var(--color-zinc-900, oklch(14.1% .005 285.823));--nath-toggle-button-bg: var(--color-slate-800, oklch(27.4% .006 286.033));--nath-toggle-button-text: var(--color-slate-200, oklch(92% .004 286.32));--nath-toggle-button-hover-bg: var(--color-slate-700, oklch(37% .013 285.805))}.nath-boolean-checkbox-container{display:flex;align-items:center;gap:var(--nath-boolean-gap);-webkit-user-select:none;user-select:none}.nath-boolean-checkbox-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;white-space:nowrap}.nath-boolean-disabled{opacity:var(--nath-boolean-disabled-opacity);cursor:not-allowed;pointer-events:none}.nath-boolean-switch-label{display:flex;align-items:center;gap:.5rem;cursor:pointer}.nath-boolean-switch-wrapper{position:relative;display:inline-flex;align-items:center}.nath-boolean-switch-input{position:absolute;width:1px;height:1px;padding:0;margin:-1px;overflow:hidden;clip:rect(0,0,0,0);white-space:nowrap;border-width:0}.nath-boolean-switch-track{width:var(--nath-switch-width);height:var(--nath-switch-height);background-color:var(--nath-switch-bg-off);border-radius:9999px;transition:var(--nath-boolean-transition);position:relative;display:flex;align-items:center}.nath-boolean-switch-input:focus-visible+.nath-boolean-switch-track{outline:var(--nath-switch-focus-ring)}.nath-boolean-switch-track:after{content:\"\";position:absolute;top:var(--nath-switch-handle-offset);left:var(--nath-switch-handle-offset);height:var(--nath-switch-handle-size);width:var(--nath-switch-handle-size);background-color:var(--nath-switch-handle-bg);border-radius:50%;transition:var(--nath-boolean-transition)}.nath-boolean-switch-input:checked+.nath-boolean-switch-track{background-color:var(--nath-switch-bg-on)}.nath-boolean-switch-input:checked+.nath-boolean-switch-track:after{transform:translate(calc(var(--nath-switch-width) - var(--nath-switch-handle-size) - (var(--nath-switch-handle-offset) * 2)));background-color:var(--nath-switch-handle-bg-on)}.nath-boolean-switch-track.is-null{background-color:var(--nath-switch-bg-null)}.nath-boolean-switch-track.is-null:after{transform:translate(calc((var(--nath-switch-width) - var(--nath-switch-handle-size) - (var(--nath-switch-handle-offset) * 2)) / 2))}.nath-boolean-switch-handle-content{position:absolute;top:var(--nath-switch-handle-offset);z-index:10;display:flex;height:var(--nath-switch-handle-size);width:var(--nath-switch-handle-size);align-items:center;justify-content:center;transition:var(--nath-boolean-transition);pointer-events:none;border-radius:50%;overflow:hidden}.nath-boolean-switch-handle-content.is-off{left:var(--nath-switch-handle-offset)}.nath-boolean-switch-handle-content.is-null{left:calc(50% - (var(--nath-switch-handle-size) / 2))}.nath-boolean-switch-handle-content.is-on{right:var(--nath-switch-handle-offset)}.nath-boolean-toggle-button{padding:.25rem;width:100%;cursor:pointer;border:1px solid transparent;border-radius:.375rem;box-sizing:border-box;display:inline-flex;gap:.5rem;align-items:center;justify-content:center;line-height:1.25rem;text-decoration:none;transition:all .2s;box-shadow:0 1px 2px #0000000d;background-color:var(--nath-toggle-button-bg);color:var(--nath-toggle-button-text)}.nath-boolean-toggle-button:hover:not(:disabled){background-color:var(--nath-toggle-button-hover-bg)}.nath-boolean-toggle-button:focus{outline:none}.nath-boolean-toggle-button:disabled{opacity:.5;cursor:not-allowed}.dark .nath-boolean-toggle-button:disabled{opacity:.3}.nath-boolean-toggle-content{padding:var(--nath-toggle-inner-padding);display:inline-flex;gap:.5rem;align-items:center;justify-content:center;line-height:1.25rem;border-radius:var(--nath-toggle-border-radius);width:100%;transition:var(--nath-boolean-transition)}.nath-boolean-toggle-null{background-color:var(--nath-toggle-bg-null);color:var(--nath-toggle-text-null)}.nath-boolean-toggle-on{background-color:var(--nath-toggle-bg-on);color:var(--nath-toggle-text-on)}.nath-boolean-toggle-off{background-color:var(--nath-toggle-bg-off);color:var(--nath-toggle-text-off)}\n"] }]
306
306
  }], ctorParameters: () => [], propDecorators: { mode: [{ type: i0.Input, args: [{ isSignal: true, alias: "mode", required: false }] }], label: [{ type: i0.Input, args: [{ isSignal: true, alias: "label", required: false }] }], allowIndeterminate: [{ type: i0.Input, args: [{ isSignal: true, alias: "allowIndeterminate", required: false }] }], inputId: [{ type: i0.Input, args: [{ isSignal: true, alias: "inputId", required: false }] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], yesLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "yesLabel", required: false }] }], noLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "noLabel", required: false }] }], indeterminateLabel: [{ type: i0.Input, args: [{ isSignal: true, alias: "indeterminateLabel", required: false }] }], icon: [{ type: i0.Input, args: [{ isSignal: true, alias: "icon", required: false }] }], toggled: [{ type: i0.Output, args: ["toggled"] }], value: [{ type: i0.Input, args: [{ isSignal: true, alias: "value", required: false }] }, { type: i0.Output, args: ["valueChange"] }], disabled: [{ type: i0.Input, args: [{ isSignal: true, alias: "disabled", required: false }] }, { type: i0.Output, args: ["disabledChange"] }], checkboxRef: [{ type: i0.ViewChild, args: ['checkboxElement', { isSignal: true }] }] } });
307
307
 
308
- class BreadcrumbService {
308
+ class NathBreadcrumbService {
309
309
  // A private writable signal holding the home item which will always be visible, if any
310
310
  _home = signal(null, /* @ts-ignore */
311
311
  ...(ngDevMode ? [{ debugName: "_home" }] : /* istanbul ignore next */ []));
@@ -365,15 +365,15 @@ class BreadcrumbService {
365
365
  clear() {
366
366
  this._breadcrumbs.set([]);
367
367
  }
368
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: BreadcrumbService, deps: [], target: i0.ɵɵFactoryTarget.Service });
369
- static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.5", ngImport: i0, type: BreadcrumbService });
368
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathBreadcrumbService, deps: [], target: i0.ɵɵFactoryTarget.Service });
369
+ static ɵprov = i0.ɵɵngDeclareService({ minVersion: "22.0.0", version: "22.0.5", ngImport: i0, type: NathBreadcrumbService });
370
370
  }
371
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: BreadcrumbService, decorators: [{
371
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathBreadcrumbService, decorators: [{
372
372
  type: Service
373
373
  }] });
374
374
 
375
375
  class NathBreadcrumbs {
376
- breadcrumbService = inject(BreadcrumbService);
376
+ breadcrumbService = inject(NathBreadcrumbService);
377
377
  // Directly expose the read-only signal to the template
378
378
  home = this.breadcrumbService.home;
379
379
  breadcrumbs = this.breadcrumbService.breadcrumbs;
@@ -1417,6 +1417,35 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
1417
1417
  `, encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, host: {}, styles: ["nath-image-preview,.nath-image-preview-theme{--nath-image-preview-bg: var(--color-zinc-300, oklch(81.7% .012 286.033));--nath-image-preview-text-muted: var(--color-zinc-500, oklch(55.2% .016 285.938));--nath-image-preview-hover-overlay: rgba(0, 0, 0, .5);--nath-image-preview-hover-icon-color: white;--nath-image-preview-modal-bg: rgba(0, 0, 0, .8);--nath-image-preview-modal-backdrop-blur: 4px;--nath-image-preview-close-bg: rgba(0, 0, 0, .4);--nath-image-preview-close-hover-bg: rgba(0, 0, 0, .6);--nath-image-preview-close-color: white;--nath-image-preview-close-hover-color: var(--color-gray-300, oklch(81.7% .012 286.033));--nath-image-preview-image-shadow: 0 25px 50px -12px rgb(0 0 0 / .25)}.dark nath-image-preview,.dark .nath-image-preview-theme{--nath-image-preview-bg: var(--color-zinc-900, oklch(21% .006 285.885));--nath-image-preview-text-muted: var(--color-zinc-400, oklch(70.5% .015 286.067))}nath-image-preview{position:relative;height:100%;width:100%;display:inline-flex;align-items:center;justify-content:center;background-color:var(--nath-image-preview-bg);overflow:hidden}.nath-image-preview-no-image{width:100%;height:100%;font-size:4rem;display:flex;justify-content:center;align-items:center;padding:2rem}.nath-image-preview-text-muted{color:var(--nath-image-preview-text-muted)}.nath-image-preview-thumbnail{max-width:100%;max-height:100%;object-fit:cover;cursor:pointer}.nath-image-preview-hover-trigger{position:absolute;top:0;right:0;width:100%;height:100%;display:flex;align-items:center;justify-content:center;cursor:pointer;opacity:0;transition:opacity .2s,background-color .2s}.nath-image-preview-hover-trigger:hover{opacity:1;background-color:var(--nath-image-preview-hover-overlay)}.nath-image-preview-eye-icon{font-size:1.5rem;color:var(--nath-image-preview-hover-icon-color)}.nath-image-preview-modal{position:fixed;inset:0;z-index:50;display:flex;align-items:center;justify-content:center;background-color:var(--nath-image-preview-modal-bg);-webkit-backdrop-filter:blur(var(--nath-image-preview-modal-backdrop-blur));backdrop-filter:blur(var(--nath-image-preview-modal-backdrop-blur));transition:opacity .3s}.nath-image-preview-close-btn{position:absolute;top:1rem;right:1rem;color:var(--nath-image-preview-close-color);padding:.5rem;border-radius:9999px;background-color:var(--nath-image-preview-close-bg);transition:color .2s,background-color .2s;border:none;cursor:pointer;display:flex;align-items:center;justify-content:center}.nath-image-preview-close-btn:hover{color:var(--nath-image-preview-close-hover-color);background-color:var(--nath-image-preview-close-hover-bg)}.nath-image-preview-modal-content{max-width:90vw;max-height:90vh;display:flex;align-items:center;justify-content:center}.nath-image-preview-full-image{max-width:100%;max-height:90vh;object-fit:contain;border-radius:.25rem;box-shadow:var(--nath-image-preview-image-shadow)}.nath-image-preview-animate-spin{animation:nath-image-preview-spin 1s linear infinite}@keyframes nath-image-preview-spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}\n"] }]
1418
1418
  }], ctorParameters: () => [], propDecorators: { image: [{ type: i0.Input, args: [{ isSignal: true, alias: "image", required: true }] }], thumbnail: [{ type: i0.Input, args: [{ isSignal: true, alias: "thumbnail", required: false }] }], text: [{ type: i0.Input, args: [{ isSignal: true, alias: "text", required: true }] }], fallbackIcon: [{ type: i0.Input, args: [{ isSignal: true, alias: "fallbackIcon", required: true }] }], loading: [{ type: i0.Input, args: [{ isSignal: true, alias: "loading", required: false }] }], preview: [{ type: i0.Input, args: [{ isSignal: true, alias: "preview", required: false }] }], imageClick: [{ type: i0.Output, args: ["imageClick"] }] } });
1419
1419
 
1420
+ /**
1421
+ * Finds the next or previous sibling of an element that matches a selector.
1422
+ */
1423
+ function findSibling(el, selector, direction = 'next') {
1424
+ if (!el)
1425
+ return null;
1426
+ let sibling = direction === 'next' ? el.nextElementSibling : el.previousElementSibling;
1427
+ let indexOffset = 0;
1428
+ while (sibling) {
1429
+ if (direction === 'next')
1430
+ indexOffset += 1;
1431
+ else
1432
+ indexOffset -= 1;
1433
+ if (sibling.matches(selector)) {
1434
+ return { sibling, indexOffset };
1435
+ }
1436
+ sibling = direction === 'next' ? sibling.nextElementSibling : sibling.previousElementSibling;
1437
+ }
1438
+ return null;
1439
+ }
1440
+
1441
+ function previousSibling(el, selector) {
1442
+ const previousEl = el.previousElementSibling;
1443
+ if (!selector || previousEl?.matches(selector)) {
1444
+ return previousEl;
1445
+ }
1446
+ return null;
1447
+ }
1448
+
1420
1449
  const SUBMENU_ALIGNMENT_CONFIG = {
1421
1450
  ESTIMATED_INITIAL_WIDTH_PX: 200,
1422
1451
  VIEWPORT_COLLISION_PADDING_PX: 8,
@@ -1425,7 +1454,10 @@ class NathMenuList {
1425
1454
  // ────────────────────────────────────────────────────────────────────────────────
1426
1455
  // INJECTIONS
1427
1456
  // ────────────────────────────────────────────────────────────────────────────────
1457
+ document = inject(DOCUMENT);
1428
1458
  sanitizer = inject(DomSanitizer);
1459
+ destroyRef = inject(DestroyRef);
1460
+ elementRef = inject(ElementRef);
1429
1461
  // ────────────────────────────────────────────────────────────────────────────────
1430
1462
  // I/O
1431
1463
  // ────────────────────────────────────────────────────────────────────────────────
@@ -1443,13 +1475,35 @@ class NathMenuList {
1443
1475
  ...(ngDevMode ? [{ debugName: "submenuContainers" }] : /* istanbul ignore next */ []));
1444
1476
  activeItem = signal(null, /* @ts-ignore */
1445
1477
  ...(ngDevMode ? [{ debugName: "activeItem" }] : /* istanbul ignore next */ []));
1446
- // Note: these will map directly to VIEWPORT coordinates via position: fixed
1478
+ focusedIndex = signal(-1, /* @ts-ignore */
1479
+ ...(ngDevMode ? [{ debugName: "focusedIndex" }] : /* istanbul ignore next */ []));
1447
1480
  submenuTop = signal(0, /* @ts-ignore */
1448
1481
  ...(ngDevMode ? [{ debugName: "submenuTop" }] : /* istanbul ignore next */ []));
1449
1482
  submenuLeft = signal(0, /* @ts-ignore */
1450
1483
  ...(ngDevMode ? [{ debugName: "submenuLeft" }] : /* istanbul ignore next */ []));
1451
1484
  nextSubmenuDirection = signal('right', /* @ts-ignore */
1452
1485
  ...(ngDevMode ? [{ debugName: "nextSubmenuDirection" }] : /* istanbul ignore next */ []));
1486
+ menuItemsElements = signal([], /* @ts-ignore */
1487
+ ...(ngDevMode ? [{ debugName: "menuItemsElements" }] : /* istanbul ignore next */ []));
1488
+ // ────────────────────────────────────────────────────────────────────────────────
1489
+ // COMPUTED
1490
+ // ────────────────────────────────────────────────────────────────────────────────
1491
+ // ────────────────────────────────────────────────────────────────────────────────
1492
+ ngAfterViewInit() {
1493
+ const menuList = this.elementRef.nativeElement;
1494
+ if (menuList) {
1495
+ const items = Array.from(menuList.querySelectorAll(':scope > div > ul > .nath-menu-item'));
1496
+ this.menuItemsElements.set(items);
1497
+ setTimeout(() => {
1498
+ const first = this.menuItemsElements()[0];
1499
+ first?.focus();
1500
+ !!first && this.focusedIndex.set(0);
1501
+ });
1502
+ }
1503
+ fromEvent(this.document, 'keydown')
1504
+ .pipe(takeUntilDestroyed(this.destroyRef))
1505
+ .subscribe((event) => this.handleKeyDown(event));
1506
+ }
1453
1507
  // ────────────────────────────────────────────────────────────────────────────────
1454
1508
  // METHODS
1455
1509
  // ────────────────────────────────────────────────────────────────────────────────
@@ -1486,7 +1540,7 @@ class NathMenuList {
1486
1540
  const subRect = subContainer.getBoundingClientRect();
1487
1541
  const dynamicMenuWidth = subRect.width;
1488
1542
  // Check if trending right spills off screen boundary
1489
- if (currentDir === 'right' && liRect.right + dynamicMenuWidth > window.innerWidth) {
1543
+ if (currentDir === 'right' && liRect.right + dynamicMenuWidth > globalThis.innerWidth) {
1490
1544
  currentDir = 'left';
1491
1545
  }
1492
1546
  // Shift horizontal layout flush using viewport targets
@@ -1498,13 +1552,13 @@ class NathMenuList {
1498
1552
  }
1499
1553
  this.nextSubmenuDirection.set(currentDir);
1500
1554
  // Fluid vertical overflow protection
1501
- if (subRect.bottom > window.innerHeight) {
1502
- const overflowDistance = subRect.bottom - window.innerHeight;
1555
+ if (subRect.bottom > globalThis.innerHeight) {
1556
+ const overflowDistance = subRect.bottom - globalThis.innerHeight;
1503
1557
  // Shift up smoothly based on screen collision
1504
1558
  this.submenuTop.set(liRect.top - overflowDistance - SUBMENU_ALIGNMENT_CONFIG.VIEWPORT_COLLISION_PADDING_PX);
1505
1559
  }
1506
1560
  // Reveal once calculations are complete
1507
- subContainer.classList.remove('invisible');
1561
+ subContainer.style.visibility = 'visible';
1508
1562
  });
1509
1563
  }
1510
1564
  executeItem(item, index, event) {
@@ -1519,12 +1573,110 @@ class NathMenuList {
1519
1573
  }
1520
1574
  }
1521
1575
  isLucideIconComponent = isLucideIconComponent;
1576
+ onMouseLeave(event) {
1577
+ // Clear the active item to hide any opened sub-menu
1578
+ this.activeItem.set(null);
1579
+ }
1580
+ debounce = (callback, wait) => {
1581
+ let timeoutId = null;
1582
+ return (...args) => {
1583
+ globalThis.clearTimeout(timeoutId);
1584
+ timeoutId = globalThis.setTimeout(() => {
1585
+ callback(...args);
1586
+ }, wait);
1587
+ };
1588
+ };
1589
+ handleKeyDown = this.debounce((event) => {
1590
+ const items = this.menuItemsElements();
1591
+ const currentIndex = this.focusedIndex();
1592
+ const currentItem = items[currentIndex];
1593
+ const currentMenuItem = this.items().at(currentIndex);
1594
+ let newIndex = currentIndex;
1595
+ switch (event.key) {
1596
+ case 'ArrowDown':
1597
+ event.preventDefault();
1598
+ event.stopPropagation();
1599
+ if (currentIndex < items.length - 1) {
1600
+ const nextInteractiveItem = findSibling(items[currentIndex], '.nath-menu-item--interactive', 'next');
1601
+ if (nextInteractiveItem?.indexOffset) {
1602
+ newIndex = currentIndex + nextInteractiveItem.indexOffset;
1603
+ }
1604
+ }
1605
+ else {
1606
+ // We're at the last item, go back to the first
1607
+ newIndex = 0;
1608
+ }
1609
+ break;
1610
+ case 'ArrowUp':
1611
+ event.preventDefault();
1612
+ event.stopPropagation();
1613
+ if (currentIndex > 0) {
1614
+ const nextInteractiveItem = findSibling(items[currentIndex], '.nath-menu-item--interactive', 'previous');
1615
+ if (nextInteractiveItem?.indexOffset) {
1616
+ newIndex = currentIndex + nextInteractiveItem.indexOffset;
1617
+ }
1618
+ }
1619
+ else {
1620
+ // We're at the first item, go to the last
1621
+ for (let i = items.length - 1; i >= 0; i--) {
1622
+ if (items[i].classList.contains('nath-menu-item--interactive')) {
1623
+ newIndex = i;
1624
+ break;
1625
+ }
1626
+ }
1627
+ }
1628
+ break;
1629
+ case 'ArrowRight':
1630
+ // Open sub-menu if any
1631
+ event.preventDefault();
1632
+ event.stopPropagation();
1633
+ if (currentMenuItem?.items?.length && !currentMenuItem?.disabled) {
1634
+ items[currentIndex].dispatchEvent(new Event('mouseenter'));
1635
+ this.focusedIndex.set(-1);
1636
+ }
1637
+ return;
1638
+ case 'ArrowLeft':
1639
+ // Close sub-menu
1640
+ if (currentMenuItem) {
1641
+ const thisList = this.elementRef.nativeElement;
1642
+ if (thisList.parentElement?.classList.contains('nath-menu-submenu-panel')) {
1643
+ const parentList = previousSibling(thisList.parentElement, '.nath-menu-list');
1644
+ parentList?.dispatchEvent(new KeyboardEvent('keydown', { key: 'ArrowLeft' }));
1645
+ }
1646
+ }
1647
+ if (this.activeItem()?.items?.length) {
1648
+ newIndex = this.items().findIndex((item) => item.label && item.label === this.activeItem()?.label);
1649
+ this.activeItem.set(null);
1650
+ }
1651
+ break;
1652
+ case 'Escape':
1653
+ event.preventDefault();
1654
+ const thisList = this.elementRef.nativeElement;
1655
+ if (thisList.parentElement?.classList.contains('nath-menu-submenu-panel')) {
1656
+ const parentList = previousSibling(thisList.parentElement, '.nath-menu-list');
1657
+ parentList?.parentElement?.dispatchEvent(new MouseEvent('mouseleave'));
1658
+ }
1659
+ return;
1660
+ case 'Enter':
1661
+ case ' ':
1662
+ event.preventDefault();
1663
+ if (currentIndex >= 0 && currentIndex < items.length) {
1664
+ const item = this.items()[currentIndex];
1665
+ this.onItemClick(item, currentIndex, event);
1666
+ }
1667
+ return;
1668
+ default:
1669
+ return;
1670
+ }
1671
+ this.focusedIndex.set(newIndex);
1672
+ setTimeout(() => items[newIndex]?.focus());
1673
+ }, 100);
1522
1674
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathMenuList, deps: [], target: i0.ɵɵFactoryTarget.Component });
1523
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NathMenuList, isStandalone: true, selector: "nath-menu-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, flat: { classPropertyName: "flat", publicName: "flat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { whenCommand: "whenCommand" }, viewQueries: [{ propertyName: "submenuContainers", predicate: ["submenuContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<ul class=\"nath-menu-list-theme nath-menu-list nath-menu-custom-scrollbar\">\r\n @for (item of items(); track item.label) {\r\n <li\r\n class=\"nath-menu-item\"\r\n [class.nath-menu-item--enabled]=\"!item.disabled\"\r\n [class.nath-menu-item--disabled]=\"item.disabled\"\r\n [class.nath-menu-item--padded]=\"!item.separator\"\r\n [class.nath-menu-item--separator]=\"item.separator\"\r\n [class.nath-menu-item--clickable]=\"item.routerLink || item.command || item.url\"\r\n [class.nath-menu-item--header]=\"!item.routerLink && !item.command && !item.url\"\r\n [class.nath-menu-item--interactive]=\"\r\n !item.disabled &&\r\n (item.routerLink || item.command || item.url || (item.items?.length && !flat()))\r\n \"\r\n [routerLink]=\"item.routerLink\"\r\n [queryParams]=\"item.queryParams\"\r\n routerLinkActive=\"bg-primary-800 text-white!\"\r\n [routerLinkActiveOptions]=\"item.routerLinkActiveOptions || { exact: false }\"\r\n [attr.tabindex]=\"-1\"\r\n [attr.title]=\"item.title\"\r\n (mouseenter)=\"!item.disabled && onItemHover(item, $event)\"\r\n (click)=\"onItemClick(item, $index, $event)\"\r\n (keydown.enter)=\"onItemClick(item, $index, $event)\"\r\n >\r\n @if (!item.separator) {\r\n <span class=\"nath-menu-item-content\">\r\n @if (item.icon) {\r\n @if (isLucideIconComponent(item.icon)) {\r\n <svg [lucideIcon]=\"item.icon\" />\r\n } @else {\r\n <i [class]=\"item.icon\"></i>\r\n }\r\n }\r\n @if (item.escape === false) {\r\n <span [innerHTML]=\"getMenuLabel(item)\"></span>\r\n } @else {\r\n <span class=\"nath-menu-item-text-truncate\">{{ item.label }}</span>\r\n }\r\n </span>\r\n\r\n @if (item.items && item.items.length > 0 && !flat()) {\r\n <span class=\"nath-menu-item-arrow\">\u203A</span>\r\n }\r\n }\r\n </li>\r\n\r\n @if (flat() && item.items) {\r\n <nath-menu-list [items]=\"item.items\" (whenCommand)=\"whenCommand.emit($event)\" />\r\n }\r\n } @empty {\r\n <li class=\"nath-menu-item nath-menu-item--padded nath-menu-item--disabled\">\r\n No actions available\r\n </li>\r\n }\r\n</ul>\r\n\r\n@if (!flat()) {\r\n @if (activeItem() && activeItem()!.items && activeItem()!.items!.length > 0) {\r\n <div\r\n #submenuContainer\r\n class=\"nath-menu-list-theme nath-menu-submenu-panel\"\r\n [style.left.px]=\"submenuLeft()\"\r\n [style.top.px]=\"submenuTop()\"\r\n >\r\n <nath-menu-list\r\n [items]=\"activeItem()!.items!\"\r\n [direction]=\"nextSubmenuDirection()\"\r\n (whenCommand)=\"whenCommand.emit($event)\"\r\n />\r\n </div>\r\n }\r\n}\r\n", styles: ["nath-menu-list,.nath-menu-list-theme{--nath-menu-list-text: var(--color-zinc-700, oklch(37.1% .021 264.444));--nath-menu-list-text-muted: var(--color-zinc-500, oklch(55.2% .016 285.938));--nath-menu-list-text-disabled: var(--color-zinc-300, oklch(87.1% .006 286.286));--nath-menu-list-hover-bg: var(--color-zinc-100, oklch(96.7% .003 264.542));--nath-menu-list-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-list-bg: #ffffff;--nath-menu-list-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--nath-menu-list-z-index: 10000}.dark nath-menu-list,.dark .nath-menu-list-theme{--nath-menu-list-text: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-list-text-muted: var(--color-zinc-400, oklch(70.5% .015 286.067));--nath-menu-list-text-disabled: var(--color-zinc-600, oklch(44.2% .017 285.786));--nath-menu-list-hover-bg: var(--color-zinc-800, oklch(27.4% .006 286.033));--nath-menu-list-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-list-bg: var(--color-zinc-900, oklch(21% .006 285.885))}.nath-menu-list{max-height:90vh;overflow-y:auto;overflow-x:hidden;list-style-type:none;margin:0;padding:0;width:100%}.nath-menu-item{position:relative;display:flex;align-items:center;justify-content:space-between;gap:1rem;transition:background-color .15s,color .15s}.nath-menu-item--enabled{color:var(--nath-menu-list-text)}.nath-menu-item--interactive:hover{background-color:var(--nath-menu-list-hover-bg)}.nath-menu-item--padded{padding:.5rem 1rem}.nath-menu-item--separator{border-top:1px solid var(--nath-menu-list-border)}.nath-menu-item--clickable{cursor:pointer}.nath-menu-item--header{font-weight:700}.nath-menu-item--disabled{color:var(--nath-menu-list-text-disabled);cursor:default;opacity:.6;pointer-events:none}.nath-menu-item-content{display:flex;align-items:center;gap:.5rem;min-width:0;pointer-events:none}.nath-menu-item-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nath-menu-item-arrow{font-size:1.5rem;color:var(--nath-menu-list-text-muted);flex-shrink:0;pointer-events:none}.nath-menu-submenu-panel{position:fixed;background-color:var(--nath-menu-list-bg);border:1px solid var(--nath-menu-list-border);border-radius:.5rem;box-shadow:var(--nath-menu-list-shadow);padding:.5rem 0;color:var(--nath-menu-list-text);z-index:var(--nath-menu-list-z-index);overflow:visible;visibility:hidden}.nath-menu-custom-scrollbar::-webkit-scrollbar{width:6px}.nath-menu-custom-scrollbar::-webkit-scrollbar-thumb{background-color:var(--color-zinc-300, oklch(87.1% .006 286.286));border-radius:3px}\n"], dependencies: [{ kind: "component", type: NathMenuList, selector: "nath-menu-list", inputs: ["items", "direction", "flat"], outputs: ["whenCommand"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], encapsulation: i0.ViewEncapsulation.None });
1675
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NathMenuList, isStandalone: true, selector: "nath-menu-list", inputs: { items: { classPropertyName: "items", publicName: "items", isSignal: true, isRequired: false, transformFunction: null }, direction: { classPropertyName: "direction", publicName: "direction", isSignal: true, isRequired: false, transformFunction: null }, flat: { classPropertyName: "flat", publicName: "flat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { whenCommand: "whenCommand" }, viewQueries: [{ propertyName: "submenuContainers", predicate: ["submenuContainer"], descendants: true, isSignal: true }], ngImport: i0, template: "<div (mouseleave)=\"onMouseLeave($event)\">\n <ul class=\"nath-menu-list-theme nath-menu-list nath-menu-custom-scrollbar\">\n @for (item of items(); track $index) {\n <li\n class=\"nath-menu-item\"\n [class.nath-menu-item--enabled]=\"!item.disabled\"\n [class.nath-menu-item--disabled]=\"item.disabled\"\n [class.nath-menu-item--padded]=\"!item.separator\"\n [class.nath-menu-item--separator]=\"item.separator\"\n [class.nath-menu-item--clickable]=\"item.routerLink || item.command || item.url\"\n [class.nath-menu-item--header]=\"!item.routerLink && !item.command && !item.url\"\n [class.nath-menu-item--interactive]=\"\n !item.disabled &&\n (item.routerLink || item.command || item.url || (item.items?.length && !flat()))\n \"\n [routerLink]=\"item.routerLink\"\n [queryParams]=\"item.queryParams\"\n routerLinkActive=\"nath-menu-item--active\"\n [routerLinkActiveOptions]=\"item.routerLinkActiveOptions || { exact: false }\"\n [attr.tabindex]=\"-1\"\n [attr.title]=\"item.title\"\n (mouseenter)=\"!item.disabled && onItemHover(item, $event)\"\n (click)=\"onItemClick(item, $index, $event)\"\n (keydown)=\"$event.preventDefault(); handleKeyDown($event)\"\n (focus)=\"focusedIndex() < 0 && focusedIndex.set($index)\"\n >\n @if (!item.separator) {\n <span class=\"nath-menu-item-content\">\n @if (item.icon) {\n @if (isLucideIconComponent(item.icon)) {\n <svg [lucideIcon]=\"item.icon\" />\n } @else {\n <i [class]=\"item.icon\"></i>\n }\n }\n @if (item.escape === false) {\n <span [innerHTML]=\"getMenuLabel(item)\"></span>\n } @else {\n <span class=\"nath-menu-item-text-truncate\">{{ item.label }}</span>\n }\n </span>\n\n @if (item.items && item.items.length > 0 && !flat()) {\n <span class=\"nath-menu-item-arrow\">\u203A</span>\n }\n }\n </li>\n\n @if (flat() && item.items) {\n <nath-menu-list [items]=\"item.items\" (whenCommand)=\"whenCommand.emit($event)\" />\n }\n } @empty {\n <li class=\"nath-menu-item nath-menu-item--padded nath-menu-item--disabled\">\n No actions available\n </li>\n }\n </ul>\n\n @if (!flat()) {\n @if (activeItem()?.items?.length) {\n <div\n #submenuContainer\n class=\"nath-menu-list-theme nath-menu-submenu-panel\"\n [style.left.px]=\"submenuLeft()\"\n [style.top.px]=\"submenuTop()\"\n >\n <nath-menu-list\n [items]=\"activeItem()!.items!\"\n [direction]=\"nextSubmenuDirection()\"\n (whenCommand)=\"whenCommand.emit($event)\"\n />\n </div>\n }\n }\n</div>\n", styles: ["nath-menu-list,.nath-menu-list-theme{--nath-menu-list-text: var(--color-zinc-700, oklch(37.1% .021 264.444));--nath-menu-list-text-muted: var(--color-zinc-500, oklch(55.2% .016 285.938));--nath-menu-list-text-disabled: var(--color-zinc-300, oklch(87.1% .006 286.286));--nath-menu-list-hover-bg: var(--color-zinc-100, oklch(96.7% .003 264.542));--nath-menu-list-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-list-bg: #ffffff;--nath-menu-list-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--nath-menu-list-z-index: 10000}.dark nath-menu-list,.dark .nath-menu-list-theme{--nath-menu-list-text: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-list-text-muted: var(--color-zinc-400, oklch(70.5% .015 286.067));--nath-menu-list-text-disabled: var(--color-zinc-600, oklch(44.2% .017 285.786));--nath-menu-list-hover-bg: var(--color-zinc-800, oklch(27.4% .006 286.033));--nath-menu-list-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-list-bg: var(--color-zinc-900, oklch(21% .006 285.885))}.nath-menu-list{max-height:90vh;overflow-y:auto;overflow-x:hidden;list-style-type:none;margin:0;padding:0;width:100%}.nath-menu-item{position:relative;display:flex;align-items:center;justify-content:space-between;gap:1rem;transition:background-color .15s,color .15s}.nath-menu-item--enabled{color:var(--nath-menu-list-text)}.nath-menu-item--interactive:hover,.nath-menu-item--interactive:focus,.nath-menu-item--interactive:focus-within{background-color:var(--nath-menu-list-hover-bg)}.nath-menu-item--padded{padding:.5rem 1rem}.nath-menu-item--separator{border-top:1px solid var(--nath-menu-list-border)}.nath-menu-item--clickable{cursor:pointer}.nath-menu-item--header{font-weight:700}.nath-menu-item--disabled{color:var(--nath-menu-list-text-disabled);cursor:default;opacity:.6;pointer-events:none}.nath-menu-item-content{display:flex;align-items:center;gap:.5rem;min-width:0;pointer-events:none}.nath-menu-item-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nath-menu-item-arrow{font-size:1.5rem;color:var(--nath-menu-list-text-muted);flex-shrink:0;pointer-events:none}.nath-menu-submenu-panel{position:fixed;background-color:var(--nath-menu-list-bg);border:1px solid var(--nath-menu-list-border);border-radius:.5rem;box-shadow:var(--nath-menu-list-shadow);padding:.5rem 0;color:var(--nath-menu-list-text);z-index:var(--nath-menu-list-z-index);overflow:visible;visibility:hidden}.nath-menu-custom-scrollbar::-webkit-scrollbar{width:6px}.nath-menu-custom-scrollbar::-webkit-scrollbar-thumb{background-color:var(--color-zinc-300, oklch(87.1% .006 286.286));border-radius:3px}\n"], dependencies: [{ kind: "component", type: NathMenuList, selector: "nath-menu-list", inputs: ["items", "direction", "flat"], outputs: ["whenCommand"] }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], encapsulation: i0.ViewEncapsulation.None });
1524
1676
  }
1525
1677
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathMenuList, decorators: [{
1526
1678
  type: Component,
1527
- args: [{ selector: 'nath-menu-list', imports: [RouterLink, RouterLinkActive, LucideDynamicIcon], host: {}, encapsulation: ViewEncapsulation.None, template: "<ul class=\"nath-menu-list-theme nath-menu-list nath-menu-custom-scrollbar\">\r\n @for (item of items(); track item.label) {\r\n <li\r\n class=\"nath-menu-item\"\r\n [class.nath-menu-item--enabled]=\"!item.disabled\"\r\n [class.nath-menu-item--disabled]=\"item.disabled\"\r\n [class.nath-menu-item--padded]=\"!item.separator\"\r\n [class.nath-menu-item--separator]=\"item.separator\"\r\n [class.nath-menu-item--clickable]=\"item.routerLink || item.command || item.url\"\r\n [class.nath-menu-item--header]=\"!item.routerLink && !item.command && !item.url\"\r\n [class.nath-menu-item--interactive]=\"\r\n !item.disabled &&\r\n (item.routerLink || item.command || item.url || (item.items?.length && !flat()))\r\n \"\r\n [routerLink]=\"item.routerLink\"\r\n [queryParams]=\"item.queryParams\"\r\n routerLinkActive=\"bg-primary-800 text-white!\"\r\n [routerLinkActiveOptions]=\"item.routerLinkActiveOptions || { exact: false }\"\r\n [attr.tabindex]=\"-1\"\r\n [attr.title]=\"item.title\"\r\n (mouseenter)=\"!item.disabled && onItemHover(item, $event)\"\r\n (click)=\"onItemClick(item, $index, $event)\"\r\n (keydown.enter)=\"onItemClick(item, $index, $event)\"\r\n >\r\n @if (!item.separator) {\r\n <span class=\"nath-menu-item-content\">\r\n @if (item.icon) {\r\n @if (isLucideIconComponent(item.icon)) {\r\n <svg [lucideIcon]=\"item.icon\" />\r\n } @else {\r\n <i [class]=\"item.icon\"></i>\r\n }\r\n }\r\n @if (item.escape === false) {\r\n <span [innerHTML]=\"getMenuLabel(item)\"></span>\r\n } @else {\r\n <span class=\"nath-menu-item-text-truncate\">{{ item.label }}</span>\r\n }\r\n </span>\r\n\r\n @if (item.items && item.items.length > 0 && !flat()) {\r\n <span class=\"nath-menu-item-arrow\">\u203A</span>\r\n }\r\n }\r\n </li>\r\n\r\n @if (flat() && item.items) {\r\n <nath-menu-list [items]=\"item.items\" (whenCommand)=\"whenCommand.emit($event)\" />\r\n }\r\n } @empty {\r\n <li class=\"nath-menu-item nath-menu-item--padded nath-menu-item--disabled\">\r\n No actions available\r\n </li>\r\n }\r\n</ul>\r\n\r\n@if (!flat()) {\r\n @if (activeItem() && activeItem()!.items && activeItem()!.items!.length > 0) {\r\n <div\r\n #submenuContainer\r\n class=\"nath-menu-list-theme nath-menu-submenu-panel\"\r\n [style.left.px]=\"submenuLeft()\"\r\n [style.top.px]=\"submenuTop()\"\r\n >\r\n <nath-menu-list\r\n [items]=\"activeItem()!.items!\"\r\n [direction]=\"nextSubmenuDirection()\"\r\n (whenCommand)=\"whenCommand.emit($event)\"\r\n />\r\n </div>\r\n }\r\n}\r\n", styles: ["nath-menu-list,.nath-menu-list-theme{--nath-menu-list-text: var(--color-zinc-700, oklch(37.1% .021 264.444));--nath-menu-list-text-muted: var(--color-zinc-500, oklch(55.2% .016 285.938));--nath-menu-list-text-disabled: var(--color-zinc-300, oklch(87.1% .006 286.286));--nath-menu-list-hover-bg: var(--color-zinc-100, oklch(96.7% .003 264.542));--nath-menu-list-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-list-bg: #ffffff;--nath-menu-list-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--nath-menu-list-z-index: 10000}.dark nath-menu-list,.dark .nath-menu-list-theme{--nath-menu-list-text: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-list-text-muted: var(--color-zinc-400, oklch(70.5% .015 286.067));--nath-menu-list-text-disabled: var(--color-zinc-600, oklch(44.2% .017 285.786));--nath-menu-list-hover-bg: var(--color-zinc-800, oklch(27.4% .006 286.033));--nath-menu-list-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-list-bg: var(--color-zinc-900, oklch(21% .006 285.885))}.nath-menu-list{max-height:90vh;overflow-y:auto;overflow-x:hidden;list-style-type:none;margin:0;padding:0;width:100%}.nath-menu-item{position:relative;display:flex;align-items:center;justify-content:space-between;gap:1rem;transition:background-color .15s,color .15s}.nath-menu-item--enabled{color:var(--nath-menu-list-text)}.nath-menu-item--interactive:hover{background-color:var(--nath-menu-list-hover-bg)}.nath-menu-item--padded{padding:.5rem 1rem}.nath-menu-item--separator{border-top:1px solid var(--nath-menu-list-border)}.nath-menu-item--clickable{cursor:pointer}.nath-menu-item--header{font-weight:700}.nath-menu-item--disabled{color:var(--nath-menu-list-text-disabled);cursor:default;opacity:.6;pointer-events:none}.nath-menu-item-content{display:flex;align-items:center;gap:.5rem;min-width:0;pointer-events:none}.nath-menu-item-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nath-menu-item-arrow{font-size:1.5rem;color:var(--nath-menu-list-text-muted);flex-shrink:0;pointer-events:none}.nath-menu-submenu-panel{position:fixed;background-color:var(--nath-menu-list-bg);border:1px solid var(--nath-menu-list-border);border-radius:.5rem;box-shadow:var(--nath-menu-list-shadow);padding:.5rem 0;color:var(--nath-menu-list-text);z-index:var(--nath-menu-list-z-index);overflow:visible;visibility:hidden}.nath-menu-custom-scrollbar::-webkit-scrollbar{width:6px}.nath-menu-custom-scrollbar::-webkit-scrollbar-thumb{background-color:var(--color-zinc-300, oklch(87.1% .006 286.286));border-radius:3px}\n"] }]
1679
+ args: [{ selector: 'nath-menu-list', imports: [RouterLink, RouterLinkActive, LucideDynamicIcon], host: {}, encapsulation: ViewEncapsulation.None, template: "<div (mouseleave)=\"onMouseLeave($event)\">\n <ul class=\"nath-menu-list-theme nath-menu-list nath-menu-custom-scrollbar\">\n @for (item of items(); track $index) {\n <li\n class=\"nath-menu-item\"\n [class.nath-menu-item--enabled]=\"!item.disabled\"\n [class.nath-menu-item--disabled]=\"item.disabled\"\n [class.nath-menu-item--padded]=\"!item.separator\"\n [class.nath-menu-item--separator]=\"item.separator\"\n [class.nath-menu-item--clickable]=\"item.routerLink || item.command || item.url\"\n [class.nath-menu-item--header]=\"!item.routerLink && !item.command && !item.url\"\n [class.nath-menu-item--interactive]=\"\n !item.disabled &&\n (item.routerLink || item.command || item.url || (item.items?.length && !flat()))\n \"\n [routerLink]=\"item.routerLink\"\n [queryParams]=\"item.queryParams\"\n routerLinkActive=\"nath-menu-item--active\"\n [routerLinkActiveOptions]=\"item.routerLinkActiveOptions || { exact: false }\"\n [attr.tabindex]=\"-1\"\n [attr.title]=\"item.title\"\n (mouseenter)=\"!item.disabled && onItemHover(item, $event)\"\n (click)=\"onItemClick(item, $index, $event)\"\n (keydown)=\"$event.preventDefault(); handleKeyDown($event)\"\n (focus)=\"focusedIndex() < 0 && focusedIndex.set($index)\"\n >\n @if (!item.separator) {\n <span class=\"nath-menu-item-content\">\n @if (item.icon) {\n @if (isLucideIconComponent(item.icon)) {\n <svg [lucideIcon]=\"item.icon\" />\n } @else {\n <i [class]=\"item.icon\"></i>\n }\n }\n @if (item.escape === false) {\n <span [innerHTML]=\"getMenuLabel(item)\"></span>\n } @else {\n <span class=\"nath-menu-item-text-truncate\">{{ item.label }}</span>\n }\n </span>\n\n @if (item.items && item.items.length > 0 && !flat()) {\n <span class=\"nath-menu-item-arrow\">\u203A</span>\n }\n }\n </li>\n\n @if (flat() && item.items) {\n <nath-menu-list [items]=\"item.items\" (whenCommand)=\"whenCommand.emit($event)\" />\n }\n } @empty {\n <li class=\"nath-menu-item nath-menu-item--padded nath-menu-item--disabled\">\n No actions available\n </li>\n }\n </ul>\n\n @if (!flat()) {\n @if (activeItem()?.items?.length) {\n <div\n #submenuContainer\n class=\"nath-menu-list-theme nath-menu-submenu-panel\"\n [style.left.px]=\"submenuLeft()\"\n [style.top.px]=\"submenuTop()\"\n >\n <nath-menu-list\n [items]=\"activeItem()!.items!\"\n [direction]=\"nextSubmenuDirection()\"\n (whenCommand)=\"whenCommand.emit($event)\"\n />\n </div>\n }\n }\n</div>\n", styles: ["nath-menu-list,.nath-menu-list-theme{--nath-menu-list-text: var(--color-zinc-700, oklch(37.1% .021 264.444));--nath-menu-list-text-muted: var(--color-zinc-500, oklch(55.2% .016 285.938));--nath-menu-list-text-disabled: var(--color-zinc-300, oklch(87.1% .006 286.286));--nath-menu-list-hover-bg: var(--color-zinc-100, oklch(96.7% .003 264.542));--nath-menu-list-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-list-bg: #ffffff;--nath-menu-list-shadow: 0 10px 15px -3px rgba(0, 0, 0, .1), 0 4px 6px -2px rgba(0, 0, 0, .05);--nath-menu-list-z-index: 10000}.dark nath-menu-list,.dark .nath-menu-list-theme{--nath-menu-list-text: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-list-text-muted: var(--color-zinc-400, oklch(70.5% .015 286.067));--nath-menu-list-text-disabled: var(--color-zinc-600, oklch(44.2% .017 285.786));--nath-menu-list-hover-bg: var(--color-zinc-800, oklch(27.4% .006 286.033));--nath-menu-list-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-list-bg: var(--color-zinc-900, oklch(21% .006 285.885))}.nath-menu-list{max-height:90vh;overflow-y:auto;overflow-x:hidden;list-style-type:none;margin:0;padding:0;width:100%}.nath-menu-item{position:relative;display:flex;align-items:center;justify-content:space-between;gap:1rem;transition:background-color .15s,color .15s}.nath-menu-item--enabled{color:var(--nath-menu-list-text)}.nath-menu-item--interactive:hover,.nath-menu-item--interactive:focus,.nath-menu-item--interactive:focus-within{background-color:var(--nath-menu-list-hover-bg)}.nath-menu-item--padded{padding:.5rem 1rem}.nath-menu-item--separator{border-top:1px solid var(--nath-menu-list-border)}.nath-menu-item--clickable{cursor:pointer}.nath-menu-item--header{font-weight:700}.nath-menu-item--disabled{color:var(--nath-menu-list-text-disabled);cursor:default;opacity:.6;pointer-events:none}.nath-menu-item-content{display:flex;align-items:center;gap:.5rem;min-width:0;pointer-events:none}.nath-menu-item-text-truncate{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nath-menu-item-arrow{font-size:1.5rem;color:var(--nath-menu-list-text-muted);flex-shrink:0;pointer-events:none}.nath-menu-submenu-panel{position:fixed;background-color:var(--nath-menu-list-bg);border:1px solid var(--nath-menu-list-border);border-radius:.5rem;box-shadow:var(--nath-menu-list-shadow);padding:.5rem 0;color:var(--nath-menu-list-text);z-index:var(--nath-menu-list-z-index);overflow:visible;visibility:hidden}.nath-menu-custom-scrollbar::-webkit-scrollbar{width:6px}.nath-menu-custom-scrollbar::-webkit-scrollbar-thumb{background-color:var(--color-zinc-300, oklch(87.1% .006 286.286));border-radius:3px}\n"] }]
1528
1680
  }], propDecorators: { items: [{ type: i0.Input, args: [{ isSignal: true, alias: "items", required: false }] }], direction: [{ type: i0.Input, args: [{ isSignal: true, alias: "direction", required: false }] }], flat: [{ type: i0.Input, args: [{ isSignal: true, alias: "flat", required: false }] }], whenCommand: [{ type: i0.Output, args: ["whenCommand"] }], submenuContainers: [{ type: i0.ViewChildren, args: ['submenuContainer', { isSignal: true }] }] } });
1529
1681
 
1530
1682
  const TIERED_MENU_LAYOUT_CONFIG = {
@@ -1536,6 +1688,8 @@ class NathMenu {
1536
1688
  ...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
1537
1689
  styleClass = model('', /* @ts-ignore */
1538
1690
  ...(ngDevMode ? [{ debugName: "styleClass" }] : /* istanbul ignore next */ []));
1691
+ panelStyleClass = model('', /* @ts-ignore */
1692
+ ...(ngDevMode ? [{ debugName: "panelStyleClass" }] : /* istanbul ignore next */ []));
1539
1693
  positionX = input('auto', /* @ts-ignore */
1540
1694
  ...(ngDevMode ? [{ debugName: "positionX" }] : /* istanbul ignore next */ []));
1541
1695
  positionY = input('auto', /* @ts-ignore */
@@ -1564,12 +1718,12 @@ class NathMenu {
1564
1718
  show(event) {
1565
1719
  event.stopPropagation();
1566
1720
  event.preventDefault();
1567
- let x = event.clientX;
1568
- let y = event.clientY;
1569
- const positionX = this.positionX();
1570
- const positionY = this.positionY();
1571
1721
  const target = event.currentTarget;
1572
1722
  const targetRect = target.getBoundingClientRect();
1723
+ let x = event instanceof MouseEvent ? event.clientX : targetRect.x;
1724
+ let y = event instanceof MouseEvent ? event.clientY : targetRect.y + targetRect.height;
1725
+ const positionX = this.positionX();
1726
+ const positionY = this.positionY();
1573
1727
  if (positionX !== 'auto' && target) {
1574
1728
  if (positionX === 'left') {
1575
1729
  x = targetRect.left;
@@ -1626,6 +1780,18 @@ class NathMenu {
1626
1780
  this.adjustedPosition.set({ x: adjustedX, y: adjustedY });
1627
1781
  el.classList.remove('nath-menu-panel--invisible');
1628
1782
  });
1783
+ setTimeout(() => {
1784
+ const rootMenuElement = this.rootMenuElement();
1785
+ if (!rootMenuElement)
1786
+ return;
1787
+ const el = rootMenuElement.nativeElement;
1788
+ event.preventDefault();
1789
+ // Focus first item in submenu
1790
+ const submenu = el.querySelector('.nath-menu-item');
1791
+ if (submenu) {
1792
+ submenu.focus();
1793
+ }
1794
+ });
1629
1795
  }
1630
1796
  hide() {
1631
1797
  if (this.isVisible() && !this.inline()) {
@@ -1662,15 +1828,184 @@ class NathMenu {
1662
1828
  }
1663
1829
  }
1664
1830
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathMenu, deps: [], target: i0.ɵɵFactoryTarget.Component });
1665
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NathMenu, isStandalone: true, selector: "nath-menu", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, positionX: { classPropertyName: "positionX", publicName: "positionX", isSignal: true, isRequired: false, transformFunction: null }, positionY: { classPropertyName: "positionY", publicName: "positionY", isSignal: true, isRequired: false, transformFunction: null }, inline: { classPropertyName: "inline", publicName: "inline", isSignal: true, isRequired: false, transformFunction: null }, flat: { classPropertyName: "flat", publicName: "flat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { model: "modelChange", styleClass: "styleClassChange", whenHide: "whenHide" }, host: { listeners: { "document:click": "hide();" }, properties: { "class": "styleClass()" } }, viewQueries: [{ propertyName: "rootMenuElement", first: true, predicate: ["rootMenu"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (isVisible()) {\n <div\n #rootMenu\n class=\"nath-menu-theme nath-menu-panel\"\n [class.nath-menu-panel--inline]=\"inline()\"\n [class.nath-menu-panel--invisible]=\"!inline()\"\n [style.left.px]=\"adjustedPosition().x\"\n [style.top.px]=\"adjustedPosition().y\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n >\n <nath-menu-list [items]=\"model()\" [flat]=\"flat()\" (whenCommand)=\"handleCommand($event)\" />\n </div>\n}\n", styles: ["nath-menu,.nath-menu-theme{--nath-menu-bg: #ffffff;--nath-menu-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1);--nath-menu-text: var(--color-gray-700, oklch(37.1% .021 264.444));--nath-menu-font-size: .875rem;--nath-menu-padding: .5rem 0;--nath-menu-radius: .5rem;--nath-menu-z-index: 999999}.dark nath-menu,.dark .nath-menu-theme{--nath-menu-bg: var(--color-zinc-900, oklch(21% .006 285.885));--nath-menu-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-text: var(--color-zinc-200, oklch(92% .004 286.32))}nath-menu{display:block}.nath-menu-panel{position:fixed;background-color:var(--nath-menu-bg);border:1px solid var(--nath-menu-border);border-radius:var(--nath-menu-radius);box-shadow:var(--nath-menu-shadow);padding:var(--nath-menu-padding);font-size:var(--nath-menu-font-size);color:var(--nath-menu-text);z-index:var(--nath-menu-z-index);overflow:visible}.nath-menu-panel--inline{position:static}.nath-menu-panel--invisible{visibility:hidden}\n"], dependencies: [{ kind: "component", type: NathMenuList, selector: "nath-menu-list", inputs: ["items", "direction", "flat"], outputs: ["whenCommand"] }], encapsulation: i0.ViewEncapsulation.None });
1831
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NathMenu, isStandalone: true, selector: "nath-menu", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null }, panelStyleClass: { classPropertyName: "panelStyleClass", publicName: "panelStyleClass", isSignal: true, isRequired: false, transformFunction: null }, positionX: { classPropertyName: "positionX", publicName: "positionX", isSignal: true, isRequired: false, transformFunction: null }, positionY: { classPropertyName: "positionY", publicName: "positionY", isSignal: true, isRequired: false, transformFunction: null }, inline: { classPropertyName: "inline", publicName: "inline", isSignal: true, isRequired: false, transformFunction: null }, flat: { classPropertyName: "flat", publicName: "flat", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { model: "modelChange", styleClass: "styleClassChange", panelStyleClass: "panelStyleClassChange", whenHide: "whenHide" }, host: { listeners: { "document:click": "hide();" }, properties: { "class": "styleClass()" } }, viewQueries: [{ propertyName: "rootMenuElement", first: true, predicate: ["rootMenu"], descendants: true, isSignal: true }], ngImport: i0, template: "@if (isVisible()) {\n <div\n #rootMenu\n class=\"nath-menu-theme nath-menu-panel {{ panelStyleClass() }}\"\n [class.nath-menu-panel--inline]=\"inline()\"\n [class.nath-menu-panel--invisible]=\"!inline()\"\n [style.left.px]=\"adjustedPosition().x\"\n [style.top.px]=\"adjustedPosition().y\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n >\n <nath-menu-list\n [items]=\"model()\"\n [flat]=\"flat()\"\n (whenCommand)=\"handleCommand($event)\"\n (keydown.escape)=\"hide()\"\n />\n </div>\n}\n", styles: ["nath-menu,.nath-menu-theme{--nath-menu-bg: #ffffff;--nath-menu-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1);--nath-menu-text: var(--color-gray-700, oklch(37.1% .021 264.444));--nath-menu-font-size: .875rem;--nath-menu-padding: .5rem 0;--nath-menu-radius: .5rem;--nath-menu-z-index: 999999}.dark nath-menu,.dark .nath-menu-theme{--nath-menu-bg: var(--color-zinc-900, oklch(21% .006 285.885));--nath-menu-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-text: var(--color-zinc-200, oklch(92% .004 286.32))}nath-menu{display:block}.nath-menu-panel{position:fixed;background-color:var(--nath-menu-bg);border:1px solid var(--nath-menu-border);border-radius:var(--nath-menu-radius);box-shadow:var(--nath-menu-shadow);padding:var(--nath-menu-padding);font-size:var(--nath-menu-font-size);color:var(--nath-menu-text);z-index:var(--nath-menu-z-index);overflow:visible}.nath-menu-panel--inline{position:static}.nath-menu-panel--invisible{visibility:hidden}\n"], dependencies: [{ kind: "component", type: NathMenuList, selector: "nath-menu-list", inputs: ["items", "direction", "flat"], outputs: ["whenCommand"] }], encapsulation: i0.ViewEncapsulation.None });
1666
1832
  }
1667
1833
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathMenu, decorators: [{
1668
1834
  type: Component,
1669
1835
  args: [{ selector: 'nath-menu', imports: [NathMenuList], host: {
1670
1836
  '[class]': `styleClass()`,
1671
1837
  '(document:click)': `hide();`,
1672
- }, encapsulation: ViewEncapsulation.None, template: "@if (isVisible()) {\n <div\n #rootMenu\n class=\"nath-menu-theme nath-menu-panel\"\n [class.nath-menu-panel--inline]=\"inline()\"\n [class.nath-menu-panel--invisible]=\"!inline()\"\n [style.left.px]=\"adjustedPosition().x\"\n [style.top.px]=\"adjustedPosition().y\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n >\n <nath-menu-list [items]=\"model()\" [flat]=\"flat()\" (whenCommand)=\"handleCommand($event)\" />\n </div>\n}\n", styles: ["nath-menu,.nath-menu-theme{--nath-menu-bg: #ffffff;--nath-menu-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1);--nath-menu-text: var(--color-gray-700, oklch(37.1% .021 264.444));--nath-menu-font-size: .875rem;--nath-menu-padding: .5rem 0;--nath-menu-radius: .5rem;--nath-menu-z-index: 999999}.dark nath-menu,.dark .nath-menu-theme{--nath-menu-bg: var(--color-zinc-900, oklch(21% .006 285.885));--nath-menu-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-text: var(--color-zinc-200, oklch(92% .004 286.32))}nath-menu{display:block}.nath-menu-panel{position:fixed;background-color:var(--nath-menu-bg);border:1px solid var(--nath-menu-border);border-radius:var(--nath-menu-radius);box-shadow:var(--nath-menu-shadow);padding:var(--nath-menu-padding);font-size:var(--nath-menu-font-size);color:var(--nath-menu-text);z-index:var(--nath-menu-z-index);overflow:visible}.nath-menu-panel--inline{position:static}.nath-menu-panel--invisible{visibility:hidden}\n"] }]
1673
- }], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }, { type: i0.Output, args: ["modelChange"] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }, { type: i0.Output, args: ["styleClassChange"] }], positionX: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionX", required: false }] }], positionY: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionY", required: false }] }], inline: [{ type: i0.Input, args: [{ isSignal: true, alias: "inline", required: false }] }], flat: [{ type: i0.Input, args: [{ isSignal: true, alias: "flat", required: false }] }], whenHide: [{ type: i0.Output, args: ["whenHide"] }], rootMenuElement: [{ type: i0.ViewChild, args: ['rootMenu', { isSignal: true }] }] } });
1838
+ }, encapsulation: ViewEncapsulation.None, template: "@if (isVisible()) {\n <div\n #rootMenu\n class=\"nath-menu-theme nath-menu-panel {{ panelStyleClass() }}\"\n [class.nath-menu-panel--inline]=\"inline()\"\n [class.nath-menu-panel--invisible]=\"!inline()\"\n [style.left.px]=\"adjustedPosition().x\"\n [style.top.px]=\"adjustedPosition().y\"\n (click)=\"$event.stopPropagation()\"\n (keydown.enter)=\"$event.stopPropagation()\"\n >\n <nath-menu-list\n [items]=\"model()\"\n [flat]=\"flat()\"\n (whenCommand)=\"handleCommand($event)\"\n (keydown.escape)=\"hide()\"\n />\n </div>\n}\n", styles: ["nath-menu,.nath-menu-theme{--nath-menu-bg: #ffffff;--nath-menu-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-shadow: 0 20px 25px -5px rgba(0, 0, 0, .1), 0 8px 10px -6px rgba(0, 0, 0, .1);--nath-menu-text: var(--color-gray-700, oklch(37.1% .021 264.444));--nath-menu-font-size: .875rem;--nath-menu-padding: .5rem 0;--nath-menu-radius: .5rem;--nath-menu-z-index: 999999}.dark nath-menu,.dark .nath-menu-theme{--nath-menu-bg: var(--color-zinc-900, oklch(21% .006 285.885));--nath-menu-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-text: var(--color-zinc-200, oklch(92% .004 286.32))}nath-menu{display:block}.nath-menu-panel{position:fixed;background-color:var(--nath-menu-bg);border:1px solid var(--nath-menu-border);border-radius:var(--nath-menu-radius);box-shadow:var(--nath-menu-shadow);padding:var(--nath-menu-padding);font-size:var(--nath-menu-font-size);color:var(--nath-menu-text);z-index:var(--nath-menu-z-index);overflow:visible}.nath-menu-panel--inline{position:static}.nath-menu-panel--invisible{visibility:hidden}\n"] }]
1839
+ }], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }, { type: i0.Output, args: ["modelChange"] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }, { type: i0.Output, args: ["styleClassChange"] }], panelStyleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "panelStyleClass", required: false }] }, { type: i0.Output, args: ["panelStyleClassChange"] }], positionX: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionX", required: false }] }], positionY: [{ type: i0.Input, args: [{ isSignal: true, alias: "positionY", required: false }] }], inline: [{ type: i0.Input, args: [{ isSignal: true, alias: "inline", required: false }] }], flat: [{ type: i0.Input, args: [{ isSignal: true, alias: "flat", required: false }] }], whenHide: [{ type: i0.Output, args: ["whenHide"] }], rootMenuElement: [{ type: i0.ViewChild, args: ['rootMenu', { isSignal: true }] }] } });
1840
+
1841
+ class NathMenuBar {
1842
+ document = inject(DOCUMENT);
1843
+ sanitizer = inject(DomSanitizer);
1844
+ destroyRef = inject(DestroyRef);
1845
+ model = input([], /* @ts-ignore */
1846
+ ...(ngDevMode ? [{ debugName: "model" }] : /* istanbul ignore next */ []));
1847
+ styleClass = input('', /* @ts-ignore */
1848
+ ...(ngDevMode ? [{ debugName: "styleClass" }] : /* istanbul ignore next */ []));
1849
+ whenCommand = output();
1850
+ menuBarElement = viewChild('menuBar', /* @ts-ignore */
1851
+ ...(ngDevMode ? [{ debugName: "menuBarElement" }] : /* istanbul ignore next */ []));
1852
+ dropdownMenu = viewChild('dropdownMenu', /* @ts-ignore */
1853
+ ...(ngDevMode ? [{ debugName: "dropdownMenu" }] : /* istanbul ignore next */ []));
1854
+ isMobileMenuOpen = signal(false, /* @ts-ignore */
1855
+ ...(ngDevMode ? [{ debugName: "isMobileMenuOpen" }] : /* istanbul ignore next */ []));
1856
+ activeItem = signal(null, /* @ts-ignore */
1857
+ ...(ngDevMode ? [{ debugName: "activeItem" }] : /* istanbul ignore next */ []));
1858
+ activeItemIndex = signal(-1, /* @ts-ignore */
1859
+ ...(ngDevMode ? [{ debugName: "activeItemIndex" }] : /* istanbul ignore next */ []));
1860
+ focusedIndex = signal(-1, /* @ts-ignore */
1861
+ ...(ngDevMode ? [{ debugName: "focusedIndex" }] : /* istanbul ignore next */ []));
1862
+ menuItemsElements = signal([], /* @ts-ignore */
1863
+ ...(ngDevMode ? [{ debugName: "menuItemsElements" }] : /* istanbul ignore next */ []));
1864
+ ngAfterViewInit() {
1865
+ const menuBar = this.menuBarElement()?.nativeElement;
1866
+ if (menuBar) {
1867
+ const items = Array.from(menuBar.querySelectorAll('.nath-menu-bar-item'));
1868
+ this.menuItemsElements.set(items);
1869
+ }
1870
+ fromEvent(this.document, 'keydown')
1871
+ .pipe(takeUntilDestroyed(this.destroyRef))
1872
+ .subscribe((event) => this.handleKeyDown(event));
1873
+ }
1874
+ handleDocumentClick(event) {
1875
+ const menuBar = this.menuBarElement()?.nativeElement;
1876
+ if (!menuBar)
1877
+ return;
1878
+ if (!menuBar.contains(event.target)) {
1879
+ this.closeAllMenus();
1880
+ this.isMobileMenuOpen.set(false);
1881
+ }
1882
+ }
1883
+ handleItemClick(item, index, event) {
1884
+ if (item.disabled)
1885
+ return;
1886
+ event.stopPropagation();
1887
+ if (item.items && item.items.length > 0) {
1888
+ this.toggleSubmenu(item, index, event);
1889
+ }
1890
+ else {
1891
+ this.executeItem(item, index, event);
1892
+ }
1893
+ }
1894
+ handleItemHover(item, index, event) {
1895
+ if (this.isMobileMenuOpen())
1896
+ return;
1897
+ if (item.items && item.items.length > 0) {
1898
+ this.activeItem.set(item);
1899
+ this.activeItemIndex.set(index);
1900
+ if (this.activeItem()?.items?.length) {
1901
+ this.dropdownMenu()?.show(event);
1902
+ }
1903
+ }
1904
+ }
1905
+ toggleSubmenu(item, index, event) {
1906
+ if (this.activeItem() === item) {
1907
+ this.activeItem.set(null);
1908
+ this.activeItemIndex.set(-1);
1909
+ }
1910
+ else {
1911
+ this.activeItem.set(item);
1912
+ this.activeItemIndex.set(index);
1913
+ if (!this.isMobileMenuOpen() && this.activeItem()?.items?.length) {
1914
+ this.dropdownMenu()?.show(event);
1915
+ }
1916
+ }
1917
+ }
1918
+ closeAllMenus() {
1919
+ this.activeItem.set(null);
1920
+ this.activeItemIndex.set(-1);
1921
+ }
1922
+ toggleMobileMenu() {
1923
+ this.isMobileMenuOpen.update((open) => !open);
1924
+ if (!this.isMobileMenuOpen()) {
1925
+ this.closeAllMenus();
1926
+ }
1927
+ }
1928
+ executeItem(item, index, event) {
1929
+ if (item.command) {
1930
+ item.command({
1931
+ originalEvent: event,
1932
+ item,
1933
+ index,
1934
+ });
1935
+ }
1936
+ this.whenCommand.emit({ item, index, event });
1937
+ this.closeAllMenus();
1938
+ this.isMobileMenuOpen.set(false);
1939
+ }
1940
+ handleKeyDown(event) {
1941
+ const items = this.menuItemsElements();
1942
+ if (items.length === 0)
1943
+ return;
1944
+ const currentIndex = this.focusedIndex();
1945
+ let newIndex;
1946
+ switch (event.key) {
1947
+ case 'ArrowRight':
1948
+ event.preventDefault();
1949
+ newIndex = currentIndex < items.length - 1 ? currentIndex + 1 : 0;
1950
+ break;
1951
+ case 'ArrowLeft':
1952
+ event.preventDefault();
1953
+ newIndex = currentIndex > 0 ? currentIndex - 1 : items.length - 1;
1954
+ break;
1955
+ case 'ArrowDown':
1956
+ return;
1957
+ case 'Escape':
1958
+ event.preventDefault();
1959
+ this.closeAllMenus();
1960
+ this.isMobileMenuOpen.set(false);
1961
+ this.focusedIndex.set(-1);
1962
+ return;
1963
+ case 'Enter':
1964
+ case ' ':
1965
+ event.preventDefault();
1966
+ if (currentIndex >= 0 && currentIndex < items.length) {
1967
+ const item = this.model()[currentIndex];
1968
+ this.handleItemClick(item, currentIndex, event);
1969
+ }
1970
+ return;
1971
+ default:
1972
+ return;
1973
+ }
1974
+ this.focusedIndex.set(newIndex);
1975
+ items[newIndex]?.focus();
1976
+ }
1977
+ handleSubmenuCommand(payload) {
1978
+ this.executeItem(payload.item, payload.index, payload.event);
1979
+ }
1980
+ getMenuLabel(item) {
1981
+ if (!item.label)
1982
+ return '';
1983
+ return item.escape === false
1984
+ ? (this.sanitizer.sanitize(SecurityContext.HTML, item.label) ?? '')
1985
+ : item.label;
1986
+ }
1987
+ isLucideIconComponent = isLucideIconComponent;
1988
+ ngOnDestroy() {
1989
+ this.closeAllMenus();
1990
+ }
1991
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathMenuBar, deps: [], target: i0.ɵɵFactoryTarget.Component });
1992
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.0.5", type: NathMenuBar, isStandalone: true, selector: "nath-menu-bar", inputs: { model: { classPropertyName: "model", publicName: "model", isSignal: true, isRequired: false, transformFunction: null }, styleClass: { classPropertyName: "styleClass", publicName: "styleClass", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { whenCommand: "whenCommand" }, host: { listeners: { "document:click": "handleDocumentClick($event)" }, properties: { "class": "styleClass()" } }, viewQueries: [{ propertyName: "menuBarElement", first: true, predicate: ["menuBar"], descendants: true, isSignal: true }, { propertyName: "dropdownMenu", first: true, predicate: ["dropdownMenu"], descendants: true, isSignal: true }], ngImport: i0, template: "<nav #menuBar class=\"nath-menu-bar-theme nath-menu-bar\" role=\"menubar\">\n <!-- Desktop Menu Bar -->\n <ul class=\"nath-menu-bar-list\">\n @for (item of model(); track item.label; let index = $index) {\n <li\n class=\"nath-menu-bar-item\"\n [class.nath-menu-bar-item--active]=\"activeItem() === item\"\n [class.nath-menu-bar-item--disabled]=\"item.disabled\"\n [class.nath-menu-bar-item--focused]=\"focusedIndex() === index\"\n [attr.tabindex]=\"item.disabled ? -1 : 0\"\n [attr.role]=\"item.items && item.items.length > 0 ? 'menuitem' : 'menuitem'\"\n [attr.aria-haspopup]=\"item.items && item.items.length > 0 ? 'true' : 'false'\"\n [attr.aria-expanded]=\"activeItem() === item ? 'true' : 'false'\"\n (mouseenter)=\"handleItemHover(item, index, $event)\"\n (click)=\"handleItemClick(item, index, $event)\"\n (keydown)=\"handleKeyDown($event)\"\n >\n <span class=\"nath-menu-bar-item-content\">\n @if (item.icon) {\n @if (isLucideIconComponent(item.icon)) {\n <svg [lucideIcon]=\"item.icon\" [size]=\"16\" />\n } @else {\n <i [class]=\"item.icon\"></i>\n }\n }\n @if (item.escape === false) {\n <span [innerHTML]=\"getMenuLabel(item)\"></span>\n } @else {\n <span>{{ item.label }}</span>\n }\n @if (item.items && item.items.length > 0) {\n <svg lucideChevronDown [size]=\"14\" class=\"nath-menu-bar-arrow\" />\n }\n </span>\n\n @if (item.routerLink) {\n <a\n [routerLink]=\"item.routerLink\"\n [queryParams]=\"item.queryParams\"\n [fragment]=\"item.fragment\"\n [queryParamsHandling]=\"item.queryParamsHandling\"\n [preserveFragment]=\"item.preserveFragment\"\n [skipLocationChange]=\"item.skipLocationChange\"\n [replaceUrl]=\"item.replaceUrl\"\n [state]=\"item.state\"\n [attr.target]=\"item.target\"\n class=\"nath-menu-bar-link\"\n ><span></span\n ></a>\n } @else if (item.url) {\n <a [href]=\"item.url\" [attr.target]=\"item.target || '_blank'\" class=\"nath-menu-bar-link\"\n ><span></span\n ></a>\n }\n </li>\n }\n </ul>\n\n <!-- Mobile Menu Button -->\n <button\n class=\"nath-menu-bar-toggle\"\n [class.nath-menu-bar-toggle--active]=\"isMobileMenuOpen()\"\n (click)=\"toggleMobileMenu()\"\n [attr.aria-label]=\"isMobileMenuOpen() ? 'Close menu' : 'Open menu'\"\n [attr.aria-expanded]=\"isMobileMenuOpen()\"\n >\n @if (isMobileMenuOpen()) {\n <svg lucideX [size]=\"24\" />\n } @else {\n <svg lucideMenu [size]=\"24\" />\n }\n </button>\n</nav>\n\n<!-- Mobile Menu Overlay -->\n@if (isMobileMenuOpen()) {\n <div\n class=\"nath-menu-bar-mobile-overlay\"\n (click)=\"toggleMobileMenu()\"\n (keydown.enter)=\"toggleMobileMenu()\"\n ></div>\n}\n\n<!-- Mobile Menu Panel -->\n@if (isMobileMenuOpen()) {\n <div class=\"nath-menu-bar-mobile-panel\">\n <ul class=\"nath-menu-bar-mobile-list\">\n @for (item of model(); track item.label; let index = $index) {\n <li\n class=\"nath-menu-bar-mobile-item\"\n [class.nath-menu-bar-mobile-item--disabled]=\"item.disabled\"\n [class.nath-menu-bar-mobile-item--expanded]=\"activeItem() === item\"\n >\n <div\n class=\"nath-menu-bar-mobile-item-content\"\n (click)=\"handleItemClick(item, index, $event)\"\n (keydown.enter)=\"handleItemClick(item, index, $event)\"\n >\n <span class=\"nath-menu-bar-mobile-item-text\">\n @if (item.icon) {\n @if (isLucideIconComponent(item.icon)) {\n <svg [lucideIcon]=\"item.icon\" [size]=\"18\" />\n } @else {\n <i [class]=\"item.icon\"></i>\n }\n }\n <span>{{ item.label }}</span>\n </span>\n @if (item.items && item.items.length > 0) {\n <svg\n lucideChevronDown\n [size]=\"16\"\n class=\"nath-menu-bar-mobile-arrow\"\n [class.nath-menu-bar-mobile-arrow--rotated]=\"activeItem() === item\"\n />\n }\n </div>\n\n @if (item.items && item.items.length > 0 && activeItem() === item) {\n <ul class=\"nath-menu-bar-mobile-submenu\">\n @for (subItem of item.items; track subItem.label; let subIndex = $index) {\n <li\n class=\"nath-menu-bar-mobile-submenu-item\"\n [class.nath-menu-bar-mobile-submenu-item--disabled]=\"subItem.disabled\"\n (click)=\"handleItemClick(subItem, subIndex, $event)\"\n (keydown.enter)=\"handleItemClick(subItem, subIndex, $event)\"\n >\n <span class=\"nath-menu-bar-mobile-submenu-item-text\">\n @if (subItem.icon) {\n @if (isLucideIconComponent(subItem.icon)) {\n <svg [lucideIcon]=\"subItem.icon\" [size]=\"16\" />\n } @else {\n <i [class]=\"subItem.icon\"></i>\n }\n }\n <span>{{ subItem.label }}</span>\n </span>\n </li>\n }\n </ul>\n }\n </li>\n }\n </ul>\n </div>\n}\n<nath-menu\n #dropdownMenu\n [model]=\"activeItem()?.items ?? []\"\n [positionX]=\"'left'\"\n [positionY]=\"'bottom'\"\n panelStyleClass=\"nath-menu-bar-dropdown\"\n/>\n", styles: ["nath-menu-bar,.nath-menu-bar-theme{--nath-menu-bar-bg: #ffffff;--nath-menu-bar-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-bar-text: var(--color-gray-700, oklch(37.1% .021 264.444));--nath-menu-bar-hover-bg: var(--color-zinc-100, oklch(96.7% .003 264.542));--nath-menu-bar-active-bg: var(--color-zinc-100, oklch(96.7% .003 264.542));--nath-menu-bar-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--nath-menu-bar-font-size: .875rem;--nath-menu-bar-height: 3rem;--nath-menu-bar-z-index: 1000}.dark nath-menu-bar,.dark .nath-menu-bar-theme{--nath-menu-bar-bg: var(--color-zinc-900, oklch(21% .006 285.885));--nath-menu-bar-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-bar-text: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-bar-hover-bg: var(--color-zinc-800, oklch(27.4% .006 286.033));--nath-menu-bar-active-bg: var(--color-zinc-800, oklch(27.4% .006 286.033))}.nath-menu-bar{position:relative;display:flex;align-items:center;justify-content:space-between;background-color:var(--nath-menu-bar-bg);border-bottom:1px solid var(--nath-menu-bar-border);height:var(--nath-menu-bar-height);padding:0 1rem;font-size:var(--nath-menu-bar-font-size);color:var(--nath-menu-bar-text);z-index:var(--nath-menu-bar-z-index)}.nath-menu-bar-list{display:flex;list-style:none;margin:0;padding:0;gap:.5rem}.nath-menu-bar-item{position:relative;display:flex;align-items:center;padding:.5rem .75rem;border-radius:.375rem;cursor:pointer;transition:background-color .15s ease;outline:none}.nath-menu-bar-item:hover:not(.nath-menu-bar-item--disabled){background-color:var(--nath-menu-bar-hover-bg)}.nath-menu-bar-item--active{background-color:var(--nath-menu-bar-active-bg)}.nath-menu-bar-item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.nath-menu-bar-item--focused{box-shadow:0 0 0 2px var(--color-blue-500, oklch(.5 .15 250))}.nath-menu-bar-item-content{display:flex;align-items:center;gap:.5rem;color:var(--nath-menu-bar-text);text-decoration:none}.nath-menu-bar-item-content svg{flex-shrink:0}.nath-menu-bar-arrow{margin-left:.25rem;color:var(--nath-menu-bar-text);opacity:.7;transition:transform .2s ease}.nath-menu-bar-item--active .nath-menu-bar-arrow{transform:rotate(180deg)}.nath-menu-bar-link{position:absolute;inset:0;text-decoration:none}.nath-menu-bar-toggle{display:none;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;padding:0;background:transparent;border:none;border-radius:.375rem;cursor:pointer;color:var(--nath-menu-bar-text);transition:background-color .15s ease}.nath-menu-bar-toggle:hover{background-color:var(--nath-menu-bar-hover-bg)}.nath-menu-bar-toggle:focus{outline:none;box-shadow:0 0 0 2px var(--color-blue-500, oklch(.5 .15 250))}.nath-menu-bar-mobile-overlay{position:fixed;inset:0;background-color:#00000080;z-index:calc(var(--nath-menu-bar-z-index) - 1)}.nath-menu-bar-mobile-panel{position:fixed;top:var(--nath-menu-bar-height);left:0;right:0;bottom:0;background-color:var(--nath-menu-bar-bg);overflow-y:auto;z-index:var(--nath-menu-bar-z-index);padding:1rem}.nath-menu-bar-mobile-list{list-style:none;margin:0;padding:0}.nath-menu-bar-mobile-item{border-bottom:1px solid var(--nath-menu-bar-border)}.nath-menu-bar-mobile-item:last-child{border-bottom:none}.nath-menu-bar-mobile-item--disabled{opacity:.5;pointer-events:none}.nath-menu-bar-mobile-item-content{display:flex;align-items:center;justify-content:space-between;padding:1rem;cursor:pointer;transition:background-color .15s ease}.nath-menu-bar-mobile-item-content:hover{background-color:var(--nath-menu-bar-hover-bg)}.nath-menu-bar-mobile-item-text{display:flex;align-items:center;gap:.75rem;font-weight:500}.nath-menu-bar-mobile-arrow{transition:transform .2s ease}.nath-menu-bar-mobile-arrow--rotated{transform:rotate(180deg)}.nath-menu-bar-mobile-submenu{list-style:none;margin:0;padding:0 0 0 1.5rem;background-color:var(--nath-menu-bar-hover-bg)}.nath-menu-bar-mobile-submenu-item{padding:.75rem 1rem;cursor:pointer;transition:background-color .15s ease;border-bottom:1px solid var(--nath-menu-bar-border)}.nath-menu-bar-mobile-submenu-item:last-child{border-bottom:none}.nath-menu-bar-mobile-submenu-item:hover{background-color:var(--nath-menu-bar-active-bg)}.nath-menu-bar-mobile-submenu-item--disabled{opacity:.5;pointer-events:none}.nath-menu-bar-mobile-submenu-item-text{display:flex;align-items:center;gap:.75rem}@media(max-width:768px){.nath-menu-bar-list{display:none}.nath-menu-bar-toggle{display:flex}.nath-menu-bar-dropdown{display:none}}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "browserUrl", "routerLink"] }, { kind: "component", type: NathMenu, selector: "nath-menu", inputs: ["model", "styleClass", "panelStyleClass", "positionX", "positionY", "inline", "flat"], outputs: ["modelChange", "styleClassChange", "panelStyleClassChange", "whenHide"] }, { kind: "component", type: LucideMenu, selector: "svg[lucideMenu]" }, { kind: "component", type: LucideX, selector: "svg[lucideX]" }, { kind: "component", type: LucideChevronDown, selector: "svg[lucideChevronDown]" }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], encapsulation: i0.ViewEncapsulation.None });
1993
+ }
1994
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathMenuBar, decorators: [{
1995
+ type: Component,
1996
+ args: [{ selector: 'nath-menu-bar', imports: [
1997
+ CommonModule,
1998
+ RouterLink,
1999
+ NathMenu,
2000
+ LucideMenu,
2001
+ LucideX,
2002
+ LucideChevronDown,
2003
+ LucideDynamicIcon,
2004
+ ], host: {
2005
+ '[class]': `styleClass()`,
2006
+ '(document:click)': `handleDocumentClick($event)`,
2007
+ }, encapsulation: ViewEncapsulation.None, template: "<nav #menuBar class=\"nath-menu-bar-theme nath-menu-bar\" role=\"menubar\">\n <!-- Desktop Menu Bar -->\n <ul class=\"nath-menu-bar-list\">\n @for (item of model(); track item.label; let index = $index) {\n <li\n class=\"nath-menu-bar-item\"\n [class.nath-menu-bar-item--active]=\"activeItem() === item\"\n [class.nath-menu-bar-item--disabled]=\"item.disabled\"\n [class.nath-menu-bar-item--focused]=\"focusedIndex() === index\"\n [attr.tabindex]=\"item.disabled ? -1 : 0\"\n [attr.role]=\"item.items && item.items.length > 0 ? 'menuitem' : 'menuitem'\"\n [attr.aria-haspopup]=\"item.items && item.items.length > 0 ? 'true' : 'false'\"\n [attr.aria-expanded]=\"activeItem() === item ? 'true' : 'false'\"\n (mouseenter)=\"handleItemHover(item, index, $event)\"\n (click)=\"handleItemClick(item, index, $event)\"\n (keydown)=\"handleKeyDown($event)\"\n >\n <span class=\"nath-menu-bar-item-content\">\n @if (item.icon) {\n @if (isLucideIconComponent(item.icon)) {\n <svg [lucideIcon]=\"item.icon\" [size]=\"16\" />\n } @else {\n <i [class]=\"item.icon\"></i>\n }\n }\n @if (item.escape === false) {\n <span [innerHTML]=\"getMenuLabel(item)\"></span>\n } @else {\n <span>{{ item.label }}</span>\n }\n @if (item.items && item.items.length > 0) {\n <svg lucideChevronDown [size]=\"14\" class=\"nath-menu-bar-arrow\" />\n }\n </span>\n\n @if (item.routerLink) {\n <a\n [routerLink]=\"item.routerLink\"\n [queryParams]=\"item.queryParams\"\n [fragment]=\"item.fragment\"\n [queryParamsHandling]=\"item.queryParamsHandling\"\n [preserveFragment]=\"item.preserveFragment\"\n [skipLocationChange]=\"item.skipLocationChange\"\n [replaceUrl]=\"item.replaceUrl\"\n [state]=\"item.state\"\n [attr.target]=\"item.target\"\n class=\"nath-menu-bar-link\"\n ><span></span\n ></a>\n } @else if (item.url) {\n <a [href]=\"item.url\" [attr.target]=\"item.target || '_blank'\" class=\"nath-menu-bar-link\"\n ><span></span\n ></a>\n }\n </li>\n }\n </ul>\n\n <!-- Mobile Menu Button -->\n <button\n class=\"nath-menu-bar-toggle\"\n [class.nath-menu-bar-toggle--active]=\"isMobileMenuOpen()\"\n (click)=\"toggleMobileMenu()\"\n [attr.aria-label]=\"isMobileMenuOpen() ? 'Close menu' : 'Open menu'\"\n [attr.aria-expanded]=\"isMobileMenuOpen()\"\n >\n @if (isMobileMenuOpen()) {\n <svg lucideX [size]=\"24\" />\n } @else {\n <svg lucideMenu [size]=\"24\" />\n }\n </button>\n</nav>\n\n<!-- Mobile Menu Overlay -->\n@if (isMobileMenuOpen()) {\n <div\n class=\"nath-menu-bar-mobile-overlay\"\n (click)=\"toggleMobileMenu()\"\n (keydown.enter)=\"toggleMobileMenu()\"\n ></div>\n}\n\n<!-- Mobile Menu Panel -->\n@if (isMobileMenuOpen()) {\n <div class=\"nath-menu-bar-mobile-panel\">\n <ul class=\"nath-menu-bar-mobile-list\">\n @for (item of model(); track item.label; let index = $index) {\n <li\n class=\"nath-menu-bar-mobile-item\"\n [class.nath-menu-bar-mobile-item--disabled]=\"item.disabled\"\n [class.nath-menu-bar-mobile-item--expanded]=\"activeItem() === item\"\n >\n <div\n class=\"nath-menu-bar-mobile-item-content\"\n (click)=\"handleItemClick(item, index, $event)\"\n (keydown.enter)=\"handleItemClick(item, index, $event)\"\n >\n <span class=\"nath-menu-bar-mobile-item-text\">\n @if (item.icon) {\n @if (isLucideIconComponent(item.icon)) {\n <svg [lucideIcon]=\"item.icon\" [size]=\"18\" />\n } @else {\n <i [class]=\"item.icon\"></i>\n }\n }\n <span>{{ item.label }}</span>\n </span>\n @if (item.items && item.items.length > 0) {\n <svg\n lucideChevronDown\n [size]=\"16\"\n class=\"nath-menu-bar-mobile-arrow\"\n [class.nath-menu-bar-mobile-arrow--rotated]=\"activeItem() === item\"\n />\n }\n </div>\n\n @if (item.items && item.items.length > 0 && activeItem() === item) {\n <ul class=\"nath-menu-bar-mobile-submenu\">\n @for (subItem of item.items; track subItem.label; let subIndex = $index) {\n <li\n class=\"nath-menu-bar-mobile-submenu-item\"\n [class.nath-menu-bar-mobile-submenu-item--disabled]=\"subItem.disabled\"\n (click)=\"handleItemClick(subItem, subIndex, $event)\"\n (keydown.enter)=\"handleItemClick(subItem, subIndex, $event)\"\n >\n <span class=\"nath-menu-bar-mobile-submenu-item-text\">\n @if (subItem.icon) {\n @if (isLucideIconComponent(subItem.icon)) {\n <svg [lucideIcon]=\"subItem.icon\" [size]=\"16\" />\n } @else {\n <i [class]=\"subItem.icon\"></i>\n }\n }\n <span>{{ subItem.label }}</span>\n </span>\n </li>\n }\n </ul>\n }\n </li>\n }\n </ul>\n </div>\n}\n<nath-menu\n #dropdownMenu\n [model]=\"activeItem()?.items ?? []\"\n [positionX]=\"'left'\"\n [positionY]=\"'bottom'\"\n panelStyleClass=\"nath-menu-bar-dropdown\"\n/>\n", styles: ["nath-menu-bar,.nath-menu-bar-theme{--nath-menu-bar-bg: #ffffff;--nath-menu-bar-border: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-bar-text: var(--color-gray-700, oklch(37.1% .021 264.444));--nath-menu-bar-hover-bg: var(--color-zinc-100, oklch(96.7% .003 264.542));--nath-menu-bar-active-bg: var(--color-zinc-100, oklch(96.7% .003 264.542));--nath-menu-bar-shadow: 0 4px 6px -1px rgba(0, 0, 0, .1), 0 2px 4px -1px rgba(0, 0, 0, .06);--nath-menu-bar-font-size: .875rem;--nath-menu-bar-height: 3rem;--nath-menu-bar-z-index: 1000}.dark nath-menu-bar,.dark .nath-menu-bar-theme{--nath-menu-bar-bg: var(--color-zinc-900, oklch(21% .006 285.885));--nath-menu-bar-border: var(--color-zinc-700, oklch(37% .013 285.805));--nath-menu-bar-text: var(--color-zinc-200, oklch(92% .004 286.32));--nath-menu-bar-hover-bg: var(--color-zinc-800, oklch(27.4% .006 286.033));--nath-menu-bar-active-bg: var(--color-zinc-800, oklch(27.4% .006 286.033))}.nath-menu-bar{position:relative;display:flex;align-items:center;justify-content:space-between;background-color:var(--nath-menu-bar-bg);border-bottom:1px solid var(--nath-menu-bar-border);height:var(--nath-menu-bar-height);padding:0 1rem;font-size:var(--nath-menu-bar-font-size);color:var(--nath-menu-bar-text);z-index:var(--nath-menu-bar-z-index)}.nath-menu-bar-list{display:flex;list-style:none;margin:0;padding:0;gap:.5rem}.nath-menu-bar-item{position:relative;display:flex;align-items:center;padding:.5rem .75rem;border-radius:.375rem;cursor:pointer;transition:background-color .15s ease;outline:none}.nath-menu-bar-item:hover:not(.nath-menu-bar-item--disabled){background-color:var(--nath-menu-bar-hover-bg)}.nath-menu-bar-item--active{background-color:var(--nath-menu-bar-active-bg)}.nath-menu-bar-item--disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.nath-menu-bar-item--focused{box-shadow:0 0 0 2px var(--color-blue-500, oklch(.5 .15 250))}.nath-menu-bar-item-content{display:flex;align-items:center;gap:.5rem;color:var(--nath-menu-bar-text);text-decoration:none}.nath-menu-bar-item-content svg{flex-shrink:0}.nath-menu-bar-arrow{margin-left:.25rem;color:var(--nath-menu-bar-text);opacity:.7;transition:transform .2s ease}.nath-menu-bar-item--active .nath-menu-bar-arrow{transform:rotate(180deg)}.nath-menu-bar-link{position:absolute;inset:0;text-decoration:none}.nath-menu-bar-toggle{display:none;align-items:center;justify-content:center;width:2.5rem;height:2.5rem;padding:0;background:transparent;border:none;border-radius:.375rem;cursor:pointer;color:var(--nath-menu-bar-text);transition:background-color .15s ease}.nath-menu-bar-toggle:hover{background-color:var(--nath-menu-bar-hover-bg)}.nath-menu-bar-toggle:focus{outline:none;box-shadow:0 0 0 2px var(--color-blue-500, oklch(.5 .15 250))}.nath-menu-bar-mobile-overlay{position:fixed;inset:0;background-color:#00000080;z-index:calc(var(--nath-menu-bar-z-index) - 1)}.nath-menu-bar-mobile-panel{position:fixed;top:var(--nath-menu-bar-height);left:0;right:0;bottom:0;background-color:var(--nath-menu-bar-bg);overflow-y:auto;z-index:var(--nath-menu-bar-z-index);padding:1rem}.nath-menu-bar-mobile-list{list-style:none;margin:0;padding:0}.nath-menu-bar-mobile-item{border-bottom:1px solid var(--nath-menu-bar-border)}.nath-menu-bar-mobile-item:last-child{border-bottom:none}.nath-menu-bar-mobile-item--disabled{opacity:.5;pointer-events:none}.nath-menu-bar-mobile-item-content{display:flex;align-items:center;justify-content:space-between;padding:1rem;cursor:pointer;transition:background-color .15s ease}.nath-menu-bar-mobile-item-content:hover{background-color:var(--nath-menu-bar-hover-bg)}.nath-menu-bar-mobile-item-text{display:flex;align-items:center;gap:.75rem;font-weight:500}.nath-menu-bar-mobile-arrow{transition:transform .2s ease}.nath-menu-bar-mobile-arrow--rotated{transform:rotate(180deg)}.nath-menu-bar-mobile-submenu{list-style:none;margin:0;padding:0 0 0 1.5rem;background-color:var(--nath-menu-bar-hover-bg)}.nath-menu-bar-mobile-submenu-item{padding:.75rem 1rem;cursor:pointer;transition:background-color .15s ease;border-bottom:1px solid var(--nath-menu-bar-border)}.nath-menu-bar-mobile-submenu-item:last-child{border-bottom:none}.nath-menu-bar-mobile-submenu-item:hover{background-color:var(--nath-menu-bar-active-bg)}.nath-menu-bar-mobile-submenu-item--disabled{opacity:.5;pointer-events:none}.nath-menu-bar-mobile-submenu-item-text{display:flex;align-items:center;gap:.75rem}@media(max-width:768px){.nath-menu-bar-list{display:none}.nath-menu-bar-toggle{display:flex}.nath-menu-bar-dropdown{display:none}}\n"] }]
2008
+ }], propDecorators: { model: [{ type: i0.Input, args: [{ isSignal: true, alias: "model", required: false }] }], styleClass: [{ type: i0.Input, args: [{ isSignal: true, alias: "styleClass", required: false }] }], whenCommand: [{ type: i0.Output, args: ["whenCommand"] }], menuBarElement: [{ type: i0.ViewChild, args: ['menuBar', { isSignal: true }] }], dropdownMenu: [{ type: i0.ViewChild, args: ['dropdownMenu', { isSignal: true }] }] } });
1674
2009
 
1675
2010
  let nextId$1 = 0;
1676
2011
  class NathMultiselect {
@@ -4827,7 +5162,7 @@ class NathSplitButton {
4827
5162
  </button>
4828
5163
  </div>
4829
5164
  <nath-menu [model]="menu()" [positionX]="positionX()" [positionY]="positionY()" />
4830
- `, isInline: true, styles: ["nath-split-button,.nath-split-button-theme{--nath-split-button-border: var(--color-zinc-300, oklch(83.1% .007 285.938));--nath-split-button-bg: var(--color-zinc-100, oklch(96.7% .003 286.375));--nath-split-button-text: var(--color-zinc-900, oklch(21% .006 285.885));--nath-split-button-hover-bg: var(--color-zinc-200, oklch(92% .004 286.32));--nath-split-button-active-bg: var(--color-zinc-300, oklch(83.1% .007 285.938));--nath-split-button-radius: .375rem}.dark nath-split-button,.dark .nath-split-button-theme{--nath-split-button-border: var(--color-zinc-700, oklch(37.1% .008 285.539));--nath-split-button-bg: var(--color-zinc-800, oklch(27.8% .006 285.923));--nath-split-button-text: var(--color-zinc-100, oklch(96.7% .003 286.375));--nath-split-button-hover-bg: var(--color-zinc-700, oklch(37.1% .008 285.539));--nath-split-button-active-bg: var(--color-zinc-600, oklch(44.6% .012 285.938))}nath-split-button{display:inline-block;vertical-align:middle}.nath-split-button-container{display:flex;align-items:stretch}.nath-split-button-main,.nath-split-button-trigger{display:inline-flex;align-items:center;justify-content:center;padding:.5rem .75rem;font-size:.875rem;line-height:1.25rem;font-weight:500;cursor:pointer;transition:all .2s;border:1px solid var(--nath-split-button-border);background-color:var(--nath-split-button-bg);color:var(--nath-split-button-text);outline:none;white-space:nowrap}.nath-split-button-main{border-radius:var(--nath-split-button-radius) 0 0 var(--nath-split-button-radius);border-right:none}.nath-split-button-trigger{border-radius:0 var(--nath-split-button-radius) var(--nath-split-button-radius) 0}.nath-split-button-main:hover,.nath-split-button-trigger:hover{background-color:var(--nath-split-button-hover-bg)}.nath-split-button-main:active,.nath-split-button-trigger:active{background-color:var(--nath-split-button-active-bg)}.nath-split-button-main:focus-visible,.nath-split-button-trigger:focus-visible{z-index:10;outline:2px solid var(--nath-split-button-border);outline-offset:-2px}.nath-split-button-main:disabled,.nath-split-button-trigger:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}\n"], dependencies: [{ kind: "component", type: LucideChevronDown, selector: "svg[lucideChevronDown]" }, { kind: "component", type: NathMenu, selector: "nath-menu", inputs: ["model", "styleClass", "positionX", "positionY", "inline", "flat"], outputs: ["modelChange", "styleClassChange", "whenHide"] }], encapsulation: i0.ViewEncapsulation.None });
5165
+ `, isInline: true, styles: ["nath-split-button,.nath-split-button-theme{--nath-split-button-border: var(--color-zinc-300, oklch(83.1% .007 285.938));--nath-split-button-bg: var(--color-zinc-100, oklch(96.7% .003 286.375));--nath-split-button-text: var(--color-zinc-900, oklch(21% .006 285.885));--nath-split-button-hover-bg: var(--color-zinc-200, oklch(92% .004 286.32));--nath-split-button-active-bg: var(--color-zinc-300, oklch(83.1% .007 285.938));--nath-split-button-radius: .375rem}.dark nath-split-button,.dark .nath-split-button-theme{--nath-split-button-border: var(--color-zinc-700, oklch(37.1% .008 285.539));--nath-split-button-bg: var(--color-zinc-800, oklch(27.8% .006 285.923));--nath-split-button-text: var(--color-zinc-100, oklch(96.7% .003 286.375));--nath-split-button-hover-bg: var(--color-zinc-700, oklch(37.1% .008 285.539));--nath-split-button-active-bg: var(--color-zinc-600, oklch(44.6% .012 285.938))}nath-split-button{display:inline-block;vertical-align:middle}.nath-split-button-container{display:flex;align-items:stretch}.nath-split-button-main,.nath-split-button-trigger{display:inline-flex;align-items:center;justify-content:center;padding:.5rem .75rem;font-size:.875rem;line-height:1.25rem;font-weight:500;cursor:pointer;transition:all .2s;border:1px solid var(--nath-split-button-border);background-color:var(--nath-split-button-bg);color:var(--nath-split-button-text);outline:none;white-space:nowrap}.nath-split-button-main{border-radius:var(--nath-split-button-radius) 0 0 var(--nath-split-button-radius);border-right:none}.nath-split-button-trigger{border-radius:0 var(--nath-split-button-radius) var(--nath-split-button-radius) 0}.nath-split-button-main:hover,.nath-split-button-trigger:hover{background-color:var(--nath-split-button-hover-bg)}.nath-split-button-main:active,.nath-split-button-trigger:active{background-color:var(--nath-split-button-active-bg)}.nath-split-button-main:focus-visible,.nath-split-button-trigger:focus-visible{z-index:10;outline:2px solid var(--nath-split-button-border);outline-offset:-2px}.nath-split-button-main:disabled,.nath-split-button-trigger:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}\n"], dependencies: [{ kind: "component", type: LucideChevronDown, selector: "svg[lucideChevronDown]" }, { kind: "component", type: NathMenu, selector: "nath-menu", inputs: ["model", "styleClass", "panelStyleClass", "positionX", "positionY", "inline", "flat"], outputs: ["modelChange", "styleClassChange", "panelStyleClassChange", "whenHide"] }], encapsulation: i0.ViewEncapsulation.None });
4831
5166
  }
4832
5167
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathSplitButton, decorators: [{
4833
5168
  type: Component,
@@ -5162,7 +5497,7 @@ class NathThemeSwitch {
5162
5497
  <svg [lucideIcon]="themeService.isDarkMode() ? LucideMoon : LucideSun"></svg>
5163
5498
  </button>
5164
5499
  <nath-menu #themeMenu [model]="themes" positionX="left" positionY="bottom" />
5165
- `, isInline: true, styles: ["app-theme-switch{display:inline-block}\n"], dependencies: [{ kind: "component", type: NathMenu, selector: "nath-menu", inputs: ["model", "styleClass", "positionX", "positionY", "inline", "flat"], outputs: ["modelChange", "styleClassChange", "whenHide"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.Eager, encapsulation: i0.ViewEncapsulation.None });
5500
+ `, isInline: true, styles: ["app-theme-switch{display:inline-block}\n"], dependencies: [{ kind: "component", type: NathMenu, selector: "nath-menu", inputs: ["model", "styleClass", "panelStyleClass", "positionX", "positionY", "inline", "flat"], outputs: ["modelChange", "styleClassChange", "panelStyleClassChange", "whenHide"] }, { kind: "component", type: LucideDynamicIcon, selector: "svg[lucideIcon]", inputs: ["lucideIcon"] }], changeDetection: i0.ChangeDetectionStrategy.Eager, encapsulation: i0.ViewEncapsulation.None });
5166
5501
  }
5167
5502
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImport: i0, type: NathThemeSwitch, decorators: [{
5168
5503
  type: Component,
@@ -5616,9 +5951,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.0.5", ngImpor
5616
5951
  }]
5617
5952
  }], propDecorators: { tooltipContent: [{ type: i0.Input, args: [{ isSignal: true, alias: "nathTooltip", required: false }] }], tooltipPosition: [{ type: i0.Input, args: [{ isSignal: true, alias: "tooltipPosition", required: false }] }], showDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "showDelay", required: false }] }], hideDelay: [{ type: i0.Input, args: [{ isSignal: true, alias: "hideDelay", required: false }] }] } });
5618
5953
 
5619
- function next(el, selector) {
5954
+ function nextSibling(el, selector) {
5620
5955
  const nextEl = el.nextElementSibling;
5621
- if (!selector || (nextEl && nextEl.matches(selector))) {
5956
+ if (!selector || nextEl?.matches(selector)) {
5622
5957
  return nextEl;
5623
5958
  }
5624
5959
  return null;
@@ -5649,5 +5984,5 @@ function isSortOrderValid(order) {
5649
5984
  * Generated bundle index. Do not edit.
5650
5985
  */
5651
5986
 
5652
- export { BreadcrumbService, DARK_THEME_CLASS, DIALOG_DATA, NathAutocomplete, NathBooleanControl, NathBreadcrumbs, NathCodeViewer, NathConfirmationDialog, NathConfirmationService, NathDatepicker, NathDialogContainer, NathDialogRef, NathDialogService, NathDrawer, NathFileUpload, NathFloatingLabel, NathFormField, NathImagePreview, NathMenu, NathMenuList, NathMultiselect, NathPaginatedView, NathPaginator, NathPanel, NathPickList, NathProgressBar, NathProgressCircle, NathRadioButtonGroup, NathRatingHeart, NathRatingInput, NathSelect, NathShowErrors, NathSkeleton, NathSlider, NathSortIcon, NathSplitButton, NathTabs, NathTag, NathThemeSwitch, NathToastContainer, NathToc, NathTooltipContainer, NathTooltipDirective, ORDER, RATING_MAP, THEME_CONFIG, TabDirective, TabPanelDirective, ThemeService, ToastService, getRatingColor, hasRequiredValidator, isRequired, isSortOrderValid, isTruthy, next, provideThemeConfig, rangeMinMax, rangeNotMinMax, validateAllFormFields };
5987
+ export { DARK_THEME_CLASS, DIALOG_DATA, NathAutocomplete, NathBooleanControl, NathBreadcrumbService, NathBreadcrumbs, NathCodeViewer, NathConfirmationDialog, NathConfirmationService, NathDatepicker, NathDialogContainer, NathDialogRef, NathDialogService, NathDrawer, NathFileUpload, NathFloatingLabel, NathFormField, NathImagePreview, NathMenu, NathMenuBar, NathMenuList, NathMultiselect, NathPaginatedView, NathPaginator, NathPanel, NathPickList, NathProgressBar, NathProgressCircle, NathRadioButtonGroup, NathRatingHeart, NathRatingInput, NathSelect, NathShowErrors, NathSkeleton, NathSlider, NathSortIcon, NathSplitButton, NathTabs, NathTag, NathThemeSwitch, NathToastContainer, NathToc, NathTooltipContainer, NathTooltipDirective, ORDER, RATING_MAP, THEME_CONFIG, TabDirective, TabPanelDirective, ThemeService, ToastService, getRatingColor, hasRequiredValidator, isRequired, isSortOrderValid, isTruthy, nextSibling, provideThemeConfig, rangeMinMax, rangeNotMinMax, validateAllFormFields };
5653
5988
  //# sourceMappingURL=nath-angular-ui.mjs.map