{
  "name": "dialog",
  "type": "registry:component",
  "files": [
    {
      "name": "dialog.component.ts",
      "content": "import { A11yModule } from '@angular/cdk/a11y';\nimport { OverlayModule } from '@angular/cdk/overlay';\nimport {\n  BasePortalOutlet,\n  CdkPortalOutlet,\n  type ComponentPortal,\n  PortalModule,\n  type TemplatePortal,\n} from '@angular/cdk/portal';\nimport {\n  ChangeDetectionStrategy,\n  Component,\n  type ComponentRef,\n  computed,\n  ElementRef,\n  type EmbeddedViewRef,\n  type EventEmitter,\n  inject,\n  output,\n  type TemplateRef,\n  type Type,\n  viewChild,\n  type ViewContainerRef,\n} from '@angular/core';\n\nimport { NgIcon, provideIcons } from '@ng-icons/core';\nimport { lucideX } from '@ng-icons/lucide';\nimport type { ClassValue } from 'clsx';\n\nimport { ZardIdDirective } from '@/shared/core';\nimport { mergeClasses, noopFn } from '@/shared/utils/merge-classes';\n\nimport type { ZardDialogRef } from './dialog-ref';\nimport {\n  dialogDescriptionVariants,\n  dialogFooterVariants,\n  dialogHeaderVariants,\n  dialogTitleVariants,\n  dialogVariants,\n} from './dialog.variants';\nimport { ZardButtonComponent } from '../button/button.component';\n\nexport type OnClickCallback<T> = (instance: T) => false | void | object;\nexport class ZardDialogOptions<T, U> {\n  zCancelIcon?: string;\n  zCancelText?: string | null;\n  zClosable?: boolean;\n  zContent?: string | TemplateRef<T> | Type<T>;\n  zCustomClasses?: ClassValue;\n  zData?: U;\n  zDescription?: string;\n  /** Animation duration (ms) used when closing. Defaults to 100 (matches CSS transition). */\n  zDuration?: number;\n  zHideFooter?: boolean;\n  zMaskClosable?: boolean;\n  zOkDestructive?: boolean;\n  zOkDisabled?: boolean;\n  zOkIcon?: string;\n  zOkText?: string | null;\n  zOnCancel?: EventEmitter<T> | OnClickCallback<T> = noopFn;\n  zOnOk?: EventEmitter<T> | OnClickCallback<T> = noopFn;\n  zTitle?: string | TemplateRef<T>;\n  zViewContainerRef?: ViewContainerRef;\n  zWidth?: string;\n}\n\n@Component({\n  selector: 'z-dialog',\n  imports: [A11yModule, OverlayModule, PortalModule, ZardButtonComponent, ZardIdDirective, NgIcon],\n  template: `\n    <ng-container zardId=\"z-dialog\" #idRef=\"zardId\">\n      @if (config.zClosable || config.zClosable === undefined) {\n        <button\n          type=\"button\"\n          data-testid=\"z-close-header-button\"\n          data-slot=\"dialog-close\"\n          z-button\n          zType=\"ghost\"\n          zSize=\"icon-sm\"\n          class=\"absolute top-2 right-2\"\n          (click)=\"onCloseClick()\"\n        >\n          <ng-icon name=\"lucideX\" class=\"size-4!\" />\n          <span class=\"sr-only\">Close</span>\n        </button>\n      }\n\n      @if (config.zTitle || config.zDescription) {\n        <header [class]=\"headerClasses()\" data-slot=\"dialog-header\">\n          @if (config.zTitle) {\n            <h4 data-testid=\"z-title\" data-slot=\"dialog-title\" [class]=\"titleClasses()\" [id]=\"idRef.id() + '-title'\">\n              {{ config.zTitle }}\n            </h4>\n\n            @if (config.zDescription) {\n              <p\n                data-testid=\"z-description\"\n                data-slot=\"dialog-description\"\n                [class]=\"descriptionClasses()\"\n                [id]=\"idRef.id() + '-description'\"\n              >\n                {{ config.zDescription }}\n              </p>\n            }\n          }\n        </header>\n      }\n\n      <main class=\"flex flex-col space-y-4\">\n        <ng-template cdkPortalOutlet />\n\n        @if (isStringContent()) {\n          <!-- Angular auto-sanitizes [innerHTML] by default; scripts/event handlers are stripped. -->\n          <div data-testid=\"z-content\" [innerHTML]=\"config.zContent\"></div>\n        }\n      </main>\n\n      @if (!config.zHideFooter) {\n        <footer [class]=\"footerClasses()\" data-slot=\"dialog-footer\">\n          @if (config.zCancelText !== null) {\n            <button type=\"button\" data-testid=\"z-cancel-button\" z-button zType=\"outline\" (click)=\"onCloseClick()\">\n              @if (config.zCancelIcon) {\n                @if (isSvgString(config.zCancelIcon)) {\n                  <ng-icon [svg]=\"config.zCancelIcon\" class=\"size-4!\" />\n                } @else {\n                  <ng-icon [name]=\"config.zCancelIcon\" class=\"size-4!\" />\n                }\n              }\n\n              {{ config.zCancelText ?? 'Cancel' }}\n            </button>\n          }\n\n          @if (config.zOkText !== null) {\n            <button\n              type=\"button\"\n              data-testid=\"z-ok-button\"\n              z-button\n              [zType]=\"config.zOkDestructive ? 'destructive' : 'default'\"\n              [zDisabled]=\"config.zOkDisabled\"\n              (click)=\"onOkClick()\"\n            >\n              @if (config.zOkIcon) {\n                @if (isSvgString(config.zOkIcon)) {\n                  <ng-icon [svg]=\"config.zOkIcon\" class=\"size-4!\" />\n                } @else {\n                  <ng-icon [name]=\"config.zOkIcon\" class=\"size-4!\" />\n                }\n              }\n\n              {{ config.zOkText ?? 'OK' }}\n            </button>\n          }\n        </footer>\n      }\n    </ng-container>\n  `,\n  styles: `\n    :host {\n      --z-dialog-duration: 100ms;\n      opacity: 1;\n      transform: scale(1);\n      transition:\n        opacity var(--z-dialog-duration) ease-out,\n        transform var(--z-dialog-duration) ease-out;\n    }\n\n    @starting-style {\n      :host {\n        opacity: 0;\n        transform: scale(0.9);\n      }\n    }\n\n    :host.dialog-leave {\n      opacity: 0;\n      transform: scale(0.9);\n      transition:\n        opacity var(--z-dialog-duration) ease-in,\n        transform var(--z-dialog-duration) ease-in;\n    }\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  viewProviders: [provideIcons({ lucideX })],\n  host: {\n    '[class]': 'classes()',\n    '[style.width]': 'config.zWidth ? config.zWidth : null',\n    '[style.--z-dialog-duration]': 'durationCss()',\n    'data-slot': 'dialog-content',\n    role: 'dialog',\n    'aria-modal': 'true',\n    '[attr.aria-labelledby]': 'titleId()',\n    '[attr.aria-describedby]': 'descriptionId()',\n    cdkTrapFocus: 'true',\n    cdkTrapFocusAutoCapture: 'true',\n  },\n  exportAs: 'zDialog',\n})\nexport class ZardDialogComponent<T, U> extends BasePortalOutlet {\n  private readonly host = inject(ElementRef<HTMLElement>);\n  protected readonly config = inject(ZardDialogOptions<T, U>);\n  private readonly idRef = viewChild.required<ZardIdDirective>('idRef');\n\n  protected readonly classes = computed(() => mergeClasses(dialogVariants(), this.config.zCustomClasses));\n  protected readonly headerClasses = computed(() => dialogHeaderVariants());\n  protected readonly titleClasses = computed(() => dialogTitleVariants());\n  protected readonly descriptionClasses = computed(() => dialogDescriptionVariants());\n  protected readonly footerClasses = computed(() => dialogFooterVariants());\n  protected readonly isStringContent = computed(() => typeof this.config.zContent === 'string');\n  protected readonly titleId = computed(() => (this.config.zTitle ? `${this.idRef().id()}-title` : null));\n  protected readonly descriptionId = computed(() =>\n    this.config.zDescription ? `${this.idRef().id()}-description` : null,\n  );\n\n  protected readonly durationCss = computed(() =>\n    this.config.zDuration !== undefined ? `${this.config.zDuration}ms` : null,\n  );\n\n  protected isSvgString(icon: string): boolean {\n    return /^\\s*<svg/i.test(icon);\n  }\n\n  dialogRef?: ZardDialogRef<T>;\n\n  readonly portalOutlet = viewChild.required(CdkPortalOutlet);\n\n  okTriggered = output<void>();\n  cancelTriggered = output<void>();\n\n  getNativeElement(): HTMLElement {\n    return this.host.nativeElement;\n  }\n\n  attachComponentPortal<C>(portal: ComponentPortal<C>): ComponentRef<C> {\n    if (this.portalOutlet().hasAttached()) {\n      throw new Error('Attempting to attach modal content after content is already attached');\n    }\n    return this.portalOutlet().attachComponentPortal(portal);\n  }\n\n  attachTemplatePortal<C>(portal: TemplatePortal<C>): EmbeddedViewRef<C> {\n    if (this.portalOutlet().hasAttached()) {\n      throw new Error('Attempting to attach modal content after content is already attached');\n    }\n    return this.portalOutlet().attachTemplatePortal(portal);\n  }\n\n  onOkClick() {\n    this.okTriggered.emit();\n  }\n\n  onCloseClick() {\n    this.cancelTriggered.emit();\n  }\n}\n"
    },
    {
      "name": "dialog.service.ts",
      "content": "import { type ComponentType, Overlay, OverlayConfig, OverlayRef } from '@angular/cdk/overlay';\nimport { ComponentPortal, TemplatePortal } from '@angular/cdk/portal';\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n  inject,\n  Injectable,\n  InjectionToken,\n  Injector,\n  PLATFORM_ID,\n  TemplateRef,\n  type ViewContainerRef,\n} from '@angular/core';\n\nimport { ZardDialogRef } from './dialog-ref';\nimport { ZardDialogComponent, ZardDialogOptions } from './dialog.component';\n\ntype ContentType<T> = ComponentType<T> | TemplateRef<T> | string;\n\nexport const Z_MODAL_DATA = new InjectionToken<unknown>('Z_MODAL_DATA');\n\n/**\n * Type-safe accessor for the data passed to a dialog via {@link ZardDialogOptions.zData}.\n *\n * Must be called from an injection context (component constructor / field initializer).\n *\n * @example\n * private readonly data = injectDialogData<MyData>();\n */\nexport function injectDialogData<T>(): T {\n  return inject(Z_MODAL_DATA) as T;\n}\n\n@Injectable({\n  providedIn: 'root',\n})\nexport class ZardDialogService {\n  private readonly overlay = inject(Overlay);\n  private readonly injector = inject(Injector);\n  private readonly platformId = inject(PLATFORM_ID);\n\n  /**\n   * Opens a dialog with the given configuration.\n   *\n   * On non-browser platforms (SSR / build) the returned `ZardDialogRef` is a\n   * no-op that resolves cleanly when calling `close()`.\n   */\n  create<T, U = unknown>(config: ZardDialogOptions<T, U>): ZardDialogRef<T> {\n    if (!isPlatformBrowser(this.platformId)) {\n      return new ZardDialogRef<T>(null, config, null, this.platformId);\n    }\n\n    const overlayRef = this.createOverlay();\n    const dialogContainer = this.attachDialogContainer<T, U>(overlayRef, config);\n    const dialogRef = this.attachDialogContent<T, U>(\n      config.zContent as ContentType<T>,\n      dialogContainer,\n      overlayRef,\n      config,\n    );\n\n    dialogContainer.dialogRef = dialogRef;\n\n    return dialogRef;\n  }\n\n  private createOverlay(): OverlayRef {\n    return this.overlay.create(\n      new OverlayConfig({\n        hasBackdrop: true,\n        backdropClass: ['bg-black/10', 'supports-backdrop-filter:backdrop-blur-xs'],\n        positionStrategy: this.overlay.position().global(),\n      }),\n    );\n  }\n\n  private attachDialogContainer<T, U>(overlayRef: OverlayRef, config: ZardDialogOptions<T, U>) {\n    const injector = Injector.create({\n      parent: this.injector,\n      providers: [\n        { provide: OverlayRef, useValue: overlayRef },\n        { provide: ZardDialogOptions, useValue: config },\n      ],\n    });\n\n    const containerPortal = new ComponentPortal<ZardDialogComponent<T, U>>(\n      ZardDialogComponent,\n      config.zViewContainerRef,\n      injector,\n    );\n\n    return overlayRef.attach<ZardDialogComponent<T, U>>(containerPortal).instance;\n  }\n\n  private attachDialogContent<T, U>(\n    componentOrTemplateRef: ContentType<T>,\n    dialogContainer: ZardDialogComponent<T, U>,\n    overlayRef: OverlayRef,\n    config: ZardDialogOptions<T, U>,\n  ): ZardDialogRef<T> {\n    const dialogRef = new ZardDialogRef<T>(overlayRef, config, dialogContainer, this.platformId);\n\n    if (componentOrTemplateRef instanceof TemplateRef) {\n      // CDK's TemplatePortal type requires a ViewContainerRef even though it tolerates null at runtime,\n      // and types the template context as T (the template's data shape) — we expose `dialogRef` instead.\n      const vcr = (config.zViewContainerRef ?? null) as unknown as ViewContainerRef;\n      const ctx = { dialogRef } as unknown as T;\n      dialogContainer.attachTemplatePortal(new TemplatePortal(componentOrTemplateRef, vcr, ctx));\n    } else if (typeof componentOrTemplateRef !== 'string') {\n      const injector = this.createInjector<T, U>(dialogRef, config);\n      const contentRef = dialogContainer.attachComponentPortal<T>(\n        new ComponentPortal(componentOrTemplateRef, config.zViewContainerRef, injector),\n      );\n      dialogRef.setComponentInstance(contentRef.instance);\n    }\n\n    return dialogRef;\n  }\n\n  private createInjector<T, U>(dialogRef: ZardDialogRef<T>, config: ZardDialogOptions<T, U>): Injector {\n    return Injector.create({\n      parent: this.injector,\n      providers: [\n        { provide: ZardDialogRef, useValue: dialogRef },\n        { provide: Z_MODAL_DATA, useValue: config.zData },\n      ],\n    });\n  }\n}\n"
    },
    {
      "name": "dialog-ref.ts",
      "content": "import type { OverlayRef } from '@angular/cdk/overlay';\nimport { isPlatformBrowser } from '@angular/common';\nimport { EventEmitter, signal } from '@angular/core';\nimport { outputToObservable } from '@angular/core/rxjs-interop';\n\nimport { filter, takeUntil } from 'rxjs';\n\nimport type { ZardDialogComponent, ZardDialogOptions } from './dialog.component';\n\nconst enum eTriggerAction {\n  CANCEL = 'cancel',\n  OK = 'ok',\n}\n\nconst ESCAPE_KEYS = ['Escape', 'Esc'] as const;\n\n/**\n * Reference to a dialog opened via {@link ZardDialogService}.\n *\n * Exposes signals for reactive consumption (`isClosing`, `result`,\n * `componentInstance`) and methods for closing the dialog.\n *\n * Multiple open dialogs are tracked in a private stack so that pressing\n * Escape only closes the topmost one.\n */\nexport class ZardDialogRef<T = unknown, R = unknown, U = unknown> {\n  /** Stack of currently open dialogs. The last entry is the topmost. */\n  private static readonly stack: ZardDialogRef[] = [];\n\n  /** Element focused before the dialog opened, used to restore focus on close. */\n  private readonly previouslyFocusedElement: HTMLElement | null;\n\n  /** Animation duration (ms) used when closing. Mirrors the CSS transition. */\n  private readonly animationDuration: number;\n\n  /** Pending dispose timer; cleared if dispose runs early or twice. */\n  private disposeTimer: ReturnType<typeof setTimeout> | null = null;\n  private disposed = false;\n\n  private readonly _isClosing = signal(false);\n  private readonly _result = signal<R | undefined>(undefined);\n  private readonly _componentInstance = signal<T | null>(null);\n\n  /** True from the moment {@link close} is called until the overlay is disposed. */\n  readonly isClosing = this._isClosing.asReadonly();\n  /** Result passed to {@link close}, available after it's called. */\n  readonly result = this._result.asReadonly();\n  /** Instance of the component projected as content, or null for templates / strings. */\n  readonly componentInstance = this._componentInstance.asReadonly();\n\n  constructor(\n    private readonly overlayRef: OverlayRef | null,\n    private readonly config: ZardDialogOptions<T, U>,\n    private readonly containerInstance: ZardDialogComponent<T, U> | null,\n    private readonly platformId: object,\n  ) {\n    this.animationDuration = config.zDuration ?? 100;\n    this.previouslyFocusedElement = isPlatformBrowser(platformId)\n      ? (document.activeElement as HTMLElement | null)\n      : null;\n\n    if (!this.overlayRef || !this.containerInstance) return;\n\n    ZardDialogRef.stack.push(this as unknown as ZardDialogRef);\n\n    const detached$ = this.overlayRef.detachments();\n\n    // If the overlay is torn down externally (parent destroyed, app shutdown, etc.),\n    // ensure stack/focus state is cleaned up.\n    detached$.subscribe(() => this.dispose());\n\n    outputToObservable(this.containerInstance.cancelTriggered)\n      .pipe(takeUntil(detached$))\n      .subscribe(() => this.trigger(eTriggerAction.CANCEL));\n    outputToObservable(this.containerInstance.okTriggered)\n      .pipe(takeUntil(detached$))\n      .subscribe(() => this.trigger(eTriggerAction.OK));\n\n    if (config.zMaskClosable ?? true) {\n      this.overlayRef\n        .outsidePointerEvents()\n        .pipe(takeUntil(detached$))\n        .subscribe(() => this.close());\n    }\n\n    this.overlayRef\n      .keydownEvents()\n      .pipe(\n        filter(event => ESCAPE_KEYS.includes(event.key as (typeof ESCAPE_KEYS)[number])),\n        takeUntil(detached$),\n      )\n      .subscribe(event => {\n        if (this.isTopmost()) {\n          event.preventDefault();\n          this.close();\n        }\n      });\n  }\n\n  /** Internal: set the component instance once attached. */\n  setComponentInstance(instance: T | null) {\n    this._componentInstance.set(instance);\n  }\n\n  close(result?: R) {\n    if (this._isClosing()) return;\n\n    this._isClosing.set(true);\n    this._result.set(result);\n\n    if (isPlatformBrowser(this.platformId) && this.containerInstance) {\n      const hostElement = this.containerInstance.getNativeElement();\n      hostElement.classList.add('dialog-leave');\n    }\n\n    this.disposeTimer = setTimeout(() => this.dispose(), this.animationDuration);\n  }\n\n  private dispose() {\n    if (this.disposed) return;\n    this.disposed = true;\n\n    if (this.disposeTimer !== null) {\n      clearTimeout(this.disposeTimer);\n      this.disposeTimer = null;\n    }\n\n    if (this.overlayRef) {\n      if (this.overlayRef.hasAttached()) {\n        this.overlayRef.detachBackdrop();\n      }\n      this.overlayRef.dispose();\n    }\n\n    const idx = ZardDialogRef.stack.indexOf(this as unknown as ZardDialogRef);\n    if (idx >= 0) ZardDialogRef.stack.splice(idx, 1);\n\n    if (isPlatformBrowser(this.platformId) && this.previouslyFocusedElement?.isConnected) {\n      this.previouslyFocusedElement.focus();\n    }\n  }\n\n  private isTopmost(): boolean {\n    return ZardDialogRef.stack[ZardDialogRef.stack.length - 1] === (this as unknown as ZardDialogRef);\n  }\n\n  private trigger(action: eTriggerAction) {\n    const trigger = action === eTriggerAction.OK ? this.config.zOnOk : this.config.zOnCancel;\n\n    if (trigger instanceof EventEmitter) {\n      trigger.emit(this._componentInstance() as T);\n    } else if (typeof trigger === 'function') {\n      const result = trigger(this._componentInstance() as T) as R | false;\n      if (result !== false) {\n        this.close(result as R);\n      }\n    } else {\n      this.close();\n    }\n  }\n}\n"
    },
    {
      "name": "dialog.variants.ts",
      "content": "import { cva, type VariantProps } from 'class-variance-authority';\n\nexport const dialogVariants = cva(\n  [\n    'fixed top-1/2 left-1/2 z-50 grid w-full max-w-[calc(100%-2rem)] -translate-x-1/2 -translate-y-1/2 gap-4',\n    'rounded-xl bg-popover p-4 text-sm text-popover-foreground ring-1 ring-foreground/10 outline-none',\n    'sm:max-w-sm',\n  ].join(' '),\n);\n\nexport const dialogHeaderVariants = cva('flex flex-col gap-2');\n\nexport const dialogTitleVariants = cva('text-base leading-none font-medium');\n\nexport const dialogDescriptionVariants = cva(\n  'text-sm text-muted-foreground *:[a]:underline *:[a]:underline-offset-[3px] *:[a]:hover:text-foreground',\n);\n\nexport const dialogFooterVariants = cva(\n  '-mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t bg-muted/50 p-4 sm:flex-row sm:justify-end',\n);\n\nexport type ZardDialogVariants = VariantProps<typeof dialogVariants>;\n"
    },
    {
      "name": "dialog.imports.ts",
      "content": "import { OverlayModule } from '@angular/cdk/overlay';\nimport { PortalModule } from '@angular/cdk/portal';\n\nimport { ZardButtonComponent } from '@/shared/components/button';\nimport { ZardDialogComponent } from '@/shared/components/dialog/dialog.component';\n\nexport const ZardDialogImports = [ZardButtonComponent, ZardDialogComponent, OverlayModule, PortalModule] as const;\n"
    },
    {
      "name": "index.ts",
      "content": "export { ZardDialogComponent, ZardDialogOptions } from './dialog.component';\nexport { type OnClickCallback as DialogOnClickCallback } from './dialog.component';\nexport * from './dialog.service';\nexport * from './dialog-ref';\nexport * from './dialog.variants';\nexport * from './dialog.imports';\n"
    }
  ],
  "registryDependencies": [
    "button"
  ],
  "demos": [
    {
      "name": "basic.ts",
      "content": "import { ChangeDetectionStrategy, Component, inject, type AfterViewInit } from '@angular/core';\nimport { FormControl, FormGroup, FormsModule, ReactiveFormsModule } from '@angular/forms';\n\nimport { ZardDialogImports } from '@/shared/components/dialog/dialog.imports';\n\nimport { ZardInputComponent } from '../../input/input.component';\nimport { Z_MODAL_DATA, ZardDialogService } from '../dialog.service';\n\ninterface iDialogData {\n  name: string;\n  username: string;\n}\n\n@Component({\n  selector: 'zard-demo-dialog-basic',\n  imports: [FormsModule, ReactiveFormsModule, ZardInputComponent],\n  template: `\n    <form [formGroup]=\"form\" class=\"grid gap-4\">\n      <div class=\"grid gap-3\">\n        <label for=\"name\" class=\"text-sm leading-none font-medium select-none\">Name</label>\n        <input z-input id=\"name\" formControlName=\"name\" />\n      </div>\n\n      <div class=\"grid gap-3\">\n        <label for=\"username\" class=\"text-sm leading-none font-medium select-none\">Username</label>\n        <input z-input id=\"username\" formControlName=\"username\" />\n      </div>\n    </form>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  exportAs: 'zardDemoDialogBasic',\n})\nexport class ZardDemoDialogBasicInputComponent implements AfterViewInit {\n  private zData = inject(Z_MODAL_DATA) as iDialogData;\n\n  form = new FormGroup({\n    name: new FormControl('Pedro Duarte'),\n    username: new FormControl('@peduarte'),\n  });\n\n  ngAfterViewInit(): void {\n    if (this.zData) {\n      this.form.patchValue(this.zData);\n    }\n  }\n}\n\n@Component({\n  imports: [ZardDialogImports],\n  template: `\n    <button type=\"button\" z-button zType=\"outline\" (click)=\"openDialog()\">Edit profile</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoDialogBasicComponent {\n  private dialogService = inject(ZardDialogService);\n\n  openDialog() {\n    this.dialogService.create({\n      zTitle: 'Edit Profile',\n      zDescription: `Make changes to your profile here. Click save when you're done.`,\n      zContent: ZardDemoDialogBasicInputComponent,\n      zData: {\n        name: 'Samuel Rizzon',\n        username: '@samuelrizzondev',\n      } as iDialogData,\n      zOkText: 'Save changes',\n      zOnOk: instance => {\n        console.log('Form submitted:', instance.form.value);\n      },\n    });\n  }\n}\n"
    },
    {
      "name": "custom-close.ts",
      "content": "import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardDialogRef } from '@/shared/components/dialog/dialog-ref';\nimport { ZardDialogService } from '@/shared/components/dialog/dialog.service';\nimport { ZardInputComponent } from '@/shared/components/input/input.component';\n\n@Component({\n  selector: 'zard-demo-dialog-custom-close-content',\n  imports: [ZardButtonComponent, ZardInputComponent],\n  template: `\n    <div class=\"flex items-center gap-2\">\n      <div class=\"grid flex-1 gap-2\">\n        <label for=\"link\" class=\"sr-only\">Link</label>\n        <input z-input id=\"link\" value=\"https://ui.zardui.com/docs/installation\" readonly />\n      </div>\n    </div>\n    <footer\n      class=\"bg-muted/50 -mx-4 -mb-4 flex flex-col-reverse gap-2 rounded-b-xl border-t p-4 sm:flex-row sm:justify-start\"\n    >\n      <button type=\"button\" z-button (click)=\"dialogRef.close()\">Close</button>\n    </footer>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoDialogCustomCloseContentComponent {\n  protected readonly dialogRef = inject(ZardDialogRef);\n}\n\n@Component({\n  selector: 'zard-demo-dialog-custom-close',\n  imports: [ZardButtonComponent],\n  template: `\n    <button type=\"button\" z-button zType=\"outline\" (click)=\"open()\">Share</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoDialogCustomCloseComponent {\n  private readonly dialogService = inject(ZardDialogService);\n\n  open() {\n    this.dialogService.create({\n      zTitle: 'Share link',\n      zDescription: 'Anyone who has this link will be able to view this.',\n      zContent: ZardDemoDialogCustomCloseContentComponent,\n      zHideFooter: true,\n    });\n  }\n}\n"
    },
    {
      "name": "no-close-button.ts",
      "content": "import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardDialogService } from '@/shared/components/dialog/dialog.service';\n\n@Component({\n  selector: 'zard-demo-dialog-no-close-button',\n  imports: [ZardButtonComponent],\n  template: `\n    <button type=\"button\" z-button zType=\"outline\" (click)=\"open()\">No Close Button</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoDialogNoCloseButtonComponent {\n  private readonly dialogService = inject(ZardDialogService);\n\n  open() {\n    this.dialogService.create({\n      zTitle: 'No Close Button',\n      zDescription: \"This dialog doesn't have a close button in the top-right corner.\",\n      zClosable: false,\n      zHideFooter: true,\n    });\n  }\n}\n"
    },
    {
      "name": "scrollable-content.ts",
      "content": "import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardDialogService } from '@/shared/components/dialog/dialog.service';\n\nconst PARAGRAPHS = Array.from({ length: 10 }).map(\n  () =>\n    'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',\n);\n\n@Component({\n  selector: 'zard-demo-dialog-scrollable-content-content',\n  template: `\n    <div class=\"no-scrollbar -mx-4 max-h-[50vh] overflow-y-auto px-4\">\n      @for (paragraph of paragraphs; track $index) {\n        <p class=\"mb-4 leading-normal\">{{ paragraph }}</p>\n      }\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoDialogScrollableContentInnerComponent {\n  protected readonly paragraphs = PARAGRAPHS;\n}\n\n@Component({\n  selector: 'zard-demo-dialog-scrollable-content',\n  imports: [ZardButtonComponent],\n  template: `\n    <button type=\"button\" z-button zType=\"outline\" (click)=\"open()\">Scrollable Content</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoDialogScrollableContentComponent {\n  private readonly dialogService = inject(ZardDialogService);\n\n  open() {\n    this.dialogService.create({\n      zTitle: 'Scrollable Content',\n      zDescription: 'This is a dialog with scrollable content.',\n      zContent: ZardDemoDialogScrollableContentInnerComponent,\n      zHideFooter: true,\n    });\n  }\n}\n"
    },
    {
      "name": "sticky-footer.ts",
      "content": "import { ChangeDetectionStrategy, Component, inject } from '@angular/core';\n\nimport { ZardButtonComponent } from '@/shared/components/button/button.component';\nimport { ZardDialogService } from '@/shared/components/dialog/dialog.service';\n\nconst PARAGRAPHS = Array.from({ length: 10 }).map(\n  () =>\n    'Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.',\n);\n\n@Component({\n  selector: 'zard-demo-dialog-sticky-footer-content',\n  template: `\n    <div class=\"no-scrollbar -mx-4 max-h-[50vh] overflow-y-auto px-4\">\n      @for (paragraph of paragraphs; track $index) {\n        <p class=\"mb-4 leading-normal\">{{ paragraph }}</p>\n      }\n    </div>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoDialogStickyFooterContentComponent {\n  protected readonly paragraphs = PARAGRAPHS;\n}\n\n@Component({\n  selector: 'zard-demo-dialog-sticky-footer',\n  imports: [ZardButtonComponent],\n  template: `\n    <button type=\"button\" z-button zType=\"outline\" (click)=\"open()\">Sticky Footer</button>\n  `,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n})\nexport class ZardDemoDialogStickyFooterComponent {\n  private readonly dialogService = inject(ZardDialogService);\n\n  open() {\n    this.dialogService.create({\n      zTitle: 'Sticky Footer',\n      zDescription: 'This dialog has a sticky footer that stays visible while the content scrolls.',\n      zContent: ZardDemoDialogStickyFooterContentComponent,\n      zCancelText: 'Close',\n      zOkText: null,\n    });\n  }\n}\n"
    }
  ]
}
