@merittdev/horus-lens 0.3.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser.cjs +440 -185
- package/dist/browser.cjs.map +1 -1
- package/dist/browser.d.cts +1 -1
- package/dist/browser.d.ts +1 -1
- package/dist/browser.js +2 -2
- package/dist/{chunk-LIYEDZV7.js → chunk-2G5FEWPU.js} +76 -16
- package/dist/{chunk-LIYEDZV7.js.map → chunk-2G5FEWPU.js.map} +1 -1
- package/dist/{chunk-PNY6BL4C.js → chunk-M3QMIY4Y.js} +367 -172
- package/dist/chunk-M3QMIY4Y.js.map +1 -0
- package/dist/cli.cjs +353 -0
- package/dist/cli.cjs.map +1 -0
- package/dist/index.cjs +75 -15
- package/dist/index.cjs.map +1 -1
- package/dist/{index.d-Dyzc1E9T.d.ts → index.d-BYuZWEkh.d.ts} +7 -0
- package/dist/{index.d-BYG_Mjs-.d.cts → index.d-DeJ1mfh0.d.cts} +7 -0
- package/dist/index.d.cts +7 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +1 -1
- package/dist/lens.min.js +204 -130
- package/dist/react.cjs +440 -185
- package/dist/react.cjs.map +1 -1
- package/dist/react.d.cts +1 -1
- package/dist/react.d.ts +1 -1
- package/dist/react.js +2 -2
- package/package.json +10 -4
- package/dist/chunk-PNY6BL4C.js.map +0 -1
- package/dist/lens.min.js.map +0 -1
package/dist/browser.cjs
CHANGED
|
@@ -29082,7 +29082,7 @@ var ApiErrorSchema = external_exports.object({
|
|
|
29082
29082
|
|
|
29083
29083
|
// ../core/dist/index.js
|
|
29084
29084
|
var SDK_NAME = "@merittdev/horus-lens";
|
|
29085
|
-
var SDK_VERSION = true ? "0.
|
|
29085
|
+
var SDK_VERSION = true ? "0.5.0" : "0.0.0-dev";
|
|
29086
29086
|
var DEFAULT_ENDPOINT = "https://api.horus.sh";
|
|
29087
29087
|
var DEFAULT_REPLAY_WINDOW_MS = 15e3;
|
|
29088
29088
|
var DEFAULT_MAX_CONSOLE_ENTRIES = 200;
|
|
@@ -29143,11 +29143,15 @@ function startAutoCapture(client, options = {}) {
|
|
|
29143
29143
|
const last = lastSeen.get(signature);
|
|
29144
29144
|
if (last !== void 0 && now - last < AUTO_CAPTURE_COOLDOWN_MS) return;
|
|
29145
29145
|
if (sessionCount >= AUTO_CAPTURE_SESSION_CAP) return;
|
|
29146
|
+
const previousSeen = lastSeen.get(signature);
|
|
29146
29147
|
lastSeen.set(signature, now);
|
|
29147
29148
|
sessionCount += 1;
|
|
29148
29149
|
submitting = true;
|
|
29149
29150
|
options.onCapture?.(signature);
|
|
29150
29151
|
void Promise.resolve().then(() => client.submitReport({ trigger: "error", include: { screenshot: false } })).catch(() => {
|
|
29152
|
+
if (previousSeen === void 0) lastSeen.delete(signature);
|
|
29153
|
+
else lastSeen.set(signature, previousSeen);
|
|
29154
|
+
sessionCount -= 1;
|
|
29151
29155
|
}).finally(() => {
|
|
29152
29156
|
submitting = false;
|
|
29153
29157
|
});
|
|
@@ -29202,6 +29206,14 @@ var RingBuffer = class {
|
|
|
29202
29206
|
return this.items.length;
|
|
29203
29207
|
}
|
|
29204
29208
|
};
|
|
29209
|
+
var HttpError = class extends Error {
|
|
29210
|
+
constructor(status, message) {
|
|
29211
|
+
super(message);
|
|
29212
|
+
this.status = status;
|
|
29213
|
+
this.name = "HttpError";
|
|
29214
|
+
}
|
|
29215
|
+
status;
|
|
29216
|
+
};
|
|
29205
29217
|
var Transport = class {
|
|
29206
29218
|
constructor(config2) {
|
|
29207
29219
|
this.config = config2;
|
|
@@ -29209,18 +29221,23 @@ var Transport = class {
|
|
|
29209
29221
|
config;
|
|
29210
29222
|
async initiate(assets) {
|
|
29211
29223
|
const body = { accessId: this.config.accessId, assets };
|
|
29212
|
-
return this.postJson(
|
|
29224
|
+
return this.postJson(
|
|
29225
|
+
`${this.config.endpoint}/v1/reports/initiate`,
|
|
29226
|
+
body,
|
|
29227
|
+
{ retries: 0 }
|
|
29228
|
+
);
|
|
29213
29229
|
}
|
|
29214
29230
|
/** Record a late-uploaded asset (background screenshot) on a finalized report. */
|
|
29215
29231
|
async attachAsset(reportId, asset) {
|
|
29216
29232
|
const body = { accessId: this.config.accessId, ...asset };
|
|
29217
29233
|
await this.postJson(`${this.config.endpoint}/v1/reports/${encodeURIComponent(reportId)}/assets`, body);
|
|
29218
29234
|
}
|
|
29219
|
-
async uploadAsset(upload, blob2) {
|
|
29235
|
+
async uploadAsset(upload, blob2, signal) {
|
|
29220
29236
|
const response = await fetch(upload.url, {
|
|
29221
29237
|
method: upload.method,
|
|
29222
29238
|
headers: upload.headers,
|
|
29223
|
-
body: blob2
|
|
29239
|
+
body: blob2,
|
|
29240
|
+
signal
|
|
29224
29241
|
});
|
|
29225
29242
|
if (!response.ok) {
|
|
29226
29243
|
throw new Error(`Asset upload failed (${upload.kind}): ${response.status}`);
|
|
@@ -29228,12 +29245,20 @@ var Transport = class {
|
|
|
29228
29245
|
}
|
|
29229
29246
|
async finalize(reportId, metadata, uploadedAssets) {
|
|
29230
29247
|
const body = { accessId: this.config.accessId, metadata, uploadedAssets };
|
|
29231
|
-
|
|
29232
|
-
|
|
29233
|
-
|
|
29234
|
-
|
|
29248
|
+
try {
|
|
29249
|
+
return await this.postJson(
|
|
29250
|
+
`${this.config.endpoint}/v1/reports/${reportId}/finalize`,
|
|
29251
|
+
body
|
|
29252
|
+
);
|
|
29253
|
+
} catch (err) {
|
|
29254
|
+
if (err instanceof HttpError && err.status === 409) {
|
|
29255
|
+
return { reportId, status: "submitted" };
|
|
29256
|
+
}
|
|
29257
|
+
throw err;
|
|
29258
|
+
}
|
|
29235
29259
|
}
|
|
29236
|
-
async postJson(url2, body,
|
|
29260
|
+
async postJson(url2, body, opts = {}) {
|
|
29261
|
+
const retries = opts.retries ?? 1;
|
|
29237
29262
|
let lastError;
|
|
29238
29263
|
for (let attempt = 0; attempt <= retries; attempt++) {
|
|
29239
29264
|
try {
|
|
@@ -29244,7 +29269,10 @@ var Transport = class {
|
|
|
29244
29269
|
});
|
|
29245
29270
|
if (!response.ok) {
|
|
29246
29271
|
const text = await response.text().catch(() => "");
|
|
29247
|
-
throw new
|
|
29272
|
+
throw new HttpError(
|
|
29273
|
+
response.status,
|
|
29274
|
+
`Request to ${url2} failed: ${response.status} ${text}`.trim()
|
|
29275
|
+
);
|
|
29248
29276
|
}
|
|
29249
29277
|
return await response.json();
|
|
29250
29278
|
} catch (err) {
|
|
@@ -29685,8 +29713,14 @@ async function captureScreenshot(excludeHost, crop, composite) {
|
|
|
29685
29713
|
return null;
|
|
29686
29714
|
}
|
|
29687
29715
|
}
|
|
29688
|
-
|
|
29689
|
-
|
|
29716
|
+
const effectiveCrop = crop ?? (composite ? void 0 : {
|
|
29717
|
+
x: window.scrollX,
|
|
29718
|
+
y: window.scrollY,
|
|
29719
|
+
width: window.innerWidth,
|
|
29720
|
+
height: window.innerHeight
|
|
29721
|
+
});
|
|
29722
|
+
if (effectiveCrop) {
|
|
29723
|
+
const cropped = await cropBlob(blob2, effectiveCrop, scale);
|
|
29690
29724
|
return cropped ?? blob2;
|
|
29691
29725
|
}
|
|
29692
29726
|
return blob2;
|
|
@@ -30120,12 +30154,22 @@ var LensClient = class {
|
|
|
30120
30154
|
input2.screenshotCrop,
|
|
30121
30155
|
input2.annotationComposite
|
|
30122
30156
|
) : Promise.resolve(null);
|
|
30157
|
+
const consumingManualRecording = wantReplay && (this.replay?.hasManualRecording() ?? false) && !(this.replay?.isManualRecording() ?? false);
|
|
30123
30158
|
const replayEvents = wantReplay ? this.replay?.snapshot() ?? [] : [];
|
|
30124
30159
|
const errorEntries = this.errorBuffer.drain();
|
|
30125
|
-
const consoleTail = this.consoleBuffer.tail(CONSOLE_TAIL_SIZE);
|
|
30126
|
-
const networkTail = this.networkBuffer.tail(NETWORK_TAIL_SIZE);
|
|
30127
30160
|
const consoleEntries = this.consoleBuffer.drain();
|
|
30128
30161
|
const networkEntries = this.networkBuffer.drain();
|
|
30162
|
+
this.errorBuffer.clear();
|
|
30163
|
+
this.consoleBuffer.clear();
|
|
30164
|
+
this.networkBuffer.clear();
|
|
30165
|
+
const consoleTail = consoleEntries.slice(-CONSOLE_TAIL_SIZE);
|
|
30166
|
+
const isNetFailure = (e) => e.ok !== true || Boolean(e.error);
|
|
30167
|
+
const recentFailures = networkEntries.filter(isNetFailure).slice(-NETWORK_TAIL_SIZE);
|
|
30168
|
+
const keep = /* @__PURE__ */ new Set([
|
|
30169
|
+
...recentFailures,
|
|
30170
|
+
...networkEntries.slice(-NETWORK_TAIL_SIZE)
|
|
30171
|
+
]);
|
|
30172
|
+
const networkTail = networkEntries.filter((e) => keep.has(e)).slice(-NETWORK_TAIL_SIZE);
|
|
30129
30173
|
let metadata = {
|
|
30130
30174
|
annotations: input2.annotations ?? [],
|
|
30131
30175
|
env: collectEnv(),
|
|
@@ -30179,13 +30223,14 @@ var LensClient = class {
|
|
|
30179
30223
|
}
|
|
30180
30224
|
if (!asset.blob) continue;
|
|
30181
30225
|
try {
|
|
30182
|
-
await this.
|
|
30226
|
+
await this.uploadAssetWithTimeout(upload, asset.blob);
|
|
30183
30227
|
uploadedAssets.push({ kind: upload.kind, key: upload.key, byteSize: asset.blob.size });
|
|
30184
30228
|
} catch (err) {
|
|
30185
30229
|
this.warn(`asset upload failed (${upload.kind})`, err);
|
|
30186
30230
|
}
|
|
30187
30231
|
}
|
|
30188
30232
|
const finalized = await this.transport.finalize(initiated.reportId, metadata, uploadedAssets);
|
|
30233
|
+
if (consumingManualRecording) this.replay?.discardManualRecording();
|
|
30189
30234
|
if (screenshotUpload) {
|
|
30190
30235
|
const upload = screenshotUpload;
|
|
30191
30236
|
void screenshotPromise.then(async (blob2) => {
|
|
@@ -30203,6 +30248,21 @@ var LensClient = class {
|
|
|
30203
30248
|
}
|
|
30204
30249
|
return { reportId: finalized.reportId };
|
|
30205
30250
|
}
|
|
30251
|
+
/**
|
|
30252
|
+
* Upload a foreground asset with a bounded timeout. Without this a stuck S3
|
|
30253
|
+
* PUT (dropped connection, half-open socket) would hang `submitReport`
|
|
30254
|
+
* forever; the timeout aborts the individual PUT so it fails as one asset
|
|
30255
|
+
* (caught by the caller) instead of wedging the whole submit.
|
|
30256
|
+
*/
|
|
30257
|
+
async uploadAssetWithTimeout(upload, blob2) {
|
|
30258
|
+
const controller = new AbortController();
|
|
30259
|
+
const timer = setTimeout(() => controller.abort(), SCREENSHOT_TIMEOUT_MS);
|
|
30260
|
+
try {
|
|
30261
|
+
await this.transport.uploadAsset(upload, blob2, controller.signal);
|
|
30262
|
+
} finally {
|
|
30263
|
+
clearTimeout(timer);
|
|
30264
|
+
}
|
|
30265
|
+
}
|
|
30206
30266
|
warn(message, err) {
|
|
30207
30267
|
if (!this.debug) return;
|
|
30208
30268
|
if (err !== void 0) console.warn(`[lens] ${message}`, err);
|
|
@@ -30331,6 +30391,113 @@ function el(tag, props = {}, children = []) {
|
|
|
30331
30391
|
function clear(node2) {
|
|
30332
30392
|
while (node2.firstChild) node2.removeChild(node2.firstChild);
|
|
30333
30393
|
}
|
|
30394
|
+
var MARGIN = 6;
|
|
30395
|
+
var DRAG_THRESHOLD = 3;
|
|
30396
|
+
var savedPositions = /* @__PURE__ */ new Map();
|
|
30397
|
+
function isInteractiveTarget(target) {
|
|
30398
|
+
return target instanceof Element && target.closest(
|
|
30399
|
+
'button, a, input, textarea, select, [role="switch"], [role="button"], [contenteditable="true"]'
|
|
30400
|
+
) !== null;
|
|
30401
|
+
}
|
|
30402
|
+
function clampToViewport(element, left, top) {
|
|
30403
|
+
const rect = element.getBoundingClientRect();
|
|
30404
|
+
const vw = window.innerWidth;
|
|
30405
|
+
const vh = window.innerHeight;
|
|
30406
|
+
const maxLeft = Math.max(MARGIN, vw - rect.width - MARGIN);
|
|
30407
|
+
const maxTop = Math.max(MARGIN, vh - rect.height - MARGIN);
|
|
30408
|
+
return {
|
|
30409
|
+
left: Math.min(Math.max(left, MARGIN), maxLeft),
|
|
30410
|
+
top: Math.min(Math.max(top, MARGIN), maxTop)
|
|
30411
|
+
};
|
|
30412
|
+
}
|
|
30413
|
+
function makeDraggable(element, opts) {
|
|
30414
|
+
const { handle, key } = opts;
|
|
30415
|
+
const ignore = opts.ignore ?? isInteractiveTarget;
|
|
30416
|
+
let startX = 0;
|
|
30417
|
+
let startY = 0;
|
|
30418
|
+
let originLeft = 0;
|
|
30419
|
+
let originTop = 0;
|
|
30420
|
+
let dragging = false;
|
|
30421
|
+
let armed = false;
|
|
30422
|
+
let pointerId = null;
|
|
30423
|
+
const apply = (left, top) => {
|
|
30424
|
+
const p = clampToViewport(element, left, top);
|
|
30425
|
+
element.style.left = `${p.left}px`;
|
|
30426
|
+
element.style.top = `${p.top}px`;
|
|
30427
|
+
element.style.right = "auto";
|
|
30428
|
+
element.style.bottom = "auto";
|
|
30429
|
+
element.style.transform = "none";
|
|
30430
|
+
savedPositions.set(key, p);
|
|
30431
|
+
opts.onMove?.();
|
|
30432
|
+
};
|
|
30433
|
+
const onPointerDown = (e) => {
|
|
30434
|
+
if (e.button !== 0 && e.pointerType === "mouse") return;
|
|
30435
|
+
if (ignore(e.target)) return;
|
|
30436
|
+
armed = true;
|
|
30437
|
+
dragging = false;
|
|
30438
|
+
pointerId = e.pointerId;
|
|
30439
|
+
startX = e.clientX;
|
|
30440
|
+
startY = e.clientY;
|
|
30441
|
+
const rect = element.getBoundingClientRect();
|
|
30442
|
+
originLeft = rect.left;
|
|
30443
|
+
originTop = rect.top;
|
|
30444
|
+
window.addEventListener("pointermove", onPointerMove, true);
|
|
30445
|
+
window.addEventListener("pointerup", onPointerUp, true);
|
|
30446
|
+
window.addEventListener("pointercancel", onPointerUp, true);
|
|
30447
|
+
};
|
|
30448
|
+
const onPointerMove = (e) => {
|
|
30449
|
+
if (!armed || e.pointerId !== pointerId) return;
|
|
30450
|
+
const dx = e.clientX - startX;
|
|
30451
|
+
const dy = e.clientY - startY;
|
|
30452
|
+
if (!dragging) {
|
|
30453
|
+
if (Math.abs(dx) + Math.abs(dy) < DRAG_THRESHOLD) return;
|
|
30454
|
+
dragging = true;
|
|
30455
|
+
element.classList.add("is-dragging");
|
|
30456
|
+
}
|
|
30457
|
+
e.preventDefault();
|
|
30458
|
+
apply(originLeft + dx, originTop + dy);
|
|
30459
|
+
};
|
|
30460
|
+
const onPointerUp = (e) => {
|
|
30461
|
+
if (e.pointerId !== pointerId) return;
|
|
30462
|
+
armed = false;
|
|
30463
|
+
if (dragging) {
|
|
30464
|
+
dragging = false;
|
|
30465
|
+
element.classList.remove("is-dragging");
|
|
30466
|
+
}
|
|
30467
|
+
pointerId = null;
|
|
30468
|
+
window.removeEventListener("pointermove", onPointerMove, true);
|
|
30469
|
+
window.removeEventListener("pointerup", onPointerUp, true);
|
|
30470
|
+
window.removeEventListener("pointercancel", onPointerUp, true);
|
|
30471
|
+
};
|
|
30472
|
+
const onResize = () => {
|
|
30473
|
+
const p = savedPositions.get(key);
|
|
30474
|
+
if (p) apply(p.left, p.top);
|
|
30475
|
+
};
|
|
30476
|
+
handle.classList.add("lens-drag-handle");
|
|
30477
|
+
handle.addEventListener("pointerdown", onPointerDown);
|
|
30478
|
+
window.addEventListener("resize", onResize);
|
|
30479
|
+
const stored = savedPositions.get(key);
|
|
30480
|
+
if (stored) requestAnimationFrame(() => apply(stored.left, stored.top));
|
|
30481
|
+
return {
|
|
30482
|
+
reclamp: onResize,
|
|
30483
|
+
reset() {
|
|
30484
|
+
savedPositions.delete(key);
|
|
30485
|
+
element.style.left = "";
|
|
30486
|
+
element.style.top = "";
|
|
30487
|
+
element.style.right = "";
|
|
30488
|
+
element.style.bottom = "";
|
|
30489
|
+
element.style.transform = "";
|
|
30490
|
+
element.classList.remove("is-dragging");
|
|
30491
|
+
},
|
|
30492
|
+
destroy() {
|
|
30493
|
+
handle.removeEventListener("pointerdown", onPointerDown);
|
|
30494
|
+
window.removeEventListener("pointermove", onPointerMove, true);
|
|
30495
|
+
window.removeEventListener("pointerup", onPointerUp, true);
|
|
30496
|
+
window.removeEventListener("pointercancel", onPointerUp, true);
|
|
30497
|
+
window.removeEventListener("resize", onResize);
|
|
30498
|
+
}
|
|
30499
|
+
};
|
|
30500
|
+
}
|
|
30334
30501
|
var THIN_MIN_DIST = 3;
|
|
30335
30502
|
var MAX_POINTS = 2e3;
|
|
30336
30503
|
var HIGHLIGHTER_WIDTH = 14;
|
|
@@ -30481,6 +30648,8 @@ var iconTrash = svg(
|
|
|
30481
30648
|
'<polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>'
|
|
30482
30649
|
);
|
|
30483
30650
|
var iconAnnotate = iconPencil;
|
|
30651
|
+
var iconGrip = `<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="9" cy="6" r="1.6"/><circle cx="15" cy="6" r="1.6"/><circle cx="9" cy="12" r="1.6"/><circle cx="15" cy="12" r="1.6"/><circle cx="9" cy="18" r="1.6"/><circle cx="15" cy="18" r="1.6"/></svg>`;
|
|
30652
|
+
var iconReport = svg('<path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2Z"/>');
|
|
30484
30653
|
var SVG_NS = "http://www.w3.org/2000/svg";
|
|
30485
30654
|
var FONT = "-apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif";
|
|
30486
30655
|
var MIN_DRAG = 6;
|
|
@@ -30509,6 +30678,7 @@ var AnnotationEditor = class {
|
|
|
30509
30678
|
svg = null;
|
|
30510
30679
|
bg = null;
|
|
30511
30680
|
toolbar = null;
|
|
30681
|
+
toolbarDrag = null;
|
|
30512
30682
|
textInputEl = null;
|
|
30513
30683
|
textAnchor = null;
|
|
30514
30684
|
textColor = COLORS[0];
|
|
@@ -30554,6 +30724,7 @@ var AnnotationEditor = class {
|
|
|
30554
30724
|
this.markNodes = [];
|
|
30555
30725
|
this.annotations = [];
|
|
30556
30726
|
this.stepCounter = 0;
|
|
30727
|
+
this.sessionBase = Math.min(this.sessionBase, this.annotations.length);
|
|
30557
30728
|
if (!this.active) this.teardownLayer();
|
|
30558
30729
|
this.syncActionButtons();
|
|
30559
30730
|
}
|
|
@@ -30568,6 +30739,7 @@ var AnnotationEditor = class {
|
|
|
30568
30739
|
this.sizeLayer();
|
|
30569
30740
|
this.updateTransform();
|
|
30570
30741
|
svg2.style.pointerEvents = "auto";
|
|
30742
|
+
if (this.bg) this.bg.style.pointerEvents = "all";
|
|
30571
30743
|
svg2.style.touchAction = "none";
|
|
30572
30744
|
svg2.style.cursor = "crosshair";
|
|
30573
30745
|
svg2.addEventListener("pointerdown", this.onPointerDown);
|
|
@@ -30588,6 +30760,7 @@ var AnnotationEditor = class {
|
|
|
30588
30760
|
if (svg2) {
|
|
30589
30761
|
svg2.removeEventListener("pointerdown", this.onPointerDown);
|
|
30590
30762
|
svg2.style.pointerEvents = "none";
|
|
30763
|
+
if (this.bg) this.bg.style.pointerEvents = "none";
|
|
30591
30764
|
svg2.style.touchAction = "";
|
|
30592
30765
|
svg2.style.cursor = "";
|
|
30593
30766
|
}
|
|
@@ -30597,15 +30770,8 @@ var AnnotationEditor = class {
|
|
|
30597
30770
|
this.onExit = null;
|
|
30598
30771
|
cb?.();
|
|
30599
30772
|
}
|
|
30600
|
-
/** Cancel — discard marks drawn during this session, then exit. */
|
|
30601
|
-
cancel() {
|
|
30602
|
-
this.cancelTextInput();
|
|
30603
|
-
const removed = this.markNodes.splice(this.sessionBase);
|
|
30604
|
-
for (const node2 of removed) node2.remove();
|
|
30605
|
-
this.annotations.splice(this.sessionBase);
|
|
30606
|
-
this.exit();
|
|
30607
|
-
}
|
|
30608
30773
|
undo() {
|
|
30774
|
+
if (this.markNodes.length <= this.sessionBase) return;
|
|
30609
30775
|
const node2 = this.markNodes.pop();
|
|
30610
30776
|
if (!node2) return;
|
|
30611
30777
|
node2.remove();
|
|
@@ -30821,39 +30987,45 @@ var AnnotationEditor = class {
|
|
|
30821
30987
|
on: { click: () => this.clear() }
|
|
30822
30988
|
});
|
|
30823
30989
|
const editGroup = el("div", { class: "lens-tool-group" }, [this.undoBtn, this.clearBtn]);
|
|
30824
|
-
const
|
|
30825
|
-
|
|
30826
|
-
|
|
30827
|
-
|
|
30828
|
-
|
|
30829
|
-
|
|
30830
|
-
}
|
|
30831
|
-
|
|
30832
|
-
|
|
30833
|
-
|
|
30834
|
-
|
|
30835
|
-
|
|
30836
|
-
|
|
30990
|
+
const closeBtn = el("button", {
|
|
30991
|
+
class: "lens-tool-close",
|
|
30992
|
+
ariaLabel: "Done",
|
|
30993
|
+
title: "Done",
|
|
30994
|
+
html: iconClose,
|
|
30995
|
+
attrs: { type: "button" },
|
|
30996
|
+
on: { click: () => this.exit() }
|
|
30997
|
+
});
|
|
30998
|
+
const grip = el("span", {
|
|
30999
|
+
class: "lens-tool-grip",
|
|
31000
|
+
html: iconGrip,
|
|
31001
|
+
title: "Drag to move toolbar",
|
|
31002
|
+
ariaLabel: "Drag to move toolbar"
|
|
31003
|
+
});
|
|
31004
|
+
const track = el("div", { class: "lens-tool-track" }, [
|
|
31005
|
+
toolGroup,
|
|
31006
|
+
el("span", { class: "lens-tool-sep" }),
|
|
31007
|
+
colorGroup,
|
|
31008
|
+
el("span", { class: "lens-tool-sep" }),
|
|
31009
|
+
widthGroup,
|
|
31010
|
+
el("span", { class: "lens-tool-sep" }),
|
|
31011
|
+
editGroup
|
|
30837
31012
|
]);
|
|
30838
31013
|
this.toolbar = el(
|
|
30839
31014
|
"div",
|
|
30840
31015
|
{ class: "lens-annotate-toolbar", attrs: { role: "toolbar", "aria-label": "Annotation tools" } },
|
|
30841
|
-
[
|
|
30842
|
-
toolGroup,
|
|
30843
|
-
el("span", { class: "lens-tool-sep" }),
|
|
30844
|
-
colorGroup,
|
|
30845
|
-
el("span", { class: "lens-tool-sep" }),
|
|
30846
|
-
widthGroup,
|
|
30847
|
-
el("span", { class: "lens-tool-sep" }),
|
|
30848
|
-
editGroup,
|
|
30849
|
-
el("span", { class: "lens-tool-sep" }),
|
|
30850
|
-
doneGroup
|
|
30851
|
-
]
|
|
31016
|
+
[grip, track, closeBtn]
|
|
30852
31017
|
);
|
|
30853
31018
|
this.host.append(this.toolbar);
|
|
31019
|
+
this.toolbarDrag = makeDraggable(this.toolbar, {
|
|
31020
|
+
handle: grip,
|
|
31021
|
+
key: "lens-annotate-toolbar",
|
|
31022
|
+
ignore: isInteractiveTarget
|
|
31023
|
+
});
|
|
30854
31024
|
this.syncActionButtons();
|
|
30855
31025
|
}
|
|
30856
31026
|
removeToolbar() {
|
|
31027
|
+
this.toolbarDrag?.destroy();
|
|
31028
|
+
this.toolbarDrag = null;
|
|
30857
31029
|
this.toolbar?.remove();
|
|
30858
31030
|
this.toolbar = null;
|
|
30859
31031
|
this.toolBtns.clear();
|
|
@@ -30890,7 +31062,7 @@ var AnnotationEditor = class {
|
|
|
30890
31062
|
}
|
|
30891
31063
|
syncActionButtons() {
|
|
30892
31064
|
const empty = this.markNodes.length === 0;
|
|
30893
|
-
if (this.undoBtn) this.undoBtn.disabled =
|
|
31065
|
+
if (this.undoBtn) this.undoBtn.disabled = this.markNodes.length <= this.sessionBase;
|
|
30894
31066
|
if (this.clearBtn) this.clearBtn.disabled = empty;
|
|
30895
31067
|
}
|
|
30896
31068
|
// --------------------------------------------------------------------------
|
|
@@ -30904,6 +31076,7 @@ var AnnotationEditor = class {
|
|
|
30904
31076
|
}
|
|
30905
31077
|
onPointerDown = (e) => {
|
|
30906
31078
|
if (!this.active) return;
|
|
31079
|
+
if (this.drag) return;
|
|
30907
31080
|
if (e.button !== void 0 && e.button !== 0) return;
|
|
30908
31081
|
e.preventDefault();
|
|
30909
31082
|
const p = this.toDoc(e);
|
|
@@ -30953,6 +31126,7 @@ var AnnotationEditor = class {
|
|
|
30953
31126
|
this.drag = drag;
|
|
30954
31127
|
window.addEventListener("pointermove", this.onPointerMove, true);
|
|
30955
31128
|
window.addEventListener("pointerup", this.onPointerUp, true);
|
|
31129
|
+
window.addEventListener("pointercancel", this.onPointerCancel, true);
|
|
30956
31130
|
};
|
|
30957
31131
|
onPointerMove = (e) => {
|
|
30958
31132
|
const d = this.drag;
|
|
@@ -31062,9 +31236,18 @@ var AnnotationEditor = class {
|
|
|
31062
31236
|
d.node.removeAttribute("data-lens-draft");
|
|
31063
31237
|
this.commitMark(annotation, d.node);
|
|
31064
31238
|
};
|
|
31239
|
+
/** Pointer capture was cancelled (OS gesture, page hidden, etc.): drop the
|
|
31240
|
+
* in-progress draft node and detach listeners so nothing leaks. */
|
|
31241
|
+
onPointerCancel = () => {
|
|
31242
|
+
const d = this.drag;
|
|
31243
|
+
this.detachDragListeners();
|
|
31244
|
+
this.drag = null;
|
|
31245
|
+
d?.node.remove();
|
|
31246
|
+
};
|
|
31065
31247
|
detachDragListeners() {
|
|
31066
31248
|
window.removeEventListener("pointermove", this.onPointerMove, true);
|
|
31067
31249
|
window.removeEventListener("pointerup", this.onPointerUp, true);
|
|
31250
|
+
window.removeEventListener("pointercancel", this.onPointerCancel, true);
|
|
31068
31251
|
}
|
|
31069
31252
|
commitMark(annotation, node2) {
|
|
31070
31253
|
this.annotations.push(annotation);
|
|
@@ -31258,29 +31441,31 @@ var AnnotationEditor = class {
|
|
|
31258
31441
|
return `lens-${++this.idSeq}`;
|
|
31259
31442
|
}
|
|
31260
31443
|
};
|
|
31261
|
-
var INCLUDE_ITEMS = [
|
|
31262
|
-
{ key: "replay", label: "Replay" },
|
|
31263
|
-
{ key: "console", label: "Console" },
|
|
31264
|
-
{ key: "network", label: "Network" },
|
|
31265
|
-
{ key: "errors", label: "Errors" },
|
|
31266
|
-
{ key: "screenshot", label: "Screenshot" }
|
|
31267
|
-
];
|
|
31268
31444
|
var Panel = class {
|
|
31269
31445
|
constructor(cb) {
|
|
31270
31446
|
this.cb = cb;
|
|
31271
31447
|
this.body = el("div", { class: "lens-panel__body" });
|
|
31272
|
-
|
|
31273
|
-
el("
|
|
31274
|
-
|
|
31275
|
-
|
|
31276
|
-
|
|
31277
|
-
|
|
31278
|
-
|
|
31279
|
-
|
|
31280
|
-
|
|
31281
|
-
|
|
31282
|
-
|
|
31448
|
+
const head = el("div", { class: "lens-panel__head" }, [
|
|
31449
|
+
el("span", {
|
|
31450
|
+
class: "lens-panel__grip",
|
|
31451
|
+
html: iconGrip,
|
|
31452
|
+
title: "Drag to move",
|
|
31453
|
+
ariaLabel: "Drag to move panel"
|
|
31454
|
+
}),
|
|
31455
|
+
el("div", { class: "lens-panel__title", text: "Report an issue" }),
|
|
31456
|
+
el("button", {
|
|
31457
|
+
class: "lens-panel__x",
|
|
31458
|
+
ariaLabel: "Close",
|
|
31459
|
+
html: iconClose,
|
|
31460
|
+
on: { click: () => this.cb.onClose() }
|
|
31461
|
+
})
|
|
31283
31462
|
]);
|
|
31463
|
+
this.root = el(
|
|
31464
|
+
"div",
|
|
31465
|
+
{ class: "lens-panel", attrs: { role: "dialog", "aria-label": "Report an issue" } },
|
|
31466
|
+
[head, this.body]
|
|
31467
|
+
);
|
|
31468
|
+
this.drag = makeDraggable(this.root, { handle: head, key: "lens-panel" });
|
|
31284
31469
|
this.renderForm();
|
|
31285
31470
|
}
|
|
31286
31471
|
cb;
|
|
@@ -31288,6 +31473,7 @@ var Panel = class {
|
|
|
31288
31473
|
body;
|
|
31289
31474
|
textarea;
|
|
31290
31475
|
submitBtn;
|
|
31476
|
+
drag = null;
|
|
31291
31477
|
autoCloseTimer = null;
|
|
31292
31478
|
submitting = false;
|
|
31293
31479
|
/** Selected capture toggles; every flag starts ON. Persists across refresh. */
|
|
@@ -31307,6 +31493,8 @@ var Panel = class {
|
|
|
31307
31493
|
}
|
|
31308
31494
|
destroy() {
|
|
31309
31495
|
if (this.autoCloseTimer) clearTimeout(this.autoCloseTimer);
|
|
31496
|
+
this.drag?.destroy();
|
|
31497
|
+
this.drag = null;
|
|
31310
31498
|
this.root.remove();
|
|
31311
31499
|
}
|
|
31312
31500
|
renderForm() {
|
|
@@ -31321,7 +31509,6 @@ var Panel = class {
|
|
|
31321
31509
|
this.body.append(
|
|
31322
31510
|
this.textarea,
|
|
31323
31511
|
this.buildContext(),
|
|
31324
|
-
this.buildIncludes(),
|
|
31325
31512
|
this.buildChips(),
|
|
31326
31513
|
this.buildActions()
|
|
31327
31514
|
);
|
|
@@ -31341,39 +31528,6 @@ var Panel = class {
|
|
|
31341
31528
|
});
|
|
31342
31529
|
return el("div", { class: "lens-context", title: s.url }, nodes);
|
|
31343
31530
|
}
|
|
31344
|
-
/** Real toggles ("switch"): which captured data to attach. All ON by default. */
|
|
31345
|
-
buildIncludes() {
|
|
31346
|
-
const s = this.cb.getStats();
|
|
31347
|
-
const counts = {
|
|
31348
|
-
console: s.console,
|
|
31349
|
-
network: s.network,
|
|
31350
|
-
errors: s.errors
|
|
31351
|
-
};
|
|
31352
|
-
const toggles = INCLUDE_ITEMS.map((item) => this.buildToggle(item.key, item.label, counts[item.key]));
|
|
31353
|
-
return el("div", { class: "lens-includes" }, [
|
|
31354
|
-
el("span", { class: "lens-includes__label", text: "Include:" }),
|
|
31355
|
-
...toggles
|
|
31356
|
-
]);
|
|
31357
|
-
}
|
|
31358
|
-
buildToggle(key, label, count) {
|
|
31359
|
-
const on2 = this.include[key];
|
|
31360
|
-
const btn = el("button", {
|
|
31361
|
-
class: `lens-tgl${on2 ? " is-on" : ""}`,
|
|
31362
|
-
attrs: { type: "button", role: "switch", "aria-checked": String(on2) },
|
|
31363
|
-
html: `<span class="lens-tgl__check" aria-hidden="true">${iconCheck}</span>`
|
|
31364
|
-
});
|
|
31365
|
-
btn.append(el("span", { class: "lens-tgl__label", text: label }));
|
|
31366
|
-
if (typeof count === "number" && count > 0) {
|
|
31367
|
-
btn.append(el("span", { class: "lens-tgl__count", text: String(count) }));
|
|
31368
|
-
}
|
|
31369
|
-
btn.addEventListener("click", () => {
|
|
31370
|
-
const next = !this.include[key];
|
|
31371
|
-
this.include[key] = next;
|
|
31372
|
-
btn.classList.toggle("is-on", next);
|
|
31373
|
-
btn.setAttribute("aria-checked", String(next));
|
|
31374
|
-
});
|
|
31375
|
-
return btn;
|
|
31376
|
-
}
|
|
31377
31531
|
/** Removable context chips: annotations, retained recording, picked element. */
|
|
31378
31532
|
buildChips() {
|
|
31379
31533
|
const row = el("div", { class: "lens-chips" });
|
|
@@ -31678,14 +31832,28 @@ var OVERLAY_CSS = (
|
|
|
31678
31832
|
`
|
|
31679
31833
|
:host {
|
|
31680
31834
|
all: initial;
|
|
31681
|
-
|
|
31682
|
-
|
|
31835
|
+
/* Black & white, mirroring the Horus Cloud dashboard: the accent is near-black
|
|
31836
|
+
in light and near-white in dark; the always-dark pill/toolbar use explicit
|
|
31837
|
+
light highlights (defined at their rules). Annotation swatch colors and
|
|
31838
|
+
status red/green are content, not brand, and keep their hues. */
|
|
31839
|
+
--lens-accent: #18181b;
|
|
31840
|
+
--lens-accent-strong: #000000;
|
|
31841
|
+
--lens-on-accent: #ffffff;
|
|
31842
|
+
--lens-focus: rgba(0, 0, 0, 0.16);
|
|
31683
31843
|
--lens-radius: 8px;
|
|
31684
31844
|
--lens-font: system-ui, -apple-system, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
|
|
31685
31845
|
--lens-z: 2147483000;
|
|
31686
31846
|
font-family: var(--lens-font);
|
|
31687
31847
|
line-height: 1.4;
|
|
31688
31848
|
}
|
|
31849
|
+
@media (prefers-color-scheme: dark) {
|
|
31850
|
+
:host {
|
|
31851
|
+
--lens-accent: #fafafa;
|
|
31852
|
+
--lens-accent-strong: #ffffff;
|
|
31853
|
+
--lens-on-accent: #18181b;
|
|
31854
|
+
--lens-focus: rgba(255, 255, 255, 0.22);
|
|
31855
|
+
}
|
|
31856
|
+
}
|
|
31689
31857
|
|
|
31690
31858
|
*, *::before, *::after { box-sizing: border-box; }
|
|
31691
31859
|
|
|
@@ -31705,7 +31873,7 @@ var OVERLAY_CSS = (
|
|
|
31705
31873
|
left: 50%;
|
|
31706
31874
|
transform: translateX(-50%);
|
|
31707
31875
|
max-width: calc(100vw - 16px);
|
|
31708
|
-
flex-wrap:
|
|
31876
|
+
flex-wrap: nowrap;
|
|
31709
31877
|
justify-content: center;
|
|
31710
31878
|
display: inline-flex;
|
|
31711
31879
|
align-items: center;
|
|
@@ -31729,7 +31897,7 @@ var OVERLAY_CSS = (
|
|
|
31729
31897
|
height: 26px;
|
|
31730
31898
|
margin-left: 4px;
|
|
31731
31899
|
border-radius: 999px;
|
|
31732
|
-
color: #
|
|
31900
|
+
color: #f4f4f5;
|
|
31733
31901
|
}
|
|
31734
31902
|
.lens-btn {
|
|
31735
31903
|
display: inline-flex;
|
|
@@ -31748,11 +31916,14 @@ var OVERLAY_CSS = (
|
|
|
31748
31916
|
transition: background 150ms ease, color 150ms ease;
|
|
31749
31917
|
}
|
|
31750
31918
|
.lens-btn:hover { background: rgba(255, 255, 255, 0.1); }
|
|
31751
|
-
.lens-btn:focus-visible { outline: 2px solid
|
|
31752
|
-
.lens-btn--primary { background:
|
|
31753
|
-
.lens-btn--primary:hover { background:
|
|
31919
|
+
.lens-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }
|
|
31920
|
+
.lens-btn--primary { background: #fff; color: #18181b; }
|
|
31921
|
+
.lens-btn--primary:hover { background: #e4e4e7; }
|
|
31922
|
+
.lens-btn--report svg { flex: none; }
|
|
31923
|
+
.lens-btn__label { white-space: nowrap; }
|
|
31754
31924
|
.lens-btn--icon { width: 30px; padding: 0; justify-content: center; }
|
|
31755
|
-
|
|
31925
|
+
/* Always-dark pill: an active control reads as a light (white) highlight. */
|
|
31926
|
+
.lens-btn--icon.is-active { background: #fff; color: #18181b; }
|
|
31756
31927
|
.lens-pill__sep {
|
|
31757
31928
|
width: 1px;
|
|
31758
31929
|
height: 18px;
|
|
@@ -31766,7 +31937,10 @@ var OVERLAY_CSS = (
|
|
|
31766
31937
|
z-index: calc(var(--lens-z) - 2);
|
|
31767
31938
|
pointer-events: none;
|
|
31768
31939
|
border: 2px solid var(--lens-accent);
|
|
31769
|
-
|
|
31940
|
+
/* A light outer ring so the (black-in-light / white-in-dark) border stays
|
|
31941
|
+
visible over any page background. */
|
|
31942
|
+
box-shadow: 0 0 0 1px rgba(255, 255, 255, 0.6), 0 0 0 3px rgba(0, 0, 0, 0.15);
|
|
31943
|
+
background: rgba(127, 127, 127, 0.14);
|
|
31770
31944
|
border-radius: 3px;
|
|
31771
31945
|
transition: all 60ms linear;
|
|
31772
31946
|
display: none;
|
|
@@ -31778,7 +31952,7 @@ var OVERLAY_CSS = (
|
|
|
31778
31952
|
padding: 1px 6px;
|
|
31779
31953
|
border-radius: 4px;
|
|
31780
31954
|
background: var(--lens-accent);
|
|
31781
|
-
color:
|
|
31955
|
+
color: var(--lens-on-accent);
|
|
31782
31956
|
font: 500 11px/1.5 var(--lens-font);
|
|
31783
31957
|
white-space: nowrap;
|
|
31784
31958
|
}
|
|
@@ -31857,7 +32031,7 @@ var OVERLAY_CSS = (
|
|
|
31857
32031
|
padding: 14px 16px;
|
|
31858
32032
|
border-bottom: 1px solid rgba(0, 0, 0, 0.07);
|
|
31859
32033
|
}
|
|
31860
|
-
.lens-panel__title { font-size: 14px; font-weight: 600; }
|
|
32034
|
+
.lens-panel__title { font-size: 14px; font-weight: 600; margin-right: auto; }
|
|
31861
32035
|
.lens-panel__x {
|
|
31862
32036
|
display: inline-flex;
|
|
31863
32037
|
align-items: center;
|
|
@@ -31895,7 +32069,7 @@ var OVERLAY_CSS = (
|
|
|
31895
32069
|
.lens-textarea:focus {
|
|
31896
32070
|
outline: none;
|
|
31897
32071
|
border-color: var(--lens-accent);
|
|
31898
|
-
box-shadow: 0 0 0 3px
|
|
32072
|
+
box-shadow: 0 0 0 3px var(--lens-focus);
|
|
31899
32073
|
}
|
|
31900
32074
|
/* ---- Context row: static, non-interactive page facts (muted, dot-joined) ---- */
|
|
31901
32075
|
.lens-context {
|
|
@@ -31910,49 +32084,6 @@ var OVERLAY_CSS = (
|
|
|
31910
32084
|
.lens-context__item { white-space: nowrap; }
|
|
31911
32085
|
.lens-context__dot { opacity: 0.55; }
|
|
31912
32086
|
|
|
31913
|
-
/* ---- Include row: real toggles (role=switch) for which data to attach ---- */
|
|
31914
|
-
.lens-includes {
|
|
31915
|
-
display: flex;
|
|
31916
|
-
flex-wrap: wrap;
|
|
31917
|
-
align-items: center;
|
|
31918
|
-
gap: 6px;
|
|
31919
|
-
}
|
|
31920
|
-
.lens-includes__label {
|
|
31921
|
-
font-size: 11.5px;
|
|
31922
|
-
font-weight: 600;
|
|
31923
|
-
color: #71717a;
|
|
31924
|
-
margin-right: 2px;
|
|
31925
|
-
}
|
|
31926
|
-
.lens-tgl {
|
|
31927
|
-
display: inline-flex;
|
|
31928
|
-
align-items: center;
|
|
31929
|
-
gap: 5px;
|
|
31930
|
-
padding: 4px 10px;
|
|
31931
|
-
border-radius: 999px;
|
|
31932
|
-
border: 1px solid rgba(0, 0, 0, 0.14);
|
|
31933
|
-
background: #fafafa;
|
|
31934
|
-
color: #a1a1aa;
|
|
31935
|
-
font-family: var(--lens-font);
|
|
31936
|
-
font-size: 11.5px;
|
|
31937
|
-
font-weight: 600;
|
|
31938
|
-
white-space: nowrap;
|
|
31939
|
-
cursor: pointer;
|
|
31940
|
-
opacity: 0.75;
|
|
31941
|
-
transition: background 150ms ease, border-color 150ms ease, color 150ms ease, opacity 150ms ease;
|
|
31942
|
-
}
|
|
31943
|
-
.lens-tgl:hover { opacity: 1; }
|
|
31944
|
-
.lens-tgl:focus-visible { outline: 2px solid var(--lens-accent); outline-offset: 1px; }
|
|
31945
|
-
.lens-tgl__check { display: none; align-items: center; }
|
|
31946
|
-
.lens-tgl__check svg { width: 13px; height: 13px; }
|
|
31947
|
-
.lens-tgl__count { font-weight: 500; opacity: 0.75; font-variant-numeric: tabular-nums; }
|
|
31948
|
-
.lens-tgl.is-on {
|
|
31949
|
-
opacity: 1;
|
|
31950
|
-
color: var(--lens-accent-strong);
|
|
31951
|
-
border-color: rgba(99, 102, 241, 0.5);
|
|
31952
|
-
background: #eef2ff;
|
|
31953
|
-
}
|
|
31954
|
-
.lens-tgl.is-on .lens-tgl__check { display: inline-flex; }
|
|
31955
|
-
|
|
31956
32087
|
.lens-chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
31957
32088
|
.lens-chip {
|
|
31958
32089
|
display: inline-flex;
|
|
@@ -31973,9 +32104,9 @@ var OVERLAY_CSS = (
|
|
|
31973
32104
|
.lens-chip--ok { color: #15803d; background: #f0fdf4; border-color: rgba(21, 128, 61, 0.18); }
|
|
31974
32105
|
.lens-chip--target {
|
|
31975
32106
|
max-width: 100%;
|
|
31976
|
-
background:
|
|
31977
|
-
border-color: rgba(
|
|
31978
|
-
color:
|
|
32107
|
+
background: rgba(0, 0, 0, 0.05);
|
|
32108
|
+
border-color: rgba(0, 0, 0, 0.16);
|
|
32109
|
+
color: #18181b;
|
|
31979
32110
|
}
|
|
31980
32111
|
.lens-chip__code {
|
|
31981
32112
|
font-family: ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
@@ -32023,7 +32154,7 @@ var OVERLAY_CSS = (
|
|
|
32023
32154
|
.lens-abtn svg { flex: none; }
|
|
32024
32155
|
.lens-abtn--ghost { background: transparent; border-color: rgba(0, 0, 0, 0.14); color: #3f3f46; }
|
|
32025
32156
|
.lens-abtn--ghost:hover { background: rgba(0, 0, 0, 0.04); }
|
|
32026
|
-
.lens-abtn--primary { background: var(--lens-accent); color:
|
|
32157
|
+
.lens-abtn--primary { background: var(--lens-accent); color: var(--lens-on-accent); }
|
|
32027
32158
|
.lens-abtn--primary:hover { background: var(--lens-accent-strong); }
|
|
32028
32159
|
.lens-abtn:disabled { opacity: 0.55; cursor: default; }
|
|
32029
32160
|
.lens-abtn:focus-visible { outline: 2px solid var(--lens-accent); outline-offset: 1px; }
|
|
@@ -32077,12 +32208,9 @@ var OVERLAY_CSS = (
|
|
|
32077
32208
|
.lens-panel__x:hover { background: rgba(255, 255, 255, 0.08); }
|
|
32078
32209
|
.lens-textarea { background: #26262a; border-color: rgba(255, 255, 255, 0.14); color: #f4f4f5; }
|
|
32079
32210
|
.lens-context { color: #a1a1aa; }
|
|
32080
|
-
.lens-includes__label { color: #a1a1aa; }
|
|
32081
|
-
.lens-tgl { background: #26262a; border-color: rgba(255, 255, 255, 0.12); color: #a1a1aa; }
|
|
32082
|
-
.lens-tgl.is-on { background: rgba(99, 102, 241, 0.18); border-color: rgba(99, 102, 241, 0.55); color: #c7d2fe; }
|
|
32083
32211
|
.lens-chip { background: #26262a; border-color: rgba(255, 255, 255, 0.08); color: #d4d4d8; }
|
|
32084
32212
|
.lens-chip--ok { color: #4ade80; background: rgba(34, 197, 94, 0.12); border-color: rgba(74, 222, 128, 0.22); }
|
|
32085
|
-
.lens-chip--target { background: rgba(
|
|
32213
|
+
.lens-chip--target { background: rgba(255, 255, 255, 0.1); border-color: rgba(255, 255, 255, 0.18); color: #f4f4f5; }
|
|
32086
32214
|
.lens-abtn--ghost { border-color: rgba(255, 255, 255, 0.16); color: #d4d4d8; }
|
|
32087
32215
|
.lens-abtn--ghost:hover { background: rgba(255, 255, 255, 0.06); }
|
|
32088
32216
|
.lens-state__msg { color: #a1a1aa; }
|
|
@@ -32116,7 +32244,9 @@ var OVERLAY_CSS = (
|
|
|
32116
32244
|
.lens-annotate-chips { z-index: var(--lens-z); }
|
|
32117
32245
|
|
|
32118
32246
|
/* ---------------- Annotation toolbar ---------------- */
|
|
32119
|
-
/*
|
|
32247
|
+
/* Floating top-center anchor. A fixed drag grip sits left of a tools "track":
|
|
32248
|
+
the track wraps on desktop and becomes a single horizontal-scroll row on
|
|
32249
|
+
narrow screens, so the bar stays one slim height instead of a bulky block. */
|
|
32120
32250
|
.lens-annotate-toolbar {
|
|
32121
32251
|
position: fixed;
|
|
32122
32252
|
top: calc(16px + env(safe-area-inset-top));
|
|
@@ -32124,11 +32254,10 @@ var OVERLAY_CSS = (
|
|
|
32124
32254
|
transform: translateX(-50%);
|
|
32125
32255
|
z-index: var(--lens-z);
|
|
32126
32256
|
display: inline-flex;
|
|
32127
|
-
flex-wrap:
|
|
32257
|
+
flex-wrap: nowrap;
|
|
32128
32258
|
align-items: center;
|
|
32129
|
-
justify-content: center;
|
|
32130
32259
|
gap: 6px;
|
|
32131
|
-
max-width: calc(100vw -
|
|
32260
|
+
max-width: calc(100vw - 16px);
|
|
32132
32261
|
padding: 6px 8px;
|
|
32133
32262
|
border-radius: 14px;
|
|
32134
32263
|
background: rgba(20, 20, 23, 0.92);
|
|
@@ -32138,12 +32267,50 @@ var OVERLAY_CSS = (
|
|
|
32138
32267
|
box-shadow: 0 8px 30px rgba(0, 0, 0, 0.35);
|
|
32139
32268
|
color: #f4f4f5;
|
|
32140
32269
|
}
|
|
32270
|
+
/* Tools lay out as ONE horizontal row that scrolls if it can't fit, so the bar
|
|
32271
|
+
is always a single slim height \u2014 never a wrapping (or, worse, min-content
|
|
32272
|
+
collapsed vertical) block. The grip sits outside this track. */
|
|
32273
|
+
.lens-tool-track {
|
|
32274
|
+
display: flex;
|
|
32275
|
+
align-items: center;
|
|
32276
|
+
flex-wrap: nowrap;
|
|
32277
|
+
justify-content: flex-start;
|
|
32278
|
+
gap: 6px;
|
|
32279
|
+
flex: 1 1 auto;
|
|
32280
|
+
min-width: 0;
|
|
32281
|
+
overflow-x: auto;
|
|
32282
|
+
overflow-y: hidden;
|
|
32283
|
+
scrollbar-width: none;
|
|
32284
|
+
-webkit-overflow-scrolling: touch;
|
|
32285
|
+
}
|
|
32286
|
+
.lens-tool-track::-webkit-scrollbar { display: none; }
|
|
32141
32287
|
.lens-tool-group {
|
|
32142
32288
|
display: inline-flex;
|
|
32143
32289
|
align-items: center;
|
|
32144
32290
|
gap: 4px;
|
|
32145
|
-
flex-wrap:
|
|
32291
|
+
flex-wrap: nowrap;
|
|
32292
|
+
flex: none;
|
|
32293
|
+
}
|
|
32294
|
+
/* Single close (=Done, keeps marks) pinned at the right, always reachable
|
|
32295
|
+
while the tools scroll. Reads as a light control on the dark bar. */
|
|
32296
|
+
.lens-tool-close {
|
|
32297
|
+
display: inline-flex;
|
|
32298
|
+
align-items: center;
|
|
32299
|
+
justify-content: center;
|
|
32300
|
+
flex: none;
|
|
32301
|
+
width: 32px;
|
|
32302
|
+
height: 30px;
|
|
32303
|
+
padding: 0;
|
|
32304
|
+
border: 0;
|
|
32305
|
+
border-radius: 8px;
|
|
32306
|
+
background: rgba(255, 255, 255, 0.14);
|
|
32307
|
+
color: #f4f4f5;
|
|
32308
|
+
cursor: pointer;
|
|
32309
|
+
transition: background 150ms ease;
|
|
32146
32310
|
}
|
|
32311
|
+
.lens-tool-close:hover { background: rgba(255, 255, 255, 0.26); }
|
|
32312
|
+
.lens-tool-close:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }
|
|
32313
|
+
.lens-tool-close svg { width: 18px; height: 18px; }
|
|
32147
32314
|
.lens-tool-sep {
|
|
32148
32315
|
width: 1px;
|
|
32149
32316
|
align-self: stretch;
|
|
@@ -32151,6 +32318,51 @@ var OVERLAY_CSS = (
|
|
|
32151
32318
|
background: rgba(255, 255, 255, 0.16);
|
|
32152
32319
|
margin: 0 2px;
|
|
32153
32320
|
}
|
|
32321
|
+
|
|
32322
|
+
/* ---------------- Draggable surfaces ---------------- */
|
|
32323
|
+
/* Every drag handle: no page pan/scroll gesture starts here, and the cursor
|
|
32324
|
+
signals grabbability. Applied to the pill, panel header, toolbar grip, chips. */
|
|
32325
|
+
.lens-drag-handle { touch-action: none; cursor: grab; }
|
|
32326
|
+
.lens-drag-handle:active { cursor: grabbing; }
|
|
32327
|
+
.is-dragging, .is-dragging * { cursor: grabbing !important; }
|
|
32328
|
+
.is-dragging { user-select: none; }
|
|
32329
|
+
/* While dragging, drop the entry animation/transition so it tracks 1:1. */
|
|
32330
|
+
.lens-pill.is-dragging, .lens-panel.is-dragging,
|
|
32331
|
+
.lens-annotate-toolbar.is-dragging, .lens-rec-chip.is-dragging {
|
|
32332
|
+
animation: none;
|
|
32333
|
+
transition: none;
|
|
32334
|
+
}
|
|
32335
|
+
|
|
32336
|
+
/* Toolbar drag grip \u2014 the only grab region, kept out of the scroll track. */
|
|
32337
|
+
.lens-tool-grip {
|
|
32338
|
+
display: inline-flex;
|
|
32339
|
+
align-items: center;
|
|
32340
|
+
justify-content: center;
|
|
32341
|
+
flex: none;
|
|
32342
|
+
width: 22px;
|
|
32343
|
+
height: 30px;
|
|
32344
|
+
margin-right: 2px;
|
|
32345
|
+
border-radius: 6px;
|
|
32346
|
+
color: #a1a1aa;
|
|
32347
|
+
}
|
|
32348
|
+
.lens-tool-grip:hover { color: #f4f4f5; background: rgba(255, 255, 255, 0.08); }
|
|
32349
|
+
.lens-tool-grip svg { width: 16px; height: 16px; }
|
|
32350
|
+
|
|
32351
|
+
/* Pill grip (the eye dot) + panel header grip. */
|
|
32352
|
+
.lens-pill__grip { cursor: grab; }
|
|
32353
|
+
.lens-panel__grip {
|
|
32354
|
+
display: inline-flex;
|
|
32355
|
+
align-items: center;
|
|
32356
|
+
justify-content: center;
|
|
32357
|
+
flex: none;
|
|
32358
|
+
width: 22px;
|
|
32359
|
+
height: 22px;
|
|
32360
|
+
margin-right: 6px;
|
|
32361
|
+
color: #a1a1aa;
|
|
32362
|
+
}
|
|
32363
|
+
.lens-panel__grip svg { width: 16px; height: 16px; }
|
|
32364
|
+
.lens-panel__head { cursor: grab; }
|
|
32365
|
+
.lens-panel__head:active { cursor: grabbing; }
|
|
32154
32366
|
.lens-tool-btn {
|
|
32155
32367
|
display: inline-flex;
|
|
32156
32368
|
align-items: center;
|
|
@@ -32166,11 +32378,11 @@ var OVERLAY_CSS = (
|
|
|
32166
32378
|
transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
|
|
32167
32379
|
}
|
|
32168
32380
|
.lens-tool-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
|
|
32169
|
-
.lens-tool-btn:focus-visible { outline: 2px solid
|
|
32381
|
+
.lens-tool-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }
|
|
32170
32382
|
.lens-tool-btn.is-active {
|
|
32171
|
-
background:
|
|
32172
|
-
border-color:
|
|
32173
|
-
color: #
|
|
32383
|
+
background: #fff;
|
|
32384
|
+
border-color: #fff;
|
|
32385
|
+
color: #18181b;
|
|
32174
32386
|
}
|
|
32175
32387
|
.lens-tool-btn:disabled { opacity: 0.4; cursor: default; }
|
|
32176
32388
|
.lens-tool-btn:disabled:hover { background: transparent; color: #d4d4d8; }
|
|
@@ -32210,17 +32422,18 @@ var OVERLAY_CSS = (
|
|
|
32210
32422
|
transition: background 150ms ease, color 150ms ease, border-color 150ms ease;
|
|
32211
32423
|
}
|
|
32212
32424
|
.lens-width-btn:hover { background: rgba(255, 255, 255, 0.1); color: #fff; }
|
|
32213
|
-
.lens-width-btn:focus-visible { outline: 2px solid
|
|
32425
|
+
.lens-width-btn:focus-visible { outline: 2px solid rgba(255, 255, 255, 0.7); outline-offset: 1px; }
|
|
32214
32426
|
.lens-width-btn.is-active {
|
|
32215
|
-
background:
|
|
32216
|
-
border-color:
|
|
32217
|
-
color: #
|
|
32427
|
+
background: #fff;
|
|
32428
|
+
border-color: #fff;
|
|
32429
|
+
color: #18181b;
|
|
32218
32430
|
}
|
|
32219
32431
|
|
|
32220
32432
|
/* Coarse pointers: bump the tool targets toward 40px. */
|
|
32221
32433
|
@media (pointer: coarse) {
|
|
32222
32434
|
.lens-tool-btn, .lens-width-btn { width: 38px; height: 38px; }
|
|
32223
32435
|
.lens-swatch { width: 30px; height: 30px; }
|
|
32436
|
+
.lens-tool-grip { width: 30px; height: 38px; }
|
|
32224
32437
|
}
|
|
32225
32438
|
|
|
32226
32439
|
/* Stacking inside the shadow layer: the panel, pill and floating chips always
|
|
@@ -32245,8 +32458,8 @@ var OVERLAY_CSS = (
|
|
|
32245
32458
|
transition: background 150ms ease;
|
|
32246
32459
|
}
|
|
32247
32460
|
.lens-pick-chip__btn:hover { background: rgba(255, 255, 255, 0.2); }
|
|
32248
|
-
.lens-pick-chip__btn--primary { background:
|
|
32249
|
-
.lens-pick-chip__btn--primary:hover { background:
|
|
32461
|
+
.lens-pick-chip__btn--primary { background: #fff; color: #18181b; }
|
|
32462
|
+
.lens-pick-chip__btn--primary:hover { background: #e4e4e7; }
|
|
32250
32463
|
|
|
32251
32464
|
/* ---------------- Recording chip ---------------- */
|
|
32252
32465
|
.lens-rec-chip {
|
|
@@ -32301,21 +32514,29 @@ var OVERLAY_CSS = (
|
|
|
32301
32514
|
.lens-rec-chip__stop:hover { background: #dc2626; }
|
|
32302
32515
|
.lens-chip--rec { gap: 6px; }
|
|
32303
32516
|
|
|
32517
|
+
/* Very narrow screens: collapse the pill's "Report issue" label to its icon so
|
|
32518
|
+
the pill stays a single slim row (never wraps into a 2-row blob). */
|
|
32519
|
+
@media (max-width: 400px) {
|
|
32520
|
+
.lens-btn__label { display: none; }
|
|
32521
|
+
.lens-btn--report { width: 44px; padding: 0; justify-content: center; }
|
|
32522
|
+
}
|
|
32523
|
+
|
|
32304
32524
|
/* ---------------- Coarse pointers (touch): \u226544px targets ---------------- */
|
|
32305
32525
|
@media (pointer: coarse) {
|
|
32306
32526
|
.lens-btn { height: 44px; padding: 0 16px; }
|
|
32307
32527
|
.lens-btn--icon { width: 44px; }
|
|
32528
|
+
.lens-tool-close { width: 44px; height: 38px; }
|
|
32308
32529
|
.lens-pill__dot { width: 40px; height: 40px; }
|
|
32309
32530
|
.lens-abtn { height: 44px; }
|
|
32310
|
-
.lens-tgl { min-height: 40px; padding: 4px 14px; }
|
|
32311
32531
|
.lens-panel__x { width: 44px; height: 44px; }
|
|
32312
32532
|
.lens-chip__x { min-width: 32px; min-height: 32px; align-items: center; justify-content: center; }
|
|
32313
32533
|
.lens-pick-chip__btn, .lens-rec-chip__stop { height: 40px; padding: 0 18px; }
|
|
32314
32534
|
}
|
|
32315
32535
|
|
|
32316
|
-
/* ----------------
|
|
32536
|
+
/* ---------------- Narrow screens (\u2264640px) ---------------- */
|
|
32317
32537
|
@media (max-width: 640px) {
|
|
32318
|
-
|
|
32538
|
+
/* Report panel as a bottom sheet (unless the user has dragged it loose). */
|
|
32539
|
+
.lens-panel:not(.is-dragging) {
|
|
32319
32540
|
left: 0;
|
|
32320
32541
|
right: 0;
|
|
32321
32542
|
bottom: 0;
|
|
@@ -32332,6 +32553,14 @@ var OVERLAY_CSS = (
|
|
|
32332
32553
|
to { opacity: 1; transform: none; }
|
|
32333
32554
|
}
|
|
32334
32555
|
.lens-textarea { font-size: 16px; }
|
|
32556
|
+
|
|
32557
|
+
/* On narrow screens the single-row tool track usually overflows: fade its
|
|
32558
|
+
trailing edge so it reads as "more tools this way" (the grip sits outside
|
|
32559
|
+
the track and stays fully opaque). */
|
|
32560
|
+
.lens-tool-track {
|
|
32561
|
+
-webkit-mask-image: linear-gradient(90deg, #000 calc(100% - 20px), transparent 100%);
|
|
32562
|
+
mask-image: linear-gradient(90deg, #000 calc(100% - 20px), transparent 100%);
|
|
32563
|
+
}
|
|
32335
32564
|
}
|
|
32336
32565
|
`
|
|
32337
32566
|
);
|
|
@@ -32349,8 +32578,14 @@ var Overlay = class {
|
|
|
32349
32578
|
this.shadow.append(this.layer);
|
|
32350
32579
|
this.picker = new ElementPicker(this.layer, this.host);
|
|
32351
32580
|
this.annotator = new AnnotationEditor(this.layer);
|
|
32352
|
-
this.
|
|
32581
|
+
const pill = this.buildPill();
|
|
32582
|
+
this.layer.append(pill);
|
|
32353
32583
|
document.documentElement.append(this.host);
|
|
32584
|
+
this.pillDrag = makeDraggable(pill, {
|
|
32585
|
+
handle: pill,
|
|
32586
|
+
key: "lens-pill",
|
|
32587
|
+
ignore: isInteractiveTarget
|
|
32588
|
+
});
|
|
32354
32589
|
window.addEventListener("keydown", this.onGlobalKey, true);
|
|
32355
32590
|
}
|
|
32356
32591
|
deps;
|
|
@@ -32363,7 +32598,9 @@ var Overlay = class {
|
|
|
32363
32598
|
panel = null;
|
|
32364
32599
|
target = null;
|
|
32365
32600
|
destroyed = false;
|
|
32601
|
+
pillDrag = null;
|
|
32366
32602
|
recordingChip = null;
|
|
32603
|
+
recordingDrag = null;
|
|
32367
32604
|
recordingTimerEl = null;
|
|
32368
32605
|
recordingInterval = null;
|
|
32369
32606
|
recordingStartTs = 0;
|
|
@@ -32378,10 +32615,16 @@ var Overlay = class {
|
|
|
32378
32615
|
on: { click: () => this.togglePicker() }
|
|
32379
32616
|
});
|
|
32380
32617
|
return el("div", { class: "lens-pill", attrs: { role: "toolbar", "aria-label": "Lens" } }, [
|
|
32381
|
-
el("span", {
|
|
32618
|
+
el("span", {
|
|
32619
|
+
class: "lens-pill__dot lens-pill__grip",
|
|
32620
|
+
html: iconEye,
|
|
32621
|
+
title: "Drag to move",
|
|
32622
|
+
ariaLabel: "Drag to move Lens"
|
|
32623
|
+
}),
|
|
32382
32624
|
el("button", {
|
|
32383
|
-
class: "lens-btn",
|
|
32384
|
-
|
|
32625
|
+
class: "lens-btn lens-btn--report",
|
|
32626
|
+
html: iconReport + '<span class="lens-btn__label">Report issue</span>',
|
|
32627
|
+
ariaLabel: "Report issue",
|
|
32385
32628
|
on: { click: () => this.open() }
|
|
32386
32629
|
}),
|
|
32387
32630
|
this.pickBtn,
|
|
@@ -32435,6 +32678,7 @@ var Overlay = class {
|
|
|
32435
32678
|
this.stopPicker();
|
|
32436
32679
|
return;
|
|
32437
32680
|
}
|
|
32681
|
+
if (this.annotator.isActive) this.annotator.exit();
|
|
32438
32682
|
this.close();
|
|
32439
32683
|
this.pickBtn.classList.add("is-active");
|
|
32440
32684
|
this.picker.start(
|
|
@@ -32496,6 +32740,11 @@ var Overlay = class {
|
|
|
32496
32740
|
})
|
|
32497
32741
|
]);
|
|
32498
32742
|
this.layer.append(this.recordingChip);
|
|
32743
|
+
this.recordingDrag = makeDraggable(this.recordingChip, {
|
|
32744
|
+
handle: this.recordingChip,
|
|
32745
|
+
key: "lens-rec-chip",
|
|
32746
|
+
ignore: isInteractiveTarget
|
|
32747
|
+
});
|
|
32499
32748
|
this.recordingInterval = setInterval(() => this.tickRecording(), 250);
|
|
32500
32749
|
}
|
|
32501
32750
|
tickRecording() {
|
|
@@ -32508,6 +32757,10 @@ var Overlay = class {
|
|
|
32508
32757
|
clearInterval(this.recordingInterval);
|
|
32509
32758
|
this.recordingInterval = null;
|
|
32510
32759
|
}
|
|
32760
|
+
if (this.recordingDrag) {
|
|
32761
|
+
this.recordingDrag.destroy();
|
|
32762
|
+
this.recordingDrag = null;
|
|
32763
|
+
}
|
|
32511
32764
|
if (this.recordingChip) {
|
|
32512
32765
|
this.recordingChip.remove();
|
|
32513
32766
|
this.recordingChip = null;
|
|
@@ -32548,6 +32801,8 @@ var Overlay = class {
|
|
|
32548
32801
|
if (this.destroyed) return;
|
|
32549
32802
|
this.destroyed = true;
|
|
32550
32803
|
window.removeEventListener("keydown", this.onGlobalKey, true);
|
|
32804
|
+
this.pillDrag?.destroy();
|
|
32805
|
+
this.pillDrag = null;
|
|
32551
32806
|
this.stopPicker();
|
|
32552
32807
|
if (this.deps.client.isRecording()) this.deps.client.stopRecording();
|
|
32553
32808
|
this.hideRecordingChip();
|