232 lines
6.9 KiB
TypeScript
232 lines
6.9 KiB
TypeScript
import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu";
|
||
import {
|
||
forwardRef,
|
||
type ComponentPropsWithoutRef,
|
||
type ElementRef,
|
||
type HTMLAttributes
|
||
} from "react";
|
||
|
||
import {
|
||
dropdownMenuContentVariants,
|
||
dropdownMenuItemVariants,
|
||
dropdownMenuLabelVariants,
|
||
dropdownMenuSeparatorVariants
|
||
} from "./dropdown-menu.variants";
|
||
import { cn } from "../lib/cn";
|
||
import type { VariantProps } from "../lib/cva";
|
||
import { createDataAttributes, createSlot } from "../lib/contracts";
|
||
|
||
export const DropdownMenu = DropdownMenuPrimitive.Root;
|
||
export const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger;
|
||
export const DropdownMenuGroup = DropdownMenuPrimitive.Group;
|
||
export const DropdownMenuPortal = DropdownMenuPrimitive.Portal;
|
||
export const DropdownMenuSub = DropdownMenuPrimitive.Sub;
|
||
export const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup;
|
||
|
||
export type DropdownMenuContentProps =
|
||
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Content> &
|
||
VariantProps<typeof dropdownMenuContentVariants>;
|
||
|
||
export const DropdownMenuContent = forwardRef<
|
||
ElementRef<typeof DropdownMenuPrimitive.Content>,
|
||
DropdownMenuContentProps
|
||
>(function DropdownMenuContent(
|
||
{ className, sideOffset = 8, size, ...props },
|
||
ref
|
||
) {
|
||
return (
|
||
<DropdownMenuPortal>
|
||
<DropdownMenuPrimitive.Content
|
||
{...props}
|
||
{...createSlot("content")}
|
||
{...createDataAttributes({ size })}
|
||
className={cn(dropdownMenuContentVariants({ size }), className)}
|
||
ref={ref}
|
||
sideOffset={sideOffset}
|
||
/>
|
||
</DropdownMenuPortal>
|
||
);
|
||
});
|
||
|
||
export type DropdownMenuSubContentProps =
|
||
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubContent> &
|
||
VariantProps<typeof dropdownMenuContentVariants>;
|
||
|
||
export const DropdownMenuSubContent = forwardRef<
|
||
ElementRef<typeof DropdownMenuPrimitive.SubContent>,
|
||
DropdownMenuSubContentProps
|
||
>(function DropdownMenuSubContent(
|
||
{ className, sideOffset = 10, size, ...props },
|
||
ref
|
||
) {
|
||
return (
|
||
<DropdownMenuPortal>
|
||
<DropdownMenuPrimitive.SubContent
|
||
{...props}
|
||
{...createSlot("content")}
|
||
{...createDataAttributes({ size })}
|
||
className={cn(dropdownMenuContentVariants({ size }), className)}
|
||
ref={ref}
|
||
sideOffset={sideOffset}
|
||
/>
|
||
</DropdownMenuPortal>
|
||
);
|
||
});
|
||
|
||
export type DropdownMenuItemProps =
|
||
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Item> &
|
||
VariantProps<typeof dropdownMenuItemVariants>;
|
||
|
||
export const DropdownMenuItem = forwardRef<
|
||
ElementRef<typeof DropdownMenuPrimitive.Item>,
|
||
DropdownMenuItemProps
|
||
>(function DropdownMenuItem(
|
||
{ className, inset, variant, ...props },
|
||
ref
|
||
) {
|
||
return (
|
||
<DropdownMenuPrimitive.Item
|
||
{...props}
|
||
{...createSlot("item")}
|
||
{...createDataAttributes({ inset, variant })}
|
||
className={cn(dropdownMenuItemVariants({ inset, variant }), className)}
|
||
ref={ref}
|
||
/>
|
||
);
|
||
});
|
||
|
||
export type DropdownMenuCheckboxItemProps =
|
||
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.CheckboxItem> &
|
||
VariantProps<typeof dropdownMenuItemVariants>;
|
||
|
||
export const DropdownMenuCheckboxItem = forwardRef<
|
||
ElementRef<typeof DropdownMenuPrimitive.CheckboxItem>,
|
||
DropdownMenuCheckboxItemProps
|
||
>(function DropdownMenuCheckboxItem(
|
||
{ checked, children, className, inset = true, variant, ...props },
|
||
ref
|
||
) {
|
||
return (
|
||
<DropdownMenuPrimitive.CheckboxItem
|
||
{...props}
|
||
checked={checked}
|
||
{...createSlot("item")}
|
||
{...createDataAttributes({ checked: checked === true, inset, variant })}
|
||
className={cn(dropdownMenuItemVariants({ inset, variant }), className)}
|
||
ref={ref}
|
||
>
|
||
<span
|
||
{...createSlot("icon")}
|
||
className="absolute left-2.5 inline-flex size-4 items-center justify-center text-xs"
|
||
>
|
||
<DropdownMenuPrimitive.ItemIndicator>✓</DropdownMenuPrimitive.ItemIndicator>
|
||
</span>
|
||
{children}
|
||
</DropdownMenuPrimitive.CheckboxItem>
|
||
);
|
||
});
|
||
|
||
export type DropdownMenuRadioItemProps =
|
||
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.RadioItem> &
|
||
VariantProps<typeof dropdownMenuItemVariants>;
|
||
|
||
export const DropdownMenuRadioItem = forwardRef<
|
||
ElementRef<typeof DropdownMenuPrimitive.RadioItem>,
|
||
DropdownMenuRadioItemProps
|
||
>(function DropdownMenuRadioItem(
|
||
{ children, className, inset = true, variant, ...props },
|
||
ref
|
||
) {
|
||
return (
|
||
<DropdownMenuPrimitive.RadioItem
|
||
{...props}
|
||
{...createSlot("item")}
|
||
{...createDataAttributes({ inset, variant })}
|
||
className={cn(dropdownMenuItemVariants({ inset, variant }), className)}
|
||
ref={ref}
|
||
>
|
||
<span
|
||
{...createSlot("icon")}
|
||
className="absolute left-2.5 inline-flex size-4 items-center justify-center text-xs"
|
||
>
|
||
<DropdownMenuPrimitive.ItemIndicator>•</DropdownMenuPrimitive.ItemIndicator>
|
||
</span>
|
||
{children}
|
||
</DropdownMenuPrimitive.RadioItem>
|
||
);
|
||
});
|
||
|
||
export type DropdownMenuLabelProps =
|
||
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Label> &
|
||
VariantProps<typeof dropdownMenuLabelVariants>;
|
||
|
||
export const DropdownMenuLabel = forwardRef<
|
||
ElementRef<typeof DropdownMenuPrimitive.Label>,
|
||
DropdownMenuLabelProps
|
||
>(function DropdownMenuLabel({ className, inset, ...props }, ref) {
|
||
return (
|
||
<DropdownMenuPrimitive.Label
|
||
{...props}
|
||
{...createSlot("label")}
|
||
{...createDataAttributes({ inset })}
|
||
className={cn(dropdownMenuLabelVariants({ inset }), className)}
|
||
ref={ref}
|
||
/>
|
||
);
|
||
});
|
||
|
||
export const DropdownMenuSeparator = forwardRef<
|
||
ElementRef<typeof DropdownMenuPrimitive.Separator>,
|
||
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.Separator>
|
||
>(function DropdownMenuSeparator({ className, ...props }, ref) {
|
||
return (
|
||
<DropdownMenuPrimitive.Separator
|
||
{...props}
|
||
{...createSlot("separator")}
|
||
className={cn(dropdownMenuSeparatorVariants(), className)}
|
||
ref={ref}
|
||
/>
|
||
);
|
||
});
|
||
|
||
export type DropdownMenuSubTriggerProps =
|
||
ComponentPropsWithoutRef<typeof DropdownMenuPrimitive.SubTrigger> &
|
||
VariantProps<typeof dropdownMenuItemVariants>;
|
||
|
||
export const DropdownMenuSubTrigger = forwardRef<
|
||
ElementRef<typeof DropdownMenuPrimitive.SubTrigger>,
|
||
DropdownMenuSubTriggerProps
|
||
>(function DropdownMenuSubTrigger(
|
||
{ children, className, inset, variant, ...props },
|
||
ref
|
||
) {
|
||
return (
|
||
<DropdownMenuPrimitive.SubTrigger
|
||
{...props}
|
||
{...createSlot("trigger")}
|
||
{...createDataAttributes({ inset, variant })}
|
||
className={cn(dropdownMenuItemVariants({ inset, variant }), className)}
|
||
ref={ref}
|
||
>
|
||
{children}
|
||
<span className="ml-auto text-xs text-[var(--color-muted-foreground)]">›</span>
|
||
</DropdownMenuPrimitive.SubTrigger>
|
||
);
|
||
});
|
||
|
||
export function DropdownMenuShortcut({
|
||
className,
|
||
...props
|
||
}: HTMLAttributes<HTMLSpanElement>) {
|
||
return (
|
||
<span
|
||
{...props}
|
||
{...createSlot("shortcut")}
|
||
className={cn(
|
||
"ml-auto text-xs uppercase tracking-[var(--tracking-caps)] text-[var(--color-muted-foreground)]",
|
||
className
|
||
)}
|
||
/>
|
||
);
|
||
}
|