react-grab 0.0.44 → 0.0.46

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.js CHANGED
@@ -1,7 +1,7 @@
1
- import { render, createComponent, memo, template, effect, style, insert, setStyleProperty, use } from 'solid-js/web';
1
+ import { delegateEvents, render, createComponent, memo, template, effect, style, insert, setStyleProperty, use } from 'solid-js/web';
2
2
  import { createRoot, createSignal, createMemo, createEffect, on, onCleanup, Show, For, onMount } from 'solid-js';
3
- import { getFiberFromHostInstance, traverseFiber, isCompositeFiber, getDisplayName, isFiber, getLatestFiber, isHostFiber } from 'bippy';
4
- import { isSourceFile, normalizeFileName, getSource } from 'bippy/source';
3
+ import { isInstrumentationActive, getFiberFromHostInstance, traverseFiber, isCompositeFiber, getDisplayName, isFiber, getLatestFiber, isHostFiber } from 'bippy';
4
+ import { getSource, isSourceFile, normalizeFileName } from 'bippy/source';
5
5
 
6
6
  /**
7
7
  * @license MIT
@@ -98,6 +98,8 @@ var SELECTION_LERP_FACTOR = 0.95;
98
98
  var SUCCESS_LABEL_DURATION_MS = 1700;
99
99
  var PROGRESS_INDICATOR_DELAY_MS = 150;
100
100
  var DRAG_THRESHOLD_PX = 2;
101
+ var AUTO_SCROLL_EDGE_THRESHOLD_PX = 25;
102
+ var AUTO_SCROLL_SPEED_PX = 10;
101
103
  var Z_INDEX_LABEL = 2147483647;
102
104
 
103
105
  // src/utils/lerp.ts
@@ -580,6 +582,87 @@ var Crosshair = (props) => {
580
582
  }
581
583
  });
582
584
  };
585
+ var _tmpl$10 = /* @__PURE__ */ template(`<div data-react-grab-input style="position:fixed;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;max-width:calc(100vw - (16px + env(safe-area-inset-left) + env(safe-area-inset-right)));overflow:hidden"><div style="position:relative;padding:2px 3px;display:flex;flex-direction:column;gap:2px"><textarea placeholder="e.g., Make this button larger"rows=1 style="width:240px;padding:2px 4px;background-color:#ffffff;color:#b21c8e;border:1px solid #f7c5ec;border-radius:3px;font-size:11px;line-height:1.2;font-family:-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;outline:none;resize:vertical;min-height:18px"></textarea><div style=font-size:9px;opacity:0.6;text-align:center>Enter \u23CE to submit, Escape to cancel`);
586
+ var InputOverlay = (props) => {
587
+ let containerRef;
588
+ let inputRef;
589
+ const position = useAnimatedPosition({
590
+ x: () => props.x,
591
+ y: () => props.y,
592
+ lerpFactor: 0.3
593
+ });
594
+ const containerBoundingRect = () => containerRef?.getBoundingClientRect();
595
+ const computedPosition = () => {
596
+ const boundingRect = containerBoundingRect();
597
+ if (!boundingRect) return {
598
+ left: position.x(),
599
+ top: position.y()
600
+ };
601
+ const viewportWidth = window.innerWidth;
602
+ const viewportHeight = window.innerHeight;
603
+ const quadrants = getCursorQuadrants(position.x(), position.y(), boundingRect.width, boundingRect.height, CURSOR_OFFSET_PX);
604
+ for (const position2 of quadrants) {
605
+ const fitsHorizontally = position2.left >= VIEWPORT_MARGIN_PX && position2.left + boundingRect.width <= viewportWidth - VIEWPORT_MARGIN_PX;
606
+ const fitsVertically = position2.top >= VIEWPORT_MARGIN_PX && position2.top + boundingRect.height <= viewportHeight - VIEWPORT_MARGIN_PX;
607
+ if (fitsHorizontally && fitsVertically) {
608
+ return position2;
609
+ }
610
+ }
611
+ const fallback = getClampedElementPosition(quadrants[0].left, quadrants[0].top, boundingRect.width, boundingRect.height);
612
+ fallback.left += INDICATOR_CLAMP_PADDING_PX;
613
+ fallback.top += INDICATOR_CLAMP_PADDING_PX;
614
+ return fallback;
615
+ };
616
+ const handleKeyDown = (event) => {
617
+ if (event.key === "Enter" && !event.shiftKey) {
618
+ event.preventDefault();
619
+ event.stopPropagation();
620
+ props.onSubmit();
621
+ } else if (event.key === "Escape") {
622
+ event.preventDefault();
623
+ event.stopPropagation();
624
+ props.onCancel();
625
+ }
626
+ };
627
+ const handleInput = (event) => {
628
+ const target = event.target;
629
+ props.onInput(target.value);
630
+ };
631
+ createEffect(() => {
632
+ if (props.visible && inputRef) {
633
+ inputRef.focus();
634
+ } else if (!props.visible && inputRef) {
635
+ inputRef.blur();
636
+ }
637
+ });
638
+ return (() => {
639
+ var _el$ = _tmpl$10(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild; _el$3.nextSibling;
640
+ var _ref$ = containerRef;
641
+ typeof _ref$ === "function" ? use(_ref$, _el$) : containerRef = _el$;
642
+ _el$3.$$keydown = handleKeyDown;
643
+ _el$3.$$input = handleInput;
644
+ var _ref$2 = inputRef;
645
+ typeof _ref$2 === "function" ? use(_ref$2, _el$3) : inputRef = _el$3;
646
+ effect((_p$) => {
647
+ var _v$ = props.visible ? "block" : "none", _v$2 = `${computedPosition().top}px`, _v$3 = `${computedPosition().left}px`, _v$4 = props.zIndex?.toString() ?? "2147483647", _v$5 = props.visible ? "auto" : "none";
648
+ _v$ !== _p$.e && setStyleProperty(_el$, "display", _p$.e = _v$);
649
+ _v$2 !== _p$.t && setStyleProperty(_el$, "top", _p$.t = _v$2);
650
+ _v$3 !== _p$.a && setStyleProperty(_el$, "left", _p$.a = _v$3);
651
+ _v$4 !== _p$.o && setStyleProperty(_el$, "z-index", _p$.o = _v$4);
652
+ _v$5 !== _p$.i && setStyleProperty(_el$, "pointer-events", _p$.i = _v$5);
653
+ return _p$;
654
+ }, {
655
+ e: void 0,
656
+ t: void 0,
657
+ a: void 0,
658
+ o: void 0,
659
+ i: void 0
660
+ });
661
+ effect(() => _el$3.value = props.value);
662
+ return _el$;
663
+ })();
664
+ };
665
+ delegateEvents(["input", "keydown"]);
583
666
 
584
667
  // src/components/renderer.tsx
585
668
  var ReactGrabRenderer = (props) => {
@@ -696,6 +779,31 @@ var ReactGrabRenderer = (props) => {
696
779
  }
697
780
  });
