react-grab 0.0.38 → 0.0.40
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 +194 -55
- package/dist/index.d.cts +4 -3
- package/dist/index.d.ts +4 -3
- package/dist/index.global.js +80 -18
- package/dist/index.js +189 -56
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -3,6 +3,7 @@ import { createRoot, createSignal, createMemo, createEffect, on, onCleanup, Show
|
|
|
3
3
|
import { instrument, _fiberRoots, getFiberFromHostInstance, traverseFiber, isCompositeFiber, getDisplayName } from 'bippy';
|
|
4
4
|
import { getSourceFromHostInstance, normalizeFileName, isSourceFile } from 'bippy/dist/source';
|
|
5
5
|
import { finder } from '@medv/finder';
|
|
6
|
+
import TurndownService from 'turndown';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* @license MIT
|
|
@@ -176,7 +177,7 @@ var SelectionBox = (props) => {
|
|
|
176
177
|
position: "fixed",
|
|
177
178
|
"box-sizing": "border-box",
|
|
178
179
|
"pointer-events": props.variant === "drag" ? "none" : "auto",
|
|
179
|
-
"z-index": "2147483646"
|
|
180
|
+
"z-index": props.variant === "grabbed" ? "2147483645" : "2147483646"
|
|
180
181
|
};
|
|
181
182
|
const variantStyle = () => {
|
|
182
183
|
if (props.variant === "drag") {
|
|
@@ -188,10 +189,16 @@ var SelectionBox = (props) => {
|
|
|
188
189
|
cursor: "crosshair"
|
|
189
190
|
};
|
|
190
191
|
}
|
|
192
|
+
if (props.variant === "selection") {
|
|
193
|
+
return {
|
|
194
|
+
border: "1px dashed rgba(210, 57, 192, 0.5)",
|
|
195
|
+
"background-color": "rgba(210, 57, 192, 0.08)"
|
|
196
|
+
};
|
|
197
|
+
}
|
|
191
198
|
return {
|
|
192
199
|
border: "1px solid rgb(210, 57, 192)",
|
|
193
|
-
"background-color": "rgba(210, 57, 192, 0.
|
|
194
|
-
transition:
|
|
200
|
+
"background-color": "rgba(210, 57, 192, 0.08)",
|
|
201
|
+
transition: "opacity 0.3s ease-out"
|
|
195
202
|
};
|
|
196
203
|
};
|
|
197
204
|
return createComponent(Show, {
|
|
@@ -678,10 +685,10 @@ var ReactGrabRenderer = (props) => {
|
|
|
678
685
|
return label.text;
|
|
679
686
|
},
|
|
680
687
|
get x() {
|
|
681
|
-
return
|
|
688
|
+
return props.mouseX ?? 0;
|
|
682
689
|
},
|
|
683
690
|
get y() {
|
|
684
|
-
return
|
|
691
|
+
return props.mouseY ?? 0;
|
|
685
692
|
}
|
|
686
693
|
})
|
|
687
694
|
}), createComponent(Show, {
|
|
@@ -746,7 +753,7 @@ var generateCSSSelector = (element) => {
|
|
|
746
753
|
return finder(element);
|
|
747
754
|
};
|
|
748
755
|
var truncateString = (string, maxLength) => string.length > maxLength ? `${string.substring(0, maxLength)}...` : string;
|
|
749
|
-
var isInternalComponent = (name) => !isCapitalized(name) || name.startsWith("_") || name.includes("Provider") && name.includes("Context");
|
|
756
|
+
var isInternalComponent = (name) => !isCapitalized(name) || name.startsWith("_") || name.startsWith("Primitive.") || name.includes("Provider") && name.includes("Context");
|
|
750
757
|
var getNearestComponentDisplayName = (element) => {
|
|
751
758
|
const fiber = getFiberFromHostInstance(element);
|
|
752
759
|
if (!fiber) return null;
|
|
@@ -771,8 +778,16 @@ var formatComponentSourceLocation = async (el) => {
|
|
|
771
778
|
const source = await getSourceFromHostInstance(el);
|
|
772
779
|
if (!source) return null;
|
|
773
780
|
const fileName = normalizeFileName(source.fileName);
|
|
774
|
-
if (
|
|
775
|
-
|
|
781
|
+
if (isSourceFile(fileName)) {
|
|
782
|
+
return `${fileName}:${source.lineNumber}:${source.columnNumber}`;
|
|
783
|
+
}
|
|
784
|
+
if (fileName && (fileName.includes(".tsx") || fileName.includes(".ts") || fileName.includes(".jsx") || fileName.includes(".js"))) {
|
|
785
|
+
const cleanedFileName = fileName.replace(/^webpack:\/\/_N_E\//, "").replace(/^webpack:\/\/\//, "").replace(/^webpack:\/\//, "").replace(/^\.\//, "");
|
|
786
|
+
if (cleanedFileName && !cleanedFileName.startsWith("node_modules") && !cleanedFileName.includes(".next") && !cleanedFileName.startsWith("webpack")) {
|
|
787
|
+
return `${cleanedFileName}:${source.lineNumber}:${source.columnNumber}`;
|
|
788
|
+
}
|
|
789
|
+
}
|
|
790
|
+
return null;
|
|
776
791
|
};
|
|
777
792
|
var getHTMLSnippet = async (element) => {
|
|
778
793
|
const semanticTags = /* @__PURE__ */ new Set([
|
|
@@ -870,14 +885,26 @@ var getHTMLSnippet = async (element) => {
|
|
|
870
885
|
ancestors.map((ancestor) => formatComponentSourceLocation(ancestor))
|
|
871
886
|
);
|
|
872
887
|
const elementSource = await formatComponentSourceLocation(element);
|
|
888
|
+
const ancestorElementIndents = [];
|
|
889
|
+
const ancestorComponentIndents = [];
|
|
890
|
+
let currentIndentLevel = 0;
|
|
891
|
+
const getIndent = (level) => " ".repeat(level);
|
|
873
892
|
for (let i = 0; i < ancestors.length; i++) {
|
|
874
|
-
const indent2 = " ".repeat(i);
|
|
875
893
|
const componentName = ancestorComponents[i];
|
|
876
894
|
const source = ancestorSources[i];
|
|
877
|
-
|
|
878
|
-
|
|
895
|
+
const isNewComponent = componentName && source && (i === 0 || ancestorComponents[i - 1] !== componentName);
|
|
896
|
+
if (isNewComponent) {
|
|
897
|
+
ancestorComponentIndents[i] = currentIndentLevel;
|
|
898
|
+
lines.push(
|
|
899
|
+
`${getIndent(currentIndentLevel)}<${componentName} used-at="${source}">`
|
|
900
|
+
);
|
|
901
|
+
currentIndentLevel++;
|
|
879
902
|
}
|
|
880
|
-
|
|
903
|
+
ancestorElementIndents[i] = currentIndentLevel;
|
|
904
|
+
lines.push(
|
|
905
|
+
`${getIndent(currentIndentLevel)}${formatElementOpeningTag(ancestors[i], true)}`
|
|
906
|
+
);
|
|
907
|
+
currentIndentLevel++;
|
|
881
908
|
}
|
|
882
909
|
const parent = element.parentElement;
|
|
883
910
|
let targetIndex = -1;
|
|
@@ -885,30 +912,37 @@ var getHTMLSnippet = async (element) => {
|
|
|
885
912
|
const siblings = Array.from(parent.children);
|
|
886
913
|
targetIndex = siblings.indexOf(element);
|
|
887
914
|
if (targetIndex > 0) {
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
915
|
+
const indent = getIndent(currentIndentLevel);
|
|
916
|
+
if (targetIndex <= 2) {
|
|
917
|
+
for (let i = 0; i < targetIndex; i++) {
|
|
918
|
+
const sibling = siblings[i];
|
|
919
|
+
const siblingId = extractSiblingIdentifier(sibling);
|
|
920
|
+
if (siblingId) {
|
|
921
|
+
lines.push(`${indent}${formatElementOpeningTag(sibling, true)}`);
|
|
922
|
+
lines.push(`${indent}</${sibling.tagName.toLowerCase()}>`);
|
|
923
|
+
}
|
|
924
|
+
}
|
|
925
|
+
} else {
|
|
896
926
|
lines.push(
|
|
897
|
-
`${
|
|
927
|
+
`${indent}... (${targetIndex} element${targetIndex === 1 ? "" : "s"})`
|
|
898
928
|
);
|
|
899
929
|
}
|
|
900
930
|
}
|
|
901
931
|
}
|
|
902
|
-
const indent = " ".repeat(ancestors.length);
|
|
903
932
|
const lastAncestorComponent = ancestors.length > 0 ? ancestorComponents[ancestorComponents.length - 1] : null;
|
|
904
933
|
const showElementComponent = elementComponent && elementSource && elementComponent !== lastAncestorComponent;
|
|
934
|
+
let elementIndentLevel = currentIndentLevel;
|
|
935
|
+
const elementComponentIndentLevel = currentIndentLevel;
|
|
905
936
|
if (showElementComponent) {
|
|
906
|
-
lines.push(
|
|
937
|
+
lines.push(
|
|
938
|
+
`${getIndent(elementIndentLevel)}<${elementComponent} used-at="${elementSource}">`
|
|
939
|
+
);
|
|
940
|
+
elementIndentLevel++;
|
|
907
941
|
}
|
|
908
|
-
|
|
942
|
+
const elementIndent = getIndent(elementIndentLevel);
|
|
943
|
+
lines.push(`${elementIndent}<!-- IMPORTANT: selected element -->`);
|
|
909
944
|
const textContent = extractTruncatedTextContent(element);
|
|
910
945
|
const childrenCount = element.children.length;
|
|
911
|
-
const elementIndent = `${indent}${showElementComponent ? " " : " "}`;
|
|
912
946
|
if (textContent && childrenCount === 0 && textContent.length < 40) {
|
|
913
947
|
lines.push(
|
|
914
948
|
`${elementIndent}${formatElementOpeningTag(element)}${textContent}${formatElementClosingTag(
|
|
@@ -928,31 +962,37 @@ var getHTMLSnippet = async (element) => {
|
|
|
928
962
|
lines.push(`${elementIndent}${formatElementClosingTag(element)}`);
|
|
929
963
|
}
|
|
930
964
|
if (showElementComponent) {
|
|
931
|
-
lines.push(
|
|
965
|
+
lines.push(
|
|
966
|
+
`${getIndent(elementComponentIndentLevel)}</${elementComponent}>`
|
|
967
|
+
);
|
|
932
968
|
}
|
|
933
969
|
if (parent && targetIndex >= 0) {
|
|
934
970
|
const siblings = Array.from(parent.children);
|
|
935
971
|
const siblingsAfter = siblings.length - targetIndex - 1;
|
|
936
972
|
if (siblingsAfter > 0) {
|
|
937
|
-
const
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
973
|
+
const indent = getIndent(currentIndentLevel);
|
|
974
|
+
if (siblingsAfter <= 2) {
|
|
975
|
+
for (let i = targetIndex + 1; i < siblings.length; i++) {
|
|
976
|
+
const sibling = siblings[i];
|
|
977
|
+
const siblingId = extractSiblingIdentifier(sibling);
|
|
978
|
+
if (siblingId) {
|
|
979
|
+
lines.push(`${indent}${formatElementOpeningTag(sibling, true)}`);
|
|
980
|
+
lines.push(`${indent}</${sibling.tagName.toLowerCase()}>`);
|
|
981
|
+
}
|
|
982
|
+
}
|
|
942
983
|
} else {
|
|
943
984
|
lines.push(
|
|
944
|
-
`${indent}
|
|
985
|
+
`${indent}... (${siblingsAfter} element${siblingsAfter === 1 ? "" : "s"})`
|
|
945
986
|
);
|
|
946
987
|
}
|
|
947
988
|
}
|
|
948
989
|
}
|
|
949
990
|
for (let i = ancestors.length - 1; i >= 0; i--) {
|
|
950
|
-
const
|
|
951
|
-
lines.push(`${
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
lines.push(`${indent2}</${componentName}>`);
|
|
991
|
+
const elementIndent2 = getIndent(ancestorElementIndents[i]);
|
|
992
|
+
lines.push(`${elementIndent2}${formatElementClosingTag(ancestors[i])}`);
|
|
993
|
+
if (ancestorComponentIndents[i] !== void 0) {
|
|
994
|
+
const compIndent = getIndent(ancestorComponentIndents[i]);
|
|
995
|
+
lines.push(`${compIndent}</${ancestorComponents[i]}>`);
|
|
956
996
|
}
|
|
957
997
|
}
|
|
958
998
|
lines.push("```");
|
|
@@ -1210,6 +1250,62 @@ var isLocalhost = () => {
|
|
|
1210
1250
|
const hostname = window.location.hostname;
|
|
1211
1251
|
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
1212
1252
|
};
|
|
1253
|
+
var turndownService = null;
|
|
1254
|
+
var getTurndownService = () => {
|
|
1255
|
+
if (!turndownService) {
|
|
1256
|
+
turndownService = new TurndownService({
|
|
1257
|
+
headingStyle: "atx",
|
|
1258
|
+
codeBlockStyle: "fenced",
|
|
1259
|
+
emDelimiter: "_",
|
|
1260
|
+
bulletListMarker: "-",
|
|
1261
|
+
linkStyle: "inlined",
|
|
1262
|
+
linkReferenceStyle: "full"
|
|
1263
|
+
});
|
|
1264
|
+
turndownService.addRule("strikethrough", {
|
|
1265
|
+
filter: ["del", "s"],
|
|
1266
|
+
replacement: (content) => `~~${content}~~`
|
|
1267
|
+
});
|
|
1268
|
+
turndownService.addRule("removeHidden", {
|
|
1269
|
+
filter: (node) => {
|
|
1270
|
+
if (node instanceof HTMLElement) {
|
|
1271
|
+
const style = window.getComputedStyle(node);
|
|
1272
|
+
return style.display === "none" || style.visibility === "hidden" || style.opacity === "0";
|
|
1273
|
+
}
|
|
1274
|
+
return false;
|
|
1275
|
+
},
|
|
1276
|
+
replacement: () => ""
|
|
1277
|
+
});
|
|
1278
|
+
turndownService.addRule("preserveButtons", {
|
|
1279
|
+
filter: ["button"],
|
|
1280
|
+
replacement: (content) => content ? `[${content}]` : ""
|
|
1281
|
+
});
|
|
1282
|
+
turndownService.addRule("preserveInputs", {
|
|
1283
|
+
filter: (node) => {
|
|
1284
|
+
if (node.nodeName === "INPUT" && node instanceof HTMLInputElement) {
|
|
1285
|
+
return true;
|
|
1286
|
+
}
|
|
1287
|
+
return false;
|
|
1288
|
+
},
|
|
1289
|
+
replacement: (_, node) => {
|
|
1290
|
+
if (node instanceof HTMLInputElement) {
|
|
1291
|
+
const value = node.value || node.placeholder;
|
|
1292
|
+
return value ? `[${value}]` : "";
|
|
1293
|
+
}
|
|
1294
|
+
return "";
|
|
1295
|
+
}
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
return turndownService;
|
|
1299
|
+
};
|
|
1300
|
+
var htmlToMarkdown = (html) => {
|
|
1301
|
+
const service = getTurndownService();
|
|
1302
|
+
return service.turndown(html).trim();
|
|
1303
|
+
};
|
|
1304
|
+
var elementToMarkdown = (element) => {
|
|
1305
|
+
const clonedElement = element.cloneNode(true);
|
|
1306
|
+
const service = getTurndownService();
|
|
1307
|
+
return service.turndown(clonedElement).trim();
|
|
1308
|
+
};
|
|
1213
1309
|
|
|
1214
1310
|
// src/core.tsx
|
|
1215
1311
|
var PROGRESS_INDICATOR_DELAY_MS = 150;
|
|
@@ -1249,6 +1345,7 @@ var init = (rawOptions) => {
|
|
|
1249
1345
|
const [grabbedBoxes, setGrabbedBoxes] = createSignal([]);
|
|
1250
1346
|
const [successLabels, setSuccessLabels] = createSignal([]);
|
|
1251
1347
|
const [isActivated, setIsActivated] = createSignal(false);
|
|
1348
|
+
const [isToggleMode, setIsToggleMode] = createSignal(false);
|
|
1252
1349
|
const [showProgressIndicator, setShowProgressIndicator] = createSignal(false);
|
|
1253
1350
|
const [didJustDrag, setDidJustDrag] = createSignal(false);
|
|
1254
1351
|
const [copyStartX, setCopyStartX] = createSignal(OFFSCREEN_POSITION);
|
|
@@ -1278,13 +1375,11 @@ var init = (rawOptions) => {
|
|
|
1278
1375
|
setGrabbedBoxes((previousBoxes) => previousBoxes.filter((box) => box.id !== boxId));
|
|
1279
1376
|
}, SUCCESS_LABEL_DURATION_MS);
|
|
1280
1377
|
};
|
|
1281
|
-
const showTemporarySuccessLabel = (text
|
|
1378
|
+
const showTemporarySuccessLabel = (text) => {
|
|
1282
1379
|
const labelId = `success-${Date.now()}-${Math.random()}`;
|
|
1283
1380
|
setSuccessLabels((previousLabels) => [...previousLabels, {
|
|
1284
1381
|
id: labelId,
|
|
1285
|
-
text
|
|
1286
|
-
x: positionX,
|
|
1287
|
-
y: positionY
|
|
1382
|
+
text
|
|
1288
1383
|
}]);
|
|
1289
1384
|
setTimeout(() => {
|
|
1290
1385
|
setSuccessLabels((previousLabels) => previousLabels.filter((label) => label.id !== labelId));
|
|
@@ -1330,7 +1425,7 @@ ${context}
|
|
|
1330
1425
|
traverseFiber(fiber, (currentFiber) => {
|
|
1331
1426
|
if (isCompositeFiber(currentFiber)) {
|
|
1332
1427
|
const displayName = getDisplayName(currentFiber);
|
|
1333
|
-
if (displayName && isCapitalized(displayName) && !displayName.startsWith("_")) {
|
|
1428
|
+
if (displayName && isCapitalized(displayName) && !displayName.startsWith("_") && !displayName.startsWith("Primitive.")) {
|
|
1334
1429
|
componentName = displayName;
|
|
1335
1430
|
return true;
|
|
1336
1431
|
}
|
|
@@ -1373,6 +1468,13 @@ ${context}
|
|
|
1373
1468
|
await operation().finally(() => {
|
|
1374
1469
|
setIsCopying(false);
|
|
1375
1470
|
stopProgressAnimation();
|
|
1471
|
+
if (isToggleMode()) {
|
|
1472
|
+
if (!isHoldingKeys()) {
|
|
1473
|
+
deactivateRenderer();
|
|
1474
|
+
} else {
|
|
1475
|
+
setIsToggleMode(false);
|
|
1476
|
+
}
|
|
1477
|
+
}
|
|
1376
1478
|
});
|
|
1377
1479
|
};
|
|
1378
1480
|
const hasInnerText = (element) => "innerText" in element;
|
|
@@ -1383,15 +1485,16 @@ ${context}
|
|
|
1383
1485
|
return element.textContent ?? "";
|
|
1384
1486
|
};
|
|
1385
1487
|
const createCombinedTextContent = (elements) => elements.map((element) => extractElementTextContent(element).trim()).filter((textContent) => textContent.length > 0).join("\n\n");
|
|
1488
|
+
const createCombinedMarkdownContent = (elements) => elements.map((element) => elementToMarkdown(element).trim()).filter((markdownContent) => markdownContent.length > 0).join("\n\n");
|
|
1386
1489
|
const copySingleElementToClipboard = async (targetElement2) => {
|
|
1387
1490
|
showTemporaryGrabbedBox(createElementBounds(targetElement2));
|
|
1388
1491
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1389
1492
|
let didCopy = false;
|
|
1390
1493
|
try {
|
|
1391
1494
|
if (isExtensionTextOnlyMode()) {
|
|
1392
|
-
const
|
|
1393
|
-
if (
|
|
1394
|
-
didCopy = await copyContent(
|
|
1495
|
+
const markdownContent = createCombinedMarkdownContent([targetElement2]);
|
|
1496
|
+
if (markdownContent.length > 0) {
|
|
1497
|
+
didCopy = await copyContent(markdownContent, options.playCopySound ? playCopySound : void 0);
|
|
1395
1498
|
}
|
|
1396
1499
|
} else {
|
|
1397
1500
|
const content = await getHTMLSnippet(targetElement2);
|
|
@@ -1416,7 +1519,7 @@ ${context}
|
|
|
1416
1519
|
}
|
|
1417
1520
|
}
|
|
1418
1521
|
if (didCopy) {
|
|
1419
|
-
showTemporarySuccessLabel(extractElementLabelText(targetElement2)
|
|
1522
|
+
showTemporarySuccessLabel(extractElementLabelText(targetElement2));
|
|
1420
1523
|
}
|
|
1421
1524
|
notifyElementsSelected([targetElement2]);
|
|
1422
1525
|
};
|
|
@@ -1429,9 +1532,9 @@ ${context}
|
|
|
1429
1532
|
let didCopy = false;
|
|
1430
1533
|
try {
|
|
1431
1534
|
if (isExtensionTextOnlyMode()) {
|
|
1432
|
-
const
|
|
1433
|
-
if (
|
|
1434
|
-
didCopy = await copyContent(
|
|
1535
|
+
const markdownContent = createCombinedMarkdownContent(targetElements);
|
|
1536
|
+
if (markdownContent.length > 0) {
|
|
1537
|
+
didCopy = await copyContent(markdownContent, options.playCopySound ? playCopySound : void 0);
|
|
1435
1538
|
}
|
|
1436
1539
|
} else {
|
|
1437
1540
|
const elementSnippetResults = await Promise.allSettled(targetElements.map((element) => getHTMLSnippet(element)));
|
|
@@ -1461,7 +1564,7 @@ ${context}
|
|
|
1461
1564
|
} catch {
|
|
1462
1565
|
}
|
|
1463
1566
|
if (didCopy) {
|
|
1464
|
-
showTemporarySuccessLabel(`${targetElements.length} elements
|
|
1567
|
+
showTemporarySuccessLabel(`${targetElements.length} elements`);
|
|
1465
1568
|
}
|
|
1466
1569
|
notifyElementsSelected(targetElements);
|
|
1467
1570
|
};
|
|
@@ -1589,6 +1692,7 @@ ${context}
|
|
|
1589
1692
|
document.body.style.cursor = "crosshair";
|
|
1590
1693
|
};
|
|
1591
1694
|
const deactivateRenderer = () => {
|
|
1695
|
+
setIsToggleMode(false);
|
|
1592
1696
|
setIsHoldingKeys(false);
|
|
1593
1697
|
setIsActivated(false);
|
|
1594
1698
|
document.body.style.cursor = "";
|
|
@@ -1614,11 +1718,25 @@ ${context}
|
|
|
1614
1718
|
deactivateRenderer();
|
|
1615
1719
|
return;
|
|
1616
1720
|
}
|
|
1721
|
+
if (event.key === "Enter" && isHoldingKeys()) {
|
|
1722
|
+
setIsToggleMode(true);
|
|
1723
|
+
if (keydownSpamTimerId !== null) {
|
|
1724
|
+
window.clearTimeout(keydownSpamTimerId);
|
|
1725
|
+
keydownSpamTimerId = null;
|
|
1726
|
+
}
|
|
1727
|
+
if (!isActivated()) {
|
|
1728
|
+
if (holdTimerId) window.clearTimeout(holdTimerId);
|
|
1729
|
+
activateRenderer();
|
|
1730
|
+
options.onActivate?.();
|
|
1731
|
+
}
|
|
1732
|
+
return;
|
|
1733
|
+
}
|
|
1617
1734
|
if (!options.allowActivationInsideInput && isKeyboardEventTriggeredByInput(event)) {
|
|
1618
1735
|
return;
|
|
1619
1736
|
}
|
|
1620
1737
|
if (!isTargetKeyCombination(event)) return;
|
|
1621
1738
|
if (isActivated()) {
|
|
1739
|
+
if (isToggleMode()) return;
|
|
1622
1740
|
if (keydownSpamTimerId !== null) {
|
|
1623
1741
|
window.clearTimeout(keydownSpamTimerId);
|
|
1624
1742
|
}
|
|
@@ -1639,13 +1757,15 @@ ${context}
|
|
|
1639
1757
|
options.onActivate?.();
|
|
1640
1758
|
}, options.keyHoldDuration);
|
|
1641
1759
|
}, {
|
|
1642
|
-
signal: eventListenerSignal
|
|
1760
|
+
signal: eventListenerSignal,
|
|
1761
|
+
capture: true
|
|
1643
1762
|
});
|
|
1644
1763
|
window.addEventListener("keyup", (event) => {
|
|
1645
1764
|
if (!isHoldingKeys() && !isActivated()) return;
|
|
1646
1765
|
const isReleasingModifier = !event.metaKey && !event.ctrlKey;
|
|
1647
1766
|
const isReleasingC = event.key.toLowerCase() === "c";
|
|
1648
1767
|
if (isReleasingC || isReleasingModifier) {
|
|
1768
|
+
if (isToggleMode()) return;
|
|
1649
1769
|
deactivateRenderer();
|
|
1650
1770
|
}
|
|
1651
1771
|
}, {
|
|
@@ -1727,9 +1847,17 @@ ${context}
|
|
|
1727
1847
|
if (isRendererActive() || isCopying() || didJustDrag()) {
|
|
1728
1848
|
event.preventDefault();
|
|
1729
1849
|
event.stopPropagation();
|
|
1730
|
-
|
|
1850
|
+
const hadDrag = didJustDrag();
|
|
1851
|
+
if (hadDrag) {
|
|
1731
1852
|
setDidJustDrag(false);
|
|
1732
1853
|
}
|
|
1854
|
+
if (isToggleMode() && !isCopying()) {
|
|
1855
|
+
if (!isHoldingKeys()) {
|
|
1856
|
+
deactivateRenderer();
|
|
1857
|
+
} else {
|
|
1858
|
+
setIsToggleMode(false);
|
|
1859
|
+
}
|
|
1860
|
+
}
|
|
1733
1861
|
}
|
|
1734
1862
|
}, {
|
|
1735
1863
|
signal: eventListenerSignal,
|
|
@@ -1752,10 +1880,14 @@ ${context}
|
|
|
1752
1880
|
document.body.style.cursor = "";
|
|
1753
1881
|
});
|
|
1754
1882
|
const rendererRoot = mountRoot();
|
|
1755
|
-
const selectionVisible = createMemo(() =>
|
|
1883
|
+
const selectionVisible = createMemo(() => isRendererActive() && !isDragging() && Boolean(targetElement()));
|
|
1756
1884
|
const dragVisible = createMemo(() => isRendererActive() && isDraggingBeyondThreshold());
|
|
1757
1885
|
const labelVariant = createMemo(() => isCopying() ? "processing" : "hover");
|
|
1758
|
-
const labelVisible = createMemo(() =>
|
|
1886
|
+
const labelVisible = createMemo(() => {
|
|
1887
|
+
if (isCopying()) return true;
|
|
1888
|
+
if (successLabels().length > 0) return false;
|
|
1889
|
+
return isRendererActive() && !isDragging() && mouseHasSettled() && (Boolean(targetElement()) && !isSameAsLast() || !targetElement());
|
|
1890
|
+
});
|
|
1759
1891
|
const progressVisible = createMemo(() => isCopying() && showProgressIndicator() && hasValidMousePosition());
|
|
1760
1892
|
const crosshairVisible = createMemo(() => isRendererActive() && !isDragging());
|
|
1761
1893
|
render(() => createComponent(ReactGrabRenderer, {
|
|
@@ -1792,6 +1924,7 @@ ${context}
|
|
|
1792
1924
|
get labelVisible() {
|
|
1793
1925
|
return labelVisible();
|
|
1794
1926
|
},
|
|
1927
|
+
labelZIndex: 2147483646,
|
|
1795
1928
|
get progressVisible() {
|
|
1796
1929
|
return progressVisible();
|
|
1797
1930
|
},
|
|
@@ -1842,4 +1975,4 @@ if (!window[EXTENSION_MARKER]) {
|
|
|
1842
1975
|
globalApi = init();
|
|
1843
1976
|
}
|
|
1844
1977
|
|
|
1845
|
-
export { getGlobalApi, init, playCopySound };
|
|
1978
|
+
export { elementToMarkdown, getGlobalApi, htmlToMarkdown, init, playCopySound };
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-grab",
|
|
3
|
-
"version": "0.0.
|
|
4
|
-
"description": "",
|
|
3
|
+
"version": "0.0.40",
|
|
4
|
+
"description": "Grab any element in your app and give it to Cursor, Claude Code, or other AI coding agents.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
7
7
|
"grab",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"devDependencies": {
|
|
55
55
|
"@babel/core": "^7.28.5",
|
|
56
56
|
"@babel/preset-typescript": "^7.28.5",
|
|
57
|
+
"@types/turndown": "^5.0.6",
|
|
57
58
|
"babel-preset-solid": "^1.9.10",
|
|
58
59
|
"esbuild-plugin-babel": "^0.2.3",
|
|
59
60
|
"eslint": "^9.37.0",
|
|
@@ -70,7 +71,8 @@
|
|
|
70
71
|
"bippy": "^0.5.14",
|
|
71
72
|
"modern-screenshot": "^4.6.6",
|
|
72
73
|
"solid-js": "^1.9.10",
|
|
73
|
-
"solid-sonner": "^0.2.8"
|
|
74
|
+
"solid-sonner": "^0.2.8",
|
|
75
|
+
"turndown": "^7.2.2"
|
|
74
76
|
},
|
|
75
77
|
"scripts": {
|
|
76
78
|
"build": "NODE_ENV=production tsup",
|