@jami-studio/pinpoint 0.1.12
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/.agents/skills/pinpoint/SKILL.md +77 -0
- package/README.md +412 -0
- package/dist/agent-context-HBCZ4MBN.js +13 -0
- package/dist/agent-context-HBCZ4MBN.js.map +1 -0
- package/dist/chunk-B7TY4FPP.js +569 -0
- package/dist/chunk-B7TY4FPP.js.map +1 -0
- package/dist/chunk-CGJZ7BOM.js +88 -0
- package/dist/chunk-CGJZ7BOM.js.map +1 -0
- package/dist/chunk-DGUM43GV.js +11 -0
- package/dist/chunk-DGUM43GV.js.map +1 -0
- package/dist/chunk-HAEYE6KB.js +25 -0
- package/dist/chunk-HAEYE6KB.js.map +1 -0
- package/dist/chunk-J5PXKVTM.js +53 -0
- package/dist/chunk-J5PXKVTM.js.map +1 -0
- package/dist/chunk-XBX2J7WU.js +94 -0
- package/dist/chunk-XBX2J7WU.js.map +1 -0
- package/dist/chunk-ZW7IO3EW.js +4927 -0
- package/dist/chunk-ZW7IO3EW.js.map +1 -0
- package/dist/cli.js +71 -0
- package/dist/cli.js.map +1 -0
- package/dist/formatter-CR4COA5Z.js +8 -0
- package/dist/formatter-CR4COA5Z.js.map +1 -0
- package/dist/index-NvFcZ4SO.d.ts +200 -0
- package/dist/index.browser.d.ts +377 -0
- package/dist/index.browser.js +620 -0
- package/dist/index.browser.js.map +1 -0
- package/dist/index.js +936 -0
- package/dist/index.js.map +1 -0
- package/dist/open-file-WR2JHI4P.js +8 -0
- package/dist/open-file-WR2JHI4P.js.map +1 -0
- package/dist/primitives/index.js +28 -0
- package/dist/primitives/index.js.map +1 -0
- package/dist/react.d.ts +23 -0
- package/dist/react.js +20 -0
- package/dist/react.js.map +1 -0
- package/dist/server/index.js +457 -0
- package/dist/server/index.js.map +1 -0
- package/dist/types/index.js +1 -0
- package/dist/types/index.js.map +1 -0
- package/package.json +88 -0
- package/src/scripts/create-pin.ts +43 -0
- package/src/scripts/delete-pin.ts +16 -0
- package/src/scripts/get-pins.ts +36 -0
- package/src/scripts/list-sessions.ts +33 -0
- package/src/scripts/resolve-pin.ts +27 -0
- package/src/scripts/run.ts +8 -0
- package/src/scripts/update-pin.ts +32 -0
|
@@ -0,0 +1,4927 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
// src/storage/memory-store.ts
|
|
4
|
+
var MemoryStore = class {
|
|
5
|
+
pins = /* @__PURE__ */ new Map();
|
|
6
|
+
async load(pageUrl) {
|
|
7
|
+
return Array.from(this.pins.values()).filter(
|
|
8
|
+
(pin) => pin.pageUrl === pageUrl
|
|
9
|
+
);
|
|
10
|
+
}
|
|
11
|
+
async save(pin) {
|
|
12
|
+
this.pins.set(pin.id, { ...pin });
|
|
13
|
+
}
|
|
14
|
+
async update(id, patch) {
|
|
15
|
+
const existing = this.pins.get(id);
|
|
16
|
+
if (!existing) return;
|
|
17
|
+
this.pins.set(id, {
|
|
18
|
+
...existing,
|
|
19
|
+
...patch,
|
|
20
|
+
id: existing.id,
|
|
21
|
+
// never overwrite ID
|
|
22
|
+
updatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
async delete(id) {
|
|
26
|
+
this.pins.delete(id);
|
|
27
|
+
}
|
|
28
|
+
async list(filter) {
|
|
29
|
+
let result = Array.from(this.pins.values());
|
|
30
|
+
if (filter?.pageUrl) {
|
|
31
|
+
result = result.filter((pin) => pin.pageUrl === filter.pageUrl);
|
|
32
|
+
}
|
|
33
|
+
if (filter?.status) {
|
|
34
|
+
result = result.filter((pin) => pin.status.state === filter.status);
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
async clear(pageUrl) {
|
|
39
|
+
if (pageUrl) {
|
|
40
|
+
for (const [id, pin] of this.pins) {
|
|
41
|
+
if (pin.pageUrl === pageUrl) {
|
|
42
|
+
this.pins.delete(id);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
} else {
|
|
46
|
+
this.pins.clear();
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// src/storage/schemas.ts
|
|
52
|
+
import { z } from "zod";
|
|
53
|
+
var ElementInfoSchema = z.object({
|
|
54
|
+
tagName: z.string(),
|
|
55
|
+
id: z.string().optional(),
|
|
56
|
+
classNames: z.array(z.string()),
|
|
57
|
+
selector: z.string(),
|
|
58
|
+
textContent: z.string().optional(),
|
|
59
|
+
boundingRect: z.object({
|
|
60
|
+
x: z.number(),
|
|
61
|
+
y: z.number(),
|
|
62
|
+
width: z.number(),
|
|
63
|
+
height: z.number()
|
|
64
|
+
}),
|
|
65
|
+
computedStyles: z.record(z.string(), z.string()).optional(),
|
|
66
|
+
ariaAttributes: z.record(z.string(), z.string()).optional(),
|
|
67
|
+
dataAttributes: z.record(z.string(), z.string()).optional(),
|
|
68
|
+
domPath: z.string().optional()
|
|
69
|
+
});
|
|
70
|
+
var FrameworkInfoSchema = z.object({
|
|
71
|
+
framework: z.string(),
|
|
72
|
+
componentPath: z.string(),
|
|
73
|
+
sourceFile: z.string().optional(),
|
|
74
|
+
frameworkVersion: z.string().optional()
|
|
75
|
+
});
|
|
76
|
+
var PinStatusSchema = z.enum([
|
|
77
|
+
"open",
|
|
78
|
+
"acknowledged",
|
|
79
|
+
"resolved",
|
|
80
|
+
"dismissed"
|
|
81
|
+
]);
|
|
82
|
+
var PinSchema = z.object({
|
|
83
|
+
id: z.string().uuid(),
|
|
84
|
+
pageUrl: z.string(),
|
|
85
|
+
createdAt: z.string().datetime(),
|
|
86
|
+
updatedAt: z.string().datetime(),
|
|
87
|
+
author: z.string().optional(),
|
|
88
|
+
comment: z.string(),
|
|
89
|
+
element: ElementInfoSchema,
|
|
90
|
+
framework: FrameworkInfoSchema.optional(),
|
|
91
|
+
status: z.object({
|
|
92
|
+
state: PinStatusSchema,
|
|
93
|
+
changedAt: z.string().datetime(),
|
|
94
|
+
changedBy: z.string().optional()
|
|
95
|
+
})
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// src/storage/rest-client.ts
|
|
99
|
+
var RestClient = class {
|
|
100
|
+
constructor(endpoint) {
|
|
101
|
+
this.endpoint = endpoint;
|
|
102
|
+
this.endpoint = endpoint.replace(/\/+$/, "");
|
|
103
|
+
}
|
|
104
|
+
endpoint;
|
|
105
|
+
async load(pageUrl) {
|
|
106
|
+
const params = new URLSearchParams({ pageUrl });
|
|
107
|
+
const res = await fetch(`${this.endpoint}?${params}`);
|
|
108
|
+
if (!res.ok) return [];
|
|
109
|
+
const data = await res.json();
|
|
110
|
+
return Array.isArray(data) ? data.filter((item) => PinSchema.safeParse(item).success) : [];
|
|
111
|
+
}
|
|
112
|
+
async save(pin) {
|
|
113
|
+
const res = await fetch(this.endpoint, {
|
|
114
|
+
method: "POST",
|
|
115
|
+
headers: { "Content-Type": "application/json" },
|
|
116
|
+
body: JSON.stringify(pin)
|
|
117
|
+
});
|
|
118
|
+
if (!res.ok) throw new Error(`Failed to save pin: ${res.status}`);
|
|
119
|
+
}
|
|
120
|
+
async update(id, patch) {
|
|
121
|
+
const res = await fetch(`${this.endpoint}/${encodeURIComponent(id)}`, {
|
|
122
|
+
method: "PATCH",
|
|
123
|
+
headers: { "Content-Type": "application/json" },
|
|
124
|
+
body: JSON.stringify(patch)
|
|
125
|
+
});
|
|
126
|
+
if (!res.ok) throw new Error(`Failed to update pin: ${res.status}`);
|
|
127
|
+
}
|
|
128
|
+
async delete(id) {
|
|
129
|
+
const res = await fetch(`${this.endpoint}/${encodeURIComponent(id)}`, {
|
|
130
|
+
method: "DELETE"
|
|
131
|
+
});
|
|
132
|
+
if (!res.ok) throw new Error(`Failed to delete pin: ${res.status}`);
|
|
133
|
+
}
|
|
134
|
+
async list(filter) {
|
|
135
|
+
const params = new URLSearchParams();
|
|
136
|
+
if (filter?.pageUrl) params.set("pageUrl", filter.pageUrl);
|
|
137
|
+
if (filter?.status) params.set("status", filter.status);
|
|
138
|
+
const res = await fetch(`${this.endpoint}?${params}`);
|
|
139
|
+
if (!res.ok) return [];
|
|
140
|
+
const data = await res.json();
|
|
141
|
+
return Array.isArray(data) ? data.filter((item) => PinSchema.safeParse(item).success) : [];
|
|
142
|
+
}
|
|
143
|
+
async clear(pageUrl) {
|
|
144
|
+
const params = new URLSearchParams();
|
|
145
|
+
if (pageUrl) params.set("pageUrl", pageUrl);
|
|
146
|
+
const res = await fetch(`${this.endpoint}?${params}`, { method: "DELETE" });
|
|
147
|
+
if (!res.ok) throw new Error(`Failed to clear pins: ${res.status}`);
|
|
148
|
+
}
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
// src/detection/element-picker.ts
|
|
152
|
+
var ElementPicker = class {
|
|
153
|
+
active = false;
|
|
154
|
+
paused = false;
|
|
155
|
+
hoveredElement = null;
|
|
156
|
+
rafId = null;
|
|
157
|
+
stableTimeout = null;
|
|
158
|
+
lastTarget = null;
|
|
159
|
+
options;
|
|
160
|
+
handleMouseMove;
|
|
161
|
+
handleClick;
|
|
162
|
+
handleKeyDown;
|
|
163
|
+
constructor(options = {}) {
|
|
164
|
+
this.options = options;
|
|
165
|
+
this.handleMouseMove = (e) => {
|
|
166
|
+
if (!this.active || this.paused) return;
|
|
167
|
+
if (this.isOwnUI(e)) return;
|
|
168
|
+
if (this.rafId !== null) return;
|
|
169
|
+
this.rafId = requestAnimationFrame(() => {
|
|
170
|
+
this.rafId = null;
|
|
171
|
+
this.processHover(e.clientX, e.clientY);
|
|
172
|
+
});
|
|
173
|
+
};
|
|
174
|
+
this.handleClick = (e) => {
|
|
175
|
+
if (!this.active || this.paused) return;
|
|
176
|
+
if (this.isOwnUI(e)) return;
|
|
177
|
+
e.preventDefault();
|
|
178
|
+
e.stopPropagation();
|
|
179
|
+
e.stopImmediatePropagation();
|
|
180
|
+
const target = this.hoveredElement;
|
|
181
|
+
if (target && !this.shouldIgnore(target)) {
|
|
182
|
+
this.options.onSelect?.(target);
|
|
183
|
+
}
|
|
184
|
+
};
|
|
185
|
+
this.handleKeyDown = (e) => {
|
|
186
|
+
if (!this.active) return;
|
|
187
|
+
if (e.key === "Escape") {
|
|
188
|
+
this.deactivate();
|
|
189
|
+
}
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Check if an event originates from Pinpoint's own UI.
|
|
194
|
+
* Uses composedPath() to cross Shadow DOM boundaries.
|
|
195
|
+
*/
|
|
196
|
+
isOwnUI(e) {
|
|
197
|
+
const path = e.composedPath();
|
|
198
|
+
for (const node of path) {
|
|
199
|
+
if (node instanceof HTMLElement) {
|
|
200
|
+
if (node.id === "pinpoint-root") return true;
|
|
201
|
+
if (node.hasAttribute?.("data-pinpoint-marker")) return true;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return false;
|
|
205
|
+
}
|
|
206
|
+
shouldIgnore(element) {
|
|
207
|
+
const root = element.getRootNode();
|
|
208
|
+
if (root instanceof ShadowRoot) {
|
|
209
|
+
const host = root.host;
|
|
210
|
+
if (host.id === "pinpoint-root") return true;
|
|
211
|
+
}
|
|
212
|
+
if (element.hasAttribute("data-pinpoint-marker")) return true;
|
|
213
|
+
if (element.closest?.("[data-pinpoint-marker]")) return true;
|
|
214
|
+
if (!this.options.ignoreSelector) return false;
|
|
215
|
+
return element.closest(this.options.ignoreSelector) !== null || element.matches(this.options.ignoreSelector);
|
|
216
|
+
}
|
|
217
|
+
pierceElementFromPoint(x, y) {
|
|
218
|
+
let element = document.elementFromPoint(x, y);
|
|
219
|
+
if (!element) return null;
|
|
220
|
+
while (element?.shadowRoot) {
|
|
221
|
+
const inner = element.shadowRoot.elementFromPoint(x, y);
|
|
222
|
+
if (!inner || inner === element) break;
|
|
223
|
+
element = inner;
|
|
224
|
+
}
|
|
225
|
+
return element;
|
|
226
|
+
}
|
|
227
|
+
processHover(x, y) {
|
|
228
|
+
const element = this.pierceElementFromPoint(x, y);
|
|
229
|
+
if (!element || this.shouldIgnore(element)) {
|
|
230
|
+
if (this.hoveredElement) {
|
|
231
|
+
this.hoveredElement = null;
|
|
232
|
+
this.lastTarget = null;
|
|
233
|
+
this.clearStableTimeout();
|
|
234
|
+
this.options.onHover?.(null, null);
|
|
235
|
+
}
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
if (element === this.lastTarget) return;
|
|
239
|
+
this.lastTarget = element;
|
|
240
|
+
this.hoveredElement = element;
|
|
241
|
+
const rect = element.getBoundingClientRect();
|
|
242
|
+
this.options.onHover?.(element, rect);
|
|
243
|
+
this.clearStableTimeout();
|
|
244
|
+
this.stableTimeout = setTimeout(() => {
|
|
245
|
+
if (this.hoveredElement === element) {
|
|
246
|
+
this.options.onStableHover?.(element);
|
|
247
|
+
}
|
|
248
|
+
}, 100);
|
|
249
|
+
}
|
|
250
|
+
clearStableTimeout() {
|
|
251
|
+
if (this.stableTimeout !== null) {
|
|
252
|
+
clearTimeout(this.stableTimeout);
|
|
253
|
+
this.stableTimeout = null;
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
activate() {
|
|
257
|
+
if (this.active) return;
|
|
258
|
+
this.active = true;
|
|
259
|
+
document.addEventListener("mousemove", this.handleMouseMove, true);
|
|
260
|
+
document.addEventListener("click", this.handleClick, true);
|
|
261
|
+
document.addEventListener("keydown", this.handleKeyDown, true);
|
|
262
|
+
if (this.options.blockInteractions) {
|
|
263
|
+
document.body.style.pointerEvents = "none";
|
|
264
|
+
const overlay = document.getElementById("pinpoint-root");
|
|
265
|
+
if (overlay) overlay.style.pointerEvents = "auto";
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
deactivate() {
|
|
269
|
+
if (!this.active) return;
|
|
270
|
+
this.active = false;
|
|
271
|
+
document.removeEventListener("mousemove", this.handleMouseMove, true);
|
|
272
|
+
document.removeEventListener("click", this.handleClick, true);
|
|
273
|
+
document.removeEventListener("keydown", this.handleKeyDown, true);
|
|
274
|
+
if (this.rafId !== null) {
|
|
275
|
+
cancelAnimationFrame(this.rafId);
|
|
276
|
+
this.rafId = null;
|
|
277
|
+
}
|
|
278
|
+
this.clearStableTimeout();
|
|
279
|
+
this.hoveredElement = null;
|
|
280
|
+
this.lastTarget = null;
|
|
281
|
+
if (this.options.blockInteractions) {
|
|
282
|
+
document.body.style.pointerEvents = "";
|
|
283
|
+
}
|
|
284
|
+
this.options.onHover?.(null, null);
|
|
285
|
+
}
|
|
286
|
+
/** Update blockInteractions at runtime (called from settings toggle) */
|
|
287
|
+
setBlockInteractions(value) {
|
|
288
|
+
const wasBlocking = this.options.blockInteractions;
|
|
289
|
+
this.options.blockInteractions = value;
|
|
290
|
+
if (this.active) {
|
|
291
|
+
if (value && !wasBlocking) {
|
|
292
|
+
document.body.style.pointerEvents = "none";
|
|
293
|
+
const overlay = document.getElementById("pinpoint-root");
|
|
294
|
+
if (overlay) overlay.style.pointerEvents = "auto";
|
|
295
|
+
} else if (!value && wasBlocking) {
|
|
296
|
+
document.body.style.pointerEvents = "";
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
/** Pause picking without removing listeners (e.g., while popup is open) */
|
|
301
|
+
pause() {
|
|
302
|
+
this.paused = true;
|
|
303
|
+
this.hoveredElement = null;
|
|
304
|
+
this.lastTarget = null;
|
|
305
|
+
this.clearStableTimeout();
|
|
306
|
+
this.options.onHover?.(null, null);
|
|
307
|
+
}
|
|
308
|
+
/** Resume picking after pause */
|
|
309
|
+
resume() {
|
|
310
|
+
this.paused = false;
|
|
311
|
+
}
|
|
312
|
+
isPaused() {
|
|
313
|
+
return this.paused;
|
|
314
|
+
}
|
|
315
|
+
isActive() {
|
|
316
|
+
return this.active;
|
|
317
|
+
}
|
|
318
|
+
/** Get the currently hovered element */
|
|
319
|
+
getHoveredElement() {
|
|
320
|
+
return this.hoveredElement;
|
|
321
|
+
}
|
|
322
|
+
dispose() {
|
|
323
|
+
this.deactivate();
|
|
324
|
+
}
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
// src/detection/selector-builder.ts
|
|
328
|
+
import { finder } from "@medv/finder";
|
|
329
|
+
var DEFAULT_SKIP_CLASSES = [
|
|
330
|
+
/^css-/,
|
|
331
|
+
// CSS-in-JS (Emotion, etc.)
|
|
332
|
+
/^_/,
|
|
333
|
+
// CSS Modules hashes
|
|
334
|
+
/^sc-/,
|
|
335
|
+
// styled-components
|
|
336
|
+
/^go\d/,
|
|
337
|
+
// Goober
|
|
338
|
+
/^tw-/,
|
|
339
|
+
// Tailwind utilities (sometimes hashed)
|
|
340
|
+
/^chakra-/
|
|
341
|
+
// Chakra UI internals
|
|
342
|
+
];
|
|
343
|
+
var DEFAULT_SKIP_IDS = [
|
|
344
|
+
/^:r[0-9]/,
|
|
345
|
+
// React auto-generated IDs
|
|
346
|
+
/^radix-/,
|
|
347
|
+
// Radix UI auto IDs
|
|
348
|
+
/^headlessui-/
|
|
349
|
+
// HeadlessUI auto IDs
|
|
350
|
+
];
|
|
351
|
+
function buildSelector(element, options = {}) {
|
|
352
|
+
const { timeoutMs = 200, skipClassPatterns = [] } = options;
|
|
353
|
+
const allSkipClasses = [...DEFAULT_SKIP_CLASSES, ...skipClassPatterns];
|
|
354
|
+
try {
|
|
355
|
+
return finder(element, {
|
|
356
|
+
className: (name) => !allSkipClasses.some((pattern) => pattern.test(name)),
|
|
357
|
+
idName: (name) => !DEFAULT_SKIP_IDS.some((pattern) => pattern.test(name)),
|
|
358
|
+
attr: (name) => name.startsWith("data-testid") || name.startsWith("data-cy"),
|
|
359
|
+
timeoutMs
|
|
360
|
+
});
|
|
361
|
+
} catch {
|
|
362
|
+
return buildFallbackSelector(element);
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
function buildFallbackSelector(element) {
|
|
366
|
+
const parts = [];
|
|
367
|
+
if (element.id) {
|
|
368
|
+
return `#${CSS.escape(element.id)}`;
|
|
369
|
+
}
|
|
370
|
+
parts.push(element.tagName.toLowerCase());
|
|
371
|
+
const testId = element.getAttribute("data-testid");
|
|
372
|
+
if (testId) {
|
|
373
|
+
return `[data-testid="${CSS.escape(testId)}"]`;
|
|
374
|
+
}
|
|
375
|
+
const classes = Array.from(element.classList).filter(
|
|
376
|
+
(name) => !DEFAULT_SKIP_CLASSES.some((pattern) => pattern.test(name))
|
|
377
|
+
);
|
|
378
|
+
if (classes.length > 0) {
|
|
379
|
+
parts.push(`.${classes.map((c) => CSS.escape(c)).join(".")}`);
|
|
380
|
+
}
|
|
381
|
+
const parent = element.parentElement;
|
|
382
|
+
if (parent) {
|
|
383
|
+
const siblings = Array.from(parent.children).filter(
|
|
384
|
+
(child) => child.tagName === element.tagName
|
|
385
|
+
);
|
|
386
|
+
if (siblings.length > 1) {
|
|
387
|
+
const index = siblings.indexOf(element) + 1;
|
|
388
|
+
parts.push(`:nth-child(${index})`);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return parts.join("");
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// src/detection/element-info.ts
|
|
395
|
+
var STYLE_KEYS = [
|
|
396
|
+
"color",
|
|
397
|
+
"backgroundColor",
|
|
398
|
+
"fontSize",
|
|
399
|
+
"fontFamily",
|
|
400
|
+
"fontWeight",
|
|
401
|
+
"lineHeight",
|
|
402
|
+
"padding",
|
|
403
|
+
"margin",
|
|
404
|
+
"border",
|
|
405
|
+
"borderRadius",
|
|
406
|
+
"display",
|
|
407
|
+
"position",
|
|
408
|
+
"width",
|
|
409
|
+
"height",
|
|
410
|
+
"opacity",
|
|
411
|
+
"zIndex",
|
|
412
|
+
"overflow",
|
|
413
|
+
"textAlign",
|
|
414
|
+
"textDecoration"
|
|
415
|
+
];
|
|
416
|
+
function extractElementInfo(element) {
|
|
417
|
+
const rect = element.getBoundingClientRect();
|
|
418
|
+
const computed = window.getComputedStyle(element);
|
|
419
|
+
const computedStyles = {};
|
|
420
|
+
for (const key of STYLE_KEYS) {
|
|
421
|
+
const value = computed.getPropertyValue(
|
|
422
|
+
key.replace(/([A-Z])/g, "-$1").toLowerCase()
|
|
423
|
+
);
|
|
424
|
+
if (value) {
|
|
425
|
+
computedStyles[key] = value;
|
|
426
|
+
}
|
|
427
|
+
}
|
|
428
|
+
const ariaAttributes = {};
|
|
429
|
+
for (const attr of element.attributes) {
|
|
430
|
+
if (attr.name.startsWith("aria-") || attr.name === "role") {
|
|
431
|
+
ariaAttributes[attr.name] = attr.value;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
const dataAttributes = {};
|
|
435
|
+
for (const attr of element.attributes) {
|
|
436
|
+
if (attr.name.startsWith("data-")) {
|
|
437
|
+
dataAttributes[attr.name] = attr.value;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
const domPath = buildDomPath(element);
|
|
441
|
+
const textContent = getTextContent(element);
|
|
442
|
+
return {
|
|
443
|
+
tagName: element.tagName.toLowerCase(),
|
|
444
|
+
id: element.id || void 0,
|
|
445
|
+
classNames: Array.from(element.classList),
|
|
446
|
+
selector: buildSelector(element),
|
|
447
|
+
textContent,
|
|
448
|
+
boundingRect: {
|
|
449
|
+
x: Math.round(rect.x),
|
|
450
|
+
y: Math.round(rect.y),
|
|
451
|
+
width: Math.round(rect.width),
|
|
452
|
+
height: Math.round(rect.height)
|
|
453
|
+
},
|
|
454
|
+
computedStyles,
|
|
455
|
+
ariaAttributes: Object.keys(ariaAttributes).length > 0 ? ariaAttributes : void 0,
|
|
456
|
+
dataAttributes: Object.keys(dataAttributes).length > 0 ? dataAttributes : void 0,
|
|
457
|
+
domPath
|
|
458
|
+
};
|
|
459
|
+
}
|
|
460
|
+
function buildElementContext(element, frameworkInfo) {
|
|
461
|
+
const info = extractElementInfo(element);
|
|
462
|
+
const htmlSnippet = getCleanedHtml(element);
|
|
463
|
+
return {
|
|
464
|
+
element: info,
|
|
465
|
+
framework: frameworkInfo,
|
|
466
|
+
htmlSnippet,
|
|
467
|
+
cssSelector: info.selector,
|
|
468
|
+
computedStyles: info.computedStyles || {}
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
function getTextContent(element) {
|
|
472
|
+
let text = "";
|
|
473
|
+
for (const node of element.childNodes) {
|
|
474
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
475
|
+
text += node.textContent?.trim() || "";
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
if (!text) {
|
|
479
|
+
text = element.textContent?.trim() || "";
|
|
480
|
+
}
|
|
481
|
+
if (!text) return void 0;
|
|
482
|
+
return text.length > 200 ? text.slice(0, 200) + "..." : text;
|
|
483
|
+
}
|
|
484
|
+
function buildDomPath(element) {
|
|
485
|
+
const parts = [];
|
|
486
|
+
let current = element;
|
|
487
|
+
while (current && current !== document.documentElement) {
|
|
488
|
+
let part = current.tagName.toLowerCase();
|
|
489
|
+
if (current.id) {
|
|
490
|
+
part += `#${current.id}`;
|
|
491
|
+
} else if (current.classList.length > 0) {
|
|
492
|
+
const firstClass = current.classList[0];
|
|
493
|
+
if (firstClass && !/^(css-|_|sc-)/.test(firstClass)) {
|
|
494
|
+
part += `.${firstClass}`;
|
|
495
|
+
}
|
|
496
|
+
}
|
|
497
|
+
parts.unshift(part);
|
|
498
|
+
current = current.parentElement;
|
|
499
|
+
}
|
|
500
|
+
return parts.join(" > ");
|
|
501
|
+
}
|
|
502
|
+
function getCleanedHtml(element, maxLength = 500) {
|
|
503
|
+
const clone = element.cloneNode(true);
|
|
504
|
+
const allElements = [clone, ...Array.from(clone.querySelectorAll("*"))];
|
|
505
|
+
for (const el of allElements) {
|
|
506
|
+
for (const attr of Array.from(el.attributes)) {
|
|
507
|
+
if (attr.name.startsWith("on")) {
|
|
508
|
+
el.removeAttribute(attr.name);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
let html = clone.outerHTML;
|
|
513
|
+
html = html.replace(/\s+/g, " ").trim();
|
|
514
|
+
if (html.length > maxLength) {
|
|
515
|
+
const openTagEnd = html.indexOf(">") + 1;
|
|
516
|
+
if (openTagEnd > 0 && openTagEnd < maxLength) {
|
|
517
|
+
html = html.slice(0, maxLength) + "...";
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
return html;
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
// src/detection/drag-select.ts
|
|
524
|
+
var DragSelect = class {
|
|
525
|
+
active = false;
|
|
526
|
+
dragging = false;
|
|
527
|
+
startX = 0;
|
|
528
|
+
startY = 0;
|
|
529
|
+
options;
|
|
530
|
+
handleMouseDown;
|
|
531
|
+
handleMouseMove;
|
|
532
|
+
handleMouseUp;
|
|
533
|
+
constructor(options = {}) {
|
|
534
|
+
this.options = { coverageThreshold: 0.75, ...options };
|
|
535
|
+
this.handleMouseDown = (e) => {
|
|
536
|
+
if (!this.active || e.button !== 0) return;
|
|
537
|
+
if (!e.shiftKey) return;
|
|
538
|
+
e.preventDefault();
|
|
539
|
+
this.dragging = true;
|
|
540
|
+
this.startX = e.clientX;
|
|
541
|
+
this.startY = e.clientY;
|
|
542
|
+
const rect = this.buildRect(e.clientX, e.clientY);
|
|
543
|
+
this.options.onDragStart?.(
|
|
544
|
+
new DOMRect(rect.x, rect.y, rect.width, rect.height)
|
|
545
|
+
);
|
|
546
|
+
};
|
|
547
|
+
this.handleMouseMove = (e) => {
|
|
548
|
+
if (!this.dragging) return;
|
|
549
|
+
e.preventDefault();
|
|
550
|
+
const rect = this.buildRect(e.clientX, e.clientY);
|
|
551
|
+
this.options.onDragMove?.(
|
|
552
|
+
new DOMRect(rect.x, rect.y, rect.width, rect.height)
|
|
553
|
+
);
|
|
554
|
+
};
|
|
555
|
+
this.handleMouseUp = (e) => {
|
|
556
|
+
if (!this.dragging) return;
|
|
557
|
+
this.dragging = false;
|
|
558
|
+
const selectionRect = this.buildRect(e.clientX, e.clientY);
|
|
559
|
+
if (selectionRect.width < 5 && selectionRect.height < 5) return;
|
|
560
|
+
const selected = this.getElementsInRect(selectionRect);
|
|
561
|
+
this.options.onDragEnd?.(selected);
|
|
562
|
+
};
|
|
563
|
+
}
|
|
564
|
+
buildRect(currentX, currentY) {
|
|
565
|
+
return {
|
|
566
|
+
x: Math.min(this.startX, currentX),
|
|
567
|
+
y: Math.min(this.startY, currentY),
|
|
568
|
+
width: Math.abs(currentX - this.startX),
|
|
569
|
+
height: Math.abs(currentY - this.startY)
|
|
570
|
+
};
|
|
571
|
+
}
|
|
572
|
+
getElementsInRect(selectionRect) {
|
|
573
|
+
const threshold = this.options.coverageThreshold;
|
|
574
|
+
const elements = [];
|
|
575
|
+
const walker = document.createTreeWalker(
|
|
576
|
+
document.body,
|
|
577
|
+
NodeFilter.SHOW_ELEMENT,
|
|
578
|
+
{
|
|
579
|
+
acceptNode: (node2) => {
|
|
580
|
+
const el = node2;
|
|
581
|
+
if (this.options.ignoreSelector && el.matches(this.options.ignoreSelector)) {
|
|
582
|
+
return NodeFilter.FILTER_REJECT;
|
|
583
|
+
}
|
|
584
|
+
return NodeFilter.FILTER_ACCEPT;
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
);
|
|
588
|
+
let node;
|
|
589
|
+
while (node = walker.nextNode()) {
|
|
590
|
+
const el = node;
|
|
591
|
+
const rect = el.getBoundingClientRect();
|
|
592
|
+
if (rect.width === 0 || rect.height === 0) continue;
|
|
593
|
+
const overlapX = Math.max(
|
|
594
|
+
0,
|
|
595
|
+
Math.min(rect.right, selectionRect.x + selectionRect.width) - Math.max(rect.left, selectionRect.x)
|
|
596
|
+
);
|
|
597
|
+
const overlapY = Math.max(
|
|
598
|
+
0,
|
|
599
|
+
Math.min(rect.bottom, selectionRect.y + selectionRect.height) - Math.max(rect.top, selectionRect.y)
|
|
600
|
+
);
|
|
601
|
+
const overlapArea = overlapX * overlapY;
|
|
602
|
+
const elementArea = rect.width * rect.height;
|
|
603
|
+
const coverage = overlapArea / elementArea;
|
|
604
|
+
if (coverage >= threshold) {
|
|
605
|
+
if (el.children.length === 0 || rect.width < 400) {
|
|
606
|
+
elements.push(el);
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
return elements;
|
|
611
|
+
}
|
|
612
|
+
activate() {
|
|
613
|
+
if (this.active) return;
|
|
614
|
+
this.active = true;
|
|
615
|
+
document.addEventListener("mousedown", this.handleMouseDown, true);
|
|
616
|
+
document.addEventListener("mousemove", this.handleMouseMove, true);
|
|
617
|
+
document.addEventListener("mouseup", this.handleMouseUp, true);
|
|
618
|
+
}
|
|
619
|
+
deactivate() {
|
|
620
|
+
if (!this.active) return;
|
|
621
|
+
this.active = false;
|
|
622
|
+
this.dragging = false;
|
|
623
|
+
document.removeEventListener("mousedown", this.handleMouseDown, true);
|
|
624
|
+
document.removeEventListener("mousemove", this.handleMouseMove, true);
|
|
625
|
+
document.removeEventListener("mouseup", this.handleMouseUp, true);
|
|
626
|
+
}
|
|
627
|
+
isDragging() {
|
|
628
|
+
return this.dragging;
|
|
629
|
+
}
|
|
630
|
+
dispose() {
|
|
631
|
+
this.deactivate();
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
// src/detection/text-select.ts
|
|
636
|
+
var TextSelect = class {
|
|
637
|
+
active = false;
|
|
638
|
+
options;
|
|
639
|
+
handleSelectionChange;
|
|
640
|
+
debounceTimer = null;
|
|
641
|
+
constructor(options = {}) {
|
|
642
|
+
this.options = { minLength: 3, ...options };
|
|
643
|
+
this.handleSelectionChange = () => {
|
|
644
|
+
if (!this.active) return;
|
|
645
|
+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
646
|
+
this.debounceTimer = setTimeout(() => {
|
|
647
|
+
const selection = this.getTextSelection();
|
|
648
|
+
this.options.onSelect?.(selection);
|
|
649
|
+
}, 150);
|
|
650
|
+
};
|
|
651
|
+
}
|
|
652
|
+
getTextSelection() {
|
|
653
|
+
const selection = window.getSelection();
|
|
654
|
+
if (!selection || selection.isCollapsed || selection.rangeCount === 0) {
|
|
655
|
+
return null;
|
|
656
|
+
}
|
|
657
|
+
const text = selection.toString().trim();
|
|
658
|
+
if (text.length < (this.options.minLength ?? 3)) {
|
|
659
|
+
return null;
|
|
660
|
+
}
|
|
661
|
+
const range = selection.getRangeAt(0);
|
|
662
|
+
const container = range.commonAncestorContainer.nodeType === Node.ELEMENT_NODE ? range.commonAncestorContainer : range.commonAncestorContainer.parentElement;
|
|
663
|
+
if (!container) return null;
|
|
664
|
+
const fullText = container.textContent || "";
|
|
665
|
+
const startOffset = range.startOffset;
|
|
666
|
+
const endOffset = range.endOffset;
|
|
667
|
+
const contextBefore = fullText.slice(
|
|
668
|
+
Math.max(0, startOffset - 50),
|
|
669
|
+
startOffset
|
|
670
|
+
);
|
|
671
|
+
const contextAfter = fullText.slice(endOffset, endOffset + 50);
|
|
672
|
+
const context = `...${contextBefore}[${text}]${contextAfter}...`;
|
|
673
|
+
const rect = range.getBoundingClientRect();
|
|
674
|
+
return {
|
|
675
|
+
text,
|
|
676
|
+
container,
|
|
677
|
+
startOffset,
|
|
678
|
+
endOffset,
|
|
679
|
+
context,
|
|
680
|
+
rect
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
activate() {
|
|
684
|
+
if (this.active) return;
|
|
685
|
+
this.active = true;
|
|
686
|
+
document.addEventListener("selectionchange", this.handleSelectionChange);
|
|
687
|
+
}
|
|
688
|
+
deactivate() {
|
|
689
|
+
if (!this.active) return;
|
|
690
|
+
this.active = false;
|
|
691
|
+
document.removeEventListener("selectionchange", this.handleSelectionChange);
|
|
692
|
+
if (this.debounceTimer) {
|
|
693
|
+
clearTimeout(this.debounceTimer);
|
|
694
|
+
this.debounceTimer = null;
|
|
695
|
+
}
|
|
696
|
+
}
|
|
697
|
+
/** Get the current text selection, if any */
|
|
698
|
+
getCurrentSelection() {
|
|
699
|
+
return this.getTextSelection();
|
|
700
|
+
}
|
|
701
|
+
dispose() {
|
|
702
|
+
this.deactivate();
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
|
|
706
|
+
// src/frameworks/adapter.ts
|
|
707
|
+
var adapters = [];
|
|
708
|
+
var detectedAdapter = null;
|
|
709
|
+
var detected = false;
|
|
710
|
+
function registerAdapter(adapter) {
|
|
711
|
+
adapters.push(adapter);
|
|
712
|
+
detected = false;
|
|
713
|
+
detectedAdapter = null;
|
|
714
|
+
}
|
|
715
|
+
function detectFramework() {
|
|
716
|
+
if (detected && detectedAdapter) return detectedAdapter;
|
|
717
|
+
for (const adapter of adapters) {
|
|
718
|
+
try {
|
|
719
|
+
if (adapter.detect()) {
|
|
720
|
+
detectedAdapter = adapter;
|
|
721
|
+
detected = true;
|
|
722
|
+
return adapter;
|
|
723
|
+
}
|
|
724
|
+
} catch {
|
|
725
|
+
}
|
|
726
|
+
}
|
|
727
|
+
detectedAdapter = genericAdapter;
|
|
728
|
+
detected = true;
|
|
729
|
+
return genericAdapter;
|
|
730
|
+
}
|
|
731
|
+
function getComponentInfo(element) {
|
|
732
|
+
const adapter = detectFramework();
|
|
733
|
+
try {
|
|
734
|
+
return adapter.getComponentInfo(element);
|
|
735
|
+
} catch {
|
|
736
|
+
return null;
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
function getSourceLocation(element) {
|
|
740
|
+
const adapter = detectFramework();
|
|
741
|
+
try {
|
|
742
|
+
return adapter.getSourceLocation(element);
|
|
743
|
+
} catch {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
var genericAdapter = {
|
|
748
|
+
name: "generic",
|
|
749
|
+
detect: () => true,
|
|
750
|
+
// Always matches as fallback
|
|
751
|
+
getComponentInfo: () => null,
|
|
752
|
+
getSourceLocation: () => null
|
|
753
|
+
};
|
|
754
|
+
|
|
755
|
+
// src/ui/components/PinMarker.tsx
|
|
756
|
+
var MAX_MARKERS = 100;
|
|
757
|
+
var BADGE_SIZE = 20;
|
|
758
|
+
var BADGE_FONT = 11;
|
|
759
|
+
var BADGE_OFFSET = -10;
|
|
760
|
+
var STATUS_COLORS = {
|
|
761
|
+
open: "#3b82f6",
|
|
762
|
+
acknowledged: "#eab308",
|
|
763
|
+
resolved: "#22c55e",
|
|
764
|
+
dismissed: "#a1a1aa"
|
|
765
|
+
};
|
|
766
|
+
var PinMarkerManager = class {
|
|
767
|
+
markers = /* @__PURE__ */ new Map();
|
|
768
|
+
updateTimer = null;
|
|
769
|
+
onClick = null;
|
|
770
|
+
onToggleSelect = null;
|
|
771
|
+
selectedPinIds = /* @__PURE__ */ new Set();
|
|
772
|
+
showCheckboxes = false;
|
|
773
|
+
constructor(markerColor = "#3b82f6") {
|
|
774
|
+
this.markerColor = markerColor;
|
|
775
|
+
}
|
|
776
|
+
setOnClick(handler) {
|
|
777
|
+
this.onClick = handler;
|
|
778
|
+
}
|
|
779
|
+
setOnToggleSelect(handler) {
|
|
780
|
+
this.onToggleSelect = handler;
|
|
781
|
+
}
|
|
782
|
+
setSelectedPins(ids) {
|
|
783
|
+
this.selectedPinIds = ids;
|
|
784
|
+
for (const [id, pair] of this.markers) {
|
|
785
|
+
this.updateCheckboxVisual(pair.checkbox, ids.has(id));
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
setShowCheckboxes(show) {
|
|
789
|
+
this.showCheckboxes = show;
|
|
790
|
+
for (const pair of this.markers.values()) {
|
|
791
|
+
pair.checkbox.style.display = show ? "flex" : "none";
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
update(pins) {
|
|
795
|
+
const visiblePins = pins.slice(0, MAX_MARKERS);
|
|
796
|
+
const pinIds = new Set(visiblePins.map((p) => p.id));
|
|
797
|
+
for (const [id, pair] of this.markers) {
|
|
798
|
+
if (!pinIds.has(id)) {
|
|
799
|
+
pair.wrapper.remove();
|
|
800
|
+
this.markers.delete(id);
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
for (let i = 0; i < visiblePins.length; i++) {
|
|
804
|
+
this.updateMarker(visiblePins[i], i + 1);
|
|
805
|
+
}
|
|
806
|
+
}
|
|
807
|
+
updateCheckboxVisual(checkbox, selected) {
|
|
808
|
+
const inner = checkbox.querySelector(".pp-marker-checkbox-inner");
|
|
809
|
+
if (!inner) return;
|
|
810
|
+
if (selected) {
|
|
811
|
+
inner.style.background = "#3b82f6";
|
|
812
|
+
inner.style.borderColor = "#3b82f6";
|
|
813
|
+
inner.innerHTML = `<svg width="10" height="10" viewBox="0 0 24 24" fill="none" stroke="#fff" stroke-width="3" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5l10 -10"/></svg>`;
|
|
814
|
+
} else {
|
|
815
|
+
inner.style.background = "rgba(0,0,0,0.5)";
|
|
816
|
+
inner.style.borderColor = "rgba(255,255,255,0.3)";
|
|
817
|
+
inner.innerHTML = "";
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
updateMarker(pin, number) {
|
|
821
|
+
const element = document.querySelector(pin.element.selector);
|
|
822
|
+
if (!element) {
|
|
823
|
+
const existing = this.markers.get(pin.id);
|
|
824
|
+
if (existing) existing.wrapper.style.display = "none";
|
|
825
|
+
return;
|
|
826
|
+
}
|
|
827
|
+
let pair = this.markers.get(pin.id);
|
|
828
|
+
const statusColor = STATUS_COLORS[pin.status.state] || this.markerColor;
|
|
829
|
+
if (!pair) {
|
|
830
|
+
const wrapper = document.createElement("div");
|
|
831
|
+
wrapper.setAttribute("data-pinpoint-marker", pin.id);
|
|
832
|
+
wrapper.style.cssText = `
|
|
833
|
+
position: fixed;
|
|
834
|
+
z-index: 2147483646;
|
|
835
|
+
pointer-events: none;
|
|
836
|
+
`;
|
|
837
|
+
const outline = document.createElement("div");
|
|
838
|
+
outline.style.cssText = `
|
|
839
|
+
position: absolute;
|
|
840
|
+
top: 0; left: 0;
|
|
841
|
+
width: 100%; height: 100%;
|
|
842
|
+
border: 1.5px solid ${statusColor};
|
|
843
|
+
border-radius: 3px;
|
|
844
|
+
pointer-events: none;
|
|
845
|
+
opacity: 0.6;
|
|
846
|
+
`;
|
|
847
|
+
const badge = document.createElement("div");
|
|
848
|
+
badge.style.cssText = `
|
|
849
|
+
position: absolute;
|
|
850
|
+
top: ${BADGE_OFFSET}px;
|
|
851
|
+
right: ${BADGE_OFFSET}px;
|
|
852
|
+
width: ${BADGE_SIZE}px;
|
|
853
|
+
height: ${BADGE_SIZE}px;
|
|
854
|
+
min-width: ${BADGE_SIZE}px;
|
|
855
|
+
padding: 0 4px;
|
|
856
|
+
border-radius: ${BADGE_SIZE / 2}px;
|
|
857
|
+
display: flex;
|
|
858
|
+
align-items: center;
|
|
859
|
+
justify-content: center;
|
|
860
|
+
font-size: ${BADGE_FONT}px;
|
|
861
|
+
font-weight: 600;
|
|
862
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
|
|
863
|
+
font-variant-numeric: tabular-nums;
|
|
864
|
+
color: #fff;
|
|
865
|
+
background: ${statusColor};
|
|
866
|
+
box-shadow: 0 1px 4px rgba(0,0,0,0.2);
|
|
867
|
+
cursor: pointer;
|
|
868
|
+
pointer-events: auto;
|
|
869
|
+
user-select: none;
|
|
870
|
+
z-index: 1;
|
|
871
|
+
animation: pp-badge-appear 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
|
872
|
+
`;
|
|
873
|
+
if (!document.getElementById("pp-marker-keyframes")) {
|
|
874
|
+
const style2 = document.createElement("style");
|
|
875
|
+
style2.id = "pp-marker-keyframes";
|
|
876
|
+
style2.textContent = `
|
|
877
|
+
@keyframes pp-badge-appear {
|
|
878
|
+
from { transform: scale(0); opacity: 0; }
|
|
879
|
+
to { transform: scale(1); opacity: 1; }
|
|
880
|
+
}
|
|
881
|
+
`;
|
|
882
|
+
document.head.appendChild(style2);
|
|
883
|
+
}
|
|
884
|
+
badge.addEventListener("click", (e) => {
|
|
885
|
+
e.stopPropagation();
|
|
886
|
+
e.preventDefault();
|
|
887
|
+
this.onClick?.(pin);
|
|
888
|
+
});
|
|
889
|
+
badge.addEventListener("mouseenter", () => {
|
|
890
|
+
badge.style.transform = "scale(1.15)";
|
|
891
|
+
});
|
|
892
|
+
badge.addEventListener("mouseleave", () => {
|
|
893
|
+
badge.style.transform = "scale(1)";
|
|
894
|
+
});
|
|
895
|
+
const checkbox = document.createElement("div");
|
|
896
|
+
checkbox.style.cssText = `
|
|
897
|
+
position: absolute;
|
|
898
|
+
top: ${BADGE_OFFSET}px;
|
|
899
|
+
left: ${BADGE_OFFSET}px;
|
|
900
|
+
width: ${BADGE_SIZE}px;
|
|
901
|
+
height: ${BADGE_SIZE}px;
|
|
902
|
+
display: ${this.showCheckboxes ? "flex" : "none"};
|
|
903
|
+
align-items: center;
|
|
904
|
+
justify-content: center;
|
|
905
|
+
cursor: pointer;
|
|
906
|
+
pointer-events: auto;
|
|
907
|
+
z-index: 1;
|
|
908
|
+
`;
|
|
909
|
+
const checkboxInner = document.createElement("div");
|
|
910
|
+
checkboxInner.className = "pp-marker-checkbox-inner";
|
|
911
|
+
checkboxInner.style.cssText = `
|
|
912
|
+
width: 16px;
|
|
913
|
+
height: 16px;
|
|
914
|
+
border-radius: 4px;
|
|
915
|
+
border: 1.5px solid rgba(255,255,255,0.3);
|
|
916
|
+
background: rgba(0,0,0,0.5);
|
|
917
|
+
display: flex;
|
|
918
|
+
align-items: center;
|
|
919
|
+
justify-content: center;
|
|
920
|
+
`;
|
|
921
|
+
checkbox.appendChild(checkboxInner);
|
|
922
|
+
checkbox.addEventListener("click", (e) => {
|
|
923
|
+
e.stopPropagation();
|
|
924
|
+
e.preventDefault();
|
|
925
|
+
this.onToggleSelect?.(pin);
|
|
926
|
+
});
|
|
927
|
+
const resolvedOverlay = document.createElement("div");
|
|
928
|
+
resolvedOverlay.style.cssText = `
|
|
929
|
+
position: absolute;
|
|
930
|
+
top: 0; left: 0;
|
|
931
|
+
width: 100%; height: 100%;
|
|
932
|
+
display: ${pin.status.state === "resolved" ? "flex" : "none"};
|
|
933
|
+
align-items: center;
|
|
934
|
+
justify-content: center;
|
|
935
|
+
background: rgba(34, 197, 94, 0.12);
|
|
936
|
+
border-radius: 3px;
|
|
937
|
+
pointer-events: none;
|
|
938
|
+
`;
|
|
939
|
+
resolvedOverlay.innerHTML = `<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="#22c55e" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><path d="M5 12l5 5l10 -10"/></svg>`;
|
|
940
|
+
wrapper.appendChild(outline);
|
|
941
|
+
wrapper.appendChild(badge);
|
|
942
|
+
wrapper.appendChild(checkbox);
|
|
943
|
+
wrapper.appendChild(resolvedOverlay);
|
|
944
|
+
document.body.appendChild(wrapper);
|
|
945
|
+
pair = {
|
|
946
|
+
wrapper,
|
|
947
|
+
outline,
|
|
948
|
+
badge,
|
|
949
|
+
checkbox,
|
|
950
|
+
resolvedOverlay
|
|
951
|
+
};
|
|
952
|
+
this.markers.set(pin.id, pair);
|
|
953
|
+
}
|
|
954
|
+
pair.badge.textContent = String(number);
|
|
955
|
+
pair.badge.title = pin.comment;
|
|
956
|
+
pair.badge.style.background = statusColor;
|
|
957
|
+
pair.outline.style.borderColor = statusColor;
|
|
958
|
+
pair.resolvedOverlay.style.display = pin.status.state === "resolved" ? "flex" : "none";
|
|
959
|
+
this.updateCheckboxVisual(pair.checkbox, this.selectedPinIds.has(pin.id));
|
|
960
|
+
const rect = element.getBoundingClientRect();
|
|
961
|
+
pair.wrapper.style.left = `${rect.left}px`;
|
|
962
|
+
pair.wrapper.style.top = `${rect.top}px`;
|
|
963
|
+
pair.wrapper.style.width = `${rect.width}px`;
|
|
964
|
+
pair.wrapper.style.height = `${rect.height}px`;
|
|
965
|
+
const visible = rect.bottom > 0 && rect.top < window.innerHeight && rect.right > 0 && rect.left < window.innerWidth;
|
|
966
|
+
pair.wrapper.style.display = visible ? "block" : "none";
|
|
967
|
+
}
|
|
968
|
+
startTracking(pins) {
|
|
969
|
+
this.stopTracking();
|
|
970
|
+
this.update(pins);
|
|
971
|
+
this.updateTimer = setInterval(() => this.update(pins), 200);
|
|
972
|
+
}
|
|
973
|
+
stopTracking() {
|
|
974
|
+
if (this.updateTimer) {
|
|
975
|
+
clearInterval(this.updateTimer);
|
|
976
|
+
this.updateTimer = null;
|
|
977
|
+
}
|
|
978
|
+
}
|
|
979
|
+
dispose() {
|
|
980
|
+
this.stopTracking();
|
|
981
|
+
for (const pair of this.markers.values()) {
|
|
982
|
+
pair.wrapper.remove();
|
|
983
|
+
}
|
|
984
|
+
this.markers.clear();
|
|
985
|
+
}
|
|
986
|
+
};
|
|
987
|
+
|
|
988
|
+
// ../../node_modules/.pnpm/solid-js@1.9.13/node_modules/solid-js/dist/solid.js
|
|
989
|
+
var sharedConfig = {
|
|
990
|
+
context: void 0,
|
|
991
|
+
registry: void 0,
|
|
992
|
+
effects: void 0,
|
|
993
|
+
done: false,
|
|
994
|
+
getContextId() {
|
|
995
|
+
return getContextId(this.context.count);
|
|
996
|
+
},
|
|
997
|
+
getNextContextId() {
|
|
998
|
+
return getContextId(this.context.count++);
|
|
999
|
+
}
|
|
1000
|
+
};
|
|
1001
|
+
function getContextId(count) {
|
|
1002
|
+
const num = String(count), len = num.length - 1;
|
|
1003
|
+
return sharedConfig.context.id + (len ? String.fromCharCode(96 + len) : "") + num;
|
|
1004
|
+
}
|
|
1005
|
+
function setHydrateContext(context) {
|
|
1006
|
+
sharedConfig.context = context;
|
|
1007
|
+
}
|
|
1008
|
+
function nextHydrateContext() {
|
|
1009
|
+
return {
|
|
1010
|
+
...sharedConfig.context,
|
|
1011
|
+
id: sharedConfig.getNextContextId(),
|
|
1012
|
+
count: 0
|
|
1013
|
+
};
|
|
1014
|
+
}
|
|
1015
|
+
var IS_DEV = false;
|
|
1016
|
+
var equalFn = (a, b) => a === b;
|
|
1017
|
+
var $TRACK = /* @__PURE__ */ Symbol("solid-track");
|
|
1018
|
+
var signalOptions = {
|
|
1019
|
+
equals: equalFn
|
|
1020
|
+
};
|
|
1021
|
+
var ERROR = null;
|
|
1022
|
+
var runEffects = runQueue;
|
|
1023
|
+
var STALE = 1;
|
|
1024
|
+
var PENDING = 2;
|
|
1025
|
+
var UNOWNED = {
|
|
1026
|
+
owned: null,
|
|
1027
|
+
cleanups: null,
|
|
1028
|
+
context: null,
|
|
1029
|
+
owner: null
|
|
1030
|
+
};
|
|
1031
|
+
var Owner = null;
|
|
1032
|
+
var Transition = null;
|
|
1033
|
+
var Scheduler = null;
|
|
1034
|
+
var ExternalSourceConfig = null;
|
|
1035
|
+
var Listener = null;
|
|
1036
|
+
var Updates = null;
|
|
1037
|
+
var Effects = null;
|
|
1038
|
+
var ExecCount = 0;
|
|
1039
|
+
function createRoot(fn, detachedOwner) {
|
|
1040
|
+
const listener = Listener, owner = Owner, unowned = fn.length === 0, current = detachedOwner === void 0 ? owner : detachedOwner, root = unowned ? UNOWNED : {
|
|
1041
|
+
owned: null,
|
|
1042
|
+
cleanups: null,
|
|
1043
|
+
context: current ? current.context : null,
|
|
1044
|
+
owner: current
|
|
1045
|
+
}, updateFn = unowned ? fn : () => fn(() => untrack(() => cleanNode(root)));
|
|
1046
|
+
Owner = root;
|
|
1047
|
+
Listener = null;
|
|
1048
|
+
try {
|
|
1049
|
+
return runUpdates(updateFn, true);
|
|
1050
|
+
} finally {
|
|
1051
|
+
Listener = listener;
|
|
1052
|
+
Owner = owner;
|
|
1053
|
+
}
|
|
1054
|
+
}
|
|
1055
|
+
function createSignal(value, options) {
|
|
1056
|
+
options = options ? Object.assign({}, signalOptions, options) : signalOptions;
|
|
1057
|
+
const s = {
|
|
1058
|
+
value,
|
|
1059
|
+
observers: null,
|
|
1060
|
+
observerSlots: null,
|
|
1061
|
+
comparator: options.equals || void 0
|
|
1062
|
+
};
|
|
1063
|
+
const setter = (value2) => {
|
|
1064
|
+
if (typeof value2 === "function") {
|
|
1065
|
+
if (Transition && Transition.running && Transition.sources.has(s)) value2 = value2(s.tValue);
|
|
1066
|
+
else value2 = value2(s.value);
|
|
1067
|
+
}
|
|
1068
|
+
return writeSignal(s, value2);
|
|
1069
|
+
};
|
|
1070
|
+
return [readSignal.bind(s), setter];
|
|
1071
|
+
}
|
|
1072
|
+
function createRenderEffect(fn, value, options) {
|
|
1073
|
+
const c = createComputation(fn, value, false, STALE);
|
|
1074
|
+
if (Scheduler && Transition && Transition.running) Updates.push(c);
|
|
1075
|
+
else updateComputation(c);
|
|
1076
|
+
}
|
|
1077
|
+
function createEffect(fn, value, options) {
|
|
1078
|
+
runEffects = runUserEffects;
|
|
1079
|
+
const c = createComputation(fn, value, false, STALE), s = SuspenseContext && useContext(SuspenseContext);
|
|
1080
|
+
if (s) c.suspense = s;
|
|
1081
|
+
if (!options || !options.render) c.user = true;
|
|
1082
|
+
Effects ? Effects.push(c) : updateComputation(c);
|
|
1083
|
+
}
|
|
1084
|
+
function createMemo(fn, value, options) {
|
|
1085
|
+
options = options ? Object.assign({}, signalOptions, options) : signalOptions;
|
|
1086
|
+
const c = createComputation(fn, value, true, 0);
|
|
1087
|
+
c.observers = null;
|
|
1088
|
+
c.observerSlots = null;
|
|
1089
|
+
c.comparator = options.equals || void 0;
|
|
1090
|
+
if (Scheduler && Transition && Transition.running) {
|
|
1091
|
+
c.tState = STALE;
|
|
1092
|
+
Updates.push(c);
|
|
1093
|
+
} else updateComputation(c);
|
|
1094
|
+
return readSignal.bind(c);
|
|
1095
|
+
}
|
|
1096
|
+
function untrack(fn) {
|
|
1097
|
+
if (!ExternalSourceConfig && Listener === null) return fn();
|
|
1098
|
+
const listener = Listener;
|
|
1099
|
+
Listener = null;
|
|
1100
|
+
try {
|
|
1101
|
+
if (ExternalSourceConfig) return ExternalSourceConfig.untrack(fn);
|
|
1102
|
+
return fn();
|
|
1103
|
+
} finally {
|
|
1104
|
+
Listener = listener;
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
function onMount(fn) {
|
|
1108
|
+
createEffect(() => untrack(fn));
|
|
1109
|
+
}
|
|
1110
|
+
function onCleanup(fn) {
|
|
1111
|
+
if (Owner === null) ;
|
|
1112
|
+
else if (Owner.cleanups === null) Owner.cleanups = [fn];
|
|
1113
|
+
else Owner.cleanups.push(fn);
|
|
1114
|
+
return fn;
|
|
1115
|
+
}
|
|
1116
|
+
function startTransition(fn) {
|
|
1117
|
+
if (Transition && Transition.running) {
|
|
1118
|
+
fn();
|
|
1119
|
+
return Transition.done;
|
|
1120
|
+
}
|
|
1121
|
+
const l = Listener;
|
|
1122
|
+
const o = Owner;
|
|
1123
|
+
return Promise.resolve().then(() => {
|
|
1124
|
+
Listener = l;
|
|
1125
|
+
Owner = o;
|
|
1126
|
+
let t;
|
|
1127
|
+
if (Scheduler || SuspenseContext) {
|
|
1128
|
+
t = Transition || (Transition = {
|
|
1129
|
+
sources: /* @__PURE__ */ new Set(),
|
|
1130
|
+
effects: [],
|
|
1131
|
+
promises: /* @__PURE__ */ new Set(),
|
|
1132
|
+
disposed: /* @__PURE__ */ new Set(),
|
|
1133
|
+
queue: /* @__PURE__ */ new Set(),
|
|
1134
|
+
running: true
|
|
1135
|
+
});
|
|
1136
|
+
t.done || (t.done = new Promise((res) => t.resolve = res));
|
|
1137
|
+
t.running = true;
|
|
1138
|
+
}
|
|
1139
|
+
runUpdates(fn, false);
|
|
1140
|
+
Listener = Owner = null;
|
|
1141
|
+
return t ? t.done : void 0;
|
|
1142
|
+
});
|
|
1143
|
+
}
|
|
1144
|
+
var [transPending, setTransPending] = /* @__PURE__ */ createSignal(false);
|
|
1145
|
+
function useContext(context) {
|
|
1146
|
+
let value;
|
|
1147
|
+
return Owner && Owner.context && (value = Owner.context[context.id]) !== void 0 ? value : context.defaultValue;
|
|
1148
|
+
}
|
|
1149
|
+
var SuspenseContext;
|
|
1150
|
+
function readSignal() {
|
|
1151
|
+
const runningTransition = Transition && Transition.running;
|
|
1152
|
+
if (this.sources && (runningTransition ? this.tState : this.state)) {
|
|
1153
|
+
if ((runningTransition ? this.tState : this.state) === STALE) updateComputation(this);
|
|
1154
|
+
else {
|
|
1155
|
+
const updates = Updates;
|
|
1156
|
+
Updates = null;
|
|
1157
|
+
runUpdates(() => lookUpstream(this), false);
|
|
1158
|
+
Updates = updates;
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
if (Listener) {
|
|
1162
|
+
const observers = this.observers;
|
|
1163
|
+
if (!observers || observers[observers.length - 1] !== Listener) {
|
|
1164
|
+
const sSlot = observers ? observers.length : 0;
|
|
1165
|
+
if (!Listener.sources) {
|
|
1166
|
+
Listener.sources = [this];
|
|
1167
|
+
Listener.sourceSlots = [sSlot];
|
|
1168
|
+
} else {
|
|
1169
|
+
Listener.sources.push(this);
|
|
1170
|
+
Listener.sourceSlots.push(sSlot);
|
|
1171
|
+
}
|
|
1172
|
+
if (!observers) {
|
|
1173
|
+
this.observers = [Listener];
|
|
1174
|
+
this.observerSlots = [Listener.sources.length - 1];
|
|
1175
|
+
} else {
|
|
1176
|
+
observers.push(Listener);
|
|
1177
|
+
this.observerSlots.push(Listener.sources.length - 1);
|
|
1178
|
+
}
|
|
1179
|
+
}
|
|
1180
|
+
}
|
|
1181
|
+
if (runningTransition && Transition.sources.has(this)) return this.tValue;
|
|
1182
|
+
return this.value;
|
|
1183
|
+
}
|
|
1184
|
+
function writeSignal(node, value, isComp) {
|
|
1185
|
+
let current = Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value;
|
|
1186
|
+
if (!node.comparator || !node.comparator(current, value)) {
|
|
1187
|
+
if (Transition) {
|
|
1188
|
+
const TransitionRunning = Transition.running;
|
|
1189
|
+
if (TransitionRunning || !isComp && Transition.sources.has(node)) {
|
|
1190
|
+
Transition.sources.add(node);
|
|
1191
|
+
node.tValue = value;
|
|
1192
|
+
}
|
|
1193
|
+
if (!TransitionRunning) node.value = value;
|
|
1194
|
+
} else node.value = value;
|
|
1195
|
+
if (node.observers && node.observers.length) {
|
|
1196
|
+
runUpdates(() => {
|
|
1197
|
+
for (let i = 0; i < node.observers.length; i += 1) {
|
|
1198
|
+
const o = node.observers[i];
|
|
1199
|
+
const TransitionRunning = Transition && Transition.running;
|
|
1200
|
+
if (TransitionRunning && Transition.disposed.has(o)) continue;
|
|
1201
|
+
if (TransitionRunning ? !o.tState : !o.state) {
|
|
1202
|
+
if (o.pure) Updates.push(o);
|
|
1203
|
+
else Effects.push(o);
|
|
1204
|
+
if (o.observers) markDownstream(o);
|
|
1205
|
+
}
|
|
1206
|
+
if (!TransitionRunning) o.state = STALE;
|
|
1207
|
+
else o.tState = STALE;
|
|
1208
|
+
}
|
|
1209
|
+
if (Updates.length > 1e6) {
|
|
1210
|
+
Updates = [];
|
|
1211
|
+
if (IS_DEV) ;
|
|
1212
|
+
throw new Error();
|
|
1213
|
+
}
|
|
1214
|
+
}, false);
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
1217
|
+
return value;
|
|
1218
|
+
}
|
|
1219
|
+
function updateComputation(node) {
|
|
1220
|
+
if (!node.fn) return;
|
|
1221
|
+
cleanNode(node);
|
|
1222
|
+
const time = ExecCount;
|
|
1223
|
+
runComputation(node, Transition && Transition.running && Transition.sources.has(node) ? node.tValue : node.value, time);
|
|
1224
|
+
if (Transition && !Transition.running && Transition.sources.has(node)) {
|
|
1225
|
+
queueMicrotask(() => {
|
|
1226
|
+
runUpdates(() => {
|
|
1227
|
+
Transition && (Transition.running = true);
|
|
1228
|
+
Listener = Owner = node;
|
|
1229
|
+
runComputation(node, node.tValue, time);
|
|
1230
|
+
Listener = Owner = null;
|
|
1231
|
+
}, false);
|
|
1232
|
+
});
|
|
1233
|
+
}
|
|
1234
|
+
}
|
|
1235
|
+
function runComputation(node, value, time) {
|
|
1236
|
+
let nextValue;
|
|
1237
|
+
const owner = Owner, listener = Listener;
|
|
1238
|
+
Listener = Owner = node;
|
|
1239
|
+
try {
|
|
1240
|
+
nextValue = node.fn(value);
|
|
1241
|
+
} catch (err) {
|
|
1242
|
+
if (node.pure) {
|
|
1243
|
+
if (Transition && Transition.running) {
|
|
1244
|
+
node.tState = STALE;
|
|
1245
|
+
node.tOwned && node.tOwned.forEach(cleanNode);
|
|
1246
|
+
node.tOwned = void 0;
|
|
1247
|
+
} else {
|
|
1248
|
+
node.state = STALE;
|
|
1249
|
+
node.owned && node.owned.forEach(cleanNode);
|
|
1250
|
+
node.owned = null;
|
|
1251
|
+
}
|
|
1252
|
+
}
|
|
1253
|
+
node.updatedAt = time + 1;
|
|
1254
|
+
return handleError(err);
|
|
1255
|
+
} finally {
|
|
1256
|
+
Listener = listener;
|
|
1257
|
+
Owner = owner;
|
|
1258
|
+
}
|
|
1259
|
+
if (!node.updatedAt || node.updatedAt <= time) {
|
|
1260
|
+
if (node.updatedAt != null && "observers" in node) {
|
|
1261
|
+
writeSignal(node, nextValue, true);
|
|
1262
|
+
} else if (Transition && Transition.running && node.pure) {
|
|
1263
|
+
if (!Transition.sources.has(node)) node.value = nextValue;
|
|
1264
|
+
Transition.sources.add(node);
|
|
1265
|
+
node.tValue = nextValue;
|
|
1266
|
+
} else node.value = nextValue;
|
|
1267
|
+
node.updatedAt = time;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
function createComputation(fn, init, pure, state = STALE, options) {
|
|
1271
|
+
const c = {
|
|
1272
|
+
fn,
|
|
1273
|
+
state,
|
|
1274
|
+
updatedAt: null,
|
|
1275
|
+
owned: null,
|
|
1276
|
+
sources: null,
|
|
1277
|
+
sourceSlots: null,
|
|
1278
|
+
cleanups: null,
|
|
1279
|
+
value: init,
|
|
1280
|
+
owner: Owner,
|
|
1281
|
+
context: Owner ? Owner.context : null,
|
|
1282
|
+
pure
|
|
1283
|
+
};
|
|
1284
|
+
if (Transition && Transition.running) {
|
|
1285
|
+
c.state = 0;
|
|
1286
|
+
c.tState = state;
|
|
1287
|
+
}
|
|
1288
|
+
if (Owner === null) ;
|
|
1289
|
+
else if (Owner !== UNOWNED) {
|
|
1290
|
+
if (Transition && Transition.running && Owner.pure) {
|
|
1291
|
+
if (!Owner.tOwned) Owner.tOwned = [c];
|
|
1292
|
+
else Owner.tOwned.push(c);
|
|
1293
|
+
} else {
|
|
1294
|
+
if (!Owner.owned) Owner.owned = [c];
|
|
1295
|
+
else Owner.owned.push(c);
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
if (ExternalSourceConfig && c.fn) {
|
|
1299
|
+
const sourceFn = c.fn;
|
|
1300
|
+
const [track, trigger] = createSignal(void 0, {
|
|
1301
|
+
equals: false
|
|
1302
|
+
});
|
|
1303
|
+
const ordinary = ExternalSourceConfig.factory(sourceFn, trigger);
|
|
1304
|
+
onCleanup(() => ordinary.dispose());
|
|
1305
|
+
let inTransition;
|
|
1306
|
+
const triggerInTransition = () => startTransition(trigger).then(() => {
|
|
1307
|
+
if (inTransition) {
|
|
1308
|
+
inTransition.dispose();
|
|
1309
|
+
inTransition = void 0;
|
|
1310
|
+
}
|
|
1311
|
+
});
|
|
1312
|
+
c.fn = (x) => {
|
|
1313
|
+
track();
|
|
1314
|
+
if (Transition && Transition.running) {
|
|
1315
|
+
if (!inTransition) inTransition = ExternalSourceConfig.factory(sourceFn, triggerInTransition);
|
|
1316
|
+
return inTransition.track(x);
|
|
1317
|
+
}
|
|
1318
|
+
return ordinary.track(x);
|
|
1319
|
+
};
|
|
1320
|
+
}
|
|
1321
|
+
return c;
|
|
1322
|
+
}
|
|
1323
|
+
function runTop(node) {
|
|
1324
|
+
const runningTransition = Transition && Transition.running;
|
|
1325
|
+
if ((runningTransition ? node.tState : node.state) === 0) return;
|
|
1326
|
+
if ((runningTransition ? node.tState : node.state) === PENDING) return lookUpstream(node);
|
|
1327
|
+
if (node.suspense && untrack(node.suspense.inFallback)) return node.suspense.effects.push(node);
|
|
1328
|
+
const ancestors = [node];
|
|
1329
|
+
while ((node = node.owner) && (!node.updatedAt || node.updatedAt < ExecCount)) {
|
|
1330
|
+
if (runningTransition && Transition.disposed.has(node)) return;
|
|
1331
|
+
if (runningTransition ? node.tState : node.state) ancestors.push(node);
|
|
1332
|
+
}
|
|
1333
|
+
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
1334
|
+
node = ancestors[i];
|
|
1335
|
+
if (runningTransition) {
|
|
1336
|
+
let top = node, prev = ancestors[i + 1];
|
|
1337
|
+
while ((top = top.owner) && top !== prev) {
|
|
1338
|
+
if (Transition.disposed.has(top)) return;
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
if ((runningTransition ? node.tState : node.state) === STALE) {
|
|
1342
|
+
updateComputation(node);
|
|
1343
|
+
} else if ((runningTransition ? node.tState : node.state) === PENDING) {
|
|
1344
|
+
const updates = Updates;
|
|
1345
|
+
Updates = null;
|
|
1346
|
+
runUpdates(() => lookUpstream(node, ancestors[0]), false);
|
|
1347
|
+
Updates = updates;
|
|
1348
|
+
}
|
|
1349
|
+
}
|
|
1350
|
+
}
|
|
1351
|
+
function runUpdates(fn, init) {
|
|
1352
|
+
if (Updates) return fn();
|
|
1353
|
+
let wait = false;
|
|
1354
|
+
if (!init) Updates = [];
|
|
1355
|
+
if (Effects) wait = true;
|
|
1356
|
+
else Effects = [];
|
|
1357
|
+
ExecCount++;
|
|
1358
|
+
try {
|
|
1359
|
+
const res = fn();
|
|
1360
|
+
completeUpdates(wait);
|
|
1361
|
+
return res;
|
|
1362
|
+
} catch (err) {
|
|
1363
|
+
if (!wait) Effects = null;
|
|
1364
|
+
Updates = null;
|
|
1365
|
+
handleError(err);
|
|
1366
|
+
}
|
|
1367
|
+
}
|
|
1368
|
+
function completeUpdates(wait) {
|
|
1369
|
+
if (Updates) {
|
|
1370
|
+
if (Scheduler && Transition && Transition.running) scheduleQueue(Updates);
|
|
1371
|
+
else runQueue(Updates);
|
|
1372
|
+
Updates = null;
|
|
1373
|
+
}
|
|
1374
|
+
if (wait) return;
|
|
1375
|
+
let res;
|
|
1376
|
+
if (Transition) {
|
|
1377
|
+
if (!Transition.promises.size && !Transition.queue.size) {
|
|
1378
|
+
const sources = Transition.sources;
|
|
1379
|
+
const disposed = Transition.disposed;
|
|
1380
|
+
Effects.push.apply(Effects, Transition.effects);
|
|
1381
|
+
res = Transition.resolve;
|
|
1382
|
+
for (const e2 of Effects) {
|
|
1383
|
+
"tState" in e2 && (e2.state = e2.tState);
|
|
1384
|
+
delete e2.tState;
|
|
1385
|
+
}
|
|
1386
|
+
Transition = null;
|
|
1387
|
+
runUpdates(() => {
|
|
1388
|
+
for (const d of disposed) cleanNode(d);
|
|
1389
|
+
for (const v of sources) {
|
|
1390
|
+
v.value = v.tValue;
|
|
1391
|
+
if (v.owned) {
|
|
1392
|
+
for (let i = 0, len = v.owned.length; i < len; i++) cleanNode(v.owned[i]);
|
|
1393
|
+
}
|
|
1394
|
+
if (v.tOwned) v.owned = v.tOwned;
|
|
1395
|
+
delete v.tValue;
|
|
1396
|
+
delete v.tOwned;
|
|
1397
|
+
v.tState = 0;
|
|
1398
|
+
}
|
|
1399
|
+
setTransPending(false);
|
|
1400
|
+
}, false);
|
|
1401
|
+
} else if (Transition.running) {
|
|
1402
|
+
Transition.running = false;
|
|
1403
|
+
Transition.effects.push.apply(Transition.effects, Effects);
|
|
1404
|
+
Effects = null;
|
|
1405
|
+
setTransPending(true);
|
|
1406
|
+
return;
|
|
1407
|
+
}
|
|
1408
|
+
}
|
|
1409
|
+
const e = Effects;
|
|
1410
|
+
Effects = null;
|
|
1411
|
+
if (e.length) runUpdates(() => runEffects(e), false);
|
|
1412
|
+
if (res) res();
|
|
1413
|
+
}
|
|
1414
|
+
function runQueue(queue) {
|
|
1415
|
+
for (let i = 0; i < queue.length; i++) runTop(queue[i]);
|
|
1416
|
+
}
|
|
1417
|
+
function scheduleQueue(queue) {
|
|
1418
|
+
for (let i = 0; i < queue.length; i++) {
|
|
1419
|
+
const item = queue[i];
|
|
1420
|
+
const tasks = Transition.queue;
|
|
1421
|
+
if (!tasks.has(item)) {
|
|
1422
|
+
tasks.add(item);
|
|
1423
|
+
Scheduler(() => {
|
|
1424
|
+
tasks.delete(item);
|
|
1425
|
+
runUpdates(() => {
|
|
1426
|
+
Transition.running = true;
|
|
1427
|
+
runTop(item);
|
|
1428
|
+
}, false);
|
|
1429
|
+
Transition && (Transition.running = false);
|
|
1430
|
+
});
|
|
1431
|
+
}
|
|
1432
|
+
}
|
|
1433
|
+
}
|
|
1434
|
+
function runUserEffects(queue) {
|
|
1435
|
+
let i, userLength = 0;
|
|
1436
|
+
for (i = 0; i < queue.length; i++) {
|
|
1437
|
+
const e = queue[i];
|
|
1438
|
+
if (!e.user) runTop(e);
|
|
1439
|
+
else queue[userLength++] = e;
|
|
1440
|
+
}
|
|
1441
|
+
if (sharedConfig.context) {
|
|
1442
|
+
if (sharedConfig.count) {
|
|
1443
|
+
sharedConfig.effects || (sharedConfig.effects = []);
|
|
1444
|
+
sharedConfig.effects.push(...queue.slice(0, userLength));
|
|
1445
|
+
return;
|
|
1446
|
+
}
|
|
1447
|
+
setHydrateContext();
|
|
1448
|
+
}
|
|
1449
|
+
if (sharedConfig.effects && (sharedConfig.done || !sharedConfig.count)) {
|
|
1450
|
+
queue = [...sharedConfig.effects, ...queue];
|
|
1451
|
+
userLength += sharedConfig.effects.length;
|
|
1452
|
+
delete sharedConfig.effects;
|
|
1453
|
+
}
|
|
1454
|
+
for (i = 0; i < userLength; i++) runTop(queue[i]);
|
|
1455
|
+
}
|
|
1456
|
+
function lookUpstream(node, ignore) {
|
|
1457
|
+
const runningTransition = Transition && Transition.running;
|
|
1458
|
+
if (runningTransition) node.tState = 0;
|
|
1459
|
+
else node.state = 0;
|
|
1460
|
+
for (let i = 0; i < node.sources.length; i += 1) {
|
|
1461
|
+
const source = node.sources[i];
|
|
1462
|
+
if (source.sources) {
|
|
1463
|
+
const state = runningTransition ? source.tState : source.state;
|
|
1464
|
+
if (state === STALE) {
|
|
1465
|
+
if (source !== ignore && (!source.updatedAt || source.updatedAt < ExecCount)) runTop(source);
|
|
1466
|
+
} else if (state === PENDING) lookUpstream(source, ignore);
|
|
1467
|
+
}
|
|
1468
|
+
}
|
|
1469
|
+
}
|
|
1470
|
+
function markDownstream(node) {
|
|
1471
|
+
const runningTransition = Transition && Transition.running;
|
|
1472
|
+
for (let i = 0; i < node.observers.length; i += 1) {
|
|
1473
|
+
const o = node.observers[i];
|
|
1474
|
+
if (runningTransition ? !o.tState : !o.state) {
|
|
1475
|
+
if (runningTransition) o.tState = PENDING;
|
|
1476
|
+
else o.state = PENDING;
|
|
1477
|
+
if (o.pure) Updates.push(o);
|
|
1478
|
+
else Effects.push(o);
|
|
1479
|
+
o.observers && markDownstream(o);
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
}
|
|
1483
|
+
function cleanNode(node) {
|
|
1484
|
+
let i;
|
|
1485
|
+
if (node.sources) {
|
|
1486
|
+
while (node.sources.length) {
|
|
1487
|
+
const source = node.sources.pop(), index = node.sourceSlots.pop(), obs = source.observers;
|
|
1488
|
+
if (obs && obs.length) {
|
|
1489
|
+
const n = obs.pop(), s = source.observerSlots.pop();
|
|
1490
|
+
if (index < obs.length) {
|
|
1491
|
+
n.sourceSlots[s] = index;
|
|
1492
|
+
obs[index] = n;
|
|
1493
|
+
source.observerSlots[index] = s;
|
|
1494
|
+
}
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
}
|
|
1498
|
+
if (node.tOwned) {
|
|
1499
|
+
for (i = node.tOwned.length - 1; i >= 0; i--) cleanNode(node.tOwned[i]);
|
|
1500
|
+
delete node.tOwned;
|
|
1501
|
+
}
|
|
1502
|
+
if (Transition && Transition.running && node.pure) {
|
|
1503
|
+
reset(node, true);
|
|
1504
|
+
} else if (node.owned) {
|
|
1505
|
+
for (i = node.owned.length - 1; i >= 0; i--) cleanNode(node.owned[i]);
|
|
1506
|
+
node.owned = null;
|
|
1507
|
+
}
|
|
1508
|
+
if (node.cleanups) {
|
|
1509
|
+
for (i = node.cleanups.length - 1; i >= 0; i--) node.cleanups[i]();
|
|
1510
|
+
node.cleanups = null;
|
|
1511
|
+
}
|
|
1512
|
+
if (Transition && Transition.running) node.tState = 0;
|
|
1513
|
+
else node.state = 0;
|
|
1514
|
+
}
|
|
1515
|
+
function reset(node, top) {
|
|
1516
|
+
if (!top) {
|
|
1517
|
+
node.tState = 0;
|
|
1518
|
+
Transition.disposed.add(node);
|
|
1519
|
+
}
|
|
1520
|
+
if (node.owned) {
|
|
1521
|
+
for (let i = 0; i < node.owned.length; i++) reset(node.owned[i]);
|
|
1522
|
+
}
|
|
1523
|
+
}
|
|
1524
|
+
function castError(err) {
|
|
1525
|
+
if (err instanceof Error) return err;
|
|
1526
|
+
return new Error(typeof err === "string" ? err : "Unknown error", {
|
|
1527
|
+
cause: err
|
|
1528
|
+
});
|
|
1529
|
+
}
|
|
1530
|
+
function runErrors(err, fns, owner) {
|
|
1531
|
+
try {
|
|
1532
|
+
for (const f of fns) f(err);
|
|
1533
|
+
} catch (e) {
|
|
1534
|
+
handleError(e, owner && owner.owner || null);
|
|
1535
|
+
}
|
|
1536
|
+
}
|
|
1537
|
+
function handleError(err, owner = Owner) {
|
|
1538
|
+
const fns = ERROR && owner && owner.context && owner.context[ERROR];
|
|
1539
|
+
const error = castError(err);
|
|
1540
|
+
if (!fns) throw error;
|
|
1541
|
+
if (Effects) Effects.push({
|
|
1542
|
+
fn() {
|
|
1543
|
+
runErrors(error, fns, owner);
|
|
1544
|
+
},
|
|
1545
|
+
state: STALE
|
|
1546
|
+
});
|
|
1547
|
+
else runErrors(error, fns, owner);
|
|
1548
|
+
}
|
|
1549
|
+
var FALLBACK = /* @__PURE__ */ Symbol("fallback");
|
|
1550
|
+
function dispose(d) {
|
|
1551
|
+
for (let i = 0; i < d.length; i++) d[i]();
|
|
1552
|
+
}
|
|
1553
|
+
function mapArray(list, mapFn, options = {}) {
|
|
1554
|
+
let items = [], mapped = [], disposers = [], len = 0, indexes = mapFn.length > 1 ? [] : null;
|
|
1555
|
+
onCleanup(() => dispose(disposers));
|
|
1556
|
+
return () => {
|
|
1557
|
+
let newItems = list() || [], newLen = newItems.length, i, j;
|
|
1558
|
+
newItems[$TRACK];
|
|
1559
|
+
return untrack(() => {
|
|
1560
|
+
let newIndices, newIndicesNext, temp, tempdisposers, tempIndexes, start, end, newEnd, item;
|
|
1561
|
+
if (newLen === 0) {
|
|
1562
|
+
if (len !== 0) {
|
|
1563
|
+
dispose(disposers);
|
|
1564
|
+
disposers = [];
|
|
1565
|
+
items = [];
|
|
1566
|
+
mapped = [];
|
|
1567
|
+
len = 0;
|
|
1568
|
+
indexes && (indexes = []);
|
|
1569
|
+
}
|
|
1570
|
+
if (options.fallback) {
|
|
1571
|
+
items = [FALLBACK];
|
|
1572
|
+
mapped[0] = createRoot((disposer) => {
|
|
1573
|
+
disposers[0] = disposer;
|
|
1574
|
+
return options.fallback();
|
|
1575
|
+
});
|
|
1576
|
+
len = 1;
|
|
1577
|
+
}
|
|
1578
|
+
} else if (len === 0) {
|
|
1579
|
+
mapped = new Array(newLen);
|
|
1580
|
+
for (j = 0; j < newLen; j++) {
|
|
1581
|
+
items[j] = newItems[j];
|
|
1582
|
+
mapped[j] = createRoot(mapper);
|
|
1583
|
+
}
|
|
1584
|
+
len = newLen;
|
|
1585
|
+
} else {
|
|
1586
|
+
temp = new Array(newLen);
|
|
1587
|
+
tempdisposers = new Array(newLen);
|
|
1588
|
+
indexes && (tempIndexes = new Array(newLen));
|
|
1589
|
+
for (start = 0, end = Math.min(len, newLen); start < end && items[start] === newItems[start]; start++) ;
|
|
1590
|
+
for (end = len - 1, newEnd = newLen - 1; end >= start && newEnd >= start && items[end] === newItems[newEnd]; end--, newEnd--) {
|
|
1591
|
+
temp[newEnd] = mapped[end];
|
|
1592
|
+
tempdisposers[newEnd] = disposers[end];
|
|
1593
|
+
indexes && (tempIndexes[newEnd] = indexes[end]);
|
|
1594
|
+
}
|
|
1595
|
+
newIndices = /* @__PURE__ */ new Map();
|
|
1596
|
+
newIndicesNext = new Array(newEnd + 1);
|
|
1597
|
+
for (j = newEnd; j >= start; j--) {
|
|
1598
|
+
item = newItems[j];
|
|
1599
|
+
i = newIndices.get(item);
|
|
1600
|
+
newIndicesNext[j] = i === void 0 ? -1 : i;
|
|
1601
|
+
newIndices.set(item, j);
|
|
1602
|
+
}
|
|
1603
|
+
for (i = start; i <= end; i++) {
|
|
1604
|
+
item = items[i];
|
|
1605
|
+
j = newIndices.get(item);
|
|
1606
|
+
if (j !== void 0 && j !== -1) {
|
|
1607
|
+
temp[j] = mapped[i];
|
|
1608
|
+
tempdisposers[j] = disposers[i];
|
|
1609
|
+
indexes && (tempIndexes[j] = indexes[i]);
|
|
1610
|
+
j = newIndicesNext[j];
|
|
1611
|
+
newIndices.set(item, j);
|
|
1612
|
+
} else disposers[i]();
|
|
1613
|
+
}
|
|
1614
|
+
for (j = start; j < newLen; j++) {
|
|
1615
|
+
if (j in temp) {
|
|
1616
|
+
mapped[j] = temp[j];
|
|
1617
|
+
disposers[j] = tempdisposers[j];
|
|
1618
|
+
if (indexes) {
|
|
1619
|
+
indexes[j] = tempIndexes[j];
|
|
1620
|
+
indexes[j](j);
|
|
1621
|
+
}
|
|
1622
|
+
} else mapped[j] = createRoot(mapper);
|
|
1623
|
+
}
|
|
1624
|
+
mapped = mapped.slice(0, len = newLen);
|
|
1625
|
+
items = newItems.slice(0);
|
|
1626
|
+
}
|
|
1627
|
+
return mapped;
|
|
1628
|
+
});
|
|
1629
|
+
function mapper(disposer) {
|
|
1630
|
+
disposers[j] = disposer;
|
|
1631
|
+
if (indexes) {
|
|
1632
|
+
const [s, set] = createSignal(j);
|
|
1633
|
+
indexes[j] = set;
|
|
1634
|
+
return mapFn(newItems[j], s);
|
|
1635
|
+
}
|
|
1636
|
+
return mapFn(newItems[j]);
|
|
1637
|
+
}
|
|
1638
|
+
};
|
|
1639
|
+
}
|
|
1640
|
+
var hydrationEnabled = false;
|
|
1641
|
+
function createComponent(Comp, props) {
|
|
1642
|
+
if (hydrationEnabled) {
|
|
1643
|
+
if (sharedConfig.context) {
|
|
1644
|
+
const c = sharedConfig.context;
|
|
1645
|
+
setHydrateContext(nextHydrateContext());
|
|
1646
|
+
const r = untrack(() => Comp(props || {}));
|
|
1647
|
+
setHydrateContext(c);
|
|
1648
|
+
return r;
|
|
1649
|
+
}
|
|
1650
|
+
}
|
|
1651
|
+
return untrack(() => Comp(props || {}));
|
|
1652
|
+
}
|
|
1653
|
+
var narrowedError = (name) => `Stale read from <${name}>.`;
|
|
1654
|
+
function For(props) {
|
|
1655
|
+
const fallback = "fallback" in props && {
|
|
1656
|
+
fallback: () => props.fallback
|
|
1657
|
+
};
|
|
1658
|
+
return createMemo(mapArray(() => props.each, props.children, fallback || void 0));
|
|
1659
|
+
}
|
|
1660
|
+
function Show(props) {
|
|
1661
|
+
const keyed = props.keyed;
|
|
1662
|
+
const conditionValue = createMemo(() => props.when, void 0, void 0);
|
|
1663
|
+
const condition = keyed ? conditionValue : createMemo(conditionValue, void 0, {
|
|
1664
|
+
equals: (a, b) => !a === !b
|
|
1665
|
+
});
|
|
1666
|
+
return createMemo(() => {
|
|
1667
|
+
const c = condition();
|
|
1668
|
+
if (c) {
|
|
1669
|
+
const child = props.children;
|
|
1670
|
+
const fn = typeof child === "function" && child.length > 0;
|
|
1671
|
+
return fn ? untrack(() => child(keyed ? c : () => {
|
|
1672
|
+
if (!untrack(condition)) throw narrowedError("Show");
|
|
1673
|
+
return conditionValue();
|
|
1674
|
+
})) : child;
|
|
1675
|
+
}
|
|
1676
|
+
return props.fallback;
|
|
1677
|
+
}, void 0, void 0);
|
|
1678
|
+
}
|
|
1679
|
+
|
|
1680
|
+
// ../../node_modules/.pnpm/solid-js@1.9.13/node_modules/solid-js/web/dist/web.js
|
|
1681
|
+
var booleans = [
|
|
1682
|
+
"allowfullscreen",
|
|
1683
|
+
"async",
|
|
1684
|
+
"alpha",
|
|
1685
|
+
"autofocus",
|
|
1686
|
+
"autoplay",
|
|
1687
|
+
"checked",
|
|
1688
|
+
"controls",
|
|
1689
|
+
"default",
|
|
1690
|
+
"disabled",
|
|
1691
|
+
"formnovalidate",
|
|
1692
|
+
"hidden",
|
|
1693
|
+
"indeterminate",
|
|
1694
|
+
"inert",
|
|
1695
|
+
"ismap",
|
|
1696
|
+
"loop",
|
|
1697
|
+
"multiple",
|
|
1698
|
+
"muted",
|
|
1699
|
+
"nomodule",
|
|
1700
|
+
"novalidate",
|
|
1701
|
+
"open",
|
|
1702
|
+
"playsinline",
|
|
1703
|
+
"readonly",
|
|
1704
|
+
"required",
|
|
1705
|
+
"reversed",
|
|
1706
|
+
"seamless",
|
|
1707
|
+
"selected",
|
|
1708
|
+
"adauctionheaders",
|
|
1709
|
+
"browsingtopics",
|
|
1710
|
+
"credentialless",
|
|
1711
|
+
"defaultchecked",
|
|
1712
|
+
"defaultmuted",
|
|
1713
|
+
"defaultselected",
|
|
1714
|
+
"defer",
|
|
1715
|
+
"disablepictureinpicture",
|
|
1716
|
+
"disableremoteplayback",
|
|
1717
|
+
"preservespitch",
|
|
1718
|
+
"shadowrootclonable",
|
|
1719
|
+
"shadowrootcustomelementregistry",
|
|
1720
|
+
"shadowrootdelegatesfocus",
|
|
1721
|
+
"shadowrootserializable",
|
|
1722
|
+
"sharedstoragewritable"
|
|
1723
|
+
];
|
|
1724
|
+
var Properties = /* @__PURE__ */ new Set([
|
|
1725
|
+
"className",
|
|
1726
|
+
"value",
|
|
1727
|
+
"readOnly",
|
|
1728
|
+
"noValidate",
|
|
1729
|
+
"formNoValidate",
|
|
1730
|
+
"isMap",
|
|
1731
|
+
"noModule",
|
|
1732
|
+
"playsInline",
|
|
1733
|
+
"adAuctionHeaders",
|
|
1734
|
+
"allowFullscreen",
|
|
1735
|
+
"browsingTopics",
|
|
1736
|
+
"defaultChecked",
|
|
1737
|
+
"defaultMuted",
|
|
1738
|
+
"defaultSelected",
|
|
1739
|
+
"disablePictureInPicture",
|
|
1740
|
+
"disableRemotePlayback",
|
|
1741
|
+
"preservesPitch",
|
|
1742
|
+
"shadowRootClonable",
|
|
1743
|
+
"shadowRootCustomElementRegistry",
|
|
1744
|
+
"shadowRootDelegatesFocus",
|
|
1745
|
+
"shadowRootSerializable",
|
|
1746
|
+
"sharedStorageWritable",
|
|
1747
|
+
...booleans
|
|
1748
|
+
]);
|
|
1749
|
+
var memo = (fn) => createMemo(() => fn());
|
|
1750
|
+
function reconcileArrays(parentNode, a, b) {
|
|
1751
|
+
let bLength = b.length, aEnd = a.length, bEnd = bLength, aStart = 0, bStart = 0, after = a[aEnd - 1].nextSibling, map = null;
|
|
1752
|
+
while (aStart < aEnd || bStart < bEnd) {
|
|
1753
|
+
if (a[aStart] === b[bStart]) {
|
|
1754
|
+
aStart++;
|
|
1755
|
+
bStart++;
|
|
1756
|
+
continue;
|
|
1757
|
+
}
|
|
1758
|
+
while (a[aEnd - 1] === b[bEnd - 1]) {
|
|
1759
|
+
aEnd--;
|
|
1760
|
+
bEnd--;
|
|
1761
|
+
}
|
|
1762
|
+
if (aEnd === aStart) {
|
|
1763
|
+
const node = bEnd < bLength ? bStart ? b[bStart - 1].nextSibling : b[bEnd - bStart] : after;
|
|
1764
|
+
while (bStart < bEnd) parentNode.insertBefore(b[bStart++], node);
|
|
1765
|
+
} else if (bEnd === bStart) {
|
|
1766
|
+
while (aStart < aEnd) {
|
|
1767
|
+
if (!map || !map.has(a[aStart])) a[aStart].remove();
|
|
1768
|
+
aStart++;
|
|
1769
|
+
}
|
|
1770
|
+
} else if (a[aStart] === b[bEnd - 1] && b[bStart] === a[aEnd - 1]) {
|
|
1771
|
+
const node = a[--aEnd].nextSibling;
|
|
1772
|
+
parentNode.insertBefore(b[bStart++], a[aStart++].nextSibling);
|
|
1773
|
+
parentNode.insertBefore(b[--bEnd], node);
|
|
1774
|
+
a[aEnd] = b[bEnd];
|
|
1775
|
+
} else {
|
|
1776
|
+
if (!map) {
|
|
1777
|
+
map = /* @__PURE__ */ new Map();
|
|
1778
|
+
let i = bStart;
|
|
1779
|
+
while (i < bEnd) map.set(b[i], i++);
|
|
1780
|
+
}
|
|
1781
|
+
const index = map.get(a[aStart]);
|
|
1782
|
+
if (index != null) {
|
|
1783
|
+
if (bStart < index && index < bEnd) {
|
|
1784
|
+
let i = aStart, sequence = 1, t;
|
|
1785
|
+
while (++i < aEnd && i < bEnd) {
|
|
1786
|
+
if ((t = map.get(a[i])) == null || t !== index + sequence) break;
|
|
1787
|
+
sequence++;
|
|
1788
|
+
}
|
|
1789
|
+
if (sequence > index - bStart) {
|
|
1790
|
+
const node = a[aStart];
|
|
1791
|
+
while (bStart < index) parentNode.insertBefore(b[bStart++], node);
|
|
1792
|
+
} else parentNode.replaceChild(b[bStart++], a[aStart++]);
|
|
1793
|
+
} else aStart++;
|
|
1794
|
+
} else a[aStart++].remove();
|
|
1795
|
+
}
|
|
1796
|
+
}
|
|
1797
|
+
}
|
|
1798
|
+
var $$EVENTS = "_$DX_DELEGATE";
|
|
1799
|
+
function render(code, element, init, options = {}) {
|
|
1800
|
+
let disposer;
|
|
1801
|
+
createRoot((dispose2) => {
|
|
1802
|
+
disposer = dispose2;
|
|
1803
|
+
element === document ? code() : insert(element, code(), element.firstChild ? null : void 0, init);
|
|
1804
|
+
}, options.owner);
|
|
1805
|
+
return () => {
|
|
1806
|
+
disposer();
|
|
1807
|
+
element.textContent = "";
|
|
1808
|
+
};
|
|
1809
|
+
}
|
|
1810
|
+
function template(html, isImportNode, isSVG, isMathML) {
|
|
1811
|
+
let node;
|
|
1812
|
+
const create = () => {
|
|
1813
|
+
const t = isMathML ? document.createElementNS("http://www.w3.org/1998/Math/MathML", "template") : document.createElement("template");
|
|
1814
|
+
t.innerHTML = html;
|
|
1815
|
+
return isSVG ? t.content.firstChild.firstChild : isMathML ? t.firstChild : t.content.firstChild;
|
|
1816
|
+
};
|
|
1817
|
+
const fn = isImportNode ? () => untrack(() => document.importNode(node || (node = create()), true)) : () => (node || (node = create())).cloneNode(true);
|
|
1818
|
+
fn.cloneNode = fn;
|
|
1819
|
+
return fn;
|
|
1820
|
+
}
|
|
1821
|
+
function delegateEvents(eventNames, document2 = window.document) {
|
|
1822
|
+
const e = document2[$$EVENTS] || (document2[$$EVENTS] = /* @__PURE__ */ new Set());
|
|
1823
|
+
for (let i = 0, l = eventNames.length; i < l; i++) {
|
|
1824
|
+
const name = eventNames[i];
|
|
1825
|
+
if (!e.has(name)) {
|
|
1826
|
+
e.add(name);
|
|
1827
|
+
document2.addEventListener(name, eventHandler);
|
|
1828
|
+
}
|
|
1829
|
+
}
|
|
1830
|
+
}
|
|
1831
|
+
function setAttribute(node, name, value) {
|
|
1832
|
+
if (isHydrating(node)) return;
|
|
1833
|
+
if (value == null) node.removeAttribute(name);
|
|
1834
|
+
else node.setAttribute(name, value);
|
|
1835
|
+
}
|
|
1836
|
+
function className(node, value) {
|
|
1837
|
+
if (isHydrating(node)) return;
|
|
1838
|
+
if (value == null) node.removeAttribute("class");
|
|
1839
|
+
else node.className = value;
|
|
1840
|
+
}
|
|
1841
|
+
function addEventListener(node, name, handler, delegate) {
|
|
1842
|
+
if (delegate) {
|
|
1843
|
+
if (Array.isArray(handler)) {
|
|
1844
|
+
node[`$$${name}`] = handler[0];
|
|
1845
|
+
node[`$$${name}Data`] = handler[1];
|
|
1846
|
+
} else node[`$$${name}`] = handler;
|
|
1847
|
+
} else if (Array.isArray(handler)) {
|
|
1848
|
+
const handlerFn = handler[0];
|
|
1849
|
+
node.addEventListener(name, handler[0] = (e) => handlerFn.call(node, handler[1], e));
|
|
1850
|
+
} else node.addEventListener(name, handler, typeof handler !== "function" && handler);
|
|
1851
|
+
}
|
|
1852
|
+
function style(node, value, prev) {
|
|
1853
|
+
if (!value) return prev ? setAttribute(node, "style") : value;
|
|
1854
|
+
const nodeStyle = node.style;
|
|
1855
|
+
if (typeof value === "string") return nodeStyle.cssText = value;
|
|
1856
|
+
typeof prev === "string" && (nodeStyle.cssText = prev = void 0);
|
|
1857
|
+
prev || (prev = {});
|
|
1858
|
+
value || (value = {});
|
|
1859
|
+
let v, s;
|
|
1860
|
+
for (s in prev) {
|
|
1861
|
+
value[s] == null && nodeStyle.removeProperty(s);
|
|
1862
|
+
delete prev[s];
|
|
1863
|
+
}
|
|
1864
|
+
for (s in value) {
|
|
1865
|
+
v = value[s];
|
|
1866
|
+
if (v !== prev[s]) {
|
|
1867
|
+
nodeStyle.setProperty(s, v);
|
|
1868
|
+
prev[s] = v;
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
return prev;
|
|
1872
|
+
}
|
|
1873
|
+
function setStyleProperty(node, name, value) {
|
|
1874
|
+
value != null ? node.style.setProperty(name, value) : node.style.removeProperty(name);
|
|
1875
|
+
}
|
|
1876
|
+
function use(fn, element, arg) {
|
|
1877
|
+
return untrack(() => fn(element, arg));
|
|
1878
|
+
}
|
|
1879
|
+
function insert(parent, accessor, marker, initial) {
|
|
1880
|
+
if (marker !== void 0 && !initial) initial = [];
|
|
1881
|
+
if (typeof accessor !== "function") return insertExpression(parent, accessor, initial, marker);
|
|
1882
|
+
createRenderEffect((current) => insertExpression(parent, accessor(), current, marker), initial);
|
|
1883
|
+
}
|
|
1884
|
+
function isHydrating(node) {
|
|
1885
|
+
return !!sharedConfig.context && !sharedConfig.done && (!node || node.isConnected);
|
|
1886
|
+
}
|
|
1887
|
+
function eventHandler(e) {
|
|
1888
|
+
if (sharedConfig.registry && sharedConfig.events) {
|
|
1889
|
+
if (sharedConfig.events.find(([el, ev]) => ev === e)) return;
|
|
1890
|
+
}
|
|
1891
|
+
let node = e.target;
|
|
1892
|
+
const key = `$$${e.type}`;
|
|
1893
|
+
const oriTarget = e.target;
|
|
1894
|
+
const oriCurrentTarget = e.currentTarget;
|
|
1895
|
+
const retarget = (value) => Object.defineProperty(e, "target", {
|
|
1896
|
+
configurable: true,
|
|
1897
|
+
value
|
|
1898
|
+
});
|
|
1899
|
+
const handleNode = () => {
|
|
1900
|
+
const handler = node[key];
|
|
1901
|
+
if (handler && !node.disabled) {
|
|
1902
|
+
const data = node[`${key}Data`];
|
|
1903
|
+
data !== void 0 ? handler.call(node, data, e) : handler.call(node, e);
|
|
1904
|
+
if (e.cancelBubble) return;
|
|
1905
|
+
}
|
|
1906
|
+
node.host && typeof node.host !== "string" && !node.host._$host && node.contains(e.target) && retarget(node.host);
|
|
1907
|
+
return true;
|
|
1908
|
+
};
|
|
1909
|
+
const walkUpTree = () => {
|
|
1910
|
+
while (handleNode() && (node = node._$host || node.parentNode || node.host)) ;
|
|
1911
|
+
};
|
|
1912
|
+
Object.defineProperty(e, "currentTarget", {
|
|
1913
|
+
configurable: true,
|
|
1914
|
+
get() {
|
|
1915
|
+
return node || document;
|
|
1916
|
+
}
|
|
1917
|
+
});
|
|
1918
|
+
if (sharedConfig.registry && !sharedConfig.done) sharedConfig.done = _$HY.done = true;
|
|
1919
|
+
if (e.composedPath) {
|
|
1920
|
+
const path = e.composedPath();
|
|
1921
|
+
retarget(path[0]);
|
|
1922
|
+
for (let i = 0; i < path.length - 2; i++) {
|
|
1923
|
+
node = path[i];
|
|
1924
|
+
if (!handleNode()) break;
|
|
1925
|
+
if (node._$host) {
|
|
1926
|
+
node = node._$host;
|
|
1927
|
+
walkUpTree();
|
|
1928
|
+
break;
|
|
1929
|
+
}
|
|
1930
|
+
if (node.parentNode === oriCurrentTarget) {
|
|
1931
|
+
break;
|
|
1932
|
+
}
|
|
1933
|
+
}
|
|
1934
|
+
} else walkUpTree();
|
|
1935
|
+
retarget(oriTarget);
|
|
1936
|
+
}
|
|
1937
|
+
function insertExpression(parent, value, current, marker, unwrapArray) {
|
|
1938
|
+
const hydrating = isHydrating(parent);
|
|
1939
|
+
if (hydrating) {
|
|
1940
|
+
!current && (current = [...parent.childNodes]);
|
|
1941
|
+
let cleaned = [];
|
|
1942
|
+
for (let i = 0; i < current.length; i++) {
|
|
1943
|
+
const node = current[i];
|
|
1944
|
+
if (node.nodeType === 8 && node.data.slice(0, 2) === "!$") node.remove();
|
|
1945
|
+
else cleaned.push(node);
|
|
1946
|
+
}
|
|
1947
|
+
current = cleaned;
|
|
1948
|
+
}
|
|
1949
|
+
while (typeof current === "function") current = current();
|
|
1950
|
+
if (value === current) return current;
|
|
1951
|
+
const t = typeof value, multi = marker !== void 0;
|
|
1952
|
+
parent = multi && current[0] && current[0].parentNode || parent;
|
|
1953
|
+
if (t === "string" || t === "number") {
|
|
1954
|
+
if (hydrating) return current;
|
|
1955
|
+
if (t === "number") {
|
|
1956
|
+
value = value.toString();
|
|
1957
|
+
if (value === current) return current;
|
|
1958
|
+
}
|
|
1959
|
+
if (multi) {
|
|
1960
|
+
let node = current[0];
|
|
1961
|
+
if (node && node.nodeType === 3) {
|
|
1962
|
+
node.data !== value && (node.data = value);
|
|
1963
|
+
} else node = document.createTextNode(value);
|
|
1964
|
+
current = cleanChildren(parent, current, marker, node);
|
|
1965
|
+
} else {
|
|
1966
|
+
if (current !== "" && typeof current === "string") {
|
|
1967
|
+
current = parent.firstChild.data = value;
|
|
1968
|
+
} else current = parent.textContent = value;
|
|
1969
|
+
}
|
|
1970
|
+
} else if (value == null || t === "boolean") {
|
|
1971
|
+
if (hydrating) return current;
|
|
1972
|
+
current = cleanChildren(parent, current, marker);
|
|
1973
|
+
} else if (t === "function") {
|
|
1974
|
+
createRenderEffect(() => {
|
|
1975
|
+
let v = value();
|
|
1976
|
+
while (typeof v === "function") v = v();
|
|
1977
|
+
current = insertExpression(parent, v, current, marker);
|
|
1978
|
+
});
|
|
1979
|
+
return () => current;
|
|
1980
|
+
} else if (Array.isArray(value)) {
|
|
1981
|
+
const array = [];
|
|
1982
|
+
const currentArray = current && Array.isArray(current);
|
|
1983
|
+
if (normalizeIncomingArray(array, value, current, unwrapArray)) {
|
|
1984
|
+
createRenderEffect(() => current = insertExpression(parent, array, current, marker, true));
|
|
1985
|
+
return () => current;
|
|
1986
|
+
}
|
|
1987
|
+
if (hydrating) {
|
|
1988
|
+
if (!array.length) return current;
|
|
1989
|
+
if (marker === void 0) return current = [...parent.childNodes];
|
|
1990
|
+
let node = array[0];
|
|
1991
|
+
if (node.parentNode !== parent) return current;
|
|
1992
|
+
const nodes = [node];
|
|
1993
|
+
while ((node = node.nextSibling) !== marker) nodes.push(node);
|
|
1994
|
+
return current = nodes;
|
|
1995
|
+
}
|
|
1996
|
+
if (array.length === 0) {
|
|
1997
|
+
current = cleanChildren(parent, current, marker);
|
|
1998
|
+
if (multi) return current;
|
|
1999
|
+
} else if (currentArray) {
|
|
2000
|
+
if (current.length === 0) {
|
|
2001
|
+
appendNodes(parent, array, marker);
|
|
2002
|
+
} else reconcileArrays(parent, current, array);
|
|
2003
|
+
} else {
|
|
2004
|
+
current && cleanChildren(parent);
|
|
2005
|
+
appendNodes(parent, array);
|
|
2006
|
+
}
|
|
2007
|
+
current = array;
|
|
2008
|
+
} else if (value.nodeType) {
|
|
2009
|
+
if (hydrating && value.parentNode) return current = multi ? [value] : value;
|
|
2010
|
+
if (Array.isArray(current)) {
|
|
2011
|
+
if (multi) return current = cleanChildren(parent, current, marker, value);
|
|
2012
|
+
cleanChildren(parent, current, null, value);
|
|
2013
|
+
} else if (current == null || current === "" || !parent.firstChild) {
|
|
2014
|
+
parent.appendChild(value);
|
|
2015
|
+
} else parent.replaceChild(value, parent.firstChild);
|
|
2016
|
+
current = value;
|
|
2017
|
+
} else ;
|
|
2018
|
+
return current;
|
|
2019
|
+
}
|
|
2020
|
+
function normalizeIncomingArray(normalized, array, current, unwrap) {
|
|
2021
|
+
let dynamic = false;
|
|
2022
|
+
for (let i = 0, len = array.length; i < len; i++) {
|
|
2023
|
+
let item = array[i], prev = current && current[normalized.length], t;
|
|
2024
|
+
if (item == null || item === true || item === false) ;
|
|
2025
|
+
else if ((t = typeof item) === "object" && item.nodeType) {
|
|
2026
|
+
normalized.push(item);
|
|
2027
|
+
} else if (Array.isArray(item)) {
|
|
2028
|
+
dynamic = normalizeIncomingArray(normalized, item, prev) || dynamic;
|
|
2029
|
+
} else if (t === "function") {
|
|
2030
|
+
if (unwrap) {
|
|
2031
|
+
while (typeof item === "function") item = item();
|
|
2032
|
+
dynamic = normalizeIncomingArray(normalized, Array.isArray(item) ? item : [item], Array.isArray(prev) ? prev : [prev]) || dynamic;
|
|
2033
|
+
} else {
|
|
2034
|
+
normalized.push(item);
|
|
2035
|
+
dynamic = true;
|
|
2036
|
+
}
|
|
2037
|
+
} else {
|
|
2038
|
+
const value = String(item);
|
|
2039
|
+
if (prev && prev.nodeType === 3 && prev.data === value) normalized.push(prev);
|
|
2040
|
+
else normalized.push(document.createTextNode(value));
|
|
2041
|
+
}
|
|
2042
|
+
}
|
|
2043
|
+
return dynamic;
|
|
2044
|
+
}
|
|
2045
|
+
function appendNodes(parent, array, marker = null) {
|
|
2046
|
+
for (let i = 0, len = array.length; i < len; i++) parent.insertBefore(array[i], marker);
|
|
2047
|
+
}
|
|
2048
|
+
function cleanChildren(parent, current, marker, replacement) {
|
|
2049
|
+
if (marker === void 0) return parent.textContent = "";
|
|
2050
|
+
const node = replacement || document.createTextNode("");
|
|
2051
|
+
if (current.length) {
|
|
2052
|
+
let inserted = false;
|
|
2053
|
+
for (let i = current.length - 1; i >= 0; i--) {
|
|
2054
|
+
const el = current[i];
|
|
2055
|
+
if (node !== el) {
|
|
2056
|
+
const isParent = el.parentNode === parent;
|
|
2057
|
+
if (!inserted && !i) isParent ? parent.replaceChild(node, el) : parent.insertBefore(node, marker);
|
|
2058
|
+
else isParent && el.remove();
|
|
2059
|
+
} else inserted = true;
|
|
2060
|
+
}
|
|
2061
|
+
} else parent.insertBefore(node, marker);
|
|
2062
|
+
return [node];
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// src/ui/icons/index.ts
|
|
2066
|
+
var S = 'width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"';
|
|
2067
|
+
var icons = {
|
|
2068
|
+
pin: `<svg ${S}><path d="M15 4.5l-4 4l-4 1.5l-1.5 1.5l7 7l1.5 -1.5l1.5 -4l4 -4"/><path d="M9 15l-4.5 4.5"/><path d="M14.5 4l5.5 5.5"/></svg>`,
|
|
2069
|
+
mapPin: `<svg ${S}><path d="M9 11a3 3 0 1 0 6 0a3 3 0 0 0 -6 0"/><path d="M17.657 16.657l-4.243 4.243a2 2 0 0 1 -2.827 0l-4.244 -4.243a8 8 0 1 1 11.314 0"/></svg>`,
|
|
2070
|
+
crosshair: `<svg ${S}><path d="M4 8v-2a2 2 0 0 1 2 -2h2"/><path d="M4 16v2a2 2 0 0 0 2 2h2"/><path d="M16 4h2a2 2 0 0 1 2 2v2"/><path d="M16 20h2a2 2 0 0 0 2 -2v-2"/><path d="M9 12l6 0"/><path d="M12 9l0 6"/></svg>`,
|
|
2071
|
+
send: `<svg ${S}><path d="M10 14l11 -11"/><path d="M21 3l-6.5 18a.55 .55 0 0 1 -1 0l-3.5 -7l-7 -3.5a.55 .55 0 0 1 0 -1l18 -6.5"/></svg>`,
|
|
2072
|
+
copy: `<svg ${S}><path d="M7 9.667a2.667 2.667 0 0 1 2.667 -2.667h8.666a2.667 2.667 0 0 1 2.667 2.667v8.666a2.667 2.667 0 0 1 -2.667 2.667h-8.666a2.667 2.667 0 0 1 -2.667 -2.667z"/><path d="M4.012 16.737a2.005 2.005 0 0 1 -1.012 -1.737v-10c0 -1.1 .9 -2 2 -2h10c.75 0 1.158 .385 1.5 1"/></svg>`,
|
|
2073
|
+
trash: `<svg ${S}><path d="M4 7l16 0"/><path d="M10 11l0 6"/><path d="M14 11l0 6"/><path d="M5 7l1 12a2 2 0 0 0 2 2h8a2 2 0 0 0 2 -2l1 -12"/><path d="M9 7v-3a1 1 0 0 1 1 -1h4a1 1 0 0 1 1 1v3"/></svg>`,
|
|
2074
|
+
settings: `<svg ${S}><path d="M10.325 4.317c.426 -1.756 2.924 -1.756 3.35 0a1.724 1.724 0 0 0 2.573 1.066c1.543 -.94 3.31 .826 2.37 2.37a1.724 1.724 0 0 0 1.065 2.572c1.756 .426 1.756 2.924 0 3.35a1.724 1.724 0 0 0 -1.066 2.573c.94 1.543 -.826 3.31 -2.37 2.37a1.724 1.724 0 0 0 -2.572 1.065c-.426 1.756 -2.924 1.756 -3.35 0a1.724 1.724 0 0 0 -2.573 -1.066c-1.543 .94 -3.31 -.826 -2.37 -2.37a1.724 1.724 0 0 0 -1.065 -2.572c-1.756 -.426 -1.756 -2.924 0 -3.35a1.724 1.724 0 0 0 1.066 -2.573c-.94 -1.543 .826 -3.31 2.37 -2.37c1 .608 2.296 .07 2.572 -1.065"/><path d="M9 12a3 3 0 1 0 6 0a3 3 0 0 0 -6 0"/></svg>`,
|
|
2075
|
+
x: `<svg ${S}><path d="M18 6l-12 12"/><path d="M6 6l12 12"/></svg>`,
|
|
2076
|
+
chevronDown: `<svg ${S}><path d="M6 9l6 6l6 -6"/></svg>`,
|
|
2077
|
+
check: `<svg ${S}><path d="M5 12l5 5l10 -10"/></svg>`,
|
|
2078
|
+
messageSquare: `<svg ${S}><path d="M8 9h8"/><path d="M8 13h6"/><path d="M18 4a3 3 0 0 1 3 3v8a3 3 0 0 1 -3 3h-5l-5 3v-3h-2a3 3 0 0 1 -3 -3v-8a3 3 0 0 1 3 -3h12"/></svg>`,
|
|
2079
|
+
eye: `<svg ${S}><path d="M10 12a2 2 0 1 0 4 0a2 2 0 0 0 -4 0"/><path d="M21 12c-2.4 4 -5.4 6 -9 6c-3.6 0 -6.6 -2 -9 -6c2.4 -4 5.4 -6 9 -6c3.6 0 6.6 2 9 6"/></svg>`,
|
|
2080
|
+
fileCode: `<svg ${S}><path d="M14 3v4a1 1 0 0 0 1 1h4"/><path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2"/><path d="M10 13l-1 2l1 2"/><path d="M14 13l1 2l-1 2"/></svg>`,
|
|
2081
|
+
history: `<svg ${S}><path d="M12 8l0 4l2 2"/><path d="M3.05 11a9 9 0 1 1 .5 4m-.5 5v-5h5"/></svg>`,
|
|
2082
|
+
minus: `<svg ${S}><path d="M5 12l14 0"/></svg>`,
|
|
2083
|
+
// Draw mode icons
|
|
2084
|
+
pencil: `<svg ${S}><path d="M4 20h4l10.5 -10.5a2.828 2.828 0 1 0 -4 -4l-10.5 10.5v4"/><path d="M13.5 6.5l4 4"/></svg>`,
|
|
2085
|
+
arrowUpRight: `<svg ${S}><path d="M17 7l-10 10"/><path d="M8 7l9 0l0 9"/></svg>`,
|
|
2086
|
+
circle: `<svg ${S}><circle cx="12" cy="12" r="9"/></svg>`,
|
|
2087
|
+
square: `<svg ${S}><rect x="4" y="4" width="16" height="16" rx="2"/></svg>`,
|
|
2088
|
+
typography: `<svg ${S}><path d="M4 20l3 0"/><path d="M14 20l7 0"/><path d="M6.9 15l6.9 0"/><path d="M10.2 6.3l5.8 13.7"/><path d="M5 20l6 -16l2 0l7 16"/></svg>`,
|
|
2089
|
+
undo: `<svg ${S}><path d="M9 14l-4 -4l4 -4"/><path d="M5 10h11a4 4 0 1 1 0 8h-1"/></svg>`,
|
|
2090
|
+
palette: `<svg ${S}><path d="M12 21a9 9 0 0 1 0 -18c4.97 0 9 3.582 9 8c0 1.06 -.474 2.078 -1.318 2.828c-.844 .75 -1.989 1.172 -3.182 1.172h-2.5a2 2 0 0 0 -1 3.75a1.3 1.3 0 0 1 -1 2.25"/><circle cx="8.5" cy="10.5" r="1"/><circle cx="12.5" cy="7.5" r="1"/><circle cx="16.5" cy="10.5" r="1"/></svg>`,
|
|
2091
|
+
lineWeight: `<svg ${S}><path d="M4 6h16"/><path d="M4 12h16" stroke-width="3"/><path d="M4 18h16" stroke-width="5"/></svg>`,
|
|
2092
|
+
// Voice icon
|
|
2093
|
+
microphone: `<svg ${S}><path d="M9 2m0 3a3 3 0 0 1 3 -3h0a3 3 0 0 1 3 3v5a3 3 0 0 1 -3 3h0a3 3 0 0 1 -3 -3z"/><path d="M5 10a7 7 0 0 0 14 0"/><path d="M8 21l8 0"/><path d="M12 17l0 4"/></svg>`,
|
|
2094
|
+
microphoneOff: `<svg ${S}><path d="M3 3l18 18"/><path d="M9 5a3 3 0 0 1 6 0v5a3 3 0 0 1 -.13 .874m-2 2a3 3 0 0 1 -3.87 -2.872v-1"/><path d="M5 10a7 7 0 0 0 10.846 5.85m2 -2a6.967 6.967 0 0 0 1.152 -3.85"/><path d="M8 21l8 0"/><path d="M12 17l0 4"/></svg>`,
|
|
2095
|
+
// Queue & batch icons
|
|
2096
|
+
plus: `<svg ${S}><path d="M12 5l0 14"/><path d="M5 12l14 0"/></svg>`,
|
|
2097
|
+
stack: `<svg ${S}><path d="M12 2l-8 4l8 4l8 -4l-8 -4"/><path d="M4 10l8 4l8 -4"/><path d="M4 14l8 4l8 -4"/></svg>`,
|
|
2098
|
+
checkSquare: `<svg ${S}><rect x="3" y="3" width="18" height="18" rx="2"/><path d="M9 12l2 2l4 -4"/></svg>`,
|
|
2099
|
+
squareEmpty: `<svg ${S}><rect x="3" y="3" width="18" height="18" rx="2"/></svg>`,
|
|
2100
|
+
bolt: `<svg ${S}><path d="M13 3l0 7l6 0l-8 11l0 -7l-6 0l8 -11"/></svg>`,
|
|
2101
|
+
checkCircle: `<svg ${S}><circle cx="12" cy="12" r="9"/><path d="M9 12l2 2l4 -4"/></svg>`
|
|
2102
|
+
};
|
|
2103
|
+
|
|
2104
|
+
// src/ui/components/ContextMenu.tsx
|
|
2105
|
+
var _tmpl$ = /* @__PURE__ */ template(`<div class=pp-context-menu><div class=pp-context-menu__item><span></span>Add Annotation</div><div class=pp-context-menu__item><span></span>Quick Prompt</div><div class=pp-context-menu__separator></div><div class=pp-context-menu__item><span></span>Copy Element Context</div><div class=pp-context-menu__item><span></span>Copy HTML Snippet</div><div class=pp-context-menu__item><span></span>Copy Computed Styles`);
|
|
2106
|
+
var ContextMenu = (props) => {
|
|
2107
|
+
let menuRef;
|
|
2108
|
+
onMount(() => {
|
|
2109
|
+
const handleClick = (e) => {
|
|
2110
|
+
if (menuRef && !e.composedPath().includes(menuRef)) {
|
|
2111
|
+
props.onClose();
|
|
2112
|
+
}
|
|
2113
|
+
};
|
|
2114
|
+
const handleKeyDown = (e) => {
|
|
2115
|
+
if (e.key === "Escape") props.onClose();
|
|
2116
|
+
};
|
|
2117
|
+
setTimeout(() => {
|
|
2118
|
+
document.addEventListener("click", handleClick, true);
|
|
2119
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
2120
|
+
}, 0);
|
|
2121
|
+
onCleanup(() => {
|
|
2122
|
+
document.removeEventListener("click", handleClick, true);
|
|
2123
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
2124
|
+
});
|
|
2125
|
+
});
|
|
2126
|
+
const x = Math.min(props.position.x, window.innerWidth - 200);
|
|
2127
|
+
const y = Math.min(props.position.y, window.innerHeight - 250);
|
|
2128
|
+
return (() => {
|
|
2129
|
+
var _el$ = _tmpl$(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$2.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$4.nextSibling, _el$7 = _el$6.nextSibling, _el$8 = _el$7.firstChild, _el$9 = _el$7.nextSibling, _el$0 = _el$9.firstChild, _el$1 = _el$9.nextSibling, _el$10 = _el$1.firstChild;
|
|
2130
|
+
var _ref$ = menuRef;
|
|
2131
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : menuRef = _el$;
|
|
2132
|
+
setStyleProperty(_el$, "left", `${x}px`);
|
|
2133
|
+
setStyleProperty(_el$, "top", `${y}px`);
|
|
2134
|
+
addEventListener(_el$2, "click", () => props.onAnnotate());
|
|
2135
|
+
addEventListener(_el$4, "click", () => props.onPrompt());
|
|
2136
|
+
addEventListener(_el$7, "click", () => props.onCopyContext());
|
|
2137
|
+
addEventListener(_el$9, "click", async () => {
|
|
2138
|
+
const html = props.element.outerHTML.replace(/\s+/g, " ").trim().slice(0, 500);
|
|
2139
|
+
await navigator.clipboard.writeText(html);
|
|
2140
|
+
props.onClose();
|
|
2141
|
+
});
|
|
2142
|
+
addEventListener(_el$1, "click", async () => {
|
|
2143
|
+
const styles = window.getComputedStyle(props.element);
|
|
2144
|
+
const relevant = ["color", "background-color", "font-size", "font-family", "padding", "margin", "border", "display", "position", "width", "height"];
|
|
2145
|
+
const result = relevant.map((key) => `${key}: ${styles.getPropertyValue(key)}`).join("\n");
|
|
2146
|
+
await navigator.clipboard.writeText(result);
|
|
2147
|
+
props.onClose();
|
|
2148
|
+
});
|
|
2149
|
+
createRenderEffect((_p$) => {
|
|
2150
|
+
var _v$ = icons.pin, _v$2 = icons.messageSquare, _v$3 = icons.copy, _v$4 = icons.fileCode, _v$5 = icons.eye;
|
|
2151
|
+
_v$ !== _p$.e && (_el$3.innerHTML = _p$.e = _v$);
|
|
2152
|
+
_v$2 !== _p$.t && (_el$5.innerHTML = _p$.t = _v$2);
|
|
2153
|
+
_v$3 !== _p$.a && (_el$8.innerHTML = _p$.a = _v$3);
|
|
2154
|
+
_v$4 !== _p$.o && (_el$0.innerHTML = _p$.o = _v$4);
|
|
2155
|
+
_v$5 !== _p$.i && (_el$10.innerHTML = _p$.i = _v$5);
|
|
2156
|
+
return _p$;
|
|
2157
|
+
}, {
|
|
2158
|
+
e: void 0,
|
|
2159
|
+
t: void 0,
|
|
2160
|
+
a: void 0,
|
|
2161
|
+
o: void 0,
|
|
2162
|
+
i: void 0
|
|
2163
|
+
});
|
|
2164
|
+
return _el$;
|
|
2165
|
+
})();
|
|
2166
|
+
};
|
|
2167
|
+
|
|
2168
|
+
// src/ui/components/OverlayCanvas.tsx
|
|
2169
|
+
var _tmpl$2 = /* @__PURE__ */ template(`<canvas style=position:fixed;top:0;left:0;z-index:2147483645>`);
|
|
2170
|
+
function lerp(start, end, t) {
|
|
2171
|
+
return start + (end - start) * t;
|
|
2172
|
+
}
|
|
2173
|
+
var OverlayCanvas = (props) => {
|
|
2174
|
+
let canvasRef;
|
|
2175
|
+
let animFrameId = null;
|
|
2176
|
+
let currentRect = {
|
|
2177
|
+
x: 0,
|
|
2178
|
+
y: 0,
|
|
2179
|
+
width: 0,
|
|
2180
|
+
height: 0
|
|
2181
|
+
};
|
|
2182
|
+
let targetRect = null;
|
|
2183
|
+
const LERP_SPEED = 0.25;
|
|
2184
|
+
function resizeCanvas() {
|
|
2185
|
+
if (!canvasRef) return;
|
|
2186
|
+
const dpr = window.devicePixelRatio || 1;
|
|
2187
|
+
canvasRef.width = window.innerWidth * dpr;
|
|
2188
|
+
canvasRef.height = window.innerHeight * dpr;
|
|
2189
|
+
canvasRef.style.width = `${window.innerWidth}px`;
|
|
2190
|
+
canvasRef.style.height = `${window.innerHeight}px`;
|
|
2191
|
+
const ctx = canvasRef.getContext("2d");
|
|
2192
|
+
if (ctx) ctx.scale(dpr, dpr);
|
|
2193
|
+
}
|
|
2194
|
+
function drawStroke(ctx, stroke) {
|
|
2195
|
+
if (stroke.points.length < 1) return;
|
|
2196
|
+
ctx.strokeStyle = stroke.color;
|
|
2197
|
+
ctx.lineWidth = stroke.lineWidth;
|
|
2198
|
+
ctx.lineCap = "round";
|
|
2199
|
+
ctx.lineJoin = "round";
|
|
2200
|
+
ctx.setLineDash([]);
|
|
2201
|
+
if (stroke.type === "freehand") {
|
|
2202
|
+
ctx.beginPath();
|
|
2203
|
+
ctx.moveTo(stroke.points[0].x, stroke.points[0].y);
|
|
2204
|
+
for (let i = 1; i < stroke.points.length; i++) {
|
|
2205
|
+
ctx.lineTo(stroke.points[i].x, stroke.points[i].y);
|
|
2206
|
+
}
|
|
2207
|
+
ctx.stroke();
|
|
2208
|
+
} else if (stroke.type === "arrow") {
|
|
2209
|
+
if (stroke.points.length < 2) return;
|
|
2210
|
+
const start = stroke.points[0];
|
|
2211
|
+
const end = stroke.points[stroke.points.length - 1];
|
|
2212
|
+
ctx.beginPath();
|
|
2213
|
+
ctx.moveTo(start.x, start.y);
|
|
2214
|
+
ctx.lineTo(end.x, end.y);
|
|
2215
|
+
ctx.stroke();
|
|
2216
|
+
const angle = Math.atan2(end.y - start.y, end.x - start.x);
|
|
2217
|
+
const headLen = 12 + stroke.lineWidth * 2;
|
|
2218
|
+
ctx.beginPath();
|
|
2219
|
+
ctx.moveTo(end.x, end.y);
|
|
2220
|
+
ctx.lineTo(end.x - headLen * Math.cos(angle - Math.PI / 6), end.y - headLen * Math.sin(angle - Math.PI / 6));
|
|
2221
|
+
ctx.moveTo(end.x, end.y);
|
|
2222
|
+
ctx.lineTo(end.x - headLen * Math.cos(angle + Math.PI / 6), end.y - headLen * Math.sin(angle + Math.PI / 6));
|
|
2223
|
+
ctx.stroke();
|
|
2224
|
+
} else if (stroke.type === "circle") {
|
|
2225
|
+
if (stroke.points.length < 2) return;
|
|
2226
|
+
const start = stroke.points[0];
|
|
2227
|
+
const end = stroke.points[stroke.points.length - 1];
|
|
2228
|
+
const rx = Math.abs(end.x - start.x) / 2;
|
|
2229
|
+
const ry = Math.abs(end.y - start.y) / 2;
|
|
2230
|
+
const cx = (start.x + end.x) / 2;
|
|
2231
|
+
const cy = (start.y + end.y) / 2;
|
|
2232
|
+
ctx.beginPath();
|
|
2233
|
+
ctx.ellipse(cx, cy, rx, ry, 0, 0, Math.PI * 2);
|
|
2234
|
+
ctx.stroke();
|
|
2235
|
+
} else if (stroke.type === "rect") {
|
|
2236
|
+
if (stroke.points.length < 2) return;
|
|
2237
|
+
const start = stroke.points[0];
|
|
2238
|
+
const end = stroke.points[stroke.points.length - 1];
|
|
2239
|
+
ctx.strokeRect(start.x, start.y, end.x - start.x, end.y - start.y);
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
function drawTextNote(ctx, note) {
|
|
2243
|
+
const fontSize = 13;
|
|
2244
|
+
const padding = 6;
|
|
2245
|
+
ctx.font = `500 ${fontSize}px -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif`;
|
|
2246
|
+
const metrics = ctx.measureText(note.text);
|
|
2247
|
+
const textWidth = metrics.width;
|
|
2248
|
+
const textHeight = fontSize + 2;
|
|
2249
|
+
ctx.fillStyle = "rgba(0, 0, 0, 0.75)";
|
|
2250
|
+
const bgX = note.x - 2;
|
|
2251
|
+
const bgY = note.y - textHeight - padding / 2;
|
|
2252
|
+
const bgW = textWidth + padding * 2;
|
|
2253
|
+
const bgH = textHeight + padding;
|
|
2254
|
+
const r = 4;
|
|
2255
|
+
ctx.beginPath();
|
|
2256
|
+
ctx.moveTo(bgX + r, bgY);
|
|
2257
|
+
ctx.lineTo(bgX + bgW - r, bgY);
|
|
2258
|
+
ctx.quadraticCurveTo(bgX + bgW, bgY, bgX + bgW, bgY + r);
|
|
2259
|
+
ctx.lineTo(bgX + bgW, bgY + bgH - r);
|
|
2260
|
+
ctx.quadraticCurveTo(bgX + bgW, bgY + bgH, bgX + bgW - r, bgY + bgH);
|
|
2261
|
+
ctx.lineTo(bgX + r, bgY + bgH);
|
|
2262
|
+
ctx.quadraticCurveTo(bgX, bgY + bgH, bgX, bgY + bgH - r);
|
|
2263
|
+
ctx.lineTo(bgX, bgY + r);
|
|
2264
|
+
ctx.quadraticCurveTo(bgX, bgY, bgX + r, bgY);
|
|
2265
|
+
ctx.closePath();
|
|
2266
|
+
ctx.fill();
|
|
2267
|
+
ctx.fillStyle = note.color;
|
|
2268
|
+
ctx.beginPath();
|
|
2269
|
+
ctx.arc(bgX + padding, bgY + bgH / 2, 3, 0, Math.PI * 2);
|
|
2270
|
+
ctx.fill();
|
|
2271
|
+
ctx.fillStyle = "#ffffff";
|
|
2272
|
+
ctx.fillText(note.text, bgX + padding + 10, note.y - 2);
|
|
2273
|
+
}
|
|
2274
|
+
function draw() {
|
|
2275
|
+
if (!canvasRef) return;
|
|
2276
|
+
const ctx = canvasRef.getContext("2d");
|
|
2277
|
+
if (!ctx) return;
|
|
2278
|
+
const dpr = window.devicePixelRatio || 1;
|
|
2279
|
+
ctx.clearRect(0, 0, canvasRef.width / dpr, canvasRef.height / dpr);
|
|
2280
|
+
if (props.active && !props.drawMode && props.hoveredRect) {
|
|
2281
|
+
targetRect = {
|
|
2282
|
+
x: props.hoveredRect.x,
|
|
2283
|
+
y: props.hoveredRect.y,
|
|
2284
|
+
width: props.hoveredRect.width,
|
|
2285
|
+
height: props.hoveredRect.height
|
|
2286
|
+
};
|
|
2287
|
+
} else if (props.active && !props.drawMode) {
|
|
2288
|
+
targetRect = null;
|
|
2289
|
+
}
|
|
2290
|
+
if (props.active && !props.drawMode && targetRect) {
|
|
2291
|
+
currentRect.x = lerp(currentRect.x, targetRect.x, LERP_SPEED);
|
|
2292
|
+
currentRect.y = lerp(currentRect.y, targetRect.y, LERP_SPEED);
|
|
2293
|
+
currentRect.width = lerp(currentRect.width, targetRect.width, LERP_SPEED);
|
|
2294
|
+
currentRect.height = lerp(currentRect.height, targetRect.height, LERP_SPEED);
|
|
2295
|
+
ctx.strokeStyle = "rgba(59, 130, 246, 0.8)";
|
|
2296
|
+
ctx.lineWidth = 2;
|
|
2297
|
+
ctx.setLineDash([]);
|
|
2298
|
+
ctx.strokeRect(currentRect.x, currentRect.y, currentRect.width, currentRect.height);
|
|
2299
|
+
ctx.fillStyle = "rgba(59, 130, 246, 0.06)";
|
|
2300
|
+
ctx.fillRect(currentRect.x, currentRect.y, currentRect.width, currentRect.height);
|
|
2301
|
+
}
|
|
2302
|
+
if (props.active && !props.drawMode && props.dragRect) {
|
|
2303
|
+
ctx.strokeStyle = "rgba(59, 130, 246, 0.6)";
|
|
2304
|
+
ctx.lineWidth = 1;
|
|
2305
|
+
ctx.setLineDash([4, 4]);
|
|
2306
|
+
ctx.strokeRect(props.dragRect.x, props.dragRect.y, props.dragRect.width, props.dragRect.height);
|
|
2307
|
+
ctx.fillStyle = "rgba(59, 130, 246, 0.08)";
|
|
2308
|
+
ctx.fillRect(props.dragRect.x, props.dragRect.y, props.dragRect.width, props.dragRect.height);
|
|
2309
|
+
}
|
|
2310
|
+
for (const stroke of props.drawStrokes) {
|
|
2311
|
+
drawStroke(ctx, stroke);
|
|
2312
|
+
}
|
|
2313
|
+
if (props.currentStroke) {
|
|
2314
|
+
drawStroke(ctx, props.currentStroke);
|
|
2315
|
+
}
|
|
2316
|
+
for (const note of props.textNotes) {
|
|
2317
|
+
drawTextNote(ctx, note);
|
|
2318
|
+
}
|
|
2319
|
+
animFrameId = requestAnimationFrame(draw);
|
|
2320
|
+
}
|
|
2321
|
+
function handleMouseDown(e) {
|
|
2322
|
+
if (!props.drawMode) return;
|
|
2323
|
+
if (props.drawTool === "text") {
|
|
2324
|
+
props.onTextPlace(e.clientX, e.clientY);
|
|
2325
|
+
} else {
|
|
2326
|
+
props.onDrawStart(e.clientX, e.clientY);
|
|
2327
|
+
}
|
|
2328
|
+
}
|
|
2329
|
+
function handleMouseMove(e) {
|
|
2330
|
+
if (!props.drawMode) return;
|
|
2331
|
+
props.onDrawMove(e.clientX, e.clientY);
|
|
2332
|
+
}
|
|
2333
|
+
function handleMouseUp(_e) {
|
|
2334
|
+
if (!props.drawMode) return;
|
|
2335
|
+
props.onDrawEnd();
|
|
2336
|
+
}
|
|
2337
|
+
function handleTouchStart(e) {
|
|
2338
|
+
if (!props.drawMode) return;
|
|
2339
|
+
e.preventDefault();
|
|
2340
|
+
const touch = e.touches[0];
|
|
2341
|
+
if (props.drawTool === "text") {
|
|
2342
|
+
props.onTextPlace(touch.clientX, touch.clientY);
|
|
2343
|
+
} else {
|
|
2344
|
+
props.onDrawStart(touch.clientX, touch.clientY);
|
|
2345
|
+
}
|
|
2346
|
+
}
|
|
2347
|
+
function handleTouchMove(e) {
|
|
2348
|
+
if (!props.drawMode) return;
|
|
2349
|
+
e.preventDefault();
|
|
2350
|
+
const touch = e.touches[0];
|
|
2351
|
+
props.onDrawMove(touch.clientX, touch.clientY);
|
|
2352
|
+
}
|
|
2353
|
+
function handleTouchEnd(e) {
|
|
2354
|
+
if (!props.drawMode) return;
|
|
2355
|
+
e.preventDefault();
|
|
2356
|
+
props.onDrawEnd();
|
|
2357
|
+
}
|
|
2358
|
+
onMount(() => {
|
|
2359
|
+
resizeCanvas();
|
|
2360
|
+
window.addEventListener("resize", resizeCanvas);
|
|
2361
|
+
animFrameId = requestAnimationFrame(draw);
|
|
2362
|
+
});
|
|
2363
|
+
onCleanup(() => {
|
|
2364
|
+
window.removeEventListener("resize", resizeCanvas);
|
|
2365
|
+
if (animFrameId !== null) {
|
|
2366
|
+
cancelAnimationFrame(animFrameId);
|
|
2367
|
+
}
|
|
2368
|
+
});
|
|
2369
|
+
return (() => {
|
|
2370
|
+
var _el$ = _tmpl$2();
|
|
2371
|
+
_el$.$$touchend = handleTouchEnd;
|
|
2372
|
+
_el$.$$touchmove = handleTouchMove;
|
|
2373
|
+
_el$.$$touchstart = handleTouchStart;
|
|
2374
|
+
_el$.$$mouseup = handleMouseUp;
|
|
2375
|
+
_el$.$$mousemove = handleMouseMove;
|
|
2376
|
+
_el$.$$mousedown = handleMouseDown;
|
|
2377
|
+
var _ref$ = canvasRef;
|
|
2378
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : canvasRef = _el$;
|
|
2379
|
+
createRenderEffect((_p$) => {
|
|
2380
|
+
var _v$ = props.drawMode ? "auto" : "none", _v$2 = props.drawMode ? props.drawTool === "text" ? "text" : "crosshair" : "default";
|
|
2381
|
+
_v$ !== _p$.e && setStyleProperty(_el$, "pointer-events", _p$.e = _v$);
|
|
2382
|
+
_v$2 !== _p$.t && setStyleProperty(_el$, "cursor", _p$.t = _v$2);
|
|
2383
|
+
return _p$;
|
|
2384
|
+
}, {
|
|
2385
|
+
e: void 0,
|
|
2386
|
+
t: void 0
|
|
2387
|
+
});
|
|
2388
|
+
return _el$;
|
|
2389
|
+
})();
|
|
2390
|
+
};
|
|
2391
|
+
delegateEvents(["mousedown", "mousemove", "mouseup", "touchstart", "touchmove", "touchend"]);
|
|
2392
|
+
|
|
2393
|
+
// src/ui/components/PinPopup.tsx
|
|
2394
|
+
var _tmpl$3 = /* @__PURE__ */ template(`<div class=pp-popup><div class=pp-popup__input-row><textarea class=pp-popup__textarea placeholder="Add your feedback..."></textarea></div><div class=pp-popup__actions><button class="pp-btn pp-btn--ghost"title="Send 'Fix this' to agent"><span style=display:inline-flex></span>Fix</button><div style=flex:1></div><button class=pp-btn>Cancel</button><button class="pp-btn pp-btn--primary">`);
|
|
2395
|
+
var _tmpl$22 = /* @__PURE__ */ template(`<div class=pp-popup__header><span class=pp-popup__name></span><span>`);
|
|
2396
|
+
var _tmpl$32 = /* @__PURE__ */ template(`<div><div class=pp-popup__details-inner><div class=pp-popup__element-info>`);
|
|
2397
|
+
var _tmpl$4 = /* @__PURE__ */ template(`<div class=pp-popup__source><span style=display:inline-flex;vertical-align:middle></span> `);
|
|
2398
|
+
var _tmpl$5 = /* @__PURE__ */ template(`<div class=pp-popup__component>`);
|
|
2399
|
+
var _tmpl$6 = /* @__PURE__ */ template(`<div class=pp-popup__element-info>`);
|
|
2400
|
+
var _tmpl$7 = /* @__PURE__ */ template(`<button>`);
|
|
2401
|
+
var _tmpl$8 = /* @__PURE__ */ template(`<button class=pp-btn title="Add to queue"><span style=display:inline-flex></span>Queue`);
|
|
2402
|
+
function getSpeechRecognition() {
|
|
2403
|
+
const w = window;
|
|
2404
|
+
return w.SpeechRecognition || w.webkitSpeechRecognition || null;
|
|
2405
|
+
}
|
|
2406
|
+
var PinPopup = (props) => {
|
|
2407
|
+
const [comment, setComment] = createSignal(props.initialComment || "");
|
|
2408
|
+
const [showDetails, setShowDetails] = createSignal(false);
|
|
2409
|
+
const [isRecording, setIsRecording] = createSignal(false);
|
|
2410
|
+
let textareaRef;
|
|
2411
|
+
let recognitionRef = null;
|
|
2412
|
+
const compact = () => props.compactPopup ?? true;
|
|
2413
|
+
const hasSpeechAPI = !!getSpeechRecognition();
|
|
2414
|
+
const displayName = () => {
|
|
2415
|
+
if (props.context.framework?.componentPath) {
|
|
2416
|
+
return props.context.framework.componentPath;
|
|
2417
|
+
}
|
|
2418
|
+
return `<${props.context.element.tagName.toLowerCase()}>`;
|
|
2419
|
+
};
|
|
2420
|
+
const popupPosition = () => {
|
|
2421
|
+
const rect = props.context.element.boundingRect;
|
|
2422
|
+
const estimatedHeight = compact() && showDetails() ? 260 : 220;
|
|
2423
|
+
const popupX = Math.min(rect.x, window.innerWidth - 380);
|
|
2424
|
+
const popupY = rect.y + rect.height + 8;
|
|
2425
|
+
const adjustedY = popupY + estimatedHeight > window.innerHeight ? rect.y - estimatedHeight - 8 : popupY;
|
|
2426
|
+
return {
|
|
2427
|
+
x: Math.max(8, popupX),
|
|
2428
|
+
y: Math.max(8, adjustedY)
|
|
2429
|
+
};
|
|
2430
|
+
};
|
|
2431
|
+
async function openFileHandler() {
|
|
2432
|
+
try {
|
|
2433
|
+
const file = props.context.framework?.sourceFile;
|
|
2434
|
+
if (!file) return;
|
|
2435
|
+
const {
|
|
2436
|
+
openFile
|
|
2437
|
+
} = await import("./open-file-WR2JHI4P.js");
|
|
2438
|
+
openFile(file);
|
|
2439
|
+
} catch {
|
|
2440
|
+
}
|
|
2441
|
+
}
|
|
2442
|
+
function toggleRecording() {
|
|
2443
|
+
if (isRecording()) {
|
|
2444
|
+
stopRecording();
|
|
2445
|
+
} else {
|
|
2446
|
+
startRecording();
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
function startRecording() {
|
|
2450
|
+
const SpeechRecognitionClass = getSpeechRecognition();
|
|
2451
|
+
if (!SpeechRecognitionClass) return;
|
|
2452
|
+
const recognition = new SpeechRecognitionClass();
|
|
2453
|
+
recognition.continuous = true;
|
|
2454
|
+
recognition.interimResults = true;
|
|
2455
|
+
recognition.lang = "en-US";
|
|
2456
|
+
let finalTranscript = "";
|
|
2457
|
+
recognition.onresult = (event) => {
|
|
2458
|
+
let interim = "";
|
|
2459
|
+
for (let i = event.resultIndex; i < event.results.length; i++) {
|
|
2460
|
+
const transcript = event.results[i][0].transcript;
|
|
2461
|
+
if (event.results[i].isFinal) {
|
|
2462
|
+
finalTranscript += transcript;
|
|
2463
|
+
} else {
|
|
2464
|
+
interim = transcript;
|
|
2465
|
+
}
|
|
2466
|
+
}
|
|
2467
|
+
const current = comment();
|
|
2468
|
+
const separator = current && !current.endsWith(" ") ? " " : "";
|
|
2469
|
+
setComment(current + separator + finalTranscript + interim);
|
|
2470
|
+
finalTranscript = "";
|
|
2471
|
+
if (textareaRef) {
|
|
2472
|
+
textareaRef.style.height = "auto";
|
|
2473
|
+
textareaRef.style.height = Math.min(textareaRef.scrollHeight, 120) + "px";
|
|
2474
|
+
}
|
|
2475
|
+
};
|
|
2476
|
+
recognition.onerror = () => {
|
|
2477
|
+
setIsRecording(false);
|
|
2478
|
+
};
|
|
2479
|
+
recognition.onend = () => {
|
|
2480
|
+
setIsRecording(false);
|
|
2481
|
+
};
|
|
2482
|
+
recognition.start();
|
|
2483
|
+
recognitionRef = recognition;
|
|
2484
|
+
setIsRecording(true);
|
|
2485
|
+
}
|
|
2486
|
+
function stopRecording() {
|
|
2487
|
+
recognitionRef?.stop();
|
|
2488
|
+
recognitionRef = null;
|
|
2489
|
+
setIsRecording(false);
|
|
2490
|
+
}
|
|
2491
|
+
onMount(() => {
|
|
2492
|
+
textareaRef?.focus();
|
|
2493
|
+
if (props.initialComment && textareaRef) {
|
|
2494
|
+
textareaRef.selectionStart = textareaRef.value.length;
|
|
2495
|
+
}
|
|
2496
|
+
const onEsc = (e) => {
|
|
2497
|
+
if (e.key === "Escape") {
|
|
2498
|
+
e.stopPropagation();
|
|
2499
|
+
stopRecording();
|
|
2500
|
+
props.onCancel();
|
|
2501
|
+
}
|
|
2502
|
+
};
|
|
2503
|
+
document.addEventListener("keydown", onEsc, true);
|
|
2504
|
+
onCleanup(() => {
|
|
2505
|
+
document.removeEventListener("keydown", onEsc, true);
|
|
2506
|
+
stopRecording();
|
|
2507
|
+
});
|
|
2508
|
+
});
|
|
2509
|
+
function handleSubmit() {
|
|
2510
|
+
const text = comment().trim();
|
|
2511
|
+
if (!text) return;
|
|
2512
|
+
stopRecording();
|
|
2513
|
+
props.onAdd(text);
|
|
2514
|
+
}
|
|
2515
|
+
function handleQueue() {
|
|
2516
|
+
const text = comment().trim();
|
|
2517
|
+
if (!text) return;
|
|
2518
|
+
stopRecording();
|
|
2519
|
+
props.onQueue?.(text);
|
|
2520
|
+
}
|
|
2521
|
+
function handleFixThis() {
|
|
2522
|
+
const text = comment().trim() || `Fix this ${displayName()}`;
|
|
2523
|
+
stopRecording();
|
|
2524
|
+
props.onFixThis?.(text);
|
|
2525
|
+
}
|
|
2526
|
+
function handleKeyDown(e) {
|
|
2527
|
+
if (e.key === "Enter" && (e.metaKey || e.ctrlKey)) {
|
|
2528
|
+
e.preventDefault();
|
|
2529
|
+
handleSubmit();
|
|
2530
|
+
}
|
|
2531
|
+
if (e.key === "Escape") {
|
|
2532
|
+
stopRecording();
|
|
2533
|
+
props.onCancel();
|
|
2534
|
+
}
|
|
2535
|
+
}
|
|
2536
|
+
function handleAutoGrow(e) {
|
|
2537
|
+
const el = e.currentTarget;
|
|
2538
|
+
setComment(el.value);
|
|
2539
|
+
el.style.height = "auto";
|
|
2540
|
+
el.style.height = Math.min(el.scrollHeight, 120) + "px";
|
|
2541
|
+
}
|
|
2542
|
+
return (() => {
|
|
2543
|
+
var _el$ = _tmpl$3(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild, _el$4 = _el$2.nextSibling, _el$5 = _el$4.firstChild, _el$6 = _el$5.firstChild, _el$7 = _el$5.nextSibling, _el$8 = _el$7.nextSibling, _el$9 = _el$8.nextSibling;
|
|
2544
|
+
insert(_el$, (() => {
|
|
2545
|
+
var _c$ = memo(() => !!compact());
|
|
2546
|
+
return () => _c$() ? (
|
|
2547
|
+
/* Compact mode — friendly name + collapsible details */
|
|
2548
|
+
[(() => {
|
|
2549
|
+
var _el$0 = _tmpl$22(), _el$1 = _el$0.firstChild, _el$10 = _el$1.nextSibling;
|
|
2550
|
+
addEventListener(_el$0, "click", () => setShowDetails(!showDetails()));
|
|
2551
|
+
insert(_el$1, displayName);
|
|
2552
|
+
createRenderEffect((_p$) => {
|
|
2553
|
+
var _v$5 = `pp-popup__chevron ${showDetails() ? "pp-popup__chevron--open" : ""}`, _v$6 = icons.chevronDown, _v$7 = showDetails();
|
|
2554
|
+
_v$5 !== _p$.e && className(_el$10, _p$.e = _v$5);
|
|
2555
|
+
_v$6 !== _p$.t && (_el$10.innerHTML = _p$.t = _v$6);
|
|
2556
|
+
_v$7 !== _p$.a && setAttribute(_el$10, "aria-expanded", _p$.a = _v$7);
|
|
2557
|
+
return _p$;
|
|
2558
|
+
}, {
|
|
2559
|
+
e: void 0,
|
|
2560
|
+
t: void 0,
|
|
2561
|
+
a: void 0
|
|
2562
|
+
});
|
|
2563
|
+
return _el$0;
|
|
2564
|
+
})(), (() => {
|
|
2565
|
+
var _el$11 = _tmpl$32(), _el$12 = _el$11.firstChild, _el$13 = _el$12.firstChild;
|
|
2566
|
+
insert(_el$13, () => props.context.cssSelector);
|
|
2567
|
+
insert(_el$12, createComponent(Show, {
|
|
2568
|
+
get when() {
|
|
2569
|
+
return props.context.framework?.sourceFile;
|
|
2570
|
+
},
|
|
2571
|
+
children: (file) => (() => {
|
|
2572
|
+
var _el$14 = _tmpl$4(), _el$15 = _el$14.firstChild, _el$16 = _el$15.nextSibling;
|
|
2573
|
+
addEventListener(_el$14, "click", openFileHandler);
|
|
2574
|
+
insert(_el$14, () => file().split("/").pop(), null);
|
|
2575
|
+
createRenderEffect((_p$) => {
|
|
2576
|
+
var _v$8 = file(), _v$9 = icons.fileCode;
|
|
2577
|
+
_v$8 !== _p$.e && setAttribute(_el$14, "title", _p$.e = _v$8);
|
|
2578
|
+
_v$9 !== _p$.t && (_el$15.innerHTML = _p$.t = _v$9);
|
|
2579
|
+
return _p$;
|
|
2580
|
+
}, {
|
|
2581
|
+
e: void 0,
|
|
2582
|
+
t: void 0
|
|
2583
|
+
});
|
|
2584
|
+
return _el$14;
|
|
2585
|
+
})()
|
|
2586
|
+
}), null);
|
|
2587
|
+
createRenderEffect(() => className(_el$11, `pp-popup__details ${showDetails() ? "pp-popup__details--open" : ""}`));
|
|
2588
|
+
return _el$11;
|
|
2589
|
+
})()]
|
|
2590
|
+
) : (
|
|
2591
|
+
/* Expanded mode — all info visible */
|
|
2592
|
+
[(() => {
|
|
2593
|
+
var _el$17 = _tmpl$5();
|
|
2594
|
+
insert(_el$17, displayName);
|
|
2595
|
+
return _el$17;
|
|
2596
|
+
})(), (() => {
|
|
2597
|
+
var _el$18 = _tmpl$6();
|
|
2598
|
+
insert(_el$18, () => props.context.cssSelector);
|
|
2599
|
+
return _el$18;
|
|
2600
|
+
})(), createComponent(Show, {
|
|
2601
|
+
get when() {
|
|
2602
|
+
return props.context.framework?.sourceFile;
|
|
2603
|
+
},
|
|
2604
|
+
children: (file) => (() => {
|
|
2605
|
+
var _el$19 = _tmpl$4(), _el$20 = _el$19.firstChild, _el$21 = _el$20.nextSibling;
|
|
2606
|
+
addEventListener(_el$19, "click", openFileHandler);
|
|
2607
|
+
insert(_el$19, () => file().split("/").pop(), null);
|
|
2608
|
+
createRenderEffect((_p$) => {
|
|
2609
|
+
var _v$0 = file(), _v$1 = icons.fileCode;
|
|
2610
|
+
_v$0 !== _p$.e && setAttribute(_el$19, "title", _p$.e = _v$0);
|
|
2611
|
+
_v$1 !== _p$.t && (_el$20.innerHTML = _p$.t = _v$1);
|
|
2612
|
+
return _p$;
|
|
2613
|
+
}, {
|
|
2614
|
+
e: void 0,
|
|
2615
|
+
t: void 0
|
|
2616
|
+
});
|
|
2617
|
+
return _el$19;
|
|
2618
|
+
})()
|
|
2619
|
+
})]
|
|
2620
|
+
);
|
|
2621
|
+
})(), _el$2);
|
|
2622
|
+
addEventListener(_el$3, "keydown", handleKeyDown);
|
|
2623
|
+
addEventListener(_el$3, "input", handleAutoGrow);
|
|
2624
|
+
var _ref$ = textareaRef;
|
|
2625
|
+
typeof _ref$ === "function" ? use(_ref$, _el$3) : textareaRef = _el$3;
|
|
2626
|
+
insert(_el$2, hasSpeechAPI && (() => {
|
|
2627
|
+
var _el$22 = _tmpl$7();
|
|
2628
|
+
addEventListener(_el$22, "click", toggleRecording);
|
|
2629
|
+
createRenderEffect((_p$) => {
|
|
2630
|
+
var _v$10 = `pp-btn--icon pp-popup__mic ${isRecording() ? "pp-popup__mic--recording" : ""}`, _v$11 = isRecording() ? "Stop recording" : "Voice input", _v$12 = isRecording() ? "Stop recording" : "Voice input", _v$13 = isRecording() ? icons.microphoneOff : icons.microphone;
|
|
2631
|
+
_v$10 !== _p$.e && className(_el$22, _p$.e = _v$10);
|
|
2632
|
+
_v$11 !== _p$.t && setAttribute(_el$22, "title", _p$.t = _v$11);
|
|
2633
|
+
_v$12 !== _p$.a && setAttribute(_el$22, "aria-label", _p$.a = _v$12);
|
|
2634
|
+
_v$13 !== _p$.o && (_el$22.innerHTML = _p$.o = _v$13);
|
|
2635
|
+
return _p$;
|
|
2636
|
+
}, {
|
|
2637
|
+
e: void 0,
|
|
2638
|
+
t: void 0,
|
|
2639
|
+
a: void 0,
|
|
2640
|
+
o: void 0
|
|
2641
|
+
});
|
|
2642
|
+
return _el$22;
|
|
2643
|
+
})(), null);
|
|
2644
|
+
addEventListener(_el$5, "click", handleFixThis);
|
|
2645
|
+
addEventListener(_el$8, "click", () => props.onCancel());
|
|
2646
|
+
insert(_el$4, (() => {
|
|
2647
|
+
var _c$2 = memo(() => !!(props.queueMode && props.onQueue));
|
|
2648
|
+
return () => _c$2() && (() => {
|
|
2649
|
+
var _el$23 = _tmpl$8(), _el$24 = _el$23.firstChild;
|
|
2650
|
+
addEventListener(_el$23, "click", handleQueue);
|
|
2651
|
+
createRenderEffect((_p$) => {
|
|
2652
|
+
var _v$14 = !comment().trim(), _v$15 = icons.plus;
|
|
2653
|
+
_v$14 !== _p$.e && (_el$23.disabled = _p$.e = _v$14);
|
|
2654
|
+
_v$15 !== _p$.t && (_el$24.innerHTML = _p$.t = _v$15);
|
|
2655
|
+
return _p$;
|
|
2656
|
+
}, {
|
|
2657
|
+
e: void 0,
|
|
2658
|
+
t: void 0
|
|
2659
|
+
});
|
|
2660
|
+
return _el$23;
|
|
2661
|
+
})();
|
|
2662
|
+
})(), _el$9);
|
|
2663
|
+
addEventListener(_el$9, "click", () => handleSubmit());
|
|
2664
|
+
insert(_el$9, () => props.isEditing ? "Save" : "Add Pin");
|
|
2665
|
+
createRenderEffect((_p$) => {
|
|
2666
|
+
var _v$ = `${popupPosition().x}px`, _v$2 = `${popupPosition().y}px`, _v$3 = icons.bolt, _v$4 = !comment().trim();
|
|
2667
|
+
_v$ !== _p$.e && setStyleProperty(_el$, "left", _p$.e = _v$);
|
|
2668
|
+
_v$2 !== _p$.t && setStyleProperty(_el$, "top", _p$.t = _v$2);
|
|
2669
|
+
_v$3 !== _p$.a && (_el$6.innerHTML = _p$.a = _v$3);
|
|
2670
|
+
_v$4 !== _p$.o && (_el$9.disabled = _p$.o = _v$4);
|
|
2671
|
+
return _p$;
|
|
2672
|
+
}, {
|
|
2673
|
+
e: void 0,
|
|
2674
|
+
t: void 0,
|
|
2675
|
+
a: void 0,
|
|
2676
|
+
o: void 0
|
|
2677
|
+
});
|
|
2678
|
+
createRenderEffect(() => _el$3.value = comment());
|
|
2679
|
+
return _el$;
|
|
2680
|
+
})();
|
|
2681
|
+
};
|
|
2682
|
+
|
|
2683
|
+
// src/ui/components/PromptMode.tsx
|
|
2684
|
+
var _tmpl$9 = /* @__PURE__ */ template(`<div class=pp-prompt><input class=pp-prompt__input type=text placeholder="Tell the agent what to do..."><button class="pp-btn pp-btn--primary pp-btn--sm"><span>`);
|
|
2685
|
+
var PromptMode = (props) => {
|
|
2686
|
+
const [instruction, setInstruction] = createSignal("");
|
|
2687
|
+
let inputRef;
|
|
2688
|
+
onMount(() => inputRef?.focus());
|
|
2689
|
+
function handleSubmit() {
|
|
2690
|
+
const text = instruction().trim();
|
|
2691
|
+
if (!text) return;
|
|
2692
|
+
props.onSend(text);
|
|
2693
|
+
}
|
|
2694
|
+
const rect = props.element.getBoundingClientRect();
|
|
2695
|
+
const x = Math.max(8, Math.min(rect.left, window.innerWidth - 300));
|
|
2696
|
+
const y = rect.bottom + 8 > window.innerHeight - 40 ? rect.top - 40 : rect.bottom + 8;
|
|
2697
|
+
return (() => {
|
|
2698
|
+
var _el$ = _tmpl$9(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling, _el$4 = _el$3.firstChild;
|
|
2699
|
+
setStyleProperty(_el$, "left", `${x}px`);
|
|
2700
|
+
setStyleProperty(_el$, "top", `${y}px`);
|
|
2701
|
+
_el$2.$$keydown = (e) => {
|
|
2702
|
+
if (e.key === "Enter") handleSubmit();
|
|
2703
|
+
if (e.key === "Escape") props.onCancel();
|
|
2704
|
+
};
|
|
2705
|
+
_el$2.$$input = (e) => setInstruction(e.currentTarget.value);
|
|
2706
|
+
var _ref$ = inputRef;
|
|
2707
|
+
typeof _ref$ === "function" ? use(_ref$, _el$2) : inputRef = _el$2;
|
|
2708
|
+
_el$3.$$click = handleSubmit;
|
|
2709
|
+
createRenderEffect(() => _el$4.innerHTML = icons.send);
|
|
2710
|
+
createRenderEffect(() => _el$2.value = instruction());
|
|
2711
|
+
return _el$;
|
|
2712
|
+
})();
|
|
2713
|
+
};
|
|
2714
|
+
delegateEvents(["input", "keydown", "click"]);
|
|
2715
|
+
|
|
2716
|
+
// src/ui/components/SelectionLabel.tsx
|
|
2717
|
+
var _tmpl$10 = /* @__PURE__ */ template(`<div class=pp-selection-label>`);
|
|
2718
|
+
var SelectionLabel = (props) => {
|
|
2719
|
+
return createComponent(Show, {
|
|
2720
|
+
get when() {
|
|
2721
|
+
return props.info;
|
|
2722
|
+
},
|
|
2723
|
+
children: (info) => {
|
|
2724
|
+
const {
|
|
2725
|
+
text,
|
|
2726
|
+
rect
|
|
2727
|
+
} = info();
|
|
2728
|
+
const y = rect.top > 30 ? rect.top - 24 : rect.bottom + 4;
|
|
2729
|
+
const x = Math.max(4, Math.min(rect.left, window.innerWidth - 300));
|
|
2730
|
+
return (() => {
|
|
2731
|
+
var _el$ = _tmpl$10();
|
|
2732
|
+
setStyleProperty(_el$, "left", `${x}px`);
|
|
2733
|
+
setStyleProperty(_el$, "top", `${y}px`);
|
|
2734
|
+
insert(_el$, text);
|
|
2735
|
+
return _el$;
|
|
2736
|
+
})();
|
|
2737
|
+
}
|
|
2738
|
+
});
|
|
2739
|
+
};
|
|
2740
|
+
|
|
2741
|
+
// src/ui/components/TextInputPopup.tsx
|
|
2742
|
+
var _tmpl$11 = /* @__PURE__ */ template(`<div class=pp-text-input-popup><div class=pp-text-input-popup__indicator></div><input class=pp-text-input-popup__input type=text placeholder="Add text note...">`);
|
|
2743
|
+
var TextInputPopup = (props) => {
|
|
2744
|
+
const [text, setText] = createSignal("");
|
|
2745
|
+
let inputRef;
|
|
2746
|
+
onMount(() => inputRef?.focus());
|
|
2747
|
+
function handleSubmit() {
|
|
2748
|
+
const t = text().trim();
|
|
2749
|
+
if (t) props.onSubmit(t);
|
|
2750
|
+
else props.onCancel();
|
|
2751
|
+
}
|
|
2752
|
+
const x = Math.max(8, Math.min(props.x, window.innerWidth - 260));
|
|
2753
|
+
const y = Math.max(8, Math.min(props.y + 8, window.innerHeight - 50));
|
|
2754
|
+
return (() => {
|
|
2755
|
+
var _el$ = _tmpl$11(), _el$2 = _el$.firstChild, _el$3 = _el$2.nextSibling;
|
|
2756
|
+
setStyleProperty(_el$, "left", `${x}px`);
|
|
2757
|
+
setStyleProperty(_el$, "top", `${y}px`);
|
|
2758
|
+
_el$3.addEventListener("blur", handleSubmit);
|
|
2759
|
+
_el$3.$$keydown = (e) => {
|
|
2760
|
+
if (e.key === "Enter") handleSubmit();
|
|
2761
|
+
if (e.key === "Escape") props.onCancel();
|
|
2762
|
+
};
|
|
2763
|
+
_el$3.$$input = (e) => setText(e.currentTarget.value);
|
|
2764
|
+
var _ref$ = inputRef;
|
|
2765
|
+
typeof _ref$ === "function" ? use(_ref$, _el$3) : inputRef = _el$3;
|
|
2766
|
+
createRenderEffect((_$p) => setStyleProperty(_el$2, "background", props.color));
|
|
2767
|
+
createRenderEffect(() => _el$3.value = text());
|
|
2768
|
+
return _el$;
|
|
2769
|
+
})();
|
|
2770
|
+
};
|
|
2771
|
+
delegateEvents(["input", "keydown"]);
|
|
2772
|
+
|
|
2773
|
+
// src/ui/components/Toolbar.tsx
|
|
2774
|
+
var _tmpl$12 = /* @__PURE__ */ template(`<div>`);
|
|
2775
|
+
var _tmpl$23 = /* @__PURE__ */ template(`<div style=display:flex;align-items:center;justify-content:center;gap:6px><span style=display:flex;align-items:center>`);
|
|
2776
|
+
var _tmpl$33 = /* @__PURE__ */ template(`<span class=pp-toolbar__badge>`);
|
|
2777
|
+
var _tmpl$42 = /* @__PURE__ */ template(`<button class="pp-btn pp-btn--primary"style=width:100%><span style=display:inline-flex></span>Send <!> selected to Claude`);
|
|
2778
|
+
var _tmpl$52 = /* @__PURE__ */ template(`<div class=pp-draw-tools><button title=Freehand></button><button title=Arrow></button><button title=Circle></button><button title=Rectangle></button><button title="Text note"></button><div style=flex:1></div><button class=pp-draw-tool title="Undo (remove last stroke)"></button><button class=pp-draw-tool title="Clear drawing">`);
|
|
2779
|
+
var _tmpl$62 = /* @__PURE__ */ template(`<div class=pp-draw-options><div class=pp-draw-colors></div><div class=pp-draw-widths>`);
|
|
2780
|
+
var _tmpl$72 = /* @__PURE__ */ template(`<div style=font-size:11px;color:var(--pp-text-muted);text-align:center> stroke`);
|
|
2781
|
+
var _tmpl$82 = /* @__PURE__ */ template(`<div class=pp-settings><div class=pp-settings__row><span class=pp-settings__label>Output detail</span><select style="background:var(--pp-bg-solid);color:var(--pp-text);border:1px solid var(--pp-border);border-radius:var(--pp-radius-sm);padding:2px 6px;font-size:11px"><option value=compact>Compact</option><option value=standard>Standard</option><option value=detailed>Detailed</option></select></div><div class=pp-settings__row><span class=pp-settings__label>Auto-submit</span><div><div class=pp-toggle__thumb></div></div></div><div class=pp-settings__row><span class=pp-settings__label>Clear on send</span><div><div class=pp-toggle__thumb></div></div></div><div class=pp-settings__row><span class=pp-settings__label>Block page clicks</span><div><div class=pp-toggle__thumb></div></div></div><div class=pp-settings__row><span class=pp-settings__label>Compact popup</span><div><div class=pp-toggle__thumb>`);
|
|
2782
|
+
var _tmpl$92 = /* @__PURE__ */ template(`<div style=display:contents><div style=display:flex;align-items:center;justify-content:space-between;font-size:12px;font-weight:600;letter-spacing:0.02em;color:var(--pp-text-muted)><span></span></div><div class=pp-mode-tabs role=tablist><button role=tab><span></span>Select</button><button role=tab><span></span>Draw</button><button role=tab><span></span>Queue</button></div><div class=pp-actions role=toolbar aria-label="Pinpoint actions"><button class=pp-btn--icon title="Send to agent"aria-label="Send to agent"></button><button class=pp-btn--icon title="Copy to clipboard"aria-label="Copy to clipboard"></button><button class=pp-btn--icon title=Settings aria-label="Toggle settings"></button><button class=pp-btn--icon title=Close aria-label="Close toolbar">`);
|
|
2783
|
+
var _tmpl$0 = /* @__PURE__ */ template(`<span class=pp-toolbar__queue-badge>`);
|
|
2784
|
+
var _tmpl$1 = /* @__PURE__ */ template(`<span class=pp-mode-tab__count>`);
|
|
2785
|
+
var _tmpl$102 = /* @__PURE__ */ template(`<div style=font-size:11px;color:var(--pp-accent);display:flex;align-items:center;gap:4px><span></span>Click any element to annotate`);
|
|
2786
|
+
var _tmpl$112 = /* @__PURE__ */ template(`<div class=pp-pin-list>`);
|
|
2787
|
+
var _tmpl$122 = /* @__PURE__ */ template(`<div class=pp-pin-item><div></div><span class=pp-pin-item__number></span><div class=pp-pin-item__content><div class=pp-pin-item__comment></div></div><button class="pp-btn--icon pp-btn--icon-sm"style=opacity:1;pointer-events:auto></button><button class="pp-btn--icon pp-btn--icon-sm"title="Remove pin"aria-label="Remove pin">`);
|
|
2788
|
+
var _tmpl$13 = /* @__PURE__ */ template(`<span style=color:var(--pp-text-muted);font-style:italic>No comment`);
|
|
2789
|
+
var _tmpl$14 = /* @__PURE__ */ template(`<button>`);
|
|
2790
|
+
var _tmpl$15 = /* @__PURE__ */ template(`<button><div style=width:16px>`);
|
|
2791
|
+
var _tmpl$16 = /* @__PURE__ */ template(`<div style="font-size:11px;color:var(--pp-text-muted);text-align:center;padding:8px 0">Queue is empty. Add pins or drawings, then queue them here.`);
|
|
2792
|
+
var _tmpl$17 = /* @__PURE__ */ template(`<div style=font-size:11px;color:var(--pp-text-muted);text-align:center>`);
|
|
2793
|
+
var _tmpl$18 = /* @__PURE__ */ template(`<div style=display:flex;gap:6px><button class=pp-btn style=flex:1>Clear</button><button class="pp-btn pp-btn--primary"style=flex:1><span style=display:inline-flex></span>Send All`);
|
|
2794
|
+
var _tmpl$19 = /* @__PURE__ */ template(`<div class=pp-pin-item><span class=pp-pin-item__number></span><div class=pp-pin-item__content><div class=pp-pin-item__comment>`);
|
|
2795
|
+
var _tmpl$20 = /* @__PURE__ */ template(`<button class=pp-btn--icon title="Clear all"aria-label="Clear all pins">`);
|
|
2796
|
+
var DRAW_COLORS = [{
|
|
2797
|
+
color: "#EF4444",
|
|
2798
|
+
name: "Red"
|
|
2799
|
+
}, {
|
|
2800
|
+
color: "#3B82F6",
|
|
2801
|
+
name: "Blue"
|
|
2802
|
+
}, {
|
|
2803
|
+
color: "#22C55E",
|
|
2804
|
+
name: "Green"
|
|
2805
|
+
}, {
|
|
2806
|
+
color: "#EAB308",
|
|
2807
|
+
name: "Yellow"
|
|
2808
|
+
}];
|
|
2809
|
+
var LINE_WIDTHS = [{
|
|
2810
|
+
width: 2,
|
|
2811
|
+
name: "Thin"
|
|
2812
|
+
}, {
|
|
2813
|
+
width: 4,
|
|
2814
|
+
name: "Medium"
|
|
2815
|
+
}, {
|
|
2816
|
+
width: 8,
|
|
2817
|
+
name: "Thick"
|
|
2818
|
+
}];
|
|
2819
|
+
var EDGE_GAP = 16;
|
|
2820
|
+
var COLLAPSED_TOOLBAR_SIZE = 60;
|
|
2821
|
+
var EXPANDED_TOOLBAR_WIDTH = 320;
|
|
2822
|
+
var AGENT_SIDEBAR_SELECTOR = ".agent-sidebar-panel";
|
|
2823
|
+
function clampRightOffset(right, toolbarWidth) {
|
|
2824
|
+
if (typeof window === "undefined") return right;
|
|
2825
|
+
const maxRight = Math.max(0, window.innerWidth - toolbarWidth - EDGE_GAP);
|
|
2826
|
+
return Math.min(right, maxRight);
|
|
2827
|
+
}
|
|
2828
|
+
function getVisibleRightSidebarInset() {
|
|
2829
|
+
if (typeof window === "undefined") return 0;
|
|
2830
|
+
let inset = 0;
|
|
2831
|
+
for (const panel of document.querySelectorAll(AGENT_SIDEBAR_SELECTOR)) {
|
|
2832
|
+
const style2 = window.getComputedStyle(panel);
|
|
2833
|
+
if (style2.display === "none" || style2.visibility === "hidden" || panel.getAttribute("aria-hidden") === "true") {
|
|
2834
|
+
continue;
|
|
2835
|
+
}
|
|
2836
|
+
const rect = panel.getBoundingClientRect();
|
|
2837
|
+
const isVisible = rect.width > 0 && rect.height > 0;
|
|
2838
|
+
const isAnchoredToRight = rect.right >= window.innerWidth - 1 && rect.left < window.innerWidth - 1;
|
|
2839
|
+
if (!isVisible || !isAnchoredToRight) continue;
|
|
2840
|
+
inset = Math.max(inset, Math.ceil(window.innerWidth - rect.left));
|
|
2841
|
+
}
|
|
2842
|
+
return inset;
|
|
2843
|
+
}
|
|
2844
|
+
var Toolbar = (props) => {
|
|
2845
|
+
const [pos, setPos] = createSignal(props.position ? {
|
|
2846
|
+
right: window.innerWidth - props.position.x,
|
|
2847
|
+
bottom: window.innerHeight - props.position.y
|
|
2848
|
+
} : {
|
|
2849
|
+
right: EDGE_GAP,
|
|
2850
|
+
bottom: EDGE_GAP
|
|
2851
|
+
});
|
|
2852
|
+
const [reservedRight, setReservedRight] = createSignal(0);
|
|
2853
|
+
const [dragStart, setDragStart] = createSignal({
|
|
2854
|
+
x: 0,
|
|
2855
|
+
y: 0,
|
|
2856
|
+
right: 0,
|
|
2857
|
+
bottom: 0
|
|
2858
|
+
});
|
|
2859
|
+
const [didDrag, setDidDrag] = createSignal(false);
|
|
2860
|
+
onMount(() => {
|
|
2861
|
+
if (typeof window === "undefined") return;
|
|
2862
|
+
let resizeObserver;
|
|
2863
|
+
const updateReservedRight = () => {
|
|
2864
|
+
setReservedRight(getVisibleRightSidebarInset());
|
|
2865
|
+
resizeObserver?.disconnect();
|
|
2866
|
+
if (typeof ResizeObserver === "undefined") return;
|
|
2867
|
+
resizeObserver = new ResizeObserver(() => {
|
|
2868
|
+
setReservedRight(getVisibleRightSidebarInset());
|
|
2869
|
+
});
|
|
2870
|
+
for (const panel of document.querySelectorAll(AGENT_SIDEBAR_SELECTOR)) {
|
|
2871
|
+
resizeObserver.observe(panel);
|
|
2872
|
+
}
|
|
2873
|
+
};
|
|
2874
|
+
updateReservedRight();
|
|
2875
|
+
const mutationObserver = new MutationObserver(updateReservedRight);
|
|
2876
|
+
mutationObserver.observe(document.body, {
|
|
2877
|
+
attributes: true,
|
|
2878
|
+
attributeFilter: ["class", "style", "aria-hidden"],
|
|
2879
|
+
childList: true,
|
|
2880
|
+
subtree: true
|
|
2881
|
+
});
|
|
2882
|
+
window.addEventListener("resize", updateReservedRight);
|
|
2883
|
+
onCleanup(() => {
|
|
2884
|
+
mutationObserver.disconnect();
|
|
2885
|
+
resizeObserver?.disconnect();
|
|
2886
|
+
window.removeEventListener("resize", updateReservedRight);
|
|
2887
|
+
});
|
|
2888
|
+
});
|
|
2889
|
+
const toolbarRight = () => {
|
|
2890
|
+
const toolbarWidth = props.expanded ? EXPANDED_TOOLBAR_WIDTH : COLLAPSED_TOOLBAR_SIZE;
|
|
2891
|
+
return clampRightOffset((props.expanded ? EDGE_GAP : pos().right) + reservedRight(), toolbarWidth);
|
|
2892
|
+
};
|
|
2893
|
+
function handleMouseDown(e) {
|
|
2894
|
+
if (props.expanded) return;
|
|
2895
|
+
setDidDrag(false);
|
|
2896
|
+
setDragStart({
|
|
2897
|
+
x: e.clientX,
|
|
2898
|
+
y: e.clientY,
|
|
2899
|
+
right: pos().right,
|
|
2900
|
+
bottom: pos().bottom
|
|
2901
|
+
});
|
|
2902
|
+
const handleMove = (e2) => {
|
|
2903
|
+
setDidDrag(true);
|
|
2904
|
+
const start = dragStart();
|
|
2905
|
+
const dx = e2.clientX - start.x;
|
|
2906
|
+
const dy = e2.clientY - start.y;
|
|
2907
|
+
const maxRight = Math.max(0, window.innerWidth - reservedRight() - COLLAPSED_TOOLBAR_SIZE);
|
|
2908
|
+
setPos({
|
|
2909
|
+
right: Math.max(0, Math.min(maxRight, start.right - dx)),
|
|
2910
|
+
bottom: Math.max(0, Math.min(window.innerHeight - COLLAPSED_TOOLBAR_SIZE, start.bottom - dy))
|
|
2911
|
+
});
|
|
2912
|
+
};
|
|
2913
|
+
const handleUp = () => {
|
|
2914
|
+
window.removeEventListener("mousemove", handleMove);
|
|
2915
|
+
window.removeEventListener("mouseup", handleUp);
|
|
2916
|
+
};
|
|
2917
|
+
window.addEventListener("mousemove", handleMove);
|
|
2918
|
+
window.addEventListener("mouseup", handleUp);
|
|
2919
|
+
}
|
|
2920
|
+
function handleClick() {
|
|
2921
|
+
if (props.expanded) return;
|
|
2922
|
+
if (didDrag()) return;
|
|
2923
|
+
props.onToggleExpand();
|
|
2924
|
+
}
|
|
2925
|
+
const queueSummary = () => {
|
|
2926
|
+
const q = props.queue;
|
|
2927
|
+
let draws = 0;
|
|
2928
|
+
let clicks = 0;
|
|
2929
|
+
for (const item of q) {
|
|
2930
|
+
if (item.drawings?.length || item.textNotes?.length) draws++;
|
|
2931
|
+
if (item.pin) clicks++;
|
|
2932
|
+
}
|
|
2933
|
+
const parts = [];
|
|
2934
|
+
if (draws > 0) parts.push(`Draw x${draws}`);
|
|
2935
|
+
if (clicks > 0) parts.push(`Click x${clicks}`);
|
|
2936
|
+
return parts.join(" / ") || "Empty";
|
|
2937
|
+
};
|
|
2938
|
+
const totalBadgeCount = () => props.pins.length + props.queue.length + props.drawStrokeCount;
|
|
2939
|
+
return (() => {
|
|
2940
|
+
var _el$ = _tmpl$12();
|
|
2941
|
+
addEventListener(_el$, "click", handleClick);
|
|
2942
|
+
addEventListener(_el$, "mousedown", props.expanded ? void 0 : handleMouseDown, true);
|
|
2943
|
+
insert(_el$, (() => {
|
|
2944
|
+
var _c$ = memo(() => !!!props.expanded);
|
|
2945
|
+
return () => _c$() ? (
|
|
2946
|
+
/* Collapsed pill */
|
|
2947
|
+
(() => {
|
|
2948
|
+
var _el$2 = _tmpl$23(), _el$3 = _el$2.firstChild;
|
|
2949
|
+
insert(_el$2, (() => {
|
|
2950
|
+
var _c$2 = memo(() => totalBadgeCount() > 0);
|
|
2951
|
+
return () => _c$2() && (() => {
|
|
2952
|
+
var _el$4 = _tmpl$33();
|
|
2953
|
+
insert(_el$4, totalBadgeCount);
|
|
2954
|
+
return _el$4;
|
|
2955
|
+
})();
|
|
2956
|
+
})(), _el$3);
|
|
2957
|
+
createRenderEffect(() => _el$3.innerHTML = icons.pin);
|
|
2958
|
+
return _el$2;
|
|
2959
|
+
})()
|
|
2960
|
+
) : (
|
|
2961
|
+
/* Expanded toolbar */
|
|
2962
|
+
(() => {
|
|
2963
|
+
var _el$5 = _tmpl$92(), _el$6 = _el$5.firstChild, _el$7 = _el$6.firstChild, _el$8 = _el$6.nextSibling, _el$9 = _el$8.firstChild, _el$0 = _el$9.firstChild, _el$1 = _el$9.nextSibling, _el$10 = _el$1.firstChild, _el$11 = _el$1.nextSibling, _el$12 = _el$11.firstChild, _el$13 = _el$12.nextSibling, _el$49 = _el$8.nextSibling, _el$50 = _el$49.firstChild, _el$51 = _el$50.nextSibling, _el$52 = _el$51.nextSibling, _el$53 = _el$52.nextSibling;
|
|
2964
|
+
addEventListener(_el$5, "click", (e) => e.stopPropagation());
|
|
2965
|
+
insert(_el$7, () => props.author || "Pinpoint");
|
|
2966
|
+
insert(_el$6, (() => {
|
|
2967
|
+
var _c$3 = memo(() => props.queue.length > 0);
|
|
2968
|
+
return () => _c$3() && (() => {
|
|
2969
|
+
var _el$54 = _tmpl$0();
|
|
2970
|
+
insert(_el$54, () => props.queue.length);
|
|
2971
|
+
return _el$54;
|
|
2972
|
+
})();
|
|
2973
|
+
})(), null);
|
|
2974
|
+
addEventListener(_el$9, "click", () => props.onModeChange("select"));
|
|
2975
|
+
addEventListener(_el$1, "click", () => props.onModeChange("draw"));
|
|
2976
|
+
addEventListener(_el$11, "click", () => props.onModeChange("queue"));
|
|
2977
|
+
insert(_el$11, (() => {
|
|
2978
|
+
var _c$4 = memo(() => props.queue.length > 0);
|
|
2979
|
+
return () => _c$4() && (() => {
|
|
2980
|
+
var _el$55 = _tmpl$1();
|
|
2981
|
+
insert(_el$55, () => props.queue.length);
|
|
2982
|
+
return _el$55;
|
|
2983
|
+
})();
|
|
2984
|
+
})(), null);
|
|
2985
|
+
insert(_el$5, createComponent(Show, {
|
|
2986
|
+
get when() {
|
|
2987
|
+
return props.mode === "select";
|
|
2988
|
+
},
|
|
2989
|
+
get children() {
|
|
2990
|
+
return [memo(() => memo(() => props.pins.length === 0)() && (() => {
|
|
2991
|
+
var _el$56 = _tmpl$102(), _el$57 = _el$56.firstChild;
|
|
2992
|
+
createRenderEffect(() => _el$57.innerHTML = icons.crosshair);
|
|
2993
|
+
return _el$56;
|
|
2994
|
+
})()), memo(() => memo(() => props.pins.length > 0)() && (() => {
|
|
2995
|
+
var _el$58 = _tmpl$112();
|
|
2996
|
+
insert(_el$58, createComponent(For, {
|
|
2997
|
+
get each() {
|
|
2998
|
+
return props.pins;
|
|
2999
|
+
},
|
|
3000
|
+
children: (pin, index) => (() => {
|
|
3001
|
+
var _el$59 = _tmpl$122(), _el$60 = _el$59.firstChild, _el$61 = _el$60.nextSibling, _el$62 = _el$61.nextSibling, _el$63 = _el$62.firstChild, _el$64 = _el$62.nextSibling, _el$65 = _el$64.nextSibling;
|
|
3002
|
+
addEventListener(_el$59, "click", () => props.onEditPin(pin));
|
|
3003
|
+
insert(_el$61, () => index() + 1);
|
|
3004
|
+
insert(_el$63, () => pin.comment || _tmpl$13());
|
|
3005
|
+
addEventListener(_el$64, "click", (e) => {
|
|
3006
|
+
e.stopPropagation();
|
|
3007
|
+
props.onTogglePinSelect(pin);
|
|
3008
|
+
});
|
|
3009
|
+
addEventListener(_el$65, "click", (e) => {
|
|
3010
|
+
e.stopPropagation();
|
|
3011
|
+
props.onRemovePin(pin.id);
|
|
3012
|
+
});
|
|
3013
|
+
createRenderEffect((_p$) => {
|
|
3014
|
+
var _v$32 = `pp-pin-item__status pp-pin-item__status--${pin.status.state}`, _v$33 = props.selectedPinIds.has(pin.id) ? "Deselect" : "Select for send", _v$34 = props.selectedPinIds.has(pin.id) ? "Deselect" : "Select for send", _v$35 = props.selectedPinIds.has(pin.id) ? icons.checkSquare : icons.squareEmpty, _v$36 = props.selectedPinIds.has(pin.id) ? "var(--pp-accent)" : "var(--pp-text-muted)", _v$37 = icons.minus;
|
|
3015
|
+
_v$32 !== _p$.e && className(_el$60, _p$.e = _v$32);
|
|
3016
|
+
_v$33 !== _p$.t && setAttribute(_el$64, "title", _p$.t = _v$33);
|
|
3017
|
+
_v$34 !== _p$.a && setAttribute(_el$64, "aria-label", _p$.a = _v$34);
|
|
3018
|
+
_v$35 !== _p$.o && (_el$64.innerHTML = _p$.o = _v$35);
|
|
3019
|
+
_v$36 !== _p$.i && setStyleProperty(_el$64, "color", _p$.i = _v$36);
|
|
3020
|
+
_v$37 !== _p$.n && (_el$65.innerHTML = _p$.n = _v$37);
|
|
3021
|
+
return _p$;
|
|
3022
|
+
}, {
|
|
3023
|
+
e: void 0,
|
|
3024
|
+
t: void 0,
|
|
3025
|
+
a: void 0,
|
|
3026
|
+
o: void 0,
|
|
3027
|
+
i: void 0,
|
|
3028
|
+
n: void 0
|
|
3029
|
+
});
|
|
3030
|
+
return _el$59;
|
|
3031
|
+
})()
|
|
3032
|
+
}));
|
|
3033
|
+
return _el$58;
|
|
3034
|
+
})()), createComponent(Show, {
|
|
3035
|
+
get when() {
|
|
3036
|
+
return props.selectedPinIds.size > 0;
|
|
3037
|
+
},
|
|
3038
|
+
get children() {
|
|
3039
|
+
var _el$14 = _tmpl$42(), _el$15 = _el$14.firstChild, _el$16 = _el$15.nextSibling, _el$18 = _el$16.nextSibling, _el$17 = _el$18.nextSibling;
|
|
3040
|
+
addEventListener(_el$14, "click", () => props.onSendSelected());
|
|
3041
|
+
insert(_el$14, () => props.selectedPinIds.size, _el$18);
|
|
3042
|
+
createRenderEffect(() => _el$15.innerHTML = icons.send);
|
|
3043
|
+
return _el$14;
|
|
3044
|
+
}
|
|
3045
|
+
})];
|
|
3046
|
+
}
|
|
3047
|
+
}), _el$49);
|
|
3048
|
+
insert(_el$5, createComponent(Show, {
|
|
3049
|
+
get when() {
|
|
3050
|
+
return props.mode === "draw";
|
|
3051
|
+
},
|
|
3052
|
+
get children() {
|
|
3053
|
+
return [(() => {
|
|
3054
|
+
var _el$19 = _tmpl$52(), _el$20 = _el$19.firstChild, _el$21 = _el$20.nextSibling, _el$22 = _el$21.nextSibling, _el$23 = _el$22.nextSibling, _el$24 = _el$23.nextSibling, _el$25 = _el$24.nextSibling, _el$26 = _el$25.nextSibling, _el$27 = _el$26.nextSibling;
|
|
3055
|
+
addEventListener(_el$20, "click", () => props.onDrawToolChange("freehand"));
|
|
3056
|
+
addEventListener(_el$21, "click", () => props.onDrawToolChange("arrow"));
|
|
3057
|
+
addEventListener(_el$22, "click", () => props.onDrawToolChange("circle"));
|
|
3058
|
+
addEventListener(_el$23, "click", () => props.onDrawToolChange("rect"));
|
|
3059
|
+
addEventListener(_el$24, "click", () => props.onDrawToolChange("text"));
|
|
3060
|
+
addEventListener(_el$26, "click", () => props.onDrawUndo());
|
|
3061
|
+
addEventListener(_el$27, "click", () => props.onDrawClear());
|
|
3062
|
+
createRenderEffect((_p$) => {
|
|
3063
|
+
var _v$3 = `pp-draw-tool ${props.drawTool === "freehand" ? "pp-draw-tool--active" : ""}`, _v$4 = icons.pencil, _v$5 = `pp-draw-tool ${props.drawTool === "arrow" ? "pp-draw-tool--active" : ""}`, _v$6 = icons.arrowUpRight, _v$7 = `pp-draw-tool ${props.drawTool === "circle" ? "pp-draw-tool--active" : ""}`, _v$8 = icons.circle, _v$9 = `pp-draw-tool ${props.drawTool === "rect" ? "pp-draw-tool--active" : ""}`, _v$0 = icons.square, _v$1 = `pp-draw-tool ${props.drawTool === "text" ? "pp-draw-tool--active" : ""}`, _v$10 = icons.typography, _v$11 = icons.undo, _v$12 = props.drawStrokeCount === 0, _v$13 = icons.trash, _v$14 = props.drawStrokeCount === 0;
|
|
3064
|
+
_v$3 !== _p$.e && className(_el$20, _p$.e = _v$3);
|
|
3065
|
+
_v$4 !== _p$.t && (_el$20.innerHTML = _p$.t = _v$4);
|
|
3066
|
+
_v$5 !== _p$.a && className(_el$21, _p$.a = _v$5);
|
|
3067
|
+
_v$6 !== _p$.o && (_el$21.innerHTML = _p$.o = _v$6);
|
|
3068
|
+
_v$7 !== _p$.i && className(_el$22, _p$.i = _v$7);
|
|
3069
|
+
_v$8 !== _p$.n && (_el$22.innerHTML = _p$.n = _v$8);
|
|
3070
|
+
_v$9 !== _p$.s && className(_el$23, _p$.s = _v$9);
|
|
3071
|
+
_v$0 !== _p$.h && (_el$23.innerHTML = _p$.h = _v$0);
|
|
3072
|
+
_v$1 !== _p$.r && className(_el$24, _p$.r = _v$1);
|
|
3073
|
+
_v$10 !== _p$.d && (_el$24.innerHTML = _p$.d = _v$10);
|
|
3074
|
+
_v$11 !== _p$.l && (_el$26.innerHTML = _p$.l = _v$11);
|
|
3075
|
+
_v$12 !== _p$.u && (_el$26.disabled = _p$.u = _v$12);
|
|
3076
|
+
_v$13 !== _p$.c && (_el$27.innerHTML = _p$.c = _v$13);
|
|
3077
|
+
_v$14 !== _p$.w && (_el$27.disabled = _p$.w = _v$14);
|
|
3078
|
+
return _p$;
|
|
3079
|
+
}, {
|
|
3080
|
+
e: void 0,
|
|
3081
|
+
t: void 0,
|
|
3082
|
+
a: void 0,
|
|
3083
|
+
o: void 0,
|
|
3084
|
+
i: void 0,
|
|
3085
|
+
n: void 0,
|
|
3086
|
+
s: void 0,
|
|
3087
|
+
h: void 0,
|
|
3088
|
+
r: void 0,
|
|
3089
|
+
d: void 0,
|
|
3090
|
+
l: void 0,
|
|
3091
|
+
u: void 0,
|
|
3092
|
+
c: void 0,
|
|
3093
|
+
w: void 0
|
|
3094
|
+
});
|
|
3095
|
+
return _el$19;
|
|
3096
|
+
})(), (() => {
|
|
3097
|
+
var _el$28 = _tmpl$62(), _el$29 = _el$28.firstChild, _el$30 = _el$29.nextSibling;
|
|
3098
|
+
insert(_el$29, createComponent(For, {
|
|
3099
|
+
each: DRAW_COLORS,
|
|
3100
|
+
children: (c) => (() => {
|
|
3101
|
+
var _el$67 = _tmpl$14();
|
|
3102
|
+
addEventListener(_el$67, "click", () => props.onDrawColorChange(c.color));
|
|
3103
|
+
createRenderEffect((_p$) => {
|
|
3104
|
+
var _v$38 = `pp-color-swatch ${props.drawColor === c.color ? "pp-color-swatch--active" : ""}`, _v$39 = c.color, _v$40 = c.name;
|
|
3105
|
+
_v$38 !== _p$.e && className(_el$67, _p$.e = _v$38);
|
|
3106
|
+
_v$39 !== _p$.t && setStyleProperty(_el$67, "background", _p$.t = _v$39);
|
|
3107
|
+
_v$40 !== _p$.a && setAttribute(_el$67, "title", _p$.a = _v$40);
|
|
3108
|
+
return _p$;
|
|
3109
|
+
}, {
|
|
3110
|
+
e: void 0,
|
|
3111
|
+
t: void 0,
|
|
3112
|
+
a: void 0
|
|
3113
|
+
});
|
|
3114
|
+
return _el$67;
|
|
3115
|
+
})()
|
|
3116
|
+
}));
|
|
3117
|
+
insert(_el$30, createComponent(For, {
|
|
3118
|
+
each: LINE_WIDTHS,
|
|
3119
|
+
children: (w) => (() => {
|
|
3120
|
+
var _el$68 = _tmpl$15(), _el$69 = _el$68.firstChild;
|
|
3121
|
+
addEventListener(_el$68, "click", () => props.onDrawLineWidthChange(w.width));
|
|
3122
|
+
createRenderEffect((_p$) => {
|
|
3123
|
+
var _v$41 = `pp-width-btn ${props.drawLineWidth === w.width ? "pp-width-btn--active" : ""}`, _v$42 = w.name, _v$43 = `${w.width}px`, _v$44 = props.drawColor, _v$45 = `${w.width / 2}px`;
|
|
3124
|
+
_v$41 !== _p$.e && className(_el$68, _p$.e = _v$41);
|
|
3125
|
+
_v$42 !== _p$.t && setAttribute(_el$68, "title", _p$.t = _v$42);
|
|
3126
|
+
_v$43 !== _p$.a && setStyleProperty(_el$69, "height", _p$.a = _v$43);
|
|
3127
|
+
_v$44 !== _p$.o && setStyleProperty(_el$69, "background", _p$.o = _v$44);
|
|
3128
|
+
_v$45 !== _p$.i && setStyleProperty(_el$69, "border-radius", _p$.i = _v$45);
|
|
3129
|
+
return _p$;
|
|
3130
|
+
}, {
|
|
3131
|
+
e: void 0,
|
|
3132
|
+
t: void 0,
|
|
3133
|
+
a: void 0,
|
|
3134
|
+
o: void 0,
|
|
3135
|
+
i: void 0
|
|
3136
|
+
});
|
|
3137
|
+
return _el$68;
|
|
3138
|
+
})()
|
|
3139
|
+
}));
|
|
3140
|
+
return _el$28;
|
|
3141
|
+
})(), createComponent(Show, {
|
|
3142
|
+
get when() {
|
|
3143
|
+
return props.drawStrokeCount > 0;
|
|
3144
|
+
},
|
|
3145
|
+
get children() {
|
|
3146
|
+
var _el$31 = _tmpl$72(), _el$32 = _el$31.firstChild;
|
|
3147
|
+
insert(_el$31, () => props.drawStrokeCount, _el$32);
|
|
3148
|
+
insert(_el$31, () => props.drawStrokeCount !== 1 ? "s" : "", null);
|
|
3149
|
+
return _el$31;
|
|
3150
|
+
}
|
|
3151
|
+
})];
|
|
3152
|
+
}
|
|
3153
|
+
}), _el$49);
|
|
3154
|
+
insert(_el$5, createComponent(Show, {
|
|
3155
|
+
get when() {
|
|
3156
|
+
return props.mode === "queue";
|
|
3157
|
+
},
|
|
3158
|
+
get children() {
|
|
3159
|
+
return memo(() => props.queue.length === 0)() ? _tmpl$16() : [(() => {
|
|
3160
|
+
var _el$71 = _tmpl$17();
|
|
3161
|
+
insert(_el$71, queueSummary);
|
|
3162
|
+
return _el$71;
|
|
3163
|
+
})(), (() => {
|
|
3164
|
+
var _el$72 = _tmpl$112();
|
|
3165
|
+
insert(_el$72, createComponent(For, {
|
|
3166
|
+
get each() {
|
|
3167
|
+
return props.queue;
|
|
3168
|
+
},
|
|
3169
|
+
children: (item, index) => (() => {
|
|
3170
|
+
var _el$77 = _tmpl$19(), _el$78 = _el$77.firstChild, _el$79 = _el$78.nextSibling, _el$80 = _el$79.firstChild;
|
|
3171
|
+
insert(_el$78, () => index() + 1);
|
|
3172
|
+
insert(_el$80, (() => {
|
|
3173
|
+
var _c$6 = memo(() => !!item.pin);
|
|
3174
|
+
return () => _c$6() ? item.pin.comment || "Pin annotation" : `Drawing (${(item.drawings?.length || 0) + (item.textNotes?.length || 0)} items)`;
|
|
3175
|
+
})());
|
|
3176
|
+
return _el$77;
|
|
3177
|
+
})()
|
|
3178
|
+
}));
|
|
3179
|
+
return _el$72;
|
|
3180
|
+
})(), (() => {
|
|
3181
|
+
var _el$73 = _tmpl$18(), _el$74 = _el$73.firstChild, _el$75 = _el$74.nextSibling, _el$76 = _el$75.firstChild;
|
|
3182
|
+
addEventListener(_el$74, "click", () => props.onQueueClear());
|
|
3183
|
+
addEventListener(_el$75, "click", () => props.onQueueSend());
|
|
3184
|
+
createRenderEffect(() => _el$76.innerHTML = icons.send);
|
|
3185
|
+
return _el$73;
|
|
3186
|
+
})()];
|
|
3187
|
+
}
|
|
3188
|
+
}), _el$49);
|
|
3189
|
+
insert(_el$5, createComponent(Show, {
|
|
3190
|
+
get when() {
|
|
3191
|
+
return props.showSettings;
|
|
3192
|
+
},
|
|
3193
|
+
get children() {
|
|
3194
|
+
var _el$33 = _tmpl$82(), _el$34 = _el$33.firstChild, _el$35 = _el$34.firstChild, _el$36 = _el$35.nextSibling, _el$37 = _el$34.nextSibling, _el$38 = _el$37.firstChild, _el$39 = _el$38.nextSibling, _el$40 = _el$37.nextSibling, _el$41 = _el$40.firstChild, _el$42 = _el$41.nextSibling, _el$43 = _el$40.nextSibling, _el$44 = _el$43.firstChild, _el$45 = _el$44.nextSibling, _el$46 = _el$43.nextSibling, _el$47 = _el$46.firstChild, _el$48 = _el$47.nextSibling;
|
|
3195
|
+
_el$36.addEventListener("change", (e) => props.onOutputFormatChange(e.currentTarget.value));
|
|
3196
|
+
addEventListener(_el$39, "click", () => props.onAutoSubmitChange(!props.autoSubmit));
|
|
3197
|
+
addEventListener(_el$42, "click", () => props.onClearOnSendChange(!props.clearOnSend));
|
|
3198
|
+
addEventListener(_el$45, "click", () => props.onBlockInteractionsChange(!props.blockInteractions));
|
|
3199
|
+
addEventListener(_el$48, "click", () => props.onCompactPopupChange(!props.compactPopup));
|
|
3200
|
+
createRenderEffect((_p$) => {
|
|
3201
|
+
var _v$15 = `pp-toggle ${props.autoSubmit ? "pp-toggle--active" : ""}`, _v$16 = `pp-toggle ${props.clearOnSend ? "pp-toggle--active" : ""}`, _v$17 = `pp-toggle ${props.blockInteractions ? "pp-toggle--active" : ""}`, _v$18 = `pp-toggle ${props.compactPopup ? "pp-toggle--active" : ""}`;
|
|
3202
|
+
_v$15 !== _p$.e && className(_el$39, _p$.e = _v$15);
|
|
3203
|
+
_v$16 !== _p$.t && className(_el$42, _p$.t = _v$16);
|
|
3204
|
+
_v$17 !== _p$.a && className(_el$45, _p$.a = _v$17);
|
|
3205
|
+
_v$18 !== _p$.o && className(_el$48, _p$.o = _v$18);
|
|
3206
|
+
return _p$;
|
|
3207
|
+
}, {
|
|
3208
|
+
e: void 0,
|
|
3209
|
+
t: void 0,
|
|
3210
|
+
a: void 0,
|
|
3211
|
+
o: void 0
|
|
3212
|
+
});
|
|
3213
|
+
createRenderEffect(() => _el$36.value = props.outputFormat);
|
|
3214
|
+
return _el$33;
|
|
3215
|
+
}
|
|
3216
|
+
}), _el$49);
|
|
3217
|
+
addEventListener(_el$50, "click", () => props.onSend());
|
|
3218
|
+
addEventListener(_el$51, "click", () => props.onCopy());
|
|
3219
|
+
insert(_el$49, (() => {
|
|
3220
|
+
var _c$5 = memo(() => props.pins.length > 0);
|
|
3221
|
+
return () => _c$5() && (() => {
|
|
3222
|
+
var _el$81 = _tmpl$20();
|
|
3223
|
+
addEventListener(_el$81, "click", () => props.onClear());
|
|
3224
|
+
createRenderEffect(() => _el$81.innerHTML = icons.trash);
|
|
3225
|
+
return _el$81;
|
|
3226
|
+
})();
|
|
3227
|
+
})(), _el$52);
|
|
3228
|
+
addEventListener(_el$52, "click", () => props.onToggleSettings());
|
|
3229
|
+
addEventListener(_el$53, "click", () => props.onToggleExpand());
|
|
3230
|
+
createRenderEffect((_p$) => {
|
|
3231
|
+
var _v$19 = `pp-mode-tab ${props.mode === "select" ? "pp-mode-tab--active" : ""}`, _v$20 = props.mode === "select", _v$21 = icons.crosshair, _v$22 = `pp-mode-tab ${props.mode === "draw" ? "pp-mode-tab--active" : ""}`, _v$23 = props.mode === "draw", _v$24 = icons.pencil, _v$25 = `pp-mode-tab ${props.mode === "queue" ? "pp-mode-tab--active" : ""}`, _v$26 = props.mode === "queue", _v$27 = icons.stack, _v$28 = icons.send, _v$29 = icons.copy, _v$30 = icons.settings, _v$31 = icons.x;
|
|
3232
|
+
_v$19 !== _p$.e && className(_el$9, _p$.e = _v$19);
|
|
3233
|
+
_v$20 !== _p$.t && setAttribute(_el$9, "aria-selected", _p$.t = _v$20);
|
|
3234
|
+
_v$21 !== _p$.a && (_el$0.innerHTML = _p$.a = _v$21);
|
|
3235
|
+
_v$22 !== _p$.o && className(_el$1, _p$.o = _v$22);
|
|
3236
|
+
_v$23 !== _p$.i && setAttribute(_el$1, "aria-selected", _p$.i = _v$23);
|
|
3237
|
+
_v$24 !== _p$.n && (_el$10.innerHTML = _p$.n = _v$24);
|
|
3238
|
+
_v$25 !== _p$.s && className(_el$11, _p$.s = _v$25);
|
|
3239
|
+
_v$26 !== _p$.h && setAttribute(_el$11, "aria-selected", _p$.h = _v$26);
|
|
3240
|
+
_v$27 !== _p$.r && (_el$12.innerHTML = _p$.r = _v$27);
|
|
3241
|
+
_v$28 !== _p$.d && (_el$50.innerHTML = _p$.d = _v$28);
|
|
3242
|
+
_v$29 !== _p$.l && (_el$51.innerHTML = _p$.l = _v$29);
|
|
3243
|
+
_v$30 !== _p$.u && (_el$52.innerHTML = _p$.u = _v$30);
|
|
3244
|
+
_v$31 !== _p$.c && (_el$53.innerHTML = _p$.c = _v$31);
|
|
3245
|
+
return _p$;
|
|
3246
|
+
}, {
|
|
3247
|
+
e: void 0,
|
|
3248
|
+
t: void 0,
|
|
3249
|
+
a: void 0,
|
|
3250
|
+
o: void 0,
|
|
3251
|
+
i: void 0,
|
|
3252
|
+
n: void 0,
|
|
3253
|
+
s: void 0,
|
|
3254
|
+
h: void 0,
|
|
3255
|
+
r: void 0,
|
|
3256
|
+
d: void 0,
|
|
3257
|
+
l: void 0,
|
|
3258
|
+
u: void 0,
|
|
3259
|
+
c: void 0
|
|
3260
|
+
});
|
|
3261
|
+
return _el$5;
|
|
3262
|
+
})()
|
|
3263
|
+
);
|
|
3264
|
+
})());
|
|
3265
|
+
createRenderEffect((_p$) => {
|
|
3266
|
+
var _v$ = `pp-toolbar ${props.expanded ? "pp-toolbar--expanded" : "pp-toolbar--collapsed"}`, _v$2 = {
|
|
3267
|
+
...props.expanded ? {
|
|
3268
|
+
bottom: `${EDGE_GAP}px`,
|
|
3269
|
+
right: `${toolbarRight()}px`
|
|
3270
|
+
} : {
|
|
3271
|
+
right: `${toolbarRight()}px`,
|
|
3272
|
+
bottom: `${pos().bottom}px`
|
|
3273
|
+
}
|
|
3274
|
+
};
|
|
3275
|
+
_v$ !== _p$.e && className(_el$, _p$.e = _v$);
|
|
3276
|
+
_p$.t = style(_el$, _v$2, _p$.t);
|
|
3277
|
+
return _p$;
|
|
3278
|
+
}, {
|
|
3279
|
+
e: void 0,
|
|
3280
|
+
t: void 0
|
|
3281
|
+
});
|
|
3282
|
+
return _el$;
|
|
3283
|
+
})();
|
|
3284
|
+
};
|
|
3285
|
+
delegateEvents(["mousedown"]);
|
|
3286
|
+
|
|
3287
|
+
// src/ui/components/PinpointApp.tsx
|
|
3288
|
+
var PinpointApp = (props) => {
|
|
3289
|
+
const [active, setActive] = createSignal(false);
|
|
3290
|
+
const [expanded, setExpanded] = createSignal(false);
|
|
3291
|
+
const [pins, setPins] = createSignal([]);
|
|
3292
|
+
const [hoveredRect, setHoveredRect] = createSignal(null);
|
|
3293
|
+
const [selectedElement, setSelectedElement] = createSignal(null);
|
|
3294
|
+
const [selectedContext, setSelectedContext] = createSignal(null);
|
|
3295
|
+
const [showPopup, setShowPopup] = createSignal(false);
|
|
3296
|
+
const [editingPin, setEditingPin] = createSignal(null);
|
|
3297
|
+
const [showContextMenu, setShowContextMenu] = createSignal(false);
|
|
3298
|
+
const [contextMenuPos, setContextMenuPos] = createSignal({
|
|
3299
|
+
x: 0,
|
|
3300
|
+
y: 0
|
|
3301
|
+
});
|
|
3302
|
+
const [showSettings, setShowSettings] = createSignal(false);
|
|
3303
|
+
const [showPrompt, setShowPrompt] = createSignal(false);
|
|
3304
|
+
const [selectionLabelInfo, setSelectionLabelInfo] = createSignal(null);
|
|
3305
|
+
const [dragRect, setDragRect] = createSignal(null);
|
|
3306
|
+
const [mode, setMode] = createSignal("select");
|
|
3307
|
+
const [drawMode, setDrawMode] = createSignal(false);
|
|
3308
|
+
const [drawStrokes, setDrawStrokes] = createSignal([]);
|
|
3309
|
+
const [currentStroke, setCurrentStroke] = createSignal(null);
|
|
3310
|
+
const [drawColor, setDrawColor] = createSignal("#EF4444");
|
|
3311
|
+
const [drawLineWidth, setDrawLineWidth] = createSignal(4);
|
|
3312
|
+
const [drawTool, setDrawTool] = createSignal("freehand");
|
|
3313
|
+
const [textNotes, setTextNotes] = createSignal([]);
|
|
3314
|
+
const [showTextInput, setShowTextInput] = createSignal(false);
|
|
3315
|
+
const [textInputPos, setTextInputPos] = createSignal({
|
|
3316
|
+
x: 0,
|
|
3317
|
+
y: 0
|
|
3318
|
+
});
|
|
3319
|
+
let isDrawing = false;
|
|
3320
|
+
const [queue, setQueue] = createSignal([]);
|
|
3321
|
+
const [selectedPinIds, setSelectedPinIds] = createSignal(/* @__PURE__ */ new Set());
|
|
3322
|
+
const [outputFormat, setOutputFormat] = createSignal(props.config.outputFormat || "detailed");
|
|
3323
|
+
const [clearOnSend, setClearOnSend] = createSignal(props.config.clearOnSend ?? false);
|
|
3324
|
+
const [blockInteractions, setBlockInteractions] = createSignal(props.config.blockInteractions ?? false);
|
|
3325
|
+
const [autoSubmit, setAutoSubmit] = createSignal(props.config.autoSubmit ?? true);
|
|
3326
|
+
const [compactPopup, setCompactPopup] = createSignal(props.config.compactPopup ?? true);
|
|
3327
|
+
async function deliverToAgent(output) {
|
|
3328
|
+
const agentOutput = {
|
|
3329
|
+
...output,
|
|
3330
|
+
submit: output.submit ?? autoSubmit()
|
|
3331
|
+
};
|
|
3332
|
+
if (props.config.sendToAgent) {
|
|
3333
|
+
await props.config.sendToAgent(agentOutput);
|
|
3334
|
+
return;
|
|
3335
|
+
}
|
|
3336
|
+
try {
|
|
3337
|
+
const {
|
|
3338
|
+
sendToAgentChat
|
|
3339
|
+
} = await import("@agent-native/core/client");
|
|
3340
|
+
sendToAgentChat(agentOutput);
|
|
3341
|
+
} catch {
|
|
3342
|
+
await navigator.clipboard.writeText([agentOutput.message, agentOutput.context].filter(Boolean).join("\n\n"));
|
|
3343
|
+
}
|
|
3344
|
+
}
|
|
3345
|
+
const storage = props.config.storage || (props.config.endpoint ? new RestClient(props.config.endpoint) : new MemoryStore());
|
|
3346
|
+
const picker = new ElementPicker({
|
|
3347
|
+
ignoreSelector: "#pinpoint-root, [data-pinpoint-marker]",
|
|
3348
|
+
blockInteractions: blockInteractions(),
|
|
3349
|
+
onHover: (element, rect) => {
|
|
3350
|
+
setHoveredRect(rect);
|
|
3351
|
+
if (element && rect) {
|
|
3352
|
+
const framework = detectFramework();
|
|
3353
|
+
const componentInfo = framework.getComponentInfo(element);
|
|
3354
|
+
const tagName = element.tagName.toLowerCase();
|
|
3355
|
+
const componentName = componentInfo?.name;
|
|
3356
|
+
const sourceFile = framework.getSourceLocation(element)?.file;
|
|
3357
|
+
const parts = [tagName];
|
|
3358
|
+
if (componentName) parts.push(componentName);
|
|
3359
|
+
if (sourceFile) parts.push(sourceFile);
|
|
3360
|
+
setSelectionLabelInfo({
|
|
3361
|
+
text: parts.join(" \xB7 "),
|
|
3362
|
+
rect
|
|
3363
|
+
});
|
|
3364
|
+
} else {
|
|
3365
|
+
setSelectionLabelInfo(null);
|
|
3366
|
+
}
|
|
3367
|
+
},
|
|
3368
|
+
onStableHover: (_element) => {
|
|
3369
|
+
},
|
|
3370
|
+
onSelect: (element) => {
|
|
3371
|
+
const framework = detectFramework();
|
|
3372
|
+
const frameworkInfo = (() => {
|
|
3373
|
+
const info = framework.getComponentInfo(element);
|
|
3374
|
+
const source = framework.getSourceLocation(element);
|
|
3375
|
+
if (!info && !source) return void 0;
|
|
3376
|
+
return {
|
|
3377
|
+
framework: framework.name,
|
|
3378
|
+
componentPath: info?.name ? `<${info.name}>` : "",
|
|
3379
|
+
sourceFile: source ? `${source.file}${source.line ? `:${source.line}` : ""}` : void 0,
|
|
3380
|
+
frameworkVersion: void 0
|
|
3381
|
+
};
|
|
3382
|
+
})();
|
|
3383
|
+
const context = buildElementContext(element, frameworkInfo);
|
|
3384
|
+
setSelectedElement(element);
|
|
3385
|
+
setSelectedContext(context);
|
|
3386
|
+
setShowPopup(true);
|
|
3387
|
+
picker.pause();
|
|
3388
|
+
}
|
|
3389
|
+
});
|
|
3390
|
+
const dragSelect = new DragSelect({
|
|
3391
|
+
ignoreSelector: "#pinpoint-root, [data-pinpoint-marker]",
|
|
3392
|
+
onDragStart: (rect) => setDragRect(rect),
|
|
3393
|
+
onDragMove: (rect) => setDragRect(rect),
|
|
3394
|
+
onDragEnd: (elements) => {
|
|
3395
|
+
setDragRect(null);
|
|
3396
|
+
for (const el of elements) {
|
|
3397
|
+
addPin(el, "Multi-selected element");
|
|
3398
|
+
}
|
|
3399
|
+
}
|
|
3400
|
+
});
|
|
3401
|
+
const textSelect = new TextSelect({
|
|
3402
|
+
onSelect: (_selection) => {
|
|
3403
|
+
}
|
|
3404
|
+
});
|
|
3405
|
+
const handleKeyDown = (e) => {
|
|
3406
|
+
const mod = e.metaKey || e.ctrlKey;
|
|
3407
|
+
if (mod && e.shiftKey && e.key === ".") {
|
|
3408
|
+
e.preventDefault();
|
|
3409
|
+
toggleActive();
|
|
3410
|
+
return;
|
|
3411
|
+
}
|
|
3412
|
+
if (mod && e.shiftKey && (e.key === "D" || e.key === "d")) {
|
|
3413
|
+
e.preventDefault();
|
|
3414
|
+
if (active()) {
|
|
3415
|
+
if (mode() === "draw") {
|
|
3416
|
+
handleModeChange("select");
|
|
3417
|
+
} else {
|
|
3418
|
+
handleModeChange("draw");
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
return;
|
|
3422
|
+
}
|
|
3423
|
+
if (!active()) return;
|
|
3424
|
+
if (mod && e.shiftKey && e.key === "C") {
|
|
3425
|
+
e.preventDefault();
|
|
3426
|
+
copyPins();
|
|
3427
|
+
return;
|
|
3428
|
+
}
|
|
3429
|
+
if (mod && e.shiftKey && e.key === "Enter") {
|
|
3430
|
+
e.preventDefault();
|
|
3431
|
+
if (queue().length > 0) {
|
|
3432
|
+
sendQueue();
|
|
3433
|
+
} else if (selectedPinIds().size > 0) {
|
|
3434
|
+
sendSelected();
|
|
3435
|
+
} else {
|
|
3436
|
+
sendPins();
|
|
3437
|
+
}
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
if (mod && e.key === "z" && drawMode()) {
|
|
3441
|
+
e.preventDefault();
|
|
3442
|
+
undoDrawStroke();
|
|
3443
|
+
return;
|
|
3444
|
+
}
|
|
3445
|
+
if (e.key === "Escape") {
|
|
3446
|
+
if (showTextInput()) {
|
|
3447
|
+
setShowTextInput(false);
|
|
3448
|
+
} else if (showPopup()) {
|
|
3449
|
+
closePopup();
|
|
3450
|
+
} else if (showContextMenu()) {
|
|
3451
|
+
setShowContextMenu(false);
|
|
3452
|
+
} else if (showPrompt()) {
|
|
3453
|
+
setShowPrompt(false);
|
|
3454
|
+
} else if (drawMode()) {
|
|
3455
|
+
handleModeChange("select");
|
|
3456
|
+
} else if (expanded()) {
|
|
3457
|
+
setExpanded(false);
|
|
3458
|
+
} else {
|
|
3459
|
+
deactivateSelection();
|
|
3460
|
+
}
|
|
3461
|
+
}
|
|
3462
|
+
};
|
|
3463
|
+
const handleContextMenu = (e) => {
|
|
3464
|
+
if (!active() || drawMode()) return;
|
|
3465
|
+
const element = document.elementFromPoint(e.clientX, e.clientY);
|
|
3466
|
+
if (!element || element.closest("#pinpoint-root")) return;
|
|
3467
|
+
e.preventDefault();
|
|
3468
|
+
setSelectedElement(element);
|
|
3469
|
+
setContextMenuPos({
|
|
3470
|
+
x: e.clientX,
|
|
3471
|
+
y: e.clientY
|
|
3472
|
+
});
|
|
3473
|
+
setShowContextMenu(true);
|
|
3474
|
+
};
|
|
3475
|
+
createEffect(() => {
|
|
3476
|
+
picker.setBlockInteractions(blockInteractions());
|
|
3477
|
+
});
|
|
3478
|
+
createEffect(() => {
|
|
3479
|
+
document.addEventListener("keydown", handleKeyDown, true);
|
|
3480
|
+
document.addEventListener("contextmenu", handleContextMenu, true);
|
|
3481
|
+
onCleanup(() => {
|
|
3482
|
+
document.removeEventListener("keydown", handleKeyDown, true);
|
|
3483
|
+
document.removeEventListener("contextmenu", handleContextMenu, true);
|
|
3484
|
+
picker.dispose();
|
|
3485
|
+
dragSelect.dispose();
|
|
3486
|
+
textSelect.dispose();
|
|
3487
|
+
markerManager.dispose();
|
|
3488
|
+
});
|
|
3489
|
+
});
|
|
3490
|
+
const markerManager = new PinMarkerManager(props.config.markerColor);
|
|
3491
|
+
markerManager.setOnClick((pin) => openEditPopup(pin));
|
|
3492
|
+
markerManager.setOnToggleSelect((pin) => togglePinSelect(pin));
|
|
3493
|
+
createEffect(() => {
|
|
3494
|
+
const pageUrl = window.location.pathname;
|
|
3495
|
+
storage.load(pageUrl).then((loaded) => setPins(loaded));
|
|
3496
|
+
});
|
|
3497
|
+
createEffect(() => {
|
|
3498
|
+
const currentPins = pins();
|
|
3499
|
+
markerManager.update(currentPins);
|
|
3500
|
+
});
|
|
3501
|
+
createEffect(() => {
|
|
3502
|
+
markerManager.setSelectedPins(selectedPinIds());
|
|
3503
|
+
});
|
|
3504
|
+
function handleModeChange(newMode) {
|
|
3505
|
+
setMode(newMode);
|
|
3506
|
+
if (newMode === "draw") {
|
|
3507
|
+
setDrawMode(true);
|
|
3508
|
+
picker.pause();
|
|
3509
|
+
dragSelect.deactivate();
|
|
3510
|
+
textSelect.deactivate();
|
|
3511
|
+
markerManager.setShowCheckboxes(false);
|
|
3512
|
+
} else if (newMode === "select") {
|
|
3513
|
+
setDrawMode(false);
|
|
3514
|
+
picker.resume();
|
|
3515
|
+
if (active()) {
|
|
3516
|
+
dragSelect.activate();
|
|
3517
|
+
textSelect.activate();
|
|
3518
|
+
}
|
|
3519
|
+
markerManager.setShowCheckboxes(false);
|
|
3520
|
+
} else if (newMode === "queue") {
|
|
3521
|
+
setDrawMode(false);
|
|
3522
|
+
picker.pause();
|
|
3523
|
+
markerManager.setShowCheckboxes(true);
|
|
3524
|
+
}
|
|
3525
|
+
}
|
|
3526
|
+
function handleDrawStart(x, y) {
|
|
3527
|
+
isDrawing = true;
|
|
3528
|
+
const toolType = drawTool();
|
|
3529
|
+
if (toolType === "text") return;
|
|
3530
|
+
setCurrentStroke({
|
|
3531
|
+
points: [{
|
|
3532
|
+
x,
|
|
3533
|
+
y
|
|
3534
|
+
}],
|
|
3535
|
+
color: drawColor(),
|
|
3536
|
+
lineWidth: drawLineWidth(),
|
|
3537
|
+
type: toolType
|
|
3538
|
+
});
|
|
3539
|
+
}
|
|
3540
|
+
function handleDrawMove(x, y) {
|
|
3541
|
+
if (!isDrawing) return;
|
|
3542
|
+
const stroke = currentStroke();
|
|
3543
|
+
if (!stroke) return;
|
|
3544
|
+
if (stroke.type === "freehand") {
|
|
3545
|
+
setCurrentStroke({
|
|
3546
|
+
...stroke,
|
|
3547
|
+
points: [...stroke.points, {
|
|
3548
|
+
x,
|
|
3549
|
+
y
|
|
3550
|
+
}]
|
|
3551
|
+
});
|
|
3552
|
+
} else {
|
|
3553
|
+
setCurrentStroke({
|
|
3554
|
+
...stroke,
|
|
3555
|
+
points: [stroke.points[0], {
|
|
3556
|
+
x,
|
|
3557
|
+
y
|
|
3558
|
+
}]
|
|
3559
|
+
});
|
|
3560
|
+
}
|
|
3561
|
+
}
|
|
3562
|
+
function handleDrawEnd() {
|
|
3563
|
+
if (!isDrawing) return;
|
|
3564
|
+
isDrawing = false;
|
|
3565
|
+
const stroke = currentStroke();
|
|
3566
|
+
if (stroke && stroke.points.length > 1) {
|
|
3567
|
+
setDrawStrokes((prev) => [...prev, stroke]);
|
|
3568
|
+
}
|
|
3569
|
+
setCurrentStroke(null);
|
|
3570
|
+
}
|
|
3571
|
+
function handleTextPlace(x, y) {
|
|
3572
|
+
setTextInputPos({
|
|
3573
|
+
x,
|
|
3574
|
+
y
|
|
3575
|
+
});
|
|
3576
|
+
setShowTextInput(true);
|
|
3577
|
+
}
|
|
3578
|
+
function handleTextSubmit(text) {
|
|
3579
|
+
setTextNotes((prev) => [...prev, {
|
|
3580
|
+
x: textInputPos().x,
|
|
3581
|
+
y: textInputPos().y,
|
|
3582
|
+
text,
|
|
3583
|
+
color: drawColor()
|
|
3584
|
+
}]);
|
|
3585
|
+
setShowTextInput(false);
|
|
3586
|
+
}
|
|
3587
|
+
function undoDrawStroke() {
|
|
3588
|
+
if (textNotes().length > 0) {
|
|
3589
|
+
setTextNotes((prev) => prev.slice(0, -1));
|
|
3590
|
+
} else if (drawStrokes().length > 0) {
|
|
3591
|
+
setDrawStrokes((prev) => prev.slice(0, -1));
|
|
3592
|
+
}
|
|
3593
|
+
}
|
|
3594
|
+
function clearDrawing() {
|
|
3595
|
+
setDrawStrokes([]);
|
|
3596
|
+
setTextNotes([]);
|
|
3597
|
+
setCurrentStroke(null);
|
|
3598
|
+
}
|
|
3599
|
+
function addToQueue(pin) {
|
|
3600
|
+
const item = {
|
|
3601
|
+
id: crypto.randomUUID(),
|
|
3602
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
3603
|
+
};
|
|
3604
|
+
if (pin) {
|
|
3605
|
+
item.pin = pin;
|
|
3606
|
+
}
|
|
3607
|
+
const strokes = drawStrokes();
|
|
3608
|
+
const notes = textNotes();
|
|
3609
|
+
if (strokes.length > 0 || notes.length > 0) {
|
|
3610
|
+
item.drawings = [...strokes];
|
|
3611
|
+
item.textNotes = [...notes];
|
|
3612
|
+
clearDrawing();
|
|
3613
|
+
}
|
|
3614
|
+
setQueue((prev) => [...prev, item]);
|
|
3615
|
+
}
|
|
3616
|
+
async function sendQueue() {
|
|
3617
|
+
const items = queue();
|
|
3618
|
+
if (items.length === 0) return;
|
|
3619
|
+
const {
|
|
3620
|
+
formatQueueForAgent
|
|
3621
|
+
} = await import("./agent-context-HBCZ4MBN.js");
|
|
3622
|
+
const {
|
|
3623
|
+
message,
|
|
3624
|
+
context
|
|
3625
|
+
} = formatQueueForAgent(items, outputFormat());
|
|
3626
|
+
await deliverToAgent({
|
|
3627
|
+
message,
|
|
3628
|
+
context
|
|
3629
|
+
});
|
|
3630
|
+
setQueue([]);
|
|
3631
|
+
if (clearOnSend()) {
|
|
3632
|
+
const pageUrl = window.location.pathname;
|
|
3633
|
+
await storage.clear(pageUrl);
|
|
3634
|
+
setPins([]);
|
|
3635
|
+
}
|
|
3636
|
+
}
|
|
3637
|
+
function clearQueue() {
|
|
3638
|
+
setQueue([]);
|
|
3639
|
+
}
|
|
3640
|
+
function togglePinSelect(pin) {
|
|
3641
|
+
setSelectedPinIds((prev) => {
|
|
3642
|
+
const next = new Set(prev);
|
|
3643
|
+
if (next.has(pin.id)) {
|
|
3644
|
+
next.delete(pin.id);
|
|
3645
|
+
} else {
|
|
3646
|
+
next.add(pin.id);
|
|
3647
|
+
}
|
|
3648
|
+
return next;
|
|
3649
|
+
});
|
|
3650
|
+
}
|
|
3651
|
+
async function sendSelected() {
|
|
3652
|
+
const ids = selectedPinIds();
|
|
3653
|
+
if (ids.size === 0) return;
|
|
3654
|
+
const selected = pins().filter((p) => ids.has(p.id));
|
|
3655
|
+
const {
|
|
3656
|
+
formatPinsForAgent
|
|
3657
|
+
} = await import("./agent-context-HBCZ4MBN.js");
|
|
3658
|
+
const {
|
|
3659
|
+
message,
|
|
3660
|
+
context
|
|
3661
|
+
} = formatPinsForAgent(selected, outputFormat());
|
|
3662
|
+
await deliverToAgent({
|
|
3663
|
+
message,
|
|
3664
|
+
context
|
|
3665
|
+
});
|
|
3666
|
+
setSelectedPinIds(/* @__PURE__ */ new Set());
|
|
3667
|
+
}
|
|
3668
|
+
function toggleActive() {
|
|
3669
|
+
if (active()) {
|
|
3670
|
+
deactivateSelection();
|
|
3671
|
+
} else {
|
|
3672
|
+
activateSelection();
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
function activateSelection() {
|
|
3676
|
+
setActive(true);
|
|
3677
|
+
setExpanded(true);
|
|
3678
|
+
if (mode() !== "draw") {
|
|
3679
|
+
picker.activate();
|
|
3680
|
+
dragSelect.activate();
|
|
3681
|
+
textSelect.activate();
|
|
3682
|
+
}
|
|
3683
|
+
}
|
|
3684
|
+
function deactivateSelection() {
|
|
3685
|
+
setActive(false);
|
|
3686
|
+
setDrawMode(false);
|
|
3687
|
+
setMode("select");
|
|
3688
|
+
picker.deactivate();
|
|
3689
|
+
dragSelect.deactivate();
|
|
3690
|
+
textSelect.deactivate();
|
|
3691
|
+
setHoveredRect(null);
|
|
3692
|
+
setSelectionLabelInfo(null);
|
|
3693
|
+
}
|
|
3694
|
+
function closePopup() {
|
|
3695
|
+
setShowPopup(false);
|
|
3696
|
+
setEditingPin(null);
|
|
3697
|
+
if (mode() !== "draw") {
|
|
3698
|
+
picker.resume();
|
|
3699
|
+
}
|
|
3700
|
+
}
|
|
3701
|
+
function addPin(element, comment) {
|
|
3702
|
+
const framework = detectFramework();
|
|
3703
|
+
const frameworkInfo = (() => {
|
|
3704
|
+
const info = framework.getComponentInfo(element);
|
|
3705
|
+
const source = framework.getSourceLocation(element);
|
|
3706
|
+
if (!info && !source) return void 0;
|
|
3707
|
+
return {
|
|
3708
|
+
framework: framework.name,
|
|
3709
|
+
componentPath: info?.name ? `<${info.name}>` : "",
|
|
3710
|
+
sourceFile: source ? `${source.file}${source.line ? `:${source.line}` : ""}` : void 0,
|
|
3711
|
+
frameworkVersion: void 0
|
|
3712
|
+
};
|
|
3713
|
+
})();
|
|
3714
|
+
const elementInfo = extractElementInfo(element);
|
|
3715
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3716
|
+
const pin = {
|
|
3717
|
+
id: crypto.randomUUID(),
|
|
3718
|
+
pageUrl: window.location.pathname,
|
|
3719
|
+
createdAt: now,
|
|
3720
|
+
updatedAt: now,
|
|
3721
|
+
author: props.config.author,
|
|
3722
|
+
comment,
|
|
3723
|
+
element: elementInfo,
|
|
3724
|
+
framework: frameworkInfo,
|
|
3725
|
+
status: {
|
|
3726
|
+
state: "open",
|
|
3727
|
+
changedAt: now,
|
|
3728
|
+
changedBy: "user"
|
|
3729
|
+
}
|
|
3730
|
+
};
|
|
3731
|
+
setPins((prev) => [...prev, pin]);
|
|
3732
|
+
storage.save(pin);
|
|
3733
|
+
closePopup();
|
|
3734
|
+
return pin;
|
|
3735
|
+
}
|
|
3736
|
+
function handleQueueFromPopup(comment) {
|
|
3737
|
+
const el = selectedElement();
|
|
3738
|
+
if (!el) return;
|
|
3739
|
+
const pin = addPin(el, comment);
|
|
3740
|
+
addToQueue(pin);
|
|
3741
|
+
}
|
|
3742
|
+
async function handleFixThis(comment) {
|
|
3743
|
+
const el = selectedElement();
|
|
3744
|
+
if (!el) return;
|
|
3745
|
+
const pin = addPin(el, comment);
|
|
3746
|
+
const {
|
|
3747
|
+
formatRichPinContext
|
|
3748
|
+
} = await import("./agent-context-HBCZ4MBN.js");
|
|
3749
|
+
const richMessage = `Please fix: ${formatRichPinContext(pin)}`;
|
|
3750
|
+
await deliverToAgent({
|
|
3751
|
+
message: richMessage,
|
|
3752
|
+
context: ""
|
|
3753
|
+
});
|
|
3754
|
+
}
|
|
3755
|
+
function openEditPopup(pin) {
|
|
3756
|
+
setShowPopup(false);
|
|
3757
|
+
queueMicrotask(() => {
|
|
3758
|
+
const el = document.querySelector(pin.element.selector);
|
|
3759
|
+
setEditingPin(pin);
|
|
3760
|
+
setSelectedContext(buildElementContext(el || document.body, pin.framework));
|
|
3761
|
+
setShowPopup(true);
|
|
3762
|
+
picker.pause();
|
|
3763
|
+
});
|
|
3764
|
+
}
|
|
3765
|
+
function updatePin(comment) {
|
|
3766
|
+
const pin = editingPin();
|
|
3767
|
+
if (!pin) return;
|
|
3768
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
3769
|
+
const updated = {
|
|
3770
|
+
...pin,
|
|
3771
|
+
comment,
|
|
3772
|
+
updatedAt: now
|
|
3773
|
+
};
|
|
3774
|
+
setPins((prev) => prev.map((p) => p.id === pin.id ? updated : p));
|
|
3775
|
+
storage.update(pin.id, {
|
|
3776
|
+
comment,
|
|
3777
|
+
updatedAt: now
|
|
3778
|
+
});
|
|
3779
|
+
closePopup();
|
|
3780
|
+
}
|
|
3781
|
+
async function copyPins() {
|
|
3782
|
+
const {
|
|
3783
|
+
formatPins
|
|
3784
|
+
} = await import("./formatter-CR4COA5Z.js");
|
|
3785
|
+
const text = formatPins(pins(), outputFormat());
|
|
3786
|
+
await navigator.clipboard.writeText(text);
|
|
3787
|
+
}
|
|
3788
|
+
async function sendPins() {
|
|
3789
|
+
const {
|
|
3790
|
+
formatPinsForAgent
|
|
3791
|
+
} = await import("./agent-context-HBCZ4MBN.js");
|
|
3792
|
+
const {
|
|
3793
|
+
message,
|
|
3794
|
+
context
|
|
3795
|
+
} = formatPinsForAgent(pins(), outputFormat());
|
|
3796
|
+
await deliverToAgent({
|
|
3797
|
+
message,
|
|
3798
|
+
context
|
|
3799
|
+
});
|
|
3800
|
+
if (clearOnSend()) {
|
|
3801
|
+
const pageUrl = window.location.pathname;
|
|
3802
|
+
await storage.clear(pageUrl);
|
|
3803
|
+
setPins([]);
|
|
3804
|
+
}
|
|
3805
|
+
}
|
|
3806
|
+
function removePin(id) {
|
|
3807
|
+
setPins((prev) => prev.filter((p) => p.id !== id));
|
|
3808
|
+
storage.delete(id);
|
|
3809
|
+
setSelectedPinIds((prev) => {
|
|
3810
|
+
const next = new Set(prev);
|
|
3811
|
+
next.delete(id);
|
|
3812
|
+
return next;
|
|
3813
|
+
});
|
|
3814
|
+
}
|
|
3815
|
+
function clearPins() {
|
|
3816
|
+
const pageUrl = window.location.pathname;
|
|
3817
|
+
storage.clear(pageUrl);
|
|
3818
|
+
setPins([]);
|
|
3819
|
+
setSelectedPinIds(/* @__PURE__ */ new Set());
|
|
3820
|
+
}
|
|
3821
|
+
return [createComponent(OverlayCanvas, {
|
|
3822
|
+
get hoveredRect() {
|
|
3823
|
+
return hoveredRect();
|
|
3824
|
+
},
|
|
3825
|
+
get dragRect() {
|
|
3826
|
+
return dragRect();
|
|
3827
|
+
},
|
|
3828
|
+
get pins() {
|
|
3829
|
+
return pins();
|
|
3830
|
+
},
|
|
3831
|
+
get active() {
|
|
3832
|
+
return active();
|
|
3833
|
+
},
|
|
3834
|
+
get drawMode() {
|
|
3835
|
+
return drawMode();
|
|
3836
|
+
},
|
|
3837
|
+
get drawStrokes() {
|
|
3838
|
+
return drawStrokes();
|
|
3839
|
+
},
|
|
3840
|
+
get currentStroke() {
|
|
3841
|
+
return currentStroke();
|
|
3842
|
+
},
|
|
3843
|
+
get drawColor() {
|
|
3844
|
+
return drawColor();
|
|
3845
|
+
},
|
|
3846
|
+
get drawLineWidth() {
|
|
3847
|
+
return drawLineWidth();
|
|
3848
|
+
},
|
|
3849
|
+
get drawTool() {
|
|
3850
|
+
return drawTool();
|
|
3851
|
+
},
|
|
3852
|
+
get textNotes() {
|
|
3853
|
+
return textNotes();
|
|
3854
|
+
},
|
|
3855
|
+
onDrawStart: handleDrawStart,
|
|
3856
|
+
onDrawMove: handleDrawMove,
|
|
3857
|
+
onDrawEnd: handleDrawEnd,
|
|
3858
|
+
onTextPlace: handleTextPlace
|
|
3859
|
+
}), createComponent(SelectionLabel, {
|
|
3860
|
+
get info() {
|
|
3861
|
+
return selectionLabelInfo();
|
|
3862
|
+
}
|
|
3863
|
+
}), createComponent(Toolbar, {
|
|
3864
|
+
get expanded() {
|
|
3865
|
+
return expanded();
|
|
3866
|
+
},
|
|
3867
|
+
get active() {
|
|
3868
|
+
return active();
|
|
3869
|
+
},
|
|
3870
|
+
get pins() {
|
|
3871
|
+
return pins();
|
|
3872
|
+
},
|
|
3873
|
+
get position() {
|
|
3874
|
+
return props.config.position;
|
|
3875
|
+
},
|
|
3876
|
+
get author() {
|
|
3877
|
+
return props.config.author;
|
|
3878
|
+
},
|
|
3879
|
+
get showSettings() {
|
|
3880
|
+
return showSettings();
|
|
3881
|
+
},
|
|
3882
|
+
get outputFormat() {
|
|
3883
|
+
return outputFormat();
|
|
3884
|
+
},
|
|
3885
|
+
get clearOnSend() {
|
|
3886
|
+
return clearOnSend();
|
|
3887
|
+
},
|
|
3888
|
+
get blockInteractions() {
|
|
3889
|
+
return blockInteractions();
|
|
3890
|
+
},
|
|
3891
|
+
get autoSubmit() {
|
|
3892
|
+
return autoSubmit();
|
|
3893
|
+
},
|
|
3894
|
+
get webhookUrl() {
|
|
3895
|
+
return props.config.webhookUrl;
|
|
3896
|
+
},
|
|
3897
|
+
get compactPopup() {
|
|
3898
|
+
return compactPopup();
|
|
3899
|
+
},
|
|
3900
|
+
get mode() {
|
|
3901
|
+
return mode();
|
|
3902
|
+
},
|
|
3903
|
+
get drawTool() {
|
|
3904
|
+
return drawTool();
|
|
3905
|
+
},
|
|
3906
|
+
get drawColor() {
|
|
3907
|
+
return drawColor();
|
|
3908
|
+
},
|
|
3909
|
+
get drawLineWidth() {
|
|
3910
|
+
return drawLineWidth();
|
|
3911
|
+
},
|
|
3912
|
+
get drawStrokeCount() {
|
|
3913
|
+
return drawStrokes().length + textNotes().length;
|
|
3914
|
+
},
|
|
3915
|
+
get queue() {
|
|
3916
|
+
return queue();
|
|
3917
|
+
},
|
|
3918
|
+
get selectedPinIds() {
|
|
3919
|
+
return selectedPinIds();
|
|
3920
|
+
},
|
|
3921
|
+
onToggleExpand: () => {
|
|
3922
|
+
const willExpand = !expanded();
|
|
3923
|
+
setExpanded(willExpand);
|
|
3924
|
+
if (willExpand) {
|
|
3925
|
+
activateSelection();
|
|
3926
|
+
} else {
|
|
3927
|
+
deactivateSelection();
|
|
3928
|
+
setShowSettings(false);
|
|
3929
|
+
if (showPopup()) {
|
|
3930
|
+
closePopup();
|
|
3931
|
+
}
|
|
3932
|
+
}
|
|
3933
|
+
},
|
|
3934
|
+
onModeChange: handleModeChange,
|
|
3935
|
+
onSend: sendPins,
|
|
3936
|
+
onCopy: copyPins,
|
|
3937
|
+
onClear: clearPins,
|
|
3938
|
+
onRemovePin: removePin,
|
|
3939
|
+
onEditPin: openEditPopup,
|
|
3940
|
+
onToggleSettings: () => setShowSettings(!showSettings()),
|
|
3941
|
+
onOutputFormatChange: setOutputFormat,
|
|
3942
|
+
onClearOnSendChange: setClearOnSend,
|
|
3943
|
+
onBlockInteractionsChange: setBlockInteractions,
|
|
3944
|
+
onAutoSubmitChange: setAutoSubmit,
|
|
3945
|
+
onCompactPopupChange: setCompactPopup,
|
|
3946
|
+
onDrawToolChange: setDrawTool,
|
|
3947
|
+
onDrawColorChange: setDrawColor,
|
|
3948
|
+
onDrawLineWidthChange: setDrawLineWidth,
|
|
3949
|
+
onDrawUndo: undoDrawStroke,
|
|
3950
|
+
onDrawClear: clearDrawing,
|
|
3951
|
+
onQueueAdd: () => addToQueue(),
|
|
3952
|
+
onQueueSend: sendQueue,
|
|
3953
|
+
onQueueClear: clearQueue,
|
|
3954
|
+
onSendSelected: sendSelected,
|
|
3955
|
+
onTogglePinSelect: togglePinSelect
|
|
3956
|
+
}), memo(() => memo(() => !!(showPopup() && selectedContext()))() && createComponent(PinPopup, {
|
|
3957
|
+
get context() {
|
|
3958
|
+
return selectedContext();
|
|
3959
|
+
},
|
|
3960
|
+
get initialComment() {
|
|
3961
|
+
return editingPin()?.comment;
|
|
3962
|
+
},
|
|
3963
|
+
get isEditing() {
|
|
3964
|
+
return !!editingPin();
|
|
3965
|
+
},
|
|
3966
|
+
get compactPopup() {
|
|
3967
|
+
return compactPopup();
|
|
3968
|
+
},
|
|
3969
|
+
get queueMode() {
|
|
3970
|
+
return mode() === "queue";
|
|
3971
|
+
},
|
|
3972
|
+
onAdd: (comment) => {
|
|
3973
|
+
if (editingPin()) {
|
|
3974
|
+
updatePin(comment);
|
|
3975
|
+
} else {
|
|
3976
|
+
addPin(selectedElement(), comment);
|
|
3977
|
+
}
|
|
3978
|
+
},
|
|
3979
|
+
onQueue: handleQueueFromPopup,
|
|
3980
|
+
onFixThis: handleFixThis,
|
|
3981
|
+
onCancel: () => closePopup()
|
|
3982
|
+
})), memo(() => memo(() => !!showTextInput())() && createComponent(TextInputPopup, {
|
|
3983
|
+
get x() {
|
|
3984
|
+
return textInputPos().x;
|
|
3985
|
+
},
|
|
3986
|
+
get y() {
|
|
3987
|
+
return textInputPos().y;
|
|
3988
|
+
},
|
|
3989
|
+
get color() {
|
|
3990
|
+
return drawColor();
|
|
3991
|
+
},
|
|
3992
|
+
onSubmit: handleTextSubmit,
|
|
3993
|
+
onCancel: () => setShowTextInput(false)
|
|
3994
|
+
})), memo(() => memo(() => !!(showContextMenu() && selectedElement()))() && createComponent(ContextMenu, {
|
|
3995
|
+
get position() {
|
|
3996
|
+
return contextMenuPos();
|
|
3997
|
+
},
|
|
3998
|
+
get element() {
|
|
3999
|
+
return selectedElement();
|
|
4000
|
+
},
|
|
4001
|
+
onClose: () => setShowContextMenu(false),
|
|
4002
|
+
onAnnotate: () => {
|
|
4003
|
+
setShowContextMenu(false);
|
|
4004
|
+
const el = selectedElement();
|
|
4005
|
+
const framework = detectFramework();
|
|
4006
|
+
const frameworkInfo = (() => {
|
|
4007
|
+
const info = framework.getComponentInfo(el);
|
|
4008
|
+
const source = framework.getSourceLocation(el);
|
|
4009
|
+
if (!info && !source) return void 0;
|
|
4010
|
+
return {
|
|
4011
|
+
framework: framework.name,
|
|
4012
|
+
componentPath: info?.name ? `<${info.name}>` : "",
|
|
4013
|
+
sourceFile: source?.file,
|
|
4014
|
+
frameworkVersion: void 0
|
|
4015
|
+
};
|
|
4016
|
+
})();
|
|
4017
|
+
setSelectedContext(buildElementContext(el, frameworkInfo));
|
|
4018
|
+
setShowPopup(true);
|
|
4019
|
+
picker.pause();
|
|
4020
|
+
},
|
|
4021
|
+
onCopyContext: async () => {
|
|
4022
|
+
const el = selectedElement();
|
|
4023
|
+
const context = buildElementContext(el);
|
|
4024
|
+
await navigator.clipboard.writeText(JSON.stringify(context, null, 2));
|
|
4025
|
+
setShowContextMenu(false);
|
|
4026
|
+
},
|
|
4027
|
+
onPrompt: () => {
|
|
4028
|
+
setShowContextMenu(false);
|
|
4029
|
+
setShowPrompt(true);
|
|
4030
|
+
}
|
|
4031
|
+
})), memo(() => memo(() => !!(showPrompt() && selectedElement()))() && createComponent(PromptMode, {
|
|
4032
|
+
get element() {
|
|
4033
|
+
return selectedElement();
|
|
4034
|
+
},
|
|
4035
|
+
onSend: async (instruction) => {
|
|
4036
|
+
const context = buildElementContext(selectedElement());
|
|
4037
|
+
await deliverToAgent({
|
|
4038
|
+
message: instruction,
|
|
4039
|
+
context: JSON.stringify(context, null, 2)
|
|
4040
|
+
});
|
|
4041
|
+
setShowPrompt(false);
|
|
4042
|
+
},
|
|
4043
|
+
onCancel: () => setShowPrompt(false)
|
|
4044
|
+
}))];
|
|
4045
|
+
};
|
|
4046
|
+
|
|
4047
|
+
// src/ui/styles/theme.ts
|
|
4048
|
+
var overlayStyles = `
|
|
4049
|
+
:host {
|
|
4050
|
+
all: initial;
|
|
4051
|
+
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
|
4052
|
+
font-size: 13px;
|
|
4053
|
+
line-height: 1.4;
|
|
4054
|
+
color: var(--pp-text);
|
|
4055
|
+
pointer-events: none;
|
|
4056
|
+
}
|
|
4057
|
+
|
|
4058
|
+
*,
|
|
4059
|
+
*::before,
|
|
4060
|
+
*::after {
|
|
4061
|
+
box-sizing: border-box;
|
|
4062
|
+
margin: 0;
|
|
4063
|
+
padding: 0;
|
|
4064
|
+
}
|
|
4065
|
+
|
|
4066
|
+
/* Theme variables */
|
|
4067
|
+
:host {
|
|
4068
|
+
--pp-bg: rgba(24, 24, 27, 0.92);
|
|
4069
|
+
--pp-bg-solid: #18181b;
|
|
4070
|
+
--pp-text: #fafafa;
|
|
4071
|
+
--pp-text-muted: #a1a1aa;
|
|
4072
|
+
--pp-border: rgba(63, 63, 70, 0.6);
|
|
4073
|
+
--pp-accent: #3b82f6;
|
|
4074
|
+
--pp-accent-hover: #60a5fa;
|
|
4075
|
+
--pp-success: #22c55e;
|
|
4076
|
+
--pp-warning: #eab308;
|
|
4077
|
+
--pp-danger: #ef4444;
|
|
4078
|
+
--pp-shadow: 0 4px 24px rgba(0, 0, 0, 0.3), 0 0 0 1px rgba(255, 255, 255, 0.06);
|
|
4079
|
+
--pp-radius: 10px;
|
|
4080
|
+
--pp-radius-sm: 6px;
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4083
|
+
:host([data-theme="light"]) {
|
|
4084
|
+
--pp-bg: rgba(255, 255, 255, 0.92);
|
|
4085
|
+
--pp-bg-solid: #ffffff;
|
|
4086
|
+
--pp-text: #18181b;
|
|
4087
|
+
--pp-text-muted: #71717a;
|
|
4088
|
+
--pp-border: rgba(228, 228, 231, 0.8);
|
|
4089
|
+
--pp-accent: #2563eb;
|
|
4090
|
+
--pp-accent-hover: #3b82f6;
|
|
4091
|
+
--pp-shadow: 0 4px 24px rgba(0, 0, 0, 0.08), 0 0 0 1px rgba(0, 0, 0, 0.06);
|
|
4092
|
+
}
|
|
4093
|
+
|
|
4094
|
+
:host([data-theme="light"]) .pp-popup__textarea {
|
|
4095
|
+
background: rgba(0, 0, 0, 0.06);
|
|
4096
|
+
}
|
|
4097
|
+
|
|
4098
|
+
/* Toolbar */
|
|
4099
|
+
.pp-toolbar {
|
|
4100
|
+
position: fixed;
|
|
4101
|
+
z-index: 2147483646;
|
|
4102
|
+
pointer-events: auto;
|
|
4103
|
+
backdrop-filter: blur(12px) saturate(180%);
|
|
4104
|
+
-webkit-backdrop-filter: blur(12px) saturate(180%);
|
|
4105
|
+
background: var(--pp-bg);
|
|
4106
|
+
border: 1px solid var(--pp-border);
|
|
4107
|
+
border-radius: var(--pp-radius);
|
|
4108
|
+
box-shadow: var(--pp-shadow);
|
|
4109
|
+
transition: all 0.2s cubic-bezier(0.16, 1, 0.3, 1);
|
|
4110
|
+
user-select: none;
|
|
4111
|
+
cursor: default;
|
|
4112
|
+
}
|
|
4113
|
+
|
|
4114
|
+
.pp-toolbar--collapsed {
|
|
4115
|
+
padding: 10px;
|
|
4116
|
+
display: flex;
|
|
4117
|
+
align-items: center;
|
|
4118
|
+
justify-content: center;
|
|
4119
|
+
gap: 6px;
|
|
4120
|
+
cursor: pointer;
|
|
4121
|
+
}
|
|
4122
|
+
|
|
4123
|
+
.pp-toolbar--expanded {
|
|
4124
|
+
padding: 12px;
|
|
4125
|
+
width: 320px;
|
|
4126
|
+
max-height: 420px;
|
|
4127
|
+
display: flex;
|
|
4128
|
+
flex-direction: column;
|
|
4129
|
+
gap: 8px;
|
|
4130
|
+
}
|
|
4131
|
+
|
|
4132
|
+
.pp-toolbar__badge {
|
|
4133
|
+
display: inline-flex;
|
|
4134
|
+
align-items: center;
|
|
4135
|
+
justify-content: center;
|
|
4136
|
+
min-width: 18px;
|
|
4137
|
+
height: 18px;
|
|
4138
|
+
padding: 0 5px;
|
|
4139
|
+
border-radius: 9px;
|
|
4140
|
+
background: var(--pp-accent);
|
|
4141
|
+
color: #fff;
|
|
4142
|
+
font-size: 11px;
|
|
4143
|
+
font-weight: 600;
|
|
4144
|
+
}
|
|
4145
|
+
|
|
4146
|
+
/* Buttons */
|
|
4147
|
+
.pp-btn {
|
|
4148
|
+
display: inline-flex;
|
|
4149
|
+
align-items: center;
|
|
4150
|
+
justify-content: center;
|
|
4151
|
+
gap: 4px;
|
|
4152
|
+
padding: 5px 10px;
|
|
4153
|
+
border: 1px solid var(--pp-border);
|
|
4154
|
+
border-radius: var(--pp-radius-sm);
|
|
4155
|
+
background: transparent;
|
|
4156
|
+
color: var(--pp-text);
|
|
4157
|
+
font-size: 12px;
|
|
4158
|
+
font-weight: 500;
|
|
4159
|
+
cursor: pointer;
|
|
4160
|
+
transition: all 0.15s ease;
|
|
4161
|
+
white-space: nowrap;
|
|
4162
|
+
}
|
|
4163
|
+
|
|
4164
|
+
.pp-btn:hover {
|
|
4165
|
+
background: rgba(255, 255, 255, 0.06);
|
|
4166
|
+
border-color: var(--pp-accent);
|
|
4167
|
+
}
|
|
4168
|
+
|
|
4169
|
+
.pp-btn--primary {
|
|
4170
|
+
background: var(--pp-accent);
|
|
4171
|
+
border-color: var(--pp-accent);
|
|
4172
|
+
color: #fff;
|
|
4173
|
+
}
|
|
4174
|
+
|
|
4175
|
+
.pp-btn--primary:hover {
|
|
4176
|
+
background: var(--pp-accent-hover);
|
|
4177
|
+
}
|
|
4178
|
+
|
|
4179
|
+
.pp-btn--sm {
|
|
4180
|
+
padding: 3px 6px;
|
|
4181
|
+
font-size: 11px;
|
|
4182
|
+
}
|
|
4183
|
+
|
|
4184
|
+
.pp-btn--icon {
|
|
4185
|
+
padding: 4px;
|
|
4186
|
+
border: none;
|
|
4187
|
+
background: transparent;
|
|
4188
|
+
color: var(--pp-text-muted);
|
|
4189
|
+
cursor: pointer;
|
|
4190
|
+
border-radius: var(--pp-radius-sm);
|
|
4191
|
+
}
|
|
4192
|
+
|
|
4193
|
+
.pp-btn--icon:hover {
|
|
4194
|
+
background: rgba(255, 255, 255, 0.06);
|
|
4195
|
+
color: var(--pp-text);
|
|
4196
|
+
}
|
|
4197
|
+
|
|
4198
|
+
.pp-btn--icon-sm {
|
|
4199
|
+
padding: 2px;
|
|
4200
|
+
opacity: 0;
|
|
4201
|
+
pointer-events: none;
|
|
4202
|
+
transition: opacity 0.15s ease, color 0.15s ease, background-color 0.15s ease;
|
|
4203
|
+
}
|
|
4204
|
+
|
|
4205
|
+
.pp-pin-item:hover .pp-btn--icon-sm,
|
|
4206
|
+
.pp-pin-item:focus-within .pp-btn--icon-sm {
|
|
4207
|
+
opacity: 1;
|
|
4208
|
+
pointer-events: auto;
|
|
4209
|
+
}
|
|
4210
|
+
|
|
4211
|
+
.pp-btn--icon-sm:hover {
|
|
4212
|
+
background: rgba(239, 68, 68, 0.15);
|
|
4213
|
+
color: var(--pp-danger);
|
|
4214
|
+
}
|
|
4215
|
+
|
|
4216
|
+
@media (hover: none) {
|
|
4217
|
+
.pp-btn--icon-sm {
|
|
4218
|
+
opacity: 0.6;
|
|
4219
|
+
pointer-events: auto;
|
|
4220
|
+
}
|
|
4221
|
+
}
|
|
4222
|
+
|
|
4223
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4224
|
+
.pp-btn--icon-sm { transition: none; }
|
|
4225
|
+
}
|
|
4226
|
+
|
|
4227
|
+
/* Pin list */
|
|
4228
|
+
.pp-pin-list {
|
|
4229
|
+
display: flex;
|
|
4230
|
+
flex-direction: column;
|
|
4231
|
+
gap: 4px;
|
|
4232
|
+
overflow-y: auto;
|
|
4233
|
+
max-height: 240px;
|
|
4234
|
+
scrollbar-width: thin;
|
|
4235
|
+
scrollbar-color: var(--pp-border) transparent;
|
|
4236
|
+
}
|
|
4237
|
+
|
|
4238
|
+
.pp-pin-item {
|
|
4239
|
+
display: flex;
|
|
4240
|
+
align-items: center;
|
|
4241
|
+
gap: 8px;
|
|
4242
|
+
padding: 6px 8px;
|
|
4243
|
+
border-radius: var(--pp-radius-sm);
|
|
4244
|
+
cursor: pointer;
|
|
4245
|
+
transition: background 0.1s;
|
|
4246
|
+
}
|
|
4247
|
+
|
|
4248
|
+
.pp-pin-item:hover {
|
|
4249
|
+
background: rgba(255, 255, 255, 0.04);
|
|
4250
|
+
}
|
|
4251
|
+
|
|
4252
|
+
.pp-pin-item__number {
|
|
4253
|
+
display: flex;
|
|
4254
|
+
align-items: center;
|
|
4255
|
+
justify-content: center;
|
|
4256
|
+
width: 22px;
|
|
4257
|
+
height: 22px;
|
|
4258
|
+
min-width: 22px;
|
|
4259
|
+
padding: 0 4px;
|
|
4260
|
+
border-radius: 11px;
|
|
4261
|
+
background: var(--pp-accent);
|
|
4262
|
+
color: #fff;
|
|
4263
|
+
font-size: 11px;
|
|
4264
|
+
font-weight: 600;
|
|
4265
|
+
font-variant-numeric: tabular-nums;
|
|
4266
|
+
flex-shrink: 0;
|
|
4267
|
+
}
|
|
4268
|
+
|
|
4269
|
+
.pp-pin-item__content {
|
|
4270
|
+
flex: 1;
|
|
4271
|
+
min-width: 0;
|
|
4272
|
+
}
|
|
4273
|
+
|
|
4274
|
+
.pp-pin-item__comment {
|
|
4275
|
+
font-size: 12px;
|
|
4276
|
+
color: var(--pp-text);
|
|
4277
|
+
display: -webkit-box;
|
|
4278
|
+
-webkit-line-clamp: 2;
|
|
4279
|
+
-webkit-box-orient: vertical;
|
|
4280
|
+
overflow: hidden;
|
|
4281
|
+
word-break: break-word;
|
|
4282
|
+
}
|
|
4283
|
+
|
|
4284
|
+
.pp-pin-item__status {
|
|
4285
|
+
width: 6px;
|
|
4286
|
+
height: 6px;
|
|
4287
|
+
border-radius: 50%;
|
|
4288
|
+
flex-shrink: 0;
|
|
4289
|
+
}
|
|
4290
|
+
|
|
4291
|
+
.pp-pin-item__status--open { background: var(--pp-danger); }
|
|
4292
|
+
.pp-pin-item__status--acknowledged { background: var(--pp-warning); }
|
|
4293
|
+
.pp-pin-item__status--resolved { background: var(--pp-success); }
|
|
4294
|
+
.pp-pin-item__status--dismissed { background: var(--pp-text-muted); }
|
|
4295
|
+
|
|
4296
|
+
/* Action bar \u2014 horizontal icon bar at bottom */
|
|
4297
|
+
.pp-actions {
|
|
4298
|
+
display: flex;
|
|
4299
|
+
align-items: center;
|
|
4300
|
+
justify-content: center;
|
|
4301
|
+
gap: 6px;
|
|
4302
|
+
padding-top: 8px;
|
|
4303
|
+
border-top: 1px solid var(--pp-border);
|
|
4304
|
+
}
|
|
4305
|
+
|
|
4306
|
+
.pp-actions .pp-btn--icon {
|
|
4307
|
+
width: 32px;
|
|
4308
|
+
height: 32px;
|
|
4309
|
+
border-radius: 50%;
|
|
4310
|
+
display: flex;
|
|
4311
|
+
align-items: center;
|
|
4312
|
+
justify-content: center;
|
|
4313
|
+
}
|
|
4314
|
+
|
|
4315
|
+
.pp-actions .pp-btn--icon:focus-visible {
|
|
4316
|
+
outline: 2px solid var(--pp-accent);
|
|
4317
|
+
outline-offset: 2px;
|
|
4318
|
+
}
|
|
4319
|
+
|
|
4320
|
+
/* Popup */
|
|
4321
|
+
.pp-popup {
|
|
4322
|
+
position: fixed;
|
|
4323
|
+
z-index: 2147483647;
|
|
4324
|
+
pointer-events: auto;
|
|
4325
|
+
backdrop-filter: blur(12px) saturate(180%);
|
|
4326
|
+
-webkit-backdrop-filter: blur(12px) saturate(180%);
|
|
4327
|
+
background: var(--pp-bg);
|
|
4328
|
+
border: 1px solid var(--pp-border);
|
|
4329
|
+
border-radius: var(--pp-radius);
|
|
4330
|
+
box-shadow: var(--pp-shadow);
|
|
4331
|
+
padding: 10px;
|
|
4332
|
+
min-width: 280px;
|
|
4333
|
+
max-width: 360px;
|
|
4334
|
+
display: flex;
|
|
4335
|
+
flex-direction: column;
|
|
4336
|
+
gap: 6px;
|
|
4337
|
+
}
|
|
4338
|
+
|
|
4339
|
+
.pp-popup__element-info {
|
|
4340
|
+
font-size: 11px;
|
|
4341
|
+
font-family: 'SF Mono', 'Fira Code', monospace;
|
|
4342
|
+
color: var(--pp-accent);
|
|
4343
|
+
word-break: break-all;
|
|
4344
|
+
}
|
|
4345
|
+
|
|
4346
|
+
.pp-popup__component {
|
|
4347
|
+
font-size: 12px;
|
|
4348
|
+
color: var(--pp-text-muted);
|
|
4349
|
+
}
|
|
4350
|
+
|
|
4351
|
+
.pp-popup__source {
|
|
4352
|
+
font-size: 11px;
|
|
4353
|
+
color: var(--pp-text-muted);
|
|
4354
|
+
cursor: pointer;
|
|
4355
|
+
display: flex;
|
|
4356
|
+
align-items: center;
|
|
4357
|
+
gap: 4px;
|
|
4358
|
+
}
|
|
4359
|
+
|
|
4360
|
+
.pp-popup__source:hover {
|
|
4361
|
+
color: var(--pp-accent);
|
|
4362
|
+
text-decoration: underline;
|
|
4363
|
+
}
|
|
4364
|
+
|
|
4365
|
+
/* Popup header with chevron toggle */
|
|
4366
|
+
.pp-popup__header {
|
|
4367
|
+
display: flex;
|
|
4368
|
+
align-items: center;
|
|
4369
|
+
justify-content: space-between;
|
|
4370
|
+
cursor: pointer;
|
|
4371
|
+
padding: 2px 0;
|
|
4372
|
+
}
|
|
4373
|
+
|
|
4374
|
+
.pp-popup__name {
|
|
4375
|
+
font-size: 12px;
|
|
4376
|
+
font-weight: 500;
|
|
4377
|
+
color: var(--pp-text);
|
|
4378
|
+
overflow: hidden;
|
|
4379
|
+
text-overflow: ellipsis;
|
|
4380
|
+
white-space: nowrap;
|
|
4381
|
+
max-width: 280px;
|
|
4382
|
+
}
|
|
4383
|
+
|
|
4384
|
+
.pp-popup__chevron {
|
|
4385
|
+
color: var(--pp-text-muted);
|
|
4386
|
+
transition: transform 0.15s ease;
|
|
4387
|
+
display: flex;
|
|
4388
|
+
align-items: center;
|
|
4389
|
+
flex-shrink: 0;
|
|
4390
|
+
transform: rotate(-90deg);
|
|
4391
|
+
}
|
|
4392
|
+
|
|
4393
|
+
.pp-popup__chevron--open {
|
|
4394
|
+
transform: rotate(0deg);
|
|
4395
|
+
}
|
|
4396
|
+
|
|
4397
|
+
/* CSS-based collapsible \u2014 keeps DOM, animates height */
|
|
4398
|
+
.pp-popup__details {
|
|
4399
|
+
display: grid;
|
|
4400
|
+
grid-template-rows: 0fr;
|
|
4401
|
+
transition: grid-template-rows 0.2s ease-out;
|
|
4402
|
+
}
|
|
4403
|
+
|
|
4404
|
+
.pp-popup__details--open {
|
|
4405
|
+
grid-template-rows: 1fr;
|
|
4406
|
+
}
|
|
4407
|
+
|
|
4408
|
+
.pp-popup__details-inner {
|
|
4409
|
+
overflow: hidden;
|
|
4410
|
+
display: flex;
|
|
4411
|
+
flex-direction: column;
|
|
4412
|
+
gap: 3px;
|
|
4413
|
+
}
|
|
4414
|
+
|
|
4415
|
+
@media (prefers-reduced-motion: reduce) {
|
|
4416
|
+
.pp-popup__chevron,
|
|
4417
|
+
.pp-popup__details {
|
|
4418
|
+
transition: none;
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
|
|
4422
|
+
.pp-popup__textarea {
|
|
4423
|
+
width: 100%;
|
|
4424
|
+
min-height: 48px;
|
|
4425
|
+
max-height: 120px;
|
|
4426
|
+
padding: 8px;
|
|
4427
|
+
border: 1px solid var(--pp-border);
|
|
4428
|
+
border-radius: var(--pp-radius-sm);
|
|
4429
|
+
background: rgba(0, 0, 0, 0.2);
|
|
4430
|
+
color: var(--pp-text);
|
|
4431
|
+
font-size: 13px;
|
|
4432
|
+
font-family: inherit;
|
|
4433
|
+
resize: none;
|
|
4434
|
+
overflow-y: auto;
|
|
4435
|
+
outline: none;
|
|
4436
|
+
}
|
|
4437
|
+
|
|
4438
|
+
.pp-popup__textarea:focus {
|
|
4439
|
+
border-color: var(--pp-accent);
|
|
4440
|
+
}
|
|
4441
|
+
|
|
4442
|
+
.pp-popup__actions {
|
|
4443
|
+
display: flex;
|
|
4444
|
+
gap: 6px;
|
|
4445
|
+
justify-content: flex-end;
|
|
4446
|
+
}
|
|
4447
|
+
|
|
4448
|
+
.pp-popup__actions .pp-btn {
|
|
4449
|
+
height: 26px;
|
|
4450
|
+
padding: 0 10px;
|
|
4451
|
+
font-size: 12px;
|
|
4452
|
+
}
|
|
4453
|
+
|
|
4454
|
+
/* Selection label */
|
|
4455
|
+
.pp-selection-label {
|
|
4456
|
+
position: fixed;
|
|
4457
|
+
z-index: 2147483646;
|
|
4458
|
+
pointer-events: none;
|
|
4459
|
+
padding: 3px 8px;
|
|
4460
|
+
border-radius: 4px;
|
|
4461
|
+
background: var(--pp-accent);
|
|
4462
|
+
color: #fff;
|
|
4463
|
+
font-size: 11px;
|
|
4464
|
+
font-weight: 500;
|
|
4465
|
+
white-space: nowrap;
|
|
4466
|
+
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
|
|
4467
|
+
}
|
|
4468
|
+
|
|
4469
|
+
/* Context menu */
|
|
4470
|
+
.pp-context-menu {
|
|
4471
|
+
position: fixed;
|
|
4472
|
+
z-index: 2147483647;
|
|
4473
|
+
pointer-events: auto;
|
|
4474
|
+
background: var(--pp-bg-solid);
|
|
4475
|
+
border: 1px solid var(--pp-border);
|
|
4476
|
+
border-radius: var(--pp-radius-sm);
|
|
4477
|
+
box-shadow: var(--pp-shadow);
|
|
4478
|
+
padding: 4px;
|
|
4479
|
+
min-width: 180px;
|
|
4480
|
+
}
|
|
4481
|
+
|
|
4482
|
+
.pp-context-menu__item {
|
|
4483
|
+
display: flex;
|
|
4484
|
+
align-items: center;
|
|
4485
|
+
gap: 8px;
|
|
4486
|
+
padding: 6px 8px;
|
|
4487
|
+
border-radius: 4px;
|
|
4488
|
+
cursor: pointer;
|
|
4489
|
+
font-size: 12px;
|
|
4490
|
+
color: var(--pp-text);
|
|
4491
|
+
transition: background 0.1s;
|
|
4492
|
+
}
|
|
4493
|
+
|
|
4494
|
+
.pp-context-menu__item:hover {
|
|
4495
|
+
background: rgba(255, 255, 255, 0.06);
|
|
4496
|
+
}
|
|
4497
|
+
|
|
4498
|
+
.pp-context-menu__separator {
|
|
4499
|
+
height: 1px;
|
|
4500
|
+
background: var(--pp-border);
|
|
4501
|
+
margin: 4px 0;
|
|
4502
|
+
}
|
|
4503
|
+
|
|
4504
|
+
/* Prompt mode */
|
|
4505
|
+
.pp-prompt {
|
|
4506
|
+
position: fixed;
|
|
4507
|
+
z-index: 2147483647;
|
|
4508
|
+
pointer-events: auto;
|
|
4509
|
+
display: flex;
|
|
4510
|
+
gap: 6px;
|
|
4511
|
+
align-items: center;
|
|
4512
|
+
}
|
|
4513
|
+
|
|
4514
|
+
.pp-prompt__input {
|
|
4515
|
+
padding: 6px 10px;
|
|
4516
|
+
border: 1px solid var(--pp-accent);
|
|
4517
|
+
border-radius: var(--pp-radius-sm);
|
|
4518
|
+
background: var(--pp-bg);
|
|
4519
|
+
color: var(--pp-text);
|
|
4520
|
+
font-size: 13px;
|
|
4521
|
+
font-family: inherit;
|
|
4522
|
+
min-width: 240px;
|
|
4523
|
+
outline: none;
|
|
4524
|
+
backdrop-filter: blur(12px) saturate(180%);
|
|
4525
|
+
}
|
|
4526
|
+
|
|
4527
|
+
/* Settings panel */
|
|
4528
|
+
.pp-settings {
|
|
4529
|
+
display: flex;
|
|
4530
|
+
flex-direction: column;
|
|
4531
|
+
gap: 8px;
|
|
4532
|
+
padding-top: 8px;
|
|
4533
|
+
border-top: 1px solid var(--pp-border);
|
|
4534
|
+
}
|
|
4535
|
+
|
|
4536
|
+
.pp-settings__row {
|
|
4537
|
+
display: flex;
|
|
4538
|
+
align-items: center;
|
|
4539
|
+
justify-content: space-between;
|
|
4540
|
+
gap: 8px;
|
|
4541
|
+
}
|
|
4542
|
+
|
|
4543
|
+
.pp-settings__label {
|
|
4544
|
+
font-size: 12px;
|
|
4545
|
+
color: var(--pp-text);
|
|
4546
|
+
}
|
|
4547
|
+
|
|
4548
|
+
.pp-settings__value {
|
|
4549
|
+
font-size: 11px;
|
|
4550
|
+
color: var(--pp-text-muted);
|
|
4551
|
+
}
|
|
4552
|
+
|
|
4553
|
+
/* Toggle switch */
|
|
4554
|
+
.pp-toggle {
|
|
4555
|
+
position: relative;
|
|
4556
|
+
width: 32px;
|
|
4557
|
+
height: 18px;
|
|
4558
|
+
border-radius: 9px;
|
|
4559
|
+
background: var(--pp-border);
|
|
4560
|
+
cursor: pointer;
|
|
4561
|
+
transition: background 0.2s;
|
|
4562
|
+
}
|
|
4563
|
+
|
|
4564
|
+
.pp-toggle--active {
|
|
4565
|
+
background: var(--pp-accent);
|
|
4566
|
+
}
|
|
4567
|
+
|
|
4568
|
+
.pp-toggle__thumb {
|
|
4569
|
+
position: absolute;
|
|
4570
|
+
top: 2px;
|
|
4571
|
+
left: 2px;
|
|
4572
|
+
width: 14px;
|
|
4573
|
+
height: 14px;
|
|
4574
|
+
border-radius: 50%;
|
|
4575
|
+
background: #fff;
|
|
4576
|
+
transition: transform 0.2s;
|
|
4577
|
+
}
|
|
4578
|
+
|
|
4579
|
+
.pp-toggle--active .pp-toggle__thumb {
|
|
4580
|
+
transform: translateX(14px);
|
|
4581
|
+
}
|
|
4582
|
+
|
|
4583
|
+
/* Kbd hints */
|
|
4584
|
+
.pp-kbd {
|
|
4585
|
+
display: inline-flex;
|
|
4586
|
+
align-items: center;
|
|
4587
|
+
justify-content: center;
|
|
4588
|
+
padding: 1px 4px;
|
|
4589
|
+
border: 1px solid var(--pp-border);
|
|
4590
|
+
border-radius: 3px;
|
|
4591
|
+
background: rgba(255, 255, 255, 0.04);
|
|
4592
|
+
font-size: 10px;
|
|
4593
|
+
font-family: inherit;
|
|
4594
|
+
color: var(--pp-text-muted);
|
|
4595
|
+
line-height: 1;
|
|
4596
|
+
}
|
|
4597
|
+
|
|
4598
|
+
/* Mode tabs */
|
|
4599
|
+
.pp-mode-tabs {
|
|
4600
|
+
display: flex;
|
|
4601
|
+
gap: 2px;
|
|
4602
|
+
padding: 2px;
|
|
4603
|
+
background: rgba(255, 255, 255, 0.04);
|
|
4604
|
+
border-radius: var(--pp-radius-sm);
|
|
4605
|
+
}
|
|
4606
|
+
|
|
4607
|
+
.pp-mode-tab {
|
|
4608
|
+
flex: 1;
|
|
4609
|
+
display: flex;
|
|
4610
|
+
align-items: center;
|
|
4611
|
+
justify-content: center;
|
|
4612
|
+
gap: 4px;
|
|
4613
|
+
padding: 5px 8px;
|
|
4614
|
+
border: none;
|
|
4615
|
+
border-radius: 4px;
|
|
4616
|
+
background: transparent;
|
|
4617
|
+
color: var(--pp-text-muted);
|
|
4618
|
+
font-size: 11px;
|
|
4619
|
+
font-weight: 500;
|
|
4620
|
+
cursor: pointer;
|
|
4621
|
+
white-space: nowrap;
|
|
4622
|
+
}
|
|
4623
|
+
|
|
4624
|
+
.pp-mode-tab:hover {
|
|
4625
|
+
color: var(--pp-text);
|
|
4626
|
+
background: rgba(255, 255, 255, 0.04);
|
|
4627
|
+
}
|
|
4628
|
+
|
|
4629
|
+
.pp-mode-tab--active {
|
|
4630
|
+
background: rgba(255, 255, 255, 0.08);
|
|
4631
|
+
color: var(--pp-text);
|
|
4632
|
+
}
|
|
4633
|
+
|
|
4634
|
+
.pp-mode-tab__count {
|
|
4635
|
+
display: inline-flex;
|
|
4636
|
+
align-items: center;
|
|
4637
|
+
justify-content: center;
|
|
4638
|
+
min-width: 16px;
|
|
4639
|
+
height: 16px;
|
|
4640
|
+
padding: 0 4px;
|
|
4641
|
+
border-radius: 8px;
|
|
4642
|
+
background: var(--pp-accent);
|
|
4643
|
+
color: #fff;
|
|
4644
|
+
font-size: 10px;
|
|
4645
|
+
font-weight: 600;
|
|
4646
|
+
}
|
|
4647
|
+
|
|
4648
|
+
/* Draw tools bar */
|
|
4649
|
+
.pp-draw-tools {
|
|
4650
|
+
display: flex;
|
|
4651
|
+
align-items: center;
|
|
4652
|
+
gap: 2px;
|
|
4653
|
+
}
|
|
4654
|
+
|
|
4655
|
+
.pp-draw-tool {
|
|
4656
|
+
display: flex;
|
|
4657
|
+
align-items: center;
|
|
4658
|
+
justify-content: center;
|
|
4659
|
+
width: 32px;
|
|
4660
|
+
height: 32px;
|
|
4661
|
+
border: none;
|
|
4662
|
+
border-radius: var(--pp-radius-sm);
|
|
4663
|
+
background: transparent;
|
|
4664
|
+
color: var(--pp-text-muted);
|
|
4665
|
+
cursor: pointer;
|
|
4666
|
+
}
|
|
4667
|
+
|
|
4668
|
+
.pp-draw-tool:hover {
|
|
4669
|
+
background: rgba(255, 255, 255, 0.06);
|
|
4670
|
+
color: var(--pp-text);
|
|
4671
|
+
}
|
|
4672
|
+
|
|
4673
|
+
.pp-draw-tool--active {
|
|
4674
|
+
background: rgba(59, 130, 246, 0.15);
|
|
4675
|
+
color: var(--pp-accent);
|
|
4676
|
+
}
|
|
4677
|
+
|
|
4678
|
+
.pp-draw-tool:disabled {
|
|
4679
|
+
opacity: 0.3;
|
|
4680
|
+
cursor: default;
|
|
4681
|
+
}
|
|
4682
|
+
|
|
4683
|
+
/* Draw options row */
|
|
4684
|
+
.pp-draw-options {
|
|
4685
|
+
display: flex;
|
|
4686
|
+
align-items: center;
|
|
4687
|
+
justify-content: space-between;
|
|
4688
|
+
gap: 8px;
|
|
4689
|
+
}
|
|
4690
|
+
|
|
4691
|
+
.pp-draw-colors {
|
|
4692
|
+
display: flex;
|
|
4693
|
+
gap: 4px;
|
|
4694
|
+
}
|
|
4695
|
+
|
|
4696
|
+
.pp-color-swatch {
|
|
4697
|
+
width: 20px;
|
|
4698
|
+
height: 20px;
|
|
4699
|
+
border-radius: 50%;
|
|
4700
|
+
border: 2px solid transparent;
|
|
4701
|
+
cursor: pointer;
|
|
4702
|
+
padding: 0;
|
|
4703
|
+
}
|
|
4704
|
+
|
|
4705
|
+
.pp-color-swatch:hover {
|
|
4706
|
+
opacity: 0.85;
|
|
4707
|
+
}
|
|
4708
|
+
|
|
4709
|
+
.pp-color-swatch--active {
|
|
4710
|
+
border-color: #fff;
|
|
4711
|
+
box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.3);
|
|
4712
|
+
}
|
|
4713
|
+
|
|
4714
|
+
.pp-draw-widths {
|
|
4715
|
+
display: flex;
|
|
4716
|
+
gap: 4px;
|
|
4717
|
+
}
|
|
4718
|
+
|
|
4719
|
+
.pp-width-btn {
|
|
4720
|
+
display: flex;
|
|
4721
|
+
align-items: center;
|
|
4722
|
+
justify-content: center;
|
|
4723
|
+
width: 28px;
|
|
4724
|
+
height: 28px;
|
|
4725
|
+
border: none;
|
|
4726
|
+
border-radius: var(--pp-radius-sm);
|
|
4727
|
+
background: transparent;
|
|
4728
|
+
cursor: pointer;
|
|
4729
|
+
padding: 0;
|
|
4730
|
+
}
|
|
4731
|
+
|
|
4732
|
+
.pp-width-btn:hover {
|
|
4733
|
+
background: rgba(255, 255, 255, 0.06);
|
|
4734
|
+
}
|
|
4735
|
+
|
|
4736
|
+
.pp-width-btn--active {
|
|
4737
|
+
background: rgba(255, 255, 255, 0.1);
|
|
4738
|
+
outline: 1px solid var(--pp-border);
|
|
4739
|
+
}
|
|
4740
|
+
|
|
4741
|
+
/* Queue badge in toolbar header */
|
|
4742
|
+
.pp-toolbar__queue-badge {
|
|
4743
|
+
display: inline-flex;
|
|
4744
|
+
align-items: center;
|
|
4745
|
+
justify-content: center;
|
|
4746
|
+
min-width: 18px;
|
|
4747
|
+
height: 18px;
|
|
4748
|
+
padding: 0 5px;
|
|
4749
|
+
border-radius: 9px;
|
|
4750
|
+
background: var(--pp-warning);
|
|
4751
|
+
color: #000;
|
|
4752
|
+
font-size: 10px;
|
|
4753
|
+
font-weight: 700;
|
|
4754
|
+
}
|
|
4755
|
+
|
|
4756
|
+
/* Popup input row with mic */
|
|
4757
|
+
.pp-popup__input-row {
|
|
4758
|
+
position: relative;
|
|
4759
|
+
display: flex;
|
|
4760
|
+
align-items: flex-start;
|
|
4761
|
+
gap: 4px;
|
|
4762
|
+
}
|
|
4763
|
+
|
|
4764
|
+
.pp-popup__input-row .pp-popup__textarea {
|
|
4765
|
+
flex: 1;
|
|
4766
|
+
}
|
|
4767
|
+
|
|
4768
|
+
.pp-popup__mic {
|
|
4769
|
+
flex-shrink: 0;
|
|
4770
|
+
width: 32px;
|
|
4771
|
+
height: 32px;
|
|
4772
|
+
display: flex;
|
|
4773
|
+
align-items: center;
|
|
4774
|
+
justify-content: center;
|
|
4775
|
+
border-radius: 50%;
|
|
4776
|
+
margin-top: 4px;
|
|
4777
|
+
}
|
|
4778
|
+
|
|
4779
|
+
.pp-popup__mic--recording {
|
|
4780
|
+
color: var(--pp-danger) !important;
|
|
4781
|
+
background: rgba(239, 68, 68, 0.15) !important;
|
|
4782
|
+
animation: pp-mic-pulse 1.2s ease-in-out infinite;
|
|
4783
|
+
}
|
|
4784
|
+
|
|
4785
|
+
@keyframes pp-mic-pulse {
|
|
4786
|
+
0%, 100% { box-shadow: 0 0 0 0 rgba(239, 68, 68, 0.4); }
|
|
4787
|
+
50% { box-shadow: 0 0 0 6px rgba(239, 68, 68, 0); }
|
|
4788
|
+
}
|
|
4789
|
+
|
|
4790
|
+
/* Ghost button (Fix this) */
|
|
4791
|
+
.pp-btn--ghost {
|
|
4792
|
+
display: inline-flex;
|
|
4793
|
+
align-items: center;
|
|
4794
|
+
gap: 4px;
|
|
4795
|
+
padding: 3px 8px;
|
|
4796
|
+
border: none;
|
|
4797
|
+
border-radius: var(--pp-radius-sm);
|
|
4798
|
+
background: transparent;
|
|
4799
|
+
color: var(--pp-warning);
|
|
4800
|
+
font-size: 11px;
|
|
4801
|
+
font-weight: 500;
|
|
4802
|
+
cursor: pointer;
|
|
4803
|
+
}
|
|
4804
|
+
|
|
4805
|
+
.pp-btn--ghost:hover {
|
|
4806
|
+
background: rgba(234, 179, 8, 0.1);
|
|
4807
|
+
}
|
|
4808
|
+
|
|
4809
|
+
/* Text input popup for draw-mode text annotations */
|
|
4810
|
+
.pp-text-input-popup {
|
|
4811
|
+
position: fixed;
|
|
4812
|
+
z-index: 2147483647;
|
|
4813
|
+
pointer-events: auto;
|
|
4814
|
+
display: flex;
|
|
4815
|
+
align-items: center;
|
|
4816
|
+
gap: 6px;
|
|
4817
|
+
padding: 4px 8px;
|
|
4818
|
+
background: var(--pp-bg);
|
|
4819
|
+
border: 1px solid var(--pp-border);
|
|
4820
|
+
border-radius: var(--pp-radius-sm);
|
|
4821
|
+
box-shadow: var(--pp-shadow);
|
|
4822
|
+
backdrop-filter: blur(12px) saturate(180%);
|
|
4823
|
+
-webkit-backdrop-filter: blur(12px) saturate(180%);
|
|
4824
|
+
}
|
|
4825
|
+
|
|
4826
|
+
.pp-text-input-popup__indicator {
|
|
4827
|
+
width: 8px;
|
|
4828
|
+
height: 8px;
|
|
4829
|
+
border-radius: 50%;
|
|
4830
|
+
flex-shrink: 0;
|
|
4831
|
+
}
|
|
4832
|
+
|
|
4833
|
+
.pp-text-input-popup__input {
|
|
4834
|
+
border: none;
|
|
4835
|
+
background: transparent;
|
|
4836
|
+
color: var(--pp-text);
|
|
4837
|
+
font-size: 13px;
|
|
4838
|
+
font-family: inherit;
|
|
4839
|
+
outline: none;
|
|
4840
|
+
min-width: 200px;
|
|
4841
|
+
}
|
|
4842
|
+
|
|
4843
|
+
/* Scrollbar */
|
|
4844
|
+
::-webkit-scrollbar {
|
|
4845
|
+
width: 4px;
|
|
4846
|
+
}
|
|
4847
|
+
|
|
4848
|
+
::-webkit-scrollbar-track {
|
|
4849
|
+
background: transparent;
|
|
4850
|
+
}
|
|
4851
|
+
|
|
4852
|
+
::-webkit-scrollbar-thumb {
|
|
4853
|
+
background: var(--pp-border);
|
|
4854
|
+
border-radius: 2px;
|
|
4855
|
+
}
|
|
4856
|
+
`;
|
|
4857
|
+
|
|
4858
|
+
// src/ui/mount.ts
|
|
4859
|
+
var CONTAINER_ID = "pinpoint-root";
|
|
4860
|
+
function mountPinpoint(config = {}, target = document.body) {
|
|
4861
|
+
const w = window;
|
|
4862
|
+
w.__pinpoint_instances = (w.__pinpoint_instances || 0) + 1;
|
|
4863
|
+
if (w.__pinpoint_instances > 1) {
|
|
4864
|
+
const existing = document.getElementById(CONTAINER_ID);
|
|
4865
|
+
if (existing) {
|
|
4866
|
+
existing.remove();
|
|
4867
|
+
}
|
|
4868
|
+
w.__pinpoint_instances = 1;
|
|
4869
|
+
}
|
|
4870
|
+
const container = document.createElement("div");
|
|
4871
|
+
container.id = CONTAINER_ID;
|
|
4872
|
+
container.style.cssText = "position:fixed;top:0;left:0;width:0;height:0;z-index:2147483647;pointer-events:none;";
|
|
4873
|
+
target.appendChild(container);
|
|
4874
|
+
const shadowRoot = container.attachShadow({ mode: "open" });
|
|
4875
|
+
const sheet = new CSSStyleSheet();
|
|
4876
|
+
sheet.replaceSync(overlayStyles);
|
|
4877
|
+
shadowRoot.adoptedStyleSheets = [sheet];
|
|
4878
|
+
const theme = resolveColorScheme(config.colorScheme || "auto");
|
|
4879
|
+
if (theme === "light") {
|
|
4880
|
+
container.setAttribute("data-theme", "light");
|
|
4881
|
+
}
|
|
4882
|
+
const solidDispose = render(() => PinpointApp({ config }), shadowRoot);
|
|
4883
|
+
const dispose2 = () => {
|
|
4884
|
+
solidDispose();
|
|
4885
|
+
container.remove();
|
|
4886
|
+
w.__pinpoint_instances = Math.max(0, (w.__pinpoint_instances || 1) - 1);
|
|
4887
|
+
};
|
|
4888
|
+
if (import.meta.hot) {
|
|
4889
|
+
import.meta.hot.dispose(dispose2);
|
|
4890
|
+
}
|
|
4891
|
+
return { dispose: dispose2, shadowRoot, container };
|
|
4892
|
+
}
|
|
4893
|
+
function unmountPinpoint() {
|
|
4894
|
+
const container = document.getElementById(CONTAINER_ID);
|
|
4895
|
+
if (container) {
|
|
4896
|
+
container.remove();
|
|
4897
|
+
window.__pinpoint_instances = 0;
|
|
4898
|
+
}
|
|
4899
|
+
}
|
|
4900
|
+
function resolveColorScheme(scheme) {
|
|
4901
|
+
if (scheme === "auto") {
|
|
4902
|
+
return window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light";
|
|
4903
|
+
}
|
|
4904
|
+
return scheme;
|
|
4905
|
+
}
|
|
4906
|
+
|
|
4907
|
+
export {
|
|
4908
|
+
MemoryStore,
|
|
4909
|
+
ElementInfoSchema,
|
|
4910
|
+
FrameworkInfoSchema,
|
|
4911
|
+
PinSchema,
|
|
4912
|
+
RestClient,
|
|
4913
|
+
ElementPicker,
|
|
4914
|
+
buildSelector,
|
|
4915
|
+
extractElementInfo,
|
|
4916
|
+
buildElementContext,
|
|
4917
|
+
DragSelect,
|
|
4918
|
+
TextSelect,
|
|
4919
|
+
registerAdapter,
|
|
4920
|
+
detectFramework,
|
|
4921
|
+
getComponentInfo,
|
|
4922
|
+
getSourceLocation,
|
|
4923
|
+
PinMarkerManager,
|
|
4924
|
+
mountPinpoint,
|
|
4925
|
+
unmountPinpoint
|
|
4926
|
+
};
|
|
4927
|
+
//# sourceMappingURL=chunk-ZW7IO3EW.js.map
|