persagy-vant 0.0.53 → 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.
Files changed (46) hide show
  1. package/es/index.d.ts +1 -1
  2. package/es/index.mjs +1 -1
  3. package/es/locale/lang/en-US.d.ts +9 -0
  4. package/es/locale/lang/en-US.mjs +9 -0
  5. package/es/locale/lang/zh-CN.d.ts +9 -0
  6. package/es/locale/lang/zh-CN.mjs +9 -0
  7. package/es/locale/lang/zh-TW.d.ts +9 -0
  8. package/es/locale/lang/zh-TW.mjs +9 -0
  9. package/es/qr-scanner/QrScanner.d.ts +18 -1
  10. package/es/qr-scanner/QrScanner.mjs +141 -18
  11. package/es/qr-scanner/decoder.d.ts +3 -3
  12. package/es/qr-scanner/decoder.mjs +99 -27
  13. package/es/qr-scanner/function-call.d.ts +13 -1
  14. package/es/qr-scanner/function-call.mjs +5 -0
  15. package/es/qr-scanner/index.d.ts +1 -1
  16. package/es/qr-scanner/startup.d.ts +3 -0
  17. package/es/qr-scanner/startup.mjs +33 -0
  18. package/es/qr-scanner/types.d.ts +16 -1
  19. package/lib/{decoder-8f5b00db.js → decoder-03a4b162.js} +112 -34
  20. package/lib/{decoder-a36ba9ae.mjs → decoder-9637718d.mjs} +112 -34
  21. package/lib/index-d68a26ab.mjs +22968 -0
  22. package/lib/index-ea574b22.js +22967 -0
  23. package/lib/index.d.ts +1 -1
  24. package/lib/index.js +1 -1
  25. package/lib/locale/lang/en-US.d.ts +9 -0
  26. package/lib/locale/lang/en-US.js +9 -0
  27. package/lib/locale/lang/zh-CN.d.ts +9 -0
  28. package/lib/locale/lang/zh-CN.js +9 -0
  29. package/lib/locale/lang/zh-TW.d.ts +9 -0
  30. package/lib/locale/lang/zh-TW.js +9 -0
  31. package/lib/qr-scanner/QrScanner.d.ts +18 -1
  32. package/lib/qr-scanner/QrScanner.js +141 -18
  33. package/lib/qr-scanner/decoder.d.ts +3 -3
  34. package/lib/qr-scanner/decoder.js +94 -26
  35. package/lib/qr-scanner/function-call.d.ts +13 -1
  36. package/lib/qr-scanner/function-call.js +5 -0
  37. package/lib/qr-scanner/index.d.ts +1 -1
  38. package/lib/qr-scanner/startup.d.ts +3 -0
  39. package/lib/qr-scanner/startup.js +52 -0
  40. package/lib/qr-scanner/types.d.ts +16 -1
  41. package/lib/vant.cjs.js +131 -22802
  42. package/lib/vant.es.js +131 -22802
  43. package/lib/vant.js +372 -137
  44. package/lib/vant.min.js +1 -1
  45. package/lib/web-types.json +1 -1
  46. package/package.json +1 -1
package/es/index.d.ts CHANGED
@@ -118,4 +118,4 @@ declare namespace _default {
118
118
  }
119
119
  export default _default;
120
120
  export function install(app: any): void;
121
- export const version: "0.0.53";
121
+ export const version: "0.0.54";
package/es/index.mjs CHANGED
@@ -111,7 +111,7 @@ import { Uploader } from "./uploader/index.mjs";
111
111
  import { VideoPreview } from "./video-preview/index.mjs";
112
112
  import { WorkOrderCard } from "./work-order-card/index.mjs";
113
113
  import { WorkOrderFilter } from "./work-order-filter/index.mjs";
114
- const version = "0.0.53";
114
+ const version = "0.0.54";
115
115
  function install(app) {
116
116
  const components = [
117
117
  ActionBar,
@@ -69,5 +69,14 @@ declare const _default: {
69
69
  recordVideo: string;
70
70
  chooseFromAlbum: string;
71
71
  };
72
+ vanQrScanner: {
73
+ startupCamera: string;
74
+ startupPreview: string;
75
+ startupDecoder: string;
76
+ timeoutCamera: string;
77
+ timeoutPreview: string;
78
+ timeoutDecoder: string;
79
+ previewFailed: string;
80
+ };
72
81
  };
73
82
  export default _default;
@@ -68,6 +68,15 @@ var stdin_default = {
68
68
  takePhoto: "Take photo",
69
69
  recordVideo: "Record video",
70
70
  chooseFromAlbum: "Choose from album"
71
+ },
72
+ vanQrScanner: {
73
+ startupCamera: "Requesting camera access and opening the camera...",
74
+ startupPreview: "Starting the camera preview...",
75
+ startupDecoder: "Preparing code recognition...",
76
+ timeoutCamera: "Camera startup timed out. Check system and browser camera permissions, or choose an image.",
77
+ timeoutPreview: "Camera preview timed out. Retry or choose an image.",
78
+ timeoutDecoder: "Code recognition setup timed out. Check the network or scanner resource deployment and retry.",
79
+ previewFailed: "Camera preview failed. Retry or choose an image."
71
80
  }
72
81
  };
