@firecms/formex 3.0.0-canary.144 → 3.0.0-canary.146

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.es.js CHANGED
@@ -157,10 +157,12 @@ function useCreateFormex({
157
157
  validation,
158
158
  validateOnChange = false,
159
159
  onSubmit,
160
- validateOnInitialRender = false
160
+ validateOnInitialRender = false,
161
+ debugId
161
162
  }) {
162
163
  const initialValuesRef = React__default.useRef(initialValues);
163
164
  const valuesRef = React__default.useRef(initialValues);
165
+ const debugIdRef = React__default.useRef(debugId);
164
166
  const [values, setValuesInner] = useState(initialValues);
165
167
  const [touchedState, setTouchedState] = useState({});
166
168
  const [errors, setErrors] = useState(initialErrors ?? {});
@@ -181,8 +183,7 @@ function useCreateFormex({
181
183
  };
182
184
  const validate = async () => {
183
185
  setIsValidating(true);
184
- const values2 = valuesRef.current;
185
- const validationErrors = await validation?.(values2);
186
+ const validationErrors = await validation?.(valuesRef.current);
186
187
  setErrors(validationErrors ?? {});
187
188
  setIsValidating(false);
188
189
  return validationErrors;
@@ -286,7 +287,8 @@ function useCreateFormex({
286
287
  validate,
287
288
  isValidating,
288
289
  resetForm,
289
- version
290
+ version,
291
+ debugId: debugIdRef.current
290
292
  };
291
293
  const controllerRef = React__default.useRef(controller);
292
294
  controllerRef.current = controller;
@@ -295,6 +297,7 @@ function useCreateFormex({
295
297
  export {
296
298
  Field,
297
299
  Formex,
300
+ clone,
298
301
  getActiveElement,
299
302
  getIn,
300
303
  isEmptyArray,
@@ -1 +1 @@
1
- {"version":3,"file":"index.es.js","sources":["../src/Formex.tsx","../src/utils.ts","../src/Field.tsx","../src/useCreateFormex.tsx"],"sourcesContent":["import React, { useContext } from \"react\";\nimport { FormexController } from \"./types\";\n\nconst FormexContext = React.createContext<FormexController<any>>({} as any);\n\nexport const useFormex = <T extends object>() => useContext<FormexController<T>>(FormexContext);\n\nexport const Formex = FormexContext.Provider;\n","import * as React from \"react\";\n\n/** @private is the value an empty array? */\nexport const isEmptyArray = (value?: any) =>\n Array.isArray(value) && value.length === 0;\n\n/** @private is the given object a Function? */\nexport const isFunction = (obj: any): obj is Function =>\n typeof obj === \"function\";\n\n/** @private is the given object an Object? */\nexport const isObject = (obj: any): obj is Object =>\n obj !== null && typeof obj === \"object\";\n\n/** @private is the given object an integer? */\nexport const isInteger = (obj: any): boolean =>\n String(Math.floor(Number(obj))) === obj;\n\n/** @private is the given object a string? */\nexport const isString = (obj: any): obj is string =>\n Object.prototype.toString.call(obj) === \"[object String]\";\n\n/** @private is the given object a NaN? */\n// eslint-disable-next-line no-self-compare\nexport const isNaN = (obj: any): boolean => obj !== obj;\n\n/** @private Does a React component have exactly 0 children? */\nexport const isEmptyChildren = (children: any): boolean =>\n React.Children.count(children) === 0;\n\n/** @private is the given object/value a promise? */\nexport const isPromise = (value: any): value is PromiseLike<any> =>\n isObject(value) && isFunction(value.then);\n\n/** @private is the given object/value a type of synthetic event? */\nexport const isInputEvent = (value: any): value is React.SyntheticEvent<any> =>\n value && isObject(value) && isObject(value.target);\n\n/**\n * Same as document.activeElement but wraps in a try-catch block. In IE it is\n * not safe to call document.activeElement if there is nothing focused.\n *\n * The activeElement will be null only if the document or document body is not\n * yet defined.\n *\n * @param {?Document} doc Defaults to current document.\n * @return {Element | null}\n * @see https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getActiveElement.js\n */\nexport function getActiveElement(doc?: Document): Element | null {\n doc = doc || (typeof document !== \"undefined\" ? document : undefined);\n if (typeof doc === \"undefined\") {\n return null;\n }\n try {\n return doc.activeElement || doc.body;\n } catch (e) {\n return doc.body;\n }\n}\n\n/**\n * Deeply get a value from an object via its path.\n */\nexport function getIn(\n obj: any,\n key: string | string[],\n def?: any,\n p = 0\n) {\n const path = toPath(key);\n while (obj && p < path.length) {\n obj = obj[path[p++]];\n }\n\n // check if path is not in the end\n if (p !== path.length && !obj) {\n return def;\n }\n\n return obj === undefined ? def : obj;\n}\n\nexport function setIn(obj: any, path: string, value: any): any {\n const res: any = clone(obj); // this keeps inheritance when obj is a class\n let resVal: any = res;\n let i = 0;\n const pathArray = toPath(path);\n\n for (; i < pathArray.length - 1; i++) {\n const currentPath: string = pathArray[i];\n const currentObj: any = getIn(obj, pathArray.slice(0, i + 1));\n\n if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) {\n resVal = resVal[currentPath] = clone(currentObj);\n } else {\n const nextPath: string = pathArray[i + 1];\n resVal = resVal[currentPath] =\n isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {};\n }\n }\n\n // Return original object if new value is the same as current\n if ((i === 0 ? obj : resVal)[pathArray[i]] === value) {\n return obj;\n }\n\n if (value === undefined) {\n delete resVal[pathArray[i]];\n } else {\n resVal[pathArray[i]] = value;\n }\n\n // If the path array has a single element, the loop did not run.\n // Deleting on `resVal` had no effect in this scenario, so we delete on the result instead.\n if (i === 0 && value === undefined) {\n delete res[pathArray[i]];\n }\n\n return res;\n}\n\n/**\n * Recursively a set the same value for all keys and arrays nested object, cloning\n * @param object\n * @param value\n * @param visited\n * @param response\n */\nexport function setNestedObjectValues<T>(\n object: any,\n value: any,\n visited: any = new WeakMap(),\n response: any = {}\n): T {\n for (const k of Object.keys(object)) {\n const val = object[k];\n if (isObject(val)) {\n if (!visited.get(val)) {\n visited.set(val, true);\n // In order to keep array values consistent for both dot path and\n // bracket syntax, we need to check if this is an array so that\n // this will output { friends: [true] } and not { friends: { \"0\": true } }\n response[k] = Array.isArray(val) ? [] : {};\n setNestedObjectValues(val, value, visited, response[k]);\n }\n } else {\n response[k] = value;\n }\n }\n\n return response;\n}\n\nfunction clone(value: any) {\n if (Array.isArray(value)) {\n return [...value];\n } else if (typeof value === \"object\" && value !== null) {\n return { ...value };\n } else {\n return value; // This is for primitive types which do not need cloning.\n }\n}\n\nfunction toPath(value: string | string[]) {\n if (Array.isArray(value)) return value; // Already in path array form.\n // Replace brackets with dots, remove leading/trailing dots, then split by dot.\n return value.replace(/\\[(\\d+)]/g, \".$1\").replace(/^\\./, \"\").replace(/\\.$/, \"\").split(\".\");\n}\n","import * as React from \"react\";\nimport { useFormex } from \"./Formex\";\nimport { getIn, isFunction, isObject } from \"./utils\";\nimport { FormexController } from \"./types\";\n\nexport interface FieldInputProps<Value> {\n /** Value of the field */\n value: Value;\n /** Name of the field */\n name: string;\n /** Multiple select? */\n multiple?: boolean;\n /** Is the field checked? */\n checked?: boolean;\n /** Change event handler */\n onChange: (event: React.SyntheticEvent) => void,\n /** Blur event handler */\n onBlur: (event: React.FocusEvent) => void,\n}\n\nexport interface FormexFieldProps<Value = any, FormValues extends object = any> {\n field: FieldInputProps<Value>;\n form: FormexController<FormValues>;\n}\n\nexport interface FieldConfig<Value, C extends React.ElementType | undefined = undefined> {\n\n /**\n * Component to render. Can either be a string e.g. 'select', 'input', or 'textarea', or a component.\n */\n as?:\n | C\n | string\n | React.ForwardRefExoticComponent<any>;\n\n /**\n * Children render function <Field name>{props => ...}</Field>)\n */\n children?: ((props: FormexFieldProps<Value>) => React.ReactNode) | React.ReactNode;\n\n /**\n * Validate a single field value independently\n */\n // validate?: FieldValidator;\n\n /**\n * Used for 'select' and related input types.\n */\n multiple?: boolean;\n\n /**\n * Field name\n */\n name: string;\n\n /** HTML input type */\n type?: string;\n\n /** Field value */\n value?: any;\n\n /** Inner ref */\n innerRef?: (instance: any) => void;\n\n}\n\nexport type FieldProps<T, C extends React.ElementType | undefined> = {\n as?: C;\n} & (C extends React.ElementType ? (React.ComponentProps<C> & FieldConfig<T, C>) : FieldConfig<T, C>);\n\nexport function Field<T, C extends React.ElementType | undefined = undefined>({\n validate,\n name,\n children,\n as: is, // `as` is reserved in typescript lol\n // component,\n className,\n ...props\n }: FieldProps<T, C>) {\n const formex = useFormex();\n\n const field = getFieldProps({ name, ...props }, formex);\n\n if (isFunction(children)) {\n return children({ field, form: formex });\n }\n\n // if (component) {\n // if (typeof component === \"string\") {\n // const { innerRef, ...rest } = props;\n // return React.createElement(\n // component,\n // { ref: innerRef, ...field, ...rest, className },\n // children\n // );\n // }\n // return React.createElement(\n // component,\n // { field, form: formex, ...props, className },\n // children\n // );\n // }\n\n // default to input here so we can check for both `as` and `children` above\n const asElement = is || \"input\";\n\n if (typeof asElement === \"string\") {\n const { innerRef, ...rest } = props;\n return React.createElement(\n asElement,\n { ref: innerRef, ...field, ...rest, className },\n children\n );\n }\n\n return React.createElement(asElement, { ...field, ...props, className }, children);\n}\n\nconst getFieldProps = (nameOrOptions: string | FieldConfig<any>, formex: FormexController<any>): FieldInputProps<any> => {\n const isAnObject = isObject(nameOrOptions);\n const name = isAnObject\n ? (nameOrOptions as FieldConfig<any>).name\n : nameOrOptions;\n const valueState = getIn(formex.values, name);\n\n const field: FieldInputProps<any> = {\n name,\n value: valueState,\n onChange: formex.handleChange,\n onBlur: formex.handleBlur,\n };\n if (isAnObject) {\n const {\n type,\n value: valueProp, // value is special for checkboxes\n as: is,\n multiple,\n } = nameOrOptions as FieldConfig<any>;\n\n if (type === \"checkbox\") {\n if (valueProp === undefined) {\n field.checked = !!valueState;\n } else {\n field.checked = !!(\n Array.isArray(valueState) && ~valueState.indexOf(valueProp)\n );\n field.value = valueProp;\n }\n } else if (type === \"radio\") {\n field.checked = valueState === valueProp;\n field.value = valueProp;\n } else if (is === \"select\" && multiple) {\n field.value = field.value || [];\n field.multiple = true;\n }\n }\n return field;\n};\n","import React, { FormEvent, useEffect, useState } from \"react\";\nimport { getIn, setIn } from \"./utils\";\nimport equal from \"react-fast-compare\"\n\nimport { FormexController, FormexResetProps } from \"./types\";\n\nexport function useCreateFormex<T extends object>({\n initialValues,\n initialErrors,\n validation,\n validateOnChange = false,\n onSubmit,\n validateOnInitialRender = false\n }: {\n initialValues: T,\n initialErrors?: Record<string, string>,\n validateOnChange?: boolean,\n validateOnInitialRender?: boolean,\n validation?: (values: T) => Record<string, string> | Promise<Record<string, string>> | undefined | void,\n onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>\n}): FormexController<T> {\n\n const initialValuesRef = React.useRef<T>(initialValues);\n const valuesRef = React.useRef<T>(initialValues);\n\n const [values, setValuesInner] = useState<T>(initialValues);\n const [touchedState, setTouchedState] = useState<Record<string, boolean>>({});\n const [errors, setErrors] = useState<Record<string, string>>(initialErrors ?? {});\n const [dirty, setDirty] = useState(false);\n const [submitCount, setSubmitCount] = useState(0);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isValidating, setIsValidating] = useState(false);\n const [version, setVersion] = useState(0);\n\n useEffect(() => {\n if (validateOnInitialRender) {\n validate();\n }\n }, []);\n\n const setValues = (newValues: T) => {\n valuesRef.current = newValues;\n setValuesInner(newValues);\n setDirty(equal(initialValuesRef.current, newValues));\n }\n\n const validate = async () => {\n setIsValidating(true);\n const values = valuesRef.current;\n const validationErrors = await validation?.(values);\n setErrors(validationErrors ?? {});\n setIsValidating(false);\n return validationErrors;\n }\n\n const setFieldValue = (key: string, value: any, shouldValidate?: boolean) => {\n const newValues = setIn(valuesRef.current, key, value);\n valuesRef.current = newValues;\n setValuesInner(newValues);\n if (!equal(getIn(initialValuesRef.current, key), value)) {\n setDirty(true);\n }\n if (shouldValidate) {\n validate();\n }\n }\n\n const setFieldError = (key: string, error: string | undefined) => {\n const newErrors = { ...errors };\n if (error) {\n newErrors[key] = error;\n } else {\n delete newErrors[key];\n }\n setErrors(newErrors);\n }\n\n const setFieldTouched = (key: string, touched: boolean, shouldValidate?: boolean | undefined) => {\n const newTouched = { ...touchedState };\n newTouched[key] = touched;\n setTouchedState(newTouched);\n if (shouldValidate) {\n validate();\n }\n }\n\n const handleChange = (event: React.SyntheticEvent) => {\n const target = event.target as HTMLInputElement;\n let value;\n if (target.type === \"checkbox\") {\n value = target.checked;\n } else if (target.type === \"number\") {\n value = target.valueAsNumber;\n } else {\n value = target.value;\n }\n const name = target.name;\n setFieldValue(name, value, validateOnChange);\n setFieldTouched(name, true);\n }\n\n const handleBlur = (event: React.FocusEvent) => {\n const target = event.target as HTMLInputElement;\n const name = target.name;\n setFieldTouched(name, true);\n }\n\n const submit = async (e?: FormEvent<HTMLFormElement>) => {\n e?.preventDefault();\n e?.stopPropagation();\n setIsSubmitting(true);\n setSubmitCount(submitCount + 1);\n const validationErrors = await validation?.(valuesRef.current);\n if (validationErrors && Object.keys(validationErrors).length > 0) {\n setErrors(validationErrors);\n } else {\n setErrors({});\n await onSubmit?.(valuesRef.current, controllerRef.current);\n }\n setIsSubmitting(false);\n setVersion(version + 1);\n }\n\n const resetForm = (props?: FormexResetProps<T>) => {\n const {\n submitCount: submitCountProp,\n values: valuesProp,\n errors: errorsProp,\n touched: touchedProp\n } = props ?? {};\n initialValuesRef.current = valuesProp ?? initialValues;\n valuesRef.current = valuesProp ?? initialValues;\n setValuesInner(valuesProp ?? initialValues);\n setErrors(errorsProp ?? {});\n setTouchedState(touchedProp ?? {});\n setDirty(false);\n setSubmitCount(submitCountProp ?? 0);\n setVersion(version + 1);\n }\n\n const controller: FormexController<T> = {\n values,\n initialValues: initialValuesRef.current,\n handleChange,\n isSubmitting,\n setSubmitting: setIsSubmitting,\n setValues,\n setFieldValue,\n errors,\n setFieldError,\n touched: touchedState,\n setFieldTouched,\n dirty,\n setDirty,\n handleSubmit: submit,\n submitCount,\n setSubmitCount,\n handleBlur,\n validate,\n isValidating,\n resetForm,\n version\n };\n\n const controllerRef = React.useRef<FormexController<T>>(controller);\n controllerRef.current = controller;\n return controller\n}\n"],"names":["React","values"],"mappings":"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"}
1
+ {"version":3,"file":"index.es.js","sources":["../src/Formex.tsx","../src/utils.ts","../src/Field.tsx","../src/useCreateFormex.tsx"],"sourcesContent":["import React, { useContext } from \"react\";\nimport { FormexController } from \"./types\";\n\nconst FormexContext = React.createContext<FormexController<any>>({} as any);\n\nexport const useFormex = <T extends object>() => useContext<FormexController<T>>(FormexContext);\n\nexport const Formex = FormexContext.Provider;\n","import * as React from \"react\";\n\n/** @private is the value an empty array? */\nexport const isEmptyArray = (value?: any) =>\n Array.isArray(value) && value.length === 0;\n\n/** @private is the given object a Function? */\nexport const isFunction = (obj: any): obj is Function =>\n typeof obj === \"function\";\n\n/** @private is the given object an Object? */\nexport const isObject = (obj: any): obj is Object =>\n obj !== null && typeof obj === \"object\";\n\n/** @private is the given object an integer? */\nexport const isInteger = (obj: any): boolean =>\n String(Math.floor(Number(obj))) === obj;\n\n/** @private is the given object a string? */\nexport const isString = (obj: any): obj is string =>\n Object.prototype.toString.call(obj) === \"[object String]\";\n\n/** @private is the given object a NaN? */\n// eslint-disable-next-line no-self-compare\nexport const isNaN = (obj: any): boolean => obj !== obj;\n\n/** @private Does a React component have exactly 0 children? */\nexport const isEmptyChildren = (children: any): boolean =>\n React.Children.count(children) === 0;\n\n/** @private is the given object/value a promise? */\nexport const isPromise = (value: any): value is PromiseLike<any> =>\n isObject(value) && isFunction(value.then);\n\n/** @private is the given object/value a type of synthetic event? */\nexport const isInputEvent = (value: any): value is React.SyntheticEvent<any> =>\n value && isObject(value) && isObject(value.target);\n\n/**\n * Same as document.activeElement but wraps in a try-catch block. In IE it is\n * not safe to call document.activeElement if there is nothing focused.\n *\n * The activeElement will be null only if the document or document body is not\n * yet defined.\n *\n * @param {?Document} doc Defaults to current document.\n * @return {Element | null}\n * @see https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getActiveElement.js\n */\nexport function getActiveElement(doc?: Document): Element | null {\n doc = doc || (typeof document !== \"undefined\" ? document : undefined);\n if (typeof doc === \"undefined\") {\n return null;\n }\n try {\n return doc.activeElement || doc.body;\n } catch (e) {\n return doc.body;\n }\n}\n\n/**\n * Deeply get a value from an object via its path.\n */\nexport function getIn(\n obj: any,\n key: string | string[],\n def?: any,\n p = 0\n) {\n const path = toPath(key);\n while (obj && p < path.length) {\n obj = obj[path[p++]];\n }\n\n // check if path is not in the end\n if (p !== path.length && !obj) {\n return def;\n }\n\n return obj === undefined ? def : obj;\n}\n\nexport function setIn(obj: any, path: string, value: any): any {\n const res: any = clone(obj); // this keeps inheritance when obj is a class\n let resVal: any = res;\n let i = 0;\n const pathArray = toPath(path);\n\n for (; i < pathArray.length - 1; i++) {\n const currentPath: string = pathArray[i];\n const currentObj: any = getIn(obj, pathArray.slice(0, i + 1));\n\n if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) {\n resVal = resVal[currentPath] = clone(currentObj);\n } else {\n const nextPath: string = pathArray[i + 1];\n resVal = resVal[currentPath] =\n isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {};\n }\n }\n\n // Return original object if new value is the same as current\n if ((i === 0 ? obj : resVal)[pathArray[i]] === value) {\n return obj;\n }\n\n if (value === undefined) {\n delete resVal[pathArray[i]];\n } else {\n resVal[pathArray[i]] = value;\n }\n\n // If the path array has a single element, the loop did not run.\n // Deleting on `resVal` had no effect in this scenario, so we delete on the result instead.\n if (i === 0 && value === undefined) {\n delete res[pathArray[i]];\n }\n\n return res;\n}\n\n/**\n * Recursively a set the same value for all keys and arrays nested object, cloning\n * @param object\n * @param value\n * @param visited\n * @param response\n */\nexport function setNestedObjectValues<T>(\n object: any,\n value: any,\n visited: any = new WeakMap(),\n response: any = {}\n): T {\n for (const k of Object.keys(object)) {\n const val = object[k];\n if (isObject(val)) {\n if (!visited.get(val)) {\n visited.set(val, true);\n // In order to keep array values consistent for both dot path and\n // bracket syntax, we need to check if this is an array so that\n // this will output { friends: [true] } and not { friends: { \"0\": true } }\n response[k] = Array.isArray(val) ? [] : {};\n setNestedObjectValues(val, value, visited, response[k]);\n }\n } else {\n response[k] = value;\n }\n }\n\n return response;\n}\n\nexport function clone(value: any) {\n if (Array.isArray(value)) {\n return [...value];\n } else if (typeof value === \"object\" && value !== null) {\n return { ...value };\n } else {\n return value; // This is for primitive types which do not need cloning.\n }\n}\n\nfunction toPath(value: string | string[]) {\n if (Array.isArray(value)) return value; // Already in path array form.\n // Replace brackets with dots, remove leading/trailing dots, then split by dot.\n return value.replace(/\\[(\\d+)]/g, \".$1\").replace(/^\\./, \"\").replace(/\\.$/, \"\").split(\".\");\n}\n","import * as React from \"react\";\nimport { useFormex } from \"./Formex\";\nimport { getIn, isFunction, isObject } from \"./utils\";\nimport { FormexController } from \"./types\";\n\nexport interface FieldInputProps<Value> {\n /** Value of the field */\n value: Value;\n /** Name of the field */\n name: string;\n /** Multiple select? */\n multiple?: boolean;\n /** Is the field checked? */\n checked?: boolean;\n /** Change event handler */\n onChange: (event: React.SyntheticEvent) => void,\n /** Blur event handler */\n onBlur: (event: React.FocusEvent) => void,\n}\n\nexport interface FormexFieldProps<Value = any, FormValues extends object = any> {\n field: FieldInputProps<Value>;\n form: FormexController<FormValues>;\n}\n\nexport interface FieldConfig<Value, C extends React.ElementType | undefined = undefined> {\n\n /**\n * Component to render. Can either be a string e.g. 'select', 'input', or 'textarea', or a component.\n */\n as?:\n | C\n | string\n | React.ForwardRefExoticComponent<any>;\n\n /**\n * Children render function <Field name>{props => ...}</Field>)\n */\n children?: ((props: FormexFieldProps<Value>) => React.ReactNode) | React.ReactNode;\n\n /**\n * Validate a single field value independently\n */\n // validate?: FieldValidator;\n\n /**\n * Used for 'select' and related input types.\n */\n multiple?: boolean;\n\n /**\n * Field name\n */\n name: string;\n\n /** HTML input type */\n type?: string;\n\n /** Field value */\n value?: any;\n\n /** Inner ref */\n innerRef?: (instance: any) => void;\n\n}\n\nexport type FieldProps<T, C extends React.ElementType | undefined> = {\n as?: C;\n} & (C extends React.ElementType ? (React.ComponentProps<C> & FieldConfig<T, C>) : FieldConfig<T, C>);\n\nexport function Field<T, C extends React.ElementType | undefined = undefined>({\n validate,\n name,\n children,\n as: is, // `as` is reserved in typescript lol\n // component,\n className,\n ...props\n }: FieldProps<T, C>) {\n const formex = useFormex();\n\n const field = getFieldProps({ name, ...props }, formex);\n\n if (isFunction(children)) {\n return children({ field, form: formex });\n }\n\n // if (component) {\n // if (typeof component === \"string\") {\n // const { innerRef, ...rest } = props;\n // return React.createElement(\n // component,\n // { ref: innerRef, ...field, ...rest, className },\n // children\n // );\n // }\n // return React.createElement(\n // component,\n // { field, form: formex, ...props, className },\n // children\n // );\n // }\n\n // default to input here so we can check for both `as` and `children` above\n const asElement = is || \"input\";\n\n if (typeof asElement === \"string\") {\n const { innerRef, ...rest } = props;\n return React.createElement(\n asElement,\n { ref: innerRef, ...field, ...rest, className },\n children\n );\n }\n\n return React.createElement(asElement, { ...field, ...props, className }, children);\n}\n\nconst getFieldProps = (nameOrOptions: string | FieldConfig<any>, formex: FormexController<any>): FieldInputProps<any> => {\n const isAnObject = isObject(nameOrOptions);\n const name = isAnObject\n ? (nameOrOptions as FieldConfig<any>).name\n : nameOrOptions;\n const valueState = getIn(formex.values, name);\n\n const field: FieldInputProps<any> = {\n name,\n value: valueState,\n onChange: formex.handleChange,\n onBlur: formex.handleBlur,\n };\n if (isAnObject) {\n const {\n type,\n value: valueProp, // value is special for checkboxes\n as: is,\n multiple,\n } = nameOrOptions as FieldConfig<any>;\n\n if (type === \"checkbox\") {\n if (valueProp === undefined) {\n field.checked = !!valueState;\n } else {\n field.checked = !!(\n Array.isArray(valueState) && ~valueState.indexOf(valueProp)\n );\n field.value = valueProp;\n }\n } else if (type === \"radio\") {\n field.checked = valueState === valueProp;\n field.value = valueProp;\n } else if (is === \"select\" && multiple) {\n field.value = field.value || [];\n field.multiple = true;\n }\n }\n return field;\n};\n","import React, { FormEvent, useEffect, useState } from \"react\";\nimport { getIn, setIn } from \"./utils\";\nimport equal from \"react-fast-compare\"\n\nimport { FormexController, FormexResetProps } from \"./types\";\n\nexport function useCreateFormex<T extends object>({\n initialValues,\n initialErrors,\n validation,\n validateOnChange = false,\n onSubmit,\n validateOnInitialRender = false,\n debugId\n }: {\n initialValues: T,\n initialErrors?: Record<string, string>,\n validateOnChange?: boolean,\n validateOnInitialRender?: boolean,\n validation?: (values: T) => Record<string, string> | Promise<Record<string, string>> | undefined | void,\n onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>,\n debugId?: string\n}): FormexController<T> {\n\n const initialValuesRef = React.useRef<T>(initialValues);\n const valuesRef = React.useRef<T>(initialValues);\n const debugIdRef = React.useRef<string | undefined>(debugId);\n\n const [values, setValuesInner] = useState<T>(initialValues);\n const [touchedState, setTouchedState] = useState<Record<string, boolean>>({});\n const [errors, setErrors] = useState<Record<string, string>>(initialErrors ?? {});\n const [dirty, setDirty] = useState(false);\n const [submitCount, setSubmitCount] = useState(0);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isValidating, setIsValidating] = useState(false);\n const [version, setVersion] = useState(0);\n\n useEffect(() => {\n if (validateOnInitialRender) {\n validate();\n }\n }, []);\n\n const setValues = (newValues: T) => {\n valuesRef.current = newValues;\n setValuesInner(newValues);\n setDirty(equal(initialValuesRef.current, newValues));\n }\n\n const validate = async () => {\n setIsValidating(true);\n const validationErrors = await validation?.(valuesRef.current);\n setErrors(validationErrors ?? {});\n setIsValidating(false);\n return validationErrors;\n }\n\n const setFieldValue = (key: string, value: any, shouldValidate?: boolean) => {\n const newValues = setIn(valuesRef.current, key, value);\n valuesRef.current = newValues;\n setValuesInner(newValues);\n if (!equal(getIn(initialValuesRef.current, key), value)) {\n setDirty(true);\n }\n if (shouldValidate) {\n validate();\n }\n }\n\n const setFieldError = (key: string, error: string | undefined) => {\n const newErrors = { ...errors };\n if (error) {\n newErrors[key] = error;\n } else {\n delete newErrors[key];\n }\n setErrors(newErrors);\n }\n\n const setFieldTouched = (key: string, touched: boolean, shouldValidate?: boolean | undefined) => {\n const newTouched = { ...touchedState };\n newTouched[key] = touched;\n setTouchedState(newTouched);\n if (shouldValidate) {\n validate();\n }\n }\n\n const handleChange = (event: React.SyntheticEvent) => {\n const target = event.target as HTMLInputElement;\n let value;\n if (target.type === \"checkbox\") {\n value = target.checked;\n } else if (target.type === \"number\") {\n value = target.valueAsNumber;\n } else {\n value = target.value;\n }\n const name = target.name;\n setFieldValue(name, value, validateOnChange);\n setFieldTouched(name, true);\n }\n\n const handleBlur = (event: React.FocusEvent) => {\n const target = event.target as HTMLInputElement;\n const name = target.name;\n setFieldTouched(name, true);\n }\n\n const submit = async (e?: FormEvent<HTMLFormElement>) => {\n e?.preventDefault();\n e?.stopPropagation();\n setIsSubmitting(true);\n setSubmitCount(submitCount + 1);\n const validationErrors = await validation?.(valuesRef.current);\n if (validationErrors && Object.keys(validationErrors).length > 0) {\n setErrors(validationErrors);\n } else {\n setErrors({});\n await onSubmit?.(valuesRef.current, controllerRef.current);\n }\n setIsSubmitting(false);\n setVersion(version + 1);\n }\n\n const resetForm = (props?: FormexResetProps<T>) => {\n const {\n submitCount: submitCountProp,\n values: valuesProp,\n errors: errorsProp,\n touched: touchedProp\n } = props ?? {};\n initialValuesRef.current = valuesProp ?? initialValues;\n valuesRef.current = valuesProp ?? initialValues;\n setValuesInner(valuesProp ?? initialValues);\n setErrors(errorsProp ?? {});\n setTouchedState(touchedProp ?? {});\n setDirty(false);\n setSubmitCount(submitCountProp ?? 0);\n setVersion(version + 1);\n }\n\n const controller: FormexController<T> = {\n values,\n initialValues: initialValuesRef.current,\n handleChange,\n isSubmitting,\n setSubmitting: setIsSubmitting,\n setValues,\n setFieldValue,\n errors,\n setFieldError,\n touched: touchedState,\n setFieldTouched,\n dirty,\n setDirty,\n handleSubmit: submit,\n submitCount,\n setSubmitCount,\n handleBlur,\n validate,\n isValidating,\n resetForm,\n version,\n debugId: debugIdRef.current\n };\n\n const controllerRef = React.useRef<FormexController<T>>(controller);\n controllerRef.current = controller;\n return controller\n}\n"],"names":["React"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -175,10 +175,12 @@
175
175
  validation,
176
176
  validateOnChange = false,
177
177
  onSubmit,
178
- validateOnInitialRender = false
178
+ validateOnInitialRender = false,
179
+ debugId
179
180
  }) {
180
181
  const initialValuesRef = React.useRef(initialValues);
181
182
  const valuesRef = React.useRef(initialValues);
183
+ const debugIdRef = React.useRef(debugId);
182
184
  const [values, setValuesInner] = React.useState(initialValues);
183
185
  const [touchedState, setTouchedState] = React.useState({});
184
186
  const [errors, setErrors] = React.useState(initialErrors ?? {});
@@ -199,8 +201,7 @@
199
201
  };
200
202
  const validate = async () => {
201
203
  setIsValidating(true);
202
- const values2 = valuesRef.current;
203
- const validationErrors = await validation?.(values2);
204
+ const validationErrors = await validation?.(valuesRef.current);
204
205
  setErrors(validationErrors ?? {});
205
206
  setIsValidating(false);
206
207
  return validationErrors;
@@ -304,7 +305,8 @@
304
305
  validate,
305
306
  isValidating,
306
307
  resetForm,
307
- version
308
+ version,
309
+ debugId: debugIdRef.current
308
310
  };
309
311
  const controllerRef = React.useRef(controller);
310
312
  controllerRef.current = controller;
@@ -312,6 +314,7 @@
312
314
  }
313
315
  exports2.Field = Field;
314
316
  exports2.Formex = Formex;
317
+ exports2.clone = clone;
315
318
  exports2.getActiveElement = getActiveElement;
316
319
  exports2.getIn = getIn;
317
320
  exports2.isEmptyArray = isEmptyArray;
@@ -1 +1 @@
1
- {"version":3,"file":"index.umd.js","sources":["../src/Formex.tsx","../src/utils.ts","../src/Field.tsx","../src/useCreateFormex.tsx"],"sourcesContent":["import React, { useContext } from \"react\";\nimport { FormexController } from \"./types\";\n\nconst FormexContext = React.createContext<FormexController<any>>({} as any);\n\nexport const useFormex = <T extends object>() => useContext<FormexController<T>>(FormexContext);\n\nexport const Formex = FormexContext.Provider;\n","import * as React from \"react\";\n\n/** @private is the value an empty array? */\nexport const isEmptyArray = (value?: any) =>\n Array.isArray(value) && value.length === 0;\n\n/** @private is the given object a Function? */\nexport const isFunction = (obj: any): obj is Function =>\n typeof obj === \"function\";\n\n/** @private is the given object an Object? */\nexport const isObject = (obj: any): obj is Object =>\n obj !== null && typeof obj === \"object\";\n\n/** @private is the given object an integer? */\nexport const isInteger = (obj: any): boolean =>\n String(Math.floor(Number(obj))) === obj;\n\n/** @private is the given object a string? */\nexport const isString = (obj: any): obj is string =>\n Object.prototype.toString.call(obj) === \"[object String]\";\n\n/** @private is the given object a NaN? */\n// eslint-disable-next-line no-self-compare\nexport const isNaN = (obj: any): boolean => obj !== obj;\n\n/** @private Does a React component have exactly 0 children? */\nexport const isEmptyChildren = (children: any): boolean =>\n React.Children.count(children) === 0;\n\n/** @private is the given object/value a promise? */\nexport const isPromise = (value: any): value is PromiseLike<any> =>\n isObject(value) && isFunction(value.then);\n\n/** @private is the given object/value a type of synthetic event? */\nexport const isInputEvent = (value: any): value is React.SyntheticEvent<any> =>\n value && isObject(value) && isObject(value.target);\n\n/**\n * Same as document.activeElement but wraps in a try-catch block. In IE it is\n * not safe to call document.activeElement if there is nothing focused.\n *\n * The activeElement will be null only if the document or document body is not\n * yet defined.\n *\n * @param {?Document} doc Defaults to current document.\n * @return {Element | null}\n * @see https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getActiveElement.js\n */\nexport function getActiveElement(doc?: Document): Element | null {\n doc = doc || (typeof document !== \"undefined\" ? document : undefined);\n if (typeof doc === \"undefined\") {\n return null;\n }\n try {\n return doc.activeElement || doc.body;\n } catch (e) {\n return doc.body;\n }\n}\n\n/**\n * Deeply get a value from an object via its path.\n */\nexport function getIn(\n obj: any,\n key: string | string[],\n def?: any,\n p = 0\n) {\n const path = toPath(key);\n while (obj && p < path.length) {\n obj = obj[path[p++]];\n }\n\n // check if path is not in the end\n if (p !== path.length && !obj) {\n return def;\n }\n\n return obj === undefined ? def : obj;\n}\n\nexport function setIn(obj: any, path: string, value: any): any {\n const res: any = clone(obj); // this keeps inheritance when obj is a class\n let resVal: any = res;\n let i = 0;\n const pathArray = toPath(path);\n\n for (; i < pathArray.length - 1; i++) {\n const currentPath: string = pathArray[i];\n const currentObj: any = getIn(obj, pathArray.slice(0, i + 1));\n\n if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) {\n resVal = resVal[currentPath] = clone(currentObj);\n } else {\n const nextPath: string = pathArray[i + 1];\n resVal = resVal[currentPath] =\n isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {};\n }\n }\n\n // Return original object if new value is the same as current\n if ((i === 0 ? obj : resVal)[pathArray[i]] === value) {\n return obj;\n }\n\n if (value === undefined) {\n delete resVal[pathArray[i]];\n } else {\n resVal[pathArray[i]] = value;\n }\n\n // If the path array has a single element, the loop did not run.\n // Deleting on `resVal` had no effect in this scenario, so we delete on the result instead.\n if (i === 0 && value === undefined) {\n delete res[pathArray[i]];\n }\n\n return res;\n}\n\n/**\n * Recursively a set the same value for all keys and arrays nested object, cloning\n * @param object\n * @param value\n * @param visited\n * @param response\n */\nexport function setNestedObjectValues<T>(\n object: any,\n value: any,\n visited: any = new WeakMap(),\n response: any = {}\n): T {\n for (const k of Object.keys(object)) {\n const val = object[k];\n if (isObject(val)) {\n if (!visited.get(val)) {\n visited.set(val, true);\n // In order to keep array values consistent for both dot path and\n // bracket syntax, we need to check if this is an array so that\n // this will output { friends: [true] } and not { friends: { \"0\": true } }\n response[k] = Array.isArray(val) ? [] : {};\n setNestedObjectValues(val, value, visited, response[k]);\n }\n } else {\n response[k] = value;\n }\n }\n\n return response;\n}\n\nfunction clone(value: any) {\n if (Array.isArray(value)) {\n return [...value];\n } else if (typeof value === \"object\" && value !== null) {\n return { ...value };\n } else {\n return value; // This is for primitive types which do not need cloning.\n }\n}\n\nfunction toPath(value: string | string[]) {\n if (Array.isArray(value)) return value; // Already in path array form.\n // Replace brackets with dots, remove leading/trailing dots, then split by dot.\n return value.replace(/\\[(\\d+)]/g, \".$1\").replace(/^\\./, \"\").replace(/\\.$/, \"\").split(\".\");\n}\n","import * as React from \"react\";\nimport { useFormex } from \"./Formex\";\nimport { getIn, isFunction, isObject } from \"./utils\";\nimport { FormexController } from \"./types\";\n\nexport interface FieldInputProps<Value> {\n /** Value of the field */\n value: Value;\n /** Name of the field */\n name: string;\n /** Multiple select? */\n multiple?: boolean;\n /** Is the field checked? */\n checked?: boolean;\n /** Change event handler */\n onChange: (event: React.SyntheticEvent) => void,\n /** Blur event handler */\n onBlur: (event: React.FocusEvent) => void,\n}\n\nexport interface FormexFieldProps<Value = any, FormValues extends object = any> {\n field: FieldInputProps<Value>;\n form: FormexController<FormValues>;\n}\n\nexport interface FieldConfig<Value, C extends React.ElementType | undefined = undefined> {\n\n /**\n * Component to render. Can either be a string e.g. 'select', 'input', or 'textarea', or a component.\n */\n as?:\n | C\n | string\n | React.ForwardRefExoticComponent<any>;\n\n /**\n * Children render function <Field name>{props => ...}</Field>)\n */\n children?: ((props: FormexFieldProps<Value>) => React.ReactNode) | React.ReactNode;\n\n /**\n * Validate a single field value independently\n */\n // validate?: FieldValidator;\n\n /**\n * Used for 'select' and related input types.\n */\n multiple?: boolean;\n\n /**\n * Field name\n */\n name: string;\n\n /** HTML input type */\n type?: string;\n\n /** Field value */\n value?: any;\n\n /** Inner ref */\n innerRef?: (instance: any) => void;\n\n}\n\nexport type FieldProps<T, C extends React.ElementType | undefined> = {\n as?: C;\n} & (C extends React.ElementType ? (React.ComponentProps<C> & FieldConfig<T, C>) : FieldConfig<T, C>);\n\nexport function Field<T, C extends React.ElementType | undefined = undefined>({\n validate,\n name,\n children,\n as: is, // `as` is reserved in typescript lol\n // component,\n className,\n ...props\n }: FieldProps<T, C>) {\n const formex = useFormex();\n\n const field = getFieldProps({ name, ...props }, formex);\n\n if (isFunction(children)) {\n return children({ field, form: formex });\n }\n\n // if (component) {\n // if (typeof component === \"string\") {\n // const { innerRef, ...rest } = props;\n // return React.createElement(\n // component,\n // { ref: innerRef, ...field, ...rest, className },\n // children\n // );\n // }\n // return React.createElement(\n // component,\n // { field, form: formex, ...props, className },\n // children\n // );\n // }\n\n // default to input here so we can check for both `as` and `children` above\n const asElement = is || \"input\";\n\n if (typeof asElement === \"string\") {\n const { innerRef, ...rest } = props;\n return React.createElement(\n asElement,\n { ref: innerRef, ...field, ...rest, className },\n children\n );\n }\n\n return React.createElement(asElement, { ...field, ...props, className }, children);\n}\n\nconst getFieldProps = (nameOrOptions: string | FieldConfig<any>, formex: FormexController<any>): FieldInputProps<any> => {\n const isAnObject = isObject(nameOrOptions);\n const name = isAnObject\n ? (nameOrOptions as FieldConfig<any>).name\n : nameOrOptions;\n const valueState = getIn(formex.values, name);\n\n const field: FieldInputProps<any> = {\n name,\n value: valueState,\n onChange: formex.handleChange,\n onBlur: formex.handleBlur,\n };\n if (isAnObject) {\n const {\n type,\n value: valueProp, // value is special for checkboxes\n as: is,\n multiple,\n } = nameOrOptions as FieldConfig<any>;\n\n if (type === \"checkbox\") {\n if (valueProp === undefined) {\n field.checked = !!valueState;\n } else {\n field.checked = !!(\n Array.isArray(valueState) && ~valueState.indexOf(valueProp)\n );\n field.value = valueProp;\n }\n } else if (type === \"radio\") {\n field.checked = valueState === valueProp;\n field.value = valueProp;\n } else if (is === \"select\" && multiple) {\n field.value = field.value || [];\n field.multiple = true;\n }\n }\n return field;\n};\n","import React, { FormEvent, useEffect, useState } from \"react\";\nimport { getIn, setIn } from \"./utils\";\nimport equal from \"react-fast-compare\"\n\nimport { FormexController, FormexResetProps } from \"./types\";\n\nexport function useCreateFormex<T extends object>({\n initialValues,\n initialErrors,\n validation,\n validateOnChange = false,\n onSubmit,\n validateOnInitialRender = false\n }: {\n initialValues: T,\n initialErrors?: Record<string, string>,\n validateOnChange?: boolean,\n validateOnInitialRender?: boolean,\n validation?: (values: T) => Record<string, string> | Promise<Record<string, string>> | undefined | void,\n onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>\n}): FormexController<T> {\n\n const initialValuesRef = React.useRef<T>(initialValues);\n const valuesRef = React.useRef<T>(initialValues);\n\n const [values, setValuesInner] = useState<T>(initialValues);\n const [touchedState, setTouchedState] = useState<Record<string, boolean>>({});\n const [errors, setErrors] = useState<Record<string, string>>(initialErrors ?? {});\n const [dirty, setDirty] = useState(false);\n const [submitCount, setSubmitCount] = useState(0);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isValidating, setIsValidating] = useState(false);\n const [version, setVersion] = useState(0);\n\n useEffect(() => {\n if (validateOnInitialRender) {\n validate();\n }\n }, []);\n\n const setValues = (newValues: T) => {\n valuesRef.current = newValues;\n setValuesInner(newValues);\n setDirty(equal(initialValuesRef.current, newValues));\n }\n\n const validate = async () => {\n setIsValidating(true);\n const values = valuesRef.current;\n const validationErrors = await validation?.(values);\n setErrors(validationErrors ?? {});\n setIsValidating(false);\n return validationErrors;\n }\n\n const setFieldValue = (key: string, value: any, shouldValidate?: boolean) => {\n const newValues = setIn(valuesRef.current, key, value);\n valuesRef.current = newValues;\n setValuesInner(newValues);\n if (!equal(getIn(initialValuesRef.current, key), value)) {\n setDirty(true);\n }\n if (shouldValidate) {\n validate();\n }\n }\n\n const setFieldError = (key: string, error: string | undefined) => {\n const newErrors = { ...errors };\n if (error) {\n newErrors[key] = error;\n } else {\n delete newErrors[key];\n }\n setErrors(newErrors);\n }\n\n const setFieldTouched = (key: string, touched: boolean, shouldValidate?: boolean | undefined) => {\n const newTouched = { ...touchedState };\n newTouched[key] = touched;\n setTouchedState(newTouched);\n if (shouldValidate) {\n validate();\n }\n }\n\n const handleChange = (event: React.SyntheticEvent) => {\n const target = event.target as HTMLInputElement;\n let value;\n if (target.type === \"checkbox\") {\n value = target.checked;\n } else if (target.type === \"number\") {\n value = target.valueAsNumber;\n } else {\n value = target.value;\n }\n const name = target.name;\n setFieldValue(name, value, validateOnChange);\n setFieldTouched(name, true);\n }\n\n const handleBlur = (event: React.FocusEvent) => {\n const target = event.target as HTMLInputElement;\n const name = target.name;\n setFieldTouched(name, true);\n }\n\n const submit = async (e?: FormEvent<HTMLFormElement>) => {\n e?.preventDefault();\n e?.stopPropagation();\n setIsSubmitting(true);\n setSubmitCount(submitCount + 1);\n const validationErrors = await validation?.(valuesRef.current);\n if (validationErrors && Object.keys(validationErrors).length > 0) {\n setErrors(validationErrors);\n } else {\n setErrors({});\n await onSubmit?.(valuesRef.current, controllerRef.current);\n }\n setIsSubmitting(false);\n setVersion(version + 1);\n }\n\n const resetForm = (props?: FormexResetProps<T>) => {\n const {\n submitCount: submitCountProp,\n values: valuesProp,\n errors: errorsProp,\n touched: touchedProp\n } = props ?? {};\n initialValuesRef.current = valuesProp ?? initialValues;\n valuesRef.current = valuesProp ?? initialValues;\n setValuesInner(valuesProp ?? initialValues);\n setErrors(errorsProp ?? {});\n setTouchedState(touchedProp ?? {});\n setDirty(false);\n setSubmitCount(submitCountProp ?? 0);\n setVersion(version + 1);\n }\n\n const controller: FormexController<T> = {\n values,\n initialValues: initialValuesRef.current,\n handleChange,\n isSubmitting,\n setSubmitting: setIsSubmitting,\n setValues,\n setFieldValue,\n errors,\n setFieldError,\n touched: touchedState,\n setFieldTouched,\n dirty,\n setDirty,\n handleSubmit: submit,\n submitCount,\n setSubmitCount,\n handleBlur,\n validate,\n isValidating,\n resetForm,\n version\n };\n\n const controllerRef = React.useRef<FormexController<T>>(controller);\n controllerRef.current = controller;\n return controller\n}\n"],"names":["useContext","React","useState","useEffect","values"],"mappings":"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"}
1
+ {"version":3,"file":"index.umd.js","sources":["../src/Formex.tsx","../src/utils.ts","../src/Field.tsx","../src/useCreateFormex.tsx"],"sourcesContent":["import React, { useContext } from \"react\";\nimport { FormexController } from \"./types\";\n\nconst FormexContext = React.createContext<FormexController<any>>({} as any);\n\nexport const useFormex = <T extends object>() => useContext<FormexController<T>>(FormexContext);\n\nexport const Formex = FormexContext.Provider;\n","import * as React from \"react\";\n\n/** @private is the value an empty array? */\nexport const isEmptyArray = (value?: any) =>\n Array.isArray(value) && value.length === 0;\n\n/** @private is the given object a Function? */\nexport const isFunction = (obj: any): obj is Function =>\n typeof obj === \"function\";\n\n/** @private is the given object an Object? */\nexport const isObject = (obj: any): obj is Object =>\n obj !== null && typeof obj === \"object\";\n\n/** @private is the given object an integer? */\nexport const isInteger = (obj: any): boolean =>\n String(Math.floor(Number(obj))) === obj;\n\n/** @private is the given object a string? */\nexport const isString = (obj: any): obj is string =>\n Object.prototype.toString.call(obj) === \"[object String]\";\n\n/** @private is the given object a NaN? */\n// eslint-disable-next-line no-self-compare\nexport const isNaN = (obj: any): boolean => obj !== obj;\n\n/** @private Does a React component have exactly 0 children? */\nexport const isEmptyChildren = (children: any): boolean =>\n React.Children.count(children) === 0;\n\n/** @private is the given object/value a promise? */\nexport const isPromise = (value: any): value is PromiseLike<any> =>\n isObject(value) && isFunction(value.then);\n\n/** @private is the given object/value a type of synthetic event? */\nexport const isInputEvent = (value: any): value is React.SyntheticEvent<any> =>\n value && isObject(value) && isObject(value.target);\n\n/**\n * Same as document.activeElement but wraps in a try-catch block. In IE it is\n * not safe to call document.activeElement if there is nothing focused.\n *\n * The activeElement will be null only if the document or document body is not\n * yet defined.\n *\n * @param {?Document} doc Defaults to current document.\n * @return {Element | null}\n * @see https://github.com/facebook/fbjs/blob/master/packages/fbjs/src/core/dom/getActiveElement.js\n */\nexport function getActiveElement(doc?: Document): Element | null {\n doc = doc || (typeof document !== \"undefined\" ? document : undefined);\n if (typeof doc === \"undefined\") {\n return null;\n }\n try {\n return doc.activeElement || doc.body;\n } catch (e) {\n return doc.body;\n }\n}\n\n/**\n * Deeply get a value from an object via its path.\n */\nexport function getIn(\n obj: any,\n key: string | string[],\n def?: any,\n p = 0\n) {\n const path = toPath(key);\n while (obj && p < path.length) {\n obj = obj[path[p++]];\n }\n\n // check if path is not in the end\n if (p !== path.length && !obj) {\n return def;\n }\n\n return obj === undefined ? def : obj;\n}\n\nexport function setIn(obj: any, path: string, value: any): any {\n const res: any = clone(obj); // this keeps inheritance when obj is a class\n let resVal: any = res;\n let i = 0;\n const pathArray = toPath(path);\n\n for (; i < pathArray.length - 1; i++) {\n const currentPath: string = pathArray[i];\n const currentObj: any = getIn(obj, pathArray.slice(0, i + 1));\n\n if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) {\n resVal = resVal[currentPath] = clone(currentObj);\n } else {\n const nextPath: string = pathArray[i + 1];\n resVal = resVal[currentPath] =\n isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {};\n }\n }\n\n // Return original object if new value is the same as current\n if ((i === 0 ? obj : resVal)[pathArray[i]] === value) {\n return obj;\n }\n\n if (value === undefined) {\n delete resVal[pathArray[i]];\n } else {\n resVal[pathArray[i]] = value;\n }\n\n // If the path array has a single element, the loop did not run.\n // Deleting on `resVal` had no effect in this scenario, so we delete on the result instead.\n if (i === 0 && value === undefined) {\n delete res[pathArray[i]];\n }\n\n return res;\n}\n\n/**\n * Recursively a set the same value for all keys and arrays nested object, cloning\n * @param object\n * @param value\n * @param visited\n * @param response\n */\nexport function setNestedObjectValues<T>(\n object: any,\n value: any,\n visited: any = new WeakMap(),\n response: any = {}\n): T {\n for (const k of Object.keys(object)) {\n const val = object[k];\n if (isObject(val)) {\n if (!visited.get(val)) {\n visited.set(val, true);\n // In order to keep array values consistent for both dot path and\n // bracket syntax, we need to check if this is an array so that\n // this will output { friends: [true] } and not { friends: { \"0\": true } }\n response[k] = Array.isArray(val) ? [] : {};\n setNestedObjectValues(val, value, visited, response[k]);\n }\n } else {\n response[k] = value;\n }\n }\n\n return response;\n}\n\nexport function clone(value: any) {\n if (Array.isArray(value)) {\n return [...value];\n } else if (typeof value === \"object\" && value !== null) {\n return { ...value };\n } else {\n return value; // This is for primitive types which do not need cloning.\n }\n}\n\nfunction toPath(value: string | string[]) {\n if (Array.isArray(value)) return value; // Already in path array form.\n // Replace brackets with dots, remove leading/trailing dots, then split by dot.\n return value.replace(/\\[(\\d+)]/g, \".$1\").replace(/^\\./, \"\").replace(/\\.$/, \"\").split(\".\");\n}\n","import * as React from \"react\";\nimport { useFormex } from \"./Formex\";\nimport { getIn, isFunction, isObject } from \"./utils\";\nimport { FormexController } from \"./types\";\n\nexport interface FieldInputProps<Value> {\n /** Value of the field */\n value: Value;\n /** Name of the field */\n name: string;\n /** Multiple select? */\n multiple?: boolean;\n /** Is the field checked? */\n checked?: boolean;\n /** Change event handler */\n onChange: (event: React.SyntheticEvent) => void,\n /** Blur event handler */\n onBlur: (event: React.FocusEvent) => void,\n}\n\nexport interface FormexFieldProps<Value = any, FormValues extends object = any> {\n field: FieldInputProps<Value>;\n form: FormexController<FormValues>;\n}\n\nexport interface FieldConfig<Value, C extends React.ElementType | undefined = undefined> {\n\n /**\n * Component to render. Can either be a string e.g. 'select', 'input', or 'textarea', or a component.\n */\n as?:\n | C\n | string\n | React.ForwardRefExoticComponent<any>;\n\n /**\n * Children render function <Field name>{props => ...}</Field>)\n */\n children?: ((props: FormexFieldProps<Value>) => React.ReactNode) | React.ReactNode;\n\n /**\n * Validate a single field value independently\n */\n // validate?: FieldValidator;\n\n /**\n * Used for 'select' and related input types.\n */\n multiple?: boolean;\n\n /**\n * Field name\n */\n name: string;\n\n /** HTML input type */\n type?: string;\n\n /** Field value */\n value?: any;\n\n /** Inner ref */\n innerRef?: (instance: any) => void;\n\n}\n\nexport type FieldProps<T, C extends React.ElementType | undefined> = {\n as?: C;\n} & (C extends React.ElementType ? (React.ComponentProps<C> & FieldConfig<T, C>) : FieldConfig<T, C>);\n\nexport function Field<T, C extends React.ElementType | undefined = undefined>({\n validate,\n name,\n children,\n as: is, // `as` is reserved in typescript lol\n // component,\n className,\n ...props\n }: FieldProps<T, C>) {\n const formex = useFormex();\n\n const field = getFieldProps({ name, ...props }, formex);\n\n if (isFunction(children)) {\n return children({ field, form: formex });\n }\n\n // if (component) {\n // if (typeof component === \"string\") {\n // const { innerRef, ...rest } = props;\n // return React.createElement(\n // component,\n // { ref: innerRef, ...field, ...rest, className },\n // children\n // );\n // }\n // return React.createElement(\n // component,\n // { field, form: formex, ...props, className },\n // children\n // );\n // }\n\n // default to input here so we can check for both `as` and `children` above\n const asElement = is || \"input\";\n\n if (typeof asElement === \"string\") {\n const { innerRef, ...rest } = props;\n return React.createElement(\n asElement,\n { ref: innerRef, ...field, ...rest, className },\n children\n );\n }\n\n return React.createElement(asElement, { ...field, ...props, className }, children);\n}\n\nconst getFieldProps = (nameOrOptions: string | FieldConfig<any>, formex: FormexController<any>): FieldInputProps<any> => {\n const isAnObject = isObject(nameOrOptions);\n const name = isAnObject\n ? (nameOrOptions as FieldConfig<any>).name\n : nameOrOptions;\n const valueState = getIn(formex.values, name);\n\n const field: FieldInputProps<any> = {\n name,\n value: valueState,\n onChange: formex.handleChange,\n onBlur: formex.handleBlur,\n };\n if (isAnObject) {\n const {\n type,\n value: valueProp, // value is special for checkboxes\n as: is,\n multiple,\n } = nameOrOptions as FieldConfig<any>;\n\n if (type === \"checkbox\") {\n if (valueProp === undefined) {\n field.checked = !!valueState;\n } else {\n field.checked = !!(\n Array.isArray(valueState) && ~valueState.indexOf(valueProp)\n );\n field.value = valueProp;\n }\n } else if (type === \"radio\") {\n field.checked = valueState === valueProp;\n field.value = valueProp;\n } else if (is === \"select\" && multiple) {\n field.value = field.value || [];\n field.multiple = true;\n }\n }\n return field;\n};\n","import React, { FormEvent, useEffect, useState } from \"react\";\nimport { getIn, setIn } from \"./utils\";\nimport equal from \"react-fast-compare\"\n\nimport { FormexController, FormexResetProps } from \"./types\";\n\nexport function useCreateFormex<T extends object>({\n initialValues,\n initialErrors,\n validation,\n validateOnChange = false,\n onSubmit,\n validateOnInitialRender = false,\n debugId\n }: {\n initialValues: T,\n initialErrors?: Record<string, string>,\n validateOnChange?: boolean,\n validateOnInitialRender?: boolean,\n validation?: (values: T) => Record<string, string> | Promise<Record<string, string>> | undefined | void,\n onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>,\n debugId?: string\n}): FormexController<T> {\n\n const initialValuesRef = React.useRef<T>(initialValues);\n const valuesRef = React.useRef<T>(initialValues);\n const debugIdRef = React.useRef<string | undefined>(debugId);\n\n const [values, setValuesInner] = useState<T>(initialValues);\n const [touchedState, setTouchedState] = useState<Record<string, boolean>>({});\n const [errors, setErrors] = useState<Record<string, string>>(initialErrors ?? {});\n const [dirty, setDirty] = useState(false);\n const [submitCount, setSubmitCount] = useState(0);\n const [isSubmitting, setIsSubmitting] = useState(false);\n const [isValidating, setIsValidating] = useState(false);\n const [version, setVersion] = useState(0);\n\n useEffect(() => {\n if (validateOnInitialRender) {\n validate();\n }\n }, []);\n\n const setValues = (newValues: T) => {\n valuesRef.current = newValues;\n setValuesInner(newValues);\n setDirty(equal(initialValuesRef.current, newValues));\n }\n\n const validate = async () => {\n setIsValidating(true);\n const validationErrors = await validation?.(valuesRef.current);\n setErrors(validationErrors ?? {});\n setIsValidating(false);\n return validationErrors;\n }\n\n const setFieldValue = (key: string, value: any, shouldValidate?: boolean) => {\n const newValues = setIn(valuesRef.current, key, value);\n valuesRef.current = newValues;\n setValuesInner(newValues);\n if (!equal(getIn(initialValuesRef.current, key), value)) {\n setDirty(true);\n }\n if (shouldValidate) {\n validate();\n }\n }\n\n const setFieldError = (key: string, error: string | undefined) => {\n const newErrors = { ...errors };\n if (error) {\n newErrors[key] = error;\n } else {\n delete newErrors[key];\n }\n setErrors(newErrors);\n }\n\n const setFieldTouched = (key: string, touched: boolean, shouldValidate?: boolean | undefined) => {\n const newTouched = { ...touchedState };\n newTouched[key] = touched;\n setTouchedState(newTouched);\n if (shouldValidate) {\n validate();\n }\n }\n\n const handleChange = (event: React.SyntheticEvent) => {\n const target = event.target as HTMLInputElement;\n let value;\n if (target.type === \"checkbox\") {\n value = target.checked;\n } else if (target.type === \"number\") {\n value = target.valueAsNumber;\n } else {\n value = target.value;\n }\n const name = target.name;\n setFieldValue(name, value, validateOnChange);\n setFieldTouched(name, true);\n }\n\n const handleBlur = (event: React.FocusEvent) => {\n const target = event.target as HTMLInputElement;\n const name = target.name;\n setFieldTouched(name, true);\n }\n\n const submit = async (e?: FormEvent<HTMLFormElement>) => {\n e?.preventDefault();\n e?.stopPropagation();\n setIsSubmitting(true);\n setSubmitCount(submitCount + 1);\n const validationErrors = await validation?.(valuesRef.current);\n if (validationErrors && Object.keys(validationErrors).length > 0) {\n setErrors(validationErrors);\n } else {\n setErrors({});\n await onSubmit?.(valuesRef.current, controllerRef.current);\n }\n setIsSubmitting(false);\n setVersion(version + 1);\n }\n\n const resetForm = (props?: FormexResetProps<T>) => {\n const {\n submitCount: submitCountProp,\n values: valuesProp,\n errors: errorsProp,\n touched: touchedProp\n } = props ?? {};\n initialValuesRef.current = valuesProp ?? initialValues;\n valuesRef.current = valuesProp ?? initialValues;\n setValuesInner(valuesProp ?? initialValues);\n setErrors(errorsProp ?? {});\n setTouchedState(touchedProp ?? {});\n setDirty(false);\n setSubmitCount(submitCountProp ?? 0);\n setVersion(version + 1);\n }\n\n const controller: FormexController<T> = {\n values,\n initialValues: initialValuesRef.current,\n handleChange,\n isSubmitting,\n setSubmitting: setIsSubmitting,\n setValues,\n setFieldValue,\n errors,\n setFieldError,\n touched: touchedState,\n setFieldTouched,\n dirty,\n setDirty,\n handleSubmit: submit,\n submitCount,\n setSubmitCount,\n handleBlur,\n validate,\n isValidating,\n resetForm,\n version,\n debugId: debugIdRef.current\n };\n\n const controllerRef = React.useRef<FormexController<T>>(controller);\n controllerRef.current = controller;\n return controller\n}\n"],"names":["useContext","React","useState","useEffect"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -25,6 +25,7 @@ export type FormexController<T extends object> = {
25
25
  * or the form is submitted.
26
26
  */
27
27
  version: number;
28
+ debugId?: string;
28
29
  };
29
30
  export type FormexResetProps<T extends object> = {
30
31
  values?: T;
@@ -1,9 +1,10 @@
1
1
  import { FormexController } from "./types";
2
- export declare function useCreateFormex<T extends object>({ initialValues, initialErrors, validation, validateOnChange, onSubmit, validateOnInitialRender }: {
2
+ export declare function useCreateFormex<T extends object>({ initialValues, initialErrors, validation, validateOnChange, onSubmit, validateOnInitialRender, debugId }: {
3
3
  initialValues: T;
4
4
  initialErrors?: Record<string, string>;
5
5
  validateOnChange?: boolean;
6
6
  validateOnInitialRender?: boolean;
7
7
  validation?: (values: T) => Record<string, string> | Promise<Record<string, string>> | undefined | void;
8
8
  onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>;
9
+ debugId?: string;
9
10
  }): FormexController<T>;
package/dist/utils.d.ts CHANGED
@@ -42,3 +42,4 @@ export declare function setIn(obj: any, path: string, value: any): any;
42
42
  * @param response
43
43
  */
44
44
  export declare function setNestedObjectValues<T>(object: any, value: any, visited?: any, response?: any): T;
45
+ export declare function clone(value: any): any;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@firecms/formex",
3
3
  "type": "module",
4
- "version": "3.0.0-canary.144",
4
+ "version": "3.0.0-canary.146",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -72,5 +72,5 @@
72
72
  "node"
73
73
  ]
74
74
  },
75
- "gitHead": "8f862289db623ffd350e61e4ab4a06957ed97bdf"
75
+ "gitHead": "601e622a79787f5b08f7ac27646d044787b972f1"
76
76
  }
package/src/types.ts CHANGED
@@ -26,6 +26,8 @@ export type FormexController<T extends object> = {
26
26
  * or the form is submitted.
27
27
  */
28
28
  version: number;
29
+
30
+ debugId?: string;
29
31
  }
30
32
 
31
33
  export type FormexResetProps<T extends object> = {
@@ -10,18 +10,21 @@ export function useCreateFormex<T extends object>({
10
10
  validation,
11
11
  validateOnChange = false,
12
12
  onSubmit,
13
- validateOnInitialRender = false
13
+ validateOnInitialRender = false,
14
+ debugId
14
15
  }: {
15
16
  initialValues: T,
16
17
  initialErrors?: Record<string, string>,
17
18
  validateOnChange?: boolean,
18
19
  validateOnInitialRender?: boolean,
19
20
  validation?: (values: T) => Record<string, string> | Promise<Record<string, string>> | undefined | void,
20
- onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>
21
+ onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>,
22
+ debugId?: string
21
23
  }): FormexController<T> {
22
24
 
23
25
  const initialValuesRef = React.useRef<T>(initialValues);
24
26
  const valuesRef = React.useRef<T>(initialValues);
27
+ const debugIdRef = React.useRef<string | undefined>(debugId);
25
28
 
26
29
  const [values, setValuesInner] = useState<T>(initialValues);
27
30
  const [touchedState, setTouchedState] = useState<Record<string, boolean>>({});
@@ -46,8 +49,7 @@ export function useCreateFormex<T extends object>({
46
49
 
47
50
  const validate = async () => {
48
51
  setIsValidating(true);
49
- const values = valuesRef.current;
50
- const validationErrors = await validation?.(values);
52
+ const validationErrors = await validation?.(valuesRef.current);
51
53
  setErrors(validationErrors ?? {});
52
54
  setIsValidating(false);
53
55
  return validationErrors;
@@ -159,7 +161,8 @@ export function useCreateFormex<T extends object>({
159
161
  validate,
160
162
  isValidating,
161
163
  resetForm,
162
- version
164
+ version,
165
+ debugId: debugIdRef.current
163
166
  };
164
167
 
165
168
  const controllerRef = React.useRef<FormexController<T>>(controller);
package/src/utils.ts CHANGED
@@ -152,7 +152,7 @@ export function setNestedObjectValues<T>(
152
152
  return response;
153
153
  }
154
154
 
155
- function clone(value: any) {
155
+ export function clone(value: any) {
156
156
  if (Array.isArray(value)) {
157
157
  return [...value];
158
158
  } else if (typeof value === "object" && value !== null) {