Watch
0
0
Fork
You've already forked hyperhive
0
hyperhive/frontend/packages/swarm-ui/src/ui/text-field/TextField.tsx
iris d76d54c412 frontend: preact 11.2.0
All four packages move from preact 10.29.8 to 11.2.0. The new types need four
small changes in swarm-ui and the shared dropdown: a ref that may be empty is
typed RefObject<T | null>, HTMLAttributes is imported from preact instead of
read from the JSX namespace, and TextField's type is the five kinds it is
used with, asserted once for the input's new union. npm-deps-hash follows the
lockfile.
2026-11-07 08:41:32 +01:00

70 lines
2.1 KiB
TypeScript

// <TextField> — a labelled single-line text input, the shared control
// every form (`CreateAgentForm` today) reaches for instead
// of hand-rolling its own label/input pair. No textarea/multi-line
// mode — promote that the day a real caller needs one, same "don't
// build ahead of a caller" rule the rest of `ui/` follows.
import { FormField } from "../form-field/FormField.js";
/** One value the field offers to complete to. */
export interface TextFieldSuggestion {
value: string;
/** Shown beside the value in the browser's list. */
label?: string;
}
export function TextField({
id,
label,
value,
onInput,
type = "text",
pattern,
title,
required,
placeholder,
hideLabel,
suggestions,
}: {
id: string;
label: string;
value: string;
onInput: (value: string) => void;
type?: "text" | "password" | "number" | "url" | "datetime-local";
pattern?: string;
title?: string;
required?: boolean;
placeholder?: string;
/** The label is for assistive tech only; the placeholder says it on screen. */
hideLabel?: boolean;
/** Values to pick from. The field stays free text: a value that is not in
* the list can still be typed. */
suggestions?: TextFieldSuggestion[];
}) {
const listId = `${id}-suggestions`;
return (
<FormField label={label} htmlFor={id} hideLabel={hideLabel}>
<input
id={id}
class="ui-form-control"
// preact 11 types `type` as a union that ties each kind to its own
// `list` and `role` attributes; the field takes any of its kinds and
// passes `list` only for suggestions, so the union is asserted here.
type={type as "text"}
value={value}
pattern={pattern}
title={title}
required={required}
placeholder={placeholder}
list={suggestions ? listId : undefined}
onInput={(e) => onInput((e.target as HTMLInputElement).value)}
/>
{suggestions ? (
<datalist id={listId}>
{suggestions.map((s) => (
<option key={s.value} value={s.value} label={s.label} />
))}
</datalist>
) : null}
</FormField>
);
}