@qaiddev/thumbs-embed 1.2.1 → 1.3.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.
- package/dist/annotate.d.ts +150 -0
- package/dist/embed.d.ts +12 -0
- package/dist/icons.d.ts +7 -0
- package/dist/index.d.ts +2 -0
- package/dist/qaid.js +657 -300
- package/dist/qaid.js.map +1 -1
- package/dist/qaid.umd.cjs +21 -7
- package/dist/qaid.umd.cjs.map +1 -1
- package/dist/types.d.ts +9 -0
- package/package.json +1 -1
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Screenshot annotation / markup editor for the thumbs embed.
|
|
3
|
+
*
|
|
4
|
+
* After a screenshot is captured the user can draw on it — rectangles, arrows,
|
|
5
|
+
* a freehand pen, and a blur/redact box — in a full-screen, focus-trapped,
|
|
6
|
+
* WCAG 2.2 AA dialog rendered inside the embed's overlay shadow root. On "Done"
|
|
7
|
+
* the base image and the vector shapes are composited into a fresh WebP data
|
|
8
|
+
* URL (so downstream code is unchanged); on "Skip"/Escape the original is kept.
|
|
9
|
+
*
|
|
10
|
+
* The geometry and compositing are kept as pure-ish exported functions
|
|
11
|
+
* (`drawShape`, `rectFromPoints`, `compositeAnnotations`) so they can be tested
|
|
12
|
+
* without a real rendering engine — happy-dom has no raster, so tests assert on
|
|
13
|
+
* spied canvas-context calls rather than pixels. The {@link AnnotationEditor}
|
|
14
|
+
* controller keeps the DOM wiring thin and its interactive methods are public
|
|
15
|
+
* so they can be driven directly in tests.
|
|
16
|
+
*/
|
|
17
|
+
/** The four drawing tools. */
|
|
18
|
+
export type ShapeType = "rect" | "arrow" | "pen" | "blur";
|
|
19
|
+
/** A point in the screenshot's natural-pixel coordinate space. */
|
|
20
|
+
export interface Point {
|
|
21
|
+
x: number;
|
|
22
|
+
y: number;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* A single vector annotation. `rect`, `arrow` and `blur` use `points[0]` as the
|
|
26
|
+
* drag start and `points[1]` as the drag end; `pen` uses every point in order.
|
|
27
|
+
*/
|
|
28
|
+
export interface Shape {
|
|
29
|
+
type: ShapeType;
|
|
30
|
+
color: string;
|
|
31
|
+
strokeWidth: number;
|
|
32
|
+
points: Point[];
|
|
33
|
+
}
|
|
34
|
+
/** Human-readable labels for the toolbar / announcements (all overridable). */
|
|
35
|
+
export interface AnnotationLabels {
|
|
36
|
+
title: string;
|
|
37
|
+
instructions: string;
|
|
38
|
+
rectangle: string;
|
|
39
|
+
arrow: string;
|
|
40
|
+
pen: string;
|
|
41
|
+
blur: string;
|
|
42
|
+
undo: string;
|
|
43
|
+
skip: string;
|
|
44
|
+
done: string;
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Normalise two drag corners into a top-left origin plus positive width/height,
|
|
48
|
+
* regardless of the direction the user dragged.
|
|
49
|
+
*/
|
|
50
|
+
export declare function rectFromPoints(a: Point, b: Point): {
|
|
51
|
+
x: number;
|
|
52
|
+
y: number;
|
|
53
|
+
w: number;
|
|
54
|
+
h: number;
|
|
55
|
+
};
|
|
56
|
+
/**
|
|
57
|
+
* Draw a single shape onto a 2D context in the shape's own (natural-pixel)
|
|
58
|
+
* coordinates. Used both for the live editing preview and for the final
|
|
59
|
+
* composite, so what the user sees is exactly what is submitted.
|
|
60
|
+
*/
|
|
61
|
+
export declare function drawShape(ctx: CanvasRenderingContext2D, shape: Shape): void;
|
|
62
|
+
/**
|
|
63
|
+
* Composite the base screenshot and the drawn shapes into a new WebP data URL
|
|
64
|
+
* at the image's natural size. Falls back to the original data URL if the image
|
|
65
|
+
* can't be loaded or a 2D context isn't available (so a submission is never
|
|
66
|
+
* lost). This is intentionally standalone so it can be unit-tested in isolation.
|
|
67
|
+
*/
|
|
68
|
+
export declare function compositeAnnotations(dataUrl: string, shapes: Shape[], opts?: {
|
|
69
|
+
quality?: number;
|
|
70
|
+
}): Promise<string>;
|
|
71
|
+
/** Options for {@link AnnotationEditor} / {@link openAnnotationEditor}. */
|
|
72
|
+
export interface AnnotationEditorOptions {
|
|
73
|
+
/** The captured screenshot as a WebP data URL. */
|
|
74
|
+
dataUrl: string;
|
|
75
|
+
/** Shadow root (or element) the editor is mounted into. */
|
|
76
|
+
root: ShadowRoot | HTMLElement;
|
|
77
|
+
/** WebP quality for the re-encoded composite. */
|
|
78
|
+
quality?: number;
|
|
79
|
+
/** Default stroke colour for rectangle/arrow/pen. */
|
|
80
|
+
color?: string;
|
|
81
|
+
/** Default stroke width. */
|
|
82
|
+
strokeWidth?: number;
|
|
83
|
+
/** Label overrides. */
|
|
84
|
+
labels?: Partial<AnnotationLabels>;
|
|
85
|
+
/** Apply the embed's per-instance `--qaid-*` CSS variables to the container. */
|
|
86
|
+
applyVars?: (el: HTMLElement) => void;
|
|
87
|
+
/** Announce a message via the embed's live regions. */
|
|
88
|
+
announce?: (message: string, assertive?: boolean) => void;
|
|
89
|
+
/** Turn the container into an accessible modal dialog (focus trap + inert). */
|
|
90
|
+
openDialog?: (container: HTMLElement, opts: {
|
|
91
|
+
labelledbyId?: string;
|
|
92
|
+
describedbyId?: string;
|
|
93
|
+
}) => void;
|
|
94
|
+
/** Tear down the dialog semantics and restore focus. */
|
|
95
|
+
closeDialog?: () => void;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Full-screen screenshot annotation editor. Construct it, call {@link open}
|
|
99
|
+
* (which returns a promise resolving to the composited WebP, or `null` when the
|
|
100
|
+
* user skips), and the controller manages its own DOM and teardown.
|
|
101
|
+
*/
|
|
102
|
+
export declare class AnnotationEditor {
|
|
103
|
+
readonly shapes: Shape[];
|
|
104
|
+
tool: ShapeType;
|
|
105
|
+
private readonly opts;
|
|
106
|
+
private readonly labels;
|
|
107
|
+
private readonly color;
|
|
108
|
+
private readonly strokeWidth;
|
|
109
|
+
private readonly uid;
|
|
110
|
+
private container;
|
|
111
|
+
private canvas;
|
|
112
|
+
private ctx;
|
|
113
|
+
private toolbar;
|
|
114
|
+
private undoBtn;
|
|
115
|
+
private img;
|
|
116
|
+
private drawing;
|
|
117
|
+
private current;
|
|
118
|
+
private settled;
|
|
119
|
+
private resolveResult;
|
|
120
|
+
constructor(opts: AnnotationEditorOptions);
|
|
121
|
+
/** Mount the editor and resolve when the user commits (Done) or skips. */
|
|
122
|
+
open(): Promise<string | null>;
|
|
123
|
+
private toolButton;
|
|
124
|
+
private actionButton;
|
|
125
|
+
private mount;
|
|
126
|
+
/** Convert a pointer event's client coordinates into natural image pixels. */
|
|
127
|
+
private toImageCoords;
|
|
128
|
+
/** Repaint the display canvas: base image (if loaded) then every shape. */
|
|
129
|
+
redraw(): void;
|
|
130
|
+
/** Select the active drawing tool and reflect it on the toolbar. */
|
|
131
|
+
selectTool(tool: ShapeType): void;
|
|
132
|
+
private onToolbarClick;
|
|
133
|
+
onPointerDown: (e: PointerEvent) => void;
|
|
134
|
+
onPointerMove: (e: PointerEvent) => void;
|
|
135
|
+
onPointerUp: () => void;
|
|
136
|
+
onKeyDown: (e: KeyboardEvent) => void;
|
|
137
|
+
/** Remove the most recently added shape. */
|
|
138
|
+
undo(): void;
|
|
139
|
+
/** Composite the annotations and resolve with the new WebP data URL. */
|
|
140
|
+
done(): Promise<void>;
|
|
141
|
+
/** Discard annotations and resolve with `null` (caller keeps the original). */
|
|
142
|
+
skip(): void;
|
|
143
|
+
private settle;
|
|
144
|
+
private teardown;
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Open the annotation editor and resolve with the composited WebP data URL, or
|
|
148
|
+
* `null` if the user skipped. Thin entry point used by the embed.
|
|
149
|
+
*/
|
|
150
|
+
export declare function openAnnotationEditor(opts: AnnotationEditorOptions): Promise<string | null>;
|
package/dist/embed.d.ts
CHANGED
|
@@ -134,6 +134,18 @@ export declare class QaidFeedback {
|
|
|
134
134
|
private removeTargetingOverlay;
|
|
135
135
|
private showSelectedMarker;
|
|
136
136
|
private hideSelectedMarker;
|
|
137
|
+
/** Whether to capture the screenshot with the DOM/canvas method (html2canvas)
|
|
138
|
+
* instead of the permission-based Screen Capture API. Explicit "dom" wins;
|
|
139
|
+
* otherwise DOM is used on touch devices to avoid the getDisplayMedia prompt. */
|
|
140
|
+
private shouldCaptureViaDom;
|
|
141
|
+
/**
|
|
142
|
+
* Open the full-screen annotation editor over the captured screenshot,
|
|
143
|
+
* reusing the overlay shadow host and the shared dialog a11y helpers.
|
|
144
|
+
* Resolves with the composited WebP data URL, or null when the user skips
|
|
145
|
+
* (caller keeps the original). Pointer events on the overlay host are
|
|
146
|
+
* enabled while the editor is open and restored on close.
|
|
147
|
+
*/
|
|
148
|
+
private openAnnotationEditor;
|
|
137
149
|
private submitFeedback;
|
|
138
150
|
/**
|
|
139
151
|
* Quest id linked to `type`, or "" when quest launching is disabled
|
package/dist/icons.d.ts
CHANGED
|
@@ -4,3 +4,10 @@
|
|
|
4
4
|
export declare const THUMBS_UP_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5\"/>\n</svg>";
|
|
5
5
|
export declare const THUMBS_DOWN_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M10 14H5.236a2 2 0 01-1.789-2.894l3.5-7A2 2 0 018.737 3h4.018a2 2 0 01.485.06l3.76.94m-7 10v5a2 2 0 002 2h.095c.5 0 .905-.405.905-.905 0-.714.211-1.412.608-2.006L17 13V4m-7 10h2m5-10h2a2 2 0 012 2v6a2 2 0 01-2 2h-2.5\"/>\n</svg>";
|
|
6
6
|
export declare const RECORD_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M15.75 10.5l4.72-4.72a.75.75 0 011.28.53v11.38a.75.75 0 01-1.28.53l-4.72-4.72M4.5 18.75h9a2.25 2.25 0 002.25-2.25v-9a2.25 2.25 0 00-2.25-2.25h-9A2.25 2.25 0 002.25 7.5v9a2.25 2.25 0 002.25 2.25z\"/>\n</svg>";
|
|
7
|
+
export declare const RECTANGLE_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <rect x=\"4\" y=\"6\" width=\"16\" height=\"12\" rx=\"1\" stroke-linejoin=\"round\"/>\n</svg>";
|
|
8
|
+
export declare const ARROW_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M5 19L19 5m0 0h-8m8 0v8\"/>\n</svg>";
|
|
9
|
+
export declare const PENCIL_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 20h9M16.5 3.5a2.121 2.121 0 013 3L7 19l-4 1 1-4L16.5 3.5z\"/>\n</svg>";
|
|
10
|
+
export declare const BLUR_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M12 3s6 6.4 6 10a6 6 0 01-12 0c0-3.6 6-10 6-10z\"/>\n</svg>";
|
|
11
|
+
export declare const UNDO_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M9 14L4 9l5-5M4 9h11a5 5 0 010 10h-4\"/>\n</svg>";
|
|
12
|
+
export declare const DONE_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M20 6L9 17l-5-5\"/>\n</svg>";
|
|
13
|
+
export declare const SKIP_ICON = "<svg xmlns=\"http://www.w3.org/2000/svg\" class=\"qaid-icon\" fill=\"none\" viewBox=\"0 0 24 24\" stroke=\"currentColor\" stroke-width=\"2\">\n <path stroke-linecap=\"round\" stroke-linejoin=\"round\" d=\"M6 6l12 12M18 6L6 18\"/>\n</svg>";
|
package/dist/index.d.ts
CHANGED
|
@@ -36,3 +36,5 @@ export { createVideoRecorder, isVideoRecordingSupported, getSupportedMimeType }
|
|
|
36
36
|
export type { VideoRecorder, VideoRecorderOptions } from "./video-capture";
|
|
37
37
|
export { captureDomScreenshot, isDomScreenshotSupported } from "./screenshot-dom";
|
|
38
38
|
export type { DomScreenshotOptions } from "./screenshot-dom";
|
|
39
|
+
export { openAnnotationEditor, compositeAnnotations, drawShape, rectFromPoints, AnnotationEditor, } from "./annotate";
|
|
40
|
+
export type { Shape, ShapeType, Point, AnnotationLabels, AnnotationEditorOptions, } from "./annotate";
|