{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "arrow-right",
  "type": "registry:component",
  "title": "arrow-right",
  "description": "Animated arrow-right icon for Angular",
  "author": "Aniket Pawar <pawaraniket508@gmail.com>",
  "registryDependencies": [],
  "dependencies": [],
  "files": [
    {
      "path": "packages/angular/src/icons/arrow-right.ts",
      "type": "registry:component",
      "target": "~/src/app/components/heroicons-animated/arrow-right.ts",
      "content": "import {\n  ChangeDetectionStrategy,\n  Component,\n  computed,\n  DestroyRef,\n  type ElementRef,\n  effect,\n  inject,\n  input,\n  signal,\n  viewChild,\n} from \"@angular/core\";\n\n@Component({\n  selector: \"hi-arrow-right\",\n  standalone: true,\n  changeDetection: ChangeDetectionStrategy.OnPush,\n  host: {\n    \"[attr.aria-label]\": \"'arrow-right'\",\n    role: \"img\",\n    \"(mouseenter)\": \"onMouseEnter()\",\n    \"(mouseleave)\": \"onMouseLeave()\",\n  },\n  template: `<svg\n    xmlns=\"http://www.w3.org/2000/svg\"\n    [attr.width]=\"size()\"\n    [attr.height]=\"size()\"\n    viewBox=\"0 0 24 24\"\n    fill=\"none\"\n    [attr.stroke]=\"color()\"\n    [attr.stroke-width]=\"strokeWidth()\"\n    stroke-linecap=\"round\"\n    stroke-linejoin=\"round\"\n    class=\"icon-svg\"\n  >\n    <path class=\"head-path\" [class.animate]=\"shouldAnimate()\" d=\"M13.5 4.5 21 12m0 0-7.5 7.5\" />\n    <path #linePath d=\"M21 12H3\" />\n  </svg>`,\n  styles: [\n    `\n      :host {\n        display: inline-block;\n      }\n      .icon-svg {\n        transform-box: fill-box;\n        transform-origin: center;\n      }\n      .head-path {\n        transform-box: fill-box;\n        transform-origin: center;\n        transition: transform 0.4s ease-in-out;\n      }\n      .head-path.animate {\n        animation: head-translate 0.4s ease-in-out forwards;\n      }\n      @keyframes head-translate {\n        0% {\n          transform: translateX(0);\n        }\n        50% {\n          transform: translateX(-3px);\n        }\n        100% {\n          transform: translateX(0);\n        }\n      }\n    `,\n  ],\n})\nexport class ArrowRightIcon {\n  readonly color = input(\"currentColor\");\n  readonly size = input(28);\n  readonly strokeWidth = input(1.5);\n  readonly animate = input(false);\n\n  protected isHovered = signal(false);\n  protected shouldAnimate = computed(() => this.animate() || this.isHovered());\n\n  private readonly linePathRef =\n    viewChild<ElementRef<SVGPathElement>>(\"linePath\");\n  private readonly destroyRef = inject(DestroyRef);\n\n  private readonly LINE_PATH_KEYFRAMES = [\n    \"M21 12H3\",\n    \"M18 12H3\",\n    \"M21 12H3\",\n  ] as const;\n  private readonly LINE_PATH_TIMES = [0, 0.5, 1] as const;\n  private readonly lineAnimationDuration = 400;\n  private readonly NUMBER_PATTERN = /-?\\d*\\.?\\d+(?:e[-+]?\\d+)?/gi;\n  private lineAnimationFrame: number | null = null;\n  private readonly parsedLinePaths: { template: string; numbers: number[] }[];\n  private readonly lineTemplate: string;\n  private readonly lineNumberCount: number;\n  private readonly canMorphLine: boolean;\n\n  constructor() {\n    this.parsedLinePaths = this.LINE_PATH_KEYFRAMES.map((path) => {\n      const numbers: number[] = [];\n      const template = path.replace(this.NUMBER_PATTERN, (value) => {\n        numbers.push(Number.parseFloat(value));\n        return \"__N__\";\n      });\n      return { template, numbers };\n    });\n    this.lineTemplate = this.parsedLinePaths[0].template;\n    this.lineNumberCount = this.parsedLinePaths[0].numbers.length;\n    this.canMorphLine = this.parsedLinePaths.every(\n      (p) =>\n        p.template === this.lineTemplate &&\n        p.numbers.length === this.lineNumberCount\n    );\n    effect(() => {\n      if (this.shouldAnimate()) {\n        this.startAnimation();\n      } else {\n        this.stopAnimation();\n      }\n    });\n    this.destroyRef.onDestroy(() => this.clearLineAnimation());\n  }\n\n  private clearLineAnimation() {\n    if (this.lineAnimationFrame !== null) {\n      cancelAnimationFrame(this.lineAnimationFrame);\n      this.lineAnimationFrame = null;\n    }\n  }\n  private getEaseInOut(value: number): number {\n    return 0.5 - Math.cos(Math.PI * value) / 2;\n  }\n  private formatNumber(value: number): string {\n    return Number(value.toFixed(4)).toString();\n  }\n  private interpolatePath(\n    template: string,\n    from: number[],\n    to: number[],\n    progress: number\n  ): string {\n    let numberIndex = 0;\n    return template.replace(/__N__/g, () => {\n      const s = from[numberIndex];\n      const e = to[numberIndex];\n      numberIndex += 1;\n      return this.formatNumber(s + (e - s) * progress);\n    });\n  }\n  private setLinePath(progress: number) {\n    const el = this.linePathRef()?.nativeElement;\n    if (!el) {\n      return;\n    }\n    if (!this.canMorphLine) {\n      el.setAttribute(\"d\", this.LINE_PATH_KEYFRAMES[0]);\n      return;\n    }\n    const cp = Math.max(0, Math.min(progress, 1));\n    let si = this.LINE_PATH_TIMES.length - 2;\n    for (let i = 1; i < this.LINE_PATH_TIMES.length; i++) {\n      if (cp <= this.LINE_PATH_TIMES[i]) {\n        si = i - 1;\n        break;\n      }\n    }\n    const ss = this.LINE_PATH_TIMES[si];\n    const se = this.LINE_PATH_TIMES[si + 1];\n    const lp = se === ss ? 0 : (cp - ss) / (se - ss);\n    el.setAttribute(\n      \"d\",\n      this.interpolatePath(\n        this.lineTemplate,\n        this.parsedLinePaths[si].numbers,\n        this.parsedLinePaths[si + 1].numbers,\n        this.getEaseInOut(lp)\n      )\n    );\n  }\n  private startAnimation() {\n    this.clearLineAnimation();\n    const st = performance.now();\n    const step = (t: number) => {\n      const p = Math.min((t - st) / this.lineAnimationDuration, 1);\n      this.setLinePath(p);\n      if (p < 1) {\n        this.lineAnimationFrame = requestAnimationFrame(step);\n      } else {\n        this.lineAnimationFrame = null;\n      }\n    };\n    this.lineAnimationFrame = requestAnimationFrame(step);\n  }\n  private stopAnimation() {\n    this.clearLineAnimation();\n    const el = this.linePathRef()?.nativeElement;\n    if (el) {\n      el.setAttribute(\"d\", this.LINE_PATH_KEYFRAMES[0]);\n    }\n  }\n  onMouseEnter() {\n    this.isHovered.set(true);\n  }\n  onMouseLeave() {\n    this.isHovered.set(false);\n  }\n}\n"
    }
  ]
}
