react-grep 0.1.2 → 0.2.1
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/README.md +19 -0
- package/dist/index.global.js +3 -3
- package/dist/index.js +44 -17
- package/package.json +4 -10
- package/dist/index.cjs +0 -607
- package/dist/index.d.cts +0 -4
package/README.md
CHANGED
|
@@ -41,6 +41,25 @@ destroy(); // stop and clean up
|
|
|
41
41
|
|
|
42
42
|
The inspector starts automatically when the script loads.
|
|
43
43
|
|
|
44
|
+
## Compatibility
|
|
45
|
+
|
|
46
|
+
react-grep works with any React app that uses `react-dom` in development mode. It reads React's internal fiber tree, so no framework-specific plugin is needed.
|
|
47
|
+
|
|
48
|
+
| Framework / Bundler | Status |
|
|
49
|
+
| --------------------------------- | ---------------------- |
|
|
50
|
+
| Vite + React | Tested |
|
|
51
|
+
| Next.js 15 (Turbopack) | Tested |
|
|
52
|
+
| Next.js (Webpack) | Untested — should work |
|
|
53
|
+
| Create React App | Untested — should work |
|
|
54
|
+
| Remix | Untested — should work |
|
|
55
|
+
| Gatsby | Untested — should work |
|
|
56
|
+
| Custom Webpack / Rollup / esbuild | Untested — should work |
|
|
57
|
+
| React Native | Not supported (no DOM) |
|
|
58
|
+
|
|
59
|
+
Next.js has dedicated support for server component names and Turbopack indexed source maps.
|
|
60
|
+
|
|
61
|
+
Source map resolution is automatic — if your dev server serves source maps (inline or external), react-grep will resolve bundled locations back to original files.
|
|
62
|
+
|
|
44
63
|
## How it works
|
|
45
64
|
|
|
46
65
|
react-grep reads React's internal fiber tree to find component names and source locations (`_debugSource` / `_debugStack`). This data is only available in **development builds** of React — production builds strip it out.
|
package/dist/index.global.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var ReactGrep=(function(exports){'use strict';var
|
|
2
|
-
`)){let i=
|
|
3
|
-
exports.destroy=
|
|
1
|
+
var ReactGrep=(function(exports){'use strict';var d=typeof navigator<"u"&&/mac/i.test(navigator.userAgentData?.platform??navigator.userAgent);var g=new Map,M="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",R=[];for(let e=0;e<M.length;e++)R[M.charCodeAt(e)]=e;var f=(e,t)=>{let n=0,i=0;for(;t.i<e.length;){let o=R[e.charCodeAt(t.i++)];if(i+=(o&31)<<n,!(o&32))return i&1?-(i>>1):i>>1;n+=5;}return 0},D=e=>{let t=[],n=0,i=0,o=0;for(let r of e.split(";")){let s=[],a=0;if(r){let l={i:0};for(;l.i<r.length;){if(r.charCodeAt(l.i)===44){l.i++;continue}a+=f(r,l),!(l.i>=r.length||r.charCodeAt(l.i)===44)&&(n+=f(r,l),i+=f(r,l),o+=f(r,l),l.i<r.length&&r.charCodeAt(l.i)!==44&&f(r,l),s.push([a,n,i,o]));}}t.push(s);}return t},U=/^data:application\/json[^,]*;base64,([A-Za-z0-9+/=]+)$/,j=(e,t)=>{try{return new URL(e).origin===new URL(t).origin}catch{return false}},I=async(e,t)=>{if(e.startsWith("data:")){let o=U.exec(e);return o?atob(o[1]):null}let n=new URL(e,t).href;if(!j(t,n))return null;let i=await fetch(n);return i.ok?i.text():null},K=e=>{let t=[],n=[];for(let i of e){let o=D(i.map.mappings),r=i.offset.line,s=i.offset.column,a=t.length;for(;n.length<r+o.length;)n.push([]);for(let l=0;l<o.length;l++){let h=n[r+l];for(let p of o[l])h.push([l===0?p[0]+s:p[0],p[1]+a,p[2],p[3]]);}t.push(...i.map.sources);}for(let i of n)i.length>1&&i.sort((o,r)=>o[0]-r[0]);return {sources:t,mappings:n}},b=e=>{try{let t=JSON.parse(e);return Array.isArray(t.sections)?K(t.sections):!t.sources||!t.mappings?null:{sources:t.sources,mappings:D(t.mappings)}}catch{return null}},G=async e=>{try{let t=await fetch(e),i=(await t.text()).match(/\/\/[#@]\s*sourceMappingURL=([^\s]+)$/m);if(i){let s=await I(i[1].trim(),e);if(s){let a=b(s);if(a)return a}}let o=t.headers.get("SourceMap")??t.headers.get("X-SourceMap");if(o){let s=await I(o.trim(),e);if(s){let a=b(s);if(a)return a}}let r=await fetch(`${e}.map`);if(r.ok){let s=await r.text();return b(s)}return null}catch{return null}},A=/^about:\/\/React\/Server\/file:\/\/\//,W=/[/\\](\.next[/\\].+?)(?:\?.*)?$/,X=async e=>{try{let t=decodeURIComponent(e.replace(A,"")),n=W.exec(t);if(!n)return null;let o=`${typeof location<"u"?location.origin:""}/__nextjs_source-map?filename=${encodeURIComponent(n[1])}`,r=await fetch(o);if(!r.ok)return null;let s=await r.text();return s?b(s):null}catch{return null}},z=e=>{let t=g.get(e);if(!t){if(g.size>=100){let n=g.keys().next().value;g.delete(n);}t=A.test(e)?X(e):G(e),g.set(e,t);}return t},V=(e,t,n)=>{if(t<0||t>=e.mappings.length)return null;let i=e.mappings[t];if(!i.length)return null;let o=0,r=i.length-1;for(;o<r;){let s=o+r+1>>1;i[s][0]<=n?o=s:r=s-1;}return i[o]},F=async(e,t,n)=>{let i=await z(e);if(!i)return null;let o=V(i,t-1,n-1);if(!o)return null;let r=i.sources[o[1]];return r.startsWith("file:///")&&(r=decodeURIComponent(new URL(r).pathname)),{fileName:r,lineNumber:o[2]+1,columnNumber:o[3]+1}};var y=e=>"env"in e&&typeof e.name=="string",x=new Set([0,1,11,14,15]),Y=e=>{try{let t=Object.keys(e).find(n=>n.startsWith("__reactFiber$"));return t?e[t]:null}catch{return null}},B=e=>{let t=e;for(;t;){if(x.has(t.tag))return t;t=t.return;}return null},J=e=>{if(typeof e=="function")return e;if(e&&typeof e=="object"){if("render"in e&&typeof e.render=="function")return e.render;if("type"in e&&typeof e.type=="function")return e.type}return null},C=e=>{let{type:t}=e;if(typeof t=="function")return t.displayName||t.name||"Anonymous";if(t&&typeof t=="object"){if("displayName"in t&&t.displayName)return t.displayName;let n=J(t);if(n)return n.displayName||n.name||"Anonymous"}return "Anonymous"},Z=new Set(["jsxDEV","jsxs","jsx","react-stack-top-frame","react_stack_bottom_frame","fakeJSXCallSite"]),Q=/at (?:(\S+) )?\(?(.+):(\d+):(\d+)\)?$/,T=e=>{let t=e._debugStack?.stack;if(!t)return null;for(let n of t.split(`
|
|
2
|
+
`)){let i=Q.exec(n.trim());if(!i)continue;let[,o,r,s,a]=i;if(!(o&&Z.has(o))&&!r.includes("/node_modules/"))return {url:r,line:Number(s),column:Number(a)}}return null},k=async e=>{let t=await F(e.url,e.line,e.column);if(t)return t;let n=e.url;try{let i=new URL(e.url);n=decodeURIComponent(i.pathname);let o=n.indexOf("?");o!==-1&&(n=n.substring(0,o));}catch{}return n=n.replace(/\.\.\//g,""),n.startsWith("/")&&(n=n.substring(1)),{fileName:n,lineNumber:e.line,columnNumber:e.column}},P=async e=>{if(e._debugSource)return e._debugSource;let t=e._debugOwner;if(t&&!y(t)&&t._debugSource)return t._debugSource;let n=T(e);if(n)return k(n);if(t&&!y(t)){let i=T(t);if(i)return k(i)}return null},_=async e=>{if(e._debugSource)return e._debugSource;let t=T(e);return t?k(t):null},E=async e=>{let t=Y(e);if(!t)return null;let n=B(t);if(!n)return null;if(t.return!=null&&x.has(t.return.tag))return {kind:"component",name:C(n),elementTag:null,source:await P(n),callSite:null};let o=t._debugOwner,r=typeof t.type=="string"?t.type:null;return o&&!y(o)&&o===n?{kind:"element",name:C(o),elementTag:r,source:await _(t),callSite:await P(n)}:{kind:"children",name:o&&y(o)?o.name:C(o&&!y(o)&&x.has(o.tag)?o:n),elementTag:r,source:await _(t),callSite:null}};var c={name:"#93c5fd",tag:"#a78bfa",path:"#71717a",pathActive:"#a1a1aa",pathDim:"#3f3f46",hint:"#52525b"},q={position:"fixed",pointerEvents:"none",zIndex:"2147483646",backgroundColor:"rgba(66, 135, 245, 0.15)",border:"1.5px solid rgba(66, 135, 245, 0.6)",borderRadius:"3px",display:"none",transition:"top 60ms ease-out, left 60ms ease-out, width 60ms ease-out, height 60ms ease-out"},tt={position:"fixed",pointerEvents:"none",zIndex:"2147483647",display:"none",fontFamily:"ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace",fontSize:"12px",lineHeight:"1.4",color:"#e4e4e7",backgroundColor:"#18181b",border:"1px solid #3f3f46",borderRadius:"6px",padding:"4px 8px",whiteSpace:"nowrap",maxWidth:"500px",overflow:"hidden",textOverflow:"ellipsis",boxShadow:"0 4px 12px rgba(0, 0, 0, 0.4)"},$=(e,t)=>{Object.assign(e.style,t);},v=e=>{let t=e.split("/");return t.length<=2?e:`.../${t.slice(-2).join("/")}`},u=(e,t)=>{let n=document.createElement("span");return n.textContent=e,Object.assign(n.style,t),n},S=class{highlight=null;tooltip=null;copiedTimer=null;init(){this.highlight||(this.highlight=document.createElement("div"),this.highlight.dataset.reactGrep="highlight",$(this.highlight,q),document.body.appendChild(this.highlight),this.tooltip=document.createElement("div"),this.tooltip.dataset.reactGrep="tooltip",$(this.tooltip,tt),document.body.appendChild(this.tooltip));}show(t,n,i="source"){if(!this.highlight||!this.tooltip)return;let o=t.getBoundingClientRect();this.highlight.style.top=`${o.top}px`,this.highlight.style.left=`${o.left}px`,this.highlight.style.width=`${o.width}px`,this.highlight.style.height=`${o.height}px`,this.highlight.style.display="block",this.tooltip.textContent="",this.tooltip.appendChild(u(n.name,{color:c.name,fontWeight:"600"})),n.elementTag!=null&&(this.tooltip.appendChild(u(" > ",{color:c.path})),this.tooltip.appendChild(u(n.elementTag,{color:c.tag,fontWeight:"600"})));let r=n.source?`${n.source.fileName}:${n.source.lineNumber}`:null,s=n.callSite?`${n.callSite.fileName}:${n.callSite.lineNumber}`:null;if(r&&s){let p=i==="source"?c.pathActive:c.pathDim,N=i==="callSite"?c.pathActive:c.pathDim,L=d?"\u21E7":"Shift",H=v(r),O=v(s);this.tooltip.appendChild(u(` ${i==="callSite"?"(":""}${H}${i==="callSite"?")":""}`,{color:p})),this.tooltip.appendChild(u(` ${L} `,{color:c.hint})),this.tooltip.appendChild(u(`${i==="source"?"(":""}${O}${i==="source"?")":""}`,{color:N}));}else r&&this.tooltip.appendChild(u(` ${v(r)}`,{color:c.path}));let a=this.tooltip.getBoundingClientRect(),l=o.top-a.height-6,h=o.left;l<4&&(l=o.bottom+6),h+a.width>window.innerWidth-4&&(h=window.innerWidth-a.width-4),this.tooltip.style.top=`${l}px`,this.tooltip.style.left=`${Math.max(4,h)}px`,this.tooltip.style.display="block";}showCopied(t){this.tooltip&&(this.tooltip.textContent="",this.tooltip.appendChild(u("Copied!",{color:"#4ade80",fontWeight:"600"})),this.tooltip.appendChild(u(` ${v(t)}`,{color:"#a1a1aa"})),this.tooltip.style.display="block",this.copiedTimer&&clearTimeout(this.copiedTimer),this.copiedTimer=setTimeout(()=>this.hide(),1500));}hide(){this.highlight&&(this.highlight.style.display="none"),this.tooltip&&(this.tooltip.style.display="none");}destroy(){this.copiedTimer&&(clearTimeout(this.copiedTimer),this.copiedTimer=null),this.highlight?.remove(),this.tooltip?.remove(),this.highlight=null,this.tooltip=null;}};var w=class{overlay=new S;moveGeneration=0;clickGeneration=0;lastTarget=null;lastInfo=null;sourceToggled=false;shiftPressedClean=false;savedCursor="";boundHandlers;constructor(){this.boundHandlers={mousemove:this.handleMouseMove.bind(this),click:this.handleClick.bind(this),keydown:this.handleKeyDown.bind(this),keyup:this.handleKeyUp.bind(this)};}start(){window.addEventListener("mousemove",this.boundHandlers.mousemove),window.addEventListener("click",this.boundHandlers.click,true),window.addEventListener("keydown",this.boundHandlers.keydown),window.addEventListener("keyup",this.boundHandlers.keyup);}stop(){window.removeEventListener("mousemove",this.boundHandlers.mousemove),window.removeEventListener("click",this.boundHandlers.click,true),window.removeEventListener("keydown",this.boundHandlers.keydown),window.removeEventListener("keyup",this.boundHandlers.keyup),this.overlay.destroy(),this.restoreCursor(),this.lastTarget=null,this.lastInfo=null,this.sourceToggled=false,this.shiftPressedClean=false;}isModifierHeld(t){return d?t.metaKey:t.ctrlKey}async handleMouseMove(t){if(!this.isModifierHeld(t)){this.overlay.hide(),this.restoreCursor(),this.lastTarget=null,this.lastInfo=null;return}this.overlay.init(),this.setCrosshairCursor();let n=document.elementFromPoint(t.clientX,t.clientY);if(!n||n.closest("[data-react-grep]"))return;n!==this.lastTarget&&(this.sourceToggled=false);let i=++this.moveGeneration,o=await E(n);if(i===this.moveGeneration){if(!o){this.overlay.hide(),this.lastTarget=null,this.lastInfo=null;return}this.lastTarget=n,this.lastInfo=o,this.overlay.show(n,o,this.getActiveSource());}}async handleClick(t){if(!this.isModifierHeld(t)||!t.shiftKey)return;let n=document.elementFromPoint(t.clientX,t.clientY);if(!n||n.closest("[data-react-grep]"))return;t.preventDefault(),t.stopPropagation(),t.stopImmediatePropagation(),this.shiftPressedClean=false;let i=++this.clickGeneration,o=await E(n);if(i!==this.clickGeneration||!o)return;let r=this.getActiveCopySource(o);if(!r)return;let{fileName:s,lineNumber:a,columnNumber:l}=r,h=l!=null?`${s}:${a}:${l}`:`${s}:${a}`;await this.copyToClipboard(h),this.overlay.showCopied(h);}handleKeyDown(t){t.key==="Shift"&&this.isModifierHeld(t)&&(this.shiftPressedClean=true);}handleKeyUp(t){if(d&&t.key==="Meta"||!d&&t.key==="Control"){this.overlay.hide(),this.restoreCursor(),this.lastTarget=null,this.lastInfo=null;return}t.key==="Shift"&&this.shiftPressedClean&&this.lastTarget&&this.lastInfo&&this.lastInfo.callSite&&(this.sourceToggled=!this.sourceToggled,this.overlay.show(this.lastTarget,this.lastInfo,this.getActiveSource())),this.shiftPressedClean=false;}getActiveSource(){return this.sourceToggled?"callSite":"source"}getActiveCopySource(t){return this.sourceToggled&&t.callSite?t.callSite:t.source}setCrosshairCursor(){document.body.style.cursor!=="crosshair"&&(this.savedCursor=document.body.style.cursor,document.body.style.cursor="crosshair");}restoreCursor(){document.body.style.cursor==="crosshair"&&(document.body.style.cursor=this.savedCursor);}async copyToClipboard(t){try{await navigator.clipboard.writeText(t);}catch{}}};var m=null,et=()=>{m||(m=new w,m.start());},dt=()=>{m&&(m.stop(),m=null);};if(typeof window<"u"){let e=()=>et();document.readyState==="loading"?document.addEventListener("DOMContentLoaded",e):e();}
|
|
3
|
+
exports.destroy=dt;exports.init=et;return exports;})({});
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
|
+
// src/env.ts
|
|
2
|
+
var isMac = typeof navigator !== "undefined" && /mac/i.test(
|
|
3
|
+
navigator.userAgentData?.platform ?? navigator.userAgent
|
|
4
|
+
);
|
|
5
|
+
|
|
1
6
|
// src/source-map.ts
|
|
7
|
+
var MAX_CACHE_SIZE = 100;
|
|
2
8
|
var cache = /* @__PURE__ */ new Map();
|
|
3
9
|
var VLQ_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
4
10
|
var charToInt = [];
|
|
@@ -144,6 +150,10 @@ var fetchAndParseServerFile = async (url) => {
|
|
|
144
150
|
var getSourceMap = (url) => {
|
|
145
151
|
let promise = cache.get(url);
|
|
146
152
|
if (!promise) {
|
|
153
|
+
if (cache.size >= MAX_CACHE_SIZE) {
|
|
154
|
+
const oldest = cache.keys().next().value;
|
|
155
|
+
cache.delete(oldest);
|
|
156
|
+
}
|
|
147
157
|
promise = ABOUT_SERVER_RE.test(url) ? fetchAndParseServerFile(url) : fetchAndParse(url);
|
|
148
158
|
cache.set(url, promise);
|
|
149
159
|
}
|
|
@@ -212,10 +222,8 @@ var getCompositeComponentFiber = (fiber) => {
|
|
|
212
222
|
var getInnerFunction = (type) => {
|
|
213
223
|
if (typeof type === "function") return type;
|
|
214
224
|
if (type && typeof type === "object") {
|
|
215
|
-
if ("render" in type && typeof type.render === "function")
|
|
216
|
-
|
|
217
|
-
if ("type" in type && typeof type.type === "function")
|
|
218
|
-
return type.type;
|
|
225
|
+
if ("render" in type && typeof type.render === "function") return type.render;
|
|
226
|
+
if ("type" in type && typeof type.type === "function") return type.type;
|
|
219
227
|
}
|
|
220
228
|
return null;
|
|
221
229
|
};
|
|
@@ -270,11 +278,12 @@ var resolveFrame = async (frame) => {
|
|
|
270
278
|
};
|
|
271
279
|
var getCompositeDebugSource = async (fiber) => {
|
|
272
280
|
if (fiber._debugSource) return fiber._debugSource;
|
|
273
|
-
|
|
281
|
+
const owner = fiber._debugOwner;
|
|
282
|
+
if (owner && !isServerComponent(owner) && owner._debugSource) return owner._debugSource;
|
|
274
283
|
const frame = parseFirstUserFrame(fiber);
|
|
275
284
|
if (frame) return resolveFrame(frame);
|
|
276
|
-
if (
|
|
277
|
-
const ownerFrame = parseFirstUserFrame(
|
|
285
|
+
if (owner && !isServerComponent(owner)) {
|
|
286
|
+
const ownerFrame = parseFirstUserFrame(owner);
|
|
278
287
|
if (ownerFrame) return resolveFrame(ownerFrame);
|
|
279
288
|
}
|
|
280
289
|
return null;
|
|
@@ -324,7 +333,6 @@ var getComponentInfo = async (el) => {
|
|
|
324
333
|
};
|
|
325
334
|
|
|
326
335
|
// src/overlay.ts
|
|
327
|
-
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
|
|
328
336
|
var COLORS = {
|
|
329
337
|
name: "#93c5fd",
|
|
330
338
|
tag: "#a78bfa",
|
|
@@ -379,6 +387,7 @@ var createSpan = (text, styles) => {
|
|
|
379
387
|
var OverlayManager = class {
|
|
380
388
|
highlight = null;
|
|
381
389
|
tooltip = null;
|
|
390
|
+
copiedTimer = null;
|
|
382
391
|
init() {
|
|
383
392
|
if (this.highlight) return;
|
|
384
393
|
this.highlight = document.createElement("div");
|
|
@@ -449,13 +458,18 @@ var OverlayManager = class {
|
|
|
449
458
|
this.tooltip.appendChild(createSpan("Copied!", { color: "#4ade80", fontWeight: "600" }));
|
|
450
459
|
this.tooltip.appendChild(createSpan(` ${truncatePath(location2)}`, { color: "#a1a1aa" }));
|
|
451
460
|
this.tooltip.style.display = "block";
|
|
452
|
-
|
|
461
|
+
if (this.copiedTimer) clearTimeout(this.copiedTimer);
|
|
462
|
+
this.copiedTimer = setTimeout(() => this.hide(), 1500);
|
|
453
463
|
}
|
|
454
464
|
hide() {
|
|
455
465
|
if (this.highlight) this.highlight.style.display = "none";
|
|
456
466
|
if (this.tooltip) this.tooltip.style.display = "none";
|
|
457
467
|
}
|
|
458
468
|
destroy() {
|
|
469
|
+
if (this.copiedTimer) {
|
|
470
|
+
clearTimeout(this.copiedTimer);
|
|
471
|
+
this.copiedTimer = null;
|
|
472
|
+
}
|
|
459
473
|
this.highlight?.remove();
|
|
460
474
|
this.tooltip?.remove();
|
|
461
475
|
this.highlight = null;
|
|
@@ -464,14 +478,15 @@ var OverlayManager = class {
|
|
|
464
478
|
};
|
|
465
479
|
|
|
466
480
|
// src/inspector.ts
|
|
467
|
-
var isMac2 = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
|
|
468
481
|
var Inspector = class {
|
|
469
482
|
overlay = new OverlayManager();
|
|
470
483
|
moveGeneration = 0;
|
|
484
|
+
clickGeneration = 0;
|
|
471
485
|
lastTarget = null;
|
|
472
486
|
lastInfo = null;
|
|
473
487
|
sourceToggled = false;
|
|
474
488
|
shiftPressedClean = false;
|
|
489
|
+
savedCursor = "";
|
|
475
490
|
boundHandlers;
|
|
476
491
|
constructor() {
|
|
477
492
|
this.boundHandlers = {
|
|
@@ -493,25 +508,25 @@ var Inspector = class {
|
|
|
493
508
|
window.removeEventListener("keydown", this.boundHandlers.keydown);
|
|
494
509
|
window.removeEventListener("keyup", this.boundHandlers.keyup);
|
|
495
510
|
this.overlay.destroy();
|
|
496
|
-
|
|
511
|
+
this.restoreCursor();
|
|
497
512
|
this.lastTarget = null;
|
|
498
513
|
this.lastInfo = null;
|
|
499
514
|
this.sourceToggled = false;
|
|
500
515
|
this.shiftPressedClean = false;
|
|
501
516
|
}
|
|
502
517
|
isModifierHeld(e) {
|
|
503
|
-
return
|
|
518
|
+
return isMac ? e.metaKey : e.ctrlKey;
|
|
504
519
|
}
|
|
505
520
|
async handleMouseMove(e) {
|
|
506
521
|
if (!this.isModifierHeld(e)) {
|
|
507
522
|
this.overlay.hide();
|
|
508
|
-
|
|
523
|
+
this.restoreCursor();
|
|
509
524
|
this.lastTarget = null;
|
|
510
525
|
this.lastInfo = null;
|
|
511
526
|
return;
|
|
512
527
|
}
|
|
513
528
|
this.overlay.init();
|
|
514
|
-
|
|
529
|
+
this.setCrosshairCursor();
|
|
515
530
|
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
516
531
|
if (!target || target.closest("[data-react-grep]")) return;
|
|
517
532
|
if (target !== this.lastTarget) {
|
|
@@ -538,8 +553,9 @@ var Inspector = class {
|
|
|
538
553
|
e.stopPropagation();
|
|
539
554
|
e.stopImmediatePropagation();
|
|
540
555
|
this.shiftPressedClean = false;
|
|
556
|
+
const gen = ++this.clickGeneration;
|
|
541
557
|
const info = await getComponentInfo(target);
|
|
542
|
-
if (!info) return;
|
|
558
|
+
if (gen !== this.clickGeneration || !info) return;
|
|
543
559
|
const source = this.getActiveCopySource(info);
|
|
544
560
|
if (!source) return;
|
|
545
561
|
const { fileName, lineNumber, columnNumber } = source;
|
|
@@ -553,9 +569,9 @@ var Inspector = class {
|
|
|
553
569
|
}
|
|
554
570
|
}
|
|
555
571
|
handleKeyUp(e) {
|
|
556
|
-
if (
|
|
572
|
+
if (isMac && e.key === "Meta" || !isMac && e.key === "Control") {
|
|
557
573
|
this.overlay.hide();
|
|
558
|
-
|
|
574
|
+
this.restoreCursor();
|
|
559
575
|
this.lastTarget = null;
|
|
560
576
|
this.lastInfo = null;
|
|
561
577
|
return;
|
|
@@ -572,6 +588,17 @@ var Inspector = class {
|
|
|
572
588
|
getActiveCopySource(info) {
|
|
573
589
|
return this.sourceToggled && info.callSite ? info.callSite : info.source;
|
|
574
590
|
}
|
|
591
|
+
setCrosshairCursor() {
|
|
592
|
+
if (document.body.style.cursor !== "crosshair") {
|
|
593
|
+
this.savedCursor = document.body.style.cursor;
|
|
594
|
+
document.body.style.cursor = "crosshair";
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
restoreCursor() {
|
|
598
|
+
if (document.body.style.cursor === "crosshair") {
|
|
599
|
+
document.body.style.cursor = this.savedCursor;
|
|
600
|
+
}
|
|
601
|
+
}
|
|
575
602
|
async copyToClipboard(text) {
|
|
576
603
|
try {
|
|
577
604
|
await navigator.clipboard.writeText(text);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-grep",
|
|
3
|
-
"version": "0.1
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Hold CMD to see React component names + file:line overlaid on any element",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"component",
|
|
@@ -30,21 +30,15 @@
|
|
|
30
30
|
],
|
|
31
31
|
"type": "module",
|
|
32
32
|
"sideEffects": true,
|
|
33
|
-
"main": "dist/index.cjs",
|
|
34
33
|
"module": "dist/index.js",
|
|
35
34
|
"browser": "dist/index.global.js",
|
|
36
35
|
"types": "dist/index.d.ts",
|
|
37
36
|
"exports": {
|
|
38
37
|
"./package.json": "./package.json",
|
|
39
38
|
".": {
|
|
40
|
-
"
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
},
|
|
44
|
-
"require": {
|
|
45
|
-
"types": "./dist/index.d.cts",
|
|
46
|
-
"default": "./dist/index.cjs"
|
|
47
|
-
}
|
|
39
|
+
"types": "./dist/index.d.ts",
|
|
40
|
+
"import": "./dist/index.js",
|
|
41
|
+
"default": "./dist/index.js"
|
|
48
42
|
}
|
|
49
43
|
},
|
|
50
44
|
"publishConfig": {
|
package/dist/index.cjs
DELETED
|
@@ -1,607 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
// src/source-map.ts
|
|
4
|
-
var cache = /* @__PURE__ */ new Map();
|
|
5
|
-
var VLQ_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
|
6
|
-
var charToInt = [];
|
|
7
|
-
for (let i = 0; i < VLQ_CHARS.length; i++) charToInt[VLQ_CHARS.charCodeAt(i)] = i;
|
|
8
|
-
var decodeVLQ = (str, pos) => {
|
|
9
|
-
let shift = 0;
|
|
10
|
-
let value = 0;
|
|
11
|
-
while (pos.i < str.length) {
|
|
12
|
-
const digit = charToInt[str.charCodeAt(pos.i++)];
|
|
13
|
-
value += (digit & 31) << shift;
|
|
14
|
-
if (!(digit & 32)) return value & 1 ? -(value >> 1) : value >> 1;
|
|
15
|
-
shift += 5;
|
|
16
|
-
}
|
|
17
|
-
return 0;
|
|
18
|
-
};
|
|
19
|
-
var decodeMappings = (raw) => {
|
|
20
|
-
const result = [];
|
|
21
|
-
let srcIdx = 0;
|
|
22
|
-
let origLine = 0;
|
|
23
|
-
let origCol = 0;
|
|
24
|
-
for (const line of raw.split(";")) {
|
|
25
|
-
const segments = [];
|
|
26
|
-
let genCol = 0;
|
|
27
|
-
if (line) {
|
|
28
|
-
const pos = { i: 0 };
|
|
29
|
-
while (pos.i < line.length) {
|
|
30
|
-
if (line.charCodeAt(pos.i) === 44) {
|
|
31
|
-
pos.i++;
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
genCol += decodeVLQ(line, pos);
|
|
35
|
-
if (pos.i >= line.length || line.charCodeAt(pos.i) === 44) continue;
|
|
36
|
-
srcIdx += decodeVLQ(line, pos);
|
|
37
|
-
origLine += decodeVLQ(line, pos);
|
|
38
|
-
origCol += decodeVLQ(line, pos);
|
|
39
|
-
if (pos.i < line.length && line.charCodeAt(pos.i) !== 44) decodeVLQ(line, pos);
|
|
40
|
-
segments.push([genCol, srcIdx, origLine, origCol]);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
result.push(segments);
|
|
44
|
-
}
|
|
45
|
-
return result;
|
|
46
|
-
};
|
|
47
|
-
var DATA_URI_RE = /^data:application\/json[^,]*;base64,([A-Za-z0-9+/=]+)$/;
|
|
48
|
-
var isSameOrigin = (a, b) => {
|
|
49
|
-
try {
|
|
50
|
-
return new URL(a).origin === new URL(b).origin;
|
|
51
|
-
} catch {
|
|
52
|
-
return false;
|
|
53
|
-
}
|
|
54
|
-
};
|
|
55
|
-
var fetchSourceMapJson = async (ref, baseUrl) => {
|
|
56
|
-
if (ref.startsWith("data:")) {
|
|
57
|
-
const dataMatch = DATA_URI_RE.exec(ref);
|
|
58
|
-
return dataMatch ? atob(dataMatch[1]) : null;
|
|
59
|
-
}
|
|
60
|
-
const mapUrl = new URL(ref, baseUrl).href;
|
|
61
|
-
if (!isSameOrigin(baseUrl, mapUrl)) return null;
|
|
62
|
-
const mapRes = await fetch(mapUrl);
|
|
63
|
-
if (!mapRes.ok) return null;
|
|
64
|
-
return mapRes.text();
|
|
65
|
-
};
|
|
66
|
-
var flattenIndexedMap = (sections) => {
|
|
67
|
-
const allSources = [];
|
|
68
|
-
const allMappings = [];
|
|
69
|
-
for (const section of sections) {
|
|
70
|
-
const decoded = decodeMappings(section.map.mappings);
|
|
71
|
-
const lineOff = section.offset.line;
|
|
72
|
-
const colOff = section.offset.column;
|
|
73
|
-
const srcOff = allSources.length;
|
|
74
|
-
while (allMappings.length < lineOff + decoded.length) allMappings.push([]);
|
|
75
|
-
for (let i = 0; i < decoded.length; i++) {
|
|
76
|
-
const target = allMappings[lineOff + i];
|
|
77
|
-
for (const seg of decoded[i]) {
|
|
78
|
-
target.push([i === 0 ? seg[0] + colOff : seg[0], seg[1] + srcOff, seg[2], seg[3]]);
|
|
79
|
-
}
|
|
80
|
-
}
|
|
81
|
-
allSources.push(...section.map.sources);
|
|
82
|
-
}
|
|
83
|
-
for (const line of allMappings) {
|
|
84
|
-
if (line.length > 1) line.sort((a, b) => a[0] - b[0]);
|
|
85
|
-
}
|
|
86
|
-
return { sources: allSources, mappings: allMappings };
|
|
87
|
-
};
|
|
88
|
-
var parseSourceMap = (json) => {
|
|
89
|
-
try {
|
|
90
|
-
const raw = JSON.parse(json);
|
|
91
|
-
if (Array.isArray(raw.sections)) return flattenIndexedMap(raw.sections);
|
|
92
|
-
if (!raw.sources || !raw.mappings) return null;
|
|
93
|
-
return { sources: raw.sources, mappings: decodeMappings(raw.mappings) };
|
|
94
|
-
} catch {
|
|
95
|
-
return null;
|
|
96
|
-
}
|
|
97
|
-
};
|
|
98
|
-
var fetchAndParse = async (url) => {
|
|
99
|
-
try {
|
|
100
|
-
const res = await fetch(url);
|
|
101
|
-
const text = await res.text();
|
|
102
|
-
const match = text.match(/\/\/[#@]\s*sourceMappingURL=([^\s]+)$/m);
|
|
103
|
-
if (match) {
|
|
104
|
-
const json = await fetchSourceMapJson(match[1].trim(), url);
|
|
105
|
-
if (json) {
|
|
106
|
-
const map = parseSourceMap(json);
|
|
107
|
-
if (map) return map;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
const headerRef = res.headers.get("SourceMap") ?? res.headers.get("X-SourceMap");
|
|
111
|
-
if (headerRef) {
|
|
112
|
-
const json = await fetchSourceMapJson(headerRef.trim(), url);
|
|
113
|
-
if (json) {
|
|
114
|
-
const map = parseSourceMap(json);
|
|
115
|
-
if (map) return map;
|
|
116
|
-
}
|
|
117
|
-
}
|
|
118
|
-
const conventionRes = await fetch(`${url}.map`);
|
|
119
|
-
if (conventionRes.ok) {
|
|
120
|
-
const json = await conventionRes.text();
|
|
121
|
-
return parseSourceMap(json);
|
|
122
|
-
}
|
|
123
|
-
return null;
|
|
124
|
-
} catch {
|
|
125
|
-
return null;
|
|
126
|
-
}
|
|
127
|
-
};
|
|
128
|
-
var ABOUT_SERVER_RE = /^about:\/\/React\/Server\/file:\/\/\//;
|
|
129
|
-
var NEXT_DOTDIR_RE = /[/\\](\.next[/\\].+?)(?:\?.*)?$/;
|
|
130
|
-
var fetchAndParseServerFile = async (url) => {
|
|
131
|
-
try {
|
|
132
|
-
const filePath = decodeURIComponent(url.replace(ABOUT_SERVER_RE, ""));
|
|
133
|
-
const dotNextMatch = NEXT_DOTDIR_RE.exec(filePath);
|
|
134
|
-
if (!dotNextMatch) return null;
|
|
135
|
-
const origin = typeof location !== "undefined" ? location.origin : "";
|
|
136
|
-
const mapUrl = `${origin}/__nextjs_source-map?filename=${encodeURIComponent(dotNextMatch[1])}`;
|
|
137
|
-
const res = await fetch(mapUrl);
|
|
138
|
-
if (!res.ok) return null;
|
|
139
|
-
const json = await res.text();
|
|
140
|
-
if (!json) return null;
|
|
141
|
-
return parseSourceMap(json);
|
|
142
|
-
} catch {
|
|
143
|
-
return null;
|
|
144
|
-
}
|
|
145
|
-
};
|
|
146
|
-
var getSourceMap = (url) => {
|
|
147
|
-
let promise = cache.get(url);
|
|
148
|
-
if (!promise) {
|
|
149
|
-
promise = ABOUT_SERVER_RE.test(url) ? fetchAndParseServerFile(url) : fetchAndParse(url);
|
|
150
|
-
cache.set(url, promise);
|
|
151
|
-
}
|
|
152
|
-
return promise;
|
|
153
|
-
};
|
|
154
|
-
var lookup = (map, genLine, genCol) => {
|
|
155
|
-
if (genLine < 0 || genLine >= map.mappings.length) return null;
|
|
156
|
-
const segments = map.mappings[genLine];
|
|
157
|
-
if (!segments.length) return null;
|
|
158
|
-
let lo = 0;
|
|
159
|
-
let hi = segments.length - 1;
|
|
160
|
-
while (lo < hi) {
|
|
161
|
-
const mid = lo + hi + 1 >> 1;
|
|
162
|
-
if (segments[mid][0] <= genCol) lo = mid;
|
|
163
|
-
else hi = mid - 1;
|
|
164
|
-
}
|
|
165
|
-
return segments[lo];
|
|
166
|
-
};
|
|
167
|
-
var resolveOriginalPosition = async (url, line, column) => {
|
|
168
|
-
const map = await getSourceMap(url);
|
|
169
|
-
if (!map) return null;
|
|
170
|
-
const seg = lookup(map, line - 1, column - 1);
|
|
171
|
-
if (!seg) return null;
|
|
172
|
-
let fileName = map.sources[seg[1]];
|
|
173
|
-
if (fileName.startsWith("file:///")) {
|
|
174
|
-
fileName = decodeURIComponent(new URL(fileName).pathname);
|
|
175
|
-
}
|
|
176
|
-
return {
|
|
177
|
-
fileName,
|
|
178
|
-
lineNumber: seg[2] + 1,
|
|
179
|
-
columnNumber: seg[3] + 1
|
|
180
|
-
};
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
// src/fiber.ts
|
|
184
|
-
var isServerComponent = (owner) => "env" in owner && typeof owner.name === "string";
|
|
185
|
-
var COMPOSITE_TAGS = /* @__PURE__ */ new Set([
|
|
186
|
-
0,
|
|
187
|
-
// FunctionComponent
|
|
188
|
-
1,
|
|
189
|
-
// ClassComponent
|
|
190
|
-
11,
|
|
191
|
-
// ForwardRef
|
|
192
|
-
14,
|
|
193
|
-
// MemoComponent
|
|
194
|
-
15
|
|
195
|
-
// SimpleMemoComponent
|
|
196
|
-
]);
|
|
197
|
-
var getFiberFromElement = (el) => {
|
|
198
|
-
try {
|
|
199
|
-
const key = Object.keys(el).find((k) => k.startsWith("__reactFiber$"));
|
|
200
|
-
if (!key) return null;
|
|
201
|
-
return el[key];
|
|
202
|
-
} catch {
|
|
203
|
-
return null;
|
|
204
|
-
}
|
|
205
|
-
};
|
|
206
|
-
var getCompositeComponentFiber = (fiber) => {
|
|
207
|
-
let current = fiber;
|
|
208
|
-
while (current) {
|
|
209
|
-
if (COMPOSITE_TAGS.has(current.tag)) return current;
|
|
210
|
-
current = current.return;
|
|
211
|
-
}
|
|
212
|
-
return null;
|
|
213
|
-
};
|
|
214
|
-
var getInnerFunction = (type) => {
|
|
215
|
-
if (typeof type === "function") return type;
|
|
216
|
-
if (type && typeof type === "object") {
|
|
217
|
-
if ("render" in type && typeof type.render === "function")
|
|
218
|
-
return type.render;
|
|
219
|
-
if ("type" in type && typeof type.type === "function")
|
|
220
|
-
return type.type;
|
|
221
|
-
}
|
|
222
|
-
return null;
|
|
223
|
-
};
|
|
224
|
-
var getComponentName = (fiber) => {
|
|
225
|
-
const { type } = fiber;
|
|
226
|
-
if (typeof type === "function") {
|
|
227
|
-
return type.displayName || type.name || "Anonymous";
|
|
228
|
-
}
|
|
229
|
-
if (type && typeof type === "object") {
|
|
230
|
-
if ("displayName" in type && type.displayName) return type.displayName;
|
|
231
|
-
const inner = getInnerFunction(type);
|
|
232
|
-
if (inner) return inner.displayName || inner.name || "Anonymous";
|
|
233
|
-
}
|
|
234
|
-
return "Anonymous";
|
|
235
|
-
};
|
|
236
|
-
var SKIP_FRAMES = /* @__PURE__ */ new Set([
|
|
237
|
-
"jsxDEV",
|
|
238
|
-
"jsxs",
|
|
239
|
-
"jsx",
|
|
240
|
-
"react-stack-top-frame",
|
|
241
|
-
"react_stack_bottom_frame",
|
|
242
|
-
"fakeJSXCallSite"
|
|
243
|
-
]);
|
|
244
|
-
var FRAME_RE = /at (?:(\S+) )?\(?(.+):(\d+):(\d+)\)?$/;
|
|
245
|
-
var parseFirstUserFrame = (fiber) => {
|
|
246
|
-
const stack = fiber._debugStack?.stack;
|
|
247
|
-
if (!stack) return null;
|
|
248
|
-
for (const line of stack.split("\n")) {
|
|
249
|
-
const match = FRAME_RE.exec(line.trim());
|
|
250
|
-
if (!match) continue;
|
|
251
|
-
const [, fnName, url, lineStr, colStr] = match;
|
|
252
|
-
if (fnName && SKIP_FRAMES.has(fnName)) continue;
|
|
253
|
-
if (url.includes("/node_modules/")) continue;
|
|
254
|
-
return { url, line: Number(lineStr), column: Number(colStr) };
|
|
255
|
-
}
|
|
256
|
-
return null;
|
|
257
|
-
};
|
|
258
|
-
var resolveFrame = async (frame) => {
|
|
259
|
-
const resolved = await resolveOriginalPosition(frame.url, frame.line, frame.column);
|
|
260
|
-
if (resolved) return resolved;
|
|
261
|
-
let fileName = frame.url;
|
|
262
|
-
try {
|
|
263
|
-
const parsed = new URL(frame.url);
|
|
264
|
-
fileName = decodeURIComponent(parsed.pathname);
|
|
265
|
-
const qIdx = fileName.indexOf("?");
|
|
266
|
-
if (qIdx !== -1) fileName = fileName.substring(0, qIdx);
|
|
267
|
-
} catch {
|
|
268
|
-
}
|
|
269
|
-
fileName = fileName.replace(/\.\.\//g, "");
|
|
270
|
-
if (fileName.startsWith("/")) fileName = fileName.substring(1);
|
|
271
|
-
return { fileName, lineNumber: frame.line, columnNumber: frame.column };
|
|
272
|
-
};
|
|
273
|
-
var getCompositeDebugSource = async (fiber) => {
|
|
274
|
-
if (fiber._debugSource) return fiber._debugSource;
|
|
275
|
-
if (fiber._debugOwner?._debugSource) return fiber._debugOwner._debugSource;
|
|
276
|
-
const frame = parseFirstUserFrame(fiber);
|
|
277
|
-
if (frame) return resolveFrame(frame);
|
|
278
|
-
if (fiber._debugOwner) {
|
|
279
|
-
const ownerFrame = parseFirstUserFrame(fiber._debugOwner);
|
|
280
|
-
if (ownerFrame) return resolveFrame(ownerFrame);
|
|
281
|
-
}
|
|
282
|
-
return null;
|
|
283
|
-
};
|
|
284
|
-
var getDomDebugSource = async (fiber) => {
|
|
285
|
-
if (fiber._debugSource) return fiber._debugSource;
|
|
286
|
-
const frame = parseFirstUserFrame(fiber);
|
|
287
|
-
if (frame) return resolveFrame(frame);
|
|
288
|
-
return null;
|
|
289
|
-
};
|
|
290
|
-
var getComponentInfo = async (el) => {
|
|
291
|
-
const domFiber = getFiberFromElement(el);
|
|
292
|
-
if (!domFiber) return null;
|
|
293
|
-
const composite = getCompositeComponentFiber(domFiber);
|
|
294
|
-
if (!composite) return null;
|
|
295
|
-
const isComponentRoot = domFiber.return != null && COMPOSITE_TAGS.has(domFiber.return.tag);
|
|
296
|
-
if (isComponentRoot) {
|
|
297
|
-
return {
|
|
298
|
-
kind: "component",
|
|
299
|
-
name: getComponentName(composite),
|
|
300
|
-
elementTag: null,
|
|
301
|
-
source: await getCompositeDebugSource(composite),
|
|
302
|
-
callSite: null
|
|
303
|
-
};
|
|
304
|
-
}
|
|
305
|
-
const owner = domFiber._debugOwner;
|
|
306
|
-
const elementTag = typeof domFiber.type === "string" ? domFiber.type : null;
|
|
307
|
-
if (owner && !isServerComponent(owner) && owner === composite) {
|
|
308
|
-
return {
|
|
309
|
-
kind: "element",
|
|
310
|
-
name: getComponentName(owner),
|
|
311
|
-
elementTag,
|
|
312
|
-
source: await getDomDebugSource(domFiber),
|
|
313
|
-
callSite: await getCompositeDebugSource(composite)
|
|
314
|
-
};
|
|
315
|
-
}
|
|
316
|
-
const name = owner && isServerComponent(owner) ? owner.name : getComponentName(
|
|
317
|
-
owner && !isServerComponent(owner) && COMPOSITE_TAGS.has(owner.tag) ? owner : composite
|
|
318
|
-
);
|
|
319
|
-
return {
|
|
320
|
-
kind: "children",
|
|
321
|
-
name,
|
|
322
|
-
elementTag,
|
|
323
|
-
source: await getDomDebugSource(domFiber),
|
|
324
|
-
callSite: null
|
|
325
|
-
};
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
// src/overlay.ts
|
|
329
|
-
var isMac = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
|
|
330
|
-
var COLORS = {
|
|
331
|
-
name: "#93c5fd",
|
|
332
|
-
tag: "#a78bfa",
|
|
333
|
-
path: "#71717a",
|
|
334
|
-
pathActive: "#a1a1aa",
|
|
335
|
-
pathDim: "#3f3f46",
|
|
336
|
-
hint: "#52525b"
|
|
337
|
-
};
|
|
338
|
-
var HIGHLIGHT_STYLES = {
|
|
339
|
-
position: "fixed",
|
|
340
|
-
pointerEvents: "none",
|
|
341
|
-
zIndex: "2147483646",
|
|
342
|
-
backgroundColor: "rgba(66, 135, 245, 0.15)",
|
|
343
|
-
border: "1.5px solid rgba(66, 135, 245, 0.6)",
|
|
344
|
-
borderRadius: "3px",
|
|
345
|
-
display: "none",
|
|
346
|
-
transition: "top 60ms ease-out, left 60ms ease-out, width 60ms ease-out, height 60ms ease-out"
|
|
347
|
-
};
|
|
348
|
-
var TOOLTIP_STYLES = {
|
|
349
|
-
position: "fixed",
|
|
350
|
-
pointerEvents: "none",
|
|
351
|
-
zIndex: "2147483647",
|
|
352
|
-
display: "none",
|
|
353
|
-
fontFamily: "ui-monospace, SFMono-Regular, 'SF Mono', Menlo, monospace",
|
|
354
|
-
fontSize: "12px",
|
|
355
|
-
lineHeight: "1.4",
|
|
356
|
-
color: "#e4e4e7",
|
|
357
|
-
backgroundColor: "#18181b",
|
|
358
|
-
border: "1px solid #3f3f46",
|
|
359
|
-
borderRadius: "6px",
|
|
360
|
-
padding: "4px 8px",
|
|
361
|
-
whiteSpace: "nowrap",
|
|
362
|
-
maxWidth: "500px",
|
|
363
|
-
overflow: "hidden",
|
|
364
|
-
textOverflow: "ellipsis",
|
|
365
|
-
boxShadow: "0 4px 12px rgba(0, 0, 0, 0.4)"
|
|
366
|
-
};
|
|
367
|
-
var applyStyles = (el, styles) => {
|
|
368
|
-
Object.assign(el.style, styles);
|
|
369
|
-
};
|
|
370
|
-
var truncatePath = (filePath) => {
|
|
371
|
-
const parts = filePath.split("/");
|
|
372
|
-
if (parts.length <= 2) return filePath;
|
|
373
|
-
return `.../${parts.slice(-2).join("/")}`;
|
|
374
|
-
};
|
|
375
|
-
var createSpan = (text, styles) => {
|
|
376
|
-
const span = document.createElement("span");
|
|
377
|
-
span.textContent = text;
|
|
378
|
-
Object.assign(span.style, styles);
|
|
379
|
-
return span;
|
|
380
|
-
};
|
|
381
|
-
var OverlayManager = class {
|
|
382
|
-
highlight = null;
|
|
383
|
-
tooltip = null;
|
|
384
|
-
init() {
|
|
385
|
-
if (this.highlight) return;
|
|
386
|
-
this.highlight = document.createElement("div");
|
|
387
|
-
this.highlight.dataset.reactGrep = "highlight";
|
|
388
|
-
applyStyles(this.highlight, HIGHLIGHT_STYLES);
|
|
389
|
-
document.body.appendChild(this.highlight);
|
|
390
|
-
this.tooltip = document.createElement("div");
|
|
391
|
-
this.tooltip.dataset.reactGrep = "tooltip";
|
|
392
|
-
applyStyles(this.tooltip, TOOLTIP_STYLES);
|
|
393
|
-
document.body.appendChild(this.tooltip);
|
|
394
|
-
}
|
|
395
|
-
show(el, info, activeSource = "source") {
|
|
396
|
-
if (!this.highlight || !this.tooltip) return;
|
|
397
|
-
const rect = el.getBoundingClientRect();
|
|
398
|
-
this.highlight.style.top = `${rect.top}px`;
|
|
399
|
-
this.highlight.style.left = `${rect.left}px`;
|
|
400
|
-
this.highlight.style.width = `${rect.width}px`;
|
|
401
|
-
this.highlight.style.height = `${rect.height}px`;
|
|
402
|
-
this.highlight.style.display = "block";
|
|
403
|
-
this.tooltip.textContent = "";
|
|
404
|
-
this.tooltip.appendChild(createSpan(info.name, { color: COLORS.name, fontWeight: "600" }));
|
|
405
|
-
if (info.elementTag != null) {
|
|
406
|
-
this.tooltip.appendChild(createSpan(" > ", { color: COLORS.path }));
|
|
407
|
-
this.tooltip.appendChild(
|
|
408
|
-
createSpan(info.elementTag, { color: COLORS.tag, fontWeight: "600" })
|
|
409
|
-
);
|
|
410
|
-
}
|
|
411
|
-
const filePath = info.source ? `${info.source.fileName}:${info.source.lineNumber}` : null;
|
|
412
|
-
const callSitePath = info.callSite ? `${info.callSite.fileName}:${info.callSite.lineNumber}` : null;
|
|
413
|
-
if (filePath && callSitePath) {
|
|
414
|
-
const sourceColor = activeSource === "source" ? COLORS.pathActive : COLORS.pathDim;
|
|
415
|
-
const callSiteColor = activeSource === "callSite" ? COLORS.pathActive : COLORS.pathDim;
|
|
416
|
-
const shiftHint = isMac ? "\u21E7" : "Shift";
|
|
417
|
-
const sourceText = truncatePath(filePath);
|
|
418
|
-
const callSiteText = truncatePath(callSitePath);
|
|
419
|
-
this.tooltip.appendChild(
|
|
420
|
-
createSpan(
|
|
421
|
-
` ${activeSource === "callSite" ? "(" : ""}${sourceText}${activeSource === "callSite" ? ")" : ""}`,
|
|
422
|
-
{ color: sourceColor }
|
|
423
|
-
)
|
|
424
|
-
);
|
|
425
|
-
this.tooltip.appendChild(createSpan(` ${shiftHint} `, { color: COLORS.hint }));
|
|
426
|
-
this.tooltip.appendChild(
|
|
427
|
-
createSpan(
|
|
428
|
-
`${activeSource === "source" ? "(" : ""}${callSiteText}${activeSource === "source" ? ")" : ""}`,
|
|
429
|
-
{ color: callSiteColor }
|
|
430
|
-
)
|
|
431
|
-
);
|
|
432
|
-
} else if (filePath) {
|
|
433
|
-
this.tooltip.appendChild(createSpan(` ${truncatePath(filePath)}`, { color: COLORS.path }));
|
|
434
|
-
}
|
|
435
|
-
const tooltipRect = this.tooltip.getBoundingClientRect();
|
|
436
|
-
let top = rect.top - tooltipRect.height - 6;
|
|
437
|
-
let left = rect.left;
|
|
438
|
-
if (top < 4) {
|
|
439
|
-
top = rect.bottom + 6;
|
|
440
|
-
}
|
|
441
|
-
if (left + tooltipRect.width > window.innerWidth - 4) {
|
|
442
|
-
left = window.innerWidth - tooltipRect.width - 4;
|
|
443
|
-
}
|
|
444
|
-
this.tooltip.style.top = `${top}px`;
|
|
445
|
-
this.tooltip.style.left = `${Math.max(4, left)}px`;
|
|
446
|
-
this.tooltip.style.display = "block";
|
|
447
|
-
}
|
|
448
|
-
showCopied(location2) {
|
|
449
|
-
if (!this.tooltip) return;
|
|
450
|
-
this.tooltip.textContent = "";
|
|
451
|
-
this.tooltip.appendChild(createSpan("Copied!", { color: "#4ade80", fontWeight: "600" }));
|
|
452
|
-
this.tooltip.appendChild(createSpan(` ${truncatePath(location2)}`, { color: "#a1a1aa" }));
|
|
453
|
-
this.tooltip.style.display = "block";
|
|
454
|
-
setTimeout(() => this.hide(), 1500);
|
|
455
|
-
}
|
|
456
|
-
hide() {
|
|
457
|
-
if (this.highlight) this.highlight.style.display = "none";
|
|
458
|
-
if (this.tooltip) this.tooltip.style.display = "none";
|
|
459
|
-
}
|
|
460
|
-
destroy() {
|
|
461
|
-
this.highlight?.remove();
|
|
462
|
-
this.tooltip?.remove();
|
|
463
|
-
this.highlight = null;
|
|
464
|
-
this.tooltip = null;
|
|
465
|
-
}
|
|
466
|
-
};
|
|
467
|
-
|
|
468
|
-
// src/inspector.ts
|
|
469
|
-
var isMac2 = typeof navigator !== "undefined" && /Mac|iPhone|iPad/.test(navigator.platform);
|
|
470
|
-
var Inspector = class {
|
|
471
|
-
overlay = new OverlayManager();
|
|
472
|
-
moveGeneration = 0;
|
|
473
|
-
lastTarget = null;
|
|
474
|
-
lastInfo = null;
|
|
475
|
-
sourceToggled = false;
|
|
476
|
-
shiftPressedClean = false;
|
|
477
|
-
boundHandlers;
|
|
478
|
-
constructor() {
|
|
479
|
-
this.boundHandlers = {
|
|
480
|
-
mousemove: this.handleMouseMove.bind(this),
|
|
481
|
-
click: this.handleClick.bind(this),
|
|
482
|
-
keydown: this.handleKeyDown.bind(this),
|
|
483
|
-
keyup: this.handleKeyUp.bind(this)
|
|
484
|
-
};
|
|
485
|
-
}
|
|
486
|
-
start() {
|
|
487
|
-
window.addEventListener("mousemove", this.boundHandlers.mousemove);
|
|
488
|
-
window.addEventListener("click", this.boundHandlers.click, true);
|
|
489
|
-
window.addEventListener("keydown", this.boundHandlers.keydown);
|
|
490
|
-
window.addEventListener("keyup", this.boundHandlers.keyup);
|
|
491
|
-
}
|
|
492
|
-
stop() {
|
|
493
|
-
window.removeEventListener("mousemove", this.boundHandlers.mousemove);
|
|
494
|
-
window.removeEventListener("click", this.boundHandlers.click, true);
|
|
495
|
-
window.removeEventListener("keydown", this.boundHandlers.keydown);
|
|
496
|
-
window.removeEventListener("keyup", this.boundHandlers.keyup);
|
|
497
|
-
this.overlay.destroy();
|
|
498
|
-
document.body.style.cursor = "";
|
|
499
|
-
this.lastTarget = null;
|
|
500
|
-
this.lastInfo = null;
|
|
501
|
-
this.sourceToggled = false;
|
|
502
|
-
this.shiftPressedClean = false;
|
|
503
|
-
}
|
|
504
|
-
isModifierHeld(e) {
|
|
505
|
-
return isMac2 ? e.metaKey : e.ctrlKey;
|
|
506
|
-
}
|
|
507
|
-
async handleMouseMove(e) {
|
|
508
|
-
if (!this.isModifierHeld(e)) {
|
|
509
|
-
this.overlay.hide();
|
|
510
|
-
document.body.style.cursor = "";
|
|
511
|
-
this.lastTarget = null;
|
|
512
|
-
this.lastInfo = null;
|
|
513
|
-
return;
|
|
514
|
-
}
|
|
515
|
-
this.overlay.init();
|
|
516
|
-
document.body.style.cursor = "crosshair";
|
|
517
|
-
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
518
|
-
if (!target || target.closest("[data-react-grep]")) return;
|
|
519
|
-
if (target !== this.lastTarget) {
|
|
520
|
-
this.sourceToggled = false;
|
|
521
|
-
}
|
|
522
|
-
const gen = ++this.moveGeneration;
|
|
523
|
-
const info = await getComponentInfo(target);
|
|
524
|
-
if (gen !== this.moveGeneration) return;
|
|
525
|
-
if (!info) {
|
|
526
|
-
this.overlay.hide();
|
|
527
|
-
this.lastTarget = null;
|
|
528
|
-
this.lastInfo = null;
|
|
529
|
-
return;
|
|
530
|
-
}
|
|
531
|
-
this.lastTarget = target;
|
|
532
|
-
this.lastInfo = info;
|
|
533
|
-
this.overlay.show(target, info, this.getActiveSource());
|
|
534
|
-
}
|
|
535
|
-
async handleClick(e) {
|
|
536
|
-
if (!this.isModifierHeld(e) || !e.shiftKey) return;
|
|
537
|
-
const target = document.elementFromPoint(e.clientX, e.clientY);
|
|
538
|
-
if (!target || target.closest("[data-react-grep]")) return;
|
|
539
|
-
e.preventDefault();
|
|
540
|
-
e.stopPropagation();
|
|
541
|
-
e.stopImmediatePropagation();
|
|
542
|
-
this.shiftPressedClean = false;
|
|
543
|
-
const info = await getComponentInfo(target);
|
|
544
|
-
if (!info) return;
|
|
545
|
-
const source = this.getActiveCopySource(info);
|
|
546
|
-
if (!source) return;
|
|
547
|
-
const { fileName, lineNumber, columnNumber } = source;
|
|
548
|
-
const location2 = columnNumber != null ? `${fileName}:${lineNumber}:${columnNumber}` : `${fileName}:${lineNumber}`;
|
|
549
|
-
await this.copyToClipboard(location2);
|
|
550
|
-
this.overlay.showCopied(location2);
|
|
551
|
-
}
|
|
552
|
-
handleKeyDown(e) {
|
|
553
|
-
if (e.key === "Shift" && this.isModifierHeld(e)) {
|
|
554
|
-
this.shiftPressedClean = true;
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
handleKeyUp(e) {
|
|
558
|
-
if (isMac2 && e.key === "Meta" || !isMac2 && e.key === "Control") {
|
|
559
|
-
this.overlay.hide();
|
|
560
|
-
document.body.style.cursor = "";
|
|
561
|
-
this.lastTarget = null;
|
|
562
|
-
this.lastInfo = null;
|
|
563
|
-
return;
|
|
564
|
-
}
|
|
565
|
-
if (e.key === "Shift" && this.shiftPressedClean && this.lastTarget && this.lastInfo && this.lastInfo.callSite) {
|
|
566
|
-
this.sourceToggled = !this.sourceToggled;
|
|
567
|
-
this.overlay.show(this.lastTarget, this.lastInfo, this.getActiveSource());
|
|
568
|
-
}
|
|
569
|
-
this.shiftPressedClean = false;
|
|
570
|
-
}
|
|
571
|
-
getActiveSource() {
|
|
572
|
-
return this.sourceToggled ? "callSite" : "source";
|
|
573
|
-
}
|
|
574
|
-
getActiveCopySource(info) {
|
|
575
|
-
return this.sourceToggled && info.callSite ? info.callSite : info.source;
|
|
576
|
-
}
|
|
577
|
-
async copyToClipboard(text) {
|
|
578
|
-
try {
|
|
579
|
-
await navigator.clipboard.writeText(text);
|
|
580
|
-
} catch {
|
|
581
|
-
}
|
|
582
|
-
}
|
|
583
|
-
};
|
|
584
|
-
|
|
585
|
-
// src/index.ts
|
|
586
|
-
var inspector = null;
|
|
587
|
-
var init = () => {
|
|
588
|
-
if (inspector) return;
|
|
589
|
-
inspector = new Inspector();
|
|
590
|
-
inspector.start();
|
|
591
|
-
};
|
|
592
|
-
var destroy = () => {
|
|
593
|
-
if (!inspector) return;
|
|
594
|
-
inspector.stop();
|
|
595
|
-
inspector = null;
|
|
596
|
-
};
|
|
597
|
-
if (typeof window !== "undefined") {
|
|
598
|
-
const bootstrap = () => init();
|
|
599
|
-
if (document.readyState === "loading") {
|
|
600
|
-
document.addEventListener("DOMContentLoaded", bootstrap);
|
|
601
|
-
} else {
|
|
602
|
-
bootstrap();
|
|
603
|
-
}
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
exports.destroy = destroy;
|
|
607
|
-
exports.init = init;
|
package/dist/index.d.cts
DELETED