react-grab 0.0.11 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +36 -2
- package/dist/index.global.js +651 -232
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,37 @@
|
|
|
1
|
-
|
|
1
|
+
interface StoreApi<T> {
|
|
2
|
+
getInitialState(): T;
|
|
3
|
+
getState(): T;
|
|
4
|
+
setState(partialState: ((prevState: T) => T) | Partial<T>): T;
|
|
5
|
+
subscribe(listener: Listener<T>): () => void;
|
|
6
|
+
subscribe<U>(listener: Listener<U>, selector: (state: T) => unknown): () => void;
|
|
7
|
+
}
|
|
8
|
+
type Listener<T> = (state: T, prevState: T | undefined) => (() => unknown) | void;
|
|
2
9
|
|
|
3
|
-
|
|
10
|
+
type Hotkey = KeyboardEvent["key"];
|
|
11
|
+
|
|
12
|
+
interface Options {
|
|
13
|
+
enabled?: boolean;
|
|
14
|
+
/**
|
|
15
|
+
* hotkey to trigger the overlay
|
|
16
|
+
*
|
|
17
|
+
* default: "Meta"
|
|
18
|
+
*/
|
|
19
|
+
hotkey?: Hotkey | Hotkey[];
|
|
20
|
+
/**
|
|
21
|
+
* time required (ms) to hold the key to trigger the overlay
|
|
22
|
+
*
|
|
23
|
+
* default: 1000
|
|
24
|
+
*/
|
|
25
|
+
keyHoldDuration?: number;
|
|
26
|
+
}
|
|
27
|
+
interface LibStore {
|
|
28
|
+
keyPressTimestamps: Map<Hotkey, number>;
|
|
29
|
+
mouseX: number;
|
|
30
|
+
mouseY: number;
|
|
31
|
+
overlayMode: "copying" | "hidden" | "visible";
|
|
32
|
+
pressedKeys: Set<Hotkey>;
|
|
33
|
+
}
|
|
34
|
+
declare const libStore: StoreApi<LibStore>;
|
|
35
|
+
declare const init: (options?: Options) => (() => void) | undefined;
|
|
36
|
+
|
|
37
|
+
export { type Options, init, libStore };
|
package/dist/index.global.js
CHANGED
|
@@ -10,11 +10,217 @@ var ReactGrab = (function (exports) {
|
|
|
10
10
|
* LICENSE file in the root directory of this source tree.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
// src/hotkeys.ts
|
|
14
|
+
var FORM_TAGS_AND_ROLES = [
|
|
15
|
+
"input",
|
|
16
|
+
"textarea",
|
|
17
|
+
"select",
|
|
18
|
+
"searchbox",
|
|
19
|
+
"slider",
|
|
20
|
+
"spinbutton",
|
|
21
|
+
"menuitem",
|
|
22
|
+
"menuitemcheckbox",
|
|
23
|
+
"menuitemradio",
|
|
24
|
+
"option",
|
|
25
|
+
"radio",
|
|
26
|
+
"textbox"
|
|
27
|
+
];
|
|
28
|
+
var isCustomElement = (element) => {
|
|
29
|
+
return Boolean(element.tagName) && !element.tagName.startsWith("-") && element.tagName.includes("-");
|
|
30
|
+
};
|
|
31
|
+
var isReadonlyArray = (value) => {
|
|
32
|
+
return Array.isArray(value);
|
|
33
|
+
};
|
|
34
|
+
var isHotkeyEnabledOnTagName = (event, enabledOnTags = false) => {
|
|
35
|
+
const { composed, target } = event;
|
|
36
|
+
let targetTagName;
|
|
37
|
+
let targetRole;
|
|
38
|
+
if (target instanceof HTMLElement && isCustomElement(target) && composed) {
|
|
39
|
+
const composedPath = event.composedPath();
|
|
40
|
+
const targetElement = composedPath[0];
|
|
41
|
+
if (targetElement instanceof HTMLElement) {
|
|
42
|
+
targetTagName = targetElement.tagName;
|
|
43
|
+
targetRole = targetElement.role;
|
|
44
|
+
}
|
|
45
|
+
} else if (target instanceof HTMLElement) {
|
|
46
|
+
targetTagName = target.tagName;
|
|
47
|
+
targetRole = target.role;
|
|
48
|
+
}
|
|
49
|
+
if (isReadonlyArray(enabledOnTags)) {
|
|
50
|
+
return Boolean(
|
|
51
|
+
targetTagName && enabledOnTags && enabledOnTags.some(
|
|
52
|
+
(tag) => typeof targetTagName === "string" && tag.toLowerCase() === targetTagName.toLowerCase() || tag === targetRole
|
|
53
|
+
)
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
return Boolean(targetTagName && enabledOnTags && enabledOnTags);
|
|
57
|
+
};
|
|
58
|
+
var isKeyboardEventTriggeredByInput = (event) => {
|
|
59
|
+
return isHotkeyEnabledOnTagName(event, FORM_TAGS_AND_ROLES);
|
|
60
|
+
};
|
|
61
|
+
var trackHotkeys = () => {
|
|
62
|
+
const handleKeyDown = (event) => {
|
|
63
|
+
if (isKeyboardEventTriggeredByInput(event)) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
if (event.code === undefined) {
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
libStore.setState((state) => {
|
|
70
|
+
const newTimestamps = new Map(state.keyPressTimestamps);
|
|
71
|
+
if (!state.pressedKeys.has(event.key)) {
|
|
72
|
+
newTimestamps.set(event.key, Date.now());
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
...state,
|
|
76
|
+
keyPressTimestamps: newTimestamps,
|
|
77
|
+
pressedKeys: /* @__PURE__ */ new Set([event.key, ...state.pressedKeys])
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
};
|
|
81
|
+
const handleKeyUp = (event) => {
|
|
82
|
+
if (event.code === undefined) {
|
|
83
|
+
return;
|
|
84
|
+
}
|
|
85
|
+
libStore.setState((state) => {
|
|
86
|
+
const newTimestamps = new Map(state.keyPressTimestamps);
|
|
87
|
+
newTimestamps.delete(event.key);
|
|
88
|
+
return {
|
|
89
|
+
...state,
|
|
90
|
+
keyPressTimestamps: newTimestamps,
|
|
91
|
+
pressedKeys: new Set(
|
|
92
|
+
[...state.pressedKeys].filter((key) => key !== event.key)
|
|
93
|
+
)
|
|
94
|
+
};
|
|
95
|
+
});
|
|
96
|
+
};
|
|
97
|
+
const handleBlur = () => {
|
|
98
|
+
libStore.setState((state) => ({
|
|
99
|
+
...state,
|
|
100
|
+
keyPressTimestamps: /* @__PURE__ */ new Map(),
|
|
101
|
+
pressedKeys: /* @__PURE__ */ new Set()
|
|
102
|
+
}));
|
|
103
|
+
};
|
|
104
|
+
const handleContextmenu = () => {
|
|
105
|
+
libStore.setState((state) => ({
|
|
106
|
+
...state,
|
|
107
|
+
keyPressTimestamps: /* @__PURE__ */ new Map(),
|
|
108
|
+
pressedKeys: /* @__PURE__ */ new Set()
|
|
109
|
+
}));
|
|
110
|
+
};
|
|
111
|
+
document.addEventListener("keydown", handleKeyDown);
|
|
112
|
+
document.addEventListener("keyup", handleKeyUp);
|
|
113
|
+
window.addEventListener("blur", handleBlur);
|
|
114
|
+
window.addEventListener("contextmenu", handleContextmenu);
|
|
115
|
+
return () => {
|
|
116
|
+
document.removeEventListener("keydown", handleKeyDown);
|
|
117
|
+
document.removeEventListener("keyup", handleKeyUp);
|
|
118
|
+
window.removeEventListener("blur", handleBlur);
|
|
119
|
+
window.removeEventListener("contextmenu", handleContextmenu);
|
|
120
|
+
};
|
|
121
|
+
};
|
|
122
|
+
var isKeyPressed = (key) => {
|
|
123
|
+
const { pressedKeys } = libStore.getState();
|
|
124
|
+
if (key.length === 1) {
|
|
125
|
+
return pressedKeys.has(key.toLowerCase()) || pressedKeys.has(key.toUpperCase());
|
|
126
|
+
}
|
|
127
|
+
return pressedKeys.has(key);
|
|
128
|
+
};
|
|
129
|
+
var watchKeyHeldFor = (key, duration, onHeld) => {
|
|
130
|
+
let timeoutId = null;
|
|
131
|
+
let unsubscribe = null;
|
|
132
|
+
const cleanup = () => {
|
|
133
|
+
if (timeoutId !== null) {
|
|
134
|
+
clearTimeout(timeoutId);
|
|
135
|
+
timeoutId = null;
|
|
136
|
+
}
|
|
137
|
+
if (unsubscribe !== null) {
|
|
138
|
+
unsubscribe();
|
|
139
|
+
unsubscribe = null;
|
|
140
|
+
}
|
|
141
|
+
};
|
|
142
|
+
const checkSingleKeyPressed = (keyToCheck, pressedKeys) => {
|
|
143
|
+
if (keyToCheck.length === 1) {
|
|
144
|
+
return pressedKeys.has(keyToCheck.toLowerCase()) || pressedKeys.has(keyToCheck.toUpperCase());
|
|
145
|
+
}
|
|
146
|
+
return pressedKeys.has(keyToCheck);
|
|
147
|
+
};
|
|
148
|
+
const checkAllKeysPressed = (pressedKeys) => {
|
|
149
|
+
if (Array.isArray(key)) {
|
|
150
|
+
return key.every((keyFromCombo) => checkSingleKeyPressed(keyFromCombo, pressedKeys));
|
|
151
|
+
}
|
|
152
|
+
return checkSingleKeyPressed(key, pressedKeys);
|
|
153
|
+
};
|
|
154
|
+
const getKeyFromTimestamps = (keyToFind, timestamps) => {
|
|
155
|
+
if (keyToFind.length === 1) {
|
|
156
|
+
return timestamps.get(keyToFind.toLowerCase()) || timestamps.get(keyToFind.toUpperCase());
|
|
157
|
+
}
|
|
158
|
+
return timestamps.get(keyToFind);
|
|
159
|
+
};
|
|
160
|
+
const getEarliestPressTime = (timestamps) => {
|
|
161
|
+
const keysToInspect = Array.isArray(key) ? key : [key];
|
|
162
|
+
let earliest;
|
|
163
|
+
for (const keyFromCombo of keysToInspect) {
|
|
164
|
+
const timestamp = getKeyFromTimestamps(keyFromCombo, timestamps);
|
|
165
|
+
if (timestamp === undefined) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
if (earliest === undefined || timestamp < earliest) {
|
|
169
|
+
earliest = timestamp;
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
return earliest;
|
|
173
|
+
};
|
|
174
|
+
const scheduleCallback = () => {
|
|
175
|
+
const state = libStore.getState();
|
|
176
|
+
const { keyPressTimestamps, pressedKeys } = state;
|
|
177
|
+
if (!checkAllKeysPressed(pressedKeys)) {
|
|
178
|
+
if (timeoutId !== null) {
|
|
179
|
+
clearTimeout(timeoutId);
|
|
180
|
+
timeoutId = null;
|
|
181
|
+
}
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
const earliestPressTime = getEarliestPressTime(keyPressTimestamps);
|
|
185
|
+
if (earliestPressTime === undefined) {
|
|
186
|
+
if (timeoutId !== null) {
|
|
187
|
+
clearTimeout(timeoutId);
|
|
188
|
+
timeoutId = null;
|
|
189
|
+
}
|
|
190
|
+
return;
|
|
191
|
+
}
|
|
192
|
+
const elapsed = Date.now() - earliestPressTime;
|
|
193
|
+
const remaining = duration - elapsed;
|
|
194
|
+
if (remaining <= 0) {
|
|
195
|
+
onHeld();
|
|
196
|
+
cleanup();
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
if (timeoutId !== null) {
|
|
200
|
+
clearTimeout(timeoutId);
|
|
201
|
+
}
|
|
202
|
+
timeoutId = setTimeout(() => {
|
|
203
|
+
onHeld();
|
|
204
|
+
cleanup();
|
|
205
|
+
}, remaining);
|
|
206
|
+
};
|
|
207
|
+
unsubscribe = libStore.subscribe(
|
|
208
|
+
() => {
|
|
209
|
+
scheduleCallback();
|
|
210
|
+
},
|
|
211
|
+
(state) => state.pressedKeys
|
|
212
|
+
);
|
|
213
|
+
scheduleCallback();
|
|
214
|
+
return cleanup;
|
|
215
|
+
};
|
|
216
|
+
|
|
13
217
|
// src/overlay.ts
|
|
218
|
+
var VIEWPORT_MARGIN_PX = 8;
|
|
219
|
+
var LABEL_OFFSET_PX = 6;
|
|
14
220
|
var lerp = (start, end, factor) => {
|
|
15
221
|
return start + (end - start) * factor;
|
|
16
222
|
};
|
|
17
|
-
var SELECTION_LERP_FACTOR = 0.
|
|
223
|
+
var SELECTION_LERP_FACTOR = 0.95;
|
|
18
224
|
var createSelectionElement = ({
|
|
19
225
|
borderRadius,
|
|
20
226
|
height,
|
|
@@ -32,23 +238,11 @@ var ReactGrab = (function (exports) {
|
|
|
32
238
|
overlay.style.borderRadius = borderRadius;
|
|
33
239
|
overlay.style.transform = transform;
|
|
34
240
|
overlay.style.pointerEvents = "none";
|
|
35
|
-
overlay.style.border = "
|
|
36
|
-
overlay.style.backgroundColor = "rgba(
|
|
241
|
+
overlay.style.border = "1px solid rgb(210, 57, 192)";
|
|
242
|
+
overlay.style.backgroundColor = "rgba(210, 57, 192, 0.2)";
|
|
37
243
|
overlay.style.zIndex = "2147483646";
|
|
38
244
|
overlay.style.boxSizing = "border-box";
|
|
39
245
|
overlay.style.display = "none";
|
|
40
|
-
overlay.animate(
|
|
41
|
-
[
|
|
42
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.1)" },
|
|
43
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.15)" },
|
|
44
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.1)" }
|
|
45
|
-
],
|
|
46
|
-
{
|
|
47
|
-
duration: 2e3,
|
|
48
|
-
easing: "ease-in-out",
|
|
49
|
-
iterations: Infinity
|
|
50
|
-
}
|
|
51
|
-
);
|
|
52
246
|
return overlay;
|
|
53
247
|
};
|
|
54
248
|
var updateSelectionElement = (element, { borderRadius, height, transform, width, x, y }) => {
|
|
@@ -79,52 +273,46 @@ var ReactGrab = (function (exports) {
|
|
|
79
273
|
element.style.transform = transform;
|
|
80
274
|
}
|
|
81
275
|
};
|
|
82
|
-
var
|
|
83
|
-
element
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
}
|
|
109
|
-
update(selection) {
|
|
110
|
-
updateSelectionElement(this.element, selection);
|
|
111
|
-
}
|
|
276
|
+
var createSelectionOverlay = (root) => {
|
|
277
|
+
const element = createSelectionElement({
|
|
278
|
+
borderRadius: "0px",
|
|
279
|
+
height: 0,
|
|
280
|
+
transform: "none",
|
|
281
|
+
width: 0,
|
|
282
|
+
x: -1e3,
|
|
283
|
+
y: -1e3
|
|
284
|
+
});
|
|
285
|
+
root.appendChild(element);
|
|
286
|
+
let visible = false;
|
|
287
|
+
return {
|
|
288
|
+
hide: () => {
|
|
289
|
+
visible = false;
|
|
290
|
+
element.style.display = "none";
|
|
291
|
+
element.style.pointerEvents = "none";
|
|
292
|
+
},
|
|
293
|
+
isVisible: () => visible,
|
|
294
|
+
show: () => {
|
|
295
|
+
visible = true;
|
|
296
|
+
element.style.display = "block";
|
|
297
|
+
element.style.pointerEvents = "auto";
|
|
298
|
+
},
|
|
299
|
+
update: (selection) => {
|
|
300
|
+
updateSelectionElement(element, selection);
|
|
301
|
+
}
|
|
302
|
+
};
|
|
112
303
|
};
|
|
113
304
|
var createSpinner = () => {
|
|
114
305
|
const spinner = document.createElement("span");
|
|
115
306
|
spinner.style.display = "inline-block";
|
|
116
307
|
spinner.style.width = "8px";
|
|
117
308
|
spinner.style.height = "8px";
|
|
118
|
-
spinner.style.border = "1.5px solid
|
|
309
|
+
spinner.style.border = "1.5px solid rgb(210, 57, 192)";
|
|
119
310
|
spinner.style.borderTopColor = "transparent";
|
|
120
311
|
spinner.style.borderRadius = "50%";
|
|
121
312
|
spinner.style.marginRight = "4px";
|
|
122
313
|
spinner.style.verticalAlign = "middle";
|
|
123
314
|
spinner.animate(
|
|
124
|
-
[
|
|
125
|
-
{ transform: "rotate(0deg)" },
|
|
126
|
-
{ transform: "rotate(360deg)" }
|
|
127
|
-
],
|
|
315
|
+
[{ transform: "rotate(0deg)" }, { transform: "rotate(360deg)" }],
|
|
128
316
|
{
|
|
129
317
|
duration: 600,
|
|
130
318
|
easing: "linear",
|
|
@@ -133,16 +321,15 @@ var ReactGrab = (function (exports) {
|
|
|
133
321
|
);
|
|
134
322
|
return spinner;
|
|
135
323
|
};
|
|
136
|
-
var
|
|
324
|
+
var activeIndicator = null;
|
|
325
|
+
var createIndicator = () => {
|
|
137
326
|
const indicator = document.createElement("div");
|
|
138
327
|
indicator.style.position = "fixed";
|
|
139
|
-
indicator.style.
|
|
140
|
-
indicator.style.
|
|
141
|
-
indicator.style.
|
|
142
|
-
indicator.style.
|
|
143
|
-
indicator.style.
|
|
144
|
-
indicator.style.color = "#1e4ed8";
|
|
145
|
-
indicator.style.border = "1px solid #c7dbfb";
|
|
328
|
+
indicator.style.top = "calc(8px + env(safe-area-inset-top))";
|
|
329
|
+
indicator.style.padding = "2px 6px";
|
|
330
|
+
indicator.style.backgroundColor = "#fde7f7";
|
|
331
|
+
indicator.style.color = "#b21c8e";
|
|
332
|
+
indicator.style.border = "1px solid #f7c5ec";
|
|
146
333
|
indicator.style.borderRadius = "4px";
|
|
147
334
|
indicator.style.fontSize = "11px";
|
|
148
335
|
indicator.style.fontWeight = "500";
|
|
@@ -153,59 +340,108 @@ var ReactGrab = (function (exports) {
|
|
|
153
340
|
indicator.style.transition = "opacity 0.2s ease-in-out";
|
|
154
341
|
indicator.style.display = "flex";
|
|
155
342
|
indicator.style.alignItems = "center";
|
|
343
|
+
indicator.style.maxWidth = "calc(100vw - (16px + env(safe-area-inset-left) + env(safe-area-inset-right)))";
|
|
344
|
+
indicator.style.overflow = "hidden";
|
|
345
|
+
indicator.style.textOverflow = "ellipsis";
|
|
346
|
+
indicator.style.whiteSpace = "nowrap";
|
|
156
347
|
return indicator;
|
|
157
348
|
};
|
|
158
|
-
var showCopyIndicator = (
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
indicator
|
|
164
|
-
|
|
349
|
+
var showCopyIndicator = (selectionLeftPx, selectionTopPx) => {
|
|
350
|
+
if (activeIndicator) {
|
|
351
|
+
activeIndicator.remove();
|
|
352
|
+
activeIndicator = null;
|
|
353
|
+
}
|
|
354
|
+
const indicator = createIndicator();
|
|
355
|
+
const loadingSpinner = createSpinner();
|
|
356
|
+
const labelText = document.createElement("span");
|
|
357
|
+
labelText.textContent = "Grabbing\u2026";
|
|
358
|
+
indicator.appendChild(loadingSpinner);
|
|
359
|
+
indicator.appendChild(labelText);
|
|
165
360
|
document.body.appendChild(indicator);
|
|
361
|
+
activeIndicator = indicator;
|
|
362
|
+
const indicatorRect = indicator.getBoundingClientRect();
|
|
363
|
+
const viewportWidthPx = window.innerWidth;
|
|
364
|
+
const viewportHeightPx = window.innerHeight;
|
|
365
|
+
let indicatorLeftPx = Math.round(selectionLeftPx);
|
|
366
|
+
let indicatorTopPx = Math.round(selectionTopPx) - indicatorRect.height - LABEL_OFFSET_PX;
|
|
367
|
+
indicatorLeftPx = Math.max(
|
|
368
|
+
VIEWPORT_MARGIN_PX,
|
|
369
|
+
Math.min(
|
|
370
|
+
indicatorLeftPx,
|
|
371
|
+
viewportWidthPx - indicatorRect.width - VIEWPORT_MARGIN_PX
|
|
372
|
+
)
|
|
373
|
+
);
|
|
374
|
+
indicatorTopPx = Math.max(
|
|
375
|
+
VIEWPORT_MARGIN_PX,
|
|
376
|
+
Math.min(
|
|
377
|
+
indicatorTopPx,
|
|
378
|
+
viewportHeightPx - indicatorRect.height - VIEWPORT_MARGIN_PX
|
|
379
|
+
)
|
|
380
|
+
);
|
|
381
|
+
indicator.style.left = `${indicatorLeftPx}px`;
|
|
382
|
+
indicator.style.top = `${indicatorTopPx}px`;
|
|
383
|
+
indicator.style.right = "auto";
|
|
166
384
|
requestAnimationFrame(() => {
|
|
167
385
|
indicator.style.opacity = "1";
|
|
168
386
|
});
|
|
169
|
-
return () => {
|
|
170
|
-
|
|
171
|
-
|
|
387
|
+
return (tagName) => {
|
|
388
|
+
loadingSpinner.remove();
|
|
389
|
+
const checkmarkIcon = document.createElement("span");
|
|
390
|
+
checkmarkIcon.textContent = "\u2713";
|
|
391
|
+
checkmarkIcon.style.display = "inline-block";
|
|
392
|
+
checkmarkIcon.style.marginRight = "4px";
|
|
393
|
+
checkmarkIcon.style.fontWeight = "600";
|
|
394
|
+
indicator.insertBefore(checkmarkIcon, labelText);
|
|
395
|
+
const tagNameMonospace = document.createElement("span");
|
|
396
|
+
tagNameMonospace.textContent = tagName ? `<${tagName}>` : "<element>";
|
|
397
|
+
tagNameMonospace.style.fontFamily = "ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace";
|
|
398
|
+
tagNameMonospace.style.fontVariantNumeric = "tabular-nums";
|
|
399
|
+
labelText.replaceChildren(
|
|
400
|
+
document.createTextNode("Grabbed "),
|
|
401
|
+
tagNameMonospace
|
|
402
|
+
);
|
|
172
403
|
setTimeout(() => {
|
|
173
404
|
indicator.style.opacity = "0";
|
|
174
405
|
setTimeout(() => {
|
|
175
|
-
|
|
406
|
+
indicator.remove();
|
|
407
|
+
if (activeIndicator === indicator) {
|
|
408
|
+
activeIndicator = null;
|
|
409
|
+
}
|
|
176
410
|
}, 200);
|
|
177
411
|
}, 1500);
|
|
178
412
|
};
|
|
179
413
|
};
|
|
180
414
|
|
|
181
415
|
// src/utils/copy-text.ts
|
|
182
|
-
var
|
|
183
|
-
|
|
416
|
+
var IS_NAVIGATOR_CLIPBOARD_AVAILABLE = typeof window !== "undefined" && window.navigator.clipboard && window.isSecureContext;
|
|
417
|
+
var copyTextToClipboard = async (text) => {
|
|
418
|
+
if (IS_NAVIGATOR_CLIPBOARD_AVAILABLE) {
|
|
184
419
|
try {
|
|
185
420
|
await navigator.clipboard.writeText(text);
|
|
186
421
|
return true;
|
|
187
422
|
} catch {
|
|
188
423
|
}
|
|
189
424
|
}
|
|
190
|
-
const
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
document.body.
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
425
|
+
const textareaElement = document.createElement("textarea");
|
|
426
|
+
textareaElement.value = text;
|
|
427
|
+
textareaElement.setAttribute("readonly", "");
|
|
428
|
+
textareaElement.style.position = "fixed";
|
|
429
|
+
textareaElement.style.top = "-9999px";
|
|
430
|
+
textareaElement.style.opacity = "0";
|
|
431
|
+
textareaElement.style.pointerEvents = "none";
|
|
432
|
+
const doc = document.body || document.documentElement;
|
|
433
|
+
doc.appendChild(textareaElement);
|
|
434
|
+
textareaElement.select();
|
|
435
|
+
textareaElement.setSelectionRange(0, textareaElement.value.length);
|
|
436
|
+
let didCopyToClipboard = false;
|
|
201
437
|
try {
|
|
202
|
-
|
|
438
|
+
didCopyToClipboard = document.execCommand("copy");
|
|
203
439
|
} catch {
|
|
204
|
-
|
|
440
|
+
didCopyToClipboard = false;
|
|
205
441
|
} finally {
|
|
206
|
-
|
|
442
|
+
doc.removeChild(textareaElement);
|
|
207
443
|
}
|
|
208
|
-
return
|
|
444
|
+
return didCopyToClipboard;
|
|
209
445
|
};
|
|
210
446
|
|
|
211
447
|
// node_modules/.pnpm/bippy@0.3.31_@types+react@19.2.2_react@19.2.0/node_modules/bippy/dist/src-R2iEnVC1.js
|
|
@@ -2424,23 +2660,20 @@ ${error.stack}`;
|
|
|
2424
2660
|
};
|
|
2425
2661
|
|
|
2426
2662
|
// src/utils/is-element-visible.ts
|
|
2427
|
-
var isElementVisible = (element, computedStyle =
|
|
2428
|
-
|
|
2429
|
-
computedStyle = window.getComputedStyle(element);
|
|
2430
|
-
}
|
|
2431
|
-
return computedStyle.display !== "none" && computedStyle.visibility !== "hidden";
|
|
2663
|
+
var isElementVisible = (element, computedStyle = window.getComputedStyle(element)) => {
|
|
2664
|
+
return computedStyle.display !== "none" && computedStyle.visibility !== "hidden" && computedStyle.opacity !== "0";
|
|
2432
2665
|
};
|
|
2433
2666
|
|
|
2434
2667
|
// src/utils/mount-root.ts
|
|
2435
2668
|
var ATTRIBUTE_NAME = "data-react-grab";
|
|
2436
2669
|
var mountRoot = () => {
|
|
2437
|
-
const
|
|
2438
|
-
if (
|
|
2439
|
-
const
|
|
2670
|
+
const mountedHost = document.querySelector(`[${ATTRIBUTE_NAME}]`);
|
|
2671
|
+
if (mountedHost) {
|
|
2672
|
+
const mountedRoot = mountedHost.shadowRoot?.querySelector(
|
|
2440
2673
|
`[${ATTRIBUTE_NAME}]`
|
|
2441
2674
|
);
|
|
2442
|
-
if (
|
|
2443
|
-
return
|
|
2675
|
+
if (mountedRoot instanceof HTMLDivElement && mountedHost.shadowRoot) {
|
|
2676
|
+
return mountedRoot;
|
|
2444
2677
|
}
|
|
2445
2678
|
}
|
|
2446
2679
|
const host = document.createElement("div");
|
|
@@ -2451,7 +2684,6 @@ ${error.stack}`;
|
|
|
2451
2684
|
host.style.left = "0";
|
|
2452
2685
|
const shadowRoot = host.attachShadow({ mode: "open" });
|
|
2453
2686
|
const root = document.createElement("div");
|
|
2454
|
-
root.style.transition = "opacity 0.1s ease-out";
|
|
2455
2687
|
root.setAttribute(ATTRIBUTE_NAME, "true");
|
|
2456
2688
|
shadowRoot.appendChild(root);
|
|
2457
2689
|
const doc = document.body ?? document.documentElement;
|
|
@@ -2472,6 +2704,77 @@ ${error.stack}`;
|
|
|
2472
2704
|
return setTimeout(callback, 0);
|
|
2473
2705
|
};
|
|
2474
2706
|
|
|
2707
|
+
// src/utils/store.ts
|
|
2708
|
+
var createStore = (initializer) => {
|
|
2709
|
+
const subscriberMap = /* @__PURE__ */ new Map();
|
|
2710
|
+
let currentListenerIndex = 0;
|
|
2711
|
+
let currentState;
|
|
2712
|
+
const setState = (maybeStateOrReducer) => {
|
|
2713
|
+
const prevState = currentState;
|
|
2714
|
+
const resolvedState = typeof maybeStateOrReducer === "function" ? maybeStateOrReducer(prevState) : maybeStateOrReducer;
|
|
2715
|
+
const nextState = {
|
|
2716
|
+
...prevState,
|
|
2717
|
+
...resolvedState
|
|
2718
|
+
};
|
|
2719
|
+
currentState = nextState;
|
|
2720
|
+
for (const entry of subscriberMap.values()) {
|
|
2721
|
+
if (entry.type === "selected" /* Selected */) {
|
|
2722
|
+
const nextSelectedValue = entry.selector(nextState);
|
|
2723
|
+
const prevSelectedValue = entry.prevSelectedValue;
|
|
2724
|
+
if (!Object.is(prevSelectedValue, nextSelectedValue)) {
|
|
2725
|
+
entry.prevSelectedValue = nextSelectedValue;
|
|
2726
|
+
entry.listener(nextSelectedValue, prevSelectedValue);
|
|
2727
|
+
}
|
|
2728
|
+
} else {
|
|
2729
|
+
entry.listener(nextState, prevState);
|
|
2730
|
+
}
|
|
2731
|
+
}
|
|
2732
|
+
return currentState;
|
|
2733
|
+
};
|
|
2734
|
+
const getState = () => {
|
|
2735
|
+
return currentState;
|
|
2736
|
+
};
|
|
2737
|
+
const initialState = initializer(setState, getState);
|
|
2738
|
+
currentState = initialState;
|
|
2739
|
+
const subscribeWithSelector = (listener, selector) => {
|
|
2740
|
+
const index = String(currentListenerIndex++);
|
|
2741
|
+
const wrappedListener = (value, prevValue) => listener(value, prevValue);
|
|
2742
|
+
const entry = {
|
|
2743
|
+
listener: wrappedListener,
|
|
2744
|
+
prevSelectedValue: selector(currentState),
|
|
2745
|
+
selector,
|
|
2746
|
+
type: "selected" /* Selected */
|
|
2747
|
+
};
|
|
2748
|
+
subscriberMap.set(index, entry);
|
|
2749
|
+
return () => {
|
|
2750
|
+
subscriberMap.delete(index);
|
|
2751
|
+
};
|
|
2752
|
+
};
|
|
2753
|
+
const subscribeToFullState = (listener) => {
|
|
2754
|
+
const index = String(currentListenerIndex++);
|
|
2755
|
+
const entry = {
|
|
2756
|
+
listener,
|
|
2757
|
+
type: "full" /* Full */
|
|
2758
|
+
};
|
|
2759
|
+
subscriberMap.set(index, entry);
|
|
2760
|
+
return () => {
|
|
2761
|
+
subscriberMap.delete(index);
|
|
2762
|
+
};
|
|
2763
|
+
};
|
|
2764
|
+
function subscribe(subscriber, selector) {
|
|
2765
|
+
return selector ? subscribeWithSelector(subscriber, selector) : subscribeToFullState(subscriber);
|
|
2766
|
+
}
|
|
2767
|
+
const store = {
|
|
2768
|
+
getInitialState() {
|
|
2769
|
+
return initialState;
|
|
2770
|
+
},
|
|
2771
|
+
getState,
|
|
2772
|
+
setState,
|
|
2773
|
+
subscribe
|
|
2774
|
+
};
|
|
2775
|
+
return store;
|
|
2776
|
+
};
|
|
2777
|
+
|
|
2475
2778
|
// src/utils/throttle.ts
|
|
2476
2779
|
var throttle = (fn, delay) => {
|
|
2477
2780
|
let timeout = null;
|
|
@@ -2494,167 +2797,282 @@ ${error.stack}`;
|
|
|
2494
2797
|
};
|
|
2495
2798
|
|
|
2496
2799
|
// src/index.ts
|
|
2497
|
-
var TICK_INTERVAL = 50;
|
|
2498
2800
|
var THROTTLE_DELAY = 16;
|
|
2499
|
-
var
|
|
2801
|
+
var libStore = createStore(() => ({
|
|
2802
|
+
keyPressTimestamps: /* @__PURE__ */ new Map(),
|
|
2803
|
+
mouseX: -1e3,
|
|
2804
|
+
mouseY: -1e3,
|
|
2805
|
+
overlayMode: "hidden",
|
|
2806
|
+
pressedKeys: /* @__PURE__ */ new Set()
|
|
2807
|
+
}));
|
|
2808
|
+
var init = (options = {}) => {
|
|
2809
|
+
if (options.enabled === false) {
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
const resolvedOptions = {
|
|
2813
|
+
enabled: true,
|
|
2814
|
+
hotkey: "Meta",
|
|
2815
|
+
keyHoldDuration: 500,
|
|
2816
|
+
...options
|
|
2817
|
+
};
|
|
2500
2818
|
const root = mountRoot();
|
|
2501
|
-
|
|
2502
|
-
let
|
|
2503
|
-
let
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2819
|
+
const selectionOverlay = createSelectionOverlay(root);
|
|
2820
|
+
let hoveredElement = null;
|
|
2821
|
+
let isCopying = false;
|
|
2822
|
+
const checkIsActivationHotkeyPressed = () => {
|
|
2823
|
+
if (Array.isArray(resolvedOptions.hotkey)) {
|
|
2824
|
+
for (const key of resolvedOptions.hotkey) {
|
|
2825
|
+
if (!isKeyPressed(key)) {
|
|
2826
|
+
return false;
|
|
2827
|
+
}
|
|
2828
|
+
}
|
|
2829
|
+
return true;
|
|
2830
|
+
}
|
|
2831
|
+
return isKeyPressed(resolvedOptions.hotkey);
|
|
2832
|
+
};
|
|
2833
|
+
const isCopyHotkeyPressed = () => {
|
|
2834
|
+
return isKeyPressed("Meta") && isKeyPressed("C");
|
|
2835
|
+
};
|
|
2836
|
+
let cleanupActivationHotkeyWatcher = null;
|
|
2837
|
+
const handleKeyStateChange = (pressedKeys) => {
|
|
2838
|
+
const { overlayMode } = libStore.getState();
|
|
2839
|
+
if (pressedKeys.has("Escape") || pressedKeys.has("Esc")) {
|
|
2840
|
+
libStore.setState((state) => {
|
|
2841
|
+
const nextPressedKeys = new Set(state.pressedKeys);
|
|
2842
|
+
nextPressedKeys.delete("Escape");
|
|
2843
|
+
nextPressedKeys.delete("Esc");
|
|
2844
|
+
const nextTimestamps = new Map(state.keyPressTimestamps);
|
|
2845
|
+
nextTimestamps.delete("Escape");
|
|
2846
|
+
nextTimestamps.delete("Esc");
|
|
2847
|
+
const activationKeys = Array.isArray(resolvedOptions.hotkey) ? resolvedOptions.hotkey : [resolvedOptions.hotkey];
|
|
2848
|
+
for (const activationKey of activationKeys) {
|
|
2849
|
+
if (activationKey.length === 1) {
|
|
2850
|
+
nextPressedKeys.delete(activationKey.toLowerCase());
|
|
2851
|
+
nextPressedKeys.delete(activationKey.toUpperCase());
|
|
2852
|
+
nextTimestamps.delete(activationKey.toLowerCase());
|
|
2853
|
+
nextTimestamps.delete(activationKey.toUpperCase());
|
|
2854
|
+
} else {
|
|
2855
|
+
nextPressedKeys.delete(activationKey);
|
|
2856
|
+
nextTimestamps.delete(activationKey);
|
|
2857
|
+
}
|
|
2858
|
+
}
|
|
2859
|
+
return {
|
|
2860
|
+
...state,
|
|
2861
|
+
keyPressTimestamps: nextTimestamps,
|
|
2862
|
+
overlayMode: "hidden",
|
|
2863
|
+
pressedKeys: nextPressedKeys
|
|
2864
|
+
};
|
|
2865
|
+
});
|
|
2866
|
+
if (cleanupActivationHotkeyWatcher) {
|
|
2867
|
+
cleanupActivationHotkeyWatcher();
|
|
2868
|
+
cleanupActivationHotkeyWatcher = null;
|
|
2869
|
+
}
|
|
2515
2870
|
return;
|
|
2516
2871
|
}
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
};
|
|
2530
|
-
const throttledRender = throttle(() => {
|
|
2531
|
-
scheduleRunWhenIdle(() => {
|
|
2532
|
-
render();
|
|
2533
|
-
});
|
|
2534
|
-
}, THROTTLE_DELAY);
|
|
2535
|
-
window.addEventListener("mousemove", (event) => {
|
|
2536
|
-
mouseX = event.clientX;
|
|
2537
|
-
mouseY = event.clientY;
|
|
2538
|
-
throttledRender();
|
|
2539
|
-
});
|
|
2540
|
-
window.addEventListener("resize", () => {
|
|
2541
|
-
throttledRender();
|
|
2542
|
-
});
|
|
2543
|
-
window.addEventListener("scroll", () => {
|
|
2544
|
-
throttledRender();
|
|
2545
|
-
});
|
|
2546
|
-
let timeout = null;
|
|
2547
|
-
const nextTick = () => {
|
|
2548
|
-
timeout = window.setTimeout(() => {
|
|
2549
|
-
throttledRender();
|
|
2550
|
-
nextTick();
|
|
2551
|
-
}, TICK_INTERVAL);
|
|
2552
|
-
};
|
|
2553
|
-
nextTick();
|
|
2554
|
-
window.addEventListener("keydown", (event) => {
|
|
2555
|
-
if (event.key === "Meta") {
|
|
2556
|
-
if (isFocusedInInput()) return;
|
|
2557
|
-
if (shiftKeyTimeout !== null) {
|
|
2558
|
-
window.clearTimeout(shiftKeyTimeout);
|
|
2872
|
+
if (isCopyHotkeyPressed() && overlayMode === "visible") {
|
|
2873
|
+
libStore.setState((state) => ({
|
|
2874
|
+
...state,
|
|
2875
|
+
overlayMode: "copying"
|
|
2876
|
+
}));
|
|
2877
|
+
return;
|
|
2878
|
+
}
|
|
2879
|
+
const isActivationHotkeyPressed = checkIsActivationHotkeyPressed();
|
|
2880
|
+
if (!isActivationHotkeyPressed) {
|
|
2881
|
+
if (cleanupActivationHotkeyWatcher) {
|
|
2882
|
+
cleanupActivationHotkeyWatcher();
|
|
2883
|
+
cleanupActivationHotkeyWatcher = null;
|
|
2559
2884
|
}
|
|
2560
|
-
|
|
2561
|
-
|
|
2562
|
-
|
|
2563
|
-
|
|
2885
|
+
if (overlayMode !== "hidden") {
|
|
2886
|
+
libStore.setState((state) => ({
|
|
2887
|
+
...state,
|
|
2888
|
+
overlayMode: "hidden"
|
|
2889
|
+
}));
|
|
2890
|
+
}
|
|
2891
|
+
return;
|
|
2564
2892
|
}
|
|
2565
|
-
if (
|
|
2566
|
-
|
|
2567
|
-
|
|
2568
|
-
|
|
2569
|
-
|
|
2570
|
-
|
|
2893
|
+
if (overlayMode === "hidden" && !cleanupActivationHotkeyWatcher) {
|
|
2894
|
+
cleanupActivationHotkeyWatcher = watchKeyHeldFor(
|
|
2895
|
+
resolvedOptions.hotkey,
|
|
2896
|
+
resolvedOptions.keyHoldDuration,
|
|
2897
|
+
() => {
|
|
2898
|
+
libStore.setState((state) => ({
|
|
2899
|
+
...state,
|
|
2900
|
+
overlayMode: "visible"
|
|
2901
|
+
}));
|
|
2902
|
+
cleanupActivationHotkeyWatcher = null;
|
|
2571
2903
|
}
|
|
2904
|
+
);
|
|
2905
|
+
}
|
|
2906
|
+
};
|
|
2907
|
+
const cleanupKeyStateChangeSubscription = libStore.subscribe(
|
|
2908
|
+
handleKeyStateChange,
|
|
2909
|
+
(state) => state.pressedKeys
|
|
2910
|
+
);
|
|
2911
|
+
const handleMouseMove = throttle((event) => {
|
|
2912
|
+
libStore.setState((state) => ({
|
|
2913
|
+
...state,
|
|
2914
|
+
mouseX: event.clientX,
|
|
2915
|
+
mouseY: event.clientY
|
|
2916
|
+
}));
|
|
2917
|
+
}, THROTTLE_DELAY);
|
|
2918
|
+
const handleMouseDown = (event) => {
|
|
2919
|
+
if (event.button !== 0) {
|
|
2920
|
+
return;
|
|
2921
|
+
}
|
|
2922
|
+
const { overlayMode } = libStore.getState();
|
|
2923
|
+
if (overlayMode === "hidden") {
|
|
2924
|
+
return;
|
|
2925
|
+
}
|
|
2926
|
+
event.preventDefault();
|
|
2927
|
+
event.stopPropagation();
|
|
2928
|
+
event.stopImmediatePropagation();
|
|
2929
|
+
libStore.setState((state) => ({
|
|
2930
|
+
...state,
|
|
2931
|
+
overlayMode: "copying"
|
|
2932
|
+
}));
|
|
2933
|
+
};
|
|
2934
|
+
window.addEventListener("mousemove", handleMouseMove);
|
|
2935
|
+
window.addEventListener("mousedown", handleMouseDown);
|
|
2936
|
+
const cleanupTrackHotkeys = trackHotkeys();
|
|
2937
|
+
const getElementAtPosition = (x, y) => {
|
|
2938
|
+
const elements = document.elementsFromPoint(x, y);
|
|
2939
|
+
for (const element of elements) {
|
|
2940
|
+
if (element.closest(`[${ATTRIBUTE_NAME}]`)) {
|
|
2941
|
+
continue;
|
|
2942
|
+
}
|
|
2943
|
+
const computedStyle = window.getComputedStyle(element);
|
|
2944
|
+
if (!isElementVisible(element, computedStyle)) {
|
|
2945
|
+
continue;
|
|
2572
2946
|
}
|
|
2947
|
+
return element;
|
|
2573
2948
|
}
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
const serializedStack = serializeStack(filteredStack);
|
|
2588
|
-
output = `${serializedStack}
|
|
2949
|
+
return null;
|
|
2950
|
+
};
|
|
2951
|
+
const handleCopy = async (element) => {
|
|
2952
|
+
const rect = element.getBoundingClientRect();
|
|
2953
|
+
const cleanupCopyIndicator = showCopyIndicator(rect.left, rect.top);
|
|
2954
|
+
try {
|
|
2955
|
+
const stack = await getStack(element);
|
|
2956
|
+
const htmlSnippet = getHTMLSnippet(element);
|
|
2957
|
+
let text = htmlSnippet;
|
|
2958
|
+
if (stack) {
|
|
2959
|
+
const filteredStack = filterStack(stack);
|
|
2960
|
+
const serializedStack = serializeStack(filteredStack);
|
|
2961
|
+
text = `${serializedStack}
|
|
2589
2962
|
|
|
2590
2963
|
${htmlSnippet}`;
|
|
2591
|
-
}
|
|
2592
|
-
return copyText(output);
|
|
2593
|
-
}).then((success) => {
|
|
2594
|
-
if (success) {
|
|
2595
|
-
showSuccess();
|
|
2596
|
-
}
|
|
2597
|
-
}).catch(() => {
|
|
2598
|
-
});
|
|
2599
2964
|
}
|
|
2965
|
+
await copyTextToClipboard(`
|
|
2966
|
+
${text}`);
|
|
2967
|
+
const tagName = (element.tagName || "").toLowerCase();
|
|
2968
|
+
cleanupCopyIndicator(tagName);
|
|
2969
|
+
} catch {
|
|
2970
|
+
cleanupCopyIndicator();
|
|
2600
2971
|
}
|
|
2601
|
-
}
|
|
2602
|
-
|
|
2603
|
-
|
|
2604
|
-
if (
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2972
|
+
};
|
|
2973
|
+
const handleRender = throttle((state) => {
|
|
2974
|
+
const { mouseX, mouseY, overlayMode } = state;
|
|
2975
|
+
if (overlayMode === "hidden") {
|
|
2976
|
+
if (selectionOverlay.isVisible()) {
|
|
2977
|
+
selectionOverlay.hide();
|
|
2978
|
+
hoveredElement = null;
|
|
2979
|
+
}
|
|
2980
|
+
return;
|
|
2981
|
+
}
|
|
2982
|
+
if (overlayMode === "copying" && hoveredElement) {
|
|
2983
|
+
const computedStyle2 = window.getComputedStyle(hoveredElement);
|
|
2984
|
+
const rect2 = hoveredElement.getBoundingClientRect();
|
|
2985
|
+
selectionOverlay.update({
|
|
2986
|
+
borderRadius: computedStyle2.borderRadius || "0px",
|
|
2987
|
+
height: rect2.height,
|
|
2988
|
+
transform: computedStyle2.transform || "none",
|
|
2989
|
+
width: rect2.width,
|
|
2990
|
+
x: rect2.left,
|
|
2991
|
+
y: rect2.top
|
|
2992
|
+
});
|
|
2993
|
+
if (!selectionOverlay.isVisible()) {
|
|
2994
|
+
selectionOverlay.show();
|
|
2995
|
+
}
|
|
2996
|
+
if (!isCopying) {
|
|
2997
|
+
isCopying = true;
|
|
2998
|
+
void handleCopy(hoveredElement).finally(() => {
|
|
2999
|
+
libStore.setState((state2) => ({
|
|
3000
|
+
...state2,
|
|
3001
|
+
overlayMode: "hidden"
|
|
3002
|
+
}));
|
|
3003
|
+
isCopying = false;
|
|
2631
3004
|
});
|
|
2632
3005
|
}
|
|
3006
|
+
return;
|
|
2633
3007
|
}
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
window.clearTimeout(shiftKeyTimeout);
|
|
2639
|
-
shiftKeyTimeout = null;
|
|
3008
|
+
const element = getElementAtPosition(mouseX, mouseY);
|
|
3009
|
+
if (!element) {
|
|
3010
|
+
if (selectionOverlay.isVisible()) {
|
|
3011
|
+
selectionOverlay.hide();
|
|
2640
3012
|
}
|
|
2641
|
-
|
|
3013
|
+
hoveredElement = null;
|
|
3014
|
+
return;
|
|
3015
|
+
}
|
|
3016
|
+
hoveredElement = element;
|
|
3017
|
+
const rect = element.getBoundingClientRect();
|
|
3018
|
+
const computedStyle = window.getComputedStyle(element);
|
|
3019
|
+
const borderRadius = computedStyle.borderRadius || "0px";
|
|
3020
|
+
const transform = computedStyle.transform || "none";
|
|
3021
|
+
selectionOverlay.update({
|
|
3022
|
+
borderRadius,
|
|
3023
|
+
height: rect.height,
|
|
3024
|
+
transform,
|
|
3025
|
+
width: rect.width,
|
|
3026
|
+
x: rect.left,
|
|
3027
|
+
y: rect.top
|
|
3028
|
+
});
|
|
3029
|
+
if (!selectionOverlay.isVisible()) {
|
|
3030
|
+
selectionOverlay.show();
|
|
2642
3031
|
}
|
|
3032
|
+
}, 10);
|
|
3033
|
+
const cleanupRenderSubscription = libStore.subscribe((state) => {
|
|
3034
|
+
scheduleRunWhenIdle(() => {
|
|
3035
|
+
handleRender(state);
|
|
3036
|
+
});
|
|
2643
3037
|
});
|
|
3038
|
+
let timeout = null;
|
|
3039
|
+
const render = () => {
|
|
3040
|
+
timeout = window.setTimeout(() => {
|
|
3041
|
+
scheduleRunWhenIdle(() => {
|
|
3042
|
+
handleRender(libStore.getState());
|
|
3043
|
+
render();
|
|
3044
|
+
});
|
|
3045
|
+
}, 100);
|
|
3046
|
+
};
|
|
3047
|
+
render();
|
|
2644
3048
|
return () => {
|
|
3049
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
3050
|
+
window.removeEventListener("mousedown", handleMouseDown);
|
|
3051
|
+
cleanupTrackHotkeys();
|
|
3052
|
+
cleanupRenderSubscription();
|
|
3053
|
+
cleanupKeyStateChangeSubscription();
|
|
2645
3054
|
if (timeout) {
|
|
2646
3055
|
window.clearTimeout(timeout);
|
|
2647
|
-
timeout = null;
|
|
2648
3056
|
}
|
|
2649
|
-
if (
|
|
2650
|
-
|
|
2651
|
-
shiftKeyTimeout = null;
|
|
3057
|
+
if (cleanupActivationHotkeyWatcher) {
|
|
3058
|
+
cleanupActivationHotkeyWatcher();
|
|
2652
3059
|
}
|
|
2653
|
-
root.remove();
|
|
2654
|
-
throttledRender.cancel();
|
|
2655
3060
|
};
|
|
2656
3061
|
};
|
|
2657
|
-
|
|
3062
|
+
if (typeof window !== "undefined" && typeof document !== "undefined") {
|
|
3063
|
+
const currentScript = document.currentScript;
|
|
3064
|
+
let options = {};
|
|
3065
|
+
if (currentScript) {
|
|
3066
|
+
const maybeOptions = currentScript.getAttribute("data-options");
|
|
3067
|
+
if (maybeOptions) {
|
|
3068
|
+
try {
|
|
3069
|
+
options = JSON.parse(maybeOptions);
|
|
3070
|
+
} catch {
|
|
3071
|
+
}
|
|
3072
|
+
}
|
|
3073
|
+
}
|
|
3074
|
+
init(options);
|
|
3075
|
+
}
|
|
2658
3076
|
/*! Bundled license information:
|
|
2659
3077
|
|
|
2660
3078
|
bippy/dist/src-R2iEnVC1.js:
|
|
@@ -2699,6 +3117,7 @@ Path: ${window.location.pathname}`;
|
|
|
2699
3117
|
*/
|
|
2700
3118
|
|
|
2701
3119
|
exports.init = init;
|
|
3120
|
+
exports.libStore = libStore;
|
|
2702
3121
|
|
|
2703
3122
|
return exports;
|
|
2704
3123
|
|