import { Component, Directive, Input, Output, EventEmitter, HostListener, ChangeDetectionStrategy, ChangeDetectorRef, signal, inject, OnDestroy, } from '@angular/core'; import { CommonModule } from '@angular/common'; // ─── Shared service to link trigger, menu, and items ────────────────────────── // We use a lightweight approach: the parent DropdownComponent holds state, // sub-components/directives receive it via injection. @Component({ selector: 'mayvio-dropdown', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: ``, host: { class: 'mv-dropdown', style: 'position:relative;display:inline-block' }, }) export class DropdownComponent implements OnDestroy { @Input() align: 'left' | 'center' | 'right' = 'left'; private _isOpen = signal(false); get isOpen(): boolean { return this._isOpen(); } private cdr = inject(ChangeDetectorRef); toggle() { this._isOpen.update((v) => !v); this.cdr.markForCheck(); } close() { this._isOpen.set(false); this.cdr.markForCheck(); } @HostListener('document:click') onDocumentClick() { // Handled separately via trigger interaction } ngOnDestroy() {} } // ─── Trigger Directive ──────────────────────────────────────────────────────── @Directive({ selector: '[mvDropdownTrigger]', standalone: true, host: { '[attr.aria-haspopup]': '"menu"', '[attr.aria-expanded]': 'dropdown.isOpen', }, }) export class DropdownTriggerDirective { dropdown = inject(DropdownComponent); @HostListener('click', ['$event']) onClick(event: MouseEvent) { event.stopPropagation(); this.dropdown.toggle(); } @HostListener('document:click') onDocumentClick() { if (this.dropdown.isOpen) { this.dropdown.close(); } } } // ─── Menu Component ─────────────────────────────────────────────────────────── @Component({ selector: 'mayvio-dropdown-menu', standalone: true, imports: [CommonModule], changeDetection: ChangeDetectionStrategy.OnPush, template: ` `, }) export class DropdownMenuComponent { dropdown = inject(DropdownComponent); } // ─── Item Component ─────────────────────────────────────────────────────────── @Component({ selector: 'mayvio-dropdown-item', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, template: ` `, }) export class DropdownItemComponent { @Input() disabled = false; @Output() itemClick = new EventEmitter(); private dropdown = inject(DropdownComponent); onItemClick(event: MouseEvent) { if (this.disabled) return; event.stopPropagation(); this.itemClick.emit(); this.dropdown.close(); } }