{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "switch",
  "title": "UI Switch",
  "description": "A switch whose checked/unchecked state is a pure function of the timeline; the track fill and sliding thumb are keyframed presets.",
  "dependencies": ["remotion"],
  "registryDependencies": ["@remocn/remocn-ui"],
  "files": [
    {
      "path": "registry/remocn-ui/switch/index.tsx",
      "content": "\"use client\";\n\nimport { type RemocnTheme, useRemocnTheme } from \"@/lib/remocn-ui\";\n\nexport type SwitchState = \"unchecked\" | \"checked\";\n\ntype SwitchSize = \"sm\" | \"default\" | \"lg\";\n\nexport interface SwitchProps {\n  state?: SwitchState;\n  style?: SwitchStyle;\n  label?: string;\n  size?: SwitchSize;\n  theme?: Partial<RemocnTheme>;\n  primary?: string;\n  className?: string;\n}\n\nconst SIZE_STYLES: Record<\n  SwitchSize,\n  {\n    trackW: number;\n    trackH: number;\n    thumb: number;\n    pad: number;\n    fontSize: number;\n    gap: number;\n  }\n> = {\n  sm: { trackW: 36, trackH: 20, thumb: 16, pad: 2, fontSize: 13, gap: 8 },\n  default: { trackW: 44, trackH: 24, thumb: 20, pad: 2, fontSize: 15, gap: 10 },\n  lg: { trackW: 52, trackH: 28, thumb: 24, pad: 2, fontSize: 17, gap: 12 },\n};\n\nexport interface SwitchStyle {\n  trackBackground: string;\n  thumbOffset: number;\n}\n\nexport interface SwitchStyleContext {\n  uncheckedTrack: string;\n  checkedTrack: string;\n  thumbColor: string;\n}\n\nexport function switchStyleContext(theme: RemocnTheme): SwitchStyleContext {\n  return {\n    uncheckedTrack: theme.input,\n    checkedTrack: theme.primary,\n    thumbColor: theme.background,\n  };\n}\n\nexport function switchStyle(\n  state: SwitchState,\n  ctx: SwitchStyleContext,\n): SwitchStyle {\n  switch (state) {\n    case \"checked\":\n      return {\n        trackBackground: ctx.checkedTrack,\n        thumbOffset: 1,\n      };\n    default:\n      return {\n        trackBackground: ctx.uncheckedTrack,\n        thumbOffset: 0,\n      };\n  }\n}\n\nexport function Switch({\n  state = \"unchecked\",\n  style,\n  label,\n  size = \"default\",\n  theme: themeOverride,\n  primary,\n  className,\n}: SwitchProps) {\n  const theme = useRemocnTheme(\n    { ...themeOverride, ...(primary ? { primary } : {}) },\n    \"light\",\n  );\n\n  const sizeStyle = SIZE_STYLES[size];\n  const ctx = switchStyleContext(theme);\n  const v = style ?? switchStyle(state, ctx);\n\n  const travel = sizeStyle.trackW - sizeStyle.thumb - sizeStyle.pad * 2;\n\n  return (\n    <div\n      style={{\n        position: \"absolute\",\n        inset: 0,\n        display: \"flex\",\n        alignItems: \"center\",\n        justifyContent: \"center\",\n        background: \"transparent\",\n        fontFamily:\n          \"var(--font-geist-sans), -apple-system, BlinkMacSystemFont, sans-serif\",\n      }}\n    >\n      <span\n        className={className}\n        style={{\n          display: \"inline-flex\",\n          alignItems: \"center\",\n          gap: sizeStyle.gap,\n        }}\n      >\n        {}\n        <span\n          style={{\n            position: \"relative\",\n            display: \"flex\",\n            alignItems: \"center\",\n            width: sizeStyle.trackW,\n            height: sizeStyle.trackH,\n            borderRadius: sizeStyle.trackH / 2,\n            background: v.trackBackground,\n          }}\n        >\n          {}\n          <span\n            style={{\n              position: \"absolute\",\n              left: sizeStyle.pad,\n              width: sizeStyle.thumb,\n              height: sizeStyle.thumb,\n              borderRadius: \"50%\",\n              background: ctx.thumbColor,\n              boxShadow: \"0 1px 2px rgba(0,0,0,0.15)\",\n              transform: `translateX(${v.thumbOffset * travel}px)`,\n            }}\n          />\n        </span>\n        {label !== undefined && (\n          <span\n            style={{\n              fontSize: sizeStyle.fontSize,\n              fontWeight: 500,\n              letterSpacing: \"-0.01em\",\n              color: theme.foreground,\n            }}\n          >\n            {label}\n          </span>\n        )}\n      </span>\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/remocn/switch.tsx"
    },
    {
      "path": "registry/remocn-ui/switch/use-switch-transition.ts",
      "content": "\"use client\";\n\nimport {\n  type SwitchState,\n  type SwitchStyle,\n  switchStyle,\n  switchStyleContext,\n} from \"@/components/remocn/switch\";\nimport {\n  easings,\n  mixOklch,\n  type RemocnTheme,\n  type Step,\n  useRemocnTheme,\n  useStateTransition,\n} from \"@/lib/remocn-ui\";\n\nexport const DEFAULT_DURATION = 10;\n\nexport function tweenSwitchStyle(\n  a: SwitchStyle,\n  b: SwitchStyle,\n  t: number,\n): SwitchStyle {\n  return {\n    trackBackground: mixOklch(a.trackBackground, b.trackBackground, t),\n    thumbOffset: a.thumbOffset + (b.thumbOffset - a.thumbOffset) * t,\n  };\n}\n\nexport interface SwitchTransitionOptions {\n  theme?: Partial<RemocnTheme>;\n  mode?: \"light\" | \"dark\";\n  primary?: string;\n  speed?: number;\n  defaultDuration?: number;\n}\n\nexport function useSwitchTransition(\n  steps: Step<SwitchState>[],\n  opts: SwitchTransitionOptions = {},\n): SwitchStyle {\n  const {\n    theme: themeOverride,\n    mode,\n    primary,\n    speed = 1,\n    defaultDuration = DEFAULT_DURATION,\n  } = opts;\n  const theme = useRemocnTheme(\n    { ...themeOverride, ...(primary ? { primary } : {}) },\n    mode,\n  );\n  const ctx = switchStyleContext(theme);\n  const { from, to, progress } = useStateTransition(\n    steps,\n    \"unchecked\",\n    speed,\n    defaultDuration,\n  );\n  const t = easings.out(progress);\n  return tweenSwitchStyle(switchStyle(from, ctx), switchStyle(to, ctx), t);\n}\n",
      "type": "registry:component",
      "target": "components/remocn/use-switch-transition.ts"
    }
  ],
  "type": "registry:component"
}
