Skip to content
60 linesCodeBlameRaw
1import { ToggleGroup as Primitive } from "radix-ui";
2import { type ComponentProps, createContext, useContext } from "react";
3
4import { 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
10type Variant = "default" | "outline";
11type Size = "sm" | "default";
12
13const GroupContext = createContext<{ variant: Variant; size: Size }>({ variant: "default", size: "default" });
14
15export 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
34const 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
36export 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}