formstand 0.10.0 → 0.12.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.d.cts CHANGED
@@ -282,6 +282,7 @@ type FieldArrayFormApi = Readonly<{
282
282
  arrayInsert(path: string, index: number, item: unknown): void;
283
283
  arrayMove(path: string, from: number, to: number): void;
284
284
  arraySwap(path: string, a: number, b: number): void;
285
+ validateField?(path: string): FieldValidationResult;
285
286
  }>;
286
287
  type FieldArrayEntry<TItem> = Readonly<{
287
288
  id: string;
@@ -398,6 +399,15 @@ type NumberFieldProps<F extends FieldFormApi = FieldFormApi> = Readonly<{
398
399
  placeholder?: string;
399
400
  ref?: FieldRef<HTMLInputElement>;
400
401
  }>;
402
+ type NumberInputBinding = Readonly<{
403
+ name: string;
404
+ value: string;
405
+ inputMode: "decimal";
406
+ "aria-invalid": true | undefined;
407
+ onChange: (e: ChangeEvent<HTMLInputElement>) => void;
408
+ onBlur: () => void;
409
+ }>;
410
+ declare const useNumberInput: (field: UseFieldReturn<number | null | undefined>) => NumberInputBinding;
401
411
  declare const NumberField: <F extends FieldFormApi>({ form, path, label, placeholder, ref, }: NumberFieldProps<F>) => react.JSX.Element;
402
412
  type CheckboxFieldProps<F extends FieldFormApi = FieldFormApi> = Readonly<{
403
413
  form: F;
@@ -488,4 +498,4 @@ declare const dateInputProps: <T extends Date | null | undefined>(field: UseFiel
488
498
  declare const checkboxProps: <T extends boolean | null | undefined>(field: UseFieldReturn<T>) => CheckboxProps;
489
499
  declare const selectProps: <T extends string | null | undefined>(field: UseFieldReturn<T>) => SelectProps;
490
500
 
491
- export { type BoolMap, type BoundUseField, type BoundUseFieldArray, type BoundUseFlag, type BoundUseSelector, CheckboxField, type CheckboxFieldProps, type CheckboxProps, type CreateFormOptions, DateField, type DateFieldProps, type DateInputProps, type DefaultPathDepth, type ErrorMap, type FieldArrayEntry, type FieldArrayFormApi, type FieldFormApi, type FieldPath, type FieldPathArg, type FieldRef, type FieldSnapshot, type FieldValidationResult, type FieldValue, type FieldsValidationResult, type Form, type FormContextApi, type FormHooks, type FormProviderProps, type FormState, type FormStateApi, type InvalidSubmitHandler, NumberField, type NumberFieldProps, type NumberInputProps, type ParsedDateText, type ParsedNumberText, type PathDepth, type PathSegment, type PathsOf, type PersistHandle, type PersistOptions, type PersistStorage, type ReadonlyStoreApi, type ResetOptions, SelectField, type SelectFieldOption, type SelectFieldProps, type SelectProps, type SettledFieldValidationResult, type SettledFieldsValidationResult, type SettledValidationResult, type SubmitHandler, type SubmitOptions, type SubmitResult, TextField, type TextFieldProps, type TextInputProps, type UseFieldArrayReturn, type UseFieldOptions, type UseFieldReturn, type ValidationMode, type ValidationResult, type ValidationTrigger, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, getAtPath, hasFieldError, isAsyncRequiredError, numberInputProps, numberToInputText, parseDateText, parseNumberText, parsePath, persistForm, selectProps, setAtPath, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormSelector, useFormSelectorShallow, useIsDirty, useIsSubmitting, useIsValid, useSubmitCount, useVariantField, validateAsync, validateSync };
501
+ export { type BoolMap, type BoundUseField, type BoundUseFieldArray, type BoundUseFlag, type BoundUseSelector, CheckboxField, type CheckboxFieldProps, type CheckboxProps, type CreateFormOptions, DateField, type DateFieldProps, type DateInputProps, type DefaultPathDepth, type ErrorMap, type FieldArrayEntry, type FieldArrayFormApi, type FieldFormApi, type FieldPath, type FieldPathArg, type FieldRef, type FieldSnapshot, type FieldValidationResult, type FieldValue, type FieldsValidationResult, type Form, type FormContextApi, type FormHooks, type FormProviderProps, type FormState, type FormStateApi, type InvalidSubmitHandler, NumberField, type NumberFieldProps, type NumberInputBinding, type NumberInputProps, type ParsedDateText, type ParsedNumberText, type PathDepth, type PathSegment, type PathsOf, type PersistHandle, type PersistOptions, type PersistStorage, type ReadonlyStoreApi, type ResetOptions, SelectField, type SelectFieldOption, type SelectFieldProps, type SelectProps, type SettledFieldValidationResult, type SettledFieldsValidationResult, type SettledValidationResult, type SubmitHandler, type SubmitOptions, type SubmitResult, TextField, type TextFieldProps, type TextInputProps, type UseFieldArrayReturn, type UseFieldOptions, type UseFieldReturn, type ValidationMode, type ValidationResult, type ValidationTrigger, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, getAtPath, hasFieldError, isAsyncRequiredError, numberInputProps, numberToInputText, parseDateText, parseNumberText, parsePath, persistForm, selectProps, setAtPath, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormSelector, useFormSelectorShallow, useIsDirty, useIsSubmitting, useIsValid, useNumberInput, useSubmitCount, useVariantField, validateAsync, validateSync };
package/dist/index.d.ts CHANGED
@@ -282,6 +282,7 @@ type FieldArrayFormApi = Readonly<{
282
282
  arrayInsert(path: string, index: number, item: unknown): void;
283
283
  arrayMove(path: string, from: number, to: number): void;
284
284
  arraySwap(path: string, a: number, b: number): void;
285
+ validateField?(path: string): FieldValidationResult;
285
286
  }>;
286
287
  type FieldArrayEntry<TItem> = Readonly<{
287
288
  id: string;
@@ -398,6 +399,15 @@ type NumberFieldProps<F extends FieldFormApi = FieldFormApi> = Readonly<{
398
399
  placeholder?: string;
399
400
  ref?: FieldRef<HTMLInputElement>;
400
401
  }>;
402
+ type NumberInputBinding = Readonly<{
403
+ name: string;
404
+ value: string;
405
+ inputMode: "decimal";
406
+ "aria-invalid": true | undefined;
407
+ onChange: (e: ChangeEvent<HTMLInputElement>) => void;
408
+ onBlur: () => void;
409
+ }>;
410
+ declare const useNumberInput: (field: UseFieldReturn<number | null | undefined>) => NumberInputBinding;
401
411
  declare const NumberField: <F extends FieldFormApi>({ form, path, label, placeholder, ref, }: NumberFieldProps<F>) => react.JSX.Element;
402
412
  type CheckboxFieldProps<F extends FieldFormApi = FieldFormApi> = Readonly<{
403
413
  form: F;
@@ -488,4 +498,4 @@ declare const dateInputProps: <T extends Date | null | undefined>(field: UseFiel
488
498
  declare const checkboxProps: <T extends boolean | null | undefined>(field: UseFieldReturn<T>) => CheckboxProps;
489
499
  declare const selectProps: <T extends string | null | undefined>(field: UseFieldReturn<T>) => SelectProps;
490
500
 
491
- export { type BoolMap, type BoundUseField, type BoundUseFieldArray, type BoundUseFlag, type BoundUseSelector, CheckboxField, type CheckboxFieldProps, type CheckboxProps, type CreateFormOptions, DateField, type DateFieldProps, type DateInputProps, type DefaultPathDepth, type ErrorMap, type FieldArrayEntry, type FieldArrayFormApi, type FieldFormApi, type FieldPath, type FieldPathArg, type FieldRef, type FieldSnapshot, type FieldValidationResult, type FieldValue, type FieldsValidationResult, type Form, type FormContextApi, type FormHooks, type FormProviderProps, type FormState, type FormStateApi, type InvalidSubmitHandler, NumberField, type NumberFieldProps, type NumberInputProps, type ParsedDateText, type ParsedNumberText, type PathDepth, type PathSegment, type PathsOf, type PersistHandle, type PersistOptions, type PersistStorage, type ReadonlyStoreApi, type ResetOptions, SelectField, type SelectFieldOption, type SelectFieldProps, type SelectProps, type SettledFieldValidationResult, type SettledFieldsValidationResult, type SettledValidationResult, type SubmitHandler, type SubmitOptions, type SubmitResult, TextField, type TextFieldProps, type TextInputProps, type UseFieldArrayReturn, type UseFieldOptions, type UseFieldReturn, type ValidationMode, type ValidationResult, type ValidationTrigger, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, getAtPath, hasFieldError, isAsyncRequiredError, numberInputProps, numberToInputText, parseDateText, parseNumberText, parsePath, persistForm, selectProps, setAtPath, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormSelector, useFormSelectorShallow, useIsDirty, useIsSubmitting, useIsValid, useSubmitCount, useVariantField, validateAsync, validateSync };
501
+ export { type BoolMap, type BoundUseField, type BoundUseFieldArray, type BoundUseFlag, type BoundUseSelector, CheckboxField, type CheckboxFieldProps, type CheckboxProps, type CreateFormOptions, DateField, type DateFieldProps, type DateInputProps, type DefaultPathDepth, type ErrorMap, type FieldArrayEntry, type FieldArrayFormApi, type FieldFormApi, type FieldPath, type FieldPathArg, type FieldRef, type FieldSnapshot, type FieldValidationResult, type FieldValue, type FieldsValidationResult, type Form, type FormContextApi, type FormHooks, type FormProviderProps, type FormState, type FormStateApi, type InvalidSubmitHandler, NumberField, type NumberFieldProps, type NumberInputBinding, type NumberInputProps, type ParsedDateText, type ParsedNumberText, type PathDepth, type PathSegment, type PathsOf, type PersistHandle, type PersistOptions, type PersistStorage, type ReadonlyStoreApi, type ResetOptions, SelectField, type SelectFieldOption, type SelectFieldProps, type SelectProps, type SettledFieldValidationResult, type SettledFieldsValidationResult, type SettledValidationResult, type SubmitHandler, type SubmitOptions, type SubmitResult, TextField, type TextFieldProps, type TextInputProps, type UseFieldArrayReturn, type UseFieldOptions, type UseFieldReturn, type ValidationMode, type ValidationResult, type ValidationTrigger, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, getAtPath, hasFieldError, isAsyncRequiredError, numberInputProps, numberToInputText, parseDateText, parseNumberText, parsePath, persistForm, selectProps, setAtPath, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormSelector, useFormSelectorShallow, useIsDirty, useIsSubmitting, useIsValid, useNumberInput, useSubmitCount, useVariantField, validateAsync, validateSync };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { createStore } from 'zustand/vanilla';
2
2
  import { devtools } from 'zustand/middleware';
3
3
  import { z } from 'zod';
4
- import { useRef, useEffect, createContext, useMemo, useCallback, useContext, useId, useState } from 'react';
4
+ import { useRef, useEffect, createContext, useMemo, useCallback, useState, useContext, useId } from 'react';
5
5
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
6
6
  import { useStore } from 'zustand/react';
7
7
  import { useShallow } from 'zustand/react/shallow';
@@ -1473,25 +1473,52 @@ function useFieldArray(form, pathArg) {
1473
1473
  const items = slice.items;
1474
1474
  const error = slice.error;
1475
1475
  const ids = deriveIds(form.store, path, items).ids;
1476
+ const revalidate = useCallback(() => {
1477
+ const state = form.store.getState();
1478
+ if (shouldValidateOn(
1479
+ "change",
1480
+ state.mode,
1481
+ state.reValidateMode,
1482
+ state.submitCount > 0,
1483
+ state.touched[path] ?? false
1484
+ )) {
1485
+ form.validateField?.(path);
1486
+ }
1487
+ }, [form, path]);
1476
1488
  const push = useCallback(
1477
- (item) => form.arrayPush(path, item),
1478
- [form, path]
1489
+ (item) => {
1490
+ form.arrayPush(path, item);
1491
+ revalidate();
1492
+ },
1493
+ [form, path, revalidate]
1479
1494
  );
1480
1495
  const remove = useCallback(
1481
- (index) => form.arrayRemove(path, index),
1482
- [form, path]
1496
+ (index) => {
1497
+ form.arrayRemove(path, index);
1498
+ revalidate();
1499
+ },
1500
+ [form, path, revalidate]
1483
1501
  );
1484
1502
  const insert = useCallback(
1485
- (index, item) => form.arrayInsert(path, index, item),
1486
- [form, path]
1503
+ (index, item) => {
1504
+ form.arrayInsert(path, index, item);
1505
+ revalidate();
1506
+ },
1507
+ [form, path, revalidate]
1487
1508
  );
1488
1509
  const move = useCallback(
1489
- (from, to) => form.arrayMove(path, from, to),
1490
- [form, path]
1510
+ (from, to) => {
1511
+ form.arrayMove(path, from, to);
1512
+ revalidate();
1513
+ },
1514
+ [form, path, revalidate]
1491
1515
  );
1492
1516
  const swap = useCallback(
1493
- (a, b) => form.arraySwap(path, a, b),
1494
- [form, path]
1517
+ (a, b) => {
1518
+ form.arraySwap(path, a, b);
1519
+ revalidate();
1520
+ },
1521
+ [form, path, revalidate]
1495
1522
  );
1496
1523
  const fields = useMemo(
1497
1524
  () => items.map((value, index) => ({
@@ -1932,6 +1959,24 @@ var nameMatchesAny = (el, paths) => {
1932
1959
  const name = el.getAttribute("name");
1933
1960
  return name !== null && paths.some((p) => isPathOrChild(name, p));
1934
1961
  };
1962
+ var cssQuoted = (value) => `"${value.replace(/[\\"]/g, (ch) => `\\${ch}`).replace(
1963
+ /[\x00-\x1f\x7f]/g,
1964
+ (ch) => `\\${ch.codePointAt(0).toString(16)} `
1965
+ )}"`;
1966
+ var idMatches = (scope, path) => path === "" ? [] : [...scope.querySelectorAll(`[id=${cssQuoted(path)}]`)];
1967
+ var inDomOrder = (els) => [...els].sort(
1968
+ (a, b) => a === b ? 0 : (a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING) !== 0 ? -1 : 1
1969
+ );
1970
+ var pathCandidates = (scope, paths) => {
1971
+ const controls = namedControls(scope);
1972
+ const named = controls.filter((el) => nameMatchesAny(el, paths));
1973
+ const focusableControls = controls.filter(isFocusCandidate);
1974
+ const unnamedPaths = paths.filter(
1975
+ (p) => !focusableControls.some((el) => nameMatchesAny(el, [p]))
1976
+ );
1977
+ const byId = unnamedPaths.flatMap((p) => idMatches(scope, p));
1978
+ return inDomOrder([.../* @__PURE__ */ new Set([...named, ...byId])]);
1979
+ };
1935
1980
  var focusFirstError = (errors, root) => {
1936
1981
  const scope = root ?? document;
1937
1982
  const erroredPaths = Object.keys(errors).filter(
@@ -1939,18 +1984,18 @@ var focusFirstError = (errors, root) => {
1939
1984
  );
1940
1985
  const hasRootError = (errors[""]?.length ?? 0) > 0;
1941
1986
  const controls = namedControls(scope);
1942
- const fieldMatches = controls.filter((el) => nameMatchesAny(el, erroredPaths)).filter(isFocusCandidate);
1987
+ const fieldMatches = pathCandidates(scope, erroredPaths).filter(
1988
+ isFocusCandidate
1989
+ );
1943
1990
  const rootFallbackApplies = hasRootError && (root !== void 0 || document.querySelectorAll("form").length <= 1);
1944
1991
  const candidates = fieldMatches.length > 0 ? fieldMatches : rootFallbackApplies ? controls.filter(isFocusCandidate) : [];
1945
1992
  return focusFirstOf(candidates);
1946
1993
  };
1947
1994
  var focusField = (path, root) => {
1948
- const controls = namedControls(root ?? document);
1949
- return path === "" ? (root !== void 0 || document.querySelectorAll("form").length <= 1) && focusFirstOf(controls.filter(isFocusCandidate)) : focusFirstOf(
1950
- controls.filter((el) => nameMatchesAny(el, [path])).filter(isFocusCandidate)
1951
- );
1995
+ const scope = root ?? document;
1996
+ return path === "" ? (root !== void 0 || document.querySelectorAll("form").length <= 1) && focusFirstOf(namedControls(scope).filter(isFocusCandidate)) : focusFirstOf(pathCandidates(scope, [path]).filter(isFocusCandidate));
1952
1997
  };
1953
1998
 
1954
- export { CheckboxField, DateField, NumberField, SelectField, TextField, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, getAtPath, hasFieldError, isAsyncRequiredError, numberInputProps, numberToInputText, parseDateText, parseNumberText, parsePath, persistForm, selectProps, setAtPath, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormSelector, useFormSelectorShallow, useIsDirty, useIsSubmitting, useIsValid, useSubmitCount, useVariantField, validateAsync, validateSync };
1999
+ export { CheckboxField, DateField, NumberField, SelectField, TextField, checkboxProps, createForm, createFormContext, createFormHooks, dateInputProps, dateToInputText, emptyValueForSchema, flattenIssues, focusField, focusFirstError, getAtPath, hasFieldError, isAsyncRequiredError, numberInputProps, numberToInputText, parseDateText, parseNumberText, parsePath, persistForm, selectProps, setAtPath, shouldValidateOn, textInputProps, useField, useFieldArray, useForm, useFormError, useFormSelector, useFormSelectorShallow, useIsDirty, useIsSubmitting, useIsValid, useNumberInput, useSubmitCount, useVariantField, validateAsync, validateSync };
1955
2000
  //# sourceMappingURL=index.js.map
1956
2001
  //# sourceMappingURL=index.js.map