698
781
  }
782
+ }), createComponent(InputOverlay, {
783
+ get x() {
784
+ return props.inputX ?? 0;
785
+ },
786
+ get y() {
787
+ return props.inputY ?? 0;
788
+ },
789
+ get zIndex() {
790
+ return props.labelZIndex;
791
+ },
792
+ get value() {
793
+ return props.inputValue ?? "";
794
+ },
795
+ get visible() {
796
+ return props.inputVisible ?? false;
797
+ },
798
+ get onInput() {
799
+ return props.onInputChange;
800
+ },
801
+ get onSubmit() {
802
+ return props.onInputSubmit;
803
+ },
804
+ get onCancel() {
805
+ return props.onInputCancel;
806
+ }
699
807
  })];
700
808
  };
701
809
 
@@ -749,50 +857,60 @@ var checkIsSourceComponentName = (name) => {
749
857
  return true;
750
858
  };
751
859
  var getNearestComponentName = (element) => {
752
- const fiber = getFiberFromHostInstance(element);
753
- if (!fiber) return null;
754
- let foundComponentName = null;
755
- traverseFiber(
756
- fiber,
757
- (currentFiber) => {
758
- if (isCompositeFiber(currentFiber)) {
759
- const displayName = getDisplayName(currentFiber);
760
- if (displayName && checkIsSourceComponentName(displayName)) {
761
- foundComponentName = displayName;
762
- return true;
860
+ if (!isInstrumentationActive()) return null;
861
+ try {
862
+ const fiber = getFiberFromHostInstance(element);
863
+ if (!fiber) return null;
864
+ let foundComponentName = null;
865
+ traverseFiber(
866
+ fiber,
867
+ (currentFiber) => {
868
+ if (isCompositeFiber(currentFiber)) {
869
+ const displayName = getDisplayName(currentFiber);
870
+ if (displayName && checkIsSourceComponentName(displayName)) {
871
+ foundComponentName = displayName;
872
+ return true;
873
+ }
763
874
  }
764
- }
765
- return false;
766
- },
767
- true
768
- );
769
- return foundComponentName;
875
+ return false;
876
+ },
877
+ true
878
+ );
879
+ return foundComponentName;
880
+ } catch {
881
+ return null;
882
+ }
770
883
  };
771
884
  var getStack = async (element) => {
772
- const maybeFiber = getFiberFromHostInstance(element);
773
- if (!maybeFiber || !isFiber(maybeFiber)) return [];
774
- const fiber = getLatestFiber(maybeFiber);
775
- const unresolvedStack = [];
776
- traverseFiber(
777
- fiber,
778
- (currentFiber) => {
779
- const displayName = isHostFiber(currentFiber) ? typeof currentFiber.type === "string" ? currentFiber.type : null : getDisplayName(currentFiber);
780
- if (displayName && !checkIsInternalComponentName(displayName)) {
781
- unresolvedStack.push({
782
- name: displayName,
783
- sourcePromise: getSource(currentFiber)
784
- });
785
- }
786
- },
787
- true
788
- );
789
- const resolvedStack = await Promise.all(
790
- unresolvedStack.map(async (frame) => ({
791
- name: frame.name,
792
- source: await frame.sourcePromise
793
- }))
794
- );
795
- return resolvedStack.filter((frame) => frame.source !== null);
885
+ if (!isInstrumentationActive()) return [];
886
+ try {
887
+ const maybeFiber = getFiberFromHostInstance(element);
888
+ if (!maybeFiber || !isFiber(maybeFiber)) return [];
889
+ const fiber = getLatestFiber(maybeFiber);
890
+ const unresolvedStack = [];
891
+ traverseFiber(
892
+ fiber,
893
+ (currentFiber) => {
894
+ const displayName = isHostFiber(currentFiber) ? typeof currentFiber.type === "string" ? currentFiber.type : null : getDisplayName(currentFiber);
895
+ if (displayName && !checkIsInternalComponentName(displayName)) {
896
+ unresolvedStack.push({
897
+ name: displayName,
898
+ sourcePromise: getSource(currentFiber)
899
+ });
900
+ }
901
+ },
902
+ true
903
+ );
904
+ const resolvedStack = await Promise.all(
905
+ unresolvedStack.map(async (frame) => ({
906
+ name: frame.name,
907
+ source: await frame.sourcePromise
908
+ }))
909
+ );
910
+ return resolvedStack.filter((frame) => frame.source !== null);
911
+ } catch {
912
+ return [];
913
+ }
796
914
  };
797
915
  var formatStack = (stack) => {
798
916
  const isNextProject = checkIsNextProject();
@@ -835,7 +953,7 @@ var getHTMLPreview = (element) => {
835
953
  if (node.textContent && node.textContent.trim().length > 0) {
836
954
  foundFirstText = true;
837
955
  }
838
- } else if (node.nodeType === Node.ELEMENT_NODE) {
956
+ } else if (node instanceof Element) {
839
957
  if (!foundFirstText) {
840
958
  topElements.push(node);
841
959
  } else {
@@ -1065,7 +1183,7 @@ var createElementBounds = (element) => {
1065
1183
  };
1066
1184
 
1067
1185
  // src/core.tsx
1068
- var hasLoggedIntro = false;
1186
+ var hasInited = false;
1069
1187
  var init = (rawOptions) => {
1070
1188
  const options = {
1071
1189
  enabled: true,
@@ -1074,7 +1192,7 @@ var init = (rawOptions) => {
1074
1192
  playCopySound: false,
1075
1193
  ...rawOptions
1076
1194
  };
1077
- if (options.enabled === false) {
1195
+ if (options.enabled === false || hasInited) {
1078
1196
  return {
1079
1197
  activate: () => {
1080
1198
  },
@@ -1087,16 +1205,15 @@ var init = (rawOptions) => {
1087
1205
  }
1088
1206
  };
1089
1207
  }
1208
+ hasInited = true;
1090
1209
  const logIntro = () => {
1091
- if (hasLoggedIntro) return;
1092
- hasLoggedIntro = true;
1093
1210
  try {
1094
- const version = "0.0.44";
1211
+ const version = "0.0.46";
1095
1212
  const logoSvg = `<svg width="294" height="294" viewBox="0 0 294 294" fill="none" xmlns="http://www.w3.org/2000/svg"><g clip-path="url(#clip0_0_3)"><mask id="mask0_0_3" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="294" height="294"><path d="M294 0H0V294H294V0Z" fill="white"/></mask><g mask="url(#mask0_0_3)"><path d="M144.599 47.4924C169.712 27.3959 194.548 20.0265 212.132 30.1797C227.847 39.2555 234.881 60.3243 231.926 89.516C231.677 92.0069 231.328 94.5423 230.94 97.1058L228.526 110.14C228.517 110.136 228.505 110.132 228.495 110.127C228.486 110.165 228.479 110.203 228.468 110.24L216.255 105.741C216.256 105.736 216.248 105.728 216.248 105.723C207.915 103.125 199.421 101.075 190.82 99.5888L190.696 99.5588L173.526 97.2648L173.511 97.2631C173.492 97.236 173.467 97.2176 173.447 97.1905C163.862 96.2064 154.233 95.7166 144.599 95.7223C134.943 95.7162 125.295 96.219 115.693 97.2286C110.075 105.033 104.859 113.118 100.063 121.453C95.2426 129.798 90.8624 138.391 86.939 147.193C90.8624 155.996 95.2426 164.588 100.063 172.933C104.866 181.302 110.099 189.417 115.741 197.245C115.749 197.245 115.758 197.246 115.766 197.247L115.752 197.27L115.745 197.283L115.754 197.296L126.501 211.013L126.574 211.089C132.136 217.767 138.126 224.075 144.507 229.974L144.609 230.082L154.572 238.287C154.539 238.319 154.506 238.35 154.472 238.38C154.485 238.392 154.499 238.402 154.513 238.412L143.846 247.482L143.827 247.497C126.56 261.128 109.472 268.745 94.8019 268.745C88.5916 268.837 82.4687 267.272 77.0657 264.208C61.3496 255.132 54.3164 234.062 57.2707 204.871C57.528 202.307 57.8806 199.694 58.2904 197.054C28.3363 185.327 9.52301 167.51 9.52301 147.193C9.52301 129.042 24.2476 112.396 50.9901 100.375C53.3443 99.3163 55.7938 98.3058 58.2904 97.3526C57.8806 94.7023 57.528 92.0803 57.2707 89.516C54.3164 60.3243 61.3496 39.2555 77.0657 30.1797C94.6494 20.0265 119.486 27.3959 144.599 47.4924ZM70.6423 201.315C70.423 202.955 70.2229 204.566 70.0704 206.168C67.6686 229.567 72.5478 246.628 83.3615 252.988L83.5176 253.062C95.0399 259.717 114.015 254.426 134.782 238.38C125.298 229.45 116.594 219.725 108.764 209.314C95.8516 207.742 83.0977 205.066 70.6423 201.315ZM80.3534 163.438C77.34 171.677 74.8666 180.104 72.9484 188.664C81.1787 191.224 89.5657 193.247 98.0572 194.724L98.4618 194.813C95.2115 189.865 92.0191 184.66 88.9311 179.378C85.8433 174.097 83.003 168.768 80.3534 163.438ZM60.759 110.203C59.234 110.839 57.7378 111.475 56.27 112.11C34.7788 121.806 22.3891 134.591 22.3891 147.193C22.3891 160.493 36.4657 174.297 60.7494 184.26C63.7439 171.581 67.8124 159.182 72.9104 147.193C67.822 135.23 63.7566 122.855 60.759 110.203ZM98.4137 99.6404C89.8078 101.145 81.3075 103.206 72.9676 105.809C74.854 114.203 77.2741 122.468 80.2132 130.554L80.3059 130.939C82.9938 125.6 85.8049 120.338 88.8834 115.008C91.9618 109.679 95.1544 104.569 98.4137 99.6404ZM94.9258 38.5215C90.9331 38.4284 86.9866 39.3955 83.4891 41.3243C72.6291 47.6015 67.6975 64.5954 70.0424 87.9446L70.0416 88.2194C70.194 89.8208 70.3941 91.4325 70.6134 93.0624C83.0737 89.3364 95.8263 86.6703 108.736 85.0924C116.57 74.6779 125.28 64.9532 134.773 56.0249C119.877 44.5087 105.895 38.5215 94.9258 38.5215ZM205.737 41.3148C202.268 39.398 198.355 38.4308 194.394 38.5099L194.29 38.512C183.321 38.512 169.34 44.4991 154.444 56.0153C163.93 64.9374 172.634 74.6557 180.462 85.064C193.375 86.6345 206.128 89.3102 218.584 93.0624C218.812 91.4325 219.003 89.8118 219.165 88.2098C221.548 64.7099 216.65 47.6164 205.737 41.3148ZM144.552 64.3097C138.104 70.2614 132.054 76.6306 126.443 83.3765C132.39 82.995 138.426 82.8046 144.552 82.8046C150.727 82.8046 156.778 83.0143 162.707 83.3765C157.08 76.6293 151.015 70.2596 144.552 64.3097Z" fill="white"/><path d="M144.598 47.4924C169.712 27.3959 194.547 20.0265 212.131 30.1797C227.847 39.2555 234.88 60.3243 231.926 89.516C231.677 92.0069 231.327 94.5423 230.941 97.1058L228.526 110.14L228.496 110.127C228.487 110.165 228.478 110.203 228.469 110.24L216.255 105.741L216.249 105.723C207.916 103.125 199.42 101.075 190.82 99.5888L190.696 99.5588L173.525 97.2648L173.511 97.263C173.492 97.236 173.468 97.2176 173.447 97.1905C163.863 96.2064 154.234 95.7166 144.598 95.7223C134.943 95.7162 125.295 96.219 115.693 97.2286C110.075 105.033 104.859 113.118 100.063 121.453C95.2426 129.798 90.8622 138.391 86.939 147.193C90.8622 155.996 95.2426 164.588 100.063 172.933C104.866 181.302 110.099 189.417 115.741 197.245L115.766 197.247L115.752 197.27L115.745 197.283L115.754 197.296L126.501 211.013L126.574 211.089C132.136 217.767 138.126 224.075 144.506 229.974L144.61 230.082L154.572 238.287C154.539 238.319 154.506 238.35 154.473 238.38L154.512 238.412L143.847 247.482L143.827 247.497C126.56 261.13 109.472 268.745 94.8018 268.745C88.5915 268.837 82.4687 267.272 77.0657 264.208C61.3496 255.132 54.3162 234.062 57.2707 204.871C57.528 202.307 57.8806 199.694 58.2904 197.054C28.3362 185.327 9.52298 167.51 9.52298 147.193C9.52298 129.042 24.2476 112.396 50.9901 100.375C53.3443 99.3163 55.7938 98.3058 58.2904 97.3526C57.8806 94.7023 57.528 92.0803 57.2707 89.516C54.3162 60.3243 61.3496 39.2555 77.0657 30.1797C94.6493 20.0265 119.486 27.3959 144.598 47.4924ZM70.6422 201.315C70.423 202.955 70.2229 204.566 70.0704 206.168C67.6686 229.567 72.5478 246.628 83.3615 252.988L83.5175 253.062C95.0399 259.717 114.015 254.426 134.782 238.38C125.298 229.45 116.594 219.725 108.764 209.314C95.8515 207.742 83.0977 205.066 70.6422 201.315ZM80.3534 163.438C77.34 171.677 74.8666 180.104 72.9484 188.664C81.1786 191.224 89.5657 193.247 98.0572 194.724L98.4618 194.813C95.2115 189.865 92.0191 184.66 88.931 179.378C85.8433 174.097 83.003 168.768 80.3534 163.438ZM60.7589 110.203C59.234 110.839 57.7378 111.475 56.2699 112.11C34.7788 121.806 22.3891 134.591 22.3891 147.193C22.3891 160.493 36.4657 174.297 60.7494 184.26C63.7439 171.581 67.8124 159.182 72.9103 147.193C67.822 135.23 63.7566 122.855 60.7589 110.203ZM98.4137 99.6404C89.8078 101.145 81.3075 103.206 72.9676 105.809C74.8539 114.203 77.2741 122.468 80.2132 130.554L80.3059 130.939C82.9938 125.6 85.8049 120.338 88.8834 115.008C91.9618 109.679 95.1544 104.569 98.4137 99.6404ZM94.9258 38.5215C90.9331 38.4284 86.9866 39.3955 83.4891 41.3243C72.629 47.6015 67.6975 64.5954 70.0424 87.9446L70.0415 88.2194C70.194 89.8208 70.3941 91.4325 70.6134 93.0624C83.0737 89.3364 95.8262 86.6703 108.736 85.0924C116.57 74.6779 125.28 64.9532 134.772 56.0249C119.877 44.5087 105.895 38.5215 94.9258 38.5215ZM205.737 41.3148C202.268 39.398 198.355 38.4308 194.394 38.5099L194.291 38.512C183.321 38.512 169.34 44.4991 154.443 56.0153C163.929 64.9374 172.634 74.6557 180.462 85.064C193.374 86.6345 206.129 89.3102 218.584 93.0624C218.813 91.4325 219.003 89.8118 219.166 88.2098C221.548 64.7099 216.65 47.6164 205.737 41.3148ZM144.551 64.3097C138.103 70.2614 132.055 76.6306 126.443 83.3765C132.389 82.995 138.427 82.8046 144.551 82.8046C150.727 82.8046 156.779 83.0143 162.707 83.3765C157.079 76.6293 151.015 70.2596 144.551 64.3097Z" fill="#FF40E0"/></g><mask id="mask1_0_3" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="102" y="84" width="161" height="162"><path d="M235.282 84.827L102.261 112.259L129.693 245.28L262.714 217.848L235.282 84.827Z" fill="white"/></mask><g mask="url(#mask1_0_3)"><path d="M136.863 129.916L213.258 141.224C220.669 142.322 222.495 152.179 215.967 155.856L187.592 171.843L184.135 204.227C183.339 211.678 173.564 213.901 169.624 207.526L129.021 141.831C125.503 136.14 130.245 128.936 136.863 129.916Z" fill="#FF40E0" stroke="#FF40E0" stroke-width="0.817337" stroke-linecap="round" stroke-linejoin="round"/></g></g><defs><clipPath id="clip0_0_3"><rect width="294" height="294" fill="white"/></clipPath></defs></svg>`;
1096
1213
  const logoDataUri = `data:image/svg+xml;base64,${btoa(logoSvg)}`;
1097
1214
  console.log(`%cReact Grab${version ? ` v${version}` : ""}%c
1098
1215
  https://react-grab.com`, `background: #330039; color: #ffffff; border: 1px solid #d75fcb; padding: 4px 4px 4px 24px; border-radius: 4px; background-image: url("${logoDataUri}"); background-size: 16px 16px; background-repeat: no-repeat; background-position: 4px center; display: inline-block; margin-bottom: 4px;`, "");
1099
- fetch("https://react-grab.com/api/version").then((res) => res.text()).catch(() => null);
1216
+ fetch("https://www.react-grab.com/api/version").then((res) => res.text()).catch(() => null);
1100
1217
  } catch {
1101
1218
  }
1102
1219
  };
@@ -1121,21 +1238,34 @@ https://react-grab.com`, `background: #330039; color: #ffffff; border: 1px solid
1121
1238
  const [copyStartX, setCopyStartX] = createSignal(OFFSCREEN_POSITION);
1122
1239
  const [copyStartY, setCopyStartY] = createSignal(OFFSCREEN_POSITION);
1123
1240
  const [mouseHasSettled, setMouseHasSettled] = createSignal(false);
1241
+ const [viewportVersion, setViewportVersion] = createSignal(0);
1242
+ const [isInputMode, setIsInputMode] = createSignal(false);
1243
+ const [inputText, setInputText] = createSignal("");
1124
1244
  let holdTimerId = null;
1125
1245
  let progressAnimationId = null;
1126
1246
  let progressDelayTimerId = null;
1127
1247
  let keydownSpamTimerId = null;
1128
1248
  let mouseSettleTimerId = null;
1249
+ let autoScrollAnimationId = null;
1129
1250
  const isRendererActive = createMemo(() => isActivated() && !isCopying());
1130
1251
  const hasValidMousePosition = createMemo(() => mouseX() > OFFSCREEN_POSITION && mouseY() > OFFSCREEN_POSITION);
1131
1252
  const isTargetKeyCombination = (event) => (event.metaKey || event.ctrlKey) && event.key.toLowerCase() === "c";
1132
- const showTemporaryGrabbedBox = (bounds) => {
1253
+ const getAutoScrollDirection = (clientX, clientY) => {
1254
+ return {
1255
+ top: clientY < AUTO_SCROLL_EDGE_THRESHOLD_PX,
1256
+ bottom: clientY > window.innerHeight - AUTO_SCROLL_EDGE_THRESHOLD_PX,
1257
+ left: clientX < AUTO_SCROLL_EDGE_THRESHOLD_PX,
1258
+ right: clientX > window.innerWidth - AUTO_SCROLL_EDGE_THRESHOLD_PX
1259
+ };
1260
+ };
1261
+ const showTemporaryGrabbedBox = (bounds, element) => {
1133
1262
  const boxId = `grabbed-${Date.now()}-${Math.random()}`;
1134
1263
  const createdAt = Date.now();
1135
1264
  const newBox = {
1136
1265
  id: boxId,
1137
1266
  bounds,
1138
- createdAt
1267
+ createdAt,
1268
+ element
1139
1269
  };
1140
1270
  const currentBoxes = grabbedBoxes();
1141
1271
  setGrabbedBoxes([...currentBoxes, newBox]);
@@ -1190,11 +1320,7 @@ ${context}
1190
1320
  setIsCopying(false);
1191
1321
  stopProgressAnimation();
1192
1322
  if (isToggleMode()) {
1193
- if (!isHoldingKeys()) {
1194
- deactivateRenderer();
1195
- } else {
1196
- setIsToggleMode(false);
1197
- }
1323
+ deactivateRenderer();
1198
1324
  }
1199
1325
  });
1200
1326
  };
@@ -1206,37 +1332,60 @@ ${context}
1206
1332
  return element.textContent ?? "";
1207
1333
  };
1208
1334
  const createCombinedTextContent = (elements) => elements.map((element) => extractElementTextContent(element).trim()).filter((textContent) => textContent.length > 0).join("\n\n");
1209
- const tryCopyWithFallback = async (elements) => {
1335
+ const tryCopyWithFallback = async (elements, extraPrompt) => {
1210
1336
  let didCopy = false;
1337
+ const isReactProject = isInstrumentationActive();
1211
1338
  try {
1212
- const elementSnippetResults = await Promise.allSettled(elements.map(async (element) => `## HTML Frame:
1213
- ${getHTMLPreview(element)}
1339
+ const elementSnippetResults = await Promise.allSettled(elements.map(async (element) => {
1340
+ const htmlPreview = getHTMLPreview(element);
1341
+ if (!isReactProject) {
1342
+ return `## HTML Frame:
1343
+ ${htmlPreview}`;
1344
+ }
1345
+ const stack = await getStack(element);
1346
+ const formattedStack = formatStack(stack);
1347
+ if (formattedStack) {
1348
+ return `## HTML Frame:
1349
+ ${htmlPreview}
1214
1350
 
1215
1351
  ## Code Location:
1216
- ${formatStack(await getStack(element))}`));
1352
+ ${formattedStack}`;
1353
+ }
1354
+ return `## HTML Frame:
1355
+ ${htmlPreview}`;
1356
+ }));
1217
1357
  const elementSnippets = elementSnippetResults.map((result) => result.status === "fulfilled" ? result.value : "").filter((snippet) => snippet.trim());
1218
1358
  if (elementSnippets.length > 0) {
1219
- const plainTextContent = elementSnippets.map((snippet) => wrapInSelectedElementTags(snippet)).join("\n\n");
1359
+ const wrappedSnippets = elementSnippets.map((snippet) => wrapInSelectedElementTags(snippet)).join("\n\n");
1360
+ const plainTextContent = extraPrompt ? `${extraPrompt}
1361
+
1362
+ ${wrappedSnippets}` : wrappedSnippets;
1220
1363
  didCopy = await copyContent(plainTextContent, options.playCopySound ? playCopySound : void 0);
1221
1364
  }
1222
1365
  if (!didCopy) {
1223
1366
  const plainTextContentOnly = createCombinedTextContent(elements);
1224
1367
  if (plainTextContentOnly.length > 0) {
1225
- didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
1368
+ const contentWithPrompt = extraPrompt ? `${extraPrompt}
1369
+
1370
+ ${plainTextContentOnly}` : plainTextContentOnly;
1371
+ didCopy = await copyContent(contentWithPrompt, options.playCopySound ? playCopySound : void 0);
1226
1372
  }
1227
1373
  }
1228
1374
  } catch {
1229
1375
  const plainTextContentOnly = createCombinedTextContent(elements);
1230
1376
  if (plainTextContentOnly.length > 0) {
1231
- didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
1377
+ const contentWithPrompt = extraPrompt ? `${extraPrompt}
1378
+
1379
+ ${plainTextContentOnly}` : plainTextContentOnly;
1380
+ didCopy = await copyContent(contentWithPrompt, options.playCopySound ? playCopySound : void 0);
1232
1381
  }
1233
1382
  }
1234
1383
  return didCopy;
1235
1384
  };
1236
- const copySingleElementToClipboard = async (targetElement2) => {
1237
- showTemporaryGrabbedBox(createElementBounds(targetElement2));
1385
+ const copySingleElementToClipboard = async (targetElement2, extraPrompt) => {
1386
+ showTemporaryGrabbedBox(createElementBounds(targetElement2), targetElement2);
1238
1387
  await new Promise((resolve) => requestAnimationFrame(resolve));
1239
- const didCopy = await tryCopyWithFallback([targetElement2]);
1388
+ const didCopy = await tryCopyWithFallback([targetElement2], extraPrompt);
1240
1389
  if (didCopy) {
1241
1390
  showTemporarySuccessLabel(extractElementLabelText(targetElement2));
1242
1391
  }
@@ -1245,7 +1394,7 @@ ${formatStack(await getStack(element))}`));
1245
1394
  const copyMultipleElementsToClipboard = async (targetElements) => {
1246
1395
  if (targetElements.length === 0) return;
1247
1396
  for (const element of targetElements) {
1248
- showTemporaryGrabbedBox(createElementBounds(element));
1397
+ showTemporaryGrabbedBox(createElementBounds(element), element);
1249
1398
  }
1250
1399
  await new Promise((resolve) => requestAnimationFrame(resolve));
1251
1400
  const didCopy = await tryCopyWithFallback(targetElements);
@@ -1259,6 +1408,7 @@ ${formatStack(await getStack(element))}`));
1259
1408
  return getElementAtPosition(mouseX(), mouseY());
1260
1409
  });
1261
1410
  const selectionBounds = createMemo(() => {
1411
+ viewportVersion();
1262
1412
  const element = targetElement();
1263
1413
  if (!element) return void 0;
1264
1414
  const elementBounds = element.getBoundingClientRect();
@@ -1272,23 +1422,29 @@ ${formatStack(await getStack(element))}`));
1272
1422
  y: elementBounds.top
1273
1423
  };
1274
1424
  });
1275
- const calculateDragDistance = (endX, endY) => ({
1276
- x: Math.abs(endX - dragStartX()),
1277
- y: Math.abs(endY - dragStartY())
1278
- });
1425
+ const calculateDragDistance = (endX, endY) => {
1426
+ const endPageX = endX + window.scrollX;
1427
+ const endPageY = endY + window.scrollY;
1428
+ return {
1429
+ x: Math.abs(endPageX - dragStartX()),
1430
+ y: Math.abs(endPageY - dragStartY())
1431
+ };
1432
+ };
1279
1433
  const isDraggingBeyondThreshold = createMemo(() => {
1280
1434
  if (!isDragging()) return false;
1281
1435
  const dragDistance = calculateDragDistance(mouseX(), mouseY());
1282
1436
  return dragDistance.x > DRAG_THRESHOLD_PX || dragDistance.y > DRAG_THRESHOLD_PX;
1283
1437
  });
1284
1438
  const calculateDragRectangle = (endX, endY) => {
1285
- const dragX = Math.min(dragStartX(), endX);
1286
- const dragY = Math.min(dragStartY(), endY);
1287
- const dragWidth = Math.abs(endX - dragStartX());
1288
- const dragHeight = Math.abs(endY - dragStartY());
1439
+ const endPageX = endX + window.scrollX;
1440
+ const endPageY = endY + window.scrollY;
1441
+ const dragPageX = Math.min(dragStartX(), endPageX);
1442
+ const dragPageY = Math.min(dragStartY(), endPageY);
1443
+ const dragWidth = Math.abs(endPageX - dragStartX());
1444
+ const dragHeight = Math.abs(endPageY - dragStartY());
1289
1445
  return {
1290
- x: dragX,
1291
- y: dragY,
1446
+ x: dragPageX - window.scrollX,
1447
+ y: dragPageY - window.scrollY,
1292
1448
  width: dragWidth,
1293
1449
  height: dragHeight
1294
1450
  };
@@ -1328,6 +1484,15 @@ ${formatStack(await getStack(element))}`));
1328
1484
  setLastGrabbedElement(null);
1329
1485
  }
1330
1486
  }));
