@firecms/formex 3.0.0-canary.205 → 3.0.0-canary.207

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
@@ -1,6 +1,6 @@
1
1
  import { c } from "react-compiler-runtime";
2
2
  import * as React from "react";
3
- import React__default, { useContext, useState, useEffect } from "react";
3
+ import React__default, { useContext, useRef, useState, useEffect, useCallback, useMemo } from "react";
4
4
  import equal from "react-fast-compare";
5
5
  const FormexContext = React__default.createContext({});
6
6
  const useFormex = () => {
@@ -281,9 +281,9 @@ function useCreateFormex({
281
281
  onReset,
282
282
  debugId
283
283
  }) {
284
- const initialValuesRef = React__default.useRef(initialValues);
285
- const valuesRef = React__default.useRef(initialValues);
286
- const debugIdRef = React__default.useRef(debugId);
284
+ const initialValuesRef = useRef(initialValues);
285
+ const valuesRef = useRef(initialValues);
286
+ const debugIdRef = useRef(debugId);
287
287
  const [values, setValuesInner] = useState(initialValues);
288
288
  const [touchedState, setTouchedState] = useState({});
289
289
  const [errors, setErrors] = useState(initialErrors ?? {});
@@ -292,24 +292,30 @@ function useCreateFormex({
292
292
  const [isSubmitting, setIsSubmitting] = useState(false);
293
293
  const [isValidating, setIsValidating] = useState(false);
294
294
  const [version, setVersion] = useState(0);
295
+ const historyRef = useRef([initialValues]);
296
+ const historyIndexRef = useRef(0);
295
297
  useEffect(() => {
296
298
  if (validateOnInitialRender) {
297
299
  validate();
298
300
  }
299
301
  }, []);
300
- const setValues = (newValues) => {
302
+ const setValues = useCallback((newValues) => {
301
303
  valuesRef.current = newValues;
302
304
  setValuesInner(newValues);
303
- setDirty(equal(initialValuesRef.current, newValues));
304
- };
305
- const validate = async () => {
305
+ setDirty(!equal(initialValuesRef.current, newValues));
306
+ const newHistory = historyRef.current.slice(0, historyIndexRef.current + 1);
307
+ newHistory.push(newValues);
308
+ historyRef.current = newHistory;
309
+ historyIndexRef.current = newHistory.length - 1;
310
+ }, []);
311
+ const validate = useCallback(async () => {
306
312
  setIsValidating(true);
307
313
  const validationErrors = await validation?.(valuesRef.current);
308
314
  setErrors(validationErrors ?? {});
309
315
  setIsValidating(false);
310
316
  return validationErrors;
311
- };
312
- const setFieldValue = (key, value, shouldValidate) => {
317
+ }, [validation]);
318
+ const setFieldValue = useCallback((key, value, shouldValidate) => {
313
319
  const newValues_0 = setIn(valuesRef.current, key, value);
314
320
  valuesRef.current = newValues_0;
315
321
  setValuesInner(newValues_0);
@@ -319,29 +325,34 @@ function useCreateFormex({
319
325
  if (shouldValidate) {
320
326
  validate();
321
327
  }
322
- };
323
- const setFieldError = (key_0, error) => {
324
- const newErrors = {
325
- ...errors
326
- };
327
- if (error) {
328
- newErrors[key_0] = error;
329
- } else {
330
- delete newErrors[key_0];
331
- }
332
- setErrors(newErrors);
333
- };
334
- const setFieldTouched = (key_1, touched, shouldValidate_0) => {
335
- const newTouched = {
336
- ...touchedState
337
- };
338
- newTouched[key_1] = touched;
339
- setTouchedState(newTouched);
328
+ const newHistory_0 = historyRef.current.slice(0, historyIndexRef.current + 1);
329
+ newHistory_0.push(newValues_0);
330
+ historyRef.current = newHistory_0;
331
+ historyIndexRef.current = newHistory_0.length - 1;
332
+ }, [validate]);
333
+ const setFieldError = useCallback((key_0, error) => {
334
+ setErrors((prevErrors) => {
335
+ const newErrors = {
336
+ ...prevErrors
337
+ };
338
+ if (error) {
339
+ newErrors[key_0] = error;
340
+ } else {
341
+ delete newErrors[key_0];
342
+ }
343
+ return newErrors;
344
+ });
345
+ }, []);
346
+ const setFieldTouched = useCallback((key_1, touched, shouldValidate_0) => {
347
+ setTouchedState((prev) => ({
348
+ ...prev,
349
+ [key_1]: touched
350
+ }));
340
351
  if (shouldValidate_0) {
341
352
  validate();
342
353
  }
343
- };
344
- const handleChange = (event) => {
354
+ }, [validate]);
355
+ const handleChange = useCallback((event) => {
345
356
  const target = event.target;
346
357
  let value_0;
347
358
  if (target.type === "checkbox") {
@@ -354,17 +365,17 @@ function useCreateFormex({
354
365
  const name = target.name;
355
366
  setFieldValue(name, value_0, validateOnChange);
356
367
  setFieldTouched(name, true);
357
- };
358
- const handleBlur = (event_0) => {
368
+ }, [setFieldValue, setFieldTouched, validateOnChange]);
369
+ const handleBlur = useCallback((event_0) => {
359
370
  const target_0 = event_0.target;
360
371
  const name_0 = target_0.name;
361
372
  setFieldTouched(name_0, true);
362
- };
363
- const submit = async (e) => {
373
+ }, [setFieldTouched]);
374
+ const submit = useCallback(async (e) => {
364
375
  e?.preventDefault();
365
376
  e?.stopPropagation();
366
377
  setIsSubmitting(true);
367
- setSubmitCount(submitCount + 1);
378
+ setSubmitCount((prev_0) => prev_0 + 1);
368
379
  const validationErrors_0 = await validation?.(valuesRef.current);
369
380
  if (validationErrors_0 && Object.keys(validationErrors_0).length > 0) {
370
381
  setErrors(validationErrors_0);
@@ -373,26 +384,46 @@ function useCreateFormex({
373
384
  await onSubmit?.(valuesRef.current, controllerRef.current);
374
385
  }
375
386
  setIsSubmitting(false);
376
- setVersion(version + 1);
377
- };
378
- const resetForm = (props) => {
387
+ setVersion((prev_1) => prev_1 + 1);
388
+ }, [onSubmit, validation]);
389
+ const resetForm = useCallback((props) => {
379
390
  const {
380
391
  submitCount: submitCountProp,
381
392
  values: valuesProp,
382
393
  errors: errorsProp,
383
394
  touched: touchedProp
384
395
  } = props ?? {};
385
- initialValuesRef.current = valuesProp ?? initialValues;
386
- valuesRef.current = valuesProp ?? initialValues;
387
- setValuesInner(valuesProp ?? initialValues);
396
+ valuesRef.current = valuesProp ?? initialValuesRef.current;
397
+ setValuesInner(valuesProp ?? initialValuesRef.current);
388
398
  setErrors(errorsProp ?? {});
389
399
  setTouchedState(touchedProp ?? {});
390
400
  setDirty(false);
391
401
  setSubmitCount(submitCountProp ?? 0);
392
- setVersion(version + 1);
402
+ setVersion((prev_2) => prev_2 + 1);
393
403
  onReset?.(controllerRef.current);
394
- };
395
- const controller = {
404
+ historyRef.current = [valuesProp ?? initialValuesRef.current];
405
+ historyIndexRef.current = 0;
406
+ }, [onReset]);
407
+ const undo = useCallback(() => {
408
+ if (historyIndexRef.current > 0) {
409
+ const newIndex = historyIndexRef.current - 1;
410
+ const newValues_1 = historyRef.current[newIndex];
411
+ setValuesInner(newValues_1);
412
+ valuesRef.current = newValues_1;
413
+ historyIndexRef.current = newIndex;
414
+ }
415
+ }, []);
416
+ const redo = useCallback(() => {
417
+ if (historyIndexRef.current < historyRef.current.length - 1) {
418
+ const newIndex_0 = historyIndexRef.current + 1;
419
+ const newValues_2 = historyRef.current[newIndex_0];
420
+ setValuesInner(newValues_2);
421
+ valuesRef.current = newValues_2;
422
+ historyIndexRef.current = newIndex_0;
423
+ }
424
+ }, []);
425
+ const controllerRef = useRef({});
426
+ const controller = useMemo(() => ({
396
427
  values,
397
428
  initialValues: initialValuesRef.current,
398
429
  handleChange,
@@ -414,10 +445,15 @@ function useCreateFormex({
414
445
  isValidating,
415
446
  resetForm,
416
447
  version,
417
- debugId: debugIdRef.current
418
- };
419
- const controllerRef = React__default.useRef(controller);
420
- controllerRef.current = controller;
448
+ debugId: debugIdRef.current,
449
+ undo,
450
+ redo,
451
+ canUndo: historyIndexRef.current > 0,
452
+ canRedo: historyIndexRef.current < historyRef.current.length - 1
453
+ }), [values, errors, touchedState, dirty, isSubmitting, submitCount, isValidating, version, handleChange, handleBlur, setValues, setFieldValue, setFieldTouched, setFieldError, validate, submit, resetForm, undo, redo]);
454
+ useEffect(() => {
455
+ controllerRef.current = controller;
456
+ }, [controller]);
421
457
  return controller;
422
458
  }
423
459
  export {
@@ -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\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 initialDirty,\n validation,\n validateOnChange = false,\n validateOnInitialRender = false,\n onSubmit,\n onReset,\n debugId\n }: {\n initialValues: T,\n initialErrors?: Record<string, string>,\n initialDirty?: boolean,\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 onReset?: (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(initialDirty ?? 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 onReset?.(controllerRef.current);\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":["FormexContext","React","createContext","useFormex","useContext","Formex","Provider","isEmptyArray","value","Array","isArray","length","isFunction","obj","isObject","isInteger","String","Math","floor","Number","isString","Object","prototype","toString","call","isNaN","isEmptyChildren","children","Children","count","isPromise","then","isInputEvent","target","getActiveElement","doc","document","undefined","activeElement","body","e","getIn","key","def","p","path","toPath","setIn","res","clone","resVal","i","pathArray","currentPath","currentObj","slice","nextPath","setNestedObjectValues","object","visited","WeakMap","response","k","keys","val","get","set","replace","split","Field","t0","$","_c","className","is","name","props","validate","t1","t2","as","t3","t4","t5","formex","field","Symbol","for","getFieldProps","form","bb0","asElement","innerRef","rest","ref","createElement","nameOrOptions","isAnObject","valueState","values","onChange","handleChange","onBlur","handleBlur","type","valueProp","multiple","checked","indexOf","useCreateFormex","initialValues","initialErrors","initialDirty","validation","validateOnChange","validateOnInitialRender","onSubmit","onReset","debugId","initialValuesRef","useRef","valuesRef","debugIdRef","setValuesInner","useState","touchedState","setTouchedState","errors","setErrors","dirty","setDirty","submitCount","setSubmitCount","isSubmitting","setIsSubmitting","isValidating","setIsValidating","version","setVersion","useEffect","setValues","newValues","current","equal","validationErrors","setFieldValue","shouldValidate","setFieldError","error","newErrors","setFieldTouched","touched","newTouched","event","valueAsNumber","submit","preventDefault","stopPropagation","controllerRef","resetForm","submitCountProp","valuesProp","errorsProp","touchedProp","controller","setSubmitting","handleSubmit"],"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, { useEffect, useState, useCallback, useMemo, useRef } 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 initialDirty,\n validation,\n validateOnChange = false,\n validateOnInitialRender = false,\n onSubmit,\n onReset,\n debugId,\n }: {\n initialValues: T;\n initialErrors?: Record<string, string>;\n initialDirty?: boolean;\n validateOnChange?: boolean;\n validateOnInitialRender?: boolean;\n validation?: (\n values: T\n ) =>\n | Record<string, string>\n | Promise<Record<string, string>>\n | undefined\n | void;\n onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>;\n onReset?: (controller: FormexController<T>) => void | Promise<void>;\n debugId?: string;\n}): FormexController<T> {\n const initialValuesRef = useRef<T>(initialValues);\n const valuesRef = useRef<T>(initialValues);\n const debugIdRef = 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(initialDirty ?? 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 // Replace state for history with refs\n const historyRef = useRef<T[]>([initialValues]);\n const historyIndexRef = useRef<number>(0);\n\n useEffect(() => {\n if (validateOnInitialRender) {\n validate();\n }\n }, []);\n\n const setValues = useCallback((newValues: T) => {\n valuesRef.current = newValues;\n setValuesInner(newValues);\n setDirty(!equal(initialValuesRef.current, newValues));\n // Update history using refs\n const newHistory = historyRef.current.slice(0, historyIndexRef.current + 1);\n newHistory.push(newValues);\n historyRef.current = newHistory;\n historyIndexRef.current = newHistory.length - 1;\n }, []);\n\n const validate = useCallback(async () => {\n setIsValidating(true);\n const validationErrors = await validation?.(valuesRef.current);\n setErrors(validationErrors ?? {});\n setIsValidating(false);\n return validationErrors;\n }, [validation]);\n\n const setFieldValue = useCallback(\n (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 // Update history using refs\n const newHistory = historyRef.current.slice(0, historyIndexRef.current + 1);\n newHistory.push(newValues);\n historyRef.current = newHistory;\n historyIndexRef.current = newHistory.length - 1;\n },\n [validate]\n );\n\n const setFieldError = useCallback((key: string, error: string | undefined) => {\n setErrors((prevErrors) => {\n const newErrors = { ...prevErrors };\n if (error) {\n newErrors[key] = error;\n } else {\n delete newErrors[key];\n }\n return newErrors;\n });\n }, []);\n\n const setFieldTouched = useCallback(\n (key: string, touched: boolean, shouldValidate?: boolean) => {\n setTouchedState((prev) => ({\n ...prev,\n [key]: touched,\n }));\n if (shouldValidate) {\n validate();\n }\n },\n [validate]\n );\n\n const handleChange = useCallback(\n (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 [setFieldValue, setFieldTouched, validateOnChange]\n );\n\n const handleBlur = useCallback((event: React.FocusEvent) => {\n const target = event.target as HTMLInputElement;\n const name = target.name;\n setFieldTouched(name, true);\n }, [setFieldTouched]);\n\n const submit = useCallback(\n async (e?: React.FormEvent<HTMLFormElement>) => {\n e?.preventDefault();\n e?.stopPropagation();\n setIsSubmitting(true);\n setSubmitCount((prev) => prev + 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((prev) => prev + 1);\n },\n [onSubmit, validation]\n );\n\n const resetForm = useCallback((props?: FormexResetProps<T>) => {\n const { submitCount: submitCountProp, values: valuesProp, errors: errorsProp, touched: touchedProp } = props ?? {};\n valuesRef.current = valuesProp ?? initialValuesRef.current;\n setValuesInner(valuesProp ?? initialValuesRef.current);\n setErrors(errorsProp ?? {});\n setTouchedState(touchedProp ?? {});\n setDirty(false);\n setSubmitCount(submitCountProp ?? 0);\n setVersion((prev) => prev + 1);\n onReset?.(controllerRef.current);\n // Reset history with refs\n historyRef.current = [valuesProp ?? initialValuesRef.current];\n historyIndexRef.current = 0;\n }, [onReset]);\n\n const undo = useCallback(() => {\n if (historyIndexRef.current > 0) {\n const newIndex = historyIndexRef.current - 1;\n const newValues = historyRef.current[newIndex];\n setValuesInner(newValues);\n valuesRef.current = newValues;\n historyIndexRef.current = newIndex;\n }\n }, []);\n\n const redo = useCallback(() => {\n if (historyIndexRef.current < historyRef.current.length - 1) {\n const newIndex = historyIndexRef.current + 1;\n const newValues = historyRef.current[newIndex];\n setValuesInner(newValues);\n valuesRef.current = newValues;\n historyIndexRef.current = newIndex;\n }\n }, []);\n\n const controllerRef = useRef<FormexController<T>>({} as FormexController<T>);\n\n const controller = useMemo<FormexController<T>>(\n () => ({\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 undo,\n redo,\n canUndo: historyIndexRef.current > 0,\n canRedo: historyIndexRef.current < historyRef.current.length - 1,\n }),\n [\n values,\n errors,\n touchedState,\n dirty,\n isSubmitting,\n submitCount,\n isValidating,\n version,\n handleChange,\n handleBlur,\n setValues,\n setFieldValue,\n setFieldTouched,\n setFieldError,\n validate,\n submit,\n resetForm,\n undo,\n redo,\n ]\n );\n\n useEffect(() => {\n controllerRef.current = controller;\n }, [controller]);\n\n return controller;\n}\n"],"names":["FormexContext","React","createContext","useFormex","useContext","Formex","Provider","isEmptyArray","value","Array","isArray","length","isFunction","obj","isObject","isInteger","String","Math","floor","Number","isString","Object","prototype","toString","call","isNaN","isEmptyChildren","children","Children","count","isPromise","then","isInputEvent","target","getActiveElement","doc","document","undefined","activeElement","body","e","getIn","key","def","p","path","toPath","setIn","res","clone","resVal","i","pathArray","currentPath","currentObj","slice","nextPath","setNestedObjectValues","object","visited","WeakMap","response","k","keys","val","get","set","replace","split","Field","t0","$","_c","className","is","name","props","validate","t1","t2","as","t3","t4","t5","formex","field","Symbol","for","getFieldProps","form","bb0","asElement","innerRef","rest","ref","createElement","nameOrOptions","isAnObject","valueState","values","onChange","handleChange","onBlur","handleBlur","type","valueProp","multiple","checked","indexOf","useCreateFormex","initialValues","initialErrors","initialDirty","validation","validateOnChange","validateOnInitialRender","onSubmit","onReset","debugId","initialValuesRef","useRef","valuesRef","debugIdRef","setValuesInner","useState","touchedState","setTouchedState","errors","setErrors","dirty","setDirty","submitCount","setSubmitCount","isSubmitting","setIsSubmitting","isValidating","setIsValidating","version","setVersion","historyRef","historyIndexRef","useEffect","setValues","useCallback","newValues","current","equal","newHistory","push","validationErrors","setFieldValue","shouldValidate","setFieldError","error","prevErrors","newErrors","setFieldTouched","touched","prev","event","valueAsNumber","submit","preventDefault","stopPropagation","controllerRef","resetForm","submitCountProp","valuesProp","errorsProp","touchedProp","undo","newIndex","redo","controller","useMemo","setSubmitting","handleSubmit","canUndo","canRedo"],"mappings":"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"}
package/dist/index.umd.js CHANGED
@@ -309,24 +309,30 @@
309
309
  const [isSubmitting, setIsSubmitting] = React.useState(false);
310
310
  const [isValidating, setIsValidating] = React.useState(false);
311
311
  const [version, setVersion] = React.useState(0);
312
+ const historyRef = React.useRef([initialValues]);
313
+ const historyIndexRef = React.useRef(0);
312
314
  React.useEffect(() => {
313
315
  if (validateOnInitialRender) {
314
316
  validate();
315
317
  }
316
318
  }, []);
317
- const setValues = (newValues) => {
319
+ const setValues = React.useCallback((newValues) => {
318
320
  valuesRef.current = newValues;
319
321
  setValuesInner(newValues);
320
- setDirty(equal(initialValuesRef.current, newValues));
321
- };
322
- const validate = async () => {
322
+ setDirty(!equal(initialValuesRef.current, newValues));
323
+ const newHistory = historyRef.current.slice(0, historyIndexRef.current + 1);
324
+ newHistory.push(newValues);
325
+ historyRef.current = newHistory;
326
+ historyIndexRef.current = newHistory.length - 1;
327
+ }, []);
328
+ const validate = React.useCallback(async () => {
323
329
  setIsValidating(true);
324
330
  const validationErrors = await validation?.(valuesRef.current);
325
331
  setErrors(validationErrors ?? {});
326
332
  setIsValidating(false);
327
333
  return validationErrors;
328
- };
329
- const setFieldValue = (key, value, shouldValidate) => {
334
+ }, [validation]);
335
+ const setFieldValue = React.useCallback((key, value, shouldValidate) => {
330
336
  const newValues_0 = setIn(valuesRef.current, key, value);
331
337
  valuesRef.current = newValues_0;
332
338
  setValuesInner(newValues_0);
@@ -336,29 +342,34 @@
336
342
  if (shouldValidate) {
337
343
  validate();
338
344
  }
339
- };
340
- const setFieldError = (key_0, error) => {
341
- const newErrors = {
342
- ...errors
343
- };
344
- if (error) {
345
- newErrors[key_0] = error;
346
- } else {
347
- delete newErrors[key_0];
348
- }
349
- setErrors(newErrors);
350
- };
351
- const setFieldTouched = (key_1, touched, shouldValidate_0) => {
352
- const newTouched = {
353
- ...touchedState
354
- };
355
- newTouched[key_1] = touched;
356
- setTouchedState(newTouched);
345
+ const newHistory_0 = historyRef.current.slice(0, historyIndexRef.current + 1);
346
+ newHistory_0.push(newValues_0);
347
+ historyRef.current = newHistory_0;
348
+ historyIndexRef.current = newHistory_0.length - 1;
349
+ }, [validate]);
350
+ const setFieldError = React.useCallback((key_0, error) => {
351
+ setErrors((prevErrors) => {
352
+ const newErrors = {
353
+ ...prevErrors
354
+ };
355
+ if (error) {
356
+ newErrors[key_0] = error;
357
+ } else {
358
+ delete newErrors[key_0];
359
+ }
360
+ return newErrors;
361
+ });
362
+ }, []);
363
+ const setFieldTouched = React.useCallback((key_1, touched, shouldValidate_0) => {
364
+ setTouchedState((prev) => ({
365
+ ...prev,
366
+ [key_1]: touched
367
+ }));
357
368
  if (shouldValidate_0) {
358
369
  validate();
359
370
  }
360
- };
361
- const handleChange = (event) => {
371
+ }, [validate]);
372
+ const handleChange = React.useCallback((event) => {
362
373
  const target = event.target;
363
374
  let value_0;
364
375
  if (target.type === "checkbox") {
@@ -371,17 +382,17 @@
371
382
  const name = target.name;
372
383
  setFieldValue(name, value_0, validateOnChange);
373
384
  setFieldTouched(name, true);
374
- };
375
- const handleBlur = (event_0) => {
385
+ }, [setFieldValue, setFieldTouched, validateOnChange]);
386
+ const handleBlur = React.useCallback((event_0) => {
376
387
  const target_0 = event_0.target;
377
388
  const name_0 = target_0.name;
378
389
  setFieldTouched(name_0, true);
379
- };
380
- const submit = async (e) => {
390
+ }, [setFieldTouched]);
391
+ const submit = React.useCallback(async (e) => {
381
392
  e?.preventDefault();
382
393
  e?.stopPropagation();
383
394
  setIsSubmitting(true);
384
- setSubmitCount(submitCount + 1);
395
+ setSubmitCount((prev_0) => prev_0 + 1);
385
396
  const validationErrors_0 = await validation?.(valuesRef.current);
386
397
  if (validationErrors_0 && Object.keys(validationErrors_0).length > 0) {
387
398
  setErrors(validationErrors_0);
@@ -390,26 +401,46 @@
390
401
  await onSubmit?.(valuesRef.current, controllerRef.current);
391
402
  }
392
403
  setIsSubmitting(false);
393
- setVersion(version + 1);
394
- };
395
- const resetForm = (props) => {
404
+ setVersion((prev_1) => prev_1 + 1);
405
+ }, [onSubmit, validation]);
406
+ const resetForm = React.useCallback((props) => {
396
407
  const {
397
408
  submitCount: submitCountProp,
398
409
  values: valuesProp,
399
410
  errors: errorsProp,
400
411
  touched: touchedProp
401
412
  } = props ?? {};
402
- initialValuesRef.current = valuesProp ?? initialValues;
403
- valuesRef.current = valuesProp ?? initialValues;
404
- setValuesInner(valuesProp ?? initialValues);
413
+ valuesRef.current = valuesProp ?? initialValuesRef.current;
414
+ setValuesInner(valuesProp ?? initialValuesRef.current);
405
415
  setErrors(errorsProp ?? {});
406
416
  setTouchedState(touchedProp ?? {});
407
417
  setDirty(false);
408
418
  setSubmitCount(submitCountProp ?? 0);
409
- setVersion(version + 1);
419
+ setVersion((prev_2) => prev_2 + 1);
410
420
  onReset?.(controllerRef.current);
411
- };
412
- const controller = {
421
+ historyRef.current = [valuesProp ?? initialValuesRef.current];
422
+ historyIndexRef.current = 0;
423
+ }, [onReset]);
424
+ const undo = React.useCallback(() => {
425
+ if (historyIndexRef.current > 0) {
426
+ const newIndex = historyIndexRef.current - 1;
427
+ const newValues_1 = historyRef.current[newIndex];
428
+ setValuesInner(newValues_1);
429
+ valuesRef.current = newValues_1;
430
+ historyIndexRef.current = newIndex;
431
+ }
432
+ }, []);
433
+ const redo = React.useCallback(() => {
434
+ if (historyIndexRef.current < historyRef.current.length - 1) {
435
+ const newIndex_0 = historyIndexRef.current + 1;
436
+ const newValues_2 = historyRef.current[newIndex_0];
437
+ setValuesInner(newValues_2);
438
+ valuesRef.current = newValues_2;
439
+ historyIndexRef.current = newIndex_0;
440
+ }
441
+ }, []);
442
+ const controllerRef = React.useRef({});
443
+ const controller = React.useMemo(() => ({
413
444
  values,
414
445
  initialValues: initialValuesRef.current,
415
446
  handleChange,
@@ -431,10 +462,15 @@
431
462
  isValidating,
432
463
  resetForm,
433
464
  version,
434
- debugId: debugIdRef.current
435
- };
436
- const controllerRef = React.useRef(controller);
437
- controllerRef.current = controller;
465
+ debugId: debugIdRef.current,
466
+ undo,
467
+ redo,
468
+ canUndo: historyIndexRef.current > 0,
469
+ canRedo: historyIndexRef.current < historyRef.current.length - 1
470
+ }), [values, errors, touchedState, dirty, isSubmitting, submitCount, isValidating, version, handleChange, handleBlur, setValues, setFieldValue, setFieldTouched, setFieldError, validate, submit, resetForm, undo, redo]);
471
+ React.useEffect(() => {
472
+ controllerRef.current = controller;
473
+ }, [controller]);
438
474
  return controller;
439
475
  }
440
476
  exports2.Field = Field;
@@ -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\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 initialDirty,\n validation,\n validateOnChange = false,\n validateOnInitialRender = false,\n onSubmit,\n onReset,\n debugId\n }: {\n initialValues: T,\n initialErrors?: Record<string, string>,\n initialDirty?: boolean,\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 onReset?: (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(initialDirty ?? 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 onReset?.(controllerRef.current);\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":["FormexContext","React","createContext","useFormex","useContext","Formex","Provider","isEmptyArray","value","Array","isArray","length","isFunction","obj","isObject","isInteger","String","Math","floor","Number","isString","Object","prototype","toString","call","isNaN","isEmptyChildren","children","Children","count","isPromise","then","isInputEvent","target","getActiveElement","doc","document","undefined","activeElement","body","e","getIn","key","def","p","path","toPath","setIn","res","clone","resVal","i","pathArray","currentPath","currentObj","slice","nextPath","setNestedObjectValues","object","visited","WeakMap","response","k","keys","val","get","set","replace","split","Field","t0","$","_c","className","is","name","props","validate","t1","t2","as","t3","t4","t5","formex","field","Symbol","for","getFieldProps","form","bb0","asElement","innerRef","rest","ref","createElement","nameOrOptions","isAnObject","valueState","values","onChange","handleChange","onBlur","handleBlur","type","valueProp","multiple","checked","indexOf","useCreateFormex","initialValues","initialErrors","initialDirty","validation","validateOnChange","validateOnInitialRender","onSubmit","onReset","debugId","initialValuesRef","useRef","valuesRef","debugIdRef","setValuesInner","useState","touchedState","setTouchedState","errors","setErrors","dirty","setDirty","submitCount","setSubmitCount","isSubmitting","setIsSubmitting","isValidating","setIsValidating","version","setVersion","useEffect","setValues","newValues","current","equal","validationErrors","setFieldValue","shouldValidate","setFieldError","error","newErrors","setFieldTouched","touched","newTouched","event","valueAsNumber","submit","preventDefault","stopPropagation","controllerRef","resetForm","submitCountProp","valuesProp","errorsProp","touchedProp","controller","setSubmitting","handleSubmit"],"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, { useEffect, useState, useCallback, useMemo, useRef } 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 initialDirty,\n validation,\n validateOnChange = false,\n validateOnInitialRender = false,\n onSubmit,\n onReset,\n debugId,\n }: {\n initialValues: T;\n initialErrors?: Record<string, string>;\n initialDirty?: boolean;\n validateOnChange?: boolean;\n validateOnInitialRender?: boolean;\n validation?: (\n values: T\n ) =>\n | Record<string, string>\n | Promise<Record<string, string>>\n | undefined\n | void;\n onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>;\n onReset?: (controller: FormexController<T>) => void | Promise<void>;\n debugId?: string;\n}): FormexController<T> {\n const initialValuesRef = useRef<T>(initialValues);\n const valuesRef = useRef<T>(initialValues);\n const debugIdRef = 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(initialDirty ?? 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 // Replace state for history with refs\n const historyRef = useRef<T[]>([initialValues]);\n const historyIndexRef = useRef<number>(0);\n\n useEffect(() => {\n if (validateOnInitialRender) {\n validate();\n }\n }, []);\n\n const setValues = useCallback((newValues: T) => {\n valuesRef.current = newValues;\n setValuesInner(newValues);\n setDirty(!equal(initialValuesRef.current, newValues));\n // Update history using refs\n const newHistory = historyRef.current.slice(0, historyIndexRef.current + 1);\n newHistory.push(newValues);\n historyRef.current = newHistory;\n historyIndexRef.current = newHistory.length - 1;\n }, []);\n\n const validate = useCallback(async () => {\n setIsValidating(true);\n const validationErrors = await validation?.(valuesRef.current);\n setErrors(validationErrors ?? {});\n setIsValidating(false);\n return validationErrors;\n }, [validation]);\n\n const setFieldValue = useCallback(\n (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 // Update history using refs\n const newHistory = historyRef.current.slice(0, historyIndexRef.current + 1);\n newHistory.push(newValues);\n historyRef.current = newHistory;\n historyIndexRef.current = newHistory.length - 1;\n },\n [validate]\n );\n\n const setFieldError = useCallback((key: string, error: string | undefined) => {\n setErrors((prevErrors) => {\n const newErrors = { ...prevErrors };\n if (error) {\n newErrors[key] = error;\n } else {\n delete newErrors[key];\n }\n return newErrors;\n });\n }, []);\n\n const setFieldTouched = useCallback(\n (key: string, touched: boolean, shouldValidate?: boolean) => {\n setTouchedState((prev) => ({\n ...prev,\n [key]: touched,\n }));\n if (shouldValidate) {\n validate();\n }\n },\n [validate]\n );\n\n const handleChange = useCallback(\n (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 [setFieldValue, setFieldTouched, validateOnChange]\n );\n\n const handleBlur = useCallback((event: React.FocusEvent) => {\n const target = event.target as HTMLInputElement;\n const name = target.name;\n setFieldTouched(name, true);\n }, [setFieldTouched]);\n\n const submit = useCallback(\n async (e?: React.FormEvent<HTMLFormElement>) => {\n e?.preventDefault();\n e?.stopPropagation();\n setIsSubmitting(true);\n setSubmitCount((prev) => prev + 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((prev) => prev + 1);\n },\n [onSubmit, validation]\n );\n\n const resetForm = useCallback((props?: FormexResetProps<T>) => {\n const { submitCount: submitCountProp, values: valuesProp, errors: errorsProp, touched: touchedProp } = props ?? {};\n valuesRef.current = valuesProp ?? initialValuesRef.current;\n setValuesInner(valuesProp ?? initialValuesRef.current);\n setErrors(errorsProp ?? {});\n setTouchedState(touchedProp ?? {});\n setDirty(false);\n setSubmitCount(submitCountProp ?? 0);\n setVersion((prev) => prev + 1);\n onReset?.(controllerRef.current);\n // Reset history with refs\n historyRef.current = [valuesProp ?? initialValuesRef.current];\n historyIndexRef.current = 0;\n }, [onReset]);\n\n const undo = useCallback(() => {\n if (historyIndexRef.current > 0) {\n const newIndex = historyIndexRef.current - 1;\n const newValues = historyRef.current[newIndex];\n setValuesInner(newValues);\n valuesRef.current = newValues;\n historyIndexRef.current = newIndex;\n }\n }, []);\n\n const redo = useCallback(() => {\n if (historyIndexRef.current < historyRef.current.length - 1) {\n const newIndex = historyIndexRef.current + 1;\n const newValues = historyRef.current[newIndex];\n setValuesInner(newValues);\n valuesRef.current = newValues;\n historyIndexRef.current = newIndex;\n }\n }, []);\n\n const controllerRef = useRef<FormexController<T>>({} as FormexController<T>);\n\n const controller = useMemo<FormexController<T>>(\n () => ({\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 undo,\n redo,\n canUndo: historyIndexRef.current > 0,\n canRedo: historyIndexRef.current < historyRef.current.length - 1,\n }),\n [\n values,\n errors,\n touchedState,\n dirty,\n isSubmitting,\n submitCount,\n isValidating,\n version,\n handleChange,\n handleBlur,\n setValues,\n setFieldValue,\n setFieldTouched,\n setFieldError,\n validate,\n submit,\n resetForm,\n undo,\n redo,\n ]\n );\n\n useEffect(() => {\n controllerRef.current = controller;\n }, [controller]);\n\n return controller;\n}\n"],"names":["FormexContext","React","createContext","useFormex","useContext","Formex","Provider","isEmptyArray","value","Array","isArray","length","isFunction","obj","isObject","isInteger","String","Math","floor","Number","isString","Object","prototype","toString","call","isNaN","isEmptyChildren","children","Children","count","isPromise","then","isInputEvent","target","getActiveElement","doc","document","undefined","activeElement","body","e","getIn","key","def","p","path","toPath","setIn","res","clone","resVal","i","pathArray","currentPath","currentObj","slice","nextPath","setNestedObjectValues","object","visited","WeakMap","response","k","keys","val","get","set","replace","split","Field","t0","$","_c","className","is","name","props","validate","t1","t2","as","t3","t4","t5","formex","field","Symbol","for","getFieldProps","form","bb0","asElement","innerRef","rest","ref","createElement","nameOrOptions","isAnObject","valueState","values","onChange","handleChange","onBlur","handleBlur","type","valueProp","multiple","checked","indexOf","useCreateFormex","initialValues","initialErrors","initialDirty","validation","validateOnChange","validateOnInitialRender","onSubmit","onReset","debugId","initialValuesRef","useRef","valuesRef","debugIdRef","setValuesInner","useState","touchedState","setTouchedState","errors","setErrors","dirty","setDirty","submitCount","setSubmitCount","isSubmitting","setIsSubmitting","isValidating","setIsValidating","version","setVersion","historyRef","historyIndexRef","useEffect","setValues","useCallback","newValues","current","equal","newHistory","push","validationErrors","setFieldValue","shouldValidate","setFieldError","error","prevErrors","newErrors","setFieldTouched","touched","prev","event","valueAsNumber","submit","preventDefault","stopPropagation","controllerRef","resetForm","submitCountProp","valuesProp","errorsProp","touchedProp","undo","newIndex","redo","controller","useMemo","setSubmitting","handleSubmit","canUndo","canRedo"],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -26,6 +26,10 @@ export type FormexController<T extends object> = {
26
26
  */
27
27
  version: number;
28
28
  debugId?: string;
29
+ undo: () => void;
30
+ redo: () => void;
31
+ canUndo: boolean;
32
+ canRedo: boolean;
29
33
  };
30
34
  export type FormexResetProps<T extends object> = {
31
35
  values?: T;
@@ -1,5 +1,5 @@
1
1
  import { FormexController } from "./types";
2
- export declare function useCreateFormex<T extends object>({ initialValues, initialErrors, initialDirty, validation, validateOnChange, validateOnInitialRender, onSubmit, onReset, debugId }: {
2
+ export declare function useCreateFormex<T extends object>({ initialValues, initialErrors, initialDirty, validation, validateOnChange, validateOnInitialRender, onSubmit, onReset, debugId, }: {
3
3
  initialValues: T;
4
4
  initialErrors?: Record<string, string>;
5
5
  initialDirty?: boolean;
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.205",
4
+ "version": "3.0.0-canary.207",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -74,5 +74,5 @@
74
74
  "node"
75
75
  ]
76
76
  },
77
- "gitHead": "b3a2a795ce5eb7edc68efea5caa69b8d477901be"
77
+ "gitHead": "04f84602ba162577101f88759b0c56d429c73ff8"
78
78
  }
package/src/types.ts CHANGED
@@ -28,6 +28,12 @@ export type FormexController<T extends object> = {
28
28
  version: number;
29
29
 
30
30
  debugId?: string;
31
+
32
+ undo: () => void;
33
+ redo: () => void;
34
+
35
+ canUndo: boolean;
36
+ canRedo: boolean;
31
37
  }
32
38
 
33
39
  export type FormexResetProps<T extends object> = {
@@ -1,6 +1,6 @@
1
- import React, { FormEvent, useEffect, useState } from "react";
1
+ import React, { useEffect, useState, useCallback, useMemo, useRef } from "react";
2
2
  import { getIn, setIn } from "./utils";
3
- import equal from "react-fast-compare"
3
+ import equal from "react-fast-compare";
4
4
 
5
5
  import { FormexController, FormexResetProps } from "./types";
6
6
 
@@ -13,22 +13,27 @@ export function useCreateFormex<T extends object>({
13
13
  validateOnInitialRender = false,
14
14
  onSubmit,
15
15
  onReset,
16
- debugId
16
+ debugId,
17
17
  }: {
18
- initialValues: T,
19
- initialErrors?: Record<string, string>,
20
- initialDirty?: boolean,
21
- validateOnChange?: boolean,
22
- validateOnInitialRender?: boolean,
23
- validation?: (values: T) => Record<string, string> | Promise<Record<string, string>> | undefined | void,
24
- onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>,
18
+ initialValues: T;
19
+ initialErrors?: Record<string, string>;
20
+ initialDirty?: boolean;
21
+ validateOnChange?: boolean;
22
+ validateOnInitialRender?: boolean;
23
+ validation?: (
24
+ values: T
25
+ ) =>
26
+ | Record<string, string>
27
+ | Promise<Record<string, string>>
28
+ | undefined
29
+ | void;
30
+ onSubmit?: (values: T, controller: FormexController<T>) => void | Promise<void>;
25
31
  onReset?: (controller: FormexController<T>) => void | Promise<void>;
26
- debugId?: string
32
+ debugId?: string;
27
33
  }): FormexController<T> {
28
-
29
- const initialValuesRef = React.useRef<T>(initialValues);
30
- const valuesRef = React.useRef<T>(initialValues);
31
- const debugIdRef = React.useRef<string | undefined>(debugId);
34
+ const initialValuesRef = useRef<T>(initialValues);
35
+ const valuesRef = useRef<T>(initialValues);
36
+ const debugIdRef = useRef<string | undefined>(debugId);
32
37
 
33
38
  const [values, setValuesInner] = useState<T>(initialValues);
34
39
  const [touchedState, setTouchedState] = useState<Record<string, boolean>>({});
@@ -39,138 +44,215 @@ export function useCreateFormex<T extends object>({
39
44
  const [isValidating, setIsValidating] = useState(false);
40
45
  const [version, setVersion] = useState(0);
41
46
 
47
+ // Replace state for history with refs
48
+ const historyRef = useRef<T[]>([initialValues]);
49
+ const historyIndexRef = useRef<number>(0);
50
+
42
51
  useEffect(() => {
43
52
  if (validateOnInitialRender) {
44
53
  validate();
45
54
  }
46
55
  }, []);
47
56
 
48
- const setValues = (newValues: T) => {
57
+ const setValues = useCallback((newValues: T) => {
49
58
  valuesRef.current = newValues;
50
59
  setValuesInner(newValues);
51
- setDirty(equal(initialValuesRef.current, newValues));
52
- }
60
+ setDirty(!equal(initialValuesRef.current, newValues));
61
+ // Update history using refs
62
+ const newHistory = historyRef.current.slice(0, historyIndexRef.current + 1);
63
+ newHistory.push(newValues);
64
+ historyRef.current = newHistory;
65
+ historyIndexRef.current = newHistory.length - 1;
66
+ }, []);
53
67
 
54
- const validate = async () => {
68
+ const validate = useCallback(async () => {
55
69
  setIsValidating(true);
56
70
  const validationErrors = await validation?.(valuesRef.current);
57
71
  setErrors(validationErrors ?? {});
58
72
  setIsValidating(false);
59
73
  return validationErrors;
60
- }
74
+ }, [validation]);
61
75
 
62
- const setFieldValue = (key: string, value: any, shouldValidate?: boolean) => {
63
- const newValues = setIn(valuesRef.current, key, value);
64
- valuesRef.current = newValues;
65
- setValuesInner(newValues);
66
- if (!equal(getIn(initialValuesRef.current, key), value)) {
67
- setDirty(true);
68
- }
69
- if (shouldValidate) {
70
- validate();
71
- }
72
- }
73
-
74
- const setFieldError = (key: string, error: string | undefined) => {
75
- const newErrors = { ...errors };
76
- if (error) {
77
- newErrors[key] = error;
78
- } else {
79
- delete newErrors[key];
80
- }
81
- setErrors(newErrors);
82
- }
83
-
84
- const setFieldTouched = (key: string, touched: boolean, shouldValidate?: boolean | undefined) => {
85
- const newTouched = { ...touchedState };
86
- newTouched[key] = touched;
87
- setTouchedState(newTouched);
88
- if (shouldValidate) {
89
- validate();
90
- }
91
- }
76
+ const setFieldValue = useCallback(
77
+ (key: string, value: any, shouldValidate?: boolean) => {
78
+ const newValues = setIn(valuesRef.current, key, value);
79
+ valuesRef.current = newValues;
80
+ setValuesInner(newValues);
81
+ if (!equal(getIn(initialValuesRef.current, key), value)) {
82
+ setDirty(true);
83
+ }
84
+ if (shouldValidate) {
85
+ validate();
86
+ }
87
+ // Update history using refs
88
+ const newHistory = historyRef.current.slice(0, historyIndexRef.current + 1);
89
+ newHistory.push(newValues);
90
+ historyRef.current = newHistory;
91
+ historyIndexRef.current = newHistory.length - 1;
92
+ },
93
+ [validate]
94
+ );
92
95
 
93
- const handleChange = (event: React.SyntheticEvent) => {
94
- const target = event.target as HTMLInputElement;
95
- let value;
96
- if (target.type === "checkbox") {
97
- value = target.checked;
98
- } else if (target.type === "number") {
99
- value = target.valueAsNumber;
100
- } else {
101
- value = target.value;
102
- }
103
- const name = target.name;
104
- setFieldValue(name, value, validateOnChange);
105
- setFieldTouched(name, true);
106
- }
96
+ const setFieldError = useCallback((key: string, error: string | undefined) => {
97
+ setErrors((prevErrors) => {
98
+ const newErrors = { ...prevErrors };
99
+ if (error) {
100
+ newErrors[key] = error;
101
+ } else {
102
+ delete newErrors[key];
103
+ }
104
+ return newErrors;
105
+ });
106
+ }, []);
107
107
 
108
- const handleBlur = (event: React.FocusEvent) => {
108
+ const setFieldTouched = useCallback(
109
+ (key: string, touched: boolean, shouldValidate?: boolean) => {
110
+ setTouchedState((prev) => ({
111
+ ...prev,
112
+ [key]: touched,
113
+ }));
114
+ if (shouldValidate) {
115
+ validate();
116
+ }
117
+ },
118
+ [validate]
119
+ );
120
+
121
+ const handleChange = useCallback(
122
+ (event: React.SyntheticEvent) => {
123
+ const target = event.target as HTMLInputElement;
124
+ let value;
125
+ if (target.type === "checkbox") {
126
+ value = target.checked;
127
+ } else if (target.type === "number") {
128
+ value = target.valueAsNumber;
129
+ } else {
130
+ value = target.value;
131
+ }
132
+ const name = target.name;
133
+ setFieldValue(name, value, validateOnChange);
134
+ setFieldTouched(name, true);
135
+ },
136
+ [setFieldValue, setFieldTouched, validateOnChange]
137
+ );
138
+
139
+ const handleBlur = useCallback((event: React.FocusEvent) => {
109
140
  const target = event.target as HTMLInputElement;
110
141
  const name = target.name;
111
142
  setFieldTouched(name, true);
112
- }
143
+ }, [setFieldTouched]);
113
144
 
114
- const submit = async (e?: FormEvent<HTMLFormElement>) => {
115
- e?.preventDefault();
116
- e?.stopPropagation();
117
- setIsSubmitting(true);
118
- setSubmitCount(submitCount + 1);
119
- const validationErrors = await validation?.(valuesRef.current);
120
- if (validationErrors && Object.keys(validationErrors).length > 0) {
121
- setErrors(validationErrors);
122
- } else {
123
- setErrors({});
124
- await onSubmit?.(valuesRef.current, controllerRef.current);
125
- }
126
- setIsSubmitting(false);
127
- setVersion(version + 1);
128
- }
129
-
130
- const resetForm = (props?: FormexResetProps<T>) => {
131
- const {
132
- submitCount: submitCountProp,
133
- values: valuesProp,
134
- errors: errorsProp,
135
- touched: touchedProp
136
- } = props ?? {};
137
- initialValuesRef.current = valuesProp ?? initialValues;
138
- valuesRef.current = valuesProp ?? initialValues;
139
- setValuesInner(valuesProp ?? initialValues);
145
+ const submit = useCallback(
146
+ async (e?: React.FormEvent<HTMLFormElement>) => {
147
+ e?.preventDefault();
148
+ e?.stopPropagation();
149
+ setIsSubmitting(true);
150
+ setSubmitCount((prev) => prev + 1);
151
+ const validationErrors = await validation?.(valuesRef.current);
152
+ if (validationErrors && Object.keys(validationErrors).length > 0) {
153
+ setErrors(validationErrors);
154
+ } else {
155
+ setErrors({});
156
+ await onSubmit?.(valuesRef.current, controllerRef.current);
157
+ }
158
+ setIsSubmitting(false);
159
+ setVersion((prev) => prev + 1);
160
+ },
161
+ [onSubmit, validation]
162
+ );
163
+
164
+ const resetForm = useCallback((props?: FormexResetProps<T>) => {
165
+ const { submitCount: submitCountProp, values: valuesProp, errors: errorsProp, touched: touchedProp } = props ?? {};
166
+ valuesRef.current = valuesProp ?? initialValuesRef.current;
167
+ setValuesInner(valuesProp ?? initialValuesRef.current);
140
168
  setErrors(errorsProp ?? {});
141
169
  setTouchedState(touchedProp ?? {});
142
170
  setDirty(false);
143
171
  setSubmitCount(submitCountProp ?? 0);
144
- setVersion(version + 1);
172
+ setVersion((prev) => prev + 1);
145
173
  onReset?.(controllerRef.current);
146
- }
147
-
148
- const controller: FormexController<T> = {
149
- values,
150
- initialValues: initialValuesRef.current,
151
- handleChange,
152
- isSubmitting,
153
- setSubmitting: setIsSubmitting,
154
- setValues,
155
- setFieldValue,
156
- errors,
157
- setFieldError,
158
- touched: touchedState,
159
- setFieldTouched,
160
- dirty,
161
- setDirty,
162
- handleSubmit: submit,
163
- submitCount,
164
- setSubmitCount,
165
- handleBlur,
166
- validate,
167
- isValidating,
168
- resetForm,
169
- version,
170
- debugId: debugIdRef.current
171
- };
172
-
173
- const controllerRef = React.useRef<FormexController<T>>(controller);
174
- controllerRef.current = controller;
175
- return controller
174
+ // Reset history with refs
175
+ historyRef.current = [valuesProp ?? initialValuesRef.current];
176
+ historyIndexRef.current = 0;
177
+ }, [onReset]);
178
+
179
+ const undo = useCallback(() => {
180
+ if (historyIndexRef.current > 0) {
181
+ const newIndex = historyIndexRef.current - 1;
182
+ const newValues = historyRef.current[newIndex];
183
+ setValuesInner(newValues);
184
+ valuesRef.current = newValues;
185
+ historyIndexRef.current = newIndex;
186
+ }
187
+ }, []);
188
+
189
+ const redo = useCallback(() => {
190
+ if (historyIndexRef.current < historyRef.current.length - 1) {
191
+ const newIndex = historyIndexRef.current + 1;
192
+ const newValues = historyRef.current[newIndex];
193
+ setValuesInner(newValues);
194
+ valuesRef.current = newValues;
195
+ historyIndexRef.current = newIndex;
196
+ }
197
+ }, []);
198
+
199
+ const controllerRef = useRef<FormexController<T>>({} as FormexController<T>);
200
+
201
+ const controller = useMemo<FormexController<T>>(
202
+ () => ({
203
+ values,
204
+ initialValues: initialValuesRef.current,
205
+ handleChange,
206
+ isSubmitting,
207
+ setSubmitting: setIsSubmitting,
208
+ setValues,
209
+ setFieldValue,
210
+ errors,
211
+ setFieldError,
212
+ touched: touchedState,
213
+ setFieldTouched,
214
+ dirty,
215
+ setDirty,
216
+ handleSubmit: submit,
217
+ submitCount,
218
+ setSubmitCount,
219
+ handleBlur,
220
+ validate,
221
+ isValidating,
222
+ resetForm,
223
+ version,
224
+ debugId: debugIdRef.current,
225
+ undo,
226
+ redo,
227
+ canUndo: historyIndexRef.current > 0,
228
+ canRedo: historyIndexRef.current < historyRef.current.length - 1,
229
+ }),
230
+ [
231
+ values,
232
+ errors,
233
+ touchedState,
234
+ dirty,
235
+ isSubmitting,
236
+ submitCount,
237
+ isValidating,
238
+ version,
239
+ handleChange,
240
+ handleBlur,
241
+ setValues,
242
+ setFieldValue,
243
+ setFieldTouched,
244
+ setFieldError,
245
+ validate,
246
+ submit,
247
+ resetForm,
248
+ undo,
249
+ redo,
250
+ ]
251
+ );
252
+
253
+ useEffect(() => {
254
+ controllerRef.current = controller;
255
+ }, [controller]);
256
+
257
+ return controller;
176
258
  }