82 lines
3.6 KiB
TypeScript
82 lines
3.6 KiB
TypeScript
import type { ComponentProps } from "react";
|
|
|
|
export function Button({
|
|
variant = "secondary",
|
|
className = "",
|
|
type = "button",
|
|
...props
|
|
}: ComponentProps<"button"> & { variant?: "primary" | "secondary" }) {
|
|
return (
|
|
<button
|
|
{...props}
|
|
type={type}
|
|
className={`rounded-control border border-solid px-4 py-2.5 text-[14px] font-semibold transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent enabled:cursor-pointer enabled:active:translate-y-px disabled:cursor-not-allowed disabled:opacity-45 compact:text-[13px] ${
|
|
variant === "primary"
|
|
? "border-foreground bg-foreground text-surface enabled:hover:bg-white white:border-transparent white:bg-linear-to-br white:from-accent white:to-brand-secondary white:text-white white:disabled:opacity-60"
|
|
: "border-line-strong bg-surface-overlay text-foreground enabled:hover:border-foreground white:border-slate-900/10 white:enabled:hover:bg-slate-200"
|
|
} ${className}`}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function IconButton({
|
|
className = "",
|
|
type = "button",
|
|
round = false,
|
|
...props
|
|
}: ComponentProps<"button"> & { round?: boolean }) {
|
|
return (
|
|
<button
|
|
{...props}
|
|
type={type}
|
|
className={`relative inline-flex size-10 shrink-0 touch-manipulation items-center justify-center border border-solid border-line bg-surface-raised p-0 text-muted transition-colors focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-accent enabled:cursor-pointer enabled:hover:border-line-strong enabled:hover:bg-surface-overlay enabled:hover:text-foreground disabled:cursor-not-allowed disabled:opacity-45 ${round ? "rounded-full" : "rounded-control"} ${className}`}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function Field({ className = "", ...props }: ComponentProps<"label">) {
|
|
return (
|
|
<label
|
|
{...props}
|
|
className={`flex min-w-0 flex-col gap-1.5 text-[14px] font-medium text-muted compact:text-[13px] [&>span]:text-[13px] [&>span]:font-semibold [&>span]:tracking-[0.04em] [&>span]:text-foreground [&>span]:uppercase compact:[&>span]:text-[12px] ${className}`}
|
|
/>
|
|
);
|
|
}
|
|
|
|
const inputStyles =
|
|
"min-w-0 rounded-control border border-solid border-line bg-surface px-3 py-2.5 font-sans text-[14px] text-foreground outline-none transition-colors focus:border-muted disabled:opacity-60 white:border-slate-900/10 white:bg-surface-raised white:focus:border-brand-secondary white:focus:shadow-[0_0_0_3px_rgb(59_130_246/0.15)]";
|
|
|
|
export function Input({ className = "", ...props }: ComponentProps<"input">) {
|
|
return (
|
|
<input
|
|
{...props}
|
|
className={`${inputStyles} [&[readonly]]:cursor-default [&[readonly]]:border-dashed [&[readonly]]:text-muted ${className}`}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function Select({ className = "", ...props }: ComponentProps<"select">) {
|
|
return <select {...props} className={`${inputStyles} ${className}`} />;
|
|
}
|
|
|
|
export function Textarea({ className = "", ...props }: ComponentProps<"textarea">) {
|
|
return (
|
|
<textarea
|
|
{...props}
|
|
className={`${inputStyles} min-h-[84px] resize-y text-[15px] compact:text-[14px] ${className}`}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function FieldHint({ className = "", ...props }: ComponentProps<"small">) {
|
|
return <small {...props} className={`text-[13px] leading-[1.4] text-faint compact:text-[12px] ${className}`} />;
|
|
}
|
|
|
|
export function DialogFooter({ className = "", ...props }: ComponentProps<"footer">) {
|
|
return <footer {...props} className={`flex justify-between gap-3 pt-1.5 ${className}`} />;
|
|
}
|
|
|
|
export function DialogIntro(props: ComponentProps<"p">) {
|
|
return <p {...props} className="m-0 text-[14px] leading-[1.5] text-muted compact:text-[13px]" />;
|
|
}
|