{
  "$schema": "https://uipkge.dev/schema/registry-item.json",
  "name": "toggle",
  "title": "Toggle",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-angular/components/toggle/toggle.component.ts",
      "content": "import {\n  ChangeDetectorRef,\n  Component,\n  ElementRef,\n  EventEmitter,\n  Input,\n  Output,\n  booleanAttribute,\n  forwardRef,\n  inject,\n  signal,\n  ChangeDetectionStrategy,\n} from '@angular/core'\nimport { NG_VALUE_ACCESSOR, type ControlValueAccessor } from '@angular/forms'\nimport { cn } from '@/lib/utils'\nimport { toggleVariants, type ToggleVariants } from './toggle.variants'\n\nexport type ToggleVariant = NonNullable<ToggleVariants['variant']>\nexport type ToggleSize = NonNullable<ToggleVariants['size']>\n\n/**\n * Angular port of UIPKGE Toggle (React `Toggle` on Radix Toggle). Radix semantics: controlled\n * `pressed` or uncontrolled `defaultPressed` + `pressedChange`, `aria-pressed`,\n * `data-state=\"on\" | \"off\"`, `data-disabled` and native `disabled` (so the `disabled:*`\n * variant styles apply and a disabled toggle is skipped by Tab). Put it on a `<button>`\n * (`<button ui-toggle>`, which also gets `type=\"button\"`); the `<ui-toggle>` custom element\n * gets button semantics via role + tabindex + Enter / Space. Also a ControlValueAccessor,\n * so `[formControl]` / `ngModel` bind the pressed state.\n */\n@Component({\n  changeDetection: ChangeDetectionStrategy.Eager,\n  selector: 'ui-toggle, [ui-toggle]',\n  standalone: true,\n  providers: [{ provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => UiToggleComponent), multi: true }],\n  host: {\n    '[attr.type]': 'isButton ? \"button\" : null',\n    '[attr.role]': 'isButton ? null : \"button\"',\n    '[attr.tabindex]': 'isButton ? null : disabled ? -1 : 0',\n    '[attr.aria-pressed]': 'pressed',\n    '[attr.data-state]': 'pressed ? \"on\" : \"off\"',\n    '[attr.data-disabled]': 'disabled ? \"\" : null',\n    '[attr.disabled]': 'disabled && isButton ? \"\" : null',\n    '[attr.aria-disabled]': 'disabled && !isButton ? \"true\" : null',\n    '[attr.data-uipkge]': '\"\"',\n    '[attr.data-slot]': '\"toggle\"',\n    '[class]': 'hostClass',\n    '(click)': 'toggle()',\n    '(keydown)': 'onKeydown($event)',\n  },\n  template: `<ng-content />`,\n})\nexport class UiToggleComponent implements ControlValueAccessor {\n  // Zoneless-safe: form writes happen outside template events, so schedule a repaint.\n  private readonly cdr = inject(ChangeDetectorRef)\n  private readonly el = inject<ElementRef<HTMLElement>>(ElementRef).nativeElement\n  readonly isButton = this.el.tagName === 'BUTTON'\n\n  /** Internal state; null until set (then `defaultPressed` applies). */\n  private readonly state = signal<boolean | null>(null)\n  private controlled = false\n\n  /** Controlled pressed state. Leave unbound for uncontrolled use with `defaultPressed`. */\n  @Input({ transform: booleanAttribute })\n  set pressed(v: boolean) {\n    this.controlled = true\n    this.state.set(v)\n  }\n  get pressed(): boolean {\n    return this.state() ?? this.defaultPressed\n  }\n  @Input({ transform: booleanAttribute }) defaultPressed = false\n  @Output() pressedChange = new EventEmitter<boolean>()\n\n  @Input() variant?: ToggleVariant\n  @Input() size?: ToggleSize\n  @Input({ transform: booleanAttribute }) disabled = false\n  @Input('class') className?: string\n\n  private onChange: (v: boolean) => void = () => {}\n  private onTouched: () => void = () => {}\n\n  get hostClass(): string {\n    return cn(toggleVariants({ variant: this.variant, size: this.size }), this.className)\n  }\n\n  toggle(): void {\n    if (this.disabled) return\n    const next = !this.pressed\n    if (!this.controlled) this.state.set(next)\n    this.onChange(next)\n    this.onTouched()\n    this.pressedChange.emit(next)\n  }\n\n  onKeydown(event: KeyboardEvent): void {\n    if (this.isButton) return\n    if (event.key === 'Enter' || event.key === ' ') {\n      event.preventDefault()\n      this.toggle()\n    }\n  }\n\n  writeValue(v: boolean | null): void {\n    this.state.set(!!v)\n    this.cdr.markForCheck()\n  }\n\n  registerOnChange(fn: (v: boolean) => void): void {\n    this.onChange = fn\n  }\n\n  registerOnTouched(fn: () => void): void {\n    this.onTouched = fn\n  }\n\n  setDisabledState(isDisabled: boolean): void {\n    this.disabled = isDisabled\n    this.cdr.markForCheck()\n  }\n}\n\nexport { toggleVariants, type ToggleVariants }\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/toggle/toggle.component.ts"
    },
    {
      "path": "packages/registry-angular/components/toggle/toggle.variants.ts",
      "content": "import type { VariantProps } from 'class-variance-authority'\nimport { cva } from 'class-variance-authority'\n\n/**\n * Variant definitions live in their own file (rather than the package\n * `index.ts`) so consuming Vue SFCs can import without creating a circular\n * dependency through the index. See card.variants.ts for the canonical\n * example + the SSR symptom that motivated the split.\n */\n\nexport const toggleVariants = cva(\n  // Focus ring intentionally subtle: 1px ring on :focus-visible only, no\n  // border swap. Keyboard users still get a clear focused state; mouse\n  // users don't see a loud 3px halo after click (which lingers because\n  // the button retains focus). Matches the segmented-control density.\n  \"inline-flex items-center justify-center gap-2 rounded-md text-sm font-medium hover:bg-muted hover:text-muted-foreground disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0 focus-visible:ring-ring/50 focus-visible:ring-1 outline-none transition-colors duration-200 whitespace-nowrap\",\n  {\n    variants: {\n      variant: {\n        default: 'bg-transparent',\n        outline: 'border border-input bg-transparent shadow-xs hover:bg-accent hover:text-accent-foreground',\n      },\n      size: {\n        default: 'h-9 px-2 min-w-9',\n        sm: 'h-8 px-1.5 min-w-8',\n        lg: 'h-10 px-2.5 min-w-10',\n      },\n    },\n    defaultVariants: {\n      variant: 'default',\n      size: 'default',\n    },\n  },\n)\n\nexport type ToggleVariants = VariantProps<typeof toggleVariants>\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/toggle/toggle.variants.ts"
    },
    {
      "path": "packages/registry-angular/components/toggle/index.ts",
      "content": "export {\n  UiToggleComponent,\n  toggleVariants,\n  type ToggleVariants,\n  type ToggleVariant,\n  type ToggleSize,\n} from './toggle.component'\n",
      "type": "registry:ui",
      "target": "~/src/app/components/ui/toggle/index.ts"
    }
  ],
  "dependencies": [
    "class-variance-authority",
    "@angular/forms"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Two-state press-and-latch button (Radix Toggle): controlled pressed or uncontrolled defaultPressed with pressedChange, aria-pressed + data-state, default / outline variants and three sizes. Doubles as a form control.",
  "categories": [
    "action"
  ]
}