@code-gorilla-au/vue-forms
Version:
form authoring light weight framework
2 lines (1 loc) • 8.01 kB
JavaScript
import{provide as e,reactive as t,computed as a,readonly as n,inject as o,defineComponent as i,h as l,unref as r,onMounted as u,watch as s,ref as d,Fragment as c}from"vue";function v({debug:e}={debug:!1}){return{log(...t){e&&console.log(...t)},warn(...t){e&&console.warn(...t)},error(...t){e&&console.error(...t)}}}let p;const f=new Uint8Array(16);function m(){if(!p&&(p="undefined"!=typeof crypto&&crypto.getRandomValues&&crypto.getRandomValues.bind(crypto),!p))throw new Error("crypto.getRandomValues() not supported. See https://github.com/uuidjs/uuid#getrandomvalues-not-supported");return p(f)}const g=[];for(let e=0;e<256;++e)g.push((e+256).toString(16).slice(1));var y={randomUUID:"undefined"!=typeof crypto&&crypto.randomUUID&&crypto.randomUUID.bind(crypto)};function h(e,t,a){if(y.randomUUID&&!t&&!e)return y.randomUUID();const n=(e=e||{}).random||(e.rng||m)();if(n[6]=15&n[6]|64,n[8]=63&n[8]|128,t){a=a||0;for(let e=0;e<16;++e)t[a+e]=n[e];return t}return function(e,t=0){return(g[e[t+0]]+g[e[t+1]]+g[e[t+2]]+g[e[t+3]]+"-"+g[e[t+4]]+g[e[t+5]]+"-"+g[e[t+6]]+g[e[t+7]]+"-"+g[e[t+8]]+g[e[t+9]]+"-"+g[e[t+10]]+g[e[t+11]]+g[e[t+12]]+g[e[t+13]]+g[e[t+14]]+g[e[t+15]]).toLowerCase()}(n)}const M="|",V=":",b=",",I="ruleNotFound",w={email:{handler:function(e){const t=e.match(S);return null!==t&&(null==t?void 0:t.length)>0},validationMessage:()=>"Email must be valid"},not:{handler:function(e,...t){return t.some((t=>!e.includes(t)))},validationMessage:e=>`${e} is not allowed`},is:{handler:function(e,...t){return t.some((t=>e===t))},validationMessage:e=>`Input does not match ${e}`},contains:{handler:function(e,...t){return t.some((t=>e.includes(t)))},validationMessage:e=>`Does not contain ${e}`},prefix:{handler:function(e,...t){return t.some((t=>e.startsWith(t)))},validationMessage:e=>`Does not contain prefix ${e}`},suffix:{handler:function(e,...t){return t.some((t=>e.endsWith(t)))},validationMessage:e=>`Does not contain suffix ${e}`},[I]:{handler:(e,...t)=>!1,validationMessage:()=>"Rule not found"}};Object.freeze(w);const S=new RegExp(/^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/);function R(){const e={rules:w,get:e=>w[e]||w[I]};return{availableRules:()=>Object.keys(e.rules),evaluate(t,a){const n=function(e,t){return t.split(M).map((t=>{const[a,n]=t.split(V);let o=[];return n&&(o=n.split(b).map((e=>e.trim()))),{rule:a.trim(),value:e,ruleArgs:o}}))}(t,a);for(let t=0;t<n.length;t+=1){const a=n[t],o=e.get(a.rule);if(o&&!o.handler(a.value,...a.ruleArgs))return o.validationMessage(a.value)}}}}const q="internal.update.data";function D(e){return""===e.name?e.id:e.name}function $(e){return e.valid}function x(e={}){if("object"!=typeof e)throw new Error("initFormData is not valid");const o=t({}),i=t({}),l=t(JSON.parse(JSON.stringify(e))),r=v(),u=R();const s=function(e={debug:!1}){var t;const a=v({debug:null!==(t=e.debug)&&void 0!==t&&t}),n={};return{topics:()=>Object.keys(n),subscribe(e,t){if(!n[e])return a.log(`registering new topic: ${e}`),void(n[e]=[t]);a.log(`adding subscriber for topic: ${e}`),n[e]=[...n[e],t]},dispatch:async(t,o)=>new Promise(((i,l)=>{try{n[t].forEach((t=>{t(e,o)})),a.log(`event dispatched for topic: ${t}`),i(null)}catch(e){a.error(`${t} dispatch error `,e),l(e)}}))}}();function d(e){return{...o[e]}}s.subscribe(q,(function(e,t){o[t.payload.id]=t.payload;const a=D(t.payload),n=""===(r=t.payload).validationMessage?void 0:r.validationMessage;var r;const u=t.payload.namespace;if(!u)return l[a]=t.payload.value,void(i[a]=n);const s={__id:t.payload.id,[a]:t.payload.value};l[u]||(l[u]=[]);const d=l[u].findIndex((e=>e.__id===s.__id));-1!==d?l[u].splice(d,1,s):l[u].push(s)}));const c=a((()=>Object.values(o).every($)));return{nodes:n(o),data:n(l),formValid:c,validations:n(i),registerNode(e){if(d(e.id))return void r.error(`${e.id} already exists`);r.log(`${e.id} registered`),o[e.id]=e;const t=D(e);l[t]=""},getNode:d,validate:u.evaluate,async dispatch(e,t){const a={id:h(),timestamp:Date.now(),payload:{...t}};return await s.dispatch(e,a),await Promise.resolve()}}}const F=Symbol("--v-form-context");var U=i({name:"VForm",emits:{submit:null},props:{initFormData:{type:Object,required:!1,default:()=>({})}},setup(t,{emit:a,slots:n}){const o=function(t={}){const a=x(t);return e(F,a),a}(t.initFormData);return()=>l("form",{onSubmit(e){e.preventDefault(),e.stopPropagation(),a("submit",{...o.data})}},{default:()=>n.default&&n.default({formData:o.data,validations:o.validations,formValid:o.formValid})})}});const O=Symbol("--v-list-context");function j(e,a={initModelValue:void 0,validationRules:void 0,customValidation:!1}){const i=o(F,void 0),l=o(O,void 0),d=t({id:"",name:"",type:"",required:!1,readonly:!1,disabled:!1,focused:!1,dirty:!1,valid:!0,validationMessage:"",value:"",namespace:void 0});function c(e){var t,n;if(d.valid=(t=d.required,n=e.validity,t?n.valid&&!n.typeMismatch&&!n.valueMissing:n.valid&&!n.typeMismatch),d.valid&&(d.validationMessage=""),(null==a?void 0:a.customValidation)||!(null==a?void 0:a.validationRules))return;if(!i||"string"!=typeof d.value)return;const o=i.validate(d.value,a.validationRules);o&&(d.valid=!1,d.validationMessage=o)}function v(e){const t=e.target;var a;d.value="checkbox"===(a=t).type?a.checked:"radio"===a.type?a.checked?a.value:"":a.value,c(t)}function p(e){v(e)}function f(){const t=function(e){var t;const a=r(e);return null!==(t=null==a?void 0:a.$el)&&void 0!==t?t:a}(e);t&&t.focus()}return u((()=>{!async function(e){if(!e)return;const t=e;d.id=h(),d.value=a.initModelValue||"",d.dirty=""!==d.value,d.type=t.type,d.name=t.name,d.readonly=t.readOnly,d.required=t.required,c(t),l&&(d.namespace=l.namespace),i&&(i.getNode(d.name)||i.registerNode(d))}(e.value)})),s(d,(async e=>{i&&await i.dispatch(q,e)})),a.customValidation?{state:d,onInput:v,onChange:p,focusInputRef:f}:{state:n(d),onInput:v,onChange:p,onBlur:function(e){const t=e.target;d.focused=!1,d.dirty=""!==(null==t?void 0:t.value),(null==a?void 0:a.customValidation)||(d.valid=t.checkValidity(),c(t))},onFocus:function(){d.focused=!0,d.dirty=!0},onInvalid:function(e){const t=e.target;d.valid=!1,d.validationMessage=t.validationMessage},focusInputRef:f}}var C=i({name:"VInput",props:{type:{type:String,required:!1,default:"text"},name:{type:String,required:!0},modelValue:{type:String,required:!1,default:void 0},value:{type:String,required:!1},validationRules:{type:String,required:!1}},emits:{"update:modelValue":null,"update:validationMessage":null},setup(e,{emit:t,attrs:n,slots:o}){const i=d(null),r=j(i,{initModelValue:e.modelValue,validationRules:e.validationRules}),u=a((()=>{var t;return i.value&&"radio"===(null===(t=i.value)||void 0===t?void 0:t.type)?e.value:r.state.value})),c=a((()=>o.default&&o.default({validationMessage:r.state.validationMessage})));return s((()=>r.state.value),(e=>{t("update:modelValue",e)})),s((()=>r.state.validationMessage),(e=>{t("update:validationMessage",e)})),()=>[l("input",{...n,ref:i,type:e.type,name:e.name,value:u.value,onInput:r.onInput,onChange:r.onChange,onBlur:r.onBlur,onFocus:r.onFocus,onInvalid:r.onInvalid}),c.value]}}),N=i({name:"VList",props:{namespace:{type:String,required:!0}},setup:(t,{slots:a})=>(function({namespace:t}){e(O,{namespace:t})}({namespace:t.namespace}),()=>l(c,a.default&&a.default()))}),k=i({name:"VSelect",props:{name:{type:String,required:!0},modelValue:{type:String,required:!1,default:void 0},validationRules:{type:String,required:!1}},emits:{"update:modelValue":null,"update:validationMessage":null},setup(e,{emit:t,attrs:n,slots:o}){const i=d(null),r=j(i,{initModelValue:e.modelValue,validationRules:e.validationRules}),u=a((()=>o.default&&o.default())),c=a((()=>o.validation&&o.validation({validationMessage:r.state.validationMessage})));return s((()=>r.state.value),(e=>{t("update:modelValue",e)})),s((()=>r.state.validationMessage),(e=>{t("update:validationMessage",e)})),()=>[l("select",{...n,ref:i,name:e.name,onInput:r.onInput,onChange:r.onChange,onFocus:r.onFocus,onInvalid:r.onInvalid},[u.value]),c.value]}});export{U as VForm,C as VInput,N as VList,k as VSelect};