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