afterbefore 0.2.4 → 0.2.5
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/overlay/index.js +571 -561
- package/dist/overlay/index.js.map +1 -1
- package/package.json +2 -2
package/dist/overlay/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
3
|
// src/overlay/index.tsx
|
|
4
|
-
import { useState as useState6, useCallback as
|
|
4
|
+
import { useState as useState6, useCallback as useCallback6, useRef as useRef5, useEffect as useEffect5 } from "react";
|
|
5
5
|
|
|
6
6
|
// src/overlay/state.ts
|
|
7
7
|
import { useState, useCallback } from "react";
|
|
@@ -33,99 +33,67 @@ function useOverlayState() {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// src/overlay/capture.ts
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
import { domToPng } from "modern-screenshot";
|
|
37
|
+
var DEV_UI_SELECTORS = [
|
|
38
|
+
// Afterbefore overlay
|
|
39
|
+
"[data-afterbefore]",
|
|
40
|
+
// Next.js dev indicators
|
|
41
|
+
"[data-nextjs-toast]",
|
|
42
|
+
"[data-nextjs-dev-overlay]",
|
|
43
|
+
"[data-nextjs-dialog]",
|
|
44
|
+
"[data-nextjs-dialog-backdrop]",
|
|
45
|
+
"[data-next-badge]",
|
|
46
|
+
"[data-next-mark]"
|
|
47
|
+
].join(",");
|
|
48
|
+
function filterDevUI(node) {
|
|
49
|
+
if (node instanceof HTMLElement) {
|
|
50
|
+
return !node.matches(DEV_UI_SELECTORS);
|
|
40
51
|
}
|
|
41
|
-
|
|
42
|
-
video: { displaySurface: "browser" },
|
|
43
|
-
preferCurrentTab: true
|
|
44
|
-
});
|
|
45
|
-
cachedStream = stream;
|
|
46
|
-
stream.getVideoTracks()[0].addEventListener("ended", () => {
|
|
47
|
-
cachedStream = null;
|
|
48
|
-
});
|
|
49
|
-
return stream;
|
|
52
|
+
return true;
|
|
50
53
|
}
|
|
51
|
-
|
|
52
|
-
const elements = document.querySelectorAll(
|
|
53
|
-
"[data-afterbefore]"
|
|
54
|
-
);
|
|
54
|
+
function hideDevUI() {
|
|
55
|
+
const elements = document.querySelectorAll(DEV_UI_SELECTORS);
|
|
55
56
|
const saved = /* @__PURE__ */ new Map();
|
|
56
57
|
elements.forEach((el) => {
|
|
57
|
-
saved.set(el, el.style.
|
|
58
|
-
el.style.
|
|
59
|
-
});
|
|
60
|
-
await new Promise((resolve) => {
|
|
61
|
-
requestAnimationFrame(() => {
|
|
62
|
-
requestAnimationFrame(() => {
|
|
63
|
-
setTimeout(resolve, 50);
|
|
64
|
-
});
|
|
65
|
-
});
|
|
58
|
+
saved.set(el, el.style.display);
|
|
59
|
+
el.style.display = "none";
|
|
66
60
|
});
|
|
67
61
|
return () => {
|
|
68
62
|
saved.forEach((v, el) => {
|
|
69
|
-
el.style.
|
|
63
|
+
el.style.display = v;
|
|
70
64
|
});
|
|
71
65
|
};
|
|
72
66
|
}
|
|
73
|
-
async function grabFrame() {
|
|
74
|
-
const stream = await getTabStream();
|
|
75
|
-
const track = stream.getVideoTracks()[0];
|
|
76
|
-
const imageCapture = new window.ImageCapture(track);
|
|
77
|
-
return imageCapture.grabFrame();
|
|
78
|
-
}
|
|
79
|
-
function bitmapToDataUrl(bitmap, crop) {
|
|
80
|
-
const canvas = document.createElement("canvas");
|
|
81
|
-
const ctx = canvas.getContext("2d");
|
|
82
|
-
if (crop) {
|
|
83
|
-
const scaleX = bitmap.width / window.innerWidth;
|
|
84
|
-
const scaleY = bitmap.height / window.innerHeight;
|
|
85
|
-
const sx = crop.x * scaleX;
|
|
86
|
-
const sy = crop.y * scaleY;
|
|
87
|
-
const sw = crop.width * scaleX;
|
|
88
|
-
const sh = crop.height * scaleY;
|
|
89
|
-
canvas.width = sw;
|
|
90
|
-
canvas.height = sh;
|
|
91
|
-
ctx.drawImage(bitmap, sx, sy, sw, sh, 0, 0, sw, sh);
|
|
92
|
-
} else {
|
|
93
|
-
canvas.width = bitmap.width;
|
|
94
|
-
canvas.height = bitmap.height;
|
|
95
|
-
ctx.drawImage(bitmap, 0, 0);
|
|
96
|
-
}
|
|
97
|
-
return canvas.toDataURL("image/png");
|
|
98
|
-
}
|
|
99
67
|
async function capture(options) {
|
|
100
68
|
const { mode, area, element } = options;
|
|
101
|
-
|
|
102
|
-
return captureFullPage();
|
|
103
|
-
}
|
|
104
|
-
const restoreOverlay = await hideOverlay();
|
|
69
|
+
const restore = hideDevUI();
|
|
105
70
|
try {
|
|
106
|
-
const bitmap = await grabFrame();
|
|
107
71
|
if (mode === "viewport") {
|
|
108
|
-
return
|
|
72
|
+
return await captureViewport();
|
|
73
|
+
}
|
|
74
|
+
if (mode === "fullpage") {
|
|
75
|
+
return await captureFullPage();
|
|
109
76
|
}
|
|
110
77
|
if (mode === "area" && area) {
|
|
111
|
-
return
|
|
78
|
+
return await captureArea(area);
|
|
112
79
|
}
|
|
113
80
|
if (mode === "component" && element) {
|
|
114
|
-
|
|
115
|
-
return bitmapToDataUrl(bitmap, {
|
|
116
|
-
x: rect.x,
|
|
117
|
-
y: rect.y,
|
|
118
|
-
width: rect.width,
|
|
119
|
-
height: rect.height
|
|
120
|
-
});
|
|
81
|
+
return await captureComponent(element);
|
|
121
82
|
}
|
|
122
83
|
throw new Error(`Invalid capture mode: ${mode}`);
|
|
123
84
|
} finally {
|
|
124
|
-
|
|
85
|
+
restore();
|
|
125
86
|
}
|
|
126
87
|
}
|
|
88
|
+
async function captureViewport() {
|
|
89
|
+
return domToPng(document.documentElement, {
|
|
90
|
+
width: window.innerWidth,
|
|
91
|
+
height: window.innerHeight,
|
|
92
|
+
style: { overflow: "hidden" },
|
|
93
|
+
filter: filterDevUI
|
|
94
|
+
});
|
|
95
|
+
}
|
|
127
96
|
async function captureFullPage() {
|
|
128
|
-
const { toPng } = await import("html-to-image");
|
|
129
97
|
const scrollY = window.scrollY;
|
|
130
98
|
const body = document.body;
|
|
131
99
|
const html = document.documentElement;
|
|
@@ -136,18 +104,52 @@ async function captureFullPage() {
|
|
|
136
104
|
html.scrollHeight,
|
|
137
105
|
html.offsetHeight
|
|
138
106
|
);
|
|
139
|
-
const dataUrl = await
|
|
107
|
+
const dataUrl = await domToPng(document.documentElement, {
|
|
140
108
|
width: window.innerWidth,
|
|
141
109
|
height: fullHeight,
|
|
142
110
|
style: {
|
|
143
111
|
overflow: "visible",
|
|
144
112
|
height: `${fullHeight}px`
|
|
145
113
|
},
|
|
146
|
-
filter:
|
|
114
|
+
filter: filterDevUI
|
|
147
115
|
});
|
|
148
116
|
window.scrollTo(0, scrollY);
|
|
149
117
|
return dataUrl;
|
|
150
118
|
}
|
|
119
|
+
async function captureArea(area) {
|
|
120
|
+
const fullDataUrl = await captureViewport();
|
|
121
|
+
const img = await loadImage(fullDataUrl);
|
|
122
|
+
const dpr = window.devicePixelRatio || 1;
|
|
123
|
+
const canvas = document.createElement("canvas");
|
|
124
|
+
canvas.width = area.width * dpr;
|
|
125
|
+
canvas.height = area.height * dpr;
|
|
126
|
+
const ctx = canvas.getContext("2d");
|
|
127
|
+
ctx.drawImage(
|
|
128
|
+
img,
|
|
129
|
+
area.x * dpr,
|
|
130
|
+
area.y * dpr,
|
|
131
|
+
area.width * dpr,
|
|
132
|
+
area.height * dpr,
|
|
133
|
+
0,
|
|
134
|
+
0,
|
|
135
|
+
area.width * dpr,
|
|
136
|
+
area.height * dpr
|
|
137
|
+
);
|
|
138
|
+
return canvas.toDataURL("image/png");
|
|
139
|
+
}
|
|
140
|
+
async function captureComponent(element) {
|
|
141
|
+
return domToPng(element, {
|
|
142
|
+
filter: filterDevUI
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
function loadImage(src) {
|
|
146
|
+
return new Promise((resolve, reject) => {
|
|
147
|
+
const img = new Image();
|
|
148
|
+
img.onload = () => resolve(img);
|
|
149
|
+
img.onerror = reject;
|
|
150
|
+
img.src = src;
|
|
151
|
+
});
|
|
152
|
+
}
|
|
151
153
|
|
|
152
154
|
// src/overlay/ui/icon.tsx
|
|
153
155
|
import { useRef, useCallback as useCallback2, useEffect, useState as useState2 } from "react";
|
|
@@ -366,327 +368,14 @@ function Icon({ phase, onClick, loading, onPositionChange }) {
|
|
|
366
368
|
);
|
|
367
369
|
}
|
|
368
370
|
|
|
369
|
-
// src/overlay/ui/menu.tsx
|
|
370
|
-
import { useEffect as useEffect2, useRef as useRef2, useCallback as useCallback3 } from "react";
|
|
371
|
-
import { jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
372
|
-
var modes = [
|
|
373
|
-
{
|
|
374
|
-
mode: "viewport",
|
|
375
|
-
label: "Viewport",
|
|
376
|
-
icon: /* @__PURE__ */ jsxs2("svg", { width: "18", height: "18", viewBox: "0 0 16 16", children: [
|
|
377
|
-
/* @__PURE__ */ jsx2(
|
|
378
|
-
"rect",
|
|
379
|
-
{
|
|
380
|
-
x: "1",
|
|
381
|
-
y: "2",
|
|
382
|
-
width: "14",
|
|
383
|
-
height: "11",
|
|
384
|
-
rx: "1.5",
|
|
385
|
-
fill: "none",
|
|
386
|
-
stroke: "currentColor",
|
|
387
|
-
strokeWidth: "1.5"
|
|
388
|
-
}
|
|
389
|
-
),
|
|
390
|
-
/* @__PURE__ */ jsx2(
|
|
391
|
-
"line",
|
|
392
|
-
{
|
|
393
|
-
x1: "1",
|
|
394
|
-
y1: "14",
|
|
395
|
-
x2: "15",
|
|
396
|
-
y2: "14",
|
|
397
|
-
stroke: "currentColor",
|
|
398
|
-
strokeWidth: "1.5",
|
|
399
|
-
strokeLinecap: "round"
|
|
400
|
-
}
|
|
401
|
-
)
|
|
402
|
-
] })
|
|
403
|
-
},
|
|
404
|
-
{
|
|
405
|
-
mode: "fullpage",
|
|
406
|
-
label: "Full Page",
|
|
407
|
-
icon: /* @__PURE__ */ jsxs2("svg", { width: "18", height: "18", viewBox: "0 0 16 16", children: [
|
|
408
|
-
/* @__PURE__ */ jsx2(
|
|
409
|
-
"rect",
|
|
410
|
-
{
|
|
411
|
-
x: "3",
|
|
412
|
-
y: "1",
|
|
413
|
-
width: "10",
|
|
414
|
-
height: "14",
|
|
415
|
-
rx: "1.5",
|
|
416
|
-
fill: "none",
|
|
417
|
-
stroke: "currentColor",
|
|
418
|
-
strokeWidth: "1.5"
|
|
419
|
-
}
|
|
420
|
-
),
|
|
421
|
-
/* @__PURE__ */ jsx2(
|
|
422
|
-
"line",
|
|
423
|
-
{
|
|
424
|
-
x1: "5.5",
|
|
425
|
-
y1: "4",
|
|
426
|
-
x2: "10.5",
|
|
427
|
-
y2: "4",
|
|
428
|
-
stroke: "currentColor",
|
|
429
|
-
strokeWidth: "1",
|
|
430
|
-
strokeLinecap: "round"
|
|
431
|
-
}
|
|
432
|
-
),
|
|
433
|
-
/* @__PURE__ */ jsx2(
|
|
434
|
-
"line",
|
|
435
|
-
{
|
|
436
|
-
x1: "5.5",
|
|
437
|
-
y1: "6.5",
|
|
438
|
-
x2: "10.5",
|
|
439
|
-
y2: "6.5",
|
|
440
|
-
stroke: "currentColor",
|
|
441
|
-
strokeWidth: "1",
|
|
442
|
-
strokeLinecap: "round"
|
|
443
|
-
}
|
|
444
|
-
),
|
|
445
|
-
/* @__PURE__ */ jsx2(
|
|
446
|
-
"line",
|
|
447
|
-
{
|
|
448
|
-
x1: "5.5",
|
|
449
|
-
y1: "9",
|
|
450
|
-
x2: "10.5",
|
|
451
|
-
y2: "9",
|
|
452
|
-
stroke: "currentColor",
|
|
453
|
-
strokeWidth: "1",
|
|
454
|
-
strokeLinecap: "round"
|
|
455
|
-
}
|
|
456
|
-
)
|
|
457
|
-
] })
|
|
458
|
-
},
|
|
459
|
-
{
|
|
460
|
-
mode: "area",
|
|
461
|
-
label: "Select Area",
|
|
462
|
-
icon: /* @__PURE__ */ jsxs2("svg", { width: "18", height: "18", viewBox: "0 0 16 16", children: [
|
|
463
|
-
/* @__PURE__ */ jsx2(
|
|
464
|
-
"path",
|
|
465
|
-
{
|
|
466
|
-
d: "M1 5V2.5A1.5 1.5 0 012.5 1H5",
|
|
467
|
-
fill: "none",
|
|
468
|
-
stroke: "currentColor",
|
|
469
|
-
strokeWidth: "1.5",
|
|
470
|
-
strokeLinecap: "round"
|
|
471
|
-
}
|
|
472
|
-
),
|
|
473
|
-
/* @__PURE__ */ jsx2(
|
|
474
|
-
"path",
|
|
475
|
-
{
|
|
476
|
-
d: "M11 1h2.5A1.5 1.5 0 0115 2.5V5",
|
|
477
|
-
fill: "none",
|
|
478
|
-
stroke: "currentColor",
|
|
479
|
-
strokeWidth: "1.5",
|
|
480
|
-
strokeLinecap: "round"
|
|
481
|
-
}
|
|
482
|
-
),
|
|
483
|
-
/* @__PURE__ */ jsx2(
|
|
484
|
-
"path",
|
|
485
|
-
{
|
|
486
|
-
d: "M15 11v2.5a1.5 1.5 0 01-1.5 1.5H11",
|
|
487
|
-
fill: "none",
|
|
488
|
-
stroke: "currentColor",
|
|
489
|
-
strokeWidth: "1.5",
|
|
490
|
-
strokeLinecap: "round"
|
|
491
|
-
}
|
|
492
|
-
),
|
|
493
|
-
/* @__PURE__ */ jsx2(
|
|
494
|
-
"path",
|
|
495
|
-
{
|
|
496
|
-
d: "M5 15H2.5A1.5 1.5 0 011 13.5V11",
|
|
497
|
-
fill: "none",
|
|
498
|
-
stroke: "currentColor",
|
|
499
|
-
strokeWidth: "1.5",
|
|
500
|
-
strokeLinecap: "round"
|
|
501
|
-
}
|
|
502
|
-
)
|
|
503
|
-
] })
|
|
504
|
-
},
|
|
505
|
-
{
|
|
506
|
-
mode: "component",
|
|
507
|
-
label: "Component",
|
|
508
|
-
icon: /* @__PURE__ */ jsxs2("svg", { width: "18", height: "18", viewBox: "0 0 16 16", children: [
|
|
509
|
-
/* @__PURE__ */ jsx2(
|
|
510
|
-
"path",
|
|
511
|
-
{
|
|
512
|
-
d: "M3 2l2.5 10 2-3.5L11 11 3 2z",
|
|
513
|
-
fill: "none",
|
|
514
|
-
stroke: "currentColor",
|
|
515
|
-
strokeWidth: "1.3",
|
|
516
|
-
strokeLinejoin: "round",
|
|
517
|
-
strokeLinecap: "round"
|
|
518
|
-
}
|
|
519
|
-
),
|
|
520
|
-
/* @__PURE__ */ jsx2(
|
|
521
|
-
"rect",
|
|
522
|
-
{
|
|
523
|
-
x: "8",
|
|
524
|
-
y: "5",
|
|
525
|
-
width: "6.5",
|
|
526
|
-
height: "6.5",
|
|
527
|
-
rx: "1",
|
|
528
|
-
fill: "none",
|
|
529
|
-
stroke: "currentColor",
|
|
530
|
-
strokeWidth: "1.2",
|
|
531
|
-
strokeDasharray: "2 1.5"
|
|
532
|
-
}
|
|
533
|
-
)
|
|
534
|
-
] })
|
|
535
|
-
}
|
|
536
|
-
];
|
|
537
|
-
var PILL_WIDTH = 270;
|
|
538
|
-
var BTN_SIZE = 40;
|
|
539
|
-
function Menu({ onSelect, onClose, position }) {
|
|
540
|
-
const menuRef = useRef2(null);
|
|
541
|
-
const handleClickOutside = useCallback3(
|
|
542
|
-
(e) => {
|
|
543
|
-
if (menuRef.current && !menuRef.current.contains(e.target)) {
|
|
544
|
-
onClose();
|
|
545
|
-
}
|
|
546
|
-
},
|
|
547
|
-
[onClose]
|
|
548
|
-
);
|
|
549
|
-
const handleKeyDown = useCallback3(
|
|
550
|
-
(e) => {
|
|
551
|
-
if (e.key === "Escape") {
|
|
552
|
-
onClose();
|
|
553
|
-
}
|
|
554
|
-
},
|
|
555
|
-
[onClose]
|
|
556
|
-
);
|
|
557
|
-
useEffect2(() => {
|
|
558
|
-
document.addEventListener("mousedown", handleClickOutside);
|
|
559
|
-
document.addEventListener("keydown", handleKeyDown);
|
|
560
|
-
return () => {
|
|
561
|
-
document.removeEventListener("mousedown", handleClickOutside);
|
|
562
|
-
document.removeEventListener("keydown", handleKeyDown);
|
|
563
|
-
};
|
|
564
|
-
}, [handleClickOutside, handleKeyDown]);
|
|
565
|
-
const menuLeft = Math.max(
|
|
566
|
-
8,
|
|
567
|
-
Math.min(position.x - PILL_WIDTH / 2 + 20, window.innerWidth - PILL_WIDTH - 8)
|
|
568
|
-
);
|
|
569
|
-
const menuBottom = window.innerHeight - position.y + 8;
|
|
570
|
-
return /* @__PURE__ */ jsxs2(
|
|
571
|
-
"div",
|
|
572
|
-
{
|
|
573
|
-
ref: menuRef,
|
|
574
|
-
"data-afterbefore": "true",
|
|
575
|
-
style: {
|
|
576
|
-
position: "fixed",
|
|
577
|
-
left: menuLeft,
|
|
578
|
-
bottom: menuBottom,
|
|
579
|
-
display: "flex",
|
|
580
|
-
alignItems: "center",
|
|
581
|
-
gap: 4,
|
|
582
|
-
background: "rgba(24, 24, 27, 0.95)",
|
|
583
|
-
borderRadius: 22,
|
|
584
|
-
padding: "5px 6px",
|
|
585
|
-
boxShadow: "0 4px 20px rgba(0,0,0,0.4), 0 0 0 1px rgba(255,255,255,0.08)",
|
|
586
|
-
zIndex: 2147483647,
|
|
587
|
-
fontFamily: "system-ui, -apple-system, sans-serif",
|
|
588
|
-
backdropFilter: "blur(12px)"
|
|
589
|
-
},
|
|
590
|
-
children: [
|
|
591
|
-
modes.map(({ mode, label, icon }) => /* @__PURE__ */ jsx2(
|
|
592
|
-
"button",
|
|
593
|
-
{
|
|
594
|
-
title: label,
|
|
595
|
-
onClick: () => onSelect(mode),
|
|
596
|
-
style: {
|
|
597
|
-
display: "flex",
|
|
598
|
-
alignItems: "center",
|
|
599
|
-
justifyContent: "center",
|
|
600
|
-
width: BTN_SIZE,
|
|
601
|
-
height: BTN_SIZE,
|
|
602
|
-
border: "none",
|
|
603
|
-
background: "transparent",
|
|
604
|
-
color: "rgba(255,255,255,0.7)",
|
|
605
|
-
borderRadius: "50%",
|
|
606
|
-
cursor: "pointer",
|
|
607
|
-
padding: 0,
|
|
608
|
-
transition: "background 0.1s, color 0.1s",
|
|
609
|
-
flexShrink: 0
|
|
610
|
-
},
|
|
611
|
-
onMouseEnter: (e) => {
|
|
612
|
-
const btn = e.currentTarget;
|
|
613
|
-
btn.style.background = "rgba(255,255,255,0.12)";
|
|
614
|
-
btn.style.color = "rgba(255,255,255,1)";
|
|
615
|
-
},
|
|
616
|
-
onMouseLeave: (e) => {
|
|
617
|
-
const btn = e.currentTarget;
|
|
618
|
-
btn.style.background = "transparent";
|
|
619
|
-
btn.style.color = "rgba(255,255,255,0.7)";
|
|
620
|
-
},
|
|
621
|
-
children: icon
|
|
622
|
-
},
|
|
623
|
-
mode
|
|
624
|
-
)),
|
|
625
|
-
/* @__PURE__ */ jsx2(
|
|
626
|
-
"div",
|
|
627
|
-
{
|
|
628
|
-
style: {
|
|
629
|
-
width: 1,
|
|
630
|
-
height: 24,
|
|
631
|
-
background: "rgba(255,255,255,0.12)",
|
|
632
|
-
flexShrink: 0,
|
|
633
|
-
margin: "0 2px"
|
|
634
|
-
}
|
|
635
|
-
}
|
|
636
|
-
),
|
|
637
|
-
/* @__PURE__ */ jsx2(
|
|
638
|
-
"button",
|
|
639
|
-
{
|
|
640
|
-
title: "Close",
|
|
641
|
-
onClick: onClose,
|
|
642
|
-
style: {
|
|
643
|
-
display: "flex",
|
|
644
|
-
alignItems: "center",
|
|
645
|
-
justifyContent: "center",
|
|
646
|
-
width: BTN_SIZE,
|
|
647
|
-
height: BTN_SIZE,
|
|
648
|
-
border: "none",
|
|
649
|
-
background: "transparent",
|
|
650
|
-
color: "rgba(255,255,255,0.45)",
|
|
651
|
-
borderRadius: "50%",
|
|
652
|
-
cursor: "pointer",
|
|
653
|
-
padding: 0,
|
|
654
|
-
transition: "background 0.1s, color 0.1s",
|
|
655
|
-
flexShrink: 0
|
|
656
|
-
},
|
|
657
|
-
onMouseEnter: (e) => {
|
|
658
|
-
const btn = e.currentTarget;
|
|
659
|
-
btn.style.background = "rgba(255,255,255,0.12)";
|
|
660
|
-
btn.style.color = "rgba(255,255,255,0.9)";
|
|
661
|
-
},
|
|
662
|
-
onMouseLeave: (e) => {
|
|
663
|
-
const btn = e.currentTarget;
|
|
664
|
-
btn.style.background = "transparent";
|
|
665
|
-
btn.style.color = "rgba(255,255,255,0.45)";
|
|
666
|
-
},
|
|
667
|
-
children: /* @__PURE__ */ jsx2("svg", { width: "16", height: "16", viewBox: "0 0 14 14", children: /* @__PURE__ */ jsx2(
|
|
668
|
-
"path",
|
|
669
|
-
{
|
|
670
|
-
d: "M3 3l8 8M11 3l-8 8",
|
|
671
|
-
stroke: "currentColor",
|
|
672
|
-
strokeWidth: "1.5",
|
|
673
|
-
strokeLinecap: "round"
|
|
674
|
-
}
|
|
675
|
-
) })
|
|
676
|
-
}
|
|
677
|
-
)
|
|
678
|
-
]
|
|
679
|
-
}
|
|
680
|
-
);
|
|
681
|
-
}
|
|
682
|
-
|
|
683
371
|
// src/overlay/ui/selector.tsx
|
|
684
|
-
import
|
|
685
|
-
import { Fragment, jsx as
|
|
372
|
+
import React2, { useState as useState3, useRef as useRef2, useCallback as useCallback3, useEffect as useEffect2 } from "react";
|
|
373
|
+
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
686
374
|
var HANDLE_R = 6;
|
|
687
375
|
var HANDLE_HIT = 16;
|
|
688
376
|
var MIN_SIZE = 20;
|
|
689
377
|
var PANEL_HEIGHT_EST = 140;
|
|
378
|
+
var SNAP_THRESHOLD = 8;
|
|
690
379
|
var ASPECT_RATIOS = [
|
|
691
380
|
{ label: "Free", value: 0 },
|
|
692
381
|
{ label: "16:9", value: 16 / 9 },
|
|
@@ -695,7 +384,7 @@ var ASPECT_RATIOS = [
|
|
|
695
384
|
{ label: "3:2", value: 3 / 2 },
|
|
696
385
|
{ label: "21:9", value: 21 / 9 }
|
|
697
386
|
];
|
|
698
|
-
function Selector({ onSelect, onCancel }) {
|
|
387
|
+
function Selector({ onSelect, onCancel, onViewport, onFullPage, onComponent }) {
|
|
699
388
|
const [rect, setRect] = useState3(null);
|
|
700
389
|
const [placed, setPlaced] = useState3(false);
|
|
701
390
|
const [aspect, setAspect] = useState3("Free");
|
|
@@ -712,13 +401,39 @@ function Selector({ onSelect, onCancel }) {
|
|
|
712
401
|
}
|
|
713
402
|
);
|
|
714
403
|
const [cursor, setCursor] = useState3("crosshair");
|
|
715
|
-
const
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
404
|
+
const [magnet, setMagnet] = useState3(() => {
|
|
405
|
+
try {
|
|
406
|
+
return localStorage.getItem("ab-magnet") !== "false";
|
|
407
|
+
} catch {
|
|
408
|
+
return true;
|
|
409
|
+
}
|
|
410
|
+
});
|
|
411
|
+
const [snappedX, setSnappedX] = useState3(false);
|
|
412
|
+
const mode = useRef2("none");
|
|
413
|
+
const start = useRef2({ x: 0, y: 0 });
|
|
414
|
+
const snapRef = useRef2({ x: 0, y: 0, w: 0, h: 0 });
|
|
415
|
+
const corner = useRef2("br");
|
|
416
|
+
const panelRef = useRef2(null);
|
|
720
417
|
const ratio = ASPECT_RATIOS.find((a) => a.label === aspect)?.value ?? 0;
|
|
721
|
-
|
|
418
|
+
const applySnap = useCallback3(
|
|
419
|
+
(r) => {
|
|
420
|
+
if (!magnet) {
|
|
421
|
+
setSnappedX(false);
|
|
422
|
+
return r;
|
|
423
|
+
}
|
|
424
|
+
const vw = window.innerWidth;
|
|
425
|
+
const centerX = r.x + r.w / 2;
|
|
426
|
+
const viewCenterX = vw / 2;
|
|
427
|
+
if (Math.abs(centerX - viewCenterX) < SNAP_THRESHOLD) {
|
|
428
|
+
setSnappedX(true);
|
|
429
|
+
return { ...r, x: viewCenterX - r.w / 2 };
|
|
430
|
+
}
|
|
431
|
+
setSnappedX(false);
|
|
432
|
+
return r;
|
|
433
|
+
},
|
|
434
|
+
[magnet]
|
|
435
|
+
);
|
|
436
|
+
useEffect2(() => {
|
|
722
437
|
const onKey = (e) => {
|
|
723
438
|
if (e.target?.tagName === "INPUT") {
|
|
724
439
|
if (e.key === "Escape") e.target.blur();
|
|
@@ -743,7 +458,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
743
458
|
document.addEventListener("keydown", onKey);
|
|
744
459
|
return () => document.removeEventListener("keydown", onKey);
|
|
745
460
|
}, [placed, rect, onSelect, onCancel]);
|
|
746
|
-
const hitCorner =
|
|
461
|
+
const hitCorner = useCallback3(
|
|
747
462
|
(mx, my, r) => {
|
|
748
463
|
const cs = [
|
|
749
464
|
["tl", r.x, r.y],
|
|
@@ -759,11 +474,11 @@ function Selector({ onSelect, onCancel }) {
|
|
|
759
474
|
},
|
|
760
475
|
[]
|
|
761
476
|
);
|
|
762
|
-
const hitInside =
|
|
477
|
+
const hitInside = useCallback3(
|
|
763
478
|
(mx, my, r) => mx >= r.x && mx <= r.x + r.w && my >= r.y && my <= r.y + r.h,
|
|
764
479
|
[]
|
|
765
480
|
);
|
|
766
|
-
const onDown =
|
|
481
|
+
const onDown = useCallback3(
|
|
767
482
|
(e) => {
|
|
768
483
|
if (panelRef.current?.contains(e.target)) return;
|
|
769
484
|
e.preventDefault();
|
|
@@ -776,13 +491,13 @@ function Selector({ onSelect, onCancel }) {
|
|
|
776
491
|
mode.current = "resizing";
|
|
777
492
|
corner.current = c;
|
|
778
493
|
start.current = { x: mx, y: my };
|
|
779
|
-
|
|
494
|
+
snapRef.current = { ...rect };
|
|
780
495
|
return;
|
|
781
496
|
}
|
|
782
497
|
if (hitInside(mx, my, rect)) {
|
|
783
498
|
mode.current = "moving";
|
|
784
499
|
start.current = { x: mx, y: my };
|
|
785
|
-
|
|
500
|
+
snapRef.current = { ...rect };
|
|
786
501
|
return;
|
|
787
502
|
}
|
|
788
503
|
setPlaced(false);
|
|
@@ -793,7 +508,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
793
508
|
},
|
|
794
509
|
[placed, rect, hitCorner, hitInside]
|
|
795
510
|
);
|
|
796
|
-
const onMove =
|
|
511
|
+
const onMove = useCallback3(
|
|
797
512
|
(e) => {
|
|
798
513
|
const mx = e.clientX, my = e.clientY;
|
|
799
514
|
if (mode.current === "drawing") {
|
|
@@ -804,16 +519,18 @@ function Selector({ onSelect, onCancel }) {
|
|
|
804
519
|
h = w / ratio;
|
|
805
520
|
if (my < sy) y = sy - h;
|
|
806
521
|
}
|
|
807
|
-
setRect({ x, y, w, h });
|
|
522
|
+
setRect(applySnap({ x, y, w, h }));
|
|
808
523
|
} else if (mode.current === "moving") {
|
|
809
524
|
const dx = mx - start.current.x, dy = my - start.current.y;
|
|
810
|
-
setRect(
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
525
|
+
setRect(
|
|
526
|
+
applySnap({
|
|
527
|
+
...snapRef.current,
|
|
528
|
+
x: snapRef.current.x + dx,
|
|
529
|
+
y: snapRef.current.y + dy
|
|
530
|
+
})
|
|
531
|
+
);
|
|
815
532
|
} else if (mode.current === "resizing") {
|
|
816
|
-
const o =
|
|
533
|
+
const o = snapRef.current;
|
|
817
534
|
const c = corner.current;
|
|
818
535
|
const nr = { ...o };
|
|
819
536
|
if (c === "br") {
|
|
@@ -833,7 +550,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
833
550
|
nr.x = o.x + o.w - nr.w;
|
|
834
551
|
nr.y = o.y + o.h - nr.h;
|
|
835
552
|
}
|
|
836
|
-
setRect(nr);
|
|
553
|
+
setRect(applySnap(nr));
|
|
837
554
|
} else if (placed && rect) {
|
|
838
555
|
const c = hitCorner(mx, my, rect);
|
|
839
556
|
if (c === "tl" || c === "br") setCursor("nwse-resize");
|
|
@@ -842,9 +559,9 @@ function Selector({ onSelect, onCancel }) {
|
|
|
842
559
|
else setCursor("crosshair");
|
|
843
560
|
}
|
|
844
561
|
},
|
|
845
|
-
[ratio, placed, rect, hitCorner, hitInside]
|
|
562
|
+
[ratio, placed, rect, hitCorner, hitInside, applySnap]
|
|
846
563
|
);
|
|
847
|
-
const onUp =
|
|
564
|
+
const onUp = useCallback3(
|
|
848
565
|
(e) => {
|
|
849
566
|
const prevMode = mode.current;
|
|
850
567
|
if (prevMode === "drawing" && rect) {
|
|
@@ -870,7 +587,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
870
587
|
},
|
|
871
588
|
[rect, placed, onSelect]
|
|
872
589
|
);
|
|
873
|
-
const setSize =
|
|
590
|
+
const setSize = useCallback3(
|
|
874
591
|
(field, v) => {
|
|
875
592
|
const n = parseInt(v, 10);
|
|
876
593
|
if (isNaN(n) || n < MIN_SIZE || !rect) return;
|
|
@@ -882,7 +599,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
882
599
|
},
|
|
883
600
|
[rect, ratio]
|
|
884
601
|
);
|
|
885
|
-
const setPos =
|
|
602
|
+
const setPos = useCallback3(
|
|
886
603
|
(field, v) => {
|
|
887
604
|
const n = parseInt(v, 10);
|
|
888
605
|
if (isNaN(n) || !rect) return;
|
|
@@ -890,7 +607,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
890
607
|
},
|
|
891
608
|
[rect]
|
|
892
609
|
);
|
|
893
|
-
const savePreset =
|
|
610
|
+
const savePreset = useCallback3(() => {
|
|
894
611
|
if (!rect) return;
|
|
895
612
|
const label = `${Math.round(rect.w)}\xD7${Math.round(rect.h)}`;
|
|
896
613
|
const next = [
|
|
@@ -904,7 +621,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
904
621
|
}
|
|
905
622
|
setSavedOpen(false);
|
|
906
623
|
}, [rect, presets]);
|
|
907
|
-
const loadPreset =
|
|
624
|
+
const loadPreset = useCallback3((p) => {
|
|
908
625
|
setRect({ ...p.rect });
|
|
909
626
|
setPlaced(true);
|
|
910
627
|
setSavedOpen(false);
|
|
@@ -912,7 +629,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
912
629
|
const activeCursor = mode.current === "moving" ? "move" : mode.current === "resizing" ? "nwse-resize" : mode.current === "drawing" ? "crosshair" : cursor;
|
|
913
630
|
const panelAbove = rect && rect.y + rect.h + PANEL_HEIGHT_EST > window.innerHeight;
|
|
914
631
|
const hasRect = rect && rect.w > 0 && rect.h > 0;
|
|
915
|
-
return /* @__PURE__ */
|
|
632
|
+
return /* @__PURE__ */ jsxs2(
|
|
916
633
|
"div",
|
|
917
634
|
{
|
|
918
635
|
"data-afterbefore": "true",
|
|
@@ -926,7 +643,22 @@ function Selector({ onSelect, onCancel }) {
|
|
|
926
643
|
cursor: activeCursor
|
|
927
644
|
},
|
|
928
645
|
children: [
|
|
929
|
-
/* @__PURE__ */
|
|
646
|
+
snappedX && /* @__PURE__ */ jsx2(
|
|
647
|
+
"div",
|
|
648
|
+
{
|
|
649
|
+
style: {
|
|
650
|
+
position: "absolute",
|
|
651
|
+
left: "50%",
|
|
652
|
+
top: 0,
|
|
653
|
+
bottom: 0,
|
|
654
|
+
width: 0,
|
|
655
|
+
borderLeft: "1px solid rgba(147, 130, 220, 0.5)",
|
|
656
|
+
pointerEvents: "none",
|
|
657
|
+
zIndex: 2
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
),
|
|
661
|
+
/* @__PURE__ */ jsx2(
|
|
930
662
|
"div",
|
|
931
663
|
{
|
|
932
664
|
style: {
|
|
@@ -947,8 +679,8 @@ function Selector({ onSelect, onCancel }) {
|
|
|
947
679
|
}
|
|
948
680
|
}
|
|
949
681
|
),
|
|
950
|
-
hasRect && /* @__PURE__ */
|
|
951
|
-
/* @__PURE__ */
|
|
682
|
+
hasRect && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
683
|
+
/* @__PURE__ */ jsx2(
|
|
952
684
|
"div",
|
|
953
685
|
{
|
|
954
686
|
style: {
|
|
@@ -962,8 +694,8 @@ function Selector({ onSelect, onCancel }) {
|
|
|
962
694
|
}
|
|
963
695
|
}
|
|
964
696
|
),
|
|
965
|
-
placed && [1, 2].map((i) => /* @__PURE__ */
|
|
966
|
-
/* @__PURE__ */
|
|
697
|
+
placed && [1, 2].map((i) => /* @__PURE__ */ jsxs2(React2.Fragment, { children: [
|
|
698
|
+
/* @__PURE__ */ jsx2(
|
|
967
699
|
"div",
|
|
968
700
|
{
|
|
969
701
|
style: {
|
|
@@ -977,7 +709,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
977
709
|
}
|
|
978
710
|
}
|
|
979
711
|
),
|
|
980
|
-
/* @__PURE__ */
|
|
712
|
+
/* @__PURE__ */ jsx2(
|
|
981
713
|
"div",
|
|
982
714
|
{
|
|
983
715
|
style: {
|
|
@@ -997,7 +729,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
997
729
|
[rect.x + rect.w, rect.y],
|
|
998
730
|
[rect.x, rect.y + rect.h],
|
|
999
731
|
[rect.x + rect.w, rect.y + rect.h]
|
|
1000
|
-
].map(([cx, cy], i) => /* @__PURE__ */
|
|
732
|
+
].map(([cx, cy], i) => /* @__PURE__ */ jsx2(
|
|
1001
733
|
"div",
|
|
1002
734
|
{
|
|
1003
735
|
style: {
|
|
@@ -1014,7 +746,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1014
746
|
},
|
|
1015
747
|
i
|
|
1016
748
|
)),
|
|
1017
|
-
placed && /* @__PURE__ */
|
|
749
|
+
placed && /* @__PURE__ */ jsxs2(
|
|
1018
750
|
"div",
|
|
1019
751
|
{
|
|
1020
752
|
ref: panelRef,
|
|
@@ -1040,43 +772,43 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1040
772
|
zIndex: 1
|
|
1041
773
|
},
|
|
1042
774
|
children: [
|
|
1043
|
-
/* @__PURE__ */
|
|
1044
|
-
/* @__PURE__ */
|
|
775
|
+
/* @__PURE__ */ jsxs2(Row, { label: "Size", children: [
|
|
776
|
+
/* @__PURE__ */ jsx2(
|
|
1045
777
|
NumInput,
|
|
1046
778
|
{
|
|
1047
779
|
value: Math.round(rect.w),
|
|
1048
780
|
onChange: (v) => setSize("w", v)
|
|
1049
781
|
}
|
|
1050
782
|
),
|
|
1051
|
-
/* @__PURE__ */
|
|
1052
|
-
/* @__PURE__ */
|
|
783
|
+
/* @__PURE__ */ jsx2(Sep, { children: "\xD7" }),
|
|
784
|
+
/* @__PURE__ */ jsx2(
|
|
1053
785
|
NumInput,
|
|
1054
786
|
{
|
|
1055
787
|
value: Math.round(rect.h),
|
|
1056
788
|
onChange: (v) => setSize("h", v)
|
|
1057
789
|
}
|
|
1058
790
|
),
|
|
1059
|
-
/* @__PURE__ */
|
|
791
|
+
/* @__PURE__ */ jsx2(Unit, { children: "px" })
|
|
1060
792
|
] }),
|
|
1061
|
-
/* @__PURE__ */
|
|
1062
|
-
/* @__PURE__ */
|
|
793
|
+
/* @__PURE__ */ jsxs2(Row, { label: "Position", children: [
|
|
794
|
+
/* @__PURE__ */ jsx2(
|
|
1063
795
|
NumInput,
|
|
1064
796
|
{
|
|
1065
797
|
value: Math.round(rect.x),
|
|
1066
798
|
onChange: (v) => setPos("x", v)
|
|
1067
799
|
}
|
|
1068
800
|
),
|
|
1069
|
-
/* @__PURE__ */
|
|
1070
|
-
/* @__PURE__ */
|
|
801
|
+
/* @__PURE__ */ jsx2(Sep, {}),
|
|
802
|
+
/* @__PURE__ */ jsx2(
|
|
1071
803
|
NumInput,
|
|
1072
804
|
{
|
|
1073
805
|
value: Math.round(rect.y),
|
|
1074
806
|
onChange: (v) => setPos("y", v)
|
|
1075
807
|
}
|
|
1076
808
|
),
|
|
1077
|
-
/* @__PURE__ */
|
|
809
|
+
/* @__PURE__ */ jsx2(Unit, { children: "px" })
|
|
1078
810
|
] }),
|
|
1079
|
-
/* @__PURE__ */
|
|
811
|
+
/* @__PURE__ */ jsx2(
|
|
1080
812
|
"div",
|
|
1081
813
|
{
|
|
1082
814
|
style: {
|
|
@@ -1086,13 +818,13 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1086
818
|
}
|
|
1087
819
|
}
|
|
1088
820
|
),
|
|
1089
|
-
/* @__PURE__ */
|
|
821
|
+
/* @__PURE__ */ jsxs2(
|
|
1090
822
|
"div",
|
|
1091
823
|
{
|
|
1092
824
|
style: { display: "flex", alignItems: "center", gap: 12 },
|
|
1093
825
|
children: [
|
|
1094
|
-
/* @__PURE__ */
|
|
1095
|
-
/* @__PURE__ */
|
|
826
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
827
|
+
/* @__PURE__ */ jsxs2(
|
|
1096
828
|
DropBtn,
|
|
1097
829
|
{
|
|
1098
830
|
active: aspect !== "Free",
|
|
@@ -1101,13 +833,13 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1101
833
|
setSavedOpen(false);
|
|
1102
834
|
},
|
|
1103
835
|
children: [
|
|
1104
|
-
/* @__PURE__ */
|
|
836
|
+
/* @__PURE__ */ jsx2(AspectIcon, {}),
|
|
1105
837
|
aspect === "Free" ? "Free" : aspect,
|
|
1106
|
-
/* @__PURE__ */
|
|
838
|
+
/* @__PURE__ */ jsx2(Chevron, {})
|
|
1107
839
|
]
|
|
1108
840
|
}
|
|
1109
841
|
),
|
|
1110
|
-
aspectOpen && /* @__PURE__ */
|
|
842
|
+
aspectOpen && /* @__PURE__ */ jsx2(DropMenu, { children: ASPECT_RATIOS.map((ar) => /* @__PURE__ */ jsx2(
|
|
1111
843
|
DropItem,
|
|
1112
844
|
{
|
|
1113
845
|
active: ar.label === aspect,
|
|
@@ -1123,8 +855,8 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1123
855
|
ar.label
|
|
1124
856
|
)) })
|
|
1125
857
|
] }),
|
|
1126
|
-
/* @__PURE__ */
|
|
1127
|
-
/* @__PURE__ */
|
|
858
|
+
/* @__PURE__ */ jsxs2("div", { style: { position: "relative" }, children: [
|
|
859
|
+
/* @__PURE__ */ jsxs2(
|
|
1128
860
|
DropBtn,
|
|
1129
861
|
{
|
|
1130
862
|
onClick: () => {
|
|
@@ -1132,14 +864,14 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1132
864
|
setAspectOpen(false);
|
|
1133
865
|
},
|
|
1134
866
|
children: [
|
|
1135
|
-
/* @__PURE__ */
|
|
867
|
+
/* @__PURE__ */ jsx2(SavedIcon, {}),
|
|
1136
868
|
"Saved",
|
|
1137
|
-
/* @__PURE__ */
|
|
869
|
+
/* @__PURE__ */ jsx2(Chevron, {})
|
|
1138
870
|
]
|
|
1139
871
|
}
|
|
1140
872
|
),
|
|
1141
|
-
savedOpen && /* @__PURE__ */
|
|
1142
|
-
/* @__PURE__ */
|
|
873
|
+
savedOpen && /* @__PURE__ */ jsxs2(DropMenu, { children: [
|
|
874
|
+
/* @__PURE__ */ jsx2(
|
|
1143
875
|
DropItem,
|
|
1144
876
|
{
|
|
1145
877
|
accent: true,
|
|
@@ -1147,7 +879,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1147
879
|
children: "Save current"
|
|
1148
880
|
}
|
|
1149
881
|
),
|
|
1150
|
-
presets.length > 0 && /* @__PURE__ */
|
|
882
|
+
presets.length > 0 && /* @__PURE__ */ jsx2(
|
|
1151
883
|
"div",
|
|
1152
884
|
{
|
|
1153
885
|
style: {
|
|
@@ -1157,7 +889,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1157
889
|
}
|
|
1158
890
|
}
|
|
1159
891
|
),
|
|
1160
|
-
presets.map((p) => /* @__PURE__ */
|
|
892
|
+
presets.map((p) => /* @__PURE__ */ jsx2(
|
|
1161
893
|
DropItem,
|
|
1162
894
|
{
|
|
1163
895
|
onClick: () => loadPreset(p),
|
|
@@ -1165,7 +897,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1165
897
|
},
|
|
1166
898
|
p.label
|
|
1167
899
|
)),
|
|
1168
|
-
presets.length === 0 && /* @__PURE__ */
|
|
900
|
+
presets.length === 0 && /* @__PURE__ */ jsx2(
|
|
1169
901
|
"div",
|
|
1170
902
|
{
|
|
1171
903
|
style: {
|
|
@@ -1181,7 +913,63 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1181
913
|
]
|
|
1182
914
|
}
|
|
1183
915
|
),
|
|
1184
|
-
/* @__PURE__ */
|
|
916
|
+
(onViewport || onFullPage || onComponent) && /* @__PURE__ */ jsxs2(Fragment, { children: [
|
|
917
|
+
/* @__PURE__ */ jsx2(
|
|
918
|
+
"div",
|
|
919
|
+
{
|
|
920
|
+
style: {
|
|
921
|
+
height: 1,
|
|
922
|
+
background: "rgba(255, 255, 255, 0.08)",
|
|
923
|
+
margin: "1px 0"
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
),
|
|
927
|
+
/* @__PURE__ */ jsxs2(
|
|
928
|
+
"div",
|
|
929
|
+
{
|
|
930
|
+
style: { display: "flex", alignItems: "center", gap: 4 },
|
|
931
|
+
children: [
|
|
932
|
+
onViewport && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onViewport, children: [
|
|
933
|
+
/* @__PURE__ */ jsx2(ViewportIcon, {}),
|
|
934
|
+
"Viewport"
|
|
935
|
+
] }),
|
|
936
|
+
onFullPage && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onFullPage, children: [
|
|
937
|
+
/* @__PURE__ */ jsx2(FullPageIcon, {}),
|
|
938
|
+
"Full Page"
|
|
939
|
+
] }),
|
|
940
|
+
onComponent && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onComponent, children: [
|
|
941
|
+
/* @__PURE__ */ jsx2(ComponentIcon, {}),
|
|
942
|
+
"Component"
|
|
943
|
+
] })
|
|
944
|
+
]
|
|
945
|
+
}
|
|
946
|
+
)
|
|
947
|
+
] }),
|
|
948
|
+
/* @__PURE__ */ jsx2(
|
|
949
|
+
"div",
|
|
950
|
+
{
|
|
951
|
+
style: {
|
|
952
|
+
display: "flex",
|
|
953
|
+
alignItems: "center",
|
|
954
|
+
gap: 6
|
|
955
|
+
},
|
|
956
|
+
children: /* @__PURE__ */ jsx2(
|
|
957
|
+
MagnetToggle,
|
|
958
|
+
{
|
|
959
|
+
enabled: magnet,
|
|
960
|
+
onToggle: () => {
|
|
961
|
+
const next = !magnet;
|
|
962
|
+
setMagnet(next);
|
|
963
|
+
try {
|
|
964
|
+
localStorage.setItem("ab-magnet", String(next));
|
|
965
|
+
} catch {
|
|
966
|
+
}
|
|
967
|
+
}
|
|
968
|
+
}
|
|
969
|
+
)
|
|
970
|
+
}
|
|
971
|
+
),
|
|
972
|
+
/* @__PURE__ */ jsx2(
|
|
1185
973
|
"div",
|
|
1186
974
|
{
|
|
1187
975
|
style: {
|
|
@@ -1195,7 +983,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1195
983
|
]
|
|
1196
984
|
}
|
|
1197
985
|
),
|
|
1198
|
-
!placed && /* @__PURE__ */
|
|
986
|
+
!placed && /* @__PURE__ */ jsxs2(
|
|
1199
987
|
"div",
|
|
1200
988
|
{
|
|
1201
989
|
style: {
|
|
@@ -1220,7 +1008,7 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1220
1008
|
}
|
|
1221
1009
|
)
|
|
1222
1010
|
] }),
|
|
1223
|
-
!rect && /* @__PURE__ */
|
|
1011
|
+
!rect && /* @__PURE__ */ jsxs2(
|
|
1224
1012
|
"div",
|
|
1225
1013
|
{
|
|
1226
1014
|
style: {
|
|
@@ -1228,13 +1016,57 @@ function Selector({ onSelect, onCancel }) {
|
|
|
1228
1016
|
top: "50%",
|
|
1229
1017
|
left: "50%",
|
|
1230
1018
|
transform: "translate(-50%, -50%)",
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1019
|
+
display: "flex",
|
|
1020
|
+
flexDirection: "column",
|
|
1021
|
+
alignItems: "center",
|
|
1022
|
+
gap: 16,
|
|
1023
|
+
fontFamily: "system-ui, -apple-system, sans-serif"
|
|
1236
1024
|
},
|
|
1237
|
-
children:
|
|
1025
|
+
children: [
|
|
1026
|
+
/* @__PURE__ */ jsx2(
|
|
1027
|
+
"div",
|
|
1028
|
+
{
|
|
1029
|
+
style: {
|
|
1030
|
+
color: "rgba(255, 255, 255, 0.7)",
|
|
1031
|
+
fontSize: 14,
|
|
1032
|
+
pointerEvents: "none",
|
|
1033
|
+
textShadow: "0 1px 4px rgba(0, 0, 0, 0.5)"
|
|
1034
|
+
},
|
|
1035
|
+
children: "Drag to select an area \xB7 Esc to cancel"
|
|
1036
|
+
}
|
|
1037
|
+
),
|
|
1038
|
+
(onViewport || onFullPage || onComponent) && /* @__PURE__ */ jsxs2(
|
|
1039
|
+
"div",
|
|
1040
|
+
{
|
|
1041
|
+
onMouseDown: (e) => e.stopPropagation(),
|
|
1042
|
+
style: {
|
|
1043
|
+
display: "flex",
|
|
1044
|
+
alignItems: "center",
|
|
1045
|
+
gap: 4,
|
|
1046
|
+
background: "rgba(32, 32, 36, 0.92)",
|
|
1047
|
+
backdropFilter: "blur(20px)",
|
|
1048
|
+
WebkitBackdropFilter: "blur(20px)",
|
|
1049
|
+
border: "1px solid rgba(255, 255, 255, 0.1)",
|
|
1050
|
+
borderRadius: 8,
|
|
1051
|
+
padding: "6px 8px"
|
|
1052
|
+
},
|
|
1053
|
+
children: [
|
|
1054
|
+
onViewport && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onViewport, children: [
|
|
1055
|
+
/* @__PURE__ */ jsx2(ViewportIcon, {}),
|
|
1056
|
+
"Viewport"
|
|
1057
|
+
] }),
|
|
1058
|
+
onFullPage && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onFullPage, children: [
|
|
1059
|
+
/* @__PURE__ */ jsx2(FullPageIcon, {}),
|
|
1060
|
+
"Full Page"
|
|
1061
|
+
] }),
|
|
1062
|
+
onComponent && /* @__PURE__ */ jsxs2(ModeBtn, { onClick: onComponent, children: [
|
|
1063
|
+
/* @__PURE__ */ jsx2(ComponentIcon, {}),
|
|
1064
|
+
"Component"
|
|
1065
|
+
] })
|
|
1066
|
+
]
|
|
1067
|
+
}
|
|
1068
|
+
)
|
|
1069
|
+
]
|
|
1238
1070
|
}
|
|
1239
1071
|
)
|
|
1240
1072
|
]
|
|
@@ -1245,8 +1077,8 @@ function Row({
|
|
|
1245
1077
|
label,
|
|
1246
1078
|
children
|
|
1247
1079
|
}) {
|
|
1248
|
-
return /* @__PURE__ */
|
|
1249
|
-
/* @__PURE__ */
|
|
1080
|
+
return /* @__PURE__ */ jsxs2("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: [
|
|
1081
|
+
/* @__PURE__ */ jsx2(
|
|
1250
1082
|
"span",
|
|
1251
1083
|
{
|
|
1252
1084
|
style: {
|
|
@@ -1263,7 +1095,7 @@ function Row({
|
|
|
1263
1095
|
] });
|
|
1264
1096
|
}
|
|
1265
1097
|
function Sep({ children }) {
|
|
1266
|
-
return /* @__PURE__ */
|
|
1098
|
+
return /* @__PURE__ */ jsx2(
|
|
1267
1099
|
"span",
|
|
1268
1100
|
{
|
|
1269
1101
|
style: {
|
|
@@ -1279,7 +1111,7 @@ function Sep({ children }) {
|
|
|
1279
1111
|
);
|
|
1280
1112
|
}
|
|
1281
1113
|
function Unit({ children }) {
|
|
1282
|
-
return /* @__PURE__ */
|
|
1114
|
+
return /* @__PURE__ */ jsx2(
|
|
1283
1115
|
"span",
|
|
1284
1116
|
{
|
|
1285
1117
|
style: {
|
|
@@ -1297,10 +1129,10 @@ function NumInput({
|
|
|
1297
1129
|
}) {
|
|
1298
1130
|
const [editing, setEditing] = useState3(false);
|
|
1299
1131
|
const [text, setText] = useState3(String(value));
|
|
1300
|
-
|
|
1132
|
+
useEffect2(() => {
|
|
1301
1133
|
if (!editing) setText(String(value));
|
|
1302
1134
|
}, [value, editing]);
|
|
1303
|
-
return /* @__PURE__ */
|
|
1135
|
+
return /* @__PURE__ */ jsx2(
|
|
1304
1136
|
"input",
|
|
1305
1137
|
{
|
|
1306
1138
|
type: "text",
|
|
@@ -1337,7 +1169,7 @@ function DropBtn({
|
|
|
1337
1169
|
onClick,
|
|
1338
1170
|
active
|
|
1339
1171
|
}) {
|
|
1340
|
-
return /* @__PURE__ */
|
|
1172
|
+
return /* @__PURE__ */ jsx2(
|
|
1341
1173
|
"button",
|
|
1342
1174
|
{
|
|
1343
1175
|
onClick,
|
|
@@ -1358,7 +1190,7 @@ function DropBtn({
|
|
|
1358
1190
|
);
|
|
1359
1191
|
}
|
|
1360
1192
|
function DropMenu({ children }) {
|
|
1361
|
-
return /* @__PURE__ */
|
|
1193
|
+
return /* @__PURE__ */ jsx2(
|
|
1362
1194
|
"div",
|
|
1363
1195
|
{
|
|
1364
1196
|
style: {
|
|
@@ -1385,7 +1217,7 @@ function DropItem({
|
|
|
1385
1217
|
active,
|
|
1386
1218
|
accent
|
|
1387
1219
|
}) {
|
|
1388
|
-
return /* @__PURE__ */
|
|
1220
|
+
return /* @__PURE__ */ jsx2(
|
|
1389
1221
|
"button",
|
|
1390
1222
|
{
|
|
1391
1223
|
onClick,
|
|
@@ -1406,7 +1238,7 @@ function DropItem({
|
|
|
1406
1238
|
);
|
|
1407
1239
|
}
|
|
1408
1240
|
function Chevron() {
|
|
1409
|
-
return /* @__PURE__ */
|
|
1241
|
+
return /* @__PURE__ */ jsx2("svg", { width: "10", height: "10", viewBox: "0 0 10 10", fill: "none", children: /* @__PURE__ */ jsx2(
|
|
1410
1242
|
"path",
|
|
1411
1243
|
{
|
|
1412
1244
|
d: "M3 4l2 2.5L7 4",
|
|
@@ -1416,8 +1248,8 @@ function Chevron() {
|
|
|
1416
1248
|
) });
|
|
1417
1249
|
}
|
|
1418
1250
|
function AspectIcon() {
|
|
1419
|
-
return /* @__PURE__ */
|
|
1420
|
-
/* @__PURE__ */
|
|
1251
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1252
|
+
/* @__PURE__ */ jsx2(
|
|
1421
1253
|
"rect",
|
|
1422
1254
|
{
|
|
1423
1255
|
x: "2",
|
|
@@ -1430,7 +1262,7 @@ function AspectIcon() {
|
|
|
1430
1262
|
strokeDasharray: "2 1.5"
|
|
1431
1263
|
}
|
|
1432
1264
|
),
|
|
1433
|
-
/* @__PURE__ */
|
|
1265
|
+
/* @__PURE__ */ jsx2(
|
|
1434
1266
|
"line",
|
|
1435
1267
|
{
|
|
1436
1268
|
x1: "6.33",
|
|
@@ -1442,7 +1274,7 @@ function AspectIcon() {
|
|
|
1442
1274
|
strokeDasharray: "1.5 1"
|
|
1443
1275
|
}
|
|
1444
1276
|
),
|
|
1445
|
-
/* @__PURE__ */
|
|
1277
|
+
/* @__PURE__ */ jsx2(
|
|
1446
1278
|
"line",
|
|
1447
1279
|
{
|
|
1448
1280
|
x1: "9.67",
|
|
@@ -1457,7 +1289,7 @@ function AspectIcon() {
|
|
|
1457
1289
|
] });
|
|
1458
1290
|
}
|
|
1459
1291
|
function SavedIcon() {
|
|
1460
|
-
return /* @__PURE__ */
|
|
1292
|
+
return /* @__PURE__ */ jsx2("svg", { width: "16", height: "16", viewBox: "0 0 16 16", fill: "none", children: /* @__PURE__ */ jsx2(
|
|
1461
1293
|
"rect",
|
|
1462
1294
|
{
|
|
1463
1295
|
x: "2",
|
|
@@ -1471,15 +1303,200 @@ function SavedIcon() {
|
|
|
1471
1303
|
}
|
|
1472
1304
|
) });
|
|
1473
1305
|
}
|
|
1306
|
+
function ModeBtn({
|
|
1307
|
+
children,
|
|
1308
|
+
onClick
|
|
1309
|
+
}) {
|
|
1310
|
+
return /* @__PURE__ */ jsx2(
|
|
1311
|
+
"button",
|
|
1312
|
+
{
|
|
1313
|
+
onClick,
|
|
1314
|
+
style: {
|
|
1315
|
+
display: "flex",
|
|
1316
|
+
alignItems: "center",
|
|
1317
|
+
gap: 5,
|
|
1318
|
+
background: "rgba(255, 255, 255, 0.06)",
|
|
1319
|
+
border: "1px solid rgba(255, 255, 255, 0.08)",
|
|
1320
|
+
borderRadius: 6,
|
|
1321
|
+
color: "rgba(255, 255, 255, 0.55)",
|
|
1322
|
+
cursor: "pointer",
|
|
1323
|
+
fontSize: 11,
|
|
1324
|
+
fontFamily: "inherit",
|
|
1325
|
+
padding: "4px 8px",
|
|
1326
|
+
transition: "background 0.1s, color 0.1s"
|
|
1327
|
+
},
|
|
1328
|
+
onMouseEnter: (e) => {
|
|
1329
|
+
const btn = e.currentTarget;
|
|
1330
|
+
btn.style.background = "rgba(255, 255, 255, 0.12)";
|
|
1331
|
+
btn.style.color = "rgba(255, 255, 255, 0.85)";
|
|
1332
|
+
},
|
|
1333
|
+
onMouseLeave: (e) => {
|
|
1334
|
+
const btn = e.currentTarget;
|
|
1335
|
+
btn.style.background = "rgba(255, 255, 255, 0.06)";
|
|
1336
|
+
btn.style.color = "rgba(255, 255, 255, 0.55)";
|
|
1337
|
+
},
|
|
1338
|
+
children
|
|
1339
|
+
}
|
|
1340
|
+
);
|
|
1341
|
+
}
|
|
1342
|
+
function MagnetToggle({
|
|
1343
|
+
enabled,
|
|
1344
|
+
onToggle
|
|
1345
|
+
}) {
|
|
1346
|
+
return /* @__PURE__ */ jsxs2(
|
|
1347
|
+
"button",
|
|
1348
|
+
{
|
|
1349
|
+
onClick: onToggle,
|
|
1350
|
+
style: {
|
|
1351
|
+
display: "flex",
|
|
1352
|
+
alignItems: "center",
|
|
1353
|
+
gap: 5,
|
|
1354
|
+
background: "none",
|
|
1355
|
+
border: "none",
|
|
1356
|
+
color: enabled ? "rgba(147, 130, 220, 0.9)" : "rgba(255, 255, 255, 0.35)",
|
|
1357
|
+
cursor: "pointer",
|
|
1358
|
+
fontSize: 11,
|
|
1359
|
+
fontFamily: "inherit",
|
|
1360
|
+
padding: "2px 0"
|
|
1361
|
+
},
|
|
1362
|
+
children: [
|
|
1363
|
+
/* @__PURE__ */ jsx2(MagnetIcon, {}),
|
|
1364
|
+
"Magnet"
|
|
1365
|
+
]
|
|
1366
|
+
}
|
|
1367
|
+
);
|
|
1368
|
+
}
|
|
1369
|
+
function MagnetIcon() {
|
|
1370
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1371
|
+
/* @__PURE__ */ jsx2(
|
|
1372
|
+
"path",
|
|
1373
|
+
{
|
|
1374
|
+
d: "M4 2v4a4 4 0 008 0V2",
|
|
1375
|
+
stroke: "currentColor",
|
|
1376
|
+
strokeWidth: "1.3",
|
|
1377
|
+
strokeLinecap: "round"
|
|
1378
|
+
}
|
|
1379
|
+
),
|
|
1380
|
+
/* @__PURE__ */ jsx2("line", { x1: "4", y1: "2", x2: "4", y2: "5", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" }),
|
|
1381
|
+
/* @__PURE__ */ jsx2("line", { x1: "12", y1: "2", x2: "12", y2: "5", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round" })
|
|
1382
|
+
] });
|
|
1383
|
+
}
|
|
1384
|
+
function ViewportIcon() {
|
|
1385
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1386
|
+
/* @__PURE__ */ jsx2(
|
|
1387
|
+
"rect",
|
|
1388
|
+
{
|
|
1389
|
+
x: "1",
|
|
1390
|
+
y: "2",
|
|
1391
|
+
width: "14",
|
|
1392
|
+
height: "11",
|
|
1393
|
+
rx: "1.5",
|
|
1394
|
+
stroke: "currentColor",
|
|
1395
|
+
strokeWidth: "1.3"
|
|
1396
|
+
}
|
|
1397
|
+
),
|
|
1398
|
+
/* @__PURE__ */ jsx2(
|
|
1399
|
+
"line",
|
|
1400
|
+
{
|
|
1401
|
+
x1: "1",
|
|
1402
|
+
y1: "14",
|
|
1403
|
+
x2: "15",
|
|
1404
|
+
y2: "14",
|
|
1405
|
+
stroke: "currentColor",
|
|
1406
|
+
strokeWidth: "1.3",
|
|
1407
|
+
strokeLinecap: "round"
|
|
1408
|
+
}
|
|
1409
|
+
)
|
|
1410
|
+
] });
|
|
1411
|
+
}
|
|
1412
|
+
function FullPageIcon() {
|
|
1413
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1414
|
+
/* @__PURE__ */ jsx2(
|
|
1415
|
+
"rect",
|
|
1416
|
+
{
|
|
1417
|
+
x: "3",
|
|
1418
|
+
y: "1",
|
|
1419
|
+
width: "10",
|
|
1420
|
+
height: "14",
|
|
1421
|
+
rx: "1.5",
|
|
1422
|
+
stroke: "currentColor",
|
|
1423
|
+
strokeWidth: "1.3"
|
|
1424
|
+
}
|
|
1425
|
+
),
|
|
1426
|
+
/* @__PURE__ */ jsx2(
|
|
1427
|
+
"line",
|
|
1428
|
+
{
|
|
1429
|
+
x1: "5.5",
|
|
1430
|
+
y1: "4",
|
|
1431
|
+
x2: "10.5",
|
|
1432
|
+
y2: "4",
|
|
1433
|
+
stroke: "currentColor",
|
|
1434
|
+
strokeWidth: "1",
|
|
1435
|
+
strokeLinecap: "round"
|
|
1436
|
+
}
|
|
1437
|
+
),
|
|
1438
|
+
/* @__PURE__ */ jsx2(
|
|
1439
|
+
"line",
|
|
1440
|
+
{
|
|
1441
|
+
x1: "5.5",
|
|
1442
|
+
y1: "6.5",
|
|
1443
|
+
x2: "10.5",
|
|
1444
|
+
y2: "6.5",
|
|
1445
|
+
stroke: "currentColor",
|
|
1446
|
+
strokeWidth: "1",
|
|
1447
|
+
strokeLinecap: "round"
|
|
1448
|
+
}
|
|
1449
|
+
),
|
|
1450
|
+
/* @__PURE__ */ jsx2(
|
|
1451
|
+
"line",
|
|
1452
|
+
{
|
|
1453
|
+
x1: "5.5",
|
|
1454
|
+
y1: "9",
|
|
1455
|
+
x2: "10.5",
|
|
1456
|
+
y2: "9",
|
|
1457
|
+
stroke: "currentColor",
|
|
1458
|
+
strokeWidth: "1",
|
|
1459
|
+
strokeLinecap: "round"
|
|
1460
|
+
}
|
|
1461
|
+
)
|
|
1462
|
+
] });
|
|
1463
|
+
}
|
|
1464
|
+
function ComponentIcon() {
|
|
1465
|
+
return /* @__PURE__ */ jsxs2("svg", { width: "14", height: "14", viewBox: "0 0 16 16", fill: "none", children: [
|
|
1466
|
+
/* @__PURE__ */ jsx2(
|
|
1467
|
+
"path",
|
|
1468
|
+
{
|
|
1469
|
+
d: "M3 2l2.5 10 2-3.5L11 11 3 2z",
|
|
1470
|
+
stroke: "currentColor",
|
|
1471
|
+
strokeWidth: "1.2",
|
|
1472
|
+
strokeLinejoin: "round",
|
|
1473
|
+
strokeLinecap: "round"
|
|
1474
|
+
}
|
|
1475
|
+
),
|
|
1476
|
+
/* @__PURE__ */ jsx2(
|
|
1477
|
+
"rect",
|
|
1478
|
+
{
|
|
1479
|
+
x: "8",
|
|
1480
|
+
y: "5",
|
|
1481
|
+
width: "6.5",
|
|
1482
|
+
height: "6.5",
|
|
1483
|
+
rx: "1",
|
|
1484
|
+
stroke: "currentColor",
|
|
1485
|
+
strokeWidth: "1.1",
|
|
1486
|
+
strokeDasharray: "2 1.5"
|
|
1487
|
+
}
|
|
1488
|
+
)
|
|
1489
|
+
] });
|
|
1490
|
+
}
|
|
1474
1491
|
|
|
1475
1492
|
// src/overlay/ui/inspector.tsx
|
|
1476
|
-
import { useEffect as
|
|
1477
|
-
import { Fragment as Fragment2, jsx as
|
|
1493
|
+
import { useEffect as useEffect3, useRef as useRef3, useCallback as useCallback4, useState as useState4 } from "react";
|
|
1494
|
+
import { Fragment as Fragment2, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
1478
1495
|
function Inspector({ onSelect, onCancel }) {
|
|
1479
1496
|
const [highlight, setHighlight] = useState4(null);
|
|
1480
|
-
const hoveredEl =
|
|
1481
|
-
const styleEl =
|
|
1482
|
-
|
|
1497
|
+
const hoveredEl = useRef3(null);
|
|
1498
|
+
const styleEl = useRef3(null);
|
|
1499
|
+
useEffect3(() => {
|
|
1483
1500
|
const style = document.createElement("style");
|
|
1484
1501
|
style.setAttribute("data-afterbefore", "true");
|
|
1485
1502
|
style.textContent = "*, *::before, *::after { cursor: crosshair !important; }";
|
|
@@ -1489,7 +1506,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1489
1506
|
style.remove();
|
|
1490
1507
|
};
|
|
1491
1508
|
}, []);
|
|
1492
|
-
const isOverlayElement =
|
|
1509
|
+
const isOverlayElement = useCallback4((el) => {
|
|
1493
1510
|
let node = el;
|
|
1494
1511
|
while (node) {
|
|
1495
1512
|
if (node instanceof HTMLElement && node.dataset.afterbefore) return true;
|
|
@@ -1497,7 +1514,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1497
1514
|
}
|
|
1498
1515
|
return false;
|
|
1499
1516
|
}, []);
|
|
1500
|
-
const handleMouseMove =
|
|
1517
|
+
const handleMouseMove = useCallback4(
|
|
1501
1518
|
(e) => {
|
|
1502
1519
|
const el = document.elementFromPoint(e.clientX, e.clientY);
|
|
1503
1520
|
if (!el || !(el instanceof HTMLElement) || isOverlayElement(el)) {
|
|
@@ -1517,7 +1534,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1517
1534
|
},
|
|
1518
1535
|
[isOverlayElement]
|
|
1519
1536
|
);
|
|
1520
|
-
const handleClick =
|
|
1537
|
+
const handleClick = useCallback4(
|
|
1521
1538
|
(e) => {
|
|
1522
1539
|
e.preventDefault();
|
|
1523
1540
|
e.stopPropagation();
|
|
@@ -1528,7 +1545,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1528
1545
|
},
|
|
1529
1546
|
[onSelect]
|
|
1530
1547
|
);
|
|
1531
|
-
const handleKeyDown =
|
|
1548
|
+
const handleKeyDown = useCallback4(
|
|
1532
1549
|
(e) => {
|
|
1533
1550
|
if (e.key === "Escape") {
|
|
1534
1551
|
onCancel();
|
|
@@ -1536,7 +1553,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1536
1553
|
},
|
|
1537
1554
|
[onCancel]
|
|
1538
1555
|
);
|
|
1539
|
-
|
|
1556
|
+
useEffect3(() => {
|
|
1540
1557
|
document.addEventListener("mousemove", handleMouseMove, true);
|
|
1541
1558
|
document.addEventListener("click", handleClick, true);
|
|
1542
1559
|
document.addEventListener("keydown", handleKeyDown);
|
|
@@ -1546,9 +1563,9 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1546
1563
|
document.removeEventListener("keydown", handleKeyDown);
|
|
1547
1564
|
};
|
|
1548
1565
|
}, [handleMouseMove, handleClick, handleKeyDown]);
|
|
1549
|
-
return /* @__PURE__ */
|
|
1550
|
-
highlight && /* @__PURE__ */
|
|
1551
|
-
/* @__PURE__ */
|
|
1566
|
+
return /* @__PURE__ */ jsxs3("div", { "data-afterbefore": "true", style: { position: "fixed", inset: 0, zIndex: 2147483646, pointerEvents: "none" }, children: [
|
|
1567
|
+
highlight && /* @__PURE__ */ jsxs3(Fragment2, { children: [
|
|
1568
|
+
/* @__PURE__ */ jsx3(
|
|
1552
1569
|
"div",
|
|
1553
1570
|
{
|
|
1554
1571
|
style: {
|
|
@@ -1564,7 +1581,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1564
1581
|
}
|
|
1565
1582
|
}
|
|
1566
1583
|
),
|
|
1567
|
-
/* @__PURE__ */
|
|
1584
|
+
/* @__PURE__ */ jsx3(
|
|
1568
1585
|
"div",
|
|
1569
1586
|
{
|
|
1570
1587
|
style: {
|
|
@@ -1585,7 +1602,7 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1585
1602
|
}
|
|
1586
1603
|
)
|
|
1587
1604
|
] }),
|
|
1588
|
-
!highlight && /* @__PURE__ */
|
|
1605
|
+
!highlight && /* @__PURE__ */ jsx3(
|
|
1589
1606
|
"div",
|
|
1590
1607
|
{
|
|
1591
1608
|
style: {
|
|
@@ -1609,18 +1626,18 @@ function Inspector({ onSelect, onCancel }) {
|
|
|
1609
1626
|
}
|
|
1610
1627
|
|
|
1611
1628
|
// src/overlay/ui/status.tsx
|
|
1612
|
-
import { useState as useState5, useRef as
|
|
1613
|
-
import { jsx as
|
|
1629
|
+
import { useState as useState5, useRef as useRef4, useEffect as useEffect4, useCallback as useCallback5 } from "react";
|
|
1630
|
+
import { jsx as jsx4, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
1614
1631
|
var PANEL_WIDTH = 220;
|
|
1615
1632
|
function Status({ onReset, position, onClose }) {
|
|
1616
|
-
const panelRef =
|
|
1633
|
+
const panelRef = useRef4(null);
|
|
1617
1634
|
const [toast, setToast] = useState5(null);
|
|
1618
1635
|
const [pushing, setPushing] = useState5(false);
|
|
1619
|
-
const showToast =
|
|
1636
|
+
const showToast = useCallback5((message, type) => {
|
|
1620
1637
|
setToast({ message, type });
|
|
1621
1638
|
setTimeout(() => setToast(null), 3e3);
|
|
1622
1639
|
}, []);
|
|
1623
|
-
|
|
1640
|
+
useEffect4(() => {
|
|
1624
1641
|
const handler = (e) => {
|
|
1625
1642
|
if (panelRef.current && !panelRef.current.contains(e.target)) {
|
|
1626
1643
|
onClose();
|
|
@@ -1629,7 +1646,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1629
1646
|
document.addEventListener("mousedown", handler);
|
|
1630
1647
|
return () => document.removeEventListener("mousedown", handler);
|
|
1631
1648
|
}, [onClose]);
|
|
1632
|
-
|
|
1649
|
+
useEffect4(() => {
|
|
1633
1650
|
const handler = (e) => {
|
|
1634
1651
|
if (e.key === "Escape") onClose();
|
|
1635
1652
|
};
|
|
@@ -1705,7 +1722,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1705
1722
|
const onLeave = (e) => {
|
|
1706
1723
|
e.currentTarget.style.background = "transparent";
|
|
1707
1724
|
};
|
|
1708
|
-
return /* @__PURE__ */
|
|
1725
|
+
return /* @__PURE__ */ jsxs4(
|
|
1709
1726
|
"div",
|
|
1710
1727
|
{
|
|
1711
1728
|
ref: panelRef,
|
|
@@ -1724,7 +1741,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1724
1741
|
overflow: "hidden"
|
|
1725
1742
|
},
|
|
1726
1743
|
children: [
|
|
1727
|
-
/* @__PURE__ */
|
|
1744
|
+
/* @__PURE__ */ jsx4(
|
|
1728
1745
|
"div",
|
|
1729
1746
|
{
|
|
1730
1747
|
style: {
|
|
@@ -1737,8 +1754,8 @@ function Status({ onReset, position, onClose }) {
|
|
|
1737
1754
|
children: "Before & After captured"
|
|
1738
1755
|
}
|
|
1739
1756
|
),
|
|
1740
|
-
/* @__PURE__ */
|
|
1741
|
-
/* @__PURE__ */
|
|
1757
|
+
/* @__PURE__ */ jsxs4("div", { style: { padding: "0 4px 4px" }, children: [
|
|
1758
|
+
/* @__PURE__ */ jsxs4(
|
|
1742
1759
|
"button",
|
|
1743
1760
|
{
|
|
1744
1761
|
style: buttonStyle,
|
|
@@ -1746,12 +1763,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1746
1763
|
onMouseEnter: onEnter,
|
|
1747
1764
|
onMouseLeave: onLeave,
|
|
1748
1765
|
children: [
|
|
1749
|
-
/* @__PURE__ */
|
|
1766
|
+
/* @__PURE__ */ jsx4(FolderIcon, {}),
|
|
1750
1767
|
"Open Folder"
|
|
1751
1768
|
]
|
|
1752
1769
|
}
|
|
1753
1770
|
),
|
|
1754
|
-
/* @__PURE__ */
|
|
1771
|
+
/* @__PURE__ */ jsxs4(
|
|
1755
1772
|
"button",
|
|
1756
1773
|
{
|
|
1757
1774
|
style: buttonStyle,
|
|
@@ -1759,12 +1776,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1759
1776
|
onMouseEnter: onEnter,
|
|
1760
1777
|
onMouseLeave: onLeave,
|
|
1761
1778
|
children: [
|
|
1762
|
-
/* @__PURE__ */
|
|
1779
|
+
/* @__PURE__ */ jsx4(CopyIcon, {}),
|
|
1763
1780
|
"Copy Markdown"
|
|
1764
1781
|
]
|
|
1765
1782
|
}
|
|
1766
1783
|
),
|
|
1767
|
-
/* @__PURE__ */
|
|
1784
|
+
/* @__PURE__ */ jsxs4(
|
|
1768
1785
|
"button",
|
|
1769
1786
|
{
|
|
1770
1787
|
style: buttonStyle,
|
|
@@ -1773,12 +1790,12 @@ function Status({ onReset, position, onClose }) {
|
|
|
1773
1790
|
onMouseEnter: onEnter,
|
|
1774
1791
|
onMouseLeave: onLeave,
|
|
1775
1792
|
children: [
|
|
1776
|
-
/* @__PURE__ */
|
|
1793
|
+
/* @__PURE__ */ jsx4(PushIcon, {}),
|
|
1777
1794
|
pushing ? "Pushing..." : "Push to PR"
|
|
1778
1795
|
]
|
|
1779
1796
|
}
|
|
1780
1797
|
),
|
|
1781
|
-
/* @__PURE__ */
|
|
1798
|
+
/* @__PURE__ */ jsx4(
|
|
1782
1799
|
"div",
|
|
1783
1800
|
{
|
|
1784
1801
|
style: {
|
|
@@ -1788,7 +1805,7 @@ function Status({ onReset, position, onClose }) {
|
|
|
1788
1805
|
}
|
|
1789
1806
|
}
|
|
1790
1807
|
),
|
|
1791
|
-
/* @__PURE__ */
|
|
1808
|
+
/* @__PURE__ */ jsxs4(
|
|
1792
1809
|
"button",
|
|
1793
1810
|
{
|
|
1794
1811
|
style: { ...buttonStyle, color: "rgba(255,255,255,0.5)" },
|
|
@@ -1796,13 +1813,13 @@ function Status({ onReset, position, onClose }) {
|
|
|
1796
1813
|
onMouseEnter: onEnter,
|
|
1797
1814
|
onMouseLeave: onLeave,
|
|
1798
1815
|
children: [
|
|
1799
|
-
/* @__PURE__ */
|
|
1816
|
+
/* @__PURE__ */ jsx4(ResetIcon, {}),
|
|
1800
1817
|
"Reset"
|
|
1801
1818
|
]
|
|
1802
1819
|
}
|
|
1803
1820
|
)
|
|
1804
1821
|
] }),
|
|
1805
|
-
toast && /* @__PURE__ */
|
|
1822
|
+
toast && /* @__PURE__ */ jsx4(
|
|
1806
1823
|
"div",
|
|
1807
1824
|
{
|
|
1808
1825
|
style: {
|
|
@@ -1828,14 +1845,14 @@ function Status({ onReset, position, onClose }) {
|
|
|
1828
1845
|
);
|
|
1829
1846
|
}
|
|
1830
1847
|
function FolderIcon() {
|
|
1831
|
-
return /* @__PURE__ */
|
|
1848
|
+
return /* @__PURE__ */ jsx4(
|
|
1832
1849
|
"svg",
|
|
1833
1850
|
{
|
|
1834
1851
|
width: "14",
|
|
1835
1852
|
height: "14",
|
|
1836
1853
|
viewBox: "0 0 14 14",
|
|
1837
1854
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1838
|
-
children: /* @__PURE__ */
|
|
1855
|
+
children: /* @__PURE__ */ jsx4(
|
|
1839
1856
|
"path",
|
|
1840
1857
|
{
|
|
1841
1858
|
d: "M1.5 3A1.5 1.5 0 013 1.5h2.38a1 1 0 01.72.3L7 2.72a1 1 0 00.72.3H11A1.5 1.5 0 0112.5 4.5v6A1.5 1.5 0 0111 12H3A1.5 1.5 0 011.5 10.5V3z",
|
|
@@ -1848,7 +1865,7 @@ function FolderIcon() {
|
|
|
1848
1865
|
);
|
|
1849
1866
|
}
|
|
1850
1867
|
function CopyIcon() {
|
|
1851
|
-
return /* @__PURE__ */
|
|
1868
|
+
return /* @__PURE__ */ jsxs4(
|
|
1852
1869
|
"svg",
|
|
1853
1870
|
{
|
|
1854
1871
|
width: "14",
|
|
@@ -1856,7 +1873,7 @@ function CopyIcon() {
|
|
|
1856
1873
|
viewBox: "0 0 14 14",
|
|
1857
1874
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1858
1875
|
children: [
|
|
1859
|
-
/* @__PURE__ */
|
|
1876
|
+
/* @__PURE__ */ jsx4(
|
|
1860
1877
|
"rect",
|
|
1861
1878
|
{
|
|
1862
1879
|
x: "4",
|
|
@@ -1869,7 +1886,7 @@ function CopyIcon() {
|
|
|
1869
1886
|
strokeWidth: "1.3"
|
|
1870
1887
|
}
|
|
1871
1888
|
),
|
|
1872
|
-
/* @__PURE__ */
|
|
1889
|
+
/* @__PURE__ */ jsx4(
|
|
1873
1890
|
"path",
|
|
1874
1891
|
{
|
|
1875
1892
|
d: "M10 4V2.5A1.5 1.5 0 008.5 1h-6A1.5 1.5 0 001 2.5v6A1.5 1.5 0 002.5 10H4",
|
|
@@ -1883,14 +1900,14 @@ function CopyIcon() {
|
|
|
1883
1900
|
);
|
|
1884
1901
|
}
|
|
1885
1902
|
function PushIcon() {
|
|
1886
|
-
return /* @__PURE__ */
|
|
1903
|
+
return /* @__PURE__ */ jsx4(
|
|
1887
1904
|
"svg",
|
|
1888
1905
|
{
|
|
1889
1906
|
width: "14",
|
|
1890
1907
|
height: "14",
|
|
1891
1908
|
viewBox: "0 0 14 14",
|
|
1892
1909
|
style: { color: "rgba(255,255,255,0.5)" },
|
|
1893
|
-
children: /* @__PURE__ */
|
|
1910
|
+
children: /* @__PURE__ */ jsx4(
|
|
1894
1911
|
"path",
|
|
1895
1912
|
{
|
|
1896
1913
|
d: "M7 11V3m0 0L4 6m3-3l3 3",
|
|
@@ -1905,7 +1922,7 @@ function PushIcon() {
|
|
|
1905
1922
|
);
|
|
1906
1923
|
}
|
|
1907
1924
|
function ResetIcon() {
|
|
1908
|
-
return /* @__PURE__ */
|
|
1925
|
+
return /* @__PURE__ */ jsxs4(
|
|
1909
1926
|
"svg",
|
|
1910
1927
|
{
|
|
1911
1928
|
width: "14",
|
|
@@ -1913,7 +1930,7 @@ function ResetIcon() {
|
|
|
1913
1930
|
viewBox: "0 0 14 14",
|
|
1914
1931
|
style: { color: "rgba(255,255,255,0.4)" },
|
|
1915
1932
|
children: [
|
|
1916
|
-
/* @__PURE__ */
|
|
1933
|
+
/* @__PURE__ */ jsx4(
|
|
1917
1934
|
"path",
|
|
1918
1935
|
{
|
|
1919
1936
|
d: "M2.5 7a4.5 4.5 0 118 2.5",
|
|
@@ -1923,7 +1940,7 @@ function ResetIcon() {
|
|
|
1923
1940
|
strokeLinecap: "round"
|
|
1924
1941
|
}
|
|
1925
1942
|
),
|
|
1926
|
-
/* @__PURE__ */
|
|
1943
|
+
/* @__PURE__ */ jsx4(
|
|
1927
1944
|
"path",
|
|
1928
1945
|
{
|
|
1929
1946
|
d: "M2.5 3v4h4",
|
|
@@ -1940,7 +1957,7 @@ function ResetIcon() {
|
|
|
1940
1957
|
}
|
|
1941
1958
|
|
|
1942
1959
|
// src/overlay/index.tsx
|
|
1943
|
-
import { jsx as
|
|
1960
|
+
import { jsx as jsx5, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
1944
1961
|
async function saveCapture(type, mode, dataUrl) {
|
|
1945
1962
|
try {
|
|
1946
1963
|
const res = await fetch("/__afterbefore/save", {
|
|
@@ -1958,39 +1975,36 @@ async function saveCapture(type, mode, dataUrl) {
|
|
|
1958
1975
|
}
|
|
1959
1976
|
function AfterBefore() {
|
|
1960
1977
|
const { state, captureComplete, reset } = useOverlayState();
|
|
1961
|
-
const [menuOpen, setMenuOpen] = useState6(false);
|
|
1962
1978
|
const [statusOpen, setStatusOpen] = useState6(false);
|
|
1963
1979
|
const [selectorActive, setSelectorActive] = useState6(false);
|
|
1964
1980
|
const [inspectorActive, setInspectorActive] = useState6(false);
|
|
1965
1981
|
const [loading, setLoading] = useState6(false);
|
|
1966
|
-
const iconPos =
|
|
1967
|
-
|
|
1982
|
+
const iconPos = useRef5({ x: 24, y: 0 });
|
|
1983
|
+
useEffect5(() => {
|
|
1968
1984
|
if (state.phase === "ready") {
|
|
1969
1985
|
const timer = setTimeout(() => {
|
|
1970
1986
|
reset();
|
|
1971
1987
|
setStatusOpen(false);
|
|
1972
|
-
setMenuOpen(false);
|
|
1973
1988
|
}, 1500);
|
|
1974
1989
|
return () => clearTimeout(timer);
|
|
1975
1990
|
}
|
|
1976
1991
|
}, [state.phase, reset]);
|
|
1977
|
-
const handlePositionChange =
|
|
1992
|
+
const handlePositionChange = useCallback6(
|
|
1978
1993
|
(pos) => {
|
|
1979
1994
|
iconPos.current = pos;
|
|
1980
1995
|
},
|
|
1981
1996
|
[]
|
|
1982
1997
|
);
|
|
1983
|
-
const handleIconClick =
|
|
1998
|
+
const handleIconClick = useCallback6(() => {
|
|
1984
1999
|
if (loading) return;
|
|
1985
2000
|
if (state.phase === "ready") {
|
|
1986
2001
|
setStatusOpen((prev) => !prev);
|
|
1987
|
-
setMenuOpen(false);
|
|
1988
2002
|
} else {
|
|
1989
|
-
|
|
2003
|
+
setSelectorActive((prev) => !prev);
|
|
1990
2004
|
setStatusOpen(false);
|
|
1991
2005
|
}
|
|
1992
2006
|
}, [state.phase, loading]);
|
|
1993
|
-
const performCapture =
|
|
2007
|
+
const performCapture = useCallback6(
|
|
1994
2008
|
async (mode, area, element) => {
|
|
1995
2009
|
setLoading(true);
|
|
1996
2010
|
try {
|
|
@@ -2010,52 +2024,47 @@ function AfterBefore() {
|
|
|
2010
2024
|
},
|
|
2011
2025
|
[state.phase, captureComplete]
|
|
2012
2026
|
);
|
|
2013
|
-
const
|
|
2014
|
-
(
|
|
2015
|
-
|
|
2016
|
-
|
|
2017
|
-
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
const handleComponentSelect = useCallback7(
|
|
2027
|
+
const handleViewportCapture = useCallback6(() => {
|
|
2028
|
+
setSelectorActive(false);
|
|
2029
|
+
performCapture("viewport");
|
|
2030
|
+
}, [performCapture]);
|
|
2031
|
+
const handleFullPageCapture = useCallback6(() => {
|
|
2032
|
+
setSelectorActive(false);
|
|
2033
|
+
performCapture("fullpage");
|
|
2034
|
+
}, [performCapture]);
|
|
2035
|
+
const handleComponentMode = useCallback6(() => {
|
|
2036
|
+
setSelectorActive(false);
|
|
2037
|
+
setInspectorActive(true);
|
|
2038
|
+
}, []);
|
|
2039
|
+
const handleComponentSelect = useCallback6(
|
|
2027
2040
|
(element) => {
|
|
2028
2041
|
setInspectorActive(false);
|
|
2029
2042
|
performCapture("component", void 0, element);
|
|
2030
2043
|
},
|
|
2031
2044
|
[performCapture]
|
|
2032
2045
|
);
|
|
2033
|
-
const handleComponentCancel =
|
|
2046
|
+
const handleComponentCancel = useCallback6(() => {
|
|
2034
2047
|
setInspectorActive(false);
|
|
2035
2048
|
}, []);
|
|
2036
|
-
const handleAreaSelect =
|
|
2049
|
+
const handleAreaSelect = useCallback6(
|
|
2037
2050
|
(area) => {
|
|
2038
2051
|
setSelectorActive(false);
|
|
2039
2052
|
performCapture("area", area);
|
|
2040
2053
|
},
|
|
2041
2054
|
[performCapture]
|
|
2042
2055
|
);
|
|
2043
|
-
const handleAreaCancel =
|
|
2056
|
+
const handleAreaCancel = useCallback6(() => {
|
|
2044
2057
|
setSelectorActive(false);
|
|
2045
2058
|
}, []);
|
|
2046
|
-
const handleReset =
|
|
2059
|
+
const handleReset = useCallback6(() => {
|
|
2047
2060
|
reset();
|
|
2048
2061
|
setStatusOpen(false);
|
|
2049
|
-
setMenuOpen(false);
|
|
2050
2062
|
}, [reset]);
|
|
2051
|
-
const
|
|
2052
|
-
setMenuOpen(false);
|
|
2053
|
-
}, []);
|
|
2054
|
-
const handleStatusClose = useCallback7(() => {
|
|
2063
|
+
const handleStatusClose = useCallback6(() => {
|
|
2055
2064
|
setStatusOpen(false);
|
|
2056
2065
|
}, []);
|
|
2057
|
-
return /* @__PURE__ */
|
|
2058
|
-
/* @__PURE__ */
|
|
2066
|
+
return /* @__PURE__ */ jsxs5("div", { "data-afterbefore": "true", children: [
|
|
2067
|
+
/* @__PURE__ */ jsx5(
|
|
2059
2068
|
Icon,
|
|
2060
2069
|
{
|
|
2061
2070
|
phase: state.phase,
|
|
@@ -2064,17 +2073,18 @@ function AfterBefore() {
|
|
|
2064
2073
|
onPositionChange: handlePositionChange
|
|
2065
2074
|
}
|
|
2066
2075
|
),
|
|
2067
|
-
|
|
2068
|
-
|
|
2076
|
+
selectorActive && /* @__PURE__ */ jsx5(
|
|
2077
|
+
Selector,
|
|
2069
2078
|
{
|
|
2070
|
-
onSelect:
|
|
2071
|
-
|
|
2072
|
-
|
|
2079
|
+
onSelect: handleAreaSelect,
|
|
2080
|
+
onCancel: handleAreaCancel,
|
|
2081
|
+
onViewport: handleViewportCapture,
|
|
2082
|
+
onFullPage: handleFullPageCapture,
|
|
2083
|
+
onComponent: handleComponentMode
|
|
2073
2084
|
}
|
|
2074
2085
|
),
|
|
2075
|
-
|
|
2076
|
-
|
|
2077
|
-
statusOpen && state.phase === "ready" && /* @__PURE__ */ jsx6(
|
|
2086
|
+
inspectorActive && /* @__PURE__ */ jsx5(Inspector, { onSelect: handleComponentSelect, onCancel: handleComponentCancel }),
|
|
2087
|
+
statusOpen && state.phase === "ready" && /* @__PURE__ */ jsx5(
|
|
2078
2088
|
Status,
|
|
2079
2089
|
{
|
|
2080
2090
|
onReset: handleReset,
|