@volverjs/form-vue 0.0.10-beta.4 → 0.0.10-beta.6

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.umd.js CHANGED
@@ -1 +1 @@
1
- (function(p,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue"),require("@vueuse/core"),require("zod")):typeof define=="function"&&define.amd?define(["exports","vue","@vueuse/core","zod"],t):(p=typeof globalThis<"u"?globalThis:p||self,t(p["@volverjs/form-vue"]={},p.Vue,p.VueUseCore,p.zod))})(this,function(p,t,A,b){"use strict";function x(e){return Array.isArray(e)}function B(e){return typeof e<"u"}function O(e){return e===null}function C(e){return typeof e=="object"}function E(e){return typeof e=="string"}function g(e){return typeof e>"u"}const W=/^[0-9]+$/,_=["__proto__","prototype","constructor"];function $(e,a,s){const l=B(s)?s:void 0;if(!C(e)||!E(a))return l;const n=I(a);if(n.length!==0){for(const r of n){if(r==="*")continue;const u=function(c){return c.map(f=>g(f)||O(f)?f:x(f)?u(f):f[r])};if(x(e)&&!W.test(r)?e=u(e):e=e[r],g(e)||O(e))break}return g(e)?l:e}}function G(e,a,s){if(!C(e)||!E(a))return;const l=I(a);if(l.length===0)return;const n=l.length;for(let r=0;r<n;r++){const u=l[r];if(r===n-1){e[u]=s;return}if(u==="*"&&x(e)){const c=l.slice(r+1).join(".");for(const f of e)G(f,c,s);return}g(e[u])&&(e[u]={}),e=e[u]}}function I(e){const a=e.split(/[.]|(?:\[(\d|\*)\])/).filter(s=>!!s);return a.some(s=>_.indexOf(s)!==-1)?[]:a}var i=(e=>(e.text="text",e.number="number",e.email="email",e.password="password",e.tel="tel",e.url="url",e.search="search",e.date="date",e.time="time",e.datetimeLocal="datetimeLocal",e.month="month",e.week="week",e.color="color",e.select="select",e.checkbox="checkbox",e.radio="radio",e.textarea="textarea",e.radioGroup="radioGroup",e.checkboxGroup="checkboxGroup",e.combobox="combobox",e.custom="custom",e))(i||{});const K=(e,a,s,l={})=>t.defineComponent({name:"FieldComponent",props:{type:{type:String,validator:n=>Object.values(i).includes(n),default:i.custom},is:{type:[Object,String],default:void 0},name:{type:[String,Number,Boolean,Symbol],required:!0},props:{type:[Object,Function],default:()=>({})},showValid:{type:Boolean,default:!1},defaultValue:{type:[String,Number,Boolean,Array,Object],default:void 0}},emits:["invalid","valid","update:formData","update:modelValue"],expose:["invalid","invalidLabel","errors"],setup(n,{slots:r,emit:u}){const c=t.computed({get(){if(o!=null&&o.modelValue)return $(Object(o.modelValue.value),String(n.name))},set(d){o!=null&&o.modelValue&&(G(Object(o.modelValue.value),String(n.name),d),u("update:modelValue",{newValue:c.value,formData:o==null?void 0:o.modelValue}))}});t.onMounted(()=>{c.value===void 0&&n.defaultValue!==void 0&&(c.value=n.defaultValue)}),t.onBeforeUnmount(()=>{U(),J()});const f=t.inject(a,void 0);f&&f.fields.value.add(n.name);const o=t.inject(e),{props:h,name:v}=t.toRefs(n),m=t.computed(()=>{if(o!=null&&o.errors.value)return $(o.errors.value,String(n.name))}),V=t.computed(()=>{var d;return(d=m.value)==null?void 0:d._errors}),y=t.computed(()=>m.value!==void 0),U=t.watch(y,()=>{y.value?(u("invalid",V.value),f&&f.errors.value.set(n.name,{_errors:V.value})):(u("valid",c.value),f&&f.errors.value.delete(n.name))}),J=t.watch(()=>o==null?void 0:o.modelValue,()=>{u("update:formData",o==null?void 0:o.modelValue)},{deep:!0}),L=d=>{c.value=d},N=t.computed(()=>typeof h.value=="function"?h.value(o==null?void 0:o.modelValue):h.value),R=t.computed(()=>({...N.value,name:N.value.name??n.name,invalid:y.value,valid:n.showValid?!!(!y.value&&c.value):void 0,type:(d=>{if([i.text,i.number,i.email,i.password,i.tel,i.url,i.search,i.date,i.time,i.datetimeLocal,i.month,i.week,i.color].includes(d))return d})(n.type),invalidLabel:V.value,modelValue:c.value,errors:n.is?m.value:void 0,"onUpdate:modelValue":L}));return t.provide(s,{name:t.readonly(v),errors:t.readonly(m)}),{component:t.computed(()=>{if(n.type===i.custom)return{render(){var d;return((d=r.default)==null?void 0:d.call(r,{modelValue:c.value,onUpdate:L,invalid:y.value,invalidLabel:V.value,formData:o==null?void 0:o.modelValue.value,formErrors:o==null?void 0:o.errors.value,errors:m.value}))??r.defalut}};if(!l.lazyLoad){let d;switch(n.type){case i.select:d=t.resolveComponent("VvSelect");break;case i.checkbox:d=t.resolveComponent("VvCheckbox");break;case i.radio:d=t.resolveComponent("VvRadio");break;case i.textarea:d=t.resolveComponent("VvTextarea");break;case i.radioGroup:d=t.resolveComponent("VvRadioGroup");break;case i.checkboxGroup:d=t.resolveComponent("VvCheckboxGroup");break;case i.combobox:d=t.resolveComponent("VvCombobox");break;default:d=t.resolveComponent("VvInputText")}if(typeof d!="string")return d;console.warn(`[form-vue warn]: ${d} not found, the component will be loaded asynchronously. To avoid this warning, please set "lazyLoad" option.`)}return t.defineAsyncComponent(async()=>{switch(l.sideEffects&&await Promise.resolve(l.sideEffects(n.type)),n.type){case i.textarea:return import("@volverjs/ui-vue/vv-textarea");case i.radio:return import("@volverjs/ui-vue/vv-radio");case i.radioGroup:return import("@volverjs/ui-vue/vv-radio-group");case i.checkbox:return import("@volverjs/ui-vue/vv-checkbox");case i.checkboxGroup:return import("@volverjs/ui-vue/vv-checkbox-group");case i.combobox:return import("@volverjs/ui-vue/vv-combobox")}return import("@volverjs/ui-vue/vv-input-text")})}),hasProps:R,invalid:y}},render(){return this.is?t.h(this.is,this.hasProps,this.$slots):this.type===i.custom?t.h(this.component,null,this.$slots):t.h(this.component,this.hasProps,this.$slots)}}),S=(e,a={})=>{const s=r=>{let u=r;for(;u instanceof b.ZodEffects;)u=u.innerType();return u},l=s(e);return{...(l instanceof b.ZodObject?l._def.unknownKeys==="passthrough":!1)?a:{},...Object.fromEntries(Object.entries(l.shape).map(([r,u])=>{const c=a[r],f=s(u);let o;if(f instanceof b.ZodDefault&&(o=f._def.defaultValue()),c===null&&f instanceof b.ZodNullable)return[r,c];if(f instanceof b.ZodSchema){const h=f.safeParse(a[r]);if(h.success)return[r,h.data??o]}return f instanceof b.ZodObject?[r,S(f,c&&typeof c=="object"?c:{})]:[r,o]}))}},M=(e,a,s)=>{const l=t.ref(),n=t.ref(),r=t.ref();return{errors:l,status:n,formData:r,component:t.defineComponent({name:"FormComponent",props:{modelValue:{type:Object,default:()=>({})},continuosValidation:{type:Boolean,default:!1}},emits:["invalid","valid","submit","update:modelValue"],expose:["submit","errors","status"],setup(u,{emit:c}){r.value=S(e,u.modelValue);const f=(s==null?void 0:s.continuosValidation)||u.continuosValidation;t.watch(()=>u.modelValue,v=>{if(v){const m=t.isProxy(v)?t.toRaw(v):v;r.value=typeof(m==null?void 0:m.clone)=="function"?m.clone():JSON.parse(JSON.stringify(m))}},{deep:!0}),A.watchThrottled(r,v=>{(l.value||f)&&o(),(!v||!u.modelValue||JSON.stringify(v)!==JSON.stringify(u.modelValue))&&c("update:modelValue",v)},{deep:!0,throttle:(s==null?void 0:s.updateThrottle)??500});const o=(v=r.value)=>{const m=e.safeParse(v);return m.success?(l.value=void 0,n.value="valid",r.value=m.data,c("update:modelValue",r.value),c("valid",m.data),!0):(l.value=m.error.format(),n.value="invalid",c("invalid",l.value),!1)},h=()=>o()?(c("submit",r.value),!0):!1;return t.provide(a,{modelValue:r,submit:h,errors:t.readonly(l)}),{submit:h}},render(){return t.h("form",{onSubmit:t.withModifiers(this.submit,["prevent"])},this.$slots)}})}},P=(e,a)=>t.defineComponent({name:"WrapperComponent",props:{name:{type:String,required:!0},tag:{type:String,default:void 0}},emits:["invalid","valid"],expose:["fields","invalid"],setup(s,{emit:l}){const n=t.inject(e),r=t.inject(a,void 0),u=t.ref(new Set),c=t.ref(new Map),{name:f}=t.toRefs(s);t.provide(a,{name:t.readonly(f),errors:c,fields:u}),t.watch(u,h=>{r!=null&&r.fields&&h.forEach(v=>{r==null||r.fields.value.add(v)})},{deep:!0}),t.watch(()=>new Map(c.value),(h,v)=>{r!=null&&r.errors&&(Array.from(v.keys()).forEach(m=>{r.errors.value.delete(m)}),Array.from(h.keys()).forEach(m=>{const V=h.get(m);V&&r.errors.value.set(m,V)}))},{deep:!0});const o=t.computed(()=>n!=null&&n.errors.value?c.value.size>0:!1);return t.watch(o,()=>{o.value?l("invalid"):l("valid")}),{formData:n==null?void 0:n.modelValue,errors:n==null?void 0:n.errors,invalid:o,fields:u,fieldsErrors:c}},render(){var s,l,n,r;return this.tag?t.h(this.tag,null,((l=(s=this.$slots).default)==null?void 0:l.call(s,{invalid:this.invalid,formData:this.formData,errors:this.errors,fieldsErrors:this.fieldsErrors}))??this.$slots.defalut):((r=(n=this.$slots).default)==null?void 0:r.call(n,{invalid:this.invalid,formData:this.formData,errors:this.errors,fieldsErrors:this.fieldsErrors}))??this.$slots.defalut}}),k=(e,a={})=>{const s=Symbol(),l=Symbol(),n=Symbol(),{component:r,errors:u,status:c,formData:f}=M(e,s,a),o=P(s,l),h=K(s,l,n,a);return{VvForm:r,VvFormWrapper:o,VvFormField:h,formInjectionKey:s,formWrapperInjectionKey:l,formFieldInjectionKey:n,errors:u,status:c,formData:f}},w=Symbol(),Z=e=>{let a={};return e.schema&&(a=k(e.schema,e)),{...a,install(s,{global:l=!1}={}){s.provide(w,e),l&&(s.config.globalProperties.$vvForm=e,a!=null&&a.VvForm&&s.component("VvForm",a.VvForm),a!=null&&a.VvFormWrapper&&s.component("VvFormWrapper",a.VvFormWrapper),a!=null&&a.VvFormField&&s.component("VvFormField",a.VvFormField))}}},q=(e,a={})=>{const s={...t.inject(w,{}),...a};return k(e,s)};p.FormFieldType=i,p.createForm=Z,p.defaultObjectBySchema=S,p.formFactory=k,p.pluginInjectionKey=w,p.useForm=q,Object.defineProperty(p,Symbol.toStringTag,{value:"Module"})});
1
+ (function(y,r){typeof exports=="object"&&typeof module<"u"?r(exports,require("vue"),require("@vueuse/core"),require("zod")):typeof define=="function"&&define.amd?define(["exports","vue","@vueuse/core","zod"],r):(y=typeof globalThis<"u"?globalThis:y||self,r(y["@volverjs/form-vue"]={},y.Vue,y.VueUseCore,y.zod))})(this,function(y,r,M,g){"use strict";function S(e){return Array.isArray(e)}function Z(e){return typeof e<"u"}function W(e){return e===null}function A(e){return typeof e=="object"}function L(e){return typeof e=="string"}function k(e){return typeof e>"u"}const U=/^[0-9]+$/,J=["__proto__","prototype","constructor"];function B(e,a,u){const f=Z(u)?u:void 0;if(!A(e)||!L(a))return f;const o=K(a);if(o.length!==0){for(const t of o){if(t==="*")continue;const s=function(i){return i.map(l=>k(l)||W(l)?l:S(l)?s(l):l[t])};if(S(e)&&!U.test(t)?e=s(e):e=e[t],k(e)||W(e))break}return k(e)?f:e}}function _(e,a,u){if(!A(e)||!L(a))return;const f=K(a);if(f.length===0)return;const o=f.length;for(let t=0;t<o;t++){const s=f[t];if(t===o-1){e[s]=u;return}if(s==="*"&&S(e)){const i=f.slice(t+1).join(".");for(const l of e)_(l,i,u);return}k(e[s])&&(e[s]={}),e=e[s]}}function K(e){const a=e.split(/[.]|(?:\[(\d|\*)\])/).filter(u=>!!u);return a.some(u=>J.indexOf(u)!==-1)?[]:a}var c=(e=>(e.text="text",e.number="number",e.email="email",e.password="password",e.tel="tel",e.url="url",e.search="search",e.date="date",e.time="time",e.datetimeLocal="datetimeLocal",e.month="month",e.week="week",e.color="color",e.select="select",e.checkbox="checkbox",e.radio="radio",e.textarea="textarea",e.radioGroup="radioGroup",e.checkboxGroup="checkboxGroup",e.combobox="combobox",e.custom="custom",e))(c||{}),C=(e=>(e.invalid="invalid",e.valid="valid",e))(C||{});const P=(e,a,u,f={})=>r.defineComponent({name:"FieldComponent",props:{type:{type:String,validator:o=>Object.values(c).includes(o),default:c.custom},is:{type:[Object,String],default:void 0},name:{type:[String,Number,Boolean,Symbol],required:!0},props:{type:[Object,Function],default:()=>({})},showValid:{type:Boolean,default:!1},defaultValue:{type:[String,Number,Boolean,Array,Object],default:void 0}},emits:["invalid","valid","update:formData","update:modelValue"],expose:["invalid","invalidLabel","errors"],setup(o,{slots:t,emit:s}){const i=r.computed({get(){if(n!=null&&n.formData)return B(Object(n.formData.value),String(o.name))},set(d){n!=null&&n.formData&&(_(Object(n.formData.value),String(o.name),d),s("update:modelValue",{newValue:i.value,formData:n==null?void 0:n.formData}))}});r.onMounted(()=>{i.value===void 0&&o.defaultValue!==void 0&&(i.value=o.defaultValue)}),r.onBeforeUnmount(()=>{w(),x()});const l=r.inject(a,void 0);l&&l.fields.value.add(o.name);const n=r.inject(e),{props:h,name:V}=r.toRefs(o),p=r.computed(()=>{if(n!=null&&n.errors.value)return B(n.errors.value,String(o.name))}),m=r.computed(()=>{var d;return(d=p.value)==null?void 0:d._errors}),v=r.computed(()=>p.value!==void 0),w=r.watch(v,()=>{v.value?(s("invalid",m.value),l&&l.errors.value.set(o.name,{_errors:m.value})):(s("valid",i.value),l&&l.errors.value.delete(o.name))}),x=r.watch(()=>n==null?void 0:n.formData,()=>{s("update:formData",n==null?void 0:n.formData)},{deep:!0}),b=d=>{i.value=d},O=r.computed(()=>typeof h.value=="function"?h.value(n==null?void 0:n.formData):h.value),G=r.computed(()=>({...O.value,name:O.value.name??o.name,invalid:v.value,valid:o.showValid?!!(!v.value&&i.value):void 0,type:(d=>{if([c.text,c.number,c.email,c.password,c.tel,c.url,c.search,c.date,c.time,c.datetimeLocal,c.month,c.week,c.color].includes(d))return d})(o.type),invalidLabel:m.value,modelValue:i.value,errors:o.is?p.value:void 0,"onUpdate:modelValue":b}));return r.provide(u,{name:r.readonly(V),errors:r.readonly(p)}),{component:r.computed(()=>{if(o.type===c.custom)return{render(){var d;return((d=t.default)==null?void 0:d.call(t,{modelValue:i.value,onUpdate:b,invalid:v.value,invalidLabel:m.value,formData:n==null?void 0:n.formData.value,formErrors:n==null?void 0:n.errors.value,errors:p.value}))??t.defalut}};if(!f.lazyLoad){let d;switch(o.type){case c.select:d=r.resolveComponent("VvSelect");break;case c.checkbox:d=r.resolveComponent("VvCheckbox");break;case c.radio:d=r.resolveComponent("VvRadio");break;case c.textarea:d=r.resolveComponent("VvTextarea");break;case c.radioGroup:d=r.resolveComponent("VvRadioGroup");break;case c.checkboxGroup:d=r.resolveComponent("VvCheckboxGroup");break;case c.combobox:d=r.resolveComponent("VvCombobox");break;default:d=r.resolveComponent("VvInputText")}if(typeof d!="string")return d;console.warn(`[form-vue warn]: ${d} not found, the component will be loaded asynchronously. To avoid this warning, please set "lazyLoad" option.`)}return r.defineAsyncComponent(async()=>{switch(f.sideEffects&&await Promise.resolve(f.sideEffects(o.type)),o.type){case c.textarea:return import("@volverjs/ui-vue/vv-textarea");case c.radio:return import("@volverjs/ui-vue/vv-radio");case c.radioGroup:return import("@volverjs/ui-vue/vv-radio-group");case c.checkbox:return import("@volverjs/ui-vue/vv-checkbox");case c.checkboxGroup:return import("@volverjs/ui-vue/vv-checkbox-group");case c.combobox:return import("@volverjs/ui-vue/vv-combobox")}return import("@volverjs/ui-vue/vv-input-text")})}),hasProps:G,invalid:v}},render(){return this.is?r.h(this.is,this.hasProps,this.$slots):this.type===c.custom?r.h(this.component,null,this.$slots):r.h(this.component,this.hasProps,this.$slots)}}),E=(e,a={})=>{const u=t=>{let s=t;for(;s instanceof g.ZodEffects;)s=s.innerType();return s},f=u(e);return{...(f instanceof g.ZodObject?f._def.unknownKeys==="passthrough":!1)?a:{},...Object.fromEntries(Object.entries(f.shape).map(([t,s])=>{const i=a[t],l=u(s);let n;if(l instanceof g.ZodDefault&&(n=l._def.defaultValue()),i===null&&l instanceof g.ZodNullable)return[t,i];if(l instanceof g.ZodSchema){const h=l.safeParse(a[t]);if(h.success)return[t,h.data??n]}return l instanceof g.ZodObject?[t,E(l,i&&typeof i=="object"?i:{})]:[t,n]}))}},z=(e,a,u)=>{const f=r.ref(),o=r.ref(),t=r.ref(),s=r.defineComponent({name:"FormComponent",props:{modelValue:{type:Object,default:()=>({})},continuosValidation:{type:Boolean,default:!1}},emits:["invalid","valid","submit","update:modelValue"],expose:["submit","errors","status"],setup(i,{emit:l}){t.value=E(e,i.modelValue);const n=(u==null?void 0:u.continuosValidation)||i.continuosValidation;r.watch(()=>i.modelValue,m=>{if(m){const v=r.isProxy(m)?r.toRaw(m):m;t.value=typeof(v==null?void 0:v.clone)=="function"?v.clone():JSON.parse(JSON.stringify(v))}},{deep:!0}),M.watchThrottled(t,m=>{(f.value||n)&&h(),(!m||!i.modelValue||JSON.stringify(m)!==JSON.stringify(i.modelValue))&&l("update:modelValue",m)},{deep:!0,throttle:(u==null?void 0:u.updateThrottle)??500});const h=(m=t.value)=>{const v=e.safeParse(m);return v.success?(f.value=void 0,o.value=C.valid,t.value=v.data,l("update:modelValue",t.value),l("valid",v.data),!0):(f.value=v.error.format(),o.value=C.invalid,l("invalid",f.value),!1)},V=()=>h()?(l("submit",t.value),!0):!1,p=r.computed(()=>o.value===C.invalid);return r.provide(a,{formData:t,submit:V,errors:r.readonly(f),status:r.readonly(o),invalid:p}),{formData:t,submit:V,errors:r.readonly(f),status:r.readonly(o),invalid:p}},render(){return r.h("form",{onSubmit:r.withModifiers(this.submit,["prevent"])},{default:()=>{var i,l;return((l=(i=this.$slots)==null?void 0:i.default)==null?void 0:l.call(i,{formData:this.formData,submit:this.submit,errors:this.errors,status:this.status,invalid:this.invalid}))??this.$slots.default}})}});return{errors:f,status:o,formData:t,VvForm:s}},H=(e,a)=>r.defineComponent({name:"WrapperComponent",props:{name:{type:String,required:!0},tag:{type:String,default:void 0}},emits:["invalid","valid"],expose:["fields","invalid"],setup(f,{emit:o}){const t=r.inject(e),s=r.inject(a,void 0),i=r.ref(new Set),l=r.ref(new Map),{name:n}=r.toRefs(f);r.provide(a,{name:r.readonly(n),errors:l,fields:i}),r.watch(i,V=>{s!=null&&s.fields&&V.forEach(p=>{s==null||s.fields.value.add(p)})},{deep:!0}),r.watch(()=>new Map(l.value),(V,p)=>{s!=null&&s.errors&&(Array.from(p.keys()).forEach(m=>{s.errors.value.delete(m)}),Array.from(V.keys()).forEach(m=>{const v=V.get(m);v&&s.errors.value.set(m,v)}))},{deep:!0});const h=r.computed(()=>t!=null&&t.invalid.value?l.value.size>0:!1);return r.watch(h,()=>{h.value?o("invalid"):o("valid")}),{formData:t==null?void 0:t.formData,errors:t==null?void 0:t.errors,invalid:h,fields:i,fieldsErrors:l}},render(){var f,o;return this.tag?r.h(this.tag,null,{default:()=>{var t,s;return((s=(t=this.$slots).default)==null?void 0:s.call(t,{invalid:this.invalid,formData:this.formData,errors:this.errors,fieldsErrors:this.fieldsErrors}))??this.$slots.defalut}}):((o=(f=this.$slots).default)==null?void 0:o.call(f,{invalid:this.invalid,formData:this.formData,errors:this.errors,fieldsErrors:this.fieldsErrors}))??this.$slots.defalut}}),Q=(e,a)=>{const u=r.defineComponent({props:{schema:{type:[Array,Function],required:!0}},setup(f,{slots:o}){const t=r.inject(e),s=typeof f.schema=="function"?f.schema(t):f.schema;let i;return()=>{var l;return s==null?void 0:s.reduce((n,h)=>{const V=typeof h=="function"?h(t):h,{vvIs:p,vvName:m,vvSlots:v,vvChildren:w,vvIf:x,vvElseIf:b,vvType:O,vvDefaultValue:G,vvShowValid:q,...d}=V;if(x!==void 0){if(i=typeof x=="function"?r.unref(x(t)):r.unref(x),!i)return n}else if(b!==void 0&&i!==void 0){if(i||(i=typeof b=="function"?r.unref(b(t)):r.unref(b),!i))return n}else i=void 0;const N=w?r.h(u,{schema:w}):void 0;return m?(n.push(r.h(a,{name:m,is:p,type:O,defaultValue:G,showValid:q,props:d},v??N)),n):p?(n.push(r.h(p,d,v??N)),n):(w&&n.push(N),n)},[(l=o==null?void 0:o.default)==null?void 0:l.call(o,{formData:t==null?void 0:t.formData.value,submit:t==null?void 0:t.submit,errors:t==null?void 0:t.errors.value,status:t==null?void 0:t.status.value,invalid:t==null?void 0:t.invalid.value})])}}});return u},I=(e,a={})=>{const u=Symbol(),f=Symbol(),o=Symbol(),{VvForm:t,errors:s,status:i,formData:l}=z(e,u,a),n=H(u,f),h=P(u,f,o,a),V=Q(u,h);return{VvForm:t,VvFormWrapper:n,VvFormField:h,VvFormTemplate:V,formInjectionKey:u,formWrapperInjectionKey:f,formFieldInjectionKey:o,errors:s,status:i,formData:l}},$=Symbol(),R=e=>{let a={};return e.schema&&(a=I(e.schema,e)),{...a,install(u,{global:f=!1}={}){u.provide($,e),f&&(u.config.globalProperties.$vvForm=e,a!=null&&a.VvForm&&u.component("VvForm",a.VvForm),a!=null&&a.VvFormWrapper&&u.component("VvFormWrapper",a.VvFormWrapper),a!=null&&a.VvFormField&&u.component("VvFormField",a.VvFormField),a!=null&&a.VvFormTemplate&&u.component("VvFormTemplate",a.VvFormTemplate))}}},T=(e,a={})=>{const u={...r.inject($,{}),...a};return I(e,u)};y.FormFieldType=c,y.createForm=R,y.defaultObjectBySchema=E,y.formFactory=I,y.pluginInjectionKey=$,y.useForm=T,Object.defineProperty(y,Symbol.toStringTag,{value:"Module"})});
package/dist/types.d.ts CHANGED
@@ -1,6 +1,11 @@
1
1
  import type { Ref } from 'vue'
2
2
  import type { z, AnyZodObject, ZodEffects } from 'zod'
3
- import type { FormFieldType } from './enums'
3
+ import type { FormFieldType, FormStatus } from './enums'
4
+
5
+ export type FormSchema =
6
+ | AnyZodObject
7
+ | ZodEffects<AnyZodObject>
8
+ | ZodEffects<ZodEffects<AnyZodObject>>
4
9
 
5
10
  export type FormComposableOptions = {
6
11
  lazyLoad?: boolean
@@ -13,34 +18,107 @@ export type FormPluginOptions = {
13
18
  schema?: ZodSchema
14
19
  } & FormComposableOptions
15
20
 
16
- export type InjectedFormData<
17
- Schema extends
18
- | AnyZodObject
19
- | ZodEffects<AnyZodObject>
20
- | ZodEffects<ZodEffects<AnyZodObject>>,
21
- > = {
22
- modelValue: Ref<Partial<z.infer<Schema>> | undefined>
21
+ export type InjectedFormData<Schema extends FormSchema> = {
22
+ formData: Ref<Partial<z.infer<Schema>> | undefined>
23
23
  errors: Readonly<Ref<DeepReadonly<z.inferFormattedError<Schema>>>>
24
24
  submit: () => boolean
25
+ status: Readonly<Ref<FormStatus | undefined>>
26
+ invalid: Readonly<Ref<boolean>>
25
27
  }
26
28
 
27
- export type InjectedFormWrapperData<
28
- Schema extends
29
- | AnyZodObject
30
- | ZodEffects<AnyZodObject>
31
- | ZodEffects<ZodEffects<AnyZodObject>>,
32
- > = {
29
+ export type InjectedFormWrapperData<Schema extends FormSchema> = {
33
30
  name: Ref<string>
34
31
  fields: Ref<Set<string>>
35
32
  errors: Readonly<Ref<DeepReadonly<z.inferFormattedError<Schema>>>>
36
33
  }
37
34
 
38
- export type InjectedFormFieldData<
39
- Schema extends
40
- | AnyZodObject
41
- | ZodEffects<AnyZodObject>
42
- | ZodEffects<ZodEffects<AnyZodObject>>,
43
- > = {
35
+ export type InjectedFormFieldData<Schema extends FormSchema> = {
44
36
  name: Ref<string>
45
37
  errors: Readonly<Ref<DeepReadonly<z.inferFormattedError<Schema>>>>
46
38
  }
39
+
40
+ export type Primitive =
41
+ | null
42
+ | undefined
43
+ | string
44
+ | number
45
+ | boolean
46
+ | symbol
47
+ | bigint
48
+
49
+ type ArrayKey = number
50
+
51
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
52
+ type IsTuple<T extends readonly any[]> = number extends T['length']
53
+ ? false
54
+ : true
55
+
56
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
57
+ type TupleKeys<T extends readonly any[]> = Exclude<keyof T, keyof any[]>
58
+
59
+ export type PathConcat<
60
+ TKey extends string | number,
61
+ TValue,
62
+ > = TValue extends Primitive ? `${TKey}` : `${TKey}` | `${TKey}.${Path<TValue>}`
63
+
64
+ export type Path<T> = T extends readonly (infer V)[]
65
+ ? IsTuple<T> extends true
66
+ ? {
67
+ [K in TupleKeys<T>]-?: PathConcat<K & string, T[K]>
68
+ }[TupleKeys<T>]
69
+ : PathConcat<ArrayKey, V>
70
+ : {
71
+ [K in keyof T]-?: PathConcat<K & string, T[K]>
72
+ }[keyof T]
73
+
74
+ export type PathValue<T, TPath extends Path<T> | ArrayPath<T>> = T extends any
75
+ ? TPath extends `${infer K}.${infer R}`
76
+ ? K extends keyof T
77
+ ? R extends Path<T[K]>
78
+ ? undefined extends T[K]
79
+ ? PathValue<T[K], R> | undefined
80
+ : PathValue<T[K], R>
81
+ : never
82
+ : K extends `${ArrayKey}`
83
+ ? T extends readonly (infer V)[]
84
+ ? PathValue<V, R & Path<V>>
85
+ : never
86
+ : never
87
+ : TPath extends keyof T
88
+ ? T[TPath]
89
+ : TPath extends `${ArrayKey}`
90
+ ? T extends readonly (infer V)[]
91
+ ? V
92
+ : never
93
+ : never
94
+ : never
95
+
96
+ export type AnyBoolean<Schema> =
97
+ | boolean
98
+ | Ref<boolean>
99
+ | ((data?: InjectedFormData<Schema>) => boolean | Ref<boolean>)
100
+
101
+ export type SimpleFormTemplateItem<Schema extends FormSchema> = Record<
102
+ string,
103
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
104
+ any
105
+ > & {
106
+ vvIs?: string | Component
107
+ vvName?: Path<z.infer<Schema>>
108
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
109
+ vvSlots?: Record<string, any>
110
+ vvChildren?: Array<
111
+ | SimpleFormTemplateItem<Schema>
112
+ | ((data?: InjectedFormData<Schema>) => SimpleFormTemplateItem<Schema>)
113
+ >
114
+ vvIf?: AnyBoolean<Schema>
115
+ vvElseIf?: AnyBoolean<Schema>
116
+ vvType?: `${FormFieldType}`
117
+ vvShowValid?: boolean
118
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
119
+ vvDefaultValue?: any
120
+ }
121
+
122
+ export type FormTemplateItem<Schema extends FormSchema> =
123
+ | SimpleFormTemplateItem<Schema>
124
+ | ((data?: InjectedFormData<Schema>) => SimpleFormTemplateItem<Schema>)
package/dist/utils.d.ts CHANGED
@@ -1,14 +1,3 @@
1
1
  import { type z } from 'zod';
2
- export declare const defaultObjectBySchema: <Schema extends z.AnyZodObject | z.ZodEffects<z.AnyZodObject, {
3
- [x: string]: any;
4
- }, {
5
- [x: string]: any;
6
- }> | z.ZodEffects<z.ZodEffects<z.AnyZodObject, {
7
- [x: string]: any;
8
- }, {
9
- [x: string]: any;
10
- }>, {
11
- [x: string]: any;
12
- }, {
13
- [x: string]: any;
14
- }>>(schema: Schema, original?: Partial<z.TypeOf<Schema>>) => Partial<z.TypeOf<Schema>>;
2
+ import type { FormSchema } from './types';
3
+ export declare const defaultObjectBySchema: <Schema extends FormSchema>(schema: Schema, original?: Partial<z.TypeOf<Schema>>) => Partial<z.TypeOf<Schema>>;
package/package.json CHANGED
@@ -19,7 +19,7 @@
19
19
  "bugs": {
20
20
  "url": "https://github.com/volverjs/form-vue/issues"
21
21
  },
22
- "version": "0.0.10-beta.4",
22
+ "version": "0.0.10-beta.6",
23
23
  "engines": {
24
24
  "node": ">= 16.x"
25
25
  },
@@ -44,8 +44,8 @@
44
44
  "devDependencies": {
45
45
  "@playwright/experimental-ct-vue": "^1.32.3",
46
46
  "@testing-library/vue": "^7.0.0",
47
- "@typescript-eslint/eslint-plugin": "^5.58.0",
48
- "@typescript-eslint/parser": "^5.58.0",
47
+ "@typescript-eslint/eslint-plugin": "^5.59.0",
48
+ "@typescript-eslint/parser": "^5.59.0",
49
49
  "@vitejs/plugin-vue": "^4.1.0",
50
50
  "@volverjs/style": "^0.1.8",
51
51
  "@vue/compiler-sfc": "^3.2.47",
@@ -55,14 +55,14 @@
55
55
  "eslint": "^8.38.0",
56
56
  "eslint-config-prettier": "^8.8.0",
57
57
  "eslint-plugin-prettier": "^4.2.1",
58
- "happy-dom": "^9.6.1",
58
+ "happy-dom": "^9.9.2",
59
59
  "prettier": "^2.8.7",
60
60
  "typescript": "^5.0.4",
61
- "vite": "^4.2.1",
61
+ "vite": "^4.3.1",
62
62
  "vite-plugin-eslint": "^1.8.1",
63
63
  "vite-plugin-externalize-deps": "^0.5.0",
64
64
  "vitest": "^0.30.1",
65
- "vue-tsc": "^1.2.0"
65
+ "vue-tsc": "^1.4.2"
66
66
  },
67
67
  "typesVersions": {
68
68
  "*": {
@@ -84,6 +84,7 @@
84
84
  "lint": "eslint . --ext .js,.jsx,.ts,.tsx",
85
85
  "type-check": "tsc --noEmit",
86
86
  "build": "vite build && vue-tsc --declaration --emitDeclarationOnly && copy src/**/types.d.ts dist",
87
+ "test": "pnpm run test-vitest && pnpm run test-playwright",
87
88
  "test-vitest": "vitest run",
88
89
  "test-vitest-watch": "vitest",
89
90
  "test-playwright": "playwright test -c playwright-ct.config.ts",
package/src/VvForm.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import {
2
2
  type InjectionKey,
3
+ type DeepReadonly,
4
+ type Ref,
3
5
  withModifiers,
4
6
  defineComponent,
5
7
  ref,
@@ -9,29 +11,15 @@ import {
9
11
  h,
10
12
  toRaw,
11
13
  isProxy,
14
+ computed,
12
15
  } from 'vue'
13
16
  import { watchThrottled } from '@vueuse/core'
14
-
15
- import {
16
- type z,
17
- type ZodFormattedError,
18
- type AnyZodObject,
19
- type ZodEffects,
20
- } from 'zod'
21
- import type { InjectedFormData } from './types'
17
+ import type { z, ZodFormattedError, TypeOf } from 'zod'
18
+ import type { FormSchema, InjectedFormData } from './types'
19
+ import { FormStatus } from './enums'
22
20
  import { defaultObjectBySchema } from './utils'
23
21
 
24
- export enum FormStatus {
25
- invalid = 'invalid',
26
- valid = 'valid',
27
- }
28
-
29
- export const defineForm = <
30
- Schema extends
31
- | AnyZodObject
32
- | ZodEffects<AnyZodObject>
33
- | ZodEffects<ZodEffects<AnyZodObject>>,
34
- >(
22
+ export const defineForm = <Schema extends FormSchema>(
35
23
  schema: Schema,
36
24
  provideKey: InjectionKey<InjectedFormData<Schema>>,
37
25
  options?: {
@@ -41,115 +29,153 @@ export const defineForm = <
41
29
  ) => {
42
30
  const errors = ref<ZodFormattedError<z.infer<Schema>>>()
43
31
  const status = ref<FormStatus | undefined>()
44
- const localModelValue = ref<Partial<z.infer<Schema> | undefined>>()
45
-
46
- return {
47
- errors,
48
- status,
49
- formData: localModelValue,
50
- component: defineComponent({
51
- name: 'FormComponent',
52
- props: {
53
- modelValue: {
54
- type: Object,
55
- default: () => ({}),
56
- },
57
- continuosValidation: {
58
- type: Boolean,
59
- default: false,
60
- },
32
+ const formData = ref<Partial<z.infer<Schema> | undefined>>()
33
+ const component = defineComponent({
34
+ name: 'FormComponent',
35
+ props: {
36
+ modelValue: {
37
+ type: Object,
38
+ default: () => ({}),
61
39
  },
62
- emits: ['invalid', 'valid', 'submit', 'update:modelValue'],
63
- expose: ['submit', 'errors', 'status'],
64
- setup(props, { emit }) {
65
- localModelValue.value = defaultObjectBySchema(
66
- schema,
67
- props.modelValue,
68
- )
69
-
70
- const keepValidation =
71
- options?.continuosValidation || props.continuosValidation
40
+ continuosValidation: {
41
+ type: Boolean,
42
+ default: false,
43
+ },
44
+ },
45
+ emits: ['invalid', 'valid', 'submit', 'update:modelValue'],
46
+ expose: ['submit', 'errors', 'status'],
47
+ setup(props, { emit }) {
48
+ formData.value = defaultObjectBySchema(schema, props.modelValue)
72
49
 
73
- watch(
74
- () => props.modelValue,
75
- (newValue) => {
76
- if (newValue) {
77
- const original = isProxy(newValue)
78
- ? toRaw(newValue)
79
- : newValue
80
- localModelValue.value =
81
- typeof original?.clone === 'function'
82
- ? original.clone()
83
- : JSON.parse(JSON.stringify(original))
84
- }
85
- },
86
- { deep: true },
87
- )
88
- // v-model
89
- watchThrottled(
90
- localModelValue,
91
- (newValue) => {
92
- if (errors.value || keepValidation) {
93
- parseModelValue()
94
- }
95
- if (
96
- !newValue ||
97
- !props.modelValue ||
98
- JSON.stringify(newValue) !==
99
- JSON.stringify(props.modelValue)
100
- ) {
101
- emit('update:modelValue', newValue)
102
- }
103
- },
104
- { deep: true, throttle: options?.updateThrottle ?? 500 },
105
- )
50
+ const keepValidation =
51
+ options?.continuosValidation || props.continuosValidation
106
52
 
107
- const parseModelValue = (value = localModelValue.value) => {
108
- const parseResult = schema.safeParse(value)
109
- if (!parseResult.success) {
110
- errors.value =
111
- parseResult.error.format() as ZodFormattedError<
112
- z.infer<Schema>
113
- >
114
- status.value = FormStatus.invalid
115
- emit('invalid', errors.value)
116
- return false
53
+ watch(
54
+ () => props.modelValue,
55
+ (newValue) => {
56
+ if (newValue) {
57
+ const original = isProxy(newValue)
58
+ ? toRaw(newValue)
59
+ : newValue
60
+ formData.value =
61
+ typeof original?.clone === 'function'
62
+ ? original.clone()
63
+ : JSON.parse(JSON.stringify(original))
64
+ }
65
+ },
66
+ { deep: true },
67
+ )
68
+ // v-model
69
+ watchThrottled(
70
+ formData,
71
+ (newValue) => {
72
+ if (errors.value || keepValidation) {
73
+ parseModelValue()
117
74
  }
118
- errors.value = undefined
119
- status.value = FormStatus.valid
120
- localModelValue.value = parseResult.data
121
- emit('update:modelValue', localModelValue.value)
122
- emit('valid', parseResult.data)
123
- return true
75
+ if (
76
+ !newValue ||
77
+ !props.modelValue ||
78
+ JSON.stringify(newValue) !==
79
+ JSON.stringify(props.modelValue)
80
+ ) {
81
+ emit('update:modelValue', newValue)
82
+ }
83
+ },
84
+ { deep: true, throttle: options?.updateThrottle ?? 500 },
85
+ )
86
+
87
+ const parseModelValue = (value = formData.value) => {
88
+ const parseResult = schema.safeParse(value)
89
+ if (!parseResult.success) {
90
+ errors.value =
91
+ parseResult.error.format() as ZodFormattedError<
92
+ z.infer<Schema>
93
+ >
94
+ status.value = FormStatus.invalid
95
+ emit('invalid', errors.value)
96
+ return false
124
97
  }
98
+ errors.value = undefined
99
+ status.value = FormStatus.valid
100
+ formData.value = parseResult.data
101
+ emit('update:modelValue', formData.value)
102
+ emit('valid', parseResult.data)
103
+ return true
104
+ }
125
105
 
126
- // submit
127
- const submit = () => {
128
- if (!parseModelValue()) {
129
- return false
130
- }
131
- emit('submit', localModelValue.value)
132
- return true
106
+ // submit
107
+ const submit = () => {
108
+ if (!parseModelValue()) {
109
+ return false
133
110
  }
111
+ emit('submit', formData.value)
112
+ return true
113
+ }
134
114
 
135
- // provide
136
- provide(provideKey, {
137
- modelValue: localModelValue,
138
- submit,
139
- errors: readonly(errors),
140
- })
115
+ const invalid = computed(() => status.value === FormStatus.invalid)
141
116
 
142
- return { submit }
143
- },
144
- render() {
145
- return h(
146
- 'form',
147
- {
148
- onSubmit: withModifiers(this.submit, ['prevent']),
149
- },
150
- this.$slots,
151
- )
152
- },
153
- }),
117
+ // provide
118
+ provide(provideKey, {
119
+ formData,
120
+ submit,
121
+ errors: readonly(errors),
122
+ status: readonly(status),
123
+ invalid,
124
+ })
125
+
126
+ return {
127
+ formData,
128
+ submit,
129
+ errors: readonly(errors),
130
+ status: readonly(status),
131
+ invalid,
132
+ }
133
+ },
134
+ render() {
135
+ return h(
136
+ 'form',
137
+ {
138
+ onSubmit: withModifiers(this.submit, ['prevent']),
139
+ },
140
+ {
141
+ default: () =>
142
+ this.$slots?.default?.({
143
+ formData: this.formData,
144
+ submit: this.submit,
145
+ errors: this.errors,
146
+ status: this.status,
147
+ invalid: this.invalid,
148
+ }) ?? this.$slots.default,
149
+ },
150
+ )
151
+ },
152
+ })
153
+ return {
154
+ errors,
155
+ status,
156
+ formData,
157
+ /**
158
+ * An hack to add types to the default slot
159
+ */
160
+ VvForm: component as typeof component & {
161
+ new (): {
162
+ $slots: {
163
+ default: (_: {
164
+ formData: unknown extends
165
+ | Partial<TypeOf<Schema>>
166
+ | undefined
167
+ ? undefined
168
+ : Partial<TypeOf<Schema>> | undefined
169
+ submit: () => boolean
170
+ errors: Readonly<
171
+ Ref<DeepReadonly<z.inferFormattedError<Schema>>>
172
+ >
173
+ status: Ref<DeepReadonly<`${FormStatus}` | undefined>>
174
+ invalid: Ref<DeepReadonly<boolean>>
175
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
176
+ }) => any
177
+ }
178
+ }
179
+ },
154
180
  }
155
181
  }
@@ -18,21 +18,18 @@ import {
18
18
  defineComponent,
19
19
  onBeforeUnmount,
20
20
  } from 'vue'
21
- import type { AnyZodObject, ZodEffects, z } from 'zod'
21
+ import type { z } from 'zod'
22
22
  import { FormFieldType } from './enums'
23
23
  import type {
24
24
  InjectedFormData,
25
25
  InjectedFormWrapperData,
26
26
  InjectedFormFieldData,
27
27
  FormComposableOptions,
28
+ Path,
29
+ FormSchema,
28
30
  } from './types'
29
31
 
30
- export const defineFormField = <
31
- Schema extends
32
- | AnyZodObject
33
- | ZodEffects<AnyZodObject>
34
- | ZodEffects<ZodEffects<AnyZodObject>>,
35
- >(
32
+ export const defineFormField = <Schema extends FormSchema>(
36
33
  formProvideKey: InjectionKey<InjectedFormData<Schema>>,
37
34
  wrapperProvideKey: InjectionKey<InjectedFormWrapperData<Schema>>,
38
35
  formFieldInjectionKey: InjectionKey<InjectedFormFieldData<Schema>>,
@@ -54,7 +51,9 @@ export const defineFormField = <
54
51
  default: undefined,
55
52
  },
56
53
  name: {
57
- type: [String, Number, Boolean, Symbol],
54
+ type: [String, Number, Boolean, Symbol] as PropType<
55
+ Path<z.infer<Schema>>
56
+ >,
58
57
  required: true,
59
58
  },
60
59
  props: {
@@ -84,22 +83,22 @@ export const defineFormField = <
84
83
  // v-model
85
84
  const modelValue = computed({
86
85
  get() {
87
- if (!injectedFormData?.modelValue) return
86
+ if (!injectedFormData?.formData) return
88
87
  return get(
89
- Object(injectedFormData.modelValue.value),
88
+ Object(injectedFormData.formData.value),
90
89
  String(props.name),
91
90
  )
92
91
  },
93
92
  set(value) {
94
- if (!injectedFormData?.modelValue) return
93
+ if (!injectedFormData?.formData) return
95
94
  set(
96
- Object(injectedFormData.modelValue.value),
95
+ Object(injectedFormData.formData.value),
97
96
  String(props.name),
98
97
  value,
99
98
  )
100
99
  emit('update:modelValue', {
101
100
  newValue: modelValue.value,
102
- formData: injectedFormData?.modelValue,
101
+ formData: injectedFormData?.formData,
103
102
  })
104
103
  },
105
104
  })
@@ -160,9 +159,9 @@ export const defineFormField = <
160
159
  }
161
160
  })
162
161
  const unwatchInjectedFormData = watch(
163
- () => injectedFormData?.modelValue,
162
+ () => injectedFormData?.formData,
164
163
  () => {
165
- emit('update:formData', injectedFormData?.modelValue)
164
+ emit('update:formData', injectedFormData?.formData)
166
165
  },
167
166
  { deep: true },
168
167
  )
@@ -171,7 +170,7 @@ export const defineFormField = <
171
170
  }
172
171
  const hasFieldProps = computed(() => {
173
172
  if (typeof fieldProps.value === 'function') {
174
- return fieldProps.value(injectedFormData?.modelValue)
173
+ return fieldProps.value(injectedFormData?.formData)
175
174
  }
176
175
  return fieldProps.value
177
176
  })
@@ -225,8 +224,7 @@ export const defineFormField = <
225
224
  onUpdate,
226
225
  invalid: invalid.value,
227
226
  invalidLabel: invalidLabel.value,
228
- formData:
229
- injectedFormData?.modelValue.value,
227
+ formData: injectedFormData?.formData.value,
230
228
  formErrors: injectedFormData?.errors.value,
231
229
  errors: errors.value,
232
230
  }) ?? slots.defalut