[
  {
    "path": ".browserslistrc",
    "content": "defaults\nnot ie 11\n"
  },
  {
    "path": ".eslintignore",
    "content": "*.local*\ncoverage\ndist\nnode_modules\n"
  },
  {
    "path": ".eslintrc.js",
    "content": "module.exports = {\n  root: true,\n  env: {\n    browser: true,\n    node: true,\n  },\n  extends: [\n    'airbnb-typescript/base',\n    'plugin:@typescript-eslint/recommended',\n    'plugin:vue/vue3-recommended',\n  ],\n  parser: 'vue-eslint-parser',\n  parserOptions: {\n    parser: '@typescript-eslint/parser',\n    project: 'tsconfig.eslint.json',\n    sourceType: 'module',\n    extraFileExtensions: ['.vue'],\n  },\n  plugins: [\n    '@typescript-eslint',\n    'import',\n    'vue',\n  ],\n  rules: {\n    '@typescript-eslint/no-explicit-any': 'off',\n    '@typescript-eslint/no-var-requires': 'off',\n    'no-restricted-properties': 'off',\n  },\n  overrides: [\n    {\n      files: ['tests/**/*.ts'],\n      env: {\n        jest: true,\n      },\n    },\n  ],\n};\n"
  },
  {
    "path": ".github/workflows/ci.yml",
    "content": "name: CI\n\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v2\n        with:\n          node-version: 16\n      - run: npm install\n      - run: npm run lint\n      - run: npm run build\n      - run: npm test\n      - run: npm run test:coverage\n"
  },
  {
    "path": ".github/workflows/deploy.yml",
    "content": "name: Deploy\n\non:\n  push:\n    tags:\n      - v2.*\n  workflow_dispatch:\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n\n    steps:\n      - uses: actions/checkout@v2\n      - uses: actions/setup-node@v2\n        with:\n          node-version: 16\n      - run: npm install\n      - run: npm run build:docs\n      - run: |\n          cd docs/dist\n          git init\n          git config user.name \"${{ github.actor }}\"\n          git config user.email \"${{ github.actor }}@users.noreply.github.com\"\n          git add --all\n          git commit --message \"♥\"\n          git push --force https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git master:gh-pages\n"
  },
  {
    "path": ".gitignore",
    "content": "*.local*\n*.log\n*.map\n.DS_Store\ncoverage\ndist\nnode_modules\n"
  },
  {
    "path": ".husky/commit-msg",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx commitlint --edit $1\n"
  },
  {
    "path": ".husky/pre-commit",
    "content": "#!/bin/sh\n. \"$(dirname \"$0\")/_/husky.sh\"\n\nnpx lint-staged\n"
  },
  {
    "path": ".stylelintignore",
    "content": "*.local*\ncoverage\ndist\nnode_modules\n"
  },
  {
    "path": "CHANGELOG.md",
    "content": "## [2.0.1](https://github.com/fengyuanchen/vue-number-input/compare/v2.0.0...v2.0.1) (2022-02-13)\n\n\n### Bug Fixes\n\n* round the normalized new value ([30aaa6a](https://github.com/fengyuanchen/vue-number-input/commit/30aaa6a4a74b99e177477fb21f8ad178d13bb8af)), closes [#32](https://github.com/fengyuanchen/vue-number-input/issues/32)\n\n\n\n# [2.0.0](https://github.com/fengyuanchen/vue-number-input/compare/v2.0.0-rc.2...v2.0.0) (2022-02-07)\n\n\n\n# [2.0.0-rc.2](https://github.com/fengyuanchen/vue-number-input/compare/v2.0.0-rc.1...v2.0.0-rc.2) (2022-01-22)\n\n\n### Bug Fixes\n\n* correct the declaration file name ([7f96219](https://github.com/fengyuanchen/vue-number-input/commit/7f96219dc88afa516244db39715b087bcb04dbcf))\n\n\n\n# [2.0.0-rc.1](https://github.com/fengyuanchen/vue-number-input/compare/v2.0.0-rc...v2.0.0-rc.1) (2022-01-08)\n\n\n### Bug Fixes\n\n* add `oldValue` to `update:modelValue` event ([4fa92f0](https://github.com/fengyuanchen/vue-number-input/commit/4fa92f03047ebe5dbc45a5e531575d1df081f20c))\n* avoid specifying `NaN` value to number input ([101abce](https://github.com/fengyuanchen/vue-number-input/commit/101abce5375f938fd06301877a84cb25c88df71c)), closes [#31](https://github.com/fengyuanchen/vue-number-input/issues/31)\n\n\n### Features\n\n* add auto-generated declaration file ([5ecd316](https://github.com/fengyuanchen/vue-number-input/commit/5ecd316699c3e60d0f7b6d591c0d3476e3f03cd2))\n\n\n\n# [2.0.0-rc](https://github.com/fengyuanchen/vue-number-input/compare/v2.0.0-beta.1...v2.0.0-rc) (2021-06-12)\n\n\n\n# [2.0.0-beta.1](https://github.com/fengyuanchen/vue-number-input/compare/v2.0.0-beta...v2.0.0-beta.1) (2021-04-10)\n\n\n### Bug Fixes\n\n* round the new value in the last setp ([c43a69f](https://github.com/fengyuanchen/vue-number-input/commit/c43a69f5b67c5e02fbd1eccb007c947aa5482f8e))\n* should emit a single value ([cb8bed9](https://github.com/fengyuanchen/vue-number-input/commit/cb8bed9b9470882588e8b281466cea088afc0009))\n\n\n### Features\n\n* support to clear the input value through the keyboard ([fd9faf2](https://github.com/fengyuanchen/vue-number-input/commit/fd9faf23737fb568426fbbe0d879c076cb6cf419)), closes [#28](https://github.com/fengyuanchen/vue-number-input/issues/28)\n\n\n\n# [2.0.0-beta](https://github.com/fengyuanchen/vue-number-input/compare/v2.0.0-alpha...v2.0.0-beta) (2021-01-16)\n\n\n\n# [2.0.0-alpha](https://github.com/fengyuanchen/vue-number-input/compare/v1.2.1...v2.0.0-alpha) (2021-01-08)\n\n\n* refactor!: upgrade to Vue 3 ([65be700](https://github.com/fengyuanchen/vue-number-input/commit/65be700df03c167abb347c546ba579035d59fc16))\n\n\n### BREAKING CHANGES\n\n* drop support for Vue 2.\n\n\n\n## [1.2.1](https://github.com/fengyuanchen/vue-number-input/compare/v1.2.0...v1.2.1) (2020-01-18)\n\n\n### Bug Fixes\n\n* add `tabindex` attribute to control buttons ([05869bc](https://github.com/fengyuanchen/vue-number-input/commit/05869bcb058d06608085141b0260962b6f028262)), closes [#20](https://github.com/fengyuanchen/vue-number-input/issues/20)\n\n\n\n# [1.2.0](https://github.com/fengyuanchen/vue-number-input/compare/v1.1.2...v1.2.0) (2019-10-19)\n\n\n### Features\n\n* add new `attrs` prop ([e8b1498](https://github.com/fengyuanchen/vue-number-input/commit/e8b1498fa485253392afe505c854f6967d6e5990))\n\n\n\n## [1.1.2](https://github.com/fengyuanchen/vue-number-input/compare/v1.1.1...v1.1.2) (2019-10-02)\n\n\n### Bug Fixes\n\n* hide the spin box in number input box in Firefox ([580ec5c](https://github.com/fengyuanchen/vue-number-input/commit/580ec5c960c6b9bd4984631a1932321443673ba5)), closes [#17](https://github.com/fengyuanchen/vue-number-input/issues/17)\n\n\n\n## [1.1.1](https://github.com/fengyuanchen/vue-number-input/compare/v1.1.0...v1.1.1) (2019-03-09)\n\n\n### Bug Fixes\n\n* add missing `-webkit-` prefix to `appearance` property ([f71d0ae](https://github.com/fengyuanchen/vue-number-input/commit/f71d0aeb2e6211e2b37dd66cc348fb035247c207)), closes [#12](https://github.com/fengyuanchen/vue-number-input/issues/12)\n* force to override the number in the input box ([7d816d4](https://github.com/fengyuanchen/vue-number-input/commit/7d816d4ec7652160aae2b330e9502ce2e256fc9a)), closes [#13](https://github.com/fengyuanchen/vue-number-input/issues/13)\n\n\n\n# [1.1.0](https://github.com/fengyuanchen/vue-number-input/compare/v1.0.0...v1.1.0) (2019-01-26)\n\n\n### Features\n\n* register as a Vue plugin ([b23b09e](https://github.com/fengyuanchen/vue-number-input/commit/b23b09ef0e14601f0bb8b673bd2313b77d6c2e28))\n* register the component automatically once loaded ([e86eab1](https://github.com/fengyuanchen/vue-number-input/commit/e86eab1db441100f71e667e5edb297c1030f6830))\n\n\n\n# [1.0.0](https://github.com/fengyuanchen/vue-number-input/compare/v0.5.3...v1.0.0) (2018-12-20)\n\n\n### Bug Fixes\n\n* avoid the size to less than 1px ([03d804d](https://github.com/fengyuanchen/vue-number-input/commit/03d804d418d1b21c971fe0e7df8a50cec2413bd9)), closes [#10](https://github.com/fengyuanchen/vue-number-input/issues/10)\n\n\n### Performance Improvements\n\n* avoid to trigger change event when created ([b1cd06f](https://github.com/fengyuanchen/vue-number-input/commit/b1cd06f901f5c2567e94cb3353f326514ac30ed0))\n\n\n\n## [0.5.3](https://github.com/fengyuanchen/vue-number-input/compare/v0.5.2...v0.5.3) (2018-12-01)\n\n\n### Bug Fixes\n\n* sync value only when it is different ([7100b1f](https://github.com/fengyuanchen/vue-number-input/commit/7100b1f01923a9dd4e5927e181a6f1fb15ae8711)), closes [#8](https://github.com/fengyuanchen/vue-number-input/issues/8)\n* update input value automatically ([b2dae7f](https://github.com/fengyuanchen/vue-number-input/commit/b2dae7f5358914d9e863b2a0604eaa2201ed7b1d)), closes [#9](https://github.com/fengyuanchen/vue-number-input/issues/9)\n\n\n\n## [0.5.2](https://github.com/fengyuanchen/vue-number-input/compare/v0.5.1...v0.5.2) (2018-08-05)\n\n\n### Bug Fixes\n\n* the 0.30000000000000004 problem ([8f5a3e0](https://github.com/fengyuanchen/vue-number-input/commit/8f5a3e0f63ed46417fa80d597aa7c246fde65ba4)), closes [#6](https://github.com/fengyuanchen/vue-number-input/issues/6)\n\n\n\n## [0.5.1](https://github.com/fengyuanchen/vue-number-input/compare/v0.5.0...v0.5.1) (2018-06-09)\n\n\n### Bug Fixes\n\n* change the input value only when it is mounted ([cada801](https://github.com/fengyuanchen/vue-number-input/commit/cada8012e9428e633188eab93b19cff6e35f8f17)), closes [#4](https://github.com/fengyuanchen/vue-number-input/issues/4)\n\n\n\n# [0.5.0](https://github.com/fengyuanchen/vue-number-input/compare/v0.4.1...v0.5.0) (2018-06-06)\n\n\n### Bug Fixes\n\n* off auto complete ([d14af46](https://github.com/fengyuanchen/vue-number-input/commit/d14af4611b182615298e841db5806e00fac34615))\n\n\n### Features\n\n* add `placeholder` prop ([331caa6](https://github.com/fengyuanchen/vue-number-input/commit/331caa6a2a1828043a0df778ddd175cd63dce5c1))\n* add `rounded` prop ([99dd179](https://github.com/fengyuanchen/vue-number-input/commit/99dd179d8e9b0438e867248e540d6f2a737a225d))\n\n\n\n## [0.4.1](https://github.com/fengyuanchen/vue-number-input/compare/v0.4.0...v0.4.1) (2018-05-27)\n\n\n\n# [0.4.0](https://github.com/fengyuanchen/vue-number-input/compare/v0.3.0...v0.4.0) (2018-05-27)\n\n\n### Features\n\n* add `inputtable` prop ([98131c9](https://github.com/fengyuanchen/vue-number-input/commit/98131c9d6890b7a0a4aa4f41b13891a766054f2e)), closes [#2](https://github.com/fengyuanchen/vue-number-input/issues/2)\n\n\n\n# [0.3.0](https://github.com/fengyuanchen/vue-number-input/compare/v0.2.0...v0.3.0) (2018-03-25)\n\n\n\n# [0.2.0](https://github.com/fengyuanchen/vue-number-input/compare/v0.1.0...v0.2.0) (2018-03-21)\n\n\n\n# 0.1.0 (2018-03-13)\n\n\n\n"
  },
  {
    "path": "LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright 2018-present Chen Fengyuan\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "# vue-number-input\n\n[![Coverage Status](https://img.shields.io/codecov/c/github/fengyuanchen/vue-number-input.svg)](https://codecov.io/gh/fengyuanchen/vue-number-input) [![Downloads](https://img.shields.io/npm/dm/@chenfengyuan/vue-number-input.svg)](https://www.npmjs.com/package/@chenfengyuan/vue-number-input) [![Version](https://img.shields.io/npm/v/@chenfengyuan/vue-number-input.svg)](https://www.npmjs.com/package/@chenfengyuan/vue-number-input) [![Gzip Size](https://img.shields.io/bundlephobia/minzip/@chenfengyuan/vue-number-input.svg)](https://unpkg.com/@chenfengyuan/vue-number-input/dist/vue-number-input.js)\n\n> Number input component for Vue 3. For Vue 2, check out the [`v1`](https://github.com/fengyuanchen/vue-number-input/tree/v1) branch.\n\n- [Docs](src/README.md)\n- [Demo](https://fengyuanchen.github.io/vue-number-input)\n\n## Main npm package files\n\n```text\ndist/\n├── vue-number-input.js         (UMD, default)\n├── vue-number-input.min.js     (UMD, compressed)\n├── vue-number-input.esm.js     (ECMAScript Module)\n├── vue-number-input.esm.min.js (ECMAScript Module, compressed)\n└── vue-number-input.d.ts       (TypeScript Declaration File)\n```\n\n## Getting started\n\n### Installation\n\nUsing npm:\n\n```shell\nnpm install vue@3 @chenfengyuan/vue-number-input@2\n```\n\nUsing pnpm:\n\n```shell\npnpm add vue@3 @chenfengyuan/vue-number-input@2\n```\n\nUsing Yarn:\n\n```shell\nyarn add vue@3 @chenfengyuan/vue-number-input@2\n```\n\nUsing CDN:\n\n```html\n<script src=\"https://unpkg.com/vue@3\"></script><!-- Vue.js is required -->\n<script src=\"https://unpkg.com/@chenfengyuan/vue-number-input@2\"></script>\n```\n\n### Usage\n\n```js\nimport { createApp } from 'vue';\nimport VueNumberInput from '@chenfengyuan/vue-number-input';\n\nconst app = createApp({});\n\napp.component(VueNumberInput.name, VueNumberInput);\n```\n\n```html\n<vue-number-input controls></vue-number-input>\n```\n\n## Browser support\n\nSame as Vue 3.\n\n## Versioning\n\nMaintained under the [Semantic Versioning guidelines](https://semver.org/).\n\n## License\n\n[MIT](https://opensource.org/licenses/MIT) © [Chen Fengyuan](https://chenfengyuan.com/)\n"
  },
  {
    "path": "babel.config.js",
    "content": "module.exports = {\n  presets: ['@babel/preset-env'],\n};\n"
  },
  {
    "path": "commitlint.config.js",
    "content": "module.exports = {\n  extends: [\n    '@commitlint/config-conventional',\n  ],\n};\n"
  },
  {
    "path": "docs/app.vue",
    "content": "<template>\n  <div class=\"app\">\n    <header class=\"navbar navbar-light navbar-expand-md\">\n      <nav class=\"container\">\n        <a\n          class=\"navbar-brand\"\n          href=\"./\"\n        >\n          {{ name }}\n        </a>\n        <button\n          class=\"navbar-toggler\"\n          type=\"button\"\n          data-bs-toggle=\"collapse\"\n          data-bs-target=\"#navbar-collapse\"\n          aria-controls=\"navbar-collapse\"\n          aria-expanded=\"false\"\n          aria-label=\"Toggle navigation\"\n        >\n          <span class=\"navbar-toggler-icon\" />\n        </button>\n        <div\n          id=\"navbar-collapse\"\n          class=\"collapse navbar-collapse justify-content-end\"\n          role=\"navigation\"\n        >\n          <nav class=\"nav navbar-nav\">\n            <a\n              class=\"nav-link\"\n              href=\"https://github.com/fengyuanchen/vue-number-input\"\n              title=\"View the GitHub project\"\n            >\n              GitHub\n            </a>\n            <a\n              class=\"nav-link\"\n              href=\"https://fengyuanchen.github.io/\"\n              title=\"Explore more projects\"\n            >\n              Explore\n            </a>\n            <a\n              class=\"nav-link\"\n              href=\"https://chenfengyuan.com/\"\n              title=\"About the author\"\n            >\n              About\n            </a>\n          </nav>\n        </div>\n      </nav>\n    </header>\n    <main>\n      <div class=\"bg-primary text-white py-5\">\n        <div class=\"container\">\n          <div class=\"row\">\n            <div class=\"col-md\">\n              <h1>\n                {{ name }} <small class=\"h6\">\n                  v{{ version }}\n                </small>\n              </h1>\n              <p class=\"lead\">\n                {{ description }}\n              </p>\n            </div>\n            <div class=\"col-md\">\n              <div\n                ref=\"carbonads\"\n                class=\"carbonads\"\n              />\n            </div>\n          </div>\n        </div>\n      </div>\n      <div class=\"container\">\n        <div class=\"markdown-body\">\n          <Readme />\n        </div>\n      </div>\n    </main>\n    <footer>\n      <div class=\"container\">\n        <p class=\"heart\" />\n        <nav class=\"nav flex-wrap justify-content-center mb-3\">\n          <a\n            class=\"nav-link\"\n            href=\"https://github.com/fengyuanchen/vue-number-input\"\n          >\n            GitHub\n          </a>\n          <a\n            class=\"nav-link\"\n            href=\"https://github.com/fengyuanchen/vue-number-input/blob/main/CHANGELOG.md\"\n          >\n            Changelog\n          </a>\n          <a\n            class=\"nav-link\"\n            href=\"https://github.com/fengyuanchen/vue-number-input/blob/main/LICENSE\"\n          >\n            License\n          </a>\n          <a\n            class=\"nav-link\"\n            href=\"https://chenfengyuan.com/\"\n          >\n            About\n          </a>\n        </nav>\n      </div>\n    </footer>\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\nimport pkg from '../package.json';\nimport Readme from '../src/README.md';\n\n// eslint-disable-next-line\npkg.name = pkg.name.split('/').pop() || '';\n\nexport default defineComponent({\n  components: {\n    Readme,\n  },\n\n  data() {\n    return pkg;\n  },\n\n  mounted() {\n    const script = document.createElement('script');\n\n    script.async = true;\n    script.id = '_carbonads_js';\n    script.src = '//cdn.carbonads.com/carbon.js?serve=CKYI55Q7&placement=fengyuanchengithubio';\n    (this.$refs.carbonads as Element).appendChild(script);\n  },\n});\n</script>\n\n<style lang=\"scss\">\n.markdown-body {\n  table {\n    display: table;\n    min-width: 100%;\n  }\n\n  code {\n    white-space: nowrap;\n  }\n}\n\n.carbonads {\n  border: 1px solid #ccc;\n  border-radius: 0.25rem;\n  font-size: 0.875rem;\n  overflow: hidden;\n  padding: 1rem;\n\n  @media (min-width: 768px) {\n    float: right;\n    margin-bottom: -1rem;\n    margin-top: -1rem;\n    max-width: 360px;\n  }\n}\n\n.carbon {\n  &-wrap {\n    overflow: hidden;\n  }\n\n  &-img {\n    clear: left;\n    display: block;\n    float: left;\n  }\n\n  &-text,\n  &-poweredby {\n    display: block;\n    margin-left: 140px;\n\n    &,\n    &:focus,\n    &:hover {\n      color: #fff;\n      text-decoration: none;\n    }\n  }\n\n  &-poweredby {\n    color: #ddd;\n  }\n}\n\n.heart {\n  color: #ddd;\n  display: block;\n  height: 2rem;\n  line-height: 2rem;\n  margin-bottom: 0;\n  margin-top: 1rem;\n  position: relative;\n  text-align: center;\n  width: 100%;\n\n  &:hover {\n    color: #ff4136;\n  }\n\n  &::before {\n    border-top: 1px solid #eee;\n    content: '';\n    display: block;\n    height: 0;\n    left: 0;\n    position: absolute;\n    right: 0;\n    top: 50%;\n  }\n\n  &::after {\n    background-color: #fff;\n    content: '♥';\n    padding-left: 0.5rem;\n    padding-right: 0.5rem;\n    position: relative;\n    z-index: 1;\n  }\n}\n</style>\n"
  },
  {
    "path": "docs/components/demo-block.vue",
    "content": "<template>\n  <div class=\"demo-block\">\n    <slot />\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nexport default defineComponent({\n  name: 'DemoBlock',\n});\n</script>\n\n<style lang=\"scss\">\n.demo-block {\n  border: 1px solid #eee;\n  border-top-left-radius: 0.25rem;\n  border-top-right-radius: 0.25rem;\n  padding: 1rem;\n  position: relative;\n\n  & + pre {\n    border: 1px solid #eee;\n    border-radius: 0.25rem;\n    border-top: 0;\n    border-top-left-radius: 0;\n    border-top-right-radius: 0;\n    margin-bottom: 1rem;\n  }\n}\n</style>\n"
  },
  {
    "path": "docs/index.html",
    "content": "<!DOCTYPE html>\n<html lang=\"en\">\n  <head>\n    <meta charset=\"utf-8\">\n    <meta http-equiv=\"x-ua-compatible\" content=\"ie=edge\">\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1, shrink-to-fit=no\">\n    <title>vue-number-input</title>\n    <meta name=\"description\" content=\"Number input component for Vue.js.\">\n    <meta name=\"author\" content=\"Chen Fengyuan\">\n    <link href=\"https://unpkg.com/bootstrap@5/dist/css/bootstrap.min.css\" rel=\"stylesheet\" crossorigin=\"anonymous\">\n    <link rel=\"stylesheet\" href=\"https://unpkg.com/github-markdown-css@4/github-markdown.css\" crossorigin=\"anonymous\">\n    <link rel=\"stylesheet\" href=\"https://unpkg.com/@highlightjs/cdn-assets@11/styles/github.min.css\" crossorigin=\"anonymous\">\n  </head>\n  <body>\n    <div id=\"app\"></div>\n    <script src=\"https://unpkg.com/bootstrap@5/dist/js/bootstrap.bundle.min.js\" crossorigin=\"anonymous\"></script>\n    <script src=\"https://unpkg.com/@highlightjs/cdn-assets@11/highlight.min.js\" crossorigin=\"anonymous\"></script>\n    <script src=\"https://unpkg.com/vue@3/dist/vue.global.prod.js\" crossorigin=\"anonymous\"></script>\n    <script src=\"https://fengyuanchen.github.io/shared/google-analytics.js\" crossorigin=\"anonymous\"></script>\n    <script>hljs.highlightAll();</script>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/index.ts",
    "content": "import { createApp } from 'vue';\nimport App from './app.vue';\nimport DemoBlock from './components/demo-block.vue';\nimport VueNumberInput from '../src';\n\nconst app = createApp(App);\n\napp.component(VueNumberInput.name, VueNumberInput);\napp.component(DemoBlock.name, DemoBlock);\napp.mount('#app');\n"
  },
  {
    "path": "jest.config.js",
    "content": "module.exports = {\n  preset: 'ts-jest',\n  collectCoverage: true,\n  coverageDirectory: 'coverage',\n  coverageReporters: ['html', 'lcov', 'text'],\n  moduleFileExtensions: ['js', 'ts', 'vue'],\n  transform: {\n    '^.+\\\\.js$': 'babel-jest',\n    '^.+\\\\.vue$': '@vue/vue3-jest',\n  },\n  testEnvironment: 'jsdom',\n  testMatch: ['**/tests/*.spec.ts'],\n};\n"
  },
  {
    "path": "lint-staged.config.js",
    "content": "module.exports = {\n  '*.{js,ts,vue}': 'eslint --fix',\n  '*.{css,scss,vue}': 'stylelint --fix',\n};\n"
  },
  {
    "path": "package.json",
    "content": "{\n  \"name\": \"@chenfengyuan/vue-number-input\",\n  \"version\": \"2.0.1\",\n  \"description\": \"Number input component for Vue 3.\",\n  \"main\": \"dist/vue-number-input.js\",\n  \"module\": \"dist/vue-number-input.esm.js\",\n  \"types\": \"dist/vue-number-input.d.ts\",\n  \"files\": [\n    \"dist\"\n  ],\n  \"scripts\": {\n    \"build\": \"rollup -c --environment BUILD:production\",\n    \"build:docs\": \"webpack --env production\",\n    \"build:types\": \"move-file dist/vue-number-input.vue.d.ts dist/vue-number-input.d.ts\",\n    \"changelog\": \"conventional-changelog -p angular -i CHANGELOG.md -s -r 0\",\n    \"clean\": \"del-cli dist\",\n    \"lint\": \"npm run lint:js && npm run lint:css\",\n    \"lint:css\": \"stylelint **/*.{css,scss,vue} --fix\",\n    \"lint:js\": \"eslint . --ext .js,.ts,.vue --fix\",\n    \"prepare\": \"husky install\",\n    \"release\": \"npm run clean && npm run lint && npm run build && npm run build:types && npm run build:docs && npm test && npm run changelog\",\n    \"serve\": \"webpack serve --hot --open\",\n    \"start\": \"npm run serve\",\n    \"test\": \"jest\",\n    \"test:coverage\": \"cat coverage/lcov.info | codecov\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"https://github.com/fengyuanchen/vue-number-input.git\"\n  },\n  \"keywords\": [\n    \"number\",\n    \"input\",\n    \"vue\",\n    \"vue3\",\n    \"vue-component\",\n    \"front-end\",\n    \"web\"\n  ],\n  \"author\": \"Chen Fengyuan (https://chenfengyuan.com/)\",\n  \"license\": \"MIT\",\n  \"bugs\": \"https://github.com/fengyuanchen/vue-number-input/issues\",\n  \"homepage\": \"https://fengyuanchen.github.io/vue-number-input\",\n  \"devDependencies\": {\n    \"@babel/core\": \"^7.17.2\",\n    \"@babel/preset-env\": \"^7.16.11\",\n    \"@commitlint/cli\": \"^16.2.1\",\n    \"@commitlint/config-conventional\": \"^16.2.1\",\n    \"@types/jest\": \"^27.4.0\",\n    \"@typescript-eslint/eslint-plugin\": \"^5.11.0\",\n    \"@typescript-eslint/parser\": \"^5.11.0\",\n    \"@vue/test-utils\": \"^2.0.0-rc.18\",\n    \"@vue/vue3-jest\": \"^27.0.0-alpha.4\",\n    \"babel-jest\": \"^27.5.1\",\n    \"babel-loader\": \"^8.2.3\",\n    \"change-case\": \"^4.1.2\",\n    \"codecov\": \"^3.8.3\",\n    \"conventional-changelog-cli\": \"^2.2.2\",\n    \"create-banner\": \"^2.0.0\",\n    \"css-loader\": \"^6.6.0\",\n    \"del-cli\": \"^4.0.1\",\n    \"eslint\": \"^8.9.0\",\n    \"eslint-config-airbnb-typescript\": \"^16.1.0\",\n    \"eslint-plugin-import\": \"^2.25.4\",\n    \"eslint-plugin-vue\": \"^8.4.1\",\n    \"html-webpack-plugin\": \"^5.5.0\",\n    \"husky\": \"^7.0.4\",\n    \"jest\": \"^27.5.1\",\n    \"lint-staged\": \"^12.3.3\",\n    \"markdown-to-vue-loader\": \"^3.1.3\",\n    \"mini-css-extract-plugin\": \"^2.5.3\",\n    \"move-file-cli\": \"^3.0.0\",\n    \"postcss\": \"^8.4.6\",\n    \"rollup\": \"^2.67.2\",\n    \"rollup-plugin-postcss\": \"^4.0.2\",\n    \"rollup-plugin-terser\": \"^7.0.2\",\n    \"rollup-plugin-typescript2\": \"^0.31.2\",\n    \"rollup-plugin-vue\": \"^6.0.0\",\n    \"sass\": \"^1.49.7\",\n    \"sass-loader\": \"^12.4.0\",\n    \"style-loader\": \"^3.3.1\",\n    \"stylelint\": \"^14.5.0\",\n    \"stylelint-config-recommended-scss\": \"^5.0.2\",\n    \"stylelint-config-recommended-vue\": \"^1.3.0\",\n    \"stylelint-order\": \"^5.0.0\",\n    \"ts-jest\": \"^27.1.3\",\n    \"ts-loader\": \"^9.2.6\",\n    \"tslib\": \"^2.3.1\",\n    \"typescript\": \"^4.5.5\",\n    \"vue\": \"^3.2.31\",\n    \"vue-loader\": \"^17.0.0\",\n    \"webpack\": \"^5.68.0\",\n    \"webpack-cli\": \"^4.9.2\",\n    \"webpack-dev-server\": \"^4.7.4\"\n  },\n  \"peerDependencies\": {\n    \"vue\": \"^3.0.0\"\n  },\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n"
  },
  {
    "path": "postcss.config.js",
    "content": "module.exports = {\n  plugins: {\n    stylelint: {\n      fix: true,\n    },\n  },\n};\n"
  },
  {
    "path": "rollup.config.js",
    "content": "import createBanner from 'create-banner';\nimport postcss from 'rollup-plugin-postcss';\nimport typescript from 'rollup-plugin-typescript2';\nimport vue from 'rollup-plugin-vue';\nimport { pascalCase } from 'change-case';\nimport { terser } from 'rollup-plugin-terser';\nimport pkg from './package.json';\n\nconst name = pascalCase(pkg.name.replace(/^.+\\//, ''));\nconst banner = createBanner({\n  data: {\n    year: '2018-present',\n  },\n  template: 'inline',\n});\n\nexport default ['umd', 'esm'].map((format) => ({\n  input: 'src/vue-number-input.vue',\n  output: ['development', 'production'].map((mode) => {\n    const output = {\n      banner,\n      format,\n      name,\n      file: pkg.main,\n      globals: {\n        vue: 'Vue',\n      },\n    };\n\n    if (format === 'esm') {\n      output.file = pkg.module;\n    }\n\n    if (mode === 'production') {\n      output.compact = true;\n      output.file = output.file.replace(/(\\.js)$/, '.min$1');\n      output.plugins = [\n        terser(),\n      ];\n    }\n\n    return output;\n  }),\n  external: Object.keys(pkg.peerDependencies),\n  plugins: [\n    typescript({\n      tsconfigOverride: {\n        compilerOptions: {\n          declaration: format === 'esm',\n        },\n        exclude: [\n          'src/index.ts',\n          'docs',\n          'tests',\n        ],\n      },\n    }),\n    vue({\n      preprocessStyles: true,\n    }),\n    postcss({\n      extensions: ['.css', '.scss'],\n      minimize: true,\n    }),\n  ],\n}));\n"
  },
  {
    "path": "src/README.md",
    "content": "# Number Input\n\n> Number input with optional controls.\n\n## Basic usage\n\n```html\n<template>\n  <p>Value: {{ value }}</p>\n  <vue-number-input v-model=\"value\" :min=\"1\" :max=\"10\" inline controls></vue-number-input>\n</template>\n\n<script>\nexport default {\n  data() {\n    return {\n      value: 1,\n    };\n  },\n};\n</script>\n```\n\n## Step\n\n```html\n<template>\n  <vue-number-input :step=\"10\" inline controls></vue-number-input>\n</template>\n```\n\n## Inline\n\n```html\n<template>\n  <p>\n    <vue-number-input placeholder=\"Block input (default)\" controls></vue-number-input>\n  </p>\n  <vue-number-input placeholder=\"Inline input\" inline controls></vue-number-input>\n</template>\n```\n\n## Center number\n\n```html\n<template>\n  <vue-number-input :model-value=\"0\" inline center controls></vue-number-input>\n</template>\n```\n\n## Sizes\n\n```html\n<template>\n  <vue-number-input placeholder=\"Small\" size=\"small\" inline controls></vue-number-input>\n  <vue-number-input placeholder=\"Default\" inline controls></vue-number-input>\n  <vue-number-input placeholder=\"Large\" size=\"large\" inline controls></vue-number-input>\n</template>\n\n<style scoped>\n.vue-number-input + .vue-number-input {\n  margin-left: 1rem;\n}\n</style>\n```\n\n## Without controls\n\n```html\n<template>\n  <vue-number-input placeholder=\"Small number input\" size=\"small\" inline></vue-number-input>\n  <vue-number-input placeholder=\"Default number input\" inline></vue-number-input>\n  <vue-number-input placeholder=\"Large number input\" size=\"large\" inline></vue-number-input>\n</template>\n\n<style scoped>\n.vue-number-input + .vue-number-input {\n  margin-left: 1rem;\n}\n</style>\n```\n\n## Rounded\n\n```html\n<template>\n  <vue-number-input :model-value=\"1.5\" inline controls rounded></vue-number-input>\n</template>\n```\n\n## Not inputtable\n\nThe input is not inputtable, but still allow to change the value by controls.\n\n```html\n<template>\n  <vue-number-input :model-value=\"1\" :min=\"1\" :max=\"3\" :inputtable=\"false\" inline controls></vue-number-input>\n</template>\n```\n\n## Readonly\n\n```html\n<template>\n  <vue-number-input :model-value=\"1\" inline controls readonly></vue-number-input>\n</template>\n```\n\n## Disabled\n\n```html\n<template>\n  <vue-number-input :model-value=\"0\" inline controls disabled></vue-number-input>\n</template>\n```\n\n## Customize attributes for the input element\n\n```html\n<template>\n  <vue-number-input :model-value=\"0\" :attrs=\"{ id: 'my-vue-number-input', tabindex: -1 }\" inline controls></vue-number-input>\n</template>\n```\n\n## Props\n\n| Name | Type | Default | Options | Description |\n| --- | --- | --- | --- | --- |\n| attrs | `Object` | - | - | Specify attributes for the built-in input element. |\n| center | `boolean` | `false` | - | Indicate if the number is center or not. |\n| controls | `boolean` | `false` | - | Indicate if the controls is visible or not. |\n| disabled | `boolean` | `false` | - | Indicate if the component is disabled or not. |\n| inline | `boolean` | `false` | - | Indicate if the input is inline or not. |\n| inputtable | `boolean` | `true` | - | Indicate if the input element is inputtable or not. |\n| max | `number` | `Infinity` | - | The maximum value. |\n| min | `number` | `-Infinity` | - | The minimum value. |\n| name | `string` | - | - | The name of the input element. |\n| placeholder | `string` | - | - | The placeholder of the input element. |\n| readonly | `boolean` | `false` | - | Indicate if the component is read only or not. |\n| rounded | `boolean` | `false` | - | Indicate if the number is rounded or not. |\n| size | `string` | - | small, large | The size of the component. |\n| step | `number` | `1` | - | The increment of each step. |\n| modelValue | `number` | - | - | The binding value. |\n\n## Events\n\n| Name | Parameters | Description |\n| --- | --- | --- |\n| update:model-value | `(newValue, oldValue)` | Fire when the value is changed. |\n\n> Native events that bubble up from child elements are also available.\n\n```html\n<template>\n  <vue-number-input @update:model-value=\"onUpdate\" @change=\"onChange\" @input=\"onInput\" inline controls></vue-number-input>\n</template>\n\n<script>\nexport default {\n  methods: {\n    onUpdate(newValue, oldValue) {\n      console.log(newValue, oldValue);\n    },\n    onChange(event) {\n      console.log(event);\n    },\n    onInput(event) {\n      console.log(event);\n    },\n  },\n};\n</script>\n```\n"
  },
  {
    "path": "src/index.ts",
    "content": "import VueNumberInput from './vue-number-input.vue';\n\nexport default VueNumberInput;\n"
  },
  {
    "path": "src/shims.d.ts",
    "content": "declare module '*.vue' {\n  const content: any;\n\n  export default content;\n}\n\ndeclare module '*.md' {\n  const content: any;\n\n  export default content;\n}\n"
  },
  {
    "path": "src/vue-number-input.vue",
    "content": "<template>\n  <div\n    class=\"vue-number-input\"\n    :class=\"{\n      'vue-number-input--inline': inline,\n      'vue-number-input--center': center,\n      'vue-number-input--controls': controls,\n      [`vue-number-input--${size}`]: size,\n    }\"\n  >\n    <button\n      v-if=\"controls\"\n      class=\"vue-number-input__button vue-number-input__button--minus\"\n      type=\"button\"\n      tabindex=\"-1\"\n      :disabled=\"disabled || readonly || !decreasable\"\n      @click.prevent=\"decrease\"\n    />\n    <input\n      ref=\"input\"\n      class=\"vue-number-input__input\"\n      v-bind=\"attrs\"\n      type=\"number\"\n      :name=\"name\"\n      :value=\"isNaN(value) ? '' : value\"\n      :min=\"min\"\n      :max=\"max\"\n      :step=\"step\"\n      :readonly=\"readonly || !inputtable\"\n      :disabled=\"disabled || (!decreasable && !increasable)\"\n      :placeholder=\"placeholder\"\n      autocomplete=\"off\"\n      @change=\"change\"\n      @paste=\"paste\"\n    >\n    <button\n      v-if=\"controls\"\n      class=\"vue-number-input__button vue-number-input__button--plus\"\n      type=\"button\"\n      tabindex=\"-1\"\n      :disabled=\"disabled || readonly || !increasable\"\n      @click.prevent=\"increase\"\n    />\n  </div>\n</template>\n\n<script lang=\"ts\">\nimport { defineComponent } from 'vue';\n\nconst isNaN = Number.isNaN || window.isNaN;\nconst REGEXP_NUMBER = /^-?(?:\\d+|\\d+\\.\\d+|\\.\\d+)(?:[eE][-+]?\\d+)?$/;\nconst REGEXP_DECIMALS = /\\.\\d*(?:0|9){10}\\d*$/;\nconst normalizeDecimalNumber = (value: number, times = 100000000000) => (\n  REGEXP_DECIMALS.test(String(value)) ? (Math.round(value * times) / times) : value\n);\n\nexport default defineComponent({\n  name: 'VueNumberInput',\n\n  props: {\n    attrs: {\n      type: Object,\n      default: undefined,\n    },\n\n    center: Boolean,\n    controls: Boolean,\n    disabled: Boolean,\n\n    inputtable: {\n      type: Boolean,\n      default: true,\n    },\n\n    inline: Boolean,\n\n    max: {\n      type: Number,\n      default: Infinity,\n    },\n\n    min: {\n      type: Number,\n      default: -Infinity,\n    },\n\n    name: {\n      type: String,\n      default: undefined,\n    },\n\n    placeholder: {\n      type: String,\n      default: undefined,\n    },\n\n    readonly: Boolean,\n    rounded: Boolean,\n\n    size: {\n      type: String,\n      default: undefined,\n    },\n\n    step: {\n      type: Number,\n      default: 1,\n    },\n\n    modelValue: {\n      type: Number,\n      default: NaN,\n    },\n  },\n\n  emits: [\n    'update:modelValue',\n  ],\n\n  data() {\n    return {\n      value: NaN,\n    };\n  },\n\n  computed: {\n    /**\n     * Indicate if the value is increasable.\n     * @returns {boolean} Return `true` if it is decreasable, else `false`.\n     */\n    increasable(): boolean {\n      return isNaN(this.value) || this.value < this.max;\n    },\n\n    /**\n     * Indicate if the value is decreasable.\n     * @returns {boolean} Return `true` if it is decreasable, else `false`.\n     */\n    decreasable(): boolean {\n      return isNaN(this.value) || this.value > this.min;\n    },\n  },\n\n  watch: {\n    modelValue: {\n      immediate: true,\n      handler(newValue, oldValue) {\n        if (\n          // Avoid triggering change event when created\n          !(isNaN(newValue) && typeof oldValue === 'undefined')\n\n          // Avoid infinite loop\n          && newValue !== this.value\n        ) {\n          this.setValue(newValue);\n        }\n      },\n    },\n  },\n\n  methods: {\n    isNaN,\n\n    /**\n     * Change event handler.\n     * @param {string} value - The new value.\n     */\n    change(event: any) {\n      this.setValue(event.target.value);\n    },\n\n    /**\n     * Paste event handler.\n     * @param {Event} event - Event object.\n     */\n    paste(event: ClipboardEvent) {\n      const clipboardData = event.clipboardData || (window as any).clipboardData;\n\n      if (clipboardData && !REGEXP_NUMBER.test(clipboardData.getData('text'))) {\n        event.preventDefault();\n      }\n    },\n\n    /**\n     * Decrease the value.\n     */\n    decrease() {\n      if (this.decreasable) {\n        let { value } = this;\n\n        if (isNaN(value)) {\n          value = 0;\n        }\n\n        this.setValue(normalizeDecimalNumber(value - this.step));\n      }\n    },\n\n    /**\n     * Increase the value.\n     */\n    increase() {\n      if (this.increasable) {\n        let { value } = this;\n\n        if (isNaN(value)) {\n          value = 0;\n        }\n\n        this.setValue(normalizeDecimalNumber(value + this.step));\n      }\n    },\n\n    /**\n     * Set new value and dispatch change event.\n     * @param {number} value - The new value to set.\n     */\n    setValue(value: number) {\n      const oldValue = this.value;\n      let newValue = typeof value !== 'number' ? parseFloat(value) : value;\n\n      if (!isNaN(newValue)) {\n        if (this.min <= this.max) {\n          newValue = Math.min(this.max, Math.max(this.min, newValue));\n        }\n\n        if (this.rounded) {\n          newValue = Math.round(newValue);\n        }\n      }\n\n      this.value = newValue;\n\n      if (newValue === oldValue) {\n        // Force to override the number in the input box (#13).\n        (this.$refs.input as HTMLInputElement).value = String(newValue);\n      }\n\n      this.$emit('update:modelValue', newValue, oldValue);\n    },\n  },\n});\n</script>\n\n<style lang=\"scss\" scoped>\n.vue-number-input {\n  display: block;\n  font-size: 0;\n  max-width: 100%;\n  overflow: hidden;\n  position: relative;\n\n  &__button {\n    background-color: #fff;\n    border: 0;\n    border-radius: 0.25rem;\n    bottom: 1px;\n    position: absolute;\n    top: 1px;\n    width: 2.5rem;\n    z-index: 1;\n\n    &:focus {\n      outline: none;\n    }\n\n    &:hover {\n      &::before,\n      &::after {\n        background-color: #0074d9;\n      }\n    }\n\n    &:disabled {\n      opacity: 0.65;\n\n      &::before,\n      &::after {\n        background-color: #ddd;\n      }\n    }\n\n    &::before,\n    &::after {\n      background-color: #111;\n      content: \"\";\n      left: 50%;\n      position: absolute;\n      top: 50%;\n      transform: translate(-50%, -50%);\n      transition: background-color 0.15s;\n    }\n\n    &::before {\n      height: 1px;\n      width: 50%;\n    }\n\n    &::after {\n      height: 50%;\n      width: 1px;\n    }\n\n    &--minus {\n      border-bottom-right-radius: 0;\n      border-right: 1px solid #ddd;\n      border-top-right-radius: 0;\n      left: 1px;\n\n      &::after {\n        visibility: hidden;\n      }\n    }\n\n    &--plus {\n      border-bottom-left-radius: 0;\n      border-left: 1px solid #ddd;\n      border-top-left-radius: 0;\n      right: 1px;\n    }\n  }\n\n  &__input {\n    -moz-appearance: textfield;\n    background-color: #fff;\n    border: 1px solid #ddd;\n    border-radius: 0.25rem;\n    display: block;\n    font-size: 1rem;\n    line-height: 1.5;\n    max-width: 100%;\n    min-height: 1.5rem;\n    min-width: 3rem;\n    padding: 0.4375rem 0.875rem;\n    transition: border-color 0.15s;\n    width: 100%;\n\n    &::-webkit-outer-spin-button,\n    &::-webkit-inner-spin-button {\n      -webkit-appearance: none;\n    }\n\n    &:focus {\n      border-color: #0074d9;\n      outline: none;\n    }\n\n    &:disabled,\n    &[readonly] {\n      background-color: #f8f8f8;\n    }\n  }\n\n  &--inline {\n    display: inline-block;\n\n    & > input {\n      display: inline-block;\n      width: 12.5rem;\n    }\n  }\n\n  &--center {\n    & > input {\n      text-align: center;\n    }\n  }\n\n  &--controls {\n    & > input {\n      padding-left: 3.375rem;\n      padding-right: 3.375rem;\n    }\n  }\n\n  &--small {\n    & > input {\n      border-radius: 0.1875rem;\n      font-size: 0.875rem;\n      padding: 0.25rem 0.5rem;\n    }\n\n    &.vue-number-input--inline > input {\n      width: 10rem;\n    }\n\n    &.vue-number-input--controls > button {\n      width: 2rem;\n    }\n\n    &.vue-number-input--controls > input {\n      padding-left: 2.5rem;\n      padding-right: 2.5rem;\n    }\n  }\n\n  &--large {\n    & > input {\n      border-radius: 0.3125rem;\n      font-size: 1.25rem;\n      padding: 0.5rem 1rem;\n    }\n\n    &.vue-number-input--inline > input {\n      width: 15rem;\n    }\n\n    &.vue-number-input--controls > button {\n      width: 3rem;\n    }\n\n    &.vue-number-input--controls > input {\n      padding-left: 4rem;\n      padding-right: 4rem;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "stylelint.config.js",
    "content": "module.exports = {\n  extends: 'stylelint-config-recommended-vue/scss',\n  plugins: [\n    'stylelint-order',\n  ],\n  rules: {\n    'no-descending-specificity': null,\n    'no-empty-source': null,\n    'order/properties-alphabetical-order': true,\n  },\n};\n"
  },
  {
    "path": "tests/events.spec.ts",
    "content": "import { mount } from '@vue/test-utils';\nimport VueNumberInput from '../src';\n\ndescribe('events', () => {\n  describe('custom', () => {\n    it('should trigger the custom `update:model-value` event', (done) => {\n      const wrapper = mount({\n        components: {\n          VueNumberInput,\n        },\n        methods: {\n          onModelValueChange(newValue: number) {\n            expect(newValue).toBe(1);\n            done();\n          },\n        },\n        template: '<vue-number-input @update:model-value=\"onModelValueChange\" />',\n      });\n\n      wrapper.get('.vue-number-input__input').setValue('1');\n    });\n  });\n\n  describe('native', () => {\n    it('should trigger the native `change` event', (done) => {\n      const wrapper = mount({\n        components: {\n          VueNumberInput,\n        },\n        methods: {\n          onChange(event: Event) {\n            expect(event.type).toBe('change');\n            expect((event.target as HTMLInputElement).value).toBe('1');\n            done();\n          },\n        },\n        template: '<vue-number-input @change=\"onChange\" />',\n      });\n\n      wrapper.get('.vue-number-input__input').setValue('1');\n    });\n\n    it('should trigger the native `input` event', (done) => {\n      const wrapper = mount({\n        components: {\n          VueNumberInput,\n        },\n        methods: {\n          onInput(event: Event) {\n            expect(event.type).toBe('input');\n            expect((event.target as HTMLInputElement).value).toBe('1');\n            done();\n          },\n        },\n        template: '<vue-number-input @input=\"onInput\" />',\n      });\n\n      wrapper.get('.vue-number-input__input').setValue('1');\n    });\n  });\n});\n"
  },
  {
    "path": "tests/methods.spec.ts",
    "content": "import { mount } from '@vue/test-utils';\nimport VueNumberInput from '../src';\n\ndescribe('methods', () => {\n  describe('increase', () => {\n    it('should increase the number', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.vm.value).toBeNaN();\n      wrapper.vm.increase();\n      expect(wrapper.vm.value).toBe(1);\n    });\n\n    it('should not increase the number when the current value is equal to the maximum value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          max: 0,\n          modelValue: 0,\n        },\n      });\n\n      expect(wrapper.vm.value).toBe(0);\n      wrapper.vm.increase();\n      expect(wrapper.vm.value).toBe(0);\n    });\n  });\n\n  describe('decrease', () => {\n    it('should decrease the number', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.vm.value).toBeNaN();\n      wrapper.vm.decrease();\n      expect(wrapper.vm.value).toBe(-1);\n    });\n\n    it('should not decrease the number when the current value is equal to the maximum value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          min: 0,\n          modelValue: 0,\n        },\n      });\n\n      expect(wrapper.vm.value).toBe(0);\n      wrapper.vm.decrease();\n      expect(wrapper.vm.value).toBe(0);\n    });\n  });\n\n  describe('setValue', () => {\n    it('should change the value', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.vm.value).toBeNaN();\n      wrapper.vm.setValue(1);\n      expect(wrapper.vm.value).toBe(1);\n    });\n\n    it('should transform the given value when it is less than the minimum value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          min: 0,\n        },\n      });\n\n      expect(wrapper.vm.value).toBeNaN();\n      wrapper.vm.setValue(-1);\n      expect(wrapper.vm.value).toBe(0);\n    });\n\n    it('should transform the given value when it is greater than the maximum value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          max: 0,\n        },\n      });\n\n      expect(wrapper.vm.value).toBeNaN();\n      wrapper.vm.setValue(1);\n      expect(wrapper.vm.value).toBe(0);\n    });\n\n    it('should not transform the given value when the maximum value is less than the minimum value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          max: -10,\n          min: 10,\n        },\n      });\n\n      expect(wrapper.vm.value).toBeNaN();\n      wrapper.vm.setValue(1);\n      expect(wrapper.vm.value).toBe(1);\n    });\n  });\n});\n"
  },
  {
    "path": "tests/others.spec.ts",
    "content": "import { mount } from '@vue/test-utils';\nimport VueNumberInput from '../src';\n\ndescribe('others', () => {\n  it('should fix the `0.30000000000000004` problem', (done) => {\n    const wrapper = mount({\n      components: {\n        VueNumberInput,\n      },\n      data() {\n        return {\n          value: 0.1,\n        };\n      },\n      template: '<vue-number-input v-model=\"value\" :step=\"0.2\" controls />',\n    });\n\n    expect(wrapper.vm.value).toBe(0.1);\n    wrapper.get('.vue-number-input__button--plus').trigger('click').then(() => {\n      expect(wrapper.vm.value).toBe(0.3);\n      done();\n    });\n  });\n\n  it('should update the model value when value changed', (done) => {\n    const wrapper = mount({\n      components: {\n        VueNumberInput,\n      },\n      data() {\n        return {\n          value: 0,\n        };\n      },\n      template: '<vue-number-input v-model=\"value\" />',\n    });\n\n    expect(wrapper.vm.value).toBe(0);\n    wrapper.get('.vue-number-input__input').setValue(1).then(() => {\n      expect(wrapper.vm.value).toBe(1);\n      done();\n    });\n  });\n\n  it('should not update the value when paste nothing', (done) => {\n    const wrapper = mount({\n      components: {\n        VueNumberInput,\n      },\n      data() {\n        return {\n          value: 0,\n        };\n      },\n      template: '<vue-number-input v-model=\"value\" />',\n    });\n\n    expect(wrapper.vm.value).toBe(0);\n    wrapper.get('.vue-number-input__input').trigger('paste').then(() => {\n      expect(wrapper.vm.value).toBe(0);\n      done();\n    });\n  });\n});\n"
  },
  {
    "path": "tests/props.spec.ts",
    "content": "import { mount } from '@vue/test-utils';\nimport VueNumberInput from '../src';\n\ndescribe('props', () => {\n  describe('attrs', () => {\n    it('should be undefined by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('attrs')).toBeUndefined();\n    });\n\n    it('should apply the given attributes', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          attrs: {\n            tabindex: 0,\n          },\n        },\n      });\n\n      expect(wrapper.props('attrs')).toEqual({\n        tabindex: 0,\n      });\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).tabIndex).toBe(0);\n    });\n  });\n\n  describe('center', () => {\n    it('should not be center by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('center')).toBe(false);\n      expect(wrapper.classes()).not.toContain('vue-number-input--center');\n    });\n\n    it('should be center', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          center: true,\n        },\n      });\n\n      expect(wrapper.props('center')).toBe(true);\n      expect(wrapper.classes()).toContain('vue-number-input--center');\n    });\n  });\n\n  describe('controls', () => {\n    it('should not display the controls by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('controls')).toBe(false);\n      expect(wrapper.classes()).not.toContain('vue-number-input--controls');\n      expect(wrapper.find('.vue-number-input__button').exists()).toBe(false);\n    });\n\n    it('should display the controls', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n        },\n      });\n\n      expect(wrapper.props('controls')).toBe(true);\n      expect(wrapper.classes()).toContain('vue-number-input--controls');\n      expect(wrapper.findAll('.vue-number-input__button').length).toBe(2);\n    });\n\n    it('should increase the number when click the plus control', (done) => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n        },\n      });\n\n      expect(wrapper.vm.value).toBeNaN();\n      wrapper.get('.vue-number-input__button--plus').trigger('click').then(() => {\n        expect(wrapper.vm.value).toBe(1);\n        expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('1');\n        done();\n      });\n    });\n\n    it('should decrease the number when click the minus control', (done) => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n        },\n      });\n\n      expect(wrapper.vm.value).toBeNaN();\n      wrapper.get('.vue-number-input__button--minus').trigger('click').then(() => {\n        expect(wrapper.vm.value).toBe(-1);\n        expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('-1');\n        done();\n      });\n    });\n  });\n\n  describe('disabled', () => {\n    it('should not be disabled by default', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n        },\n      });\n\n      expect(wrapper.props('disabled')).toBe(false);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).disabled).toBe(false);\n      expect((wrapper.get('.vue-number-input__button--plus').element as HTMLButtonElement).disabled).toBe(false);\n      expect((wrapper.get('.vue-number-input__button--minus').element as HTMLButtonElement).disabled).toBe(false);\n    });\n\n    it('should by disabled', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n          disabled: true,\n        },\n      });\n\n      expect(wrapper.props('disabled')).toBe(true);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).disabled).toBe(true);\n      expect((wrapper.get('.vue-number-input__button--plus').element as HTMLButtonElement).disabled).toBe(true);\n      expect((wrapper.get('.vue-number-input__button--minus').element as HTMLButtonElement).disabled).toBe(true);\n    });\n  });\n\n  describe('inline', () => {\n    it('should not be inline by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('inline')).toBe(false);\n      expect(wrapper.classes()).not.toContain('vue-number-input--inline');\n    });\n\n    it('should be inline', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          inline: true,\n        },\n      });\n\n      expect(wrapper.props('inline')).toBe(true);\n      expect(wrapper.classes()).toContain('vue-number-input--inline');\n    });\n  });\n\n  describe('inputtable', () => {\n    it('should be inputtable by default', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n        },\n      });\n\n      expect(wrapper.props('inputtable')).toBe(true);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).readOnly).toBe(false);\n      expect((wrapper.get('.vue-number-input__button--plus').element as HTMLButtonElement).disabled).toBe(false);\n      expect((wrapper.get('.vue-number-input__button--minus').element as HTMLButtonElement).disabled).toBe(false);\n    });\n\n    it('should not be inputtable', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n          inputtable: false,\n        },\n      });\n\n      expect(wrapper.props('inputtable')).toBe(false);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).readOnly).toBe(true);\n      expect((wrapper.get('.vue-number-input__button--plus').element as HTMLButtonElement).disabled).toBe(false);\n      expect((wrapper.get('.vue-number-input__button--minus').element as HTMLButtonElement).disabled).toBe(false);\n    });\n  });\n\n  describe('max', () => {\n    it('should be `Infinity` by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('max')).toBe(Infinity);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).max).toBe('Infinity');\n    });\n\n    it('should be equal to the given value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          max: 10,\n        },\n      });\n\n      expect(wrapper.props('max')).toBe(10);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).max).toBe('10');\n    });\n\n    it('should not be greater than the given maximum value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          modelValue: 11,\n          max: 10,\n        },\n      });\n\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('10');\n    });\n\n    it('should fix the out of range value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          max: 10,\n        },\n      });\n\n      wrapper.get('.vue-number-input__input').setValue('11').then(() => {\n        expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('10');\n      });\n    });\n  });\n\n  describe('min', () => {\n    it('should be `-Infinity` by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('min')).toBe(-Infinity);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).min).toBe('-Infinity');\n    });\n\n    it('should be equal to the given value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          min: -10,\n        },\n      });\n\n      expect(wrapper.props('min')).toBe(-10);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).min).toBe('-10');\n    });\n\n    it('should not be less than the given minimum value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          modelValue: -11,\n          min: -10,\n        },\n      });\n\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('-10');\n    });\n\n    it('should fix the out of range value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          min: -10,\n        },\n      });\n\n      wrapper.get('.vue-number-input__input').setValue('-11').then(() => {\n        expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('-10');\n      });\n    });\n  });\n\n  describe('name', () => {\n    it('should be undefined by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('name')).toBeUndefined();\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).name).toBe('');\n    });\n\n    it('should be equal to the given value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          name: 'digit',\n        },\n      });\n\n      expect(wrapper.props('name')).toBe('digit');\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).name).toBe('digit');\n    });\n  });\n\n  describe('placeholder', () => {\n    it('should be undefined by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('placeholder')).toBeUndefined();\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).placeholder).toBe('');\n    });\n\n    it('should be equal to the given value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          placeholder: 'Number input',\n        },\n      });\n\n      expect(wrapper.props('placeholder')).toBe('Number input');\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).placeholder).toBe('Number input');\n    });\n  });\n\n  describe('readonly', () => {\n    it('should not be read-only by default', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n        },\n      });\n\n      expect(wrapper.props('readonly')).toBe(false);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).readOnly).toBe(false);\n      expect((wrapper.get('.vue-number-input__button--plus').element as HTMLButtonElement).disabled).toBe(false);\n      expect((wrapper.get('.vue-number-input__button--minus').element as HTMLButtonElement).disabled).toBe(false);\n    });\n\n    it('should be read-only', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n          readonly: true,\n        },\n      });\n\n      expect(wrapper.props('readonly')).toBe(true);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).readOnly).toBe(true);\n      expect((wrapper.get('.vue-number-input__button--plus').element as HTMLButtonElement).disabled).toBe(true);\n      expect((wrapper.get('.vue-number-input__button--minus').element as HTMLButtonElement).disabled).toBe(true);\n    });\n  });\n\n  describe('rounded', () => {\n    it('should not round the number by default', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          modelValue: 1.5,\n        },\n      });\n\n      expect(wrapper.props('rounded')).toBe(false);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('1.5');\n    });\n\n    it('should round the number', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          modelValue: 1.5,\n          rounded: true,\n        },\n      });\n\n      expect(wrapper.props('rounded')).toBe(true);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('2');\n    });\n  });\n\n  describe('size', () => {\n    it('should be small size', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          size: 'small',\n        },\n      });\n\n      expect(wrapper.props('size')).toBe('small');\n      expect(wrapper.classes()).toContain('vue-number-input--small');\n    });\n\n    it('should be large size', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          size: 'large',\n        },\n      });\n\n      expect(wrapper.props('size')).toBe('large');\n      expect(wrapper.classes()).toContain('vue-number-input--large');\n    });\n  });\n\n  describe('step', () => {\n    it('should be `1` by default', (done) => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n        },\n      });\n\n      expect(wrapper.props('step')).toBe(1);\n      wrapper.get('.vue-number-input__button--plus').trigger('click').then(() => {\n        expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).step).toBe('1');\n        done();\n      });\n    });\n\n    it('should match the given value', (done) => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          controls: true,\n          step: 2,\n        },\n      });\n\n      expect(wrapper.props('step')).toBe(2);\n      wrapper.get('.vue-number-input__button--plus').trigger('click').then(() => {\n        expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).step).toBe('2');\n        done();\n      });\n    });\n  });\n\n  describe('modelValue', () => {\n    it('should be `NaN` by default', () => {\n      const wrapper = mount(VueNumberInput);\n\n      expect(wrapper.props('modelValue')).toBeNaN();\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('');\n    });\n\n    it('should be equal to the given value', () => {\n      const wrapper = mount(VueNumberInput, {\n        props: {\n          modelValue: 10,\n        },\n      });\n\n      expect(wrapper.props('modelValue')).toBe(10);\n      expect((wrapper.get('.vue-number-input__input').element as HTMLInputElement).value).toBe('10');\n    });\n  });\n});\n"
  },
  {
    "path": "tsconfig.eslint.json",
    "content": "{\n  \"extends\": \"./tsconfig\",\n  \"include\": [\n    \"*.js\",\n    \".*.js\",\n    \"docs/**/*\",\n    \"src/**/*\",\n    \"tests/**/*\"\n  ]\n}\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n  \"compilerOptions\": {\n    \"allowSyntheticDefaultImports\": true,\n    \"moduleResolution\": \"node\",\n    \"resolveJsonModule\": true,\n    \"strict\": true,\n    \"target\": \"esnext\"\n  },\n  \"include\": [\n    \"src/**/*\",\n    \"docs/**/*\",\n    \"tests/**/*\"\n  ]\n}\n"
  },
  {
    "path": "webpack.config.js",
    "content": "const path = require('path');\nconst webpack = require('webpack');\nconst HtmlWebpackPlugin = require('html-webpack-plugin');\nconst VueLoaderPlugin = require('vue-loader/dist/plugin').default;\nconst MiniCssExtractPlugin = require('mini-css-extract-plugin');\n\nmodule.exports = (env) => ({\n  mode: env.production ? 'production' : 'development',\n  entry: './docs',\n  output: {\n    path: path.resolve(__dirname, './docs/dist'),\n  },\n  module: {\n    rules: [\n      {\n        test: /\\.js$/,\n        use: 'babel-loader',\n      },\n      {\n        test: /\\.ts$/,\n        loader: 'ts-loader',\n        options: {\n          appendTsSuffixTo: [/\\.vue$/],\n        },\n      },\n      {\n        test: /\\.vue$/,\n        loader: 'vue-loader',\n      },\n      {\n        test: /\\.scss$/,\n        use: [\n          MiniCssExtractPlugin.loader,\n          'css-loader',\n          'sass-loader',\n        ],\n      },\n      {\n        test: /\\.md$/,\n        use: [\n          'vue-loader',\n          {\n            loader: 'markdown-to-vue-loader',\n            options: {\n              componentWrapper: '<demo-block></demo-block>',\n              tableClass: 'table',\n              tableWrapper: '<div class=\"table-responsive\"></div>',\n            },\n          },\n        ],\n      },\n    ],\n  },\n  plugins: [\n    new HtmlWebpackPlugin({\n      filename: 'index.html',\n      template: './docs/index.html',\n    }),\n    new MiniCssExtractPlugin(),\n    new VueLoaderPlugin(),\n    new webpack.DefinePlugin({\n      __VUE_OPTIONS_API__: true,\n      __VUE_PROD_DEVTOOLS__: false,\n    }),\n  ],\n  externals: env.production ? {\n    vue: 'Vue',\n  } : {},\n  resolve: {\n    alias: {\n      vue$: 'vue/dist/vue.esm-bundler',\n    },\n    extensions: ['.js', '.json', '.ts', '.d.ts', '.vue'],\n  },\n});\n"
  }
]