{
  "name": "core",
  "type": "registry:component",
  "files": [
    {
      "name": "directives/string-template-outlet/string-template-outlet.directive.ts",
      "content": "import {\n  Directive,\n  type EmbeddedViewRef,\n  inject,\n  input,\n  type OnDestroy,\n  TemplateRef,\n  ViewContainerRef,\n  effect,\n  type EffectRef,\n} from '@angular/core';\n\nexport function isTemplateRef<C = unknown>(value: unknown): value is TemplateRef<C> {\n  return value instanceof TemplateRef;\n}\n\nexport interface ZardStringTemplateOutletContext {\n  $implicit: unknown;\n  [key: string]: unknown;\n}\n\n@Directive({\n  selector: '[zStringTemplateOutlet]',\n  exportAs: 'zStringTemplateOutlet',\n})\nexport class ZardStringTemplateOutletDirective<T = unknown> implements OnDestroy {\n  private readonly viewContainer = inject(ViewContainerRef);\n  private readonly templateRef = inject(TemplateRef<void>);\n\n  private embeddedViewRef: EmbeddedViewRef<ZardStringTemplateOutletContext> | null = null;\n  private readonly context = {} as ZardStringTemplateOutletContext;\n\n  #isFirstChange = true;\n  #lastOutletWasTemplate = false;\n  #lastTemplateRef: TemplateRef<void> | null = null;\n  #lastContext?: ZardStringTemplateOutletContext;\n\n  readonly zStringTemplateOutletContext = input<ZardStringTemplateOutletContext | undefined>(undefined);\n  readonly zStringTemplateOutlet = input.required<T | TemplateRef<void>>();\n\n  #hasContextShapeChanged(context: ZardStringTemplateOutletContext | undefined): boolean {\n    if (!context) {\n      return false;\n    }\n    const prevCtxKeys = Object.keys(this.#lastContext || {});\n    const currCtxKeys = Object.keys(context || {});\n\n    if (prevCtxKeys.length === currCtxKeys.length) {\n      for (const propName of currCtxKeys) {\n        if (!prevCtxKeys.includes(propName)) {\n          return true;\n        }\n      }\n      return false;\n    } else {\n      return true;\n    }\n  }\n\n  #shouldViewBeRecreated(\n    stringTemplateOutlet: TemplateRef<void> | T,\n    stringTemplateOutletContext: ZardStringTemplateOutletContext | undefined,\n  ): boolean {\n    const isTemplate = isTemplateRef(stringTemplateOutlet);\n\n    const shouldOutletRecreate =\n      this.#isFirstChange ||\n      isTemplate !== this.#lastOutletWasTemplate ||\n      (isTemplate && stringTemplateOutlet !== this.#lastTemplateRef);\n\n    const shouldContextRecreate = this.#hasContextShapeChanged(stringTemplateOutletContext);\n    return shouldContextRecreate || shouldOutletRecreate;\n  }\n\n  #updateTrackingState(\n    stringTemplateOutlet: TemplateRef<void> | T,\n    stringTemplateOutletContext: ZardStringTemplateOutletContext | undefined,\n  ): void {\n    const isTemplate = isTemplateRef(stringTemplateOutlet);\n    if (this.#isFirstChange && !isTemplate) {\n      this.#isFirstChange = false;\n    }\n\n    if (stringTemplateOutletContext !== undefined) {\n      this.#lastContext = stringTemplateOutletContext;\n    }\n\n    this.#lastOutletWasTemplate = isTemplate;\n    this.#lastTemplateRef = isTemplate ? stringTemplateOutlet : null;\n  }\n\n  readonly #viewEffect: EffectRef = effect(() => {\n    const stringTemplateOutlet = this.zStringTemplateOutlet();\n    const stringTemplateOutletContext = this.zStringTemplateOutletContext();\n\n    if (!this.#isFirstChange && isTemplateRef(stringTemplateOutlet)) {\n      this.#isFirstChange = true;\n    }\n\n    if (!isTemplateRef(stringTemplateOutlet)) {\n      this.context['$implicit'] = stringTemplateOutlet as T;\n    }\n\n    const recreateView = this.#shouldViewBeRecreated(stringTemplateOutlet, stringTemplateOutletContext);\n    this.#updateTrackingState(stringTemplateOutlet, stringTemplateOutletContext);\n\n    if (recreateView) {\n      this.#recreateView(\n        stringTemplateOutlet as TemplateRef<ZardStringTemplateOutletContext>,\n        stringTemplateOutletContext,\n      );\n    } else {\n      this.#updateContext(stringTemplateOutlet, stringTemplateOutletContext);\n    }\n  });\n\n  #recreateView(\n    outlet: TemplateRef<ZardStringTemplateOutletContext>,\n    context: ZardStringTemplateOutletContext | undefined,\n  ): void {\n    this.viewContainer.clear();\n    if (isTemplateRef(outlet)) {\n      this.embeddedViewRef = this.viewContainer.createEmbeddedView(outlet, context);\n    } else {\n      this.embeddedViewRef = this.viewContainer.createEmbeddedView(this.templateRef, this.context);\n    }\n  }\n\n  #updateContext(outlet: TemplateRef<void> | T, context: ZardStringTemplateOutletContext | undefined): void {\n    const newCtx = isTemplateRef(outlet) ? context : this.context;\n    let oldCtx = this.embeddedViewRef?.context;\n\n    if (!oldCtx) {\n      oldCtx = newCtx;\n    } else if (newCtx && typeof newCtx === 'object') {\n      for (const propName of Object.keys(newCtx)) {\n        oldCtx[propName] = newCtx[propName];\n      }\n    }\n    this.#lastContext = oldCtx;\n  }\n\n  static ngTemplateContextGuard<T>(\n    _dir: ZardStringTemplateOutletDirective<T>,\n    _ctx: unknown,\n  ): _ctx is ZardStringTemplateOutletContext {\n    return true;\n  }\n\n  ngOnDestroy(): void {\n    this.#viewEffect.destroy();\n    this.viewContainer.clear();\n    this.embeddedViewRef = null;\n  }\n}\n"
    },
    {
      "name": "directives/id.directive.ts",
      "content": "import { Directive, inject, Injectable, input, computed } from '@angular/core';\n\n@Injectable({ providedIn: 'root' })\nclass ZardIdInternalService {\n  private counter = 0;\n  generate(prefix: string) {\n    return `${prefix}-${++this.counter}`;\n  }\n}\n\n@Directive({\n  selector: '[zardId]',\n  exportAs: 'zardId',\n})\nexport class ZardIdDirective {\n  private idService = inject(ZardIdInternalService);\n\n  readonly zardId = input('ssr');\n\n  readonly id = computed(() => this.idService.generate(this.zardId()));\n}\n"
    },
    {
      "name": "provider/event-manager-plugins/zard-debounce-event-manager-plugin.ts",
      "content": "import type { ListenerOptions } from '@angular/core';\nimport { EventManagerPlugin } from '@angular/platform-browser';\n\nexport class ZardDebounceEventManagerPlugin extends EventManagerPlugin {\n  override supports(eventName: string): boolean {\n    return /\\.debounce(?:\\.|$)/.test(eventName);\n  }\n\n  override addEventListener(\n    element: HTMLElement,\n    eventName: string,\n    handler: (event: Event) => void,\n    options?: ListenerOptions,\n    // eslint-disable-next-line\n  ): Function {\n    // Expected format: \"event.debounce.delay\" (e.g., \"input.debounce.150\")\n    // If delay is omitted or invalid, defaults to 300ms\n    const [event, , delay] = eventName.split('.');\n    const parsedDelay = Number.parseInt(delay);\n    const resolvedDelay = Number.isNaN(parsedDelay) ? 300 : parsedDelay;\n\n    let timeoutId!: ReturnType<typeof setTimeout>;\n    const listener = (event: Event) => {\n      clearTimeout(timeoutId);\n      timeoutId = setTimeout(() => handler(event), resolvedDelay);\n    };\n    const unsubscribe = this.manager.addEventListener(element, event, listener, options);\n    return () => {\n      clearTimeout(timeoutId);\n      unsubscribe();\n    };\n  }\n}\n"
    },
    {
      "name": "provider/event-manager-plugins/zard-event-manager-plugin.ts",
      "content": "import type { ListenerOptions } from '@angular/core';\nimport { EventManagerPlugin } from '@angular/platform-browser';\n\n/**\n * Angular EventManagerPlugin that provides event modifier syntax for templates.\n *\n * Supports modifiers: .prevent, .stop, .stop-immediate, .prevent-with-stop\n * Supports key filters: enter, escape, {enter,space}\n *\n * @example\n * Prevent default on any click\n * (click.prevent)=\"handler()\"\n *\n * @example\n * Prevent default only on Enter key\n * (keydown.enter.prevent)=\"handler()\"\n *\n * @example\n * Prevent default on more keys like Enter and Space key\n * (keydown.{enter,space}.prevent)=\"handler()\"\n *\n * @example\n * Stop propagation\n * (click.stop)=\"handler()\"\n */\nexport class ZardEventManagerPlugin extends EventManagerPlugin {\n  #keywords = ['prevent', 'stop', 'stop-immediate', 'prevent-with-stop'];\n\n  override supports(eventName: string): boolean {\n    return this.#keywords.some(keyword => eventName.endsWith(`.${keyword}`));\n  }\n\n  override addEventListener(\n    element: HTMLElement,\n    eventName: string,\n    handler: (event: Event) => void,\n    options?: ListenerOptions,\n    // eslint-disable-next-line\n  ): Function {\n    const { event, keyword, keys } = this.#provideEventFrom(eventName, this.#keywords);\n    return this.manager.addEventListener(\n      element,\n      event,\n      (event: Event) => {\n        const isKeyboardEvent = event instanceof KeyboardEvent;\n        const isElementDisabled = element.getAttribute('aria-disabled') === 'true';\n        const shouldApplyModifier =\n          (!keys.length || (isKeyboardEvent && keys.includes(event.key.toLowerCase()))) && !isElementDisabled;\n\n        if (shouldApplyModifier) {\n          switch (keyword) {\n            case 'stop':\n              event.stopPropagation();\n              break;\n            case 'stop-immediate':\n              event.stopImmediatePropagation();\n              break;\n            case 'prevent-with-stop':\n              event.preventDefault();\n              event.stopPropagation();\n              break;\n            default:\n              event.preventDefault();\n              break;\n          }\n        }\n        handler(event);\n      },\n      options,\n    );\n  }\n\n  #provideEventFrom(eventName: string, keywords: string[]): { event: string; keyword: string; keys: string[] } {\n    const eventNameSubstrings = eventName.split('.');\n    let event = '';\n    let keys: string[] = [];\n    let keyword = '';\n\n    for (const substring of eventNameSubstrings) {\n      if (substring.startsWith('{')) {\n        keys = this.#extractKeys(substring);\n        continue;\n      } else if (keywords.includes(substring)) {\n        keyword = substring;\n        break;\n      } else if (!event) {\n        event = substring;\n      } else {\n        event += `.${substring}`;\n      }\n    }\n\n    return { event, keyword, keys };\n  }\n\n  #extractKeys(substring: string): string[] {\n    const stringList = substring.substring(1, substring.length - 1);\n    return stringList\n      .split(',')\n      .map(raw => {\n        const s = raw.toLowerCase().trim();\n        return s === 'space' ? ' ' : s;\n      })\n      .filter(Boolean);\n  }\n}\n"
    },
    {
      "name": "provider/providezard.ts",
      "content": "import { makeEnvironmentProviders, type EnvironmentProviders } from '@angular/core';\nimport { EVENT_MANAGER_PLUGINS } from '@angular/platform-browser';\n\nimport { ZardDebounceEventManagerPlugin } from './event-manager-plugins/zard-debounce-event-manager-plugin';\nimport { ZardEventManagerPlugin } from './event-manager-plugins/zard-event-manager-plugin';\n\nexport function provideZard(): EnvironmentProviders {\n  const eventManagerPlugins = [\n    {\n      provide: EVENT_MANAGER_PLUGINS,\n      useClass: ZardEventManagerPlugin,\n      multi: true,\n    },\n    {\n      provide: EVENT_MANAGER_PLUGINS,\n      useClass: ZardDebounceEventManagerPlugin,\n      multi: true,\n    },\n  ];\n\n  return makeEnvironmentProviders([...eventManagerPlugins]);\n}\n"
    },
    {
      "name": "css/tailwind.css",
      "content": "@theme inline {\n  --animate-caret-blink: caret-blink 1s ease-out infinite;\n\n  @keyframes caret-blink {\n    0%,\n    70%,\n    100% {\n      opacity: 1;\n    }\n    20%,\n    50% {\n      opacity: 0;\n    }\n  }\n\n  @keyframes accordion-down {\n    from {\n      height: 0;\n    }\n    to {\n      height: var(--radix-accordion-content-height, var(--accordion-panel-height, auto));\n    }\n  }\n\n  @keyframes accordion-up {\n    from {\n      height: var(--radix-accordion-content-height, var(--accordion-panel-height, auto));\n    }\n    to {\n      height: 0;\n    }\n  }\n}\n\n/* Custom variants */\n@custom-variant data-open {\n  &:where([data-state='open']),\n  &:where([data-open]:not([data-open='false'])) {\n    @slot;\n  }\n}\n\n@custom-variant data-closed {\n  &:where([data-state='closed']),\n  &:where([data-closed]:not([data-closed='false'])) {\n    @slot;\n  }\n}\n\n@custom-variant data-checked {\n  &:where([data-state='checked']),\n  &:where([data-checked]:not([data-checked='false'])) {\n    @slot;\n  }\n}\n\n@custom-variant data-unchecked {\n  &:where([data-state='unchecked']),\n  &:where([data-unchecked]:not([data-unchecked='false'])) {\n    @slot;\n  }\n}\n\n@custom-variant data-selected {\n  &:where([data-selected='true']) {\n    @slot;\n  }\n}\n\n@custom-variant data-disabled {\n  &:where([data-disabled='true']),\n  &:where([data-disabled]:not([data-disabled='false'])) {\n    @slot;\n  }\n}\n\n@custom-variant data-active {\n  &:where([data-state='active']),\n  &:where([data-active]:not([data-active='false'])) {\n    @slot;\n  }\n}\n\n@custom-variant data-horizontal {\n  &:where([data-orientation='horizontal']) {\n    @slot;\n  }\n}\n\n@custom-variant data-vertical {\n  &:where([data-orientation='vertical']) {\n    @slot;\n  }\n}\n\n@utility no-scrollbar {\n  -ms-overflow-style: none;\n  scrollbar-width: none;\n\n  &::-webkit-scrollbar {\n    display: none;\n  }\n}\n"
    },
    {
      "name": "index.ts",
      "content": "export * from './directives/string-template-outlet/string-template-outlet.directive';\nexport * from './directives/id.directive';\nexport * from './provider/providezard';\nexport * from './provider/event-manager-plugins/zard-debounce-event-manager-plugin';\nexport * from './provider/event-manager-plugins/zard-event-manager-plugin';\n"
    }
  ]
}
