{
  "name": "command",
  "type": "registry:component",
  "files": [
    {
      "name": "command.component.ts",
      "content": "import {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  contentChild,\n  contentChildren,\n  effect,\n  forwardRef,\n  input,\n  output,\n  signal,\n  ViewEncapsulation,\n} from '@angular/core';\nimport { type ControlValueAccessor, FormsModule, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport type { IconName } from '@ng-icons/core';\nimport type { ClassValue } from 'clsx';\n\nimport { ZardCommandInputComponent } from '@/shared/components/command/command-input.component';\nimport { ZardCommandOptionComponent } from '@/shared/components/command/command-option.component';\nimport { commandVariants } from '@/shared/components/command/command.variants';\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\nexport interface ZardCommandOption {\n  value: unknown;\n  label: string;\n  disabled?: boolean;\n  command?: string;\n  shortcut?: string;\n  icon?: IconName;\n  action?: () => void;\n  key?: string;\n}\n\nexport interface ZardCommandGroup {\n  label: string;\n  options: ZardCommandOption[];\n}\n\nexport interface ZardCommandConfig {\n  placeholder?: string;\n  emptyText?: string;\n  groups: ZardCommandGroup[];\n  dividers?: boolean;\n  onSelect?: (option: ZardCommandOption) => void;\n}\n\nexport abstract class ZardCommand {\n  abstract registerOption(option: ZardCommandOptionComponent): void;\n  abstract unregisterOption(option: ZardCommandOptionComponent): void;\n}\n\n@Component({\n  selector: 'z-command',\n  imports: [FormsModule],\n  template: `\n    <div [class]=\"classes()\">\n      <div id=\"command-instructions\" class=\"sr-only\">\n        Use arrow keys to navigate, Enter to select, Escape to clear selection.\n      </div>\n      <div id=\"command-status\" class=\"sr-only\" aria-live=\"polite\" aria-atomic=\"true\">\n        {{ statusMessage() }}\n      </div>\n      <ng-content />\n    </div>\n  `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => ZardCommandComponent),\n      multi: true,\n    },\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    'data-slot': 'command',\n    role: 'combobox',\n    'aria-haspopup': 'listbox',\n    '[attr.aria-expanded]': 'true',\n    '(keydown.{arrowdown,arrowup,enter,escape}.prevent)': 'onKeyDown($event)',\n  },\n  exportAs: 'zCommand',\n})\nexport class ZardCommandComponent implements ControlValueAccessor, ZardCommand {\n  private readonly commandInput = contentChild(ZardCommandInputComponent);\n  private readonly optionComponentsAsChildren = contentChildren(ZardCommandOptionComponent, { descendants: true });\n  private readonly registeredOptionComponents = signal<ZardCommandOptionComponent[]>([]);\n\n  readonly class = input<ClassValue>('');\n\n  readonly zCommandChange = output<ZardCommandOption>();\n  readonly zCommandSelected = output<ZardCommandOption>();\n\n  // Internal signals for search functionality\n  readonly searchTerm = signal('');\n  readonly selectedIndex = signal(0);\n\n  /**\n   * Clamps selectedIndex to valid bounds of filteredOptions and skips disabled\n   * options. Returns -1 when there are no enabled options to highlight.\n   */\n  private readonly resolvedIndex = computed(() => {\n    const options = this.filteredOptions();\n    const len = options.length;\n    if (len === 0) return -1;\n\n    const raw = this.selectedIndex();\n    const target = raw < 0 || raw >= len ? 0 : raw;\n\n    if (!options[target].zDisabled()) return target;\n\n    for (let i = 1; i < len; i++) {\n      const candidate = (target + i) % len;\n      if (!options[candidate].zDisabled()) return candidate;\n    }\n    return -1;\n  });\n\n  /**\n   * Finds the next enabled option index in the given direction, wrapping\n   * around. Returns -1 if there is no enabled option.\n   */\n  private findEnabledIndex(from: number, direction: 1 | -1, options: readonly ZardCommandOptionComponent[]): number {\n    const len = options.length;\n    if (len === 0) return -1;\n    let idx = from;\n    for (let i = 0; i < len; i++) {\n      idx = (idx + direction + len) % len;\n      if (!options[idx].zDisabled()) return idx;\n    }\n    return -1;\n  }\n\n  protected readonly optionComponents = computed(() =>\n    this.optionComponentsAsChildren().length ? this.optionComponentsAsChildren() : this.registeredOptionComponents(),\n  );\n\n  registerOption(option: ZardCommandOptionComponent) {\n    this.registeredOptionComponents.update(current => [...current, option]);\n  }\n\n  unregisterOption(option: ZardCommandOptionComponent) {\n    this.registeredOptionComponents.update(current => current.filter(o => o !== option));\n  }\n\n  // Signal to trigger updates when optionComponents change\n  private readonly optionsUpdateTrigger = signal(0);\n\n  protected readonly classes = computed(() => mergeClasses(commandVariants(), this.class()));\n\n  // Computed signal for filtered options - this will automatically update when searchTerm or options change\n  readonly filteredOptions = computed(() => {\n    const searchTerm = this.searchTerm();\n    // Include the trigger signal to make this computed reactive to option changes\n    this.optionsUpdateTrigger();\n\n    if (!this.optionComponents()) {\n      return [];\n    }\n\n    const lowerSearchTerm = searchTerm.toLowerCase().trim();\n    if (!lowerSearchTerm) {\n      return this.optionComponents();\n    }\n\n    return this.optionComponents().filter(option => {\n      const label = option.zLabel().toLowerCase();\n      const command = option.zCommand()?.toLowerCase() ?? '';\n      return label.includes(lowerSearchTerm) || command.includes(lowerSearchTerm);\n    });\n  });\n\n  /**\n   * True when there is a search term and no results match. Useful to render\n   * an empty state next to the command list (e.g. <z-empty />).\n   */\n  readonly isEmpty = computed(() => {\n    const searchTerm = this.searchTerm().trim();\n    if (!searchTerm) return false;\n    return this.filteredOptions().length === 0;\n  });\n\n  // Status message for screen readers\n  protected readonly statusMessage = computed(() => {\n    const searchTerm = this.searchTerm().trim();\n    const filteredCount = this.filteredOptions().length;\n\n    if (!searchTerm) {\n      return searchTerm;\n    }\n\n    if (!filteredCount) {\n      return `No results found for \"${searchTerm}\"`;\n    }\n\n    return `${filteredCount} result${filteredCount === 1 ? '' : 's'} found for \"${searchTerm}\"`;\n  });\n\n  private onChange = (_value: unknown) => {\n    // ControlValueAccessor implementation\n  };\n\n  private onTouched = () => {\n    // ControlValueAccessor implementation\n  };\n\n  constructor() {\n    this.triggerOptionsUpdate();\n\n    effect(() => {\n      const idx = this.resolvedIndex();\n      this.filteredOptions().forEach((opt, i) => opt.setSelected(i === idx));\n    });\n  }\n\n  /**\n   * Trigger an update to the filteredOptions computed signal\n   */\n  private triggerOptionsUpdate(): void {\n    this.optionsUpdateTrigger.update(value => value + 1);\n  }\n\n  onSearch(searchTerm: string) {\n    this.searchTerm.set(searchTerm);\n    this.selectedIndex.set(0);\n  }\n\n  /**\n   * Sets the active item by index. Called by command-option on mouseenter\n   * and by command-list on mouseleave (with 0 to reset to first).\n   */\n  setActiveByIndex(index: number) {\n    this.selectedIndex.set(index);\n  }\n\n  selectOption(option: ZardCommandOptionComponent) {\n    const commandOption: ZardCommandOption = {\n      value: option.zValue(),\n      label: option.zLabel(),\n      disabled: option.zDisabled(),\n      command: option.zCommand(),\n      shortcut: option.zShortcut(),\n      icon: option.zIcon(),\n    };\n\n    this.onChange(commandOption.value);\n    this.zCommandChange.emit(commandOption);\n    this.zCommandSelected.emit(commandOption);\n  }\n\n  // in @Component host: '(keydown)': 'onKeyDown($event)'\n  onKeyDown(event: Event) {\n    const filteredOptions = this.filteredOptions();\n    if (filteredOptions.length === 0) return;\n\n    const { key } = event as KeyboardEvent;\n    const currentIndex = this.resolvedIndex();\n\n    switch (key) {\n      case 'ArrowDown': {\n        const nextIndex = this.findEnabledIndex(currentIndex, 1, filteredOptions);\n        if (nextIndex >= 0) {\n          this.selectedIndex.set(nextIndex);\n          filteredOptions[nextIndex].focus();\n        }\n        break;\n      }\n      case 'ArrowUp': {\n        const prevIndex = this.findEnabledIndex(currentIndex, -1, filteredOptions);\n        if (prevIndex >= 0) {\n          this.selectedIndex.set(prevIndex);\n          filteredOptions[prevIndex].focus();\n        }\n        break;\n      }\n      case 'Enter':\n        if (currentIndex >= 0 && currentIndex < filteredOptions.length) {\n          const selectedOption = filteredOptions[currentIndex];\n          if (!selectedOption.zDisabled()) {\n            this.selectOption(selectedOption);\n          }\n        }\n        break;\n      case 'Escape':\n        this.selectedIndex.set(0);\n        break;\n    }\n  }\n\n  // ControlValueAccessor implementation\n  writeValue(_value: unknown): void {\n    // Implementation if needed for form control integration\n  }\n\n  registerOnChange(fn: (value: unknown) => void): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(_isDisabled: boolean): void {\n    // Implementation if needed for form control disabled state\n  }\n\n  /**\n   * Refresh the options list - useful when options are added/removed dynamically\n   */\n  refreshOptions(): void {\n    this.triggerOptionsUpdate();\n  }\n\n  /**\n   * Focus the command input\n   */\n  focus(): void {\n    this.commandInput()?.focus();\n  }\n}\n"
    },
    {
      "name": "command-input.component.ts",
      "content": "import {\n  ChangeDetectionStrategy,\n  Component,\n  type ElementRef,\n  forwardRef,\n  inject,\n  input,\n  output,\n  signal,\n  viewChild,\n  ViewEncapsulation,\n} from '@angular/core';\nimport { type ControlValueAccessor, NG_VALUE_ACCESSOR } from '@angular/forms';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideSearch } from '@ng-icons/lucide';\n\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\nimport { ZardInputComponent } from '@/shared/components/input/input.component';\nimport { ZardInputGroupImports } from '@/shared/components/input-group/input-group.imports';\n\n@Component({\n  selector: 'z-command-input',\n  imports: [NgIcon, ZardInputComponent, ...ZardInputGroupImports],\n  template: `\n    <div data-slot=\"command-input-wrapper\" class=\"p-1 pb-0\">\n      <z-input-group\n        class=\"border-input/30 has-[input:focus-visible]:border-input/30! shadow-none! has-[input:focus-visible]:ring-0!\"\n      >\n        <z-input-group-addon>\n          <ng-icon name=\"lucideSearch\" class=\"size-4! shrink-0 opacity-50\" />\n        </z-input-group-addon>\n        <input\n          z-input\n          #searchInput\n          [placeholder]=\"placeholder()\"\n          [value]=\"searchTerm()\"\n          [disabled]=\"disabled()\"\n          (input)=\"onInput($event)\"\n          (keydown)=\"onKeyDown($event)\"\n          (blur)=\"onTouched()\"\n          aria-controls=\"command-list\"\n          aria-describedby=\"command-instructions\"\n          aria-haspopup=\"listbox\"\n          aria-label=\"Search commands\"\n          autocomplete=\"off\"\n          autocorrect=\"off\"\n          spellcheck=\"false\"\n          role=\"combobox\"\n          [attr.aria-expanded]=\"true\"\n        />\n      </z-input-group>\n    </div>\n  `,\n  providers: [\n    {\n      provide: NG_VALUE_ACCESSOR,\n      useExisting: forwardRef(() => ZardCommandInputComponent),\n      multi: true,\n    },\n  ],\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  viewProviders: [provideIcons({ lucideSearch })],\n  exportAs: 'zCommandInput',\n})\nexport class ZardCommandInputComponent implements ControlValueAccessor {\n  private readonly commandComponent = inject(ZardCommandComponent, { optional: true });\n  readonly searchInput = viewChild<ElementRef<HTMLInputElement>>('searchInput');\n\n  readonly placeholder = input<string>('Type a command or search...');\n\n  readonly valueChange = output<string>();\n\n  readonly searchTerm = signal('');\n  readonly disabled = signal(false);\n\n  protected onChange = (_: string) => {\n    /* CVA */\n  };\n\n  protected onTouched = () => {\n    /* CVA */\n  };\n\n  onInput(event: Event) {\n    const value = (event.target as HTMLInputElement).value;\n    this.updateParentComponents(value);\n  }\n\n  updateParentComponents(value: string): void {\n    this.searchTerm.set(value);\n    this.commandComponent?.onSearch(value);\n    this.onChange(value);\n    this.valueChange.emit(value);\n  }\n\n  onKeyDown(event: KeyboardEvent) {\n    if (['ArrowDown', 'ArrowUp', 'Enter', 'Escape'].includes(event.key)) {\n      if (event.key !== 'Escape') {\n        event.preventDefault();\n        event.stopPropagation();\n      }\n      this.commandComponent?.onKeyDown(event);\n    }\n  }\n\n  writeValue(value: string | null): void {\n    const normalized = value ?? '';\n    this.searchTerm.set(normalized);\n    this.commandComponent?.onSearch(normalized);\n  }\n\n  registerOnChange(fn: (value: string) => void): void {\n    this.onChange = fn;\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouched = fn;\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.disabled.set(isDisabled);\n  }\n\n  focus(): void {\n    this.searchInput()?.nativeElement?.focus();\n  }\n}\n"
    },
    {
      "name": "command-list.component.ts",
      "content": "import { ChangeDetectionStrategy, Component, computed, input, ViewEncapsulation } from '@angular/core';\n\nimport type { ClassValue } from 'clsx';\n\nimport { commandListVariants } from '@/shared/components/command/command.variants';\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\n@Component({\n  selector: 'z-command-list',\n  template: `\n    <div [class]=\"classes()\" role=\"listbox\" id=\"command-list\" data-slot=\"command-list\">\n      <ng-content />\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  exportAs: 'zCommandList',\n})\nexport class ZardCommandListComponent {\n  readonly class = input<ClassValue>('');\n\n  protected readonly classes = computed(() => mergeClasses(commandListVariants(), this.class()));\n}\n"
    },
    {
      "name": "command-option.component.ts",
      "content": "import {\n  booleanAttribute,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  effect,\n  ElementRef,\n  inject,\n  input,\n  signal,\n  ViewEncapsulation,\n} from '@angular/core';\n\nimport { NgIcon, type IconName } from '@ng-icons/core';\nimport type { ClassValue } from 'clsx';\n\nimport type { ZardCommandOptionGroupComponent } from '@/shared/components/command/command-option-group.component';\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\nimport {\n  commandItemVariants,\n  commandShortcutVariants,\n  type ZardCommandItemVariants,\n} from '@/shared/components/command/command.variants';\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\n@Component({\n  selector: 'z-command-option',\n  imports: [NgIcon],\n  template: `\n    @if (isOptionVisible()) {\n      <div\n        [class]=\"classes()\"\n        data-slot=\"command-item\"\n        [attr.role]=\"'option'\"\n        [attr.aria-selected]=\"isSelected()\"\n        [attr.data-selected]=\"isSelected() ? '' : null\"\n        [attr.data-disabled]=\"zDisabled()\"\n        [attr.tabindex]=\"0\"\n        (click)=\"onClick()\"\n        (keydown.{enter,space}.prevent)=\"onClick()\"\n        (mouseenter)=\"onMouseEnter()\"\n      >\n        <ng-content select=\"[data-slot=command-option-leading]\" />\n        @if (zIcon()) {\n          <ng-icon [name]=\"zIcon()!\" />\n        }\n        <span class=\"flex-1\">{{ zLabel() }}</span>\n        @if (zShortcut()) {\n          <span [class]=\"shortcutClasses()\" data-slot=\"command-shortcut\">{{ zShortcut() }}</span>\n        }\n        <ng-content select=\"[data-slot=command-option-trailing]\" />\n      </div>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  exportAs: 'zCommandOption',\n})\nexport class ZardCommandOptionComponent {\n  private readonly elementRef = inject(ElementRef);\n  private readonly parentCommandComponent = inject(ZardCommandComponent, { optional: true });\n\n  readonly zValue = input.required<unknown>();\n  readonly zLabel = input.required<string>();\n  readonly zCommand = input<string>('');\n  readonly zIcon = input<IconName>();\n  readonly zShortcut = input<string>('');\n  readonly zDisabled = input(false, { transform: booleanAttribute });\n  readonly variant = input<ZardCommandItemVariants>('default');\n  readonly class = input<ClassValue>('');\n  readonly parentCommand = input<ZardCommandComponent | null>(null);\n  readonly commandGroup = input<ZardCommandOptionGroupComponent | null>(null);\n\n  readonly isSelected = signal(false);\n\n  protected readonly classes = computed(() =>\n    mergeClasses(commandItemVariants({ variant: this.variant() }), this.class()),\n  );\n\n  protected readonly shortcutClasses = computed(() => mergeClasses(commandShortcutVariants()));\n\n  private get commandComponent() {\n    let parent = this.parentCommand();\n    parent ||= this.parentCommandComponent;\n    return parent;\n  }\n\n  protected readonly isOptionVisible = computed(() => {\n    const parent = this.commandComponent;\n\n    if (!parent) {\n      return true;\n    }\n    /*\n      If no search term, show this option, otherwise check\n      if this option is included in the filtered list\n     */\n    return !parent.searchTerm() || parent.filteredOptions().includes(this);\n  });\n\n  constructor() {\n    effect(onCleanup => {\n      const cmd = this.parentCommand();\n      const grp = this.commandGroup();\n\n      if (cmd) {\n        cmd.registerOption(this);\n        onCleanup(() => cmd.unregisterOption(this));\n      }\n\n      if (grp) {\n        grp.registerOption(this);\n        onCleanup(() => grp.unregisterOption(this));\n      }\n    });\n  }\n\n  onClick() {\n    if (this.zDisabled()) {\n      return;\n    }\n\n    this.commandComponent?.selectOption(this);\n  }\n\n  onMouseEnter() {\n    if (this.zDisabled()) return;\n    const parent = this.commandComponent;\n    if (!parent) return;\n    const idx = parent.filteredOptions().indexOf(this);\n    if (idx >= 0) parent.setActiveByIndex(idx);\n  }\n\n  setSelected(selected: boolean) {\n    this.isSelected.set(selected);\n  }\n\n  focus() {\n    const element = this.elementRef.nativeElement;\n    element.focus();\n    element.scrollIntoView({ behavior: 'smooth', block: 'nearest' });\n  }\n}\n"
    },
    {
      "name": "command-option-group.component.ts",
      "content": "import {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  contentChildren,\n  inject,\n  input,\n  signal,\n  ViewEncapsulation,\n} from '@angular/core';\n\nimport type { ClassValue } from 'clsx';\n\nimport { ZardCommandOptionComponent } from '@/shared/components/command/command-option.component';\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\nimport { commandGroupVariants } from '@/shared/components/command/command.variants';\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\nexport abstract class ZardCommandOptionGroup {\n  abstract registerOption(option: ZardCommandOptionComponent): void;\n  abstract unregisterOption(option: ZardCommandOptionComponent): void;\n}\n\n@Component({\n  selector: 'z-command-option-group',\n  template: `\n    @if (isGroupVisible()) {\n      <div [class]=\"classes()\" role=\"group\" data-slot=\"command-group\">\n        @if (zLabel()) {\n          <div data-slot=\"command-group-heading\" role=\"presentation\">\n            {{ zLabel() }}\n          </div>\n        }\n        <div role=\"group\">\n          <ng-content />\n        </div>\n      </div>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  exportAs: 'zCommandOptionGroup',\n})\nexport class ZardCommandOptionGroupComponent implements ZardCommandOptionGroup {\n  private readonly commandComponent = inject(ZardCommandComponent, { optional: true });\n  private readonly optionComponentsAsChildren = contentChildren(ZardCommandOptionComponent, { descendants: true });\n  private readonly registeredOptionComponents = signal<ZardCommandOptionComponent[]>([]);\n\n  readonly zLabel = input.required<string>();\n  readonly class = input<ClassValue>('');\n\n  protected readonly classes = computed(() => mergeClasses(commandGroupVariants(), this.class()));\n  private readonly optionComponents = computed(() =>\n    this.optionComponentsAsChildren().length ? this.optionComponentsAsChildren() : this.registeredOptionComponents(),\n  );\n\n  protected readonly isGroupVisible = computed(() => {\n    if (!this.commandComponent || !this.optionComponents().length) {\n      return true;\n    }\n\n    const searchTerm = this.commandComponent.searchTerm();\n    // If no search term, show all groups\n    if (!searchTerm) {\n      return true;\n    }\n\n    const filteredOptions = this.commandComponent.filteredOptions();\n    // Check if any option in this group is in the filtered list\n    return this.optionComponents().some(option => filteredOptions.includes(option));\n  });\n\n  registerOption(option: ZardCommandOptionComponent) {\n    this.registeredOptionComponents.update(current => [...current, option]);\n  }\n\n  unregisterOption(option: ZardCommandOptionComponent) {\n    this.registeredOptionComponents.update(current => current.filter(o => o !== option));\n  }\n}\n"
    },
    {
      "name": "command-divider.component.ts",
      "content": "import { ChangeDetectionStrategy, Component, computed, inject, input, ViewEncapsulation } from '@angular/core';\n\nimport type { ClassValue } from 'clsx';\n\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\nimport { commandSeparatorVariants } from '@/shared/components/command/command.variants';\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\n@Component({\n  selector: 'z-command-divider',\n  template: `\n    @if (shouldShow()) {\n      <div [class]=\"classes()\" role=\"separator\" data-slot=\"command-separator\"></div>\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  exportAs: 'zCommandDivider',\n})\nexport class ZardCommandDividerComponent {\n  private readonly commandComponent = inject(ZardCommandComponent, { optional: true });\n\n  readonly class = input<ClassValue>('');\n\n  protected readonly classes = computed(() => mergeClasses(commandSeparatorVariants(), this.class()));\n\n  protected readonly shouldShow = computed(() => {\n    if (!this.commandComponent) {\n      return true;\n    }\n\n    const searchTerm = this.commandComponent.searchTerm();\n\n    // If no search, always show dividers\n    if (searchTerm === '') {\n      return true;\n    }\n\n    // If there's a search term, hide all dividers for now\n    // This is a simple approach - we can make it smarter later\n    return false;\n  });\n}\n"
    },
    {
      "name": "command.imports.ts",
      "content": "import { ZardCommandDividerComponent } from '@/shared/components/command/command-divider.component';\nimport { ZardCommandInputComponent } from '@/shared/components/command/command-input.component';\nimport { ZardCommandListComponent } from '@/shared/components/command/command-list.component';\nimport { ZardCommandOptionGroupComponent } from '@/shared/components/command/command-option-group.component';\nimport { ZardCommandOptionComponent } from '@/shared/components/command/command-option.component';\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\n\nexport const ZardCommandImports = [\n  ZardCommandComponent,\n  ZardCommandInputComponent,\n  ZardCommandListComponent,\n  ZardCommandOptionComponent,\n  ZardCommandOptionGroupComponent,\n  ZardCommandDividerComponent,\n] as const;\n"
    },
    {
      "name": "command.variants.ts",
      "content": "import { cva, type VariantProps } from 'class-variance-authority';\n\nexport const commandVariants = cva(\n  'flex size-full flex-col overflow-hidden rounded-xl bg-popover p-1 text-popover-foreground border shadow-md',\n);\n\nexport const commandListVariants = cva(\n  'no-scrollbar max-h-72 scroll-py-1 overflow-x-hidden overflow-y-auto outline-none p-1',\n);\n\nexport const commandGroupVariants = cva(\n  'overflow-hidden text-foreground **:data-[slot=command-group-heading]:px-2 **:data-[slot=command-group-heading]:py-1.5 **:data-[slot=command-group-heading]:text-xs **:data-[slot=command-group-heading]:font-medium **:data-[slot=command-group-heading]:text-muted-foreground',\n);\n\nexport const commandItemVariants = cva(\n  [\n    'group/command-item relative flex cursor-pointer items-center gap-2 rounded-sm px-2 py-1.5 text-sm outline-none select-none transition-colors',\n    'data-[disabled=true]:pointer-events-none data-[disabled=true]:opacity-50',\n    'data-selected:bg-muted data-selected:text-accent-foreground',\n    \"[&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n    'data-selected:*:[svg]:text-accent-foreground',\n  ].join(' '),\n  {\n    variants: {\n      variant: {\n        default: '',\n        destructive: 'data-selected:bg-destructive data-selected:text-destructive-foreground',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n    },\n  },\n);\n\nexport const commandSeparatorVariants = cva('-mx-1 my-1 h-px bg-border');\n\nexport const commandShortcutVariants = cva(\n  'ml-auto text-xs tracking-widest text-muted-foreground group-data-selected/command-item:text-accent-foreground',\n);\n\nexport type ZardCommandItemVariants = NonNullable<VariantProps<typeof commandItemVariants>['variant']>;\n"
    },
    {
      "name": "index.ts",
      "content": "export * from '@/shared/components/command/command.component';\nexport * from '@/shared/components/command/command-input.component';\nexport * from '@/shared/components/command/command-list.component';\nexport * from '@/shared/components/command/command-option.component';\nexport * from '@/shared/components/command/command-option-group.component';\nexport * from '@/shared/components/command/command-divider.component';\nexport * from '@/shared/components/command/command.imports';\nexport * from '@/shared/components/command/command.variants';\n"
    }
  ],
  "demos": [
    {
      "name": "basic.ts",
      "content": "import { type AfterViewInit, Component, inject, viewChild } from '@angular/core';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\nimport { ZardCommandImports } from '@/shared/components/command/command.imports';\nimport { ZardDialogService } from '@/shared/components/dialog/dialog.service';\n\n@Component({\n  selector: 'z-demo-command-basic-dialog',\n  imports: [ZardCommandImports],\n  template: `\n    <z-command #cmd=\"zCommand\">\n      <z-command-input placeholder=\"Type a command or search...\" />\n      <z-command-list>\n        @if (cmd.isEmpty()) {\n          <div class=\"py-6 text-center text-sm\">No results found.</div>\n        }\n        <z-command-option-group zLabel=\"Suggestions\">\n          <z-command-option zLabel=\"Calendar\" zValue=\"calendar\" />\n          <z-command-option zLabel=\"Search Emoji\" zValue=\"emoji\" />\n          <z-command-option zLabel=\"Calculator\" zValue=\"calculator\" />\n        </z-command-option-group>\n      </z-command-list>\n    </z-command>\n  `,\n})\nclass ZardDemoCommandBasicDialogComponent implements AfterViewInit {\n  private readonly cmd = viewChild.required(ZardCommandComponent);\n  ngAfterViewInit() {\n    setTimeout(() => this.cmd().focus(), 0);\n  }\n}\n\n@Component({\n  selector: 'z-demo-command-basic',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"outline\" (click)=\"open()\">Open Menu</button>\n  `,\n})\nexport class ZardDemoCommandBasicComponent {\n  private readonly dialogService = inject(ZardDialogService);\n\n  open() {\n    this.dialogService.create({\n      zContent: ZardDemoCommandBasicDialogComponent,\n      zClosable: false,\n      zHideFooter: true,\n      zOkText: null,\n      zCancelText: null,\n      zMaskClosable: true,\n      zWidth: '24rem',\n      zCustomClasses: '!p-0 !gap-0 !border-0 !bg-transparent !shadow-none',\n    });\n  }\n}\n"
    },
    {
      "name": "default.ts",
      "content": "import { Component } from '@angular/core';\n\nimport { provideIcons } from '@ng-icons/core';\nimport {\n  lucideCalculator,\n  lucideCalendar,\n  lucideCreditCard,\n  lucideSettings,\n  lucideSmile,\n  lucideUser,\n} from '@ng-icons/lucide';\n\nimport { ZardCommandImports } from '@/shared/components/command/command.imports';\n\n@Component({\n  selector: 'z-demo-command-default',\n  imports: [ZardCommandImports],\n  template: `\n    <z-command class=\"min-w-sm\" #cmd=\"zCommand\">\n      <z-command-input placeholder=\"Type a command or search...\" />\n      <z-command-list>\n        @if (cmd.isEmpty()) {\n          <div class=\"py-6 text-center text-sm\">No results found.</div>\n        }\n\n        <z-command-option-group zLabel=\"Suggestions\">\n          <z-command-option zLabel=\"Calendar\" zValue=\"calendar\" zIcon=\"lucideCalendar\" />\n          <z-command-option zLabel=\"Search Emoji\" zValue=\"emoji\" zIcon=\"lucideSmile\" />\n          <z-command-option zLabel=\"Calculator\" zValue=\"calculator\" zIcon=\"lucideCalculator\" [zDisabled]=\"true\" />\n        </z-command-option-group>\n\n        <z-command-divider />\n\n        <z-command-option-group zLabel=\"Settings\">\n          <z-command-option zLabel=\"Profile\" zValue=\"profile\" zIcon=\"lucideUser\" zShortcut=\"⌘P\" />\n          <z-command-option zLabel=\"Billing\" zValue=\"billing\" zIcon=\"lucideCreditCard\" zShortcut=\"⌘B\" />\n          <z-command-option zLabel=\"Settings\" zValue=\"settings\" zIcon=\"lucideSettings\" zShortcut=\"⌘S\" />\n        </z-command-option-group>\n      </z-command-list>\n    </z-command>\n  `,\n  viewProviders: [\n    provideIcons({\n      lucideCalendar,\n      lucideSmile,\n      lucideCalculator,\n      lucideUser,\n      lucideCreditCard,\n      lucideSettings,\n    }),\n  ],\n})\nexport class ZardDemoCommandDefaultComponent {}\n"
    },
    {
      "name": "groups.ts",
      "content": "import { type AfterViewInit, Component, inject, viewChild } from '@angular/core';\n\nimport { provideIcons } from '@ng-icons/core';\nimport {\n  lucideCalculator,\n  lucideCalendar,\n  lucideCreditCard,\n  lucideSettings,\n  lucideSmile,\n  lucideUser,\n} from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\nimport { ZardCommandImports } from '@/shared/components/command/command.imports';\nimport { ZardDialogService } from '@/shared/components/dialog/dialog.service';\n\n@Component({\n  selector: 'z-demo-command-groups-dialog',\n  imports: [ZardCommandImports],\n  template: `\n    <z-command #cmd=\"zCommand\">\n      <z-command-input placeholder=\"Type a command or search...\" />\n      <z-command-list>\n        @if (cmd.isEmpty()) {\n          <div class=\"py-6 text-center text-sm\">No results found.</div>\n        }\n\n        <z-command-option-group zLabel=\"Suggestions\">\n          <z-command-option zLabel=\"Calendar\" zValue=\"calendar\" zIcon=\"lucideCalendar\" />\n          <z-command-option zLabel=\"Search Emoji\" zValue=\"emoji\" zIcon=\"lucideSmile\" />\n          <z-command-option zLabel=\"Calculator\" zValue=\"calculator\" zIcon=\"lucideCalculator\" />\n        </z-command-option-group>\n\n        <z-command-divider />\n\n        <z-command-option-group zLabel=\"Settings\">\n          <z-command-option zLabel=\"Profile\" zValue=\"profile\" zIcon=\"lucideUser\" zShortcut=\"⌘P\" />\n          <z-command-option zLabel=\"Billing\" zValue=\"billing\" zIcon=\"lucideCreditCard\" zShortcut=\"⌘B\" />\n          <z-command-option zLabel=\"Settings\" zValue=\"settings\" zIcon=\"lucideSettings\" zShortcut=\"⌘S\" />\n        </z-command-option-group>\n      </z-command-list>\n    </z-command>\n  `,\n  viewProviders: [\n    provideIcons({ lucideCalendar, lucideSmile, lucideCalculator, lucideUser, lucideCreditCard, lucideSettings }),\n  ],\n})\nclass ZardDemoCommandGroupsDialogComponent implements AfterViewInit {\n  private readonly cmd = viewChild.required(ZardCommandComponent);\n  ngAfterViewInit() {\n    setTimeout(() => this.cmd().focus(), 0);\n  }\n}\n\n@Component({\n  selector: 'z-demo-command-groups',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"outline\" (click)=\"open()\">Open Menu</button>\n  `,\n})\nexport class ZardDemoCommandGroupsComponent {\n  private readonly dialogService = inject(ZardDialogService);\n\n  open() {\n    this.dialogService.create({\n      zContent: ZardDemoCommandGroupsDialogComponent,\n      zClosable: false,\n      zHideFooter: true,\n      zOkText: null,\n      zCancelText: null,\n      zMaskClosable: true,\n      zWidth: '24rem',\n      zCustomClasses: '!p-0 !gap-0 !border-0 !bg-transparent !shadow-none',\n    });\n  }\n}\n"
    },
    {
      "name": "scrollable.ts",
      "content": "import { type AfterViewInit, Component, inject, viewChild } from '@angular/core';\n\nimport { provideIcons } from '@ng-icons/core';\nimport {\n  lucideBell,\n  lucideCalculator,\n  lucideCalendar,\n  lucideCircleHelp,\n  lucideClipboardPaste,\n  lucideCode,\n  lucideCopy,\n  lucideCreditCard,\n  lucideFileText,\n  lucideFolder,\n  lucideFolderPlus,\n  lucideHouse,\n  lucideImage,\n  lucideInbox,\n  lucideLayoutGrid,\n  lucideList,\n  lucidePlus,\n  lucideScissors,\n  lucideSettings,\n  lucideTrash2,\n  lucideUser,\n  lucideZoomIn,\n  lucideZoomOut,\n} from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\nimport { ZardCommandImports } from '@/shared/components/command/command.imports';\nimport { ZardDialogService } from '@/shared/components/dialog/dialog.service';\n\n@Component({\n  selector: 'z-demo-command-scrollable-dialog',\n  imports: [ZardCommandImports],\n  template: `\n    <z-command #cmd=\"zCommand\">\n      <z-command-input placeholder=\"Type a command or search...\" />\n      <z-command-list>\n        @if (cmd.isEmpty()) {\n          <div class=\"py-6 text-center text-sm\">No results found.</div>\n        }\n\n        <z-command-option-group zLabel=\"Navigation\">\n          <z-command-option zLabel=\"Home\" zValue=\"home\" zIcon=\"lucideHouse\" zShortcut=\"⌘H\" />\n          <z-command-option zLabel=\"Inbox\" zValue=\"inbox\" zIcon=\"lucideInbox\" zShortcut=\"⌘I\" />\n          <z-command-option zLabel=\"Documents\" zValue=\"documents\" zIcon=\"lucideFileText\" zShortcut=\"⌘D\" />\n          <z-command-option zLabel=\"Folders\" zValue=\"folders\" zIcon=\"lucideFolder\" zShortcut=\"⌘F\" />\n        </z-command-option-group>\n\n        <z-command-divider />\n\n        <z-command-option-group zLabel=\"Actions\">\n          <z-command-option zLabel=\"New File\" zValue=\"new-file\" zIcon=\"lucidePlus\" zShortcut=\"⌘N\" />\n          <z-command-option zLabel=\"New Folder\" zValue=\"new-folder\" zIcon=\"lucideFolderPlus\" zShortcut=\"⇧⌘N\" />\n          <z-command-option zLabel=\"Copy\" zValue=\"copy\" zIcon=\"lucideCopy\" zShortcut=\"⌘C\" />\n          <z-command-option zLabel=\"Cut\" zValue=\"cut\" zIcon=\"lucideScissors\" zShortcut=\"⌘X\" />\n          <z-command-option zLabel=\"Paste\" zValue=\"paste\" zIcon=\"lucideClipboardPaste\" zShortcut=\"⌘V\" />\n          <z-command-option zLabel=\"Delete\" zValue=\"delete\" zIcon=\"lucideTrash2\" zShortcut=\"⌫\" />\n        </z-command-option-group>\n\n        <z-command-divider />\n\n        <z-command-option-group zLabel=\"View\">\n          <z-command-option zLabel=\"Grid View\" zValue=\"grid\" zIcon=\"lucideLayoutGrid\" />\n          <z-command-option zLabel=\"List View\" zValue=\"list\" zIcon=\"lucideList\" />\n          <z-command-option zLabel=\"Zoom In\" zValue=\"zoom-in\" zIcon=\"lucideZoomIn\" zShortcut=\"⌘+\" />\n          <z-command-option zLabel=\"Zoom Out\" zValue=\"zoom-out\" zIcon=\"lucideZoomOut\" zShortcut=\"⌘-\" />\n        </z-command-option-group>\n\n        <z-command-divider />\n\n        <z-command-option-group zLabel=\"Account\">\n          <z-command-option zLabel=\"Profile\" zValue=\"profile\" zIcon=\"lucideUser\" zShortcut=\"⌘P\" />\n          <z-command-option zLabel=\"Billing\" zValue=\"billing\" zIcon=\"lucideCreditCard\" zShortcut=\"⌘B\" />\n          <z-command-option zLabel=\"Settings\" zValue=\"settings\" zIcon=\"lucideSettings\" zShortcut=\"⌘S\" />\n          <z-command-option zLabel=\"Notifications\" zValue=\"notifications\" zIcon=\"lucideBell\" />\n          <z-command-option zLabel=\"Help & Support\" zValue=\"help\" zIcon=\"lucideCircleHelp\" />\n        </z-command-option-group>\n\n        <z-command-divider />\n\n        <z-command-option-group zLabel=\"Tools\">\n          <z-command-option zLabel=\"Calculator\" zValue=\"calculator\" zIcon=\"lucideCalculator\" />\n          <z-command-option zLabel=\"Calendar\" zValue=\"calendar\" zIcon=\"lucideCalendar\" />\n          <z-command-option zLabel=\"Image Editor\" zValue=\"image\" zIcon=\"lucideImage\" />\n          <z-command-option zLabel=\"Code Editor\" zValue=\"code\" zIcon=\"lucideCode\" />\n        </z-command-option-group>\n      </z-command-list>\n    </z-command>\n  `,\n  viewProviders: [\n    provideIcons({\n      lucideHouse,\n      lucideInbox,\n      lucideFileText,\n      lucideFolder,\n      lucidePlus,\n      lucideFolderPlus,\n      lucideCopy,\n      lucideScissors,\n      lucideClipboardPaste,\n      lucideTrash2,\n      lucideLayoutGrid,\n      lucideList,\n      lucideZoomIn,\n      lucideZoomOut,\n      lucideUser,\n      lucideCreditCard,\n      lucideSettings,\n      lucideBell,\n      lucideCircleHelp,\n      lucideCalculator,\n      lucideCalendar,\n      lucideImage,\n      lucideCode,\n    }),\n  ],\n})\nclass ZardDemoCommandScrollableDialogComponent implements AfterViewInit {\n  private readonly cmd = viewChild.required(ZardCommandComponent);\n  ngAfterViewInit() {\n    setTimeout(() => this.cmd().focus(), 0);\n  }\n}\n\n@Component({\n  selector: 'z-demo-command-scrollable',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"outline\" (click)=\"open()\">Open Menu</button>\n  `,\n})\nexport class ZardDemoCommandScrollableComponent {\n  private readonly dialogService = inject(ZardDialogService);\n\n  open() {\n    this.dialogService.create({\n      zContent: ZardDemoCommandScrollableDialogComponent,\n      zClosable: false,\n      zHideFooter: true,\n      zOkText: null,\n      zCancelText: null,\n      zMaskClosable: true,\n      zWidth: '24rem',\n      zCustomClasses: '!p-0 !gap-0 !border-0 !bg-transparent !shadow-none',\n    });\n  }\n}\n"
    },
    {
      "name": "shortcuts.ts",
      "content": "import { type AfterViewInit, Component, inject, viewChild } from '@angular/core';\n\nimport { provideIcons } from '@ng-icons/core';\nimport { lucideCreditCard, lucideSettings, lucideUser } from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardCommandComponent } from '@/shared/components/command/command.component';\nimport { ZardCommandImports } from '@/shared/components/command/command.imports';\nimport { ZardDialogService } from '@/shared/components/dialog/dialog.service';\n\n@Component({\n  selector: 'z-demo-command-shortcuts-dialog',\n  imports: [ZardCommandImports],\n  template: `\n    <z-command #cmd=\"zCommand\">\n      <z-command-input placeholder=\"Type a command or search...\" />\n      <z-command-list>\n        @if (cmd.isEmpty()) {\n          <div class=\"py-6 text-center text-sm\">No results found.</div>\n        }\n        <z-command-option-group zLabel=\"Settings\">\n          <z-command-option zLabel=\"Profile\" zValue=\"profile\" zIcon=\"lucideUser\" zShortcut=\"⌘P\" />\n          <z-command-option zLabel=\"Billing\" zValue=\"billing\" zIcon=\"lucideCreditCard\" zShortcut=\"⌘B\" />\n          <z-command-option zLabel=\"Settings\" zValue=\"settings\" zIcon=\"lucideSettings\" zShortcut=\"⌘S\" />\n        </z-command-option-group>\n      </z-command-list>\n    </z-command>\n  `,\n  viewProviders: [provideIcons({ lucideUser, lucideCreditCard, lucideSettings })],\n})\nclass ZardDemoCommandShortcutsDialogComponent implements AfterViewInit {\n  private readonly cmd = viewChild.required(ZardCommandComponent);\n  ngAfterViewInit() {\n    setTimeout(() => this.cmd().focus(), 0);\n  }\n}\n\n@Component({\n  selector: 'z-demo-command-shortcuts',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"outline\" (click)=\"open()\">Open Menu</button>\n  `,\n})\nexport class ZardDemoCommandShortcutsComponent {\n  private readonly dialogService = inject(ZardDialogService);\n\n  open() {\n    this.dialogService.create({\n      zContent: ZardDemoCommandShortcutsDialogComponent,\n      zClosable: false,\n      zHideFooter: true,\n      zOkText: null,\n      zCancelText: null,\n      zMaskClosable: true,\n      zWidth: '24rem',\n      zCustomClasses: '!p-0 !gap-0 !border-0 !bg-transparent !shadow-none',\n    });\n  }\n}\n"
    }
  ]
}
