{
  "name": "button",
  "type": "registry:component",
  "files": [
    {
      "name": "button.component.ts",
      "content": "import {\n  afterNextRender,\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  type OnDestroy,\n  ElementRef,\n  inject,\n  input,\n  signal,\n  ViewEncapsulation,\n  booleanAttribute,\n} from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideLoaderCircle } from '@ng-icons/lucide';\nimport type { ClassValue } from 'clsx';\n\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\nimport {\n  buttonVariants,\n  type ZardButtonShapeVariants,\n  type ZardButtonSizeVariants,\n  type ZardButtonTypeVariants,\n} from './button.variants';\n\n@Component({\n  selector: 'z-button, button[z-button], a[z-button]',\n  imports: [NgIcon],\n  template: `\n    @if (zLoading()) {\n      <ng-icon name=\"lucideLoaderCircle\" class=\"animate-spin duration-2000\" />\n    }\n    <ng-content />\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  encapsulation: ViewEncapsulation.None,\n  viewProviders: [provideIcons({ lucideLoaderCircle })],\n  host: {\n    'data-slot': 'button',\n    '[class]': 'classes()',\n    '[attr.data-disabled]': 'isNotInsideOfButtonOrLink() && zDisabled() || null',\n    '[attr.data-icon-only]': 'iconOnly() || null',\n    '[attr.data-size]': 'zSize()',\n    '[attr.data-variant]': 'zType()',\n    '[attr.aria-disabled]': 'isNotInsideOfButtonOrLink() && zDisabled() || null',\n    '[attr.disabled]': 'isNotInsideOfButtonOrLink() && zDisabled() ? \"\" : null',\n    '[attr.role]': 'isNotInsideOfButtonOrLink() ? \"button\" : null',\n    '[attr.tabindex]': 'isNotInsideOfButtonOrLink() ? \"0\" : null',\n  },\n  exportAs: 'zButton',\n})\nexport class ZardButtonComponent implements OnDestroy {\n  private readonly elementRef = inject(ElementRef<HTMLElement>);\n\n  readonly zType = input<ZardButtonTypeVariants>('default');\n  readonly zSize = input<ZardButtonSizeVariants>('default');\n  readonly zShape = input<ZardButtonShapeVariants>('default');\n  readonly class = input<ClassValue>('');\n  readonly zLoading = input(false, { transform: booleanAttribute });\n  readonly zDisabled = input(false, { transform: booleanAttribute });\n\n  private readonly iconOnlyState = signal(false);\n  readonly iconOnly = this.iconOnlyState.asReadonly();\n\n  private _mutationObserver: MutationObserver | null = null;\n\n  constructor() {\n    afterNextRender(() => {\n      if (typeof window === 'undefined' || typeof MutationObserver === 'undefined') {\n        return;\n      }\n\n      const check = () => {\n        const el = this.elementRef.nativeElement;\n        const hasIcon = el.querySelector('ng-icon') !== null;\n        const children = Array.from<Node>(el.childNodes);\n        const hasText = children.some(node => {\n          if (node.nodeType === 3) {\n            return node.textContent?.trim() !== '';\n          }\n          if (node.nodeType === 1) {\n            const element = node as HTMLElement;\n            if (element.matches('ng-icon')) {\n              return false;\n            }\n            return element.textContent?.trim() !== '';\n          }\n          return false;\n        });\n\n        this.iconOnlyState.set(hasIcon && !hasText);\n      };\n\n      check();\n      this._mutationObserver = new MutationObserver(check);\n      this._mutationObserver.observe(this.elementRef.nativeElement, {\n        childList: true,\n        characterData: true,\n        subtree: true,\n      });\n    });\n  }\n\n  ngOnDestroy(): void {\n    if (this._mutationObserver) {\n      this._mutationObserver.disconnect();\n      this._mutationObserver = null;\n    }\n  }\n\n  protected readonly classes = computed(() =>\n    mergeClasses(\n      buttonVariants({\n        zType: this.zType(),\n        zSize: this.zSize(),\n        zShape: this.zShape(),\n        zLoading: this.zLoading(),\n        zDisabled: this.zDisabled(),\n      }),\n      this.class(),\n    ),\n  );\n\n  protected readonly isNotInsideOfButtonOrLink = computed(() => {\n    // Evaluated once; assumes component parent doesn't change after mount\n    const zardButtonElement = this.elementRef.nativeElement;\n    if (zardButtonElement.parentElement) {\n      const { tagName } = zardButtonElement.parentElement;\n      return tagName !== 'BUTTON' && tagName !== 'A';\n    }\n    return true;\n  });\n}\n"
    },
    {
      "name": "button.variants.ts",
      "content": "import { cva, type VariantProps } from 'class-variance-authority';\n\nimport { mergeClasses } from '@/shared/utils/merge-classes';\n\nexport const buttonVariants = cva(\n  mergeClasses(\n    \"group/button inline-flex shrink-0 items-center justify-center rounded-lg border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n  ),\n  {\n    variants: {\n      zType: {\n        default: 'bg-primary text-primary-foreground [a]:hover:bg-primary/80',\n        destructive:\n          'bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40',\n        outline:\n          'border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:border-input dark:bg-input/30 dark:hover:bg-input/50',\n        secondary:\n          'bg-secondary text-secondary-foreground hover:bg-secondary/80 aria-expanded:bg-secondary aria-expanded:text-secondary-foreground',\n        ghost:\n          'hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50',\n        link: 'text-primary underline-offset-4 hover:underline',\n      },\n      zSize: {\n        default: 'h-8 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',\n        xs: \"h-6 gap-1 rounded-[min(var(--radius-md),10px)] px-2 text-xs in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3\",\n        sm: \"h-7 gap-1 rounded-[min(var(--radius-md),12px)] px-2.5 text-[0.8rem] in-data-[slot=button-group]:rounded-lg has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 [&_svg:not([class*='size-'])]:size-3.5\",\n        lg: 'h-9 gap-1.5 px-2.5 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2',\n        icon: 'size-8',\n        'icon-xs':\n          \"size-6 rounded-[min(var(--radius-md),10px)] in-data-[slot=button-group]:rounded-lg [&_svg:not([class*='size-'])]:size-3\",\n        'icon-sm': 'size-7 rounded-[min(var(--radius-md),12px)] in-data-[slot=button-group]:rounded-lg',\n        'icon-lg': 'size-9',\n      },\n      zShape: {\n        default: 'rounded-md',\n        circle: 'rounded-full',\n        square: 'rounded-none',\n      },\n      zLoading: {\n        true: 'pointer-events-none opacity-50',\n      },\n      zDisabled: {\n        true: 'pointer-events-none opacity-50',\n      },\n    },\n    defaultVariants: {\n      zType: 'default',\n      zSize: 'default',\n      zShape: 'default',\n    },\n  },\n);\nexport type ZardButtonShapeVariants = NonNullable<VariantProps<typeof buttonVariants>['zShape']>;\nexport type ZardButtonSizeVariants = NonNullable<VariantProps<typeof buttonVariants>['zSize']>;\nexport type ZardButtonTypeVariants = NonNullable<VariantProps<typeof buttonVariants>['zType']>;\n"
    },
    {
      "name": "index.ts",
      "content": "export * from './button.component';\nexport * from './button.variants';\n"
    }
  ],
  "demos": [
    {
      "name": "as-child.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-as-child',\n  imports: [ZardButtonComponent],\n  template: `\n    <a z-button href=\"/login\">Login</a>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoButtonAsChildComponent {}\n"
    },
    {
      "name": "button-group.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport {\n  lucideArchive,\n  lucideArrowLeft,\n  lucideCalendarPlus,\n  lucideChevronRight,\n  lucideClock,\n  lucideEllipsis,\n  lucideListFilter,\n  lucideMailCheck,\n  lucideTag,\n  lucideTrash2,\n} from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardButtonGroupComponent } from '@/shared/components/button-group/button-group.component';\nimport { ZardMenuImports } from '@/shared/components/menu/menu.imports';\nimport { ZardSeparatorComponent } from '@/shared/components/separator';\n\n@Component({\n  selector: 'z-demo-button-button-group',\n  imports: [ZardButtonGroupComponent, ZardButtonComponent, NgIcon, ZardMenuImports, ZardSeparatorComponent],\n  template: `\n    <z-button-group>\n      <z-button-group class=\"hidden sm:flex\">\n        <button type=\"button\" z-button zType=\"outline\" zSize=\"icon\" aria-label=\"Go Back\">\n          <ng-icon name=\"lucideArrowLeft\" />\n        </button>\n      </z-button-group>\n\n      <z-button-group>\n        <button type=\"button\" z-button zType=\"outline\">Archive</button>\n        <button type=\"button\" z-button zType=\"outline\">Report</button>\n      </z-button-group>\n\n      <z-button-group>\n        <button type=\"button\" z-button zType=\"outline\">Snooze</button>\n        <button\n          type=\"button\"\n          z-button\n          zType=\"outline\"\n          zSize=\"icon\"\n          aria-label=\"More Options\"\n          z-menu\n          [zMenuTriggerFor]=\"menu\"\n        >\n          <ng-icon name=\"lucideEllipsis\" />\n\n          <ng-template #menu>\n            <div z-menu-content class=\"w-40\">\n              <button type=\"button\" z-menu-item>\n                <ng-icon name=\"lucideMailCheck\" />\n                Mark as Read\n              </button>\n              <button type=\"button\" z-menu-item>\n                <ng-icon name=\"lucideArchive\" />\n                Archive\n              </button>\n\n              <z-separator class=\"my-2\" />\n\n              <button type=\"button\" z-menu-item>\n                <ng-icon name=\"lucideClock\" />\n                Snooze\n              </button>\n              <button type=\"button\" z-menu-item>\n                <ng-icon name=\"lucideCalendarPlus\" />\n                Add to Calendar\n              </button>\n              <button type=\"button\" z-menu-item>\n                <ng-icon name=\"lucideListFilter\" />\n                Add to List\n              </button>\n              <button\n                type=\"button\"\n                z-menu-item\n                z-menu\n                [zMenuTriggerFor]=\"labelMenu\"\n                zPlacement=\"rightTop\"\n                class=\"justify-between\"\n              >\n                <div class=\"flex items-center gap-2\">\n                  <ng-icon name=\"lucideTag\" />\n                  Label As...\n                </div>\n                <ng-icon name=\"lucideChevronRight\" />\n\n                <ng-template #labelMenu>\n                  <div z-menu-content class=\"w-40\">\n                    <button type=\"button\" z-menu-item>Personal</button>\n                    <button type=\"button\" z-menu-item>Work</button>\n                    <button type=\"button\" z-menu-item>Other</button>\n                  </div>\n                </ng-template>\n              </button>\n\n              <z-separator class=\"my-2\" />\n\n              <button type=\"button\" z-menu-item class=\"text-destructive\">\n                <ng-icon name=\"lucideTrash2\" />\n                Trash\n              </button>\n            </div>\n          </ng-template>\n        </button>\n      </z-button-group>\n    </z-button-group>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [\n    provideIcons({\n      lucideArrowLeft,\n      lucideEllipsis,\n      lucideMailCheck,\n      lucideArchive,\n      lucideClock,\n      lucideCalendarPlus,\n      lucideListFilter,\n      lucideTag,\n      lucideChevronRight,\n      lucideTrash2,\n    }),\n  ],\n})\nexport class ZardDemoButtonButtonGroupComponent {}\n"
    },
    {
      "name": "default.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-default',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button>Button</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoButtonDefaultComponent {}\n"
    },
    {
      "name": "destructive.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-destructive',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"destructive\">Destructive</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoButtonDestructiveComponent {}\n"
    },
    {
      "name": "ghost.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-ghost',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"ghost\">Ghost</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoButtonGhostComponent {}\n"
    },
    {
      "name": "icon.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideCircleFadingArrowUp } from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-icon',\n  imports: [ZardButtonComponent, NgIcon],\n  template: `\n    <button z-button zType=\"outline\" zSize=\"icon\" aria-label=\"Submit\">\n      <ng-icon name=\"lucideCircleFadingArrowUp\" />\n    </button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [provideIcons({ lucideCircleFadingArrowUp })],\n})\nexport class ZardDemoButtonIconComponent {}\n"
    },
    {
      "name": "link.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-link',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"link\">Link</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoButtonLinkComponent {}\n"
    },
    {
      "name": "outline.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-outline',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"outline\">Outline</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoButtonOutlineComponent {}\n"
    },
    {
      "name": "preview.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideArrowUp } from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-preview',\n  imports: [ZardButtonComponent, NgIcon],\n  template: `\n    <div class=\"flex flex-wrap items-center gap-2 md:flex-row\">\n      <button z-button zType=\"outline\">Button</button>\n      <button z-button zType=\"outline\" zSize=\"icon\" aria-label=\"Submit\">\n        <ng-icon name=\"lucideArrowUp\" />\n      </button>\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [provideIcons({ lucideArrowUp })],\n})\nexport class ZardDemoButtonPreviewComponent {}\n"
    },
    {
      "name": "rounded.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideArrowUp } from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-rounded',\n  imports: [ZardButtonComponent, NgIcon],\n  template: `\n    <div class=\"flex flex-col gap-8\">\n      <button z-button zType=\"outline\" zSize=\"icon\" class=\"rounded-full\" aria-label=\"Submit\">\n        <ng-icon name=\"lucideArrowUp\" />\n      </button>\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [provideIcons({ lucideArrowUp })],\n})\nexport class ZardDemoButtonRoundedComponent {}\n"
    },
    {
      "name": "secondary.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-secondary',\n  imports: [ZardButtonComponent],\n  template: `\n    <button z-button zType=\"secondary\">Secondary</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoButtonSecondaryComponent {}\n"
    },
    {
      "name": "size.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideArrowUpRight } from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-size',\n  imports: [ZardButtonComponent, NgIcon],\n  template: `\n    <div class=\"flex flex-col items-start gap-8 sm:flex-row\">\n      <div class=\"flex items-start gap-2\">\n        <button z-button zSize=\"xs\" zType=\"outline\">Extra Small</button>\n        <button z-button zSize=\"icon-xs\" zType=\"outline\" aria-label=\"Submit\">\n          <ng-icon name=\"lucideArrowUpRight\" />\n        </button>\n      </div>\n      <div class=\"flex items-start gap-2\">\n        <button z-button zSize=\"sm\" zType=\"outline\">Small</button>\n        <button z-button zSize=\"icon-sm\" zType=\"outline\" aria-label=\"Submit\">\n          <ng-icon name=\"lucideArrowUpRight\" />\n        </button>\n      </div>\n      <div class=\"flex items-start gap-2\">\n        <button z-button zType=\"outline\">Default</button>\n        <button z-button zSize=\"icon\" zType=\"outline\" aria-label=\"Submit\">\n          <ng-icon name=\"lucideArrowUpRight\" />\n        </button>\n      </div>\n      <div class=\"flex items-start gap-2\">\n        <button z-button zType=\"outline\" zSize=\"lg\">Large</button>\n        <button z-button zSize=\"icon-lg\" zType=\"outline\" aria-label=\"Submit\">\n          <ng-icon name=\"lucideArrowUpRight\" />\n        </button>\n      </div>\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [provideIcons({ lucideArrowUpRight })],\n})\nexport class ZardDemoButtonSizeComponent {}\n"
    },
    {
      "name": "spinner.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideLoaderCircle } from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-spinner',\n  imports: [ZardButtonComponent, NgIcon],\n  template: `\n    <div class=\"flex gap-2\">\n      <button z-button zType=\"outline\" [zLoading]=\"true\" [zDisabled]=\"true\">Generating</button>\n      <button z-button zType=\"secondary\" [zDisabled]=\"true\">\n        Downloading\n        <ng-icon name=\"lucideLoaderCircle\" class=\"animate-spin\" />\n      </button>\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [provideIcons({ lucideLoaderCircle })],\n})\nexport class ZardDemoButtonSpinnerComponent {}\n"
    },
    {
      "name": "with-icon.ts",
      "content": "import { ChangeDetectionStrategy, Component } from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideGitBranch } from '@ng-icons/lucide';\n\nimport { ZardButtonComponent } from '../button.component';\n\n@Component({\n  selector: 'z-demo-button-with-icon',\n  imports: [ZardButtonComponent, NgIcon],\n  template: `\n    <button z-button zType=\"outline\" zSize=\"sm\">\n      <ng-icon name=\"lucideGitBranch\" />\n      New Branch\n    </button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [provideIcons({ lucideGitBranch })],\n})\nexport class ZardDemoButtonWithIconComponent {}\n"
    }
  ]
}
