vue-formify
Version:
Build powerful, type-safe forms in Vue.
2 lines (1 loc) • 12.8 kB
JavaScript
(function(T,u){typeof exports=="object"&&typeof module<"u"?u(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],u):(T=typeof globalThis<"u"?globalThis:T||self,u(T.VueFormify={},T.Vue))})(this,function(T,u){"use strict";const l=u.reactive({}),k=/^\[(.+?)\]$/gm,x=/(^.*\[|\].*$)/g,C=/\[(\d*)\]/gm,I=/\[(\d+)\]/,$=/\[\d+\]/,Q=(e,t,a)=>{if(e&&!(e in l[t].values)){const n=U(e,a);l[t].values=b(l[t].values,n)}},Z=(e,t)=>{let a=e.as||"";return!e.as&&!t&&(a="input"),a},ee=(e,t,a)=>t.default?typeof e=="string"||!e?t.default(a()):{default:()=>t.default?.(a())}:t.default,U=(e,t)=>{const a=e.match(k);return a?{[a[0].replace(x,"")]:t}:e.split(".").reduceRight((i,o)=>{const s=o.match(C),y=o.replace($,""),p=o.match(I)?.[1];return s?{[y]:{value:{[`[${p}]`]:i}}}:{[o]:i}},t)},j=(e,t="")=>{let a={};for(const n in e){const r=t?`${t}.${n}`:n;if(typeof e[n]=="object"&&e[n]!==null&&!Array.isArray(e[n])){const i=j(e[n],r);a={...a,...i}}else a[r]=e[n]}return a},f=(e,t)=>{if(!t)return;const a=t.match(k);if(a){const o=a[0].replace(x,"");return e[o]}let n=e;const r=t.split("."),i=r.pop();for(const o of r){if(o.match(C)){const y=o.replace($,""),p=o.match(I)?.[1];n=n?.[y]?.value?.[`[${p}]`]}else n=n[o];if(!n)return}if(i&&i.match(C)){const s=i.replace($,""),y=i.match(I)?.[1];return i&&n?.[s]?.value?.[`[${y}]`]}return i&&n[i]},M=(e,t)=>{const a=t.match(k);if(a){const o=a[0].replace(x,"");delete e[o]}let n=e;const r=t.split("."),i=r.pop();for(const o of r){if(o.match(C)){const y=o.replace($,""),p=o.match(I)?.[1];n=n?.[y]?.value?.[`[${p}]`]}else n=n[o];if(!n)return}if(i){if(i.match(C)){const s=i.replace($,""),y=i.match(I)?.[1];delete n?.[s]?.value?.[`[${y}]`],n?.[s]?.value&&!Object.keys(n?.[s]?.value).length&&(n[s].value=[])}else delete n[i];Object.keys(n).length===0&&M(e,r.join("."))}};function P(e){return typeof e=="boolean"?e:Array.isArray(e)?e.every(t=>P(t)):typeof e=="object"&&e!==null?Object.values(e).every(t=>P(t)):!1}function G(e){return typeof e=="string"&&e?!0:Array.isArray(e)?e.some(t=>G(t)):typeof e=="object"&&e!==null?Object.values(e).some(t=>G(t)):!1}const Y=(e,t)=>f(e,t)?.error,F=(e,t="value")=>{const a={};for(const n in e)if(e[n]&&typeof e[n]=="object"&&"value"in e[n])if(typeof e[n].value=="object")if(Array.isArray(e[n].value)&&(a[n]=[]),Object.keys(e[n].value)?.[0]?.match?.(k))for(const r in e[n].value)!a[n]&&!e[n].ignore&&(a[n]=[]),t in e[n].value[r]?e[n].value[r][t]&&a[n].push(e[n].value[r][t]):!e[n].ignore&&a[n].push(F(e[n].value[r],t));else!e[n].ignore&&(a[n]=e[n][t]);else!e[n].ignore&&(a[n]=e[n][t]);else typeof e[n]=="object"&&(a[n]=F(e[n],t));return a},te=e=>{const t=[];if(!Array.isArray(e.value)&&typeof e.value=="object"&&!(e.value instanceof Date))for(const a in e.value)t.push(e.value[a].value);else return e.value||typeof e.value=="boolean"?e.value:"";return t},b=(...e)=>{const t=a=>a&&typeof a=="object";return e.reduce((a,n)=>(Object.keys(n).forEach(r=>{const i=a[r],o=n[r];Array.isArray(i)&&Array.isArray(o)?a[r]=i.concat(...o):t(i)&&t(o)?a[r]=b(i,o):a[r]=o}),a),{})},z=(e,t="")=>{const a=new FormData;return Object.keys(e).reduce((n,r)=>{const i=t?`${t}.${r}`:r;if(typeof e[r]=="object"&&e[r]!==null&&!Array.isArray(e[r])&&!(e[r]instanceof Date)&&!(e[r]instanceof File)&&!(e[r]instanceof Blob)){const o=z(e[r],i);n+=o}else Array.isArray(e[r])?e[r].forEach(o=>{a.append(`${i}[]`,o)}):a.append(`${i}`,e[r]);return n},""),a},ae=e=>{if(e.path?.length){let t="";for(const a of e.path){const n=typeof a=="object"?a.key:a;if(typeof n=="string")t?t+=`.${n}`:t+=n;else if(typeof n=="number")t+=`[${n}]`;else return null}return t}return null},ne=async e=>{try{return await e}catch{return}};class _{static eventListeners={};static on(t,a){this.eventListeners[t]||(this.eventListeners[t]=[]),this.eventListeners[t].push(a)}static off(t,a){const n=this.eventListeners[t];n&&(this.eventListeners[t]=n.filter(r=>r!==a))}static emit(t,a){const n=this.eventListeners[t];n&&n.forEach(r=>r(a))}}const J=async(e,t,a,n)=>{const r=await e["~standard"].validate(t);if(r.issues){for(const i of r.issues)a(n||ae(i),i.message);return!1}return!0},X=(e,t=!1)=>{const{uid:a,preserveForm:n,mode:r,isSubmitted:i}=u.inject("formData",Object.create({})),o=u.getCurrentInstance(),s=e.name,y={value:f(l[a].values,s)?.value??void 0,error:void 0,ignore:e.ignore,isDirty:!1,isTouched:!1,isValid:!0},p=u.computed({get(){if(d.value)return d.value.value},set(c){if(t||Array.isArray(c)){d.value.value=[];for(let g=0;g<c.length;g++)H({[`[${g}]`]:{value:c[g]}},s);return d.value.value}d.value.value=c||typeof c=="boolean"?c:""}}),d=u.computed(()=>f(l[a].values,s)),h=u.computed(()=>!(d.value?.error&&(d.value.isDirty||i.value||r==="onSubmit"))),m=u.computed(()=>d.value?.isTouched),V=u.computed(()=>d.value?.isDirty),A=u.computed(()=>te(p)),B=()=>{if(t||Array.isArray(f(l[a].initialValues,s))){if(f(l[a].initialValues,s)){const c=f(l[a].initialValues,s);let g={};for(let R=0;R<c.length;R++)g={...g,[`[${R}]`]:{value:c[R],error:void 0}};return g}return[]}return f(l[a].values,s).value??e.modelValue??e.default??f(l[a].initialValues,s)??""},v=async()=>{if(e?.rule){const c=await J(e.rule,p.value,E,s);d.value.isValid=c}},E=(c,g)=>{f(l[a].values,c)&&(f(l[a].values,c).error=g)},S=c=>c.type==="checkbox"?L(c.checked):c.type==="file"?c.multiple?c.files:c.files?.[0]:c.type==="select-multiple"?Array.from(c.options).filter(q=>q.selected).map(q=>q.value):c.value,N=c=>p.value=c,L=c=>c?e.trueValue||!0:e.falseValue||!1,K=()=>d.value?.isDirty||i.value||r==="onSubmit"?d.value?.error:void 0,w=()=>{d.value?.error&&(d.value.error=void 0),f(l[a].values,s.replace(/\[\d+\]/,""))?.error&&(f(l[a].values,s.replace(/\[\d+\]/,"")).error=void 0)},O=async c=>{typeof c=="object"&&"target"in c?N(S(c.target)):N(c),d.value.error=void 0,d.value&&!d.value?.isTouched&&(d.value.isTouched=!0),d.value?.isTouched&&y.value!==p.value&&(d.value.isDirty=!0),w(),r==="onChange"&&(_.emit("validate"),v())},D=()=>{w()},W=async()=>{d.value&&!d.value?.isTouched&&(d.value.isTouched=!0),await v()},H=(c,g=s)=>{f(l[a].values,g).value=b(f(l[a].values,g).value,c),f(l[a].values,g).error=void 0};Q(s,a,JSON.parse(JSON.stringify(y))),s?d.value.value=B():u.warn("`name` prop is required"),u.onBeforeUnmount(()=>{e.preserve||n||M(l[a].values,s)}),u.onMounted(async()=>{await u.nextTick(),p.value&&!Array.isArray(p.value)&&(d.value.isDirty=!0),o?.subTree?.el&&"as"in e&&e.as==="select"&&Array.from(o.subTree.el.options).forEach(g=>{y.value?.includes?.(g.value)&&(g.selected=!0)})});const oe=u.ref({modelValue:A,value:A,"onUpdate:modelValue":c=>{p.value=c,r==="onChange"&&(_.emit("validate"),v())},isTouched:m.value,onInput:O,onFocus:D,onBlur:W});return{value:p,isValid:h,isTouched:m,isDirty:V,inputProps:oe,getError:K,setError:E,setArrayValue:H}},re=()=>u.defineComponent((e,{slots:t,emit:a,attrs:n})=>{const r=u.ref([]),{getError:i,setArrayValue:o}=X(e,!0),{uid:s}=u.inject("formData",Object.create({})),y=()=>{!e.ignore&&(f(l[s].values,e.name).error=void 0),r.value.push({id:r.value.length,name:e.name})},p=async h=>{f(l[s].values,e.name).error=void 0;const m=r.value.findIndex(V=>V.id===h);for(let V=m+1;V<r.value.length;V++){const A=`${e.name}[${V}]`,B=`${e.name}[${V-1}]`;f(l[s].values,A).error=void 0,f(l[s].values,B).error=void 0,f(l[s].values,B)&&o({[`[${V-1}]`]:JSON.parse(JSON.stringify(f(l[s].values,A)))})}await u.nextTick(),M(l[s].values,`${r.value[r.value.length-1].name}[${r.value.length-1}]`),r.value.splice(-1)};return(async()=>{r.value=[];const h=l[s].initialValues?.[e.name]||l[s].values[e.name].value;h&&(h.forEach?.(()=>{r.value.push({id:r.value.length,name:e.name})}),await u.nextTick(),h.forEach?.((m,V)=>{typeof m=="object"?Object.keys(m).forEach(A=>{o({[`[${V}]`]:{[A]:{value:m[A]}}})}):o({[`[${V}]`]:{value:m}})}))})(),()=>u.h("div",{...e,...n,...a},t.default?.({fields:u.toValue(r),add:y,remove:p,error:i}))},{name:"FieldArray",props:{name:{type:String,default:""},default:{type:[String,Array,Boolean,Number,Object],default:void 0},preserve:{type:Boolean,default:!1},modelValue:{type:[String,Array,Boolean,Number,Object],default:void 0},as:{type:String,default:"input"},rule:{type:Object,default:void 0}},emits:["update:modelValue"],slots:Object}),le=()=>u.defineComponent((e,{slots:t,emit:a,attrs:n})=>{const{uid:r,mode:i,isSubmitted:o}=u.inject("formData",Object.create({})),s=()=>{if(i==="onSubmit"||o.value||f(l[r].values,e.errorFor)?.isDirty)return Y(l[r].values,e.errorFor)};return()=>u.h("span",{...e,...n,...a},t.default?t.default?.({error:s()}):Array.isArray(s())?s()?.[0]:s())},{name:"FieldError",props:{errorFor:{type:String,default:void 0}},slots:Object}),se=e=>{const t=e?.name||Math.floor(Math.random()*Date.now()),a=u.ref(!1),n=u.ref(!1),r=u.ref(!1);let i=Object.create({});const o=(v=!1)=>{r.value=!1,v?(l[t].initialValues=Object.create({}),l[t].values=Object.create({}),i=JSON.stringify(Object.create({}))):l[t].values=JSON.parse(i),l[t].key++},s=v=>async()=>{await v?.(m.value)},y=(v,E)=>{if(f(l[t].values,v))Array.isArray(E)||(f(l[t].values,v).value=E);else{const S=U(v,{value:E,error:void 0});l[t].values=b(l[t].values,S)}},p=v=>{const E=j(v);for(const S in E)f(l[t].values,S)&&"value"in f(l[t].values,S)&&(f(l[t].values,S).value=E[S])},d=v=>{l[t].initialValues=b(l[t].initialValues,F(l[t].values),v),l[t].key++},h=(v,E)=>{f(l[t].values,v)&&(f(l[t].values,v).error=E,f(l[t].values,v).isValid=!1)},m=u.computed({get:()=>F(l[t]?.values),set:v=>v}),V=u.computed(()=>P(F(l[t]?.values,"isDirty"))),A=u.computed(()=>V.value&&!G(F(l[t]?.values,"error")));return l[t]?m.value=F(l[t].values):l[t]={values:Object.create({}),initialValues:e?.initialValues||Object.create({}),key:0},u.provide("formData",{uid:t,preserveForm:e?.preserve,mode:e?.mode,isSubmitted:r}),{cmp:u.defineComponent((v,{slots:E,emit:S,attrs:N})=>{const L=O=>Y(l[t].values,O),K=async O=>{O.preventDefault(),r.value=!0;let D=m.value;if(e?.schema&&!await J(e.schema,F(l[t].values),h))return O.preventDefault();v?.enctype==="multipart/form-data"&&(D=z(F(l[t].values))),!v.action&&(O.preventDefault(),a.value=!0,await ne(v.onSubmit?.(D,O)),a.value=!1)},w=()=>{const O=j(l[t].initialValues);for(const D in O)!l[t].values[D]?.value&&y(D,O[D])};return u.watch(m,(O,D)=>{m.value=O,n.value&&JSON.stringify(O)!==JSON.stringify(D)&&v.onValueChange&&_.emit("value-change",t),e?.mode==="onChange"&&V.value&&_.emit("validate")},{deep:!0}),Object.keys(v.initialValues).length&&(l[t].initialValues=b(l[t].initialValues,v.initialValues)),u.onMounted(async()=>{w(),i=JSON.stringify(l[t].values),v?.onValueChange&&l[t]&&_.on("value-change",O=>{O===t&&S("value-change",m.value)}),e?.mode==="onChange"&&_.on("validate",async()=>{if(e?.schema)return await J(e.schema,F(l[t].values),h)}),await u.nextTick(),n.value=!0}),()=>u.h("form",{...v,...N,...S,key:l[t].key,onSubmit:K},E.default?.({values:m.value,getError:L,isDirty:V.value,isValid:A.value}))},{name:"FormComponent",props:{enctype:{type:String,default:"application/x-www-form-urlencoded"},initialValues:{type:Object,default:Object.create({})},onValueChange:{type:Function,default:void 0},onSubmit:{type:Function,default:void 0}},emits:["submit","value-change"],slots:Object}),values:m,isSubmitting:a,reset:o,setInitialValues:d,setValue:y,setValues:p,setError:h,handleSubmit:s}},ie=()=>u.defineComponent((e,{slots:t,attrs:a})=>{const{value:n,isValid:r,isTouched:i,isDirty:o,inputProps:s,getError:y}=X(e),p=u.computed(()=>{const h={...a,name:e.name,error:y(),onInput:m=>{s.value.onInput?.(m),typeof a.onInput=="function"&&a.onInput()},onChange:m=>{s.value.onInput?.(m),typeof a.onChange=="function"&&a.onChange()},onFocus:()=>{s.value.onFocus?.(),typeof a.onFocus=="function"&&a.onFocus()},onBlur:async()=>{s.value.onBlur?.(),typeof a.onBlur=="function"&&a.onBlur()}};return h.type==="checkbox"&&n.value&&(h.checked=!0),a.type!=="file"&&e.as!=="select"&&!h.multiple&&(h.value=n.value),h}),d=()=>({field:{...s.value,error:y(),isValid:r.value,isTouched:i.value,isDirty:o.value,onFocus:s.value.onFocus,onBlur:s.value.onBlur}});return()=>{const h=u.resolveDynamicComponent(Z(e,!!t.default)),m=ee(h,t,d);return h?u.h(h,{...e,...p.value,...s.value,isValid:r.value,isTouched:i.value,isDirty:o.value},m):m}},{name:"Field",inheritAttrs:!1,props:{name:{type:String,default:""},default:{type:[String,Array,Boolean,Number,Object],default:void 0},preserve:{type:Boolean,default:!1},modelValue:{type:[String,Array,Boolean,Number,Object],default:void 0},as:{type:String,default:void 0},rule:{type:[Object,Function],default:void 0}},emits:["update:modelValue"]}),ue=e=>{const t=se(e),a=ie(),n=re(),r=le();return{Form:t.cmp,Field:a,FieldArray:n,Error:r,reset:t.reset,setInitialValues:t.setInitialValues,setValue:t.setValue,setValues:t.setValues,setError:t.setError,handleSubmit:t.handleSubmit,values:t.values,isSubmitting:t.isSubmitting}};T.useForm=ue,T.useInput=X,Object.defineProperty(T,Symbol.toStringTag,{value:"Module"})});