1487
+ createEffect(on(() => viewportVersion(), () => {
1488
+ const currentBoxes = grabbedBoxes();
1489
+ if (currentBoxes.length === 0) return;
1490
+ const updatedBoxes = currentBoxes.map((box) => ({
1491
+ ...box,
1492
+ bounds: createElementBounds(box.element)
1493
+ }));
1494
+ setGrabbedBoxes(updatedBoxes);
1495
+ }));
1331
1496
  const startProgressAnimation = () => {
1332
1497
  const startTime = Date.now();
1333
1498
  setProgressStartTime(startTime);
@@ -1364,6 +1529,31 @@ ${formatStack(await getStack(element))}`));
1364
1529
  setProgress(1);
1365
1530
  setShowProgressIndicator(false);
1366
1531
  };
1532
+ const startAutoScroll = () => {
1533
+ const scroll = () => {
1534
+ if (!isDragging()) {
1535
+ stopAutoScroll();
1536
+ return;
1537
+ }
1538
+ const direction = getAutoScrollDirection(mouseX(), mouseY());
1539
+ if (direction.top) window.scrollBy(0, -AUTO_SCROLL_SPEED_PX);
1540
+ if (direction.bottom) window.scrollBy(0, AUTO_SCROLL_SPEED_PX);
1541
+ if (direction.left) window.scrollBy(-AUTO_SCROLL_SPEED_PX, 0);
1542
+ if (direction.right) window.scrollBy(AUTO_SCROLL_SPEED_PX, 0);
1543
+ if (direction.top || direction.bottom || direction.left || direction.right) {
1544
+ autoScrollAnimationId = requestAnimationFrame(scroll);
1545
+ } else {
1546
+ autoScrollAnimationId = null;
1547
+ }
1548
+ };
1549
+ scroll();
1550
+ };
1551
+ const stopAutoScroll = () => {
1552
+ if (autoScrollAnimationId !== null) {
1553
+ cancelAnimationFrame(autoScrollAnimationId);
1554
+ autoScrollAnimationId = null;
1555
+ }
1556
+ };
1367
1557
  const activateRenderer = () => {
1368
1558
  stopProgressAnimation();
1369
1559
  setIsActivated(true);
@@ -1374,6 +1564,8 @@ ${formatStack(await getStack(element))}`));
1374
1564
  setIsToggleMode(false);
