{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "theme-switch",
  "title": "Theme Switch",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-angular/components/theme-switch/theme-switch.component.ts",
      "content": "import {\n  Component,\n  EventEmitter,\n  HostListener,\n  Input,\n  Output,\n  booleanAttribute,\n  ChangeDetectionStrategy,\n} from '@angular/core'\nimport { cn } from '@/lib/utils'\nimport { UiSectionCardComponent } from '@/ui/section-card'\n\nexport type Theme = 'light' | 'dark' | 'system' | 'black'\nexport type ThemeSwitchVariant = 'cards' | 'icons' | 'icon-only' | 'dropdown' | 'pill' | 'pill-4' | 'switch'\n\nconst VARIANT_OPTIONS: Record<ThemeSwitchVariant, Theme[]> = {\n  cards: ['light', 'dark', 'system'],\n  icons: ['light', 'dark', 'system'],\n  'icon-only': ['light', 'dark'],\n  dropdown: ['light', 'dark', 'system'],\n  pill: ['light', 'dark', 'system'],\n  'pill-4': ['system', 'light', 'dark', 'black'],\n  switch: ['light', 'dark'],\n}\n\ntype ViewTransitionDocument = Document & {\n  startViewTransition?: (callback: () => unknown) => { finished: Promise<void> }\n}\n\nlet revealing = false\n\nasync function withThemeReveal(enabled: boolean, event: MouseEvent | undefined, swap: () => void): Promise<void> {\n  if (typeof document === 'undefined') {\n    swap()\n    return\n  }\n  const startViewTransition = (document as ViewTransitionDocument).startViewTransition?.bind(document)\n  const reduceMotion = typeof window !== 'undefined' && window.matchMedia('(prefers-reduced-motion: reduce)').matches\n  if (!enabled || !startViewTransition || reduceMotion) {\n    swap()\n    return\n  }\n  if (revealing) return\n  revealing = true\n\n  const root = document.documentElement\n  const x = event?.clientX ?? window.innerWidth / 2\n  const y = event?.clientY ?? window.innerHeight / 2\n  const radius = Math.hypot(Math.max(x, window.innerWidth - x), Math.max(y, window.innerHeight - y))\n  root.style.setProperty('--uipkge-theme-x', `${x}px`)\n  root.style.setProperty('--uipkge-theme-y', `${y}px`)\n  root.style.setProperty('--uipkge-theme-r', `${radius}px`)\n  root.setAttribute('data-uipkge-theme-reveal', '')\n\n  try {\n    await startViewTransition(swap).finished\n  } finally {\n    root.removeAttribute('data-uipkge-theme-reveal')\n    revealing = false\n  }\n}\n\n/**\n * Angular port of UIPKGE ThemeSwitch — light/dark/system toggle persisted to\n * localStorage. Same seven visual variants as Vue; theme swap runs inside a\n * View Transition wipe when enabled and supported.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-theme-switch, [ui-theme-switch]',\n  standalone: true,\n  imports: [UiSectionCardComponent],\n  host: {\n    '[attr.data-slot]': '\"theme-switch\"',\n    '[attr.data-uipkge]': '\"\"',\n    '[attr.data-variant]': 'variant',\n    '[attr.data-theme]': 'currentValue',\n    '[class]': 'hostClass',\n  },\n  template: `\n    @switch (variant) {\n      @case ('cards') {\n        <ui-section-card\n          [title]=\"title ?? 'Appearance'\"\n          [description]=\"description ?? 'Choose your interface theme.'\"\n          class=\"w-full\"\n        >\n          <svg\n            slot=\"header-action\"\n            class=\"text-muted-foreground size-5\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            viewBox=\"0 0 24 24\"\n            fill=\"none\"\n            stroke=\"currentColor\"\n            stroke-width=\"2\"\n            stroke-linecap=\"round\"\n            stroke-linejoin=\"round\"\n          >\n            <circle cx=\"13.5\" cy=\"6.5\" r=\".5\" fill=\"currentColor\" />\n            <circle cx=\"17.5\" cy=\"10.5\" r=\".5\" fill=\"currentColor\" />\n            <circle cx=\"8.5\" cy=\"7.5\" r=\".5\" fill=\"currentColor\" />\n            <circle cx=\"6.5\" cy=\"12.5\" r=\".5\" fill=\"currentColor\" />\n            <path\n              d=\"M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10c.926 0 1.648-.746 1.648-1.688 0-.437-.18-.835-.437-1.125-.29-.289-.438-.652-.438-1.125a1.64 1.64 0 0 1 1.668-1.668h1.996c3.051 0 5.555-2.503 5.555-5.554C21.965 6.012 17.461 2 12 2z\"\n            />\n          </svg>\n          <div class=\"grid grid-cols-3 gap-2\" role=\"radiogroup\" [attr.aria-label]=\"title ?? 'Theme'\">\n            @for (t of options(); track t) {\n              <button\n                type=\"button\"\n                role=\"radio\"\n                [attr.aria-checked]=\"currentValue === t\"\n                class=\"focus-visible:ring-ring rounded-md border p-3 text-left transition focus:outline-none focus-visible:ring-2 focus-visible:outline-none\"\n                [class]=\"\n                  currentValue === t\n                    ? 'border-primary ring-primary bg-primary/5 ring-1'\n                    : 'border-border hover:bg-muted/50'\n                \"\n                (click)=\"select(t, $event)\"\n              >\n                @switch (t) {\n                  @case ('light') {\n                    <svg\n                      class=\"text-muted-foreground mb-2 size-4\"\n                      aria-hidden=\"true\"\n                      xmlns=\"http://www.w3.org/2000/svg\"\n                      viewBox=\"0 0 24 24\"\n                      fill=\"none\"\n                      stroke=\"currentColor\"\n                      stroke-width=\"2\"\n                      stroke-linecap=\"round\"\n                      stroke-linejoin=\"round\"\n                    >\n                      <circle cx=\"12\" cy=\"12\" r=\"4\" />\n                      <path d=\"M12 2v2\" />\n                      <path d=\"M12 20v2\" />\n                      <path d=\"m4.93 4.93 1.41 1.41\" />\n                      <path d=\"m17.66 17.66 1.41 1.41\" />\n                      <path d=\"M2 12h2\" />\n                      <path d=\"M20 12h2\" />\n                      <path d=\"m6.34 17.66-1.41 1.41\" />\n                      <path d=\"m19.07 4.93-1.41 1.41\" />\n                    </svg>\n                  }\n                  @case ('dark') {\n                    <svg\n                      class=\"text-muted-foreground mb-2 size-4\"\n                      aria-hidden=\"true\"\n                      xmlns=\"http://www.w3.org/2000/svg\"\n                      viewBox=\"0 0 24 24\"\n                      fill=\"none\"\n                      stroke=\"currentColor\"\n                      stroke-width=\"2\"\n                      stroke-linecap=\"round\"\n                      stroke-linejoin=\"round\"\n                    >\n                      <path\n                        d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\n                      />\n                    </svg>\n                  }\n                  @case ('system') {\n                    <svg\n                      class=\"text-muted-foreground mb-2 size-4\"\n                      aria-hidden=\"true\"\n                      xmlns=\"http://www.w3.org/2000/svg\"\n                      viewBox=\"0 0 24 24\"\n                      fill=\"none\"\n                      stroke=\"currentColor\"\n                      stroke-width=\"2\"\n                      stroke-linecap=\"round\"\n                      stroke-linejoin=\"round\"\n                    >\n                      <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n                      <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n                      <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n                    </svg>\n                  }\n                }\n                <p class=\"text-xs font-medium\">{{ labels[t] }}</p>\n              </button>\n            }\n          </div>\n        </ui-section-card>\n      }\n\n      @case ('icons') {\n        <div\n          role=\"radiogroup\"\n          [attr.aria-label]=\"title ?? 'Theme'\"\n          class=\"border-border bg-card inline-flex items-center gap-0.5 rounded-md border p-0.5\"\n        >\n          @for (t of options(); track t) {\n            <button\n              type=\"button\"\n              role=\"radio\"\n              [attr.aria-checked]=\"currentValue === t\"\n              [attr.aria-label]=\"labels[t]\"\n              class=\"focus-visible:ring-ring grid size-7 place-items-center rounded transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n              [class]=\"\n                currentValue === t\n                  ? 'bg-primary text-primary-foreground'\n                  : 'text-muted-foreground hover:bg-muted hover:text-foreground'\n              \"\n              (click)=\"select(t, $event)\"\n            >\n              @switch (t) {\n                @case ('light') {\n                  <svg\n                    class=\"size-4\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <circle cx=\"12\" cy=\"12\" r=\"4\" />\n                    <path d=\"M12 2v2\" />\n                    <path d=\"M12 20v2\" />\n                    <path d=\"m4.93 4.93 1.41 1.41\" />\n                    <path d=\"m17.66 17.66 1.41 1.41\" />\n                    <path d=\"M2 12h2\" />\n                    <path d=\"M20 12h2\" />\n                    <path d=\"m6.34 17.66-1.41 1.41\" />\n                    <path d=\"m19.07 4.93-1.41 1.41\" />\n                  </svg>\n                }\n                @case ('dark') {\n                  <svg\n                    class=\"size-4\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <path\n                      d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\n                    />\n                  </svg>\n                }\n                @case ('system') {\n                  <svg\n                    class=\"size-4\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n                    <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n                    <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n                  </svg>\n                }\n              }\n            </button>\n          }\n        </div>\n      }\n\n      @case ('icon-only') {\n        <button\n          type=\"button\"\n          [attr.aria-label]=\"labels[currentValue]\"\n          class=\"text-muted-foreground hover:text-foreground hover:bg-accent focus-visible:ring-ring inline-flex size-8 items-center justify-center rounded-lg transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n          (click)=\"cycle($event)\"\n        >\n          @switch (currentValue) {\n            @case ('light') {\n              <svg\n                class=\"size-4\"\n                aria-hidden=\"true\"\n                xmlns=\"http://www.w3.org/2000/svg\"\n                viewBox=\"0 0 24 24\"\n                fill=\"none\"\n                stroke=\"currentColor\"\n                stroke-width=\"2\"\n                stroke-linecap=\"round\"\n                stroke-linejoin=\"round\"\n              >\n                <circle cx=\"12\" cy=\"12\" r=\"4\" />\n                <path d=\"M12 2v2\" />\n                <path d=\"M12 20v2\" />\n                <path d=\"m4.93 4.93 1.41 1.41\" />\n                <path d=\"m17.66 17.66 1.41 1.41\" />\n                <path d=\"M2 12h2\" />\n                <path d=\"M20 12h2\" />\n                <path d=\"m6.34 17.66-1.41 1.41\" />\n                <path d=\"m19.07 4.93-1.41 1.41\" />\n              </svg>\n            }\n            @case ('dark') {\n              <svg\n                class=\"size-4\"\n                aria-hidden=\"true\"\n                xmlns=\"http://www.w3.org/2000/svg\"\n                viewBox=\"0 0 24 24\"\n                fill=\"none\"\n                stroke=\"currentColor\"\n                stroke-width=\"2\"\n                stroke-linecap=\"round\"\n                stroke-linejoin=\"round\"\n              >\n                <path\n                  d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\n                />\n              </svg>\n            }\n            @default {\n              <svg\n                class=\"size-4\"\n                aria-hidden=\"true\"\n                xmlns=\"http://www.w3.org/2000/svg\"\n                viewBox=\"0 0 24 24\"\n                fill=\"none\"\n                stroke=\"currentColor\"\n                stroke-width=\"2\"\n                stroke-linecap=\"round\"\n                stroke-linejoin=\"round\"\n              >\n                <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n                <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n                <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n              </svg>\n            }\n          }\n        </button>\n      }\n\n      @case ('dropdown') {\n        <div class=\"relative inline-block text-left\">\n          <button\n            type=\"button\"\n            aria-haspopup=\"menu\"\n            [attr.aria-expanded]=\"dropdownOpen\"\n            class=\"border-border bg-card hover:bg-muted focus-visible:ring-ring inline-flex h-9 items-center gap-2 rounded-md border px-3 text-sm transition focus-visible:ring-2 focus-visible:outline-none\"\n            (click)=\"dropdownOpen = !dropdownOpen\"\n          >\n            @switch (currentValue) {\n              @case ('light') {\n                <svg\n                  class=\"size-4\"\n                  aria-hidden=\"true\"\n                  xmlns=\"http://www.w3.org/2000/svg\"\n                  viewBox=\"0 0 24 24\"\n                  fill=\"none\"\n                  stroke=\"currentColor\"\n                  stroke-width=\"2\"\n                  stroke-linecap=\"round\"\n                  stroke-linejoin=\"round\"\n                >\n                  <circle cx=\"12\" cy=\"12\" r=\"4\" />\n                  <path d=\"M12 2v2\" />\n                  <path d=\"M12 20v2\" />\n                  <path d=\"m4.93 4.93 1.41 1.41\" />\n                  <path d=\"m17.66 17.66 1.41 1.41\" />\n                  <path d=\"M2 12h2\" />\n                  <path d=\"M20 12h2\" />\n                  <path d=\"m6.34 17.66-1.41 1.41\" />\n                  <path d=\"m19.07 4.93-1.41 1.41\" />\n                </svg>\n              }\n              @case ('dark') {\n                <svg\n                  class=\"size-4\"\n                  aria-hidden=\"true\"\n                  xmlns=\"http://www.w3.org/2000/svg\"\n                  viewBox=\"0 0 24 24\"\n                  fill=\"none\"\n                  stroke=\"currentColor\"\n                  stroke-width=\"2\"\n                  stroke-linecap=\"round\"\n                  stroke-linejoin=\"round\"\n                >\n                  <path\n                    d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\n                  />\n                </svg>\n              }\n              @default {\n                <svg\n                  class=\"size-4\"\n                  aria-hidden=\"true\"\n                  xmlns=\"http://www.w3.org/2000/svg\"\n                  viewBox=\"0 0 24 24\"\n                  fill=\"none\"\n                  stroke=\"currentColor\"\n                  stroke-width=\"2\"\n                  stroke-linecap=\"round\"\n                  stroke-linejoin=\"round\"\n                >\n                  <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n                  <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n                  <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n                </svg>\n              }\n            }\n            <span>{{ labels[currentValue] }}</span>\n            <svg\n              class=\"size-3 opacity-60\"\n              aria-hidden=\"true\"\n              xmlns=\"http://www.w3.org/2000/svg\"\n              viewBox=\"0 0 24 24\"\n              fill=\"none\"\n              stroke=\"currentColor\"\n              stroke-width=\"2\"\n              stroke-linecap=\"round\"\n              stroke-linejoin=\"round\"\n            >\n              <path d=\"m6 9 6 6 6-6\" />\n            </svg>\n          </button>\n          @if (dropdownOpen) {\n            <div\n              role=\"menu\"\n              class=\"border-border bg-popover text-popover-foreground absolute right-0 z-50 mt-1 min-w-[140px] rounded-md border p-1 shadow-md\"\n              (keydown.escape)=\"dropdownOpen = false\"\n            >\n              @for (t of options(); track t) {\n                <button\n                  type=\"button\"\n                  role=\"menuitem\"\n                  class=\"hover:bg-accent hover:text-accent-foreground relative flex w-full cursor-pointer items-center rounded-sm px-2 py-1.5 text-sm outline-none select-none\"\n                  (click)=\"select(t, $event); dropdownOpen = false\"\n                >\n                  <span class=\"mr-2 inline-flex size-4 items-center justify-center\">\n                    @switch (t) {\n                      @case ('light') {\n                        <svg\n                          class=\"size-4\"\n                          aria-hidden=\"true\"\n                          xmlns=\"http://www.w3.org/2000/svg\"\n                          viewBox=\"0 0 24 24\"\n                          fill=\"none\"\n                          stroke=\"currentColor\"\n                          stroke-width=\"2\"\n                          stroke-linecap=\"round\"\n                          stroke-linejoin=\"round\"\n                        >\n                          <circle cx=\"12\" cy=\"12\" r=\"4\" />\n                          <path d=\"M12 2v2\" />\n                          <path d=\"M12 20v2\" />\n                          <path d=\"m4.93 4.93 1.41 1.41\" />\n                          <path d=\"m17.66 17.66 1.41 1.41\" />\n                          <path d=\"M2 12h2\" />\n                          <path d=\"M20 12h2\" />\n                          <path d=\"m6.34 17.66-1.41 1.41\" />\n                          <path d=\"m19.07 4.93-1.41 1.41\" />\n                        </svg>\n                      }\n                      @case ('dark') {\n                        <svg\n                          class=\"size-4\"\n                          aria-hidden=\"true\"\n                          xmlns=\"http://www.w3.org/2000/svg\"\n                          viewBox=\"0 0 24 24\"\n                          fill=\"none\"\n                          stroke=\"currentColor\"\n                          stroke-width=\"2\"\n                          stroke-linecap=\"round\"\n                          stroke-linejoin=\"round\"\n                        >\n                          <path\n                            d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\n                          />\n                        </svg>\n                      }\n                      @case ('system') {\n                        <svg\n                          class=\"size-4\"\n                          aria-hidden=\"true\"\n                          xmlns=\"http://www.w3.org/2000/svg\"\n                          viewBox=\"0 0 24 24\"\n                          fill=\"none\"\n                          stroke=\"currentColor\"\n                          stroke-width=\"2\"\n                          stroke-linecap=\"round\"\n                          stroke-linejoin=\"round\"\n                        >\n                          <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n                          <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n                          <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n                        </svg>\n                      }\n                    }\n                  </span>\n                  <span>{{ labels[t] }}</span>\n                </button>\n              }\n            </div>\n          }\n        </div>\n      }\n\n      @case ('pill') {\n        <div\n          role=\"radiogroup\"\n          [attr.aria-label]=\"title ?? 'Theme'\"\n          class=\"border-border bg-card relative inline-flex w-full max-w-md rounded-full border p-0.5\"\n        >\n          <span\n            aria-hidden=\"true\"\n            class=\"bg-primary pointer-events-none absolute top-0.5 bottom-0.5 left-0.5 rounded-full transition-transform duration-300 ease-out\"\n            [style.width]=\"indicatorStyle()['width']\"\n            [style.transform]=\"indicatorStyle()['transform']\"\n          ></span>\n          @for (t of options(); track t) {\n            <button\n              type=\"button\"\n              role=\"radio\"\n              [attr.aria-checked]=\"currentValue === t\"\n              [attr.aria-label]=\"labels[t]\"\n              class=\"focus-visible:ring-ring relative z-[1] inline-flex h-7 flex-1 items-center justify-center gap-1.5 rounded-full px-3 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n              [class]=\"currentValue === t ? 'text-primary-foreground' : 'text-muted-foreground hover:text-foreground'\"\n              (click)=\"select(t, $event)\"\n            >\n              @switch (t) {\n                @case ('light') {\n                  <svg\n                    class=\"size-3.5\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <circle cx=\"12\" cy=\"12\" r=\"4\" />\n                    <path d=\"M12 2v2\" />\n                    <path d=\"M12 20v2\" />\n                    <path d=\"m4.93 4.93 1.41 1.41\" />\n                    <path d=\"m17.66 17.66 1.41 1.41\" />\n                    <path d=\"M2 12h2\" />\n                    <path d=\"M20 12h2\" />\n                    <path d=\"m6.34 17.66-1.41 1.41\" />\n                    <path d=\"m19.07 4.93-1.41 1.41\" />\n                  </svg>\n                }\n                @case ('dark') {\n                  <svg\n                    class=\"size-3.5\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <path\n                      d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\n                    />\n                  </svg>\n                }\n                @case ('system') {\n                  <svg\n                    class=\"size-3.5\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n                    <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n                    <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n                  </svg>\n                }\n              }\n              <span>{{ labels[t] }}</span>\n            </button>\n          }\n        </div>\n      }\n\n      @case ('pill-4') {\n        <div\n          role=\"radiogroup\"\n          [attr.aria-label]=\"title ?? 'Theme'\"\n          class=\"border-border bg-card relative inline-flex w-full max-w-md rounded-full border p-0.5\"\n        >\n          <span\n            aria-hidden=\"true\"\n            class=\"bg-primary pointer-events-none absolute top-0.5 bottom-0.5 left-0.5 rounded-full transition-transform duration-300 ease-out\"\n            [style.width]=\"indicatorStyle()['width']\"\n            [style.transform]=\"indicatorStyle()['transform']\"\n          ></span>\n          @for (t of options(); track t) {\n            <button\n              type=\"button\"\n              role=\"radio\"\n              [attr.aria-checked]=\"currentValue === t\"\n              [attr.aria-label]=\"labels[t]\"\n              class=\"focus-visible:ring-ring relative z-[1] inline-flex h-7 flex-1 items-center justify-center gap-1.5 rounded-full px-3 text-xs font-medium transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n              [class]=\"currentValue === t ? 'text-primary-foreground' : 'text-muted-foreground hover:text-foreground'\"\n              (click)=\"select(t, $event)\"\n            >\n              @switch (t) {\n                @case ('light') {\n                  <svg\n                    class=\"size-3.5\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <circle cx=\"12\" cy=\"12\" r=\"4\" />\n                    <path d=\"M12 2v2\" />\n                    <path d=\"M12 20v2\" />\n                    <path d=\"m4.93 4.93 1.41 1.41\" />\n                    <path d=\"m17.66 17.66 1.41 1.41\" />\n                    <path d=\"M2 12h2\" />\n                    <path d=\"M20 12h2\" />\n                    <path d=\"m6.34 17.66-1.41 1.41\" />\n                    <path d=\"m19.07 4.93-1.41 1.41\" />\n                  </svg>\n                }\n                @case ('dark') {\n                  <svg\n                    class=\"size-3.5\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <path\n                      d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\n                    />\n                  </svg>\n                }\n                @case ('system') {\n                  <svg\n                    class=\"size-3.5\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <rect width=\"20\" height=\"14\" x=\"2\" y=\"3\" rx=\"2\" />\n                    <line x1=\"8\" x2=\"16\" y1=\"21\" y2=\"21\" />\n                    <line x1=\"12\" x2=\"12\" y1=\"17\" y2=\"21\" />\n                  </svg>\n                }\n                @case ('black') {\n                  <svg\n                    class=\"size-3.5\"\n                    aria-hidden=\"true\"\n                    xmlns=\"http://www.w3.org/2000/svg\"\n                    viewBox=\"0 0 24 24\"\n                    fill=\"none\"\n                    stroke=\"currentColor\"\n                    stroke-width=\"2\"\n                    stroke-linecap=\"round\"\n                    stroke-linejoin=\"round\"\n                  >\n                    <path\n                      d=\"M9.937 15.5A2 2 0 0 0 8.5 14.063l-6.135-1.582a.5.5 0 0 1 0-.962L8.5 9.936A2 2 0 0 0 9.937 8.5l1.582-6.135a.5.5 0 0 1 .963 0L14.063 8.5A2 2 0 0 0 15.5 9.937l6.135 1.581a.5.5 0 0 1 0 .964L15.5 14.063a2 2 0 0 0-1.437 1.437l-1.582 6.135a.5.5 0 0 1-.963 0z\"\n                    />\n                    <path d=\"M20 3v4\" />\n                    <path d=\"M22 5h-4\" />\n                    <path d=\"M4 17v2\" />\n                    <path d=\"M5 18H3\" />\n                  </svg>\n                }\n              }\n              <span>{{ labels[t] }}</span>\n            </button>\n          }\n        </div>\n      }\n\n      @case ('switch') {\n        <button\n          type=\"button\"\n          role=\"switch\"\n          [attr.aria-checked]=\"currentValue === 'dark'\"\n          [attr.aria-label]=\"labels[currentValue]\"\n          class=\"border-border focus-visible:ring-ring relative inline-flex h-8 w-16 items-center rounded-full border transition-colors focus-visible:ring-2 focus-visible:outline-none\"\n          [class]=\"currentValue === 'dark' ? 'bg-primary' : 'bg-muted'\"\n          (click)=\"select(currentValue === 'dark' ? 'light' : 'dark', $event)\"\n        >\n          <svg\n            class=\"text-warning absolute left-1.5 size-4 transition-opacity\"\n            [class]=\"currentValue === 'dark' ? 'opacity-30' : 'opacity-100'\"\n            aria-hidden=\"true\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            viewBox=\"0 0 24 24\"\n            fill=\"none\"\n            stroke=\"currentColor\"\n            stroke-width=\"2\"\n            stroke-linecap=\"round\"\n            stroke-linejoin=\"round\"\n          >\n            <circle cx=\"12\" cy=\"12\" r=\"4\" />\n            <path d=\"M12 2v2\" />\n            <path d=\"M12 20v2\" />\n            <path d=\"m4.93 4.93 1.41 1.41\" />\n            <path d=\"m17.66 17.66 1.41 1.41\" />\n            <path d=\"M2 12h2\" />\n            <path d=\"M20 12h2\" />\n            <path d=\"m6.34 17.66-1.41 1.41\" />\n            <path d=\"m19.07 4.93-1.41 1.41\" />\n          </svg>\n          <svg\n            class=\"text-muted-foreground absolute right-1.5 size-4 transition-opacity\"\n            [class]=\"currentValue === 'light' ? 'opacity-30' : 'opacity-100'\"\n            aria-hidden=\"true\"\n            xmlns=\"http://www.w3.org/2000/svg\"\n            viewBox=\"0 0 24 24\"\n            fill=\"none\"\n            stroke=\"currentColor\"\n            stroke-width=\"2\"\n            stroke-linecap=\"round\"\n            stroke-linejoin=\"round\"\n          >\n            <path\n              d=\"M20.985 12.486a9 9 0 1 1-9.473-9.472c.405-.022.617.46.402.803a6 6 0 0 0 8.268 8.268c.344-.215.825-.004.803.401\"\n            />\n          </svg>\n          <span\n            aria-hidden=\"true\"\n            class=\"bg-card border-border absolute size-6 rounded-full border shadow transition-transform duration-300 ease-out\"\n            [style.transform]=\"switchThumbStyle()['transform']\"\n          ></span>\n        </button>\n      }\n    }\n  `,\n})\nexport class UiThemeSwitchComponent {\n  // Last click seen bubbling through this component's host. The document listener runs later in\n  // the same bubble phase, so a matching event originated inside and must not close the dropdown.\n  // This avoids injecting ElementRef, whose constructor DI metadata broke JIT/TestBed instantiation\n  // (NG0202), and keeps the class `new`-able without an injection context.\n  private lastInsideEvent: Event | null = null\n\n  @HostListener('click', ['$event'])\n  onHostClick(event: Event): void {\n    this.lastInsideEvent = event\n  }\n\n  /** Radix Menu parity: clicking anywhere outside the open dropdown closes it. */\n  @HostListener('document:click', ['$event'])\n  onDocumentClick(event: Event): void {\n    if (event === this.lastInsideEvent) {\n      this.lastInsideEvent = null\n      return\n    }\n    if (this.dropdownOpen) {\n      this.dropdownOpen = false\n    }\n  }\n\n  @Input() value?: Theme\n  @Input() modelValue: Theme = 'system'\n  @Input() variant: ThemeSwitchVariant = 'cards'\n  @Input() title?: string\n  @Input() description?: string\n  @Input({ transform: booleanAttribute }) viewTransition = true\n  @Input('class') className?: string\n  @Output() valueChange = new EventEmitter<Theme>()\n  @Output() modelValueChange = new EventEmitter<Theme>()\n\n  dropdownOpen = false\n\n  readonly labels: Record<Theme, string> = {\n    light: 'Light',\n    dark: 'Dark',\n    system: 'System',\n    black: 'Black',\n  }\n\n  get currentValue(): Theme {\n    return this.value ?? this.modelValue\n  }\n\n  get hostClass(): string {\n    if (this.variant === 'cards') return cn('block w-full', this.className)\n    if (this.variant === 'pill' || this.variant === 'pill-4') return cn('inline-flex w-full', this.className)\n    if (this.variant === 'switch') return cn('contents', this.className)\n    return cn('inline-flex items-center', this.className)\n  }\n\n  options(): Theme[] {\n    return VARIANT_OPTIONS[this.variant]\n  }\n\n  activeIndex(): number {\n    const i = this.options().indexOf(this.currentValue)\n    return i === -1 ? 0 : i\n  }\n\n  indicatorStyle(): Record<string, string> {\n    const n = this.options().length\n    return {\n      width: `calc((100% - 4px) / ${n})`,\n      transform: `translateX(calc(${this.activeIndex()} * 100%))`,\n    }\n  }\n\n  switchThumbStyle(): Record<string, string> {\n    return { transform: `translateX(${this.currentValue === 'dark' ? '36px' : '4px'})` }\n  }\n\n  select(theme: Theme, event?: MouseEvent): void {\n    void withThemeReveal(this.viewTransition, event, () => {\n      this.modelValue = theme\n      this.value = theme\n      this.modelValueChange.emit(theme)\n      this.valueChange.emit(theme)\n    })\n  }\n\n  cycle(event?: MouseEvent): void {\n    const opts = this.options()\n    const next = opts[(this.activeIndex() + 1) % opts.length]\n    if (next) this.select(next, event)\n  }\n\n  resolve(systemDark: boolean): 'light' | 'dark' {\n    if (this.currentValue === 'system') return systemDark ? 'dark' : 'light'\n    return this.currentValue === 'dark' ? 'dark' : 'light'\n  }\n}\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/theme-switch/theme-switch.component.ts"
    },
    {
      "path": "packages/registry-angular/components/theme-switch/index.ts",
      "content": "export { UiThemeSwitchComponent, type Theme, type ThemeSwitchVariant } from './theme-switch.component'\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/theme-switch/index.ts"
    }
  ],
  "dependencies": [],
  "devDependencies": [],
  "registryDependencies": [
    "https://uipkge.dev/r/angular/section-card.json"
  ],
  "description": "Light / dark / system theme toggle — drop in the header. Seven visual variants: cards, icons, icon-only, dropdown, pill, pill-4, and switch. Persists to localStorage and respects prefers-color-scheme for system.",
  "categories": [
    "action"
  ]
}