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/lib/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/lib/index.js CHANGED
@@ -250,7 +250,7 @@ __reExport(stdin_exports, require("./uploader"), module.exports);
250
250
  __reExport(stdin_exports, require("./video-preview"), module.exports);
251
251
  __reExport(stdin_exports, require("./work-order-card"), module.exports);
252
252
  __reExport(stdin_exports, require("./work-order-filter"), module.exports);
253
- const version = "0.0.53";
253
+ const version = "0.0.54";
254
254
  function install(app) {
255
255
  const components = [
256
256
  import_action_bar.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;
@@ -90,5 +90,14 @@ var stdin_default = {
90
90
  takePhoto: "Take photo",
91
91
  recordVideo: "Record video",
92
92
  chooseFromAlbum: "Choose from album"
93
+ },
94
+ vanQrScanner: {
95
+ startupCamera: "Requesting camera access and opening the camera...",
96
+ startupPreview: "Starting the camera preview...",
97
+ startupDecoder: "Preparing code recognition...",
98
+ timeoutCamera: "Camera startup timed out. Check system and browser camera permissions, or choose an image.",
99
+ timeoutPreview: "Camera preview timed out. Retry or choose an image.",
100
+ timeoutDecoder: "Code recognition setup timed out. Check the network or scanner resource deployment and retry.",
101
+ previewFailed: "Camera preview failed. Retry or choose an image."
93
102
  }
94
103
  };
@@ -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;
@@ -90,5 +90,14 @@ var stdin_default = {
90
90
  takePhoto: "\u62CD\u7167",
91
91
  recordVideo: "\u62CD\u89C6\u9891",
92
92
  chooseFromAlbum: "\u4ECE\u76F8\u518C\u9009\u62E9"
93
+ },
94
+ vanQrScanner: {
95
+ startupCamera: "\u6B63\u5728\u8BF7\u6C42\u76F8\u673A\u6743\u9650\u5E76\u6253\u5F00\u6444\u50CF\u5934...",
96
+ startupPreview: "\u6B63\u5728\u542F\u52A8\u76F8\u673A\u753B\u9762...",
97
+ startupDecoder: "\u6B63\u5728\u51C6\u5907\u626B\u7801\u8BC6\u522B...",
98
+ 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",
99
+ timeoutPreview: "\u76F8\u673A\u753B\u9762\u542F\u52A8\u8D85\u65F6\uFF0C\u8BF7\u91CD\u8BD5\u6216\u4ECE\u76F8\u518C\u8BC6\u522B",
100
+ 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",
101
+ previewFailed: "\u76F8\u673A\u753B\u9762\u542F\u52A8\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5\u6216\u4ECE\u76F8\u518C\u8BC6\u522B"
93
102
  }
94
103
  };
@@ -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;
@@ -81,5 +81,14 @@ var stdin_default = {
81
81
  },
82
82
  vanAddressList: {
83
83
  add: "\u65B0\u589E\u5730\u5740"
84
+ },
85
+ vanQrScanner: {
86
+ startupCamera: "\u6B63\u5728\u8ACB\u6C42\u76F8\u6A5F\u6B0A\u9650\u4E26\u958B\u555F\u651D\u5F71\u6A5F...",
87
+ startupPreview: "\u6B63\u5728\u555F\u52D5\u76F8\u6A5F\u756B\u9762...",
88
+ startupDecoder: "\u6B63\u5728\u6E96\u5099\u6383\u78BC\u8B58\u5225...",
89
+ 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",
90
+ timeoutPreview: "\u76F8\u6A5F\u756B\u9762\u555F\u52D5\u903E\u6642\uFF0C\u8ACB\u91CD\u8A66\u6216\u5F9E\u76F8\u7C3F\u8B58\u5225",
91
+ 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",
92
+ previewFailed: "\u76F8\u6A5F\u756B\u9762\u555F\u52D5\u5931\u6557\uFF0C\u8ACB\u91CD\u8A66\u6216\u5F9E\u76F8\u7C3F\u8B58\u5225"
84
93
  }
85
94
  };
@@ -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;
@@ -58,12 +58,16 @@ var import_button = require("../button");
58
58
  var import_icon = require("../icon");
59
59
  var import_loading = require("../loading");
60
60
  var import_popup = require("../popup");
61
- const [name, bem] = (0, import_utils.createNamespace)("qr-scanner");
61
+ var import_zh_CN = __toESM(require("../locale/lang/zh-CN"));
62
+ var import_startup = require("./startup");
63
+ const [name, bem, t] = (0, import_utils.createNamespace)("qr-scanner");
62
64
  const qrScannerProps = {
63
65
  show: Boolean,
64
66
  title: (0, import_utils.makeStringProp)("\u626B\u63CF\u8BBE\u5907\u4E8C\u7EF4\u7801"),
65
67
  tip: (0, import_utils.makeStringProp)("\u5C06\u8BBE\u5907\u4E8C\u7EF4\u7801\u7F6E\u4E8E\u53D6\u666F\u6846\u5185\uFF0C\u5373\u53EF\u81EA\u52A8\u8BC6\u522B"),
66
68
  processingText: (0, import_utils.makeStringProp)("\u6B63\u5728\u5904\u7406\u626B\u7801\u7ED3\u679C..."),
69
+ startupTimeout: (0, import_utils.makeNumericProp)(import_startup.DEFAULT_STARTUP_TIMEOUT),
70
+ startupTexts: Object,
67
71
  formats: (0, import_utils.extend)((0, import_utils.makeArrayProp)(), {
68
72
  default: () => ["QRCode"]
69
73
  }),
@@ -89,7 +93,7 @@ const qrScannerProps = {
89
93
  var stdin_default = (0, import_vue.defineComponent)({
90
94
  name,
91
95
  props: qrScannerProps,
92
- emits: ["update:show", "scan", "error", "cancel", "close", "closed", "ready"],
96
+ emits: ["update:show", "scan", "error", "cancel", "close", "closed", "ready", "stageChange"],
93
97
  setup(props, {
94
98
  emit
95
99
  }) {
@@ -98,6 +102,7 @@ var stdin_default = (0, import_vue.defineComponent)({
98
102
  const frame = (0, import_vue.ref)();
99
103
  const fileInput = (0, import_vue.ref)();
100
104
  const phase = (0, import_vue.ref)("idle");
105
+ const startupStage = (0, import_vue.ref)("camera");
101
106
  const message = (0, import_vue.ref)("");
102
107
  const hasTorch = (0, import_vue.ref)(false);
103
108
  const torchOn = (0, import_vue.ref)(false);
@@ -108,13 +113,25 @@ var stdin_default = (0, import_vue.defineComponent)({
108
113
  let stream;
109
114
  let canvas;
110
115
  let timer;
116
+ let startupTimer;
117
+ let startupStartedAt = 0;
118
+ let startupDeadline = 0;
111
119
  let generation = 0;
112
120
  let abortController;
113
121
  let resumeWhenVisible = false;
122
+ let pickingAlbum = false;
114
123
  const recentResults = /* @__PURE__ */ new Map();
115
124
  const isCurrent = (id) => id === generation && props.show && !props.paused;
125
+ const startupText = (key) => t(key) || import_zh_CN.default.vanQrScanner[key];
126
+ const clearStartupTimer = () => {
127
+ if (startupTimer !== void 0)
128
+ clearTimeout(startupTimer);
129
+ startupTimer = void 0;
130
+ startupDeadline = 0;
131
+ };
116
132
  const release = () => {
117
133
  generation += 1;
134
+ clearStartupTimer();
118
135
  if (timer)
119
136
  clearTimeout(timer);
120
137
  timer = void 0;
@@ -133,6 +150,7 @@ var stdin_default = (0, import_vue.defineComponent)({
133
150
  phase.value = "paused";
134
151
  };
135
152
  const close = (cancelled = false) => {
153
+ pickingAlbum = false;
136
154
  release();
137
155
  phase.value = "idle";
138
156
  if (cancelled)
@@ -140,14 +158,46 @@ var stdin_default = (0, import_vue.defineComponent)({
140
158
  emit("update:show", false);
141
159
  };
142
160
  const reportError = (code, text, cause) => {
161
+ const startupInfo = phase.value === "starting" && abortController && !props.nativeScan ? {
162
+ stage: startupStage.value,
163
+ elapsedMs: Math.max(0, Date.now() - startupStartedAt)
164
+ } : {};
143
165
  release();
144
166
  phase.value = "error";
145
167
  message.value = text;
146
- emit("error", {
168
+ emit("error", (0, import_utils.extend)({
147
169
  code,
148
170
  message: text,
149
171
  cause
172
+ }, startupInfo));
173
+ };
174
+ const reportStartupTimeout = () => {
175
+ const timeoutMessages = {
176
+ camera: startupText("timeoutCamera"),
177
+ preview: startupText("timeoutPreview"),
178
+ decoder: startupText("timeoutDecoder"),
179
+ ready: ""
180
+ };
181
+ reportError("STARTUP_TIMEOUT", timeoutMessages[startupStage.value]);
182
+ };
183
+ const canContinueStartup = (id) => {
184
+ if (!isCurrent(id))
185
+ return false;
186
+ if (startupDeadline && Date.now() >= startupDeadline) {
187
+ reportStartupTimeout();
188
+ return false;
189
+ }
190
+ return true;
191
+ };
192
+ const setStartupStage = (stage, id) => {
193
+ if (!canContinueStartup(id))
194
+ return false;
195
+ startupStage.value = stage;
196
+ emit("stageChange", {
197
+ stage,
198
+ elapsedMs: Math.max(0, Date.now() - startupStartedAt)
150
199
  });
200
+ return isCurrent(id);
151
201
  };
152
202
  const cameraError = (error) => {
153
203
  const errorName = error == null ? void 0 : error.name;
@@ -235,7 +285,7 @@ var stdin_default = (0, import_vue.defineComponent)({
235
285
  height: target.height / scale
236
286
  });
237
287
  if (image) {
238
- const result = yield decoder.decode(image, props.formats, props.wasmUrl);
288
+ const result = yield decoder.decode(image, props.formats, props.wasmUrl, abortController == null ? void 0 : abortController.signal);
239
289
  if (!isCurrent(id))
240
290
  return;
241
291
  if (result)
@@ -261,6 +311,7 @@ var stdin_default = (0, import_vue.defineComponent)({
261
311
  return;
262
312
  }
263
313
  const id = generation;
314
+ pickingAlbum = false;
264
315
  phase.value = "starting";
265
316
  message.value = "";
266
317
  if (props.nativeScan) {
@@ -296,8 +347,25 @@ var stdin_default = (0, import_vue.defineComponent)({
296
347
  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");
297
348
  return;
298
349
  }
350
+ abortController = new AbortController();
351
+ const {
352
+ signal
353
+ } = abortController;
354
+ startupStartedAt = Date.now();
355
+ const configuredTimeout = Number(props.startupTimeout);
356
+ const timeout = Number.isFinite(configuredTimeout) ? Math.max(0, configuredTimeout) : import_startup.DEFAULT_STARTUP_TIMEOUT;
357
+ if (timeout > 0) {
358
+ startupDeadline = startupStartedAt + timeout;
359
+ startupTimer = setTimeout(() => {
360
+ if (!isCurrent(id) || phase.value !== "starting")
361
+ return;
362
+ reportStartupTimeout();
363
+ }, timeout);
364
+ }
365
+ if (!setStartupStage("camera", id))
366
+ return;
299
367
  try {
300
- const acquiredStream = yield navigator.mediaDevices.getUserMedia({
368
+ const acquiredStream = yield (0, import_startup.waitForAbort)(navigator.mediaDevices.getUserMedia({
301
369
  audio: false,
302
370
  video: (0, import_utils.extend)(deviceId ? {
303
371
  deviceId: {
@@ -315,28 +383,44 @@ var stdin_default = (0, import_vue.defineComponent)({
315
383
  ideal: 720
316
384
  }
317
385
  })
318
- });
386
+ }).then((acquired) => {
387
+ if (!isCurrent(id))
388
+ acquired.getTracks().forEach((track2) => track2.stop());
389
+ return acquired;
390
+ }), signal);
319
391
  if (!isCurrent(id)) {
320
392
  acquiredStream.getTracks().forEach((track2) => track2.stop());
321
393
  return;
322
394
  }
323
395
  stream = acquiredStream;
396
+ } catch (error) {
397
+ if (isCurrent(id))
398
+ cameraError(error);
399
+ return;
400
+ }
401
+ if (!setStartupStage("preview", id))
402
+ return;
403
+ try {
324
404
  yield (0, import_vue.nextTick)();
325
- if (!isCurrent(id))
405
+ if (!canContinueStartup(id))
326
406
  return;
327
407
  if (!video.value)
328
408
  throw new Error("\u626B\u7801\u9884\u89C8\u5C1A\u672A\u5C31\u7EEA");
329
409
  video.value.srcObject = stream;
330
- yield video.value.play();
410
+ yield (0, import_startup.waitForAbort)(video.value.play(), signal);
331
411
  } catch (error) {
332
412
  if (isCurrent(id))
333
- cameraError(error);
413
+ reportError("PREVIEW_FAILED", startupText("previewFailed"), error);
334
414
  return;
335
415
  }
416
+ if (!setStartupStage("decoder", id))
417
+ return;
336
418
  let decoder;
337
419
  try {
338
- decoder = yield import("./decoder");
339
- yield decoder.prepareDecoder(props.wasmUrl);
420
+ decoder = yield (0, import_startup.waitForAbort)(import("./decoder"), signal);
421
+ if (!canContinueStartup(id))
422
+ return;
423
+ yield (0, import_startup.waitForAbort)(decoder.prepareDecoder(props.wasmUrl, signal), signal);
340
424
  } catch (error) {
341
425
  if (isCurrent(id))
342
426
  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);
@@ -344,6 +428,8 @@ var stdin_default = (0, import_vue.defineComponent)({
344
428
  }
345
429
  if (!isCurrent(id))
346
430
  return;
431
+ if (!canContinueStartup(id))
432
+ return;
347
433
  const track = stream == null ? void 0 : stream.getVideoTracks()[0];
348
434
  try {
349
435
  const capability = (_b = track == null ? void 0 : track.getCapabilities) == null ? void 0 : _b.call(track).torch;
@@ -365,6 +451,9 @@ var stdin_default = (0, import_vue.defineComponent)({
365
451
  }).catch(() => {
366
452
  });
367
453
  phase.value = "scanning";
454
+ clearStartupTimer();
455
+ if (!setStartupStage("ready", id))
456
+ return;
368
457
  emit("ready", {
369
458
  torch: hasTorch.value
370
459
  });
@@ -374,25 +463,32 @@ var stdin_default = (0, import_vue.defineComponent)({
374
463
  const scanImage = (file) => __async(this, null, function* () {
375
464
  if (!props.show || props.paused)
376
465
  return;
466
+ pickingAlbum = false;
467
+ release();
468
+ phase.value = "processing";
469
+ message.value = "";
377
470
  if (file.size > Number(props.maxImageSize)) {
378
471
  reportError("IMAGE_TOO_LARGE", "\u56FE\u7247\u8FC7\u5927\uFF0C\u8BF7\u9009\u62E9\u8F83\u5C0F\u7684\u56FE\u7247");
379
472
  return;
380
473
  }
381
- release();
382
474
  const id = generation;
383
- phase.value = "processing";
384
- message.value = "";
475
+ abortController = new AbortController();
476
+ const {
477
+ signal
478
+ } = abortController;
385
479
  let imageCanvas;
386
480
  try {
387
- const decoder = yield import("./decoder");
388
- const image = yield decoder.loadImage(file);
481
+ const decoder = yield (0, import_startup.waitForAbort)(import("./decoder"), signal);
482
+ if (!isCurrent(id))
483
+ return;
484
+ const image = yield (0, import_startup.waitForAbort)(decoder.loadImage(file, signal), signal);
389
485
  if (!isCurrent(id))
390
486
  return;
391
487
  imageCanvas = document.createElement("canvas");
392
488
  const data = decoder.captureImage(image, imageCanvas, 1920);
393
489
  if (!data)
394
490
  throw new Error("\u65E0\u6CD5\u8BFB\u53D6\u56FE\u7247");
395
- const result = yield decoder.decode(data, props.formats, props.wasmUrl);
491
+ const result = yield (0, import_startup.waitForAbort)(decoder.decode(data, props.formats, props.wasmUrl, signal), signal);
396
492
  if (!isCurrent(id))
397
493
  return;
398
494
  if (!result) {
@@ -461,6 +557,15 @@ var stdin_default = (0, import_vue.defineComponent)({
461
557
  start();
462
558
  }
463
559
  };
560
+ const onAlbumCancel = () => {
561
+ if (pickingAlbum && phase.value === "paused")
562
+ start();
563
+ pickingAlbum = false;
564
+ };
565
+ (0, import_vue.watch)(fileInput, (input, previous) => {
566
+ previous == null ? void 0 : previous.removeEventListener("cancel", onAlbumCancel);
567
+ input == null ? void 0 : input.addEventListener("cancel", onAlbumCancel);
568
+ });
464
569
  (0, import_vue.watch)(() => props.show, (show) => __async(this, null, function* () {
465
570
  release();
466
571
  recentResults.clear();
@@ -487,9 +592,15 @@ var stdin_default = (0, import_vue.defineComponent)({
487
592
  if (props.show)
488
593
  start();
489
594
  });
595
+ (0, import_vue.watch)(() => props.wasmUrl, () => {
596
+ if (props.show && !props.nativeScan && (phase.value === "starting" || phase.value === "scanning"))
597
+ start();
598
+ });
490
599
  (0, import_vue.onMounted)(() => document.addEventListener("visibilitychange", onVisibilityChange));
491
600
  (0, import_vue.onBeforeUnmount)(() => {
601
+ var _a;
492
602
  release();
603
+ (_a = fileInput.value) == null ? void 0 : _a.removeEventListener("cancel", onAlbumCancel);
493
604
  if (canvas) {
494
605
  canvas.width = 0;
495
606
  canvas.height = 0;
@@ -574,7 +685,15 @@ var stdin_default = (0, import_vue.defineComponent)({
574
685
  "color": "white",
575
686
  "vertical": true
576
687
  }, {
577
- default: () => [phase.value === "starting" ? props.nativeScan ? "\u6B63\u5728\u6253\u5F00\u626B\u7801..." : "\u6B63\u5728\u542F\u52A8\u6444\u50CF\u5934..." : props.processingText]
688
+ default: () => {
689
+ var _a, _b, _c, _d, _e, _f;
690
+ return [phase.value === "starting" ? props.nativeScan ? "\u6B63\u5728\u6253\u5F00\u626B\u7801..." : {
691
+ camera: (_b = (_a = props.startupTexts) == null ? void 0 : _a.camera) != null ? _b : startupText("startupCamera"),
692
+ preview: (_d = (_c = props.startupTexts) == null ? void 0 : _c.preview) != null ? _d : startupText("startupPreview"),
693
+ decoder: (_f = (_e = props.startupTexts) == null ? void 0 : _e.decoder) != null ? _f : startupText("startupDecoder"),
694
+ ready: ""
695
+ }[startupStage.value] : props.processingText];
696
+ }
578
697
  }), needsRetry && (0, import_vue.createVNode)(import_vue.Fragment, null, [(0, import_vue.createVNode)("p", {
579
698
  "class": bem("message")
580
699
  }, [message.value || "\u626B\u63CF\u5DF2\u6682\u505C"]), (0, import_vue.createVNode)(import_button.Button, {
@@ -607,6 +726,7 @@ var stdin_default = (0, import_vue.defineComponent)({
607
726
  var _a;
608
727
  stop();
609
728
  resumeWhenVisible = false;
729
+ pickingAlbum = true;
610
730
  (_a = fileInput.value) == null ? void 0 : _a.click();
611
731
  }
612
732
  }, [(0, import_vue.createVNode)(import_icon.Icon, {
@@ -636,6 +756,9 @@ var stdin_default = (0, import_vue.defineComponent)({
636
756
  input.value = "";
637
757
  if (file)
638
758
  scanImage(file);
759
+ else if (pickingAlbum && phase.value === "paused")
760
+ start();
761
+ pickingAlbum = false;
639
762
  }
640
763
  }, null)]
641
764
  });
@@ -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;
@@ -54,47 +54,115 @@ __export(stdin_exports, {
54
54
  });
55
55
  module.exports = __toCommonJS(stdin_exports);
56
56
  var import_reader = require("zxing-wasm/reader");
57
- let ready;
58
- let activeWasmUrl;
59
- function prepareDecoder(wasmUrl) {
60
- return __async(this, null, function* () {
57
+ var import_startup = require("./startup");
58
+ let preparation;
59
+ function invalidate(entry) {
60
+ if (preparation === entry) {
61
+ preparation = void 0;
62
+ (0, import_reader.purgeZXingModule)();
63
+ }
64
+ }
65
+ function createPreparation(wasmUrl) {
66
+ const controller = new AbortController();
67
+ const entry = {
68
+ wasmUrl,
69
+ pending: true,
70
+ controller,
71
+ consumers: /* @__PURE__ */ new Set(),
72
+ promise: void 0
73
+ };
74
+ const initialize = () => __async(this, null, function* () {
61
75
  const url = wasmUrl || (yield import("zxing-wasm/reader/zxing_reader.wasm?url")).default;
62
- if (!ready || url !== activeWasmUrl) {
63
- activeWasmUrl = url;
64
- ready = Promise.resolve(
65
- (0, import_reader.prepareZXingModule)({
66
- overrides: { locateFile: () => url },
67
- fireImmediately: true
68
- })
69
- ).catch((error) => {
70
- ready = void 0;
71
- throw error;
72
- });
76
+ if (controller.signal.aborted || preparation !== entry)
77
+ throw (0, import_startup.abortError)();
78
+ yield (0, import_reader.prepareZXingModule)({
79
+ overrides: { locateFile: () => url },
80
+ fireImmediately: true
81
+ });
82
+ });
83
+ entry.promise = (0, import_startup.waitForAbort)(
84
+ Promise.resolve().then(initialize),
85
+ controller.signal
86
+ ).then(
87
+ () => {
88
+ entry.pending = false;
89
+ },
90
+ (error) => {
91
+ entry.pending = false;
92
+ invalidate(entry);
93
+ throw error;
94
+ }
95
+ );
96
+ return entry;
97
+ }
98
+ function prepareDecoder(wasmUrl, signal) {
99
+ return __async(this, null, function* () {
100
+ if (signal == null ? void 0 : signal.aborted)
101
+ throw (0, import_startup.abortError)();
102
+ if (!preparation || preparation.wasmUrl !== wasmUrl) {
103
+ preparation = createPreparation(wasmUrl);
104
+ }
105
+ const entry = preparation;
106
+ const consumer = Symbol("decoder-consumer");
107
+ entry.consumers.add(consumer);
108
+ const releaseConsumer = () => {
109
+ entry.consumers.delete(consumer);
110
+ if (entry.pending && !entry.consumers.size) {
111
+ invalidate(entry);
112
+ entry.controller.abort();
113
+ }
114
+ };
115
+ signal == null ? void 0 : signal.addEventListener("abort", releaseConsumer, { once: true });
116
+ try {
117
+ yield (0, import_startup.waitForAbort)(entry.promise, signal);
118
+ } finally {
119
+ signal == null ? void 0 : signal.removeEventListener("abort", releaseConsumer);
120
+ releaseConsumer();
73
121
  }
74
- yield ready;
75
122
  });
76
123
  }
77
- function decode(image, formats, wasmUrl) {
124
+ function decode(image, formats, wasmUrl, signal) {
78
125
  return __async(this, null, function* () {
79
- yield prepareDecoder(wasmUrl);
80
- const results = yield (0, import_reader.readBarcodes)(image, {
81
- formats: formats.length ? formats : ["QRCode"],
82
- tryHarder: true,
83
- maxNumberOfSymbols: 1
84
- });
126
+ yield prepareDecoder(wasmUrl, signal);
127
+ if (signal == null ? void 0 : signal.aborted)
128
+ throw (0, import_startup.abortError)();
129
+ const results = yield (0, import_startup.waitForAbort)(
130
+ (0, import_reader.readBarcodes)(image, {
131
+ formats: formats.length ? formats : ["QRCode"],
132
+ tryHarder: true,
133
+ maxNumberOfSymbols: 1
134
+ }),
135
+ signal
136
+ );
85
137
  return results.find((result) => result.isValid && result.text.length > 0);
86
138
  });
87
139
  }
88
- function loadImage(file) {
140
+ function loadImage(file, signal) {
89
141
  return new Promise((resolve, reject) => {
142
+ if (signal == null ? void 0 : signal.aborted) {
143
+ reject((0, import_startup.abortError)());
144
+ return;
145
+ }
90
146
  const url = URL.createObjectURL(file);
91
147
  const image = new Image();
92
- image.onload = () => {
148
+ const cleanup = () => {
93
149
  URL.revokeObjectURL(url);
150
+ signal == null ? void 0 : signal.removeEventListener("abort", onAbort);
151
+ image.onload = null;
152
+ image.onerror = null;
153
+ };
154
+ const onAbort = () => {
155
+ cleanup();
156
+ image.src = "";
157
+ reject((0, import_startup.abortError)());
158
+ };
159
+ signal == null ? void 0 : signal.addEventListener("abort", onAbort, { once: true });
160
+ image.onload = () => {
161
+ cleanup();
94
162
  resolve(image);
95
163
  };
96
164
  image.onerror = () => {
97
- URL.revokeObjectURL(url);
165
+ cleanup();
98
166
  reject(new Error("\u65E0\u6CD5\u8BFB\u53D6\u56FE\u7247\uFF0C\u8BF7\u9009\u62E9 JPG\u3001PNG \u7B49\u6D4F\u89C8\u5668\u652F\u6301\u7684\u56FE\u7247"));
99
167
  };
100
168
  image.src = url;