summaryrefslogtreecommitdiffstats
path: root/packages/gitbook-core/src/components/InjectedComponent.js
diff options
context:
space:
mode:
authorSamy Pessé <samypesse@gmail.com>2016-09-05 11:51:52 +0200
committerSamy Pessé <samypesse@gmail.com>2016-09-05 11:51:52 +0200
commitd7e415b0b396639b7e5c64d61f47569b40ced053 (patch)
tree9d68aedd70c6a9edcd26bacd57c592149d752755 /packages/gitbook-core/src/components/InjectedComponent.js
parentb170b4d197822f3949b63df69e063d07cbb8e5c9 (diff)
downloadgitbook-d7e415b0b396639b7e5c64d61f47569b40ced053.zip
gitbook-d7e415b0b396639b7e5c64d61f47569b40ced053.tar.gz
gitbook-d7e415b0b396639b7e5c64d61f47569b40ced053.tar.bz2
Add components for injections
Diffstat (limited to 'packages/gitbook-core/src/components/InjectedComponent.js')
-rw-r--r--packages/gitbook-core/src/components/InjectedComponent.js91
1 files changed, 91 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..fe386ef
--- /dev/null
+++ b/packages/gitbook-core/src/components/InjectedComponent.js
@@ -0,0 +1,91 @@
+const React = require('react');
+const connect = require('./connect');
+
+const UnsafeComponent = require('./UnsafeComponent');
+
+/*
+ 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 InjectedComponentSet = React.createClass({
+ propTypes: {
+ components: React.PropTypes.arrayOf(React.PropTypes.func).isRequired,
+ props: React.PropTypes.object,
+ withContainer: React.PropTypes.bool
+ },
+
+ render() {
+ const { components, props, ...divProps } = this.props;
+
+ const inner = components.map(Component => {
+ if (Component.sandbox === false) {
+ return <Component key={Component.displayName} {...props} />;
+ } else {
+ return <UnsafeComponent key={Component.displayName} Component={Component} props={props} />;
+ }
+ });
+
+ return (
+ <div {...divProps}>
+ {inner}
+ </div>
+ );
+ }
+});
+
+/**
+ * Find all components matching a descriptor
+ * @param {List<ComponentDescriptor>} components
+ * @param {String} matching.role
+ */
+function findMatchingComponents(components, matching) {
+ return components
+ .filter(({descriptor}) => {
+ if (matching.role && matching.role === descriptor.role) {
+ return false;
+ }
+
+ return true;
+ })
+ .map(component => component.Component);
+}
+
+/**
+ * Map Redux state to InjectedComponentSet's props
+ */
+function mapStateToProps(state, props) {
+ const { components } = state;
+ const { matching } = props;
+
+ return {
+ components: findMatchingComponents(components, matching)
+ };
+}
+
+module.exports = {
+ InjectedComponent: connect(InjectedComponentSet, (state, props) => {
+ const result = mapStateToProps(state, props);
+ result.components = result.components.slice(0, 1);
+ result.withContainer = false;
+ return result;
+ }),
+ InjectedComponentSet: connect(InjectedComponentSet, mapStateToProps)
+};