{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "switch",
  "type": "registry:component",
  "title": "Switch",
  "description": "Turns one setting on or off. A slim 44×24px track sits inside a 44px touch target.",
  "registryDependencies": [
    "https://vlak.dev/r/vlak-base.json",
    "https://vlak.dev/r/inter.json",
    "https://vlak.dev/r/vlak-lib.json"
  ],
  "dependencies": [
    "@stylexjs/stylex"
  ],
  "devDependencies": [
    "@stylexjs/babel-plugin"
  ],
  "docs": "Vlak leaves are StyleX. Compile them with @stylexjs/babel-plugin (Vite: @stylexjs/unplugin, Next: @stylexjs/nextjs-plugin). If you would rather not run a compiler, import @noorddev/vlak-react instead: it ships precompiled with one stylesheet.",
  "files": [
    {
      "path": "vlak/switch.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\nimport * as stylex from \"@stylexjs/stylex\";\nimport { vlak, mq } from \"./tokens.stylex\";\nimport { rs } from \"./rs\";\n\nexport interface SwitchProps\n  extends Omit<React.ButtonHTMLAttributes<HTMLButtonElement>, \"onChange\"> {\n  checked?: boolean;\n  defaultChecked?: boolean;\n  onCheckedChange?: (checked: boolean) => void;\n}\n\nconst styles = stylex.create({\n  track: {\n    display: \"inline-flex\",\n    boxSizing: \"border-box\",\n    width: vlak.hit,\n    height: vlak.hit,\n    minWidth: vlak.hit,\n    minHeight: vlak.hit,\n    borderRadius: vlak.radiusSm,\n    borderWidth: 0,\n    position: \"relative\",\n    flexShrink: 0,\n    padding: 0,\n    backgroundColor: \"transparent\",\n    cursor: \"pointer\",\n    // The visible rail is slim; the transparent button keeps a 44px hit area.\n    \"::before\": {\n      content: '\"\"',\n      boxSizing: \"border-box\",\n      position: \"absolute\",\n      top: \"0.625rem\",\n      insetInlineStart: 0,\n      width: \"2.75rem\",\n      height: \"1.5rem\",\n      borderRadius: \"0.75rem\",\n      borderWidth: 1.5,\n      borderStyle: \"solid\",\n      borderColor: {\n        default: vlak.controlBorder,\n        [mq.forcedColors]: \"ButtonText\",\n      },\n      backgroundColor: \"transparent\",\n      transition: {\n        default: `background-color ${vlak.duration} ${vlak.ease}, border-color ${vlak.duration} ${vlak.ease}`,\n        [mq.reduce]: \"none\",\n      },\n    },\n    outlineWidth: {\n      default: null,\n      \":focus-visible\": 2,\n    },\n    outlineStyle: {\n      default: null,\n      \":focus-visible\": \"solid\",\n    },\n    outlineColor: {\n      default: null,\n      \":focus-visible\": vlak.ink,\n    },\n    outlineOffset: {\n      default: null,\n      \":focus-visible\": 2,\n    },\n  },\n  on: {\n    \"::before\": {\n      backgroundColor: {\n        default: vlak.ink,\n        [mq.forcedColors]: \"Highlight\",\n      },\n      borderColor: {\n        default: vlak.ink,\n        [mq.forcedColors]: \"Highlight\",\n      },\n    },\n    forcedColorAdjust: \"none\",\n  },\n  thumb: {\n    position: \"absolute\",\n    top: \"0.84375rem\",\n    insetInlineStart: \"0.21875rem\",\n    width: \"1.0625rem\",\n    height: \"1.0625rem\",\n    borderRadius: \"50%\",\n    backgroundColor: {\n      default: vlak.gray,\n      [mq.forcedColors]: \"ButtonText\",\n    },\n    forcedColorAdjust: \"none\",\n    transition: {\n      default: `inset-inline-start ${vlak.duration} ${vlak.ease}`,\n      [mq.reduce]: \"none\",\n    },\n  },\n  thumbOn: {\n    backgroundColor: {\n      default: vlak.paper,\n      [mq.forcedColors]: \"HighlightText\",\n    },\n    insetInlineStart: \"1.46875rem\",\n  },\n});\n\n/** A button with role=\"switch\". */\nexport const Switch = React.forwardRef<HTMLButtonElement, SwitchProps>(function Switch(\n  { checked, defaultChecked, onCheckedChange, className, style, onClick, ...props },\n  ref,\n) {\n  const [inner, setInner] = React.useState(defaultChecked ?? false);\n  const isControlled = checked !== undefined;\n  const on = isControlled ? checked : inner;\n  const sx = rs([\"rs-switch\", on && \"rs-switch-on\", className], styles.track, on && styles.on);\n  const knob = rs([\"rs-switch-thumb\", on && \"rs-switch-thumb-on\"], styles.thumb, on && styles.thumbOn);\n  return (\n    <button\n      ref={ref}\n      type=\"button\"\n      role=\"switch\"\n      aria-checked={on}\n      className={sx.className}\n      style={{ ...sx.style, ...style }}\n      onClick={(e) => {\n        if (!isControlled) setInner(!on);\n        onCheckedChange?.(!on);\n        onClick?.(e);\n      }}\n      {...props}\n    >\n      <i aria-hidden=\"true\" className={knob.className} style={knob.style} />\n    </button>\n  );\n});\n",
      "type": "registry:component",
      "target": "components/vlak/switch.tsx"
    },
    {
      "path": "vlak/styles/switch.css",
      "content": "/* ── switch: generated from packages/react/src/components/switch.tsx ── */\n.rs-switch{display:inline-flex;box-sizing:border-box;width:var(--hit);height:var(--hit);min-width:var(--hit);min-height:var(--hit);border-radius:var(--radius-sm);border-width:0;position:relative;flex-shrink:0;padding:0;background-color:transparent;cursor:pointer}\n.rs-switch::before{content:\"\";box-sizing:border-box;position:absolute;top:0.625rem;inset-inline-start:0;width:2.75rem;height:1.5rem;border-radius:0.75rem;border-width:1.5px;border-style:solid;border-color:var(--control-border);background-color:transparent;transition:background-color var(--duration) var(--ease), border-color var(--duration) var(--ease)}\n.rs-switch:focus-visible{outline-width:2px;outline-style:solid;outline-color:var(--text);outline-offset:2px}\n@media (forced-colors: active){.rs-switch::before{border-color:ButtonText}}\n@media (prefers-reduced-motion: reduce){.rs-switch::before{transition:none}}\n.rs-switch-on::before{background-color:var(--text);border-color:var(--text)}\n.rs-switch-on{forced-color-adjust:none}\n@media (forced-colors: active){.rs-switch-on::before{background-color:Highlight;border-color:Highlight}}\n.rs-switch-thumb{position:absolute;top:0.84375rem;inset-inline-start:0.21875rem;width:1.0625rem;height:1.0625rem;border-radius:50%;background-color:var(--text-secondary);forced-color-adjust:none;transition:inset-inline-start var(--duration) var(--ease)}\n@media (forced-colors: active){.rs-switch-thumb{background-color:ButtonText}}\n@media (prefers-reduced-motion: reduce){.rs-switch-thumb{transition:none}}\n.rs-switch-thumb-on{background-color:var(--bg);inset-inline-start:1.46875rem}\n@media (forced-colors: active){.rs-switch-thumb-on{background-color:HighlightText}}\n",
      "type": "registry:file",
      "target": "styles/vlak/switch.css"
    }
  ],
  "meta": {
    "vlak": {
      "category": "forms",
      "classes": [
        "rs-switch",
        "rs-switch-on",
        "rs-switch-thumb",
        "rs-switch-thumb-on"
      ],
      "snippet": "<button type=\"button\" class=\"rs-switch rs-switch-on\" role=\"switch\" aria-checked=\"true\" aria-label=\"Notifications\"><i class=\"rs-switch-thumb rs-switch-thumb-on\" aria-hidden=\"true\"></i></button>",
      "cssOnly": false,
      "registryDependencies": [
        "vlak-lib"
      ],
      "aliases": [
        "Switch",
        "Toggle switch"
      ],
      "example": "import { useState } from \"react\";\nimport { Switch } from \"@noorddev/vlak-react\";\n\nconst [enabled, setEnabled] = useState(false);\n\n<Switch checked={enabled} onCheckedChange={setEnabled} aria-label=\"Notifications\" />",
      "usage": {
        "use": [
          "A setting that applies as soon as it flips.",
          "Binary state with a clear on and off."
        ],
        "avoid": [
          "Choices that need a submit button; use Checkbox.",
          "More than two states; use ToggleGroup."
        ]
      },
      "keyboard": [
        {
          "keys": "Tab",
          "does": "Moves focus to the switch"
        },
        {
          "keys": "Space, Enter",
          "does": "Toggles it"
        }
      ],
      "a11y": [
        "A native <button> with role=\"switch\" and aria-checked.",
        "It has no visible text; pass aria-label or aria-labelledby.",
        "Controlled with checked and onCheckedChange, or uncontrolled with defaultChecked."
      ]
    }
  }
}
