{"version":3,"file":"useFormState.mjs","names":[],"sources":["../../../../../../../react-form/src/hooks/useFormState.ts"],"sourcesContent":["\"use client\";\n\nimport { ReactNode, useEffect, useState } from \"react\";\nimport { FormContextData } from \"../types\";\nimport { useForm } from \"./useForm\";\n\nexport type FormState = {\n  /** Whether the form currently has no invalid controls. */\n  isValid: boolean;\n  /** Whether any control has been changed from its initial value. */\n  isDirty: boolean;\n  /** Whether the form is mid-submit. */\n  isSubmitting: boolean;\n  /** Whether the form has attempted submission at least once. */\n  isSubmitted: boolean;\n  /** Whether any control has an async validation in flight. */\n  isValidating: boolean;\n  /** Form-level errors with no owning control (whole-form schema). */\n  formErrors: ReactNode[];\n};\n\nconst emptyState: FormState = {\n  isValid: true,\n  isDirty: false,\n  isSubmitting: false,\n  isSubmitted: false,\n  isValidating: false,\n  formErrors: [],\n};\n\nfunction readState(form: FormContextData): FormState {\n  if (!form) return emptyState;\n\n  return {\n    isValid: form.isValid(),\n    isDirty: form.isDirty,\n    isSubmitting: form.isSubmitting(),\n    isSubmitted: form.wasSubmitted,\n    isValidating: form.controls().some((control) => control.isValidating),\n    formErrors: form.formErrors,\n  };\n}\n\n/**\n * One-stop reactive snapshot of form-level state — `isValid`, `isDirty`,\n * `isSubmitting`, `isSubmitted`, `isValidating`, and `formErrors` — for any\n * descendant of a `Form` / `NativeForm`.\n *\n * ```tsx\n * const { isValid, isSubmitting, isDirty } = useFormState();\n * <button disabled={!isValid || isSubmitting || !isDirty}>Save</button>\n * ```\n */\nexport function useFormState(): FormState {\n  const form = useForm();\n  const [state, setState] = useState<FormState>(() => readState(form));\n\n  useEffect(() => {\n    if (!form) return;\n\n    const update = () => setState(readState(form));\n\n    const subscriptions = [\n      form.on(\"validControls\", update),\n      form.on(\"invalidControls\", update),\n      form.on(\"validation\", update),\n      form.on(\"dirty\", update),\n      form.on(\"submitting\", update),\n      form.on(\"submit\", update),\n      form.on(\"reset\", update),\n      form.on(\"change\", update),\n    ];\n\n    // Sync once on mount in case state changed between render and effect.\n    update();\n\n    return () => {\n      subscriptions.forEach((subscription) => subscription.unsubscribe());\n    };\n  }, [form]);\n\n  return state;\n}\n"],"mappings":";;;;;;AAqBA,MAAM,aAAwB;CAC5B,SAAS;CACT,SAAS;CACT,cAAc;CACd,aAAa;CACb,cAAc;CACd,YAAY,CAAC;AACf;AAEA,SAAS,UAAU,MAAkC;CACnD,IAAI,CAAC,MAAM,OAAO;CAElB,OAAO;EACL,SAAS,KAAK,QAAQ;EACtB,SAAS,KAAK;EACd,cAAc,KAAK,aAAa;EAChC,aAAa,KAAK;EAClB,cAAc,KAAK,SAAS,CAAC,CAAC,MAAM,YAAY,QAAQ,YAAY;EACpE,YAAY,KAAK;CACnB;AACF;;;;;;;;;;;AAYA,SAAgB,eAA0B;CACxC,MAAM,OAAO,QAAQ;CACrB,MAAM,CAAC,OAAO,YAAY,eAA0B,UAAU,IAAI,CAAC;CAEnE,gBAAgB;EACd,IAAI,CAAC,MAAM;EAEX,MAAM,eAAe,SAAS,UAAU,IAAI,CAAC;EAE7C,MAAM,gBAAgB;GACpB,KAAK,GAAG,iBAAiB,MAAM;GAC/B,KAAK,GAAG,mBAAmB,MAAM;GACjC,KAAK,GAAG,cAAc,MAAM;GAC5B,KAAK,GAAG,SAAS,MAAM;GACvB,KAAK,GAAG,cAAc,MAAM;GAC5B,KAAK,GAAG,UAAU,MAAM;GACxB,KAAK,GAAG,SAAS,MAAM;GACvB,KAAK,GAAG,UAAU,MAAM;EAC1B;EAGA,OAAO;EAEP,aAAa;GACX,cAAc,SAAS,iBAAiB,aAAa,YAAY,CAAC;EACpE;CACF,GAAG,CAAC,IAAI,CAAC;CAET,OAAO;AACT"}