formstand 0.18.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.19.0 — 2026-09-17
4
+
5
+ ### Added
6
+
7
+ - **The React 19 form-actions bridge.** `useFormAction(form, onValid,
8
+ options?)` returns an action for `<form action={...}>` that validates
9
+ first and hands the handler parsed `z.output` data (plus the raw
10
+ `FormData` last, for file pickers and uncontrolled co-inputs) under
11
+ the full submit lifecycle — isSubmitting/submitCount, errors written
12
+ and marked touched on failure, `onInvalid`/`onError` mirroring
13
+ `handleSubmit`, the same dev warning when a failure resolves
14
+ unobserved, and a reference-stable identity. `useFormActionState(form,
15
+ action, initialState, options?)` is `useActionState` with
16
+ schema-validated data: the handler's `(prevState, data, formData)`
17
+ shape lets a `"use server"` function slot straight in, and invalid,
18
+ skipped, or throwing submissions keep the previous state, because
19
+ field errors already live in the form store. Client-side integration
20
+ by design: no-JS progressive enhancement bypasses any client wrapper,
21
+ so that path validates server-side with the same zod schema.
22
+
3
23
  ## 0.18.0 — 2026-09-17
4
24
 
5
25
  ### Changed
package/dist/index.cjs CHANGED
@@ -1317,6 +1317,51 @@ var useForm = (schema, options) => {
1317
1317
  }, [form, schema, options.initialValues]);
1318
1318
  return form;
1319
1319
  };
1320
+ var warnUnobserved = (result, options, site) => {
1321
+ if (result.kind === "error" && options?.onError === void 0 && process.env.NODE_ENV !== "production") {
1322
+ console.warn(
1323
+ `[formstand] action handler threw and nothing observed it \u2014 the form shows no feedback. Pass { onError } to ${site} (or setError inside your handler):`,
1324
+ result.error
1325
+ );
1326
+ }
1327
+ };
1328
+ var useFormAction = (form, onValid, options) => {
1329
+ const latest = react.useRef({ onValid, options });
1330
+ react.useEffect(() => {
1331
+ latest.current = { onValid, options };
1332
+ });
1333
+ return react.useCallback(
1334
+ async (formData) => {
1335
+ const { onValid: handler, options: opts } = latest.current;
1336
+ const result = await form.submit(
1337
+ (data) => handler(data, formData),
1338
+ opts?.onInvalid,
1339
+ opts?.onError === void 0 ? void 0 : { onError: opts.onError }
1340
+ );
1341
+ warnUnobserved(result, opts, "useFormAction");
1342
+ },
1343
+ [form]
1344
+ );
1345
+ };
1346
+ var useFormActionState = (form, action, initialState, options) => {
1347
+ const [state, formAction, isPending] = react.useActionState(
1348
+ async (prevState, formData) => {
1349
+ const prev = prevState;
1350
+ const nextRef = { current: prev };
1351
+ const result = await form.submit(
1352
+ async (data) => {
1353
+ nextRef.current = await action(prev, data, formData);
1354
+ },
1355
+ options?.onInvalid,
1356
+ options?.onError === void 0 ? void 0 : { onError: options.onError }
1357
+ );
1358
+ warnUnobserved(result, options, "useFormActionState");
1359
+ return nextRef.current;
1360
+ },
1361
+ initialState
1362
+ );
1363
+ return [state, formAction, isPending];
1364
+ };
1320
1365
  var createFormContext = () => {
1321
1366
  const Context = react.createContext(null);
1322
1367
  const Provider = ({ form, children }) => /* @__PURE__ */ jsxRuntime.jsx(Context.Provider, { value: form, children });
@@ -2207,6 +2252,8 @@ exports.useField = useField;
2207
2252
  exports.useFieldArray = useFieldArray;
2208
2253
  exports.useFields = useFields;
2209
2254
  exports.useForm = useForm;
2255
+ exports.useFormAction = useFormAction;
2256
+ exports.useFormActionState = useFormActionState;
2210
2257
  exports.useFormError = useFormError;
2211
2258
  exports.useFormSelector = useFormSelector;
2212
2259
  exports.useFormSelectorShallow = useFormSelectorShallow;