Skip to content

Commit 0f2fb5b

Browse files
author
Brian Vaughn
authored
Standalone NPM packages and React Native support (#335)
* Add version 4 react-devtools and react-devtools-core packages which support both React Native and e.g. Safari or iframe DOM usage. * Replaces typed operations arrays with regular arrays in order to support Hermes. This is unfortunate, since in theory a typed array buffer could be more efficiently transferred between frontend and backend for the web extension, but this never actually worked properly in v8, only Spidermonkey, and it fails entirely in Hermes so for the time being- it's been removed. * Adds support for React Native (paper renderer) * Adds a style editor for react-native and react-native-web
1 parent 39a811d commit 0f2fb5b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

77 files changed

+3911
-387
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
/shells/browser/firefox/*.xpi
44
/shells/browser/firefox/*.pem
55
/shells/browser/shared/build
6+
/packages/react-devtools-core/dist
67
/shells/dev/dist
78
build
89
node_modules

babel.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,9 @@ module.exports = api => {
2424
} else {
2525
targets.chrome = minChromeVersion.toString();
2626
targets.firefox = minFirefoxVersion.toString();
27+
28+
// This targets RN/Hermes.
29+
targets.IE = '11';
2730
}
2831
const plugins = [
2932
['@babel/plugin-transform-flow-strip-types'],

fixtures/standalone/index.html

Lines changed: 284 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,284 @@
1+
<!DOCTYPE html>
2+
<html>
3+
<head>
4+
<meta charset="UTF-8" />
5+
<title>TODO List</title>
6+
7+
<!-- DevTools -->
8+
<script src="http://localhost:8097"></script>
9+
10+
<script src="https://unpkg.com/react@16/umd/react.development.js"></script>
11+
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script>
12+
13+
<!-- Don't use this in production: -->
14+
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script>
15+
16+
<style type="text/css">
17+
.Input {
18+
font-size: 1rem;
19+
padding: 0.25rem;
20+
}
21+
22+
.IconButton {
23+
padding: 0.25rem;
24+
border: none;
25+
background: none;
26+
cursor: pointer;
27+
}
28+
29+
.List {
30+
margin: 0.5rem 0 0;
31+
padding: 0;
32+
}
33+
34+
.ListItem {
35+
list-style-type: none;
36+
}
37+
38+
.Label {
39+
cursor: pointer;
40+
padding: 0.25rem;
41+
color: #555;
42+
}
43+
.Label:hover {
44+
color: #000;
45+
}
46+
47+
.IconButton {
48+
padding: 0.25rem;
49+
border: none;
50+
background: none;
51+
cursor: pointer;
52+
}
53+
</style>
54+
</head>
55+
<body>
56+
<div id="root"></div>
57+
<script type="text/babel">
58+
const { Fragment, useCallback, useState } = React;
59+
60+
function List(props) {
61+
const [newItemText, setNewItemText] = useState("");
62+
const [items, setItems] = useState([
63+
{ id: 1, isComplete: true, text: "First" },
64+
{ id: 2, isComplete: true, text: "Second" },
65+
{ id: 3, isComplete: false, text: "Third" }
66+
]);
67+
const [uid, setUID] = useState(4);
68+
69+
const handleClick = useCallback(() => {
70+
if (newItemText !== "") {
71+
setItems([
72+
...items,
73+
{
74+
id: uid,
75+
isComplete: false,
76+
text: newItemText
77+
}
78+
]);
79+
setUID(uid + 1);
80+
setNewItemText("");
81+
}
82+
}, [newItemText, items, uid]);
83+
84+
const handleKeyPress = useCallback(
85+
event => {
86+
if (event.key === "Enter") {
87+
handleClick();
88+
}
89+
},
90+
[handleClick]
91+
);
92+
93+
const handleChange = useCallback(
94+
event => {
95+
setNewItemText(event.currentTarget.value);
96+
},
97+
[setNewItemText]
98+
);
99+
100+
const removeItem = useCallback(
101+
itemToRemove => setItems(items.filter(item => item !== itemToRemove)),
102+
[items]
103+
);
104+
105+
const toggleItem = useCallback(
106+
itemToToggle => {
107+
const index = items.indexOf(itemToToggle);
108+
109+
setItems(
110+
items
111+
.slice(0, index)
112+
.concat({
113+
...itemToToggle,
114+
isComplete: !itemToToggle.isComplete
115+
})
116+
.concat(items.slice(index + 1))
117+
);
118+
},
119+
[items]
120+
);
121+
122+
return (
123+
<Fragment>
124+
<h1>List</h1>
125+
<input
126+
type="text"
127+
placeholder="New list item..."
128+
className="Input"
129+
value={newItemText}
130+
onChange={handleChange}
131+
onKeyPress={handleKeyPress}
132+
/>
133+
<button
134+
className="IconButton"
135+
disabled={newItemText === ""}
136+
onClick={handleClick}
137+
>
138+
<span role="img" aria-label="Add item">
139+
140+
</span>
141+
</button>
142+
<ul className="List">
143+
{items.map(item => (
144+
<ListItem
145+
key={item.id}
146+
item={item}
147+
removeItem={removeItem}
148+
toggleItem={toggleItem}
149+
/>
150+
))}
151+
</ul>
152+
</Fragment>
153+
);
154+
}
155+
156+
function ListItem({ item, removeItem, toggleItem }) {
157+
const handleDelete = useCallback(() => {
158+
removeItem(item);
159+
}, [item, removeItem]);
160+
161+
const handleToggle = useCallback(() => {
162+
toggleItem(item);
163+
}, [item, toggleItem]);
164+
165+
return (
166+
<li className="ListItem">
167+
<button className="IconButton" onClick={handleDelete}>
168+
🗑
169+
</button>
170+
<label className="Label">
171+
<input
172+
className="Input"
173+
checked={item.isComplete}
174+
onChange={handleToggle}
175+
type="checkbox"
176+
/>{" "}
177+
{item.text}
178+
</label>
179+
</li>
180+
);
181+
}
182+
183+
function SimpleValues() {
184+
return (
185+
<ChildComponent
186+
string="abc"
187+
emptyString=""
188+
number={123}
189+
undefined={undefined}
190+
null={null}
191+
nan={NaN}
192+
infinity={Infinity}
193+
true={true}
194+
false={false}
195+
/>
196+
);
197+
}
198+
199+
class Custom {
200+
_number = 42;
201+
get number() {
202+
return this._number;
203+
}
204+
}
205+
206+
function CustomObject() {
207+
return <ChildComponent customObject={new Custom()} />;
208+
}
209+
210+
const object = {
211+
string: "abc",
212+
longString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKJLMNOPQRSTUVWXYZ1234567890",
213+
emptyString: "",
214+
number: 123,
215+
boolean: true,
216+
undefined: undefined,
217+
null: null
218+
};
219+
220+
function ObjectProps() {
221+
return (
222+
<ChildComponent
223+
object={{
224+
outer: {
225+
inner: object
226+
}
227+
}}
228+
array={["first", "second", "third"]}
229+
objectInArray={[object]}
230+
arrayInObject={{ array: ["first", "second", "third"] }}
231+
deepObject={{
232+
// Known limitation: we won't go deeper than several levels.
233+
// In the future, we might offer a way to request deeper access on demand.
234+
a: {
235+
b: {
236+
c: {
237+
d: {
238+
e: {
239+
f: {
240+
g: {
241+
h: {
242+
i: {
243+
j: 10
244+
}
245+
}
246+
}
247+
}
248+
}
249+
}
250+
}
251+
}
252+
}
253+
}}
254+
/>
255+
);
256+
}
257+
258+
function ChildComponent(props: any) {
259+
return null;
260+
}
261+
262+
function InspectableElements() {
263+
return (
264+
<Fragment>
265+
<SimpleValues />
266+
<ObjectProps />
267+
<CustomObject />
268+
</Fragment>
269+
);
270+
}
271+
272+
function App() {
273+
return (
274+
<Fragment>
275+
<List />
276+
<InspectableElements />
277+
</Fragment>
278+
);
279+
}
280+
281+
ReactDOM.render(<App />, document.getElementById("root"));
282+
</script>
283+
</body>
284+
</html>

flow-typed/chrome.js

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// @flow
2+
3+
declare var chrome: {
4+
devtools: {
5+
network: {
6+
onNavigated: {
7+
addListener: (cb: (url: string) => void) => void,
8+
removeListener: (cb: () => void) => void,
9+
},
10+
},
11+
inspectedWindow: {
12+
eval: (code: string, cb?: (res: any, err: ?Object) => any) => void,
13+
tabId: number,
14+
},
15+
panels: {
16+
create: (
17+
title: string,
18+
icon: string,
19+
filename: string,
20+
cb: (panel: {
21+
onHidden: {
22+
addListener: (cb: (window: Object) => void) => void,
23+
},
24+
onShown: {
25+
addListener: (cb: (window: Object) => void) => void,
26+
},
27+
}) => void
28+
) => void,
29+
themeName: ?string,
30+
},
31+
},
32+
tabs: {
33+
create: (options: Object) => void,
34+
executeScript: (tabId: number, options: Object, fn: () => void) => void,
35+
onUpdated: {
36+
addListener: (
37+
fn: (tabId: number, changeInfo: Object, tab: Object) => void
38+
) => void,
39+
},
40+
query: (options: Object, fn: (tabArray: Array<Object>) => void) => void,
41+
},
42+
browserAction: {
43+
setIcon: (options: {
44+
tabId: number,
45+
path: { [key: string]: string },
46+
}) => void,
47+
setPopup: (options: {
48+
tabId: number,
49+
popup: string,
50+
}) => void,
51+
},
52+
runtime: {
53+
getURL: (path: string) => string,
54+
sendMessage: (config: Object) => void,
55+
connect: (
56+
config: Object
57+
) => {
58+
disconnect: () => void,
59+
onMessage: {
60+
addListener: (fn: (message: Object) => void) => void,
61+
},
62+
onDisconnect: {
63+
addListener: (fn: (message: Object) => void) => void,
64+
},
65+
postMessage: (data: Object) => void,
66+
},
67+
onConnect: {
68+
addListener: (
69+
fn: (port: {
70+
name: string,
71+
sender: {
72+
tab: {
73+
id: number,
74+
url: string,
75+
},
76+
},
77+
}) => void
78+
) => void,
79+
},
80+
onMessage: {
81+
addListener: (
82+
fn: (
83+
req: Object,
84+
sender: {
85+
url: string,
86+
tab: {
87+
id: number,
88+
},
89+
}
90+
) => void
91+
) => void,
92+
},
93+
},
94+
};

0 commit comments

Comments
 (0)