├── .browserslistrc
├── .eslintignore
├── .eslintrc.js
├── .github
└── workflows
│ ├── ci.yml
│ └── deploy.yml
├── .gitignore
├── .husky
├── commit-msg
└── pre-commit
├── .stylelintignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── babel.config.js
├── commitlint.config.js
├── docs
├── app.vue
├── components
│ └── demo-block.vue
├── index.html
├── index.ts
└── shims.d.ts
├── jest.config.js
├── lint-staged.config.js
├── package-lock.json
├── package.json
├── rollup.config.js
├── src
├── README.md
├── index.ts
└── shims.d.ts
├── stylelint.config.js
├── tests
├── events.spec.ts
└── props.spec.ts
├── tsconfig.eslint.json
├── tsconfig.json
└── webpack.config.js
/.browserslistrc:
--------------------------------------------------------------------------------
1 | defaults
2 | not ie 11
3 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | *.local*
2 | coverage
3 | dist
4 | node_modules
5 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {
4 | browser: true,
5 | node: true,
6 | },
7 | extends: [
8 | 'airbnb-base',
9 | 'airbnb-typescript/base',
10 | 'plugin:@typescript-eslint/recommended',
11 | 'plugin:vue/vue3-recommended',
12 | ],
13 | parser: 'vue-eslint-parser',
14 | parserOptions: {
15 | parser: '@typescript-eslint/parser',
16 | project: 'tsconfig.eslint.json',
17 | sourceType: 'module',
18 | extraFileExtensions: ['.vue'],
19 | },
20 | plugins: [
21 | '@typescript-eslint',
22 | 'import',
23 | 'vue',
24 | ],
25 | rules: {
26 | '@typescript-eslint/no-explicit-any': 'off',
27 | '@typescript-eslint/no-var-requires': 'off',
28 | 'no-restricted-properties': 'off',
29 | },
30 | overrides: [
31 | {
32 | files: ['tests/**/*.ts'],
33 | env: {
34 | jest: true,
35 | },
36 | },
37 | ],
38 | };
39 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | push:
5 | branches: [main]
6 | pull_request:
7 | branches: [main]
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: actions/setup-node@v2
16 | with:
17 | node-version: 16
18 | - run: npm install
19 | - run: npm run lint
20 | - run: npm run build
21 | - run: npm test
22 | - run: npm run test:coverage
23 |
--------------------------------------------------------------------------------
/.github/workflows/deploy.yml:
--------------------------------------------------------------------------------
1 | name: Deploy
2 |
3 | on:
4 | push:
5 | tags:
6 | - v2.*
7 | workflow_dispatch:
8 |
9 | jobs:
10 | build:
11 | runs-on: ubuntu-latest
12 |
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: actions/setup-node@v2
16 | with:
17 | node-version: 16
18 | - run: npm install
19 | - run: npm run build:docs
20 | - run: |
21 | cd docs/dist
22 | git init
23 | git config user.name "${{ github.actor }}"
24 | git config user.email "${{ github.actor }}@users.noreply.github.com"
25 | git add --all
26 | git commit --message "♥"
27 | git push --force https://x-access-token:${{ secrets.GITHUB_TOKEN }}@github.com/${{ github.repository }}.git master:gh-pages
28 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.local*
2 | *.log
3 | *.map
4 | .DS_Store
5 | coverage
6 | dist
7 | node_modules
8 |
--------------------------------------------------------------------------------
/.husky/commit-msg:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx commitlint --edit $1
5 |
--------------------------------------------------------------------------------
/.husky/pre-commit:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 | . "$(dirname "$0")/_/husky.sh"
3 |
4 | npx lint-staged
5 |
--------------------------------------------------------------------------------
/.stylelintignore:
--------------------------------------------------------------------------------
1 | *.local*
2 | coverage
3 | dist
4 | node_modules
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # [2.0.0](https://github.com/fengyuanchen/vue-qrcode/compare/v2.0.0-rc.1...v2.0.0) (2022-02-07)
2 |
3 |
4 |
5 | # [2.0.0-rc.1](https://github.com/fengyuanchen/vue-qrcode/compare/v2.0.0-rc...v2.0.0-rc.1) (2021-08-23)
6 |
7 |
8 | ### Bug Fixes
9 |
10 | * improve the compatibility of svg elements ([102a388](https://github.com/fengyuanchen/vue-qrcode/commit/102a38859e4d6211905981faf13c3b915246fa3c))
11 |
12 |
13 | ### Features
14 |
15 | * add `ready` event ([10ddebb](https://github.com/fengyuanchen/vue-qrcode/commit/10ddebba22b731348364ede873947ac3b4d33eaa))
16 |
17 |
18 |
19 | # [2.0.0-rc](https://github.com/fengyuanchen/vue-qrcode/compare/v2.0.0-beta...v2.0.0-rc) (2021-06-12)
20 |
21 |
22 |
23 | # [2.0.0-beta](https://github.com/fengyuanchen/vue-qrcode/compare/v2.0.0-alpha...v2.0.0-beta) (2021-02-10)
24 |
25 |
26 |
27 | # [2.0.0-alpha](https://github.com/fengyuanchen/vue-qrcode/compare/v1.0.2...v2.0.0-alpha) (2021-01-30)
28 |
29 |
30 | * refactor!: upgrade to Vue 3 ([14c1866](https://github.com/fengyuanchen/vue-qrcode/commit/14c1866d88117f1f895a6b90407f62d50d18a5d1))
31 |
32 |
33 | ### BREAKING CHANGES
34 |
35 | * drop support for Vue 2.
36 |
37 |
38 |
39 | ## [1.0.2](https://github.com/fengyuanchen/vue-qrcode/compare/v1.0.1...v1.0.2) (2020-01-18)
40 |
41 |
42 |
43 | ## [1.0.1](https://github.com/fengyuanchen/vue-qrcode/compare/v1.0.0...v1.0.1) (2019-06-29)
44 |
45 |
46 |
47 | # 1.0.0 (2018-10-21)
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright 2018-present Chen Fengyuan
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
13 | all 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
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-qrcode
2 |
3 | [](https://codecov.io/gh/fengyuanchen/vue-qrcode) [](https://www.npmjs.com/package/@chenfengyuan/vue-qrcode) [](https://www.npmjs.com/package/@chenfengyuan/vue-qrcode) [](https://unpkg.com/@chenfengyuan/vue-qrcode/dist/vue-qrcode.js)
4 |
5 | > QR code component for Vue 3, bases on [node-qrcode](https://github.com/soldair/node-qrcode). For Vue 2, check out the [`v1`](https://github.com/fengyuanchen/vue-qrcode/tree/v1) branch.
6 |
7 | - [Docs](src/README.md)
8 | - [Demo](https://fengyuanchen.github.io/vue-qrcode)
9 |
10 | ## Main npm package files
11 |
12 | ```text
13 | dist/
14 | ├── vue-qrcode.js (UMD, default)
15 | ├── vue-qrcode.min.js (UMD, compressed)
16 | ├── vue-qrcode.esm.js (ECMAScript Module)
17 | ├── vue-qrcode.esm.min.js (ECMAScript Module, compressed)
18 | └── vue-qrcode.d.ts (TypeScript Declaration File)
19 | ```
20 |
21 | ## Getting started
22 |
23 | ### Installation
24 |
25 | Using npm:
26 |
27 | ```shell
28 | npm install vue@3 qrcode@1 @chenfengyuan/vue-qrcode@2
29 | ```
30 |
31 | Using pnpm:
32 |
33 | ```shell
34 | pnpm add vue@3 qrcode@1 @chenfengyuan/vue-qrcode@2
35 | ```
36 |
37 | Using Yarn:
38 |
39 | ```shell
40 | yarn add vue@3 qrcode@1 @chenfengyuan/vue-qrcode@2
41 | ```
42 |
43 | Using CDN:
44 |
45 | ```html
46 |
47 |
48 |
49 | ```
50 |
51 | ### Usage
52 |
53 | ```js
54 | import { createApp } from 'vue';
55 | import VueQrcode from '@chenfengyuan/vue-qrcode';
56 |
57 | const app = createApp({});
58 |
59 | app.component(VueQrcode.name, VueQrcode);
60 | ```
61 |
62 | ```html
63 |
64 | ```
65 |
66 | ## Browser support
67 |
68 | Same as Vue 3.
69 |
70 | ## Versioning
71 |
72 | Maintained under the [Semantic Versioning guidelines](https://semver.org/).
73 |
74 | ## License
75 |
76 | [MIT](https://opensource.org/licenses/MIT) © [Chen Fengyuan](https://chenfengyuan.com/)
77 |
--------------------------------------------------------------------------------
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: ['@babel/preset-env'],
3 | };
4 |
--------------------------------------------------------------------------------
/commitlint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: [
3 | '@commitlint/config-conventional',
4 | ],
5 | };
6 |
--------------------------------------------------------------------------------
/docs/app.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | {{ name }}
60 | v{{ version }}
61 |
62 |
63 |
64 | {{ description }}
65 |
66 |
67 |
73 |
74 |
75 |
76 |
81 |
82 |
113 |
114 |
115 |
116 |
143 |
144 |
244 |
--------------------------------------------------------------------------------
/docs/components/demo-block.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
14 |
15 |
33 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 | vue-qrcode
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/docs/index.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import App from './app.vue';
3 | import DemoBlock from './components/demo-block.vue';
4 | import VueQrcode from '../src';
5 |
6 | const app = createApp(App);
7 |
8 | app.component(DemoBlock.name, DemoBlock);
9 | app.component(VueQrcode.name, VueQrcode);
10 | app.mount('#app');
11 |
--------------------------------------------------------------------------------
/docs/shims.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue' {
2 | const content: any;
3 |
4 | export default content;
5 | }
6 |
--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | preset: 'ts-jest',
3 | collectCoverage: true,
4 | coverageDirectory: 'coverage',
5 | coverageReporters: ['html', 'lcov', 'text'],
6 | moduleFileExtensions: ['js', 'ts'],
7 | transform: {
8 | '^.+\\.js$': 'babel-jest',
9 | },
10 | testEnvironment: 'jsdom',
11 | testMatch: ['**/tests/*.spec.ts'],
12 | };
13 |
--------------------------------------------------------------------------------
/lint-staged.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | '*.{js,ts,vue}': 'eslint --fix',
3 | '*.{css,scss,vue}': 'stylelint --fix',
4 | };
5 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@chenfengyuan/vue-qrcode",
3 | "version": "2.0.0",
4 | "description": "QR code component for Vue 3.",
5 | "main": "dist/vue-qrcode.js",
6 | "module": "dist/vue-qrcode.esm.js",
7 | "types": "dist/vue-qrcode.d.ts",
8 | "files": [
9 | "dist"
10 | ],
11 | "scripts": {
12 | "build": "rollup -c --environment BUILD:production",
13 | "build:docs": "webpack --env production",
14 | "build:types": "move-file dist/index.d.ts dist/vue-qrcode.d.ts",
15 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0",
16 | "clean": "del-cli dist",
17 | "lint": "npm run lint:js && npm run lint:css",
18 | "lint:css": "stylelint **/*.{css,scss,vue} --fix",
19 | "lint:js": "eslint . --ext .js,.ts,.vue --fix",
20 | "prepare": "husky install",
21 | "release": "npm run clean && npm run lint && npm run build && npm run build:types && npm run build:docs && npm test && npm run changelog",
22 | "serve": "webpack serve --hot --open",
23 | "start": "npm run serve",
24 | "test": "jest",
25 | "test:coverage": "cat coverage/lcov.info | codecov"
26 | },
27 | "repository": {
28 | "type": "git",
29 | "url": "https://github.com/fengyuanchen/vue-qrcode.git"
30 | },
31 | "keywords": [
32 | "qrcode",
33 | "qr-code",
34 | "2d-bar-code",
35 | "vue",
36 | "vue3",
37 | "vue-component",
38 | "front-end",
39 | "web"
40 | ],
41 | "author": "Chen Fengyuan (https://chenfengyuan.com/)",
42 | "license": "MIT",
43 | "bugs": "https://github.com/fengyuanchen/vue-qrcode/issues",
44 | "homepage": "https://fengyuanchen.github.io/vue-qrcode",
45 | "devDependencies": {
46 | "@babel/core": "^7.17.0",
47 | "@babel/preset-env": "^7.16.11",
48 | "@commitlint/cli": "^16.1.0",
49 | "@commitlint/config-conventional": "^16.0.0",
50 | "@types/jest": "^27.4.0",
51 | "@types/qrcode": "^1.4.2",
52 | "@typescript-eslint/eslint-plugin": "^5.10.2",
53 | "@typescript-eslint/parser": "^5.10.2",
54 | "@vue/test-utils": "^2.0.0-rc.18",
55 | "babel-jest": "^27.5.0",
56 | "babel-loader": "^8.2.3",
57 | "canvas": "^2.9.0",
58 | "change-case": "^4.1.2",
59 | "codecov": "^3.8.3",
60 | "conventional-changelog-cli": "^2.2.2",
61 | "create-banner": "^2.0.0",
62 | "css-loader": "^6.6.0",
63 | "del-cli": "^4.0.1",
64 | "eslint": "^8.8.0",
65 | "eslint-config-airbnb-base": "^15.0.0",
66 | "eslint-config-airbnb-typescript": "^16.1.0",
67 | "eslint-plugin-import": "^2.25.4",
68 | "eslint-plugin-vue": "^8.4.1",
69 | "html-webpack-plugin": "^5.5.0",
70 | "husky": "^7.0.4",
71 | "jest": "^27.5.0",
72 | "lint-staged": "^12.3.3",
73 | "markdown-it-anchor": "^8.4.1",
74 | "markdown-to-vue-loader": "^3.1.3",
75 | "mini-css-extract-plugin": "^2.5.3",
76 | "move-file-cli": "^3.0.0",
77 | "qrcode": "^1.5.0",
78 | "rollup": "^2.67.1",
79 | "rollup-plugin-terser": "^7.0.2",
80 | "rollup-plugin-typescript2": "^0.31.2",
81 | "sass": "^1.49.7",
82 | "sass-loader": "^12.4.0",
83 | "style-loader": "^3.3.1",
84 | "stylelint": "^14.3.0",
85 | "stylelint-config-recommended-scss": "^5.0.2",
86 | "stylelint-config-recommended-vue": "^1.1.0",
87 | "stylelint-order": "^5.0.0",
88 | "ts-jest": "^27.1.3",
89 | "ts-loader": "^9.2.6",
90 | "tslib": "^2.3.1",
91 | "typescript": "^4.5.5",
92 | "vue": "^3.2.30",
93 | "vue-loader": "^17.0.0",
94 | "webpack": "^5.68.0",
95 | "webpack-cli": "^4.9.2",
96 | "webpack-dev-server": "^4.7.4"
97 | },
98 | "peerDependencies": {
99 | "qrcode": "^1.5.0",
100 | "vue": "^3.0.0"
101 | },
102 | "publishConfig": {
103 | "access": "public"
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/rollup.config.js:
--------------------------------------------------------------------------------
1 | import createBanner from 'create-banner';
2 | import typescript from 'rollup-plugin-typescript2';
3 | import { pascalCase } from 'change-case';
4 | import { terser } from 'rollup-plugin-terser';
5 | import pkg from './package.json';
6 |
7 | const name = pascalCase(pkg.name.replace(/^.+\//, ''));
8 | const banner = createBanner({
9 | data: {
10 | year: '2018-present',
11 | },
12 | template: 'inline',
13 | });
14 |
15 | export default ['umd', 'esm'].map((format) => ({
16 | input: 'src/index.ts',
17 | output: ['development', 'production'].map((mode) => {
18 | const output = {
19 | banner,
20 | format,
21 | name,
22 | file: pkg.main,
23 | globals: {
24 | vue: 'Vue',
25 | qrcode: 'QRCode',
26 | },
27 | };
28 |
29 | if (format === 'esm') {
30 | output.file = pkg.module;
31 | }
32 |
33 | if (mode === 'production') {
34 | output.compact = true;
35 | output.file = output.file.replace(/(\.js)$/, '.min$1');
36 | output.plugins = [
37 | terser(),
38 | ];
39 | }
40 |
41 | return output;
42 | }),
43 | external: Object.keys(pkg.peerDependencies),
44 | plugins: [
45 | typescript({
46 | tsconfigOverride: {
47 | compilerOptions: {
48 | declaration: format === 'esm',
49 | },
50 | exclude: [
51 | 'docs',
52 | 'tests',
53 | ],
54 | },
55 | }),
56 | ],
57 | }));
58 |
--------------------------------------------------------------------------------
/src/README.md:
--------------------------------------------------------------------------------
1 | # QR Code
2 |
3 | > Easy to use QR code component, bases on [node-qrcode](https://github.com/soldair/node-qrcode).
4 |
5 | ## Basic usage
6 |
7 | ```html
8 |
9 |
10 |
11 |
12 | ```
13 |
14 | ## Add options
15 |
16 | ```html
17 |
18 |
19 |
28 |
29 | ```
30 |
31 | ## Custom tag
32 |
33 | ```html
34 |
35 |
36 |
37 |
38 | ```
39 |
40 | ## Add a logo
41 |
42 | ### Covering
43 |
44 | ```html
45 |
46 |
47 |
55 |
60 |
61 |
62 |
63 |
85 | ```
86 |
87 | ### Drawing
88 |
89 | > Only available to canvas elements.
90 |
91 | ```html
92 |
93 |
101 |
102 |
103 |
144 | ```
145 |
146 | ## Props
147 |
148 | | Name | Type | Default | Options | Description |
149 | | --- | --- | --- | --- | --- |
150 | | value | `string` | - | - | The value of the QR code. |
151 | | options | `Object` | - | [Checkout the available options](https://github.com/soldair/node-qrcode#qr-code-options) | The options for the QR code generator. |
152 | | tag | `string` | `"canvas"` | canvas, img, svg | The tag of the QR code. |
153 |
154 | ## Events
155 |
156 | | Name | Parameters | Description |
157 | | --- | --- | --- |
158 | | ready | `($el)` | Fire when the QR code is generated. |
159 |
--------------------------------------------------------------------------------
/src/index.ts:
--------------------------------------------------------------------------------
1 | import { defineComponent, h } from 'vue';
2 | import { toCanvas, toDataURL, toString } from 'qrcode';
3 |
4 | const EVENT_READY = 'ready';
5 |
6 | export default defineComponent({
7 | name: 'VueQrcode',
8 |
9 | props: {
10 | /**
11 | * The value of the QR code.
12 | */
13 | value: {
14 | type: String,
15 | default: undefined,
16 | },
17 |
18 | /**
19 | * The options for the QR code generator.
20 | * {@link https://github.com/soldair/node-qrcode#qr-code-options}
21 | */
22 | options: {
23 | type: Object,
24 | default: undefined,
25 | },
26 |
27 | /**
28 | * The tag name of the component's root element.
29 | */
30 | tag: {
31 | type: String,
32 | default: 'canvas',
33 | },
34 | },
35 |
36 | emits: [EVENT_READY],
37 |
38 | watch: {
39 | $props: {
40 | deep: true,
41 | immediate: true,
42 |
43 | /**
44 | * Update the QR code when props changed.
45 | */
46 | handler() {
47 | if (this.$el) {
48 | this.generate();
49 | }
50 | },
51 | },
52 | },
53 |
54 | mounted() {
55 | this.generate();
56 | },
57 |
58 | methods: {
59 | /**
60 | * Generate QR code.
61 | */
62 | generate() {
63 | const options = this.options || {};
64 | const value = String(this.value);
65 | const done = () => {
66 | this.$emit(EVENT_READY, this.$el);
67 | };
68 |
69 | switch (this.tag) {
70 | case 'canvas':
71 | toCanvas(this.$el, value, options, (error) => {
72 | if (error) {
73 | throw error;
74 | }
75 |
76 | done();
77 | });
78 | break;
79 |
80 | case 'img':
81 | toDataURL(value, options, (error, url) => {
82 | if (error) {
83 | throw error;
84 | }
85 |
86 | this.$el.src = url;
87 | this.$el.onload = done;
88 | });
89 | break;
90 |
91 | case 'svg':
92 | toString(value, options, (error, string) => {
93 | if (error) {
94 | throw error;
95 | }
96 |
97 | const div = document.createElement('div');
98 |
99 | div.innerHTML = string;
100 |
101 | const svg = div.querySelector('svg');
102 |
103 | if (svg) {
104 | const { attributes, childNodes } = svg;
105 |
106 | Object.keys(attributes).forEach((key: string) => {
107 | const attribute = attributes[Number(key)];
108 |
109 | this.$el.setAttribute(attribute.name, attribute.value);
110 | });
111 | Object.keys(childNodes).forEach((key: string) => {
112 | const childNode = childNodes[Number(key)];
113 |
114 | this.$el.appendChild(childNode.cloneNode(true));
115 | });
116 | done();
117 | }
118 | });
119 | break;
120 |
121 | default:
122 | }
123 | },
124 | },
125 |
126 | render() {
127 | return h(this.tag, this.$slots.default);
128 | },
129 | });
130 |
--------------------------------------------------------------------------------
/src/shims.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.md' {
2 | const content: any;
3 |
4 | export default content;
5 | }
6 |
--------------------------------------------------------------------------------
/stylelint.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | extends: 'stylelint-config-recommended-vue/scss',
3 | plugins: [
4 | 'stylelint-order',
5 | ],
6 | rules: {
7 | 'no-descending-specificity': null,
8 | 'no-empty-source': null,
9 | 'order/properties-alphabetical-order': true,
10 | },
11 | };
12 |
--------------------------------------------------------------------------------
/tests/events.spec.ts:
--------------------------------------------------------------------------------
1 | import { mount } from '@vue/test-utils';
2 | import VueQrcode from '../src';
3 |
4 | describe('events', () => {
5 | describe('custom', () => {
6 | it('should trigger the custom `ready` event', (done) => {
7 | mount({
8 | components: {
9 | VueQrcode,
10 | },
11 | methods: {
12 | onReady(element: HTMLCanvasElement) {
13 | expect(element).toBeInstanceOf(HTMLCanvasElement);
14 | done();
15 | },
16 | },
17 | template: '',
18 | });
19 | });
20 | });
21 | });
22 |
--------------------------------------------------------------------------------
/tests/props.spec.ts:
--------------------------------------------------------------------------------
1 | import { mount } from '@vue/test-utils';
2 | import VueQrcode from '../src';
3 |
4 | describe('props', () => {
5 | describe('options', () => {
6 | it('should apply the options', (done) => {
7 | const wrapper = mount(VueQrcode, {
8 | props: {
9 | value: 'foo',
10 | options: {
11 | width: 200,
12 | },
13 | },
14 | });
15 |
16 | setTimeout(() => {
17 | expect(wrapper.vm.$el.width).toBe(200);
18 | done();
19 | }, 100);
20 | });
21 |
22 | it('should update the QR code automatically when the options changed', (done) => {
23 | const wrapper = mount({
24 | components: {
25 | VueQrcode,
26 | },
27 | data() {
28 | return {
29 | options: {
30 | width: 200,
31 | },
32 | };
33 | },
34 | mounted() {
35 | setTimeout(() => {
36 | expect(wrapper.vm.$el.width).toBe(200);
37 | this.options.width = 400;
38 | setTimeout(() => {
39 | expect(wrapper.vm.$el.width).toBe(400);
40 | done();
41 | }, 100);
42 | }, 100);
43 | },
44 | template: '',
45 | });
46 | });
47 | });
48 |
49 | describe('tag', () => {
50 | it('should be "canvas" by default', () => {
51 | const wrapper = mount(VueQrcode, {
52 | props: {
53 | value: 'foo',
54 | },
55 | });
56 |
57 | expect(wrapper.props('tag')).toBe('canvas');
58 | expect(wrapper.vm.$el.tagName.toLowerCase()).toBe('canvas');
59 | });
60 |
61 | it('should be "img"', () => {
62 | const wrapper = mount(VueQrcode, {
63 | props: {
64 | value: 'foo',
65 | tag: 'img',
66 | },
67 | });
68 |
69 | expect(wrapper.props('tag')).toBe('img');
70 | expect(wrapper.vm.$el.tagName.toLowerCase()).toBe('img');
71 | });
72 |
73 | it('should be "svg"', () => {
74 | const wrapper = mount(VueQrcode, {
75 | props: {
76 | value: 'foo',
77 | tag: 'svg',
78 | },
79 | });
80 |
81 | expect(wrapper.props('tag')).toBe('svg');
82 | expect(wrapper.vm.$el.tagName.toLowerCase()).toBe('svg');
83 | });
84 | });
85 |
86 | describe('value', () => {
87 | it('should be undefined by default', () => {
88 | const wrapper = mount(VueQrcode);
89 |
90 | expect(wrapper.props('value')).toBeUndefined();
91 | });
92 |
93 | it('should match the given value', () => {
94 | const wrapper = mount(VueQrcode, {
95 | props: {
96 | value: 'foo',
97 | },
98 | });
99 |
100 | expect(wrapper.props('value')).toBe('foo');
101 | });
102 |
103 | it('should update the QR code automatically when the value changed', (done) => {
104 | const wrapper = mount({
105 | components: {
106 | VueQrcode,
107 | },
108 | data() {
109 | return {
110 | value: 'foo',
111 | };
112 | },
113 | mounted() {
114 | setTimeout(() => {
115 | const oldDataURL = wrapper.vm.$el.toDataURL();
116 |
117 | this.value = 'bar';
118 | setTimeout(() => {
119 | const newDataURL = wrapper.vm.$el.toDataURL();
120 |
121 | expect(newDataURL).not.toBe(oldDataURL);
122 | done();
123 | }, 100);
124 | }, 100);
125 | },
126 | template: '',
127 | });
128 | });
129 | });
130 | });
131 |
--------------------------------------------------------------------------------
/tsconfig.eslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig",
3 | "include": [
4 | "*.js",
5 | ".*.js",
6 | "docs/**/*",
7 | "src/**/*",
8 | "tests/**/*"
9 | ]
10 | }
11 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "allowSyntheticDefaultImports": true,
4 | "moduleResolution": "node",
5 | "resolveJsonModule": true,
6 | "strict": true,
7 | "target": "esnext",
8 | },
9 | "include": [
10 | "src/**/*",
11 | "docs/**/*",
12 | "tests/**/*"
13 | ]
14 | }
15 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const HtmlWebpackPlugin = require('html-webpack-plugin');
4 | const VueLoaderPlugin = require('vue-loader/dist/plugin').default;
5 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
6 | const markdownItAnchor = require('markdown-it-anchor');
7 |
8 | module.exports = (env) => ({
9 | mode: env.production ? 'production' : 'development',
10 | entry: './docs',
11 | output: {
12 | path: path.resolve(__dirname, './docs/dist'),
13 | },
14 | module: {
15 | rules: [
16 | {
17 | test: /\.js$/,
18 | use: 'babel-loader',
19 | },
20 | {
21 | test: /\.ts$/,
22 | loader: 'ts-loader',
23 | options: {
24 | appendTsSuffixTo: [/\.vue$/],
25 | },
26 | },
27 | {
28 | test: /\.vue$/,
29 | loader: 'vue-loader',
30 | },
31 | {
32 | test: /\.scss$/,
33 | use: [
34 | MiniCssExtractPlugin.loader,
35 | 'css-loader',
36 | 'sass-loader',
37 | ],
38 | },
39 | {
40 | test: /\.md$/,
41 | use: [
42 | 'vue-loader',
43 | {
44 | loader: 'markdown-to-vue-loader',
45 | options: {
46 | componentWrapper: '',
47 | tableClass: 'table',
48 | tableWrapper: '',
49 | configureMarkdownIt(md) {
50 | md.use(markdownItAnchor, {
51 | permalink: markdownItAnchor.permalink.headerLink(),
52 | });
53 | },
54 | },
55 | },
56 | ],
57 | },
58 | ],
59 | },
60 | plugins: [
61 | new HtmlWebpackPlugin({
62 | filename: 'index.html',
63 | template: './docs/index.html',
64 | }),
65 | new MiniCssExtractPlugin(),
66 | new VueLoaderPlugin(),
67 | new webpack.DefinePlugin({
68 | __VUE_OPTIONS_API__: true,
69 | __VUE_PROD_DEVTOOLS__: false,
70 | }),
71 | ],
72 | externals: env.production ? {
73 | vue: 'Vue',
74 | qrcode: 'QRCode',
75 | } : {},
76 | resolve: {
77 | alias: {
78 | vue$: 'vue/dist/vue.esm-bundler',
79 | },
80 | extensions: ['.js', '.json', '.ts', '.d.ts', '.vue'],
81 | },
82 | });
83 |
--------------------------------------------------------------------------------