summaryrefslogtreecommitdiffstats
path: root/packages/gitbook-core/src/components/InjectedComponent.js
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2016-12-22 10:18:38 +0100
committerGitHub <noreply@github.com>2016-12-22 10:18:38 +0100
commit194ebc3da9641ff96f083f9d8ab43c2d27944f9a (patch)
treec50988f32ccf18df93ae7ab40be78e9459642818 /packages/gitbook-core/src/components/InjectedComponent.js
parent64ccb6b00b4b63fa0e516d4e35351275b34f8c07 (diff)
parent16af264360e48e8a833e9efa9ab8d194574dbc70 (diff)
downloadgitbook-194ebc3da9641ff96f083f9d8ab43c2d27944f9a.zip
gitbook-194ebc3da9641ff96f083f9d8ab43c2d27944f9a.tar.gz
gitbook-194ebc3da9641ff96f083f9d8ab43c2d27944f9a.tar.bz2
Merge pull request #1543 from GitbookIO/dream
React for rendering website with plugins
Diffstat (limited to 'packages/gitbook-core/src/components/InjectedComponent.js')
-rw-r--r--packages/gitbook-core/src/components/InjectedComponent.js117
1 files changed, 117 insertions, 0 deletions
diff --git a/packages/gitbook-core/src/components/InjectedComponent.js b/packages/gitbook-core/src/components/InjectedComponent.js
new file mode 100644
index 0000000..097edaf
--- /dev/null
+++ b/packages/gitbook-core/src/components/InjectedComponent.js
@@ -0,0 +1,117 @@
+const React = require('react');
+const ReactRedux = require('react-redux');
+const { List } = require('immutable');
+
+const { findMatchingComponents } = require('../actions/components');
+
+/*
+ Public: InjectedComponent makes it easy to include a set of dynamically registered
+ components inside of your React render method. Rather than explicitly render
+ an array of buttons, for example, you can use InjectedComponentSet:
+
+ ```js
+ <InjectedComponentSet className="message-actions"
+ matching={{role: 'ThreadActionButton'}}
+ props={{ a: 1 }}>
+ ```
+
+ InjectedComponentSet will look up components registered for the location you provide,
+ render them inside a {Flexbox} and pass them `exposedProps`. By default, all injected
+ children are rendered inside {UnsafeComponent} wrappers to prevent third-party code
+ from throwing exceptions that break React renders.
+
+ InjectedComponentSet monitors the ComponentStore for changes. If a new component
+ is registered into the location you provide, InjectedComponentSet will re-render.
+ If no matching components is found, the InjectedComponent renders an empty span.
+ */
+
+const Injection = React.createClass({
+ propTypes: {
+ component: React.PropTypes.func,
+ props: React.PropTypes.object,
+ children: React.PropTypes.node
+ },
+
+ render() {
+ const Comp = this.props.component;
+ const { props, children } = this.props;
+
+ // TODO: try to render with an error handling for unsafe component
+ return <Comp {...props}>{children}</Comp>;
+ }
+});
+
+const InjectedComponentSet = React.createClass({
+ propTypes: {
+ components: React.PropTypes.oneOfType([
+ React.PropTypes.arrayOf(React.PropTypes.func),
+ React.PropTypes.instanceOf(List)
+ ]).isRequired,
+ props: React.PropTypes.object,
+ children: React.PropTypes.node
+ },
+
+ render() {
+ const { components, props, children, ...divProps } = this.props;
+
+ const inner = components.map((Comp, i) => <Injection key={i} component={Comp} props={props} />);
+
+ return (
+ <div {...divProps}>
+ {children}
+ {inner}
+ </div>
+ );
+ }
+});
+
+/**
+ * Render only the first component matching
+ */
+const InjectedComponent = React.createClass({
+ propTypes: {
+ components: React.PropTypes.oneOfType([
+ React.PropTypes.arrayOf(React.PropTypes.func),
+ React.PropTypes.instanceOf(List)
+ ]).isRequired,
+ props: React.PropTypes.object,
+ children: React.PropTypes.node
+ },
+
+ render() {
+ let { components, props, children } = this.props;
+
+ if (!children) {
+ children = null;
+ } else {
+ children = React.Children.only(children);
+ }
+
+ return components.reduce((inner, Comp) => {
+ return (
+ <Injection component={Comp} props={props}>
+ {inner}
+ </Injection>
+ );
+ }, children);
+ }
+});
+
+/**
+ * Map Redux state to InjectedComponentSet's props
+ */
+function mapStateToProps(state, props) {
+ const { components } = state;
+ const { matching } = props;
+
+ return {
+ components: findMatchingComponents(components, matching)
+ };
+}
+
+const connect = ReactRedux.connect(mapStateToProps);
+
+module.exports = {
+ InjectedComponent: connect(InjectedComponent),
+ InjectedComponentSet: connect(InjectedComponentSet)
+};