react-grab 0.0.40 → 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 +305 -631
- package/dist/index.d.cts +1 -15
- package/dist/index.d.ts +1 -15
- package/dist/index.global.js +31 -87
- package/dist/index.js +307 -627
- package/package.json +3 -8
package/dist/index.js
CHANGED
|
@@ -1,9 +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';
|
|
6
|
-
import TurndownService from 'turndown';
|
|
3
|
+
import { getFiberFromHostInstance, traverseFiber, isCompositeFiber, getDisplayName, isFiber, getLatestFiber, isHostFiber } from 'bippy';
|
|
4
|
+
import { isSourceFile, normalizeFileName, getSource } from 'bippy/source';
|
|
7
5
|
|
|
8
6
|
/**
|
|
9
7
|
* @license MIT
|
|
@@ -95,8 +93,12 @@ var mountRoot = () => {
|
|
|
95
93
|
var VIEWPORT_MARGIN_PX = 8;
|
|
96
94
|
var INDICATOR_CLAMP_PADDING_PX = 4;
|
|
97
95
|
var CURSOR_OFFSET_PX = 14;
|
|
96
|
+
var OFFSCREEN_POSITION = -1e3;
|
|
98
97
|
var SELECTION_LERP_FACTOR = 0.95;
|
|
99
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;
|
|
100
102
|
|
|
101
103
|
// src/utils/lerp.ts
|
|
102
104
|
var lerp = (start, end, factor) => {
|
|
@@ -261,30 +263,22 @@ var getClampedElementPosition = (positionLeft, positionTop, elementWidth, elemen
|
|
|
261
263
|
const clampedTop = Math.max(minTop, Math.min(positionTop, maxTop));
|
|
262
264
|
return { left: clampedLeft, top: clampedTop };
|
|
263
265
|
};
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
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">`);
|
|
272
|
-
var Label = (props) => {
|
|
273
|
-
const [opacity, setOpacity] = createSignal(0);
|
|
274
|
-
const [positionTick, setPositionTick] = createSignal(0);
|
|
275
|
-
let labelRef;
|
|
276
|
-
let currentX = props.x;
|
|
277
|
-
let currentY = props.y;
|
|
278
|
-
let targetX = props.x;
|
|
279
|
-
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();
|
|
280
273
|
let animationFrameId = null;
|
|
281
274
|
let hasBeenRenderedOnce = false;
|
|
282
275
|
const animate = () => {
|
|
283
|
-
currentX = lerp(
|
|
284
|
-
currentY = lerp(
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
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) {
|
|
288
282
|
animationFrameId = requestAnimationFrame(animate);
|
|
289
283
|
} else {
|
|
290
284
|
animationFrameId = null;
|
|
@@ -294,36 +288,16 @@ var Label = (props) => {
|
|
|
294
288
|
if (animationFrameId !== null) return;
|
|
295
289
|
animationFrameId = requestAnimationFrame(animate);
|
|
296
290
|
};
|
|
297
|
-
|
|
298
|
-
targetX =
|
|
299
|
-
targetY =
|
|
291
|
+
createEffect(() => {
|
|
292
|
+
targetX = options.x();
|
|
293
|
+
targetY = options.y();
|
|
300
294
|
if (!hasBeenRenderedOnce) {
|
|
301
|
-
|
|
302
|
-
|
|
295
|
+
setX(targetX);
|
|
296
|
+
setY(targetY);
|
|
303
297
|
hasBeenRenderedOnce = true;
|
|
304
|
-
setPositionTick((tick) => tick + 1);
|
|
305
298
|
return;
|
|
306
299
|
}
|
|
307
300
|
startAnimation();
|
|
308
|
-
};
|
|
309
|
-
createEffect(on(() => props.visible, (visible) => {
|
|
310
|
-
if (visible !== false) {
|
|
311
|
-
requestAnimationFrame(() => {
|
|
312
|
-
setOpacity(1);
|
|
313
|
-
});
|
|
314
|
-
} else {
|
|
315
|
-
setOpacity(0);
|
|
316
|
-
return;
|
|
317
|
-
}
|
|
318
|
-
if (props.variant === "success") {
|
|
319
|
-
const fadeOutTimer = setTimeout(() => {
|
|
320
|
-
setOpacity(0);
|
|
321
|
-
}, SUCCESS_LABEL_DURATION_MS);
|
|
322
|
-
onCleanup(() => clearTimeout(fadeOutTimer));
|
|
323
|
-
}
|
|
324
|
-
}));
|
|
325
|
-
createEffect(() => {
|
|
326
|
-
updateTarget();
|
|
327
301
|
});
|
|
328
302
|
onCleanup(() => {
|
|
329
303
|
if (animationFrameId !== null) {
|
|
@@ -331,34 +305,89 @@ var Label = (props) => {
|
|
|
331
305
|
animationFrameId = null;
|
|
332
306
|
}
|
|
333
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
|
+
});
|
|
334
376
|
const labelBoundingRect = () => labelRef?.getBoundingClientRect();
|
|
335
377
|
const computedPosition = () => {
|
|
336
|
-
positionTick();
|
|
337
378
|
const boundingRect = labelBoundingRect();
|
|
338
379
|
if (!boundingRect) return {
|
|
339
|
-
left:
|
|
340
|
-
top:
|
|
380
|
+
left: position.x(),
|
|
381
|
+
top: position.y()
|
|
341
382
|
};
|
|
342
383
|
const viewportWidth = window.innerWidth;
|
|
343
384
|
const viewportHeight = window.innerHeight;
|
|
344
|
-
const quadrants =
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
left: Math.round(currentX) - boundingRect.width - CURSOR_OFFSET_PX,
|
|
349
|
-
top: Math.round(currentY) + CURSOR_OFFSET_PX
|
|
350
|
-
}, {
|
|
351
|
-
left: Math.round(currentX) + CURSOR_OFFSET_PX,
|
|
352
|
-
top: Math.round(currentY) - boundingRect.height - CURSOR_OFFSET_PX
|
|
353
|
-
}, {
|
|
354
|
-
left: Math.round(currentX) - boundingRect.width - CURSOR_OFFSET_PX,
|
|
355
|
-
top: Math.round(currentY) - boundingRect.height - CURSOR_OFFSET_PX
|
|
356
|
-
}];
|
|
357
|
-
for (const position of quadrants) {
|
|
358
|
-
const fitsHorizontally = position.left >= VIEWPORT_MARGIN_PX && position.left + boundingRect.width <= viewportWidth - VIEWPORT_MARGIN_PX;
|
|
359
|
-
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;
|
|
360
389
|
if (fitsHorizontally && fitsVertically) {
|
|
361
|
-
return
|
|
390
|
+
return position2;
|
|
362
391
|
}
|
|
363
392
|
}
|
|
364
393
|
const fallback = getClampedElementPosition(quadrants[0].left, quadrants[0].top, boundingRect.width, boundingRect.height);
|
|
@@ -465,21 +494,10 @@ var Label = (props) => {
|
|
|
465
494
|
});
|
|
466
495
|
};
|
|
467
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)">`);
|
|
468
|
-
var useFadeInOut = (visible) => {
|
|
469
|
-
const [opacity, setOpacity] = createSignal(0);
|
|
470
|
-
createEffect(on(() => visible, (isVisible) => {
|
|
471
|
-
if (isVisible !== false) {
|
|
472
|
-
requestAnimationFrame(() => {
|
|
473
|
-
setOpacity(1);
|
|
474
|
-
});
|
|
475
|
-
} else {
|
|
476
|
-
setOpacity(0);
|
|
477
|
-
}
|
|
478
|
-
}));
|
|
479
|
-
return opacity;
|
|
480
|
-
};
|
|
481
497
|
var ProgressIndicator = (props) => {
|
|
482
|
-
const opacity = useFadeInOut(
|
|
498
|
+
const opacity = useFadeInOut({
|
|
499
|
+
visible: props.visible
|
|
500
|
+
});
|
|
483
501
|
let progressIndicatorRef;
|
|
484
502
|
const computedPosition = () => {
|
|
485
503
|
const boundingRect = progressIndicatorRef?.getBoundingClientRect();
|
|
@@ -524,12 +542,11 @@ var Crosshair = (props) => {
|
|
|
524
542
|
let width = 0;
|
|
525
543
|
let height = 0;
|
|
526
544
|
let dpr = 1;
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
let hasBeenRenderedOnce = false;
|
|
545
|
+
const position = useAnimatedPosition({
|
|
546
|
+
x: () => props.mouseX,
|
|
547
|
+
y: () => props.mouseY,
|
|
548
|
+
lerpFactor: 0.3
|
|
549
|
+
});
|
|
533
550
|
const setupCanvas = () => {
|
|
534
551
|
if (!canvasRef) return;
|
|
535
552
|
dpr = Math.max(window.devicePixelRatio || 1, 2);
|
|
@@ -550,39 +567,12 @@ var Crosshair = (props) => {
|
|
|
550
567
|
context.strokeStyle = "rgba(210, 57, 192)";
|
|
551
568
|
context.lineWidth = 1;
|
|
552
569
|
context.beginPath();
|
|
553
|
-
context.moveTo(
|
|
554
|
-
context.lineTo(
|
|
555
|
-
context.moveTo(0,
|
|
556
|
-
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());
|
|
557
574
|
context.stroke();
|
|
558
575
|
};
|
|
559
|
-
const animate = () => {
|
|
560
|
-
currentX = lerp(currentX, targetX, 0.3);
|
|
561
|
-
currentY = lerp(currentY, targetY, 0.3);
|
|
562
|
-
render2();
|
|
563
|
-
const hasConvergedToTarget = Math.abs(currentX - targetX) < 0.5 && Math.abs(currentY - targetY) < 0.5;
|
|
564
|
-
if (!hasConvergedToTarget) {
|
|
565
|
-
animationFrameId = requestAnimationFrame(animate);
|
|
566
|
-
} else {
|
|
567
|
-
animationFrameId = null;
|
|
568
|
-
}
|
|
569
|
-
};
|
|
570
|
-
const startAnimation = () => {
|
|
571
|
-
if (animationFrameId !== null) return;
|
|
572
|
-
animationFrameId = requestAnimationFrame(animate);
|
|
573
|
-
};
|
|
574
|
-
const updateTarget = () => {
|
|
575
|
-
targetX = props.mouseX;
|
|
576
|
-
targetY = props.mouseY;
|
|
577
|
-
if (!hasBeenRenderedOnce) {
|
|
578
|
-
currentX = targetX;
|
|
579
|
-
currentY = targetY;
|
|
580
|
-
hasBeenRenderedOnce = true;
|
|
581
|
-
render2();
|
|
582
|
-
return;
|
|
583
|
-
}
|
|
584
|
-
startAnimation();
|
|
585
|
-
};
|
|
586
576
|
createEffect(() => {
|
|
587
577
|
setupCanvas();
|
|
588
578
|
render2();
|
|
@@ -593,14 +583,12 @@ var Crosshair = (props) => {
|
|
|
593
583
|
window.addEventListener("resize", handleResize);
|
|
594
584
|
onCleanup(() => {
|
|
595
585
|
window.removeEventListener("resize", handleResize);
|
|
596
|
-
if (animationFrameId !== null) {
|
|
597
|
-
cancelAnimationFrame(animationFrameId);
|
|
598
|
-
animationFrameId = null;
|
|
599
|
-
}
|
|
600
586
|
});
|
|
601
587
|
});
|
|
602
588
|
createEffect(() => {
|
|
603
|
-
|
|
589
|
+
position.x();
|
|
590
|
+
position.y();
|
|
591
|
+
render2();
|
|
604
592
|
});
|
|
605
593
|
return createComponent(Show, {
|
|
606
594
|
get when() {
|
|
@@ -744,27 +732,62 @@ var ReactGrabRenderer = (props) => {
|
|
|
744
732
|
var isCapitalized = (value) => value.length > 0 && /^[A-Z]/.test(value);
|
|
745
733
|
|
|
746
734
|
// src/instrumentation.ts
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
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;
|
|
754
779
|
};
|
|
755
|
-
var
|
|
756
|
-
var isInternalComponent = (name) => !isCapitalized(name) || name.startsWith("_") || name.startsWith("Primitive.") || name.includes("Provider") && name.includes("Context");
|
|
757
|
-
var getNearestComponentDisplayName = (element) => {
|
|
780
|
+
var getNearestComponentName = (element) => {
|
|
758
781
|
const fiber = getFiberFromHostInstance(element);
|
|
759
782
|
if (!fiber) return null;
|
|
760
|
-
let
|
|
783
|
+
let foundComponentName = null;
|
|
761
784
|
traverseFiber(
|
|
762
785
|
fiber,
|
|
763
786
|
(currentFiber) => {
|
|
764
787
|
if (isCompositeFiber(currentFiber)) {
|
|
765
788
|
const displayName = getDisplayName(currentFiber);
|
|
766
|
-
if (displayName &&
|
|
767
|
-
|
|
789
|
+
if (displayName && checkIsSourceComponentName(displayName)) {
|
|
790
|
+
foundComponentName = displayName;
|
|
768
791
|
return true;
|
|
769
792
|
}
|
|
770
793
|
}
|
|
@@ -772,231 +795,95 @@ var getNearestComponentDisplayName = (element) => {
|
|
|
772
795
|
},
|
|
773
796
|
true
|
|
774
797
|
);
|
|
775
|
-
return
|
|
776
|
-
};
|
|
777
|
-
var formatComponentSourceLocation = async (el) => {
|
|
778
|
-
const source = await getSourceFromHostInstance(el);
|
|
779
|
-
if (!source) return null;
|
|
780
|
-
const fileName = normalizeFileName(source.fileName);
|
|
781
|
-
if (isSourceFile(fileName)) {
|
|
782
|
-
return `${fileName}:${source.lineNumber}:${source.columnNumber}`;
|
|
783
|
-
}
|
|
784
|
-
if (fileName && (fileName.includes(".tsx") || fileName.includes(".ts") || fileName.includes(".jsx") || fileName.includes(".js"))) {
|
|
785
|
-
const cleanedFileName = fileName.replace(/^webpack:\/\/_N_E\//, "").replace(/^webpack:\/\/\//, "").replace(/^webpack:\/\//, "").replace(/^\.\//, "");
|
|
786
|
-
if (cleanedFileName && !cleanedFileName.startsWith("node_modules") && !cleanedFileName.includes(".next") && !cleanedFileName.startsWith("webpack")) {
|
|
787
|
-
return `${cleanedFileName}:${source.lineNumber}:${source.columnNumber}`;
|
|
788
|
-
}
|
|
789
|
-
}
|
|
790
|
-
return null;
|
|
798
|
+
return foundComponentName;
|
|
791
799
|
};
|
|
792
|
-
var
|
|
793
|
-
const
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
if (el.id) return true;
|
|
807
|
-
if (el.className && typeof el.className === "string") {
|
|
808
|
-
const classes = el.className.trim();
|
|
809
|
-
if (classes && classes.length > 0) return true;
|
|
810
|
-
}
|
|
811
|
-
return Array.from(el.attributes).some(
|
|
812
|
-
(attr) => attr.name.startsWith("data-")
|
|
813
|
-
);
|
|
814
|
-
};
|
|
815
|
-
const collectDistinguishingAncestors = (el, maxDepth = 10) => {
|
|
816
|
-
const ancestors2 = [];
|
|
817
|
-
let current = el.parentElement;
|
|
818
|
-
let depth = 0;
|
|
819
|
-
while (current && depth < maxDepth && current.tagName !== "BODY") {
|
|
820
|
-
if (hasDistinguishingFeatures(current)) {
|
|
821
|
-
ancestors2.push(current);
|
|
822
|
-
if (ancestors2.length >= 3) break;
|
|
823
|
-
}
|
|
824
|
-
current = current.parentElement;
|
|
825
|
-
depth++;
|
|
826
|
-
}
|
|
827
|
-
return ancestors2.reverse();
|
|
828
|
-
};
|
|
829
|
-
const formatElementOpeningTag = (el, compact = false) => {
|
|
830
|
-
const tagName = el.tagName.toLowerCase();
|
|
831
|
-
const attrs = [];
|
|
832
|
-
if (el.id) {
|
|
833
|
-
attrs.push(`id="${el.id}"`);
|
|
834
|
-
}
|
|
835
|
-
if (el.className && typeof el.className === "string") {
|
|
836
|
-
const classes = el.className.trim().split(/\s+/);
|
|
837
|
-
if (classes.length > 0 && classes[0]) {
|
|
838
|
-
const displayClasses = compact ? classes.slice(0, 3) : classes;
|
|
839
|
-
const classStr = truncateString(displayClasses.join(" "), 30);
|
|
840
|
-
attrs.push(`class="${classStr}"`);
|
|
841
|
-
}
|
|
842
|
-
}
|
|
843
|
-
const dataAttrs = Array.from(el.attributes).filter(
|
|
844
|
-
(attr) => attr.name.startsWith("data-")
|
|
845
|
-
);
|
|
846
|
-
const displayDataAttrs = compact ? dataAttrs.slice(0, 1) : dataAttrs;
|
|
847
|
-
for (const attr of displayDataAttrs) {
|
|
848
|
-
attrs.push(`${attr.name}="${truncateString(attr.value, 20)}"`);
|
|
849
|
-
}
|
|
850
|
-
const ariaLabel = el.getAttribute("aria-label");
|
|
851
|
-
if (ariaLabel && !compact) {
|
|
852
|
-
attrs.push(`aria-label="${truncateString(ariaLabel, 20)}"`);
|
|
853
|
-
}
|
|
854
|
-
return attrs.length > 0 ? `<${tagName} ${attrs.join(" ")}>` : `<${tagName}>`;
|
|
855
|
-
};
|
|
856
|
-
const formatElementClosingTag = (el) => `</${el.tagName.toLowerCase()}>`;
|
|
857
|
-
const extractTruncatedTextContent = (el) => {
|
|
858
|
-
const text = (el.textContent || "").trim().replace(/\s+/g, " ");
|
|
859
|
-
return truncateString(text, 60);
|
|
860
|
-
};
|
|
861
|
-
const extractSiblingIdentifier = (el) => {
|
|
862
|
-
if (el.id) return `#${el.id}`;
|
|
863
|
-
if (el.className && typeof el.className === "string") {
|
|
864
|
-
const classes = el.className.trim().split(/\s+/);
|
|
865
|
-
if (classes.length > 0 && classes[0]) {
|
|
866
|
-
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
|
+
});
|
|
867
814
|
}
|
|
868
|
-
}
|
|
869
|
-
|
|
870
|
-
};
|
|
871
|
-
const lines = [];
|
|
872
|
-
const selector = generateCSSSelector(element);
|
|
873
|
-
lines.push(`- selector: ${selector}`);
|
|
874
|
-
const rect = element.getBoundingClientRect();
|
|
875
|
-
lines.push(`- width: ${Math.round(rect.width)}`);
|
|
876
|
-
lines.push(`- height: ${Math.round(rect.height)}`);
|
|
877
|
-
lines.push("HTML snippet:");
|
|
878
|
-
lines.push("```html");
|
|
879
|
-
const ancestors = collectDistinguishingAncestors(element);
|
|
880
|
-
const ancestorComponents = ancestors.map(
|
|
881
|
-
(ancestor) => getNearestComponentDisplayName(ancestor)
|
|
815
|
+
},
|
|
816
|
+
true
|
|
882
817
|
);
|
|
883
|
-
const
|
|
884
|
-
|
|
885
|
-
|
|
818
|
+
const resolvedStack = await Promise.all(
|
|
819
|
+
unresolvedStack.map(async (frame) => ({
|
|
820
|
+
name: frame.name,
|
|
821
|
+
source: await frame.sourcePromise
|
|
822
|
+
}))
|
|
886
823
|
);
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
const isNewComponent = componentName && source && (i === 0 || ancestorComponents[i - 1] !== componentName);
|
|
896
|
-
if (isNewComponent) {
|
|
897
|
-
ancestorComponentIndents[i] = currentIndentLevel;
|
|
898
|
-
lines.push(
|
|
899
|
-
`${getIndent(currentIndentLevel)}<${componentName} used-at="${source}">`
|
|
900
|
-
);
|
|
901
|
-
currentIndentLevel++;
|
|
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)`;
|
|
902
832
|
}
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
currentIndentLevel++;
|
|
908
|
-
}
|
|
909
|
-
const parent = element.parentElement;
|
|
910
|
-
let targetIndex = -1;
|
|
911
|
-
if (parent) {
|
|
912
|
-
const siblings = Array.from(parent.children);
|
|
913
|
-
targetIndex = siblings.indexOf(element);
|
|
914
|
-
if (targetIndex > 0) {
|
|
915
|
-
const indent = getIndent(currentIndentLevel);
|
|
916
|
-
if (targetIndex <= 2) {
|
|
917
|
-
for (let i = 0; i < targetIndex; i++) {
|
|
918
|
-
const sibling = siblings[i];
|
|
919
|
-
const siblingId = extractSiblingIdentifier(sibling);
|
|
920
|
-
if (siblingId) {
|
|
921
|
-
lines.push(`${indent}${formatElementOpeningTag(sibling, true)}`);
|
|
922
|
-
lines.push(`${indent}</${sibling.tagName.toLowerCase()}>`);
|
|
923
|
-
}
|
|
924
|
-
}
|
|
925
|
-
} else {
|
|
926
|
-
lines.push(
|
|
927
|
-
`${indent}... (${targetIndex} element${targetIndex === 1 ? "" : "s"})`
|
|
928
|
-
);
|
|
929
|
-
}
|
|
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}`;
|
|
930
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} />`;
|
|
931
845
|
}
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
const
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
elementIndentLevel++;
|
|
941
|
-
}
|
|
942
|
-
const elementIndent = getIndent(elementIndentLevel);
|
|
943
|
-
lines.push(`${elementIndent}<!-- IMPORTANT: selected element -->`);
|
|
944
|
-
const textContent = extractTruncatedTextContent(element);
|
|
945
|
-
const childrenCount = element.children.length;
|
|
946
|
-
if (textContent && childrenCount === 0 && textContent.length < 40) {
|
|
947
|
-
lines.push(
|
|
948
|
-
`${elementIndent}${formatElementOpeningTag(element)}${textContent}${formatElementClosingTag(
|
|
949
|
-
element
|
|
950
|
-
)}`
|
|
951
|
-
);
|
|
952
|
-
} else {
|
|
953
|
-
lines.push(`${elementIndent}${formatElementOpeningTag(element)}`);
|
|
954
|
-
if (textContent) {
|
|
955
|
-
lines.push(`${elementIndent} ${textContent}`);
|
|
956
|
-
}
|
|
957
|
-
if (childrenCount > 0) {
|
|
958
|
-
lines.push(
|
|
959
|
-
`${elementIndent} ... (${childrenCount} element${childrenCount === 1 ? "" : "s"})`
|
|
960
|
-
);
|
|
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)}...`;
|
|
961
854
|
}
|
|
962
|
-
|
|
855
|
+
attrsText += ` ${name}="${value}"`;
|
|
963
856
|
}
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
const siblingId = extractSiblingIdentifier(sibling);
|
|
978
|
-
if (siblingId) {
|
|
979
|
-
lines.push(`${indent}${formatElementOpeningTag(sibling, true)}`);
|
|
980
|
-
lines.push(`${indent}</${sibling.tagName.toLowerCase()}>`);
|
|
981
|
-
}
|
|
982
|
-
}
|
|
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++;
|
|
983
870
|
} else {
|
|
984
|
-
|
|
985
|
-
`${indent}... (${siblingsAfter} element${siblingsAfter === 1 ? "" : "s"})`
|
|
986
|
-
);
|
|
871
|
+
bottomElements++;
|
|
987
872
|
}
|
|
988
873
|
}
|
|
989
874
|
}
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
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}>`;
|
|
997
885
|
}
|
|
998
|
-
|
|
999
|
-
return lines.join("\n");
|
|
886
|
+
return `<${tagName}${attrsText} />`;
|
|
1000
887
|
};
|
|
1001
888
|
|
|
1002
889
|
// src/utils/copy-content.ts
|
|
@@ -1016,73 +903,13 @@ var waitForFocus = () => {
|
|
|
1016
903
|
var copyContent = async (content, onSuccess) => {
|
|
1017
904
|
await waitForFocus();
|
|
1018
905
|
try {
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
for (const contentPart of content) {
|
|
1022
|
-
if (typeof contentPart === "string") {
|
|
1023
|
-
const result = copyContentFallback(contentPart, onSuccess);
|
|
1024
|
-
if (!result) return result;
|
|
1025
|
-
}
|
|
1026
|
-
}
|
|
1027
|
-
onSuccess?.();
|
|
1028
|
-
return true;
|
|
1029
|
-
}
|
|
1030
|
-
const mimeTypeMap = /* @__PURE__ */ new Map();
|
|
1031
|
-
for (const contentPart of content) {
|
|
1032
|
-
if (contentPart instanceof Blob) {
|
|
1033
|
-
const mimeType = contentPart.type || "text/plain";
|
|
1034
|
-
if (!mimeTypeMap.has(mimeType)) {
|
|
1035
|
-
mimeTypeMap.set(mimeType, contentPart);
|
|
1036
|
-
}
|
|
1037
|
-
} else {
|
|
1038
|
-
if (!mimeTypeMap.has("text/plain")) {
|
|
1039
|
-
mimeTypeMap.set(
|
|
1040
|
-
"text/plain",
|
|
1041
|
-
new Blob([contentPart], { type: "text/plain" })
|
|
1042
|
-
);
|
|
1043
|
-
}
|
|
1044
|
-
}
|
|
1045
|
-
}
|
|
1046
|
-
if (mimeTypeMap.size === 0) {
|
|
1047
|
-
const plainTextFallback = content.find(
|
|
1048
|
-
(contentPart) => typeof contentPart === "string"
|
|
1049
|
-
);
|
|
1050
|
-
if (typeof plainTextFallback === "string") {
|
|
1051
|
-
return copyContentFallback(plainTextFallback, onSuccess);
|
|
1052
|
-
}
|
|
1053
|
-
return false;
|
|
1054
|
-
}
|
|
1055
|
-
try {
|
|
1056
|
-
await navigator.clipboard.write([
|
|
1057
|
-
new ClipboardItem(Object.fromEntries(mimeTypeMap))
|
|
1058
|
-
]);
|
|
1059
|
-
onSuccess?.();
|
|
1060
|
-
return true;
|
|
1061
|
-
} catch {
|
|
1062
|
-
const plainTextParts = content.filter(
|
|
1063
|
-
(contentPart) => typeof contentPart === "string"
|
|
1064
|
-
);
|
|
1065
|
-
if (plainTextParts.length > 0) {
|
|
1066
|
-
const combinedText = plainTextParts.join("\n\n");
|
|
1067
|
-
return copyContentFallback(combinedText, onSuccess);
|
|
1068
|
-
}
|
|
1069
|
-
return false;
|
|
1070
|
-
}
|
|
1071
|
-
} else if (content instanceof Blob) {
|
|
1072
|
-
await navigator.clipboard.write([
|
|
1073
|
-
new ClipboardItem({ [content.type]: content })
|
|
1074
|
-
]);
|
|
906
|
+
try {
|
|
907
|
+
await navigator.clipboard.writeText(content);
|
|
1075
908
|
onSuccess?.();
|
|
1076
909
|
return true;
|
|
1077
|
-
}
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
onSuccess?.();
|
|
1081
|
-
return true;
|
|
1082
|
-
} catch {
|
|
1083
|
-
const result = copyContentFallback(content, onSuccess);
|
|
1084
|
-
return result;
|
|
1085
|
-
}
|
|
910
|
+
} catch {
|
|
911
|
+
const result = copyContentFallback(content, onSuccess);
|
|
912
|
+
return result;
|
|
1086
913
|
}
|
|
1087
914
|
} catch {
|
|
1088
915
|
return false;
|
|
@@ -1171,13 +998,27 @@ var getElementAtPosition = (clientX, clientY) => {
|
|
|
1171
998
|
|
|
1172
999
|
// src/utils/get-elements-in-drag.ts
|
|
1173
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
|
+
};
|
|
1174
1013
|
var filterElementsInDrag = (dragRect, isValidGrabbableElement2, shouldCheckCoverage) => {
|
|
1175
1014
|
const elements = [];
|
|
1176
1015
|
const allElements = Array.from(document.querySelectorAll("*"));
|
|
1177
|
-
const
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1016
|
+
const dragBounds = {
|
|
1017
|
+
left: dragRect.x,
|
|
1018
|
+
top: dragRect.y,
|
|
1019
|
+
right: dragRect.x + dragRect.width,
|
|
1020
|
+
bottom: dragRect.y + dragRect.height
|
|
1021
|
+
};
|
|
1181
1022
|
for (const candidateElement of allElements) {
|
|
1182
1023
|
if (!shouldCheckCoverage) {
|
|
1183
1024
|
const tagName = (candidateElement.tagName || "").toUpperCase();
|
|
@@ -1187,26 +1028,21 @@ var filterElementsInDrag = (dragRect, isValidGrabbableElement2, shouldCheckCover
|
|
|
1187
1028
|
continue;
|
|
1188
1029
|
}
|
|
1189
1030
|
const elementRect = candidateElement.getBoundingClientRect();
|
|
1190
|
-
const
|
|
1191
|
-
|
|
1192
|
-
|
|
1193
|
-
|
|
1031
|
+
const elementBounds = {
|
|
1032
|
+
left: elementRect.left,
|
|
1033
|
+
top: elementRect.top,
|
|
1034
|
+
right: elementRect.left + elementRect.width,
|
|
1035
|
+
bottom: elementRect.top + elementRect.height
|
|
1036
|
+
};
|
|
1194
1037
|
if (shouldCheckCoverage) {
|
|
1195
|
-
const
|
|
1196
|
-
const intersectionTop = Math.max(dragTop, elementTop);
|
|
1197
|
-
const intersectionRight = Math.min(dragRight, elementRight);
|
|
1198
|
-
const intersectionBottom = Math.min(dragBottom, elementBottom);
|
|
1199
|
-
const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft);
|
|
1200
|
-
const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop);
|
|
1201
|
-
const intersectionArea = intersectionWidth * intersectionHeight;
|
|
1038
|
+
const intersectionArea = calculateIntersectionArea(dragBounds, elementBounds);
|
|
1202
1039
|
const elementArea = Math.max(0, elementRect.width * elementRect.height);
|
|
1203
1040
|
const hasMajorityCoverage = elementArea > 0 && intersectionArea / elementArea >= DRAG_COVERAGE_THRESHOLD;
|
|
1204
1041
|
if (hasMajorityCoverage) {
|
|
1205
1042
|
elements.push(candidateElement);
|
|
1206
1043
|
}
|
|
1207
1044
|
} else {
|
|
1208
|
-
|
|
1209
|
-
if (hasIntersection) {
|
|
1045
|
+
if (hasIntersection(elementBounds, dragBounds)) {
|
|
1210
1046
|
elements.push(candidateElement);
|
|
1211
1047
|
}
|
|
1212
1048
|
}
|
|
@@ -1245,70 +1081,7 @@ var createElementBounds = (element) => {
|
|
|
1245
1081
|
};
|
|
1246
1082
|
};
|
|
1247
1083
|
|
|
1248
|
-
// src/utils/is-localhost.ts
|
|
1249
|
-
var isLocalhost = () => {
|
|
1250
|
-
const hostname = window.location.hostname;
|
|
1251
|
-
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
1252
|
-
};
|
|
1253
|
-
var turndownService = null;
|
|
1254
|
-
var getTurndownService = () => {
|
|
1255
|
-
if (!turndownService) {
|
|
1256
|
-
turndownService = new TurndownService({
|
|
1257
|
-
headingStyle: "atx",
|
|
1258
|
-
codeBlockStyle: "fenced",
|
|
1259
|
-
emDelimiter: "_",
|
|
1260
|
-
bulletListMarker: "-",
|
|
1261
|
-
linkStyle: "inlined",
|
|
1262
|
-
linkReferenceStyle: "full"
|
|
1263
|
-
});
|
|
1264
|
-
turndownService.addRule("strikethrough", {
|
|
1265
|
-
filter: ["del", "s"],
|
|
1266
|
-
replacement: (content) => `~~${content}~~`
|
|
1267
|
-
});
|
|
1268
|
-
turndownService.addRule("removeHidden", {
|
|
1269
|
-
filter: (node) => {
|
|
1270
|
-
if (node instanceof HTMLElement) {
|
|
1271
|
-
const style = window.getComputedStyle(node);
|
|
1272
|
-
return style.display === "none" || style.visibility === "hidden" || style.opacity === "0";
|
|
1273
|
-
}
|
|
1274
|
-
return false;
|
|
1275
|
-
},
|
|
1276
|
-
replacement: () => ""
|
|
1277
|
-
});
|
|
1278
|
-
turndownService.addRule("preserveButtons", {
|
|
1279
|
-
filter: ["button"],
|
|
1280
|
-
replacement: (content) => content ? `[${content}]` : ""
|
|
1281
|
-
});
|
|
1282
|
-
turndownService.addRule("preserveInputs", {
|
|
1283
|
-
filter: (node) => {
|
|
1284
|
-
if (node.nodeName === "INPUT" && node instanceof HTMLInputElement) {
|
|
1285
|
-
return true;
|
|
1286
|
-
}
|
|
1287
|
-
return false;
|
|
1288
|
-
},
|
|
1289
|
-
replacement: (_, node) => {
|
|
1290
|
-
if (node instanceof HTMLInputElement) {
|
|
1291
|
-
const value = node.value || node.placeholder;
|
|
1292
|
-
return value ? `[${value}]` : "";
|
|
1293
|
-
}
|
|
1294
|
-
return "";
|
|
1295
|
-
}
|
|
1296
|
-
});
|
|
1297
|
-
}
|
|
1298
|
-
return turndownService;
|
|
1299
|
-
};
|
|
1300
|
-
var htmlToMarkdown = (html) => {
|
|
1301
|
-
const service = getTurndownService();
|
|
1302
|
-
return service.turndown(html).trim();
|
|
1303
|
-
};
|
|
1304
|
-
var elementToMarkdown = (element) => {
|
|
1305
|
-
const clonedElement = element.cloneNode(true);
|
|
1306
|
-
const service = getTurndownService();
|
|
1307
|
-
return service.turndown(clonedElement).trim();
|
|
1308
|
-
};
|
|
1309
|
-
|
|
1310
1084
|
// src/core.tsx
|
|
1311
|
-
var PROGRESS_INDICATOR_DELAY_MS = 150;
|
|
1312
1085
|
var init = (rawOptions) => {
|
|
1313
1086
|
const options = {
|
|
1314
1087
|
enabled: true,
|
|
@@ -1331,7 +1104,6 @@ var init = (rawOptions) => {
|
|
|
1331
1104
|
};
|
|
1332
1105
|
}
|
|
1333
1106
|
return createRoot((dispose) => {
|
|
1334
|
-
const OFFSCREEN_POSITION = -1e3;
|
|
1335
1107
|
const [isHoldingKeys, setIsHoldingKeys] = createSignal(false);
|
|
1336
1108
|
const [mouseX, setMouseX] = createSignal(OFFSCREEN_POSITION);
|
|
1337
1109
|
const [mouseY, setMouseY] = createSignal(OFFSCREEN_POSITION);
|
|
@@ -1341,7 +1113,7 @@ var init = (rawOptions) => {
|
|
|
1341
1113
|
const [isCopying, setIsCopying] = createSignal(false);
|
|
1342
1114
|
const [lastGrabbedElement, setLastGrabbedElement] = createSignal(null);
|
|
1343
1115
|
const [progressStartTime, setProgressStartTime] = createSignal(null);
|
|
1344
|
-
const [
|
|
1116
|
+
const [progress, setProgress] = createSignal(0);
|
|
1345
1117
|
const [grabbedBoxes, setGrabbedBoxes] = createSignal([]);
|
|
1346
1118
|
const [successLabels, setSuccessLabels] = createSignal([]);
|
|
1347
1119
|
const [isActivated, setIsActivated] = createSignal(false);
|
|
@@ -1388,55 +1160,10 @@ var init = (rawOptions) => {
|
|
|
1388
1160
|
const wrapInSelectedElementTags = (context) => `<selected_element>
|
|
1389
1161
|
${context}
|
|
1390
1162
|
</selected_element>`;
|
|
1391
|
-
const extractRelevantComputedStyles = (element) => {
|
|
1392
|
-
const computed = window.getComputedStyle(element);
|
|
1393
|
-
const rect = element.getBoundingClientRect();
|
|
1394
|
-
return {
|
|
1395
|
-
width: `${Math.round(rect.width)}px`,
|
|
1396
|
-
height: `${Math.round(rect.height)}px`,
|
|
1397
|
-
paddingTop: computed.paddingTop,
|
|
1398
|
-
paddingRight: computed.paddingRight,
|
|
1399
|
-
paddingBottom: computed.paddingBottom,
|
|
1400
|
-
paddingLeft: computed.paddingLeft,
|
|
1401
|
-
background: computed.background,
|
|
1402
|
-
opacity: computed.opacity
|
|
1403
|
-
};
|
|
1404
|
-
};
|
|
1405
|
-
const createStructuredClipboardHtmlBlob = (elements) => {
|
|
1406
|
-
const structuredData = {
|
|
1407
|
-
elements: elements.map((element) => ({
|
|
1408
|
-
tagName: element.tagName,
|
|
1409
|
-
content: element.content,
|
|
1410
|
-
computedStyles: element.computedStyles
|
|
1411
|
-
}))
|
|
1412
|
-
};
|
|
1413
|
-
const jsonString = JSON.stringify(structuredData);
|
|
1414
|
-
const base64Data = btoa(encodeURIComponent(jsonString).replace(/%([0-9A-F]{2})/g, (_match, p1) => String.fromCharCode(parseInt(p1, 16))));
|
|
1415
|
-
const htmlContent = `<div data-react-grab="${base64Data}"></div>`;
|
|
1416
|
-
return new Blob([htmlContent], {
|
|
1417
|
-
type: "text/html"
|
|
1418
|
-
});
|
|
1419
|
-
};
|
|
1420
1163
|
const extractElementTagName = (element) => (element.tagName || "").toLowerCase();
|
|
1421
|
-
const extractNearestComponentName = (element) => {
|
|
1422
|
-
const fiber = getFiberFromHostInstance(element);
|
|
1423
|
-
if (!fiber) return null;
|
|
1424
|
-
let componentName = null;
|
|
1425
|
-
traverseFiber(fiber, (currentFiber) => {
|
|
1426
|
-
if (isCompositeFiber(currentFiber)) {
|
|
1427
|
-
const displayName = getDisplayName(currentFiber);
|
|
1428
|
-
if (displayName && isCapitalized(displayName) && !displayName.startsWith("_") && !displayName.startsWith("Primitive.")) {
|
|
1429
|
-
componentName = displayName;
|
|
1430
|
-
return true;
|
|
1431
|
-
}
|
|
1432
|
-
}
|
|
1433
|
-
return false;
|
|
1434
|
-
}, true);
|
|
1435
|
-
return componentName;
|
|
1436
|
-
};
|
|
1437
1164
|
const extractElementLabelText = (element) => {
|
|
1438
1165
|
const tagName = extractElementTagName(element);
|
|
1439
|
-
const componentName =
|
|
1166
|
+
const componentName = getNearestComponentName(element);
|
|
1440
1167
|
if (tagName && componentName) {
|
|
1441
1168
|
return `<${tagName}> in ${componentName}`;
|
|
1442
1169
|
}
|
|
@@ -1458,8 +1185,6 @@ ${context}
|
|
|
1458
1185
|
} catch {
|
|
1459
1186
|
}
|
|
1460
1187
|
};
|
|
1461
|
-
const isExtensionEnvironment = () => window.__REACT_GRAB_EXTENSION_ACTIVE__ === true || options.isExtension === true;
|
|
1462
|
-
const isExtensionTextOnlyMode = () => isExtensionEnvironment() && !isLocalhost();
|
|
1463
1188
|
const executeCopyOperation = async (positionX, positionY, operation) => {
|
|
1464
1189
|
setCopyStartX(positionX);
|
|
1465
1190
|
setCopyStartY(positionY);
|
|
@@ -1485,39 +1210,37 @@ ${context}
|
|
|
1485
1210
|
return element.textContent ?? "";
|
|
1486
1211
|
};
|
|
1487
1212
|
const createCombinedTextContent = (elements) => elements.map((element) => extractElementTextContent(element).trim()).filter((textContent) => textContent.length > 0).join("\n\n");
|
|
1488
|
-
const
|
|
1489
|
-
const copySingleElementToClipboard = async (targetElement2) => {
|
|
1490
|
-
showTemporaryGrabbedBox(createElementBounds(targetElement2));
|
|
1491
|
-
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1213
|
+
const tryCopyWithFallback = async (elements) => {
|
|
1492
1214
|
let didCopy = false;
|
|
1493
1215
|
try {
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
const plainTextContent = wrapInSelectedElementTags(
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1508
|
-
if (!didCopy) {
|
|
1509
|
-
const plainTextContentOnly = createCombinedTextContent([targetElement2]);
|
|
1510
|
-
if (plainTextContentOnly.length > 0) {
|
|
1511
|
-
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1512
|
-
}
|
|
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);
|
|
1513
1230
|
}
|
|
1514
1231
|
}
|
|
1515
1232
|
} catch {
|
|
1516
|
-
const plainTextContentOnly = createCombinedTextContent(
|
|
1233
|
+
const plainTextContentOnly = createCombinedTextContent(elements);
|
|
1517
1234
|
if (plainTextContentOnly.length > 0) {
|
|
1518
1235
|
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1519
1236
|
}
|
|
1520
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]);
|
|
1521
1244
|
if (didCopy) {
|
|
1522
1245
|
showTemporarySuccessLabel(extractElementLabelText(targetElement2));
|
|
1523
1246
|
}
|
|
@@ -1529,40 +1252,7 @@ ${context}
|
|
|
1529
1252
|
showTemporaryGrabbedBox(createElementBounds(element));
|
|
1530
1253
|
}
|
|
1531
1254
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1532
|
-
|
|
1533
|
-
try {
|
|
1534
|
-
if (isExtensionTextOnlyMode()) {
|
|
1535
|
-
const markdownContent = createCombinedMarkdownContent(targetElements);
|
|
1536
|
-
if (markdownContent.length > 0) {
|
|
1537
|
-
didCopy = await copyContent(markdownContent, options.playCopySound ? playCopySound : void 0);
|
|
1538
|
-
}
|
|
1539
|
-
} else {
|
|
1540
|
-
const elementSnippetResults = await Promise.allSettled(targetElements.map((element) => getHTMLSnippet(element)));
|
|
1541
|
-
const elementSnippets = elementSnippetResults.map((result) => result.status === "fulfilled" ? result.value : "").filter((snippet) => snippet.trim());
|
|
1542
|
-
if (elementSnippets.length > 0) {
|
|
1543
|
-
const plainTextContent = elementSnippets.map((snippet) => wrapInSelectedElementTags(snippet)).join("\n\n");
|
|
1544
|
-
const structuredElements = elementSnippets.map((content, elementIndex) => ({
|
|
1545
|
-
tagName: extractElementTagName(targetElements[elementIndex]),
|
|
1546
|
-
content,
|
|
1547
|
-
computedStyles: extractRelevantComputedStyles(targetElements[elementIndex])
|
|
1548
|
-
}));
|
|
1549
|
-
const htmlContent = createStructuredClipboardHtmlBlob(structuredElements);
|
|
1550
|
-
didCopy = await copyContent([plainTextContent, htmlContent], options.playCopySound ? playCopySound : void 0);
|
|
1551
|
-
if (!didCopy) {
|
|
1552
|
-
const plainTextContentOnly = createCombinedTextContent(targetElements);
|
|
1553
|
-
if (plainTextContentOnly.length > 0) {
|
|
1554
|
-
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1555
|
-
}
|
|
1556
|
-
}
|
|
1557
|
-
} else {
|
|
1558
|
-
const plainTextContentOnly = createCombinedTextContent(targetElements);
|
|
1559
|
-
if (plainTextContentOnly.length > 0) {
|
|
1560
|
-
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
} catch {
|
|
1565
|
-
}
|
|
1255
|
+
const didCopy = await tryCopyWithFallback(targetElements);
|
|
1566
1256
|
if (didCopy) {
|
|
1567
1257
|
showTemporarySuccessLabel(`${targetElements.length} elements`);
|
|
1568
1258
|
}
|
|
@@ -1586,7 +1276,6 @@ ${context}
|
|
|
1586
1276
|
y: elementBounds.top
|
|
1587
1277
|
};
|
|
1588
1278
|
});
|
|
1589
|
-
const DRAG_THRESHOLD_PX = 2;
|
|
1590
1279
|
const calculateDragDistance = (endX, endY) => ({
|
|
1591
1280
|
x: Math.abs(endX - dragStartX()),
|
|
1592
1281
|
y: Math.abs(endY - dragStartY())
|
|
@@ -1644,30 +1333,23 @@ ${context}
|
|
|
1644
1333
|
setLastGrabbedElement(null);
|
|
1645
1334
|
}
|
|
1646
1335
|
}));
|
|
1647
|
-
const progress = createMemo(() => {
|
|
1648
|
-
const startTime = progressStartTime();
|
|
1649
|
-
progressTick();
|
|
1650
|
-
if (startTime === null) return 0;
|
|
1651
|
-
const elapsedTime = Date.now() - startTime;
|
|
1652
|
-
const normalizedTime = elapsedTime / options.keyHoldDuration;
|
|
1653
|
-
const easedProgress = 1 - Math.exp(-normalizedTime);
|
|
1654
|
-
const maxProgressBeforeCompletion = 0.95;
|
|
1655
|
-
if (isCopying()) {
|
|
1656
|
-
return Math.min(easedProgress, maxProgressBeforeCompletion);
|
|
1657
|
-
}
|
|
1658
|
-
return 1;
|
|
1659
|
-
});
|
|
1660
1336
|
const startProgressAnimation = () => {
|
|
1661
|
-
|
|
1337
|
+
const startTime = Date.now();
|
|
1338
|
+
setProgressStartTime(startTime);
|
|
1662
1339
|
setShowProgressIndicator(false);
|
|
1663
1340
|
progressDelayTimerId = window.setTimeout(() => {
|
|
1664
1341
|
setShowProgressIndicator(true);
|
|
1665
1342
|
progressDelayTimerId = null;
|
|
1666
1343
|
}, PROGRESS_INDICATOR_DELAY_MS);
|
|
1667
1344
|
const animateProgress = () => {
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
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);
|
|
1671
1353
|
if (currentProgress < 1) {
|
|
1672
1354
|
progressAnimationId = requestAnimationFrame(animateProgress);
|
|
1673
1355
|
}
|
|
@@ -1684,6 +1366,7 @@ ${context}
|
|
|
1684
1366
|
progressDelayTimerId = null;
|
|
1685
1367
|
}
|
|
1686
1368
|
setProgressStartTime(null);
|
|
1369
|
+
setProgress(1);
|
|
1687
1370
|
setShowProgressIndicator(false);
|
|
1688
1371
|
};
|
|
1689
1372
|
const activateRenderer = () => {
|
|
@@ -1924,7 +1607,7 @@ ${context}
|
|
|
1924
1607
|
get labelVisible() {
|
|
1925
1608
|
return labelVisible();
|
|
1926
1609
|
},
|
|
1927
|
-
labelZIndex:
|
|
1610
|
+
labelZIndex: Z_INDEX_LABEL,
|
|
1928
1611
|
get progressVisible() {
|
|
1929
1612
|
return progressVisible();
|
|
1930
1613
|
},
|
|
@@ -1970,9 +1653,6 @@ ${context}
|
|
|
1970
1653
|
// src/index.ts
|
|
1971
1654
|
var globalApi = null;
|
|
1972
1655
|
var getGlobalApi = () => globalApi;
|
|
1973
|
-
|
|
1974
|
-
if (!window[EXTENSION_MARKER]) {
|
|
1975
|
-
globalApi = init();
|
|
1976
|
-
}
|
|
1656
|
+
globalApi = init();
|
|
1977
1657
|
|
|
1978
|
-
export {
|
|
1658
|
+
export { getGlobalApi, init, playCopySound };
|