{
  "name": "menu",
  "type": "registry:component",
  "files": [
    {
      "name": "menu.directive.ts",
      "content": "import type { BooleanInput } from '@angular/cdk/coercion';\nimport { CdkMenuTrigger } from '@angular/cdk/menu';\nimport type { ConnectedPosition } from '@angular/cdk/overlay';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n  booleanAttribute,\n  computed,\n  Directive,\n  DOCUMENT,\n  effect,\n  ElementRef,\n  inject,\n  input,\n  type OnDestroy,\n  type OnInit,\n  PLATFORM_ID,\n  type TemplateRef,\n  untracked,\n} from '@angular/core';\n\nimport { ZardMenuManagerService } from './menu-manager.service';\nimport { MENU_POSITIONS_MAP, type ZardMenuPlacement } from './menu-positions';\n\nexport type ZardMenuTrigger = 'click' | 'hover';\n\n@Directive({\n  selector: '[z-menu]',\n  host: {\n    role: 'button',\n    '[attr.tabindex]': \"'0'\",\n    '[attr.aria-haspopup]': \"'menu'\",\n    '[attr.aria-expanded]': 'cdkTrigger.isOpen()',\n    '[attr.data-state]': \"cdkTrigger.isOpen() ? 'open': 'closed'\",\n    '[attr.data-disabled]': \"zDisabled() ? '' : undefined\",\n    '[style.cursor]': \"'pointer'\",\n  },\n  hostDirectives: [\n    {\n      directive: CdkMenuTrigger,\n      inputs: ['cdkMenuTriggerFor: zMenuTriggerFor'],\n    },\n  ],\n})\nexport class ZardMenuDirective implements OnInit, OnDestroy {\n  private static readonly MENU_CONTENT_SELECTOR = '.cdk-overlay-pane [z-menu-content]';\n\n  protected readonly cdkTrigger = inject(CdkMenuTrigger, { host: true });\n  private readonly document = inject(DOCUMENT);\n  private readonly elementRef = inject<ElementRef<HTMLElement>>(ElementRef);\n  private readonly menuManager = inject(ZardMenuManagerService);\n  private readonly platformId = inject(PLATFORM_ID);\n\n  private closeTimeout: ReturnType<typeof setTimeout> | null = null;\n  private readonly cleanupFunctions: Array<() => void> = [];\n\n  readonly zMenuTriggerFor = input.required<TemplateRef<void>>();\n  readonly zDisabled = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n  readonly zTrigger = input<ZardMenuTrigger>('click');\n  readonly zHoverDelay = input<number>(100);\n  readonly zPlacement = input<ZardMenuPlacement>('bottomLeft');\n\n  private readonly menuPositions = computed(() => this.getPositionsByPlacement(this.zPlacement()));\n\n  constructor() {\n    effect(() => {\n      const positions = this.menuPositions();\n      untracked(() => {\n        this.cdkTrigger.menuPosition = positions;\n      });\n    });\n  }\n\n  private getPositionsByPlacement(placement: ZardMenuPlacement): ConnectedPosition[] {\n    return MENU_POSITIONS_MAP[placement] || MENU_POSITIONS_MAP['bottomLeft'];\n  }\n\n  ngOnInit(): void {\n    const isMobile = this.isMobileDevice();\n\n    // If trigger is hover but device is mobile, skip hover behavior\n    // The CDK MenuTrigger will handle click by default\n    if (this.zTrigger() === 'hover' && !isMobile) {\n      this.initializeHoverBehavior();\n    }\n  }\n\n  ngOnDestroy(): void {\n    this.cancelScheduledClose();\n    this.menuManager.unregisterHoverMenu(this);\n    this.cleanupFunctions.forEach(cleanup => cleanup());\n    this.cleanupFunctions.length = 0;\n  }\n\n  close(): void {\n    this.cancelScheduledClose();\n    this.cdkTrigger.close();\n  }\n\n  private initializeHoverBehavior(): void {\n    this.setupTriggerListeners();\n    this.setupMenuOpenListener();\n  }\n\n  private setupTriggerListeners(): void {\n    const element = this.elementRef.nativeElement;\n\n    this.addEventListenerWithCleanup(element, 'mouseenter', () => {\n      if (this.zDisabled()) {\n        return;\n      }\n\n      element.focus({ preventScroll: true });\n      this.cancelScheduledClose();\n      this.menuManager.registerHoverMenu(this);\n      this.cdkTrigger.open();\n    });\n\n    this.addEventListenerWithCleanup(element, 'mouseleave', event => this.scheduleCloseIfNeeded(event as MouseEvent));\n  }\n\n  private setupMenuOpenListener(): void {\n    const openSubscription = this.cdkTrigger.opened.subscribe(() => {\n      setTimeout(() => this.setupMenuContentListeners(), 0);\n    });\n\n    const closeSubscription = this.cdkTrigger.closed.subscribe(() => {\n      this.menuManager.unregisterHoverMenu(this);\n    });\n\n    this.cleanupFunctions.push(\n      () => openSubscription.unsubscribe(),\n      () => closeSubscription.unsubscribe(),\n    );\n  }\n\n  private setupMenuContentListeners(): void {\n    const menuContent = this.document.querySelector(ZardMenuDirective.MENU_CONTENT_SELECTOR);\n    if (!menuContent) {\n      return;\n    }\n\n    this.addEventListenerWithCleanup(menuContent, 'mouseenter', () => this.cancelScheduledClose());\n    this.addEventListenerWithCleanup(menuContent, 'mouseleave', event =>\n      this.scheduleCloseIfNeeded(event as MouseEvent),\n    );\n  }\n\n  private cancelScheduledClose(): void {\n    if (this.closeTimeout) {\n      clearTimeout(this.closeTimeout);\n      this.closeTimeout = null;\n    }\n  }\n\n  private scheduleCloseIfNeeded(event: MouseEvent): void {\n    if (this.shouldKeepMenuOpen(event.relatedTarget as Element)) {\n      return;\n    }\n\n    this.scheduleMenuClose();\n  }\n\n  private shouldKeepMenuOpen(relatedTarget: Element | null): boolean {\n    if (!relatedTarget) {\n      return false;\n    }\n\n    const isMovingToTrigger = this.elementRef.nativeElement.contains(relatedTarget);\n    const isMovingToMenu = relatedTarget.closest(ZardMenuDirective.MENU_CONTENT_SELECTOR);\n    const isMovingToOtherTrigger =\n      relatedTarget.matches('[z-menu]') && !this.elementRef.nativeElement.contains(relatedTarget);\n\n    if (isMovingToOtherTrigger) {\n      return false;\n    }\n\n    return isMovingToTrigger || !!isMovingToMenu;\n  }\n\n  private scheduleMenuClose(): void {\n    this.closeTimeout = setTimeout(() => {\n      this.cdkTrigger.close();\n    }, this.zHoverDelay());\n  }\n\n  private addEventListenerWithCleanup(\n    element: Element,\n    eventType: string,\n    handler: (event: MouseEvent | Event) => void,\n    options?: AddEventListenerOptions,\n  ): void {\n    if (isPlatformBrowser(this.platformId)) {\n      element.addEventListener(eventType, handler, options);\n      this.cleanupFunctions.push(() => element.removeEventListener(eventType, handler, options));\n    }\n  }\n\n  private isMobileDevice(): boolean {\n    if (!isPlatformBrowser(this.platformId)) {\n      return false; // Default to desktop behavior on server\n    }\n\n    const window = this.document.defaultView;\n    if (!window) {\n      return false;\n    }\n\n    const { navigator } = window;\n    const hasTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;\n\n    // Check for mobile user agent\n    const mobileRegex = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i;\n    const isMobileUA = mobileRegex.test(navigator.userAgent);\n\n    // Check viewport width for small screens\n    const isSmallScreen = window.innerWidth <= 768;\n\n    return hasTouch && (isMobileUA || isSmallScreen);\n  }\n}\n"
    },
    {
      "name": "menu.variants.ts",
      "content": "import { cva, type VariantProps } from 'class-variance-authority';\n\nexport const menuContentVariants = cva([\n  'z-50 min-w-32 overflow-hidden rounded-md border bg-popover p-2 text-popover-foreground',\n  'shadow-lg animate-in data-[state=open]:animate-in data-[state=closed]:animate-out',\n  'data-[state=closed]:fade-out-0 data-[state=open]:fade-in-0 data-[state=closed]:zoom-out-95',\n  'data-[state=open]:zoom-in-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2',\n  'data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2',\n]);\n\nexport const menuItemVariants = cva(\n  [\n    'relative flex w-full cursor-default select-none items-center rounded-sm px-2 py-1.5',\n    'text-sm outline-none transition-colors hover:bg-accent hover:text-accent-foreground',\n    'focus:bg-accent focus:text-accent-foreground data-disabled:pointer-events-none',\n    'data-disabled:opacity-50 text-left [&>i]:mr-2 [&>z-icon]:mr-2 [&>ng-icon]:mr-2',\n  ],\n  {\n    variants: {\n      inset: {\n        true: 'pl-8',\n        false: '',\n      },\n      zType: {\n        default: '',\n        destructive: 'text-destructive',\n      },\n    },\n    defaultVariants: {\n      inset: false,\n    },\n  },\n);\n\nexport const submenuArrowVariants = cva([\n  'ml-auto opacity-60 transition-opacity duration-150',\n  'text-muted-foreground dark:text-gray-400',\n  'group-hover:opacity-100 group-focus:opacity-100',\n]);\n\nexport const menuLabelVariants = cva(\n  'relative flex items-center px-2 py-1.5 text-sm font-medium text-muted-foreground',\n  {\n    variants: {\n      inset: {\n        true: 'pl-8',\n        false: '',\n      },\n    },\n    defaultVariants: {\n      inset: false,\n    },\n  },\n);\n\nexport const menuShortcutVariants = cva('ml-auto text-xs tracking-widest text-muted-foreground');\n\nexport type ZardMenuItemTypeVariants = NonNullable<VariantProps<typeof menuItemVariants>['zType']>;\n"
    },
    {
      "name": "context-menu.directive.ts",
      "content": "import { CdkContextMenuTrigger } from '@angular/cdk/menu';\nimport { DestroyRef, Directive, DOCUMENT, ElementRef, inject, input, type TemplateRef } from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\nimport { noopFn } from '@/shared/utils/merge-classes';\n\n@Directive({\n  selector: '[z-context-menu]',\n  host: {\n    'data-slot': 'context-menu-trigger',\n    '[attr.tabindex]': \"'0'\",\n    '[style.cursor]': \"'context-menu'\",\n    '[attr.aria-haspopup]': \"'menu'\",\n    '[attr.aria-expanded]': 'cdkTrigger.isOpen()',\n    '[attr.data-state]': \"cdkTrigger.isOpen() ? 'open': 'closed'\",\n    '(contextmenu)': 'noopFn()',\n    '(keydown)': 'handleKeyDown($event)',\n  },\n  hostDirectives: [\n    {\n      directive: CdkContextMenuTrigger,\n      inputs: ['cdkContextMenuTriggerFor: zContextMenuTriggerFor'],\n    },\n  ],\n})\nexport class ZardContextMenuDirective {\n  protected readonly cdkTrigger = inject(CdkContextMenuTrigger, { host: true });\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly document = inject(DOCUMENT);\n  private readonly elementRef = inject(ElementRef);\n\n  readonly zContextMenuTriggerFor = input.required<TemplateRef<void>>();\n  noopFn = noopFn;\n\n  constructor() {\n    this.cdkTrigger.menuPosition = [\n      {\n        originX: 'start',\n        originY: 'top',\n        overlayX: 'start',\n        overlayY: 'top',\n      },\n    ];\n    this.cdkTrigger.opened.pipe(takeUntilDestroyed(this.destroyRef)).subscribe(() => this.attachCloseListeners());\n  }\n\n  protected handleKeyDown(event: KeyboardEvent): void {\n    if (event.key === 'ContextMenu' || (event.shiftKey && event.key === 'F10')) {\n      event.preventDefault();\n      this.open();\n    }\n  }\n\n  private open(coordinates?: { x: number; y: number }): void {\n    const coords = coordinates || this.getDefaultCoordinates();\n    this.cdkTrigger.open(coords);\n  }\n\n  private getDefaultCoordinates(): { x: number; y: number } {\n    const rect = this.elementRef.nativeElement.getBoundingClientRect();\n    return {\n      x: rect.left + rect.width / 2,\n      y: rect.top + rect.height / 2,\n    };\n  }\n\n  private attachCloseListeners(): void {\n    const closeMenu = () => {\n      if (this.cdkTrigger.isOpen()) {\n        this.cdkTrigger.close();\n      }\n    };\n\n    const window = this.document.defaultView;\n    if (window) {\n      window.addEventListener('scroll', closeMenu, { passive: true });\n      window.addEventListener('resize', closeMenu);\n\n      const cleanup = () => {\n        window.removeEventListener('scroll', closeMenu);\n        window.removeEventListener('resize', closeMenu);\n      };\n\n      const unregisterFn = this.destroyRef.onDestroy(cleanup);\n\n      const menuClosed = this.cdkTrigger.closed.subscribe(() => {\n        unregisterFn();\n        cleanup();\n        menuClosed.unsubscribe();\n      });\n    }\n  }\n}\n"
    },
    {
      "name": "menu-content.directive.ts",
      "content": "import { CdkTrapFocus } from '@angular/cdk/a11y';\nimport { CdkMenu } from '@angular/cdk/menu';\nimport { computed, Directive, inject, input, type OnInit } from '@angular/core';\n\nimport type { ClassValue } from 'clsx';\n\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\nimport { menuContentVariants } from './menu.variants';\n\n@Directive({\n  selector: '[z-menu-content]',\n  host: {\n    '[class]': 'classes()',\n    tabindex: '0',\n  },\n  hostDirectives: [CdkMenu, CdkTrapFocus],\n})\nexport class ZardMenuContentDirective implements OnInit {\n  private cdkTrapFocus = inject(CdkTrapFocus);\n  readonly class = input<ClassValue>('');\n\n  protected readonly classes = computed(() => mergeClasses(menuContentVariants(), this.class()));\n\n  ngOnInit(): void {\n    this.cdkTrapFocus.enabled = true;\n    this.cdkTrapFocus.autoCapture = true;\n  }\n}\n"
    },
    {
      "name": "menu-item.directive.ts",
      "content": "import type { BooleanInput } from '@angular/cdk/coercion';\nimport { CdkMenuItem } from '@angular/cdk/menu';\nimport { booleanAttribute, computed, Directive, effect, inject, input, signal, untracked } from '@angular/core';\n\nimport type { ClassValue } from 'clsx';\n\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\nimport { menuItemVariants, type ZardMenuItemTypeVariants } from './menu.variants';\n\n@Directive({\n  selector: 'button[z-menu-item], [z-menu-item]',\n  host: {\n    '[class]': 'classes()',\n    '[attr.data-orientation]': \"'horizontal'\",\n    '[attr.data-state]': 'isOpenState()',\n    '[attr.aria-disabled]': \"disabledState() ? '' : undefined\",\n    '[attr.data-disabled]': \"disabledState() ? '' : undefined\",\n    '[attr.data-highlighted]': \"highlightedState() ? '' : undefined\",\n    '(focus)': 'onFocus()',\n    '(blur)': 'onBlur()',\n    '(pointermove)': 'onPointerMove($event)',\n    '(click)': 'onClick($event)',\n    '(keydown.enter)': 'onClick($event)',\n    '(keydown.space)': 'onClick($event)',\n  },\n  hostDirectives: [\n    {\n      directive: CdkMenuItem,\n      outputs: ['cdkMenuItemTriggered: menuItemTriggered'],\n    },\n  ],\n})\nexport class ZardMenuItemDirective {\n  private readonly cdkMenuItem = inject(CdkMenuItem, { host: true });\n\n  readonly zDisabled = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n  readonly zInset = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n  readonly zType = input<ZardMenuItemTypeVariants>('default');\n  readonly class = input<ClassValue>('');\n\n  private readonly isFocused = signal(false);\n\n  protected readonly disabledState = computed(() => this.zDisabled());\n\n  protected readonly isOpenState = computed(() => this.cdkMenuItem.isMenuOpen());\n\n  protected readonly highlightedState = computed(() => this.isFocused());\n\n  protected readonly classes = computed(() =>\n    mergeClasses(\n      menuItemVariants({\n        inset: this.zInset(),\n        zType: this.zType(),\n      }),\n      this.class(),\n    ),\n  );\n\n  constructor() {\n    effect(() => {\n      const disabled = this.zDisabled();\n      untracked(() => {\n        this.cdkMenuItem.disabled = disabled;\n      });\n    });\n  }\n\n  onFocus(): void {\n    if (!this.zDisabled()) {\n      this.isFocused.set(true);\n    }\n  }\n\n  onBlur(): void {\n    this.isFocused.set(false);\n  }\n\n  onPointerMove(event: PointerEvent) {\n    if (event.defaultPrevented || !(event.pointerType === 'mouse')) {\n      return;\n    }\n\n    if (!this.zDisabled()) {\n      const item = event.currentTarget;\n      (item as HTMLElement)?.focus({ preventScroll: true });\n    }\n  }\n\n  onClick(event: Event) {\n    if (this.disabledState()) {\n      event.preventDefault();\n      event.stopPropagation();\n    }\n  }\n}\n"
    },
    {
      "name": "menu-manager.service.ts",
      "content": "import { Injectable } from '@angular/core';\n\nimport type { ZardMenuDirective } from './menu.directive';\n\n@Injectable({\n  providedIn: 'root',\n})\nexport class ZardMenuManagerService {\n  private activeHoverMenu: ZardMenuDirective | null = null;\n\n  registerHoverMenu(menu: ZardMenuDirective): void {\n    if (this.activeHoverMenu && this.activeHoverMenu !== menu) {\n      this.activeHoverMenu.close();\n    }\n    this.activeHoverMenu = menu;\n  }\n\n  unregisterHoverMenu(menu: ZardMenuDirective): void {\n    if (this.activeHoverMenu === menu) {\n      this.activeHoverMenu = null;\n    }\n  }\n\n  closeActiveMenu(): void {\n    if (this.activeHoverMenu) {\n      this.activeHoverMenu.close();\n      this.activeHoverMenu = null;\n    }\n  }\n}\n"
    },
    {
      "name": "menu.imports.ts",
      "content": "import { ZardContextMenuDirective } from '@/shared/components/menu/context-menu.directive';\nimport { ZardMenuContentDirective } from '@/shared/components/menu/menu-content.directive';\nimport { ZardMenuItemDirective } from '@/shared/components/menu/menu-item.directive';\nimport { ZardMenuLabelComponent } from '@/shared/components/menu/menu-label.component';\nimport { ZardMenuShortcutComponent } from '@/shared/components/menu/menu-shortcut.component';\nimport { ZardMenuDirective } from '@/shared/components/menu/menu.directive';\n\nexport const ZardMenuImports = [\n  ZardContextMenuDirective,\n  ZardMenuContentDirective,\n  ZardMenuItemDirective,\n  ZardMenuDirective,\n  ZardMenuLabelComponent,\n  ZardMenuShortcutComponent,\n] as const;\n"
    },
    {
      "name": "menu-positions.ts",
      "content": "import type { ConnectedPosition } from '@angular/cdk/overlay';\n\nexport const MENU_POSITIONS_MAP: { [key: string]: ConnectedPosition[] } = {\n  bottomLeft: [\n    {\n      originX: 'start',\n      originY: 'bottom',\n      overlayX: 'start',\n      overlayY: 'top',\n      offsetY: 8,\n    },\n    {\n      originX: 'start',\n      originY: 'top',\n      overlayX: 'start',\n      overlayY: 'bottom',\n      offsetY: -8,\n    },\n  ],\n  bottomCenter: [\n    {\n      originX: 'center',\n      originY: 'bottom',\n      overlayX: 'center',\n      overlayY: 'top',\n      offsetY: 8,\n    },\n    {\n      originX: 'center',\n      originY: 'top',\n      overlayX: 'center',\n      overlayY: 'bottom',\n      offsetY: -8,\n    },\n  ],\n  bottomRight: [\n    {\n      originX: 'end',\n      originY: 'bottom',\n      overlayX: 'end',\n      overlayY: 'top',\n      offsetY: 8,\n    },\n    {\n      originX: 'end',\n      originY: 'top',\n      overlayX: 'end',\n      overlayY: 'bottom',\n      offsetY: -8,\n    },\n  ],\n  topLeft: [\n    {\n      originX: 'start',\n      originY: 'top',\n      overlayX: 'start',\n      overlayY: 'bottom',\n      offsetY: -8,\n    },\n    {\n      originX: 'start',\n      originY: 'bottom',\n      overlayX: 'start',\n      overlayY: 'top',\n      offsetY: 8,\n    },\n  ],\n  topCenter: [\n    {\n      originX: 'center',\n      originY: 'top',\n      overlayX: 'center',\n      overlayY: 'bottom',\n      offsetY: -8,\n    },\n    {\n      originX: 'center',\n      originY: 'bottom',\n      overlayX: 'center',\n      overlayY: 'top',\n      offsetY: 8,\n    },\n  ],\n  topRight: [\n    {\n      originX: 'end',\n      originY: 'top',\n      overlayX: 'end',\n      overlayY: 'bottom',\n      offsetY: -8,\n    },\n    {\n      originX: 'end',\n      originY: 'bottom',\n      overlayX: 'end',\n      overlayY: 'top',\n      offsetY: 8,\n    },\n  ],\n  leftTop: [\n    {\n      originX: 'start',\n      originY: 'top',\n      overlayX: 'end',\n      overlayY: 'top',\n      offsetX: -8,\n    },\n    {\n      originX: 'end',\n      originY: 'top',\n      overlayX: 'start',\n      overlayY: 'top',\n      offsetX: 8,\n    },\n  ],\n  leftCenter: [\n    {\n      originX: 'start',\n      originY: 'center',\n      overlayX: 'end',\n      overlayY: 'center',\n      offsetX: -8,\n    },\n    {\n      originX: 'end',\n      originY: 'center',\n      overlayX: 'start',\n      overlayY: 'center',\n      offsetX: 8,\n    },\n  ],\n  leftBottom: [\n    {\n      originX: 'start',\n      originY: 'bottom',\n      overlayX: 'end',\n      overlayY: 'bottom',\n      offsetX: -8,\n    },\n    {\n      originX: 'end',\n      originY: 'bottom',\n      overlayX: 'start',\n      overlayY: 'bottom',\n      offsetX: 8,\n    },\n  ],\n  rightTop: [\n    {\n      originX: 'end',\n      originY: 'top',\n      overlayX: 'start',\n      overlayY: 'top',\n      offsetX: 8,\n    },\n    {\n      originX: 'start',\n      originY: 'top',\n      overlayX: 'end',\n      overlayY: 'top',\n      offsetX: -8,\n    },\n  ],\n  rightCenter: [\n    {\n      originX: 'end',\n      originY: 'center',\n      overlayX: 'start',\n      overlayY: 'center',\n      offsetX: 8,\n    },\n    {\n      originX: 'start',\n      originY: 'center',\n      overlayX: 'end',\n      overlayY: 'center',\n      offsetX: -8,\n    },\n  ],\n  rightBottom: [\n    {\n      originX: 'end',\n      originY: 'bottom',\n      overlayX: 'start',\n      overlayY: 'bottom',\n      offsetX: 8,\n    },\n    {\n      originX: 'start',\n      originY: 'bottom',\n      overlayX: 'end',\n      overlayY: 'bottom',\n      offsetX: -8,\n    },\n  ],\n};\n\nexport type ZardMenuPlacement =\n  | 'bottomLeft'\n  | 'bottomCenter'\n  | 'bottomRight'\n  | 'topLeft'\n  | 'topCenter'\n  | 'topRight'\n  | 'leftTop'\n  | 'leftCenter'\n  | 'leftBottom'\n  | 'rightTop'\n  | 'rightCenter'\n  | 'rightBottom';\n"
    },
    {
      "name": "menu-label.component.ts",
      "content": "import type { BooleanInput } from '@angular/cdk/coercion';\nimport {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  input,\n  ViewEncapsulation,\n} from '@angular/core';\n\nimport type { ClassValue } from 'clsx';\n\nimport { menuLabelVariants } from '@/shared/components/menu/menu.variants';\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\n@Component({\n  selector: 'z-menu-label, [z-menu-label], z-dropdown-menu-label, [z-dropdown-menu-label]',\n  template: `\n    <ng-content />\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    '[class]': 'classes()',\n    '[attr.data-inset]': 'inset() || null',\n  },\n  exportAs: 'zMenuLabel',\n})\nexport class ZardMenuLabelComponent {\n  readonly class = input<ClassValue>('');\n  readonly inset = input<boolean, BooleanInput>(false, { transform: booleanAttribute });\n\n  protected readonly classes = computed(() =>\n    mergeClasses(\n      menuLabelVariants({\n        inset: this.inset(),\n      }),\n      this.class(),\n    ),\n  );\n}\n"
    },
    {
      "name": "menu-shortcut.component.ts",
      "content": "import { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';\n\nimport type { ClassValue } from 'clsx';\n\nimport { menuShortcutVariants } from '@/shared/components/menu/menu.variants';\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\n@Component({\n  selector: 'z-menu-shortcut, [z-menu-shortcut]',\n  template: `\n    <ng-content />\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    '[class]': 'classes()',\n  },\n  exportAs: 'zMenuShortcut',\n})\nexport class ZardMenuShortcutComponent {\n  readonly class = input<ClassValue>('');\n\n  protected readonly classes = computed(() => mergeClasses(menuShortcutVariants(), this.class()));\n}\n"
    },
    {
      "name": "index.ts",
      "content": "export * from '@/shared/components/menu/context-menu.directive';\nexport * from '@/shared/components/menu/menu-manager.service';\nexport * from '@/shared/components/menu/menu-content.directive';\nexport * from '@/shared/components/menu/menu-item.directive';\nexport * from '@/shared/components/menu/menu.directive';\nexport * from '@/shared/components/menu/menu.variants';\nexport * from '@/shared/components/menu/menu.imports';\nexport * from '@/shared/components/menu/menu-positions';\nexport * from '@/shared/components/menu/menu-shortcut.component';\nexport * from '@/shared/components/menu/menu-label.component';\n"
    }
  ],
  "demos": [
    {
      "name": "context-menu.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideChevronRight } from '@ng-icons/lucide';\n\nimport { ZardMenuImports } from '@/shared/components/menu/menu.imports';\nimport { ZardSeparatorComponent } from '@/shared/components/separator';\n\n@Component({\n  selector: 'z-demo-context-menu',\n  imports: [ZardMenuImports, ZardSeparatorComponent, NgIcon],\n  template: `\n    <div\n      z-context-menu\n      [zContextMenuTriggerFor]=\"contextMenu\"\n      class=\"flex h-38 w-75 items-center justify-center rounded-md border border-dashed text-sm\"\n    >\n      Right click here\n    </div>\n\n    <ng-template #contextMenu>\n      <div z-menu-content class=\"w-48\">\n        <button type=\"button\" z-menu-item (click)=\"log('Back')\">\n          Back\n          <z-menu-shortcut>⌘[</z-menu-shortcut>\n        </button>\n        <button type=\"button\" z-menu-item (click)=\"log('Forward')\" zDisabled>\n          Forward\n          <z-menu-shortcut>⌘]</z-menu-shortcut>\n        </button>\n        <button type=\"button\" z-menu-item (click)=\"log('Reload')\">\n          Reload\n          <z-menu-shortcut>⌘R</z-menu-shortcut>\n        </button>\n        <button\n          type=\"button\"\n          z-menu-item\n          z-menu\n          [zMenuTriggerFor]=\"moreTools\"\n          zPlacement=\"rightTop\"\n          class=\"justify-between\"\n        >\n          <div class=\"flex items-center\">More Tools</div>\n          <ng-icon name=\"lucideChevronRight\" />\n        </button>\n        <z-separator class=\"my-2\" />\n        <z-menu-label>People</z-menu-label>\n        <button type=\"button\" z-menu-item (click)=\"log('Pedro Duarte')\">Pedro Duarte</button>\n        <button type=\"button\" z-menu-item (click)=\"log('Colm Tuite')\">Colm Tuite</button>\n      </div>\n    </ng-template>\n\n    <ng-template #moreTools>\n      <div z-menu-content class=\"w-48\">\n        <button type=\"button\" z-menu-item (click)=\"log('Save Page')\">Save Page...</button>\n        <button type=\"button\" z-menu-item (click)=\"log('Create Shortcut')\">Create Shortcut...</button>\n        <button type=\"button\" z-menu-item (click)=\"log('Name Window')\">Name Window...</button>\n        <z-separator class=\"my-2\" />\n        <button type=\"button\" z-menu-item (click)=\"log('Developer Tools')\">Developer Tools</button>\n        <z-separator class=\"my-2\" />\n        <button type=\"button\" z-menu-item zType=\"destructive\" (click)=\"log('Delete')\">Delete</button>\n      </div>\n    </ng-template>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [provideIcons({ lucideChevronRight })],\n})\nexport class ZardDemoContextMenu {\n  log(item: string) {\n    console.log('Navigate to:', item);\n  }\n}\n"
    },
    {
      "name": "default.ts",
      "content": "import { Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport {\n  lucideBookOpen,\n  lucideChevronDown,\n  lucideChevronRight,\n  lucideFileText,\n  lucideInfo,\n  lucideUsers,\n} from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '@/shared/components/button';\nimport { ZardMenuImports } from '@/shared/components/menu/menu.imports';\nimport { ZardSeparatorComponent } from '@/shared/components/separator';\n\n@Component({\n  selector: 'zard-demo-menu-default',\n  imports: [ZardMenuImports, ZardButtonComponent, ZardSeparatorComponent, NgIcon],\n  template: `\n    <nav class=\"flex items-center justify-between p-4\">\n      <div class=\"flex items-center space-x-6\">\n        <div class=\"flex items-center space-x-1\">\n          <div class=\"relative\">\n            <button type=\"button\" z-button zType=\"ghost\" z-menu zTrigger=\"hover\" [zMenuTriggerFor]=\"productsMenu\">\n              Products\n              <ng-icon name=\"lucideChevronDown\" class=\"ml-1\" />\n            </button>\n\n            <ng-template #productsMenu>\n              <div z-menu-content class=\"w-48\">\n                <button type=\"button\" z-menu-item (click)=\"log('Analytics')\">Analytics</button>\n                <button type=\"button\" z-menu-item (click)=\"log('Dashboard')\">Dashboard</button>\n                <button type=\"button\" z-menu-item (click)=\"log('Reports')\">Reports</button>\n                <button type=\"button\" z-menu-item zDisabled (click)=\"log('Insights')\">Insights</button>\n              </div>\n            </ng-template>\n          </div>\n\n          <div class=\"relative\">\n            <button type=\"button\" z-button zType=\"ghost\" z-menu zTrigger=\"hover\" [zMenuTriggerFor]=\"solutionsMenu\">\n              Solutions\n              <ng-icon name=\"lucideChevronDown\" class=\"ml-1\" />\n            </button>\n\n            <ng-template #solutionsMenu>\n              <div z-menu-content class=\"w-80 p-2\">\n                <div class=\"grid gap-1\">\n                  <button\n                    type=\"button\"\n                    z-menu-item\n                    (click)=\"log('For Startups')\"\n                    class=\"flex h-auto flex-col items-start py-3\"\n                  >\n                    <div class=\"text-sm font-medium\">For Startups</div>\n                    <div class=\"text-muted-foreground mt-1 text-xs\">\n                      Get started quickly with our startup-friendly tools\n                    </div>\n                  </button>\n\n                  <button\n                    type=\"button\"\n                    z-menu-item\n                    (click)=\"log('For Enterprise')\"\n                    class=\"flex h-auto flex-col items-start py-3\"\n                  >\n                    <div class=\"text-sm font-medium\">For Enterprise</div>\n                    <div class=\"text-muted-foreground mt-1 text-xs\">\n                      Scale your business with enterprise-grade features\n                    </div>\n                  </button>\n\n                  <button\n                    type=\"button\"\n                    z-menu-item\n                    (click)=\"log('For Agencies')\"\n                    class=\"flex h-auto flex-col items-start py-3\"\n                  >\n                    <div class=\"text-sm font-medium\">For Agencies</div>\n                    <div class=\"text-muted-foreground mt-1 text-xs\">Manage multiple clients with our agency tools</div>\n                  </button>\n                </div>\n              </div>\n            </ng-template>\n          </div>\n\n          <div class=\"relative\">\n            <button type=\"button\" z-button zType=\"ghost\" z-menu zTrigger=\"hover\" [zMenuTriggerFor]=\"resourcesMenu\">\n              Resources\n              <ng-icon name=\"lucideChevronDown\" />\n            </button>\n\n            <ng-template #resourcesMenu>\n              <div z-menu-content class=\"w-56\">\n                <button type=\"button\" z-menu-item (click)=\"log('Blog')\">\n                  <ng-icon name=\"lucideBookOpen\" class=\"mr-2\" />\n                  Blog\n                </button>\n\n                <button type=\"button\" z-menu-item (click)=\"log('Documentation')\">\n                  <ng-icon name=\"lucideFileText\" class=\"mr-2\" />\n                  Documentation\n                </button>\n\n                <button\n                  type=\"button\"\n                  z-menu-item\n                  z-menu\n                  [zMenuTriggerFor]=\"helpSubmenu\"\n                  zPlacement=\"rightTop\"\n                  class=\"justify-between\"\n                >\n                  <div class=\"flex items-center\">\n                    <ng-icon name=\"lucideInfo\" class=\"mr-2\" />\n                    Help & Support\n                  </div>\n                  <ng-icon name=\"lucideChevronRight\" />\n                </button>\n\n                <z-separator class=\"my-2\" />\n\n                <button type=\"button\" z-menu-item (click)=\"log('Community')\">\n                  <ng-icon name=\"lucideUsers\" class=\"mr-2\" />\n                  Community\n                </button>\n              </div>\n            </ng-template>\n\n            <ng-template #helpSubmenu>\n              <div z-menu-content class=\"w-48\">\n                <button type=\"button\" z-menu-item (click)=\"log('Getting Started')\">Getting Started</button>\n                <button type=\"button\" z-menu-item (click)=\"log('Tutorials')\">Tutorials</button>\n                <button type=\"button\" z-menu-item (click)=\"log('FAQ')\">FAQ</button>\n\n                <z-separator class=\"my-2\" />\n\n                <button type=\"button\" z-menu-item (click)=\"log('Contact Support')\">Contact Support</button>\n                <button type=\"button\" z-menu-item (click)=\"log('Live Chat')\">Live Chat</button>\n              </div>\n            </ng-template>\n          </div>\n        </div>\n      </div>\n    </nav>\n  `,\n  viewProviders: [\n    provideIcons({\n      lucideChevronDown,\n      lucideChevronRight,\n      lucideBookOpen,\n      lucideFileText,\n      lucideInfo,\n      lucideUsers,\n    }),\n  ],\n})\nexport class ZardDemoMenuDefaultComponent {\n  log(item: string) {\n    console.log('Navigate to:', item);\n  }\n}\n"
    }
  ]
}
