Files
ersatztv/design-system/components/forms/Input.jsx
T
2026-07-02 07:37:00 +02:00

91 lines
2.5 KiB
React

import React from "react";
/**
* Text input with optional label, leading icon and error state.
*/
export function Input({
label,
value,
onChange,
placeholder,
leadingIcon = null,
trailing = null,
error = null,
disabled = false,
size = "md",
type = "text",
fullWidth = true,
style = {},
...rest
}) {
const [focus, setFocus] = React.useState(false);
const height = size === "sm" ? "var(--control-h-sm)" : "var(--control-h)";
const borderColor = error
? "var(--status-error)"
: focus
? "var(--action-primary)"
: "var(--border-control)";
return (
<label style={{ display: "block", width: fullWidth ? "100%" : "auto" }}>
{label && (
<span
style={{
display: "block",
marginBottom: "6px",
font: "var(--weight-medium) var(--text-xs)/1 var(--font-sans)",
color: "var(--text-secondary)",
}}
>
{label}
</span>
)}
<span
style={{
display: "flex",
alignItems: "center",
gap: "8px",
height,
padding: "0 10px",
background: "var(--ctv-bg-sunken)",
border: `1px solid ${borderColor}`,
borderRadius: "var(--radius-sm)",
boxShadow: focus && !error ? "0 0 0 3px var(--focus-ring)" : "none",
transition: "border-color var(--dur-fast) var(--ease-standard), box-shadow var(--dur-fast) var(--ease-standard)",
opacity: disabled ? 0.5 : 1,
...style,
}}
>
{leadingIcon && (
<span style={{ display: "flex", color: "var(--text-disabled)", flex: "0 0 auto" }}>{leadingIcon}</span>
)}
<input
type={type}
value={value}
onChange={onChange}
placeholder={placeholder}
disabled={disabled}
onFocus={() => setFocus(true)}
onBlur={() => setFocus(false)}
style={{
flex: 1,
minWidth: 0,
background: "transparent",
border: "none",
outline: "none",
color: "var(--text-primary)",
font: "var(--weight-normal) var(--text-sm)/1 var(--font-sans)",
}}
{...rest}
/>
{trailing && <span style={{ display: "flex", flex: "0 0 auto" }}>{trailing}</span>}
</span>
{error && (
<span style={{ display: "block", marginTop: "5px", font: "var(--text-xs)/1.3 var(--font-sans)", color: "var(--status-error)" }}>
{error}
</span>
)}
</label>
);
}