react-grab 0.0.36 → 0.0.38
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 +264 -80
- package/dist/index.d.cts +15 -1
- package/dist/index.d.ts +15 -1
- package/dist/index.global.js +20 -16
- package/dist/index.js +264 -81
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -258,9 +258,10 @@ var getClampedElementPosition = (positionLeft, positionTop, elementWidth, elemen
|
|
|
258
258
|
// src/components/label.tsx
|
|
259
259
|
var _tmpl$3 = /* @__PURE__ */ template(`<span style=display:inline-block;margin-right:4px;font-weight:600>\u2713`);
|
|
260
260
|
var _tmpl$22 = /* @__PURE__ */ template(`<div style=margin-right:4px>Copied`);
|
|
261
|
-
var _tmpl$32 = /* @__PURE__ */ template(`<span style="font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;font-variant-numeric:tabular-nums">`);
|
|
262
|
-
var _tmpl$4 = /* @__PURE__ */ template(`<
|
|
263
|
-
var _tmpl$5 = /* @__PURE__ */ template(`<div style=
|
|
261
|
+
var _tmpl$32 = /* @__PURE__ */ template(`<span style="font-family:ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, 'Liberation Mono', 'Courier New', monospace;font-variant-numeric:tabular-nums;vertical-align:middle">`);
|
|
262
|
+
var _tmpl$4 = /* @__PURE__ */ template(`<span style=font-variant-numeric:tabular-nums;font-size:10px;margin-left:4px;vertical-align:middle>`);
|
|
263
|
+
var _tmpl$5 = /* @__PURE__ */ template(`<div style=margin-left:4px>to clipboard`);
|
|
264
|
+
var _tmpl$6 = /* @__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">`);
|
|
264
265
|
var Label = (props) => {
|
|
265
266
|
const [opacity, setOpacity] = createSignal(0);
|
|
266
267
|
const [positionTick, setPositionTick] = createSignal(0);
|
|
@@ -358,12 +359,26 @@ var Label = (props) => {
|
|
|
358
359
|
fallback.top += INDICATOR_CLAMP_PADDING_PX;
|
|
359
360
|
return fallback;
|
|
360
361
|
};
|
|
362
|
+
const labelSegments = () => {
|
|
363
|
+
const separator = " in ";
|
|
364
|
+
const separatorIndex = props.text.indexOf(separator);
|
|
365
|
+
if (separatorIndex === -1) {
|
|
366
|
+
return {
|
|
367
|
+
primary: props.text,
|
|
368
|
+
secondary: ""
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
return {
|
|
372
|
+
primary: props.text.slice(0, separatorIndex),
|
|
373
|
+
secondary: props.text.slice(separatorIndex)
|
|
374
|
+
};
|
|
375
|
+
};
|
|
361
376
|
return createComponent(Show, {
|
|
362
377
|
get when() {
|
|
363
378
|
return props.visible !== false;
|
|
364
379
|
},
|
|
365
380
|
get children() {
|
|
366
|
-
var _el$ = _tmpl$
|
|
381
|
+
var _el$ = _tmpl$6();
|
|
367
382
|
var _ref$ = labelRef;
|
|
368
383
|
typeof _ref$ === "function" ? use(_ref$, _el$) : labelRef = _el$;
|
|
369
384
|
insert(_el$, createComponent(Show, {
|
|
@@ -401,9 +416,20 @@ var Label = (props) => {
|
|
|
401
416
|
return props.variant !== "processing";
|
|
402
417
|
},
|
|
403
418
|
get children() {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
419
|
+
return [(() => {
|
|
420
|
+
var _el$4 = _tmpl$32();
|
|
421
|
+
insert(_el$4, () => labelSegments().primary);
|
|
422
|
+
return _el$4;
|
|
423
|
+
})(), createComponent(Show, {
|
|
424
|
+
get when() {
|
|
425
|
+
return memo(() => props.variant === "hover")() && labelSegments().secondary !== "";
|
|
426
|
+
},
|
|
427
|
+
get children() {
|
|
428
|
+
var _el$5 = _tmpl$4();
|
|
429
|
+
insert(_el$5, () => labelSegments().secondary);
|
|
430
|
+
return _el$5;
|
|
431
|
+
}
|
|
432
|
+
})];
|
|
407
433
|
}
|
|
408
434
|
}), null);
|
|
409
435
|
insert(_el$, createComponent(Show, {
|
|
@@ -411,7 +437,7 @@ var Label = (props) => {
|
|
|
411
437
|
return props.variant === "success";
|
|
412
438
|
},
|
|
413
439
|
get children() {
|
|
414
|
-
return _tmpl$
|
|
440
|
+
return _tmpl$5();
|
|
415
441
|
}
|
|
416
442
|
}), null);
|
|
417
443
|
effect((_p$) => {
|
|
@@ -431,7 +457,7 @@ var Label = (props) => {
|
|
|
431
457
|
}
|
|
432
458
|
});
|
|
433
459
|
};
|
|
434
|
-
var _tmpl$
|
|
460
|
+
var _tmpl$7 = /* @__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)">`);
|
|
435
461
|
var useFadeInOut = (visible) => {
|
|
436
462
|
const [opacity, setOpacity] = createSignal(0);
|
|
437
463
|
createEffect(on(() => visible, (isVisible) => {
|
|
@@ -464,7 +490,7 @@ var ProgressIndicator = (props) => {
|
|
|
464
490
|
return props.visible !== false;
|
|
465
491
|
},
|
|
466
492
|
get children() {
|
|
467
|
-
var _el$ = _tmpl$
|
|
493
|
+
var _el$ = _tmpl$7(), _el$2 = _el$.firstChild, _el$3 = _el$2.firstChild;
|
|
468
494
|
var _ref$ = progressIndicatorRef;
|
|
469
495
|
typeof _ref$ === "function" ? use(_ref$, _el$) : progressIndicatorRef = _el$;
|
|
470
496
|
effect((_p$) => {
|
|
@@ -484,7 +510,7 @@ var ProgressIndicator = (props) => {
|
|
|
484
510
|
}
|
|
485
511
|
});
|
|
486
512
|
};
|
|
487
|
-
var _tmpl$
|
|
513
|
+
var _tmpl$8 = /* @__PURE__ */ template(`<canvas style=position:fixed;top:0;left:0;pointer-events:none;z-index:2147483645>`);
|
|
488
514
|
var Crosshair = (props) => {
|
|
489
515
|
let canvasRef;
|
|
490
516
|
let context = null;
|
|
@@ -574,7 +600,7 @@ var Crosshair = (props) => {
|
|
|
574
600
|
return props.visible !== false;
|
|
575
601
|
},
|
|
576
602
|
get children() {
|
|
577
|
-
var _el$ = _tmpl$
|
|
603
|
+
var _el$ = _tmpl$8();
|
|
578
604
|
var _ref$ = canvasRef;
|
|
579
605
|
typeof _ref$ === "function" ? use(_ref$, _el$) : canvasRef = _el$;
|
|
580
606
|
return _el$;
|
|
@@ -706,6 +732,11 @@ var ReactGrabRenderer = (props) => {
|
|
|
706
732
|
}
|
|
707
733
|
})];
|
|
708
734
|
};
|
|
735
|
+
|
|
736
|
+
// src/utils/is-capitalized.ts
|
|
737
|
+
var isCapitalized = (value) => value.length > 0 && /^[A-Z]/.test(value);
|
|
738
|
+
|
|
739
|
+
// src/instrumentation.ts
|
|
709
740
|
instrument({
|
|
710
741
|
onCommitFiberRoot(_, fiberRoot) {
|
|
711
742
|
_fiberRoots.add(fiberRoot);
|
|
@@ -714,40 +745,36 @@ instrument({
|
|
|
714
745
|
var generateCSSSelector = (element) => {
|
|
715
746
|
return finder(element);
|
|
716
747
|
};
|
|
717
|
-
var
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
if (isCompositeFiber(currentFiber)) {
|
|
732
|
-
const displayName = getDisplayName(currentFiber);
|
|
733
|
-
if (displayName && !isInternalComponent(displayName)) {
|
|
734
|
-
componentName = displayName;
|
|
735
|
-
return true;
|
|
736
|
-
}
|
|
748
|
+
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");
|
|
750
|
+
var getNearestComponentDisplayName = (element) => {
|
|
751
|
+
const fiber = getFiberFromHostInstance(element);
|
|
752
|
+
if (!fiber) return null;
|
|
753
|
+
let componentName = null;
|
|
754
|
+
traverseFiber(
|
|
755
|
+
fiber,
|
|
756
|
+
(currentFiber) => {
|
|
757
|
+
if (isCompositeFiber(currentFiber)) {
|
|
758
|
+
const displayName = getDisplayName(currentFiber);
|
|
759
|
+
if (displayName && !isInternalComponent(displayName)) {
|
|
760
|
+
componentName = displayName;
|
|
761
|
+
return true;
|
|
737
762
|
}
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
}
|
|
763
|
+
}
|
|
764
|
+
return false;
|
|
765
|
+
},
|
|
766
|
+
true
|
|
767
|
+
);
|
|
768
|
+
return componentName;
|
|
769
|
+
};
|
|
770
|
+
var formatComponentSourceLocation = async (el) => {
|
|
771
|
+
const source = await getSourceFromHostInstance(el);
|
|
772
|
+
if (!source) return null;
|
|
773
|
+
const fileName = normalizeFileName(source.fileName);
|
|
774
|
+
if (!isSourceFile(fileName)) return null;
|
|
775
|
+
return `${fileName}:${source.lineNumber}:${source.columnNumber}`;
|
|
776
|
+
};
|
|
777
|
+
var getHTMLSnippet = async (element) => {
|
|
751
778
|
const semanticTags = /* @__PURE__ */ new Set([
|
|
752
779
|
"article",
|
|
753
780
|
"aside",
|
|
@@ -836,9 +863,9 @@ var getHTMLSnippet = async (element) => {
|
|
|
836
863
|
lines.push("```html");
|
|
837
864
|
const ancestors = collectDistinguishingAncestors(element);
|
|
838
865
|
const ancestorComponents = ancestors.map(
|
|
839
|
-
(ancestor) =>
|
|
866
|
+
(ancestor) => getNearestComponentDisplayName(ancestor)
|
|
840
867
|
);
|
|
841
|
-
const elementComponent =
|
|
868
|
+
const elementComponent = getNearestComponentDisplayName(element);
|
|
842
869
|
const ancestorSources = await Promise.all(
|
|
843
870
|
ancestors.map((ancestor) => formatComponentSourceLocation(ancestor))
|
|
844
871
|
);
|
|
@@ -946,17 +973,18 @@ var waitForFocus = () => {
|
|
|
946
973
|
window.focus();
|
|
947
974
|
});
|
|
948
975
|
};
|
|
949
|
-
var copyContent = async (content) => {
|
|
976
|
+
var copyContent = async (content, onSuccess) => {
|
|
950
977
|
await waitForFocus();
|
|
951
978
|
try {
|
|
952
979
|
if (Array.isArray(content)) {
|
|
953
980
|
if (!navigator?.clipboard?.write) {
|
|
954
981
|
for (const contentPart of content) {
|
|
955
982
|
if (typeof contentPart === "string") {
|
|
956
|
-
const result = copyContentFallback(contentPart);
|
|
983
|
+
const result = copyContentFallback(contentPart, onSuccess);
|
|
957
984
|
if (!result) return result;
|
|
958
985
|
}
|
|
959
986
|
}
|
|
987
|
+
onSuccess?.();
|
|
960
988
|
return true;
|
|
961
989
|
}
|
|
962
990
|
const mimeTypeMap = /* @__PURE__ */ new Map();
|
|
@@ -975,28 +1003,52 @@ var copyContent = async (content) => {
|
|
|
975
1003
|
}
|
|
976
1004
|
}
|
|
977
1005
|
}
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
1006
|
+
if (mimeTypeMap.size === 0) {
|
|
1007
|
+
const plainTextFallback = content.find(
|
|
1008
|
+
(contentPart) => typeof contentPart === "string"
|
|
1009
|
+
);
|
|
1010
|
+
if (typeof plainTextFallback === "string") {
|
|
1011
|
+
return copyContentFallback(plainTextFallback, onSuccess);
|
|
1012
|
+
}
|
|
1013
|
+
return false;
|
|
1014
|
+
}
|
|
1015
|
+
try {
|
|
1016
|
+
await navigator.clipboard.write([
|
|
1017
|
+
new ClipboardItem(Object.fromEntries(mimeTypeMap))
|
|
1018
|
+
]);
|
|
1019
|
+
onSuccess?.();
|
|
1020
|
+
return true;
|
|
1021
|
+
} catch {
|
|
1022
|
+
const plainTextParts = content.filter(
|
|
1023
|
+
(contentPart) => typeof contentPart === "string"
|
|
1024
|
+
);
|
|
1025
|
+
if (plainTextParts.length > 0) {
|
|
1026
|
+
const combinedText = plainTextParts.join("\n\n");
|
|
1027
|
+
return copyContentFallback(combinedText, onSuccess);
|
|
1028
|
+
}
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
982
1031
|
} else if (content instanceof Blob) {
|
|
983
1032
|
await navigator.clipboard.write([
|
|
984
1033
|
new ClipboardItem({ [content.type]: content })
|
|
985
1034
|
]);
|
|
1035
|
+
onSuccess?.();
|
|
986
1036
|
return true;
|
|
987
1037
|
} else {
|
|
988
1038
|
try {
|
|
989
1039
|
await navigator.clipboard.writeText(String(content));
|
|
1040
|
+
onSuccess?.();
|
|
990
1041
|
return true;
|
|
991
1042
|
} catch {
|
|
992
|
-
|
|
1043
|
+
const result = copyContentFallback(content, onSuccess);
|
|
1044
|
+
return result;
|
|
993
1045
|
}
|
|
994
1046
|
}
|
|
995
1047
|
} catch {
|
|
996
1048
|
return false;
|
|
997
1049
|
}
|
|
998
1050
|
};
|
|
999
|
-
var copyContentFallback = (content) => {
|
|
1051
|
+
var copyContentFallback = (content, onSuccess) => {
|
|
1000
1052
|
if (!document.execCommand) return false;
|
|
1001
1053
|
const el = document.createElement("textarea");
|
|
1002
1054
|
el.value = String(content);
|
|
@@ -1006,12 +1058,46 @@ var copyContentFallback = (content) => {
|
|
|
1006
1058
|
doc.append(el);
|
|
1007
1059
|
try {
|
|
1008
1060
|
el.select();
|
|
1009
|
-
|
|
1061
|
+
const result = document.execCommand("copy");
|
|
1062
|
+
if (result) onSuccess?.();
|
|
1063
|
+
return result;
|
|
1010
1064
|
} finally {
|
|
1011
1065
|
el.remove();
|
|
1012
1066
|
}
|
|
1013
1067
|
};
|
|
1014
1068
|
|
|
1069
|
+
// src/utils/play-copy-sound.ts
|
|
1070
|
+
var playCopySound = () => {
|
|
1071
|
+
try {
|
|
1072
|
+
const audioContext = new (window.AudioContext || // eslint-disable-next-line @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-member-access -- window.webkitAudioContext is not typed
|
|
1073
|
+
window.webkitAudioContext)();
|
|
1074
|
+
const masterGain = audioContext.createGain();
|
|
1075
|
+
masterGain.connect(audioContext.destination);
|
|
1076
|
+
const notes = [
|
|
1077
|
+
{ freq: 523.25, start: 0, duration: 0.1 },
|
|
1078
|
+
{ freq: 659.25, start: 0.05, duration: 0.1 },
|
|
1079
|
+
{ freq: 783.99, start: 0.1, duration: 0.15 }
|
|
1080
|
+
];
|
|
1081
|
+
notes.forEach((note) => {
|
|
1082
|
+
const oscillator = audioContext.createOscillator();
|
|
1083
|
+
const gainNode = audioContext.createGain();
|
|
1084
|
+
oscillator.connect(gainNode);
|
|
1085
|
+
gainNode.connect(masterGain);
|
|
1086
|
+
oscillator.frequency.value = note.freq;
|
|
1087
|
+
oscillator.type = "triangle";
|
|
1088
|
+
const startTime = audioContext.currentTime + note.start;
|
|
1089
|
+
const peakTime = startTime + 0.01;
|
|
1090
|
+
const endTime = startTime + note.duration;
|
|
1091
|
+
gainNode.gain.setValueAtTime(0, startTime);
|
|
1092
|
+
gainNode.gain.linearRampToValueAtTime(0.15, peakTime);
|
|
1093
|
+
gainNode.gain.exponentialRampToValueAtTime(0.01, endTime);
|
|
1094
|
+
oscillator.start(startTime);
|
|
1095
|
+
oscillator.stop(endTime);
|
|
1096
|
+
});
|
|
1097
|
+
} catch {
|
|
1098
|
+
}
|
|
1099
|
+
};
|
|
1100
|
+
|
|
1015
1101
|
// src/utils/is-element-visible.ts
|
|
1016
1102
|
var isElementVisible = (element, computedStyle = window.getComputedStyle(element)) => {
|
|
1017
1103
|
return computedStyle.display !== "none" && computedStyle.visibility !== "hidden" && computedStyle.opacity !== "0";
|
|
@@ -1119,6 +1205,12 @@ var createElementBounds = (element) => {
|
|
|
1119
1205
|
};
|
|
1120
1206
|
};
|
|
1121
1207
|
|
|
1208
|
+
// src/utils/is-localhost.ts
|
|
1209
|
+
var isLocalhost = () => {
|
|
1210
|
+
const hostname = window.location.hostname;
|
|
1211
|
+
return hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
1212
|
+
};
|
|
1213
|
+
|
|
1122
1214
|
// src/core.tsx
|
|
1123
1215
|
var PROGRESS_INDICATOR_DELAY_MS = 150;
|
|
1124
1216
|
var init = (rawOptions) => {
|
|
@@ -1126,6 +1218,7 @@ var init = (rawOptions) => {
|
|
|
1126
1218
|
enabled: true,
|
|
1127
1219
|
keyHoldDuration: 300,
|
|
1128
1220
|
allowActivationInsideInput: true,
|
|
1221
|
+
playCopySound: false,
|
|
1129
1222
|
...rawOptions
|
|
1130
1223
|
};
|
|
1131
1224
|
if (options.enabled === false) {
|
|
@@ -1222,13 +1315,41 @@ ${context}
|
|
|
1222
1315
|
computedStyles: element.computedStyles
|
|
1223
1316
|
}))
|
|
1224
1317
|
};
|
|
1225
|
-
const
|
|
1318
|
+
const jsonString = JSON.stringify(structuredData);
|
|
1319
|
+
const base64Data = btoa(encodeURIComponent(jsonString).replace(/%([0-9A-F]{2})/g, (_match, p1) => String.fromCharCode(parseInt(p1, 16))));
|
|
1226
1320
|
const htmlContent = `<div data-react-grab="${base64Data}"></div>`;
|
|
1227
1321
|
return new Blob([htmlContent], {
|
|
1228
1322
|
type: "text/html"
|
|
1229
1323
|
});
|
|
1230
1324
|
};
|
|
1231
1325
|
const extractElementTagName = (element) => (element.tagName || "").toLowerCase();
|
|
1326
|
+
const extractNearestComponentName = (element) => {
|
|
1327
|
+
const fiber = getFiberFromHostInstance(element);
|
|
1328
|
+
if (!fiber) return null;
|
|
1329
|
+
let componentName = null;
|
|
1330
|
+
traverseFiber(fiber, (currentFiber) => {
|
|
1331
|
+
if (isCompositeFiber(currentFiber)) {
|
|
1332
|
+
const displayName = getDisplayName(currentFiber);
|
|
1333
|
+
if (displayName && isCapitalized(displayName) && !displayName.startsWith("_")) {
|
|
1334
|
+
componentName = displayName;
|
|
1335
|
+
return true;
|
|
1336
|
+
}
|
|
1337
|
+
}
|
|
1338
|
+
return false;
|
|
1339
|
+
}, true);
|
|
1340
|
+
return componentName;
|
|
1341
|
+
};
|
|
1342
|
+
const extractElementLabelText = (element) => {
|
|
1343
|
+
const tagName = extractElementTagName(element);
|
|
1344
|
+
const componentName = extractNearestComponentName(element);
|
|
1345
|
+
if (tagName && componentName) {
|
|
1346
|
+
return `<${tagName}> in ${componentName}`;
|
|
1347
|
+
}
|
|
1348
|
+
if (tagName) {
|
|
1349
|
+
return `<${tagName}>`;
|
|
1350
|
+
}
|
|
1351
|
+
return "<element>";
|
|
1352
|
+
};
|
|
1232
1353
|
const notifyElementsSelected = (elements) => {
|
|
1233
1354
|
try {
|
|
1234
1355
|
const elementsPayload = elements.map((element) => ({
|
|
@@ -1242,6 +1363,8 @@ ${context}
|
|
|
1242
1363
|
} catch {
|
|
1243
1364
|
}
|
|
1244
1365
|
};
|
|
1366
|
+
const isExtensionEnvironment = () => window.__REACT_GRAB_EXTENSION_ACTIVE__ === true || options.isExtension === true;
|
|
1367
|
+
const isExtensionTextOnlyMode = () => isExtensionEnvironment() && !isLocalhost();
|
|
1245
1368
|
const executeCopyOperation = async (positionX, positionY, operation) => {
|
|
1246
1369
|
setCopyStartX(positionX);
|
|
1247
1370
|
setCopyStartY(positionY);
|
|
@@ -1252,22 +1375,49 @@ ${context}
|
|
|
1252
1375
|
stopProgressAnimation();
|
|
1253
1376
|
});
|
|
1254
1377
|
};
|
|
1378
|
+
const hasInnerText = (element) => "innerText" in element;
|
|
1379
|
+
const extractElementTextContent = (element) => {
|
|
1380
|
+
if (hasInnerText(element)) {
|
|
1381
|
+
return element.innerText;
|
|
1382
|
+
}
|
|
1383
|
+
return element.textContent ?? "";
|
|
1384
|
+
};
|
|
1385
|
+
const createCombinedTextContent = (elements) => elements.map((element) => extractElementTextContent(element).trim()).filter((textContent) => textContent.length > 0).join("\n\n");
|
|
1255
1386
|
const copySingleElementToClipboard = async (targetElement2) => {
|
|
1256
|
-
const tagName = extractElementTagName(targetElement2);
|
|
1257
1387
|
showTemporaryGrabbedBox(createElementBounds(targetElement2));
|
|
1258
1388
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1389
|
+
let didCopy = false;
|
|
1259
1390
|
try {
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1391
|
+
if (isExtensionTextOnlyMode()) {
|
|
1392
|
+
const plainTextContent = createCombinedTextContent([targetElement2]);
|
|
1393
|
+
if (plainTextContent.length > 0) {
|
|
1394
|
+
didCopy = await copyContent(plainTextContent, options.playCopySound ? playCopySound : void 0);
|
|
1395
|
+
}
|
|
1396
|
+
} else {
|
|
1397
|
+
const content = await getHTMLSnippet(targetElement2);
|
|
1398
|
+
const plainTextContent = wrapInSelectedElementTags(content);
|
|
1399
|
+
const htmlContent = createStructuredClipboardHtmlBlob([{
|
|
1400
|
+
tagName: extractElementTagName(targetElement2),
|
|
1401
|
+
content,
|
|
1402
|
+
computedStyles: extractRelevantComputedStyles(targetElement2)
|
|
1403
|
+
}]);
|
|
1404
|
+
didCopy = await copyContent([plainTextContent, htmlContent], options.playCopySound ? playCopySound : void 0);
|
|
1405
|
+
if (!didCopy) {
|
|
1406
|
+
const plainTextContentOnly = createCombinedTextContent([targetElement2]);
|
|
1407
|
+
if (plainTextContentOnly.length > 0) {
|
|
1408
|
+
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
}
|
|
1268
1412
|
} catch {
|
|
1413
|
+
const plainTextContentOnly = createCombinedTextContent([targetElement2]);
|
|
1414
|
+
if (plainTextContentOnly.length > 0) {
|
|
1415
|
+
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
if (didCopy) {
|
|
1419
|
+
showTemporarySuccessLabel(extractElementLabelText(targetElement2), copyStartX(), copyStartY());
|
|
1269
1420
|
}
|
|
1270
|
-
showTemporarySuccessLabel(tagName ? `<${tagName}>` : "<element>", copyStartX(), copyStartY());
|
|
1271
1421
|
notifyElementsSelected([targetElement2]);
|
|
1272
1422
|
};
|
|
1273
1423
|
const copyMultipleElementsToClipboard = async (targetElements) => {
|
|
@@ -1276,19 +1426,43 @@ ${context}
|
|
|
1276
1426
|
showTemporaryGrabbedBox(createElementBounds(element));
|
|
1277
1427
|
}
|
|
1278
1428
|
await new Promise((resolve) => requestAnimationFrame(resolve));
|
|
1429
|
+
let didCopy = false;
|
|
1279
1430
|
try {
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1431
|
+
if (isExtensionTextOnlyMode()) {
|
|
1432
|
+
const plainTextContent = createCombinedTextContent(targetElements);
|
|
1433
|
+
if (plainTextContent.length > 0) {
|
|
1434
|
+
didCopy = await copyContent(plainTextContent, options.playCopySound ? playCopySound : void 0);
|
|
1435
|
+
}
|
|
1436
|
+
} else {
|
|
1437
|
+
const elementSnippetResults = await Promise.allSettled(targetElements.map((element) => getHTMLSnippet(element)));
|
|
1438
|
+
const elementSnippets = elementSnippetResults.map((result) => result.status === "fulfilled" ? result.value : "").filter((snippet) => snippet.trim());
|
|
1439
|
+
if (elementSnippets.length > 0) {
|
|
1440
|
+
const plainTextContent = elementSnippets.map((snippet) => wrapInSelectedElementTags(snippet)).join("\n\n");
|
|
1441
|
+
const structuredElements = elementSnippets.map((content, elementIndex) => ({
|
|
1442
|
+
tagName: extractElementTagName(targetElements[elementIndex]),
|
|
1443
|
+
content,
|
|
1444
|
+
computedStyles: extractRelevantComputedStyles(targetElements[elementIndex])
|
|
1445
|
+
}));
|
|
1446
|
+
const htmlContent = createStructuredClipboardHtmlBlob(structuredElements);
|
|
1447
|
+
didCopy = await copyContent([plainTextContent, htmlContent], options.playCopySound ? playCopySound : void 0);
|
|
1448
|
+
if (!didCopy) {
|
|
1449
|
+
const plainTextContentOnly = createCombinedTextContent(targetElements);
|
|
1450
|
+
if (plainTextContentOnly.length > 0) {
|
|
1451
|
+
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1452
|
+
}
|
|
1453
|
+
}
|
|
1454
|
+
} else {
|
|
1455
|
+
const plainTextContentOnly = createCombinedTextContent(targetElements);
|
|
1456
|
+
if (plainTextContentOnly.length > 0) {
|
|
1457
|
+
didCopy = await copyContent(plainTextContentOnly, options.playCopySound ? playCopySound : void 0);
|
|
1458
|
+
}
|
|
1459
|
+
}
|
|
1460
|
+
}
|
|
1289
1461
|
} catch {
|
|
1290
1462
|
}
|
|
1291
|
-
|
|
1463
|
+
if (didCopy) {
|
|
1464
|
+
showTemporarySuccessLabel(`${targetElements.length} elements`, copyStartX(), copyStartY());
|
|
1465
|
+
}
|
|
1292
1466
|
notifyElementsSelected(targetElements);
|
|
1293
1467
|
};
|
|
1294
1468
|
const targetElement = createMemo(() => {
|
|
@@ -1345,7 +1519,7 @@ ${context}
|
|
|
1345
1519
|
});
|
|
1346
1520
|
const labelText = createMemo(() => {
|
|
1347
1521
|
const element = targetElement();
|
|
1348
|
-
return element ?
|
|
1522
|
+
return element ? extractElementLabelText(element) : "<element>";
|
|
1349
1523
|
});
|
|
1350
1524
|
const labelPosition = createMemo(() => isCopying() ? {
|
|
1351
1525
|
x: copyStartX(),
|
|
@@ -1372,7 +1546,13 @@ ${context}
|
|
|
1372
1546
|
progressTick();
|
|
1373
1547
|
if (startTime === null) return 0;
|
|
1374
1548
|
const elapsedTime = Date.now() - startTime;
|
|
1375
|
-
|
|
1549
|
+
const normalizedTime = elapsedTime / options.keyHoldDuration;
|
|
1550
|
+
const easedProgress = 1 - Math.exp(-normalizedTime);
|
|
1551
|
+
const maxProgressBeforeCompletion = 0.95;
|
|
1552
|
+
if (isCopying()) {
|
|
1553
|
+
return Math.min(easedProgress, maxProgressBeforeCompletion);
|
|
1554
|
+
}
|
|
1555
|
+
return 1;
|
|
1376
1556
|
});
|
|
1377
1557
|
const startProgressAnimation = () => {
|
|
1378
1558
|
setProgressStartTime(Date.now());
|
|
@@ -1657,6 +1837,9 @@ ${context}
|
|
|
1657
1837
|
// src/index.ts
|
|
1658
1838
|
var globalApi = null;
|
|
1659
1839
|
var getGlobalApi = () => globalApi;
|
|
1660
|
-
|
|
1840
|
+
var EXTENSION_MARKER = "__REACT_GRAB_EXTENSION_ACTIVE__";
|
|
1841
|
+
if (!window[EXTENSION_MARKER]) {
|
|
1842
|
+
globalApi = init();
|
|
1843
|
+
}
|
|
1661
1844
|
|
|
1662
|
-
export { getGlobalApi, init };
|
|
1845
|
+
export { getGlobalApi, init, playCopySound };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-grab",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.38",
|
|
4
4
|
"description": "",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"react",
|
|
@@ -69,7 +69,8 @@
|
|
|
69
69
|
"@medv/finder": "^4.0.2",
|
|
70
70
|
"bippy": "^0.5.14",
|
|
71
71
|
"modern-screenshot": "^4.6.6",
|
|
72
|
-
"solid-js": "^1.9.10"
|
|
72
|
+
"solid-js": "^1.9.10",
|
|
73
|
+
"solid-sonner": "^0.2.8"
|
|
73
74
|
},
|
|
74
75
|
"scripts": {
|
|
75
76
|
"build": "NODE_ENV=production tsup",
|