58 lines
1.9 KiB
TypeScript
58 lines
1.9 KiB
TypeScript
import { cva, VariantProps } from "class-variance-authority";
|
|
import * as React from "react";
|
|
|
|
import { cn } from "~/lib/utils";
|
|
|
|
function Input({
|
|
className,
|
|
type,
|
|
variant,
|
|
dirty,
|
|
...props
|
|
}: React.ComponentProps<"input"> &
|
|
VariantProps<typeof inputVariants> & {
|
|
asChild?: boolean;
|
|
isLoading?: boolean;
|
|
dirty?: boolean;
|
|
}) {
|
|
return (
|
|
<input
|
|
type={type}
|
|
data-slot="input"
|
|
className={cn(
|
|
inputVariants({ variant }), //
|
|
className,
|
|
dirty && "bg-yellow-50 dark:bg-yellow-100 dark:text-yellow-900",
|
|
// Readonly inputs keep full text opacity so their value/placeholder still
|
|
// meets WCAG AA contrast (opacity-50 dropped dark text to ~3.7:1). A muted
|
|
// background still signals the non-editable state.
|
|
props.readOnly && "pointer-events-none cursor-not-allowed bg-surface-neutral-secondary"
|
|
)}
|
|
{...props}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export { Input };
|
|
|
|
export const inputVariants = cva(
|
|
cn(
|
|
"file:text-text-neutral-primary placeholder:text-text-neutral-subtle selection:bg-brand-brand-surface-solid-default selection:text-text-neutral-on-solid dark:bg-input/30 border-border-strong flex h-9 w-full min-w-0 rounded-md border bg-transparent px-3 py-1 text-base shadow-xs transition-[color,box-shadow] outline-none file:inline-flex file:h-7 file:border-0 file:bg-transparent file:text-sm file:font-medium disabled:pointer-events-none disabled:cursor-not-allowed disabled:opacity-50 md:text-sm",
|
|
"focus-visible:border-brand-brand-border-solid-default focus-visible:shadow-focus",
|
|
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
|
|
|
|
// "focus-visible:ring-0"),
|
|
),
|
|
{
|
|
variants: {
|
|
variant: {
|
|
default: "",
|
|
dirty: cn("bg-yellow-50/50"),
|
|
},
|
|
},
|
|
defaultVariants: {
|
|
variant: "default",
|
|
},
|
|
}
|
|
);
|