73
82
  export {
@@ -69,5 +69,14 @@ declare const _default: {
69
69
  recordVideo: string;
70
70
  chooseFromAlbum: string;
71
71
  };
72
+ vanQrScanner: {
73
+ startupCamera: string;
74
+ startupPreview: string;
75
+ startupDecoder: string;
76
+ timeoutCamera: string;
77
+ timeoutPreview: string;
78
+ timeoutDecoder: string;
79
+ previewFailed: string;
80
+ };
72
81
  };
73
82
  export default _default;
@@ -68,6 +68,15 @@ var stdin_default = {
68
68
  takePhoto: "\u62CD\u7167",
69
69
  recordVideo: "\u62CD\u89C6\u9891",
70
70
  chooseFromAlbum: "\u4ECE\u76F8\u518C\u9009\u62E9"
71
+ },
72
+ vanQrScanner: {
73
+ startupCamera: "\u6B63\u5728\u8BF7\u6C42\u76F8\u673A\u6743\u9650\u5E76\u6253\u5F00\u6444\u50CF\u5934...",
74
+ startupPreview: "\u6B63\u5728\u542F\u52A8\u76F8\u673A\u753B\u9762...",
75
+ startupDecoder: "\u6B63\u5728\u51C6\u5907\u626B\u7801\u8BC6\u522B...",
76
+ timeoutCamera: "\u6444\u50CF\u5934\u542F\u52A8\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5\u7CFB\u7EDF\u548C\u6D4F\u89C8\u5668\u76F8\u673A\u6388\u6743\uFF0C\u4E5F\u53EF\u4EE5\u4ECE\u76F8\u518C\u8BC6\u522B",
77
+ timeoutPreview: "\u76F8\u673A\u753B\u9762\u542F\u52A8\u8D85\u65F6\uFF0C\u8BF7\u91CD\u8BD5\u6216\u4ECE\u76F8\u518C\u8BC6\u522B",
78
+ timeoutDecoder: "\u626B\u7801\u8BC6\u522B\u51C6\u5907\u8D85\u65F6\uFF0C\u8BF7\u68C0\u67E5\u7F51\u7EDC\u6216\u626B\u7801\u8D44\u6E90\u90E8\u7F72\u540E\u91CD\u8BD5",
79
+ previewFailed: "\u76F8\u673A\u753B\u9762\u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u6216\u4ECE\u76F8\u518C\u8BC6\u522B"
71
80
  }
72
81
  };
73
82
  export {
@@ -60,5 +60,14 @@ declare const _default: {
60
60
  vanAddressList: {
61
61
  add: string;
62
62
  };
63
+ vanQrScanner: {
64
+ startupCamera: string;
65
+ startupPreview: string;
66
+ startupDecoder: string;
67
+ timeoutCamera: string;
68
+ timeoutPreview: string;
69
+ timeoutDecoder: string;
70
+ previewFailed: string;
71
+ };
63
72
  };
64
73
  export default _default;
@@ -59,6 +59,15 @@ var stdin_default = {
59
59
  },
60
60
  vanAddressList: {
61
61
  add: "\u65B0\u589E\u5730\u5740"
62
+ },
63
+ vanQrScanner: {
64
+ startupCamera: "\u6B63\u5728\u8ACB\u6C42\u76F8\u6A5F\u6B0A\u9650\u4E26\u958B\u555F\u651D\u5F71\u6A5F...",
65
+ startupPreview: "\u6B63\u5728\u555F\u52D5\u76F8\u6A5F\u756B\u9762...",
66
+ startupDecoder: "\u6B63\u5728\u6E96\u5099\u6383\u78BC\u8B58\u5225...",
67
+ timeoutCamera: "\u651D\u5F71\u6A5F\u555F\u52D5\u903E\u6642\uFF0C\u8ACB\u6AA2\u67E5\u7CFB\u7D71\u548C\u700F\u89BD\u5668\u76F8\u6A5F\u6388\u6B0A\uFF0C\u4E5F\u53EF\u4EE5\u5F9E\u76F8\u7C3F\u8B58\u5225",
68
+ timeoutPreview: "\u76F8\u6A5F\u756B\u9762\u555F\u52D5\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66\u6216\u5F9E\u76F8\u7C3F\u8B58\u5225",
69
+ timeoutDecoder: "\u6383\u78BC\u8B58\u5225\u6E96\u5099\u903E\u6642\uFF0C\u8ACB\u6AA2\u67E5\u7DB2\u8DEF\u6216\u6383\u78BC\u8CC7\u6E90\u90E8\u7F72\u5F8C\u91CD\u8A66",
70
+ previewFailed: "\u76F8\u6A5F\u756B\u9762\u555F\u52D5\u5931\u6557\uFF0C\u8ACB\u91CD\u8A66\u6216\u5F9E\u76F8\u7C3F\u8B58\u5225"
62
71
  }
63
72
  };
