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