react-grab 0.0.39 → 0.0.41
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.cjs +355 -555
- package/dist/index.d.cts +0 -11
- package/dist/index.d.ts +0 -11
- package/dist/index.global.js +27 -21
- package/dist/index.js +356 -556
- package/package.json +4 -7
package/dist/index.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { render, createComponent, memo, template, effect, style, insert, setStyleProperty, use } from 'solid-js/web';
|
|
2
2
|
import { createRoot, createSignal, createMemo, createEffect, on, onCleanup, Show, For, onMount } from 'solid-js';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { finder } from '@medv/finder';
|
|
3
|
+
import { getFiberFromHostInstance, traverseFiber, isCompositeFiber, getDisplayName, isFiber, getLatestFiber, isHostFiber } from 'bippy';
|
|
4
|
+
import { isSourceFile, normalizeFileName, getSource } from 'bippy/source';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* @license MIT
|
|
@@ -94,8 +93,12 @@ var mountRoot = () => {
|
|
|
94
93
|
var VIEWPORT_MARGIN_PX = 8;
|
|
95
94
|
var INDICATOR_CLAMP_PADDING_PX = 4;
|
|
96
95
|
var CURSOR_OFFSET_PX = 14;
|
|
96
|
+
var OFFSCREEN_POSITION = -1e3;
|
|
97
97
|
var SELECTION_LERP_FACTOR = 0.95;
|
|
98
98
|
var SUCCESS_LABEL_DURATION_MS = 1700;
|
|
99
|
+
var PROGRESS_INDICATOR_DELAY_MS = 150;
|
|
100
|
+
var DRAG_THRESHOLD_PX = 2;
|
|
101
|
+
var Z_INDEX_LABEL = 2147483647;
|
|
99
102
|
|
|
100
103
|
// src/utils/lerp.ts
|
|
101
104
|
var lerp = (start, end, factor) => {
|
|
@@ -176,7 +179,7 @@ var SelectionBox = (props) => {
|
|
|
176
179
|
position: "fixed",
|
|
177
180
|
"box-sizing": "border-box",
|
|
178
181
|
"pointer-events": props.variant === "drag" ? "none" : "auto",
|
|
179
|
-
"z-index": "2147483646"
|
|
182
|
+
"z-index": props.variant === "grabbed" ? "2147483645" : "2147483646"
|
|
180
183
|
};
|
|
181
184
|
const variantStyle = () => {
|
|
182
185
|
if (props.variant === "drag") {
|
|
@@ -188,10 +191,16 @@ var SelectionBox = (props) => {
|
|
|
188
191
|
cursor: "crosshair"
|
|
189
192
|
};
|
|
190
193
|
}
|
|
194
|
+
if (props.variant === "selection") {
|
|
195
|
+
return {
|
|
196
|
+
border: "1px dashed rgba(210, 57, 192, 0.5)",
|
|
197
|
+
"background-color": "rgba(210, 57, 192, 0.08)"
|
|
198
|
+
};
|
|
199
|
+
}
|
|
191
200
|
return {
|
|
192
201
|
border: "1px solid rgb(210, 57, 192)",
|
|
193
|
-
"background-color": "rgba(210, 57, 192, 0.
|
|
194
|
-
transition:
|
|
202
|
+
"background-color": "rgba(210, 57, 192, 0.08)",
|
|
203
|
+
transition: "opacity 0.3s ease-out"
|
|
195
204
|
};
|
|
196
205
|
};
|
|
197
206
|
return createComponent(Show, {
|
|
@@ -254,30 +263,22 @@ var getClampedElementPosition = (positionLeft, positionTop, elementWidth, elemen
|
|
|
254
263
|
const clampedTop = Math.max(minTop, Math.min(positionTop, maxTop));
|
|
255
264
|
return { left: clampedLeft, top: clampedTop };
|
|
256
265
|
};
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
var _tmpl$6 = /* @__PURE__ */ template(`<div style="position:fixed;padding:2px 6px;background-color:#fde7f7;color:#b21c8e;border:1px solid #f7c5ec;border-radius:4px;font-size:11px;font-weight:500;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;pointer-events:none;transition:opacity 0.2s ease-in-out;display:flex;align-items:center;max-width:calc(100vw - (16px + env(safe-area-inset-left) + env(safe-area-inset-right)));overflow:hidden;text-overflow:ellipsis;white-space:nowrap">`);
|
|
265
|
-
var Label = (props) => {
|
|
266
|
-
const [opacity, setOpacity] = createSignal(0);
|
|
267
|
-
const [positionTick, setPositionTick] = createSignal(0);
|
|
268
|
-
let labelRef;
|
|
269
|
-
let currentX = props.x;
|
|
270
|
-
let currentY = props.y;
|
|
271
|
-
let targetX = props.x;
|
|
272
|
-
let targetY = props.y;
|
|
266
|
+
var useAnimatedPosition = (options) => {
|
|
267
|
+
const lerpFactor = options.lerpFactor ?? 0.3;
|
|
268
|
+
const convergenceThreshold = options.convergenceThreshold ?? 0.5;
|
|
269
|
+
const [x, setX] = createSignal(options.x());
|
|
270
|
+
const [y, setY] = createSignal(options.y());
|
|
271
|
+
let targetX = options.x();
|
|
272
|
+
let targetY = options.y();
|
|
273
273
|
let animationFrameId = null;
|
|
274
274
|
let hasBeenRenderedOnce = false;
|
|
275
275
|
const animate = () => {
|
|
276
|
-
currentX = lerp(
|
|
277
|
-
currentY = lerp(
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
276
|
+
const currentX = lerp(x(), targetX, lerpFactor);
|
|
277
|
+
const currentY = lerp(y(), targetY, lerpFactor);
|
|
278
|
+
setX(currentX);
|
|
279
|
+
setY(currentY);
|
|
280
|
+
const hasConverged = Math.abs(currentX - targetX) < convergenceThreshold && Math.abs(currentY - targetY) < convergenceThreshold;
|
|
281
|
+
if (!hasConverged) {
|
|
281
282
|
animationFrameId = requestAnimationFrame(animate);
|
|
282
283
|
} else {
|
|
283
284
|
animationFrameId = null;
|
|
@@ -287,36 +288,16 @@ var Label = (props) => {
|
|
|
287
288
|
if (animationFrameId !== null) return;
|
|
288
289
|
animationFrameId = requestAnimationFrame(animate);
|
|
289
290
|
};
|
|
290
|
-
|
|
291
|
-
targetX =
|
|
292
|
-
targetY =
|
|
291
|
+
createEffect(() => {
|
|
292
|
+
targetX = options.x();
|
|
293
|
+
targetY = options.y();
|
|
293
294
|
if (!hasBeenRenderedOnce) {
|
|
294
|
-
|
|
295
|
-
|
|
295
|
+
setX(targetX);
|
|
296
|
+
setY(targetY);
|
|
296
297
|
hasBeenRenderedOnce = true;
|
|
297
|
-
setPositionTick((tick) => tick + 1);
|
|
298
298
|
return;
|
|
299
299
|
}
|
|
300
300
|
startAnimation();
|
|
301
|
-
};
|
|
302
|
-
createEffect(on(() => props.visible, (visible) => {
|
|
303
|
-
if (visible !== false) {
|
|
304
|
-
requestAnimationFrame(() => {
|
|
305
|
-
setOpacity(1);
|
|
306
|
-
});
|
|
307
|
-
} else {
|
|
308
|
-
setOpacity(0);
|
|
309
|
-
return;
|
|
310
|
-
}
|
|
311
|
-
if (props.variant === "success") {
|
|
312
|
-
const fadeOutTimer = setTimeout(() => {
|
|
313
|
-
setOpacity(0);
|
|
314
|
-
}, SUCCESS_LABEL_DURATION_MS);
|
|
315
|
-
onCleanup(() => clearTimeout(fadeOutTimer));
|
|
316
|
-
}
|
|
317
|
-
}));
|
|
318
|
-
createEffect(() => {
|
|
319
|
-
updateTarget();
|
|
320
301
|
});
|
|
321
302
|
onCleanup(() => {
|
|
322
303
|
if (animationFrameId !== null) {
|
|
@@ -324,34 +305,89 @@ var Label = (props) => {
|
|
|
324
305
|
animationFrameId = null;
|
|
325
306
|
}
|
|
326
307
|
});
|
|
308
|
+
return { x, y };
|
|
309
|
+
};
|
|
310
|
+
var useFadeInOut = (options) => {
|
|
311
|
+
const [opacity, setOpacity] = createSignal(0);
|
|
312
|
+
createEffect(
|
|
313
|
+
on(
|
|
314
|
+
() => options.visible,
|
|
315
|
+
(isVisible) => {
|
|
316
|
+
if (isVisible !== false) {
|
|
317
|
+
requestAnimationFrame(() => {
|
|
318
|
+
setOpacity(1);
|
|
319
|
+
});
|
|
320
|
+
} else {
|
|
321
|
+
setOpacity(0);
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
if (options.autoFadeOutAfter !== void 0) {
|
|
325
|
+
const fadeOutTimer = setTimeout(() => {
|
|
326
|
+
setOpacity(0);
|
|
327
|
+
}, options.autoFadeOutAfter);
|
|
328
|
+
onCleanup(() => clearTimeout(fadeOutTimer));
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
)
|
|
332
|
+
);
|
|
333
|
+
return opacity;
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
// src/utils/get-cursor-quadrants.ts
|
|
337
|
+
var getCursorQuadrants = (cursorX, cursorY, elementWidth, elementHeight, offset) => {
|
|
338
|
+
return [
|
|
339
|
+
{
|
|
340
|
+
left: Math.round(cursorX) + offset,
|
|
341
|
+
top: Math.round(cursorY) + offset
|
|
342
|
+
},
|
|
343
|
+
{
|
|
344
|
+
left: Math.round(cursorX) - elementWidth - offset,
|
|
345
|
+
top: Math.round(cursorY) + offset
|
|
346
|
+
},
|
|
347
|
+
{
|
|
348
|
+
left: Math.round(cursorX) + offset,
|
|
349
|
+
top: Math.round(cursorY) - elementHeight - offset
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
left: Math.round(cursorX) - elementWidth - offset,
|
|
353
|
+
top: Math.round(cursorY) - elementHeight - offset
|
|
354
|
+
}
|
|
355
|
+
];
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
// src/components/label.tsx
|
|
359
|
+
var _tmpl$3 = /* @__PURE__ */ template(`<span style=display:inline-block;margin-right:4px;font-weight:600>\u2713`);
|
|
360
|
+
var _tmpl$22 = /* @__PURE__ */ template(`<div style=margin-right:4px>Copied`);
|
|
361
|
+
var _tmpl$32 = /* @__PURE__ */ template(`<span style="font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;font-variant-numeric:tabular-nums;vertical-align:middle">`);
|
|
362
|
+
var _tmpl$4 = /* @__PURE__ */ template(`<span style=font-variant-numeric:tabular-nums;font-size:10px;margin-left:4px;vertical-align:middle>`);
|
|
363
|
+
var _tmpl$5 = /* @__PURE__ */ template(`<div style=margin-left:4px>to clipboard`);
|
|
364
|
+
var _tmpl$6 = /* @__PURE__ */ template(`<div style="position:fixed;padding:2px 6px;background-color:#fde7f7;color:#b21c8e;border:1px solid #f7c5ec;border-radius:4px;font-size:11px;font-weight:500;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;pointer-events:none;transition:opacity 0.2s ease-in-out;display:flex;align-items:center;max-width:calc(100vw - (16px + env(safe-area-inset-left) + env(safe-area-inset-right)));overflow:hidden;text-overflow:ellipsis;white-space:nowrap">`);
|
|
365
|
+
var Label = (props) => {
|
|
366
|
+
let labelRef;
|
|
367
|
+
const position = useAnimatedPosition({
|
|
368
|
+
x: () => props.x,
|
|
369
|
+
y: () => props.y,
|
|
370
|
+
lerpFactor: 0.3
|
|
371
|
+
});
|
|
372
|
+
const opacity = useFadeInOut({
|
|
373
|
+
visible: props.visible,
|
|
374
|
+
autoFadeOutAfter: props.variant === "success" ? SUCCESS_LABEL_DURATION_MS : void 0
|
|
375
|
+
});
|
|
327
376
|
const labelBoundingRect = () => labelRef?.getBoundingClientRect();
|
|
328
377
|
const computedPosition = () => {
|
|
329
|
-
positionTick();
|
|
330
378
|
const boundingRect = labelBoundingRect();
|
|
331
379
|
if (!boundingRect) return {
|
|
332
|
-
left:
|
|
333
|
-
top:
|
|
380
|
+
left: position.x(),
|
|
381
|
+
top: position.y()
|
|
334
382
|
};
|
|
335
383
|
const viewportWidth = window.innerWidth;
|
|
336
384
|
const viewportHeight = window.innerHeight;
|
|
337
|
-
const quadrants =
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
left: Math.round(currentX) - boundingRect.width - CURSOR_OFFSET_PX,
|
|
342
|
-
top: Math.round(currentY) + CURSOR_OFFSET_PX
|
|
343
|
-
}, {
|
|
344
|
-
left: Math.round(currentX) + CURSOR_OFFSET_PX,
|
|
345
|
-
top: Math.round(currentY) - boundingRect.height - CURSOR_OFFSET_PX
|
|
346
|
-
}, {
|
|
347
|
-
left: Math.round(currentX) - boundingRect.width - CURSOR_OFFSET_PX,
|
|
348
|
-
top: Math.round(currentY) - boundingRect.height - CURSOR_OFFSET_PX
|
|
349
|
-
}];
|
|
350
|
-
for (const position of quadrants) {
|
|
351
|
-
const fitsHorizontally = position.left >= VIEWPORT_MARGIN_PX && position.left + boundingRect.width <= viewportWidth - VIEWPORT_MARGIN_PX;
|
|
352
|
-
const fitsVertically = position.top >= VIEWPORT_MARGIN_PX && position.top + boundingRect.height <= viewportHeight - VIEWPORT_MARGIN_PX;
|
|
385
|
+
const quadrants = getCursorQuadrants(position.x(), position.y(), boundingRect.width, boundingRect.height, CURSOR_OFFSET_PX);
|
|
386
|
+
for (const position2 of quadrants) {
|
|
387
|
+
const fitsHorizontally = position2.left >= VIEWPORT_MARGIN_PX && position2.left + boundingRect.width <= viewportWidth - VIEWPORT_MARGIN_PX;
|
|
388
|
+
const fitsVertically = position2.top >= VIEWPORT_MARGIN_PX && position2.top + boundingRect.height <= viewportHeight - VIEWPORT_MARGIN_PX;
|
|
353
389
|
if (fitsHorizontally && fitsVertically) {
|
|
354
|
-
return
|
|
390
|
+
return position2;
|
|
355
391
|
}
|
|
356
392
|
}
|
|
357
393
|
const fallback = getClampedElementPosition(quadrants[0].left, quadrants[0].top, boundingRect.width, boundingRect.height);
|
|
@@ -458,21 +494,10 @@ var Label = (props) => {
|
|
|
458
494
|
});
|
|
459
495
|
};
|
|
460
496
|
var _tmpl$7 = /* @__PURE__ */ template(`<div style="position:fixed;z-index:2147483647;pointer-events:none;transition:opacity 0.1s ease-in-out"><div style="width:32px;height:2px;background-color:rgba(178, 28, 142, 0.2);border-radius:1px;overflow:hidden;position:relative"><div style="height:100%;background-color:#b21c8e;border-radius:1px;transition:width 0.05s cubic-bezier(0.165, 0.84, 0.44, 1)">`);
|
|
461
|
-
var useFadeInOut = (visible) => {
|
|
462
|
-
const [opacity, setOpacity] = createSignal(0);
|
|
463
|
-
createEffect(on(() => visible, (isVisible) => {
|
|
464
|
-
if (isVisible !== false) {
|
|
465
|
-
requestAnimationFrame(() => {
|
|
466
|
-
setOpacity(1);
|
|
467
|
-
});
|
|
468
|
-
} else {
|
|
469
|
-
setOpacity(0);
|
|
470
|
-
}
|
|
471
|
-
}));
|
|
472
|
-
return opacity;
|
|
473
|
-
};
|
|
474
497
|
var ProgressIndicator = (props) => {
|
|
475
|
-
const opacity = useFadeInOut(
|
|
498
|
+
const opacity = useFadeInOut({
|
|
499
|
+
visible: props.visible
|
|
500
|
+
});
|
|
476
501
|
let progressIndicatorRef;
|
|
477
502
|
const computedPosition = () => {
|
|
478
503
|
const boundingRect = progressIndicatorRef?.getBoundingClientRect();
|
|
@@ -517,12 +542,11 @@ var Crosshair = (props) => {
|
|
|
517
542
|
let width = 0;
|
|
518
543
|
let height = 0;
|
|
519
544
|
let dpr = 1;
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
let hasBeenRenderedOnce = false;
|
|
545
|
+
const position = useAnimatedPosition({
|
|
546
|
+
x: () => props.mouseX,
|
|
547
|
+
y: () => props.mouseY,
|
|
548
|
+
lerpFactor: 0.3
|
|
549
|
+
});
|
|
526
550
|
const setupCanvas = () => {
|
|
527
551
|
if (!canvasRef) return;
|
|
528
552
|
dpr = Math.max(window.devicePixelRatio || 1, 2);
|
|
@@ -543,39 +567,12 @@ var Crosshair = (props) => {
|
|
|
543
567
|
context.strokeStyle = "rgba(210, 57, 192)";
|
|
544
568
|
context.lineWidth = 1;
|
|
545
569
|
context.beginPath();
|
|
546
|
-
context.moveTo(
|
|
547
|
-
context.lineTo(
|
|
548
|
-
context.moveTo(0,
|
|
549
|
-
context.lineTo(width,
|
|
570
|
+
context.moveTo(position.x(), 0);
|
|
571
|
+
context.lineTo(position.x(), height);
|
|
572
|
+
context.moveTo(0, position.y());
|
|
573
|
+
context.lineTo(width, position.y());
|
|
550
574
|
context.stroke();
|
|
551
575
|
};
|
|
552
|
-
const animate = () => {
|
|
553
|
-
currentX = lerp(currentX, targetX, 0.3);
|
|
554
|
-
currentY = lerp(currentY, targetY, 0.3);
|
|
555
|
-
render2();
|
|
556
|
-
const hasConvergedToTarget = Math.abs(currentX - targetX) < 0.5 && Math.abs(currentY - targetY) < 0.5;
|
|
557
|
-
if (!hasConvergedToTarget) {
|
|
558
|
-
animationFrameId = requestAnimationFrame(animate);
|
|
559
|
-
} else {
|
|
560
|
-
animationFrameId = null;
|
|
561
|
-
}
|
|
562
|
-
};
|
|
563
|
-
const startAnimation = () => {
|
|
564
|
-
if (animationFrameId !== null) return;
|
|
565
|
-
animationFrameId = requestAnimationFrame(animate);
|
|
566
|
-
};
|
|
567
|
-
const updateTarget = () => {
|
|
568
|
-
targetX = props.mouseX;
|
|
569
|
-
targetY = props.mouseY;
|
|
570
|
-
if (!hasBeenRenderedOnce) {
|
|
571
|
-
currentX = targetX;
|
|
572
|
-
currentY = targetY;
|
|
573
|
-
hasBeenRenderedOnce = true;
|
|
574
|
-
render2();
|
|
575
|
-
return;
|
|
576
|
-
}
|
|
577
|
-
startAnimation();
|
|
578
|
-
};
|
|
579
576
|
createEffect(() => {
|
|
580
577
|
setupCanvas();
|
|
581
578
|
render2();
|
|
@@ -586,14 +583,12 @@ var Crosshair = (props) => {
|
|
|
586
583
|
window.addEventListener("resize", handleResize);
|
|
587
584
|
onCleanup(() => {
|
|
588
585
|
window.removeEventListener("resize", handleResize);
|
|
589
|
-
if (animationFrameId !== null) {
|
|
590
|
-
cancelAnimationFrame(animationFrameId);
|
|
591
|
-
animationFrameId = null;
|
|
592
|
-
}
|
|
593
586
|
});
|
|
594
587
|
});
|
|
595
588
|
createEffect(() => {
|
|
596
|
-
|
|
589
|
+
position.x();
|
|
590
|
+
position.y();
|
|
591
|
+
render2();
|
|
597
592
|
});
|
|
598
593
|
return createComponent(Show, {
|
|
599
594
|
get when() {
|
|
@@ -737,27 +732,62 @@ var ReactGrabRenderer = (props) => {
|
|
|
737
732
|
var isCapitalized = (value) => value.length > 0 && /^[A-Z]/.test(value);
|
|
738
733
|
|
|
739
734
|
// src/instrumentation.ts
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
735
|
+
var NEXT_INTERNAL_COMPONENT_NAMES = [
|
|
736
|
+
"InnerLayoutRouter",
|
|
737
|
+
"RedirectErrorBoundary",
|
|
738
|
+
"RedirectBoundary",
|
|
739
|
+
"HTTPAccessFallbackErrorBoundary",
|
|
740
|
+
"HTTPAccessFallbackBoundary",
|
|
741
|
+
"LoadingBoundary",
|
|
742
|
+
"ErrorBoundary",
|
|
743
|
+
"InnerScrollAndFocusHandler",
|
|
744
|
+
"ScrollAndFocusHandler",
|
|
745
|
+
"RenderFromTemplateContext",
|
|
746
|
+
"OuterLayoutRouter",
|
|
747
|
+
"body",
|
|
748
|
+
"html",
|
|
749
|
+
"RedirectErrorBoundary",
|
|
750
|
+
"RedirectBoundary",
|
|
751
|
+
"HTTPAccessFallbackErrorBoundary",
|
|
752
|
+
"HTTPAccessFallbackBoundary",
|
|
753
|
+
"DevRootHTTPAccessFallbackBoundary",
|
|
754
|
+
"AppDevOverlayErrorBoundary",
|
|
755
|
+
"AppDevOverlay",
|
|
756
|
+
"HotReload",
|
|
757
|
+
"Router",
|
|
758
|
+
"ErrorBoundaryHandler",
|
|
759
|
+
"ErrorBoundary",
|
|
760
|
+
"AppRouter",
|
|
761
|
+
"ServerRoot",
|
|
762
|
+
"SegmentStateProvider",
|
|
763
|
+
"RootErrorBoundary"
|
|
764
|
+
];
|
|
765
|
+
var checkIsNextProject = () => {
|
|
766
|
+
return Boolean(document.getElementById("__NEXT_DATA__"));
|
|
767
|
+
};
|
|
768
|
+
var checkIsInternalComponentName = (name) => {
|
|
769
|
+
if (name.startsWith("_")) return true;
|
|
770
|
+
if (NEXT_INTERNAL_COMPONENT_NAMES.includes(name)) return true;
|
|
771
|
+
return false;
|
|
772
|
+
};
|
|
773
|
+
var checkIsSourceComponentName = (name) => {
|
|
774
|
+
if (checkIsInternalComponentName(name)) return false;
|
|
775
|
+
if (!isCapitalized(name)) return false;
|
|
776
|
+
if (name.startsWith("Primitive.")) return false;
|
|
777
|
+
if (name.includes("Provider") && name.includes("Context")) return false;
|
|
778
|
+
return true;
|
|
747
779
|
};
|
|
748
|
-
var
|
|
749
|
-
var isInternalComponent = (name) => !isCapitalized(name) || name.startsWith("_") || name.includes("Provider") && name.includes("Context");
|
|
750
|
-
var getNearestComponentDisplayName = (element) => {
|
|
780
|
+
var getNearestComponentName = (element) => {
|
|
751
781
|
const fiber = getFiberFromHostInstance(element);
|
|
752
782
|
if (!fiber) return null;
|
|
753
|
-
let
|
|
783
|
+
let foundComponentName = null;
|
|
754
784
|
traverseFiber(
|
|
755
785
|
fiber,
|
|
756
786
|
(currentFiber) => {
|
|
757
787
|
if (isCompositeFiber(currentFiber)) {
|
|
758
788
|
const displayName = getDisplayName(currentFiber);
|
|
759
|
-
if (displayName &&
|
|
760
|
-
|
|
789
|
+
if (displayName && checkIsSourceComponentName(displayName)) {
|
|
790
|
+
foundComponentName = displayName;
|
|
761
791
|
return true;
|
|
762
792
|
}
|
|
763
793
|
}
|
|
@@ -765,213 +795,95 @@ var getNearestComponentDisplayName = (element) => {
|
|
|
765
795
|
},
|
|
766
796
|
true
|
|
767
797
|
);
|
|
768
|
-
return
|
|
798
|
+
return foundComponentName;
|
|
769
799
|
};
|
|
770
|
-
var
|
|
771
|
-
const
|
|
772
|
-
if (!
|
|
773
|
-
const
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
};
|
|
785
|
-
var getHTMLSnippet = async (element) => {
|
|
786
|
-
const semanticTags = /* @__PURE__ */ new Set([
|
|
787
|
-
"article",
|
|
788
|
-
"aside",
|
|
789
|
-
"footer",
|
|
790
|
-
"form",
|
|
791
|
-
"header",
|
|
792
|
-
"main",
|
|
793
|
-
"nav",
|
|
794
|
-
"section"
|
|
795
|
-
]);
|
|
796
|
-
const hasDistinguishingFeatures = (el) => {
|
|
797
|
-
const tagName = el.tagName.toLowerCase();
|
|
798
|
-
if (semanticTags.has(tagName)) return true;
|
|
799
|
-
if (el.id) return true;
|
|
800
|
-
if (el.className && typeof el.className === "string") {
|
|
801
|
-
const classes = el.className.trim();
|
|
802
|
-
if (classes && classes.length > 0) return true;
|
|
803
|
-
}
|
|
804
|
-
return Array.from(el.attributes).some(
|
|
805
|
-
(attr) => attr.name.startsWith("data-")
|
|
806
|
-
);
|
|
807
|
-
};
|
|
808
|
-
const collectDistinguishingAncestors = (el, maxDepth = 10) => {
|
|
809
|
-
const ancestors2 = [];
|
|
810
|
-
let current = el.parentElement;
|
|
811
|
-
let depth = 0;
|
|
812
|
-
while (current && depth < maxDepth && current.tagName !== "BODY") {
|
|
813
|
-
if (hasDistinguishingFeatures(current)) {
|
|
814
|
-
ancestors2.push(current);
|
|
815
|
-
if (ancestors2.length >= 3) break;
|
|
816
|
-
}
|
|
817
|
-
current = current.parentElement;
|
|
818
|
-
depth++;
|
|
819
|
-
}
|
|
820
|
-
return ancestors2.reverse();
|
|
821
|
-
};
|
|
822
|
-
const formatElementOpeningTag = (el, compact = false) => {
|
|
823
|
-
const tagName = el.tagName.toLowerCase();
|
|
824
|
-
const attrs = [];
|
|
825
|
-
if (el.id) {
|
|
826
|
-
attrs.push(`id="${el.id}"`);
|
|
827
|
-
}
|
|
828
|
-
if (el.className && typeof el.className === "string") {
|
|
829
|
-
const classes = el.className.trim().split(/\s+/);
|
|
830
|
-
if (classes.length > 0 && classes[0]) {
|
|
831
|
-
const displayClasses = compact ? classes.slice(0, 3) : classes;
|
|
832
|
-
const classStr = truncateString(displayClasses.join(" "), 30);
|
|
833
|
-
attrs.push(`class="${classStr}"`);
|
|
834
|
-
}
|
|
835
|
-
}
|
|
836
|
-
const dataAttrs = Array.from(el.attributes).filter(
|
|
837
|
-
(attr) => attr.name.startsWith("data-")
|
|
838
|
-
);
|
|
839
|
-
const displayDataAttrs = compact ? dataAttrs.slice(0, 1) : dataAttrs;
|
|
840
|
-
for (const attr of displayDataAttrs) {
|
|
841
|
-
attrs.push(`${attr.name}="${truncateString(attr.value, 20)}"`);
|
|
842
|
-
}
|
|
843
|
-
const ariaLabel = el.getAttribute("aria-label");
|
|
844
|
-
if (ariaLabel && !compact) {
|
|
845
|
-
attrs.push(`aria-label="${truncateString(ariaLabel, 20)}"`);
|
|
846
|
-
}
|
|
847
|
-
return attrs.length > 0 ? `<${tagName} ${attrs.join(" ")}>` : `<${tagName}>`;
|
|
848
|
-
};
|
|
849
|
-
const formatElementClosingTag = (el) => `</${el.tagName.toLowerCase()}>`;
|
|
850
|
-
const extractTruncatedTextContent = (el) => {
|
|
851
|
-
const text = (el.textContent || "").trim().replace(/\s+/g, " ");
|
|
852
|
-
return truncateString(text, 60);
|
|
853
|
-
};
|
|
854
|
-
const extractSiblingIdentifier = (el) => {
|
|
855
|
-
if (el.id) return `#${el.id}`;
|
|
856
|
-
if (el.className && typeof el.className === "string") {
|
|
857
|
-
const classes = el.className.trim().split(/\s+/);
|
|
858
|
-
if (classes.length > 0 && classes[0]) {
|
|
859
|
-
return `.${classes[0]}`;
|
|
800
|
+
var getStack = async (element) => {
|
|
801
|
+
const maybeFiber = getFiberFromHostInstance(element);
|
|
802
|
+
if (!maybeFiber || !isFiber(maybeFiber)) return [];
|
|
803
|
+
const fiber = getLatestFiber(maybeFiber);
|
|
804
|
+
const unresolvedStack = [];
|
|
805
|
+
traverseFiber(
|
|
806
|
+
fiber,
|
|
807
|
+
(currentFiber) => {
|
|
808
|
+
const displayName = isHostFiber(currentFiber) ? typeof currentFiber.type === "string" ? currentFiber.type : null : getDisplayName(currentFiber);
|
|
809
|
+
if (displayName && !checkIsInternalComponentName(displayName)) {
|
|
810
|
+
unresolvedStack.push({
|
|
811
|
+
name: displayName,
|
|
812
|
+
sourcePromise: getSource(currentFiber)
|
|
813
|
+
});
|
|
860
814
|
}
|
|
861
|
-
}
|
|
862
|
-
|
|
863
|
-
};
|
|
864
|
-
const lines = [];
|
|
865
|
-
const selector = generateCSSSelector(element);
|
|
866
|
-
lines.push(`- selector: ${selector}`);
|
|
867
|
-
const rect = element.getBoundingClientRect();
|
|
868
|
-
lines.push(`- width: ${Math.round(rect.width)}`);
|
|
869
|
-
lines.push(`- height: ${Math.round(rect.height)}`);
|
|
870
|
-
lines.push("HTML snippet:");
|
|
871
|
-
lines.push("```html");
|
|
872
|
-
const ancestors = collectDistinguishingAncestors(element);
|
|
873
|
-
const ancestorComponents = ancestors.map(
|
|
874
|
-
(ancestor) => getNearestComponentDisplayName(ancestor)
|
|
815
|
+
},
|
|
816
|
+
true
|
|
875
817
|
);
|
|
876
|
-
const
|
|
877
|
-
|
|
878
|
-
|
|
818
|
+
const resolvedStack = await Promise.all(
|
|
819
|
+
unresolvedStack.map(async (frame) => ({
|
|
820
|
+
name: frame.name,
|
|
821
|
+
source: await frame.sourcePromise
|
|
822
|
+
}))
|
|
879
823
|
);
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
if (
|
|
886
|
-
|
|
824
|
+
return resolvedStack.filter((frame) => frame.source !== null);
|
|
825
|
+
};
|
|
826
|
+
var formatStack = (stack) => {
|
|
827
|
+
const isNextProject = checkIsNextProject();
|
|
828
|
+
return stack.map(({ name, source }) => {
|
|
829
|
+
if (!source) return ` at ${name}`;
|
|
830
|
+
if (source.fileName.startsWith("about://React/Server")) {
|
|
831
|
+
return ` at ${name} (Server)`;
|
|
887
832
|
}
|
|
888
|
-
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
if (parent) {
|
|
893
|
-
const siblings = Array.from(parent.children);
|
|
894
|
-
targetIndex = siblings.indexOf(element);
|
|
895
|
-
if (targetIndex > 0) {
|
|
896
|
-
const indent2 = " ".repeat(ancestors.length);
|
|
897
|
-
if (targetIndex <= 2) {
|
|
898
|
-
for (let i = 0; i < targetIndex; i++) {
|
|
899
|
-
const sibling = siblings[i];
|
|
900
|
-
const siblingId = extractSiblingIdentifier(sibling);
|
|
901
|
-
if (siblingId) {
|
|
902
|
-
lines.push(`${indent2} ${formatElementOpeningTag(sibling, true)}`);
|
|
903
|
-
lines.push(`${indent2} </${sibling.tagName.toLowerCase()}>`);
|
|
904
|
-
}
|
|
905
|
-
}
|
|
906
|
-
} else {
|
|
907
|
-
lines.push(
|
|
908
|
-
`${indent2} ... (${targetIndex} element${targetIndex === 1 ? "" : "s"})`
|
|
909
|
-
);
|
|
910
|
-
}
|
|
833
|
+
if (!isSourceFile(source.fileName)) return ` at ${name}`;
|
|
834
|
+
const framePart = ` at ${name} in ${normalizeFileName(source.fileName)}`;
|
|
835
|
+
if (isNextProject) {
|
|
836
|
+
return `${framePart}:${source.lineNumber}:${source.columnNumber}`;
|
|
911
837
|
}
|
|
838
|
+
return framePart;
|
|
839
|
+
}).join("\n");
|
|
840
|
+
};
|
|
841
|
+
var getHTMLPreview = (element) => {
|
|
842
|
+
const tagName = element.tagName.toLowerCase();
|
|
843
|
+
if (!(element instanceof HTMLElement)) {
|
|
844
|
+
return `<${tagName} />`;
|
|
912
845
|
}
|
|
913
|
-
const
|
|
914
|
-
|
|
915
|
-
const
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
const childrenCount = element.children.length;
|
|
922
|
-
const elementIndent = `${indent}${showElementComponent ? " " : " "}`;
|
|
923
|
-
if (textContent && childrenCount === 0 && textContent.length < 40) {
|
|
924
|
-
lines.push(
|
|
925
|
-
`${elementIndent}${formatElementOpeningTag(element)}${textContent}${formatElementClosingTag(
|
|
926
|
-
element
|
|
927
|
-
)}`
|
|
928
|
-
);
|
|
929
|
-
} else {
|
|
930
|
-
lines.push(`${elementIndent}${formatElementOpeningTag(element)}`);
|
|
931
|
-
if (textContent) {
|
|
932
|
-
lines.push(`${elementIndent} ${textContent}`);
|
|
933
|
-
}
|
|
934
|
-
if (childrenCount > 0) {
|
|
935
|
-
lines.push(
|
|
936
|
-
`${elementIndent} ... (${childrenCount} element${childrenCount === 1 ? "" : "s"})`
|
|
937
|
-
);
|
|
846
|
+
const text = element.innerText?.trim() ?? element.textContent?.trim() ?? "";
|
|
847
|
+
let attrsText = "";
|
|
848
|
+
const attributes = Array.from(element.attributes);
|
|
849
|
+
for (const attribute of attributes) {
|
|
850
|
+
const name = attribute.name;
|
|
851
|
+
let value = attribute.value;
|
|
852
|
+
if (value.length > 20) {
|
|
853
|
+
value = `${value.slice(0, 20)}...`;
|
|
938
854
|
}
|
|
939
|
-
|
|
940
|
-
}
|
|
941
|
-
if (showElementComponent) {
|
|
942
|
-
lines.push(`${indent} </${elementComponent}>`);
|
|
855
|
+
attrsText += ` ${name}="${value}"`;
|
|
943
856
|
}
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
948
|
-
|
|
949
|
-
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
857
|
+
let topElements = 0;
|
|
858
|
+
let bottomElements = 0;
|
|
859
|
+
let foundFirstText = false;
|
|
860
|
+
const childNodes = Array.from(element.childNodes);
|
|
861
|
+
for (const node of childNodes) {
|
|
862
|
+
if (node.nodeType === Node.COMMENT_NODE) continue;
|
|
863
|
+
if (node.nodeType === Node.TEXT_NODE) {
|
|
864
|
+
if (node.textContent && node.textContent.trim().length > 0) {
|
|
865
|
+
foundFirstText = true;
|
|
866
|
+
}
|
|
867
|
+
} else if (node.nodeType === Node.ELEMENT_NODE) {
|
|
868
|
+
if (!foundFirstText) {
|
|
869
|
+
topElements++;
|
|
957
870
|
} else {
|
|
958
|
-
|
|
959
|
-
`${indent} ... (${siblingsAfter} element${siblingsAfter === 1 ? "" : "s"})`
|
|
960
|
-
);
|
|
871
|
+
bottomElements++;
|
|
961
872
|
}
|
|
962
873
|
}
|
|
963
874
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
875
|
+
let content = "";
|
|
876
|
+
if (topElements > 0) content += `
|
|
877
|
+
(${topElements} elements)`;
|
|
878
|
+
if (text.length > 0) content += `
|
|
879
|
+
${text}`;
|
|
880
|
+
if (bottomElements > 0) content += `
|
|
881
|
+
(${bottomElements} elements)`;
|
|
882
|
+
if (content.length > 0) {
|
|
883
|
+
return `<${tagName}${attrsText}>${content}
|
|
884
|
+
</${tagName}>`;
|
|
972
885
|
}
|
|
973
|
-
|
|
974
|
-
return lines.join("\n");
|
|
886
|
+
return `<${tagName}${attrsText} />`;
|
|
975
887
|
};
|
|
976
888
|
|
|
977
889
|
// src/utils/copy-content.ts
|
|
@@ -991,73 +903,13 @@ var waitForFocus = () => {
|
|
|
991
903
|
var copyContent = async (content, onSuccess) => {
|
|
992
904
|
await waitForFocus();
|
|
993
905
|
try {
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
for (const contentPart of content) {
|
|
997
|
-
if (typeof contentPart === "string") {
|
|
998
|
-
const result = copyContentFallback(contentPart, onSuccess);
|
|
999
|
-
if (!result) return result;
|
|
1000
|
-
}
|
|
1001
|
-
}
|
|
1002
|
-
onSuccess?.();
|
|
1003
|
-
return true;
|
|
1004
|
-
}
|
|
1005
|
-
const mimeTypeMap = /* @__PURE__ */ new Map();
|
|
1006
|
-
for (const contentPart of content) {
|
|
1007
|
-
if (contentPart instanceof Blob) {
|
|
1008
|
-
const mimeType = contentPart.type || "text/plain";
|
|
1009
|
-
if (!mimeTypeMap.has(mimeType)) {
|
|
1010
|
-
mimeTypeMap.set(mimeType, contentPart);
|
|
1011
|
-
}
|
|
1012
|
-
} else {
|
|
1013
|
-
if (!mimeTypeMap.has("text/plain")) {
|
|
1014
|
-
mimeTypeMap.set(
|
|
1015
|
-
"text/plain",
|
|
1016
|
-
new Blob([contentPart], { type: "text/plain" })
|
|
1017
|
-
);
|
|
1018
|
-
}
|
|
1019
|
-
}
|
|
1020
|
-
}
|
|
1021
|
-
if (mimeTypeMap.size === 0) {
|
|
1022
|
-
const plainTextFallback = content.find(
|
|
1023
|
-
(contentPart) => typeof contentPart === "string"
|
|
1024
|
-
);
|
|
1025
|
-
if (typeof plainTextFallback === "string") {
|
|
1026
|
-
return copyContentFallback(plainTextFallback, onSuccess);
|
|
1027
|
-
}
|
|
1028
|
-
return false;
|
|
1029
|
-
}
|
|
1030
|
-
try {
|
|
1031
|
-
await navigator.clipboard.write([
|
|
1032
|
-
new ClipboardItem(Object.fromEntries(mimeTypeMap))
|
|
1033
|
-
]);
|
|
1034
|
-
onSuccess?.();
|
|
1035
|
-
return true;
|
|
1036
|
-
} catch {
|
|
1037
|
-
const plainTextParts = content.filter(
|
|
1038
|
-
(contentPart) => typeof contentPart === "string"
|
|
1039
|
-
);
|
|
1040
|
-
if (plainTextParts.length > 0) {
|
|
1041
|
-
const combinedText = plainTextParts.join("\n\n");
|
|
1042
|
-
return copyContentFallback(combinedText, onSuccess);
|
|
1043
|
-
}
|
|
1044
|
-
return false;
|
|
1045
|
-
}
|
|
1046
|
-
} else if (content instanceof Blob) {
|
|
1047
|
-
await navigator.clipboard.write([
|
|
1048
|
-
new ClipboardItem({ [content.type]: content })
|
|
1049
|
-
]);
|
|
906
|
+
try {
|
|
907
|
+
await navigator.clipboard.writeText(content);
|
|
1050
908
|
onSuccess?.();
|
|
1051
909
|
return true;
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
onSuccess?.();
|
|
1056
|
-
return true;
|
|
1057
|
-
} catch {
|
|
1058
|
-
const result = copyContentFallback(content, onSuccess);
|
|
1059
|
-
return result;
|
|
1060
|
-
}
|
|
910
|
+
} catch {
|
|
911
|
+
const result = copyContentFallback(content, onSuccess);
|
|
912
|
+
return result;
|
|
1061
913
|
}
|
|
1062
914
|
} catch {
|
|
1063
915
|
return false;
|
|
@@ -1146,13 +998,27 @@ var getElementAtPosition = (clientX, clientY) => {
|
|
|
1146
998
|
|
|
1147
999
|
// src/utils/get-elements-in-drag.ts
|
|
1148
1000
|
var DRAG_COVERAGE_THRESHOLD = 0.75;
|
|
1001
|
+
var calculateIntersectionArea = (rect1, rect2) => {
|
|
1002
|
+
const intersectionLeft = Math.max(rect1.left, rect2.left);
|
|
1003
|
+
const intersectionTop = Math.max(rect1.top, rect2.top);
|
|
1004
|
+
const intersectionRight = Math.min(rect1.right, rect2.right);
|
|
1005
|
+
const intersectionBottom = Math.min(rect1.bottom, rect2.bottom);
|
|
1006
|
+
const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft);
|
|
1007
|
+
const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop);
|
|
1008
|
+
return intersectionWidth * intersectionHeight;
|
|
1009
|
+
};
|
|
1010
|
+
var hasIntersection = (rect1, rect2) => {
|
|
1011
|
+
return rect1.left < rect2.right && rect1.right > rect2.left && rect1.top < rect2.bottom && rect1.bottom > rect2.top;
|
|
1012
|
+
};
|
|
1149
1013
|
var filterElementsInDrag = (dragRect, isValidGrabbableElement2, shouldCheckCoverage) => {
|
|
1150
1014
|
const elements = [];
|
|
1151
1015
|
const allElements = Array.from(document.querySelectorAll("*"));
|
|
1152
|
-
const
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1016
|
+
const dragBounds = {
|
|
1017
|
+
left: dragRect.x,
|
|
1018
|
+
top: dragRect.y,
|
|
1019
|
+
right: dragRect.x + dragRect.width,
|
|
1020
|
+
bottom: dragRect.y + dragRect.height
|
|
1021
|
+
};
|
|
1156
1022
|
for (const candidateElement of allElements) {
|
|
1157
1023
|
if (!shouldCheckCoverage) {
|
|
1158
1024
|
const tagName = (candidateElement.tagName || "").toUpperCase();
|
|
@@ -1162,26 +1028,21 @@ var filterElementsInDrag = (dragRect, isValidGrabbableElement2, shouldCheckCover
|
|
|
1162
1028
|
continue;
|
|
1163
1029
|
}
|
|
1164
1030
|
const elementRect = candidateElement.getBoundingClientRect();
|
|
1165
|
-
const
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1031
|
+
const elementBounds = {
|
|
1032
|
+
left: elementRect.left,
|
|
1033
|
+
top: elementRect.top,
|
|
1034
|
+
right: elementRect.left + elementRect.width,
|
|
1035
|
+
bottom: elementRect.top + elementRect.height
|
|
1036
|
+
};
|
|
1169
1037
|
if (shouldCheckCoverage) {
|
|
1170
|
-
const
|
|
1171
|
-
const intersectionTop = Math.max(dragTop, elementTop);
|
|
1172
|
-
const intersectionRight = Math.min(dragRight, elementRight);
|
|
1173
|
-
const intersectionBottom = Math.min(dragBottom, elementBottom);
|
|
1174
|
-
const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft);
|
|
1175
|
-
const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop);
|
|
1176
|
-
const intersectionArea = intersectionWidth * intersectionHeight;
|
|
1038
|
+
const intersectionArea = calculateIntersectionArea(dragBounds, elementBounds);
|
|
1177
1039
|
const elementArea = Math.max(0, elementRect.width * elementRect.height);
|
|
1178
1040
|
const hasMajorityCoverage = elementArea > 0 && intersectionArea / elementArea >= DRAG_COVERAGE_THRESHOLD;
|
|
1179
1041
|
if (hasMajorityCoverage) {
|
|
1180
1042
|
elements.push(candidateElement);
|
|
1181
1043
|
}
|
|
1182
1044
|
} else {
|
|
1183
|
-
|
|
1184
|
-
if (hasIntersection) {
|
|
1045
|
+
if (hasIntersection(elementBounds, dragBounds)) {
|
|
1185
1046
|
elements.push(candidateElement);
|
|
1186
1047
|
}
|
|
1187
1048
|
}
|
|
@@ -1220,14 +1081,7 @@ var createElementBounds = (element) => {
|
|
|
1220
1081
|
};
|
|
1221
1082
|
};
|
|
1222
1083
|
|
|
1223
|
-
// src/utils/is-localhost.ts
|
|
1224
|
-
var isLocalhost = () => {
|
|
1225
|
-
const hostname = window.location.hostname;
|
|
1226
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
1227
|
-
};
|
|
1228
|
-
|
|
1229
1084
|
// src/core.tsx
|
|
1230
|
-
var PROGRESS_INDICATOR_DELAY_MS = 150;
|
|
1231
1085
|
var init = (rawOptions) => {
|
|
1232
1086
|
const options = {
|
|
1233
1087
|
enabled: true,
|
|
@@ -1250,7 +1104,6 @@ var init = (rawOptions) => {
|
|
|
1250
1104
|
};
|
|
1251
1105
|
}
|
|
1252
1106
|
return createRoot((dispose) => {
|
|
1253
|
-
const OFFSCREEN_POSITION = -1e3;
|
|
1254
1107
|
const [isHoldingKeys, setIsHoldingKeys] = createSignal(false);
|
|
1255
1108
|
const [mouseX, setMouseX] = createSignal(OFFSCREEN_POSITION);
|
|
1256
1109
|
const [mouseY, setMouseY] = createSignal(OFFSCREEN_POSITION);
|
|
@@ -1260,10 +1113,11 @@ var init = (rawOptions) => {
|
|
|
1260
1113
|
const [isCopying, setIsCopying] = createSignal(false);
|
|
1261
1114
|
const [lastGrabbedElement, setLastGrabbedElement] = createSignal(null);
|
|
1262
1115
|
const [progressStartTime, setProgressStartTime] = createSignal(null);
|
|
1263
|
-
const [
|
|
1116
|
+
const [progress, setProgress] = createSignal(0);
|
|
1264
1117
|
const [grabbedBoxes, setGrabbedBoxes] = createSignal([]);
|
|
1265
1118
|
const [successLabels, setSuccessLabels] = createSignal([]);
|
|
1266
1119
|
const [isActivated, setIsActivated] = createSignal(false);
|
|
1120
|
+
const [isToggleMode, setIsToggleMode] = createSignal(false);
|
|
1267
1121
|
const [showProgressIndicator, setShowProgressIndicator] = createSignal(false);
|
|
1268
1122
|
const [didJustDrag, setDidJustDrag] = createSignal(false);
|
|
1269
1123
|
const [copyStartX, setCopyStartX] = createSignal(OFFSCREEN_POSITION);
|
|
@@ -1306,55 +1160,10 @@ var init = (rawOptions) => {
|
|
|
1306
1160
|
const wrapInSelectedElementTags = (context) => `<selected_element>
|
|
1307
1161
|
${context}
|
|
1308
1162
|
</selected_element>`;
|
|
1309
|
-
const extractRelevantComputedStyles = (element) => {
|
|
1310
|
-
const computed = window.getComputedStyle(element);
|
|
1311
|
-
const rect = element.getBoundingClientRect();
|
|
1312
|
-
return {
|
|
1313
|
-
width: `${Math.round(rect.width)}px`,
|
|
1314
|
-
height: `${Math.round(rect.height)}px`,
|
|
1315
|
-
paddingTop: computed.paddingTop,
|
|
1316
|
-
paddingRight: computed.paddingRight,
|
|
1317
|
-
paddingBottom: computed.paddingBottom,
|
|
1318
|
-
paddingLeft: computed.paddingLeft,
|
|
1319
|
-
background: computed.background,
|
|
1320
|
-
opacity: computed.opacity
|
|
1321
|
-
};
|
|
1322
|
-
};
|
|
1323
|
-
const createStructuredClipboardHtmlBlob = (elements) => {
|
|
1324
|
-
const structuredData = {
|
|
1325
|
-
elements: elements.map((element) => ({
|
|
1326
|
-
tagName: element.tagName,
|
|
1327
|
-
content: element.content,
|
|
1328
|
-
computedStyles: element.computedStyles
|
|
1329
|
-
}))
|
|
1330
|
-
};
|
|
1331
|
-
const jsonString = JSON.stringify(structuredData);
|
|
1332
|
-
const base64Data = btoa(encodeURIComponent(jsonString).replace(/%([0-9A-F]{2})/g, (_match, p1) => String.fromCharCode(parseInt(p1, 16))));
|
|
1333
|
-
const htmlContent = `<div data-react-grab="${base64Data}"></div>`;
|
|
1334
|
-
return new Blob([htmlContent], {
|
|
1335
|
-
type: "text/html"
|
|
1336
|
-
});
|
|
1337
|
-
};
|
|
1338
1163
|
const extractElementTagName = (element) => (element.tagName || "").toLowerCase();
|
|
1339
|
-
const extractNearestComponentName = (element) => {
|
|
1340
|
-
const fiber = getFiberFromHostInstance(element);
|
|
1341
|
-
if (!fiber) return null;
|
|
1342
|
-
let componentName = null;
|
|
1343
|
-
traverseFiber(fiber, (currentFiber) => {
|
|
1344
|
-
if (isCompositeFiber(currentFiber)) {
|
|
1345
|
-
const displayName = getDisplayName(currentFiber);
|
|
1346
|
-
if (displayName && isCapitalized(displayName) && !displayName.startsWith("_")) {
|
|
1347
|
-
componentName = displayName;
|
|
1348
|
-
return true;
|
|
1349
|
-
}
|
|
1350
|
-
}
|
|
1351
|
-
return false;
|
|
1352
|
-
}, true);
|
|
1353
|
-
return componentName;
|
|
1354
|
-
};
|
|
1355
1164
|
const extractElementLabelText = (element) => {
|
|
1356
1165
|
const tagName = extractElementTagName(element);
|
|
1357
|
-
const componentName =
|
|
1166
|
+
const componentName = getNearestComponentName(element);
|
|
1358
1167
|
if (tagName && componentName) {
|
|
1359
1168
|
return `<${tagName}> in ${componentName}`;
|
|
1360
1169
|
}
|
|
@@ -1376,8 +1185,6 @@ ${context}
|
|
|
1376
1185
|
} catch {
|
|
1377
1186
|
}
|
|
1378
1187
|
};
|
|
1379
|
-
const isExtensionEnvironment = () => window.__REACT_GRAB_EXTENSION_ACTIVE__ === true || options.isExtension === true;
|
|
1380
|
-
const isExtensionTextOnlyMode = () => isExtensionEnvironment() && !isLocalhost();
|
|
1381
1188
|
const executeCopyOperation = async (positionX, positionY, operation) => {
|
|
1382
1189
|
setCopyStartX(positionX);
|
|
1383
1190
|
setCopyStartY(positionY);
|
|
@@ -1386,6 +1193,13 @@ ${context}
|
|
|
1386
1193
|
await operation().finally(() => {
|
|
1387
1194
|
setIsCopying(false);
|
|
1388
1195
|
stopProgressAnimation();
|
|
1196
|
+
if (isToggleMode()) {
|
|
1197
|
+
if (!isHoldingKeys()) {
|
|
1198
|
+
deactivateRenderer();
|
|
1199
|
+
} else {
|
|
1200
|
+
setIsToggleMode(false);
|
|
1201
|
+
}
|
|
1202
|
+
}
|
|
1389
1203
|
});
|
|
1390
1204
|
};
|
|
1391
1205
|
const hasInnerText = (element) => "innerText" in element;
|
|
@@ -1396,38 +1210,37 @@ ${context}
|
|
|
1396
1210
|
return element.textContent ?? "";
|
|
1397
1211
|
};
|
|
1398
1212
|
const createCombinedTextContent = (elements) => elements.map((element) => extractElementTextContent(element).trim()).filter((textContent) => textContent.length > 0).join("\n\n");
|
|
1399
|
-
const
|
|
1400
|
-
showTemporaryGrabbedBox(createElementBounds(targetElement2));
|
|
1401
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1213
|
+
const tryCopyWithFallback = async (elements) => {
|
|
1402
1214
|
let didCopy = false;
|
|
1403
1215
|
try {
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1410
|
-
|
|
1411
|
-
const plainTextContent = wrapInSelectedElementTags(
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
if (!didCopy) {
|
|
1419
|
-
const plainTextContentOnly = createCombinedTextContent([targetElement2]);
|
|
1420
|
-
if (plainTextContentOnly.length > 0) {
|
|
1421
|
-
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1422
|
-
}
|
|
1216
|
+
const elementSnippetResults = await Promise.allSettled(elements.map(async (element) => `## HTML Frame:
|
|
1217
|
+
${getHTMLPreview(element)}
|
|
1218
|
+
|
|
1219
|
+
## Code Location:
|
|
1220
|
+
${formatStack(await getStack(element))}`));
|
|
1221
|
+
const elementSnippets = elementSnippetResults.map((result) => result.status === "fulfilled" ? result.value : "").filter((snippet) => snippet.trim());
|
|
1222
|
+
if (elementSnippets.length > 0) {
|
|
1223
|
+
const plainTextContent = elementSnippets.map((snippet) => wrapInSelectedElementTags(snippet)).join("\n\n");
|
|
1224
|
+
didCopy = await copyContent(plainTextContent, options.playCopySound ? playCopySound : void 0);
|
|
1225
|
+
}
|
|
1226
|
+
if (!didCopy) {
|
|
1227
|
+
const plainTextContentOnly = createCombinedTextContent(elements);
|
|
1228
|
+
if (plainTextContentOnly.length > 0) {
|
|
1229
|
+
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1423
1230
|
}
|
|
1424
1231
|
}
|
|
1425
1232
|
} catch {
|
|
1426
|
-
const plainTextContentOnly = createCombinedTextContent(
|
|
1233
|
+
const plainTextContentOnly = createCombinedTextContent(elements);
|
|
1427
1234
|
if (plainTextContentOnly.length > 0) {
|
|
1428
1235
|
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1429
1236
|
}
|
|
1430
1237
|
}
|
|
1238
|
+
return didCopy;
|
|
1239
|
+
};
|
|
1240
|
+
const copySingleElementToClipboard = async (targetElement2) => {
|
|
1241
|
+
showTemporaryGrabbedBox(createElementBounds(targetElement2));
|
|
1242
|
+
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1243
|
+
const didCopy = await tryCopyWithFallback([targetElement2]);
|
|
1431
1244
|
if (didCopy) {
|
|
1432
1245
|
showTemporarySuccessLabel(extractElementLabelText(targetElement2));
|
|
1433
1246
|
}
|
|
@@ -1439,40 +1252,7 @@ ${context}
|
|
|
1439
1252
|
showTemporaryGrabbedBox(createElementBounds(element));
|
|
1440
1253
|
}
|
|
1441
1254
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1442
|
-
|
|
1443
|
-
try {
|
|
1444
|
-
if (isExtensionTextOnlyMode()) {
|
|
1445
|
-
const plainTextContent = createCombinedTextContent(targetElements);
|
|
1446
|
-
if (plainTextContent.length > 0) {
|
|
1447
|
-
didCopy = await copyContent(plainTextContent, options.playCopySound ? playCopySound : void 0);
|
|
1448
|
-
}
|
|
1449
|
-
} else {
|
|
1450
|
-
const elementSnippetResults = await Promise.allSettled(targetElements.map((element) => getHTMLSnippet(element)));
|
|
1451
|
-
const elementSnippets = elementSnippetResults.map((result) => result.status === "fulfilled" ? result.value : "").filter((snippet) => snippet.trim());
|
|
1452
|
-
if (elementSnippets.length > 0) {
|
|
1453
|
-
const plainTextContent = elementSnippets.map((snippet) => wrapInSelectedElementTags(snippet)).join("\n\n");
|
|
1454
|
-
const structuredElements = elementSnippets.map((content, elementIndex) => ({
|
|
1455
|
-
tagName: extractElementTagName(targetElements[elementIndex]),
|
|
1456
|
-
content,
|
|
1457
|
-
computedStyles: extractRelevantComputedStyles(targetElements[elementIndex])
|
|
1458
|
-
}));
|
|
1459
|
-
const htmlContent = createStructuredClipboardHtmlBlob(structuredElements);
|
|
1460
|
-
didCopy = await copyContent([plainTextContent, htmlContent], options.playCopySound ? playCopySound : void 0);
|
|
1461
|
-
if (!didCopy) {
|
|
1462
|
-
const plainTextContentOnly = createCombinedTextContent(targetElements);
|
|
1463
|
-
if (plainTextContentOnly.length > 0) {
|
|
1464
|
-
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1465
|
-
}
|
|
1466
|
-
}
|
|
1467
|
-
} else {
|
|
1468
|
-
const plainTextContentOnly = createCombinedTextContent(targetElements);
|
|
1469
|
-
if (plainTextContentOnly.length > 0) {
|
|
1470
|
-
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1471
|
-
}
|
|
1472
|
-
}
|
|
1473
|
-
}
|
|
1474
|
-
} catch {
|
|
1475
|
-
}
|
|
1255
|
+
const didCopy = await tryCopyWithFallback(targetElements);
|
|
1476
1256
|
if (didCopy) {
|
|
1477
1257
|
showTemporarySuccessLabel(`${targetElements.length} elements`);
|
|
1478
1258
|
}
|
|
@@ -1496,7 +1276,6 @@ ${context}
|
|
|
1496
1276
|
y: elementBounds.top
|
|
1497
1277
|
};
|
|
1498
1278
|
});
|
|
1499
|
-
const DRAG_THRESHOLD_PX = 2;
|
|
1500
1279
|
const calculateDragDistance = (endX, endY) => ({
|
|
1501
1280
|
x: Math.abs(endX - dragStartX()),
|
|
1502
1281
|
y: Math.abs(endY - dragStartY())
|
|
@@ -1554,30 +1333,23 @@ ${context}
|
|
|
1554
1333
|
setLastGrabbedElement(null);
|
|
1555
1334
|
}
|
|
1556
1335
|
}));
|
|
1557
|
-
const progress = createMemo(() => {
|
|
1558
|
-
const startTime = progressStartTime();
|
|
1559
|
-
progressTick();
|
|
1560
|
-
if (startTime === null) return 0;
|
|
1561
|
-
const elapsedTime = Date.now() - startTime;
|
|
1562
|
-
const normalizedTime = elapsedTime / options.keyHoldDuration;
|
|
1563
|
-
const easedProgress = 1 - Math.exp(-normalizedTime);
|
|
1564
|
-
const maxProgressBeforeCompletion = 0.95;
|
|
1565
|
-
if (isCopying()) {
|
|
1566
|
-
return Math.min(easedProgress, maxProgressBeforeCompletion);
|
|
1567
|
-
}
|
|
1568
|
-
return 1;
|
|
1569
|
-
});
|
|
1570
1336
|
const startProgressAnimation = () => {
|
|
1571
|
-
|
|
1337
|
+
const startTime = Date.now();
|
|
1338
|
+
setProgressStartTime(startTime);
|
|
1572
1339
|
setShowProgressIndicator(false);
|
|
1573
1340
|
progressDelayTimerId = window.setTimeout(() => {
|
|
1574
1341
|
setShowProgressIndicator(true);
|
|
1575
1342
|
progressDelayTimerId = null;
|
|
1576
1343
|
}, PROGRESS_INDICATOR_DELAY_MS);
|
|
1577
1344
|
const animateProgress = () => {
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
const
|
|
1345
|
+
const currentStartTime = progressStartTime();
|
|
1346
|
+
if (currentStartTime === null) return;
|
|
1347
|
+
const elapsedTime = Date.now() - currentStartTime;
|
|
1348
|
+
const normalizedTime = elapsedTime / options.keyHoldDuration;
|
|
1349
|
+
const easedProgress = 1 - Math.exp(-normalizedTime);
|
|
1350
|
+
const maxProgressBeforeCompletion = 0.95;
|
|
1351
|
+
const currentProgress = isCopying() ? Math.min(easedProgress, maxProgressBeforeCompletion) : 1;
|
|
1352
|
+
setProgress(currentProgress);
|
|
1581
1353
|
if (currentProgress < 1) {
|
|
1582
1354
|
progressAnimationId = requestAnimationFrame(animateProgress);
|
|
1583
1355
|
}
|
|
@@ -1594,6 +1366,7 @@ ${context}
|
|
|
1594
1366
|
progressDelayTimerId = null;
|
|
1595
1367
|
}
|
|
1596
1368
|
setProgressStartTime(null);
|
|
1369
|
+
setProgress(1);
|
|
1597
1370
|
setShowProgressIndicator(false);
|
|
1598
1371
|
};
|
|
1599
1372
|
const activateRenderer = () => {
|
|
@@ -1602,6 +1375,7 @@ ${context}
|
|
|
1602
1375
|
document.body.style.cursor = "crosshair";
|
|
1603
1376
|
};
|
|
1604
1377
|
const deactivateRenderer = () => {
|
|
1378
|
+
setIsToggleMode(false);
|
|
1605
1379
|
setIsHoldingKeys(false);
|
|
1606
1380
|
setIsActivated(false);
|
|
1607
1381
|
document.body.style.cursor = "";
|
|
@@ -1627,11 +1401,25 @@ ${context}
|
|
|
1627
1401
|
deactivateRenderer();
|
|
1628
1402
|
return;
|
|
1629
1403
|
}
|
|
1404
|
+
if (event.key === "Enter" && isHoldingKeys()) {
|
|
1405
|
+
setIsToggleMode(true);
|
|
1406
|
+
if (keydownSpamTimerId !== null) {
|
|
1407
|
+
window.clearTimeout(keydownSpamTimerId);
|
|
1408
|
+
keydownSpamTimerId = null;
|
|
1409
|
+
}
|
|
1410
|
+
if (!isActivated()) {
|
|
1411
|
+
if (holdTimerId) window.clearTimeout(holdTimerId);
|
|
1412
|
+
activateRenderer();
|
|
1413
|
+
options.onActivate?.();
|
|
1414
|
+
}
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1630
1417
|
if (!options.allowActivationInsideInput && isKeyboardEventTriggeredByInput(event)) {
|
|
1631
1418
|
return;
|
|
1632
1419
|
}
|
|
1633
1420
|
if (!isTargetKeyCombination(event)) return;
|
|
1634
1421
|
if (isActivated()) {
|
|
1422
|
+
if (isToggleMode()) return;
|
|
1635
1423
|
if (keydownSpamTimerId !== null) {
|
|
1636
1424
|
window.clearTimeout(keydownSpamTimerId);
|
|
1637
1425
|
}
|
|
@@ -1652,13 +1440,15 @@ ${context}
|
|
|
1652
1440
|
options.onActivate?.();
|
|
1653
1441
|
}, options.keyHoldDuration);
|
|
1654
1442
|
}, {
|
|
1655
|
-
signal: eventListenerSignal
|
|
1443
|
+
signal: eventListenerSignal,
|
|
1444
|
+
capture: true
|
|
1656
1445
|
});
|
|
1657
1446
|
window.addEventListener("keyup", (event) => {
|
|
1658
1447
|
if (!isHoldingKeys() && !isActivated()) return;
|
|
1659
1448
|
const isReleasingModifier = !event.metaKey && !event.ctrlKey;
|
|
1660
1449
|
const isReleasingC = event.key.toLowerCase() === "c";
|
|
1661
1450
|
if (isReleasingC || isReleasingModifier) {
|
|
1451
|
+
if (isToggleMode()) return;
|
|
1662
1452
|
deactivateRenderer();
|
|
1663
1453
|
}
|
|
1664
1454
|
}, {
|
|
@@ -1740,9 +1530,17 @@ ${context}
|
|
|
1740
1530
|
if (isRendererActive() || isCopying() || didJustDrag()) {
|
|
1741
1531
|
event.preventDefault();
|
|
1742
1532
|
event.stopPropagation();
|
|
1743
|
-
|
|
1533
|
+
const hadDrag = didJustDrag();
|
|
1534
|
+
if (hadDrag) {
|
|
1744
1535
|
setDidJustDrag(false);
|
|
1745
1536
|
}
|
|
1537
|
+
if (isToggleMode() && !isCopying()) {
|
|
1538
|
+
if (!isHoldingKeys()) {
|
|
1539
|
+
deactivateRenderer();
|
|
1540
|
+
} else {
|
|
1541
|
+
setIsToggleMode(false);
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1746
1544
|
}
|
|
1747
1545
|
}, {
|
|
1748
1546
|
signal: eventListenerSignal,
|
|
@@ -1765,10 +1563,14 @@ ${context}
|
|
|
1765
1563
|
document.body.style.cursor = "";
|
|
1766
1564
|
});
|
|
1767
1565
|
const rendererRoot = mountRoot();
|
|
1768
|
-
const selectionVisible = createMemo(() =>
|
|
1566
|
+
const selectionVisible = createMemo(() => isRendererActive() && !isDragging() && Boolean(targetElement()));
|
|
1769
1567
|
const dragVisible = createMemo(() => isRendererActive() && isDraggingBeyondThreshold());
|
|
1770
1568
|
const labelVariant = createMemo(() => isCopying() ? "processing" : "hover");
|
|
1771
|
-
const labelVisible = createMemo(() =>
|
|
1569
|
+
const labelVisible = createMemo(() => {
|
|
1570
|
+
if (isCopying()) return true;
|
|
1571
|
+
if (successLabels().length > 0) return false;
|
|
1572
|
+
return isRendererActive() && !isDragging() && mouseHasSettled() && (Boolean(targetElement()) && !isSameAsLast() || !targetElement());
|
|
1573
|
+
});
|
|
1772
1574
|
const progressVisible = createMemo(() => isCopying() && showProgressIndicator() && hasValidMousePosition());
|
|
1773
1575
|
const crosshairVisible = createMemo(() => isRendererActive() && !isDragging());
|
|
1774
1576
|
render(() => createComponent(ReactGrabRenderer, {
|
|
@@ -1805,6 +1607,7 @@ ${context}
|
|
|
1805
1607
|
get labelVisible() {
|
|
1806
1608
|
return labelVisible();
|
|
1807
1609
|
},
|
|
1610
|
+
labelZIndex: Z_INDEX_LABEL,
|
|
1808
1611
|
get progressVisible() {
|
|
1809
1612
|
return progressVisible();
|
|
1810
1613
|
},
|
|
@@ -1850,9 +1653,6 @@ ${context}
|
|
|
1850
1653
|
// src/index.ts
|
|
1851
1654
|
var globalApi = null;
|
|
1852
1655
|
var getGlobalApi = () => globalApi;
|
|
1853
|
-
|
|
1854
|
-
if (!window[EXTENSION_MARKER]) {
|
|
1855
|
-
globalApi = init();
|
|
1856
|
-
}
|
|
1656
|
+
globalApi = init();
|
|
1857
1657
|
|
|
1858
1658
|
export { getGlobalApi, init, playCopySound };
|