react-grab 0.0.9 → 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 +765 -320
- package/package.json +1 -1
- package/dist/core.cjs +0 -259
- package/dist/core.d.cts +0 -10
- package/dist/core.d.ts +0 -10
- package/dist/core.js +0 -254
package/dist/index.global.js
CHANGED
|
@@ -10,6 +10,440 @@ 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
|
+
|
|
217
|
+
// src/overlay.ts
|
|
218
|
+
var VIEWPORT_MARGIN_PX = 8;
|
|
219
|
+
var LABEL_OFFSET_PX = 6;
|
|
220
|
+
var lerp = (start, end, factor) => {
|
|
221
|
+
return start + (end - start) * factor;
|
|
222
|
+
};
|
|
223
|
+
var SELECTION_LERP_FACTOR = 0.95;
|
|
224
|
+
var createSelectionElement = ({
|
|
225
|
+
borderRadius,
|
|
226
|
+
height,
|
|
227
|
+
transform,
|
|
228
|
+
width,
|
|
229
|
+
x,
|
|
230
|
+
y
|
|
231
|
+
}) => {
|
|
232
|
+
const overlay = document.createElement("div");
|
|
233
|
+
overlay.style.position = "fixed";
|
|
234
|
+
overlay.style.top = `${y}px`;
|
|
235
|
+
overlay.style.left = `${x}px`;
|
|
236
|
+
overlay.style.width = `${width}px`;
|
|
237
|
+
overlay.style.height = `${height}px`;
|
|
238
|
+
overlay.style.borderRadius = borderRadius;
|
|
239
|
+
overlay.style.transform = transform;
|
|
240
|
+
overlay.style.pointerEvents = "none";
|
|
241
|
+
overlay.style.border = "1px solid rgb(210, 57, 192)";
|
|
242
|
+
overlay.style.backgroundColor = "rgba(210, 57, 192, 0.2)";
|
|
243
|
+
overlay.style.zIndex = "2147483646";
|
|
244
|
+
overlay.style.boxSizing = "border-box";
|
|
245
|
+
overlay.style.display = "none";
|
|
246
|
+
return overlay;
|
|
247
|
+
};
|
|
248
|
+
var updateSelectionElement = (element, { borderRadius, height, transform, width, x, y }) => {
|
|
249
|
+
const currentTop = parseFloat(element.style.top) || 0;
|
|
250
|
+
const currentLeft = parseFloat(element.style.left) || 0;
|
|
251
|
+
const currentWidth = parseFloat(element.style.width) || 0;
|
|
252
|
+
const currentHeight = parseFloat(element.style.height) || 0;
|
|
253
|
+
const topValue = `${lerp(currentTop, y, SELECTION_LERP_FACTOR)}px`;
|
|
254
|
+
const leftValue = `${lerp(currentLeft, x, SELECTION_LERP_FACTOR)}px`;
|
|
255
|
+
const widthValue = `${lerp(currentWidth, width, SELECTION_LERP_FACTOR)}px`;
|
|
256
|
+
const heightValue = `${lerp(currentHeight, height, SELECTION_LERP_FACTOR)}px`;
|
|
257
|
+
if (element.style.top !== topValue) {
|
|
258
|
+
element.style.top = topValue;
|
|
259
|
+
}
|
|
260
|
+
if (element.style.left !== leftValue) {
|
|
261
|
+
element.style.left = leftValue;
|
|
262
|
+
}
|
|
263
|
+
if (element.style.width !== widthValue) {
|
|
264
|
+
element.style.width = widthValue;
|
|
265
|
+
}
|
|
266
|
+
if (element.style.height !== heightValue) {
|
|
267
|
+
element.style.height = heightValue;
|
|
268
|
+
}
|
|
269
|
+
if (element.style.borderRadius !== borderRadius) {
|
|
270
|
+
element.style.borderRadius = borderRadius;
|
|
271
|
+
}
|
|
272
|
+
if (element.style.transform !== transform) {
|
|
273
|
+
element.style.transform = transform;
|
|
274
|
+
}
|
|
275
|
+
};
|
|
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
|
+
};
|
|
303
|
+
};
|
|
304
|
+
var createSpinner = () => {
|
|
305
|
+
const spinner = document.createElement("span");
|
|
306
|
+
spinner.style.display = "inline-block";
|
|
307
|
+
spinner.style.width = "8px";
|
|
308
|
+
spinner.style.height = "8px";
|
|
309
|
+
spinner.style.border = "1.5px solid rgb(210, 57, 192)";
|
|
310
|
+
spinner.style.borderTopColor = "transparent";
|
|
311
|
+
spinner.style.borderRadius = "50%";
|
|
312
|
+
spinner.style.marginRight = "4px";
|
|
313
|
+
spinner.style.verticalAlign = "middle";
|
|
314
|
+
spinner.animate(
|
|
315
|
+
[{ transform: "rotate(0deg)" }, { transform: "rotate(360deg)" }],
|
|
316
|
+
{
|
|
317
|
+
duration: 600,
|
|
318
|
+
easing: "linear",
|
|
319
|
+
iterations: Infinity
|
|
320
|
+
}
|
|
321
|
+
);
|
|
322
|
+
return spinner;
|
|
323
|
+
};
|
|
324
|
+
var activeIndicator = null;
|
|
325
|
+
var createIndicator = () => {
|
|
326
|
+
const indicator = document.createElement("div");
|
|
327
|
+
indicator.style.position = "fixed";
|
|
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";
|
|
333
|
+
indicator.style.borderRadius = "4px";
|
|
334
|
+
indicator.style.fontSize = "11px";
|
|
335
|
+
indicator.style.fontWeight = "500";
|
|
336
|
+
indicator.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
337
|
+
indicator.style.zIndex = "2147483647";
|
|
338
|
+
indicator.style.pointerEvents = "none";
|
|
339
|
+
indicator.style.opacity = "0";
|
|
340
|
+
indicator.style.transition = "opacity 0.2s ease-in-out";
|
|
341
|
+
indicator.style.display = "flex";
|
|
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";
|
|
347
|
+
return indicator;
|
|
348
|
+
};
|
|
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);
|
|
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";
|
|
384
|
+
requestAnimationFrame(() => {
|
|
385
|
+
indicator.style.opacity = "1";
|
|
386
|
+
});
|
|
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
|
+
);
|
|
403
|
+
setTimeout(() => {
|
|
404
|
+
indicator.style.opacity = "0";
|
|
405
|
+
setTimeout(() => {
|
|
406
|
+
indicator.remove();
|
|
407
|
+
if (activeIndicator === indicator) {
|
|
408
|
+
activeIndicator = null;
|
|
409
|
+
}
|
|
410
|
+
}, 200);
|
|
411
|
+
}, 1500);
|
|
412
|
+
};
|
|
413
|
+
};
|
|
414
|
+
|
|
415
|
+
// src/utils/copy-text.ts
|
|
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) {
|
|
419
|
+
try {
|
|
420
|
+
await navigator.clipboard.writeText(text);
|
|
421
|
+
return true;
|
|
422
|
+
} catch {
|
|
423
|
+
}
|
|
424
|
+
}
|
|
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;
|
|
437
|
+
try {
|
|
438
|
+
didCopyToClipboard = document.execCommand("copy");
|
|
439
|
+
} catch {
|
|
440
|
+
didCopyToClipboard = false;
|
|
441
|
+
} finally {
|
|
442
|
+
doc.removeChild(textareaElement);
|
|
443
|
+
}
|
|
444
|
+
return didCopyToClipboard;
|
|
445
|
+
};
|
|
446
|
+
|
|
13
447
|
// node_modules/.pnpm/bippy@0.3.31_@types+react@19.2.2_react@19.2.0/node_modules/bippy/dist/src-R2iEnVC1.js
|
|
14
448
|
var version = "0.3.31";
|
|
15
449
|
var BIPPY_INSTRUMENTATION_STRING = `bippy-${version}`;
|
|
@@ -1983,7 +2417,7 @@ ${error.stack}`;
|
|
|
1983
2417
|
return matches;
|
|
1984
2418
|
};
|
|
1985
2419
|
|
|
1986
|
-
// src/
|
|
2420
|
+
// src/utils/data.ts
|
|
1987
2421
|
var getStack = async (element) => {
|
|
1988
2422
|
const fiber = getFiberFromHostInstance(element);
|
|
1989
2423
|
if (!fiber) return null;
|
|
@@ -2225,190 +2659,21 @@ ${error.stack}`;
|
|
|
2225
2659
|
return lines.join("\n");
|
|
2226
2660
|
};
|
|
2227
2661
|
|
|
2228
|
-
// src/overlay.ts
|
|
2229
|
-
var createSelection = ({
|
|
2230
|
-
borderRadius,
|
|
2231
|
-
height,
|
|
2232
|
-
transform,
|
|
2233
|
-
width,
|
|
2234
|
-
x,
|
|
2235
|
-
y
|
|
2236
|
-
}) => {
|
|
2237
|
-
const overlay = document.createElement("div");
|
|
2238
|
-
overlay.style.position = "fixed";
|
|
2239
|
-
overlay.style.top = `${y}px`;
|
|
2240
|
-
overlay.style.left = `${x}px`;
|
|
2241
|
-
overlay.style.width = `${width}px`;
|
|
2242
|
-
overlay.style.height = `${height}px`;
|
|
2243
|
-
overlay.style.borderRadius = borderRadius;
|
|
2244
|
-
overlay.style.transform = transform;
|
|
2245
|
-
overlay.style.pointerEvents = "none";
|
|
2246
|
-
overlay.style.border = "2px solid #007AFF";
|
|
2247
|
-
overlay.style.backgroundColor = "rgba(0, 122, 255, 0.1)";
|
|
2248
|
-
overlay.style.zIndex = "2147483646";
|
|
2249
|
-
overlay.style.boxSizing = "border-box";
|
|
2250
|
-
overlay.animate(
|
|
2251
|
-
[
|
|
2252
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.1)" },
|
|
2253
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.15)" },
|
|
2254
|
-
{ backgroundColor: "rgba(0, 122, 255, 0.1)" }
|
|
2255
|
-
],
|
|
2256
|
-
{
|
|
2257
|
-
duration: 2e3,
|
|
2258
|
-
easing: "ease-in-out",
|
|
2259
|
-
iterations: Infinity
|
|
2260
|
-
}
|
|
2261
|
-
);
|
|
2262
|
-
return overlay;
|
|
2263
|
-
};
|
|
2264
|
-
var lerp = (start, end, factor) => {
|
|
2265
|
-
return start + (end - start) * factor;
|
|
2266
|
-
};
|
|
2267
|
-
var SELECTION_LERP_FACTOR = 1;
|
|
2268
|
-
var updateSelection = (element, { borderRadius, height, transform, width, x, y }) => {
|
|
2269
|
-
const currentTop = parseFloat(element.style.top) || 0;
|
|
2270
|
-
const currentLeft = parseFloat(element.style.left) || 0;
|
|
2271
|
-
const currentWidth = parseFloat(element.style.width) || 0;
|
|
2272
|
-
const currentHeight = parseFloat(element.style.height) || 0;
|
|
2273
|
-
const topValue = `${lerp(currentTop, y, SELECTION_LERP_FACTOR)}px`;
|
|
2274
|
-
const leftValue = `${lerp(currentLeft, x, SELECTION_LERP_FACTOR)}px`;
|
|
2275
|
-
const widthValue = `${lerp(currentWidth, width, SELECTION_LERP_FACTOR)}px`;
|
|
2276
|
-
const heightValue = `${lerp(currentHeight, height, SELECTION_LERP_FACTOR)}px`;
|
|
2277
|
-
if (element.style.top !== topValue) {
|
|
2278
|
-
element.style.top = topValue;
|
|
2279
|
-
}
|
|
2280
|
-
if (element.style.left !== leftValue) {
|
|
2281
|
-
element.style.left = leftValue;
|
|
2282
|
-
}
|
|
2283
|
-
if (element.style.width !== widthValue) {
|
|
2284
|
-
element.style.width = widthValue;
|
|
2285
|
-
}
|
|
2286
|
-
if (element.style.height !== heightValue) {
|
|
2287
|
-
element.style.height = heightValue;
|
|
2288
|
-
}
|
|
2289
|
-
if (element.style.borderRadius !== borderRadius) {
|
|
2290
|
-
element.style.borderRadius = borderRadius;
|
|
2291
|
-
}
|
|
2292
|
-
if (element.style.transform !== transform) {
|
|
2293
|
-
element.style.transform = transform;
|
|
2294
|
-
}
|
|
2295
|
-
};
|
|
2296
|
-
var createSpinner = () => {
|
|
2297
|
-
const spinner = document.createElement("span");
|
|
2298
|
-
spinner.style.display = "inline-block";
|
|
2299
|
-
spinner.style.width = "8px";
|
|
2300
|
-
spinner.style.height = "8px";
|
|
2301
|
-
spinner.style.border = "1.5px solid #1e4ed8";
|
|
2302
|
-
spinner.style.borderTopColor = "transparent";
|
|
2303
|
-
spinner.style.borderRadius = "50%";
|
|
2304
|
-
spinner.style.marginRight = "4px";
|
|
2305
|
-
spinner.style.verticalAlign = "middle";
|
|
2306
|
-
spinner.animate(
|
|
2307
|
-
[
|
|
2308
|
-
{ transform: "rotate(0deg)" },
|
|
2309
|
-
{ transform: "rotate(360deg)" }
|
|
2310
|
-
],
|
|
2311
|
-
{
|
|
2312
|
-
duration: 600,
|
|
2313
|
-
easing: "linear",
|
|
2314
|
-
iterations: Infinity
|
|
2315
|
-
}
|
|
2316
|
-
);
|
|
2317
|
-
return spinner;
|
|
2318
|
-
};
|
|
2319
|
-
var createIndicator = (x, y) => {
|
|
2320
|
-
const indicator = document.createElement("div");
|
|
2321
|
-
indicator.style.position = "fixed";
|
|
2322
|
-
indicator.style.left = `${x}px`;
|
|
2323
|
-
indicator.style.top = `${y - 4}px`;
|
|
2324
|
-
indicator.style.transform = "translateY(-100%)";
|
|
2325
|
-
indicator.style.padding = "0px 4px";
|
|
2326
|
-
indicator.style.backgroundColor = "#dbeafe";
|
|
2327
|
-
indicator.style.color = "#1e4ed8";
|
|
2328
|
-
indicator.style.border = "1px solid #c7dbfb";
|
|
2329
|
-
indicator.style.borderRadius = "4px";
|
|
2330
|
-
indicator.style.fontSize = "11px";
|
|
2331
|
-
indicator.style.fontWeight = "500";
|
|
2332
|
-
indicator.style.fontFamily = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif";
|
|
2333
|
-
indicator.style.zIndex = "2147483647";
|
|
2334
|
-
indicator.style.pointerEvents = "none";
|
|
2335
|
-
indicator.style.opacity = "0";
|
|
2336
|
-
indicator.style.transition = "opacity 0.2s ease-in-out";
|
|
2337
|
-
indicator.style.display = "flex";
|
|
2338
|
-
indicator.style.alignItems = "center";
|
|
2339
|
-
return indicator;
|
|
2340
|
-
};
|
|
2341
|
-
var showCopyIndicator = (x, y) => {
|
|
2342
|
-
const indicator = createIndicator(x, y);
|
|
2343
|
-
const spinner = createSpinner();
|
|
2344
|
-
const text = document.createElement("span");
|
|
2345
|
-
text.textContent = "Copying\u2026";
|
|
2346
|
-
indicator.appendChild(spinner);
|
|
2347
|
-
indicator.appendChild(text);
|
|
2348
|
-
document.body.appendChild(indicator);
|
|
2349
|
-
requestAnimationFrame(() => {
|
|
2350
|
-
indicator.style.opacity = "1";
|
|
2351
|
-
});
|
|
2352
|
-
return () => {
|
|
2353
|
-
spinner.remove();
|
|
2354
|
-
text.textContent = "Copied!";
|
|
2355
|
-
setTimeout(() => {
|
|
2356
|
-
indicator.style.opacity = "0";
|
|
2357
|
-
setTimeout(() => {
|
|
2358
|
-
document.body.removeChild(indicator);
|
|
2359
|
-
}, 200);
|
|
2360
|
-
}, 1500);
|
|
2361
|
-
};
|
|
2362
|
-
};
|
|
2363
|
-
|
|
2364
|
-
// src/utils/copy-text.ts
|
|
2365
|
-
var copyText = async (text) => {
|
|
2366
|
-
if (navigator.clipboard && window.isSecureContext) {
|
|
2367
|
-
try {
|
|
2368
|
-
await navigator.clipboard.writeText(text);
|
|
2369
|
-
return true;
|
|
2370
|
-
} catch {
|
|
2371
|
-
}
|
|
2372
|
-
}
|
|
2373
|
-
const textareaEl = document.createElement("textarea");
|
|
2374
|
-
textareaEl.value = text;
|
|
2375
|
-
textareaEl.setAttribute("readonly", "");
|
|
2376
|
-
textareaEl.style.position = "fixed";
|
|
2377
|
-
textareaEl.style.top = "-9999px";
|
|
2378
|
-
textareaEl.style.opacity = "0";
|
|
2379
|
-
textareaEl.style.pointerEvents = "none";
|
|
2380
|
-
document.body.appendChild(textareaEl);
|
|
2381
|
-
textareaEl.select();
|
|
2382
|
-
textareaEl.setSelectionRange(0, textareaEl.value.length);
|
|
2383
|
-
let didCopy = false;
|
|
2384
|
-
try {
|
|
2385
|
-
didCopy = document.execCommand("copy");
|
|
2386
|
-
} catch {
|
|
2387
|
-
didCopy = false;
|
|
2388
|
-
} finally {
|
|
2389
|
-
document.body.removeChild(textareaEl);
|
|
2390
|
-
}
|
|
2391
|
-
return didCopy;
|
|
2392
|
-
};
|
|
2393
|
-
|
|
2394
2662
|
// src/utils/is-element-visible.ts
|
|
2395
|
-
var isElementVisible = (element, computedStyle =
|
|
2396
|
-
|
|
2397
|
-
computedStyle = window.getComputedStyle(element);
|
|
2398
|
-
}
|
|
2399
|
-
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";
|
|
2400
2665
|
};
|
|
2401
2666
|
|
|
2402
2667
|
// src/utils/mount-root.ts
|
|
2403
2668
|
var ATTRIBUTE_NAME = "data-react-grab";
|
|
2404
2669
|
var mountRoot = () => {
|
|
2405
|
-
const
|
|
2406
|
-
if (
|
|
2407
|
-
const
|
|
2670
|
+
const mountedHost = document.querySelector(`[${ATTRIBUTE_NAME}]`);
|
|
2671
|
+
if (mountedHost) {
|
|
2672
|
+
const mountedRoot = mountedHost.shadowRoot?.querySelector(
|
|
2408
2673
|
`[${ATTRIBUTE_NAME}]`
|
|
2409
2674
|
);
|
|
2410
|
-
if (
|
|
2411
|
-
return
|
|
2675
|
+
if (mountedRoot instanceof HTMLDivElement && mountedHost.shadowRoot) {
|
|
2676
|
+
return mountedRoot;
|
|
2412
2677
|
}
|
|
2413
2678
|
}
|
|
2414
2679
|
const host = document.createElement("div");
|
|
@@ -2419,7 +2684,6 @@ ${error.stack}`;
|
|
|
2419
2684
|
host.style.left = "0";
|
|
2420
2685
|
const shadowRoot = host.attachShadow({ mode: "open" });
|
|
2421
2686
|
const root = document.createElement("div");
|
|
2422
|
-
root.style.transition = "opacity 0.1s ease-out";
|
|
2423
2687
|
root.setAttribute(ATTRIBUTE_NAME, "true");
|
|
2424
2688
|
shadowRoot.appendChild(root);
|
|
2425
2689
|
const doc = document.body ?? document.documentElement;
|
|
@@ -2440,6 +2704,77 @@ ${error.stack}`;
|
|
|
2440
2704
|
return setTimeout(callback, 0);
|
|
2441
2705
|
};
|
|
2442
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
|
+
|
|
2443
2778
|
// src/utils/throttle.ts
|
|
2444
2779
|
var throttle = (fn, delay) => {
|
|
2445
2780
|
let timeout = null;
|
|
@@ -2462,173 +2797,282 @@ ${error.stack}`;
|
|
|
2462
2797
|
};
|
|
2463
2798
|
|
|
2464
2799
|
// src/index.ts
|
|
2465
|
-
var TICK_INTERVAL = 50;
|
|
2466
2800
|
var THROTTLE_DELAY = 16;
|
|
2467
|
-
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
|
+
};
|
|
2468
2818
|
const root = mountRoot();
|
|
2469
|
-
|
|
2470
|
-
let
|
|
2471
|
-
let
|
|
2472
|
-
|
|
2473
|
-
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
|
|
2479
|
-
|
|
2480
|
-
|
|
2481
|
-
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
}
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
if (
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
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
|
+
}
|
|
2493
2870
|
return;
|
|
2494
2871
|
}
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
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;
|
|
2884
|
+
}
|
|
2885
|
+
if (overlayMode !== "hidden") {
|
|
2886
|
+
libStore.setState((state) => ({
|
|
2887
|
+
...state,
|
|
2888
|
+
overlayMode: "hidden"
|
|
2889
|
+
}));
|
|
2890
|
+
}
|
|
2891
|
+
return;
|
|
2892
|
+
}
|
|
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;
|
|
2903
|
+
}
|
|
2904
|
+
);
|
|
2905
|
+
}
|
|
2507
2906
|
};
|
|
2508
|
-
const
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
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
|
+
}));
|
|
2512
2917
|
}, THROTTLE_DELAY);
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
if (
|
|
2536
|
-
|
|
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;
|
|
2537
2942
|
}
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
}, 200);
|
|
2943
|
+
const computedStyle = window.getComputedStyle(element);
|
|
2944
|
+
if (!isElementVisible(element, computedStyle)) {
|
|
2945
|
+
continue;
|
|
2946
|
+
}
|
|
2947
|
+
return element;
|
|
2544
2948
|
}
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
const serializedStack = serializeStack(filteredStack);
|
|
2559
|
-
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}
|
|
2560
2962
|
|
|
2561
2963
|
${htmlSnippet}`;
|
|
2562
|
-
}
|
|
2563
|
-
return copyText(output);
|
|
2564
|
-
}).then((success) => {
|
|
2565
|
-
if (success) {
|
|
2566
|
-
showSuccess();
|
|
2567
|
-
}
|
|
2568
|
-
}).catch(() => {
|
|
2569
|
-
});
|
|
2570
2964
|
}
|
|
2965
|
+
await copyTextToClipboard(`
|
|
2966
|
+
${text}`);
|
|
2967
|
+
const tagName = (element.tagName || "").toLowerCase();
|
|
2968
|
+
cleanupCopyIndicator(tagName);
|
|
2969
|
+
} catch {
|
|
2970
|
+
cleanupCopyIndicator();
|
|
2571
2971
|
}
|
|
2572
|
-
}
|
|
2573
|
-
|
|
2574
|
-
|
|
2575
|
-
if (
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
2596
|
-
|
|
2597
|
-
|
|
2598
|
-
|
|
2599
|
-
|
|
2600
|
-
|
|
2601
|
-
|
|
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;
|
|
2602
3004
|
});
|
|
2603
3005
|
}
|
|
3006
|
+
return;
|
|
2604
3007
|
}
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
|
|
2608
|
-
|
|
2609
|
-
window.clearTimeout(shiftKeyTimeout);
|
|
2610
|
-
shiftKeyTimeout = null;
|
|
3008
|
+
const element = getElementAtPosition(mouseX, mouseY);
|
|
3009
|
+
if (!element) {
|
|
3010
|
+
if (selectionOverlay.isVisible()) {
|
|
3011
|
+
selectionOverlay.hide();
|
|
2611
3012
|
}
|
|
3013
|
+
hoveredElement = null;
|
|
3014
|
+
return;
|
|
2612
3015
|
}
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
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();
|
|
3031
|
+
}
|
|
3032
|
+
}, 10);
|
|
3033
|
+
const cleanupRenderSubscription = libStore.subscribe((state) => {
|
|
3034
|
+
scheduleRunWhenIdle(() => {
|
|
3035
|
+
handleRender(state);
|
|
3036
|
+
});
|
|
2617
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();
|
|
2618
3048
|
return () => {
|
|
3049
|
+
window.removeEventListener("mousemove", handleMouseMove);
|
|
3050
|
+
window.removeEventListener("mousedown", handleMouseDown);
|
|
3051
|
+
cleanupTrackHotkeys();
|
|
3052
|
+
cleanupRenderSubscription();
|
|
3053
|
+
cleanupKeyStateChangeSubscription();
|
|
2619
3054
|
if (timeout) {
|
|
2620
3055
|
window.clearTimeout(timeout);
|
|
2621
|
-
timeout = null;
|
|
2622
3056
|
}
|
|
2623
|
-
if (
|
|
2624
|
-
|
|
2625
|
-
shiftKeyTimeout = null;
|
|
3057
|
+
if (cleanupActivationHotkeyWatcher) {
|
|
3058
|
+
cleanupActivationHotkeyWatcher();
|
|
2626
3059
|
}
|
|
2627
|
-
root.remove();
|
|
2628
|
-
throttledRender.cancel();
|
|
2629
3060
|
};
|
|
2630
3061
|
};
|
|
2631
|
-
|
|
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
|
+
}
|
|
2632
3076
|
/*! Bundled license information:
|
|
2633
3077
|
|
|
2634
3078
|
bippy/dist/src-R2iEnVC1.js:
|
|
@@ -2673,6 +3117,7 @@ Path: ${window.location.pathname}`;
|
|
|
2673
3117
|
*/
|
|
2674
3118
|
|
|
2675
3119
|
exports.init = init;
|
|
3120
|
+
exports.libStore = libStore;
|
|
2676
3121
|
|
|
2677
3122
|
return exports;
|
|
2678
3123
|
|