g1t/apps/web/app/components/ui/checkbox.tsx
Pick any line to see why it is the way it is: the commit, the pull request and issue it came from, and what the agent was thinking.
| Workspace names and icons, and a component kit for every control | 1 | import { Check, Minus } from "lucide-react"; |
| 2 | import { Checkbox as Primitive } from "radix-ui"; | |
| 3 | import { type ComponentProps, type ReactNode, useId } from "react"; | |
| 4 | ||
| 5 | import { cn } from "../../lib/cn"; | |
| 6 | ||
| 7 | // shadcn/ui's checkbox, styled with g1t's tokens. | |
| 8 | // | |
| 9 | // Inside a <Form>, a `name` makes Radix render a hidden checkbox beside it, | |
| 10 | // so it posts `value` (default "on") when checked and nothing when not, | |
| 11 | // exactly as a native one does. Wrap it and its text in a <label>, or point | |
| 12 | // a <Label htmlFor> at its `id`. | |
| 13 | ||
| 14 | /** A checkbox with its label, and optionally a line under it. */ | |
| 15 | export function CheckboxOption({ | |
| 16 | label, | |
| 17 | description, | |
| 18 | className, | |
| 19 | labelClassName, | |
| 20 | ...props | |
| 21 | }: ComponentProps<typeof Primitive.Root> & { label: ReactNode; description?: ReactNode; labelClassName?: string }) { | |
| 22 | const generated = useId(); | |
| 23 | const id = props.id ?? generated; | |
| 24 | return ( | |
| 25 | <div className={cn("flex items-start gap-2.5", props.disabled && "opacity-60", className)}> | |
| 26 | <Checkbox id={id} className={className?.includes("items-center") ? undefined : "mt-0.5"} aria-describedby={description ? `${id}-d` : undefined} {...props} /> | |
| 27 | <label htmlFor={id} className={cn("min-w-0 text-sm text-fg", props.disabled ? "cursor-not-allowed" : "cursor-pointer", labelClassName)}> | |
| 28 | {label} | |
| 29 | {description && ( | |
| 30 | <span id={`${id}-d`} className="mt-0.5 block text-xs text-faint"> | |
| 31 | {description} | |
| 32 | </span> | |
| 33 | )} | |
| 34 | </label> | |
| 35 | </div> | |
| 36 | ); | |
| 37 | } | |
| 38 | ||
| 39 | export function Checkbox({ className, ...props }: ComponentProps<typeof Primitive.Root>) { | |
| 40 | return ( | |
| 41 | <Primitive.Root | |
| 42 | className={cn( | |
| 43 | "peer inline-flex size-4 shrink-0 items-center justify-center rounded-[5px] border border-line-strong bg-bg text-bg outline-none transition-colors", | |
| 44 | "hover:border-faint focus-visible:ring-2 focus-visible:ring-accent/40 focus-visible:ring-offset-1 focus-visible:ring-offset-bg focus-visible:outline-none", | |
| 45 | "data-[state=checked]:border-accent data-[state=checked]:bg-accent data-[state=indeterminate]:border-accent data-[state=indeterminate]:bg-accent", | |
| 46 | "disabled:cursor-not-allowed disabled:opacity-50 aria-invalid:border-danger/70", | |
| 47 | className, | |
| 48 | )} | |
| 49 | {...props} | |
| 50 | > | |
| 51 | <Primitive.Indicator className="flex items-center justify-center data-[state=checked]:animate-pop-in motion-reduce:animate-none"> | |
| 52 | {props.checked === "indeterminate" ? ( | |
| 53 | <Minus size={12} strokeWidth={3} /> | |
| 54 | ) : ( | |
| 55 | <Check size={12} strokeWidth={3} /> | |
| 56 | )} | |
| 57 | </Primitive.Indicator> | |
| 58 | </Primitive.Root> | |
| 59 | ); | |
| 60 | } |