Files
ai-workflow/dashboard/src/components/ui/InlineComposer.tsx
T

72 lines
1.8 KiB
TypeScript

import type { FormEvent, ReactNode, Ref } from "react";
import Button from "./Button";
import InsetPanel from "./InsetPanel";
import TextInput from "./TextInput";
import { cx } from "./cx";
interface InlineComposerProps {
label: ReactNode;
value: string;
onChange: (value: string) => void;
onSubmit: () => void;
placeholder?: string;
hint?: ReactNode;
error?: ReactNode;
submitLabel: ReactNode;
disabled?: boolean;
inputId: string;
inputRef?: Ref<HTMLInputElement>;
className?: string;
action?: ReactNode;
}
export default function InlineComposer({
label,
value,
onChange,
onSubmit,
placeholder,
hint,
error,
submitLabel,
disabled = false,
inputId,
inputRef,
className,
action,
}: InlineComposerProps) {
return (
<InsetPanel className={cx("space-y-2.5", className)} padding="sm" as="form" onSubmit={(event: FormEvent) => {
event.preventDefault();
onSubmit();
}}
>
<label htmlFor={inputId} className="app-text-soft app-overline mb-1 block">
{label}
</label>
<div className="flex flex-col gap-2 sm:flex-row">
<TextInput
ref={inputRef}
id={inputId}
value={value}
onChange={(event) => onChange(event.target.value)}
placeholder={placeholder}
disabled={disabled}
className="flex-1"
/>
{action ?? (
<Button type="submit" disabled={disabled || !value.trim()} size="xs" variant="solid" tone="brand">
{submitLabel}
</Button>
)}
</div>
{hint ? <div className="app-text-faint app-caption mt-1">{hint}</div> : null}
{error ? (
<div role="alert" className="app-text-danger app-caption mt-2">
{error}
</div>
) : null}
</InsetPanel>
);
}