Skip to content
This repository was archived by the owner on Jun 4, 2024. It is now read-only.

allow any property to be a dash component, not just children #26

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
145 changes: 142 additions & 3 deletions src/TreeContainer.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,24 @@
'use strict'
/* global window:true */

import R from 'ramda';
import React, {Component, PropTypes} from 'react';
import Registry from './registry';
import NotifyObservers from './components/core/NotifyObservers.react';
//import {NotifyObservers} from './components/core/NotifyObservers.react';

/* global window:true */
import {connect} from 'react-redux';
import {isEmpty} from 'ramda';
//import {notifyObservers, updateProps} from '../../actions';
import {notifyObservers, updateProps} from './actions';
//import React, {PropTypes} from 'react';
//import {render} from '../../TreeContainer.js';
window.render = render;


var reactDocs = require('react-docgen');

window.reactDocs = reactDocs;


export default class TreeContainer extends Component {
shouldComponentUpdate(nextProps) {
Expand All @@ -19,7 +34,7 @@ TreeContainer.propTypes = {
layout: PropTypes.object,
}

function render(component) {
export function render(component) {
if (R.contains(R.type(component), ['String', 'Number', 'Null'])) {
return component;
}
Expand Down Expand Up @@ -84,3 +99,127 @@ function render(component) {
render.propTypes = {
children: PropTypes.object
}


/*
* NotifyObservers passes a connected `setProps` handler down to
* its child as a prop
*/

function mapStateToProps (state) {
return {
dependencies: state.dependenciesRequest.content,
paths: state.paths
};
}

function mapDispatchToProps (dispatch) {
return {dispatch};
}

function mergeProps(stateProps, dispatchProps, ownProps) {
const {dispatch} = dispatchProps;
return {
id: ownProps.id,
children: ownProps.children,
dependencies: stateProps.dependencies,
paths: stateProps.paths,

fireEvent: function fireEvent({event}) {
// Update this component's observers with the updated props
dispatch(notifyObservers({event, id: ownProps.id}));
},

setProps: function setProps(newProps) {
const payload = {
props: newProps,
id: ownProps.id,
itempath: stateProps.paths[ownProps.id]
};

// Update this component's props
dispatch(updateProps(payload));

// Update output components that depend on this input
dispatch(notifyObservers({id: ownProps.id, props: newProps}));
}
}

}

function NotifyObserversComponent ({
children,
id,
paths,

dependencies,

fireEvent,
setProps
}) {
const thisComponentTriggersEvents = (
dependencies && dependencies.find(dependency => (
dependency.events.find(event => event.id === id)
))
);
const thisComponentSharesState = (
dependencies && dependencies.find(dependency => (
dependency.inputs.find(input => input.id === id) ||
dependency.state.find(state => state.id === id)
))
);
/*
* Only pass in `setProps` and `fireEvent` if they are actually
* necessary.
* This allows component authors to skip computing data
* for `setProps` or `fireEvent` (which can be expensive)
* in the case when they aren't actually used.
* For example, consider `hoverData` for graphs. If it isn't
* actually used, then the component author can skip binding
* the events for the component.
*
* TODO - A nice enhancement would be to pass in the actual events
* and properties that are used into the component so that the
* component author can check for something like `subscribed_events`
* or `subscribed_properties` instead of `fireEvent` and `setProps`.
*/
const extraProps = {};
if (thisComponentSharesState &&

// there is a bug with graphs right now where
// the restyle listener gets assigned with a
// setProps function that was created before
// the item was added. only pass in setProps
// if the item's path exists for now.
paths[id]
) {
extraProps.setProps = setProps;
}
if (thisComponentTriggersEvents && paths[id]) {
extraProps.fireEvent = fireEvent;
}
extraProps.render = componentJson => {
// TODO - check if it's already react component
// TODO - we could push all of the recursive rendering
// to the components and their children
return render(componentJson);
};

if (!isEmpty(extraProps)) {
return React.cloneElement(children, extraProps);
} else {
return children;
}
}

NotifyObserversComponent.propTypes = {
id: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
path: PropTypes.array.isRequired
};

export const NotifyObservers = connect(
mapStateToProps,
mapDispatchToProps,
mergeProps
)(NotifyObserversComponent);
30 changes: 10 additions & 20 deletions src/reducers/utils.js
Original file line number Diff line number Diff line change
@@ -1,34 +1,24 @@
import R from 'ramda';

const extend = R.reduce(R.flip(R.append))

// crawl a layout object, apply a function on every object
export const crawlLayout = (object, func, path=[]) => {
func(object, path);
/* eslint-disable */
console.warn(path);
/* eslint-enable */

/*
* object may be a string, a number, or null
* R.has will return false for both of those types
*/
if (R.type(object) === 'Object' &&
R.has('props', object) &&
R.has('children', object.props)
) {
const newPath = extend(path, ['props', 'children']);
if (Array.isArray(object.props.children)) {
object.props.children.forEach((child, i) => {
if (R.type(object) === 'Object') {
R.keys(object).forEach(key => {
if (R.contains(R.type(object[key]), ['Array', 'Object'])) {
crawlLayout(
child,
func,
R.append(i, newPath));
});
} else {
crawlLayout(
object.props.children,
func,
newPath
);
}
object[key], func, R.append(key, path)
);
}
})
} else if (R.type(object) === 'Array') {

/*
Expand Down