├── .github
├── CONTRIBUTING.md
├── ISSUE_TEMPLATE.md
├── PULL_REQUEST_TEMPLATE.md
└── workflows
│ └── node.js.yml
├── .gitignore
├── LICENSE
├── README.md
├── dist
└── vue-numeric.min.js
├── docs
└── index.html
├── package-lock.json
├── package.json
├── src
├── index.js
└── vue-numeric.vue
├── test
├── karma.config.js
└── specs
│ └── vue-numeric.spec.js
└── webpack.config.js
/.github/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing guidelines
2 | When contributing to this repository, please first discuss the change you wish to make via issue, email, or any other method with the owners of this repository before making a change.
3 |
4 | ## Proposing a change
5 | If you intend to change the public API, or make any non-trivial changes to the implementation, we recommend filing an issue. This lets us reach an agreement on your proposal before you put significant effort into it.
6 |
7 | ## Javascript style guides
8 | - Javascript must adhere to [Vue.js official recommended style](https://github.com/vuejs/eslint-plugin-vue).
9 | - Lint command: `npm run lint`.
10 |
11 | ## DocBlock
12 | Every function, methods, computed properties, props should have a docblock to explain what it does
13 |
14 | example:
15 | ```js
16 | /**
17 | * Check provided value againts maximum allowed.
18 | * @param {Number} value
19 | * @return {Boolean}
20 | */
21 | checkMaxValue (value) {
22 | if (this.max) {
23 | if (value <= this.maxValue) return false
24 | return true
25 | }
26 | return false
27 | },
28 | ```
29 |
30 | ## Test
31 | - Make sure current tests is all green :white_check_mark:
32 | - If you've added code that should be tested, add tests!
33 | - Any new feature or changes should include tests for it.
34 | - Make sure code coverage % does not decrease.
35 |
36 | ## Readme
37 | Update the [README.md](https://github.com/kevinongko/vue-numeric/blob/master/README.md) with details of changes.
38 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | > If you are reporting bugs please fill the form below otherwise feel free to delete the form.
2 |
3 | ## Expected Behavior
4 |
5 |
6 | ## Actual Behavior
7 |
8 |
9 | ## Steps to Reproduce the Problem
10 |
11 | 1.
12 | 1.
13 | 1.
14 |
15 | ## Specifications
16 |
17 | - Plugin Version:
18 | - Vue.js Version:
19 | - Browser:
20 | - OS:
21 |
--------------------------------------------------------------------------------
/.github/PULL_REQUEST_TEMPLATE.md:
--------------------------------------------------------------------------------
1 | > Make sure to read the [contribution guidelines](https://github.com/kevinongko/vue-numeric/blob/master/.github/CONTRIBUTING.md) before submitting PR.
--------------------------------------------------------------------------------
/.github/workflows/node.js.yml:
--------------------------------------------------------------------------------
1 | # This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs
3 |
4 | name: Node.js CI
5 |
6 | on:
7 | push:
8 | branches: [ "master" ]
9 | pull_request:
10 | branches: [ "master" ]
11 |
12 | jobs:
13 | build:
14 |
15 | runs-on: ubuntu-latest
16 |
17 | strategy:
18 | matrix:
19 | node-version: [14.x]
20 | # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
21 |
22 | steps:
23 | - uses: actions/checkout@v3
24 | - name: Use Node.js ${{ matrix.node-version }}
25 | uses: actions/setup-node@v3
26 | with:
27 | node-version: ${{ matrix.node-version }}
28 | cache: 'npm'
29 | - run: npm install
30 | - run: npm run lint
31 | - run: npm run test
32 | - run: npm run report-coverage
33 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | npm-debug.log
2 | yarn-error.log
3 | node_modules
4 | .DS_Store
5 | /test/coverage/
6 | /.vscode
7 | /.idea
8 | *.swp
9 | *.swo
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 Kevin Ongko
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-numeric
2 |
3 | [](https://www.npmjs.com/package/vue-numeric)
4 | [](https://www.npmjs.com/package/vue-numeric)
5 | [](https://www.npmjs.com/package/vue-numeric)
6 | [](https://github.com/kevinongko/vue-numeric/actions/workflows/node.js.yml)
7 | [](https://codecov.io/gh/kevinongko/vue-numeric)
8 | [](http://opensource.org/licenses/MIT)
9 |
10 | Input field component to display a formatted currency value based on [Vue](https://vuejs.org/).
11 |
12 | [Live Demo](https://kevinongko.github.io/vue-numeric/)
13 |
14 | **Works with Vue 2.***
15 |
16 | ## Installation
17 |
18 | ### Install via CDN
19 | ```html
20 |
21 |
22 |
23 |
24 |
27 | ```
28 | ### Install via NPM
29 | ```sh
30 | $ npm install vue-numeric --save
31 | ```
32 |
33 | #### Register as Component
34 | ```js
35 | import Vue from 'vue'
36 | import VueNumeric from 'vue-numeric'
37 |
38 | export default {
39 | name: 'App',
40 |
41 | components: {
42 | VueNumeric
43 | }
44 | }
45 | ```
46 |
47 | #### Register as Plugin
48 | ```js
49 | import Vue from 'vue'
50 | import VueNumeric from 'vue-numeric'
51 |
52 | Vue.use(VueNumeric)
53 | ```
54 |
55 | ## Usage
56 |
57 | 
58 |
59 | ### Quick example
60 |
61 | ```vue
62 |
63 |
64 |
65 |
66 |
81 | ```
82 |
83 | ### Currency symbol
84 |
85 | Set the `currency` prop to add a currency symbol within the input.
86 |
87 | ```vue
88 |
89 | ```
90 |
91 | ### Minimum & maximum constraint
92 |
93 | Limit the minimum and maximum value by using `min` and `max` props.
94 |
95 | - `min` defaults to `0`.
96 | - `min` and `max` accept `String` or `Number` values.
97 |
98 | ```vue
99 |
100 | ```
101 |
102 | ### Disable/enable negative values
103 |
104 | `minus` defaults to `false` (no negative numbers).
105 |
106 | ```vue
107 |
108 | ```
109 |
110 | ### Enable decimal precision
111 |
112 | By default the decimal value is disabled. To use decimals in the value, add the `precision` prop.
113 | - `precision` accept a `String` or `Number` numeric value.
114 |
115 | ```vue
116 |
117 | ```
118 |
119 | ### Thousands separator
120 | - Default thousand separator's symbol is `,`.
121 | - Use the `separator` prop to change the thousands separator.
122 | - `separator` only accepts `space`, `,` or `.`.
123 | - When using the `.` or `space` as thousand separator, the decimal separator will be `,`.
124 |
125 | ```vue
126 |
127 | ```
128 |
129 | ### Input placeholder when empty
130 | ```vue
131 |
132 | ```
133 |
134 | ### Value when empty
135 | By default, when you clean the input the value is set to `0`. You can change this value to fit your needs.
136 | ```vue
137 |
138 | ```
139 |
140 | ### Output Type
141 | By default the value emitted for the input event is of type `Number`. However you may choose to get a `String` instead
142 | by setting the property `output-type` to `String`.
143 | ```vue
144 |
145 | ```
146 |
147 | ## Props
148 | |Props|Description|Required|Type|Default|
149 | |-----|-----------|--------|----|-------|
150 | |currency|Currency prefix|false|String|-|
151 | |currency-symbol-position|Position of the symbol (accepted values: `prefix` or `suffix`)|false|String|`prefix`|
152 | |max|Maximum value allowed|false|Number|9007199254740991|
153 | |min|Minimum value allowed|false|Number|-9007199254740991|
154 | |minus|Enable/disable negative values|false|Boolean|`false`|
155 | |placeholder|Input placeholder|false|String|-|
156 | |empty-value|Value when input is empty|false|Number|0|
157 | |output-type|Output Type for input event|false|String|`Number`|
158 | |precision|Number of decimals|false|Number|-|
159 | |separator|Thousand separator symbol (accepts `space`, `.` or `,`)|false|String|`,`|
160 | |decimal-separator|Custom decimal separator|false|String|-|
161 | |thousand-separator|Custom thousand separator|false|String|-|
162 | |read-only|Hide input field and show the value as text|false|Boolean|false|
163 | |read-only-class|Class for read-only element|false|String|''|
164 | |allow-clear|Use input type search|false|Boolean|false|
165 |
166 | ## License
167 |
168 | Vue-Numeric is open-sourced software licensed under the [MIT license](http://opensource.org/licenses/MIT)
169 |
170 | ## Support
171 | Hello, I'm Kevin the maintainer of this project in my free time (which is getting lessen these days), if this project does help you in any way please consider to support me. Thanks :smiley:
172 | - [One-time donation via Paypal](https://www.paypal.me/kevinongko)
173 |
174 |
--------------------------------------------------------------------------------
/dist/vue-numeric.min.js:
--------------------------------------------------------------------------------
1 | !function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t(require("accounting-js")):"function"==typeof define&&define.amd?define("VueNumeric",["accounting-js"],t):"object"==typeof exports?exports.VueNumeric=t(require("accounting-js")):e.VueNumeric=t(e.accounting)}("undefined"!=typeof self?self:this,function(e){return function(e){function t(n){if(r[n])return r[n].exports;var a=r[n]={i:n,l:!1,exports:{}};return e[n].call(a.exports,a,a.exports,t),a.l=!0,a.exports}var r={};return t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=1)}([function(e,t,r){"use strict";var n=r(4);r.n(n);t.a={name:"VueNumeric",props:{allowClear:{type:Boolean,default:!1,required:!1},currency:{type:String,default:"",required:!1},max:{type:Number,default:Number.MAX_SAFE_INTEGER||9007199254740991,required:!1},min:{type:Number,default:Number.MIN_SAFE_INTEGER||-9007199254740991,required:!1},minus:{type:Boolean,default:!1,required:!1},placeholder:{type:String,default:"",required:!1},emptyValue:{type:[Number,String],default:"",required:!1},precision:{type:Number,default:0,required:!1},separator:{type:String,default:",",required:!1},thousandSeparator:{default:void 0,required:!1,type:String},decimalSeparator:{default:void 0,required:!1,type:String},outputType:{required:!1,type:String,default:"Number"},value:{type:[Number,String],default:0,required:!0},readOnly:{type:Boolean,default:!1,required:!1},readOnlyClass:{type:String,default:"",required:!1},disabled:{type:Boolean,default:!1,required:!1},currencySymbolPosition:{type:String,default:"prefix",required:!1}},data:function(){return{amount:""}},computed:{amountNumber:function(){return this.unformat(this.amount)},valueNumber:function(){return this.unformat(this.value)},decimalSeparatorSymbol:function(){return void 0!==this.decimalSeparator?this.decimalSeparator:","===this.separator?".":","},thousandSeparatorSymbol:function(){return void 0!==this.thousandSeparator?this.thousandSeparator:"."===this.separator?".":"space"===this.separator?" ":","},symbolPosition:function(){return this.currency?"suffix"===this.currencySymbolPosition?"%v %s":"%s %v":"%v"}},watch:{valueNumber:function(e){this.$refs.numeric!==document.activeElement&&(this.amount=this.format(e))},readOnly:function(e,t){var r=this;!1===t&&!0===e&&this.$nextTick(function(){r.$refs.readOnly.className=r.readOnlyClass})},separator:function(){this.process(this.valueNumber),this.amount=this.format(this.valueNumber)},currency:function(){this.process(this.valueNumber),this.amount=this.format(this.valueNumber)},precision:function(){this.process(this.valueNumber),this.amount=this.format(this.valueNumber)}},mounted:function(){var e=this;(this.valueNumber||this.isDeliberatelyZero())&&(this.process(this.valueNumber),this.amount=this.format(this.valueNumber),setTimeout(function(){e.process(e.valueNumber),e.amount=e.format(e.valueNumber)},500)),this.readOnly&&(this.$refs.readOnly.className=this.readOnlyClass)},methods:{onChangeHandler:function(e){this.$emit("change",e)},onBlurHandler:function(e){this.$emit("blur",e),this.amount=this.format(this.valueNumber)},onFocusHandler:function(e){if(this.$emit("focus",e),"string"==typeof this.valueNumber&&""===this.valueNumber)return"";this.amount=Object(n.formatMoney)(this.valueNumber,{symbol:"",format:"%v",thousand:"",decimal:this.decimalSeparatorSymbol,precision:Number(this.precision)})},onInputHandler:function(){this.process(this.amountNumber)},process:function(e){"string"==typeof e&&""===e?this.$emit("input",e):(e>=this.max&&this.update(this.max),e<=this.min&&this.update(this.min),e>this.min&&e=0?this.update(this.min):this.update(0)))},update:function(e){var t=Object(n.toFixed)(e,this.precision),r="string"===this.outputType.toLowerCase()?t:Number(t);this.$emit("input",r)},format:function(e){return"string"==typeof e&&""===e?"":Object(n.formatMoney)(e,{symbol:this.currency,format:this.symbolPosition,precision:Number(this.precision),decimal:this.decimalSeparatorSymbol,thousand:this.thousandSeparatorSymbol})},unformat:function(e){var t="string"==typeof e&&""===e?this.emptyValue:e;return"string"==typeof t&&""===t?"":Object(n.unformat)(t,this.decimalSeparatorSymbol)},isDeliberatelyZero:function(){return 0===this.valueNumber&&""!==this.value}}}},function(e,t,r){"use strict";Object.defineProperty(t,"__esModule",{value:!0});var n=r(2),a={install:function(e){e.component(n.a.name,n.a)}};n.a.install=a.install,t.default=n.a},function(e,t,r){"use strict";var n=r(0),a=r(5),i=r(3),o=i(n.a,a.a,!1,null,null,null);t.a=o.exports},function(e,t){e.exports=function(e,t,r,n,a,i){var o,u=e=e||{},s=typeof e.default;"object"!==s&&"function"!==s||(o=e,u=e.default);var l="function"==typeof u?u.options:u;t&&(l.render=t.render,l.staticRenderFns=t.staticRenderFns,l._compiled=!0),r&&(l.functional=!0),a&&(l._scopeId=a);var c;if(i?(c=function(e){e=e||this.$vnode&&this.$vnode.ssrContext||this.parent&&this.parent.$vnode&&this.parent.$vnode.ssrContext,e||"undefined"==typeof __VUE_SSR_CONTEXT__||(e=__VUE_SSR_CONTEXT__),n&&n.call(this,e),e&&e._registeredComponents&&e._registeredComponents.add(i)},l._ssrRegister=c):n&&(c=n),c){var d=l.functional,m=d?l.render:l.beforeCreate;d?(l._injectStyles=c,l.render=function(e,t){return c.call(t),m(e,t)}):l.beforeCreate=m?[].concat(m,c):[c]}return{esModule:o,exports:u,options:l}}},function(t,r){t.exports=e},function(e,t,r){"use strict";var n=function(){var e=this,t=e.$createElement,r=e._self._c||t;return"checkbox"!=(e.allowClear?"search":"tel")||e.readOnly?"radio"!=(e.allowClear?"search":"tel")||e.readOnly?e.readOnly?r("span",{ref:"readOnly"},[e._v(e._s(e.amount))]):r("input",{directives:[{name:"model",rawName:"v-model",value:e.amount,expression:"amount"}],ref:"numeric",attrs:{placeholder:e.placeholder,disabled:e.disabled,type:e.allowClear?"search":"tel"},domProps:{value:e.amount},on:{blur:e.onBlurHandler,input:[function(t){t.target.composing||(e.amount=t.target.value)},e.onInputHandler],focus:e.onFocusHandler,change:e.onChangeHandler}}):r("input",{directives:[{name:"model",rawName:"v-model",value:e.amount,expression:"amount"}],ref:"numeric",attrs:{placeholder:e.placeholder,disabled:e.disabled,type:"radio"},domProps:{checked:e._q(e.amount,null)},on:{blur:e.onBlurHandler,input:e.onInputHandler,focus:e.onFocusHandler,change:[function(t){e.amount=null},e.onChangeHandler]}}):r("input",{directives:[{name:"model",rawName:"v-model",value:e.amount,expression:"amount"}],ref:"numeric",attrs:{placeholder:e.placeholder,disabled:e.disabled,type:"checkbox"},domProps:{checked:Array.isArray(e.amount)?e._i(e.amount,null)>-1:e.amount},on:{blur:e.onBlurHandler,input:e.onInputHandler,focus:e.onFocusHandler,change:[function(t){var r=e.amount,n=t.target,a=!!n.checked;if(Array.isArray(r)){var i=e._i(r,null);n.checked?i<0&&(e.amount=r.concat([null])):i>-1&&(e.amount=r.slice(0,i).concat(r.slice(i+1)))}else e.amount=a},e.onChangeHandler]}})},a=[],i={render:n,staticRenderFns:a};t.a=i}])});
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | vue-numeric demo
7 |
8 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | Vue Numeric
21 |
22 |
23 | Input field component to display currency value based on Vue.js
24 |