chore: import upstream snapshot with attribution
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
import { useEffect, useRef, useState } from "react";
|
||||
import { cn } from "~/utils/cn";
|
||||
import { CopyButton } from "./CopyButton";
|
||||
|
||||
const variants = {
|
||||
"primary/small": {
|
||||
container:
|
||||
"flex items-center text-text-dimmed font-mono rounded border bg-background-hover text-xs transition hover:bg-background-raised focus-visible:outline-hidden focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-hidden focus:ring-0 focus:ring-transparent",
|
||||
input:
|
||||
"bg-transparent border-0 text-xs px-2 w-auto rounded-l h-6 leading-6 focus:ring-transparent",
|
||||
buttonVariant: "primary" as const,
|
||||
size: "small" as const,
|
||||
button: "rounded-l-none",
|
||||
},
|
||||
"secondary/small": {
|
||||
container:
|
||||
"flex items-center text-text-dimmed font-mono rounded border bg-background-hover text-xs transition hover:bg-background-raised focus-visible:outline-hidden focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-hidden focus:ring-0 focus:ring-transparent",
|
||||
input:
|
||||
"bg-transparent border-0 text-xs px-2 w-auto rounded-l h-6 leading-6 focus:ring-transparent",
|
||||
buttonVariant: "tertiary" as const,
|
||||
size: "small" as const,
|
||||
button: "rounded-l-none border-l border-grid-dimmed",
|
||||
},
|
||||
"tertiary/small": {
|
||||
container:
|
||||
"group/clipboard flex items-center text-text-dimmed font-mono rounded bg-transparent border border-transparent text-xs transition duration-150 hover:border-grid-bright focus-visible:outline-hidden focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-hidden focus:ring-0 focus:ring-transparent",
|
||||
input:
|
||||
"bg-transparent border-0 text-xs px-2 w-auto rounded-l h-6 leading-6 focus:ring-transparent",
|
||||
buttonVariant: "minimal" as const,
|
||||
size: "small" as const,
|
||||
button:
|
||||
"rounded-l-none border-l border-transparent transition group-hover/clipboard:border-grid-bright",
|
||||
},
|
||||
"primary/medium": {
|
||||
container:
|
||||
"flex items-center text-text-dimmed font-mono rounded border bg-background-hover text-sm transition hover:bg-background-raised focus-visible:outline-hidden focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-hidden focus:ring-0 focus:ring-transparent",
|
||||
input:
|
||||
"bg-transparent border-0 text-sm px-3 w-auto rounded-l h-8 leading-6 focus:ring-transparent",
|
||||
buttonVariant: "primary" as const,
|
||||
size: "medium" as const,
|
||||
button: "rounded-l-none",
|
||||
},
|
||||
"secondary/medium": {
|
||||
container:
|
||||
"flex items-center text-text-dimmed font-mono rounded bg-background-hover text-sm transition hover:bg-background-raised focus-visible:outline-hidden focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-hidden focus:ring-0 focus:ring-transparent",
|
||||
input:
|
||||
"bg-transparent border-0 text-sm px-3 w-auto rounded-l h-8 leading-6 focus:ring-transparent",
|
||||
buttonVariant: "tertiary" as const,
|
||||
size: "medium" as const,
|
||||
button: "rounded-l-none border-l border-grid-dimmed",
|
||||
},
|
||||
"tertiary/medium": {
|
||||
container:
|
||||
"group flex items-center text-text-dimmed font-mono rounded bg-transparent border border-transparent text-sm transition hover:border-grid-bright focus-visible:outline-hidden focus-visible:ring-0 focus-visible:ring-offset-0 focus:border-transparent focus:outline-hidden focus:ring-0 focus:ring-transparent",
|
||||
input:
|
||||
"bg-transparent border-0 text-sm px-3 w-auto rounded-l h-8 leading-6 focus:ring-transparent",
|
||||
buttonVariant: "minimal" as const,
|
||||
size: "medium" as const,
|
||||
button: "rounded-l-none border-l border-transparent transition group-hover:border-grid-bright",
|
||||
},
|
||||
};
|
||||
|
||||
type ClipboardFieldProps = {
|
||||
value: string;
|
||||
secure?: boolean | string;
|
||||
variant: keyof typeof variants;
|
||||
className?: string;
|
||||
icon?: React.ReactNode;
|
||||
iconButton?: boolean;
|
||||
fullWidth?: boolean;
|
||||
};
|
||||
|
||||
export function ClipboardField({
|
||||
value,
|
||||
secure = false,
|
||||
variant,
|
||||
className,
|
||||
icon,
|
||||
iconButton = false,
|
||||
fullWidth = true,
|
||||
}: ClipboardFieldProps) {
|
||||
const [isSecure, setIsSecure] = useState(secure !== undefined && secure);
|
||||
const inputIcon = useRef<HTMLInputElement>(null);
|
||||
const { container, input, buttonVariant, button, size } = variants[variant];
|
||||
|
||||
useEffect(() => {
|
||||
setIsSecure(secure !== undefined && secure);
|
||||
}, [secure]);
|
||||
|
||||
return (
|
||||
<span className={cn(container, fullWidth ? "w-full" : "max-w-fit", className)}>
|
||||
{icon && (
|
||||
<span
|
||||
onClick={() => inputIcon.current && inputIcon.current.focus()}
|
||||
className="flex items-center pl-1"
|
||||
>
|
||||
{icon}
|
||||
</span>
|
||||
)}
|
||||
<input
|
||||
type="text"
|
||||
ref={inputIcon}
|
||||
value={isSecure ? (typeof secure === "string" ? secure : "••••••••••••••••") : value}
|
||||
readOnly={true}
|
||||
className={cn(
|
||||
"shrink grow select-all overflow-x-auto",
|
||||
fullWidth ? "w-full" : "max-w-fit",
|
||||
input
|
||||
)}
|
||||
onFocus={(e) => {
|
||||
if (secure) {
|
||||
setIsSecure(false);
|
||||
}
|
||||
e.currentTarget.select();
|
||||
}}
|
||||
onBlur={() => {
|
||||
if (secure) {
|
||||
setIsSecure(true);
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<CopyButton
|
||||
value={value}
|
||||
variant={iconButton ? "icon" : "button"}
|
||||
buttonVariant={buttonVariant}
|
||||
size={size}
|
||||
buttonClassName={button}
|
||||
showTooltip={false}
|
||||
/>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user