{"$schema":"https://ui.shadcn.com/schema/registry-item.json","author":"Eduardo Calvo <edu@smoothui.dev>","css":{},"dependencies":["@base-ui/react","motion"],"description":"Checkbox Group for SmoothUI with parent/indeterminate support, Base UI twin and Radix-parity twin.","devDependencies":[],"files":[{"content":"\"use client\";\n\nimport { Checkbox as CheckboxPrimitive } from \"@base-ui/react/checkbox\";\nimport { CheckboxGroup as CheckboxGroupPrimitive } from \"@base-ui/react/checkbox-group\";\nimport { cn } from \"@/lib/utils\";\nimport { AnimatePresence, motion, useReducedMotion } from \"motion/react\";\nimport { type ComponentProps, type ReactNode, useId } from \"react\";\nimport { SPRING_DEFAULT } from \"@/components/smoothui/lib/animation\";\n\nexport interface CheckboxGroupProps {\n  /** All child values — required when using a parent item */\n  allValues?: string[];\n  /** Accessible name when there is no visible label */\n  \"aria-label\"?: string;\n  /** ID of the labelling element */\n  \"aria-labelledby\"?: string;\n  /** Group items */\n  children?: ReactNode;\n  /** Optional CSS class for the group */\n  className?: string;\n  /** Uncontrolled initial values */\n  defaultValue?: string[];\n  /** Disable the whole group */\n  disabled?: boolean;\n  /** Called when the selected values change */\n  onValueChange?: (value: string[]) => void;\n  /** Controlled selected values */\n  value?: string[];\n}\n\nexport interface CheckboxGroupItemProps {\n  /** Label content rendered next to the checkbox */\n  children?: ReactNode;\n  /** Optional CSS class for the checkbox control */\n  className?: string;\n  /** Disable this item */\n  disabled?: boolean;\n  /** ID for label association */\n  id?: string;\n  /** Parent / select-all control — requires `allValues` on the group */\n  parent?: boolean;\n  /** Value identifying this item in the group (omit for parent) */\n  value?: string;\n}\n\nexport type CheckboxGroupRootProps = Omit<\n  ComponentProps<typeof CheckboxGroupPrimitive>,\n  \"className\"\n> & { className?: string };\n\nconst CHECKBOX_CLASS =\n  \"peer size-4 shrink-0 cursor-pointer appearance-none rounded-[4px] border border-foreground/40 bg-background p-0 shadow-xs outline-none state-transition focus-visible:border-ring focus-ring disabled:cursor-not-allowed disabled:border-foreground/30 disabled:bg-muted aria-invalid:border-destructive aria-invalid:ring-destructive/20 data-checked:border-foreground data-indeterminate:border-foreground data-checked:bg-foreground data-indeterminate:bg-foreground data-unchecked:bg-background data-checked:text-background data-indeterminate:text-background disabled:data-checked:border-muted-foreground disabled:data-indeterminate:border-muted-foreground disabled:data-checked:bg-muted-foreground disabled:data-indeterminate:bg-muted-foreground dark:data-unchecked:bg-foreground/10 dark:aria-invalid:ring-destructive/40\";\n\nconst CheckmarkPath = motion.path;\nconst MotionSvg = motion.svg;\n\nconst CheckboxGlyph = ({\n  state,\n}: {\n  state: \"checked\" | \"indeterminate\" | \"unchecked\";\n}) => {\n  const shouldReduceMotion = useReducedMotion();\n\n  return (\n    <AnimatePresence mode=\"wait\">\n      {state === \"checked\" ? (\n        <MotionSvg\n          animate={\n            shouldReduceMotion ? { opacity: 1 } : { opacity: 1, scale: 1 }\n          }\n          className=\"size-3.5\"\n          exit={\n            shouldReduceMotion\n              ? { opacity: 0, transition: { duration: 0 } }\n              : { opacity: 0, scale: 0.8 }\n          }\n          fill=\"none\"\n          initial={\n            shouldReduceMotion ? { opacity: 1 } : { opacity: 0, scale: 0.8 }\n          }\n          key=\"check\"\n          stroke=\"currentColor\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          strokeWidth={3}\n          transition={shouldReduceMotion ? { duration: 0 } : SPRING_DEFAULT}\n          aria-hidden=\"true\"\n          focusable=\"false\"\n          viewBox=\"0 0 24 24\"\n        >\n          <CheckmarkPath\n            animate={shouldReduceMotion ? {} : { pathLength: 1 }}\n            d=\"M20 6L9 17l-5-5\"\n            initial={shouldReduceMotion ? {} : { pathLength: 0 }}\n            transition={\n              shouldReduceMotion\n                ? { duration: 0 }\n                : { ...SPRING_DEFAULT, delay: 0.05 }\n            }\n          />\n        </MotionSvg>\n      ) : null}\n      {state === \"indeterminate\" ? (\n        <MotionSvg\n          animate={\n            shouldReduceMotion ? { opacity: 1 } : { opacity: 1, scale: 1 }\n          }\n          className=\"size-3.5\"\n          exit={\n            shouldReduceMotion\n              ? { opacity: 0, transition: { duration: 0 } }\n              : { opacity: 0, scale: 0.8 }\n          }\n          fill=\"none\"\n          initial={\n            shouldReduceMotion ? { opacity: 1 } : { opacity: 0, scale: 0.8 }\n          }\n          key=\"indeterminate\"\n          stroke=\"currentColor\"\n          strokeLinecap=\"round\"\n          strokeLinejoin=\"round\"\n          strokeWidth={3}\n          transition={shouldReduceMotion ? { duration: 0 } : SPRING_DEFAULT}\n          aria-hidden=\"true\"\n          focusable=\"false\"\n          viewBox=\"0 0 24 24\"\n        >\n          <CheckmarkPath\n            animate={shouldReduceMotion ? {} : { pathLength: 1 }}\n            d=\"M5 12h14\"\n            initial={shouldReduceMotion ? {} : { pathLength: 0 }}\n            transition={\n              shouldReduceMotion\n                ? { duration: 0 }\n                : { ...SPRING_DEFAULT, delay: 0.05 }\n            }\n          />\n        </MotionSvg>\n      ) : null}\n    </AnimatePresence>\n  );\n};\n\n/**\n * SmoothUI Checkbox Group — Base UI twin (default).\n */\nexport function CheckboxGroup({\n  allValues,\n  \"aria-label\": ariaLabel,\n  \"aria-labelledby\": ariaLabelledBy,\n  children,\n  className,\n  defaultValue,\n  disabled = false,\n  onValueChange,\n  value,\n}: CheckboxGroupProps) {\n  return (\n    <CheckboxGroupPrimitive\n      allValues={allValues}\n      aria-label={ariaLabel}\n      aria-labelledby={ariaLabelledBy}\n      className={cn(\"grid gap-3\", className)}\n      data-slot=\"checkbox-group\"\n      defaultValue={defaultValue}\n      disabled={disabled}\n      onValueChange={onValueChange}\n      value={value}\n    >\n      {children}\n    </CheckboxGroupPrimitive>\n  );\n}\n\n/**\n * Labelled checkbox row. Pass `parent` for select-all (requires `allValues`).\n */\nexport function CheckboxGroupItem({\n  children,\n  className,\n  disabled,\n  id,\n  parent = false,\n  value,\n}: CheckboxGroupItemProps) {\n  const generatedId = useId();\n  const itemId = id ?? generatedId;\n\n  return (\n    <label\n      className=\"flex cursor-pointer items-center gap-2 text-sm leading-none peer-disabled:cursor-not-allowed has-disabled:cursor-not-allowed has-disabled:opacity-50\"\n      htmlFor={itemId}\n    >\n      <CheckboxPrimitive.Root\n        className={cn(CHECKBOX_CLASS, className)}\n        data-slot=\"checkbox\"\n        disabled={disabled}\n        id={itemId}\n        nativeButton\n        parent={parent}\n        render={<button type=\"button\" />}\n        value={value}\n      >\n        <CheckboxPrimitive.Indicator\n          className=\"grid place-content-center text-current\"\n          data-slot=\"checkbox-indicator\"\n          keepMounted\n          render={(props, state) => {\n            let glyphState: \"checked\" | \"indeterminate\" | \"unchecked\" =\n              \"unchecked\";\n            if (state.indeterminate) {\n              glyphState = \"indeterminate\";\n            } else if (state.checked) {\n              glyphState = \"checked\";\n            }\n            return (\n              <span {...props}>\n                <CheckboxGlyph state={glyphState} />\n              </span>\n            );\n          }}\n        />\n      </CheckboxPrimitive.Root>\n      {children ? <span>{children}</span> : null}\n    </label>\n  );\n}\n\nexport default CheckboxGroup;\n","path":"index.tsx","target":"components/smoothui/checkbox-group/index.tsx","type":"registry:ui"}],"name":"checkbox-group","registryDependencies":["https://smoothui.dev/r/lib.json","https://smoothui.dev/r/tokens.json"],"title":"Checkbox Group","type":"registry:ui"}