react-grab 0.0.25 → 0.0.26
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 +291 -117
- package/dist/index.d.cts +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.global.js +16 -16
- package/dist/index.js +292 -118
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { render, createComponent, memo, template, effect, style,
|
|
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
3
|
import { instrument, _fiberRoots, getFiberFromHostInstance } from 'bippy';
|
|
4
4
|
import { getOwnerStack, getSourcesFromStack } from 'bippy/dist/source';
|
|
@@ -110,11 +110,12 @@ var SelectionBox = (props) => {
|
|
|
110
110
|
const [opacity, setOpacity] = createSignal(1);
|
|
111
111
|
let hasBeenRenderedOnce = false;
|
|
112
112
|
let animationFrameId = null;
|
|
113
|
+
let fadeTimerId = null;
|
|
113
114
|
let targetBounds = props.bounds;
|
|
114
115
|
let isAnimating = false;
|
|
115
116
|
const lerpFactor = () => {
|
|
116
117
|
if (props.lerpFactor !== void 0) return props.lerpFactor;
|
|
117
|
-
if (props.variant === "drag") return 0.
|
|
118
|
+
if (props.variant === "drag") return 0.7;
|
|
118
119
|
return SELECTION_LERP_FACTOR;
|
|
119
120
|
};
|
|
120
121
|
const startAnimation = () => {
|
|
@@ -151,11 +152,22 @@ var SelectionBox = (props) => {
|
|
|
151
152
|
}
|
|
152
153
|
startAnimation();
|
|
153
154
|
}));
|
|
155
|
+
createEffect(() => {
|
|
156
|
+
if (props.variant === "grabbed" && props.createdAt) {
|
|
157
|
+
fadeTimerId = window.setTimeout(() => {
|
|
158
|
+
setOpacity(0);
|
|
159
|
+
}, 1500);
|
|
160
|
+
}
|
|
161
|
+
});
|
|
154
162
|
onCleanup(() => {
|
|
155
163
|
if (animationFrameId !== null) {
|
|
156
164
|
cancelAnimationFrame(animationFrameId);
|
|
157
165
|
animationFrameId = null;
|
|
158
166
|
}
|
|
167
|
+
if (fadeTimerId !== null) {
|
|
168
|
+
window.clearTimeout(fadeTimerId);
|
|
169
|
+
fadeTimerId = null;
|
|
170
|
+
}
|
|
159
171
|
isAnimating = false;
|
|
160
172
|
});
|
|
161
173
|
const baseStyle = {
|
|
@@ -167,8 +179,8 @@ var SelectionBox = (props) => {
|
|
|
167
179
|
const variantStyle = () => {
|
|
168
180
|
if (props.variant === "drag") {
|
|
169
181
|
return {
|
|
170
|
-
border: "1px dashed
|
|
171
|
-
"background-color": "rgba(210, 57, 192, 0.
|
|
182
|
+
border: "1px dashed rgba(210, 57, 192, 0.4)",
|
|
183
|
+
"background-color": "rgba(210, 57, 192, 0.05)",
|
|
172
184
|
"will-change": "transform, width, height",
|
|
173
185
|
contain: "layout paint size",
|
|
174
186
|
cursor: "crosshair"
|
|
@@ -243,11 +255,47 @@ var getClampedElementPosition = (positionLeft, positionTop, elementWidth, elemen
|
|
|
243
255
|
|
|
244
256
|
// src/components/label.tsx
|
|
245
257
|
var _tmpl$3 = /* @__PURE__ */ template(`<span style=display:inline-block;margin-right:4px;font-weight:600>\u2713`);
|
|
246
|
-
var _tmpl$22 = /* @__PURE__ */ template(`<div style=margin-right:4px>
|
|
247
|
-
var _tmpl$32 = /* @__PURE__ */ template(`<div style=
|
|
258
|
+
var _tmpl$22 = /* @__PURE__ */ template(`<div style=margin-right:4px>Copied`);
|
|
259
|
+
var _tmpl$32 = /* @__PURE__ */ template(`<div style=margin-left:4px>to clipboard`);
|
|
260
|
+
var _tmpl$4 = /* @__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">`);
|
|
261
|
+
var _tmpl$5 = /* @__PURE__ */ template(`<span style="font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;font-variant-numeric:tabular-nums">`);
|
|
248
262
|
var Label = (props) => {
|
|
249
263
|
const [opacity, setOpacity] = createSignal(0);
|
|
264
|
+
const [positionTick, setPositionTick] = createSignal(0);
|
|
250
265
|
let labelRef;
|
|
266
|
+
let currentX = props.x;
|
|
267
|
+
let currentY = props.y;
|
|
268
|
+
let targetX = props.x;
|
|
269
|
+
let targetY = props.y;
|
|
270
|
+
let animationFrameId = null;
|
|
271
|
+
let hasBeenRenderedOnce = false;
|
|
272
|
+
const animate = () => {
|
|
273
|
+
currentX = lerp(currentX, targetX, 0.3);
|
|
274
|
+
currentY = lerp(currentY, targetY, 0.3);
|
|
275
|
+
setPositionTick((tick) => tick + 1);
|
|
276
|
+
const hasConvergedToTarget = Math.abs(currentX - targetX) < 0.5 && Math.abs(currentY - targetY) < 0.5;
|
|
277
|
+
if (!hasConvergedToTarget) {
|
|
278
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
279
|
+
} else {
|
|
280
|
+
animationFrameId = null;
|
|
281
|
+
}
|
|
282
|
+
};
|
|
283
|
+
const startAnimation = () => {
|
|
284
|
+
if (animationFrameId !== null) return;
|
|
285
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
286
|
+
};
|
|
287
|
+
const updateTarget = () => {
|
|
288
|
+
targetX = props.x;
|
|
289
|
+
targetY = props.y;
|
|
290
|
+
if (!hasBeenRenderedOnce) {
|
|
291
|
+
currentX = targetX;
|
|
292
|
+
currentY = targetY;
|
|
293
|
+
hasBeenRenderedOnce = true;
|
|
294
|
+
setPositionTick((tick) => tick + 1);
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
startAnimation();
|
|
298
|
+
};
|
|
251
299
|
createEffect(on(() => props.visible, (visible) => {
|
|
252
300
|
if (visible !== false) {
|
|
253
301
|
requestAnimationFrame(() => {
|
|
@@ -264,16 +312,26 @@ var Label = (props) => {
|
|
|
264
312
|
onCleanup(() => clearTimeout(fadeOutTimer));
|
|
265
313
|
}
|
|
266
314
|
}));
|
|
315
|
+
createEffect(() => {
|
|
316
|
+
updateTarget();
|
|
317
|
+
});
|
|
318
|
+
onCleanup(() => {
|
|
319
|
+
if (animationFrameId !== null) {
|
|
320
|
+
cancelAnimationFrame(animationFrameId);
|
|
321
|
+
animationFrameId = null;
|
|
322
|
+
}
|
|
323
|
+
});
|
|
267
324
|
const labelBoundingRect = () => labelRef?.getBoundingClientRect();
|
|
268
325
|
const computedPosition = () => {
|
|
326
|
+
positionTick();
|
|
269
327
|
const boundingRect = labelBoundingRect();
|
|
270
328
|
if (!boundingRect) return {
|
|
271
|
-
left:
|
|
272
|
-
top:
|
|
329
|
+
left: currentX,
|
|
330
|
+
top: currentY
|
|
273
331
|
};
|
|
274
332
|
if (props.variant === "success") {
|
|
275
|
-
const indicatorLeft = Math.round(
|
|
276
|
-
const indicatorTop = Math.round(
|
|
333
|
+
const indicatorLeft = Math.round(currentX);
|
|
334
|
+
const indicatorTop = Math.round(currentY) - boundingRect.height - 6;
|
|
277
335
|
const willClampLeft = indicatorLeft < VIEWPORT_MARGIN_PX;
|
|
278
336
|
const willClampTop = indicatorTop < VIEWPORT_MARGIN_PX;
|
|
279
337
|
const isClamped = willClampLeft || willClampTop;
|
|
@@ -288,17 +346,17 @@ var Label = (props) => {
|
|
|
288
346
|
const viewportWidth = window.innerWidth;
|
|
289
347
|
const viewportHeight = window.innerHeight;
|
|
290
348
|
const quadrants = [{
|
|
291
|
-
left: Math.round(
|
|
292
|
-
top: Math.round(
|
|
349
|
+
left: Math.round(currentX) + CROSSHAIR_OFFSET,
|
|
350
|
+
top: Math.round(currentY) + CROSSHAIR_OFFSET
|
|
293
351
|
}, {
|
|
294
|
-
left: Math.round(
|
|
295
|
-
top: Math.round(
|
|
352
|
+
left: Math.round(currentX) - boundingRect.width - CROSSHAIR_OFFSET,
|
|
353
|
+
top: Math.round(currentY) + CROSSHAIR_OFFSET
|
|
296
354
|
}, {
|
|
297
|
-
left: Math.round(
|
|
298
|
-
top: Math.round(
|
|
355
|
+
left: Math.round(currentX) + CROSSHAIR_OFFSET,
|
|
356
|
+
top: Math.round(currentY) - boundingRect.height - CROSSHAIR_OFFSET
|
|
299
357
|
}, {
|
|
300
|
-
left: Math.round(
|
|
301
|
-
top: Math.round(
|
|
358
|
+
left: Math.round(currentX) - boundingRect.width - CROSSHAIR_OFFSET,
|
|
359
|
+
top: Math.round(currentY) - boundingRect.height - CROSSHAIR_OFFSET
|
|
302
360
|
}];
|
|
303
361
|
for (const position of quadrants) {
|
|
304
362
|
const fitsHorizontally = position.left >= VIEWPORT_MARGIN_PX && position.left + boundingRect.width <= viewportWidth - VIEWPORT_MARGIN_PX;
|
|
@@ -317,7 +375,7 @@ var Label = (props) => {
|
|
|
317
375
|
return props.visible !== false;
|
|
318
376
|
},
|
|
319
377
|
get children() {
|
|
320
|
-
var _el$ = _tmpl$
|
|
378
|
+
var _el$ = _tmpl$4();
|
|
321
379
|
var _ref$ = labelRef;
|
|
322
380
|
typeof _ref$ === "function" ? use(_ref$, _el$) : labelRef = _el$;
|
|
323
381
|
insert(_el$, createComponent(Show, {
|
|
@@ -327,7 +385,7 @@ var Label = (props) => {
|
|
|
327
385
|
get children() {
|
|
328
386
|
return createComponent(Spinner, {});
|
|
329
387
|
}
|
|
330
|
-
}),
|
|
388
|
+
}), null);
|
|
331
389
|
insert(_el$, createComponent(Show, {
|
|
332
390
|
get when() {
|
|
333
391
|
return props.variant === "success";
|
|
@@ -335,7 +393,7 @@ var Label = (props) => {
|
|
|
335
393
|
get children() {
|
|
336
394
|
return _tmpl$3();
|
|
337
395
|
}
|
|
338
|
-
}),
|
|
396
|
+
}), null);
|
|
339
397
|
insert(_el$, createComponent(Show, {
|
|
340
398
|
get when() {
|
|
341
399
|
return props.variant === "success";
|
|
@@ -343,14 +401,36 @@ var Label = (props) => {
|
|
|
343
401
|
get children() {
|
|
344
402
|
return _tmpl$22();
|
|
345
403
|
}
|
|
346
|
-
}),
|
|
404
|
+
}), null);
|
|
347
405
|
insert(_el$, createComponent(Show, {
|
|
348
406
|
get when() {
|
|
349
407
|
return props.variant === "processing";
|
|
350
408
|
},
|
|
351
409
|
children: "Grabbing\u2026"
|
|
352
|
-
}),
|
|
353
|
-
insert(_el
|
|
410
|
+
}), null);
|
|
411
|
+
insert(_el$, createComponent(Show, {
|
|
412
|
+
get when() {
|
|
413
|
+
return props.text.startsWith("(");
|
|
414
|
+
},
|
|
415
|
+
get fallback() {
|
|
416
|
+
return (() => {
|
|
417
|
+
var _el$5 = _tmpl$5();
|
|
418
|
+
insert(_el$5, () => props.text);
|
|
419
|
+
return _el$5;
|
|
420
|
+
})();
|
|
421
|
+
},
|
|
422
|
+
get children() {
|
|
423
|
+
return props.text;
|
|
424
|
+
}
|
|
425
|
+
}), null);
|
|
426
|
+
insert(_el$, createComponent(Show, {
|
|
427
|
+
get when() {
|
|
428
|
+
return props.variant === "success";
|
|
429
|
+
},
|
|
430
|
+
get children() {
|
|
431
|
+
return _tmpl$32();
|
|
432
|
+
}
|
|
433
|
+
}), null);
|
|
354
434
|
effect((_p$) => {
|
|
355
435
|
var _v$ = `${computedPosition().top}px`, _v$2 = `${computedPosition().left}px`, _v$3 = props.zIndex?.toString() ?? "2147483647", _v$4 = opacity();
|
|
356
436
|
_v$ !== _p$.e && setStyleProperty(_el$, "top", _p$.e = _v$);
|
|
@@ -368,7 +448,7 @@ var Label = (props) => {
|
|
|
368
448
|
}
|
|
369
449
|
});
|
|
370
450
|
};
|
|
371
|
-
var _tmpl$
|
|
451
|
+
var _tmpl$6 = /* @__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)">`);
|
|
372
452
|
var useFadeInOut = (visible) => {
|
|
373
453
|
const [opacity, setOpacity] = createSignal(0);
|
|
374
454
|
createEffect(on(() => visible, (isVisible) => {
|
|
@@ -401,7 +481,7 @@ var ProgressIndicator = (props) => {
|
|
|
401
481
|
return props.visible !== false;
|
|
402
482
|
},
|
|
403
483
|
get children() {
|
|
404
|
-
var _el$ = _tmpl$
|
|
484
|
+
var _el$ = _tmpl$6(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild;
|
|
405
485
|
var _ref$ = progressIndicatorRef;
|
|
406
486
|
typeof _ref$ === "function" ? use(_ref$, _el$) : progressIndicatorRef = _el$;
|
|
407
487
|
effect((_p$) => {
|
|
@@ -421,66 +501,99 @@ var ProgressIndicator = (props) => {
|
|
|
421
501
|
}
|
|
422
502
|
});
|
|
423
503
|
};
|
|
424
|
-
var _tmpl$
|
|
504
|
+
var _tmpl$7 = /* @__PURE__ */ template(`<canvas style=position:fixed;top:0;left:0;pointer-events:none;z-index:2147483645>`);
|
|
425
505
|
var Crosshair = (props) => {
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
let
|
|
429
|
-
let
|
|
506
|
+
let canvasRef;
|
|
507
|
+
let context = null;
|
|
508
|
+
let width = 0;
|
|
509
|
+
let height = 0;
|
|
510
|
+
let dpr = 1;
|
|
511
|
+
let currentX = props.mouseX;
|
|
512
|
+
let currentY = props.mouseY;
|
|
430
513
|
let targetX = props.mouseX;
|
|
431
514
|
let targetY = props.mouseY;
|
|
432
|
-
let
|
|
515
|
+
let animationFrameId = null;
|
|
516
|
+
let hasBeenRenderedOnce = false;
|
|
517
|
+
const setupCanvas = () => {
|
|
518
|
+
if (!canvasRef) return;
|
|
519
|
+
dpr = Math.max(window.devicePixelRatio || 1, 2);
|
|
520
|
+
width = window.innerWidth;
|
|
521
|
+
height = window.innerHeight;
|
|
522
|
+
canvasRef.width = width * dpr;
|
|
523
|
+
canvasRef.height = height * dpr;
|
|
524
|
+
canvasRef.style.width = `${width}px`;
|
|
525
|
+
canvasRef.style.height = `${height}px`;
|
|
526
|
+
context = canvasRef.getContext("2d");
|
|
527
|
+
if (context) {
|
|
528
|
+
context.scale(dpr, dpr);
|
|
529
|
+
}
|
|
530
|
+
};
|
|
531
|
+
const render2 = () => {
|
|
532
|
+
if (!context) return;
|
|
533
|
+
context.clearRect(0, 0, width, height);
|
|
534
|
+
context.strokeStyle = "rgba(210, 57, 192)";
|
|
535
|
+
context.lineWidth = 1;
|
|
536
|
+
context.beginPath();
|
|
537
|
+
context.moveTo(currentX, 0);
|
|
538
|
+
context.lineTo(currentX, height);
|
|
539
|
+
context.moveTo(0, currentY);
|
|
540
|
+
context.lineTo(width, currentY);
|
|
541
|
+
context.stroke();
|
|
542
|
+
};
|
|
543
|
+
const animate = () => {
|
|
544
|
+
currentX = lerp(currentX, targetX, 0.3);
|
|
545
|
+
currentY = lerp(currentY, targetY, 0.3);
|
|
546
|
+
render2();
|
|
547
|
+
const hasConvergedToTarget = Math.abs(currentX - targetX) < 0.5 && Math.abs(currentY - targetY) < 0.5;
|
|
548
|
+
if (!hasConvergedToTarget) {
|
|
549
|
+
animationFrameId = requestAnimationFrame(animate);
|
|
550
|
+
} else {
|
|
551
|
+
animationFrameId = null;
|
|
552
|
+
}
|
|
553
|
+
};
|
|
433
554
|
const startAnimation = () => {
|
|
434
|
-
if (
|
|
435
|
-
isAnimating = true;
|
|
436
|
-
const animate = () => {
|
|
437
|
-
const interpolatedX = lerp(currentX(), targetX, 0.3);
|
|
438
|
-
const interpolatedY = lerp(currentY(), targetY, 0.3);
|
|
439
|
-
setCurrentX(interpolatedX);
|
|
440
|
-
setCurrentY(interpolatedY);
|
|
441
|
-
const hasConvergedToTarget = Math.abs(interpolatedX - targetX) < 0.5 && Math.abs(interpolatedY - targetY) < 0.5;
|
|
442
|
-
if (!hasConvergedToTarget) {
|
|
443
|
-
animationFrameId = requestAnimationFrame(animate);
|
|
444
|
-
} else {
|
|
445
|
-
animationFrameId = null;
|
|
446
|
-
isAnimating = false;
|
|
447
|
-
}
|
|
448
|
-
};
|
|
555
|
+
if (animationFrameId !== null) return;
|
|
449
556
|
animationFrameId = requestAnimationFrame(animate);
|
|
450
557
|
};
|
|
451
|
-
|
|
452
|
-
targetX =
|
|
453
|
-
targetY =
|
|
558
|
+
const updateTarget = () => {
|
|
559
|
+
targetX = props.mouseX;
|
|
560
|
+
targetY = props.mouseY;
|
|
454
561
|
if (!hasBeenRenderedOnce) {
|
|
455
|
-
|
|
456
|
-
|
|
562
|
+
currentX = targetX;
|
|
563
|
+
currentY = targetY;
|
|
457
564
|
hasBeenRenderedOnce = true;
|
|
565
|
+
render2();
|
|
458
566
|
return;
|
|
459
567
|
}
|
|
460
568
|
startAnimation();
|
|
461
|
-
}
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
569
|
+
};
|
|
570
|
+
createEffect(() => {
|
|
571
|
+
setupCanvas();
|
|
572
|
+
render2();
|
|
573
|
+
const handleResize = () => {
|
|
574
|
+
setupCanvas();
|
|
575
|
+
render2();
|
|
576
|
+
};
|
|
577
|
+
window.addEventListener("resize", handleResize);
|
|
578
|
+
onCleanup(() => {
|
|
579
|
+
window.removeEventListener("resize", handleResize);
|
|
580
|
+
if (animationFrameId !== null) {
|
|
581
|
+
cancelAnimationFrame(animationFrameId);
|
|
582
|
+
animationFrameId = null;
|
|
583
|
+
}
|
|
584
|
+
});
|
|
585
|
+
});
|
|
586
|
+
createEffect(() => {
|
|
587
|
+
updateTarget();
|
|
468
588
|
});
|
|
469
589
|
return createComponent(Show, {
|
|
470
590
|
get when() {
|
|
471
591
|
return props.visible !== false;
|
|
472
592
|
},
|
|
473
593
|
get children() {
|
|
474
|
-
var _el$ = _tmpl$
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
_v$ !== _p$.e && setStyleProperty(_el$2, "left", _p$.e = _v$);
|
|
478
|
-
_v$2 !== _p$.t && setStyleProperty(_el$3, "top", _p$.t = _v$2);
|
|
479
|
-
return _p$;
|
|
480
|
-
}, {
|
|
481
|
-
e: void 0,
|
|
482
|
-
t: void 0
|
|
483
|
-
});
|
|
594
|
+
var _el$ = _tmpl$7();
|
|
595
|
+
var _ref$ = canvasRef;
|
|
596
|
+
typeof _ref$ === "function" ? use(_ref$, _el$) : canvasRef = _el$;
|
|
484
597
|
return _el$;
|
|
485
598
|
}
|
|
486
599
|
});
|
|
@@ -541,6 +654,9 @@ var ReactGrabRenderer = (props) => {
|
|
|
541
654
|
variant: "grabbed",
|
|
542
655
|
get bounds() {
|
|
543
656
|
return box.bounds;
|
|
657
|
+
},
|
|
658
|
+
get createdAt() {
|
|
659
|
+
return box.createdAt;
|
|
544
660
|
}
|
|
545
661
|
})
|
|
546
662
|
}), createComponent(For, {
|
|
@@ -971,11 +1087,65 @@ var filterElementsInDrag = (dragRect, isValidGrabbableElement2, shouldCheckCover
|
|
|
971
1087
|
}
|
|
972
1088
|
return elements;
|
|
973
1089
|
};
|
|
1090
|
+
var removeNestedElements = (elements) => {
|
|
1091
|
+
return elements.filter((element) => {
|
|
1092
|
+
return !elements.some(
|
|
1093
|
+
(otherElement) => otherElement !== element && otherElement.contains(element)
|
|
1094
|
+
);
|
|
1095
|
+
});
|
|
1096
|
+
};
|
|
1097
|
+
var findBestParentElement = (elements, dragRect, isValidGrabbableElement2) => {
|
|
1098
|
+
if (elements.length <= 1) return null;
|
|
1099
|
+
const dragLeft = dragRect.x;
|
|
1100
|
+
const dragTop = dragRect.y;
|
|
1101
|
+
const dragRight = dragRect.x + dragRect.width;
|
|
1102
|
+
const dragBottom = dragRect.y + dragRect.height;
|
|
1103
|
+
let currentParent = elements[0];
|
|
1104
|
+
while (currentParent) {
|
|
1105
|
+
const parent = currentParent.parentElement;
|
|
1106
|
+
if (!parent) break;
|
|
1107
|
+
const parentRect = parent.getBoundingClientRect();
|
|
1108
|
+
const intersectionLeft = Math.max(dragLeft, parentRect.left);
|
|
1109
|
+
const intersectionTop = Math.max(dragTop, parentRect.top);
|
|
1110
|
+
const intersectionRight = Math.min(dragRight, parentRect.left + parentRect.width);
|
|
1111
|
+
const intersectionBottom = Math.min(dragBottom, parentRect.top + parentRect.height);
|
|
1112
|
+
const intersectionWidth = Math.max(0, intersectionRight - intersectionLeft);
|
|
1113
|
+
const intersectionHeight = Math.max(0, intersectionBottom - intersectionTop);
|
|
1114
|
+
const intersectionArea = intersectionWidth * intersectionHeight;
|
|
1115
|
+
const parentArea = Math.max(0, parentRect.width * parentRect.height);
|
|
1116
|
+
const hasMajorityCoverage = parentArea > 0 && intersectionArea / parentArea >= DRAG_COVERAGE_THRESHOLD;
|
|
1117
|
+
if (!hasMajorityCoverage) break;
|
|
1118
|
+
if (!isValidGrabbableElement2(parent)) {
|
|
1119
|
+
currentParent = parent;
|
|
1120
|
+
continue;
|
|
1121
|
+
}
|
|
1122
|
+
const allChildrenInParent = elements.every(
|
|
1123
|
+
(element) => parent.contains(element)
|
|
1124
|
+
);
|
|
1125
|
+
if (allChildrenInParent) {
|
|
1126
|
+
return parent;
|
|
1127
|
+
}
|
|
1128
|
+
currentParent = parent;
|
|
1129
|
+
}
|
|
1130
|
+
return null;
|
|
1131
|
+
};
|
|
974
1132
|
var getElementsInDrag = (dragRect, isValidGrabbableElement2) => {
|
|
975
|
-
|
|
1133
|
+
const elements = filterElementsInDrag(dragRect, isValidGrabbableElement2, true);
|
|
1134
|
+
const uniqueElements = removeNestedElements(elements);
|
|
1135
|
+
const bestParent = findBestParentElement(uniqueElements, dragRect, isValidGrabbableElement2);
|
|
1136
|
+
if (bestParent) {
|
|
1137
|
+
return [bestParent];
|
|
1138
|
+
}
|
|
1139
|
+
return uniqueElements;
|
|
976
1140
|
};
|
|
977
1141
|
var getElementsInDragLoose = (dragRect, isValidGrabbableElement2) => {
|
|
978
|
-
|
|
1142
|
+
const elements = filterElementsInDrag(dragRect, isValidGrabbableElement2, false);
|
|
1143
|
+
const uniqueElements = removeNestedElements(elements);
|
|
1144
|
+
const bestParent = findBestParentElement(uniqueElements, dragRect, isValidGrabbableElement2);
|
|
1145
|
+
if (bestParent) {
|
|
1146
|
+
return [bestParent];
|
|
1147
|
+
}
|
|
1148
|
+
return uniqueElements;
|
|
979
1149
|
};
|
|
980
1150
|
|
|
981
1151
|
// src/utils/create-element-bounds.ts
|
|
@@ -1020,22 +1190,26 @@ var init = (rawOptions) => {
|
|
|
1020
1190
|
const [successLabels, setSuccessLabels] = createSignal([]);
|
|
1021
1191
|
const [isActivated, setIsActivated] = createSignal(false);
|
|
1022
1192
|
const [showProgressIndicator, setShowProgressIndicator] = createSignal(false);
|
|
1023
|
-
const [grabMouseX, setGrabMouseX] = createSignal(null);
|
|
1024
|
-
const [grabMouseY, setGrabMouseY] = createSignal(null);
|
|
1025
1193
|
let holdTimerId = null;
|
|
1026
1194
|
let progressAnimationId = null;
|
|
1027
1195
|
let progressDelayTimerId = null;
|
|
1196
|
+
let keydownSpamTimerId = null;
|
|
1028
1197
|
const isRendererActive = createMemo(() => isActivated() && !isCopying());
|
|
1029
1198
|
const hasValidMousePosition = createMemo(() => mouseX() > OFFSCREEN_POSITION && mouseY() > OFFSCREEN_POSITION);
|
|
1030
1199
|
const isTargetKeyCombination = (event) => (event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "c";
|
|
1031
1200
|
const addGrabbedBox = (bounds) => {
|
|
1032
1201
|
const boxId = `grabbed-${Date.now()}-${Math.random()}`;
|
|
1202
|
+
const createdAt = Date.now();
|
|
1033
1203
|
const newBox = {
|
|
1034
1204
|
id: boxId,
|
|
1035
|
-
bounds
|
|
1205
|
+
bounds,
|
|
1206
|
+
createdAt
|
|
1036
1207
|
};
|
|
1037
1208
|
const currentBoxes = grabbedBoxes();
|
|
1038
1209
|
setGrabbedBoxes([...currentBoxes, newBox]);
|
|
1210
|
+
setTimeout(() => {
|
|
1211
|
+
setGrabbedBoxes((previousBoxes) => previousBoxes.filter((box) => box.id !== boxId));
|
|
1212
|
+
}, SUCCESS_LABEL_DURATION_MS);
|
|
1039
1213
|
};
|
|
1040
1214
|
const addSuccessLabel = (text, positionX, positionY) => {
|
|
1041
1215
|
const labelId = `success-${Date.now()}-${Math.random()}`;
|
|
@@ -1058,6 +1232,9 @@ var init = (rawOptions) => {
|
|
|
1058
1232
|
return ` ${functionName} - ${fileName}:${lineNumber}:${columnNumber}`;
|
|
1059
1233
|
}).join("\n");
|
|
1060
1234
|
};
|
|
1235
|
+
const wrapContextInXmlTags = (context) => {
|
|
1236
|
+
return `<selected_element>${context}</selected_element>`;
|
|
1237
|
+
};
|
|
1061
1238
|
const getElementContentWithTrace = async (element) => {
|
|
1062
1239
|
const elementHtml = getHTMLSnippet(element);
|
|
1063
1240
|
const componentStackTrace = await getSourceTrace(element);
|
|
@@ -1074,12 +1251,10 @@ ${formattedStackTrace}`;
|
|
|
1074
1251
|
const handleCopy = async (targetElement2) => {
|
|
1075
1252
|
const elementBounds = targetElement2.getBoundingClientRect();
|
|
1076
1253
|
const tagName = getElementTagName(targetElement2);
|
|
1077
|
-
setGrabMouseX(mouseX());
|
|
1078
|
-
setGrabMouseY(mouseY());
|
|
1079
1254
|
addGrabbedBox(createElementBounds(targetElement2));
|
|
1080
1255
|
try {
|
|
1081
1256
|
const content = await getElementContentWithTrace(targetElement2);
|
|
1082
|
-
await copyContent(content);
|
|
1257
|
+
await copyContent(wrapContextInXmlTags(content));
|
|
1083
1258
|
} catch {
|
|
1084
1259
|
}
|
|
1085
1260
|
addSuccessLabel(tagName ? `<${tagName}>` : "<element>", elementBounds.left, elementBounds.top);
|
|
@@ -1088,8 +1263,6 @@ ${formattedStackTrace}`;
|
|
|
1088
1263
|
if (targetElements.length === 0) return;
|
|
1089
1264
|
let minPositionX = Infinity;
|
|
1090
1265
|
let minPositionY = Infinity;
|
|
1091
|
-
setGrabMouseX(mouseX());
|
|
1092
|
-
setGrabMouseY(mouseY());
|
|
1093
1266
|
for (const element of targetElements) {
|
|
1094
1267
|
const elementBounds = element.getBoundingClientRect();
|
|
1095
1268
|
minPositionX = Math.min(minPositionX, elementBounds.left);
|
|
@@ -1099,7 +1272,7 @@ ${formattedStackTrace}`;
|
|
|
1099
1272
|
try {
|
|
1100
1273
|
const elementSnippets = await Promise.all(targetElements.map((element) => getElementContentWithTrace(element)));
|
|
1101
1274
|
const combinedContent = elementSnippets.join("\n\n---\n\n");
|
|
1102
|
-
await copyContent(combinedContent);
|
|
1275
|
+
await copyContent(wrapContextInXmlTags(combinedContent));
|
|
1103
1276
|
} catch {
|
|
1104
1277
|
}
|
|
1105
1278
|
addSuccessLabel(`${targetElements.length} elements`, minPositionX, minPositionY);
|
|
@@ -1122,7 +1295,7 @@ ${formattedStackTrace}`;
|
|
|
1122
1295
|
y: elementBounds.top
|
|
1123
1296
|
};
|
|
1124
1297
|
});
|
|
1125
|
-
const DRAG_THRESHOLD_PX =
|
|
1298
|
+
const DRAG_THRESHOLD_PX = 2;
|
|
1126
1299
|
const getDragDistance = (endX, endY) => ({
|
|
1127
1300
|
x: Math.abs(endX - dragStartX()),
|
|
1128
1301
|
y: Math.abs(endY - dragStartY())
|
|
@@ -1158,7 +1331,7 @@ ${formattedStackTrace}`;
|
|
|
1158
1331
|
});
|
|
1159
1332
|
const labelText = createMemo(() => {
|
|
1160
1333
|
const element = targetElement();
|
|
1161
|
-
if (!element) return "";
|
|
1334
|
+
if (!element) return "(click or drag to select element(s))";
|
|
1162
1335
|
const tagName = getElementTagName(element);
|
|
1163
1336
|
return tagName ? `<${tagName}>` : "<element>";
|
|
1164
1337
|
});
|
|
@@ -1178,18 +1351,6 @@ ${formattedStackTrace}`;
|
|
|
1178
1351
|
setLastGrabbedElement(null);
|
|
1179
1352
|
}
|
|
1180
1353
|
}));
|
|
1181
|
-
createEffect(on(() => [mouseX(), mouseY(), grabMouseX(), grabMouseY()], ([currentMouseX, currentMouseY, initialGrabMouseX, initialGrabMouseY]) => {
|
|
1182
|
-
if (initialGrabMouseX === null || initialGrabMouseY === null) return;
|
|
1183
|
-
if (grabbedBoxes().length === 0) return;
|
|
1184
|
-
const MOUSE_MOVE_THRESHOLD_PX = 5;
|
|
1185
|
-
const distanceX = Math.abs(currentMouseX - initialGrabMouseX);
|
|
1186
|
-
const distanceY = Math.abs(currentMouseY - initialGrabMouseY);
|
|
1187
|
-
if (distanceX > MOUSE_MOVE_THRESHOLD_PX || distanceY > MOUSE_MOVE_THRESHOLD_PX) {
|
|
1188
|
-
setGrabbedBoxes([]);
|
|
1189
|
-
setGrabMouseX(null);
|
|
1190
|
-
setGrabMouseY(null);
|
|
1191
|
-
}
|
|
1192
|
-
}));
|
|
1193
1354
|
const progress = createMemo(() => {
|
|
1194
1355
|
const startTime = progressStartTime();
|
|
1195
1356
|
progressTick();
|
|
@@ -1231,43 +1392,55 @@ ${formattedStackTrace}`;
|
|
|
1231
1392
|
setIsActivated(true);
|
|
1232
1393
|
document.body.style.cursor = "crosshair";
|
|
1233
1394
|
};
|
|
1395
|
+
const deactivateRenderer = () => {
|
|
1396
|
+
setIsHoldingKeys(false);
|
|
1397
|
+
setIsActivated(false);
|
|
1398
|
+
document.body.style.cursor = "";
|
|
1399
|
+
if (isDragging()) {
|
|
1400
|
+
setIsDragging(false);
|
|
1401
|
+
document.body.style.userSelect = "";
|
|
1402
|
+
}
|
|
1403
|
+
if (holdTimerId) window.clearTimeout(holdTimerId);
|
|
1404
|
+
if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
|
|
1405
|
+
stopProgressAnimation();
|
|
1406
|
+
};
|
|
1234
1407
|
const abortController = new AbortController();
|
|
1235
1408
|
const eventListenerSignal = abortController.signal;
|
|
1236
1409
|
window.addEventListener("keydown", (event) => {
|
|
1237
1410
|
if (event.key === "Escape" && isHoldingKeys()) {
|
|
1238
|
-
|
|
1239
|
-
setIsActivated(false);
|
|
1240
|
-
document.body.style.cursor = "";
|
|
1241
|
-
if (isDragging()) {
|
|
1242
|
-
setIsDragging(false);
|
|
1243
|
-
document.body.style.userSelect = "";
|
|
1244
|
-
}
|
|
1245
|
-
if (holdTimerId) window.clearTimeout(holdTimerId);
|
|
1246
|
-
stopProgressAnimation();
|
|
1411
|
+
deactivateRenderer();
|
|
1247
1412
|
return;
|
|
1248
1413
|
}
|
|
1249
1414
|
if (isKeyboardEventTriggeredByInput(event)) return;
|
|
1250
|
-
if (isTargetKeyCombination(event)
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1415
|
+
if (isTargetKeyCombination(event)) {
|
|
1416
|
+
if (!isHoldingKeys()) {
|
|
1417
|
+
setIsHoldingKeys(true);
|
|
1418
|
+
startProgressAnimation();
|
|
1419
|
+
holdTimerId = window.setTimeout(() => {
|
|
1420
|
+
activateRenderer();
|
|
1421
|
+
options.onActivate?.();
|
|
1422
|
+
}, options.keyHoldDuration);
|
|
1423
|
+
}
|
|
1424
|
+
if (isActivated()) {
|
|
1425
|
+
if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
|
|
1426
|
+
keydownSpamTimerId = window.setTimeout(() => {
|
|
1427
|
+
deactivateRenderer();
|
|
1428
|
+
}, 200);
|
|
1429
|
+
}
|
|
1257
1430
|
}
|
|
1258
1431
|
}, {
|
|
1259
1432
|
signal: eventListenerSignal
|
|
1260
1433
|
});
|
|
1261
1434
|
window.addEventListener("keyup", (event) => {
|
|
1262
|
-
if (isHoldingKeys() &&
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
stopProgressAnimation();
|
|
1435
|
+
if (!isHoldingKeys() && !isActivated()) return;
|
|
1436
|
+
const isReleasingC = event.key.toLowerCase() === "c";
|
|
1437
|
+
const isReleasingModifier = !event.metaKey && !event.ctrlKey;
|
|
1438
|
+
if (isReleasingC || isReleasingModifier) {
|
|
1439
|
+
deactivateRenderer();
|
|
1268
1440
|
}
|
|
1269
1441
|
}, {
|
|
1270
|
-
signal: eventListenerSignal
|
|
1442
|
+
signal: eventListenerSignal,
|
|
1443
|
+
capture: true
|
|
1271
1444
|
});
|
|
1272
1445
|
window.addEventListener("mousemove", (event) => {
|
|
1273
1446
|
setMouseX(event.clientX);
|
|
@@ -1330,6 +1503,7 @@ ${formattedStackTrace}`;
|
|
|
1330
1503
|
onCleanup(() => {
|
|
1331
1504
|
abortController.abort();
|
|
1332
1505
|
if (holdTimerId) window.clearTimeout(holdTimerId);
|
|
1506
|
+
if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
|
|
1333
1507
|
stopProgressAnimation();
|
|
1334
1508
|
document.body.style.userSelect = "";
|
|
1335
1509
|
document.body.style.cursor = "";
|
|
@@ -1338,7 +1512,7 @@ ${formattedStackTrace}`;
|
|
|
1338
1512
|
const selectionVisible = createMemo(() => false);
|
|
1339
1513
|
const dragVisible = createMemo(() => isRendererActive() && isDraggingBeyondThreshold());
|
|
1340
1514
|
const labelVariant = createMemo(() => isCopying() ? "processing" : "hover");
|
|
1341
|
-
const labelVisible = createMemo(() => isRendererActive() && !isDragging() && !!targetElement() && !isSameAsLast() || isCopying());
|
|
1515
|
+
const labelVisible = createMemo(() => isRendererActive() && !isDragging() && (!!targetElement() && !isSameAsLast() || !targetElement()) || isCopying());
|
|
1342
1516
|
const progressVisible = createMemo(() => isHoldingKeys() && showProgressIndicator() && hasValidMousePosition());
|
|
1343
1517
|
const crosshairVisible = createMemo(() => isRendererActive() && !isDragging());
|
|
1344
1518
|
render(() => createComponent(ReactGrabRenderer, {
|