{"version":3,"file":"ngwr-click-spark.mjs","sources":["../../../projects/lib/click-spark/click-spark.ts","../../../projects/lib/click-spark/click-spark.html","../../../projects/lib/click-spark/ngwr-click-spark.ts"],"sourcesContent":["/**\n * @license\n *\n * Use of this source code is governed by an MIT-style license that can be\n * found in the LICENSE file at https://github.com/thekhegay/ngwr/blob/main/LICENSE\n *\n * Angular adaptation of the ClickSpark effect by David Haz / reactbits.dev.\n * Original: https://www.reactbits.dev/animations/click-spark\n */\n\nimport { isPlatformBrowser } from '@angular/common';\nimport {\n  Component,\n  DestroyRef,\n  ElementRef,\n  PLATFORM_ID,\n  ViewEncapsulation,\n  afterNextRender,\n  inject,\n  input,\n  viewChild,\n} from '@angular/core';\n\nimport { WrPlatform } from 'ngwr/platform';\nimport { numAttr } from 'ngwr/utils';\n\nimport type { WrClickSparkEasing } from './interfaces';\n\ninterface Spark {\n  readonly x: number;\n  readonly y: number;\n  readonly angle: number;\n  readonly startTime: number;\n}\n\nconst EASINGS: Readonly<Record<WrClickSparkEasing, (t: number) => number>> = {\n  linear: t => t,\n  'ease-in': t => t * t,\n  'ease-in-out': t => (t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t),\n  'ease-out': t => t * (2 - t),\n};\n\n/**\n * Click ripple — bursts a ring of short line sparks from the click point\n * across any projected content. Wraps children in a positioned container\n * with a `pointer-events: none` canvas overlay, so projected DOM stays\n * fully interactive.\n *\n * @example\n * ```html\n * <wr-click-spark>\n *   <h1>Click anywhere</h1>\n *   <button>Buttons still work</button>\n * </wr-click-spark>\n * ```\n *\n * @see https://www.reactbits.dev/animations/click-spark\n */\n@Component({\n  selector: 'wr-click-spark',\n  templateUrl: './click-spark.html',\n  styleUrl: './click-spark.scss',\n  encapsulation: ViewEncapsulation.None,\n  host: {\n    class: 'wr-click-spark',\n    '(click)': 'onClick($event)',\n  },\n})\nexport class WrClickSpark {\n  /**\n   * Spark line colour. Accepts any CSS colour, or a `var(--wr-…)` token which is\n   * resolved against the host so it tracks the theme. The default flips with the\n   * theme — dark sparks in light mode, light sparks in dark.\n   * @default 'var(--wr-color-dark)'\n   */\n  readonly sparkColor = input('var(--wr-color-dark)');\n\n  /** Length of each spark line in pixels (at t=0; tapers to 0 at t=1). @default 10 */\n  readonly sparkSize = input(10, { transform: numAttr(10) });\n\n  /** Distance each spark travels from origin in pixels. @default 15 */\n  readonly sparkRadius = input(15, { transform: numAttr(15) });\n\n  /** Number of sparks per click (evenly distributed around the circle). @default 8 */\n  readonly sparkCount = input(8, { transform: numAttr(8) });\n\n  /** Animation duration in ms. @default 400 */\n  readonly duration = input(400, { transform: numAttr(400) });\n\n  /** Easing function applied to the travel distance. @default 'ease-out' */\n  readonly easing = input<WrClickSparkEasing>('ease-out');\n\n  /** Multiplier on the travel distance — bumps the radius without changing `sparkRadius`. @default 1 */\n  readonly extraScale = input(1, { transform: numAttr(1) });\n\n  private readonly canvasRef = viewChild.required<ElementRef<HTMLCanvasElement>>('canvas');\n\n  private readonly host = inject<ElementRef<HTMLElement>>(ElementRef);\n  private readonly destroyRef = inject(DestroyRef);\n  private readonly isBrowser = isPlatformBrowser(inject(PLATFORM_ID));\n  private readonly platform = inject(WrPlatform);\n\n  private sparks: Spark[] = [];\n\n  constructor() {\n    if (!this.isBrowser) return;\n    afterNextRender(() => {\n      this.syncCanvasSize();\n      this.watchResize();\n      this.startLoop();\n    });\n  }\n\n  protected onClick(event: MouseEvent): void {\n    // Reduced motion: no spark bursts — same policy as wr-confetti.\n    if (this.platform.prefersReducedMotion()) return;\n    const canvas = this.canvasRef().nativeElement;\n    const rect = canvas.getBoundingClientRect();\n    const x = event.clientX - rect.left;\n    const y = event.clientY - rect.top;\n    const now = performance.now();\n    const count = this.sparkCount();\n    for (let i = 0; i < count; i++) {\n      this.sparks.push({ x, y, angle: (2 * Math.PI * i) / count, startTime: now });\n    }\n  }\n\n  // Internals\n\n  /**\n   * Canvas `strokeStyle` can't read CSS custom properties, so a `var(--wr-…)`\n   * token is resolved against the host's computed style here. Plain colours\n   * pass through untouched. Falls back to a dark literal if the custom\n   * property resolves to nothing.\n   */\n  private resolveColor(): string {\n    const color = this.sparkColor();\n    const match = /^var\\((--[\\w-]+)\\)$/.exec(color.trim());\n    if (!match) return color;\n    const resolved = getComputedStyle(this.host.nativeElement).getPropertyValue(match[1]).trim();\n    return resolved || '#0f172a';\n  }\n\n  private syncCanvasSize(): void {\n    const canvas = this.canvasRef().nativeElement;\n    const host = this.host.nativeElement;\n    const { width, height } = host.getBoundingClientRect();\n    if (canvas.width !== Math.round(width)) canvas.width = Math.round(width);\n    if (canvas.height !== Math.round(height)) canvas.height = Math.round(height);\n  }\n\n  private watchResize(): void {\n    if (typeof ResizeObserver === 'undefined') return;\n    let resizeTimer: ReturnType<typeof setTimeout> | undefined;\n    const ro = new ResizeObserver(() => {\n      clearTimeout(resizeTimer);\n      resizeTimer = setTimeout(() => this.syncCanvasSize(), 100);\n    });\n    ro.observe(this.host.nativeElement);\n    this.destroyRef.onDestroy(() => {\n      ro.disconnect();\n      clearTimeout(resizeTimer);\n    });\n  }\n\n  private startLoop(): void {\n    const canvas = this.canvasRef().nativeElement;\n    const ctx = canvas.getContext('2d');\n    if (!ctx) return;\n\n    let raf = 0;\n\n    const draw = (ts: number): void => {\n      ctx.clearRect(0, 0, canvas.width, canvas.height);\n      const ease = EASINGS[this.easing()];\n      const duration = this.duration();\n      const sparkRadius = this.sparkRadius();\n      const sparkSize = this.sparkSize();\n      const extraScale = this.extraScale();\n      const color = this.resolveColor();\n\n      this.sparks = this.sparks.filter(spark => {\n        const elapsed = ts - spark.startTime;\n        if (elapsed >= duration) return false;\n        const progress = elapsed / duration;\n        const eased = ease(progress);\n        const distance = eased * sparkRadius * extraScale;\n        const lineLength = sparkSize * (1 - eased);\n\n        const x1 = spark.x + distance * Math.cos(spark.angle);\n        const y1 = spark.y + distance * Math.sin(spark.angle);\n        const x2 = spark.x + (distance + lineLength) * Math.cos(spark.angle);\n        const y2 = spark.y + (distance + lineLength) * Math.sin(spark.angle);\n\n        ctx.strokeStyle = color;\n        ctx.lineWidth = 2;\n        ctx.beginPath();\n        ctx.moveTo(x1, y1);\n        ctx.lineTo(x2, y2);\n        ctx.stroke();\n        return true;\n      });\n\n      raf = requestAnimationFrame(draw);\n    };\n\n    raf = requestAnimationFrame(draw);\n    this.destroyRef.onDestroy(() => cancelAnimationFrame(raf));\n  }\n}\n\nexport type { WrClickSparkEasing } from './interfaces';\n","<canvas #canvas class=\"wr-click-spark__canvas\"></canvas>\n<ng-content />\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}