| 1 | import { ToggleGroup as Primitive } from "radix-ui"; |
| 2 | import { type ComponentProps, createContext, useContext } from "react"; |
| 3 | |
| 4 | import { cn } from "../../lib/cn"; |
| 5 | |
| 6 | // shadcn/ui's toggle group, styled with g1t's tokens: a row of choices of |
| 7 | // which one (type="single") or several (type="multiple") are pressed, drawn |
| 8 | // as one segmented control. The group's size and variant reach its items. |
| 9 | |
| 10 | type Variant = "default" | "outline"; |
| 11 | type Size = "sm" | "default"; |
| 12 | |
| 13 | const GroupContext = createContext<{ variant: Variant; size: Size }>({ variant: "default", size: "default" }); |
| 14 | |
| 15 | export function ToggleGroup({ |
| 16 | className, |
| 17 | variant = "default", |
| 18 | size = "default", |
| 19 | children, |
| 20 | ...props |
| 21 | }: ComponentProps<typeof Primitive.Root> & { variant?: Variant; size?: Size }) { |
| 22 | return ( |
| 23 | <Primitive.Root |
| 24 | data-variant={variant} |
| 25 | data-size={size} |
| 26 | className={cn("group/toggle-group inline-flex max-w-full flex-wrap items-center rounded-md", variant === "outline" && "border border-line bg-bg", className)} |
| 27 | {...props} |
| 28 | > |
| 29 | <GroupContext.Provider value={{ variant, size }}>{children}</GroupContext.Provider> |
| 30 | </Primitive.Root> |
| 31 | ); |
| 32 | } |
| 33 | |
| 34 | const SIZES: Record<Size, string> = { sm: "h-7 min-w-7 px-2 text-xs", default: "h-8 min-w-8 px-2.5 text-[0.8125rem]" }; |
| 35 | |
| 36 | export function ToggleGroupItem({ className, children, variant, size, ...props }: ComponentProps<typeof Primitive.Item> & { variant?: Variant; size?: Size }) { |
| 37 | const group = useContext(GroupContext); |
| 38 | const v = variant ?? group.variant; |
| 39 | return ( |
| 40 | <Primitive.Item |
| 41 | data-variant={v} |
| 42 | data-size={size ?? group.size} |
| 43 | className={cn( |
| 44 | "inline-flex shrink-0 items-center justify-center gap-1.5 font-medium whitespace-nowrap text-muted outline-none transition-colors select-none", |
| 45 | "hover:bg-raised hover:text-fg focus-visible:z-10 focus-visible:ring-2 focus-visible:ring-accent/40", |
| 46 | "disabled:pointer-events-none disabled:opacity-50", |
| 47 | "data-[state=on]:bg-accent/15 data-[state=on]:text-accent", |
| 48 | "[&_svg]:size-3.5 [&_svg]:shrink-0", |
| 49 | SIZES[size ?? group.size], |
| 50 | v === "outline" |
| 51 | ? "rounded-none border-l border-line first:rounded-l-[5px] first:border-l-0 last:rounded-r-[5px]" |
| 52 | : "rounded-md", |
| 53 | className, |
| 54 | )} |
| 55 | {...props} |
| 56 | > |
| 57 | {children} |
| 58 | </Primitive.Item> |
| 59 | ); |
| 60 | } |