1375
1565
  setIsHoldingKeys(false);
1376
1566
  setIsActivated(false);
1567
+ setIsInputMode(false);
1568
+ setInputText("");
1377
1569
  document.body.style.cursor = "";
1378
1570
  if (isDragging()) {
1379
1571
  setIsDragging(false);
@@ -1386,17 +1578,44 @@ ${formatStack(await getStack(element))}`));
1386
1578
  mouseSettleTimerId = null;
1387
1579
  }
1388
1580
  setMouseHasSettled(false);
1581
+ stopAutoScroll();
1389
1582
  stopProgressAnimation();
1390
1583
  options.onDeactivate?.();
1391
1584
  };
1585
+ const handleInputChange = (value) => {
1586
+ setInputText(value);
1587
+ };
1588
+ const handleInputSubmit = () => {
1589
+ if (!isInputMode()) return;
1590
+ const element = targetElement();
1591
+ const prompt = inputText().trim();
1592
+ const currentX = mouseX();
1593
+ const currentY = mouseY();
1594
+ setIsInputMode(false);
1595
+ setInputText("");
1596
+ if (element) {
1597
+ void executeCopyOperation(currentX, currentY, () => copySingleElementToClipboard(element, prompt || void 0)).then(() => {
1598
+ deactivateRenderer();
1599
+ });
1600
+ } else {
1601
+ deactivateRenderer();
1602
+ }
1603
+ };
1604
+ const handleInputCancel = () => {
1605
+ if (!isInputMode()) return;
1606
+ deactivateRenderer();
1607
+ };
1392
1608
  const abortController = new AbortController();
1393
1609
  const eventListenerSignal = abortController.signal;
1394
1610
  window.addEventListener("keydown", (event) => {
1395
1611
  if (event.key === "Escape" && isHoldingKeys()) {
1612
+ if (isInputMode()) {
1613
+ return;
1614
+ }
1396
1615
  deactivateRenderer();
1397
1616
  return;
1398
1617
  }
1399
- if (event.key === "Enter" && isHoldingKeys()) {
1618
+ if (event.key === "Enter" && isHoldingKeys() && !isInputMode()) {
1400
1619
  setIsToggleMode(true);
1401
1620
  if (keydownSpamTimerId !== null) {
1402
1621
  window.clearTimeout(keydownSpamTimerId);
@@ -1406,6 +1625,7 @@ ${formatStack(await getStack(element))}`));
1406
1625
  if (holdTimerId) window.clearTimeout(holdTimerId);
