applySpotlightEffect function exported

Last updated: 2026-03-05T12:56:18.445Z

Metrics

LOC: 77 Complexity: 6 Params: 3

Signature

applySpotlightEffect( target: Element | null, config: SpotlightEffect, ): : Promise<void>

Summary

Dims the page and spotlights the target element for duration ms.

Source Code

export function applySpotlightEffect(
  target: Element | null,
  config: SpotlightEffect,
): Promise<void> {
  return new Promise((resolve) => {
    if (!target) {
      resolve();
      return;
    }

    injectStyles();

    const opacity = config.opacity ?? 0.6;
    const duration = config.duration ?? 2000;

    const rect = target.getBoundingClientRect();
    const padding = 8;

    // Dark overlay with clip-path to create a hole
    const overlay = document.createElement("div");
    overlay.id = OVERLAY_ID;
    overlay.style.backgroundColor = `rgba(0,0,0,${opacity})`;
    overlay.style.opacity = "0";

    // Create a clip-path polygon that covers everything except the target area
    const x1 = rect.left - padding;
    const y1 = rect.top - padding;
    const x2 = rect.right + padding;
    const y2 = rect.bottom + padding;
    const vpWidth = window.innerWidth;
    const vpHeight = window.innerHeight;

    overlay.style.clipPath = `polygon(
      0% 0%,
      100% 0%,
      100% 100%,
      0% 100%,
      0% 0%,
      ${x1}px ${y1}px,
      ${x1}px ${y2}px,
      ${x2}px ${y2}px,
      ${x2}px ${y1}px,
      ${x1}px ${y1}px
    )`;

    document.body.appendChild(overlay);

    // Bright hole around the target for visual effect
    const hole = document.createElement("div");
    hole.id = HOLE_ID;
    hole.style.top = `${rect.top - padding}px`;
    hole.style.left = `${rect.left - padding}px`;
    hole.style.width = `${rect.width + padding * 2}px`;
    hole.style.height = `${rect.height + padding * 2}px`;
    hole.style.background = "transparent";
    document.body.appendChild(hole);

    requestAnimationFrame(() => {
      overlay.style.opacity = "1";
    });

    const cleanup = () => {
      overlay.style.opacity = "0";
      setTimeout(() => {
        overlay.remove();
        hole.remove();
        resolve();
      }, 320);
    };

    if (duration > 0) {
      setTimeout(cleanup, duration);
    } else {
      resolve();
    }
  });
}

Dependencies (Outgoing)

graph LR applySpotlightEffect["applySpotlightEffect"] injectStyles["injectStyles"] applySpotlightEffect -->|calls| injectStyles style applySpotlightEffect fill:#dbeafe,stroke:#2563eb,stroke-width:2px click applySpotlightEffect "ed098e44a2649922.html" click injectStyles "e97e8d96c98fbc38.html"
TargetType
injectStyles calls

Impact (Incoming)

graph LR applySpotlightEffect["applySpotlightEffect"] resolveTarget["resolveTarget"] applyEffect["applyEffect"] resolveTarget -->|uses| applySpotlightEffect applyEffect -->|calls| applySpotlightEffect style applySpotlightEffect fill:#dbeafe,stroke:#2563eb,stroke-width:2px click applySpotlightEffect "ed098e44a2649922.html" click resolveTarget "cefe589bdbdd3b3b.html" click applyEffect "baf0d9f2a6803bb4.html"
SourceType
resolveTarget uses
applyEffect calls