{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "vintage-toggle",
  "title": "Vintage Toggle",
  "author": "Visant Labs <visantsupply@gmail.com>",
  "description": "Chave de duas posições com estalo visual.",
  "registryDependencies": [
    "@visant/vintage-theme",
    "utils",
    "@visant/sfx-bus"
  ],
  "files": [
    {
      "path": "registry/vintage/ui/vintage-toggle.tsx",
      "content": "\"use client\";\n\nimport { useState } from \"react\";\nimport { cn } from \"@/lib/utils\";\nimport { playSfx } from \"@/lib/sfx-bus\";\n\ntype TogglePosition = \"up\" | \"middle\" | \"down\";\n\ninterface VintageToggleProps {\n  labels?: [string, string, string];\n  title?: string;\n  position?: TogglePosition;\n  accent?: string;\n  onChange?: (position: TogglePosition) => void;\n  className?: string;\n}\n\nexport function VintageToggle({\n  labels = [\"U\", \"M\", \"D\"],\n  title = \"TOGGLE\",\n  position: controlledPos,\n  accent,\n  onChange,\n  className,\n}: VintageToggleProps) {\n  const [internalPos, setInternalPos] = useState<TogglePosition>(\"middle\");\n  const position = controlledPos ?? internalPos;\n\n  const positions: TogglePosition[] = [\"up\", \"middle\", \"down\"];\n  const indice = positions.indexOf(position);\n\n  const ir = (next: TogglePosition) => {\n    if (next === position) return;\n    playSfx(\"toggle\");\n    if (controlledPos === undefined) setInternalPos(next);\n    onChange?.(next);\n  };\n\n  const handleClick = () => ir(positions[(indice + 1) % positions.length]);\n\n  /*\n   * Teclado: a chave era só do mouse. Seta pra cima e pra baixo movem a\n   * alavanca um degrau (como o dedo faria), Home/End vão aos extremos, e Enter\n   * ou Espaço ciclam igual ao clique.\n   */\n  const handleKeyDown = (e: React.KeyboardEvent) => {\n    let next: TogglePosition | null = null;\n    if (e.key === \"ArrowUp\" || e.key === \"ArrowLeft\") next = positions[Math.max(0, indice - 1)];\n    else if (e.key === \"ArrowDown\" || e.key === \"ArrowRight\") next = positions[Math.min(2, indice + 1)];\n    else if (e.key === \"Home\") next = \"up\";\n    else if (e.key === \"End\") next = \"down\";\n    else if (e.key === \"Enter\" || e.key === \" \") next = positions[(indice + 1) % positions.length];\n    if (!next) return;\n    e.preventDefault();\n    e.stopPropagation();\n    ir(next);\n  };\n\n  const activeColor = accent || \"var(--vintage-light)\";\n  /** Paradas da alavanca no curso do trilho, em % da altura. */\n  const PARADAS = [12, 50, 88];\n\n  return (\n    <div\n      onClick={handleClick}\n      onKeyDown={handleKeyDown}\n      tabIndex={0}\n      role=\"slider\"\n      aria-label={title}\n      aria-valuemin={0}\n      aria-valuemax={2}\n      aria-valuenow={indice}\n      aria-valuetext={labels[indice]}\n      aria-orientation=\"vertical\"\n      title={`${title}: ${labels[indice]}\nclique ou setas`}\n      className={cn(\n        \"group relative inline-flex cursor-pointer select-none flex-col items-center gap-3 px-4 pt-3 pb-4 outline-none\",\n        \"rounded-[var(--r-control,10px)]\",\n        className\n      )}\n      style={{\n        // O mesmo painel do resto do kit: chapa escura, luz de cima.\n        background: \"linear-gradient(180deg, var(--vintage-surface-3), var(--vintage-surface-2))\",\n        border: \"1px solid var(--vintage-surface-1)\",\n        boxShadow:\n          \"var(--vintage-panel-shadow)\",\n      }}\n    >\n      {/* Anel de foco num filho: o relevo mora no `box-shadow` inline, que\n          venceria qualquer classe de foco no próprio elemento. */}\n      <span\n        aria-hidden\n        className=\"pointer-events-none absolute -inset-px rounded-[inherit] group-focus-visible:[box-shadow:var(--focus,0_0_0_2px_var(--vintage-value))]\"\n      />\n      <span\n        className=\"font-vintage-mono text-[10px] font-semibold uppercase tracking-[0.18em] whitespace-nowrap\"\n        style={{\n          color: \"var(--vintage-text-muted)\",\n          textShadow: \"var(--vintage-engrave)\",\n        }}\n      >\n        {title}\n      </span>\n\n      <div className=\"flex items-stretch gap-3\">\n        {/* O rasgo na chapa, com a alavanca dentro. */}\n        <div\n          className=\"relative h-[132px] w-[26px] rounded-full\"\n          style={{\n            background: \"var(--vintage-surface-1)\",\n            boxShadow: \"inset 0 2px 5px rgba(0,0,0,0.85), 0 1px 0 var(--vintage-lip)\",\n          }}\n        >\n          <div\n            className=\"absolute left-1/2 top-0 h-[34px] w-[34px] -ml-[17px] rounded-[8px]\"\n            style={{\n              top: `${PARADAS[indice]}%`,\n              transform: \"translateY(-50%)\",\n              // Mola: passa um pouco da parada e volta, como a trava de uma\n              // chave de verdade. Curta (200ms) porque responde a um gesto.\n              transition: \"top var(--dur-base,200ms) cubic-bezier(0.34, 1.56, 0.64, 1)\",\n              background:\n                \"linear-gradient(180deg, var(--vintage-metal-channel-light) 0%, var(--vintage-metal-mid) 48%, var(--vintage-metal-light) 52%, var(--vintage-metal-channel-dark) 100%)\",\n              boxShadow:\n                \"inset 0 1px 0 rgba(255,255,255,0.6), 0 0 0 1px var(--vintage-edge), 0 4px 6px rgba(0,0,0,0.55)\",\n            }}\n          >\n            {/* Frisos de pega. */}\n            <div\n              className=\"absolute inset-x-[7px] top-1/2 h-[10px] -translate-y-1/2\"\n              style={{\n                background:\n                  \"repeating-linear-gradient(180deg, rgba(0,0,0,0.35) 0 1px, rgba(255,255,255,0.35) 1px 2px, transparent 2px 4px)\",\n              }}\n            />\n          </div>\n        </div>\n\n        {/* Rótulos serigrafados, um por parada. O da posição atual acende. */}\n        <div className=\"relative h-[132px] w-8\">\n          {labels.map((lbl, i) => (\n            <span\n              key={i}\n              className=\"absolute left-0 -translate-y-1/2 font-vintage-mono text-[10px] font-semibold uppercase tracking-[0.12em] whitespace-nowrap\"\n              style={{\n                top: `${PARADAS[i]}%`,\n                color: i === indice ? \"var(--vintage-value)\" : \"var(--vintage-text-muted)\",\n                textShadow:\n                  i === indice\n                    ? `0 0 6px color-mix(in srgb, ${activeColor} 45%, transparent)`\n                    : \"0 -1px 0 rgba(0,0,0,0.55)\",\n                transition: \"color var(--dur-fast,160ms) var(--ease-out,ease)\",\n              }}\n            >\n              {lbl}\n            </span>\n          ))}\n        </div>\n      </div>\n    </div>\n  );\n}\n",
      "type": "registry:ui"
    }
  ],
  "meta": {
    "uso": {
      "quando": "Ligar e desligar função num painel de áudio, como bypass ou phantom, com cara de chave física",
      "evite": "Switch de configuração em produto comum: liquid-toggle; tema claro e escuro, eclipse-switch"
    }
  },
  "categories": [
    "controles",
    "audio",
    "chave"
  ],
  "type": "registry:ui"
}