Skip to content

v1.20.0

Choose a tag to compare

@edmundhung edmundhung released this 19 Jul 23:47
0509e08

Breaking Changes (Future APIs)

Important

All options previously deprecated in the future APIs will be removed in the next minor release as we prepare for an upcoming v2.0 beta.

  • Renamed the value returned by resolveSubmission() to targetValue. (#1246)

    -const { intent, value } = resolveSubmission(submission);
    +const { intent, targetValue } = resolveSubmission(submission);
  • Staged validation in onValidate() now uses a { result, pending } object instead of a tuple. (#1247)

    Staged validation lets onValidate() return a known validation result immediately while a slower asynchronous check continues. This behavior was previously undocumented. If you relied on it, update your callback to use the new object structure:

    -return [result, pending];
    +return { result, pending };

What's Changed

  • Added custom intents to the future APIs. Define an intent with defineIntent(), register it through configureForms() or useForm(), and dispatch it alongside the built-in intents. (#1191)

    const copyField = defineIntent<
      (options: { from: string; to: string }) => void
    >({
      parse(options) {
        return options;
      },
      resolve({ value, payload }) {
        return setPathValue(
          value,
          payload.to,
          getPathValue(value, payload.from),
        );
      },
    });
    
    const forms = configureForms({
      intents: { copyField },
    });
    
    const { intent } = forms.useForm();
    
    intent.copyField({
      from: fields.billing.name,
      to: fields.shipping.name,
    });

    This also adds resolveSubmission() for resolving custom and built-in intents on the server.

  • Added custom form state to the future APIs. Use defineCustomState() to derive state from intents and submission results, then read it from form.customState. (#1244)

    const submitCount = defineCustomState({
      initialize() {
        return 0;
      },
      handleIntent(count, { intent }) {
        return intent.type === 'submit' ? count + 1 : count;
      },
    });
    
    const { form } = useForm({
      customState: { submitCount },
    });
    
    form.customState.submitCount;
  • The value option from report() has also been deprecated in favor of targetValue for consistency. It will be removed in the next minor release. (#1247)

    report(submission, {
    -  value,
    +  targetValue,
    });
  • Improved the future Zod getConstraints() API so fields required within a union or discriminated-union branch remain required. This better supports conditional forms where each branch renders its own fields. (#1236)

  • Added support for z.readonly() schemas in coerceFormValue() and getZodConstraint(). The inner schema is now coerced correctly and its validation constraints are preserved across the default, /v3, and /v4 exports. (#1239)

  • Preserved empty string values inside array fields when building submission payloads, avoiding dropped or shifted entries. (#1233)

  • Preserved empty values in defaultPayload so custom controls can render their complete default structure before user interaction. (#1235)

  • Preserved lastResult errors when initialValue is omitted. Passing null remains the explicit reset behavior. (#1237)

  • Fixed the default stable metadata types so schema-specific metadata remains assignable to FormMetadata and FieldMetadata without explicitly providing a schema generic. (#1221)

  • Improved intent.update() types so extra properties are rejected when updating an array item by index. (#1245)

Documentation

  • Fixed the getInputProps documentation. (#1227)

New Contributors

Full Changelog: v1.19.4...v1.20.0