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