/** * Right-rail field-properties editor for the form-builder. Renders the * full editable surface for the currently-selected field — label, key, * required, placeholder, help-text, length validation and per-option * editing for select/radio types. * * The component is a controlled view: every input change calls back * through `onChange` with a fresh field object so the parent * `` can persist + dispatch the canvas update. */ import type * as React from "react"; import { useTranslation } from "react-i18next"; import type { FormField } from "@toolctrl/form-widget"; export type FieldPropertiesProps = { field: FormField | null; onChange: (next: FormField) => void; }; function NumericInput({ fieldId, value, onChange, }: { fieldId: string; value: number | undefined; onChange: (next: number | undefined) => void; }): React.JSX.Element { return ( { const raw = e.target.value.trim(); if (raw === "") return onChange(undefined); const n = Number.parseInt(raw, 10); onChange(Number.isFinite(n) ? n : undefined); }} /> ); } function OptionsEditor({ options, onChange, }: { options: { value: string; label: string }[]; onChange: (next: { value: string; label: string }[]) => void; }): React.JSX.Element { const { t } = useTranslation(); return (
{t("settings.forms.builder.properties.options.value")} {t("settings.forms.builder.properties.options.label")}
{options.map((opt, idx) => (
{ const next = options.slice(); next[idx] = { ...opt, value: e.target.value }; onChange(next); }} aria-label={t("settings.forms.builder.properties.options.valueAria", { number: idx + 1 })} /> { const next = options.slice(); next[idx] = { ...opt, label: e.target.value }; onChange(next); }} aria-label={t("settings.forms.builder.properties.options.labelAria", { number: idx + 1 })} />
))}
); } export function FieldProperties({ field, onChange }: FieldPropertiesProps): React.JSX.Element { const { t } = useTranslation(); if (!field) { return ( ); } const supportsOptions = field.type === "select" || field.type === "radio"; const supportsPlaceholder = field.type === "text" || field.type === "email" || field.type === "number" || field.type === "textarea" || field.type === "select"; const supportsLength = field.type === "text" || field.type === "email" || field.type === "textarea"; return ( ); }