react-f0rm 0.5.1 → 0.6.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/README.md CHANGED
@@ -349,6 +349,39 @@ const form = createForm({
349
349
  });
350
350
  ```
351
351
 
352
+ #### Per-field mode override
353
+
354
+ Sometimes one field deserves a different schedule than the rest of the form — a signup form that validates on submit, except the email field whose check should fire as soon as the user leaves the input. Any field can declare its own `mode`: it replaces the form-level `mode` for that field only, while every other field keeps the form's timing.
355
+
356
+ ```jsx
357
+ import {Form, Field, useForm} from 'react-f0rm';
358
+
359
+ function Register() {
360
+ // Form default: validate on submit.
361
+ const form = useForm({initialValues: {email: '', bio: ''}});
362
+
363
+ return (
364
+ <Form form={form}>
365
+ {/* This field alone validates on blur... */}
366
+ <Field name="email" mode="onBlur" validate={checkEmail} />
367
+ {/* ...while every other field waits for submit. */}
368
+ <Field name="bio" />
369
+ </Form>
370
+ );
371
+ }
372
+ ```
373
+
374
+ The same option exists on `useField` (and `Checkbox` / `Select`):
375
+
376
+ ```jsx
377
+ const email = useField({name: 'email', mode: 'onBlur', validate: checkEmail});
378
+ ```
379
+
380
+ - Accepted values are the same `ValidationMode` union as the form's `mode`; omit it and the field follows `form.mode` exactly as before.
381
+ - Precedence is per field: `field.mode ?? form.mode`. A field cannot change another field's timing, and declaring `mode: 'onSubmit'` opts a field out of an `'onChange'` form.
382
+ - `reValidateMode` stays form-level for every field: once a field has an error (after a failed submit, say), re-validation follows the form's `reValidateMode` regardless of the field's own `mode` — a `mode: 'onBlur'` field with the default `reValidateMode: 'onChange'` still re-validates on every keystroke while errored.
383
+ - Manual `trigger` and submit validation are unaffected — they always run the field's validators regardless of any mode.
384
+
352
385
  ### Triggering validation manually
353
386
 
354
387
  `trigger` runs field validators on demand. Without a name it runs every registered validator; a single name — or an array of names — narrows it to those fields:
@@ -603,5 +603,5 @@ interface SetFocusOptions {
603
603
  */
604
604
  declare function setFocus(form: Form, name: Name, options?: SetFocusOptions): void;
605
605
 
606
- export { setServerErrors as $, getValueByPath as A, getValues as B, handleSubmit as C, hasErrors as D, hasTouched as E, hasTouchedByPath as G, incrementSubmitCount as I, isDirty as J, isTouched as K, removeField as L, removeFieldByPath as M, reset as Q, resetField as T, setDisabled as U, VALIDATION_OUTCOME as V, setError as W, setErrorByPath as X, setFocus as Y, setInitialValues as Z, setIsSubmitting as _, setSubmitSuccessful as a0, setTouched as a1, setTouchedByPath as a2, setValidatingByPath as a3, setValue as a4, setValueByPath as a5, trigger as a6, unsetValidatingByPath as a7, validate as a8, clearErrors as n, create as o, ensureValidate as p, getDirtyFields as q, getError as r, getErrorByPath as s, getErrors as t, getFieldErrors as u, getFieldErrorsByPath as v, getFieldState as w, getFirstError as x, getTouchedFields as y, getValue as z };
607
- export type { Form as F, HandleSubmitOptions as H, Name as N, Options as O, PathValueOf as P, ReValidateMode as R, SetFieldOptions as S, FieldPath as a, FieldError as b, Path as c, FieldErrorEntry as d, FieldState as e, PathValue as f, ResetFieldOptions as g, ResetOptions as h, SetFocusOptions as i, SetServerErrorsOptions as j, ValidateResult as k, ValidationMode as l, ValidationOutcome as m };
606
+ export { setServerErrors as $, getValueByPath as A, getValues as B, handleSubmit as C, hasErrors as D, hasTouched as E, hasTouchedByPath as G, incrementSubmitCount as I, isDirty as J, isTouched as K, removeField as L, removeFieldByPath as M, reset as Q, resetField as T, setDisabled as U, setError as W, setErrorByPath as X, setFocus as Y, setInitialValues as Z, setIsSubmitting as _, setSubmitSuccessful as a0, setTouched as a1, setTouchedByPath as a2, setValidatingByPath as a3, setValue as a4, setValueByPath as a5, trigger as a6, unsetValidatingByPath as a7, validate as a8, VALIDATION_OUTCOME as k, clearErrors as n, create as o, ensureValidate as p, getDirtyFields as q, getError as r, getErrorByPath as s, getErrors as t, getFieldErrors as u, getFieldErrorsByPath as v, getFieldState as w, getFirstError as x, getTouchedFields as y, getValue as z };
607
+ export type { Form as F, HandleSubmitOptions as H, Name as N, Options as O, PathValueOf as P, ReValidateMode as R, SetFieldOptions as S, ValidationMode as V, FieldPath as a, FieldError as b, Path as c, FieldErrorEntry as d, FieldState as e, PathValue as f, ResetFieldOptions as g, ResetOptions as h, SetFocusOptions as i, SetServerErrorsOptions as j, ValidateResult as l, ValidationOutcome as m };
package/dist/index.cjs.js CHANGED
@@ -1280,7 +1280,8 @@ function useFieldCore({
1280
1280
  rules,
1281
1281
  validateDebounce,
1282
1282
  delayError,
1283
- disabled
1283
+ disabled,
1284
+ mode: modeOption
1284
1285
  }, Context) {
1285
1286
  const contextForm = React.useContext(Context);
1286
1287
  const form = f1 || contextForm;
@@ -1300,6 +1301,7 @@ function useFieldCore({
1300
1301
  const error = errorObject?.message;
1301
1302
  const value = useValueByPath(form, path);
1302
1303
  const formDisabled = useWatch(form.emitter, "disabled", () => form.disabled);
1304
+ const mode = modeOption ?? form.mode;
1303
1305
  React.useEffect(() => {
1304
1306
  if (initialValue === void 0) return;
1305
1307
  if (getValueByPath(form, path) === void 0) {
@@ -1308,12 +1310,12 @@ function useFieldCore({
1308
1310
  }, [form, path, initialValue]);
1309
1311
  const onChange = useStageFn((v) => {
1310
1312
  setValueByPath(form, path, v);
1311
- if (form.mode === "onChange" || form.mode === "all" || form.mode === "onTouched" && hasTouchedByPath(form, path) || liveErrors.length > 0 && form.reValidateMode === "onChange")
1313
+ if (mode === "onChange" || mode === "all" || mode === "onTouched" && hasTouchedByPath(form, path) || liveErrors.length > 0 && form.reValidateMode === "onChange")
1312
1314
  validator();
1313
1315
  });
1314
1316
  const onBlur = useStageFn(() => {
1315
1317
  setTouchedByPath(form, path);
1316
- if (form.mode === "onBlur" || form.mode === "onTouched" || form.mode === "all" || liveErrors.length > 0 && form.reValidateMode === "onBlur")
1318
+ if (mode === "onBlur" || mode === "onTouched" || mode === "all" || liveErrors.length > 0 && form.reValidateMode === "onBlur")
1317
1319
  validator();
1318
1320
  });
1319
1321
  React.useEffect(
@@ -1532,6 +1534,7 @@ const Field = React__namespace.forwardRef(
1532
1534
  validateDebounce,
1533
1535
  disabled,
1534
1536
  delayError,
1537
+ mode,
1535
1538
  ...props
1536
1539
  }, ref) => {
1537
1540
  const innerRef = React__namespace.useRef(null);
@@ -1560,6 +1563,7 @@ const Field = React__namespace.forwardRef(
1560
1563
  validateDebounce,
1561
1564
  delayError,
1562
1565
  disabled,
1566
+ mode,
1563
1567
  validate: (...params) => {
1564
1568
  const el = innerRef.current;
1565
1569
  if (el && typeof el.checkValidity === "function") {
@@ -1633,6 +1637,7 @@ const Checkbox = React__namespace.forwardRef(
1633
1637
  validateDebounce,
1634
1638
  disabled,
1635
1639
  delayError,
1640
+ mode,
1636
1641
  ...props
1637
1642
  }, ref) => {
1638
1643
  const {
@@ -1651,7 +1656,8 @@ const Checkbox = React__namespace.forwardRef(
1651
1656
  rules,
1652
1657
  validateDebounce,
1653
1658
  delayError,
1654
- disabled
1659
+ disabled,
1660
+ mode
1655
1661
  });
1656
1662
  return /* @__PURE__ */ React__namespace.createElement(
1657
1663
  "input",
@@ -1687,6 +1693,7 @@ const Select = React__namespace.forwardRef(
1687
1693
  validateDebounce,
1688
1694
  disabled,
1689
1695
  delayError,
1696
+ mode,
1690
1697
  ...props
1691
1698
  }, ref) => {
1692
1699
  const {
@@ -1705,7 +1712,8 @@ const Select = React__namespace.forwardRef(
1705
1712
  rules,
1706
1713
  validateDebounce,
1707
1714
  delayError,
1708
- disabled
1715
+ disabled,
1716
+ mode
1709
1717
  });
1710
1718
  return /* @__PURE__ */ React__namespace.createElement(
1711
1719
  "select",