Skip to content

Commit

Permalink
Working context
Browse files Browse the repository at this point in the history
  • Loading branch information
ericclemmons committed Apr 10, 2015
1 parent c92d721 commit 746eb8c
Show file tree
Hide file tree
Showing 11 changed files with 359 additions and 133 deletions.
85 changes: 66 additions & 19 deletions dist/Container.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,27 10,50 @@ var _inherits = function (subClass, superClass) { if (typeof superClass !== "fun

var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };

var React = _interopRequire(require("react"));
var React = _interopRequire(require("react/addons"));

var ResolverContainer = (function (_React$Component) {
function ResolverContainer(props, context) {
_classCallCheck(this, ResolverContainer);
var ResolverError = _interopRequire(require("./ResolverError"));

_get(Object.getPrototypeOf(ResolverContainer.prototype), "constructor", this).call(this, props, context);
var Children = React.Children;
var cloneWithProps = React.addons.cloneWithProps;

this.state = this.context.resolver.getContainerState(this);
var Container = (function (_React$Component) {
function Container(props, context) {
_classCallCheck(this, Container);

_get(Object.getPrototypeOf(Container.prototype), "constructor", this).call(this, props, context);

this.state = this.getResolver().getContainerState(this);
}

_inherits(ResolverContainer, _React$Component);
_inherits(Container, _React$Component);

_createClass(ResolverContainer, {
_createClass(Container, {
componentWillMount: {
value: function componentWillMount() {
if (!this.state.fulfilled) {
this.context.resolver.resolve(this, this.setState.bind(this));
this.getResolver().resolve(this, this.setState.bind(this));
}
}
},
getChildContext: {
value: function getChildContext() {
var resolver = this.getResolver();

return { resolver: resolver };
}
},
getResolver: {
value: function getResolver() {
var resolver = this.props.resolver || this.context.resolver;

if (!resolver) {
throw new ReferenceError("Resolver is not defined in either `context` or `props`. (Perhaps missing a root <Container resolver={new Resolver()} />?)");
}

return resolver;
}
},
shouldComponentUpdate: {
value: function shouldComponentUpdate(props, state) {
return state.fulfilled;
Expand All @@ -42,22 65,46 @@ var ResolverContainer = (function (_React$Component) {
return false;
}

return React.createElement(this.props.component, this.state.values);
if (this.props.component) {
return React.createElement(this.props.component, this.state.values);
}

if (this.props.element) {
return cloneWithProps(this.props.element);
}

if (this.props.children) {
if (Children.count(this.props.children) === 1) {
return cloneWithProps(Children.only(this.props.children));
}
return React.createElement(
"span",
null,
Children.map(this.props.children, cloneWithProps)
);
}

throw new ResolverError("<Container /> requires one of the following props to render: `element`, `component`, or `children`");
}
}
});

return ResolverContainer;
return Container;
})(React.Component);

ResolverContainer.contextTypes = {
id: React.PropTypes.string.isRequired,
resolver: React.PropTypes.object.isRequired };
Container.childContextTypes = {
resolver: React.PropTypes.any };

Container.contextTypes = {
id: React.PropTypes.string,
resolver: React.PropTypes.object };

ResolverContainer.displayName = "ResolverContainer";
Container.displayName = "ResolverContainer";

ResolverContainer.propTypes = {
component: React.PropTypes.any.isRequired,
resolve: React.PropTypes.object.isRequired };
Container.propTypes = {
component: React.PropTypes.any,
element: React.PropTypes.element,
resolve: React.PropTypes.object,
resolver: React.PropTypes.any };

module.exports = ResolverContainer;
module.exports = Container;
30 changes: 30 additions & 0 deletions dist/ResolverError.js
Original file line number Diff line number Diff line change
@@ -0,0 1,30 @@
"use strict";

var _get = function get(object, property, receiver) { var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { return get(parent, property, receiver); } } else if ("value" in desc && desc.writable) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } };

var _inherits = function (subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; };

var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } };

var ResolverError = (function (_Error) {
function ResolverError(message) {
_classCallCheck(this, ResolverError);

_get(Object.getPrototypeOf(ResolverError.prototype), "constructor", this).call(this, message);

this.name = this.constructor.name;
this.message = message;

if (Error.hasOwnProperty("captureStackTrace")) {
Error.captureStackTrace(this, this.constructor);
} else {
this.stack = new Error().stack;
}
}

_inherits(ResolverError, _Error);

return ResolverError;
})(Error);

module.exports = ResolverError;
79 changes: 56 additions & 23 deletions dist/resolver.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,19 16,15 @@ var React = _interopRequire(require("react"));

var Container = _interopRequire(require("./Container"));

var Context = _interopRequire(require("./Context"));

var Resolver = (function () {
function Resolver(element) {
var states = arguments[1] === undefined ? {} : arguments[1];
function Resolver() {
var states = arguments[0] === undefined ? {} : arguments[0];

_classCallCheck(this, Resolver);

this.container = React.createElement(Container, { resolver: this });
this.promises = [];
this.root = React.createElement(Context, { element: element, resolver: this });
this.states = states;

React.renderToStaticMarkup(this.root);
}

_createClass(Resolver, {
Expand All @@ -52,14 48,27 @@ var Resolver = (function () {
return _this.finish();
}

return _this.root;
return _this.container;
});
}
},
fulfillState: {
value: function fulfillState(state, callback) {
state.error = undefined;
state.fulfilled = true;
state.rejected = false;

return callback ? callback(state) : state;
}
},
getContainerState: {
value: function getContainerState(container) {
var id = container.context.id;

if (!id) {
throw new TypeError("Container does not have an ID");
}

if (!this.states.hasOwnProperty(id)) {
this.states[id] = {
fulfilled: false,
Expand All @@ -71,17 80,49 @@ var Resolver = (function () {
return this.states[id];
}
},
rejectState: {
value: function rejectState(error, state, callback) {
state.error = error;
state.fulfilled = false;
state.rejected = true;

if (callback) {
callback(state);
}

throw new Error("" this.constructor.displayName " was rejected: " error);
}
},
resolve: {
value: function resolve(container, callback) {
var _this = this;

var props = container.props;

var asyncProps = container.props.resolve || {};
var state = this.getContainerState(container);

var promises = Object.keys(props.resolve).map(function (prop) {
var valueOf = props.resolve[prop];
var value = props.hasOwnProperty(prop) ? props[prop] : valueOf(props);
var asyncKeys = Object.keys(asyncProps)
// Assign existing prop values
.filter(function (asyncProp) {
if (container.props.hasOwnProperty(asyncProp)) {
state.values[asyncProp] = container.props[asyncProp];

return false;
}

return true;
})
// Filter out pre-loaded values
.filter(function (asyncProp) {
return state.values.hasOwnProperty(asyncProp);
});

if (!asyncKeys.length) {
return this.fulfillState(state);
}

var promises = asyncKeys.map(function (prop) {
var valueOf = container.props.resolve[prop];
var value = container.props.hasOwnProperty(prop) ? container.props[prop] : valueOf(container.props);

return Promise.resolve(value).then(function (value) {
state.values[prop] = value;
Expand All @@ -93,17 134,9 @@ var Resolver = (function () {
});

return this.await(promises).then(function () {
state.error = undefined;
state.fulfilled = true;
state.rejected = false;

callback(state);
return _this.fulfillState(state, callback);
}, function (error) {
state.error = error;
state.fulfilled = false;
state.rejected = true;

throw new Error("" _this.constructor.displayName " was rejected: " error);
return _this.rejectState(error, state, callback);
});
}
},
Expand Down
76 changes: 61 additions & 15 deletions src/Container.js
Original file line number Diff line number Diff line change
@@ -1,16 1,37 @@
import React from "react";
import React from "react/addons";

class ResolverContainer extends React.Component {
import ResolverError from "./ResolverError";

const { Children } = React;
const { cloneWithProps } = React.addons;

class Container extends React.Component {
constructor(props, context) {
super(props, context);

this.state = this.context.resolver.getContainerState(this);
this.state = this.getResolver().getContainerState(this);
}

componentWillMount() {
if (!this.state.fulfilled) {
this.context.resolver.resolve(this, this.setState.bind(this));
this.getResolver().resolve(this, this.setState.bind(this));
}
}

getChildContext() {
const resolver = this.getResolver();

return { resolver };
}

getResolver() {
const resolver = this.props.resolver || this.context.resolver;

if (!resolver) {
throw new ReferenceError("Resolver is not defined in either `context` or `props`. (Perhaps missing a root <Container resolver={new Resolver()} />?)");
}

return resolver;
}

shouldComponentUpdate(props, state) {
Expand All @@ -22,22 43,47 @@ class ResolverContainer extends React.Component {
return false;
}

return (
<this.props.component {...this.state.values} />
);
if (this.props.component) {
return (
<this.props.component {...this.state.values} />
);
}

if (this.props.element) {
return cloneWithProps(this.props.element);
}

if (this.props.children) {
if (Children.count(this.props.children) === 1) {
return cloneWithProps(Children.only(this.props.children));
}
return (
<span>
{Children.map(this.props.children, cloneWithProps)}
</span>
);
}

throw new ResolverError("<Container /> requires one of the following props to render: `element`, `component`, or `children`");
}
}

ResolverContainer.contextTypes = {
id: React.PropTypes.string.isRequired,
resolver: React.PropTypes.object.isRequired,
Container.childContextTypes = {
resolver: React.PropTypes.any,
};

Container.contextTypes = {
id: React.PropTypes.string,
resolver: React.PropTypes.object,
};

ResolverContainer.displayName = "ResolverContainer";
Container.displayName = "ResolverContainer";

ResolverContainer.propTypes = {
component: React.PropTypes.any.isRequired,
resolve: React.PropTypes.object.isRequired,
Container.propTypes = {
component: React.PropTypes.any,
element: React.PropTypes.element,
resolve: React.PropTypes.object,
resolver: React.PropTypes.any,
};

export default ResolverContainer;
export default Container;
Loading

0 comments on commit 746eb8c

Please sign in to comment.