@alza/hateoas-react-hook-form
React Hook Form integrace pro @alza/hateoas formuláře.
Installation
yarn add @alza/hateoas-react-hook-form --exactPeer dependencies required in your application:
reactreact-hook-form@alza/hateoas
Základní použití
import { useHateoasForm } from "@alza/hateoas-react-hook-form";
import type { HateoasFormV2, HateoasFieldMap } from "@alza/hateoas";
const fieldMap = {
token: ["token", "string"],
password: ["password", "string"],
} as const satisfies HateoasFieldMap;
export function Example({ form }: { form: HateoasFormV2 }) {
const hf = useHateoasForm(form, fieldMap, t, callClientApi);
return (
<form
onSubmit={hf.handleSubmit(async (values) => {
await hf.submitForm({ formValues: values });
})}
>
<input type="hidden" {...hf.register("token")} />
<input
type="password"
aria-invalid={hf.register("password").hasError}
{...hf.register("password")}
/>
{hf.register("password").helperText && (
<div>{hf.register("password").helperText}</div>
)}
<button type="submit">Odeslat</button>
</form>
);
}Co je fieldMap a kdy ho použít
fieldMap mapuje lokální názvy polí (klíče ve react-hook-form) na serverové názvy z HATEOAS formuláře.
Tvar je vždy:
type HateoasFieldMap = Record<
string,
[serverFieldName: string, fieldType: "string" | "integer" | "set"]
>;Použití dává smysl i když jsou názvy stejné (určíš typ a validátory), a hlavně když chceš lokální názvy změnit nebo vnořit:
const fieldMap = {
"auth.password": ["password", "string"],
token: ["token", "string"],
} as const;
// pak: hf.register("auth.password")Automatická tvorba fieldMap z HateoasFormV2
V @alza/hateoas existuje utilita createFieldMapFromForm (také dostupná jako Hateoas.createFieldMapFromForm).
1) Identity mapping (nejčastější)
import { Hateoas } from "@alza/hateoas";
const fieldMap = Hateoas.createFieldMapFromForm(form);
const hf = useHateoasForm(form, fieldMap, t, callClientApi);2) Rename server → local
import { createFieldMapFromForm } from "@alza/hateoas";
const fieldMap = createFieldMapFromForm(form, {
rename: {
password: "auth.password",
},
});3) Unsupported pole (boolean/set/date…)
Defaultně se unsupported itemTypes přeskočí. Když chceš fail-fast:
const fieldMap = createFieldMapFromForm(form, { unsupported: "throw" });submitForm a API integrace
Hook si přes AlzaHateoasForm vytáhne url/method/data ze serverového formu a zavolá callClientApi:
type CallClientApi = (args: {
url: string;
method: string;
data?: unknown;
}) => Promise<{ isOk: () => boolean; value: { data: unknown } }>;- Když
response.isOk()vrátítrue, můžeš dodatformFromResponse, které z odpovědi vytáhne novýHateoasFormV2. Ten se pak uloží do hooku a provede sereset()+ propsánívalidationErrordo React Hook Form přessetError.
await hf.submitForm({
formValues: values,
formFromResponse: (data) => data.form,
});set (select) – renderování a práce s hodnotou
HATEOAS set se typicky renderuje jako <select> s <option>.
- pro single-select bývá hodnota v UI
string - pro multi-select (když
maxSize > 1) je hodnota typickystring[] - při submitu se
setvždy odešle jako array (server tvar)
useHateoasForm.register() vrací kromě RHF props i hateoasField (UI field model z @alza/hateoas), takže máš po ruce options a multiple.
Příklad: single-select
import { useHateoasForm } from "@alza/hateoas-react-hook-form";
import type { HateoasFieldMap, HateoasFormV2 } from "@alza/hateoas";
const fieldMap = {
day: ["day", "set"],
} as const satisfies HateoasFieldMap;
export function Example({ form }: { form: HateoasFormV2 }) {
const hf = useHateoasForm(form, fieldMap, t, callClientApi);
const day = hf.register("day");
const field = day.hateoasField;
if (!field || field.itemType !== "set") return null;
return (
<form
onSubmit={hf.handleSubmit(async (values) => {
await hf.submitForm({ formValues: values });
})}
>
<select aria-invalid={day.hasError} multiple={field.multiple} {...day}>
{field.options.map((o) => (
<option key={o.value} value={o.value} disabled={o.disabled}>
{o.label}
</option>
))}
</select>
{day.helperText && <div>{day.helperText}</div>}
<button type="submit">Odeslat</button>
</form>
);
}Příklad: nastavení hodnoty
// single-select: string
hf.setValue("day", "nextday");
// multi-select: string[]
hf.setValue("categories", ["Int", "Float"]);Pozn.: při submitu se day: "nextday" pošle jako day: ["nextday"].
Testování
Balíček má Vitest testy v lib/__tests_.
-
V rootu (Windows/PowerShell policy friendly):
cd packages/hateoas-react-hook-formnpx vitest run
-
Pokud máš funkční Yarn workspace:
yarn workspace @alza/hateoas-react-hook-form test