helldots 0.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/LICENSE +21 -0
- package/README.md +227 -0
- package/dist/helldots.esm.js +1019 -0
- package/dist/helldots.esm.js.map +7 -0
- package/dist/helldots.umd.js +1032 -0
- package/dist/index.d.ts +199 -0
- package/package.json +75 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
export interface CommentAnchorFingerprint {
|
|
2
|
+
tagName: string;
|
|
3
|
+
/** First ~64 chars of the element's normalized textContent. */
|
|
4
|
+
textSnippet: string;
|
|
5
|
+
/** Stable attributes only (id, name, role, aria-label, non-framework data-*). */
|
|
6
|
+
attributes: Record<string, string>;
|
|
7
|
+
/** 0-based position among same-tag siblings at creation time. */
|
|
8
|
+
siblingIndex: number;
|
|
9
|
+
siblingCount: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface CommentAnchor {
|
|
13
|
+
version: 1;
|
|
14
|
+
/** Best-effort unique CSS selector, or null when none could be generated. */
|
|
15
|
+
selector: string | null;
|
|
16
|
+
/** Selector for the exact clicked element when deeper than the container. */
|
|
17
|
+
targetSelector?: string | null;
|
|
18
|
+
fingerprint: CommentAnchorFingerprint;
|
|
19
|
+
/** Fraction (0–1) of the anchor element's box, captured at creation. */
|
|
20
|
+
relativeX: number;
|
|
21
|
+
relativeY: number;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type AnchorState = "anchored" | "orphaned" | "inactive";
|
|
25
|
+
|
|
26
|
+
/** RF09 — comment lifecycle state. */
|
|
27
|
+
export type CommentStatus = "open" | "in_progress" | "resolved";
|
|
28
|
+
|
|
29
|
+
/** RF3 — comment category. `null` means deliberately unclassified. */
|
|
30
|
+
export type CommentType = "bug" | "suggestion" | "question" | "improvement";
|
|
31
|
+
|
|
32
|
+
/** RF4 — comment priority. `null` means deliberately unprioritised. */
|
|
33
|
+
export type CommentPriority = "high" | "medium" | "low";
|
|
34
|
+
|
|
35
|
+
/** RF2 — environment snapshot taken when the comment was created. */
|
|
36
|
+
export interface CommentContext {
|
|
37
|
+
version: 1;
|
|
38
|
+
/** Full location.href at creation time. */
|
|
39
|
+
url: string;
|
|
40
|
+
viewport: { width: number; height: number };
|
|
41
|
+
/** Screen resolution (screen.width/height). */
|
|
42
|
+
screen: { width: number; height: number };
|
|
43
|
+
devicePixelRatio: number;
|
|
44
|
+
/** Raw UA — always stored, even when browser/os parsing fails. */
|
|
45
|
+
userAgent: string;
|
|
46
|
+
browser: { name: string; version: string };
|
|
47
|
+
os: { name: string; version: string };
|
|
48
|
+
language: string;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export interface SerializedComment {
|
|
52
|
+
id: number;
|
|
53
|
+
text: string;
|
|
54
|
+
anchor: CommentAnchor | null;
|
|
55
|
+
/** location.pathname where the comment was created. */
|
|
56
|
+
page: string;
|
|
57
|
+
replies: CommentReply[];
|
|
58
|
+
author: string;
|
|
59
|
+
createdAt: string;
|
|
60
|
+
screenshots: string[];
|
|
61
|
+
status: CommentStatus;
|
|
62
|
+
/** RF3 — `null` when deliberately unclassified. */
|
|
63
|
+
type: CommentType | null;
|
|
64
|
+
/** RF4 — `null` when deliberately unprioritised. */
|
|
65
|
+
priority: CommentPriority | null;
|
|
66
|
+
/**
|
|
67
|
+
* RF3 — free-form labels. `setCommentTags` normalises them (trimmed,
|
|
68
|
+
* lowercased, de-duplicated); values loaded via `loadComments` are
|
|
69
|
+
* trusted as-is and are not renormalised on read.
|
|
70
|
+
*/
|
|
71
|
+
tags: string[];
|
|
72
|
+
/** RF5 — set on entering "resolved", cleared on leaving it. */
|
|
73
|
+
resolvedAt: string | null;
|
|
74
|
+
/** RF2 — environment snapshot taken at creation. */
|
|
75
|
+
context: CommentContext | null;
|
|
76
|
+
/** RF1 — automatic viewport capture (JPEG data-URL). */
|
|
77
|
+
contextScreenshot: string | null;
|
|
78
|
+
/**
|
|
79
|
+
* RF6 — emoji → authors who reacted. Reserved, not implemented yet.
|
|
80
|
+
* Optional and absent by default, so shipping it later needs no migration.
|
|
81
|
+
*/
|
|
82
|
+
reactions?: Record<string, string[]>;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface CommentOverlayOptions {
|
|
86
|
+
shortcutKey?: string;
|
|
87
|
+
shortcutModifier?: "alt" | "ctrl" | "shift";
|
|
88
|
+
autoInit?: boolean;
|
|
89
|
+
/** UI language. Defaults to the browser's language when supported, else "en". */
|
|
90
|
+
locale?: "en" | "es";
|
|
91
|
+
/** Auto save/restore comments. Default: "none" (host app persists via callbacks). */
|
|
92
|
+
persistence?: "localStorage" | "none";
|
|
93
|
+
/** Capture a viewport screenshot and environment snapshot on every new comment. Default: true. */
|
|
94
|
+
autoScreenshot?: boolean;
|
|
95
|
+
/** Identity used as the author of new comments and replies. */
|
|
96
|
+
user?: { name: string };
|
|
97
|
+
/** Fired after a new comment is saved. */
|
|
98
|
+
onCommentCreated?: (comment: SerializedComment) => void;
|
|
99
|
+
/** Fired after a reply is added to any comment. */
|
|
100
|
+
onReplyAdded?: (comment: SerializedComment, reply: CommentReply) => void;
|
|
101
|
+
/** Fired for each comment that could not be re-anchored by loadComments. */
|
|
102
|
+
onAnchorLost?: (comment: SerializedComment) => void;
|
|
103
|
+
/** Fired after deleteComment removes a comment. */
|
|
104
|
+
onCommentDeleted?: (id: number) => void;
|
|
105
|
+
/** Fired after setCommentStatus changes a comment's lifecycle state. */
|
|
106
|
+
onCommentStatusChanged?: (comment: SerializedComment) => void;
|
|
107
|
+
/** Fired after type, priority or tags change on any comment. */
|
|
108
|
+
onCommentUpdated?: (comment: SerializedComment) => void;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export interface CommentReply {
|
|
112
|
+
id: number;
|
|
113
|
+
text: string;
|
|
114
|
+
author: string;
|
|
115
|
+
timestamp: string;
|
|
116
|
+
screenshots?: string[];
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface Comment {
|
|
120
|
+
id: number;
|
|
121
|
+
text: string;
|
|
122
|
+
/** Live anchor element; null while the comment is orphaned or inactive. */
|
|
123
|
+
container: HTMLElement | null;
|
|
124
|
+
relativeX: number;
|
|
125
|
+
relativeY: number;
|
|
126
|
+
anchor: CommentAnchor | null;
|
|
127
|
+
anchorState: AnchorState;
|
|
128
|
+
/** Runtime-only: anchor element currently has zero size (not serialized). */
|
|
129
|
+
hidden: boolean;
|
|
130
|
+
/** Runtime-only: exact element the user clicked on (not serialized). */
|
|
131
|
+
target?: HTMLElement | null;
|
|
132
|
+
/** location.pathname where the comment was created. */
|
|
133
|
+
page: string;
|
|
134
|
+
replies: CommentReply[];
|
|
135
|
+
author: string;
|
|
136
|
+
createdAt: string;
|
|
137
|
+
screenshots: string[];
|
|
138
|
+
status: CommentStatus;
|
|
139
|
+
/** RF3 — `null` when deliberately unclassified. */
|
|
140
|
+
type: CommentType | null;
|
|
141
|
+
/** RF4 — `null` when deliberately unprioritised. */
|
|
142
|
+
priority: CommentPriority | null;
|
|
143
|
+
/**
|
|
144
|
+
* RF3 — free-form labels. `setCommentTags` normalises them (trimmed,
|
|
145
|
+
* lowercased, de-duplicated); values loaded via `loadComments` are
|
|
146
|
+
* trusted as-is and are not renormalised on read.
|
|
147
|
+
*/
|
|
148
|
+
tags: string[];
|
|
149
|
+
/** RF5 — set on entering "resolved", cleared on leaving it. */
|
|
150
|
+
resolvedAt: string | null;
|
|
151
|
+
/** RF2 — environment snapshot taken at creation. */
|
|
152
|
+
context: CommentContext | null;
|
|
153
|
+
/** RF1 — automatic viewport capture (JPEG data-URL). */
|
|
154
|
+
contextScreenshot: string | null;
|
|
155
|
+
/**
|
|
156
|
+
* RF6 — emoji → authors who reacted. Reserved, not implemented yet.
|
|
157
|
+
* Optional and absent by default, so shipping it later needs no migration.
|
|
158
|
+
*/
|
|
159
|
+
reactions?: Record<string, string[]>;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export declare class CommentOverlay {
|
|
163
|
+
comments: Comment[];
|
|
164
|
+
commentMode: boolean;
|
|
165
|
+
|
|
166
|
+
constructor(options?: Omit<CommentOverlayOptions, "autoInit">);
|
|
167
|
+
|
|
168
|
+
toggleCommentMode(): void;
|
|
169
|
+
addReply(comment: Comment, text: string): CommentReply;
|
|
170
|
+
serializeComments(): SerializedComment[];
|
|
171
|
+
loadComments(data: SerializedComment[]): {
|
|
172
|
+
anchored: number;
|
|
173
|
+
orphaned: number;
|
|
174
|
+
inactive: number;
|
|
175
|
+
};
|
|
176
|
+
deleteComment(id: number): boolean;
|
|
177
|
+
setCommentStatus(id: number, status: CommentStatus): boolean;
|
|
178
|
+
setCommentType(id: number, type: CommentType | null): boolean;
|
|
179
|
+
setCommentPriority(id: number, priority: CommentPriority | null): boolean;
|
|
180
|
+
setCommentTags(id: number, tags: string[]): boolean;
|
|
181
|
+
cleanup(): void;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* Creates a CommentOverlay and mounts it. Safe to call before the document
|
|
186
|
+
* is ready — the instance defers its own DOM work to `DOMContentLoaded`.
|
|
187
|
+
*/
|
|
188
|
+
export declare function createCommentOverlay(
|
|
189
|
+
options?: CommentOverlayOptions & { autoInit?: true }
|
|
190
|
+
): CommentOverlay;
|
|
191
|
+
/**
|
|
192
|
+
* With `autoInit: false`, nothing is mounted yet: you get an initializer to
|
|
193
|
+
* call when you are ready.
|
|
194
|
+
*/
|
|
195
|
+
export declare function createCommentOverlay(
|
|
196
|
+
options: CommentOverlayOptions & { autoInit: false }
|
|
197
|
+
): () => CommentOverlay;
|
|
198
|
+
|
|
199
|
+
export default createCommentOverlay;
|
package/package.json
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "helldots",
|
|
3
|
+
"version": "0.3.0",
|
|
4
|
+
"description": "Drop-in comment overlay for web apps — click anywhere to leave a comment anchored to that element, with an automatic screenshot and environment capture",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"comments",
|
|
7
|
+
"annotations",
|
|
8
|
+
"feedback",
|
|
9
|
+
"bug-report",
|
|
10
|
+
"screenshot",
|
|
11
|
+
"overlay",
|
|
12
|
+
"review",
|
|
13
|
+
"shadow-dom",
|
|
14
|
+
"widget"
|
|
15
|
+
],
|
|
16
|
+
"homepage": "https://github.com/xKeCo/helldots#readme",
|
|
17
|
+
"bugs": {
|
|
18
|
+
"url": "https://github.com/xKeCo/helldots/issues"
|
|
19
|
+
},
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "git+https://github.com/xKeCo/helldots.git"
|
|
23
|
+
},
|
|
24
|
+
"author": "xKeCo <kevcollazos@gmail.com>",
|
|
25
|
+
"license": "MIT",
|
|
26
|
+
"type": "module",
|
|
27
|
+
"sideEffects": false,
|
|
28
|
+
"exports": {
|
|
29
|
+
".": {
|
|
30
|
+
"types": "./dist/index.d.ts",
|
|
31
|
+
"import": "./dist/helldots.esm.js",
|
|
32
|
+
"default": "./dist/helldots.esm.js"
|
|
33
|
+
},
|
|
34
|
+
"./package.json": "./package.json"
|
|
35
|
+
},
|
|
36
|
+
"types": "./dist/index.d.ts",
|
|
37
|
+
"unpkg": "dist/helldots.umd.js",
|
|
38
|
+
"jsdelivr": "dist/helldots.umd.js",
|
|
39
|
+
"files": [
|
|
40
|
+
"dist/"
|
|
41
|
+
],
|
|
42
|
+
"engines": {
|
|
43
|
+
"node": ">=18"
|
|
44
|
+
},
|
|
45
|
+
"scripts": {
|
|
46
|
+
"test": "vitest run",
|
|
47
|
+
"test:coverage": "vitest run --coverage",
|
|
48
|
+
"lint": "eslint .",
|
|
49
|
+
"typecheck": "tsc --noEmit",
|
|
50
|
+
"format": "prettier --write .",
|
|
51
|
+
"format:check": "prettier --check .",
|
|
52
|
+
"build": "node scripts/build.mjs",
|
|
53
|
+
"size": "node scripts/check-size.mjs",
|
|
54
|
+
"verify": "npm run lint && npm run typecheck && npm run format:check && npm test && npm run build && npm run size",
|
|
55
|
+
"prepublishOnly": "npm run verify",
|
|
56
|
+
"changeset": "changeset",
|
|
57
|
+
"release": "changeset version"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@changesets/cli": "^2.31.0",
|
|
61
|
+
"@eslint/js": "^10.0.1",
|
|
62
|
+
"@vitest/coverage-v8": "^4.1.9",
|
|
63
|
+
"esbuild": "^0.28.1",
|
|
64
|
+
"eslint": "^10.6.0",
|
|
65
|
+
"eslint-config-prettier": "^10.1.8",
|
|
66
|
+
"globals": "^17.7.0",
|
|
67
|
+
"jsdom": "^29.1.1",
|
|
68
|
+
"prettier": "^3.9.4",
|
|
69
|
+
"typescript": "^6.0.3",
|
|
70
|
+
"vitest": "^4.1.9"
|
|
71
|
+
},
|
|
72
|
+
"dependencies": {
|
|
73
|
+
"modern-screenshot": "^4.7.0"
|
|
74
|
+
}
|
|
75
|
+
}
|