feat(ui): enhance shadcn dialog, tabs, tooltip, and command components
- Add showCloseButton prop to DialogContent for modal workflows - Add line variant to TabsList via class-variance-authority - Add arrowClassName prop to TooltipContent for arrow styling - Add optional title prop to CommandDialog for accessibility
This commit is contained in:
parent
ae732496ed
commit
452aa392bd
4 changed files with 49 additions and 17 deletions
|
|
@ -6,7 +6,7 @@ import { Command as CommandPrimitive } from "cmdk";
|
|||
import { Search } from "lucide-react";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
import { Dialog, DialogContent } from "@/components/ui/dialog";
|
||||
import { Dialog, DialogContent, DialogTitle } from "@/components/ui/dialog";
|
||||
|
||||
const Command = React.forwardRef<
|
||||
React.ElementRef<typeof CommandPrimitive>,
|
||||
|
|
@ -23,10 +23,15 @@ const Command = React.forwardRef<
|
|||
));
|
||||
Command.displayName = CommandPrimitive.displayName;
|
||||
|
||||
const CommandDialog = ({ children, ...props }: DialogProps) => {
|
||||
const CommandDialog = ({
|
||||
children,
|
||||
title,
|
||||
...props
|
||||
}: DialogProps & { title?: React.ReactNode }) => {
|
||||
return (
|
||||
<Dialog {...props}>
|
||||
<DialogContent className="overflow-hidden p-0">
|
||||
{title && <DialogTitle className="sr-only">{title}</DialogTitle>}
|
||||
<Command className="[&_[cmdk-group-heading]]:px-2 [&_[cmdk-group-heading]]:font-medium [&_[cmdk-group-heading]]:text-muted-foreground [&_[cmdk-group]:not([hidden])_~[cmdk-group]]:pt-0 [&_[cmdk-group]]:px-2 [&_[cmdk-input-wrapper]_svg]:h-5 [&_[cmdk-input-wrapper]_svg]:w-5 [&_[cmdk-input]]:h-12 [&_[cmdk-item]]:px-2 [&_[cmdk-item]]:py-3 [&_[cmdk-item]_svg]:h-5 [&_[cmdk-item]_svg]:w-5">
|
||||
{children}
|
||||
</Command>
|
||||
|
|
|
|||
|
|
@ -31,8 +31,10 @@ DialogOverlay.displayName = DialogPrimitive.Overlay.displayName;
|
|||
|
||||
const DialogContent = React.forwardRef<
|
||||
React.ElementRef<typeof DialogPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content>
|
||||
>(({ className, children, ...props }, ref) => (
|
||||
React.ComponentPropsWithoutRef<typeof DialogPrimitive.Content> & {
|
||||
showCloseButton?: boolean;
|
||||
}
|
||||
>(({ className, children, showCloseButton = true, ...props }, ref) => (
|
||||
<DialogPortal>
|
||||
<DialogOverlay />
|
||||
<DialogPrimitive.Content
|
||||
|
|
@ -44,10 +46,12 @@ const DialogContent = React.forwardRef<
|
|||
{...props}
|
||||
>
|
||||
{children}
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
{showCloseButton && (
|
||||
<DialogPrimitive.Close className="absolute right-4 top-4 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
||||
<X className="h-4 w-4" />
|
||||
<span className="sr-only">Close</span>
|
||||
</DialogPrimitive.Close>
|
||||
)}
|
||||
</DialogPrimitive.Content>
|
||||
</DialogPortal>
|
||||
));
|
||||
|
|
|
|||
|
|
@ -2,21 +2,36 @@
|
|||
|
||||
import * as React from "react";
|
||||
import * as TabsPrimitive from "@radix-ui/react-tabs";
|
||||
import { cva, type VariantProps } from "class-variance-authority";
|
||||
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const Tabs = TabsPrimitive.Root;
|
||||
|
||||
const tabsListVariants = cva(
|
||||
"inline-flex items-center justify-center text-muted-foreground",
|
||||
{
|
||||
variants: {
|
||||
variant: {
|
||||
default: "h-9 rounded-lg bg-muted p-1",
|
||||
line: "h-9 w-full justify-start gap-1 border-b border-border bg-transparent p-0 group",
|
||||
},
|
||||
},
|
||||
defaultVariants: {
|
||||
variant: "default",
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const TabsList = React.forwardRef<
|
||||
React.ElementRef<typeof TabsPrimitive.List>,
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>
|
||||
>(({ className, ...props }, ref) => (
|
||||
React.ComponentPropsWithoutRef<typeof TabsPrimitive.List> &
|
||||
VariantProps<typeof tabsListVariants>
|
||||
>(({ className, variant, ...props }, ref) => (
|
||||
<TabsPrimitive.List
|
||||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex h-9 items-center justify-center rounded-lg bg-muted p-1 text-muted-foreground",
|
||||
className,
|
||||
)}
|
||||
data-variant={variant ?? "default"}
|
||||
className={cn(tabsListVariants({ variant, className }))}
|
||||
{...props}
|
||||
/>
|
||||
));
|
||||
|
|
@ -30,6 +45,9 @@ const TabsTrigger = React.forwardRef<
|
|||
ref={ref}
|
||||
className={cn(
|
||||
"inline-flex items-center justify-center whitespace-nowrap rounded-md px-3 py-1 text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow",
|
||||
// "line" variant: underline-style triggers (applies only when the parent
|
||||
// TabsList has data-variant="line" + the `group` class from the cva above).
|
||||
"group-data-[variant=line]:rounded-none group-data-[variant=line]:border-b-2 group-data-[variant=line]:border-transparent group-data-[variant=line]:bg-transparent group-data-[variant=line]:px-4 group-data-[variant=line]:py-2 group-data-[variant=line]:shadow-none group-data-[variant=line]:data-[state=active]:border-primary group-data-[variant=line]:data-[state=active]:bg-transparent group-data-[variant=line]:data-[state=active]:text-foreground group-data-[variant=line]:data-[state=active]:shadow-none",
|
||||
className,
|
||||
)}
|
||||
{...props}
|
||||
|
|
|
|||
|
|
@ -13,8 +13,10 @@ const TooltipTrigger = TooltipPrimitive.Trigger;
|
|||
|
||||
const TooltipContent = React.forwardRef<
|
||||
React.ElementRef<typeof TooltipPrimitive.Content>,
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content>
|
||||
>(({ className, sideOffset = 4, ...props }, ref) => (
|
||||
React.ComponentPropsWithoutRef<typeof TooltipPrimitive.Content> & {
|
||||
arrowClassName?: string;
|
||||
}
|
||||
>(({ className, sideOffset = 4, arrowClassName, children, ...props }, ref) => (
|
||||
<TooltipPrimitive.Portal>
|
||||
<TooltipPrimitive.Content
|
||||
ref={ref}
|
||||
|
|
@ -24,7 +26,10 @@ const TooltipContent = React.forwardRef<
|
|||
className,
|
||||
)}
|
||||
{...props}
|
||||
/>
|
||||
>
|
||||
{arrowClassName && <TooltipPrimitive.Arrow className={arrowClassName} />}
|
||||
{children}
|
||||
</TooltipPrimitive.Content>
|
||||
</TooltipPrimitive.Portal>
|
||||
));
|
||||
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
||||
|
|
|
|||
Loading…
Reference in a new issue