{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "tabselector", "type": "registry:component", "title": "TabSelector", "description": "Componente Concorde TabSelector — un solo archivo, TabSelector.tsx.", "dependencies": [ "react" ], "registryDependencies": [], "files": [ { "path": "components/TabSelector.tsx", "type": "registry:file", "target": "components/TabSelector.tsx", "content": "\"use client\";\n\n/**\n * TabSelector — Generado por Concorde\n * Fuente: Figma VOYAGER · \"RadioGroup\" (nodo 3008:15095)\n *\n * Selector tipo segmented/tab: contenedor pill blanco (radio 24.5, borde\n * gradiente #8460E5 → #FFF8F1) con N opciones. La opción activa lleva relleno\n * gradiente oscuro (#8460E5 → #3B1782), borde gradiente (white → #F4AC59 →\n * #8460E5 → white), texto blanco y sombra; las inactivas llevan texto en\n * gradiente lila (#8460E5 → #3B1782). Controlado o no controlado.\n */\n\nimport { useId, useState } from \"react\";\nimport type { JSX } from \"react\";\n\n// ─── Types ────────────────────────────────────────────────────────────────────\n\nexport interface TabSelectorProps {\n /** Etiquetas de las opciones */\n options: string[];\n /** Índice activo (controlado, 0-based) */\n value?: number;\n /** Índice inicial (no controlado, default 0) */\n defaultValue?: number;\n /** Callback al cambiar de opción */\n onChange?: (index: number) => void;\n \"aria-label\"?: string;\n className?: string;\n}\n\n// ─── Self-contained CSS ───────────────────────────────────────────────────────\n\nconst STYLE_ID = \"concorde-tabselector-styles\";\n\nconst TABSELECTOR_STYLES = `\n.ptabs {\n display: inline-flex;\n align-items: center;\n gap: 4px;\n height: 49px;\n padding: 0 7px;\n border-radius: 24.5px;\n border: 1px solid transparent;\n background-image: linear-gradient(#ffffff, #ffffff), linear-gradient(330deg, #8460E5 0%, #FFF8F1 100%);\n background-origin: border-box;\n background-clip: padding-box, border-box;\n font-family: var(--vmc-font-display, \"Plus Jakarta Sans\", -apple-system, sans-serif);\n}\n.ptabs__tab {\n appearance: none;\n box-sizing: border-box;\n min-width: 83px;\n height: 34px;\n padding: 0 16px;\n border: 2px solid transparent;\n border-radius: 17px;\n white-space: nowrap;\n background: transparent;\n font-family: inherit;\n font-size: 12px;\n font-weight: 600;\n line-height: 16px;\n cursor: pointer;\n /* inactivo: texto en gradiente lila */\n color: #3B1782;\n background-image: linear-gradient(135deg, #8460E5 0%, #3B1782 100%);\n -webkit-background-clip: text;\n background-clip: text;\n -webkit-text-fill-color: transparent;\n transition: transform 0.16s, box-shadow 0.2s, opacity 0.16s;\n}\n.ptabs__tab:hover { opacity: 0.78; }\n.ptabs__tab:active { transform: scale(0.97); }\n.ptabs__tab:focus-visible { outline: 2px solid #8460E5; outline-offset: 2px; }\n.ptabs__tab--active {\n color: #ffffff;\n -webkit-text-fill-color: #ffffff;\n background-image:\n linear-gradient(150deg, #8460E5 0%, #3B1782 100%),\n linear-gradient(120deg, #ffffff 0%, #F4AC59 22%, #8460E5 75%, #ffffff 100%);\n background-origin: border-box;\n background-clip: padding-box, border-box;\n box-shadow: rgba(32,0,104,0.2) 0px 8px 16px;\n}\n.ptabs__tab--active:hover { opacity: 1; }\n@media (prefers-reduced-motion: reduce) {\n .ptabs__tab { transition: none; }\n}\n`;\n\nlet _stylesInjected = false;\n\n// ─── Component ────────────────────────────────────────────────────────────────\n\nexport default function TabSelector({\n options,\n value,\n defaultValue = 0,\n onChange,\n \"aria-label\": ariaLabel,\n className = \"\",\n}: TabSelectorProps): JSX.Element {\n const uid = useId().replace(/:/g, \"-\");\n const controlled = value !== undefined;\n const [internal, setInternal] = useState(defaultValue);\n const active = controlled ? value : internal;\n\n function select(i: number): void {\n if (!controlled) setInternal(i);\n onChange?.(i);\n }\n\n if (typeof document !== \"undefined\" && !_stylesInjected) {\n if (!document.getElementById(STYLE_ID)) {\n const el = document.createElement(\"style\");\n el.id = STYLE_ID;\n el.textContent = TABSELECTOR_STYLES;\n document.head.appendChild(el);\n }\n _stylesInjected = true;\n }\n\n return (\n <>\n \n