ablok-components 0.3.125 → 0.3.127

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.
@@ -0,0 +1,34 @@
1
+ export interface CaptureOptions {
2
+ /** Target canvas dimensions; falls back to the source video dimensions. */
3
+ targetResolution?: {
4
+ width: number;
5
+ height: number;
6
+ } | undefined;
7
+ /** True when the target ratio was explicitly requested (else derive height from source ratio). */
8
+ hasExplicitRatio: boolean;
9
+ /** Crop to the target ratio (cover) instead of letterboxing (contain). */
10
+ enableCropImage: boolean;
11
+ /** Digital zoom factor (1 = none). */
12
+ zoom: number;
13
+ /** Front-camera mirroring — flip horizontally. */
14
+ mirror: boolean;
15
+ /** Portrait-upright correction rotation (0/90/180/270), from useOrientationCorrection. */
16
+ captureRotation: number;
17
+ /** Called with the resulting PNG data URL. */
18
+ onSave: (dataUrl: string) => void;
19
+ }
20
+ /**
21
+ * Captures the current video frame onto the canvas, honouring ratio cropping,
22
+ * zoom, mirroring and device-orientation rotation. Pure drawing logic — no
23
+ * reactivity, trivially unit-testable.
24
+ */
25
+ export declare function captureFrame(canvas: HTMLCanvasElement, image: HTMLVideoElement, options: CaptureOptions): void;
26
+ /** Runs the canvas-capture pipeline (drawing + optional post-filter) and returns the PNG data URL. */
27
+ export declare function captureToDataUrl(canvas: HTMLCanvasElement, image: HTMLVideoElement, options: CaptureOptions, applyFilter?: (context: CanvasRenderingContext2D, width: number, height: number) => void): string;
28
+ /** Converts a captured data URL into the emitted photo payload. */
29
+ export declare function toPhotoPayload(dataUrl: string): {
30
+ name: string;
31
+ id: string;
32
+ blob: Blob;
33
+ size: number;
34
+ };
@@ -0,0 +1,53 @@
1
+ import { dataURItoBlob as e } from "../utilities/helpers.js";
2
+ //#region src/composables/useCameraCapture.ts
3
+ function t(e, t, n, r, i, a, o) {
4
+ let s = e.canvas.width, c = e.canvas.height;
5
+ e.translate(s / 2, c / 2), o && e.scale(-1, 1), e.rotate(n * Math.PI / 180);
6
+ let l = c, u = s, d = Math.max(l / r, u / i) * (a && a > 0 ? a : 1), f = r * d, p = i * d;
7
+ e.drawImage(t, -f / 2, -p / 2, f, p);
8
+ }
9
+ function n(e, n, r) {
10
+ let i = e.getContext("2d");
11
+ if (!i) return;
12
+ let a = n.srcObject instanceof MediaStream ? n.srcObject.getTracks() : [], { aspectRatio: o, width: s, height: c } = a.length ? a[0].getSettings() : {}, l = n?.videoWidth || s || 0, u = n?.videoHeight || c || 0, d = l && u ? l / u : o, f = r.targetResolution || {
13
+ width: l,
14
+ height: u
15
+ }, p = f?.width || l, m = r.hasExplicitRatio ? f?.height || u : Math.round(p / (d || 1)), h = p / m;
16
+ if (e.width = p, e.height = m, !l || !u || !d) return;
17
+ let g = r.zoom, _ = r.mirror;
18
+ if (i.save(), r.captureRotation === 90 || r.captureRotation === 270) {
19
+ t(i, n, r.captureRotation, l, u, g, _), i.restore();
20
+ return;
21
+ }
22
+ if (r.captureRotation === 180 && (i.translate(e.width, e.height), i.scale(-1, -1)), _ && (i.translate(e.width, 0), i.scale(-1, 1)), r.enableCropImage) {
23
+ let t = 0, r = 0, a = l, o = u;
24
+ if (d > h ? (a = u * h, t = (l - a) / 2) : d < h && (o = l / h, r = (u - o) / 2), g && g !== 1) {
25
+ let e = a / g, n = o / g;
26
+ t += (a - e) / 2, r += (o - n) / 2, a = e, o = n;
27
+ }
28
+ i.drawImage(n, t, r, a, o, 0, 0, e.width, e.height);
29
+ } else {
30
+ let t = e.width, r = e.height, a = 0, o = 0;
31
+ if (d > h ? (r = e.width / d, o = (e.height - r) / 2) : d < h && (t = e.height * d, a = (e.width - t) / 2), g && g !== 1) {
32
+ let s = l / g, c = u / g, d = (l - s) / 2, f = (u - c) / 2;
33
+ _ && (a = e.width - a - t), i.drawImage(n, d, f, s, c, a, o, t, r);
34
+ } else _ && (a = e.width - a - t), i.drawImage(n, 0, 0, l, u, a, o, t, r);
35
+ }
36
+ i.restore();
37
+ }
38
+ function r(e, t, r, i) {
39
+ n(e, t, r);
40
+ let a = e.getContext("2d");
41
+ return a && i && i(a, e.width, e.height), e.toDataURL("image/png");
42
+ }
43
+ function i(t) {
44
+ let n = e(t), r = `cam-pic-${(/* @__PURE__ */ new Date()).toISOString()}`;
45
+ return {
46
+ name: r,
47
+ id: r,
48
+ blob: n,
49
+ size: n.size
50
+ };
51
+ }
52
+ //#endregion
53
+ export { n as captureFrame, r as captureToDataUrl, i as toPhotoPayload };
@@ -0,0 +1,27 @@
1
+ import { ComputedRef, Ref } from '../../vue/dist/vue.esm-bundler.js';
2
+ /**
3
+ * Device-orientation correction for rotation-locked pages.
4
+ *
5
+ * When the page is rotation-locked, the OS bakes a portrait-up OR portrait-down
6
+ * (0°/180°) orientation into the camera buffer based on gravity. That affects the
7
+ * preview AND the captured canvas identically. `orientationFlip` is true only while
8
+ * the device is actually held in landscape (in-plane gravity near ±90°), where the
9
+ * buffer arrives upside-down relative to the device frame; the preview counter-rotates
10
+ * with a 180° rotation. Portrait-up and portrait-down are left untouched. Hysteresis
11
+ * around the band edges prevents flicker.
12
+ *
13
+ * `previewReady` gates the preview until the correction is live (motion permission
14
+ * granted + first sensor reading applied). A safety timeout prevents the preview
15
+ * from being blocked forever if permission is denied or never granted.
16
+ */
17
+ export declare function useOrientationCorrection(enabled: () => boolean): {
18
+ motionEnabled: Ref<boolean, boolean>;
19
+ orientationFlip: Ref<boolean>;
20
+ lastGravityAngle: Ref<number | null, number | null>;
21
+ orientationReady: Ref<boolean, boolean>;
22
+ requiresGate: ComputedRef<boolean>;
23
+ enableMotion: () => Promise<void>;
24
+ armGate: () => void;
25
+ getCaptureRotation: () => number;
26
+ dispose: () => void;
27
+ };
@@ -0,0 +1,66 @@
1
+ import { computed as e, ref as t } from "vue";
2
+ //#region src/composables/useOrientationCorrection.ts
3
+ function n(n) {
4
+ let r = t(!1), i = t(!1), a = t(null), o = t(!1), s, c, l = typeof window < "u" && "DeviceMotionEvent" in window && (window.matchMedia?.("(pointer: coarse)")?.matches || "ontouchstart" in window), u = e(() => n() && l);
5
+ function d() {
6
+ c &&= (window.removeEventListener("pointerdown", c, !0), window.removeEventListener("touchend", c, !0), void 0);
7
+ }
8
+ function f() {
9
+ o.value = !0, s &&= (clearTimeout(s), void 0), d();
10
+ }
11
+ function p() {
12
+ c || (c = () => {
13
+ h();
14
+ }, window.addEventListener("pointerdown", c, !0), window.addEventListener("touchend", c, !0));
15
+ }
16
+ function m(e) {
17
+ let t = e.accelerationIncludingGravity;
18
+ if (!t || t.x == null || t.y == null) return;
19
+ let n = Math.round(Math.atan2(t.x, t.y) * 180 / Math.PI);
20
+ if (a.value = n, !(typeof screen < "u" && screen.orientation && screen.orientation.type || "portrait-primary").startsWith("portrait")) i.value = !1;
21
+ else {
22
+ let e = Math.abs(Math.abs(n) - 90);
23
+ !i.value && e < 40 ? i.value = !0 : i.value && e > 50 && (i.value = !1);
24
+ }
25
+ o.value || f();
26
+ }
27
+ async function h() {
28
+ if (!(!n() || r.value)) try {
29
+ let e = window.DeviceOrientationEvent, t = window.DeviceMotionEvent;
30
+ if (e && typeof e.requestPermission == "function" && await e.requestPermission() !== "granted") {
31
+ f();
32
+ return;
33
+ }
34
+ t && typeof t.requestPermission == "function" && await t.requestPermission().catch(() => {}), window.addEventListener("devicemotion", m, !0), r.value = !0, d();
35
+ } catch (e) {
36
+ console.error(e, "enableMotion: failed"), f();
37
+ }
38
+ }
39
+ function g() {
40
+ if (!u.value) return;
41
+ s = setTimeout(f, 3e3);
42
+ let e = window.DeviceOrientationEvent;
43
+ e && typeof e.requestPermission == "function" ? p() : h();
44
+ }
45
+ function _() {
46
+ if (!n() || a.value == null) return 0;
47
+ let e = ((a.value - 180) % 360 + 360) % 360;
48
+ return (-1 * (Math.round(e / 90) * 90 % 360) % 360 + 360) % 360;
49
+ }
50
+ function v() {
51
+ window.removeEventListener("devicemotion", m, !0), s && clearTimeout(s), d();
52
+ }
53
+ return {
54
+ motionEnabled: r,
55
+ orientationFlip: i,
56
+ lastGravityAngle: a,
57
+ orientationReady: o,
58
+ requiresGate: u,
59
+ enableMotion: h,
60
+ armGate: g,
61
+ getCaptureRotation: _,
62
+ dispose: v
63
+ };
64
+ }
65
+ //#endregion
66
+ export { n as useOrientationCorrection };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "ablok-components",
3
3
  "private": false,
4
- "version": "0.3.125",
4
+ "version": "0.3.127",
5
5
  "type": "module",
6
6
  "dependencies": {
7
7
  "@tiptap/core": "^3.30.0",