@feugene/granularity-media 0.1.0 → 0.2.1

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 (38) hide show
  1. package/README.md +27 -4
  2. package/dist/chunks/classTokens-bAzTjLuQ.js +6 -0
  3. package/dist/chunks/{config-CrV_FDnM.js → config-Be_Mh801.js} +13 -17
  4. package/dist/chunks/config-CZ4ZDG0_.js +27 -0
  5. package/dist/chunks/en-C-Wc5fTB.js +32 -0
  6. package/dist/chunks/es-BUPtE9_0.js +32 -0
  7. package/dist/chunks/ru-BqNILj54.js +32 -0
  8. package/dist/chunks/ru-DN_wJDkP.js +4 -0
  9. package/dist/components/GrCameraCapture/chunks/GrCameraCapture-B9EPXm7r.js +201 -0
  10. package/dist/components/GrCameraCapture/index.js +3 -0
  11. package/dist/components/GrImageCrop/chunks/{GrImageCrop-DYM2vZHV.js → GrImageCrop-Fo2qrX2n.js} +8 -8
  12. package/dist/components/GrImageCrop/index.js +2 -2
  13. package/dist/granular-provider.js +15 -11
  14. package/dist/i18n/all.js +1 -1
  15. package/dist/i18n/index.js +4 -4
  16. package/dist/index.js +5 -3
  17. package/dist/resolver.js +1 -1
  18. package/dist/types/componentNames.d.ts +1 -1
  19. package/dist/types/components/GrCameraCapture/GrCameraCapture.vue.d.ts +131 -0
  20. package/dist/types/components/GrCameraCapture/__tests__/GrCameraCapture.test.d.ts +1 -0
  21. package/dist/types/components/GrCameraCapture/__tests__/cameraState.test.d.ts +1 -0
  22. package/dist/types/components/GrCameraCapture/cameraState.d.ts +67 -0
  23. package/dist/types/components/GrCameraCapture/config.d.ts +6 -0
  24. package/dist/types/components/GrCameraCapture/defaults.d.ts +16 -0
  25. package/dist/types/components/GrCameraCapture/grCameraCaptureStyles.d.ts +21 -0
  26. package/dist/types/components/GrCameraCapture/index.d.ts +9 -0
  27. package/dist/types/components/GrImageCrop/GrImageCrop.vue.d.ts +6 -6
  28. package/dist/types/granular-provider/shared.d.ts +1 -0
  29. package/dist/types/i18n/index.d.ts +48 -0
  30. package/dist/types/i18n/messages/en.d.ts +32 -0
  31. package/dist/types/i18n/messages/es.d.ts +32 -0
  32. package/dist/types/i18n/messages/ru.d.ts +32 -0
  33. package/dist/types/index.d.ts +1 -0
  34. package/package.json +5 -1
  35. package/dist/chunks/en-BrjpU7lq.js +0 -13
  36. package/dist/chunks/es-BdTkuOLs.js +0 -13
  37. package/dist/chunks/ru-ByR24Aqk.js +0 -13
  38. package/dist/chunks/ru-C4IsSzR5.js +0 -4
package/README.md CHANGED
@@ -1,7 +1,9 @@
1
1
  # `@feugene/granularity-media`
2
2
 
3
- Работа с изображением и камерой для `@feugene/granularity`. Первый компонент
4
- `GrImageCrop`: пользователь выбирает кадр, приложение получает готовый `Blob`.
3
+ Работа с изображением и камерой для `@feugene/granularity`. Два компонента, и они
4
+ стоят рядом по сценарию: `GrCameraCapture` снимает кадр камерой,
5
+ `GrImageCrop` выбирает кадр из уже существующей картинки. Оба отдают готовый
6
+ `Blob` — можно сразу отправлять.
5
7
 
6
8
  ```bash
7
9
  yarn add @feugene/granularity-media
@@ -29,7 +31,9 @@ async function save() {
29
31
 
30
32
  <template>
31
33
  <GrImageCrop ref="cropper" :src="file" shape="circle" :output="{ width: 256, height: 256 }" />
32
- <button @click="save">Сохранить</button>
34
+ <button @click="save">
35
+ Сохранить
36
+ </button>
33
37
  </template>
34
38
  ```
35
39
 
