///
///
///
///
///
///
///
///
///
///
///
import React = require("react");
import ReactDOM = require("react-dom");
import ReactDOMServer = require("react-dom/server");
import createFragment = require("react-addons-create-fragment");
import CSSTransitionGroup = require("react-addons-css-transition-group");
import LinkedStateMixin = require("react-addons-linked-state-mixin");
import Perf = require("react-addons-perf");
import PureRenderMixin = require("react-addons-pure-render-mixin");
import shallowCompare = require("react-addons-shallow-compare");
import TestUtils = require("react-addons-test-utils");
import TransitionGroup = require("react-addons-transition-group");
import update = require("react-addons-update");
interface Props {
hello: string;
world?: string;
foo: number;
}
interface State {
inputValue?: string;
seconds?: number;
}
interface Context {
someValue?: string;
}
interface ChildContext {
someOtherValue: string;
}
interface MyComponent extends React.Component {
reset(): void;
}
var props: Props & React.ClassAttributes<{}> = {
key: 42,
ref: "myComponent42",
hello: "world",
foo: 42
};
var container: Element;
//
// Top-Level API
// --------------------------------------------------------------------------
var ClassicComponent: React.ClassicComponentClass =
React.createClass({
getDefaultProps() {
return {
hello: undefined,
world: "peace",
foo: undefined
};
},
getInitialState() {
return {
inputValue: this.context.someValue,
seconds: this.props.foo
};
},
reset() {
this.replaceState(this.getInitialState());
},
render() {
return React.DOM.div(null,
React.DOM.input({
ref: input => this._input = input,
value: this.state.inputValue
}));
}
});
class ModernComponent extends React.Component
implements MyComponent, React.ChildContextProvider {
static propTypes: React.ValidationMap = {
foo: React.PropTypes.number
};
static contextTypes: React.ValidationMap = {
someValue: React.PropTypes.string
};
static childContextTypes: React.ValidationMap = {
someOtherValue: React.PropTypes.string
};
context: Context;
getChildContext() {
return {
someOtherValue: "foo"
};
}
state = {
inputValue: this.context.someValue,
seconds: this.props.foo
};
reset() {
this._myComponent.reset();
this.setState({
inputValue: this.context.someValue,
seconds: this.props.foo
});
}
private _myComponent: MyComponent;
private _input: HTMLInputElement;
render() {
return React.DOM.div(null,
React.DOM.input({
ref: input => this._input = input,
value: this.state.inputValue
}));
}
shouldComponentUpdate(nextProps: Props, nextState: State, nextContext: any): boolean {
return shallowCompare(this, nextProps, nextState);
}
}
interface SCProps {
foo?: number;
}
function StatelessComponent(props: SCProps) {
return React.DOM.div(null, props.foo);
};
namespace StatelessComponent {
export var displayName = "StatelessComponent";
export var defaultProps = { foo: 42 };
}
var StatelessComponent2: React.SFC =
// props is contextually typed
props => React.DOM.div(null, props.foo);
StatelessComponent2.displayName = "StatelessComponent2";
StatelessComponent2.defaultProps = {
foo: 42
};
// React.createFactory
var factory: React.CFactory =
React.createFactory(ModernComponent);
var factoryElement: React.CElement =
factory(props);
var statelessFactory: React.SFCFactory =
React.createFactory(StatelessComponent);
var statelessElement: React.SFCElement =
statelessFactory(props);
var classicFactory: React.ClassicFactory =
React.createFactory(ClassicComponent);
var classicFactoryElement: React.ClassicElement =
classicFactory(props);
var domFactory: React.DOMFactory =
React.createFactory("foo");
var domFactoryElement: React.DOMElement =
domFactory();
// React.createElement
var element: React.CElement =
React.createElement(ModernComponent, props);
var statelessElement: React.SFCElement =
React.createElement(StatelessComponent, props);
var classicElement: React.ClassicElement =
React.createElement(ClassicComponent, props);
var domElement: React.ReactHTMLElement =
React.createElement("div");
// React.cloneElement
var clonedElement: React.CElement =
React.cloneElement(element, { foo: 43 });
var clonedElement2: React.CElement =
// known problem: cloning with key or ref requires cast
React.cloneElement(element, >{
ref: c => c.reset()
});
var clonedElement3: React.CElement =
React.cloneElement(element, <{ foo: number } & React.Attributes>{
key: "8eac7",
foo: 55
});
var clonedStatelessElement: React.SFCElement =
// known problem: cloning with optional props don't work properly
// workaround: cast to actual props type
React.cloneElement(statelessElement, { foo: 44 });
var clonedClassicElement: React.ClassicElement =
React.cloneElement(classicElement, props);
var clonedDOMElement: React.ReactHTMLElement =
React.cloneElement(domElement, {
className: "clonedElement"
});
// React.render
var component: ModernComponent =
ReactDOM.render(element, container);
var classicComponent: React.ClassicComponent =
ReactDOM.render(classicElement, container);
var domComponent: Element =
ReactDOM.render(domElement, container);
// Other Top-Level API
var unmounted: boolean = ReactDOM.unmountComponentAtNode(container);
var str: string = ReactDOMServer.renderToString(element);
var markup: string = ReactDOMServer.renderToStaticMarkup(element);
var notValid: boolean = React.isValidElement(props); // false
var isValid = React.isValidElement(element); // true
var domNode: Element = ReactDOM.findDOMNode(component);
domNode = ReactDOM.findDOMNode(domNode);
//
// React Elements
// --------------------------------------------------------------------------
var type: React.ComponentClass = element.type;
var elementProps: Props = element.props;
var key: React.Key = element.key;
var t: React.ReactType;
var name = typeof t === "string" ? t : t.displayName;
//
// React Components
// --------------------------------------------------------------------------
var displayName: string = ClassicComponent.displayName;
var defaultProps: Props = ClassicComponent.getDefaultProps();
var propTypes: React.ValidationMap = ClassicComponent.propTypes;
//
// Component API
// --------------------------------------------------------------------------
// modern
var componentState: State = component.state;
component.setState({ inputValue: "!!!" });
component.forceUpdate();
// classic
var isMounted: boolean = classicComponent.isMounted();
classicComponent.replaceState({ inputValue: "???", seconds: 60 });
var myComponent = component;
myComponent.reset();
//
// Refs
// --------------------------------------------------------------------------
interface RCProps {
}
class RefComponent extends React.Component {
static create = React.createFactory(RefComponent);
refMethod() {
}
}
var componentRef: RefComponent;
RefComponent.create({ ref: "componentRef" });
// type of c should be inferred
RefComponent.create({ ref: c => componentRef = c });
componentRef.refMethod();
var domNodeRef: Element;
React.DOM.div({ ref: "domRef" });
// type of node should be inferred
React.DOM.div({ ref: node => domNodeRef = node });
var inputNodeRef: HTMLInputElement;
React.DOM.input({ ref: node => inputNodeRef = node });
//
// Attributes
// --------------------------------------------------------------------------
var children: any[] = ["Hello world", [null], React.DOM.span(null)];
var divStyle: React.CSSProperties = { // CSSProperties
flex: "1 1 main-size",
backgroundImage: "url('hello.png')"
};
var htmlAttr: React.HTMLProps = {
key: 36,
ref: "htmlComponent",
children: children,
className: "test-attr",
style: divStyle,
onClick: (event: React.MouseEvent) => {
event.preventDefault();
event.stopPropagation();
},
dangerouslySetInnerHTML: {
__html: "STRONG"
}
};
React.DOM.div(htmlAttr);
React.DOM.span(htmlAttr);
React.DOM.input(htmlAttr);
React.DOM.svg({ viewBox: "0 0 48 48" },
React.DOM.rect({
x: 22,
y: 10,
width: 4,
height: 28
}),
React.DOM.rect({
x: 10,
y: 22,
width: 28,
height: 4
}));
//
// React.PropTypes
// --------------------------------------------------------------------------
var PropTypesSpecification: React.ComponentSpec = {
propTypes: {
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
optionalNode: React.PropTypes.node,
optionalElement: React.PropTypes.element,
optionalMessage: React.PropTypes.instanceOf(Date),
optionalEnum: React.PropTypes.oneOf(["News", "Photos"]),
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Date)
]),
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
requiredFunc: React.PropTypes.func.isRequired,
requiredAny: React.PropTypes.any.isRequired,
customProp: function(props: any, propName: string, componentName: string) {
if (!/matchme/.test(props[propName])) {
return new Error("Validation failed!");
}
return null;
}
},
render: (): React.ReactElement => {
return null;
}
};
//
// ContextTypes
// --------------------------------------------------------------------------
var ContextTypesSpecification: React.ComponentSpec = {
contextTypes: {
optionalArray: React.PropTypes.array,
optionalBool: React.PropTypes.bool,
optionalFunc: React.PropTypes.func,
optionalNumber: React.PropTypes.number,
optionalObject: React.PropTypes.object,
optionalString: React.PropTypes.string,
optionalNode: React.PropTypes.node,
optionalElement: React.PropTypes.element,
optionalMessage: React.PropTypes.instanceOf(Date),
optionalEnum: React.PropTypes.oneOf(["News", "Photos"]),
optionalUnion: React.PropTypes.oneOfType([
React.PropTypes.string,
React.PropTypes.number,
React.PropTypes.instanceOf(Date)
]),
optionalArrayOf: React.PropTypes.arrayOf(React.PropTypes.number),
optionalObjectOf: React.PropTypes.objectOf(React.PropTypes.number),
optionalObjectWithShape: React.PropTypes.shape({
color: React.PropTypes.string,
fontSize: React.PropTypes.number
}),
requiredFunc: React.PropTypes.func.isRequired,
requiredAny: React.PropTypes.any.isRequired,
customProp: function(props: any, propName: string, componentName: string) {
if (!/matchme/.test(props[propName])) {
return new Error("Validation failed!");
}
return null;
}
},
render: (): React.ReactElement => {
return null;
}
};
//
// React.Children
// --------------------------------------------------------------------------
var mappedChildrenArray: number[] =
React.Children.map(children, (child) => { return 42; });
React.Children.forEach(children, (child) => {});
var nChildren: number = React.Children.count(children);
var onlyChild: React.ReactElement = React.Children.only(React.DOM.div()); // ok
onlyChild = React.Children.only([null, [[["Hallo"], true]], false]); // error
var childrenToArray: React.ReactChild[] = React.Children.toArray(children);
//
// Example from http://facebook.github.io/react/
// --------------------------------------------------------------------------
interface TimerState {
secondsElapsed: number;
}
class Timer extends React.Component<{}, TimerState> {
state = {
secondsElapsed: 0
};
private _interval: number;
tick() {
this.setState((prevState, props) => ({
secondsElapsed: prevState.secondsElapsed + 1
}));
}
componentDidMount() {
this._interval = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this._interval);
}
render() {
return React.DOM.div(
null,
"Seconds Elapsed: ",
this.state.secondsElapsed
);
}
}
ReactDOM.render(React.createElement(Timer), container);
//
// createFragment addon
// --------------------------------------------------------------------------
createFragment({
a: React.DOM.div(),
b: ["a", false, React.createElement("span")]
});
//
// CSSTransitionGroup addon
// --------------------------------------------------------------------------
React.createFactory(CSSTransitionGroup)({
component: React.createClass({
render: (): React.ReactElement => null
}),
childFactory: (c) => c,
transitionName: "transition",
transitionAppear: false,
transitionEnter: true,
transitionLeave: true
});
React.createFactory(CSSTransitionGroup)({
transitionName: {
enter: "enter",
enterActive: "enterActive",
leave: "leave",
leaveActive: "leaveActive",
appear: "appear",
appearActive: "appearActive"
}
});
//
// LinkedStateMixin addon
// --------------------------------------------------------------------------
React.createClass({
mixins: [LinkedStateMixin],
getInitialState: function() {
return {
isChecked: false,
message: "hello!"
};
},
render: function() {
return React.DOM.div(null,
React.DOM.input({
type: "checkbox",
checkedLink: this.linkState("isChecked")
}),
React.DOM.input({
type: "text",
valueLink: this.linkState("message")
})
);
}
});
//
// Perf addon
// --------------------------------------------------------------------------
Perf.start();
Perf.stop();
var measurements = Perf.getLastMeasurements();
Perf.printInclusive(measurements);
Perf.printExclusive(measurements);
Perf.printWasted(measurements);
Perf.printDOM(measurements);
//
// PureRenderMixin addon
// --------------------------------------------------------------------------
React.createClass({
mixins: [PureRenderMixin],
render: function() { return React.DOM.div(null); }
});
//
// TestUtils addon
// --------------------------------------------------------------------------
var inst: ModernComponent = TestUtils.renderIntoDocument(element);
var node: Element = TestUtils.renderIntoDocument(React.DOM.div());
TestUtils.Simulate.click(node);
TestUtils.Simulate.change(node);
TestUtils.Simulate.keyDown(node, { key: "Enter" });
var renderer: React.ShallowRenderer =
TestUtils.createRenderer();
renderer.render(React.createElement(Timer));
var output: React.ReactElement> =
renderer.getRenderOutput();
var foundComponent: ModernComponent = TestUtils.findRenderedComponentWithType(
inst, ModernComponent);
var foundComponents: ModernComponent[] = TestUtils.scryRenderedComponentsWithType(
inst, ModernComponent);
// ReactTestUtils custom type guards
var emptyElement: React.ReactElement<{}>;
if (TestUtils.isElementOfType(emptyElement, StatelessComponent)) {
emptyElement.props.foo;
}
var anyInstance: Element | React.Component;
if (TestUtils.isDOMComponent(anyInstance)) {
anyInstance.getAttribute("className");
} else if (TestUtils.isCompositeComponent(anyInstance)) {
anyInstance.props;
}
//
// TransitionGroup addon
// --------------------------------------------------------------------------
React.createFactory(TransitionGroup)({ component: "div" });
//
// update addon
// --------------------------------------------------------------------------
{
// These are copied from https://facebook.github.io/react/docs/update.html
let initialArray = [1, 2, 3];
let newArray = update(initialArray, {$push: [4]}); // => [1, 2, 3, 4]
let collection = [1, 2, {a: [12, 17, 15]}];
let newCollection = update(collection, {2: {a: {$splice: [[1, 1, 13, 14]]}}});
// => [1, 2, {a: [12, 13, 14, 15]}]
let obj = {a: 5, b: 3};
let newObj = update(obj, {b: {$apply: function(x) {return x * 2;}}});
// => {a: 5, b: 6}
let newObj2 = update(obj, {b: {$set: obj.b * 2}});
let objShallow = {a: 5, b: 3};
let newObjShallow = update(obj, {$merge: {b: 6, c: 7}}); // => {a: 5, b: 6, c: 7}
}