1407
1626
  activateRenderer();
1408
1627
  }
1628
+ setIsInputMode(true);
1409
1629
  return;
1410
1630
  }
1411
1631
  if (!options.allowActivationInsideInput && isKeyboardEventTriggeredByInput(event)) {
@@ -1459,15 +1679,32 @@ ${formatStack(await getStack(element))}`));
1459
1679
  setMouseHasSettled(true);
1460
1680
  mouseSettleTimerId = null;
1461
1681
  }, 300);
1682
+ if (isDragging()) {
1683
+ const direction = getAutoScrollDirection(event.clientX, event.clientY);
1684
+ const isNearEdge = direction.top || direction.bottom || direction.left || direction.right;
1685
+ if (isNearEdge && autoScrollAnimationId === null) {
1686
+ startAutoScroll();
1687
+ } else if (!isNearEdge && autoScrollAnimationId !== null) {
1688
+ stopAutoScroll();
1689
+ }
1690
+ }
1462
1691
  }, {
1463
1692
  signal: eventListenerSignal
1464
1693
  });
1465
1694
  window.addEventListener("mousedown", (event) => {
1695
+ if (isInputMode()) {
1696
+ const target = event.target;
1697
+ const isClickingInput = target.closest("[data-react-grab-input]");
1698
+ if (!isClickingInput) {
1699
+ handleInputCancel();
1700
+ }
1701
+ return;
1702
+ }
1466
1703
  if (!isRendererActive() || isCopying()) return;
1467
1704
  event.preventDefault();
1468
1705
  setIsDragging(true);
1469
- setDragStartX(event.clientX);
1470
- setDragStartY(event.clientY);
1706
+ setDragStartX(event.clientX + window.scrollX);
1707
+ setDragStartY(event.clientY + window.scrollY);
1471
1708
  document.body.style.userSelect = "none";
1472
1709
  }, {
1473
1710
  signal: eventListenerSignal
@@ -1477,6 +1714,7 @@ ${formatStack(await getStack(element))}`));
1477
1714
  const dragDistance = calculateDragDistance(event.clientX, event.clientY);
