persagy-vant 0.0.52 → 0.0.54
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/es/icon/index.css +1 -1
- package/es/icon/latest-iconfont.css +1 -1
- package/es/icon/latest-iconfont.less +2 -14
- package/es/icon/svg-icon-masks.css +1 -0
- package/es/icon/svg-icon-masks.less +18 -0
- package/es/index.d.ts +1 -1
- package/es/index.mjs +1 -1
- package/es/locale/lang/en-US.d.ts +9 -0
- package/es/locale/lang/en-US.mjs +9 -0
- package/es/locale/lang/zh-CN.d.ts +9 -0
- package/es/locale/lang/zh-CN.mjs +9 -0
- package/es/locale/lang/zh-TW.d.ts +9 -0
- package/es/locale/lang/zh-TW.mjs +9 -0
- package/es/qr-scanner/QrScanner.d.ts +18 -1
- package/es/qr-scanner/QrScanner.mjs +141 -18
- package/es/qr-scanner/decoder.d.ts +3 -3
- package/es/qr-scanner/decoder.mjs +99 -27
- package/es/qr-scanner/function-call.d.ts +13 -1
- package/es/qr-scanner/function-call.mjs +5 -0
- package/es/qr-scanner/index.d.ts +1 -1
- package/es/qr-scanner/startup.d.ts +3 -0
- package/es/qr-scanner/startup.mjs +33 -0
- package/es/qr-scanner/types.d.ts +16 -1
- package/lib/{decoder-8f5b00db.js → decoder-03a4b162.js} +112 -34
- package/lib/{decoder-a36ba9ae.mjs → decoder-9637718d.mjs} +112 -34
- package/lib/icon/index.css +1 -1
- package/lib/icon/latest-iconfont.css +1 -1
- package/lib/icon/latest-iconfont.less +2 -14
- package/lib/icon/svg-icon-masks.css +1 -0
- package/lib/icon/svg-icon-masks.less +18 -0
- package/lib/index-d68a26ab.mjs +22968 -0
- package/lib/index-ea574b22.js +22967 -0
- package/lib/index.css +1 -1
- package/lib/index.d.ts +1 -1
- package/lib/index.js +1 -1
- package/lib/locale/lang/en-US.d.ts +9 -0
- package/lib/locale/lang/en-US.js +9 -0
- package/lib/locale/lang/zh-CN.d.ts +9 -0
- package/lib/locale/lang/zh-CN.js +9 -0
- package/lib/locale/lang/zh-TW.d.ts +9 -0
- package/lib/locale/lang/zh-TW.js +9 -0
- package/lib/qr-scanner/QrScanner.d.ts +18 -1
- package/lib/qr-scanner/QrScanner.js +141 -18
- package/lib/qr-scanner/decoder.d.ts +3 -3
- package/lib/qr-scanner/decoder.js +94 -26
- package/lib/qr-scanner/function-call.d.ts +13 -1
- package/lib/qr-scanner/function-call.js +5 -0
- package/lib/qr-scanner/index.d.ts +1 -1
- package/lib/qr-scanner/startup.d.ts +3 -0
- package/lib/qr-scanner/startup.js +52 -0
- package/lib/qr-scanner/types.d.ts +16 -1
- package/lib/vant.cjs.js +131 -22802
- package/lib/vant.es.js +131 -22802
- package/lib/vant.js +372 -137
- package/lib/vant.min.js +1 -1
- package/lib/web-types.json +1 -1
- package/package.json +6 -4
|
@@ -26,12 +26,16 @@ import { Button } from "../button/index.mjs";
|
|
|
26
26
|
import { Icon } from "../icon/index.mjs";
|
|
27
27
|
import { Loading } from "../loading/index.mjs";
|
|
28
28
|
import { Popup } from "../popup/index.mjs";
|
|
29
|
-
|
|
29
|
+
import zhCN from "../locale/lang/zh-CN.mjs";
|
|
30
|
+
import { DEFAULT_STARTUP_TIMEOUT, waitForAbort } from "./startup.mjs";
|
|
31
|
+
const [name, bem, t] = createNamespace("qr-scanner");
|
|
30
32
|
const qrScannerProps = {
|
|
31
33
|
show: Boolean,
|
|
32
34
|
title: makeStringProp("\u626B\u63CF\u8BBE\u5907\u4E8C\u7EF4\u7801"),
|
|
33
35
|
tip: makeStringProp("\u5C06\u8BBE\u5907\u4E8C\u7EF4\u7801\u7F6E\u4E8E\u53D6\u666F\u6846\u5185\uFF0C\u5373\u53EF\u81EA\u52A8\u8BC6\u522B"),
|
|
34
36
|
processingText: makeStringProp("\u6B63\u5728\u5904\u7406\u626B\u7801\u7ED3\u679C..."),
|
|
37
|
+
startupTimeout: makeNumericProp(DEFAULT_STARTUP_TIMEOUT),
|
|
38
|
+
startupTexts: Object,
|
|
35
39
|
formats: extend(makeArrayProp(), {
|
|
36
40
|
default: () => ["QRCode"]
|
|
37
41
|
}),
|
|
@@ -57,7 +61,7 @@ const qrScannerProps = {
|
|
|
57
61
|
var stdin_default = defineComponent({
|
|
58
62
|
name,
|
|
59
63
|
props: qrScannerProps,
|
|
60
|
-
emits: ["update:show", "scan", "error", "cancel", "close", "closed", "ready"],
|
|
64
|
+
emits: ["update:show", "scan", "error", "cancel", "close", "closed", "ready", "stageChange"],
|
|
61
65
|
setup(props, {
|
|
62
66
|
emit
|
|
63
67
|
}) {
|
|
@@ -66,6 +70,7 @@ var stdin_default = defineComponent({
|
|
|
66
70
|
const frame = ref();
|
|
67
71
|
const fileInput = ref();
|
|
68
72
|
const phase = ref("idle");
|
|
73
|
+
const startupStage = ref("camera");
|
|
69
74
|
const message = ref("");
|
|
70
75
|
const hasTorch = ref(false);
|
|
71
76
|
const torchOn = ref(false);
|
|
@@ -76,13 +81,25 @@ var stdin_default = defineComponent({
|
|
|
76
81
|
let stream;
|
|
77
82
|
let canvas;
|
|
78
83
|
let timer;
|
|
84
|
+
let startupTimer;
|
|
85
|
+
let startupStartedAt = 0;
|
|
86
|
+
let startupDeadline = 0;
|
|
79
87
|
let generation = 0;
|
|
80
88
|
let abortController;
|
|
81
89
|
let resumeWhenVisible = false;
|
|
90
|
+
let pickingAlbum = false;
|
|
82
91
|
const recentResults = /* @__PURE__ */ new Map();
|
|
83
92
|
const isCurrent = (id) => id === generation && props.show && !props.paused;
|
|
93
|
+
const startupText = (key) => t(key) || zhCN.vanQrScanner[key];
|
|
94
|
+
const clearStartupTimer = () => {
|
|
95
|
+
if (startupTimer !== void 0)
|
|
96
|
+
clearTimeout(startupTimer);
|
|
97
|
+
startupTimer = void 0;
|
|
98
|
+
startupDeadline = 0;
|
|
99
|
+
};
|
|
84
100
|
const release = () => {
|
|
85
101
|
generation += 1;
|
|
102
|
+
clearStartupTimer();
|
|
86
103
|
if (timer)
|
|
87
104
|
clearTimeout(timer);
|
|
88
105
|
timer = void 0;
|
|
@@ -101,6 +118,7 @@ var stdin_default = defineComponent({
|
|
|
101
118
|
phase.value = "paused";
|
|
102
119
|
};
|
|
103
120
|
const close = (cancelled = false) => {
|
|
121
|
+
pickingAlbum = false;
|
|
104
122
|
release();
|
|
105
123
|
phase.value = "idle";
|
|
106
124
|
if (cancelled)
|
|
@@ -108,14 +126,46 @@ var stdin_default = defineComponent({
|
|
|
108
126
|
emit("update:show", false);
|
|
109
127
|
};
|
|
110
128
|
const reportError = (code, text, cause) => {
|
|
129
|
+
const startupInfo = phase.value === "starting" && abortController && !props.nativeScan ? {
|
|
130
|
+
stage: startupStage.value,
|
|
131
|
+
elapsedMs: Math.max(0, Date.now() - startupStartedAt)
|
|
132
|
+
} : {};
|
|
111
133
|
release();
|
|
112
134
|
phase.value = "error";
|
|
113
135
|
message.value = text;
|
|
114
|
-
emit("error", {
|
|
136
|
+
emit("error", extend({
|
|
115
137
|
code,
|
|
116
138
|
message: text,
|
|
117
139
|
cause
|
|
140
|
+
}, startupInfo));
|
|
141
|
+
};
|
|
142
|
+
const reportStartupTimeout = () => {
|
|
143
|
+
const timeoutMessages = {
|
|
144
|
+
camera: startupText("timeoutCamera"),
|
|
145
|
+
preview: startupText("timeoutPreview"),
|
|
146
|
+
decoder: startupText("timeoutDecoder"),
|
|
147
|
+
ready: ""
|
|
148
|
+
};
|
|
149
|
+
reportError("STARTUP_TIMEOUT", timeoutMessages[startupStage.value]);
|
|
150
|
+
};
|
|
151
|
+
const canContinueStartup = (id) => {
|
|
152
|
+
if (!isCurrent(id))
|
|
153
|
+
return false;
|
|
154
|
+
if (startupDeadline && Date.now() >= startupDeadline) {
|
|
155
|
+
reportStartupTimeout();
|
|
156
|
+
return false;
|
|
157
|
+
}
|
|
158
|
+
return true;
|
|
159
|
+
};
|
|
160
|
+
const setStartupStage = (stage, id) => {
|
|
161
|
+
if (!canContinueStartup(id))
|
|
162
|
+
return false;
|
|
163
|
+
startupStage.value = stage;
|
|
164
|
+
emit("stageChange", {
|
|
165
|
+
stage,
|
|
166
|
+
elapsedMs: Math.max(0, Date.now() - startupStartedAt)
|
|
118
167
|
});
|
|
168
|
+
return isCurrent(id);
|
|
119
169
|
};
|
|
120
170
|
const cameraError = (error) => {
|
|
121
171
|
const errorName = error == null ? void 0 : error.name;
|
|
@@ -203,7 +253,7 @@ var stdin_default = defineComponent({
|
|
|
203
253
|
height: target.height / scale
|
|
204
254
|
});
|
|
205
255
|
if (image) {
|
|
206
|
-
const result = yield decoder.decode(image, props.formats, props.wasmUrl);
|
|
256
|
+
const result = yield decoder.decode(image, props.formats, props.wasmUrl, abortController == null ? void 0 : abortController.signal);
|
|
207
257
|
if (!isCurrent(id))
|
|
208
258
|
return;
|
|
209
259
|
if (result)
|
|
@@ -229,6 +279,7 @@ var stdin_default = defineComponent({
|
|
|
229
279
|
return;
|
|
230
280
|
}
|
|
231
281
|
const id = generation;
|
|
282
|
+
pickingAlbum = false;
|
|
232
283
|
phase.value = "starting";
|
|
233
284
|
message.value = "";
|
|
234
285
|
if (props.nativeScan) {
|
|
@@ -264,8 +315,25 @@ var stdin_default = defineComponent({
|
|
|
264
315
|
reportError("CAMERA_UNSUPPORTED", "\u5F53\u524D\u73AF\u5883\u4E0D\u652F\u6301\u5B9E\u65F6\u626B\u7801\uFF0C\u8BF7\u4ECE\u76F8\u518C\u8BC6\u522B\u6216\u5728\u7CFB\u7EDF\u6D4F\u89C8\u5668\u6253\u5F00");
|
|
265
316
|
return;
|
|
266
317
|
}
|
|
318
|
+
abortController = new AbortController();
|
|
319
|
+
const {
|
|
320
|
+
signal
|
|
321
|
+
} = abortController;
|
|
322
|
+
startupStartedAt = Date.now();
|
|
323
|
+
const configuredTimeout = Number(props.startupTimeout);
|
|
324
|
+
const timeout = Number.isFinite(configuredTimeout) ? Math.max(0, configuredTimeout) : DEFAULT_STARTUP_TIMEOUT;
|
|
325
|
+
if (timeout > 0) {
|
|
326
|
+
startupDeadline = startupStartedAt + timeout;
|
|
327
|
+
startupTimer = setTimeout(() => {
|
|
328
|
+
if (!isCurrent(id) || phase.value !== "starting")
|
|
329
|
+
return;
|
|
330
|
+
reportStartupTimeout();
|
|
331
|
+
}, timeout);
|
|
332
|
+
}
|
|
333
|
+
if (!setStartupStage("camera", id))
|
|
334
|
+
return;
|
|
267
335
|
try {
|
|
268
|
-
const acquiredStream = yield navigator.mediaDevices.getUserMedia({
|
|
336
|
+
const acquiredStream = yield waitForAbort(navigator.mediaDevices.getUserMedia({
|
|
269
337
|
audio: false,
|
|
270
338
|
video: extend(deviceId ? {
|
|
271
339
|
deviceId: {
|
|
@@ -283,28 +351,44 @@ var stdin_default = defineComponent({
|
|
|
283
351
|
ideal: 720
|
|
284
352
|
}
|
|
285
353
|
})
|
|
286
|
-
})
|
|
354
|
+
}).then((acquired) => {
|
|
355
|
+
if (!isCurrent(id))
|
|
356
|
+
acquired.getTracks().forEach((track2) => track2.stop());
|
|
357
|
+
return acquired;
|
|
358
|
+
}), signal);
|
|
287
359
|
if (!isCurrent(id)) {
|
|
288
360
|
acquiredStream.getTracks().forEach((track2) => track2.stop());
|
|
289
361
|
return;
|
|
290
362
|
}
|
|
291
363
|
stream = acquiredStream;
|
|
364
|
+
} catch (error) {
|
|
365
|
+
if (isCurrent(id))
|
|
366
|
+
cameraError(error);
|
|
367
|
+
return;
|
|
368
|
+
}
|
|
369
|
+
if (!setStartupStage("preview", id))
|
|
370
|
+
return;
|
|
371
|
+
try {
|
|
292
372
|
yield nextTick();
|
|
293
|
-
if (!
|
|
373
|
+
if (!canContinueStartup(id))
|
|
294
374
|
return;
|
|
295
375
|
if (!video.value)
|
|
296
376
|
throw new Error("\u626B\u7801\u9884\u89C8\u5C1A\u672A\u5C31\u7EEA");
|
|
297
377
|
video.value.srcObject = stream;
|
|
298
|
-
yield video.value.play();
|
|
378
|
+
yield waitForAbort(video.value.play(), signal);
|
|
299
379
|
} catch (error) {
|
|
300
380
|
if (isCurrent(id))
|
|
301
|
-
|
|
381
|
+
reportError("PREVIEW_FAILED", startupText("previewFailed"), error);
|
|
302
382
|
return;
|
|
303
383
|
}
|
|
384
|
+
if (!setStartupStage("decoder", id))
|
|
385
|
+
return;
|
|
304
386
|
let decoder;
|
|
305
387
|
try {
|
|
306
|
-
decoder = yield import("./decoder");
|
|
307
|
-
|
|
388
|
+
decoder = yield waitForAbort(import("./decoder"), signal);
|
|
389
|
+
if (!canContinueStartup(id))
|
|
390
|
+
return;
|
|
391
|
+
yield waitForAbort(decoder.prepareDecoder(props.wasmUrl, signal), signal);
|
|
308
392
|
} catch (error) {
|
|
309
393
|
if (isCurrent(id))
|
|
310
394
|
reportError("DECODER_LOAD_FAILED", "\u626B\u7801\u8D44\u6E90\u52A0\u8F7D\u5931\u8D25\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u8D44\u6E90\u90E8\u7F72\u540E\u91CD\u8BD5", error);
|
|
@@ -312,6 +396,8 @@ var stdin_default = defineComponent({
|
|
|
312
396
|
}
|
|
313
397
|
if (!isCurrent(id))
|
|
314
398
|
return;
|
|
399
|
+
if (!canContinueStartup(id))
|
|
400
|
+
return;
|
|
315
401
|
const track = stream == null ? void 0 : stream.getVideoTracks()[0];
|
|
316
402
|
try {
|
|
317
403
|
const capability = (_b = track == null ? void 0 : track.getCapabilities) == null ? void 0 : _b.call(track).torch;
|
|
@@ -333,6 +419,9 @@ var stdin_default = defineComponent({
|
|
|
333
419
|
}).catch(() => {
|
|
334
420
|
});
|
|
335
421
|
phase.value = "scanning";
|
|
422
|
+
clearStartupTimer();
|
|
423
|
+
if (!setStartupStage("ready", id))
|
|
424
|
+
return;
|
|
336
425
|
emit("ready", {
|
|
337
426
|
torch: hasTorch.value
|
|
338
427
|
});
|
|
@@ -342,25 +431,32 @@ var stdin_default = defineComponent({
|
|
|
342
431
|
const scanImage = (file) => __async(this, null, function* () {
|
|
343
432
|
if (!props.show || props.paused)
|
|
344
433
|
return;
|
|
434
|
+
pickingAlbum = false;
|
|
435
|
+
release();
|
|
436
|
+
phase.value = "processing";
|
|
437
|
+
message.value = "";
|
|
345
438
|
if (file.size > Number(props.maxImageSize)) {
|
|
346
439
|
reportError("IMAGE_TOO_LARGE", "\u56FE\u7247\u8FC7\u5927\uFF0C\u8BF7\u9009\u62E9\u8F83\u5C0F\u7684\u56FE\u7247");
|
|
347
440
|
return;
|
|
348
441
|
}
|
|
349
|
-
release();
|
|
350
442
|
const id = generation;
|
|
351
|
-
|
|
352
|
-
|
|
443
|
+
abortController = new AbortController();
|
|
444
|
+
const {
|
|
445
|
+
signal
|
|
446
|
+
} = abortController;
|
|
353
447
|
let imageCanvas;
|
|
354
448
|
try {
|
|
355
|
-
const decoder = yield import("./decoder");
|
|
356
|
-
|
|
449
|
+
const decoder = yield waitForAbort(import("./decoder"), signal);
|
|
450
|
+
if (!isCurrent(id))
|
|
451
|
+
return;
|
|
452
|
+
const image = yield waitForAbort(decoder.loadImage(file, signal), signal);
|
|
357
453
|
if (!isCurrent(id))
|
|
358
454
|
return;
|
|
359
455
|
imageCanvas = document.createElement("canvas");
|
|
360
456
|
const data = decoder.captureImage(image, imageCanvas, 1920);
|
|
361
457
|
if (!data)
|
|
362
458
|
throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u56FE\u7247");
|
|
363
|
-
const result = yield decoder.decode(data, props.formats, props.wasmUrl);
|
|
459
|
+
const result = yield waitForAbort(decoder.decode(data, props.formats, props.wasmUrl, signal), signal);
|
|
364
460
|
if (!isCurrent(id))
|
|
365
461
|
return;
|
|
366
462
|
if (!result) {
|
|
@@ -429,6 +525,15 @@ var stdin_default = defineComponent({
|
|
|
429
525
|
start();
|
|
430
526
|
}
|
|
431
527
|
};
|
|
528
|
+
const onAlbumCancel = () => {
|
|
529
|
+
if (pickingAlbum && phase.value === "paused")
|
|
530
|
+
start();
|
|
531
|
+
pickingAlbum = false;
|
|
532
|
+
};
|
|
533
|
+
watch(fileInput, (input, previous) => {
|
|
534
|
+
previous == null ? void 0 : previous.removeEventListener("cancel", onAlbumCancel);
|
|
535
|
+
input == null ? void 0 : input.addEventListener("cancel", onAlbumCancel);
|
|
536
|
+
});
|
|
432
537
|
watch(() => props.show, (show) => __async(this, null, function* () {
|
|
433
538
|
release();
|
|
434
539
|
recentResults.clear();
|
|
@@ -455,9 +560,15 @@ var stdin_default = defineComponent({
|
|
|
455
560
|
if (props.show)
|
|
456
561
|
start();
|
|
457
562
|
});
|
|
563
|
+
watch(() => props.wasmUrl, () => {
|
|
564
|
+
if (props.show && !props.nativeScan && (phase.value === "starting" || phase.value === "scanning"))
|
|
565
|
+
start();
|
|
566
|
+
});
|
|
458
567
|
onMounted(() => document.addEventListener("visibilitychange", onVisibilityChange));
|
|
459
568
|
onBeforeUnmount(() => {
|
|
569
|
+
var _a;
|
|
460
570
|
release();
|
|
571
|
+
(_a = fileInput.value) == null ? void 0 : _a.removeEventListener("cancel", onAlbumCancel);
|
|
461
572
|
if (canvas) {
|
|
462
573
|
canvas.width = 0;
|
|
463
574
|
canvas.height = 0;
|
|
@@ -542,7 +653,15 @@ var stdin_default = defineComponent({
|
|
|
542
653
|
"color": "white",
|
|
543
654
|
"vertical": true
|
|
544
655
|
}, {
|
|
545
|
-
default: () =>
|
|
656
|
+
default: () => {
|
|
657
|
+
var _a, _b, _c, _d, _e, _f;
|
|
658
|
+
return [phase.value === "starting" ? props.nativeScan ? "\u6B63\u5728\u6253\u5F00\u626B\u7801..." : {
|
|
659
|
+
camera: (_b = (_a = props.startupTexts) == null ? void 0 : _a.camera) != null ? _b : startupText("startupCamera"),
|
|
660
|
+
preview: (_d = (_c = props.startupTexts) == null ? void 0 : _c.preview) != null ? _d : startupText("startupPreview"),
|
|
661
|
+
decoder: (_f = (_e = props.startupTexts) == null ? void 0 : _e.decoder) != null ? _f : startupText("startupDecoder"),
|
|
662
|
+
ready: ""
|
|
663
|
+
}[startupStage.value] : props.processingText];
|
|
664
|
+
}
|
|
546
665
|
}), needsRetry && _createVNode(_Fragment, null, [_createVNode("p", {
|
|
547
666
|
"class": bem("message")
|
|
548
667
|
}, [message.value || "\u626B\u63CF\u5DF2\u6682\u505C"]), _createVNode(Button, {
|
|
@@ -575,6 +694,7 @@ var stdin_default = defineComponent({
|
|
|
575
694
|
var _a;
|
|
576
695
|
stop();
|
|
577
696
|
resumeWhenVisible = false;
|
|
697
|
+
pickingAlbum = true;
|
|
578
698
|
(_a = fileInput.value) == null ? void 0 : _a.click();
|
|
579
699
|
}
|
|
580
700
|
}, [_createVNode(Icon, {
|
|
@@ -604,6 +724,9 @@ var stdin_default = defineComponent({
|
|
|
604
724
|
input.value = "";
|
|
605
725
|
if (file)
|
|
606
726
|
scanImage(file);
|
|
727
|
+
else if (pickingAlbum && phase.value === "paused")
|
|
728
|
+
start();
|
|
729
|
+
pickingAlbum = false;
|
|
607
730
|
}
|
|
608
731
|
}, null)]
|
|
609
732
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { QrScannerFormat } from './types';
|
|
2
|
-
export declare function prepareDecoder(wasmUrl?: string): Promise<void>;
|
|
3
|
-
export declare function decode(image: ImageData, formats: QrScannerFormat[], wasmUrl?: string): Promise<import("zxing-wasm/reader").ReadResult | undefined>;
|
|
4
|
-
export declare function loadImage(file: File): Promise<HTMLImageElement>;
|
|
2
|
+
export declare function prepareDecoder(wasmUrl?: string, signal?: AbortSignal): Promise<void>;
|
|
3
|
+
export declare function decode(image: ImageData, formats: QrScannerFormat[], wasmUrl?: string, signal?: AbortSignal): Promise<import("zxing-wasm/reader").ReadResult | undefined>;
|
|
4
|
+
export declare function loadImage(file: File, signal?: AbortSignal): Promise<HTMLImageElement>;
|
|
5
5
|
export declare function captureImage(source: HTMLVideoElement | HTMLImageElement, canvas: HTMLCanvasElement, maxSize?: number, region?: {
|
|
6
6
|
x: number;
|
|
7
7
|
y: number;
|
|
@@ -18,48 +18,120 @@ var __async = (__this, __arguments, generator) => {
|
|
|
18
18
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
19
19
|
});
|
|
20
20
|
};
|
|
21
|
-
import {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
21
|
+
import {
|
|
22
|
+
prepareZXingModule,
|
|
23
|
+
purgeZXingModule,
|
|
24
|
+
readBarcodes
|
|
25
|
+
} from "zxing-wasm/reader";
|
|
26
|
+
import { abortError, waitForAbort } from "./startup.mjs";
|
|
27
|
+
let preparation;
|
|
28
|
+
function invalidate(entry) {
|
|
29
|
+
if (preparation === entry) {
|
|
30
|
+
preparation = void 0;
|
|
31
|
+
purgeZXingModule();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function createPreparation(wasmUrl) {
|
|
35
|
+
const controller = new AbortController();
|
|
36
|
+
const entry = {
|
|
37
|
+
wasmUrl,
|
|
38
|
+
pending: true,
|
|
39
|
+
controller,
|
|
40
|
+
consumers: /* @__PURE__ */ new Set(),
|
|
41
|
+
promise: void 0
|
|
42
|
+
};
|
|
43
|
+
const initialize = () => __async(this, null, function* () {
|
|
26
44
|
const url = wasmUrl || (yield import("zxing-wasm/reader/zxing_reader.wasm?url")).default;
|
|
27
|
-
if (
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
45
|
+
if (controller.signal.aborted || preparation !== entry)
|
|
46
|
+
throw abortError();
|
|
47
|
+
yield prepareZXingModule({
|
|
48
|
+
overrides: { locateFile: () => url },
|
|
49
|
+
fireImmediately: true
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
entry.promise = waitForAbort(
|
|
53
|
+
Promise.resolve().then(initialize),
|
|
54
|
+
controller.signal
|
|
55
|
+
).then(
|
|
56
|
+
() => {
|
|
57
|
+
entry.pending = false;
|
|
58
|
+
},
|
|
59
|
+
(error) => {
|
|
60
|
+
entry.pending = false;
|
|
61
|
+
invalidate(entry);
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
);
|
|
65
|
+
return entry;
|
|
66
|
+
}
|
|
67
|
+
function prepareDecoder(wasmUrl, signal) {
|
|
68
|
+
return __async(this, null, function* () {
|
|
69
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
70
|
+
throw abortError();
|
|
71
|
+
if (!preparation || preparation.wasmUrl !== wasmUrl) {
|
|
72
|
+
preparation = createPreparation(wasmUrl);
|
|
73
|
+
}
|
|
74
|
+
const entry = preparation;
|
|
75
|
+
const consumer = Symbol("decoder-consumer");
|
|
76
|
+
entry.consumers.add(consumer);
|
|
77
|
+
const releaseConsumer = () => {
|
|
78
|
+
entry.consumers.delete(consumer);
|
|
79
|
+
if (entry.pending && !entry.consumers.size) {
|
|
80
|
+
invalidate(entry);
|
|
81
|
+
entry.controller.abort();
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
signal == null ? void 0 : signal.addEventListener("abort", releaseConsumer, { once: true });
|
|
85
|
+
try {
|
|
86
|
+
yield waitForAbort(entry.promise, signal);
|
|
87
|
+
} finally {
|
|
88
|
+
signal == null ? void 0 : signal.removeEventListener("abort", releaseConsumer);
|
|
89
|
+
releaseConsumer();
|
|
38
90
|
}
|
|
39
|
-
yield ready;
|
|
40
91
|
});
|
|
41
92
|
}
|
|
42
|
-
function decode(image, formats, wasmUrl) {
|
|
93
|
+
function decode(image, formats, wasmUrl, signal) {
|
|
43
94
|
return __async(this, null, function* () {
|
|
44
|
-
yield prepareDecoder(wasmUrl);
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
95
|
+
yield prepareDecoder(wasmUrl, signal);
|
|
96
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
97
|
+
throw abortError();
|
|
98
|
+
const results = yield waitForAbort(
|
|
99
|
+
readBarcodes(image, {
|
|
100
|
+
formats: formats.length ? formats : ["QRCode"],
|
|
101
|
+
tryHarder: true,
|
|
102
|
+
maxNumberOfSymbols: 1
|
|
103
|
+
}),
|
|
104
|
+
signal
|
|
105
|
+
);
|
|
50
106
|
return results.find((result) => result.isValid && result.text.length > 0);
|
|
51
107
|
});
|
|
52
108
|
}
|
|
53
|
-
function loadImage(file) {
|
|
109
|
+
function loadImage(file, signal) {
|
|
54
110
|
return new Promise((resolve, reject) => {
|
|
111
|
+
if (signal == null ? void 0 : signal.aborted) {
|
|
112
|
+
reject(abortError());
|
|
113
|
+
return;
|
|
114
|
+
}
|
|
55
115
|
const url = URL.createObjectURL(file);
|
|
56
116
|
const image = new Image();
|
|
57
|
-
|
|
117
|
+
const cleanup = () => {
|
|
58
118
|
URL.revokeObjectURL(url);
|
|
119
|
+
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
120
|
+
image.onload = null;
|
|
121
|
+
image.onerror = null;
|
|
122
|
+
};
|
|
123
|
+
const onAbort = () => {
|
|
124
|
+
cleanup();
|
|
125
|
+
image.src = "";
|
|
126
|
+
reject(abortError());
|
|
127
|
+
};
|
|
128
|
+
signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
|
|
129
|
+
image.onload = () => {
|
|
130
|
+
cleanup();
|
|
59
131
|
resolve(image);
|
|
60
132
|
};
|
|
61
133
|
image.onerror = () => {
|
|
62
|
-
|
|
134
|
+
cleanup();
|
|
63
135
|
reject(new Error("\u65E0\u6CD5\u8BFB\u53D6\u56FE\u7247\uFF0C\u8BF7\u9009\u62E9 JPG\u3001PNG \u7B49\u6D4F\u89C8\u5668\u652F\u6301\u7684\u56FE\u7247"));
|
|
64
136
|
};
|
|
65
137
|
image.src = url;
|
|
@@ -17,6 +17,11 @@ declare const QrScanner: {
|
|
|
17
17
|
type: import("vue").PropType<string>;
|
|
18
18
|
default: string;
|
|
19
19
|
};
|
|
20
|
+
startupTimeout: {
|
|
21
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
22
|
+
default: number;
|
|
23
|
+
};
|
|
24
|
+
startupTexts: import("vue").PropType<Partial<Record<"camera" | "preview" | "decoder", string>>>;
|
|
20
25
|
formats: {
|
|
21
26
|
type: import("vue").PropType<import("./types").QrScannerFormat[]>;
|
|
22
27
|
default: () => never[];
|
|
@@ -68,7 +73,7 @@ declare const QrScanner: {
|
|
|
68
73
|
type: BooleanConstructor;
|
|
69
74
|
default: true;
|
|
70
75
|
};
|
|
71
|
-
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("close" | "error" | "closed" | "update:show" | "cancel" | "scan" | "ready")[], "close" | "error" | "closed" | "update:show" | "cancel" | "scan" | "ready", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
76
|
+
}, () => JSX.Element, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("close" | "error" | "closed" | "update:show" | "cancel" | "scan" | "ready" | "stageChange")[], "close" | "error" | "closed" | "update:show" | "cancel" | "scan" | "ready" | "stageChange", import("vue").VNodeProps & import("vue").AllowedComponentProps & import("vue").ComponentCustomProps, Readonly<import("vue").ExtractPropTypes<{
|
|
72
77
|
show: BooleanConstructor;
|
|
73
78
|
title: {
|
|
74
79
|
type: import("vue").PropType<string>;
|
|
@@ -82,6 +87,11 @@ declare const QrScanner: {
|
|
|
82
87
|
type: import("vue").PropType<string>;
|
|
83
88
|
default: string;
|
|
84
89
|
};
|
|
90
|
+
startupTimeout: {
|
|
91
|
+
type: (NumberConstructor | StringConstructor)[];
|
|
92
|
+
default: number;
|
|
93
|
+
};
|
|
94
|
+
startupTexts: import("vue").PropType<Partial<Record<"camera" | "preview" | "decoder", string>>>;
|
|
85
95
|
formats: {
|
|
86
96
|
type: import("vue").PropType<import("./types").QrScannerFormat[]>;
|
|
87
97
|
default: () => never[];
|
|
@@ -141,6 +151,7 @@ declare const QrScanner: {
|
|
|
141
151
|
onCancel?: ((...args: any[]) => any) | undefined;
|
|
142
152
|
onScan?: ((...args: any[]) => any) | undefined;
|
|
143
153
|
onReady?: ((...args: any[]) => any) | undefined;
|
|
154
|
+
onStageChange?: ((...args: any[]) => any) | undefined;
|
|
144
155
|
}, {
|
|
145
156
|
title: string;
|
|
146
157
|
show: boolean;
|
|
@@ -149,6 +160,7 @@ declare const QrScanner: {
|
|
|
149
160
|
closeOnPopstate: boolean;
|
|
150
161
|
tip: string;
|
|
151
162
|
processingText: string;
|
|
163
|
+
startupTimeout: string | number;
|
|
152
164
|
formats: import("./types").QrScannerFormat[];
|
|
153
165
|
facingMode: "environment" | "user";
|
|
154
166
|
showAlbum: boolean;
|
|
@@ -3,11 +3,14 @@ import { extend, inBrowser, withInstall } from "../utils/index.mjs";
|
|
|
3
3
|
import { mountComponent, usePopupState } from "../utils/mount-component.mjs";
|
|
4
4
|
import { useExpose } from "../composables/use-expose.mjs";
|
|
5
5
|
import VanQrScanner from "./QrScanner.mjs";
|
|
6
|
+
import { DEFAULT_STARTUP_TIMEOUT } from "./startup.mjs";
|
|
6
7
|
let instance;
|
|
7
8
|
const defaultOptions = {
|
|
8
9
|
title: "\u626B\u63CF\u8BBE\u5907\u4E8C\u7EF4\u7801",
|
|
9
10
|
tip: "\u5C06\u8BBE\u5907\u4E8C\u7EF4\u7801\u7F6E\u4E8E\u53D6\u666F\u6846\u5185\uFF0C\u5373\u53EF\u81EA\u52A8\u8BC6\u522B",
|
|
10
11
|
processingText: "\u6B63\u5728\u5904\u7406\u626B\u7801\u7ED3\u679C...",
|
|
12
|
+
startupTimeout: DEFAULT_STARTUP_TIMEOUT,
|
|
13
|
+
startupTexts: void 0,
|
|
11
14
|
formats: ["QRCode"],
|
|
12
15
|
facingMode: "environment",
|
|
13
16
|
showAlbum: true,
|
|
@@ -26,6 +29,8 @@ const defaultOptions = {
|
|
|
26
29
|
closeOnPopstate: true,
|
|
27
30
|
onScan: void 0,
|
|
28
31
|
onError: void 0,
|
|
32
|
+
onStageChange: void 0,
|
|
33
|
+
onReady: void 0,
|
|
29
34
|
onCancel: void 0,
|
|
30
35
|
onClose: void 0
|
|
31
36
|
};
|
package/es/qr-scanner/index.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { QrScanner } from './function-call';
|
|
|
2
2
|
export default QrScanner;
|
|
3
3
|
export { QrScanner };
|
|
4
4
|
export type { QrScannerProps } from './QrScanner';
|
|
5
|
-
export type { QrScannerBeforeConfirm, QrScannerError, QrScannerErrorCode, QrScannerExpose, QrScannerFormat, QrScannerInstance, QrScannerNativeScan, QrScannerOptions, QrScannerResult, } from './types';
|
|
5
|
+
export type { QrScannerBeforeConfirm, QrScannerError, QrScannerErrorCode, QrScannerExpose, QrScannerFormat, QrScannerInstance, QrScannerNativeScan, QrScannerOptions, QrScannerResult, QrScannerStageChange, QrScannerStartupStage, QrScannerStartupTexts, } from './types';
|
|
6
6
|
declare module 'vue' {
|
|
7
7
|
interface GlobalComponents {
|
|
8
8
|
VanQrScanner: typeof QrScanner.Component;
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
const DEFAULT_STARTUP_TIMEOUT = 15e3;
|
|
2
|
+
function abortError() {
|
|
3
|
+
const error = new Error("Scanner startup cancelled");
|
|
4
|
+
error.name = "AbortError";
|
|
5
|
+
return error;
|
|
6
|
+
}
|
|
7
|
+
function waitForAbort(task, signal) {
|
|
8
|
+
return new Promise((resolve, reject) => {
|
|
9
|
+
const onAbort = () => {
|
|
10
|
+
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
11
|
+
reject(abortError());
|
|
12
|
+
};
|
|
13
|
+
if (signal == null ? void 0 : signal.aborted)
|
|
14
|
+
onAbort();
|
|
15
|
+
else
|
|
16
|
+
signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
|
|
17
|
+
task.then(
|
|
18
|
+
(value) => {
|
|
19
|
+
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
20
|
+
resolve(value);
|
|
21
|
+
},
|
|
22
|
+
(error) => {
|
|
23
|
+
signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
|
|
24
|
+
reject(error);
|
|
25
|
+
}
|
|
26
|
+
);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
export {
|
|
30
|
+
DEFAULT_STARTUP_TIMEOUT,
|
|
31
|
+
abortError,
|
|
32
|
+
waitForAbort
|
|
33
|
+
};
|
package/es/qr-scanner/types.d.ts
CHANGED
|
@@ -6,11 +6,20 @@ export declare type QrScannerResult = {
|
|
|
6
6
|
format: string;
|
|
7
7
|
source: 'camera' | 'image' | 'native';
|
|
8
8
|
};
|
|
9
|
-
export declare type
|
|
9
|
+
export declare type QrScannerStartupStage = 'camera' | 'preview' | 'decoder' | 'ready';
|
|
10
|
+
export declare type QrScannerStartupTexts = Partial<Record<Exclude<QrScannerStartupStage, 'ready'>, string>>;
|
|
11
|
+
export declare type QrScannerStageChange = {
|
|
12
|
+
stage: QrScannerStartupStage;
|
|
13
|
+
/** Milliseconds since this H5 startup attempt began. */
|
|
14
|
+
elapsedMs: number;
|
|
15
|
+
};
|
|
16
|
+
export declare type QrScannerErrorCode = 'INSECURE_CONTEXT' | 'CAMERA_UNSUPPORTED' | 'CAMERA_PERMISSION_DENIED' | 'CAMERA_NOT_FOUND' | 'CAMERA_UNAVAILABLE' | 'PREVIEW_FAILED' | 'STARTUP_TIMEOUT' | 'DECODER_LOAD_FAILED' | 'DECODE_FAILED' | 'IMAGE_TOO_LARGE' | 'IMAGE_NOT_FOUND' | 'CONFIRM_FAILED' | 'NATIVE_SCAN_FAILED' | 'TORCH_UNAVAILABLE';
|
|
10
17
|
export declare type QrScannerError = {
|
|
11
18
|
code: QrScannerErrorCode;
|
|
12
19
|
message: string;
|
|
13
20
|
cause?: unknown;
|
|
21
|
+
stage?: QrScannerStartupStage;
|
|
22
|
+
elapsedMs?: number;
|
|
14
23
|
};
|
|
15
24
|
export declare type QrScannerBeforeConfirm = (result: QrScannerResult) => boolean | void | Promise<boolean | void>;
|
|
16
25
|
export declare type QrScannerNativeScan = (options: {
|
|
@@ -24,6 +33,8 @@ export declare type QrScannerOptions = {
|
|
|
24
33
|
title?: string;
|
|
25
34
|
tip?: string;
|
|
26
35
|
processingText?: string;
|
|
36
|
+
startupTimeout?: number | string;
|
|
37
|
+
startupTexts?: QrScannerStartupTexts;
|
|
27
38
|
formats?: QrScannerFormat[];
|
|
28
39
|
facingMode?: 'environment' | 'user';
|
|
29
40
|
showAlbum?: boolean;
|
|
@@ -42,6 +53,10 @@ export declare type QrScannerOptions = {
|
|
|
42
53
|
closeOnPopstate?: boolean;
|
|
43
54
|
onScan?: (result: QrScannerResult) => void;
|
|
44
55
|
onError?: (error: QrScannerError) => void;
|
|
56
|
+
onStageChange?: (info: QrScannerStageChange) => void;
|
|
57
|
+
onReady?: (info: {
|
|
58
|
+
torch: boolean;
|
|
59
|
+
}) => void;
|
|
45
60
|
onCancel?: () => void;
|
|
46
61
|
onClose?: () => void;
|
|
47
62
|
};
|