react-f0rm 0.7.0 → 0.8.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/dist/index.umd.js CHANGED
@@ -537,16 +537,13 @@
537
537
  const settle = () => waitUntil(
538
538
  form.emitter,
539
539
  "validating",
540
- () => !form.validating.size,
540
+ () => fieldsSettled(form),
541
541
  () => false
542
542
  );
543
543
  if (name === void 0) {
544
544
  form.validators.forEach((validator) => validator());
545
545
  await settle();
546
- if (form.validate) {
547
- const result = await form.validate(getValues(form));
548
- applyValidateResult(form, result);
549
- }
546
+ if (form.validate) await runFormValidate(form);
550
547
  return !hasErrors(form);
551
548
  }
552
549
  const keys = typeof name === "string" || isSegmentsPath(name) ? [create$1(name).key] : name.map((one) => create$1(one).key);
@@ -589,19 +586,110 @@
589
586
  }
590
587
  setFormErrors(form, result);
591
588
  }
589
+ const FORM_VALIDATING_KEY = "__form_validate__";
590
+ function fieldsSettled(form) {
591
+ for (const key of form.validating) {
592
+ if (key !== FORM_VALIDATING_KEY) return false;
593
+ }
594
+ return true;
595
+ }
596
+ const SETTLED = /* @__PURE__ */ Symbol("form-validate-settled");
597
+ const formValidateStates = /* @__PURE__ */ new WeakMap();
598
+ function getFormValidateState(form) {
599
+ let state = formValidateStates.get(form);
600
+ if (!state) {
601
+ state = {
602
+ timer: null,
603
+ controller: null,
604
+ round: null,
605
+ marked: false,
606
+ waiters: []
607
+ };
608
+ formValidateStates.set(form, state);
609
+ }
610
+ return state;
611
+ }
612
+ function runFormValidate(form) {
613
+ const validate2 = form.validate;
614
+ if (!validate2) return Promise.resolve();
615
+ const debounce = form.validateDebounce ?? 0;
616
+ if (debounce <= 0) {
617
+ const controller = new AbortController();
618
+ return Promise.resolve(
619
+ validate2(getValues(form), { form, signal: controller.signal })
620
+ ).then((result) => {
621
+ applyValidateResult(form, result);
622
+ });
623
+ }
624
+ const state = getFormValidateState(form);
625
+ if (state.timer !== null) clearTimeout(state.timer);
626
+ else {
627
+ state.marked = true;
628
+ form.validating.add(FORM_VALIDATING_KEY);
629
+ emit(form.emitter, "validating");
630
+ }
631
+ state.timer = setTimeout(() => {
632
+ state.timer = null;
633
+ const round = state.round = {};
634
+ runFormValidateRound(form, state, round).then(
635
+ () => settleFormValidate(form, state, round, SETTLED),
636
+ (error) => settleFormValidate(form, state, round, error)
637
+ );
638
+ }, debounce);
639
+ return new Promise((resolve, reject) => {
640
+ state.waiters.push({ resolve, reject });
641
+ });
642
+ }
643
+ function runFormValidateRound(form, state, round) {
644
+ const validate2 = form.validate;
645
+ if (!validate2) return Promise.resolve();
646
+ state.controller?.abort();
647
+ const controller = state.controller = new AbortController();
648
+ let outcome;
649
+ try {
650
+ outcome = Promise.resolve(
651
+ validate2(getValues(form), { form, signal: controller.signal })
652
+ );
653
+ } catch (error) {
654
+ outcome = Promise.reject(error);
655
+ }
656
+ return outcome.then(
657
+ (result) => {
658
+ if (state.round === round) applyValidateResult(form, result);
659
+ },
660
+ (error) => {
661
+ if (state.round === round) throw error;
662
+ }
663
+ );
664
+ }
665
+ function settleFormValidate(form, state, round, outcome) {
666
+ if (state.round !== round) return;
667
+ state.round = null;
668
+ if (state.timer !== null) return;
669
+ if (state.marked) {
670
+ state.marked = false;
671
+ form.validating.delete(FORM_VALIDATING_KEY);
672
+ emit(form.emitter, "validating");
673
+ }
674
+ const waiters = state.waiters;
675
+ state.waiters = [];
676
+ for (const waiter of waiters) {
677
+ if (outcome === SETTLED) waiter.resolve();
678
+ else waiter.reject(outcome);
679
+ }
680
+ }
592
681
  async function ensureValidate(form) {
593
682
  form.validators.forEach((validator) => validator());
594
683
  await waitUntil(
595
684
  form.emitter,
596
685
  "validating",
597
- () => !form.validating.size,
686
+ () => fieldsSettled(form),
598
687
  () => hasErrors(form)
599
688
  ).catch(() => {
600
689
  throw new Error(getFirstError(form));
601
690
  });
602
691
  if (form.validate) {
603
- const result = await form.validate(getValues(form));
604
- applyValidateResult(form, result);
692
+ await runFormValidate(form);
605
693
  if (hasErrors(form)) throw new Error(getFirstError(form));
606
694
  }
607
695
  }
@@ -1139,6 +1227,24 @@
1139
1227
  function useIsSubmitting(form) {
1140
1228
  return useWatch(form.emitter, "submitting", () => form.isSubmitting);
1141
1229
  }
1230
+ function useCanSubmit(form) {
1231
+ const { emitter } = form;
1232
+ const subscribeFactory = React.useCallback(
1233
+ (invalidate) => {
1234
+ const offErrors = on(emitter, "errors", invalidate);
1235
+ const offSubmitting = on(emitter, "submitting", invalidate);
1236
+ return () => {
1237
+ offErrors();
1238
+ offSubmitting();
1239
+ };
1240
+ },
1241
+ [emitter]
1242
+ );
1243
+ return useWatchCore(
1244
+ subscribeFactory,
1245
+ () => !form.isSubmitting && !hasErrors(form)
1246
+ );
1247
+ }
1142
1248
  function useSubmitCount(form) {
1143
1249
  return useWatch(form.emitter, "submitCount", () => form.submitCount);
1144
1250
  }
@@ -1811,6 +1917,7 @@
1811
1917
  exports.subscribe = subscribe;
1812
1918
  exports.trigger = trigger;
1813
1919
  exports.unsetValidatingByPath = unsetValidatingByPath;
1920
+ exports.useCanSubmit = useCanSubmit;
1814
1921
  exports.useCheckboxGroupContext = useCheckboxGroupContext;
1815
1922
  exports.useDirtyFields = useDirtyFields;
1816
1923
  exports.useError = useError;