{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"checkbox","type":"registry:ui","title":"Checkbox","description":"A checkbox that draws its check mark and squishes when pressed.","dependencies":["@radix-ui/react-checkbox@^1.3.11","motion@^14.0.0"],"files":[{"path":"components/ui/checkbox.tsx","type":"registry:ui","content":"\"use client\";\n\nimport * as CheckboxPrimitive from \"@radix-ui/react-checkbox\";\nimport { motion } from \"motion/react\";\nimport * as React from \"react\";\nimport { chewyEase } from \"@/lib/motion\";\nimport { useControllableState } from \"@/hooks/use-controllable-state\";\nimport { cn } from \"@/lib/utils\";\n\nfunction Checkbox({\n  className,\n  checked: checkedProp,\n  defaultChecked,\n  onCheckedChange,\n  ...props\n}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {\n  const [checked, setChecked] = useControllableState<CheckboxPrimitive.CheckedState>(\n    checkedProp,\n    defaultChecked ?? false,\n    onCheckedChange,\n  );\n\n  return (\n    <CheckboxPrimitive.Root data-slot=\"checkbox\" checked={checked} onCheckedChange={setChecked} asChild {...props}>\n      <motion.button\n        whileTap={{ scale: 0.85 }}\n        transition={{ type: \"spring\", stiffness: 600, damping: 25 }}\n        className={cn(\n          \"peer border-input data-[state=unchecked]:bg-background dark:data-[state=unchecked]:bg-input/30 flex size-4 shrink-0 items-center justify-center rounded-[5px] border shadow-xs transition-[background-color,border-color] outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-solid focus-visible:outline-foreground aria-invalid:focus-visible:outline-destructive disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-destructive\",\n          \"data-[state=checked]:bg-primary data-[state=checked]:border-primary data-[state=checked]:text-primary-foreground data-[state=indeterminate]:bg-primary data-[state=indeterminate]:border-primary data-[state=indeterminate]:text-primary-foreground\",\n          \"data-[state=checked]:shadow-[inset_0_1px_0_rgb(255_255_255/0.2)] data-[state=indeterminate]:shadow-[inset_0_1px_0_rgb(255_255_255/0.2)]\",\n          className,\n        )}\n      >\n        <CheckboxPrimitive.Indicator forceMount data-slot=\"checkbox-indicator\" className=\"flex\">\n          <svg viewBox=\"0 0 16 16\" fill=\"none\" className=\"size-3.5\" aria-hidden>\n            <motion.path\n              d={checked === \"indeterminate\" ? \"M4 8h8\" : \"M3.5 8.5l3 3 6-6.5\"}\n              stroke=\"currentColor\"\n              strokeWidth={2}\n              strokeLinecap=\"round\"\n              strokeLinejoin=\"round\"\n              initial={false}\n              animate={{ pathLength: checked ? 1 : 0, opacity: checked ? 1 : 0 }}\n              transition={{ duration: 0.2, ease: chewyEase }}\n            />\n          </svg>\n        </CheckboxPrimitive.Indicator>\n      </motion.button>\n    </CheckboxPrimitive.Root>\n  );\n}\n\nexport { Checkbox };\n"},{"path":"lib/motion.ts","type":"registry:lib","content":"\"use client\";\n\nimport * as React from \"react\";\nimport { useControllableState } from \"@/hooks/use-controllable-state\";\nimport type { MotionProps, Transition } from \"motion/react\";\n\nexport const chewyEase = [0.32, 0.72, 0, 1] as const;\n\nexport const growTransition = { duration: 0.6, ease: chewyEase };\n\nconst springIn: Transition = { type: \"spring\", bounce: 0.2, duration: 0.3 };\nconst quickOut: Transition = { duration: 0.12, ease: \"easeIn\" };\n\nexport const popMotion = {\n  initial: { opacity: 0, scale: 0.96 },\n  animate: { opacity: 1, scale: 1, transition: springIn },\n  exit: { opacity: 0, scale: 0.96, transition: quickOut },\n};\n\nexport const tooltipMotion = {\n  initial: { opacity: 0, scale: 0.94 },\n  animate: { opacity: 1, scale: 1, transition: { ...springIn, duration: 0.2 } },\n  exit: { opacity: 0, scale: 0.94, transition: { duration: 0.08 } },\n};\n\nexport const dialogMotion = {\n  initial: { opacity: 0, scale: 0.95, y: 8 },\n  animate: { opacity: 1, scale: 1, y: 0, transition: { type: \"spring\", bounce: 0.25, duration: 0.4 } as Transition },\n  exit: { opacity: 0, scale: 0.97, y: 4, transition: { duration: 0.15, ease: \"easeIn\" } as Transition },\n};\n\nexport const overlayMotion = {\n  initial: { opacity: 0 },\n  animate: { opacity: 1, transition: { duration: 0.2 } },\n  exit: { opacity: 0, transition: { duration: 0.15 } },\n};\n\nexport type PanelSide = \"top\" | \"right\" | \"bottom\" | \"left\";\n\nexport function panelMotion(side: PanelSide): Pick<MotionProps, \"initial\" | \"animate\" | \"exit\"> {\n  const offscreen = side === \"left\" || side === \"top\" ? \"calc(-100% - 1rem)\" : \"calc(100% + 1rem)\";\n  const horizontal = side === \"left\" || side === \"right\";\n  const hidden = horizontal ? { x: offscreen } : { y: offscreen };\n  const shown = horizontal ? { x: 0 } : { y: 0 };\n\n  return {\n    initial: hidden,\n    animate: { ...shown, transition: { duration: 0.45, ease: chewyEase } },\n    exit: { ...hidden, transition: { duration: 0.3, ease: chewyEase } },\n  };\n}\n\nexport function useAnimatedOpen(\n  openProp: boolean | undefined,\n  defaultOpen: boolean | undefined,\n  onOpenChange: ((open: boolean) => void) | undefined,\n) {\n  const [open, setOpen] = useControllableState(openProp, defaultOpen ?? false, onOpenChange);\n  const [exiting, setExiting] = React.useState(false);\n  const [wasOpen, setWasOpen] = React.useState(open);\n\n  if (open !== wasOpen) {\n    setWasOpen(open);\n    setExiting(!open);\n  }\n\n  const onExitComplete = React.useCallback(() => setExiting(false), []);\n\n  return { open, setOpen, radixOpen: open || exiting, onExitComplete };\n}\n\ntype AnimatedOpenState = { open: boolean; onExitComplete: () => void };\n\ntype OpenProps = { open?: boolean; defaultOpen?: boolean; onOpenChange?: (open: boolean) => void };\n\nexport function createAnimatedRoot<P extends OpenProps>(Primitive: React.ComponentType<P>, slot: string) {\n  const Context = React.createContext<AnimatedOpenState>({ open: false, onExitComplete: () => {} });\n\n  function AnimatedRoot({ open: openProp, defaultOpen, onOpenChange, ...props }: P) {\n    const { open, setOpen, radixOpen, onExitComplete } = useAnimatedOpen(openProp, defaultOpen, onOpenChange);\n    const value = React.useMemo(() => ({ open, onExitComplete }), [open, onExitComplete]);\n    const primitiveProps = { \"data-slot\": slot, ...props, open: radixOpen, onOpenChange: setOpen } as unknown as P;\n\n    return React.createElement(Context.Provider, { value }, React.createElement(Primitive, primitiveProps));\n  }\n\n  return [AnimatedRoot, () => React.useContext(Context)] as const;\n}\n"},{"path":"hooks/use-controllable-state.ts","type":"registry:hook","content":"import * as React from \"react\";\n\nexport function useControllableState<T>(prop: T | undefined, defaultProp: T, onChange?: (value: T) => void) {\n  const [uncontrolled, setUncontrolled] = React.useState(defaultProp);\n  const isControlled = prop !== undefined;\n  const value = isControlled ? prop : uncontrolled;\n\n  const setValue = React.useCallback(\n    (next: T) => {\n      if (!isControlled) setUncontrolled(next);\n      onChange?.(next);\n    },\n    [isControlled, onChange],\n  );\n\n  return [value, setValue] as const;\n}\n"}]}