@@ -73,8 +77,27 @@ presetGranularNode({
73
77
  Локали подключаются тем же `createFintI18n`, что и словари ядра — блок
74
78
  `GR_MEDIA_I18N_BLOCK`.
75
79
 
80
+ ## Снимок камерой
81
+
82
+ ```vue
83
+ <GrCameraCapture :aspect-ratio="1" @capture="blob => upload(blob)" />
84
+ ```
85
+
86
+ Камера включается только по кнопке: запрос разрешения, всплывший сам по себе,
87
+ отклоняют не глядя — а второй раз браузер уже не спросит, потому что решение
88
+ запоминается для сайта целиком.
89
+
90
+ Отказ разведён на четыре состояния (`denied`, `missing`, `busy`, `insecure`),
91
+ потому что действия пользователя в них разные: «разрешите доступ» при
92
+ отсутствующей камере отправляет искать настройку, которой нет, а на `http://`
93
+ объекта `navigator.mediaDevices` не существует вовсе.
94
+
95
+ Превью фронтальной камеры зеркальное, снимок — нет: иначе текст на визитке или в
96
+ документе уехал бы в зазеркалье.
97
+
76
98
  ## Документация
77
99
 
78
100
  - [`docs/components.md`](./docs/components.md) — состав пакета;
79
- - [`docs/components/GrImageCrop.md`](./docs/components/GrImageCrop.md) — страница компонента;
101
+ - [`docs/components/GrImageCrop.md`](./docs/components/GrImageCrop.md) и
102
+ [`docs/components/GrCameraCapture.md`](./docs/components/GrCameraCapture.md) — страницы компонентов;
80
103
  - [`docs/keyboard.md`](./docs/keyboard.md), [`docs/ssr.md`](./docs/ssr.md) — сквозные правила пакета.
@@ -0,0 +1,6 @@
1
+ //#region src/internal/classTokens.ts
2
+ function e(e) {
3
+ return e.split(/\s+/).filter(Boolean);
4
+ }
5
+ //#endregion
6
+ export { e as t };
@@ -1,9 +1,5 @@
1
- import { defineGranularComponent as e } from "@feugene/unocss-preset-granular/contract";
2
- //#region src/internal/classTokens.ts
3
- function t(e) {
4
- return e.split(/\s+/).filter(Boolean);
5
- }
6
- //#endregion
1
+ import { t as e } from "./classTokens-bAzTjLuQ.js";
2
+ import { defineGranularComponent as t } from "@feugene/unocss-preset-granular/contract";
7
3
  //#region src/components/GrImageCrop/grImageCropStyles.ts
8
4
  var n = "grid gap-2", r = "relative w-full select-none overflow-hidden rounded-[var(--gr-radius-md)] border border-[var(--gr-brd)] bg-[var(--gr-muted)] touch-none focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--gr-ring)]", i = "pointer-events-none absolute left-1/2 top-1/2 max-w-none origin-center", a = "pointer-events-none absolute inset-0 m-auto aspect-square rounded-[var(--gr-radius-full)] border border-[var(--gr-image-crop-guide,var(--gr-brd))] shadow-[0_0_0_9999px_var(--gr-image-crop-mask,rgb(0_0_0/0.55))]", o = "pointer-events-none absolute inset-0 border border-[var(--gr-image-crop-guide,var(--gr-brd))]", s = "transition-transform duration-[var(--gr-duration-fast)] ease-[var(--gr-ease-out)]", c = "flex items-center gap-3", l = "flex items-center justify-center text-[var(--gr-muted-fg)]", u = {
9
5
  xs: "text-[length:var(--gr-control-text-xs)] leading-[var(--gr-control-leading-xs)]",
@@ -16,17 +12,17 @@ var n = "grid gap-2", r = "relative w-full select-none overflow-hidden rounded-[
16
12
  md: "min-h-48",
17
13
  lg: "min-h-56"
18
14
  }, f = [
19
- ...t(n),
20
- ...t(r),
21
- ...t(i),
22
- ...t(s),
23
- ...t(a),
24
- ...t(o),
25
- ...t(c),
26
- ...t(l),
27
- ...Object.values(u).flatMap(t),
28
- ...Object.values(d).flatMap(t)
29
- ], p = e(import.meta.url, {
15
+ ...e(n),
16
+ ...e(r),
17
+ ...e(i),
18
+ ...e(s),
19
+ ...e(a),
20
+ ...e(o),
21
+ ...e(c),
22
+ ...e(l),
23
+ ...Object.values(u).flatMap(e),
24
+ ...Object.values(d).flatMap(e)
25
+ ], p = t(import.meta.url, {
30
26
  name: "GrImageCrop",
31
27
  safelist: f,
32
28
  dependencies: [{
@@ -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/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 = {
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: "GrCameraCapture",
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 };
@@ -0,0 +1,32 @@
1
+ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
+ //#region src/i18n/locales/en.json
3
+ var t = /* @__PURE__ */ e({
4
+ camera: () => r,
5
+ default: () => i,
6
+ imageCrop: () => n
7
+ }), n = {
8
+ label: "Image crop",
9
+ frame: "Frame: arrow keys move the image, plus and minus zoom",
10
+ empty: "No image selected",
11
+ zoom: "Zoom"
12
+ }, r = {
13
+ label: "Camera",
14
+ idle: "The camera is off.",
15
+ starting: "Requesting camera access…",
16
+ denied: "Camera access is blocked. Allow it in the browser settings for this site.",
17
+ missing: "No camera found on this device.",
18
+ busy: "The camera is busy in another application.",
19
+ insecure: "The camera works only over HTTPS.",
20
+ error: "The camera could not be started.",
21
+ start: "Turn on camera",
22
+ retry: "Try again",
23
+ capture: "Take photo",
24
+ stop: "Turn off",
25
+ live: "Camera is on",
26
+ captured: "Photo taken"
27
+ }, i = {
28
+ imageCrop: n,
29
+ camera: r
30
+ };
31
+ //#endregion
32
+ export { t as n, i as t };
@@ -0,0 +1,32 @@
1
+ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
+ //#region src/i18n/locales/es.json
3
+ var t = /* @__PURE__ */ e({
4
+ camera: () => r,
5
+ default: () => i,
6
+ imageCrop: () => n
7
+ }), n = {
8
+ label: "Recorte de imagen",
9
+ frame: "Marco: las flechas mueven la imagen, más y menos ajustan el zoom",
10
+ empty: "Ninguna imagen seleccionada",
11
+ zoom: "Zoom"
12
+ }, r = {
13
+ label: "Cámara",
14
+ idle: "La cámara está apagada.",
15
+ starting: "Solicitando acceso a la cámara…",
16
+ denied: "El acceso a la cámara está bloqueado. Permítelo en la configuración del navegador para este sitio.",
17
+ missing: "No se encontró ninguna cámara en este dispositivo.",
18
+ busy: "La cámara está ocupada por otra aplicación.",
19
+ insecure: "La cámara solo funciona por HTTPS.",
20
+ error: "No se pudo iniciar la cámara.",
21
+ start: "Encender cámara",
22
+ retry: "Reintentar",
23
+ capture: "Tomar foto",
24
+ stop: "Apagar",
25
+ live: "Cámara encendida",
26
+ captured: "Foto tomada"
27
+ }, i = {
28
+ imageCrop: n,
29
+ camera: r
30
+ };
31
+ //#endregion
32
+ export { t as n, i as t };
@@ -0,0 +1,32 @@
1
+ import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
+ //#region src/i18n/locales/ru.json
3
+ var t = /* @__PURE__ */ e({
4
+ camera: () => r,
5
+ default: () => i,
6
+ imageCrop: () => n
7
+ }), n = {
8
+ label: "Кадрирование изображения",
9
+ frame: "Кадр: стрелки двигают изображение, плюс и минус меняют увеличение",
10
+ empty: "Изображение не выбрано",
11
+ zoom: "Увеличение"
12
+ }, r = {
13
+ label: "Камера",
14
+ idle: "Камера выключена.",
15
+ starting: "Запрашиваем доступ к камере…",
16
+ denied: "Доступ к камере запрещён. Разрешите его в настройках браузера для этого сайта.",
17
+ missing: "Камера на устройстве не найдена.",
18
+ busy: "Камера занята другим приложением.",
19
+ insecure: "Камера работает только по HTTPS.",
20
+ error: "Не удалось включить камеру.",
21
+ start: "Включить камеру",
22
+ retry: "Повторить",
23
+ capture: "Сделать снимок",
24
+ stop: "Выключить",
25
+ live: "Камера включена",
26
+ captured: "Снимок сделан"
27
+ }, i = {
28
+ imageCrop: n,
29
+ camera: r
30
+ };
31
+ //#endregion
32
+ export { t as n, i as t };
@@ -0,0 +1,4 @@
1
+ //#region src/i18n/messages/const.ts
2
+ var e = "grMedia", t = { en: { [e]: async () => import("./en-C-Wc5fTB.js").then((e) => e.n) } }, n = { es: { [e]: async () => import("./es-BUPtE9_0.js").then((e) => e.n) } }, r = { ru: { [e]: async () => import("./ru-BqNILj54.js").then((e) => e.n) } };
3
+ //#endregion
4
+ export { e as i, n, t as r, r as t };
@@ -0,0 +1,201 @@
1
+ import { a as e, c as t, l as n, n as r, o as i, r as a, s as o, u as s } from "../../../chunks/config-CZ4ZDG0_.js";
2
+ import { computed as c, createBlock as l, createCommentVNode as u, createElementBlock as d, createElementVNode as f, createTextVNode as p, createVNode as m, defineComponent as h, normalizeClass as g, normalizeStyle as _, onBeforeUnmount as v, onMounted as y, openBlock as b, ref as x, renderSlot as S, shallowRef as C, toDisplayString as w, unref as T, withCtx as E } from "vue";
3
+ import D from "@feugene/granularity/components/GrButton";
4
+ import { useAnnouncer as ee } from "@feugene/granularity/composables/useAnnouncer";
5
+ import { useGrComponentSize as te } from "@feugene/granularity/composables/useGrComponentConfig";
6
+ import { useGranularityTranslations as ne } from "@feugene/granularity/composables/useGranularityTranslations";
7
+ //#region src/components/GrCameraCapture/cameraState.ts
8
+ function O(e) {
9
+ switch (e instanceof Error ? e.name : "") {
10
+ case "NotAllowedError":
11
+ case "SecurityError":
12
+ case "PermissionDeniedError": return "denied";
13
+ case "NotFoundError":
14
+ case "DevicesNotFoundError":
15
+ case "OverconstrainedError": return "missing";
16
+ case "NotReadableError":
17
+ case "TrackStartError":
18
+ case "AbortError": return "busy";
19
+ default: return "error";
20
+ }
21
+ }
22
+ function k(e) {
23
+ return typeof e?.mediaDevices?.getUserMedia == "function";
24
+ }
25
+ function A(e, t) {
26
+ return t ?? e === "user";
27
+ }
28
+ function j(e, t) {
29
+ let n = t > 0 ? t : 1;
30
+ if (e.width <= 0 || e.height <= 0) return {
31
+ sx: 0,
32
+ sy: 0,
33
+ sw: 0,
34
+ sh: 0
35
+ };
36
+ if (e.width / e.height > n) {
37
+ let t = e.height * n;
38
+ return {
39
+ sx: (e.width - t) / 2,
40
+ sy: 0,
41
+ sw: t,
42
+ sh: e.height
43
+ };
44
+ }
45
+ let r = e.width / n;
46
+ return {
47
+ sx: 0,
48
+ sy: (e.height - r) / 2,
49
+ sw: e.width,
50
+ sh: r
51
+ };
52
+ }
53
+ //#endregion
54
+ //#region src/components/GrCameraCapture/GrCameraCapture.vue?vue&type=script&setup=true&lang.ts
55
+ var M = ["aria-label"], N = /* @__PURE__ */ h({
56
+ __name: "GrCameraCapture",
57
+ props: {
58
+ facing: { default: "user" },
59
+ deviceId: { default: void 0 },
60
+ aspectRatio: { default: void 0 },
61
+ autoStart: {
62
+ type: Boolean,
63
+ default: !1
64
+ },
65
+ mirror: {
66
+ type: Boolean,
67
+ default: void 0
68
+ },
69
+ output: { default: void 0 },
70
+ size: { default: void 0 },
71
+ disabled: {
72
+ type: Boolean,
73
+ default: !1
74
+ },
75
+ ariaLabel: { default: void 0 }
76
+ },
77
+ emits: [
78
+ "capture",
79
+ "start",
80
+ "stop",
81
+ "statusChange"
82
+ ],
83
+ setup(h, { expose: N, emit: P }) {
84
+ let F = h, I = P, { t: L } = ne(), { announce: R } = ee(), z = te(() => F.size, { component: "GrCameraCapture" }), B = x(null), V = C(null), H = x("idle"), U = x(null), W = c(() => F.aspectRatio ?? U.value ?? 4 / 3), G = c(() => A(F.facing, F.mirror)), K = c(() => H.value === "live"), q = c(() => {
85
+ switch (H.value) {
86
+ case "starting": return L("grMedia.camera.starting", "Requesting camera access…");
87
+ case "denied": return L("grMedia.camera.denied", "Camera access is blocked. Allow it in the browser settings for this site.");
88
+ case "missing": return L("grMedia.camera.missing", "No camera found on this device.");
89
+ case "busy": return L("grMedia.camera.busy", "The camera is busy in another application.");
90
+ case "insecure": return L("grMedia.camera.insecure", "The camera works only over HTTPS.");
91
+ case "error": return L("grMedia.camera.error", "The camera could not be started.");
92
+ default: return L("grMedia.camera.idle", "The camera is off.");
93
+ }
94
+ });
95
+ function J(e) {
96
+ H.value !== e && (H.value = e, I("statusChange", e));
97
+ }
98
+ function Y() {
99
+ let e = B.value;
100
+ !e || e.videoWidth <= 0 || e.videoHeight <= 0 || (U.value = e.videoWidth / e.videoHeight);
101
+ }
102
+ function X() {
103
+ V.value?.getTracks().forEach((e) => e.stop()), V.value = null, U.value = null, B.value && (B.value.srcObject = null);
104
+ }
105
+ async function Z() {
106
+ if (!(F.disabled || H.value === "starting" || H.value === "live")) {
107
+ if (!k(navigator)) {
108
+ J("insecure");
109
+ return;
110
+ }
111
+ J("starting");
112
+ try {
113
+ let e = await navigator.mediaDevices.getUserMedia({
114
+ video: F.deviceId ? { deviceId: { exact: F.deviceId } } : { facingMode: F.facing },
115
+ audio: !1
116
+ });
117
+ V.value = e, B.value && (B.value.srcObject = e, B.value.addEventListener("loadedmetadata", Y, { once: !0 }), await B.value.play().catch(() => void 0), Y()), J("live"), I("start"), R(L("grMedia.camera.live", "Camera is on"));
118
+ } catch (e) {
119
+ X(), J(O(e)), R(q.value, { politeness: "assertive" });
120
+ }
121
+ }
122
+ }
123
+ function Q() {
124
+ V.value && (X(), J("idle"), I("stop"));
125
+ }
126
+ async function $() {
127
+ let e = B.value;
128
+ if (!e || !K.value) return null;
129
+ let t = j({
130
+ width: e.videoWidth,
131
+ height: e.videoHeight
132
+ }, W.value);
133
+ if (t.sw <= 0) return null;
134
+ let n = document.createElement("canvas");
135
+ n.width = Math.max(1, Math.round(F.output?.width ?? t.sw)), n.height = Math.max(1, Math.round(F.output?.height ?? t.sh));
136
+ let r = n.getContext("2d");
137
+ if (!r) return null;
138
+ r.drawImage(e, t.sx, t.sy, t.sw, t.sh, 0, 0, n.width, n.height);
139
+ let i = await new Promise((e) => {
140
+ n.toBlob(e, F.output?.type ?? "image/jpeg", F.output?.quality ?? .92);
141
+ });
142
+ return i && (I("capture", i), R(L("grMedia.camera.captured", "Photo taken"))), i;
143
+ }
144
+ return y(() => {
145
+ F.autoStart && Z();
146
+ }), v(X), N({
147
+ start: Z,
148
+ stop: Q,
149
+ capture: $,
150
+ status: H
151
+ }), (c, v) => (b(), d("div", {
152
+ class: g(T(i)),
153
+ role: "group",
154
+ "aria-label": h.ariaLabel ?? T(L)("grMedia.camera.label", "Camera")
155
+ }, [f("div", {
156
+ class: g(T(a)),
157
+ style: _({ aspectRatio: String(W.value) })
158
+ }, [f("video", {
159
+ ref_key: "videoEl",
160
+ ref: B,
161
+ class: g([T(s), G.value ? T(e) : ""]),
162
+ playsinline: "",
163
+ muted: "",
164
+ autoplay: ""
165
+ }, null, 2), K.value ? u("", !0) : (b(), d("div", {
166
+ key: 0,
167
+ class: g(T(t))
168
+ }, [f("p", { class: g([T(n), T(o)[T(z)]]) }, w(q.value), 3), H.value !== "starting" && H.value !== "insecure" && H.value !== "missing" ? (b(), l(T(D), {
169
+ key: 0,
170
+ size: T(z),
171
+ disabled: h.disabled,
172
+ onClick: Z
173
+ }, {
174
+ default: E(() => [p(w(H.value === "idle" ? T(L)("grMedia.camera.start", "Turn on camera") : T(L)("grMedia.camera.retry", "Try again")), 1)]),
175
+ _: 1
176
+ }, 8, ["size", "disabled"])) : u("", !0)], 2))], 6), f("div", { class: g(T(r)) }, [S(c.$slots, "controls", {
177
+ status: H.value,
178
+ start: Z,
179
+ stop: Q,
180
+ capture: $
181
+ }, () => [m(T(D), {
182
+ size: T(z),
183
+ disabled: h.disabled || !K.value,
184
+ onClick: $
185
+ }, {
186
+ default: E(() => [p(w(T(L)("grMedia.camera.capture", "Take photo")), 1)]),
187
+ _: 1
188
+ }, 8, ["size", "disabled"]), K.value ? (b(), l(T(D), {
189
+ key: 0,
190
+ variant: "outline",
191
+ size: T(z),
192
+ disabled: h.disabled,
193
+ onClick: Q
194
+ }, {
195
+ default: E(() => [p(w(T(L)("grMedia.camera.stop", "Turn off")), 1)]),
196
+ _: 1
197
+ }, 8, ["size", "disabled"])) : u("", !0)])], 2)], 10, M));
198
+ }
199
+ });
200
+ //#endregion
201
+ export { A as a, k as i, j as n, O as r, N as t };
@@ -0,0 +1,3 @@
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,9 +1,9 @@
1
- import { c as e, d as t, f as n, i as r, l as i, n as a, o, r as s, s as c, u as l } from "../../../chunks/config-CrV_FDnM.js";
1
+ import { c as e, d as t, f as n, i as r, l as i, n as a, o, r as s, s as c, u as l } from "../../../chunks/config-Be_Mh801.js";
2
2
  import { Fragment as u, computed as d, createCommentVNode as ee, createElementBlock as f, createElementVNode as p, createVNode as te, defineComponent as m, normalizeClass as h, normalizeStyle as g, onBeforeUnmount as _, onMounted as ne, openBlock as v, ref as y, renderSlot as b, shallowRef as x, toDisplayString as re, unref as S, watch as ie } from "vue";
3
- import ae from "@feugene/granularity/components/GrSlider";
4
- import { useDragGesture as oe } from "@feugene/granularity/composables/useDragGesture";
5
- import { useGrComponentSize as se } from "@feugene/granularity/composables/useGrComponentConfig";
6
- import { useGranularityTranslations as ce } from "@feugene/granularity/composables/useGranularityTranslations";
3
+ import { useGrComponentSize as ae } from "@feugene/granularity/composables/useGrComponentConfig";
4
+ import { useGranularityTranslations as oe } from "@feugene/granularity/composables/useGranularityTranslations";
5
+ import se from "@feugene/granularity/components/GrSlider";
6
+ import { useDragGesture as ce } from "@feugene/granularity/composables/useDragGesture";
7
7
  //#region src/components/GrImageCrop/cropGeometry.ts
8
8
  function C(e, t) {
9
9
  return e.width <= 0 || e.height <= 0 ? 1 : Math.max(t.width / e.width, t.height / e.height);
@@ -80,7 +80,7 @@ var le = ["aria-label"], ue = [
80
80
  "error"
81
81
  ],
82
82
  setup(m, { expose: C, emit: w }) {
83
- let T = m, j = w, { t: M } = ce(), N = se(() => T.size, { component: "GrImageCrop" }), P = y(null), F = x(null), I = y({
83
+ let T = m, j = w, { t: M } = oe(), N = ae(() => T.size, { component: "GrImageCrop" }), P = y(null), F = x(null), I = y({
84
84
  width: 0,
85
85
  height: 0
86
86
  }), L = y(0), R = y({
@@ -123,7 +123,7 @@ var le = ["aria-label"], ue = [
123
123
  }), Y = y({
124
124
  x: 0,
125
125
  y: 0
126
- }), X = oe({
126
+ }), X = ce({
127
127
  disabled: () => T.disabled || !V.value,
128
128
  onStart: (e) => {
129
129
  J.value = {
@@ -249,7 +249,7 @@ var le = ["aria-label"], ue = [
249
249
  }, [b(d.$slots, "controls", {
250
250
  zoom: H.value,
251
251
  setZoom: K
252
- }, () => [te(S(ae), {
252
+ }, () => [te(S(se), {
253
253
  "model-value": H.value,
254
254
  min: 1,
255
255
  max: m.maxZoom,
@@ -1,3 +1,3 @@
1
- import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./chunks/GrImageCrop-DYM2vZHV.js";
2
- import { a as s, t as c } from "../../chunks/config-CrV_FDnM.js";
1
+ import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./chunks/GrImageCrop-Fo2qrX2n.js";
2
+ import { a as s, t as c } from "../../chunks/config-Be_Mh801.js";
3
3
  export { o as GrImageCrop, o as default, n as clampOffset, i as coverScale, t as cropRect, e as displaySize, c as grImageCropConfig, s as grImageCropSafelist, r as offsetBounds, a as viewportFor };
@@ -1,17 +1,21 @@
1
- import { t as e } from "./chunks/config-CrV_FDnM.js";
2
- import { defineGranularProvider as t, resolvePackageBaseUrl as n } from "@feugene/unocss-preset-granular/contract";
3
- import { granularityProvider as r } from "@feugene/granularity/granular-provider";
1
+ import { t as e } from "./chunks/config-CZ4ZDG0_.js";
2
+ import { t } from "./chunks/config-Be_Mh801.js";
3
+ import { defineGranularProvider as n, resolvePackageBaseUrl as r } from "@feugene/unocss-preset-granular/contract";
4
+ import { granularityProvider as i } from "@feugene/granularity/granular-provider";
4
5
  //#region src/granular-provider/shared.ts
5
- var i = "@feugene/granularity-media", a = { GrImageCrop: e };
6
- function o(e, n) {
7
- return t({
8
- id: i,
6
+ var a = "@feugene/granularity-media", o = {
7
+ GrCameraCapture: e,
8
+ GrImageCrop: t
9
+ };
10
+ function s(e, t) {
11
+ return n({
12
+ id: a,
9
13
  contractVersion: 1,
10
- packageBaseUrl: n,
11
- components: Object.values(a),
14
+ packageBaseUrl: t,
15
+ components: Object.values(o),
12
16
  dependencies: [e]
13
17
  });
14
18
  }
15
- var s = o(r, n(import.meta.url, 0));
19
+ var c = s(i, r(import.meta.url, 0));
16
20
  //#endregion
17
- export { i as GRANULARITY_MEDIA_PROVIDER_ID, o as createGranularityMediaProvider, s as default, s as granularityMediaProvider, a as granularityMediaComponentConfigs };
21
+ export { a as GRANULARITY_MEDIA_PROVIDER_ID, s as createGranularityMediaProvider, c as default, c as granularityMediaProvider, o as granularityMediaComponentConfigs };
package/dist/i18n/all.js CHANGED
@@ -1,4 +1,4 @@
1
- import { n as e, r as t, t as n } from "../chunks/ru-C4IsSzR5.js";
1
+ import { n as e, r as t, t as n } from "../chunks/ru-DN_wJDkP.js";
2
2
  //#region src/i18n/all.ts
3
3
  var r = [
4
4
  t,
@@ -1,7 +1,7 @@
1
- import { t as e } from "../chunks/en-BrjpU7lq.js";
2
- import { t } from "../chunks/es-BdTkuOLs.js";
3
- import { t as n } from "../chunks/ru-ByR24Aqk.js";
4
- import { i as r, n as i, r as a, t as o } from "../chunks/ru-C4IsSzR5.js";
1
+ import { t as e } from "../chunks/en-C-Wc5fTB.js";
2
+ import { t } from "../chunks/es-BUPtE9_0.js";
3
+ import { t as n } from "../chunks/ru-BqNILj54.js";
4
+ import { i as r, n as i, r as a, t as o } from "../chunks/ru-DN_wJDkP.js";
5
5
  //#region src/i18n/index.ts
6
6
  var s = {
7
7
  en: e,
package/dist/index.js CHANGED
@@ -1,3 +1,5 @@
1
- import { a as e, i as t, n, o as r, r as i, s as a, t as o } from "./components/GrImageCrop/chunks/GrImageCrop-DYM2vZHV.js";
2
- import { a as s, t as c } from "./chunks/config-CrV_FDnM.js";
3
- export { o as GrImageCrop, n as clampOffset, i as coverScale, t as cropRect, e as displaySize, c as grImageCropConfig, s as grImageCropSafelist, r as offsetBounds, a as viewportFor };
1
+ import { a as e, i as t, n, r, t as i } from "./components/GrCameraCapture/chunks/GrCameraCapture-B9EPXm7r.js";
2
+ import { i as a, t as o } from "./chunks/config-CZ4ZDG0_.js";
3
+ import { a as s, i as c, n as l, o as u, r as d, s as f, t as p } from "./components/GrImageCrop/chunks/GrImageCrop-Fo2qrX2n.js";
4
+ import { a as m, t as h } from "./chunks/config-Be_Mh801.js";
5
+ export { i as GrCameraCapture, p as GrImageCrop, n as cameraFrameRect, r as cameraStatusFromError, t as cameraSupported, l as clampOffset, d as coverScale, c as cropRect, s as displaySize, o as grCameraCaptureConfig, a as grCameraCaptureSafelist, h as grImageCropConfig, m as grImageCropSafelist, u as offsetBounds, e as shouldMirrorPreview, f as viewportFor };
package/dist/resolver.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { createGranularResolver as e } from "@feugene/unplugin-granularity";
2
2
  //#region src/componentNames.ts
3
- var t = ["GrImageCrop"], n = "@feugene/granularity-media";
3
+ var t = ["GrCameraCapture", "GrImageCrop"], n = "@feugene/granularity-media";
4
4
  function r() {
5
5
  return e({
6
6
  packageName: n,
@@ -8,5 +8,5 @@
8
8
  *
9
9
  * Список генерируется `yarn generate:registry` — руками не писать.
10
10
  */
11
- export declare const GRANULARITY_MEDIA_COMPONENTS: readonly ["GrImageCrop"];
11
+ export declare const GRANULARITY_MEDIA_COMPONENTS: readonly ["GrCameraCapture", "GrImageCrop"];
12
12
  export type GranularityMediaComponentName = typeof GRANULARITY_MEDIA_COMPONENTS[number];
@@ -0,0 +1,131 @@
1
+ import type { GrCameraStatus } from './cameraState';
2
+ import type { GrCameraCaptureSize, GrCameraFacing } from './grCameraCaptureStyles';
3
+ export interface GrCameraCaptureOutput {
4
+ width?: number;
5
+ height?: number;
6
+ type?: string;
7
+ quality?: number;
8
+ }
9
+ export interface GrCameraCaptureProps {
10
+ /** Какая камера: `user` — фронтальная, `environment` — тыловая. */
11
+ facing?: GrCameraFacing;
12
+ /** Конкретное устройство, если приложение его уже выбрало. */
13
+ deviceId?: string;
14
+ /**
15
+ * Соотношение сторон рамки и снимка.
16
+ *
17
+ * Без него рамка принимает соотношение самого потока: камеры отдают то 4:3,
18
+ * то 16:9, и любое зашитое число показало бы обрезанный кадр как настоящий.
19
+ */
20
+ aspectRatio?: number;
21
+ /**
22
+ * Включать камеру сразу.
23
+ *
24
+ * По умолчанию `false`: запрос разрешения без действия пользователя
25
+ * отклоняют не глядя, а второй раз браузер уже не спросит.
26
+ */
27
+ autoStart?: boolean;
28
+ /** Зеркалить превью. По умолчанию — только фронтальную камеру. */
29
+ mirror?: boolean;
30
+ output?: GrCameraCaptureOutput;
31
+ size?: GrCameraCaptureSize;
32
+ disabled?: boolean;
33
+ ariaLabel?: string;
34
+ }
35
+ export interface GrCameraCaptureEmits {
36
+ (e: 'capture', blob: Blob): void;
37
+ (e: 'start'): void;
38
+ (e: 'stop'): void;
39
+ (e: 'statusChange', status: GrCameraStatus): void;
40
+ }
41
+ type __VLS_Slots = {
42
+ /** Своя панель управления вместо встроенной. */
43
+ controls?: (props: {
44
+ status: GrCameraStatus;
45
+ start: () => void;
46
+ stop: () => void;
47
+ capture: () => Promise<Blob | null>;
48
+ }) => unknown;
49
+ };
50
+ declare function start(): Promise<void>;
51
+ declare function stop(): void;
52
+ /**
53
+ * Снимок текущего кадра.
54
+ *
55
+ * Зеркало превью сюда **не переносится**: на снимке оказывается то, что было
56
+ * перед камерой. Иначе текст на визитке или в документе уехал бы в зазеркалье —
57
+ * а снимают ими ровно это.
58
+ */
59
+ declare function capture(): Promise<Blob | null>;
60
+ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<GrCameraCaptureProps>, {
61
+ facing: string;
62
+ deviceId: undefined;
63
+ autoStart: boolean;
64
+ aspectRatio: undefined;
65
+ mirror: undefined;
66
+ output: undefined;
67
+ size: undefined;
68
+ disabled: boolean;
69
+ ariaLabel: undefined;
70
+ }>>, {
71
+ start: typeof start;
72
+ stop: typeof stop;
73
+ capture: typeof capture;
74
+ status: import("vue").Ref<GrCameraStatus, GrCameraStatus>;
75
+ }, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {
76
+ capture: (blob: Blob) => void;
77
+ start: () => void;
78
+ stop: () => void;
79
+ statusChange: (status: GrCameraStatus) => void;
80
+ }, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<__VLS_WithDefaults<__VLS_TypePropsToOption<GrCameraCaptureProps>, {
81
+ facing: string;
82
+ deviceId: undefined;
83
+ autoStart: boolean;
84
+ aspectRatio: undefined;
85
+ mirror: undefined;
86
+ output: undefined;
87
+ size: undefined;
88
+ disabled: boolean;
89
+ ariaLabel: undefined;
90
+ }>>> & Readonly<{
91
+ onCapture?: ((blob: Blob) => any) | undefined;
92
+ onStart?: (() => any) | undefined;
93
+ onStop?: (() => any) | undefined;
94
+ onStatusChange?: ((status: GrCameraStatus) => any) | undefined;
95
+ }>, {
96
+ facing: GrCameraFacing;
97
+ deviceId: string;
98
+ aspectRatio: number;
99
+ autoStart: boolean;
100
+ mirror: boolean;
101
+ output: GrCameraCaptureOutput;
102
+ size: GrCameraCaptureSize;
103
+ disabled: boolean;
104
+ ariaLabel: string;
105
+ }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
106
+ declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
107
+ declare const _default: typeof __VLS_export;
108
+ export default _default;
109
+ type __VLS_TypePropsToOption<T> = {
110
+ [K in keyof T]-?: {} extends Pick<T, K> ? {
111
+ type: import('vue').PropType<Required<T>[K]>;
112
+ } : {
113
+ type: import('vue').PropType<T[K]>;
114
+ required: true;
115
+ };
116
+ };
117
+ type __VLS_WithDefaults<P, D> = {
118
+ [K in keyof Pick<P, keyof P>]: K extends keyof D ? __VLS_PrettifyLocal<P[K] & {
119
+ default: D[K];
120
+ }> : P[K];
121
+ };
122
+ type __VLS_WithSlots<T, S> = T & {
123
+ new (): {
124
+ $slots: S;
125
+ };
126
+ };
127
+ type __VLS_PrettifyLocal<T> = (T extends any ? {
128
+ [K in keyof T]: T[K];
129
+ } : {
130
+ [K in keyof T as K]: T[K];
131
+ }) & {};
@@ -0,0 +1,67 @@
1
+ /**
2
+ * Состояния камеры и разбор отказов.
3
+ *
4
+ * Вынесено из компонента, потому что именно здесь живёт вся неочевидность:
5
+ * `getUserMedia` отвечает `DOMException` с полудюжиной имён, и от того, в какое
6
+ * из них попал отказ, зависит текст, который увидит пользователь. Проверить это
7
+ * рендером нельзя — камеры у тестового окружения нет.
8
+ */
9
+ export type GrCameraStatus = 'idle'
10
+ /** Разрешение запрошено, ответа нет. */
11
+ | 'starting'
12
+ /** Поток идёт. */
13
+ | 'live'
14
+ /** Пользователь отказал или запретила политика. */
15
+ | 'denied'
16
+ /** Камеры в системе нет. */
17
+ | 'missing'
18
+ /** Устройство занято другим приложением. */
19
+ | 'busy'
20
+ /** Страница открыта не по HTTPS: API просто отсутствует. */
21
+ | 'insecure' | 'error';
22
+ /**
23
+ * Имя `DOMException` → состояние.
24
+ *
25
+ * Названия заданы спецификацией, но разные браузеры выбирают из них по-разному
26
+ * в одной и той же ситуации: отказ пользователя — `NotAllowedError` везде, а
27
+ * вот занятое устройство Safari называет `NotReadableError`, Firefox —
28
+ * `AbortError`. Поэтому разбор по имени, а не по сообщению: сообщение
29
+ * локализовано браузером и меняется между версиями.
30
+ */
31
+ export declare function cameraStatusFromError(error: unknown): GrCameraStatus;
32
+ /**
33
+ * Доступен ли API вовсе.
34
+ *
35
+ * На `http://` (кроме localhost) `navigator.mediaDevices` не существует —
36
+ * не «отказ», а отсутствие. Сообщение «разрешите доступ к камере» в этом случае
37
+ * отправляет пользователя искать настройку, которой нет.
38
+ */
39
+ export declare function cameraSupported(navigatorLike: Pick<Navigator, 'mediaDevices'> | undefined): boolean;
40
+ /**
41
+ * Зеркалить ли превью.
42
+ *
43
+ * Фронтальную камеру зеркалят всегда: человек видит себя как в зеркале, и
44
+ * незеркальное превью читается как чужое лицо. Тыловую — никогда: там в кадре
45
+ * мир, а не ты.
46
+ *
47
+ * **Снимок при этом не зеркалится.** Иначе текст на визитке или в документе
48
+ * уедет в зазеркалье — а снимают ими ровно это.
49
+ */
50
+ export declare function shouldMirrorPreview(facing: 'user' | 'environment', mirror: boolean | undefined): boolean;
51
+ export interface GrCameraFrameRect {
52
+ sx: number;
53
+ sy: number;
54
+ sw: number;
55
+ sh: number;
56
+ }
57
+ /**
58
+ * Какая часть кадра камеры попадёт в снимок при заданном соотношении сторон.
59
+ *
60
+ * Камера отдаёт своё соотношение (обычно 4:3 или 16:9), а приложению нужно
61
+ * своё. Лишнее срезается по центру — так же, как это делает `object-fit: cover`
62
+ * в превью: снимок обязан совпасть с тем, что пользователь видел.
63
+ */
64
+ export declare function cameraFrameRect(frame: {
65
+ width: number;
66
+ height: number;
67
+ }, aspectRatio: number): GrCameraFrameRect;
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Кнопки состояния и съёмки — `GrButton` ядра, и ребро объявлено: пресет
3
+ * подмешивает safelist и CSS только тем компонентам, что попали в селекцию, и
4
+ * без графа потребитель, выбравший одну камеру, получил бы кнопки без фона.
5
+ */
6
+ export declare const grCameraCaptureConfig: import("@feugene/unocss-preset-granular/contract").GranularComponentDescriptor<"GrCameraCapture">;
@@ -0,0 +1,16 @@
1
+ import type { GrCameraCaptureSize } from './grCameraCaptureStyles';
2
+ /**
3
+ * Настраиваемые через `GrConfigProvider` пропы.
4
+ *
5
+ * Аугментация реестра идёт по месту объявления — через
6
+ * `@feugene/granularity/composables/useGrComponentConfig`, а не через реэкспорт:
7
+ * иначе слияние отваливается молча.
8
+ */
9
+ export interface GrCameraCaptureConfigurableProps {
10
+ size?: GrCameraCaptureSize;
11
+ }
12
+ declare module '@feugene/granularity/composables/useGrComponentConfig' {
13
+ interface GrComponentDefaultsRegistry {
14
+ GrCameraCapture?: GrCameraCaptureConfigurableProps;
15
+ }
16
+ }
@@ -0,0 +1,21 @@
1
+ export type GrCameraCaptureSize = 'xs' | 'sm' | 'md' | 'lg';
2
+ export type GrCameraFacing = 'user' | 'environment';
3
+ export declare const rootClass = "grid gap-2";
4
+ export declare const frameClass = "relative w-full overflow-hidden rounded-[var(--gr-radius-md)] border border-[var(--gr-brd)] bg-[var(--gr-muted)]";
5
+ /** Превью покрывает рамку целиком: снимок берётся тем же `cover`, что и показ. */
6
+ export declare const videoClass = "h-full w-full object-cover";
7
+ export declare const mirroredClass = "scale-x-[-1]";
8
+ /**
9
+ * Подложка состояния поверх рамки. Появление плавное: отказ и ошибка приходят
10
+ * асинхронно, и мгновенная подмена картинки текстом читается как сбой.
11
+ */
12
+ export declare const stateLayerClass = "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)]";
13
+ export declare const stateTextClass = "text-[var(--gr-muted-fg)]";
14
+ export declare const controlsClass = "flex flex-wrap items-center gap-2";
15
+ export declare const sizeTextClass: {
16
+ readonly xs: "text-[length:var(--gr-control-text-xs)] leading-[var(--gr-control-leading-xs)]";
17
+ readonly sm: "text-[length:var(--gr-control-text-sm)] leading-[var(--gr-control-leading-sm)]";
18
+ readonly md: "text-[length:var(--gr-control-text-md)] leading-[var(--gr-control-leading-md)]";
19
+ readonly lg: "text-[length:var(--gr-control-text-lg)] leading-[var(--gr-control-leading-lg)]";
20
+ };
21
+ export declare const grCameraCaptureSafelist: string[];
@@ -0,0 +1,9 @@
1
+ export { default } from './GrCameraCapture.vue';
2
+ export { default as GrCameraCapture } from './GrCameraCapture.vue';
3
+ export type { GrCameraFrameRect, GrCameraStatus } from './cameraState';
4
+ export { cameraFrameRect, cameraStatusFromError, cameraSupported, shouldMirrorPreview } from './cameraState';
5
+ export { grCameraCaptureConfig } from './config';
6
+ export type { GrCameraCaptureConfigurableProps } from './defaults';
7
+ export type { GrCameraCaptureEmits, GrCameraCaptureOutput, GrCameraCaptureProps } from './GrCameraCapture.vue';
8
+ export { grCameraCaptureSafelist } from './grCameraCaptureStyles';
9
+ export type { GrCameraCaptureSize, GrCameraFacing } from './grCameraCaptureStyles';
@@ -84,23 +84,23 @@ declare const __VLS_base: import("vue").DefineComponent<import("vue").ExtractPro
84
84
  disabled: boolean;
85
85
  ariaLabel: undefined;
86
86
  }>>> & Readonly<{
87
- "onUpdate:zoom"?: ((value: number) => any) | undefined;
87
+ onError?: ((error: unknown) => any) | undefined;
88
88
  onChange?: ((rect: GrCropRect) => any) | undefined;
89
89
  onLoad?: ((size: {
90
90
  width: number;
91
91
  height: number;
92
92
  }) => any) | undefined;
93
- onError?: ((error: unknown) => any) | undefined;
93
+ "onUpdate:zoom"?: ((value: number) => any) | undefined;
94
94
  }>, {
95
- src: string | File | Blob | null;
96
95
  aspectRatio: number;
97
- shape: GrImageCropShape;
98
- zoom: number;
99
- maxZoom: number;
100
96
  output: GrImageCropOutput;
101
97
  size: GrImageCropSize;
102
98
  disabled: boolean;
103
99
  ariaLabel: string;
100
+ src: string | File | Blob | null;
101
+ shape: GrImageCropShape;
102
+ zoom: number;
103
+ maxZoom: number;
104
104
  }, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>;
105
105
  declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
106
106
  declare const _default: typeof __VLS_export;
@@ -8,6 +8,7 @@ export declare const GRANULARITY_MEDIA_PROVIDER_ID = "@feugene/granularity-media
8
8
  * генератор — раскладывает компонент по четырём спискам.
9
9
  */
10
10
  export declare const granularityMediaComponentConfigs: {
11
+ GrCameraCapture: GranularComponentDescriptor<"GrCameraCapture">;
11
12
  GrImageCrop: GranularComponentDescriptor<"GrImageCrop">;
12
13
  };
13
14
  export type GranularityMediaComponentName = keyof typeof granularityMediaComponentConfigs;
@@ -6,6 +6,22 @@ export declare const grMediaMessages: {
6
6
  empty: string;
7
7
  zoom: string;
8
8
  };
9
+ camera: {
10
+ label: string;
11
+ idle: string;
12
+ starting: string;
13
+ denied: string;
14
+ missing: string;
15
+ busy: string;
16
+ insecure: string;
17
+ error: string;
18
+ start: string;
19
+ retry: string;
20
+ capture: string;
21
+ stop: string;
22
+ live: string;
23
+ captured: string;
24
+ };
9
25
  };
10
26
  readonly es: {
11
27
  imageCrop: {
@@ -14,6 +30,22 @@ export declare const grMediaMessages: {
14
30
  empty: string;
15
31
  zoom: string;
16
32
  };
33
+ camera: {
34
+ label: string;
35
+ idle: string;
36
+ starting: string;
37
+ denied: string;
38
+ missing: string;
39
+ busy: string;
40
+ insecure: string;
41
+ error: string;
42
+ start: string;
43
+ retry: string;
44
+ capture: string;
45
+ stop: string;
46
+ live: string;
47
+ captured: string;
48
+ };
17
49
  };
18
50
  readonly ru: {
19
51
  imageCrop: {
@@ -22,6 +54,22 @@ export declare const grMediaMessages: {
22
54
  empty: string;
23
55
  zoom: string;
24
56
  };
57
+ camera: {
58
+ label: string;
59
+ idle: string;
60
+ starting: string;
61
+ denied: string;
62
+ missing: string;
63
+ busy: string;
64
+ insecure: string;
65
+ error: string;
66
+ start: string;
67
+ retry: string;
68
+ capture: string;
69
+ stop: string;
70
+ live: string;
71
+ captured: string;
72
+ };
25
73
  };
26
74
  };
27
75
  export type GrMediaLocale = keyof typeof grMediaMessages;
@@ -8,6 +8,22 @@ export declare const en: {
8
8
  empty: string;
9
9
  zoom: string;
10
10
  };
11
+ camera: {
12
+ label: string;
13
+ idle: string;
14
+ starting: string;
15
+ denied: string;
16
+ missing: string;
17
+ busy: string;
18
+ insecure: string;
19
+ error: string;
20
+ start: string;
21
+ retry: string;
22
+ capture: string;
23
+ stop: string;
24
+ live: string;
25
+ captured: string;
26
+ };
11
27
  };
12
28
  imageCrop: {
13
29
  label: string;
@@ -15,6 +31,22 @@ export declare const en: {
15
31
  empty: string;
16
32
  zoom: string;
17
33
  };
34
+ camera: {
35
+ label: string;
36
+ idle: string;
37
+ starting: string;
38
+ denied: string;
39
+ missing: string;
40
+ busy: string;
41
+ insecure: string;
42
+ error: string;
43
+ start: string;
44
+ retry: string;
45
+ capture: string;
46
+ stop: string;
47
+ live: string;
48
+ captured: string;
49
+ };
18
50
  }>;
19
51
  };
20
52
  };
@@ -8,6 +8,22 @@ export declare const es: {
8
8
  empty: string;
9
9
  zoom: string;
10
10
  };
11
+ camera: {
12
+ label: string;
13
+ idle: string;
14
+ starting: string;
15
+ denied: string;
16
+ missing: string;
17
+ busy: string;
18
+ insecure: string;
19
+ error: string;
20
+ start: string;
21
+ retry: string;
22
+ capture: string;
23
+ stop: string;
24
+ live: string;
25
+ captured: string;
26
+ };
11
27
  };
12
28
  imageCrop: {
13
29
  label: string;
@@ -15,6 +31,22 @@ export declare const es: {
15
31
  empty: string;
16
32
  zoom: string;
17
33
  };
34
+ camera: {
35
+ label: string;
36
+ idle: string;
37
+ starting: string;
38
+ denied: string;
39
+ missing: string;
40
+ busy: string;
41
+ insecure: string;
42
+ error: string;
43
+ start: string;
44
+ retry: string;
45
+ capture: string;
46
+ stop: string;
47
+ live: string;
48
+ captured: string;
49
+ };
18
50
  }>;
19
51
  };
20
52
  };
@@ -8,6 +8,22 @@ export declare const ru: {
8
8
  empty: string;
9
9
  zoom: string;
10
10
  };
11
+ camera: {
12
+ label: string;
13
+ idle: string;
14
+ starting: string;
15
+ denied: string;
16
+ missing: string;
17
+ busy: string;
18
+ insecure: string;
19
+ error: string;
20
+ start: string;
21
+ retry: string;
22
+ capture: string;
23
+ stop: string;
24
+ live: string;
25
+ captured: string;
26
+ };
11
27
  };
12
28
  imageCrop: {
13
29
  label: string;
@@ -15,6 +31,22 @@ export declare const ru: {
15
31
  empty: string;
16
32
  zoom: string;
17
33
  };
34
+ camera: {
35
+ label: string;
36
+ idle: string;
37
+ starting: string;
38
+ denied: string;
39
+ missing: string;
40
+ busy: string;
41
+ insecure: string;
42
+ error: string;
43
+ start: string;
44
+ retry: string;
45
+ capture: string;
46
+ stop: string;
47
+ live: string;
48
+ captured: string;
49
+ };
18
50
  }>;
19
51
  };
20
52
  };
@@ -1 +1,2 @@
1
+ export * from './components/GrCameraCapture';
1
2
  export * from './components/GrImageCrop';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@feugene/granularity-media",
3
3
  "description": "Media components for @feugene/granularity: image cropping, camera capture, code scanning and video playback.",
4
- "version": "0.1.0",
4
+ "version": "0.2.1",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "author": {
7
7
  "name": "Evgeniy Fureev",
@@ -47,6 +47,10 @@
47
47
  "types": "./dist/types/index.d.ts",
48
48
  "import": "./dist/index.js"
49
49
  },
50
+ "./components/GrCameraCapture": {
51
+ "types": "./dist/types/components/GrCameraCapture/index.d.ts",
52
+ "import": "./dist/components/GrCameraCapture/index.js"
53
+ },
50
54
  "./components/GrImageCrop": {
51
55
  "types": "./dist/types/components/GrImageCrop/index.d.ts",
52
56
  "import": "./dist/components/GrImageCrop/index.js"
@@ -1,13 +0,0 @@
1
- import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
- //#region src/i18n/locales/en.json
3
- var t = /* @__PURE__ */ e({
4
- default: () => r,
5
- imageCrop: () => n
6
- }), n = {
7
- label: "Image crop",
8
- frame: "Frame: arrow keys move the image, plus and minus zoom",
9
- empty: "No image selected",
10
- zoom: "Zoom"
11
- }, r = { imageCrop: n };
12
- //#endregion
13
- export { t as n, r as t };
@@ -1,13 +0,0 @@
1
- import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
- //#region src/i18n/locales/es.json
3
- var t = /* @__PURE__ */ e({
4
- default: () => r,
5
- imageCrop: () => n
6
- }), n = {
7
- label: "Recorte de imagen",
8
- frame: "Marco: las flechas mueven la imagen, más y menos ajustan el zoom",
9
- empty: "Ninguna imagen seleccionada",
10
- zoom: "Zoom"
11
- }, r = { imageCrop: n };
12
- //#endregion
13
- export { t as n, r as t };
@@ -1,13 +0,0 @@
1
- import { t as e } from "./rolldown-runtime-Dy4uBu1J.js";
2
- //#region src/i18n/locales/ru.json
3
- var t = /* @__PURE__ */ e({
4
- default: () => r,
5
- imageCrop: () => n
6
- }), n = {
7
- label: "Кадрирование изображения",
8
- frame: "Кадр: стрелки двигают изображение, плюс и минус меняют увеличение",
9
- empty: "Изображение не выбрано",
10
- zoom: "Увеличение"
11
- }, r = { imageCrop: n };
12
- //#endregion
13
- export { t as n, r as t };
@@ -1,4 +0,0 @@
1
- //#region src/i18n/messages/const.ts
2
- var e = "grMedia", t = { en: { [e]: async () => import("./en-BrjpU7lq.js").then((e) => e.n) } }, n = { es: { [e]: async () => import("./es-BdTkuOLs.js").then((e) => e.n) } }, r = { ru: { [e]: async () => import("./ru-ByR24Aqk.js").then((e) => e.n) } };
3
- //#endregion
4
- export { e as i, n, t as r, r as t };