{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "toggle",
  "type": "registry:ui",
  "title": "Toggle",
  "description": "Switch control with a label and optional description, for a single on/off setting.",
  "categories": [
    "forms"
  ],
  "registryDependencies": [
    "https://whiskeyjack.net/r/utils.json"
  ],
  "files": [
    {
      "path": "components/ui/toggle.tsx",
      "type": "registry:ui",
      "target": "components/ui/toggle.tsx",
      "content": "import * as React from \"react\";\nimport { cn } from \"@/lib/utils\";\n\nexport interface ToggleProps {\n  /** Optional label rendered to the left of the switch. */\n  label?: React.ReactNode;\n  /** Optional helper text rendered below the label. */\n  description?: React.ReactNode;\n  checked: boolean;\n  onChange: (checked: boolean) => void;\n  disabled?: boolean;\n  className?: string;\n  /** Inline styles for the root element. */\n  style?: React.CSSProperties;\n  /** Accessible label when no visible `label` is provided. */\n  \"aria-label\"?: string;\n}\n\n/**\n * Switch-style boolean toggle. When `label` is provided, the whole row reads\n * as `[label]  [switch]`; without a label, just the switch renders (use the\n * `aria-label` prop in that case for accessibility).\n */\nconst Toggle = React.forwardRef<HTMLButtonElement, ToggleProps>(\n  ({ label, description, checked, onChange, disabled, className, ...rest }, ref) => {\n    const handleToggle = () => {\n      if (!disabled) onChange(!checked);\n    };\n\n    const switchEl = (\n      <button\n        ref={ref}\n        type=\"button\"\n        role=\"switch\"\n        aria-checked={checked}\n        onClick={handleToggle}\n        disabled={disabled}\n        className={cn(\n          \"relative inline-flex h-6 w-11 shrink-0 rounded-full transition-colors\",\n          \"wj-focus-ring\",\n          \"disabled:cursor-not-allowed disabled:opacity-50\",\n          // The track's tone follows the theme when off and is an accent fill\n          // when on, so the bevel it takes switches with it.\n          checked\n            ? \"bg-[var(--color-accent-500)] shadow-bevel-accent\"\n            : \"bg-[var(--color-warm-200)] shadow-bevel dark:bg-[var(--color-neutral-700)]\",\n          !label && className,\n        )}\n        {...(!label ? rest : {})}\n      >\n        <span\n          aria-hidden\n          data-on={checked}\n          // Position, size and travel live in .wj-toggle-knob: it drives both\n          // edges independently to get the squash-and-stretch, which a\n          // transform cannot express. White in both themes, so its edge is\n          // always the light-surface one.\n          className=\"wj-toggle-knob bg-white shadow-md-bevel-light\"\n        />\n      </button>\n    );\n\n    if (!label) return switchEl;\n\n    return (\n      <label\n        className={cn(\n          \"flex items-center justify-between gap-3 cursor-pointer\",\n          disabled && \"cursor-not-allowed opacity-50\",\n          className,\n        )}\n      >\n        <span className=\"flex flex-col gap-0.5 min-w-0\">\n          {/*\n            `text-sm` on secondary, matching every other labelled row: an Input's\n            label, a Select's, and the label a caller puts beside a Slider or a\n            SegmentedControl. This was `text-xs` on muted, which made a toggle's\n            title the smallest and faintest text in a settings card while being\n            the primary thing in its row -- visibly undersized as soon as one sat\n            next to any other labelled control.\n\n            The description keeps the smaller muted treatment, so the pair still\n            reads as title-then-hint rather than two lines of equal weight.\n          */}\n          <span className=\"text-sm text-[var(--color-text-secondary-light)] dark:text-[var(--color-text-secondary-dark)]\">\n            {label}\n          </span>\n          {description && (\n            <span className=\"text-[11px] leading-snug text-[var(--color-text-muted-light)]/80 dark:text-[var(--color-text-muted-dark)]/80\">\n              {description}\n            </span>\n          )}\n        </span>\n        {switchEl}\n      </label>\n    );\n  },\n);\nToggle.displayName = \"Toggle\";\n\nexport { Toggle };\n"
    }
  ],
  "docs": "Presentational and controlled: you own the value and the change handler, so it drops straight into a settings list. The switch stays physical under RTL by convention, since it carries an on/off metaphor rather than a directional one.",
  "meta": {
    "group": "forms",
    "related": [
      "toggle-group"
    ],
    "exports": [
      "Toggle"
    ],
    "siteSlug": "toggles"
  }
}
