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

50 lines
1.7 KiB
TypeScript

"use client"
import * as React from "react"
import * as SwitchPrimitive from "@radix-ui/react-switch"
import { Switch as SubframeSwitch } from "~/ui/components/Switch"
import { cn } from "~/lib/utils"
// Subframe migration (strangler shim):
// Keeps the original shadcn/Radix `Switch` API (`React.ComponentProps<typeof
// SwitchPrimitive.Root>`) but renders the Subframe design-system Switch behind it.
//
// Pitfall handled here: Subframe's Switch is ALWAYS controlled (it defaults `checked`
// to false and has no uncontrolled/`defaultChecked` path). Since this primitive is often
// used uncontrolled (`defaultChecked`, no `checked`), the shim owns the checked state with
// its own `useState` and only defers to the caller when `checked` is supplied — preserving
// both the controlled and uncontrolled public behavior.
function Switch({
className,
checked,
defaultChecked,
onCheckedChange,
...props
}: React.ComponentPropsWithoutRef<typeof SwitchPrimitive.Root>) {
// ref intentionally excluded: Radix Switch.Root's ref targets a <button> while Subframe's
// Switch ref targets a <div>; forwarding would be a type/element mismatch.
const isControlled = checked !== undefined
const [internalChecked, setInternalChecked] = React.useState(defaultChecked ?? false)
const currentChecked = isControlled ? checked : internalChecked
const handleCheckedChange = (next: boolean) => {
if (!isControlled) {
setInternalChecked(next)
}
onCheckedChange?.(next)
}
return (
<SubframeSwitch
{...props}
checked={currentChecked}
onCheckedChange={handleCheckedChange}
className={cn(className)}
/>
)
}
export { Switch }