Remove examples/ folder (#9323)

This commit is contained in:
Dan Abramov
2017-04-07 14:05:17 -07:00
committed by Andrew Clark
parent b596e0bcaa
commit b3ec0cb488
37 changed files with 6585 additions and 752 deletions
+4
View File
@@ -9,7 +9,11 @@ docs/_site/
docs/vendor/bundle/
# This should be more like examples/**/thirdparty/** but
# we should fix https://github.com/facebook/esprima/pull/85 first
<<<<<<< HEAD
examples/
=======
fixtures/
>>>>>>> 4a37718... Remove examples/ folder (#9323)
# Ignore built files.
build/
coverage/
+4
View File
@@ -1,6 +1,10 @@
[ignore]
<<<<<<< HEAD
<PROJECT_ROOT>/examples/.*
=======
<PROJECT_ROOT>/fixtures/.*
>>>>>>> 4a37718... Remove examples/ folder (#9323)
<PROJECT_ROOT>/build/.*
<PROJECT_ROOT>/.*/node_modules/y18n/.*
<PROJECT_ROOT>/.*/__mocks__/.*
+5
View File
@@ -17,8 +17,13 @@ docs/.sass-cache
docs/js/*
docs/downloads/*.zip
docs/vendor/bundle
<<<<<<< HEAD
examples/shared/*.js
examples/**/bundle.js
=======
fixtures/dom/public/react-dom.js
fixtures/dom/public/react.js
>>>>>>> 4a37718... Remove examples/ folder (#9323)
test/the-files-to-test.generated.js
*.log*
chrome-user-data
-2
View File
@@ -56,5 +56,3 @@ const proto = Object.create(HTMLElement.prototype, {
});
document.registerElement('x-search', {prototype: proto});
```
You can also check out this [complete Web Components example on GitHub](https://github.com/facebook/react/tree/master/examples/webcomponents).
-5
View File
@@ -1,5 +0,0 @@
# React Examples
Here are some small React demos. Some use [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html) and some include third-party library integration.
For more fully-featured examples, check out [React TodoMVC](http://todomvc.com/examples/react/) and [React + Backbone TodoMVC](http://todomvc.com/examples/react-backbone/).
-3
View File
@@ -1,3 +0,0 @@
{
"presets": ["react", "es2015"]
}
-9
View File
@@ -1,9 +0,0 @@
# Basic example of using React with Browserify
Run `npm install` in the directory to install React from npm. Then run:
```sh
npm start
```
to produce `bundle.js` with example code and React.
-37
View File
@@ -1,37 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic CommonJS Example with Browserify</title>
<link rel="stylesheet" href="../shared/css/base.css" />
</head>
<body>
<h1>Basic CommonJS Example with Browserify</h1>
<div id="container">
<p>
To install React, follow the instructions on
<a href="https://github.com/facebook/react/">GitHub</a>.
</p>
<p>
If you can see this, React is <strong>not</strong> working right.
If you checked out the source from GitHub make sure to run <code>grunt</code>.
</p>
</div>
<h4>Example Details</h4>
<p>This is written with JSX in a CommonJS module and precompiled to vanilla JS by navigating to the example
directory
<pre>cd /path/to/react/examples/example-name</pre>
and running
<pre>npm start</pre>
<br>
(don't forget to install first)
<pre>npm install</pre>
<br>
</p>
<p>
Learn more about React at
<a href="https://facebook.github.io/react" target="_blank">facebook.github.io/react</a>.
</p>
<script src="bundle.js"></script>
</body>
</html>
-24
View File
@@ -1,24 +0,0 @@
'use strict';
var React = require('react');
var ReactDOM = require('react-dom');
var ExampleApplication = React.createClass({
render: function() {
var elapsed = Math.round(this.props.elapsed / 100);
var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
var message =
'React has been successfully running for ' + seconds + ' seconds.';
return <p>{message}</p>;
}
});
var start = new Date().getTime();
setInterval(function() {
ReactDOM.render(
<ExampleApplication elapsed={new Date().getTime() - start} />,
document.getElementById('container')
);
}, 50);
-19
View File
@@ -1,19 +0,0 @@
{
"name": "react-basic-commonjs-example",
"description": "Basic example of using React with CommonJS",
"private": true,
"main": "index.js",
"dependencies": {
"babel-preset-es2015": "^6.6.0",
"babel-preset-react": "^6.5.0",
"babelify": "^7.3.0",
"browserify": "^13.0.0",
"react": "^15.0.2",
"react-dom": "^15.0.2",
"watchify": "^3.7.0"
},
"scripts": {
"build": "browserify ./index.js -t babelify -o bundle.js",
"start": "watchify ./index.js -v -t babelify -o bundle.js"
}
}
-19
View File
@@ -1,19 +0,0 @@
var ExampleApplication = React.createClass({
render: function() {
var elapsed = Math.round(this.props.elapsed / 100);
var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
var message =
'React has been successfully running for ' + seconds + ' seconds.';
return <p>{message}</p>;
}
});
var start = new Date().getTime();
setInterval(function() {
ReactDOM.render(
<ExampleApplication elapsed={new Date().getTime() - start} />,
document.getElementById('container')
);
}, 50);
-19
View File
@@ -1,19 +0,0 @@
var ExampleApplication = React.createClass({
render: function() {
var elapsed = Math.round(this.props.elapsed / 100);
var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
var message =
'React has been successfully running for ' + seconds + ' seconds.';
return <p>{message}</p>;
}
});
var start = new Date().getTime();
setInterval(function() {
ReactDOM.render(
<ExampleApplication elapsed={new Date().getTime() - start} />,
document.getElementById('container')
);
}, 50);
-40
View File
@@ -1,40 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Example with Precompiled JSX</title>
<link rel="stylesheet" href="../shared/css/base.css" />
</head>
<body>
<h1>Basic Example with Precompiled JSX</h1>
<div id="container">
<p>
If you can see this, React is <strong>not</strong> running. Try running:
</p>
<pre>npm install -g babel-cli
cd examples/basic-jsx-precompile/
npm install babel-preset-react
babel example.js --presets react --out-dir=build</pre>
</div>
<h4>Example Details</h4>
<p>This is written with JSX in a separate file and precompiled to vanilla JS by running:</p>
<p><i>With Babel lower than 6.0</i></p>
<pre>npm install -g babel
cd examples/basic-jsx-precompile/
babel example.js --out-dir=build</pre>
<p><i>With Babel 6.0 or higher</i></p>
<pre>npm install -g babel-cli
cd examples/basic-jsx-precompile/
npm install babel-preset-react
babel example.js --presets react --out-dir=build</pre>
<p>
Learn more about React at
<a href="https://facebook.github.io/react" target="_blank">facebook.github.io/react</a>.
</p>
<script src="../../build/react.js"></script>
<script src="../../build/react-dom.js"></script>
<script src="build/example.js"></script>
</body>
</html>
-52
View File
@@ -1,52 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Basic Example</title>
<link rel="stylesheet" href="../shared/css/base.css" />
</head>
<body>
<h1>Basic Example</h1>
<div id="container">
<p>
To install React, follow the instructions on
<a href="https://github.com/facebook/react/">GitHub</a>.
</p>
<p>
If you can see this, React is <strong>not</strong> working right.
If you checked out the source from GitHub make sure to run <code>grunt</code>.
</p>
</div>
<h4>Example Details</h4>
<p>This is written in vanilla JavaScript (without JSX) and transformed in the browser.</p>
<p>
Learn more about React at
<a href="https://facebook.github.io/react" target="_blank">facebook.github.io/react</a>.
</p>
<script src="../../build/react.js"></script>
<script src="../../build/react-dom.js"></script>
<script>
var ExampleApplication = React.createClass({
render: function() {
var elapsed = Math.round(this.props.elapsed / 100);
var seconds = elapsed / 10 + (elapsed % 10 ? '' : '.0' );
var message =
'React has been successfully running for ' + seconds + ' seconds.';
return React.DOM.p(null, message);
}
});
// Call React.createFactory instead of directly call ExampleApplication({...}) in React.render
var ExampleApplicationFactory = React.createFactory(ExampleApplication);
var start = new Date().getTime();
setInterval(function() {
ReactDOM.render(
ExampleApplicationFactory({elapsed: new Date().getTime() - start}),
document.getElementById('container')
);
}, 50);
</script>
</body>
</html>
@@ -1,3 +0,0 @@
.example {
margin: 20px;
}
-139
View File
@@ -1,139 +0,0 @@
'use strict';
// Simple pure-React component so we don't have to remember
// Bootstrap's classes
var BootstrapButton = React.createClass({
render: function() {
return (
<a {...this.props}
href="javascript:;"
role="button"
className={(this.props.className || '') + ' btn'} />
);
}
});
var BootstrapModal = React.createClass({
// The following two methods are the only places we need to
// integrate Bootstrap or jQuery with the components lifecycle methods.
componentDidMount: function() {
// When the component is added, turn it into a modal
$(this.refs.root).modal({backdrop: 'static', keyboard: false, show: false});
// Bootstrap's modal class exposes a few events for hooking into modal
// functionality. Lets hook into one of them:
$(this.refs.root).on('hidden.bs.modal', this.handleHidden);
},
componentWillUnmount: function() {
$(this.refs.root).off('hidden.bs.modal', this.handleHidden);
},
close: function() {
$(this.refs.root).modal('hide');
},
open: function() {
$(this.refs.root).modal('show');
},
render: function() {
var confirmButton = null;
var cancelButton = null;
if (this.props.confirm) {
confirmButton = (
<BootstrapButton
onClick={this.handleConfirm}
className="btn-primary">
{this.props.confirm}
</BootstrapButton>
);
}
if (this.props.cancel) {
cancelButton = (
<BootstrapButton onClick={this.handleCancel} className="btn-default">
{this.props.cancel}
</BootstrapButton>
);
}
return (
<div className="modal fade" ref="root">
<div className="modal-dialog">
<div className="modal-content">
<div className="modal-header">
<button
type="button"
className="close"
onClick={this.handleCancel}>
&times;
</button>
<h3>{this.props.title}</h3>
</div>
<div className="modal-body">
{this.props.children}
</div>
<div className="modal-footer">
{cancelButton}
{confirmButton}
</div>
</div>
</div>
</div>
);
},
handleCancel: function() {
if (this.props.onCancel) {
this.props.onCancel();
}
},
handleConfirm: function() {
if (this.props.onConfirm) {
this.props.onConfirm();
}
},
handleHidden: function() {
if (this.props.onHidden) {
this.props.onHidden();
}
}
});
var Example = React.createClass({
handleCancel: function() {
if (confirm('Are you sure you want to cancel?')) {
this.refs.modal.close();
}
},
render: function() {
var modal = null;
modal = (
<BootstrapModal
ref="modal"
confirm="OK"
cancel="Cancel"
onCancel={this.handleCancel}
onConfirm={this.closeModal}
onHidden={this.handleModalDidClose}
title="Hello, Bootstrap!">
This is a React component powered by jQuery and Bootstrap!
</BootstrapModal>
);
return (
<div className="example">
{modal}
<BootstrapButton onClick={this.openModal} className="btn-default">
Open modal
</BootstrapButton>
</div>
);
},
openModal: function() {
this.refs.modal.open();
},
closeModal: function() {
this.refs.modal.close();
},
handleModalDidClose: function() {
alert("The modal has been dismissed!");
}
});
ReactDOM.render(<Example />, document.getElementById('jqueryexample'));
-6
View File
@@ -1,6 +0,0 @@
jQuery Mobile React Example
===========================
This example demonstrates how jQuery Mobile applications can be built with React.
The source code is based on jQuery Mobile's [pages-multi-page example](https://github.com/jquery/jquery-mobile/tree/master/demos/pages-multi-page).
-19
View File
@@ -1,19 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>jQuery Mobile React Example</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jquery-mobile/1.4.5/jquery.mobile.min.css" />
<link rel="stylesheet" href="https://demos.jquerymobile.com/1.4.5/_assets/css/jqm-demos.css" />
</head>
<body class="ui-mobile-viewport ui-overlay-a">
<div id="content"></div>
<script src="http://code.jquery.com/jquery-2.2.2.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-mobile/1.4.5/jquery.mobile.min.js"></script>
<script src="../../build/react.js"></script>
<script src="../../build/react-dom.js"></script>
<script src="js/app.js"></script>
</body>
</html>
-191
View File
@@ -1,191 +0,0 @@
/**
* jQuery Mobile React Example
*
* Main application script.
* For variety, this example is written in 100% JSHint-compliant JavaScript, not in JSX.
*
* Component structure:
*
* - App
* |-- JQueryMobilePage (one)
* | |-- JQueryMobileHeader
* | |-- JQueryMobileContent
* | | |-- PageOneContent
* | | |-- JQueryMobileButton
* | |-- JQueryMobileFooter
* |-- JQueryMobilePage (two)
* | |-- JQueryMobileHeader
* | |-- JQueryMobileContent
* | | |-- PageTwoContent
* | | |-- JQueryMobileButton
* | |-- JQueryMobileFooter
* |-- JQueryMobilePage (popup)
* |-- JQueryMobileHeader
* |-- JQueryMobileContent
* | |-- PagePopUpContent
* | |-- JQueryMobileButton
* |-- JQueryMobileFooter
*/
/* global document, React */
'use strict';
/** Main application component. */
var App = React.createClass({
displayName: 'App',
render: function() {
return React.DOM.div({className:'app'},
JQueryMobilePage({id:'one'}, PageOneContent(null)),
JQueryMobilePage({id:'two'}, PageTwoContent(null)),
JQueryMobilePage({id:'popup', headerTheme:'b'}, PagePopUpContent(null))
);
}
});
App = React.createFactory(App);
/** jQuery Mobile button component. */
var JQueryMobileButton = React.createClass({
displayName: 'JQueryMobileButton',
getDefaultProps: function() {
return {className:'ui-btn ui-shadow ui-corner-all'};
},
render: function() {
return React.DOM.p(null,
React.DOM.a(this.props, this.props.children)
);
}
});
JQueryMobileButton = React.createFactory(JQueryMobileButton);
/** jQuery Mobile page content component. */
var JQueryMobileContent = React.createClass({
displayName: 'JQueryMobileContent',
render: function() {
return React.DOM.div({role:'main', className:'ui-content'},
this.props.children
);
}
});
JQueryMobileContent = React.createFactory(JQueryMobileContent);
/** jQuery Mobile footer component. */
var JQueryMobileFooter = React.createClass({
displayName: 'JQueryMobileFooter',
render: function() {
return React.DOM.div({'data-role':'footer'},
React.DOM.h4(null, 'Page footer')
);
}
});
JQueryMobileFooter = React.createFactory(JQueryMobileFooter);
/** jQuery Mobile header component. */
var JQueryMobileHeader = React.createClass({
displayName: 'JQueryMobileHeader',
render: function() {
return React.DOM.div({'data-role':'header', 'data-theme':this.props.headerTheme},
React.DOM.h1(null, this.props.title)
);
}
});
JQueryMobileHeader = React.createFactory(JQueryMobileHeader);
/** jQuery Mobile page component. */
var JQueryMobilePage = React.createClass({
displayName: 'JQueryMobilePage',
getDefaultProps: function() {
return {'data-role':'page', 'data-theme':'a', headerTheme:'a'};
},
render: function() {
var props = {};
for (var key in this.props) {
props[key] = this.props[key];
}
return React.DOM.div(props,
JQueryMobileHeader({title:'Page ' + this.props.id, headerTheme:this.props.headerTheme}),
JQueryMobileContent(null, this.props.children),
JQueryMobileFooter(null)
);
}
});
JQueryMobilePage = React.createFactory(JQueryMobilePage);
/** Application page one component. */
var PageOneContent = React.createClass({
displayName: 'PageOneContent',
render: function() {
return React.DOM.div(null,
React.DOM.h2(null, 'One'),
React.DOM.p(null,
'I have an ',
React.DOM.code(null, 'id'),
' of "one" on my page container. I\'m first in the source order so I\'m shown when the page loads.'
),
React.DOM.p(null, 'This is a multi-page boilerplate template that you can copy to build your first jQuery Mobile page. This template contains multiple "page" containers inside, unlike a single page template that has just one page within it.'),
React.DOM.p(null, 'Just view the source and copy the code to get started. All the CSS and JS is linked to the jQuery CDN versions so this is super easy to set up. Remember to include a meta viewport tag in the head to set the zoom level.'),
React.DOM.p(null,
'You link to internal pages by referring to the ',
React.DOM.code(null, 'id'),
' of the page you want to show. For example, to ',
React.DOM.a({href:'#two'}, 'link'),
' to the page with an ',
React.DOM.code(null, 'id'),
' of "two", my link would have a ',
React.DOM.code(null, 'href="#two"'),
' in the code.'
),
React.DOM.h3(null, 'Show internal pages:'),
JQueryMobileButton({href:'#two'}, 'Show page "two"'),
JQueryMobileButton({href:'#popup', 'data-rel':'dialog', 'data-transition':'pop'}, 'Show page "popup" (as a dialog)')
);
}
});
PageOneContent = React.createFactory(PageOneContent);
/** Application page two component. */
var PageTwoContent = React.createClass({
displayName: 'PageTwoContent',
render: function() {
return React.DOM.div(null,
React.DOM.h2(null, 'Two'),
React.DOM.p(null, 'I have an id of "two" on my page container. I\'m the second page container in this multi-page template.'),
React.DOM.p(null, 'Notice that the theme is different for this page because we\'ve added a few ',
React.DOM.code(null, 'data-theme'),
' swatch assigments here to show off how flexible it is. You can add any content or widget to these pages, but we\'re keeping these simple.'),
JQueryMobileButton({href:'#one', 'data-direction':'reverse', className:'ui-btn ui-shadow ui-corner-all ui-btn-b'}, 'Back to page "one"')
);
}
});
PageTwoContent = React.createFactory(PageTwoContent);
/** Application popup page component. */
var PagePopUpContent = React.createClass({
displayName: 'PagePopUpContent',
render: function() {
return React.DOM.div(null,
React.DOM.h2(null, 'Popup'),
React.DOM.p(null, 'I have an id of "popup" on my page container and only look like a dialog because the link to me had a ',
React.DOM.code(null, 'data-rel="dialog"'),
' attribute which gives me this inset look and a ',
React.DOM.code(null, 'data-transition="pop"'),
' attribute to change the transition to pop. Without this, I\'d be styled as a normal page.'),
JQueryMobileButton({href:'#one', 'data-rel':'back', className:'ui-btn ui-shadow ui-corner-all ui-btn-inline ui-icon-back ui-btn-icon-left'}, 'Back to page "one"')
);
}
});
PagePopUpContent = React.createFactory(PagePopUpContent);
// Render application.
ReactDOM.render(App(null), document.getElementById('content'));
-59
View File
@@ -1,59 +0,0 @@
var QuadraticCalculator = React.createClass({
getInitialState: function() {
return {
a: 1,
b: 3,
c: -4
};
},
/**
* This function will be re-bound in render multiple times. Each .bind() will
* create a new function that calls this with the appropriate key as well as
* the event. The key is the key in the state object that the value should be
* mapped from.
*/
handleInputChange: function(key, event) {
var partialState = {};
partialState[key] = parseFloat(event.target.value);
this.setState(partialState);
},
render: function() {
var a = this.state.a;
var b = this.state.b;
var c = this.state.c;
var root = Math.sqrt(Math.pow(b, 2) - 4 * a * c);
var denominator = 2 * a;
var x1 = (-b + root) / denominator;
var x2 = (-b - root) / denominator;
return (
<div>
<strong>
<em>ax</em><sup>2</sup> + <em>bx</em> + <em>c</em> = 0
</strong>
<h4>Solve for <em>x</em>:</h4>
<p>
<label>
a: <input type="number" value={a} onChange={this.handleInputChange.bind(null, 'a')} />
</label>
<br />
<label>
b: <input type="number" value={b} onChange={this.handleInputChange.bind(null, 'b')} />
</label>
<br />
<label>
c: <input type="number" value={c} onChange={this.handleInputChange.bind(null, 'c')} />
</label>
<br />
x: <strong>{x1}, {x2}</strong>
</p>
</div>
);
}
});
ReactDOM.render(
<QuadraticCalculator />,
document.getElementById('container')
);
-62
View File
@@ -1,62 +0,0 @@
body {
background: #fff;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
font-size: 15px;
line-height: 1.7;
margin: 0;
padding: 30px;
}
a {
color: #4183c4;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
code {
background-color: #f8f8f8;
border: 1px solid #ddd;
border-radius: 3px;
font-family: "Bitstream Vera Sans Mono", Consolas, Courier, monospace;
font-size: 12px;
margin: 0 2px;
padding: 0px 5px;
}
h1, h2, h3, h4 {
font-weight: bold;
margin: 0 0 15px;
padding: 0;
}
h1 {
border-bottom: 1px solid #ddd;
font-size: 2.5em;
font-weight: bold;
margin: 0 0 15px;
padding: 0;
}
h2 {
border-bottom: 1px solid #eee;
font-size: 2em;
}
h3 {
font-size: 1.5em;
}
h4 {
font-size: 1.2em;
}
p, ul {
margin: 15px 0;
}
ul {
padding-left: 30px;
}
-44
View File
@@ -1,44 +0,0 @@
.example-enter,
.example-leave {
-webkit-transition: all .25s;
transition: all .25s;
}
.example-enter,
.example-leave.example-leave-active {
opacity: 0.01;
}
.example-leave.example-leave-active {
margin-left: -128px;
}
.example-enter {
margin-left: 128px;
}
.example-enter.example-enter-active,
.example-leave {
margin-left: 0;
opacity: 1;
}
.animateExample {
display: block;
height: 128px;
position: relative;
width: 384px;
}
.animateItem {
color: white;
font-size: 36px;
font-weight: bold;
height: 128px;
line-height: 128px;
position: absolute;
text-align: center;
-webkit-transition: all .25s; /* TODO: make this a move animation */
transition: all .25s; /* TODO: make this a move animation */
width: 128px;
}
+1
View File
@@ -0,0 +1 @@
NODE_PATH=../../build/packages
+14
View File
@@ -0,0 +1,14 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# dependencies
node_modules
# testing
coverage
# production
build
# misc
.DS_Store
npm-debug.log
+25
View File
@@ -0,0 +1,25 @@
# Fiber Debugger
This is a debugger handy for visualizing how [Fiber](https://github.com/facebook/react/issues/6170) works internally.
**It is only meant to be used by React contributors, and not by React users.**
It is likely that it might get broken at some point. If it's broken, ping [Dan](https://twitter.com/dan_abramov).
### Running
First, `npm run build` in React root repo folder.
Then `npm install` and `npm start` in this folder.
Open `http://localhost:3000` in Chrome.
### Features
* Edit code that uses `ReactNoop` renderer
* Visualize how relationships between fibers change over time
* Current tree is displayed in green
![fiber debugger](https://d17oy1vhnax1f7.cloudfront.net/items/3R2W1H2M3a0h3p1l133r/Screen%20Recording%202016-10-21%20at%2020.41.gif?v=e4323e51)
+18
View File
@@ -0,0 +1,18 @@
{
"name": "react-fiber-debugger",
"version": "0.0.1",
"private": true,
"devDependencies": {
"react-scripts": "0.9.0"
},
"dependencies": {
"dagre": "^0.7.4",
"pretty-format": "^4.2.1",
"react-draggable": "^2.2.2",
"react-motion": "^0.4.5"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build"
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

+13
View File
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
<script src="https://cdnjs.cloudflare.com/ajax/libs/babel-standalone/6.14.0/babel.min.js"></script>
<title>React App</title>
</head>
<body>
<div id="root"></div>
</body>
</html>
+196
View File
@@ -0,0 +1,196 @@
import React, { Component } from 'react';
import Draggable from 'react-draggable';
import ReactNoop from 'react-noop-renderer';
import ReactFiberInstrumentation from 'react-noop-renderer/lib/ReactFiberInstrumentation';
import Editor from './Editor';
import Fibers from './Fibers';
import describeFibers from './describeFibers';
function getFiberState(root, workInProgress) {
if (!root) {
return null;
}
return describeFibers(root.current, workInProgress);
}
const defaultCode = `
log('Render <div>Hello</div>');
ReactNoop.render(<div>Hello</div>);
ReactNoop.flush();
log('Render <h1>Goodbye</h1>');
ReactNoop.render(<h1>Goodbye</h1>);
ReactNoop.flush();
`;
class App extends Component {
constructor(props) {
super(props);
this.state = {
code: localStorage.getItem('fiber-debugger-code') || defaultCode,
isEditing: false,
history: [],
currentStep: 0,
show: {
alt: false,
child: true,
sibling: true,
return: false,
fx: false,
progressedChild: false,
progressedDel: false
}
};
}
componentDidMount() {
this.runCode(this.state.code);
}
runCode(code) {
let currentStage;
let currentRoot;
ReactFiberInstrumentation.debugTool = null;
ReactNoop.render(null);
ReactNoop.flush();
ReactFiberInstrumentation.debugTool = {
onMountContainer: (root) => {
currentRoot = root;
},
onUpdateContainer: (root) => {
currentRoot = root;
},
onBeginWork: (fiber) => {
const fibers = getFiberState(currentRoot, fiber);
const stage = currentStage;
this.setState(({ history }) => ({
history: [
...history, {
action: 'BEGIN',
fibers,
stage
}
]
}));
},
onCompleteWork: (fiber) => {
const fibers = getFiberState(currentRoot, fiber);
const stage = currentStage;
this.setState(({ history }) => ({
history: [
...history, {
action: 'COMPLETE',
fibers,
stage
}
]
}));
},
onCommitWork: (fiber) => {
const fibers = getFiberState(currentRoot, fiber);
const stage = currentStage;
this.setState(({ history }) => ({
history: [
...history, {
action: 'COMMIT',
fibers,
stage
}
]
}));
},
};
window.React = React;
window.ReactNoop = ReactNoop;
window.expect = () => ({
toBe() {},
toContain() {},
toEqual() {},
});
window.log = s => currentStage = s;
// eslint-disable-next-line
eval(window.Babel.transform(code, {
presets: ['react', 'es2015']
}).code);
}
handleEdit = (e) => {
e.preventDefault();
this.setState({
isEditing: true
});
}
handleCloseEdit = (nextCode) => {
localStorage.setItem('fiber-debugger-code', nextCode);
this.setState({
isEditing: false,
history: [],
currentStep: 0,
code: nextCode
});
this.runCode(nextCode);
}
render() {
const { history, currentStep, isEditing, code } = this.state;
if (isEditing) {
return <Editor code={code} onClose={this.handleCloseEdit} />;
}
const { fibers, action, stage } = history[currentStep] || {};
let friendlyAction;
if (fibers) {
let wipFiber = fibers.descriptions[fibers.workInProgressID];
let friendlyFiber = wipFiber.type || wipFiber.tag + ' #' + wipFiber.id;
friendlyAction = `After ${action} on ${friendlyFiber}`;
}
return (
<div style={{ height: '100%' }}>
{fibers &&
<Draggable>
<Fibers fibers={fibers} show={this.state.show} />
</Draggable>
}
<div style={{
width: '100%',
textAlign: 'center',
position: 'fixed',
bottom: 0,
padding: 10,
zIndex: 1,
backgroundColor: '#fafafa',
border: '1px solid #ccc'
}}>
<input
type="range"
style={{ width: '25%' }}
min={0}
max={history.length - 1}
value={currentStep}
onChange={e => this.setState({ currentStep: Number(e.target.value) })}
/>
<p>Step {currentStep}: {friendlyAction} (<a style={{ color: 'gray' }} onClick={this.handleEdit} href='#'>Edit</a>)</p>
{stage && <p>Stage: {stage}</p>}
{Object.keys(this.state.show).map(key =>
<label style={{ marginRight: '10px' }} key={key}>
<input
type="checkbox"
checked={this.state.show[key]}
onChange={e => {
this.setState(({ show }) => ({
show: {...show, [key]: !show[key]}
}));
}} />
{key}
</label>
)}
</div>
</div>
);
}
}
export default App;
+35
View File
@@ -0,0 +1,35 @@
import React, { Component } from 'react';
class Editor extends Component {
constructor(props) {
super(props);
this.state = {
code: props.code
};
}
render() {
return (
<div style={{
height: '100%',
width: '100%'
}}>
<textarea
value={this.state.code}
onChange={e => this.setState({ code: e.target.value })}
style={{
height: '80%',
width: '100%',
fontSize: '15px'
}} />
<div style={{ height: '20%', textAlign: 'center' }}>
<button onClick={() => this.props.onClose(this.state.code)} style={{ fontSize: 'large' }}>
Run
</button>
</div>
</div>
)
}
}
export default Editor;
+395
View File
@@ -0,0 +1,395 @@
import React from 'react';
import { Motion, spring } from 'react-motion';
import dagre from 'dagre';
import prettyFormat from 'pretty-format';
import reactElement from 'pretty-format/plugins/ReactElement';
function getFiberColor(fibers, id) {
if (fibers.currentIDs.indexOf(id) > -1) {
return 'lightgreen';
}
if (id === fibers.workInProgressID) {
return 'yellow';
}
return 'lightyellow';
}
function Graph(props) {
var g = new dagre.graphlib.Graph();
g.setGraph({
width: 1000,
height: 1000,
nodesep: 50,
edgesep: 150,
ranksep: 150,
marginx: 100,
marginy: 100,
});
var edgeLabels = {};
React.Children.forEach(props.children, function(child) {
if (!child) {
return;
}
if (child.type.isVertex) {
g.setNode(child.key, {
label: child,
width: child.props.width,
height: child.props.height
});
} else if (child.type.isEdge) {
const relationshipKey = child.props.source + ':' + child.props.target;
if (!edgeLabels[relationshipKey]) {
edgeLabels[relationshipKey] = [];
}
edgeLabels[relationshipKey].push(child);
}
});
Object.keys(edgeLabels).forEach(key => {
const children = edgeLabels[key];
const child = children[0];
g.setEdge(child.props.source, child.props.target, {
label: child,
allChildren: children.map(c => c.props.children),
weight: child.props.weight
});
});
dagre.layout(g);
var activeNode = g.nodes().map(v => g.node(v)).find(node =>
node.label.props.isActive
);
const [winX, winY] = [window.innerWidth / 2, window.innerHeight / 2]
var focusDx = activeNode ? (winX - activeNode.x) : 0;
var focusDy = activeNode ? (winY - activeNode.y) : 0;
var nodes = g.nodes().map(v => {
var node = g.node(v);
return (
<Motion style={{
x: props.isDragging ? node.x + focusDx : spring(node.x + focusDx),
y: props.isDragging ? node.y + focusDy : spring(node.y + focusDy)
}} key={node.label.key}>
{interpolatingStyle =>
React.cloneElement(node.label, {
x: interpolatingStyle.x + props.dx,
y: interpolatingStyle.y + props.dy,
vanillaX: node.x,
vanillaY: node.y,
})
}
</Motion>
);
});
var edges = g.edges().map(e => {
var edge = g.edge(e);
let idx = 0;
return (
<Motion style={edge.points.reduce((bag, point) => {
bag[idx + ':x'] = props.isDragging ? point.x + focusDx : spring(point.x + focusDx);
bag[idx + ':y'] = props.isDragging ? point.y + focusDy : spring(point.y + focusDy);
idx++;
return bag;
}, {})} key={edge.label.key}>
{interpolatedStyle => {
let points = [];
Object.keys(interpolatedStyle).forEach(key => {
const [idx, prop] = key.split(':');
if (!points[idx]) {
points[idx] = { x: props.dx, y: props.dy };
}
points[idx][prop] += interpolatedStyle[key];
});
return React.cloneElement(edge.label, {
points,
id: edge.label.key,
children: edge.allChildren.join(', ')
});
}}
</Motion>
);
});
return (
<div style={{
position: 'relative',
height: '100%'
}}>
{edges}
{nodes}
</div>
);
}
function Vertex(props) {
if (Number.isNaN(props.x) || Number.isNaN(props.y)) {
return null;
}
return (
<div style={{
position: 'absolute',
border: '1px solid black',
left: (props.x-(props.width/2)),
top: (props.y-(props.height/2)),
width: props.width,
height: props.height,
overflow: 'hidden',
padding: '4px',
wordWrap: 'break-word'
}}>
{props.children}
</div>
);
}
Vertex.isVertex = true;
const strokes = {
alt: 'blue',
child: 'green',
sibling: 'darkgreen',
return: 'red',
fx: 'purple',
progressedChild: 'cyan',
progressedDel: 'brown'
};
function Edge(props) {
var points = props.points;
var path = "M" + points[0].x + " " + points[0].y + " ";
if (!points[0].x || !points[0].y) {
return null;
}
for (var i = 1; i < points.length; i++) {
path += "L" + points[i].x + " " + points[i].y + " ";
if (!points[i].x || !points[i].y) {
return null;
}
}
var lineID = props.id;
return (
<svg width="100%" height="100%" style={{
position: 'absolute',
left: 0,
right: 0,
top: 0,
bottom: 0,
}}>
<defs>
<path d={path} id={lineID} />
<marker id="markerCircle" markerWidth="8" markerHeight="8" refX="5" refY="5">
<circle cx="5" cy="5" r="3" style={{stroke: 'none', fill:'black'}}/>
</marker>
<marker id="markerArrow" markerWidth="13" markerHeight="13" refX="2" refY="6"
orient="auto">
<path d="M2,2 L2,11 L10,6 L2,2" style={{fill: 'black'}} />
</marker>
</defs>
<use xlinkHref={`#${lineID}`} fill="none" stroke={strokes[props.kind]} style={{
markerStart: 'url(#markerCircle)',
markerEnd: 'url(#markerArrow)'
}} />
<text>
<textPath xlinkHref={`#${lineID}`}>
{'     '}{props.children}
</textPath>
</text>
</svg>
);
}
Edge.isEdge = true;
function formatPriority(priority) {
switch (priority) {
case 1:
return 'synchronous';
case 2:
return 'task';
case 3:
return 'animation';
case 4:
return 'hi-pri work';
case 5:
return 'lo-pri work';
case 6:
return 'offscreen work';
default:
throw new Error('Unknown priority.');
}
}
export default function Fibers({ fibers, show, ...rest }) {
const items = Object.keys(fibers.descriptions).map(id =>
fibers.descriptions[id]
);
const isDragging = rest.className.indexOf('dragging') > -1;
const [_, sdx, sdy] = rest.style.transform.match(/translate\((\-?\d+)px,(\-?\d+)px\)/) || [];
const dx = Number(sdx);
const dy = Number(sdy);
return (
<div {...rest} style={{
width: '100%',
height: '100%',
position: 'absolute',
top: 0,
left: 0,
...rest.style,
transform: null
}}>
<Graph
className="graph"
dx={dx}
dy={dy}
isDragging={isDragging}
>
{items.map(fiber => [
<Vertex
key={fiber.id}
width={200}
height={100}
isActive={fiber.id === fibers.workInProgressID}>
<div
style={{
width: '100%',
height: '100%',
backgroundColor: getFiberColor(fibers, fiber.id)
}}
title={prettyFormat(fiber, { plugins: [reactElement ]})}>
<small>{fiber.tag} #{fiber.id}</small>
<br />
{fiber.type}
<br />
{fibers.currentIDs.indexOf(fiber.id) === -1 ?
<small>
{fiber.pendingWorkPriority !== 0 && [
<span style={{
fontWeight: fiber.pendingWorkPriority <= fiber.progressedPriority ?
'bold' :
'normal'
}} key="span">
Needs: {formatPriority(fiber.pendingWorkPriority)}
</span>,
<br key="br" />
]}
{fiber.progressedPriority !== 0 && [
`Finished: ${formatPriority(fiber.progressedPriority)}`,
<br key="br" />
]}
{fiber.memoizedProps !== null && fiber.pendingProps !== null && [
fiber.memoizedProps === fiber.pendingProps ?
'Can reuse memoized.' :
'Cannot reuse memoized.',
<br />
]}
</small> :
<small>
Committed
</small>
}
</div>
</Vertex>,
fiber.child && show.child &&
<Edge
source={fiber.id}
target={fiber.child}
kind="child"
weight={1000}
key={`${fiber.id}-${fiber.child}-child`}>
child
</Edge>,
fiber.progressedChild && show.progressedChild &&
<Edge
source={fiber.id}
target={fiber.progressedChild}
kind="progressedChild"
weight={1000}
key={`${fiber.id}-${fiber.progressedChild}-pChild`}>
pChild
</Edge>,
fiber.sibling && show.sibling &&
<Edge
source={fiber.id}
target={fiber.sibling}
kind="sibling"
weight={2000}
key={`${fiber.id}-${fiber.sibling}-sibling`}>
sibling
</Edge>,
fiber.return && show.return &&
<Edge
source={fiber.id}
target={fiber.return}
kind="return"
weight={1000}
key={`${fiber.id}-${fiber.return}-return`}>
return
</Edge>,
fiber.nextEffect && show.fx &&
<Edge
source={fiber.id}
target={fiber.nextEffect}
kind="fx"
weight={100}
key={`${fiber.id}-${fiber.nextEffect}-nextEffect`}>
nextFx
</Edge>,
fiber.firstEffect && show.fx &&
<Edge
source={fiber.id}
target={fiber.firstEffect}
kind="fx"
weight={100}
key={`${fiber.id}-${fiber.firstEffect}-firstEffect`}>
firstFx
</Edge>,
fiber.lastEffect && show.fx &&
<Edge
source={fiber.id}
target={fiber.lastEffect}
kind="fx"
weight={100}
key={`${fiber.id}-${fiber.lastEffect}-lastEffect`}>
lastFx
</Edge>,
fiber.progressedFirstDeletion && show.progressedDel &&
<Edge
source={fiber.id}
target={fiber.progressedFirstDeletion}
kind="progressedDel"
weight={100}
key={`${fiber.id}-${fiber.progressedFirstDeletion}-pFD`}>
pFDel
</Edge>,
fiber.progressedLastDeletion && show.progressedDel &&
<Edge
source={fiber.id}
target={fiber.progressedLastDeletion}
kind="progressedDel"
weight={100}
key={`${fiber.id}-${fiber.progressedLastDeletion}-pLD`}>
pLDel
</Edge>,
fiber.alternate && show.alt &&
<Edge
source={fiber.id}
target={fiber.alternate}
kind="alt"
weight={10}
key={`${fiber.id}-${fiber.alternate}-alt`}>
alt
</Edge>,
])}
</Graph>
</div>
);
}
@@ -0,0 +1,96 @@
let nextFiberID = 1;
const fiberIDMap = new WeakMap();
function getFiberUniqueID(fiber) {
if (!fiberIDMap.has(fiber)) {
fiberIDMap.set(fiber, nextFiberID++);
}
return fiberIDMap.get(fiber);
}
function getFriendlyTag(tag) {
switch (tag) {
case 0:
return '[indeterminate]';
case 1:
return '[fn]';
case 2:
return '[class]';
case 3:
return '[root]';
case 4:
return '[portal]';
case 5:
return '[host]';
case 6:
return '[text]';
case 7:
return '[coroutine]';
case 8:
return '[handler]';
case 9:
return '[yield]';
case 10:
return '[frag]';
default:
throw new Error('Unknown tag.');
}
}
export default function describeFibers(rootFiber, workInProgress) {
let descriptions = {};
function acknowledgeFiber(fiber) {
if (!fiber) {
return null;
}
if (!fiber.return && fiber.tag !== 3) {
return null;
}
const id = getFiberUniqueID(fiber);
if (descriptions[id]) {
return id;
}
descriptions[id] = {};
Object.assign(descriptions[id], {
...fiber,
id: id,
tag: getFriendlyTag(fiber.tag),
type: (fiber.type && ('<' + (fiber.type.name || fiber.type) + '>')),
stateNode: `[${typeof fiber.stateNode}]`,
return: acknowledgeFiber(fiber.return),
child: acknowledgeFiber(fiber.child),
sibling: acknowledgeFiber(fiber.sibling),
nextEffect: acknowledgeFiber(fiber.nextEffect),
firstEffect: acknowledgeFiber(fiber.firstEffect),
lastEffect: acknowledgeFiber(fiber.lastEffect),
progressedChild: acknowledgeFiber(fiber.progressedChild),
progressedFirstDeletion: acknowledgeFiber(fiber.progressedFirstDeletion),
progressedLastDeletion: acknowledgeFiber(fiber.progressedLastDeletion),
alternate: acknowledgeFiber(fiber.alternate),
});
return id;
}
const rootID = acknowledgeFiber(rootFiber);
const workInProgressID = acknowledgeFiber(workInProgress);
let currentIDs = new Set();
function markAsCurent(id) {
currentIDs.add(id);
const fiber = descriptions[id];
if (fiber.sibling) {
markAsCurent(fiber.sibling);
}
if (fiber.child) {
markAsCurent(fiber.child);
}
}
markAsCurent(rootID);
return {
descriptions,
rootID,
currentIDs: Array.from(currentIDs),
workInProgressID
};
}
+15
View File
@@ -0,0 +1,15 @@
html, body {
margin: 0;
padding: 0;
font-family: sans-serif;
height: 100vh;
cursor: -webkit-grab; cursor: -moz-grab;
}
#root {
height: 100vh;
}
* {
box-sizing: border-box;
}
+9
View File
@@ -0,0 +1,9 @@
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import './index.css';
ReactDOM.render(
<App />,
document.getElementById('root')
);
File diff suppressed because it is too large Load Diff
+14
View File
@@ -0,0 +1,14 @@
<html>
<body>
<script src="../../build/react.js"></script>
<script src="../../build/react-dom.js"></script>
<script src="https://unpkg.com/babel-standalone@6/babel.js"></script>
<div id="container"></div>
<script type="text/babel">
ReactDOM.render(
<h1>Hello World!</h1>,
document.getElementById('container')
);
</script>
</body>
</html>