-
-
Notifications
You must be signed in to change notification settings - Fork 54
/
Copy pathindex.ts
125 lines (113 loc) · 3.18 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import type {
QRCodeErrorCorrectionLevel,
QRCodeMaskPattern,
QRCodeSegment,
QRCodeToDataURLOptions,
QRCodeToDataURLOptionsJpegWebp,
QRCodeToSJISFunc,
} from 'qrcode'
import QRCode from 'qrcode'
import { type PropType, defineComponent, h, ref, watch } from 'vue'
export const LEVELS = [
'low',
'medium',
'quartile',
'high',
'L',
'M',
'Q',
'H',
] as const
// eslint-disable-next-line @typescript-eslint/no-magic-numbers
export const MASK_PATTERNS = [0, 1, 2, 3, 4, 5, 6, 7] as const
export const MODES = ['alphanumeric', 'numeric', 'kanji', 'byte'] as const
export type { QRCodeSegment } from 'qrcode'
export type QRCodeValue = QRCodeSegment[] | string
export const TYPES = ['image/png', 'image/jpeg', 'image/webp'] as const
export type QRCodeProps = Omit<QRCodeToDataURLOptions, 'renderOptions'> &
QRCodeToDataURLOptionsJpegWebp['rendererOpts'] & {
value: QRCodeValue
}
const MAX_QR_VERSION = 40
export default defineComponent({
props: {
version: {
type: Number,
validator: (version: number) =>
version === Number.parseInt(String(version), 10) &&
version >= 1 &&
version <= MAX_QR_VERSION,
},
errorCorrectionLevel: {
type: String as PropType<QRCodeErrorCorrectionLevel>,
validator: (level: QRCodeErrorCorrectionLevel) => LEVELS.includes(level),
},
maskPattern: {
type: Number as PropType<QRCodeMaskPattern>,
validator: (maskPattern: QRCodeMaskPattern) =>
MASK_PATTERNS.includes(maskPattern),
},
toSJISFunc: Function as PropType<QRCodeToSJISFunc>,
margin: Number,
scale: Number,
width: Number,
color: {
type: Object,
validator: (color: QRCodeProps['color']) =>
(['dark', 'light'] as const).every(c =>
['string', 'undefined'].includes(typeof color![c]),
),
required: true,
},
type: {
type: String as PropType<QRCodeProps['type']>,
validator: (type: QRCodeProps['type']) => TYPES.includes(type!),
required: true,
},
quality: {
type: Number,
validator: (quality: number) =>
quality === Number.parseFloat(String(quality)) &&
quality >= 0 &&
quality <= 1,
required: false,
},
value: {
type: [String, Array] as PropType<QRCodeValue>,
required: true,
validator(value: QRCodeValue) {
if (typeof value === 'string') {
return true
}
return value.every(
it =>
typeof it.data === 'string' &&
'mode' in it &&
it.mode &&
MODES.includes(it.mode),
)
},
},
},
setup(props, { attrs, emit }) {
const dataUrlRef = ref<string>()
const toDataURL = () => {
const { quality, value, ...rest } = props
QRCode.toDataURL(
value,
Object.assign(rest, quality == null || { renderOptions: { quality } }),
)
.then(dataUrl => {
dataUrlRef.value = dataUrl
emit('change', dataUrl)
})
.catch((err: unknown) => emit('error', err))
}
watch(props, toDataURL, { immediate: true })
return () =>
h('img', {
...attrs,
src: dataUrlRef.value,
})
},
})