@firecms/formex
Advanced tools
Comparing version 3.0.0-beta.8 to 3.0.0-beta.9
@@ -21,3 +21,2 @@ import * as React from "react"; | ||
} | ||
export type FieldValidator = (value: any) => string | void | Promise<string | void>; | ||
export interface FieldConfig<Value, C extends React.ElementType | undefined = undefined> { | ||
@@ -24,0 +23,0 @@ /** |
@@ -1,172 +0,307 @@ | ||
import * as x from "react"; | ||
import b, { useContext as Q, useState as h, useEffect as U } from "react"; | ||
import T from "react-fast-compare"; | ||
const D = b.createContext({}), X = () => Q(D), nt = D.Provider, st = (t) => Array.isArray(t) && t.length === 0, M = (t) => typeof t == "function", y = (t) => t !== null && typeof t == "object", Y = (t) => String(Math.floor(Number(t))) === t, ot = (t) => Object.prototype.toString.call(t) === "[object String]", ct = (t) => t !== t, ut = (t) => x.Children.count(t) === 0, it = (t) => y(t) && M(t.then), at = (t) => t && y(t) && y(t.target); | ||
function lt(t) { | ||
if (t = t || (typeof document < "u" ? document : void 0), typeof t > "u") | ||
import * as React from "react"; | ||
import React__default, { useContext, useState, useEffect } from "react"; | ||
import equal from "react-fast-compare"; | ||
const FormexContext = React__default.createContext({}); | ||
const useFormex = () => useContext(FormexContext); | ||
const Formex = FormexContext.Provider; | ||
const isEmptyArray = (value) => Array.isArray(value) && value.length === 0; | ||
const isFunction = (obj) => typeof obj === "function"; | ||
const isObject = (obj) => obj !== null && typeof obj === "object"; | ||
const isInteger = (obj) => String(Math.floor(Number(obj))) === obj; | ||
const isString = (obj) => Object.prototype.toString.call(obj) === "[object String]"; | ||
const isNaN = (obj) => obj !== obj; | ||
const isEmptyChildren = (children) => React.Children.count(children) === 0; | ||
const isPromise = (value) => isObject(value) && isFunction(value.then); | ||
const isInputEvent = (value) => value && isObject(value) && isObject(value.target); | ||
function getActiveElement(doc) { | ||
doc = doc || (typeof document !== "undefined" ? document : void 0); | ||
if (typeof doc === "undefined") { | ||
return null; | ||
} | ||
try { | ||
return t.activeElement || t.body; | ||
} catch { | ||
return t.body; | ||
return doc.activeElement || doc.body; | ||
} catch (e) { | ||
return doc.body; | ||
} | ||
} | ||
function F(t, a, n, u = 0) { | ||
const r = O(a); | ||
for (; t && u < r.length; ) | ||
t = t[r[u++]]; | ||
return u !== r.length && !t || t === void 0 ? n : t; | ||
function getIn(obj, key, def, p = 0) { | ||
const path = toPath(key); | ||
while (obj && p < path.length) { | ||
obj = obj[path[p++]]; | ||
} | ||
if (p !== path.length && !obj) { | ||
return def; | ||
} | ||
return obj === void 0 ? def : obj; | ||
} | ||
function Z(t, a, n) { | ||
const u = V(t); | ||
let r = u, e = 0; | ||
const i = O(a); | ||
for (; e < i.length - 1; e++) { | ||
const c = i[e], f = F(t, i.slice(0, e + 1)); | ||
if (f && (y(f) || Array.isArray(f))) | ||
r = r[c] = V(f); | ||
else { | ||
const d = i[e + 1]; | ||
r = r[c] = Y(d) && Number(d) >= 0 ? [] : {}; | ||
function setIn(obj, path, value) { | ||
const res = clone(obj); | ||
let resVal = res; | ||
let i = 0; | ||
const pathArray = toPath(path); | ||
for (; i < pathArray.length - 1; i++) { | ||
const currentPath = pathArray[i]; | ||
const currentObj = getIn(obj, pathArray.slice(0, i + 1)); | ||
if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) { | ||
resVal = resVal[currentPath] = clone(currentObj); | ||
} else { | ||
const nextPath = pathArray[i + 1]; | ||
resVal = resVal[currentPath] = isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {}; | ||
} | ||
} | ||
return (e === 0 ? t : r)[i[e]] === n ? t : (n === void 0 ? delete r[i[e]] : r[i[e]] = n, e === 0 && n === void 0 && delete u[i[e]], u); | ||
if ((i === 0 ? obj : resVal)[pathArray[i]] === value) { | ||
return obj; | ||
} | ||
if (value === void 0) { | ||
delete resVal[pathArray[i]]; | ||
} else { | ||
resVal[pathArray[i]] = value; | ||
} | ||
if (i === 0 && value === void 0) { | ||
delete res[pathArray[i]]; | ||
} | ||
return res; | ||
} | ||
function j(t, a, n = /* @__PURE__ */ new WeakMap(), u = {}) { | ||
for (const r of Object.keys(t)) { | ||
const e = t[r]; | ||
y(e) ? n.get(e) || (n.set(e, !0), u[r] = Array.isArray(e) ? [] : {}, j(e, a, n, u[r])) : u[r] = a; | ||
function setNestedObjectValues(object, value, visited = /* @__PURE__ */ new WeakMap(), response = {}) { | ||
for (const k of Object.keys(object)) { | ||
const val = object[k]; | ||
if (isObject(val)) { | ||
if (!visited.get(val)) { | ||
visited.set(val, true); | ||
response[k] = Array.isArray(val) ? [] : {}; | ||
setNestedObjectValues(val, value, visited, response[k]); | ||
} | ||
} else { | ||
response[k] = value; | ||
} | ||
} | ||
return u; | ||
return response; | ||
} | ||
function V(t) { | ||
return Array.isArray(t) ? [...t] : typeof t == "object" && t !== null ? { ...t } : t; | ||
function clone(value) { | ||
if (Array.isArray(value)) { | ||
return [...value]; | ||
} else if (typeof value === "object" && value !== null) { | ||
return { ...value }; | ||
} else { | ||
return value; | ||
} | ||
} | ||
function O(t) { | ||
return Array.isArray(t) ? t : t.replace(/\[(\d+)]/g, ".$1").replace(/^\./, "").replace(/\.$/, "").split("."); | ||
function toPath(value) { | ||
if (Array.isArray(value)) return value; | ||
return value.replace(/\[(\d+)]/g, ".$1").replace(/^\./, "").replace(/\.$/, "").split("."); | ||
} | ||
function ft({ | ||
validate: t, | ||
name: a, | ||
children: n, | ||
as: u, | ||
function Field({ | ||
validate, | ||
name, | ||
children, | ||
as: is, | ||
// `as` is reserved in typescript lol | ||
// component, | ||
className: r, | ||
...e | ||
className, | ||
...props | ||
}) { | ||
const i = X(), c = tt({ name: a, ...e }, i); | ||
if (M(n)) | ||
return n({ field: c, form: i }); | ||
const f = u || "input"; | ||
if (typeof f == "string") { | ||
const { innerRef: d, ...p } = e; | ||
return x.createElement( | ||
f, | ||
{ ref: d, ...c, ...p, className: r }, | ||
n | ||
const formex = useFormex(); | ||
const field = getFieldProps({ name, ...props }, formex); | ||
if (isFunction(children)) { | ||
return children({ field, form: formex }); | ||
} | ||
const asElement = is || "input"; | ||
if (typeof asElement === "string") { | ||
const { innerRef, ...rest } = props; | ||
return React.createElement( | ||
asElement, | ||
{ ref: innerRef, ...field, ...rest, className }, | ||
children | ||
); | ||
} | ||
return x.createElement(f, { ...c, ...e, className: r }, n); | ||
return React.createElement(asElement, { ...field, ...props, className }, children); | ||
} | ||
const tt = (t, a) => { | ||
const n = y(t), u = n ? t.name : t, r = F(a.values, u), e = { | ||
name: u, | ||
value: r, | ||
onChange: a.handleChange, | ||
onBlur: a.handleBlur | ||
const getFieldProps = (nameOrOptions, formex) => { | ||
const isAnObject = isObject(nameOrOptions); | ||
const name = isAnObject ? nameOrOptions.name : nameOrOptions; | ||
const valueState = getIn(formex.values, name); | ||
const field = { | ||
name, | ||
value: valueState, | ||
onChange: formex.handleChange, | ||
onBlur: formex.handleBlur | ||
}; | ||
if (n) { | ||
if (isAnObject) { | ||
const { | ||
type: i, | ||
value: c, | ||
type, | ||
value: valueProp, | ||
// value is special for checkboxes | ||
as: f, | ||
multiple: d | ||
} = t; | ||
i === "checkbox" ? c === void 0 ? e.checked = !!r : (e.checked = !!(Array.isArray(r) && ~r.indexOf(c)), e.value = c) : i === "radio" ? (e.checked = r === c, e.value = c) : f === "select" && d && (e.value = e.value || [], e.multiple = !0); | ||
as: is, | ||
multiple | ||
} = nameOrOptions; | ||
if (type === "checkbox") { | ||
if (valueProp === void 0) { | ||
field.checked = !!valueState; | ||
} else { | ||
field.checked = !!(Array.isArray(valueState) && ~valueState.indexOf(valueProp)); | ||
field.value = valueProp; | ||
} | ||
} else if (type === "radio") { | ||
field.checked = valueState === valueProp; | ||
field.value = valueProp; | ||
} else if (is === "select" && multiple) { | ||
field.value = field.value || []; | ||
field.multiple = true; | ||
} | ||
} | ||
return e; | ||
return field; | ||
}; | ||
function dt({ initialValues: t, initialErrors: a, validation: n, validateOnChange: u = !1, onSubmit: r, validateOnInitialRender: e = !1 }) { | ||
const i = b.useRef(t), c = b.useRef(t), [f, d] = h(t), [p, R] = h({}), [k, g] = h(a ?? {}), [_, A] = h(!1), [I, C] = h(0), [$, S] = h(!1), [q, w] = h(!1); | ||
U(() => { | ||
e && E(); | ||
function useCreateFormex({ | ||
initialValues, | ||
initialErrors, | ||
validation, | ||
validateOnChange = false, | ||
onSubmit, | ||
validateOnInitialRender = false | ||
}) { | ||
const initialValuesRef = React__default.useRef(initialValues); | ||
const valuesRef = React__default.useRef(initialValues); | ||
const [values, setValuesInner] = useState(initialValues); | ||
const [touchedState, setTouchedState] = useState({}); | ||
const [errors, setErrors] = useState(initialErrors ?? {}); | ||
const [dirty, setDirty] = useState(false); | ||
const [submitCount, setSubmitCount] = useState(0); | ||
const [isSubmitting, setIsSubmitting] = useState(false); | ||
const [isValidating, setIsValidating] = useState(false); | ||
const [version, setVersion] = useState(0); | ||
useEffect(() => { | ||
if (validateOnInitialRender) { | ||
validate(); | ||
} | ||
}, []); | ||
const W = (s) => { | ||
c.current = s, d(s), A(T(i.current, s)); | ||
}, E = async () => { | ||
w(!0); | ||
const s = c.current, o = await n?.(s); | ||
return g(o ?? {}), w(!1), o; | ||
}, N = (s, o, l) => { | ||
const m = Z(c.current, s, o); | ||
c.current = m, d(m), T(F(i.current, s), o) || A(!0), l && E(); | ||
}, z = (s, o) => { | ||
const l = { ...k }; | ||
o ? l[s] = o : delete l[s], g(l); | ||
}, v = (s, o, l) => { | ||
const m = { ...p }; | ||
m[s] = o, R(m), l && E(); | ||
}, G = (s) => { | ||
const o = s.target, l = o.type === "checkbox" ? o.checked : o.value, m = o.name; | ||
N(m, l, u), v(m, !0); | ||
}, H = (s) => { | ||
const l = s.target.name; | ||
v(l, !0); | ||
}, J = async (s) => { | ||
s?.preventDefault(), s?.stopPropagation(), S(!0), C(I + 1); | ||
const o = await n?.(c.current); | ||
o && Object.keys(o).length > 0 ? g(o) : (g({}), await r?.(c.current, B.current)), S(!1); | ||
}, K = (s) => { | ||
const setValues = (newValues) => { | ||
valuesRef.current = newValues; | ||
setValuesInner(newValues); | ||
setDirty(equal(initialValuesRef.current, newValues)); | ||
}; | ||
const validate = async () => { | ||
setIsValidating(true); | ||
const values2 = valuesRef.current; | ||
const validationErrors = await validation?.(values2); | ||
setErrors(validationErrors ?? {}); | ||
setIsValidating(false); | ||
return validationErrors; | ||
}; | ||
const setFieldValue = (key, value, shouldValidate) => { | ||
const newValues = setIn(valuesRef.current, key, value); | ||
valuesRef.current = newValues; | ||
setValuesInner(newValues); | ||
if (!equal(getIn(initialValuesRef.current, key), value)) { | ||
setDirty(true); | ||
} | ||
if (shouldValidate) { | ||
validate(); | ||
} | ||
}; | ||
const setFieldError = (key, error) => { | ||
const newErrors = { ...errors }; | ||
if (error) { | ||
newErrors[key] = error; | ||
} else { | ||
delete newErrors[key]; | ||
} | ||
setErrors(newErrors); | ||
}; | ||
const setFieldTouched = (key, touched, shouldValidate) => { | ||
const newTouched = { ...touchedState }; | ||
newTouched[key] = touched; | ||
setTouchedState(newTouched); | ||
if (shouldValidate) { | ||
validate(); | ||
} | ||
}; | ||
const handleChange = (event) => { | ||
const target = event.target; | ||
const value = target.type === "checkbox" ? target.checked : target.value; | ||
const name = target.name; | ||
setFieldValue(name, value, validateOnChange); | ||
setFieldTouched(name, true); | ||
}; | ||
const handleBlur = (event) => { | ||
const target = event.target; | ||
const name = target.name; | ||
setFieldTouched(name, true); | ||
}; | ||
const submit = async (e) => { | ||
e?.preventDefault(); | ||
e?.stopPropagation(); | ||
setIsSubmitting(true); | ||
setSubmitCount(submitCount + 1); | ||
const validationErrors = await validation?.(valuesRef.current); | ||
if (validationErrors && Object.keys(validationErrors).length > 0) { | ||
setErrors(validationErrors); | ||
} else { | ||
setErrors({}); | ||
await onSubmit?.(valuesRef.current, controllerRef.current); | ||
} | ||
setIsSubmitting(false); | ||
setVersion(version + 1); | ||
}; | ||
const resetForm = (props) => { | ||
const { | ||
submitCount: o, | ||
values: l, | ||
errors: m, | ||
touched: L | ||
} = s ?? {}; | ||
i.current = l ?? t, c.current = l ?? t, d(l ?? t), g(m ?? {}), R(L ?? {}), A(!1), C(o ?? 0); | ||
}, P = { | ||
values: f, | ||
initialValues: i.current, | ||
handleChange: G, | ||
isSubmitting: $, | ||
setSubmitting: S, | ||
setValues: W, | ||
setFieldValue: N, | ||
errors: k, | ||
setFieldError: z, | ||
touched: p, | ||
setFieldTouched: v, | ||
dirty: _, | ||
setDirty: A, | ||
handleSubmit: J, | ||
submitCount: I, | ||
setSubmitCount: C, | ||
handleBlur: H, | ||
validate: E, | ||
isValidating: q, | ||
resetForm: K | ||
}, B = b.useRef(P); | ||
return B.current = P, P; | ||
submitCount: submitCountProp, | ||
values: valuesProp, | ||
errors: errorsProp, | ||
touched: touchedProp | ||
} = props ?? {}; | ||
initialValuesRef.current = valuesProp ?? initialValues; | ||
valuesRef.current = valuesProp ?? initialValues; | ||
setValuesInner(valuesProp ?? initialValues); | ||
setErrors(errorsProp ?? {}); | ||
setTouchedState(touchedProp ?? {}); | ||
setDirty(false); | ||
setSubmitCount(submitCountProp ?? 0); | ||
setVersion(version + 1); | ||
}; | ||
const controller = { | ||
values, | ||
initialValues: initialValuesRef.current, | ||
handleChange, | ||
isSubmitting, | ||
setSubmitting: setIsSubmitting, | ||
setValues, | ||
setFieldValue, | ||
errors, | ||
setFieldError, | ||
touched: touchedState, | ||
setFieldTouched, | ||
dirty, | ||
setDirty, | ||
handleSubmit: submit, | ||
submitCount, | ||
setSubmitCount, | ||
handleBlur, | ||
validate, | ||
isValidating, | ||
resetForm, | ||
version | ||
}; | ||
const controllerRef = React__default.useRef(controller); | ||
controllerRef.current = controller; | ||
return controller; | ||
} | ||
export { | ||
ft as Field, | ||
nt as Formex, | ||
lt as getActiveElement, | ||
F as getIn, | ||
st as isEmptyArray, | ||
ut as isEmptyChildren, | ||
M as isFunction, | ||
at as isInputEvent, | ||
Y as isInteger, | ||
ct as isNaN, | ||
y as isObject, | ||
it as isPromise, | ||
ot as isString, | ||
Z as setIn, | ||
j as setNestedObjectValues, | ||
dt as useCreateFormex, | ||
X as useFormex | ||
Field, | ||
Formex, | ||
getActiveElement, | ||
getIn, | ||
isEmptyArray, | ||
isEmptyChildren, | ||
isFunction, | ||
isInputEvent, | ||
isInteger, | ||
isNaN, | ||
isObject, | ||
isPromise, | ||
isString, | ||
setIn, | ||
setNestedObjectValues, | ||
useCreateFormex, | ||
useFormex | ||
}; | ||
//# sourceMappingURL=index.es.js.map |
@@ -1,2 +0,325 @@ | ||
(function(s,f){typeof exports=="object"&&typeof module<"u"?f(exports,require("react"),require("react-fast-compare")):typeof define=="function"&&define.amd?define(["exports","react","react-fast-compare"],f):(s=typeof globalThis<"u"?globalThis:s||self,f(s.Formex={},s.React,s.equal))})(this,function(s,f,k){"use strict";function x(e){const a=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e){for(const n in e)if(n!=="default"){const c=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(a,n,c.get?c:{enumerable:!0,get:()=>e[n]})}}return a.default=e,Object.freeze(a)}const F=x(f),N=f.createContext({}),w=()=>f.useContext(N),G=N.Provider,H=e=>Array.isArray(e)&&e.length===0,v=e=>typeof e=="function",h=e=>e!==null&&typeof e=="object",T=e=>String(Math.floor(Number(e)))===e,J=e=>Object.prototype.toString.call(e)==="[object String]",K=e=>e!==e,L=e=>F.Children.count(e)===0,Q=e=>h(e)&&v(e.then),U=e=>e&&h(e)&&h(e.target);function X(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function b(e,a,n,c=0){const r=V(a);for(;e&&c<r.length;)e=e[r[c++]];return c!==r.length&&!e||e===void 0?n:e}function j(e,a,n){const c=M(e);let r=c,t=0;const l=V(a);for(;t<l.length-1;t++){const u=l[t],m=b(e,l.slice(0,t+1));if(m&&(h(m)||Array.isArray(m)))r=r[u]=M(m);else{const y=l[t+1];r=r[u]=T(y)&&Number(y)>=0?[]:{}}}return(t===0?e:r)[l[t]]===n?e:(n===void 0?delete r[l[t]]:r[l[t]]=n,t===0&&n===void 0&&delete c[l[t]],c)}function D(e,a,n=new WeakMap,c={}){for(const r of Object.keys(e)){const t=e[r];h(t)?n.get(t)||(n.set(t,!0),c[r]=Array.isArray(t)?[]:{},D(t,a,n,c[r])):c[r]=a}return c}function M(e){return Array.isArray(e)?[...e]:typeof e=="object"&&e!==null?{...e}:e}function V(e){return Array.isArray(e)?e:e.replace(/\[(\d+)]/g,".$1").replace(/^\./,"").replace(/\.$/,"").split(".")}function Y({validate:e,name:a,children:n,as:c,className:r,...t}){const l=w(),u=Z({name:a,...t},l);if(v(n))return n({field:u,form:l});const m=c||"input";if(typeof m=="string"){const{innerRef:y,...p}=t;return F.createElement(m,{ref:y,...u,...p,className:r},n)}return F.createElement(m,{...u,...t,className:r},n)}const Z=(e,a)=>{const n=h(e),c=n?e.name:e,r=b(a.values,c),t={name:c,value:r,onChange:a.handleChange,onBlur:a.handleBlur};if(n){const{type:l,value:u,as:m,multiple:y}=e;l==="checkbox"?u===void 0?t.checked=!!r:(t.checked=!!(Array.isArray(r)&&~r.indexOf(u)),t.value=u):l==="radio"?(t.checked=r===u,t.value=u):m==="select"&&y&&(t.value=t.value||[],t.multiple=!0)}return t};function R({initialValues:e,initialErrors:a,validation:n,validateOnChange:c=!1,onSubmit:r,validateOnInitialRender:t=!1}){const l=f.useRef(e),u=f.useRef(e),[m,y]=f.useState(e),[p,B]=f.useState({}),[_,S]=f.useState(a??{}),[ee,A]=f.useState(!1),[q,P]=f.useState(0),[te,C]=f.useState(!1),[ne,$]=f.useState(!1);f.useEffect(()=>{t&&E()},[]);const re=o=>{u.current=o,y(o),A(k(l.current,o))},E=async()=>{$(!0);const o=u.current,i=await n?.(o);return S(i??{}),$(!1),i},z=(o,i,d)=>{const g=j(u.current,o,i);u.current=g,y(g),k(b(l.current,o),i)||A(!0),d&&E()},se=(o,i)=>{const d={..._};i?d[o]=i:delete d[o],S(d)},I=(o,i,d)=>{const g={...p};g[o]=i,B(g),d&&E()},ce=o=>{const i=o.target,d=i.type==="checkbox"?i.checked:i.value,g=i.name;z(g,d,c),I(g,!0)},oe=o=>{const d=o.target.name;I(d,!0)},ie=async o=>{o?.preventDefault(),o?.stopPropagation(),C(!0),P(q+1);const i=await n?.(u.current);i&&Object.keys(i).length>0?S(i):(S({}),await r?.(u.current,W.current)),C(!1)},ue=o=>{const{submitCount:i,values:d,errors:g,touched:ae}=o??{};l.current=d??e,u.current=d??e,y(d??e),S(g??{}),B(ae??{}),A(!1),P(i??0)},O={values:m,initialValues:l.current,handleChange:ce,isSubmitting:te,setSubmitting:C,setValues:re,setFieldValue:z,errors:_,setFieldError:se,touched:p,setFieldTouched:I,dirty:ee,setDirty:A,handleSubmit:ie,submitCount:q,setSubmitCount:P,handleBlur:oe,validate:E,isValidating:ne,resetForm:ue},W=f.useRef(O);return W.current=O,O}s.Field=Y,s.Formex=G,s.getActiveElement=X,s.getIn=b,s.isEmptyArray=H,s.isEmptyChildren=L,s.isFunction=v,s.isInputEvent=U,s.isInteger=T,s.isNaN=K,s.isObject=h,s.isPromise=Q,s.isString=J,s.setIn=j,s.setNestedObjectValues=D,s.useCreateFormex=R,s.useFormex=w,Object.defineProperty(s,Symbol.toStringTag,{value:"Module"})}); | ||
(function(global, factory) { | ||
typeof exports === "object" && typeof module !== "undefined" ? factory(exports, require("react"), require("react-fast-compare")) : typeof define === "function" && define.amd ? define(["exports", "react", "react-fast-compare"], factory) : (global = typeof globalThis !== "undefined" ? globalThis : global || self, factory(global.Formex = {}, global.React, global.equal)); | ||
})(this, function(exports2, React, equal) { | ||
"use strict"; | ||
function _interopNamespaceDefault(e) { | ||
const n = Object.create(null, { [Symbol.toStringTag]: { value: "Module" } }); | ||
if (e) { | ||
for (const k in e) { | ||
if (k !== "default") { | ||
const d = Object.getOwnPropertyDescriptor(e, k); | ||
Object.defineProperty(n, k, d.get ? d : { | ||
enumerable: true, | ||
get: () => e[k] | ||
}); | ||
} | ||
} | ||
} | ||
n.default = e; | ||
return Object.freeze(n); | ||
} | ||
const React__namespace = /* @__PURE__ */ _interopNamespaceDefault(React); | ||
const FormexContext = React.createContext({}); | ||
const useFormex = () => React.useContext(FormexContext); | ||
const Formex = FormexContext.Provider; | ||
const isEmptyArray = (value) => Array.isArray(value) && value.length === 0; | ||
const isFunction = (obj) => typeof obj === "function"; | ||
const isObject = (obj) => obj !== null && typeof obj === "object"; | ||
const isInteger = (obj) => String(Math.floor(Number(obj))) === obj; | ||
const isString = (obj) => Object.prototype.toString.call(obj) === "[object String]"; | ||
const isNaN = (obj) => obj !== obj; | ||
const isEmptyChildren = (children) => React__namespace.Children.count(children) === 0; | ||
const isPromise = (value) => isObject(value) && isFunction(value.then); | ||
const isInputEvent = (value) => value && isObject(value) && isObject(value.target); | ||
function getActiveElement(doc) { | ||
doc = doc || (typeof document !== "undefined" ? document : void 0); | ||
if (typeof doc === "undefined") { | ||
return null; | ||
} | ||
try { | ||
return doc.activeElement || doc.body; | ||
} catch (e) { | ||
return doc.body; | ||
} | ||
} | ||
function getIn(obj, key, def, p = 0) { | ||
const path = toPath(key); | ||
while (obj && p < path.length) { | ||
obj = obj[path[p++]]; | ||
} | ||
if (p !== path.length && !obj) { | ||
return def; | ||
} | ||
return obj === void 0 ? def : obj; | ||
} | ||
function setIn(obj, path, value) { | ||
const res = clone(obj); | ||
let resVal = res; | ||
let i = 0; | ||
const pathArray = toPath(path); | ||
for (; i < pathArray.length - 1; i++) { | ||
const currentPath = pathArray[i]; | ||
const currentObj = getIn(obj, pathArray.slice(0, i + 1)); | ||
if (currentObj && (isObject(currentObj) || Array.isArray(currentObj))) { | ||
resVal = resVal[currentPath] = clone(currentObj); | ||
} else { | ||
const nextPath = pathArray[i + 1]; | ||
resVal = resVal[currentPath] = isInteger(nextPath) && Number(nextPath) >= 0 ? [] : {}; | ||
} | ||
} | ||
if ((i === 0 ? obj : resVal)[pathArray[i]] === value) { | ||
return obj; | ||
} | ||
if (value === void 0) { | ||
delete resVal[pathArray[i]]; | ||
} else { | ||
resVal[pathArray[i]] = value; | ||
} | ||
if (i === 0 && value === void 0) { | ||
delete res[pathArray[i]]; | ||
} | ||
return res; | ||
} | ||
function setNestedObjectValues(object, value, visited = /* @__PURE__ */ new WeakMap(), response = {}) { | ||
for (const k of Object.keys(object)) { | ||
const val = object[k]; | ||
if (isObject(val)) { | ||
if (!visited.get(val)) { | ||
visited.set(val, true); | ||
response[k] = Array.isArray(val) ? [] : {}; | ||
setNestedObjectValues(val, value, visited, response[k]); | ||
} | ||
} else { | ||
response[k] = value; | ||
} | ||
} | ||
return response; | ||
} | ||
function clone(value) { | ||
if (Array.isArray(value)) { | ||
return [...value]; | ||
} else if (typeof value === "object" && value !== null) { | ||
return { ...value }; | ||
} else { | ||
return value; | ||
} | ||
} | ||
function toPath(value) { | ||
if (Array.isArray(value)) return value; | ||
return value.replace(/\[(\d+)]/g, ".$1").replace(/^\./, "").replace(/\.$/, "").split("."); | ||
} | ||
function Field({ | ||
validate, | ||
name, | ||
children, | ||
as: is, | ||
// `as` is reserved in typescript lol | ||
// component, | ||
className, | ||
...props | ||
}) { | ||
const formex = useFormex(); | ||
const field = getFieldProps({ name, ...props }, formex); | ||
if (isFunction(children)) { | ||
return children({ field, form: formex }); | ||
} | ||
const asElement = is || "input"; | ||
if (typeof asElement === "string") { | ||
const { innerRef, ...rest } = props; | ||
return React__namespace.createElement( | ||
asElement, | ||
{ ref: innerRef, ...field, ...rest, className }, | ||
children | ||
); | ||
} | ||
return React__namespace.createElement(asElement, { ...field, ...props, className }, children); | ||
} | ||
const getFieldProps = (nameOrOptions, formex) => { | ||
const isAnObject = isObject(nameOrOptions); | ||
const name = isAnObject ? nameOrOptions.name : nameOrOptions; | ||
const valueState = getIn(formex.values, name); | ||
const field = { | ||
name, | ||
value: valueState, | ||
onChange: formex.handleChange, | ||
onBlur: formex.handleBlur | ||
}; | ||
if (isAnObject) { | ||
const { | ||
type, | ||
value: valueProp, | ||
// value is special for checkboxes | ||
as: is, | ||
multiple | ||
} = nameOrOptions; | ||
if (type === "checkbox") { | ||
if (valueProp === void 0) { | ||
field.checked = !!valueState; | ||
} else { | ||
field.checked = !!(Array.isArray(valueState) && ~valueState.indexOf(valueProp)); | ||
field.value = valueProp; | ||
} | ||
} else if (type === "radio") { | ||
field.checked = valueState === valueProp; | ||
field.value = valueProp; | ||
} else if (is === "select" && multiple) { | ||
field.value = field.value || []; | ||
field.multiple = true; | ||
} | ||
} | ||
return field; | ||
}; | ||
function useCreateFormex({ | ||
initialValues, | ||
initialErrors, | ||
validation, | ||
validateOnChange = false, | ||
onSubmit, | ||
validateOnInitialRender = false | ||
}) { | ||
const initialValuesRef = React.useRef(initialValues); | ||
const valuesRef = React.useRef(initialValues); | ||
const [values, setValuesInner] = React.useState(initialValues); | ||
const [touchedState, setTouchedState] = React.useState({}); | ||
const [errors, setErrors] = React.useState(initialErrors ?? {}); | ||
const [dirty, setDirty] = React.useState(false); | ||
const [submitCount, setSubmitCount] = React.useState(0); | ||
const [isSubmitting, setIsSubmitting] = React.useState(false); | ||
const [isValidating, setIsValidating] = React.useState(false); | ||
const [version, setVersion] = React.useState(0); | ||
React.useEffect(() => { | ||
if (validateOnInitialRender) { | ||
validate(); | ||
} | ||
}, []); | ||
const setValues = (newValues) => { | ||
valuesRef.current = newValues; | ||
setValuesInner(newValues); | ||
setDirty(equal(initialValuesRef.current, newValues)); | ||
}; | ||
const validate = async () => { | ||
setIsValidating(true); | ||
const values2 = valuesRef.current; | ||
const validationErrors = await validation?.(values2); | ||
setErrors(validationErrors ?? {}); | ||
setIsValidating(false); | ||
return validationErrors; | ||
}; | ||
const setFieldValue = (key, value, shouldValidate) => { | ||
const newValues = setIn(valuesRef.current, key, value); | ||
valuesRef.current = newValues; | ||
setValuesInner(newValues); | ||
if (!equal(getIn(initialValuesRef.current, key), value)) { | ||
setDirty(true); | ||
} | ||
if (shouldValidate) { | ||
validate(); | ||
} | ||
}; | ||
const setFieldError = (key, error) => { | ||
const newErrors = { ...errors }; | ||
if (error) { | ||
newErrors[key] = error; | ||
} else { | ||
delete newErrors[key]; | ||
} | ||
setErrors(newErrors); | ||
}; | ||
const setFieldTouched = (key, touched, shouldValidate) => { | ||
const newTouched = { ...touchedState }; | ||
newTouched[key] = touched; | ||
setTouchedState(newTouched); | ||
if (shouldValidate) { | ||
validate(); | ||
} | ||
}; | ||
const handleChange = (event) => { | ||
const target = event.target; | ||
const value = target.type === "checkbox" ? target.checked : target.value; | ||
const name = target.name; | ||
setFieldValue(name, value, validateOnChange); | ||
setFieldTouched(name, true); | ||
}; | ||
const handleBlur = (event) => { | ||
const target = event.target; | ||
const name = target.name; | ||
setFieldTouched(name, true); | ||
}; | ||
const submit = async (e) => { | ||
e?.preventDefault(); | ||
e?.stopPropagation(); | ||
setIsSubmitting(true); | ||
setSubmitCount(submitCount + 1); | ||
const validationErrors = await validation?.(valuesRef.current); | ||
if (validationErrors && Object.keys(validationErrors).length > 0) { | ||
setErrors(validationErrors); | ||
} else { | ||
setErrors({}); | ||
await onSubmit?.(valuesRef.current, controllerRef.current); | ||
} | ||
setIsSubmitting(false); | ||
setVersion(version + 1); | ||
}; | ||
const resetForm = (props) => { | ||
const { | ||
submitCount: submitCountProp, | ||
values: valuesProp, | ||
errors: errorsProp, | ||
touched: touchedProp | ||
} = props ?? {}; | ||
initialValuesRef.current = valuesProp ?? initialValues; | ||
valuesRef.current = valuesProp ?? initialValues; | ||
setValuesInner(valuesProp ?? initialValues); | ||
setErrors(errorsProp ?? {}); | ||
setTouchedState(touchedProp ?? {}); | ||
setDirty(false); | ||
setSubmitCount(submitCountProp ?? 0); | ||
setVersion(version + 1); | ||
}; | ||
const controller = { | ||
values, | ||
initialValues: initialValuesRef.current, | ||
handleChange, | ||
isSubmitting, | ||
setSubmitting: setIsSubmitting, | ||
setValues, | ||
setFieldValue, | ||
errors, | ||
setFieldError, | ||
touched: touchedState, | ||
setFieldTouched, | ||
dirty, | ||
setDirty, | ||
handleSubmit: submit, | ||
submitCount, | ||
setSubmitCount, | ||
handleBlur, | ||
validate, | ||
isValidating, | ||
resetForm, | ||
version | ||
}; | ||
const controllerRef = React.useRef(controller); | ||
controllerRef.current = controller; | ||
return controller; | ||
} | ||
exports2.Field = Field; | ||
exports2.Formex = Formex; | ||
exports2.getActiveElement = getActiveElement; | ||
exports2.getIn = getIn; | ||
exports2.isEmptyArray = isEmptyArray; | ||
exports2.isEmptyChildren = isEmptyChildren; | ||
exports2.isFunction = isFunction; | ||
exports2.isInputEvent = isInputEvent; | ||
exports2.isInteger = isInteger; | ||
exports2.isNaN = isNaN; | ||
exports2.isObject = isObject; | ||
exports2.isPromise = isPromise; | ||
exports2.isString = isString; | ||
exports2.setIn = setIn; | ||
exports2.setNestedObjectValues = setNestedObjectValues; | ||
exports2.useCreateFormex = useCreateFormex; | ||
exports2.useFormex = useFormex; | ||
Object.defineProperty(exports2, Symbol.toStringTag, { value: "Module" }); | ||
}); | ||
//# sourceMappingURL=index.umd.js.map |
@@ -23,2 +23,7 @@ import React, { FormEvent } from "react"; | ||
isValidating: boolean; | ||
/** | ||
* The version of the form. This is incremented every time the form is reset | ||
* or the form is submitted. | ||
*/ | ||
version: number; | ||
}; | ||
@@ -25,0 +30,0 @@ export type FormexResetProps<T extends object> = { |
{ | ||
"name": "@firecms/formex", | ||
"type": "module", | ||
"version": "3.0.0-beta.8", | ||
"version": "3.0.0-beta.9", | ||
"publishConfig": { | ||
@@ -41,9 +41,9 @@ "access": "public" | ||
"@types/jest": "^29.5.12", | ||
"@types/node": "^20.14.9", | ||
"@types/node": "^20.14.12", | ||
"@types/react": "^18.3.3", | ||
"@types/react-dom": "^18.3.0", | ||
"jest": "^29.7.0", | ||
"ts-jest": "^29.1.5", | ||
"typescript": "^5.5.3", | ||
"vite": "^5.3.2" | ||
"ts-jest": "^29.2.3", | ||
"typescript": "^5.5.4", | ||
"vite": "^5.3.4" | ||
}, | ||
@@ -76,3 +76,3 @@ "scripts": { | ||
}, | ||
"gitHead": "4ef14d60f86cb2e581b908a1dc84ad6a87b14e2e" | ||
"gitHead": "a2fffa74049d185e674aae9f70b462f011edd1c2" | ||
} |
@@ -24,2 +24,7 @@ import React, { FormEvent } from "react"; | ||
isValidating: boolean; | ||
/** | ||
* The version of the form. This is incremented every time the form is reset | ||
* or the form is submitted. | ||
*/ | ||
version: number; | ||
} | ||
@@ -26,0 +31,0 @@ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Minified code
QualityThis package contains minified code. This may be harmless in some cases where minified code is included in packaged libraries, however packages on npm should not minify code.
Found 1 instance in 1 package
98044
1250
2