import { useId } from "react"; import { t } from "@lingui/core/macro"; import { Controller, type FieldValues, type Path, type RegisterOptions, useFormContext, } from "react-hook-form"; import { TextEditor, type TextEditorHandle } from "../TextEditor.tsx"; interface RichTextFieldProps { name: Path; label?: string; placeholder?: string; rows?: number; /** Counted in the editor and enforced on submit, with a message saying so. */ maxLength?: number; autoResize?: boolean; disabled?: boolean; rules?: RegisterOptions>; /** Forwarded to the underlying TextEditor so callers can focus it. */ editorRef?: React.Ref; /** Ctrl/Cmd+Enter handler (e.g. submit the comment). */ onSubmit?: () => void; } /** * Rich-text field: a `Controller`-wrapped {@link TextEditor} (mentions, emoji, * image upload, char count) bound to react-hook-form via the surrounding * `FormProvider`. */ export function RichTextField({ name, label, placeholder, rows, maxLength, autoResize, disabled, rules, editorRef, onSubmit, }: RichTextFieldProps) { const id = useId(); const hintId = useId(); const { control, formState: { errors } } = useFormContext(); const error = errors[name]; // A bare numeric rule fails without a message, which left a submit that did // nothing and said nothing. const allRules = maxLength == null ? rules : { ...rules, maxLength: { value: maxLength, message: t`At most ${maxLength} characters.`, }, }; return (
{label && ( )} ( )} /> {error?.message && ( {String(error.message)} )}
); }