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