64
73
  export {
@@ -14,6 +14,11 @@ declare const qrScannerProps: {
14
14
  type: PropType<string>;
15
15
  default: string;
16
16
  };
17
+ startupTimeout: {
18
+ type: (NumberConstructor | StringConstructor)[];
19
+ default: number;
20
+ };
21
+ startupTexts: PropType<Partial<Record<"camera" | "preview" | "decoder", string>>>;
17
22
  formats: {
18
23
  type: PropType<QrScannerFormat[]>;
19
24
  default: () => never[];
@@ -81,6 +86,11 @@ declare const _default: import("vue").DefineComponent<{
81
86
  type: PropType<string>;
82
87
  default: string;
83
88
  };
89
+ startupTimeout: {
90
+ type: (NumberConstructor | StringConstructor)[];
91
+ default: number;
92
+ };
93
+ startupTexts: PropType<Partial<Record<"camera" | "preview" | "decoder", string>>>;
84
94
  formats: {
85
95
  type: PropType<QrScannerFormat[]>;
86
96
  default: () => never[];
@@ -132,7 +142,7 @@ declare const _default: import("vue").DefineComponent<{
132
142
  type: BooleanConstructor;
133
143
  default: true;
134
144
  };
135
- }, () => 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<ExtractPropTypes<{
145
+ }, () => 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<ExtractPropTypes<{
136
146
  show: BooleanConstructor;
137
147
  title: {
138
148
  type: PropType<string>;
@@ -146,6 +156,11 @@ declare const _default: import("vue").DefineComponent<{
146
156
  type: PropType<string>;
147
157
  default: string;
148
158
  };
159
+ startupTimeout: {
160
+ type: (NumberConstructor | StringConstructor)[];
161
+ default: number;
162
+ };
163
+ startupTexts: PropType<Partial<Record<"camera" | "preview" | "decoder", string>>>;
149
164
  formats: {
150
165
  type: PropType<QrScannerFormat[]>;
151
166
  default: () => never[];
@@ -205,6 +220,7 @@ declare const _default: import("vue").DefineComponent<{
205
220
  onCancel?: ((...args: any[]) => any) | undefined;
206
221
  onScan?: ((...args: any[]) => any) | undefined;
207
222
  onReady?: ((...args: any[]) => any) | undefined;
223
+ onStageChange?: ((...args: any[]) => any) | undefined;
208
224
  }, {
209
225
  title: string;
210
226
  show: boolean;
@@ -213,6 +229,7 @@ declare const _default: import("vue").DefineComponent<{
213
229
  closeOnPopstate: boolean;
214
230
  tip: string;
215
231
  processingText: string;
232
+ startupTimeout: string | number;
216
233
  formats: QrScannerFormat[];
217
234
  facingMode: "environment" | "user";
218
235
  showAlbum: boolean;
@@ -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
- const [name, bem] = createNamespace("qr-scanner");
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 (!isCurrent(id))
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
- cameraError(error);
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
- yield decoder.prepareDecoder(props.wasmUrl);
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
- phase.value = "processing";
352
- message.value = "";
443
+ abortController = new AbortController();
444
+ const {
445
+ signal
446
+ } = abortController;
353
447
  let imageCanvas;
354
448
  try {
355
- const decoder = yield import("./decoder");
356
- const image = yield decoder.loadImage(file);
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: () => [phase.value === "starting" ? props.nativeScan ? "\u6B63\u5728\u6253\u5F00\u626B\u7801..." : "\u6B63\u5728\u542F\u52A8\u6444\u50CF\u5934..." : props.processingText]
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 { prepareZXingModule, readBarcodes } from "zxing-wasm/reader";
22
- let ready;
23
- let activeWasmUrl;
24
- function prepareDecoder(wasmUrl) {
25
- return __async(this, null, function* () {
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 (!ready || url !== activeWasmUrl) {
28
- activeWasmUrl = url;
29
- ready = Promise.resolve(
30
- prepareZXingModule({
31
- overrides: { locateFile: () => url },
32
- fireImmediately: true
33
- })
34
- ).catch((error) => {
35
- ready = void 0;
36
- throw error;
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
- const results = yield readBarcodes(image, {
46
- formats: formats.length ? formats : ["QRCode"],
47
- tryHarder: true,
48
- maxNumberOfSymbols: 1
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
- image.onload = () => {
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
- URL.revokeObjectURL(url);
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;