UNPKG

@coders-tm/vue-number-format

Version:

Easy formatted numbers, currency and percentage with input/directive mask for Vue.js

7 lines (6 loc) 8.82 kB
/** * Vue Number Format 3.34.1 * (c) 2021-2025 Dipak Sarkar <hello@dipaksarkar.in> (https://dipaksarkar.in/) * @license MIT */ "use strict";Object.defineProperty(exports,"__esModule",{value:!0});var e=require("vue"),t={prefix:"",suffix:"",separator:",",decimal:".",inputmode:"numeric",precision:2,minimumFractionDigits:null,prefill:!0,reverseFill:!1,min:null,max:null,nullValue:""};function i(e){return t=0,i=e,n=20,Math.max(t,Math.min(i,n));var t,i,n}class n{options;input;number;isClean;isCustomDecimal;noPreSuffix;hasPreOrSuffix;prefix;preSufRegExp;prefixRegExp;suffixRegExp;numberRegExp;cleanRegExp;negativeRegExp;constructor(e){this.options=Object.assign(u(t),e);const{prefix:i,suffix:n,decimal:r,reverseFill:s}=this.options;this.input="",this.number="",this.isClean=!s;const l=i,a=n,o=l.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&"),p=a.replace(/[-/\\^$*+?.()|[\]{}]/g,"\\$&");o&&(this.prefixRegExp=new RegExp(`^${o}`)),p&&(this.suffixRegExp=new RegExp(`${p}$`)),this.prefix=i,this.numberRegExp=new RegExp(`[^0-9\\${r||"."}]+`,"gi"),this.cleanRegExp=new RegExp("[^0-9]+","gi"),this.negativeRegExp=new RegExp("[^0-9\\-]+","gi"),this.isCustomDecimal="."!==r,this.noPreSuffix=!l&&!a,this.hasPreOrSuffix=!this.noPreSuffix}isNull(){return!this.numberOnly(this.isClean?this.cleanRegExp:this.negativeRegExp)}clean(e=!1){return this.isClean=e,this}sign(){if(null===this.input||void 0===this.input)return"";const e=this.input.toString().indexOf(r)>=0;return this.isClean?e&&this.realNumber()>0?r:"":e?r:""}toFixed(){const e=Math.pow(10,this.options.precision);return(parseFloat(this.numberOnly(/\D+/g))/e||0).toFixed(i(this.options.precision))}toNumber(e){return Number(e)}numberOnly(e){let t=this.input?.toString();return this.prefixRegExp&&(t=t.replace(this.prefixRegExp,"")),this.suffixRegExp&&(t=t.replace(this.suffixRegExp,"")),t.replace(e||this.numberRegExp,"")}inputWithPreOrSuffix(){return this.input&&this.prefixRegExp?this.prefixRegExp.test(this.input.toString()):!this.input||!this.suffixRegExp||this.suffixRegExp.test(this.input.toString())}isNegative(){return this.sign()===r}isNumber(e){return!isNaN(this.toNumber(e||this.input))}numbers(){const{reverseFill:e,decimal:t,separator:i}=this.options;if(e)this.number=this.toFixed().replace(".",t);else{const e=this.input?.toString().replace(this.prefixRegExp??"","").replace(this.suffixRegExp??"","").replace(new RegExp(r,"g"),""),n=this.input.toString().indexOf(t)>=0&&this.isCustomDecimal;let u=e;i&&(u=u.replace(new RegExp(`\\${i}`,"g"),"")),u=u.replace(t,"."),"number"==typeof this.input||this.isNumber()&&!n&&!this.inputWithPreOrSuffix()&&this.hasPreOrSuffix?this.number=this.parts(e,".").join(t):this.isNumber(u)&&!n&&this.inputWithPreOrSuffix()&&this.hasPreOrSuffix?this.number=this.parts(u,".").join(t):this.number=this.parts(this.numberOnly()).join(t)}return this.number}unformatNumber(){return this.numbers().toString().replace(this.options.decimal,".")}realNumber(){return parseFloat(this.unformatNumber())}parts(e,t){const{precision:i,minimumFractionDigits:n,decimal:r}=this.options;let u=e.toString().split(t||r);if(u.length>1&&(u[0]=this.toNumber(u[0])||0,u[1]=u.slice(1,u.length).join(""),u=u.slice(0,2)),this.isClean){const e=this.toNumber(u.join(".")).toFixed(i),t=this.toNumber(e),r=t.toFixed(n);u=n>=0&&t.toString().length<r.length?r.toString().split("."):t.toString().split(".")}return u.slice(0,2)}addSeparator(){const{decimal:e,separator:t}=this.options,i=this.numbers().split(e);return i[0]=i[0].toString().replace(/(\d)(?=(?:\d{3})+\b)/gm,`$1${t}`),i.join(e)}format(e){this.input=e;const{reverseFill:t,nullValue:i,prefix:n,suffix:r}=this.options;return this.isNull()&&!t?i:this.sign()+n+this.addSeparator()+r}unformat(e){this.input=e;const{reverseFill:t,nullValue:i}=this.options,n=this.realNumber(),r=this.unformatNumber();return this.isNull()||t&&0===n?i:this.sign()+r}}const r="-";function u(e){return JSON.parse(JSON.stringify(e))}function s(e){return new CustomEvent(e,{bubbles:!0,cancelable:!0,detail:{facade:!0}})}function l(e){const t=e instanceof HTMLInputElement?e:e.querySelector("input");if(!t)throw new Error("number directive requires an input element");return t}function a(e,t){const i=()=>{e.setSelectionRange(t,t)};i(),setTimeout(i,1)}function o(e,t,{emit:i=!0,force:r=!1,clean:u=!1}={}){const{options:l,oldValue:a}=e,{reverseFill:o,max:p,min:m}=l,c=t?.props?.value||e.value;if(r||a!==c){const t=new n(l).clean(u&&!o);let i=t.format(c),r=t.clean(!o).unformat(c);u&&(Number(p)===p&&Number(r)>p?(i=t.format(p),r=p.toString()):Number(m)===m&&Number(r)<m&&(i=t.format(m),r=m.toString())),e.oldValue=i,e.unmasked=r,e.value!==i&&(e.value=i)}return i&&e.dispatchEvent(s("input"))}var p={beforeMount:(e,{value:i,modifiers:r},s)=>{e=l(e);const a=Object.assign(u(t),i,r),{reverseFill:p,precision:m,decimal:c,inputmode:f}=a;e.options=a,e.setAttribute("inputmode",f),p&&e.value?(e.value=parseFloat(new n({...a,reverseFill:!1}).unformat(e.value)).toFixed(m),s?.props?.value&&(s.props.value=e.value)):e.value&&!isNaN(Number(e.value))&&(e.value=e.value.replace(".",c)),o(e,s,{force:a.prefill,clean:!0,emit:!1})},mounted:e=>{const t=(e=l(e)).parentElement||e,i=t=>{t.target===e&&function(e){const{target:t,detail:i}=e;if(i?.facade)return!1;e.stopPropagation();let n=t.value.length;const{oldValue:r,options:u}=t;t.selectionEnd&&(n=t.value.length-t.selectionEnd),o(t,null,{clean:!u.precision,emit:!1}),u.suffix&&(n=Math.max(n,u.suffix.length)),n=t.value.length-n,u.prefix&&(n=Math.max(n,u.prefix.length)),a(t,n),r!==t.value&&t.dispatchEvent(s("input"))}(t)},n=t=>{t.target===e&&function(e){const{target:t}=e,{oldValue:i}=t;o(t,null,{force:!0,clean:!0,emit:!1}),i!==t.value&&t.dispatchEvent(s("input"))}(t)},u=t=>{t.target===e&&function(e,t){const{options:i}=t,{prefix:n,suffix:u,decimal:s,min:l,separator:o}=i,{key:p}=e,m=new RegExp(`${n}|${u}`,"g"),c=t.value.replace(m,""),f=void 0===l||Number(l)<0||Number(l)!==l;if(p===s)c.includes(s)?e.preventDefault():c||(t.value="0",t.dispatchEvent(new Event("input")));else if(p!==r||f){if("Backspace"===p){const i=t.selectionEnd||0,s=t.value.slice(i-1,i),l=t.value.slice(i-2,i);let p=t.value.length-i;[n,r,o].includes(s)&&(e.preventDefault(),t.value=s===o?t.value.replace(l,""):t.value.replace(new RegExp(`[${n}${r}]`,"g"),""),p=Math.max(p,u.length),p=t.value.length-p,p=Math.max(p,n.length),a(t,p),t.dispatchEvent(new Event("input")))}}else e.preventDefault()}(t,e)};t.addEventListener("input",i,!0),t.addEventListener("blur",n,!0),t.addEventListener("keydown",u,!0),e.cleanup=()=>{t.removeEventListener("input",i,!0),t.removeEventListener("blur",n,!0),t.removeEventListener("keydown",u,!0)}},updated:(e,{value:t,oldValue:i,modifiers:n},r)=>{if(e=l(e),t!==i){const i=e.options;e.options=Object.assign(i,t,n),o(e,r,{force:!0,clean:!1,emit:!1})}else o(e,r,{emit:!1})},unmounted:e=>{l(e)?.cleanup()}};const m=u(t);var c=e.defineComponent({name:"VueNumber",directives:{number:p},props:{modelValue:{type:[String,Number],required:!0},nullValue:{type:[Number,String],default:m.nullValue},masked:Boolean,readonly:Boolean,disabled:Boolean,reverseFill:{type:Boolean,default:m.reverseFill},prefill:{type:Boolean,default:m.prefill},precision:{type:Number,default:()=>m.precision},minimumFractionDigits:{type:Number,default:()=>m.minimumFractionDigits},decimal:{type:String,default:()=>m.decimal},min:{type:Number,default:()=>m.min},max:{type:Number,default:()=>m.max},separator:{type:String,default:()=>m.separator},prefix:{type:String,default:()=>m.prefix},suffix:{type:String,default:()=>m.suffix},inputmode:{type:String,default:()=>m.inputmode}},emits:["update:model-value","input:model-value"],setup(t,{emit:i}){const r=e.ref(t.modelValue),u=e.ref(!1),s=e.ref(""),l=e.computed((()=>({...t}))),a=new n(l.value),o=e.computed((()=>t.masked?a.format(r.value):s.value)),p=()=>{i("update:model-value",o.value)};return e.watch((()=>t.modelValue),(e=>{o.value!==e&&(r.value=a.format(e))})),{config:l,maskedValue:r,unmaskedValue:s,input:e=>{const{target:t}=e;r.value=t.value,s.value=t.unmasked,u.value=!0,i("input:model-value",o.value)},blur:()=>{u.value&&o.value!==t.modelValue&&p()},change:p}}});const f=["value","readonly","disabled"];c.render=function(t,i,n,r,u,s){const l=e.resolveDirective("number");return e.withDirectives((e.openBlock(),e.createElementBlock("input",{type:"text",autocomplete:"off",value:t.maskedValue,readonly:t.readonly,disabled:t.disabled,class:"v-number vue-number-format",onChange:i[0]||(i[0]=(...e)=>t.change&&t.change(...e)),onInput:i[1]||(i[1]=(...e)=>t.input&&t.input(...e)),onBlur:i[2]||(i[2]=(...e)=>t.blur&&t.blur(...e))},null,40,f)),[[l,t.config]])},c.__file="src/component.vue";const h={install(e,i){i&&Object.assign(t,i),e.directive("number",p),e.component("VueNumber",c)}};exports.NumberFormat=n,exports.component=c,exports.default=h,exports.directive=p,exports.options=t;