Skip to content

Instantly share code, notes, and snippets.

@AlexGalays
Last active August 24, 2016 20:30
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AlexGalays/f3ee01ff940defd147700c2725dd3976 to your computer and use it in GitHub Desktop.
Save AlexGalays/f3ee01ff940defd147700c2725dd3976 to your computer and use it in GitHub Desktop.
import React = __React;
import { State, StateMap } from './abyssa';
export interface ReactState {
(uri: string, component: React.ComponentClass<any> | React.StatelessComponent<any>, children?: StateMap): State;
}
export default function reactStateForContainer(container: HTMLElement): ReactState;
/* Addon making using React easier */
import _React from 'react';
import _ReactDOM from 'react-dom';
export default (function() {
// Enable this addon even in build-less systems (JsFiddle, etc)
const React = _React || window.React;
const ReactDOM = _ReactDOM || window.ReactDOM;
function createEl(fromClass, route, params, acc, key, child) {
return React.createElement(fromClass, { route, params, acc, key }, child);
}
function parentStates(stateApi) {
const result = [];
let parent = stateApi.parent;
while (parent) {
result.push(parent);
parent = parent.parent;
}
return result;
}
// Enable this addon even in build-less systems (JsFiddle, etc)
if (window.Abyssa)
window.Abyssa.ReactState = ReactStateForContainer
return function ReactStateForContainer(container) {
let stateId = 0;
const componentByState = {};
return function ReactState(uri, component, children) {
// Create the Abyssa state object
const state = {
data: { id: stateId++ },
uri,
children
};
componentByState[state.data.id] = component;
// The router will add a default state to any parent without one; Add ours first so that it's a ReactState.
if (children && !Object.keys(children).some(name => children[name].uri.split('?')[0] == ''))
children._default_ = ReactState('');
state.enter = function(params, acc, router) {
const route = router.current();
// Let the component react to the route change, e.g to redirect to another state
if (component && component.onEnter) {
const current = route.fullName;
component.onEnter();
// The current state changed, cancel everything.
if (router.current().fullName != current) return;
}
// It is the responsability of the leaf state to render the whole component hierarchy; Bail if we're a parent.
if (children) return;
const stateApi = router.findState(state);
const parents = parentStates(stateApi);
const states = component ? [stateApi].concat(parents) : parents;
// The actual VDOM element created from the component class hierarchy
const instance = states.slice(1).reduce((child, parent) => {
const parentComp = componentByState[parent.data.id]
return createEl(parentComp, route, params, acc, parent.fullName, child);
}, createEl(componentByState[states[0].data.id], route, params, acc, states[0].fullName));
ReactDOM.render(instance, container);
};
return state;
}
}
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment