@feugene/granularity-media 0.2.1 → 0.4.0

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 (45) hide show
  1. package/README.md +23 -6
  2. package/dist/chunks/{config-CZ4ZDG0_.js → config-DHLlFslI.js} +1 -1
  3. package/dist/chunks/config-DfJkKtIh.js +27 -0
  4. package/dist/chunks/{en-C-Wc5fTB.js → en-BugobSAO.js} +12 -4
  5. package/dist/chunks/{es-BUPtE9_0.js → es-B7iA-ExH.js} +12 -4
  6. package/dist/chunks/outputSize-D2FU4CbB.js +23 -0
  7. package/dist/chunks/ru-DSjpFh8N.js +4 -0
  8. package/dist/chunks/{ru-BqNILj54.js → ru-DpiW6Vax.js} +12 -4
  9. package/dist/chunks/useCameraStream-CPdm3r90.js +86 -0
  10. package/dist/components/GrCameraCapture/chunks/GrCameraCapture-t-uFTD9s.js +134 -0
  11. package/dist/components/GrCameraCapture/index.js +4 -3
  12. package/dist/components/GrCodeScanner/chunks/GrCodeScanner-BX147Gct.js +162 -0
  13. package/dist/components/GrCodeScanner/index.js +3 -0
  14. package/dist/components/GrImageCrop/chunks/{GrImageCrop-Fo2qrX2n.js → GrImageCrop-g1StRUis.js} +85 -84
  15. package/dist/components/GrImageCrop/index.js +1 -1
  16. package/dist/granular-provider.js +14 -12
  17. package/dist/i18n/all.js +1 -1
  18. package/dist/i18n/index.js +4 -4
  19. package/dist/index.js +8 -5
  20. package/dist/resolver.js +5 -1
  21. package/dist/types/componentNames.d.ts +1 -1
  22. package/dist/types/components/GrCameraCapture/GrCameraCapture.vue.d.ts +13 -9
  23. package/dist/types/components/GrCameraCapture/cameraState.d.ts +0 -17
  24. package/dist/types/components/GrCameraCapture/grCameraCaptureStyles.d.ts +6 -2
  25. package/dist/types/components/GrCameraCapture/index.d.ts +2 -2
  26. package/dist/types/components/GrCodeScanner/GrCodeScanner.vue.d.ts +121 -0
  27. package/dist/types/components/GrCodeScanner/__tests__/GrCodeScanner.test.d.ts +1 -0
  28. package/dist/types/components/GrCodeScanner/__tests__/codeDetection.test.d.ts +1 -0
  29. package/dist/types/components/GrCodeScanner/codeDetection.d.ts +42 -0
  30. package/dist/types/components/GrCodeScanner/config.d.ts +5 -0
  31. package/dist/types/components/GrCodeScanner/defaults.d.ts +16 -0
  32. package/dist/types/components/GrCodeScanner/grCodeScannerStyles.d.ts +19 -0
  33. package/dist/types/components/GrCodeScanner/index.d.ts +9 -0
  34. package/dist/types/granular-provider/shared.d.ts +1 -0
  35. package/dist/types/i18n/index.d.ts +21 -0
  36. package/dist/types/i18n/messages/en.d.ts +14 -0
  37. package/dist/types/i18n/messages/es.d.ts +14 -0
  38. package/dist/types/i18n/messages/ru.d.ts +14 -0
  39. package/dist/types/index.d.ts +1 -0
  40. package/dist/types/internal/__tests__/outputSize.test.d.ts +1 -0
  41. package/dist/types/internal/outputSize.d.ts +26 -0
  42. package/dist/types/internal/useCameraStream.d.ts +30 -0
  43. package/package.json +5 -1
  44. package/dist/chunks/ru-DN_wJDkP.js +0 -4
  45. package/dist/components/GrCameraCapture/chunks/GrCameraCapture-B9EPXm7r.js +0 -201
package/README.md CHANGED
@@ -1,9 +1,9 @@
1
1
  # `@feugene/granularity-media`
2
2
 
3
- Работа с изображением и камерой для `@feugene/granularity`. Два компонента, и они
4
- стоят рядом по сценарию: `GrCameraCapture` снимает кадр камерой,
5
- `GrImageCrop` выбирает кадр из уже существующей картинки. Оба отдают готовый
6
- `Blob`можно сразу отправлять.
3
+ Работа с изображением и камерой для `@feugene/granularity`. Три компонента, и они
4
+ стоят рядом по сценарию: `GrCameraCapture` снимает кадр камерой, `GrImageCrop`
5
+ выбирает кадр из уже существующей картинки, `GrCodeScanner` читает камерой QR и
6
+ штрихкоды. Первые два отдают готовый `Blob`, третий содержимое кода.
7
7
 
8
8
  ```bash
9
9
  yarn add @feugene/granularity-media
@@ -95,9 +95,26 @@ presetGranularNode({
95
95
  Превью фронтальной камеры зеркальное, снимок — нет: иначе текст на визитке или в
96
96
  документе уехал бы в зазеркалье.
97
97
 
98
+ ## Чтение кодов
99
+
100
+ ```vue
101
+ <GrCodeScanner :formats="['qr_code']" @detect="codes => open(codes[0].value)" />
102
+ ```
103
+
104
+ Декодера пакет не несёт. Нативный `BarcodeDetector` есть в Chrome и Edge, а
105
+ Safari и Firefox закрываются детектором, который передаёт приложение
106
+ (`:detector`): встроить библиотеку значило бы навязать самую тяжёлую
107
+ зависимость и тем, кто взял один кроп. Готовый рецепт на `@zxing/browser` — на
108
+ странице компонента.
109
+
110
+ Один код в кадре даёт одно событие: камера отдаёт десятки кадров в секунду, и
111
+ без фильтра приложение оформило бы двадцать заказов вместо одного. Режим
112
+ приёмки, где сканируют одинаковые упаковки подряд, включается `continuous`.
113
+
98
114
  ## Документация
99
115
 
100
116
  - [`docs/components.md`](./docs/components.md) — состав пакета;
101
- - [`docs/components/GrImageCrop.md`](./docs/components/GrImageCrop.md) и
102
- [`docs/components/GrCameraCapture.md`](./docs/components/GrCameraCapture.md) — страницы компонентов;
117
+ - [`docs/components/GrImageCrop.md`](./docs/components/GrImageCrop.md),
118
+ [`docs/components/GrCameraCapture.md`](./docs/components/GrCameraCapture.md) и
119
+ [`docs/components/GrCodeScanner.md`](./docs/components/GrCodeScanner.md) — страницы компонентов;
103
120
  - [`docs/keyboard.md`](./docs/keyboard.md), [`docs/ssr.md`](./docs/ssr.md) — сквозные правила пакета.
@@ -1,7 +1,7 @@
1
1
  import { t as e } from "./classTokens-bAzTjLuQ.js";
2
2
  import { defineGranularComponent as t } from "@feugene/unocss-preset-granular/contract";
3
3
  //#region src/components/GrCameraCapture/grCameraCaptureStyles.ts
4
- var n = "grid gap-2", r = "relative w-full overflow-hidden rounded-[var(--gr-radius-md)] border border-[var(--gr-brd)] bg-[var(--gr-muted)]", i = "h-full w-full object-cover", a = "scale-x-[-1]", o = "absolute inset-0 grid place-content-center gap-3 p-4 text-center transition-opacity duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]", s = "text-[var(--gr-muted-fg)]", c = "flex flex-wrap items-center gap-2", l = {
4
+ var n = "grid gap-2", r = "relative w-full overflow-hidden rounded-[var(--gr-radius-md)] border border-[var(--gr-brd)] bg-[var(--gr-muted)]", i = "h-full w-full object-contain", a = "scale-x-[-1]", o = "absolute inset-0 grid place-content-center gap-3 p-4 text-center transition-opacity duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]", s = "text-[var(--gr-muted-fg)]", c = "flex flex-wrap items-center gap-2", l = {
5
5
  xs: "text-[length:var(--gr-control-text-xs)] leading-[var(--gr-control-leading-xs)]",
6
6
  sm: "text-[length:var(--gr-control-text-sm)] leading-[var(--gr-control-leading-sm)]",
7
7
  md: "text-[length:var(--gr-control-text-md)] leading-[var(--gr-control-leading-md)]",
@@ -0,0 +1,27 @@
1
+ import { t as e } from "./classTokens-bAzTjLuQ.js";
2
+ import { defineGranularComponent as t } from "@feugene/unocss-preset-granular/contract";
3
+ //#region src/components/GrCodeScanner/grCodeScannerStyles.ts
4
+ var n = "grid gap-2", r = "relative w-full overflow-hidden rounded-[var(--gr-radius-md)] border border-[var(--gr-brd)] bg-[var(--gr-muted)]", i = "h-full w-full object-contain", a = "pointer-events-none absolute inset-[15%] rounded-[var(--gr-radius-md)] border-2 border-[var(--gr-code-scanner-reticle,var(--gr-primary))]", o = "absolute inset-0 grid place-content-center gap-3 p-4 text-center transition-opacity duration-[var(--gr-duration-base)] ease-[var(--gr-ease-out)]", s = "text-[var(--gr-muted-fg)]", c = "flex flex-wrap items-center gap-2", l = {
5
+ xs: "text-[length:var(--gr-control-text-xs)] leading-[var(--gr-control-leading-xs)]",
6
+ sm: "text-[length:var(--gr-control-text-sm)] leading-[var(--gr-control-leading-sm)]",
7
+ md: "text-[length:var(--gr-control-text-md)] leading-[var(--gr-control-leading-md)]",
8
+ lg: "text-[length:var(--gr-control-text-lg)] leading-[var(--gr-control-leading-lg)]"
9
+ }, u = [
10
+ ...e(n),
11
+ ...e(r),
12
+ ...e(i),
13
+ ...e(a),
14
+ ...e(o),
15
+ ...e(s),
16
+ ...e(c),
17
+ ...Object.values(l).flatMap(e)
18
+ ], d = t(import.meta.url, {
19
+ name: "GrCodeScanner",
20
+ safelist: u,
21
+ dependencies: [{
22
+ provider: "@feugene/granularity",
23
+ components: ["GrButton"]
24
+ }]
25
+ });
26
+ //#endregion
27
+ export { a, o as c, u as i, s as l, c as n, n as o, r, l as s, d as t, i as u };
@@ -2,8 +2,9 @@ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
2
  //#region src/i18n/locales/en.json
3
3
  var t = /* @__PURE__ */ e({
4
4
  camera: () => r,
5
- default: () => i,
6
- imageCrop: () => n
5
+ default: () => a,
6
+ imageCrop: () => n,
7
+ scanner: () => i
7
8
  }), n = {
8
9
  label: "Image crop",
9
10
  frame: "Frame: arrow keys move the image, plus and minus zoom",
@@ -25,8 +26,15 @@ var t = /* @__PURE__ */ e({
25
26
  live: "Camera is on",
26
27
  captured: "Photo taken"
27
28
  }, i = {
29
+ label: "Code scanner",
30
+ start: "Start scanning",
31
+ stop: "Stop",
32
+ unsupported: "This browser cannot read codes. Pass a `detector` to enable it.",
33
+ detected: "Code recognised"
34
+ }, a = {
28
35
  imageCrop: n,
29
- camera: r
36
+ camera: r,
37
+ scanner: i
30
38
  };
31
39
  //#endregion
32
- export { t as n, i as t };
40
+ export { t as n, a as t };
@@ -2,8 +2,9 @@ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
2
  //#region src/i18n/locales/es.json
3
3
  var t = /* @__PURE__ */ e({
4
4
  camera: () => r,
5
- default: () => i,
6
- imageCrop: () => n
5
+ default: () => a,
6
+ imageCrop: () => n,
7
+ scanner: () => i
7
8
  }), n = {
8
9
  label: "Recorte de imagen",
9
10
  frame: "Marco: las flechas mueven la imagen, más y menos ajustan el zoom",
@@ -25,8 +26,15 @@ var t = /* @__PURE__ */ e({
25
26
  live: "Cámara encendida",
26
27
  captured: "Foto tomada"
27
28
  }, i = {
29
+ label: "Escáner de códigos",
30
+ start: "Iniciar escaneo",
31
+ stop: "Detener",
32
+ unsupported: "Este navegador no puede leer códigos. Pasa un `detector` para habilitarlos.",
33
+ detected: "Código reconocido"
34
+ }, a = {
28
35
  imageCrop: n,
29
- camera: r
36
+ camera: r,
37
+ scanner: i
30
38
  };
31
39
  //#endregion
32
- export { t as n, i as t };
40
+ export { t as n, a as t };
@@ -0,0 +1,23 @@
1
+ //#region src/internal/outputSize.ts
2
+ function e(e, t) {
3
+ let n = e.sh > 0 ? e.sw / e.sh : 1, r = (e) => Math.max(1, Math.round(e));
4
+ if (t?.width && t?.height) {
5
+ let n = Math.min(t.width / (e.sw || 1), t.height / (e.sh || 1));
6
+ return {
7
+ width: r(e.sw * n),
8
+ height: r(e.sh * n)
9
+ };
10
+ }
11
+ return t?.width ? {
12
+ width: r(t.width),
13
+ height: r(t.width / n)
14
+ } : t?.height ? {
15
+ width: r(t.height * n),
16
+ height: r(t.height)
17
+ } : {
18
+ width: r(e.sw),
19
+ height: r(e.sh)
20
+ };
21
+ }
22
+ //#endregion
23
+ export { e as t };
@@ -0,0 +1,4 @@
1
+ //#region src/i18n/messages/const.ts
2
+ var e = "grMedia", t = { en: { [e]: async () => import("./en-BugobSAO.js").then((e) => e.n) } }, n = { es: { [e]: async () => import("./es-B7iA-ExH.js").then((e) => e.n) } }, r = { ru: { [e]: async () => import("./ru-DpiW6Vax.js").then((e) => e.n) } };
3
+ //#endregion
4
+ export { e as i, n, t as r, r as t };
@@ -2,8 +2,9 @@ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
2
  //#region src/i18n/locales/ru.json
3
3
  var t = /* @__PURE__ */ e({
4
4
  camera: () => r,
5
- default: () => i,
6
- imageCrop: () => n
5
+ default: () => a,
6
+ imageCrop: () => n,
7
+ scanner: () => i
7
8
  }), n = {
8
9
  label: "Кадрирование изображения",
9
10
  frame: "Кадр: стрелки двигают изображение, плюс и минус меняют увеличение",
@@ -25,8 +26,15 @@ var t = /* @__PURE__ */ e({
25
26
  live: "Камера включена",
26
27
  captured: "Снимок сделан"
27
28
  }, i = {
29
+ label: "Сканер кодов",
30
+ start: "Начать сканирование",
31
+ stop: "Остановить",
32
+ unsupported: "Этот браузер не умеет читать коды. Передайте `detector`, чтобы включить их.",
33
+ detected: "Код распознан"
34
+ }, a = {
28
35
  imageCrop: n,
29
- camera: r
36
+ camera: r,
37
+ scanner: i
30
38
  };
31
39
  //#endregion
32
- export { t as n, i as t };
40
+ export { t as n, a as t };
@@ -0,0 +1,86 @@
1
+ import { computed as e, onBeforeUnmount as t, ref as n, shallowRef as r } from "vue";
2
+ import { useAnnouncer as i } from "@feugene/granularity/composables/useAnnouncer";
3
+ import { useGranularityTranslations as a } from "@feugene/granularity/composables/useGranularityTranslations";
4
+ //#region src/components/GrCameraCapture/cameraState.ts
5
+ function o(e) {
6
+ switch (e instanceof Error ? e.name : "") {
7
+ case "NotAllowedError":
8
+ case "SecurityError":
9
+ case "PermissionDeniedError": return "denied";
10
+ case "NotFoundError":
11
+ case "DevicesNotFoundError":
12
+ case "OverconstrainedError": return "missing";
13
+ case "NotReadableError":
14
+ case "TrackStartError":
15
+ case "AbortError": return "busy";
16
+ default: return "error";
17
+ }
18
+ }
19
+ function s(e) {
20
+ return typeof e?.mediaDevices?.getUserMedia == "function";
21
+ }
22
+ function c(e, t) {
23
+ return t ?? e === "user";
24
+ }
25
+ //#endregion
26
+ //#region src/internal/useCameraStream.ts
27
+ function l(c) {
28
+ let { t: l } = a(), { announce: u } = i(), d = r(null), f = n("idle"), p = n(null), m = e(() => f.value === "live"), h = e(() => p.value ?? 4 / 3), g = e(() => {
29
+ switch (f.value) {
30
+ case "starting": return l("grMedia.camera.starting", "Requesting camera access…");
31
+ case "denied": return l("grMedia.camera.denied", "Camera access is blocked. Allow it in the browser settings for this site.");
32
+ case "missing": return l("grMedia.camera.missing", "No camera found on this device.");
33
+ case "busy": return l("grMedia.camera.busy", "The camera is busy in another application.");
34
+ case "insecure": return l("grMedia.camera.insecure", "The camera works only over HTTPS.");
35
+ case "error": return l("grMedia.camera.error", "The camera could not be started.");
36
+ default: return l("grMedia.camera.idle", "The camera is off.");
37
+ }
38
+ });
39
+ function _(e) {
40
+ f.value !== e && (f.value = e, c.onStatus?.(e));
41
+ }
42
+ function v() {
43
+ let e = c.video.value;
44
+ !e || e.videoWidth <= 0 || e.videoHeight <= 0 || (p.value = e.videoWidth / e.videoHeight);
45
+ }
46
+ function y() {
47
+ d.value?.getTracks().forEach((e) => e.stop()), d.value = null, p.value = null, c.video.value && (c.video.value.srcObject = null);
48
+ }
49
+ async function b() {
50
+ if (!(c.disabled() || f.value === "starting" || f.value === "live")) {
51
+ if (!s(navigator)) {
52
+ _("insecure");
53
+ return;
54
+ }
55
+ _("starting");
56
+ try {
57
+ let e = c.aspectRatio?.(), t = await navigator.mediaDevices.getUserMedia({
58
+ video: {
59
+ ...c.deviceId() ? { deviceId: { exact: c.deviceId() } } : { facingMode: c.facing() },
60
+ ...e ? { aspectRatio: e } : {}
61
+ },
62
+ audio: !1
63
+ });
64
+ d.value = t;
65
+ let n = c.video.value;
66
+ n && (n.srcObject = t, n.addEventListener("loadedmetadata", v, { once: !0 }), await n.play().catch(() => void 0), v()), _("live"), c.onStart?.(), u(l("grMedia.camera.live", "Camera is on"));
67
+ } catch (e) {
68
+ y(), _(o(e)), u(g.value, { politeness: "assertive" });
69
+ }
70
+ }
71
+ }
72
+ function x() {
73
+ d.value && (y(), _("idle"), c.onStop?.());
74
+ }
75
+ return t(y), {
76
+ status: f,
77
+ streamRatio: p,
78
+ frameRatio: h,
79
+ isLive: m,
80
+ message: g,
81
+ start: b,
82
+ stop: x
83
+ };
84
+ }
85
+ //#endregion
86
+ export { c as i, o as n, s as r, l as t };
@@ -0,0 +1,134 @@
1
+ import { t as e } from "../../../chunks/outputSize-D2FU4CbB.js";
2
+ import { i as t, t as n } from "../../../chunks/useCameraStream-CPdm3r90.js";
3
+ import { a as r, c as i, l as a, n as o, o as s, r as c, s as l, u } from "../../../chunks/config-DHLlFslI.js";
4
+ import { computed as d, createBlock as f, createCommentVNode as p, createElementBlock as m, createElementVNode as h, createTextVNode as g, createVNode as _, defineComponent as v, normalizeClass as y, normalizeStyle as b, onMounted as x, openBlock as S, ref as C, renderSlot as w, toDisplayString as T, unref as E, withCtx as D } from "vue";
5
+ import O from "@feugene/granularity/components/GrButton";
6
+ import { useAnnouncer as k } from "@feugene/granularity/composables/useAnnouncer";
7
+ import { useGrComponentSize as A } from "@feugene/granularity/composables/useGrComponentConfig";
8
+ import { useGranularityTranslations as j } from "@feugene/granularity/composables/useGranularityTranslations";
9
+ //#region src/components/GrCameraCapture/GrCameraCapture.vue?vue&type=script&setup=true&lang.ts
10
+ var M = ["aria-label"], N = /* @__PURE__ */ v({
11
+ __name: "GrCameraCapture",
12
+ props: {
13
+ facing: { default: "user" },
14
+ deviceId: { default: void 0 },
15
+ aspectRatio: { default: void 0 },
16
+ autoStart: {
17
+ type: Boolean,
18
+ default: !1
19
+ },
20
+ mirror: {
21
+ type: Boolean,
22
+ default: void 0
23
+ },
24
+ output: { default: void 0 },
25
+ size: { default: void 0 },
26
+ disabled: {
27
+ type: Boolean,
28
+ default: !1
29
+ },
30
+ ariaLabel: { default: void 0 }
31
+ },
32
+ emits: [
33
+ "capture",
34
+ "start",
35
+ "stop",
36
+ "statusChange"
37
+ ],
38
+ setup(v, { expose: N, emit: P }) {
39
+ let F = v, I = P, { t: L } = j(), { announce: R } = k(), z = A(() => F.size, { component: "GrCameraCapture" }), B = C(null), { frameRatio: V, isLive: H, message: U, start: W, status: G, stop: K } = n({
40
+ video: B,
41
+ disabled: () => F.disabled,
42
+ facing: () => F.facing,
43
+ deviceId: () => F.deviceId,
44
+ aspectRatio: () => F.aspectRatio,
45
+ onStatus: (e) => I("statusChange", e),
46
+ onStart: () => I("start"),
47
+ onStop: () => I("stop")
48
+ }), q = d(() => t(F.facing, F.mirror));
49
+ async function J() {
50
+ let t = B.value;
51
+ if (!t || !H.value) return null;
52
+ let n = {
53
+ sx: 0,
54
+ sy: 0,
55
+ sw: t.videoWidth,
56
+ sh: t.videoHeight
57
+ };
58
+ if (n.sw <= 0) return null;
59
+ let r = document.createElement("canvas"), i = e(n, F.output);
60
+ r.width = i.width, r.height = i.height;
61
+ let a = r.getContext("2d");
62
+ if (!a) return null;
63
+ a.drawImage(t, n.sx, n.sy, n.sw, n.sh, 0, 0, r.width, r.height);
64
+ let o = await new Promise((e) => {
65
+ r.toBlob(e, F.output?.type ?? "image/jpeg", F.output?.quality ?? .92);
66
+ });
67
+ return o && (I("capture", o), R(L("grMedia.camera.captured", "Photo taken"))), o;
68
+ }
69
+ return x(() => {
70
+ F.autoStart && W();
71
+ }), N({
72
+ start: W,
73
+ stop: K,
74
+ capture: J,
75
+ status: G
76
+ }), (e, t) => (S(), m("div", {
77
+ class: y(E(s)),
78
+ role: "group",
79
+ "aria-label": v.ariaLabel ?? E(L)("grMedia.camera.label", "Camera")
80
+ }, [h("div", {
81
+ class: y(E(c)),
82
+ style: b({ aspectRatio: String(E(V)) })
83
+ }, [h("video", {
84
+ ref_key: "videoEl",
85
+ ref: B,
86
+ class: y([E(u), q.value ? E(r) : ""]),
87
+ playsinline: "",
88
+ muted: "",
89
+ autoplay: ""
90
+ }, null, 2), E(H) ? p("", !0) : (S(), m("div", {
91
+ key: 0,
92
+ class: y(E(i))
93
+ }, [h("p", { class: y([E(a), E(l)[E(z)]]) }, T(E(U)), 3), E(G) !== "starting" && E(G) !== "insecure" && E(G) !== "missing" ? (S(), f(E(O), {
94
+ key: 0,
95
+ size: E(z),
96
+ disabled: v.disabled,
97
+ onClick: E(W)
98
+ }, {
99
+ default: D(() => [g(T(E(G) === "idle" ? E(L)("grMedia.camera.start", "Turn on camera") : E(L)("grMedia.camera.retry", "Try again")), 1)]),
100
+ _: 1
101
+ }, 8, [
102
+ "size",
103
+ "disabled",
104
+ "onClick"
105
+ ])) : p("", !0)], 2))], 6), h("div", { class: y(E(o)) }, [w(e.$slots, "controls", {
106
+ status: E(G),
107
+ start: E(W),
108
+ stop: E(K),
109
+ capture: J
110
+ }, () => [_(E(O), {
111
+ size: E(z),
112
+ disabled: v.disabled || !E(H),
113
+ onClick: J
114
+ }, {
115
+ default: D(() => [g(T(E(L)("grMedia.camera.capture", "Take photo")), 1)]),
116
+ _: 1
117
+ }, 8, ["size", "disabled"]), E(H) ? (S(), f(E(O), {
118
+ key: 0,
119
+ variant: "outline",
120
+ size: E(z),
121
+ disabled: v.disabled,
122
+ onClick: E(K)
123
+ }, {
124
+ default: D(() => [g(T(E(L)("grMedia.camera.stop", "Turn off")), 1)]),
125
+ _: 1
126
+ }, 8, [
127
+ "size",
128
+ "disabled",
129
+ "onClick"
130
+ ])) : p("", !0)])], 2)], 10, M));
131
+ }
132
+ });
133
+ //#endregion
134
+ export { N as t };
@@ -1,3 +1,4 @@
1
- import { a as e, i as t, n, r, t as i } from "./chunks/GrCameraCapture-B9EPXm7r.js";
2
- import { i as a, t as o } from "../../chunks/config-CZ4ZDG0_.js";
3
- export { i as GrCameraCapture, i as default, n as cameraFrameRect, r as cameraStatusFromError, t as cameraSupported, o as grCameraCaptureConfig, a as grCameraCaptureSafelist, e as shouldMirrorPreview };
1
+ import { i as e, n as t, r as n } from "../../chunks/useCameraStream-CPdm3r90.js";
2
+ import { i as r, t as i } from "../../chunks/config-DHLlFslI.js";
3
+ import { t as a } from "./chunks/GrCameraCapture-t-uFTD9s.js";
4
+ export { a as GrCameraCapture, a as default, t as cameraStatusFromError, n as cameraSupported, i as grCameraCaptureConfig, r as grCameraCaptureSafelist, e as shouldMirrorPreview };
@@ -0,0 +1,162 @@
1
+ import { t as e } from "../../../chunks/useCameraStream-CPdm3r90.js";
2
+ import { a as t, c as n, l as r, n as ee, o as i, r as a, s as o, u as te } from "../../../chunks/config-DfJkKtIh.js";
3
+ import { computed as s, createBlock as c, createCommentVNode as l, createElementBlock as u, createElementVNode as d, createTextVNode as f, defineComponent as p, normalizeClass as m, normalizeStyle as h, onBeforeUnmount as g, onMounted as ne, openBlock as _, ref as v, renderSlot as y, shallowRef as b, toDisplayString as x, unref as S, withCtx as C } from "vue";
4
+ import w from "@feugene/granularity/components/GrButton";
5
+ import { useAnnouncer as T } from "@feugene/granularity/composables/useAnnouncer";
6
+ import { useGrComponentSize as E } from "@feugene/granularity/composables/useGrComponentConfig";
7
+ import { useGranularityTranslations as D } from "@feugene/granularity/composables/useGranularityTranslations";
8
+ //#region src/components/GrCodeScanner/codeDetection.ts
9
+ function O(e = globalThis) {
10
+ return typeof e.BarcodeDetector == "function";
11
+ }
12
+ function k(e, t = globalThis) {
13
+ if (!O(t)) return null;
14
+ let n = t.BarcodeDetector, r = new n(e ? { formats: [...e] } : void 0);
15
+ return async (e) => (await r.detect(e)).map((e) => ({
16
+ value: e.rawValue,
17
+ format: e.format
18
+ }));
19
+ }
20
+ function A(e, t, n) {
21
+ if (n) return [...t];
22
+ let r = new Set(e.map((e) => `${e.format}:${e.value}`));
23
+ return t.filter((e) => !r.has(`${e.format}:${e.value}`));
24
+ }
25
+ //#endregion
26
+ //#region src/components/GrCodeScanner/GrCodeScanner.vue?vue&type=script&setup=true&lang.ts
27
+ var j = ["aria-label"], M = /* @__PURE__ */ p({
28
+ __name: "GrCodeScanner",
29
+ props: {
30
+ facing: { default: "environment" },
31
+ deviceId: { default: void 0 },
32
+ autoStart: {
33
+ type: Boolean,
34
+ default: !1
35
+ },
36
+ formats: { default: void 0 },
37
+ detector: {
38
+ type: Function,
39
+ default: void 0
40
+ },
41
+ interval: { default: 250 },
42
+ continuous: {
43
+ type: Boolean,
44
+ default: !1
45
+ },
46
+ size: { default: void 0 },
47
+ disabled: {
48
+ type: Boolean,
49
+ default: !1
50
+ },
51
+ ariaLabel: { default: void 0 }
52
+ },
53
+ emits: [
54
+ "detect",
55
+ "start",
56
+ "stop",
57
+ "statusChange"
58
+ ],
59
+ setup(p, { expose: M, emit: re }) {
60
+ let N = p, P = re, { t: F } = D(), { announce: I } = T(), L = E(() => N.size, { component: "GrCodeScanner" }), R = v(null), z = b(null), B = b([]), { frameRatio: V, isLive: H, message: U, start: W, status: G, stop: K } = e({
61
+ video: R,
62
+ disabled: () => N.disabled,
63
+ facing: () => N.facing,
64
+ deviceId: () => N.deviceId,
65
+ onStatus: (e) => P("statusChange", e),
66
+ onStart: () => {
67
+ B.value = [], ae(), P("start");
68
+ },
69
+ onStop: () => P("stop")
70
+ }), q = s(() => !N.detector && !O()), J = s(() => q.value ? F("grMedia.scanner.unsupported", "This browser cannot read codes. Pass a `detector` to enable it.") : U.value);
71
+ function Y() {
72
+ return N.detector ?? k(N.formats);
73
+ }
74
+ let X = null, Z = !1;
75
+ async function ie() {
76
+ let e = R.value;
77
+ if (!(!e || !H.value || N.disabled) && (z.value ??= Y(), z.value)) try {
78
+ let t = await z.value(e), n = A(B.value, t, N.continuous);
79
+ B.value = t, n.length > 0 && (P("detect", n), I(F("grMedia.scanner.detected", "Code recognised")));
80
+ } catch {}
81
+ }
82
+ function ae() {
83
+ if (Z) return;
84
+ Z = !0;
85
+ let e = async () => {
86
+ if (Z) {
87
+ if (await ie(), !Z || !H.value) {
88
+ X = null, Z = !1;
89
+ return;
90
+ }
91
+ X = setTimeout(() => void e(), N.interval);
92
+ }
93
+ };
94
+ X = setTimeout(() => void e(), N.interval);
95
+ }
96
+ function Q() {
97
+ Z = !1, X !== null && (clearTimeout(X), X = null);
98
+ }
99
+ ne(() => {
100
+ N.autoStart && W();
101
+ }), g(Q);
102
+ function $() {
103
+ Q(), K();
104
+ }
105
+ return M({
106
+ start: W,
107
+ stop: $,
108
+ status: G
109
+ }), (e, s) => (_(), u("div", {
110
+ class: m(S(i)),
111
+ role: "group",
112
+ "aria-label": p.ariaLabel ?? S(F)("grMedia.scanner.label", "Code scanner")
113
+ }, [d("div", {
114
+ class: m(S(a)),
115
+ style: h({ aspectRatio: String(S(V)) })
116
+ }, [
117
+ d("video", {
118
+ ref_key: "videoEl",
119
+ ref: R,
120
+ class: m(S(te)),
121
+ playsinline: "",
122
+ muted: "",
123
+ autoplay: ""
124
+ }, null, 2),
125
+ S(H) && !q.value ? (_(), u("div", {
126
+ key: 0,
127
+ class: m(S(t))
128
+ }, null, 2)) : l("", !0),
129
+ !S(H) || q.value ? (_(), u("div", {
130
+ key: 1,
131
+ class: m(S(n))
132
+ }, [d("p", { class: m([S(r), S(o)[S(L)]]) }, x(J.value), 3), !q.value && S(G) !== "starting" && S(G) !== "insecure" && S(G) !== "missing" ? (_(), c(S(w), {
133
+ key: 0,
134
+ size: S(L),
135
+ disabled: p.disabled,
136
+ onClick: S(W)
137
+ }, {
138
+ default: C(() => [f(x(S(G) === "idle" ? S(F)("grMedia.scanner.start", "Start scanning") : S(F)("grMedia.camera.retry", "Try again")), 1)]),
139
+ _: 1
140
+ }, 8, [
141
+ "size",
142
+ "disabled",
143
+ "onClick"
144
+ ])) : l("", !0)], 2)) : l("", !0)
145
+ ], 6), d("div", { class: m(S(ee)) }, [y(e.$slots, "controls", {
146
+ status: S(G),
147
+ start: S(W),
148
+ stop: $
149
+ }, () => [S(H) ? (_(), c(S(w), {
150
+ key: 0,
151
+ variant: "outline",
152
+ size: S(L),
153
+ disabled: p.disabled,
154
+ onClick: $
155
+ }, {
156
+ default: C(() => [f(x(S(F)("grMedia.scanner.stop", "Stop")), 1)]),
157
+ _: 1
158
+ }, 8, ["size", "disabled"])) : l("", !0)])], 2)], 10, j));
159
+ }
160
+ });
161
+ //#endregion
162
+ export { O as i, k as n, A as r, M as t };
@@ -0,0 +1,3 @@
1
+ import { i as e, n as t, r as n, t as r } from "./chunks/GrCodeScanner-BX147Gct.js";
2
+ import { i, t as a } from "../../chunks/config-DfJkKtIh.js";
3
+ export { r as GrCodeScanner, r as default, t as createNativeDetector, n as freshCodes, a as grCodeScannerConfig, i as grCodeScannerSafelist, e as nativeDetectorSupported };