1478
1715
  const wasDragGesture = dragDistance.x > DRAG_THRESHOLD_PX || dragDistance.y > DRAG_THRESHOLD_PX;
1479
1716
  setIsDragging(false);
1717
+ stopAutoScroll();
1480
1718
  document.body.style.userSelect = "";
1481
1719
  if (wasDragGesture) {
1482
1720
  setDidJustDrag(true);
@@ -1526,11 +1764,23 @@ ${formatStack(await getStack(element))}`));
1526
1764
  }, {
1527
1765
  signal: eventListenerSignal
1528
1766
  });
1767
+ window.addEventListener("scroll", () => {
1768
+ setViewportVersion((version) => version + 1);
1769
+ }, {
1770
+ signal: eventListenerSignal,
1771
+ capture: true
1772
+ });
1773
+ window.addEventListener("resize", () => {
1774
+ setViewportVersion((version) => version + 1);
1775
+ }, {
1776
+ signal: eventListenerSignal
1777
+ });
1529
1778
  onCleanup(() => {
1530
1779
  abortController.abort();
1531
1780
  if (holdTimerId) window.clearTimeout(holdTimerId);
1532
1781
  if (keydownSpamTimerId) window.clearTimeout(keydownSpamTimerId);
1533
1782
  if (mouseSettleTimerId) window.clearTimeout(mouseSettleTimerId);
1783
+ stopAutoScroll();
1534
1784
  stopProgressAnimation();
1535
1785
  document.body.style.userSelect = "";
1536
1786
  document.body.style.cursor = "";
@@ -1540,12 +1790,14 @@ ${formatStack(await getStack(element))}`));
1540
1790
  const dragVisible = createMemo(() => isRendererActive() && isDraggingBeyondThreshold());
