summaryrefslogtreecommitdiffstats
path: root/packages/gitbook-core/src/components/InjectedComponent.js
blob: 39b48b2ef315a9511b6745b0ee14f2a069a5bcd2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
const React = require('react');
const ReactRedux = require('react-redux');

const UnsafeComponent = require('./UnsafeComponent');
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 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>
        );
    }
});

/**
 * 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: ReactRedux.connect(InjectedComponentSet, (state, props) => {
        const result = mapStateToProps(state, props);
        result.components = result.components.slice(0, 1);
        result.withContainer = false;
        return result;
    }),
    InjectedComponentSet: ReactRedux.connect(InjectedComponentSet, mapStateToProps)
};