mobx-react-hook-form 5.3.0 → 5.5.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
@@ -102,3 +102,7 @@ const Component = () => {
102
102
  );
103
103
  };
104
104
  ```
105
+
106
+ ## Contribution Guide
107
+
108
+ Want to contribute ? [Follow this guide](https://github.com/js2me/mobx-react-hook-form/blob/master/CONTRIBUTING.md)
package/index.cjs ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const e=require("react/jsx-runtime"),t=require("mobx-react-lite"),i=require("react-hook-form"),s=require("linked-abort-controller"),r=require("mobx"),o=require("yummies/mobx");class a{constructor(e){this.config=e,this.abortController=new s.LinkedAbortController(e.abortSignal),this.originalForm=i.createFormControl({...e,defaultValues:{...e.defaultValues}});const t=e.defaultValues?{...e.defaultValues}:{};this.setError=this.originalForm.setError,this.clearErrors=this.originalForm.clearErrors,this.trigger=this.originalForm.trigger,this.resetField=r.action((...e)=>(i.set(this.values,e[0],i.get(this.defaultValues,e[0])),this.originalForm.resetField(...e))),this.unregister=this.originalForm.unregister,this.control=this.originalForm.control,this.register=this.originalForm.register,this.setFocus=this.originalForm.setFocus,this.setValue=r.action((...e)=>(i.set(this.values,e[0],e[1]),this.originalForm.setValue(...e))),this.resetForm=r.action((...e)=>{let t=e[0]??this.defaultValues;return t=r.isObservableObject(t)?r.toJS(t):structuredClone(t),this.values=t,this.originalForm.reset(...e)}),this._observableStruct=new o.DeepObservableStruct({values:this.originalForm.getValues(),errors:{},dirtyFields:{},touchedFields:{},validatingFields:{}}),this.values=this._observableStruct.data.values,this.errors=this._observableStruct.data.errors,this.validatingFields=this._observableStruct.data.validatingFields,this.dirtyFields=this._observableStruct.data.dirtyFields,this.touchedFields=this._observableStruct.data.touchedFields,Object.assign(this,{defaultValues:t});const a=this.originalForm.subscribe({formState:{values:!0,errors:!0,isValid:!0,isDirty:!0,isValidating:!0,dirtyFields:!0,touchedFields:!0,validatingFields:!0},callback:e=>{!1===this.config.lazyUpdates?this.updateFormState(e):this.scheduleUpdateFormState(e)}});r.observable.ref(this,"isDirty"),r.observable.ref(this,"isLoading"),r.observable.ref(this,"isSubmitted"),r.observable.ref(this,"isSubmitSuccessful"),r.observable.ref(this,"isSubmitting"),r.observable.ref(this,"isValidating"),r.observable.ref(this,"isValid"),r.observable.ref(this,"disabled"),r.observable.ref(this,"submitCount"),r.observable.ref(this,"isReady"),r.observable.deep(this,"defaultValues"),r.action(this,"updateFormState"),r.observable.ref(this,"originalForm"),r.action.bound(this,"submit"),r.action.bound(this,"reset"),r.makeObservable(this),this.abortController.signal.addEventListener("abort",()=>{a(),this.originalForm=null})}values;isDirty=!1;isLoading=!1;isSubmitted=!1;isSubmitSuccessful=!1;isSubmitting=!1;isValidating=!1;isValid=!1;disabled=!1;submitCount=0;defaultValues;dirtyFields;touchedFields;validatingFields;errors;isReady=!1;setError;clearErrors;trigger;resetField;unregister;control;register;setFocus;setValue;resetForm;abortController;originalForm;_observableStruct;changeField=(e,t,i)=>{this.setValue(e,t,{shouldDirty:!0,shouldValidate:this.isSubmitted,...i})};submit(e){return new Promise((t,i)=>{if(!this.originalForm){const e=this.values??{},i=this.config.onSubmit?.(e);return i instanceof Promise?i.then(()=>t(e)):Promise.resolve(e)}this.originalForm.handleSubmit(async(e,i)=>{await(this.config.onSubmit?.(e,i)),t(e)},async(e,t)=>{await(this.config.onSubmitFailed?.(e,t)),i(e)})(e)})}reset(e){this.resetForm(),this.config.onReset?.(e)}updateFormState({values:e,errors:t,dirtyFields:i,validatingFields:s,touchedFields:r,...o}){Object.entries(o).forEach(([e,t])=>{null!=t&&(this[e]=t)}),this._observableStruct.set({dirtyFields:i,errors:t,touchedFields:r,validatingFields:s,values:e})}lastTimeoutId;stopScheduledFormStateUpdate=()=>{void 0!==this.lastTimeoutId&&(clearTimeout(this.lastTimeoutId),this.lastTimeoutId=void 0)};scheduleUpdateFormState=e=>{this.stopScheduledFormStateUpdate(),this.lastTimeoutId=setTimeout(()=>{this.updateFormState(e),this.lastTimeoutId=void 0},this.config.lazyUpdatesTimer??0)};destroy(){this.abortController.abort(),this.stopScheduledFormStateUpdate()}}exports.Controller=s=>e.jsx(i.Controller,{...s,render:i=>e.jsx(t.Observer,{children:()=>s.render(i)})}),exports.Form=a,exports.MobxForm=class extends a{};
2
+ //# sourceMappingURL=index.cjs.map
package/index.cjs.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","sources":["../src/mobx-form/mobx-form.ts","../src/components/controller.tsx"],"sourcesContent":["import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n isObservableObject,\n makeObservable,\n observable,\n toJS,\n} from 'mobx';\nimport type { BaseSyntheticEvent } from 'react';\nimport {\n type Control,\n createFormControl,\n type DeepMap,\n type DeepPartial,\n type DefaultValues,\n type FieldErrors,\n type FieldPath,\n type FieldPathValue,\n type FieldValues,\n type FormState,\n get,\n type SetValueConfig,\n set,\n type UseFormClearErrors,\n type UseFormRegister,\n type UseFormReset,\n type UseFormResetField,\n type UseFormSetError,\n type UseFormSetFocus,\n type UseFormSetValue,\n type UseFormTrigger,\n type UseFormUnregister,\n} from 'react-hook-form';\nimport { DeepObservableStruct } from 'yummies/mobx';\nimport type { FormParams } from './mobx-form.types.js';\n\ntype FormFullState<TFieldValues extends FieldValues> =\n FormState<TFieldValues> & {\n values: TFieldValues;\n };\n\nexport class Form<\n TFieldValues extends FieldValues = FieldValues,\n TContext = any,\n TTransformedValues = TFieldValues,\n> implements FormFullState<TFieldValues>\n{\n values: TFieldValues;\n isDirty: boolean = false;\n isLoading: boolean = false;\n isSubmitted: boolean = false;\n isSubmitSuccessful: boolean = false;\n isSubmitting: boolean = false;\n isValidating: boolean = false;\n isValid: boolean = false;\n disabled: boolean = false;\n submitCount: number = 0;\n /**\n * If you want to change this property\n * Use {resetForm} method\n */\n defaultValues!: Readonly<DefaultValues<TFieldValues>>;\n dirtyFields: Partial<Readonly<DeepMap<DeepPartial<TFieldValues>, boolean>>>;\n touchedFields: Partial<Readonly<DeepMap<DeepPartial<TFieldValues>, boolean>>>;\n validatingFields: Partial<\n Readonly<DeepMap<DeepPartial<TFieldValues>, boolean>>\n >;\n errors: FieldErrors<TFieldValues>;\n isReady: boolean = false;\n\n /**\n * Set an error for the field. When set an error which is not associated to a field then manual `clearErrors` invoke is required.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/seterror) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-seterror-nfxxu) • [Video](https://www.youtube.com/watch?v=raMqvE0YyIY)\n *\n * @param name - the path name to the form field value.\n * @param error - an error object which contains type and optional message\n * @param options - whether or not to focus on the field\n *\n * @example\n * ```tsx\n * // when the error is not associated with any fields, `clearError` will need to invoke to clear the error\n * const onSubmit = () => setError(\"serverError\", { type: \"server\", message: \"Error occurred\"})\n *\n * <button onClick={() => setError(\"name\", { type: \"min\" })} />\n *\n * // focus on the input after setting the error\n * <button onClick={() => setError(\"name\", { type: \"max\" }, { shouldFocus: true })} />\n * ```\n */\n setError: UseFormSetError<TFieldValues>;\n\n /**\n * Clear the entire form errors.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/clearerrors) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-clearerrors-w3ymx)\n *\n * @param name - the path name to the form field value.\n *\n * @example\n * Clear all errors\n * ```tsx\n * clearErrors(); // clear the entire form error\n * clearErrors([\"name\", \"name1\"]) // clear an array of fields' error\n * clearErrors(\"name2\"); // clear a single field error\n * ```\n */\n clearErrors: UseFormClearErrors<TFieldValues>;\n\n /**\n * Trigger field or form validation\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/trigger) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-triggervalidation-forked-xs7hl) • [Video](https://www.youtube.com/watch?v=-bcyJCDjksE)\n *\n * @param name - provide empty argument will trigger the entire form validation, an array of field names will validate an array of fields, and a single field name will only trigger that field's validation.\n * @param options - should focus on the error field\n *\n * @returns validation result\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * trigger();\n * }, [trigger])\n *\n * <button onClick={async () => {\n * const result = await trigger(); // result will be a boolean value\n * }}>\n * trigger\n * </button>\n * ```\n */\n trigger: UseFormTrigger<TFieldValues>;\n\n /**\n * Reset a field state and reference.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/resetfield) • [Demo](https://codesandbox.io/s/priceless-firefly-d0kuv) • [Video](https://www.youtube.com/watch?v=IdLFcNaEFEo)\n *\n * @param name - the path name to the form field value.\n * @param options - keep form state options\n *\n * @example\n * ```tsx\n * <input {...register(\"firstName\", { required: true })} />\n * <button type=\"button\" onClick={() => resetField(\"firstName\"))}>Reset</button>\n * ```\n */\n resetField: UseFormResetField<TFieldValues>;\n\n /**\n * Unregister a field reference and remove its value.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/unregister) • [Demo](https://codesandbox.io/s/react-hook-form-unregister-4k2ey) • [Video](https://www.youtube.com/watch?v=TM99g_NW5Gk&feature=emb_imp_woyt)\n *\n * @param name - the path name to the form field value.\n * @param options - keep form state options\n *\n * @example\n * ```tsx\n * register(\"name\", { required: true })\n *\n * <button onClick={() => unregister(\"name\")} />\n * // there are various keep options to retain formState\n * <button onClick={() => unregister(\"name\", { keepErrors: true })} />\n * ```\n */\n unregister: UseFormUnregister<TFieldValues>;\n\n /**\n * Form control\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/control)\n *\n */\n control: Control<TFieldValues, TContext, TTransformedValues>;\n\n /**\n * Register field into hook form with or without the actual DOM ref. You can invoke register anywhere in the component including at `useEffect`.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/register) • [Demo](https://codesandbox.io/s/react-hook-form-register-ts-ip2j3) • [Video](https://www.youtube.com/watch?v=JFIpCoajYkA)\n *\n * @param name - the path name to the form field value, name is required and unique\n * @param options - register options include validation, disabled, unregister, value as and dependent validation\n *\n * @returns onChange, onBlur, name, ref, and native contribute attribute if browser validation is enabled.\n *\n * @example\n * ```tsx\n * // Register HTML native input\n * <input {...register(\"input\")} />\n * <select {...register(\"select\")} />\n *\n * // Register options\n * <textarea {...register(\"textarea\", { required: \"This is required.\", maxLength: 20 })} />\n * <input type=\"number\" {...register(\"name2\", { valueAsNumber: true })} />\n * <input {...register(\"name3\", { deps: [\"name2\"] })} />\n *\n * // Register custom field at useEffect\n * useEffect(() => {\n * register(\"name4\");\n * register(\"name5\", { value: \"hiddenValue\" });\n * }, [register])\n *\n * // Register without ref\n * const { onChange, onBlur, name } = register(\"name6\")\n * <input onChange={onChange} onBlur={onBlur} name={name} />\n * ```\n */\n register: UseFormRegister<TFieldValues>;\n\n /**\n * Set focus on a registered field. You can start to invoke this method after all fields are mounted to the DOM.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/setfocus) • [Demo](https://codesandbox.io/s/setfocus-rolus)\n *\n * @param name - the path name to the form field value.\n * @param options - input focus behavior options\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * setFocus(\"name\");\n * }, [setFocus])\n * // shouldSelect allows to select input's content on focus\n * <button onClick={() => setFocus(\"name\", { shouldSelect: true })}>Focus</button>\n * ```\n */\n setFocus: UseFormSetFocus<TFieldValues>;\n\n /**\n * Set a single field value, or a group of fields value.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/setvalue) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-setvalue-8z9hx) • [Video](https://www.youtube.com/watch?v=qpv51sCH3fI)\n *\n * @param name - the path name to the form field value.\n * @param value - field value\n * @param options - should validate or update form state\n *\n * @example\n * ```tsx\n * // Update a single field\n * setValue('name', 'value', {\n * shouldValidate: true, // trigger validation\n * shouldTouch: true, // update touched fields form state\n * shouldDirty: true, // update dirty and dirty fields form state\n * });\n *\n * // Update a group fields\n * setValue('root', {\n * a: 'test', // setValue('root.a', 'data')\n * b: 'test1', // setValue('root.b', 'data')\n * });\n *\n * // Update a nested object field\n * setValue('select', { label: 'test', value: 'Test' });\n * ```\n */\n setValue: UseFormSetValue<TFieldValues>;\n\n /**\n * Reset at the entire form state.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/reset) • [Demo](https://codesandbox.io/s/react-hook-form-reset-v7-ts-pu901) • [Video](https://www.youtube.com/watch?v=qmCLBjyPwVk)\n *\n * @param values - the entire form values to be reset\n * @param keepStateOptions - keep form state options\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * // reset the entire form after component mount or form defaultValues is ready\n * reset({\n * fieldA: \"test\"\n * fieldB: \"test\"\n * });\n * }, [reset])\n *\n * // reset by combine with existing form values\n * reset({\n * ...getValues(),\n * fieldB: \"test\"\n *});\n *\n * // reset and keep form state\n * reset({\n * ...getValues(),\n *}, {\n * keepErrors: true,\n * keepDirty: true\n *});\n * ```\n */\n resetForm: UseFormReset<TFieldValues>;\n\n protected abortController: AbortController;\n\n /**\n * Original react-hook-form form\n */\n originalForm: ReturnType<\n typeof createFormControl<TFieldValues, TContext, TTransformedValues>\n >;\n\n private _observableStruct: DeepObservableStruct<\n Pick<\n FormFullState<TFieldValues>,\n 'dirtyFields' | 'errors' | 'touchedFields' | 'validatingFields' | 'values'\n >\n >;\n\n constructor(\n private config: FormParams<TFieldValues, TContext, TTransformedValues>,\n ) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n\n this.originalForm = createFormControl<\n TFieldValues,\n TContext,\n TTransformedValues\n >({\n ...config,\n defaultValues: {\n ...config.defaultValues,\n } as DefaultValues<TFieldValues>,\n });\n\n const defaultValues = config.defaultValues\n ? { ...config.defaultValues }\n : ({} as any);\n\n this.setError = this.originalForm.setError;\n this.clearErrors = this.originalForm.clearErrors;\n this.trigger = this.originalForm.trigger;\n this.resetField = action((...args) => {\n set(this.values, args[0], get(this.defaultValues, args[0]));\n return this.originalForm.resetField(...args);\n });\n this.unregister = this.originalForm.unregister;\n this.control = this.originalForm.control;\n this.register = this.originalForm.register;\n this.setFocus = this.originalForm.setFocus;\n this.setValue = action((...args) => {\n set(this.values, args[0], args[1]);\n return this.originalForm.setValue(...args);\n });\n this.resetForm = action((...args) => {\n let defaultValues = args[0] ?? this.defaultValues;\n\n if (isObservableObject(defaultValues)) {\n defaultValues = toJS(defaultValues);\n } else {\n defaultValues = structuredClone(defaultValues);\n }\n\n // @ts-expect-error\n this.values = defaultValues;\n return this.originalForm.reset(...args);\n });\n\n this._observableStruct = new DeepObservableStruct({\n values: this.originalForm.getValues(),\n errors: {},\n dirtyFields: {},\n touchedFields: {},\n validatingFields: {},\n });\n\n this.values = this._observableStruct.data.values;\n this.errors = this._observableStruct.data.errors;\n this.validatingFields = this._observableStruct.data.validatingFields;\n this.dirtyFields = this._observableStruct.data.dirtyFields;\n this.touchedFields = this._observableStruct.data.touchedFields;\n\n Object.assign(this, {\n defaultValues,\n });\n\n const subscription = this.originalForm.subscribe({\n formState: {\n values: true,\n errors: true,\n isValid: true,\n isDirty: true,\n isValidating: true,\n dirtyFields: true,\n touchedFields: true,\n validatingFields: true,\n },\n callback: (rawFormState) => {\n if (this.config.lazyUpdates === false) {\n this.updateFormState(rawFormState);\n } else {\n this.scheduleUpdateFormState(rawFormState);\n }\n },\n });\n\n observable.ref(this, 'isDirty');\n observable.ref(this, 'isLoading');\n observable.ref(this, 'isSubmitted');\n observable.ref(this, 'isSubmitSuccessful');\n observable.ref(this, 'isSubmitting');\n observable.ref(this, 'isValidating');\n observable.ref(this, 'isValid');\n observable.ref(this, 'disabled');\n observable.ref(this, 'submitCount');\n observable.ref(this, 'isReady');\n observable.deep(this, 'defaultValues');\n action(this, 'updateFormState');\n\n observable.ref(this, 'originalForm');\n action.bound(this, 'submit');\n action.bound(this, 'reset');\n\n makeObservable(this);\n\n this.abortController.signal.addEventListener('abort', () => {\n subscription();\n // @ts-expect-error\n this.originalForm = null;\n });\n }\n\n /**\n * The same as setValue, but will trigger validation if form was submitted, also marks this field as dirty\n * It should work the same as field.onChange from react-hook-form's Controller\n *\n * @param name - the path name to the form field value.\n * @param value - field value\n * @param options - should validate or update form state\n *\n * @example\n * ```tsx\n * // Update a single field\n * changeField('name', 'value');\n * ->\n * setValue('name', 'value', { shouldDirty: true });\n *\n * ** form submitted **\n *\n * changeField('name', 'value');\n * ->\n * setValue('name', 'value', { shouldDirty: true, shouldValidate: true });\n * ```\n */\n changeField = <\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n >(\n name: TFieldName,\n value: FieldPathValue<TFieldValues, TFieldName> | undefined,\n options?: SetValueConfig,\n ) => {\n this.setValue(name, value as any, {\n shouldDirty: true,\n shouldValidate: this.isSubmitted,\n ...options,\n });\n };\n\n /**\n * Method to manually submit form.\n * Used to attach this method to <form /> element\n *\n * @example\n *\n * <form onSubmit={form.submit} />\n */\n submit(e?: BaseSyntheticEvent) {\n return new Promise<TTransformedValues>((resolve, reject) => {\n if (this.originalForm) {\n this.originalForm.handleSubmit(\n async (data, event) => {\n await this.config.onSubmit?.(data, event);\n resolve(data);\n },\n async (errors, event) => {\n await this.config.onSubmitFailed?.(errors, event);\n reject(errors);\n },\n )(e);\n } else {\n const emptyData = (this.values ?? {}) as unknown as TTransformedValues;\n const result = this.config.onSubmit?.(emptyData);\n if (result instanceof Promise) {\n return result.then(() => resolve(emptyData));\n } else {\n return Promise.resolve(emptyData);\n }\n }\n });\n }\n\n /**\n * Method to manually reset all form.\n * Used to attach this method to <form /> element\n *\n * @example\n *\n * <form onReset={form.reset} />\n */\n reset(e?: BaseSyntheticEvent) {\n this.resetForm();\n this.config.onReset?.(e);\n }\n\n private updateFormState({\n values,\n errors,\n dirtyFields,\n validatingFields,\n touchedFields,\n ...simpleProperties\n }: Partial<FormFullState<TFieldValues>>) {\n Object.entries(simpleProperties).forEach(([key, value]) => {\n if (value != null) {\n // @ts-expect-error\n this[key] = value;\n }\n });\n\n this._observableStruct.set({\n dirtyFields,\n errors,\n touchedFields,\n validatingFields,\n values,\n });\n }\n\n protected lastTimeoutId: ReturnType<typeof setTimeout> | undefined;\n\n private stopScheduledFormStateUpdate = () => {\n if (this.lastTimeoutId !== undefined) {\n clearTimeout(this.lastTimeoutId);\n this.lastTimeoutId = undefined;\n }\n };\n\n private scheduleUpdateFormState = (\n rawFormState: Partial<FormFullState<TFieldValues>>,\n ) => {\n this.stopScheduledFormStateUpdate();\n this.lastTimeoutId = setTimeout(() => {\n this.updateFormState(rawFormState);\n this.lastTimeoutId = undefined;\n }, this.config.lazyUpdatesTimer ?? 0);\n };\n\n destroy(): void {\n this.abortController.abort();\n this.stopScheduledFormStateUpdate();\n }\n}\n\n/**\n * @deprecated ⚠️ use `Form`. This export will be removed in next major release\n */\nexport class MobxForm<\n TFieldValues extends FieldValues = FieldValues,\n TContext = any,\n TTransformedValues = TFieldValues,\n> extends Form<TFieldValues, TContext, TTransformedValues> {}\n","import { Observer } from 'mobx-react-lite';\nimport { Controller as LibController } from 'react-hook-form';\n\nexport const Controller = ((props: any) => (\n <LibController\n {...props}\n render={(renderProps) => (\n <Observer>{() => props.render(renderProps)}</Observer>\n )}\n />\n)) as unknown as typeof LibController;\n"],"names":["Form","constructor","config","this","abortController","LinkedAbortController","abortSignal","originalForm","createFormControl","defaultValues","setError","clearErrors","trigger","resetField","action","args","set","values","get","unregister","control","register","setFocus","setValue","resetForm","isObservableObject","toJS","structuredClone","reset","_observableStruct","DeepObservableStruct","getValues","errors","dirtyFields","touchedFields","validatingFields","data","Object","assign","subscription","subscribe","formState","isValid","isDirty","isValidating","callback","rawFormState","lazyUpdates","updateFormState","scheduleUpdateFormState","observable","ref","deep","bound","makeObservable","signal","addEventListener","isLoading","isSubmitted","isSubmitSuccessful","isSubmitting","disabled","submitCount","isReady","changeField","name","value","options","shouldDirty","shouldValidate","submit","e","Promise","resolve","reject","emptyData","result","onSubmit","then","handleSubmit","async","event","onSubmitFailed","onReset","simpleProperties","entries","forEach","key","lastTimeoutId","stopScheduledFormStateUpdate","clearTimeout","setTimeout","lazyUpdatesTimer","destroy","abort","props","jsx","LibController","render","renderProps","Observer","children"],"mappings":"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"}
package/index.js CHANGED
@@ -1,2 +1,476 @@
1
- export * from './components/index.js';
2
- export * from './mobx-form/index.js';
1
+ import { jsx } from "react/jsx-runtime";
2
+ import { Observer } from "mobx-react-lite";
3
+ import { Controller as Controller$1, createFormControl, set, get } from "react-hook-form";
4
+ import { LinkedAbortController } from "linked-abort-controller";
5
+ import { action, isObservableObject, toJS, observable, makeObservable } from "mobx";
6
+ import { DeepObservableStruct } from "yummies/mobx";
7
+ const Controller = ((props) => /* @__PURE__ */ jsx(
8
+ Controller$1,
9
+ {
10
+ ...props,
11
+ render: (renderProps) => /* @__PURE__ */ jsx(Observer, { children: () => props.render(renderProps) })
12
+ }
13
+ ));
14
+ class Form {
15
+ constructor(config) {
16
+ this.config = config;
17
+ this.abortController = new LinkedAbortController(config.abortSignal);
18
+ this.originalForm = createFormControl({
19
+ ...config,
20
+ defaultValues: {
21
+ ...config.defaultValues
22
+ }
23
+ });
24
+ const defaultValues = config.defaultValues ? { ...config.defaultValues } : {};
25
+ this.setError = this.originalForm.setError;
26
+ this.clearErrors = this.originalForm.clearErrors;
27
+ this.trigger = this.originalForm.trigger;
28
+ this.resetField = action((...args) => {
29
+ set(this.values, args[0], get(this.defaultValues, args[0]));
30
+ return this.originalForm.resetField(...args);
31
+ });
32
+ this.unregister = this.originalForm.unregister;
33
+ this.control = this.originalForm.control;
34
+ this.register = this.originalForm.register;
35
+ this.setFocus = this.originalForm.setFocus;
36
+ this.setValue = action((...args) => {
37
+ set(this.values, args[0], args[1]);
38
+ return this.originalForm.setValue(...args);
39
+ });
40
+ this.resetForm = action((...args) => {
41
+ let defaultValues2 = args[0] ?? this.defaultValues;
42
+ if (isObservableObject(defaultValues2)) {
43
+ defaultValues2 = toJS(defaultValues2);
44
+ } else {
45
+ defaultValues2 = structuredClone(defaultValues2);
46
+ }
47
+ this.values = defaultValues2;
48
+ return this.originalForm.reset(...args);
49
+ });
50
+ this._observableStruct = new DeepObservableStruct({
51
+ values: this.originalForm.getValues(),
52
+ errors: {},
53
+ dirtyFields: {},
54
+ touchedFields: {},
55
+ validatingFields: {}
56
+ });
57
+ this.values = this._observableStruct.data.values;
58
+ this.errors = this._observableStruct.data.errors;
59
+ this.validatingFields = this._observableStruct.data.validatingFields;
60
+ this.dirtyFields = this._observableStruct.data.dirtyFields;
61
+ this.touchedFields = this._observableStruct.data.touchedFields;
62
+ Object.assign(this, {
63
+ defaultValues
64
+ });
65
+ const subscription = this.originalForm.subscribe({
66
+ formState: {
67
+ values: true,
68
+ errors: true,
69
+ isValid: true,
70
+ isDirty: true,
71
+ isValidating: true,
72
+ dirtyFields: true,
73
+ touchedFields: true,
74
+ validatingFields: true
75
+ },
76
+ callback: (rawFormState) => {
77
+ if (this.config.lazyUpdates === false) {
78
+ this.updateFormState(rawFormState);
79
+ } else {
80
+ this.scheduleUpdateFormState(rawFormState);
81
+ }
82
+ }
83
+ });
84
+ observable.ref(this, "isDirty");
85
+ observable.ref(this, "isLoading");
86
+ observable.ref(this, "isSubmitted");
87
+ observable.ref(this, "isSubmitSuccessful");
88
+ observable.ref(this, "isSubmitting");
89
+ observable.ref(this, "isValidating");
90
+ observable.ref(this, "isValid");
91
+ observable.ref(this, "disabled");
92
+ observable.ref(this, "submitCount");
93
+ observable.ref(this, "isReady");
94
+ observable.deep(this, "defaultValues");
95
+ action(this, "updateFormState");
96
+ observable.ref(this, "originalForm");
97
+ action.bound(this, "submit");
98
+ action.bound(this, "reset");
99
+ makeObservable(this);
100
+ this.abortController.signal.addEventListener("abort", () => {
101
+ subscription();
102
+ this.originalForm = null;
103
+ });
104
+ }
105
+ values;
106
+ isDirty = false;
107
+ isLoading = false;
108
+ isSubmitted = false;
109
+ isSubmitSuccessful = false;
110
+ isSubmitting = false;
111
+ isValidating = false;
112
+ isValid = false;
113
+ disabled = false;
114
+ submitCount = 0;
115
+ /**
116
+ * If you want to change this property
117
+ * Use {resetForm} method
118
+ */
119
+ defaultValues;
120
+ dirtyFields;
121
+ touchedFields;
122
+ validatingFields;
123
+ errors;
124
+ isReady = false;
125
+ /**
126
+ * Set an error for the field. When set an error which is not associated to a field then manual `clearErrors` invoke is required.
127
+ *
128
+ * @remarks
129
+ * [API](https://react-hook-form.com/docs/useform/seterror) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-seterror-nfxxu) • [Video](https://www.youtube.com/watch?v=raMqvE0YyIY)
130
+ *
131
+ * @param name - the path name to the form field value.
132
+ * @param error - an error object which contains type and optional message
133
+ * @param options - whether or not to focus on the field
134
+ *
135
+ * @example
136
+ * ```tsx
137
+ * // when the error is not associated with any fields, `clearError` will need to invoke to clear the error
138
+ * const onSubmit = () => setError("serverError", { type: "server", message: "Error occurred"})
139
+ *
140
+ * <button onClick={() => setError("name", { type: "min" })} />
141
+ *
142
+ * // focus on the input after setting the error
143
+ * <button onClick={() => setError("name", { type: "max" }, { shouldFocus: true })} />
144
+ * ```
145
+ */
146
+ setError;
147
+ /**
148
+ * Clear the entire form errors.
149
+ *
150
+ * @remarks
151
+ * [API](https://react-hook-form.com/docs/useform/clearerrors) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-clearerrors-w3ymx)
152
+ *
153
+ * @param name - the path name to the form field value.
154
+ *
155
+ * @example
156
+ * Clear all errors
157
+ * ```tsx
158
+ * clearErrors(); // clear the entire form error
159
+ * clearErrors(["name", "name1"]) // clear an array of fields' error
160
+ * clearErrors("name2"); // clear a single field error
161
+ * ```
162
+ */
163
+ clearErrors;
164
+ /**
165
+ * Trigger field or form validation
166
+ *
167
+ * @remarks
168
+ * [API](https://react-hook-form.com/docs/useform/trigger) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-triggervalidation-forked-xs7hl) • [Video](https://www.youtube.com/watch?v=-bcyJCDjksE)
169
+ *
170
+ * @param name - provide empty argument will trigger the entire form validation, an array of field names will validate an array of fields, and a single field name will only trigger that field's validation.
171
+ * @param options - should focus on the error field
172
+ *
173
+ * @returns validation result
174
+ *
175
+ * @example
176
+ * ```tsx
177
+ * useEffect(() => {
178
+ * trigger();
179
+ * }, [trigger])
180
+ *
181
+ * <button onClick={async () => {
182
+ * const result = await trigger(); // result will be a boolean value
183
+ * }}>
184
+ * trigger
185
+ * </button>
186
+ * ```
187
+ */
188
+ trigger;
189
+ /**
190
+ * Reset a field state and reference.
191
+ *
192
+ * @remarks
193
+ * [API](https://react-hook-form.com/docs/useform/resetfield) • [Demo](https://codesandbox.io/s/priceless-firefly-d0kuv) • [Video](https://www.youtube.com/watch?v=IdLFcNaEFEo)
194
+ *
195
+ * @param name - the path name to the form field value.
196
+ * @param options - keep form state options
197
+ *
198
+ * @example
199
+ * ```tsx
200
+ * <input {...register("firstName", { required: true })} />
201
+ * <button type="button" onClick={() => resetField("firstName"))}>Reset</button>
202
+ * ```
203
+ */
204
+ resetField;
205
+ /**
206
+ * Unregister a field reference and remove its value.
207
+ *
208
+ * @remarks
209
+ * [API](https://react-hook-form.com/docs/useform/unregister) • [Demo](https://codesandbox.io/s/react-hook-form-unregister-4k2ey) • [Video](https://www.youtube.com/watch?v=TM99g_NW5Gk&feature=emb_imp_woyt)
210
+ *
211
+ * @param name - the path name to the form field value.
212
+ * @param options - keep form state options
213
+ *
214
+ * @example
215
+ * ```tsx
216
+ * register("name", { required: true })
217
+ *
218
+ * <button onClick={() => unregister("name")} />
219
+ * // there are various keep options to retain formState
220
+ * <button onClick={() => unregister("name", { keepErrors: true })} />
221
+ * ```
222
+ */
223
+ unregister;
224
+ /**
225
+ * Form control
226
+ *
227
+ * @remarks
228
+ * [API](https://react-hook-form.com/docs/useform/control)
229
+ *
230
+ */
231
+ control;
232
+ /**
233
+ * Register field into hook form with or without the actual DOM ref. You can invoke register anywhere in the component including at `useEffect`.
234
+ *
235
+ * @remarks
236
+ * [API](https://react-hook-form.com/docs/useform/register) • [Demo](https://codesandbox.io/s/react-hook-form-register-ts-ip2j3) • [Video](https://www.youtube.com/watch?v=JFIpCoajYkA)
237
+ *
238
+ * @param name - the path name to the form field value, name is required and unique
239
+ * @param options - register options include validation, disabled, unregister, value as and dependent validation
240
+ *
241
+ * @returns onChange, onBlur, name, ref, and native contribute attribute if browser validation is enabled.
242
+ *
243
+ * @example
244
+ * ```tsx
245
+ * // Register HTML native input
246
+ * <input {...register("input")} />
247
+ * <select {...register("select")} />
248
+ *
249
+ * // Register options
250
+ * <textarea {...register("textarea", { required: "This is required.", maxLength: 20 })} />
251
+ * <input type="number" {...register("name2", { valueAsNumber: true })} />
252
+ * <input {...register("name3", { deps: ["name2"] })} />
253
+ *
254
+ * // Register custom field at useEffect
255
+ * useEffect(() => {
256
+ * register("name4");
257
+ * register("name5", { value: "hiddenValue" });
258
+ * }, [register])
259
+ *
260
+ * // Register without ref
261
+ * const { onChange, onBlur, name } = register("name6")
262
+ * <input onChange={onChange} onBlur={onBlur} name={name} />
263
+ * ```
264
+ */
265
+ register;
266
+ /**
267
+ * Set focus on a registered field. You can start to invoke this method after all fields are mounted to the DOM.
268
+ *
269
+ * @remarks
270
+ * [API](https://react-hook-form.com/docs/useform/setfocus) • [Demo](https://codesandbox.io/s/setfocus-rolus)
271
+ *
272
+ * @param name - the path name to the form field value.
273
+ * @param options - input focus behavior options
274
+ *
275
+ * @example
276
+ * ```tsx
277
+ * useEffect(() => {
278
+ * setFocus("name");
279
+ * }, [setFocus])
280
+ * // shouldSelect allows to select input's content on focus
281
+ * <button onClick={() => setFocus("name", { shouldSelect: true })}>Focus</button>
282
+ * ```
283
+ */
284
+ setFocus;
285
+ /**
286
+ * Set a single field value, or a group of fields value.
287
+ *
288
+ * @remarks
289
+ * [API](https://react-hook-form.com/docs/useform/setvalue) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-setvalue-8z9hx) • [Video](https://www.youtube.com/watch?v=qpv51sCH3fI)
290
+ *
291
+ * @param name - the path name to the form field value.
292
+ * @param value - field value
293
+ * @param options - should validate or update form state
294
+ *
295
+ * @example
296
+ * ```tsx
297
+ * // Update a single field
298
+ * setValue('name', 'value', {
299
+ * shouldValidate: true, // trigger validation
300
+ * shouldTouch: true, // update touched fields form state
301
+ * shouldDirty: true, // update dirty and dirty fields form state
302
+ * });
303
+ *
304
+ * // Update a group fields
305
+ * setValue('root', {
306
+ * a: 'test', // setValue('root.a', 'data')
307
+ * b: 'test1', // setValue('root.b', 'data')
308
+ * });
309
+ *
310
+ * // Update a nested object field
311
+ * setValue('select', { label: 'test', value: 'Test' });
312
+ * ```
313
+ */
314
+ setValue;
315
+ /**
316
+ * Reset at the entire form state.
317
+ *
318
+ * @remarks
319
+ * [API](https://react-hook-form.com/docs/useform/reset) • [Demo](https://codesandbox.io/s/react-hook-form-reset-v7-ts-pu901) • [Video](https://www.youtube.com/watch?v=qmCLBjyPwVk)
320
+ *
321
+ * @param values - the entire form values to be reset
322
+ * @param keepStateOptions - keep form state options
323
+ *
324
+ * @example
325
+ * ```tsx
326
+ * useEffect(() => {
327
+ * // reset the entire form after component mount or form defaultValues is ready
328
+ * reset({
329
+ * fieldA: "test"
330
+ * fieldB: "test"
331
+ * });
332
+ * }, [reset])
333
+ *
334
+ * // reset by combine with existing form values
335
+ * reset({
336
+ * ...getValues(),
337
+ * fieldB: "test"
338
+ *});
339
+ *
340
+ * // reset and keep form state
341
+ * reset({
342
+ * ...getValues(),
343
+ *}, {
344
+ * keepErrors: true,
345
+ * keepDirty: true
346
+ *});
347
+ * ```
348
+ */
349
+ resetForm;
350
+ abortController;
351
+ /**
352
+ * Original react-hook-form form
353
+ */
354
+ originalForm;
355
+ _observableStruct;
356
+ /**
357
+ * The same as setValue, but will trigger validation if form was submitted, also marks this field as dirty
358
+ * It should work the same as field.onChange from react-hook-form's Controller
359
+ *
360
+ * @param name - the path name to the form field value.
361
+ * @param value - field value
362
+ * @param options - should validate or update form state
363
+ *
364
+ * @example
365
+ * ```tsx
366
+ * // Update a single field
367
+ * changeField('name', 'value');
368
+ * ->
369
+ * setValue('name', 'value', { shouldDirty: true });
370
+ *
371
+ * ** form submitted **
372
+ *
373
+ * changeField('name', 'value');
374
+ * ->
375
+ * setValue('name', 'value', { shouldDirty: true, shouldValidate: true });
376
+ * ```
377
+ */
378
+ changeField = (name, value, options) => {
379
+ this.setValue(name, value, {
380
+ shouldDirty: true,
381
+ shouldValidate: this.isSubmitted,
382
+ ...options
383
+ });
384
+ };
385
+ /**
386
+ * Method to manually submit form.
387
+ * Used to attach this method to <form /> element
388
+ *
389
+ * @example
390
+ *
391
+ * <form onSubmit={form.submit} />
392
+ */
393
+ submit(e) {
394
+ return new Promise((resolve, reject) => {
395
+ if (this.originalForm) {
396
+ this.originalForm.handleSubmit(
397
+ async (data, event) => {
398
+ await this.config.onSubmit?.(data, event);
399
+ resolve(data);
400
+ },
401
+ async (errors, event) => {
402
+ await this.config.onSubmitFailed?.(errors, event);
403
+ reject(errors);
404
+ }
405
+ )(e);
406
+ } else {
407
+ const emptyData = this.values ?? {};
408
+ const result = this.config.onSubmit?.(emptyData);
409
+ if (result instanceof Promise) {
410
+ return result.then(() => resolve(emptyData));
411
+ } else {
412
+ return Promise.resolve(emptyData);
413
+ }
414
+ }
415
+ });
416
+ }
417
+ /**
418
+ * Method to manually reset all form.
419
+ * Used to attach this method to <form /> element
420
+ *
421
+ * @example
422
+ *
423
+ * <form onReset={form.reset} />
424
+ */
425
+ reset(e) {
426
+ this.resetForm();
427
+ this.config.onReset?.(e);
428
+ }
429
+ updateFormState({
430
+ values,
431
+ errors,
432
+ dirtyFields,
433
+ validatingFields,
434
+ touchedFields,
435
+ ...simpleProperties
436
+ }) {
437
+ Object.entries(simpleProperties).forEach(([key, value]) => {
438
+ if (value != null) {
439
+ this[key] = value;
440
+ }
441
+ });
442
+ this._observableStruct.set({
443
+ dirtyFields,
444
+ errors,
445
+ touchedFields,
446
+ validatingFields,
447
+ values
448
+ });
449
+ }
450
+ lastTimeoutId;
451
+ stopScheduledFormStateUpdate = () => {
452
+ if (this.lastTimeoutId !== void 0) {
453
+ clearTimeout(this.lastTimeoutId);
454
+ this.lastTimeoutId = void 0;
455
+ }
456
+ };
457
+ scheduleUpdateFormState = (rawFormState) => {
458
+ this.stopScheduledFormStateUpdate();
459
+ this.lastTimeoutId = setTimeout(() => {
460
+ this.updateFormState(rawFormState);
461
+ this.lastTimeoutId = void 0;
462
+ }, this.config.lazyUpdatesTimer ?? 0);
463
+ };
464
+ destroy() {
465
+ this.abortController.abort();
466
+ this.stopScheduledFormStateUpdate();
467
+ }
468
+ }
469
+ class MobxForm extends Form {
470
+ }
471
+ export {
472
+ Controller,
473
+ Form,
474
+ MobxForm
475
+ };
476
+ //# sourceMappingURL=index.js.map
package/index.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sources":["../src/components/controller.tsx","../src/mobx-form/mobx-form.ts"],"sourcesContent":["import { Observer } from 'mobx-react-lite';\nimport { Controller as LibController } from 'react-hook-form';\n\nexport const Controller = ((props: any) => (\n <LibController\n {...props}\n render={(renderProps) => (\n <Observer>{() => props.render(renderProps)}</Observer>\n )}\n />\n)) as unknown as typeof LibController;\n","import { LinkedAbortController } from 'linked-abort-controller';\nimport {\n action,\n isObservableObject,\n makeObservable,\n observable,\n toJS,\n} from 'mobx';\nimport type { BaseSyntheticEvent } from 'react';\nimport {\n type Control,\n createFormControl,\n type DeepMap,\n type DeepPartial,\n type DefaultValues,\n type FieldErrors,\n type FieldPath,\n type FieldPathValue,\n type FieldValues,\n type FormState,\n get,\n type SetValueConfig,\n set,\n type UseFormClearErrors,\n type UseFormRegister,\n type UseFormReset,\n type UseFormResetField,\n type UseFormSetError,\n type UseFormSetFocus,\n type UseFormSetValue,\n type UseFormTrigger,\n type UseFormUnregister,\n} from 'react-hook-form';\nimport { DeepObservableStruct } from 'yummies/mobx';\nimport type { FormParams } from './mobx-form.types.js';\n\ntype FormFullState<TFieldValues extends FieldValues> =\n FormState<TFieldValues> & {\n values: TFieldValues;\n };\n\nexport class Form<\n TFieldValues extends FieldValues = FieldValues,\n TContext = any,\n TTransformedValues = TFieldValues,\n> implements FormFullState<TFieldValues>\n{\n values: TFieldValues;\n isDirty: boolean = false;\n isLoading: boolean = false;\n isSubmitted: boolean = false;\n isSubmitSuccessful: boolean = false;\n isSubmitting: boolean = false;\n isValidating: boolean = false;\n isValid: boolean = false;\n disabled: boolean = false;\n submitCount: number = 0;\n /**\n * If you want to change this property\n * Use {resetForm} method\n */\n defaultValues!: Readonly<DefaultValues<TFieldValues>>;\n dirtyFields: Partial<Readonly<DeepMap<DeepPartial<TFieldValues>, boolean>>>;\n touchedFields: Partial<Readonly<DeepMap<DeepPartial<TFieldValues>, boolean>>>;\n validatingFields: Partial<\n Readonly<DeepMap<DeepPartial<TFieldValues>, boolean>>\n >;\n errors: FieldErrors<TFieldValues>;\n isReady: boolean = false;\n\n /**\n * Set an error for the field. When set an error which is not associated to a field then manual `clearErrors` invoke is required.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/seterror) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-seterror-nfxxu) • [Video](https://www.youtube.com/watch?v=raMqvE0YyIY)\n *\n * @param name - the path name to the form field value.\n * @param error - an error object which contains type and optional message\n * @param options - whether or not to focus on the field\n *\n * @example\n * ```tsx\n * // when the error is not associated with any fields, `clearError` will need to invoke to clear the error\n * const onSubmit = () => setError(\"serverError\", { type: \"server\", message: \"Error occurred\"})\n *\n * <button onClick={() => setError(\"name\", { type: \"min\" })} />\n *\n * // focus on the input after setting the error\n * <button onClick={() => setError(\"name\", { type: \"max\" }, { shouldFocus: true })} />\n * ```\n */\n setError: UseFormSetError<TFieldValues>;\n\n /**\n * Clear the entire form errors.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/clearerrors) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-clearerrors-w3ymx)\n *\n * @param name - the path name to the form field value.\n *\n * @example\n * Clear all errors\n * ```tsx\n * clearErrors(); // clear the entire form error\n * clearErrors([\"name\", \"name1\"]) // clear an array of fields' error\n * clearErrors(\"name2\"); // clear a single field error\n * ```\n */\n clearErrors: UseFormClearErrors<TFieldValues>;\n\n /**\n * Trigger field or form validation\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/trigger) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-triggervalidation-forked-xs7hl) • [Video](https://www.youtube.com/watch?v=-bcyJCDjksE)\n *\n * @param name - provide empty argument will trigger the entire form validation, an array of field names will validate an array of fields, and a single field name will only trigger that field's validation.\n * @param options - should focus on the error field\n *\n * @returns validation result\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * trigger();\n * }, [trigger])\n *\n * <button onClick={async () => {\n * const result = await trigger(); // result will be a boolean value\n * }}>\n * trigger\n * </button>\n * ```\n */\n trigger: UseFormTrigger<TFieldValues>;\n\n /**\n * Reset a field state and reference.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/resetfield) • [Demo](https://codesandbox.io/s/priceless-firefly-d0kuv) • [Video](https://www.youtube.com/watch?v=IdLFcNaEFEo)\n *\n * @param name - the path name to the form field value.\n * @param options - keep form state options\n *\n * @example\n * ```tsx\n * <input {...register(\"firstName\", { required: true })} />\n * <button type=\"button\" onClick={() => resetField(\"firstName\"))}>Reset</button>\n * ```\n */\n resetField: UseFormResetField<TFieldValues>;\n\n /**\n * Unregister a field reference and remove its value.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/unregister) • [Demo](https://codesandbox.io/s/react-hook-form-unregister-4k2ey) • [Video](https://www.youtube.com/watch?v=TM99g_NW5Gk&feature=emb_imp_woyt)\n *\n * @param name - the path name to the form field value.\n * @param options - keep form state options\n *\n * @example\n * ```tsx\n * register(\"name\", { required: true })\n *\n * <button onClick={() => unregister(\"name\")} />\n * // there are various keep options to retain formState\n * <button onClick={() => unregister(\"name\", { keepErrors: true })} />\n * ```\n */\n unregister: UseFormUnregister<TFieldValues>;\n\n /**\n * Form control\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/control)\n *\n */\n control: Control<TFieldValues, TContext, TTransformedValues>;\n\n /**\n * Register field into hook form with or without the actual DOM ref. You can invoke register anywhere in the component including at `useEffect`.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/register) • [Demo](https://codesandbox.io/s/react-hook-form-register-ts-ip2j3) • [Video](https://www.youtube.com/watch?v=JFIpCoajYkA)\n *\n * @param name - the path name to the form field value, name is required and unique\n * @param options - register options include validation, disabled, unregister, value as and dependent validation\n *\n * @returns onChange, onBlur, name, ref, and native contribute attribute if browser validation is enabled.\n *\n * @example\n * ```tsx\n * // Register HTML native input\n * <input {...register(\"input\")} />\n * <select {...register(\"select\")} />\n *\n * // Register options\n * <textarea {...register(\"textarea\", { required: \"This is required.\", maxLength: 20 })} />\n * <input type=\"number\" {...register(\"name2\", { valueAsNumber: true })} />\n * <input {...register(\"name3\", { deps: [\"name2\"] })} />\n *\n * // Register custom field at useEffect\n * useEffect(() => {\n * register(\"name4\");\n * register(\"name5\", { value: \"hiddenValue\" });\n * }, [register])\n *\n * // Register without ref\n * const { onChange, onBlur, name } = register(\"name6\")\n * <input onChange={onChange} onBlur={onBlur} name={name} />\n * ```\n */\n register: UseFormRegister<TFieldValues>;\n\n /**\n * Set focus on a registered field. You can start to invoke this method after all fields are mounted to the DOM.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/setfocus) • [Demo](https://codesandbox.io/s/setfocus-rolus)\n *\n * @param name - the path name to the form field value.\n * @param options - input focus behavior options\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * setFocus(\"name\");\n * }, [setFocus])\n * // shouldSelect allows to select input's content on focus\n * <button onClick={() => setFocus(\"name\", { shouldSelect: true })}>Focus</button>\n * ```\n */\n setFocus: UseFormSetFocus<TFieldValues>;\n\n /**\n * Set a single field value, or a group of fields value.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/setvalue) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-setvalue-8z9hx) • [Video](https://www.youtube.com/watch?v=qpv51sCH3fI)\n *\n * @param name - the path name to the form field value.\n * @param value - field value\n * @param options - should validate or update form state\n *\n * @example\n * ```tsx\n * // Update a single field\n * setValue('name', 'value', {\n * shouldValidate: true, // trigger validation\n * shouldTouch: true, // update touched fields form state\n * shouldDirty: true, // update dirty and dirty fields form state\n * });\n *\n * // Update a group fields\n * setValue('root', {\n * a: 'test', // setValue('root.a', 'data')\n * b: 'test1', // setValue('root.b', 'data')\n * });\n *\n * // Update a nested object field\n * setValue('select', { label: 'test', value: 'Test' });\n * ```\n */\n setValue: UseFormSetValue<TFieldValues>;\n\n /**\n * Reset at the entire form state.\n *\n * @remarks\n * [API](https://react-hook-form.com/docs/useform/reset) • [Demo](https://codesandbox.io/s/react-hook-form-reset-v7-ts-pu901) • [Video](https://www.youtube.com/watch?v=qmCLBjyPwVk)\n *\n * @param values - the entire form values to be reset\n * @param keepStateOptions - keep form state options\n *\n * @example\n * ```tsx\n * useEffect(() => {\n * // reset the entire form after component mount or form defaultValues is ready\n * reset({\n * fieldA: \"test\"\n * fieldB: \"test\"\n * });\n * }, [reset])\n *\n * // reset by combine with existing form values\n * reset({\n * ...getValues(),\n * fieldB: \"test\"\n *});\n *\n * // reset and keep form state\n * reset({\n * ...getValues(),\n *}, {\n * keepErrors: true,\n * keepDirty: true\n *});\n * ```\n */\n resetForm: UseFormReset<TFieldValues>;\n\n protected abortController: AbortController;\n\n /**\n * Original react-hook-form form\n */\n originalForm: ReturnType<\n typeof createFormControl<TFieldValues, TContext, TTransformedValues>\n >;\n\n private _observableStruct: DeepObservableStruct<\n Pick<\n FormFullState<TFieldValues>,\n 'dirtyFields' | 'errors' | 'touchedFields' | 'validatingFields' | 'values'\n >\n >;\n\n constructor(\n private config: FormParams<TFieldValues, TContext, TTransformedValues>,\n ) {\n this.abortController = new LinkedAbortController(config.abortSignal);\n\n this.originalForm = createFormControl<\n TFieldValues,\n TContext,\n TTransformedValues\n >({\n ...config,\n defaultValues: {\n ...config.defaultValues,\n } as DefaultValues<TFieldValues>,\n });\n\n const defaultValues = config.defaultValues\n ? { ...config.defaultValues }\n : ({} as any);\n\n this.setError = this.originalForm.setError;\n this.clearErrors = this.originalForm.clearErrors;\n this.trigger = this.originalForm.trigger;\n this.resetField = action((...args) => {\n set(this.values, args[0], get(this.defaultValues, args[0]));\n return this.originalForm.resetField(...args);\n });\n this.unregister = this.originalForm.unregister;\n this.control = this.originalForm.control;\n this.register = this.originalForm.register;\n this.setFocus = this.originalForm.setFocus;\n this.setValue = action((...args) => {\n set(this.values, args[0], args[1]);\n return this.originalForm.setValue(...args);\n });\n this.resetForm = action((...args) => {\n let defaultValues = args[0] ?? this.defaultValues;\n\n if (isObservableObject(defaultValues)) {\n defaultValues = toJS(defaultValues);\n } else {\n defaultValues = structuredClone(defaultValues);\n }\n\n // @ts-expect-error\n this.values = defaultValues;\n return this.originalForm.reset(...args);\n });\n\n this._observableStruct = new DeepObservableStruct({\n values: this.originalForm.getValues(),\n errors: {},\n dirtyFields: {},\n touchedFields: {},\n validatingFields: {},\n });\n\n this.values = this._observableStruct.data.values;\n this.errors = this._observableStruct.data.errors;\n this.validatingFields = this._observableStruct.data.validatingFields;\n this.dirtyFields = this._observableStruct.data.dirtyFields;\n this.touchedFields = this._observableStruct.data.touchedFields;\n\n Object.assign(this, {\n defaultValues,\n });\n\n const subscription = this.originalForm.subscribe({\n formState: {\n values: true,\n errors: true,\n isValid: true,\n isDirty: true,\n isValidating: true,\n dirtyFields: true,\n touchedFields: true,\n validatingFields: true,\n },\n callback: (rawFormState) => {\n if (this.config.lazyUpdates === false) {\n this.updateFormState(rawFormState);\n } else {\n this.scheduleUpdateFormState(rawFormState);\n }\n },\n });\n\n observable.ref(this, 'isDirty');\n observable.ref(this, 'isLoading');\n observable.ref(this, 'isSubmitted');\n observable.ref(this, 'isSubmitSuccessful');\n observable.ref(this, 'isSubmitting');\n observable.ref(this, 'isValidating');\n observable.ref(this, 'isValid');\n observable.ref(this, 'disabled');\n observable.ref(this, 'submitCount');\n observable.ref(this, 'isReady');\n observable.deep(this, 'defaultValues');\n action(this, 'updateFormState');\n\n observable.ref(this, 'originalForm');\n action.bound(this, 'submit');\n action.bound(this, 'reset');\n\n makeObservable(this);\n\n this.abortController.signal.addEventListener('abort', () => {\n subscription();\n // @ts-expect-error\n this.originalForm = null;\n });\n }\n\n /**\n * The same as setValue, but will trigger validation if form was submitted, also marks this field as dirty\n * It should work the same as field.onChange from react-hook-form's Controller\n *\n * @param name - the path name to the form field value.\n * @param value - field value\n * @param options - should validate or update form state\n *\n * @example\n * ```tsx\n * // Update a single field\n * changeField('name', 'value');\n * ->\n * setValue('name', 'value', { shouldDirty: true });\n *\n * ** form submitted **\n *\n * changeField('name', 'value');\n * ->\n * setValue('name', 'value', { shouldDirty: true, shouldValidate: true });\n * ```\n */\n changeField = <\n TFieldName extends FieldPath<TFieldValues> = FieldPath<TFieldValues>,\n >(\n name: TFieldName,\n value: FieldPathValue<TFieldValues, TFieldName> | undefined,\n options?: SetValueConfig,\n ) => {\n this.setValue(name, value as any, {\n shouldDirty: true,\n shouldValidate: this.isSubmitted,\n ...options,\n });\n };\n\n /**\n * Method to manually submit form.\n * Used to attach this method to <form /> element\n *\n * @example\n *\n * <form onSubmit={form.submit} />\n */\n submit(e?: BaseSyntheticEvent) {\n return new Promise<TTransformedValues>((resolve, reject) => {\n if (this.originalForm) {\n this.originalForm.handleSubmit(\n async (data, event) => {\n await this.config.onSubmit?.(data, event);\n resolve(data);\n },\n async (errors, event) => {\n await this.config.onSubmitFailed?.(errors, event);\n reject(errors);\n },\n )(e);\n } else {\n const emptyData = (this.values ?? {}) as unknown as TTransformedValues;\n const result = this.config.onSubmit?.(emptyData);\n if (result instanceof Promise) {\n return result.then(() => resolve(emptyData));\n } else {\n return Promise.resolve(emptyData);\n }\n }\n });\n }\n\n /**\n * Method to manually reset all form.\n * Used to attach this method to <form /> element\n *\n * @example\n *\n * <form onReset={form.reset} />\n */\n reset(e?: BaseSyntheticEvent) {\n this.resetForm();\n this.config.onReset?.(e);\n }\n\n private updateFormState({\n values,\n errors,\n dirtyFields,\n validatingFields,\n touchedFields,\n ...simpleProperties\n }: Partial<FormFullState<TFieldValues>>) {\n Object.entries(simpleProperties).forEach(([key, value]) => {\n if (value != null) {\n // @ts-expect-error\n this[key] = value;\n }\n });\n\n this._observableStruct.set({\n dirtyFields,\n errors,\n touchedFields,\n validatingFields,\n values,\n });\n }\n\n protected lastTimeoutId: ReturnType<typeof setTimeout> | undefined;\n\n private stopScheduledFormStateUpdate = () => {\n if (this.lastTimeoutId !== undefined) {\n clearTimeout(this.lastTimeoutId);\n this.lastTimeoutId = undefined;\n }\n };\n\n private scheduleUpdateFormState = (\n rawFormState: Partial<FormFullState<TFieldValues>>,\n ) => {\n this.stopScheduledFormStateUpdate();\n this.lastTimeoutId = setTimeout(() => {\n this.updateFormState(rawFormState);\n this.lastTimeoutId = undefined;\n }, this.config.lazyUpdatesTimer ?? 0);\n };\n\n destroy(): void {\n this.abortController.abort();\n this.stopScheduledFormStateUpdate();\n }\n}\n\n/**\n * @deprecated ⚠️ use `Form`. This export will be removed in next major release\n */\nexport class MobxForm<\n TFieldValues extends FieldValues = FieldValues,\n TContext = any,\n TTransformedValues = TFieldValues,\n> extends Form<TFieldValues, TContext, TTransformedValues> {}\n"],"names":["LibController","defaultValues"],"mappings":"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"}
@@ -1,6 +1,6 @@
1
- import type { BaseSyntheticEvent } from 'react';
2
- import { type Control, createFormControl, type DeepMap, type DeepPartial, type DefaultValues, type FieldErrors, type FieldPath, type FieldPathValue, type FieldValues, type FormState, type SetValueConfig, type UseFormClearErrors, type UseFormRegister, type UseFormReset, type UseFormResetField, type UseFormSetError, type UseFormSetFocus, type UseFormSetValue, type UseFormTrigger, type UseFormUnregister } from 'react-hook-form';
3
- import type { FormParams } from './mobx-form.types.js';
1
+ import { BaseSyntheticEvent } from 'react';
2
+ import { Control, createFormControl, DeepMap, DeepPartial, DefaultValues, FieldErrors, FieldPath, FieldPathValue, FieldValues, FormState, SetValueConfig, UseFormClearErrors, UseFormRegister, UseFormReset, UseFormResetField, UseFormSetError, UseFormSetFocus, UseFormSetValue, UseFormTrigger, UseFormUnregister } from 'react-hook-form';
3
+ import { FormParams } from './mobx-form.types.js';
4
4
  type FormFullState<TFieldValues extends FieldValues> = FormState<TFieldValues> & {
5
5
  values: TFieldValues;
6
6
  };
@@ -300,7 +300,7 @@ export declare class Form<TFieldValues extends FieldValues = FieldValues, TConte
300
300
  */
301
301
  reset(e?: BaseSyntheticEvent): void;
302
302
  private updateFormState;
303
- protected lastTimeoutId: number | undefined;
303
+ protected lastTimeoutId: ReturnType<typeof setTimeout> | undefined;
304
304
  private stopScheduledFormStateUpdate;
305
305
  private scheduleUpdateFormState;
306
306
  destroy(): void;
@@ -1 +1 @@
1
- {"version":3,"file":"mobx-form.d.ts","sourceRoot":"","sources":["../../src/mobx-form/mobx-form.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"mobx-form.d.ts","sourceRoot":"","sources":["../../src/mobx-form/mobx-form.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
- import type { DeepPartial, FieldValues, SubmitErrorHandler, SubmitHandler, UseFormProps } from 'react-hook-form';
2
- import type { Form } from './mobx-form.js';
1
+ import { DeepPartial, FieldValues, SubmitErrorHandler, SubmitHandler, UseFormProps } from 'react-hook-form';
2
+ import { Form } from './mobx-form.js';
3
3
  export type AnyForm = Form<any, any, any>;
4
4
  /**
5
5
  * @deprecated ⚠️ use `AnyForm`. This export will be removed in next major release
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "mobx-react-hook-form",
3
- "version": "5.3.0",
3
+ "version": "5.5.0",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "keywords": [],
@@ -22,66 +22,51 @@
22
22
  },
23
23
  "dependencies": {
24
24
  "@types/react": "^18.0.0 || ^19.0.0",
25
- "disposer-util": "^2.0.0",
26
25
  "linked-abort-controller": "^1.1.0",
27
- "yummies": "^5.0.0"
26
+ "yummies": "^6.0.0"
28
27
  },
29
28
  "devDependencies": {
30
- "@biomejs/biome": "2.2.2",
29
+ "@biomejs/biome": "2.2.6",
30
+ "@changesets/changelog-github": "^0.5.1",
31
+ "@changesets/cli": "^2.29.5",
31
32
  "@vitejs/plugin-react-swc": "^3.9.0",
32
33
  "@vitest/coverage-istanbul": "^3.1.2",
33
34
  "commitfmt": "^1.0.4",
34
- "js2me-biome-config": "^1.0.4",
35
+ "js2me-biome-config": "^1.0.6",
35
36
  "js2me-exports-post-build-script": "^3.0.2",
36
37
  "jsdom": "^26.1.0",
37
38
  "lefthook": "^1.11.13",
38
39
  "nodemon": "^3.1.10",
39
40
  "rimraf": "^6.0.1",
41
+ "sborshik": "^1.8.2",
40
42
  "typescript": "^5.8.3",
43
+ "vite": "^7.1.12",
41
44
  "vitest": "^3.1.2"
42
45
  },
43
46
  "exports": {
44
- "./components/controller": {
45
- "import": "./components/controller.js",
46
- "default": "./components/controller.js",
47
- "types": "./components/controller.d.ts"
48
- },
49
- "./components": {
50
- "import": "./components/index.js",
51
- "default": "./components/index.js",
52
- "types": "./components/index.d.ts"
53
- },
47
+ "./LICENSE": "./LICENSE",
48
+ "./README": "./README.md",
49
+ "./package": "./package.json",
50
+ "./package.json": "./package.json",
54
51
  ".": {
55
52
  "import": "./index.js",
56
53
  "default": "./index.js",
57
- "types": "./index.d.ts"
58
- },
59
- "./mobx-form": {
60
- "import": "./mobx-form/index.js",
61
- "default": "./mobx-form/index.js",
62
- "types": "./mobx-form/index.d.ts"
63
- },
64
- "./mobx-form/mobx-form": {
65
- "import": "./mobx-form/mobx-form.js",
66
- "default": "./mobx-form/mobx-form.js",
67
- "types": "./mobx-form/mobx-form.d.ts"
68
- },
69
- "./package.json": "./package.json"
54
+ "types": "./index.d.ts",
55
+ "require": "./index.cjs"
56
+ }
70
57
  },
71
58
  "files": [
72
59
  "*"
73
60
  ],
74
- "main": "./index.js",
75
- "typings": "./index.d.ts",
76
61
  "scripts": {
77
62
  "clean": "rimraf dist",
78
63
  "lint:check": "pnpm exec biome check --write --no-errors-on-unmatched --files-ignore-unknown=true",
79
64
  "ts:check": "tsc --noEmit",
80
65
  "check": "npm run lint:check && npm run ts:check",
81
66
  "prebuild": "npm run clean && npm run check",
82
- "build": "tsc && node ./post-build.mjs",
83
- "build:watch": "npm run build && nodemon --delay 0.5 --watch src --ext ts,tsx --exec \"tsc && node ./post-build.mjs\"",
84
- "pub": "PUBLISH=true pnpm run build",
67
+ "build:watch": "pnpm build && nodemon --delay 0.5 --watch src --ext ts,tsx --exec \"pnpm build\"",
68
+ "build": "vite build",
69
+ "pub": "pnpm build && sborshik publish --useDistDir",
85
70
  "pub:next": "PUBLISH=true PUBLISH_TAG=next PUBLISH_FORCE=true pnpm run build",
86
71
  "pub:patch": "PUBLISH=true PUBLISH_VERSION=patch pnpm run build",
87
72
  "pub:minor": "PUBLISH=true PUBLISH_VERSION=minor pnpm run build",
@@ -1,4 +0,0 @@
1
- import { jsx as _jsx } from "react/jsx-runtime";
2
- import { Observer } from 'mobx-react-lite';
3
- import { Controller as LibController } from 'react-hook-form';
4
- export const Controller = ((props) => (_jsx(LibController, { ...props, render: (renderProps) => (_jsx(Observer, { children: () => props.render(renderProps) })) })));
@@ -1 +0,0 @@
1
- export * from './controller.js';
@@ -1,2 +0,0 @@
1
- export * from './mobx-form.js';
2
- export * from './mobx-form.types.js';
@@ -1,464 +0,0 @@
1
- import { LinkedAbortController } from 'linked-abort-controller';
2
- import { action, isObservableObject, makeObservable, observable, toJS, } from 'mobx';
3
- import { createFormControl, get, set, } from 'react-hook-form';
4
- import { DeepObservableStruct } from 'yummies/mobx';
5
- export class Form {
6
- config;
7
- values;
8
- isDirty = false;
9
- isLoading = false;
10
- isSubmitted = false;
11
- isSubmitSuccessful = false;
12
- isSubmitting = false;
13
- isValidating = false;
14
- isValid = false;
15
- disabled = false;
16
- submitCount = 0;
17
- /**
18
- * If you want to change this property
19
- * Use {resetForm} method
20
- */
21
- defaultValues;
22
- dirtyFields;
23
- touchedFields;
24
- validatingFields;
25
- errors;
26
- isReady = false;
27
- /**
28
- * Set an error for the field. When set an error which is not associated to a field then manual `clearErrors` invoke is required.
29
- *
30
- * @remarks
31
- * [API](https://react-hook-form.com/docs/useform/seterror) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-seterror-nfxxu) • [Video](https://www.youtube.com/watch?v=raMqvE0YyIY)
32
- *
33
- * @param name - the path name to the form field value.
34
- * @param error - an error object which contains type and optional message
35
- * @param options - whether or not to focus on the field
36
- *
37
- * @example
38
- * ```tsx
39
- * // when the error is not associated with any fields, `clearError` will need to invoke to clear the error
40
- * const onSubmit = () => setError("serverError", { type: "server", message: "Error occurred"})
41
- *
42
- * <button onClick={() => setError("name", { type: "min" })} />
43
- *
44
- * // focus on the input after setting the error
45
- * <button onClick={() => setError("name", { type: "max" }, { shouldFocus: true })} />
46
- * ```
47
- */
48
- setError;
49
- /**
50
- * Clear the entire form errors.
51
- *
52
- * @remarks
53
- * [API](https://react-hook-form.com/docs/useform/clearerrors) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-clearerrors-w3ymx)
54
- *
55
- * @param name - the path name to the form field value.
56
- *
57
- * @example
58
- * Clear all errors
59
- * ```tsx
60
- * clearErrors(); // clear the entire form error
61
- * clearErrors(["name", "name1"]) // clear an array of fields' error
62
- * clearErrors("name2"); // clear a single field error
63
- * ```
64
- */
65
- clearErrors;
66
- /**
67
- * Trigger field or form validation
68
- *
69
- * @remarks
70
- * [API](https://react-hook-form.com/docs/useform/trigger) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-triggervalidation-forked-xs7hl) • [Video](https://www.youtube.com/watch?v=-bcyJCDjksE)
71
- *
72
- * @param name - provide empty argument will trigger the entire form validation, an array of field names will validate an array of fields, and a single field name will only trigger that field's validation.
73
- * @param options - should focus on the error field
74
- *
75
- * @returns validation result
76
- *
77
- * @example
78
- * ```tsx
79
- * useEffect(() => {
80
- * trigger();
81
- * }, [trigger])
82
- *
83
- * <button onClick={async () => {
84
- * const result = await trigger(); // result will be a boolean value
85
- * }}>
86
- * trigger
87
- * </button>
88
- * ```
89
- */
90
- trigger;
91
- /**
92
- * Reset a field state and reference.
93
- *
94
- * @remarks
95
- * [API](https://react-hook-form.com/docs/useform/resetfield) • [Demo](https://codesandbox.io/s/priceless-firefly-d0kuv) • [Video](https://www.youtube.com/watch?v=IdLFcNaEFEo)
96
- *
97
- * @param name - the path name to the form field value.
98
- * @param options - keep form state options
99
- *
100
- * @example
101
- * ```tsx
102
- * <input {...register("firstName", { required: true })} />
103
- * <button type="button" onClick={() => resetField("firstName"))}>Reset</button>
104
- * ```
105
- */
106
- resetField;
107
- /**
108
- * Unregister a field reference and remove its value.
109
- *
110
- * @remarks
111
- * [API](https://react-hook-form.com/docs/useform/unregister) • [Demo](https://codesandbox.io/s/react-hook-form-unregister-4k2ey) • [Video](https://www.youtube.com/watch?v=TM99g_NW5Gk&feature=emb_imp_woyt)
112
- *
113
- * @param name - the path name to the form field value.
114
- * @param options - keep form state options
115
- *
116
- * @example
117
- * ```tsx
118
- * register("name", { required: true })
119
- *
120
- * <button onClick={() => unregister("name")} />
121
- * // there are various keep options to retain formState
122
- * <button onClick={() => unregister("name", { keepErrors: true })} />
123
- * ```
124
- */
125
- unregister;
126
- /**
127
- * Form control
128
- *
129
- * @remarks
130
- * [API](https://react-hook-form.com/docs/useform/control)
131
- *
132
- */
133
- control;
134
- /**
135
- * Register field into hook form with or without the actual DOM ref. You can invoke register anywhere in the component including at `useEffect`.
136
- *
137
- * @remarks
138
- * [API](https://react-hook-form.com/docs/useform/register) • [Demo](https://codesandbox.io/s/react-hook-form-register-ts-ip2j3) • [Video](https://www.youtube.com/watch?v=JFIpCoajYkA)
139
- *
140
- * @param name - the path name to the form field value, name is required and unique
141
- * @param options - register options include validation, disabled, unregister, value as and dependent validation
142
- *
143
- * @returns onChange, onBlur, name, ref, and native contribute attribute if browser validation is enabled.
144
- *
145
- * @example
146
- * ```tsx
147
- * // Register HTML native input
148
- * <input {...register("input")} />
149
- * <select {...register("select")} />
150
- *
151
- * // Register options
152
- * <textarea {...register("textarea", { required: "This is required.", maxLength: 20 })} />
153
- * <input type="number" {...register("name2", { valueAsNumber: true })} />
154
- * <input {...register("name3", { deps: ["name2"] })} />
155
- *
156
- * // Register custom field at useEffect
157
- * useEffect(() => {
158
- * register("name4");
159
- * register("name5", { value: "hiddenValue" });
160
- * }, [register])
161
- *
162
- * // Register without ref
163
- * const { onChange, onBlur, name } = register("name6")
164
- * <input onChange={onChange} onBlur={onBlur} name={name} />
165
- * ```
166
- */
167
- register;
168
- /**
169
- * Set focus on a registered field. You can start to invoke this method after all fields are mounted to the DOM.
170
- *
171
- * @remarks
172
- * [API](https://react-hook-form.com/docs/useform/setfocus) • [Demo](https://codesandbox.io/s/setfocus-rolus)
173
- *
174
- * @param name - the path name to the form field value.
175
- * @param options - input focus behavior options
176
- *
177
- * @example
178
- * ```tsx
179
- * useEffect(() => {
180
- * setFocus("name");
181
- * }, [setFocus])
182
- * // shouldSelect allows to select input's content on focus
183
- * <button onClick={() => setFocus("name", { shouldSelect: true })}>Focus</button>
184
- * ```
185
- */
186
- setFocus;
187
- /**
188
- * Set a single field value, or a group of fields value.
189
- *
190
- * @remarks
191
- * [API](https://react-hook-form.com/docs/useform/setvalue) • [Demo](https://codesandbox.io/s/react-hook-form-v7-ts-setvalue-8z9hx) • [Video](https://www.youtube.com/watch?v=qpv51sCH3fI)
192
- *
193
- * @param name - the path name to the form field value.
194
- * @param value - field value
195
- * @param options - should validate or update form state
196
- *
197
- * @example
198
- * ```tsx
199
- * // Update a single field
200
- * setValue('name', 'value', {
201
- * shouldValidate: true, // trigger validation
202
- * shouldTouch: true, // update touched fields form state
203
- * shouldDirty: true, // update dirty and dirty fields form state
204
- * });
205
- *
206
- * // Update a group fields
207
- * setValue('root', {
208
- * a: 'test', // setValue('root.a', 'data')
209
- * b: 'test1', // setValue('root.b', 'data')
210
- * });
211
- *
212
- * // Update a nested object field
213
- * setValue('select', { label: 'test', value: 'Test' });
214
- * ```
215
- */
216
- setValue;
217
- /**
218
- * Reset at the entire form state.
219
- *
220
- * @remarks
221
- * [API](https://react-hook-form.com/docs/useform/reset) • [Demo](https://codesandbox.io/s/react-hook-form-reset-v7-ts-pu901) • [Video](https://www.youtube.com/watch?v=qmCLBjyPwVk)
222
- *
223
- * @param values - the entire form values to be reset
224
- * @param keepStateOptions - keep form state options
225
- *
226
- * @example
227
- * ```tsx
228
- * useEffect(() => {
229
- * // reset the entire form after component mount or form defaultValues is ready
230
- * reset({
231
- * fieldA: "test"
232
- * fieldB: "test"
233
- * });
234
- * }, [reset])
235
- *
236
- * // reset by combine with existing form values
237
- * reset({
238
- * ...getValues(),
239
- * fieldB: "test"
240
- *});
241
- *
242
- * // reset and keep form state
243
- * reset({
244
- * ...getValues(),
245
- *}, {
246
- * keepErrors: true,
247
- * keepDirty: true
248
- *});
249
- * ```
250
- */
251
- resetForm;
252
- abortController;
253
- /**
254
- * Original react-hook-form form
255
- */
256
- originalForm;
257
- _observableStruct;
258
- constructor(config) {
259
- this.config = config;
260
- this.abortController = new LinkedAbortController(config.abortSignal);
261
- this.originalForm = createFormControl({
262
- ...config,
263
- defaultValues: {
264
- ...config.defaultValues,
265
- },
266
- });
267
- const defaultValues = config.defaultValues
268
- ? { ...config.defaultValues }
269
- : {};
270
- this.setError = this.originalForm.setError;
271
- this.clearErrors = this.originalForm.clearErrors;
272
- this.trigger = this.originalForm.trigger;
273
- this.resetField = action((...args) => {
274
- set(this.values, args[0], get(this.defaultValues, args[0]));
275
- return this.originalForm.resetField(...args);
276
- });
277
- this.unregister = this.originalForm.unregister;
278
- this.control = this.originalForm.control;
279
- this.register = this.originalForm.register;
280
- this.setFocus = this.originalForm.setFocus;
281
- this.setValue = action((...args) => {
282
- set(this.values, args[0], args[1]);
283
- return this.originalForm.setValue(...args);
284
- });
285
- this.resetForm = action((...args) => {
286
- let defaultValues = args[0] ?? this.defaultValues;
287
- if (isObservableObject(defaultValues)) {
288
- defaultValues = toJS(defaultValues);
289
- }
290
- else {
291
- defaultValues = structuredClone(defaultValues);
292
- }
293
- // @ts-expect-error
294
- this.values = defaultValues;
295
- return this.originalForm.reset(...args);
296
- });
297
- this._observableStruct = new DeepObservableStruct({
298
- values: this.originalForm.getValues(),
299
- errors: {},
300
- dirtyFields: {},
301
- touchedFields: {},
302
- validatingFields: {},
303
- });
304
- this.values = this._observableStruct.data.values;
305
- this.errors = this._observableStruct.data.errors;
306
- this.validatingFields = this._observableStruct.data.validatingFields;
307
- this.dirtyFields = this._observableStruct.data.dirtyFields;
308
- this.touchedFields = this._observableStruct.data.touchedFields;
309
- Object.assign(this, {
310
- defaultValues,
311
- });
312
- const subscription = this.originalForm.subscribe({
313
- formState: {
314
- values: true,
315
- errors: true,
316
- isValid: true,
317
- isDirty: true,
318
- isValidating: true,
319
- dirtyFields: true,
320
- touchedFields: true,
321
- validatingFields: true,
322
- },
323
- callback: (rawFormState) => {
324
- if (this.config.lazyUpdates === false) {
325
- this.updateFormState(rawFormState);
326
- }
327
- else {
328
- this.scheduleUpdateFormState(rawFormState);
329
- }
330
- },
331
- });
332
- observable.ref(this, 'isDirty');
333
- observable.ref(this, 'isLoading');
334
- observable.ref(this, 'isSubmitted');
335
- observable.ref(this, 'isSubmitSuccessful');
336
- observable.ref(this, 'isSubmitting');
337
- observable.ref(this, 'isValidating');
338
- observable.ref(this, 'isValid');
339
- observable.ref(this, 'disabled');
340
- observable.ref(this, 'submitCount');
341
- observable.ref(this, 'isReady');
342
- observable.deep(this, 'defaultValues');
343
- action(this, 'updateFormState');
344
- observable.ref(this, 'originalForm');
345
- action.bound(this, 'submit');
346
- action.bound(this, 'reset');
347
- makeObservable(this);
348
- this.abortController.signal.addEventListener('abort', () => {
349
- subscription();
350
- // @ts-expect-error
351
- this.originalForm = null;
352
- });
353
- }
354
- /**
355
- * The same as setValue, but will trigger validation if form was submitted, also marks this field as dirty
356
- * It should work the same as field.onChange from react-hook-form's Controller
357
- *
358
- * @param name - the path name to the form field value.
359
- * @param value - field value
360
- * @param options - should validate or update form state
361
- *
362
- * @example
363
- * ```tsx
364
- * // Update a single field
365
- * changeField('name', 'value');
366
- * ->
367
- * setValue('name', 'value', { shouldDirty: true });
368
- *
369
- * ** form submitted **
370
- *
371
- * changeField('name', 'value');
372
- * ->
373
- * setValue('name', 'value', { shouldDirty: true, shouldValidate: true });
374
- * ```
375
- */
376
- changeField = (name, value, options) => {
377
- this.setValue(name, value, {
378
- shouldDirty: true,
379
- shouldValidate: this.isSubmitted,
380
- ...options,
381
- });
382
- };
383
- /**
384
- * Method to manually submit form.
385
- * Used to attach this method to <form /> element
386
- *
387
- * @example
388
- *
389
- * <form onSubmit={form.submit} />
390
- */
391
- submit(e) {
392
- return new Promise((resolve, reject) => {
393
- if (this.originalForm) {
394
- this.originalForm.handleSubmit(async (data, event) => {
395
- await this.config.onSubmit?.(data, event);
396
- resolve(data);
397
- }, async (errors, event) => {
398
- await this.config.onSubmitFailed?.(errors, event);
399
- reject(errors);
400
- })(e);
401
- }
402
- else {
403
- const emptyData = (this.values ?? {});
404
- const result = this.config.onSubmit?.(emptyData);
405
- if (result instanceof Promise) {
406
- return result.then(() => resolve(emptyData));
407
- }
408
- else {
409
- return Promise.resolve(emptyData);
410
- }
411
- }
412
- });
413
- }
414
- /**
415
- * Method to manually reset all form.
416
- * Used to attach this method to <form /> element
417
- *
418
- * @example
419
- *
420
- * <form onReset={form.reset} />
421
- */
422
- reset(e) {
423
- this.resetForm();
424
- this.config.onReset?.(e);
425
- }
426
- updateFormState({ values, errors, dirtyFields, validatingFields, touchedFields, ...simpleProperties }) {
427
- Object.entries(simpleProperties).forEach(([key, value]) => {
428
- if (value != null) {
429
- // @ts-expect-error
430
- this[key] = value;
431
- }
432
- });
433
- this._observableStruct.set({
434
- dirtyFields,
435
- errors,
436
- touchedFields,
437
- validatingFields,
438
- values,
439
- });
440
- }
441
- lastTimeoutId;
442
- stopScheduledFormStateUpdate = () => {
443
- if (this.lastTimeoutId !== undefined) {
444
- clearTimeout(this.lastTimeoutId);
445
- this.lastTimeoutId = undefined;
446
- }
447
- };
448
- scheduleUpdateFormState = (rawFormState) => {
449
- this.stopScheduledFormStateUpdate();
450
- this.lastTimeoutId = setTimeout(() => {
451
- this.updateFormState(rawFormState);
452
- this.lastTimeoutId = undefined;
453
- }, this.config.lazyUpdatesTimer ?? 0);
454
- };
455
- destroy() {
456
- this.abortController.abort();
457
- this.stopScheduledFormStateUpdate();
458
- }
459
- }
460
- /**
461
- * @deprecated ⚠️ use `Form`. This export will be removed in next major release
462
- */
463
- export class MobxForm extends Form {
464
- }
@@ -1 +0,0 @@
1
- export {};