1541
1791
  const labelVariant = createMemo(() => isCopying() ? "processing" : "hover");
1542
1792
  const labelVisible = createMemo(() => {
1793
+ if (isInputMode()) return false;
1543
1794
  if (isCopying()) return true;
1544
1795
  if (successLabels().length > 0) return false;
1545
1796
  return isRendererActive() && !isDragging() && Boolean(targetElement());
1546
1797
  });
1547
1798
  const progressVisible = createMemo(() => isCopying() && showProgressIndicator() && hasValidMousePosition());
1548
1799
  const crosshairVisible = createMemo(() => isRendererActive() && !isDragging());
1800
+ const inputVisible = createMemo(() => isInputMode());
1549
1801
  render(() => createComponent(ReactGrabRenderer, {
1550
1802
  get selectionVisible() {
1551
1803
  return selectionVisible();
@@ -1598,7 +1850,22 @@ ${formatStack(await getStack(element))}`));
1598
1850
  },
1599
1851
  get crosshairVisible() {
1600
1852
  return crosshairVisible();
1601
- }
1853
+ },
1854
+ get inputVisible() {
1855
+ return inputVisible();
1856
+ },
1857
+ get inputX() {
1858
+ return mouseX();
1859
+ },
1860
+ get inputY() {
1861
+ return mouseY();
1862
+ },
1863
+ get inputValue() {
1864
+ return inputText();
1865
+ },
1866
+ onInputChange: handleInputChange,
1867
+ onInputSubmit: handleInputSubmit,
1868
+ onInputCancel: handleInputCancel
1602
1869
  }), rendererRoot);
1603
1870
  return {
1604
1871
  activate: () => {