Skip to content
Source
Sign inSign up
Open History to see the last commit

toggle-group.tsx

84 lines3.5 KB

1import type { Toggle as TogglePrimitive } from "@base-ui/react/toggle";
2import { ToggleGroup as ToggleGroupPrimitive } from "@base-ui/react/toggle-group";
3import type { VariantProps } from "class-variance-authority";
4import * as React from "react";
5​
6import { cn } from "~/lib/utils";
7import { Toggle as ToggleComponent, type toggleVariants } from "~/components/ui/toggle";
8​
9const ToggleGroupContext = React.createContext<VariantProps<typeof toggleVariants>>({
10 size: "default",
11 variant: "default",
12});
13​
14function ToggleGroup({
15 className,
16 variant = "segmented",
17 size: sizeProp,
18 orientation = "horizontal",
19 detached = false,
20 children,
21 ...props
22}: ToggleGroupPrimitive.Props & VariantProps<typeof toggleVariants> & { detached?: boolean }) {
23 const size =
24 sizeProp === undefined ? (variant === "segmented" ? "segmented" : "default") : sizeProp;
25 const value = { size, variant };
26 return (
27 <ToggleGroupPrimitive
28 className={cn(
29 "flex w-fit *:focus-visible:z-10 dark:*:[[data-slot=separator]:has(+[data-slot=toggle]:hover)]:before:bg-input/64 dark:*:[[data-slot=separator]:has(+[data-slot=toggle][data-pressed])]:before:bg-input dark:*:[[data-slot=toggle]:hover+[data-slot=separator]]:before:bg-input/64 dark:*:[[data-slot=toggle][data-pressed]+[data-slot=separator]]:before:bg-input",
30 orientation === "horizontal"
31 ? "*:pointer-coarse:after:min-w-auto"
32 : "*:pointer-coarse:after:min-h-auto",
33 size === "segmented-wide"
34 ? "surface-well h-7 items-center gap-0.5 rounded-[10px] p-px"
35 : variant === "segmented"
36 ? "surface-well gap-0.5 rounded-[9px] p-px"
37 : detached
38 ? cn("gap-1", orientation === "vertical" && "flex-col")
39 : variant === "default"
40 ? "gap-0.5"
41 : orientation === "horizontal"
42 ? "*:not-first:not-data-[slot=separator]:before:-start-[0.5px] *:not-last:not-data-[slot=separator]:before:-end-[0.5px] *:not-first:rounded-s-none *:not-last:rounded-e-none *:not-first:border-s-0 *:not-last:border-e-0 *:not-first:before:rounded-s-none *:not-last:before:rounded-e-none"
43 : "*:not-first:not-data-[slot=separator]:before:-top-[0.5px] *:not-last:not-data-[slot=separator]:before:-bottom-[0.5px] flex-col *:not-first:rounded-t-none *:not-last:rounded-b-none *:not-first:border-t-0 *:not-last:border-b-0 *:not-first:before:rounded-t-none *:not-last:before:rounded-b-none *:data-[slot=toggle]:not-last:before:hidden dark:*:last:before:hidden dark:*:first:before:block",
44 detached && variant === "outline" && "*:data-pressed:text-strong-foreground",
45 className,
46 )}
47 data-size={size}
48 data-slot="toggle-group"
49 data-variant={variant}
50 orientation={orientation}
51 {...props}
52 >
53 <ToggleGroupContext value={value}>{children}</ToggleGroupContext>
54 </ToggleGroupPrimitive>
55 );
57​
58function Toggle({
59 className,
60 children,
61 variant,
62 size,
63 ...props
64}: TogglePrimitive.Props & VariantProps<typeof toggleVariants>) {
65 const context = React.use(ToggleGroupContext);
66​
67 const resolvedVariant = variant ?? context.variant;
68 const resolvedSize = size ?? context.size;
69​
70 return (
71 <ToggleComponent
72 className={className}
73 data-size={resolvedSize}
74 data-variant={resolvedVariant}
75 size={resolvedSize}
76 variant={resolvedVariant}
77 {...props}
78 >
79 {children}
80 </ToggleComponent>
81 );
83​
84export { ToggleGroup, Toggle, Toggle as ToggleGroupItem };