Files
HiveGrid-Wireframes/hivegrid-cloud/apps/web/app/components/ui/checkbox.tsx
T

59 lines
2.1 KiB
TypeScript

"use client"
import * as React from "react"
import * as CheckboxPrimitive from "@radix-ui/react-checkbox"
import { Checkbox as SubframeCheckbox } from "~/ui/components/Checkbox"
import { cn } from "~/lib/utils"
// Subframe migration (strangler shim):
// Keeps the original shadcn/Radix `Checkbox` API (`React.ComponentProps<typeof
// CheckboxPrimitive.Root>`) but renders the Subframe design-system Checkbox behind it.
//
// Pitfalls handled here:
// - Subframe's Checkbox is ALWAYS controlled (no uncontrolled/`defaultChecked` path), so
// the shim owns the checked state with `useState` and only defers to the caller when
// `checked` is supplied — preserving controlled + uncontrolled behavior.
// - Radix `CheckedState` is `boolean | "indeterminate"`. Subframe splits this into separate
// `checked` (boolean) + `indeterminate` (boolean) props, so the shim maps them apart and
// re-assembles the `CheckedState` back into `onCheckedChange`.
// - The bare checkbox renders just the box (no label), so Subframe's label slot is hidden by
// default; a caller can still override `hideLabel`.
function Checkbox({
className,
checked,
defaultChecked,
onCheckedChange,
...props
}: React.ComponentProps<typeof CheckboxPrimitive.Root>) {
const isControlled = checked !== undefined
const [internalChecked, setInternalChecked] = React.useState<CheckboxPrimitive.CheckedState>(
defaultChecked ?? false
)
const currentChecked = isControlled ? checked : internalChecked
const indeterminate = currentChecked === "indeterminate"
const handleCheckedChange = (next: boolean) => {
// When the box was indeterminate, a click resolves it to checked (Radix semantics).
const resolved: CheckboxPrimitive.CheckedState = next
if (!isControlled) {
setInternalChecked(resolved)
}
onCheckedChange?.(resolved)
}
return (
<SubframeCheckbox
hideLabel={true}
{...props}
checked={indeterminate ? false : Boolean(currentChecked)}
indeterminate={indeterminate}
onCheckedChange={handleCheckedChange}
className={cn(className)}
/>
)
}
export { Checkbox }