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.
70 lines
2.1 KiB
TypeScript
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>
|
|
);
|
|
}
|