{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "border-beam",
  "title": "Border Beam",
  "type": "registry:ui",
  "description": "Rotating conic light beam that traces the border ring of its parent. Place inside a `relative` parent (e.g. a Card); the overlay is absolutely positioned, pointer-events-none, and masked down to a ring of `size` px thickness. Tune `duration`, `delay`, and `color`, or set `paused` to freeze it. Keyframes and the `--uipkge-border-angle` @property ship in the canonical tailwind tokens — re-pull init/tailwind if upgrading.",
  "categories": [
    "feedback",
    "motion"
  ],
  "files": [
    {
      "path": "packages/elements-lit/src/components/border-beam/border-beam.ts",
      "content": "import { LitElement, css, html, isServer } from 'lit'\nimport { tailwind } from '../../lib/styles'\nimport { ThemeController } from '../../lib/theme'\n\nif (!isServer && typeof CSS !== 'undefined' && 'registerProperty' in CSS) {\n  try {\n    CSS.registerProperty({\n      name: '--uipkge-border-angle',\n      syntax: '<angle>',\n      inherits: false,\n      initialValue: '0deg',\n    })\n  } catch {\n    // already registered\n  }\n}\n\nconst beamStyles = css`\n  @keyframes uipkge-border-beam {\n    to {\n      --uipkge-border-angle: 360deg;\n    }\n  }\n`\n\n/**\n * <uip-border-beam> — a conic highlight that traces an element's border ring.\n */\nexport class UipBorderBeam extends LitElement {\n  static styles = [\n    tailwind,\n    beamStyles,\n    css`\n      :host {\n        display: block;\n        position: absolute;\n        inset: 0;\n        pointer-events: none;\n        border-radius: inherit;\n      }\n    `,\n  ]\n\n  static properties = {\n    size: { type: Number, reflect: true },\n    duration: { type: Number, reflect: true },\n    delay: { type: Number, reflect: true },\n    color: { reflect: true },\n    paused: { type: Boolean, reflect: true },\n    reducedMotion: { state: true },\n  }\n\n  size = 2\n  duration = 6\n  delay = 0\n  color = 'var(--primary)'\n  paused = false\n  private reducedMotion = false\n  private mediaQueryHandler?: (e: MediaQueryListEvent) => void\n\n  constructor() {\n    super()\n    new ThemeController(this)\n  }\n\n  connectedCallback() {\n    super.connectedCallback()\n    this.setAttribute('data-uipkge', '')\n    this.setAttribute('data-slot', 'border-beam')\n    this.setAttribute('aria-hidden', 'true')\n\n    if (!isServer) {\n      const query = window.matchMedia('(prefers-reduced-motion: reduce)')\n      this.reducedMotion = query.matches\n      this.mediaQueryHandler = (e: MediaQueryListEvent) => {\n        this.reducedMotion = e.matches\n      }\n      query.addEventListener('change', this.mediaQueryHandler)\n    }\n  }\n\n  disconnectedCallback() {\n    super.disconnectedCallback()\n    if (!isServer && this.mediaQueryHandler) {\n      window.matchMedia('(prefers-reduced-motion: reduce)').removeEventListener('change', this.mediaQueryHandler)\n    }\n  }\n\n  render() {\n    const background = this.reducedMotion\n      ? `conic-gradient(from 45deg, transparent 0deg, transparent 290deg, ${this.color} 330deg, transparent 360deg)`\n      : `conic-gradient(from var(--uipkge-border-angle), transparent 0deg, transparent 290deg, ${this.color} 330deg, transparent 360deg)`\n    const animation = this.reducedMotion ? 'none' : `uipkge-border-beam ${this.duration}s linear infinite ${this.delay}s`\n    const playState = !this.reducedMotion && this.paused ? 'paused' : 'running'\n    const style = `padding: ${this.size}px; background: ${background}; animation: ${animation}; animation-play-state: ${playState}; -webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); -webkit-mask-composite: xor; mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0); mask-composite: exclude;`\n\n    return html`\n      <span\n        part=\"base\"\n        data-slot=\"border-beam\"\n        aria-hidden=\"true\"\n        class=\"pointer-events-none absolute inset-0 rounded-[inherit]\"\n        style=${style}\n      ></span>\n    `\n  }\n}\n\ncustomElements.get('uip-border-beam') || customElements.define('uip-border-beam', UipBorderBeam)\n\ndeclare global {\n  interface HTMLElementTagNameMap {\n    'uip-border-beam': UipBorderBeam\n  }\n}\n",
      "type": "registry:file",
      "target": "src/uip/components/border-beam/border-beam.ts"
    }
  ],
  "dependencies": [
    "lit"
  ],
  "registryDependencies": [
    "https://uipkge.dev/r/lit/lit-core.json"
  ]
}
