-
Notifications
You must be signed in to change notification settings - Fork 47.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
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
- Loading branch information
Brian Vaughn
authored
Jul 13, 2019
1 parent
39a811d
commit 0f2fb5b
Showing
77 changed files
with
3,911 additions
and
387 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,284 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<title>TODO List</title> | ||
|
||
<!-- DevTools --> | ||
<script src="http://localhost:8097"></script> | ||
|
||
<script src="https://unpkg.com/react@16/umd/react.development.js"></script> | ||
<script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js"></script> | ||
|
||
<!-- Don't use this in production: --> | ||
<script src="https://unpkg.com/babel-standalone@6.15.0/babel.min.js"></script> | ||
|
||
<style type="text/css"> | ||
.Input { | ||
font-size: 1rem; | ||
padding: 0.25rem; | ||
} | ||
|
||
.IconButton { | ||
padding: 0.25rem; | ||
border: none; | ||
background: none; | ||
cursor: pointer; | ||
} | ||
|
||
.List { | ||
margin: 0.5rem 0 0; | ||
padding: 0; | ||
} | ||
|
||
.ListItem { | ||
list-style-type: none; | ||
} | ||
|
||
.Label { | ||
cursor: pointer; | ||
padding: 0.25rem; | ||
color: #555; | ||
} | ||
.Label:hover { | ||
color: #000; | ||
} | ||
|
||
.IconButton { | ||
padding: 0.25rem; | ||
border: none; | ||
background: none; | ||
cursor: pointer; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<div id="root"></div> | ||
<script type="text/babel"> | ||
const { Fragment, useCallback, useState } = React; | ||
|
||
function List(props) { | ||
const [newItemText, setNewItemText] = useState(""); | ||
const [items, setItems] = useState([ | ||
{ id: 1, isComplete: true, text: "First" }, | ||
{ id: 2, isComplete: true, text: "Second" }, | ||
{ id: 3, isComplete: false, text: "Third" } | ||
]); | ||
const [uid, setUID] = useState(4); | ||
|
||
const handleClick = useCallback(() => { | ||
if (newItemText !== "") { | ||
setItems([ | ||
...items, | ||
{ | ||
id: uid, | ||
isComplete: false, | ||
text: newItemText | ||
} | ||
]); | ||
setUID(uid + 1); | ||
setNewItemText(""); | ||
} | ||
}, [newItemText, items, uid]); | ||
|
||
const handleKeyPress = useCallback( | ||
event => { | ||
if (event.key === "Enter") { | ||
handleClick(); | ||
} | ||
}, | ||
[handleClick] | ||
); | ||
|
||
const handleChange = useCallback( | ||
event => { | ||
setNewItemText(event.currentTarget.value); | ||
}, | ||
[setNewItemText] | ||
); | ||
|
||
const removeItem = useCallback( | ||
itemToRemove => setItems(items.filter(item => item !== itemToRemove)), | ||
[items] | ||
); | ||
|
||
const toggleItem = useCallback( | ||
itemToToggle => { | ||
const index = items.indexOf(itemToToggle); | ||
|
||
setItems( | ||
items | ||
.slice(0, index) | ||
.concat({ | ||
...itemToToggle, | ||
isComplete: !itemToToggle.isComplete | ||
}) | ||
.concat(items.slice(index + 1)) | ||
); | ||
}, | ||
[items] | ||
); | ||
|
||
return ( | ||
<Fragment> | ||
<h1>List</h1> | ||
<input | ||
type="text" | ||
placeholder="New list item..." | ||
className="Input" | ||
value={newItemText} | ||
onChange={handleChange} | ||
onKeyPress={handleKeyPress} | ||
/> | ||
<button | ||
className="IconButton" | ||
disabled={newItemText === ""} | ||
onClick={handleClick} | ||
> | ||
<span role="img" aria-label="Add item"> | ||
➕ | ||
</span> | ||
</button> | ||
<ul className="List"> | ||
{items.map(item => ( | ||
<ListItem | ||
key={item.id} | ||
item={item} | ||
removeItem={removeItem} | ||
toggleItem={toggleItem} | ||
/> | ||
))} | ||
</ul> | ||
</Fragment> | ||
); | ||
} | ||
|
||
function ListItem({ item, removeItem, toggleItem }) { | ||
const handleDelete = useCallback(() => { | ||
removeItem(item); | ||
}, [item, removeItem]); | ||
|
||
const handleToggle = useCallback(() => { | ||
toggleItem(item); | ||
}, [item, toggleItem]); | ||
|
||
return ( | ||
<li className="ListItem"> | ||
<button className="IconButton" onClick={handleDelete}> | ||
🗑 | ||
</button> | ||
<label className="Label"> | ||
<input | ||
className="Input" | ||
checked={item.isComplete} | ||
onChange={handleToggle} | ||
type="checkbox" | ||
/>{" "} | ||
{item.text} | ||
</label> | ||
</li> | ||
); | ||
} | ||
|
||
function SimpleValues() { | ||
return ( | ||
<ChildComponent | ||
string="abc" | ||
emptyString="" | ||
number={123} | ||
undefined={undefined} | ||
null={null} | ||
nan={NaN} | ||
infinity={Infinity} | ||
true={true} | ||
false={false} | ||
/> | ||
); | ||
} | ||
|
||
class Custom { | ||
_number = 42; | ||
get number() { | ||
return this._number; | ||
} | ||
} | ||
|
||
function CustomObject() { | ||
return <ChildComponent customObject={new Custom()} />; | ||
} | ||
|
||
const object = { | ||
string: "abc", | ||
longString: "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKJLMNOPQRSTUVWXYZ1234567890", | ||
emptyString: "", | ||
number: 123, | ||
boolean: true, | ||
undefined: undefined, | ||
null: null | ||
}; | ||
|
||
function ObjectProps() { | ||
return ( | ||
<ChildComponent | ||
object={{ | ||
outer: { | ||
inner: object | ||
} | ||
}} | ||
array={["first", "second", "third"]} | ||
objectInArray={[object]} | ||
arrayInObject={{ array: ["first", "second", "third"] }} | ||
deepObject={{ | ||
// Known limitation: we won't go deeper than several levels. | ||
// In the future, we might offer a way to request deeper access on demand. | ||
a: { | ||
b: { | ||
c: { | ||
d: { | ||
e: { | ||
f: { | ||
g: { | ||
h: { | ||
i: { | ||
j: 10 | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
}} | ||
/> | ||
); | ||
} | ||
|
||
function ChildComponent(props: any) { | ||
return null; | ||
} | ||
|
||
function InspectableElements() { | ||
return ( | ||
<Fragment> | ||
<SimpleValues /> | ||
<ObjectProps /> | ||
<CustomObject /> | ||
</Fragment> | ||
); | ||
} | ||
|
||
function App() { | ||
return ( | ||
<Fragment> | ||
<List /> | ||
<InspectableElements /> | ||
</Fragment> | ||
); | ||
} | ||
|
||
ReactDOM.render(<App />, document.getElementById("root")); | ||
</script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
// @flow | ||
|
||
declare var chrome: { | ||
devtools: { | ||
network: { | ||
onNavigated: { | ||
addListener: (cb: (url: string) => void) => void, | ||
removeListener: (cb: () => void) => void, | ||
}, | ||
}, | ||
inspectedWindow: { | ||
eval: (code: string, cb?: (res: any, err: ?Object) => any) => void, | ||
tabId: number, | ||
}, | ||
panels: { | ||
create: ( | ||
title: string, | ||
icon: string, | ||
filename: string, | ||
cb: (panel: { | ||
onHidden: { | ||
addListener: (cb: (window: Object) => void) => void, | ||
}, | ||
onShown: { | ||
addListener: (cb: (window: Object) => void) => void, | ||
}, | ||
}) => void | ||
) => void, | ||
themeName: ?string, | ||
}, | ||
}, | ||
tabs: { | ||
create: (options: Object) => void, | ||
executeScript: (tabId: number, options: Object, fn: () => void) => void, | ||
onUpdated: { | ||
addListener: ( | ||
fn: (tabId: number, changeInfo: Object, tab: Object) => void | ||
) => void, | ||
}, | ||
query: (options: Object, fn: (tabArray: Array<Object>) => void) => void, | ||
}, | ||
browserAction: { | ||
setIcon: (options: { | ||
tabId: number, | ||
path: { [key: string]: string }, | ||
}) => void, | ||
setPopup: (options: { | ||
tabId: number, | ||
popup: string, | ||
}) => void, | ||
}, | ||
runtime: { | ||
getURL: (path: string) => string, | ||
sendMessage: (config: Object) => void, | ||
connect: ( | ||
config: Object | ||
) => { | ||
disconnect: () => void, | ||
onMessage: { | ||
addListener: (fn: (message: Object) => void) => void, | ||
}, | ||
onDisconnect: { | ||
addListener: (fn: (message: Object) => void) => void, | ||
}, | ||
postMessage: (data: Object) => void, | ||
}, | ||
onConnect: { | ||
addListener: ( | ||
fn: (port: { | ||
name: string, | ||
sender: { | ||
tab: { | ||
id: number, | ||
url: string, | ||
}, | ||
}, | ||
}) => void | ||
) => void, | ||
}, | ||
onMessage: { | ||
addListener: ( | ||
fn: ( | ||
req: Object, | ||
sender: { | ||
url: string, | ||
tab: { | ||
id: number, | ||
}, | ||
} | ||
) => void | ||
) => void, | ||
}, | ||
}, | ||
}; |
Oops, something went wrong.