maska
Version:
Simple zero-dependency input mask for Vanilla JS, Vue, Alpine.js and Svelte
3 lines (2 loc) • 7.31 kB
JavaScript
/*! maska v3.1.1 by Alexander Shabunevich | Released under the MIT license */
(function(c,l){typeof exports=="object"&&typeof module<"u"?l(exports):typeof define=="function"&&define.amd?define(["exports"],l):(c=typeof globalThis<"u"?globalThis:c||self,l(c.Maska={}))})(this,function(c){"use strict";var j=Object.defineProperty;var x=(c,l,b)=>l in c?j(c,l,{enumerable:!0,configurable:!0,writable:!0,value:b}):c[l]=b;var E=(c,l,b)=>x(c,typeof l!="symbol"?l+"":l,b);const l={"#":{pattern:/[0-9]/},"@":{pattern:/[a-zA-Z]/},"*":{pattern:/[a-zA-Z0-9]/}},b=(n,t,e)=>n.replaceAll(t,"").replace(e,".").replace("..",".").replace(/[^.\d]/g,""),w=(n,t,e)=>{var s;return new Intl.NumberFormat(((s=e.number)==null?void 0:s.locale)??"en",{minimumFractionDigits:n,maximumFractionDigits:t,roundingMode:"trunc"})},P=(n,t=!0,e)=>{var v,y,A,g;const s=((v=e.number)==null?void 0:v.unsigned)!==!0&&n.startsWith("-")?"-":"",r=((y=e.number)==null?void 0:y.fraction)??0;let a=w(0,r,e);const f=a.formatToParts(1000.12),m=((A=f.find(o=>o.type==="group"))==null?void 0:A.value)??" ",k=((g=f.find(o=>o.type==="decimal"))==null?void 0:g.value)??".",i=b(n,m,k);if(Number.isNaN(parseFloat(i)))return s;const p=i.split(".");if(p[1]!=null&&p[1].length>=1){const o=p[1].length<=r?p[1].length:r;a=w(o,r,e)}let h=a.format(parseFloat(i));return t?r>0&&i.endsWith(".")&&!i.slice(0,-1).includes(".")&&(h+=k):h=b(h,m,k),s+h};class I{constructor(t={}){E(this,"opts",{});E(this,"memo",new Map);const e={...t};if(e.tokens!=null){e.tokens=e.tokensReplace?{...e.tokens}:{...l,...e.tokens};for(const s of Object.values(e.tokens))typeof s.pattern=="string"&&(s.pattern=new RegExp(s.pattern))}else e.tokens=l;Array.isArray(e.mask)&&(e.mask.length>1?e.mask=[...e.mask].sort((s,r)=>s.length-r.length):e.mask=e.mask[0]??""),e.mask===""&&(e.mask=null),this.opts=e}masked(t){return this.process(String(t),this.findMask(String(t)))}unmasked(t){return this.process(String(t),this.findMask(String(t)),!1)}isEager(){return this.opts.eager===!0}isReversed(){return this.opts.reversed===!0}completed(t){const e=this.findMask(String(t));if(this.opts.mask==null||e==null)return!1;const s=this.process(String(t),e).length;return typeof this.opts.mask=="string"?s>=this.opts.mask.length:s>=e.length}findMask(t){const e=this.opts.mask;if(e==null)return null;if(typeof e=="string")return e;if(typeof e=="function")return e(t);const s=this.process(t,e.slice(-1).pop()??"",!1);return e.find(r=>this.process(t,r,!1).length>=s.length)??""}escapeMask(t){const e=[],s=[];return t.split("").forEach((r,a)=>{r==="!"&&t[a-1]!=="!"?s.push(a-s.length):e.push(r)}),{mask:e.join(""),escaped:s}}process(t,e,s=!0){if(this.opts.number!=null)return P(t,s,this.opts);if(e==null)return t;const r=`v=${t},mr=${e},m=${s?1:0}`;if(this.memo.has(r))return this.memo.get(r);const{mask:a,escaped:f}=this.escapeMask(e),m=[],k=this.opts.tokens!=null?this.opts.tokens:{},i=this.isReversed()?-1:1,p=this.isReversed()?"unshift":"push",h=this.isReversed()?0:a.length-1,v=this.isReversed()?()=>o>-1&&u>-1:()=>o<a.length&&u<t.length,y=M=>!this.isReversed()&&M<=h||this.isReversed()&&M>=h;let A,g=-1,o=this.isReversed()?a.length-1:0,u=this.isReversed()?t.length-1:0,C=!1;for(;v();){const M=a.charAt(o),d=k[M],R=(d==null?void 0:d.transform)!=null?d.transform(t.charAt(u)):t.charAt(u);if(!f.includes(o)&&d!=null?(R.match(d.pattern)!=null?(m[p](R),d.repeated?(g===-1?g=o:o===h&&o!==g&&(o=g-i),h===g&&(o-=i)):d.multiple&&(C=!0,o-=i),o+=i):d.multiple?C&&(o+=i,u-=i,C=!1):R===A?A=void 0:d.optional&&(o+=i,u-=i),u+=i):(s&&!this.isEager()&&m[p](M),R===M&&!this.isEager()?u+=i:A=M,this.isEager()||(o+=i)),this.isEager())for(;y(o)&&(k[a.charAt(o)]==null||f.includes(o));){if(s){if(m[p](a.charAt(o)),t.charAt(u)===a.charAt(o)){o+=i,u+=i;continue}}else a.charAt(o)===t.charAt(u)&&(u+=i);o+=i}}return this.memo.set(r,m.join("")),this.memo.get(r)}}const S=n=>JSON.parse(n.replaceAll("'",'"')),T=(n,t={})=>{const e={...t};n.dataset.maska!=null&&n.dataset.maska!==""&&(e.mask=F(n.dataset.maska)),n.dataset.maskaEager!=null&&(e.eager=N(n.dataset.maskaEager)),n.dataset.maskaReversed!=null&&(e.reversed=N(n.dataset.maskaReversed)),n.dataset.maskaTokensReplace!=null&&(e.tokensReplace=N(n.dataset.maskaTokensReplace)),n.dataset.maskaTokens!=null&&(e.tokens=O(n.dataset.maskaTokens));const s={};return n.dataset.maskaNumberLocale!=null&&(s.locale=n.dataset.maskaNumberLocale),n.dataset.maskaNumberFraction!=null&&(s.fraction=parseInt(n.dataset.maskaNumberFraction)),n.dataset.maskaNumberUnsigned!=null&&(s.unsigned=N(n.dataset.maskaNumberUnsigned)),(n.dataset.maskaNumber!=null||Object.values(s).length>0)&&(e.number=s),e},N=n=>n!==""?!!JSON.parse(n):!0,F=n=>n.startsWith("[")&&n.endsWith("]")?S(n):n,O=n=>{if(n.startsWith("{")&&n.endsWith("}"))return S(n);const t={};return n.split("|").forEach(e=>{const s=e.split(":");t[s[0]]={pattern:new RegExp(s[1]),optional:s[2]==="optional",multiple:s[2]==="multiple",repeated:s[2]==="repeated"}}),t};class W{constructor(t,e={}){E(this,"items",new Map);E(this,"eventAbortController");E(this,"onInput",t=>{if(t instanceof CustomEvent&&t.type==="input"&&!t.isTrusted&&!t.bubbles)return;const e=t.target,s=this.items.get(e);if(s===void 0)return;const r="inputType"in t&&t.inputType.startsWith("delete"),a=s.isEager(),f=r&&a&&s.unmasked(e.value)===""?"":e.value;this.fixCursor(e,r,()=>this.setValue(e,f))});this.options=e,this.eventAbortController=new AbortController,this.init(this.getInputs(t))}update(t={}){this.options={...t},this.init(Array.from(this.items.keys()))}updateValue(t){var e;t.value!==""&&t.value!==((e=this.processInput(t))==null?void 0:e.masked)&&this.setValue(t,t.value)}destroy(){this.eventAbortController.abort(),this.items.clear()}init(t){const e=this.getOptions(this.options);for(const s of t){if(!this.items.has(s)){const{signal:a}=this.eventAbortController;s.addEventListener("input",this.onInput,{capture:!0,signal:a})}const r=new I(T(s,e));this.items.set(s,r),queueMicrotask(()=>this.updateValue(s)),s.selectionStart===null&&r.isEager()&&console.warn("Maska: input of `%s` type is not supported",s.type)}}getInputs(t){return typeof t=="string"?Array.from(document.querySelectorAll(t)):"length"in t?Array.from(t):[t]}getOptions(t){const{onMaska:e,preProcess:s,postProcess:r,...a}=t;return a}fixCursor(t,e,s){var v,y;const r=t.selectionStart,a=t.value;if(s(),r===null||r===a.length&&!e)return;const f=t.value,m=a.slice(0,r),k=f.slice(0,r),i=(v=this.processInput(t,m))==null?void 0:v.unmasked,p=(y=this.processInput(t,k))==null?void 0:y.unmasked;if(i===void 0||p===void 0)return;let h=r;m!==k&&(h+=e?f.length-a.length:i.length-p.length),t.setSelectionRange(h,h)}setValue(t,e){const s=this.processInput(t,e);s!==void 0&&(t.value=s.masked,this.options.onMaska!=null&&(Array.isArray(this.options.onMaska)?this.options.onMaska.forEach(r=>r(s)):this.options.onMaska(s)),t.dispatchEvent(new CustomEvent("maska",{detail:s})),t.dispatchEvent(new CustomEvent("input",{detail:s.masked})))}processInput(t,e){const s=this.items.get(t);if(s===void 0)return;let r=e??t.value;this.options.preProcess!=null&&(r=this.options.preProcess(r));let a=s.masked(r);return this.options.postProcess!=null&&(a=this.options.postProcess(a)),{masked:a,unmasked:s.unmasked(r),completed:s.completed(r)}}}c.Mask=I,c.MaskInput=W,c.tokens=l,Object.defineProperty(c,Symbol.toStringTag,{value:"Module"})});