Components
npx shadcn@latest add https://21st.dev/r/originui/dialogLoading preview...
"use client";
import { cn } from "@/lib/utils";
import { Button } from "@/components/ui/button";
import {
Dialog,
DialogContent,
DialogDescription,
DialogHeader,
DialogTitle,
DialogTrigger,
} from "@/components/ui/dialog";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
import {
Tooltip,
TooltipContent,
TooltipProvider,
TooltipTrigger,
} from "@/components/ui/tooltip";
import { Check, Copy, UserRoundPlus } from "lucide-react";
import { useId, useRef, useState } from "react";
function Component() {
const id = useId();
const [emails, setEmails] = useState(["mark@yourcompany.com", "jane@yourcompany.com", ""]);
const [copied, setCopied] = useState<boolean>(false);
const inputRef = useRef<HTMLInputElement>(null);
const lastInputRef = useRef<HTMLInputElement>(null);
const addEmail = () => {
setEmails([...emails, ""]);
};
const handleEmailChange = (index: number, value: string) => {
const newEmails = [...emails];
newEmails[index] = value;
setEmails(newEmails);
};
const handleCopy = () => {
if (inputRef.current) {
navigator.clipboard.writeText(inputRef.current.value);
setCopied(true);
setTimeout(() => setCopied(false), 1500);
}
};
return (
<Dialog>
<DialogTrigger asChild>
<Button variant="outline">Invite members</Button>
</DialogTrigger>
<DialogContent
onOpenAutoFocus={(e) => {
e.preventDefault();
lastInputRef.current?.focus();
}}
>
<div className="flex flex-col gap-2">
<div
className="flex size-11 shrink-0 items-center justify-center rounded-full border border-border"
aria-hidden="true"
>
<UserRoundPlus className="opacity-80" size={16} strokeWidth={2} />
</div>
<DialogHeader>
<DialogTitle className="text-left">Invite team members</DialogTitle>
<DialogDescription className="text-left">
Invite teammates to earn free components.
</DialogDescription>
</DialogHeader>
</div>
<form className="space-y-5">
<div className="space-y-4">
<div className="space-y-2">
<Label>Invite via email</Label>
<div className="space-y-3">
{emails.map((email, index) => (
<Input
key={index}
id={`team-email-${index + 1}`}
placeholder="hi@yourcompany.com"
type="email"
value={email}
onChange={(e) => handleEmailChange(index, e.target.value)}
ref={index === emails.length - 1 ? lastInputRef : undefined}
/>
))}
</div>
</div>
<button
type="button"
onClick={addEmail}
className="text-sm underline hover:no-underline"
>
+ Add another
</button>
</div>
<Button type="button" className="w-full">
Send invites
</Button>
</form>
<hr className="my-1 border-t border-border" />
<div className="space-y-2">
<Label htmlFor={id}>Invite via magic link</Label>
<div className="relative">
<Input
ref={inputRef}
id={id}
className="pe-9"
type="text"
defaultValue="https://originui.com/refer/87689"
readOnly
/>
<TooltipProvider delayDuration={0}>
<Tooltip>
<TooltipTrigger asChild>
<button
onClick={handleCopy}
className="absolute inset-y-0 end-0 flex h-full w-9 items-center justify-center rounded-e-lg border border-transparent text-muted-foreground/80 outline-offset-2 transition-colors hover:text-foreground focus-visible:text-foreground focus-visible:outline focus-visible:outline-2 focus-visible:outline-ring/70 disabled:pointer-events-none disabled:cursor-not-allowed"
aria-label={copied ? "Copied" : "Copy to clipboard"}
disabled={copied}
>
<div
className={cn(
"transition-all",
copied ? "scale-100 opacity-100" : "scale-0 opacity-0",
)}
>
<Check
className="stroke-emerald-500"
size={16}
strokeWidth={2}
aria-hidden="true"
/>
</div>
<div
className={cn(
"absolute transition-all",
copied ? "scale-0 opacity-0" : "scale-100 opacity-100",
)}
>
<Copy size={16} strokeWidth={2} aria-hidden="true" />
</div>
</button>
</TooltipTrigger>
<TooltipContent className="px-2 py-1 text-xs">Copy to clipboard</TooltipContent>
</Tooltip>
</TooltipProvider>
</div>
</div>
</DialogContent>
</Dialog>
);
}
export { Component };
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...
Loading preview...

Loading preview...
Loading preview...
Loading preview...