@@ -2,8 +2,8 @@ import {Component, createElement, PropTypes} from 'react';
22import hoistStatics from 'hoist-non-react-statics' ;
33import { connect } from 'react-redux' ;
44
5- import { getMergedComponents , getPreviousPath } from './selector' ;
6- import { removeComponent } from './action' ;
5+ import { getComponents } from './selector' ;
6+ import { removeComponent , updateComponent } from './action' ;
77import { componentsShape , renderMapShape , getDisplayName } from './util' ;
88
99/**
@@ -12,18 +12,18 @@ import {componentsShape, renderMapShape, getDisplayName} from './util';
1212 *
1313 * @param {Object|Function } rawRenderMap An object with component type/render
1414 * function key value pairs or a function returning such an object.
15- * @param {Object|Function } rawConfig An object or a function returing such an
15+ * @param {Object } defaultProps An object or a function returing such an
1616 * object.
1717 * @returns {Function } Higher-order component wrapper.
1818 */
19- export default ( rawRenderMap , rawConfig = { } ) => ( WrappedComponent ) => {
19+ export default ( { scope , ... defaultProps } = { } ) => ( WrappedComponent ) => {
2020 class Connect extends Component {
2121 static propTypes = {
22- dispatch : PropTypes . func . isRequired ,
23- ___relocation___ : PropTypes . shape ( {
22+ ___relocationDispatch___ : PropTypes . shape ( {
23+ removeComponent : PropTypes . func . isRequired ,
24+ } ) ,
25+ ___relocationState___ : PropTypes . shape ( {
2426 components : componentsShape . isRequired ,
25- previousPath : PropTypes . string . isRequired ,
26- config : PropTypes . object . isRequired ,
2727 renderMap : renderMapShape . isRequired ,
2828 } ) . isRequired ,
2929 } ;
@@ -32,107 +32,50 @@ export default (rawRenderMap, rawConfig = {}) => (WrappedComponent) => {
3232 router : PropTypes . object ,
3333 }
3434
35- navigateToPath ( path , { useHistoryBack = true } = { } ) {
36- // Check for the react-router context.
37- if ( ! this . context . router ) {
38- return ;
39- }
40-
41- const { previousPath} = this . props . ___relocation___ ;
42-
43- // The `useHistoryBack` option will trigger the use of the `goBack` method
44- // instead of `push` in an effort to keep the if the requested path is
45- // equal to the previous path.
46- //
47- // This is useful in scenraios where component that is displayed in
48- // response to a route change is considered dismissed or completed on
49- // removal.
50- if ( useHistoryBack && path === previousPath ) {
51- this . context . router . goBack ( ) ;
52- } else {
53- this . context . router . push ( path ) ;
54- }
55- }
56-
57- removeComponent ( id /* , options */ ) {
58- return this . props . dispatch ( removeComponent ( id ) ) ;
59- }
60-
6135 render ( ) {
62- const { components, renderMap} = this . props . ___relocation___ ;
63-
64- const assignRender = ( component ) => ( {
65- ...component ,
66- render : renderMap [ component . type ] ,
67- } ) ;
36+ const { components, renderMap} = this . props . ___relocationState___ ;
37+ const {
38+ removeComponent,
39+ updateComponent,
40+ } = this . props . ___relocationDispatch___ ;
6841
6942 const inRenderMap = ( component ) =>
7043 typeof renderMap [ component . type ] === 'function' ;
7144
72- const assignRemoveHandler = ( component ) => {
73- let removeHandler = null ;
74-
75- if ( typeof component . remove === 'function' ) {
76- // The component object remove property is already a function.
77- // We don't want to override this behavior.
78- removeHandler = component . remove ;
79- } else if ( component . remove === undefined || component . remove ) {
80- // The component object does not have a `remove` property, or it has
81- // a truthy value that is not a function. Either case indicates that
82- // it should use the default remove handler.
83- removeHandler = ( options ) =>
84- this . removeComponent ( component . id , options ) ;
85- }
86-
87- let pathRemoveHandler = null ;
45+ const assign = ( component ) => {
46+ const result = {
47+ ...component ,
48+ render : renderMap [ component . type ] ,
49+ update : ( props ) => updateComponent ( component . id , props ) ,
50+ remove : ( ) => removeComponent ( component . id ) ,
51+ } ;
8852
89- if ( typeof component . removePath === 'string' ) {
90- // Create a function that will change the history state when removing
91- // the component.
92- pathRemoveHandler = ( options ) =>
93- this . navigateToPath ( component . removePath , options ) ;
53+ if ( scope ) {
54+ result . scope = scope ;
9455 }
9556
96- if ( pathRemoveHandler && removeHandler ) {
97- // A remove handler function and a
98- return {
99- ...component ,
100- remove : ( options ) => {
101- pathRemoveHandler ( options ) ;
102- return removeHandler ( options ) ;
103- } ,
104- } ;
105- }
57+ return result ;
58+ } ;
10659
107- if ( pathRemoveHandler && ! removeHandler ) {
108- return {
109- ...component ,
110- remove : pathRemoveHandler ,
111- } ;
112- }
60+ const currentComponents = components
61+ // Remove components not included in the render function map.
62+ . filter ( inRenderMap )
63+ // Assign render update and remove functions and scope if it is defined.
64+ . map ( assign ) ;
11365
114- if ( ! pathRemoveHandler && removeHandler !== component . remove ) {
115- return {
116- ...component ,
117- remove : removeHandler ,
118- } ;
119- }
120-
121- // `!pathRemoveHandler && removeHandler === component.remove` is true.
122- // This means `remove` was set and `removePath` was not set on the
123- // component object. No modification is necessary.
124- return component ;
125- } ;
66+ /* eslint-disable no-unused-vars */
67+ const {
68+ ___relocationState___,
69+ ___relocationDispatch___,
70+ ...childProps ,
71+ } = this . props ;
72+ /* eslint-enable no-unused-vars */
12673
12774 const mergedProps = {
128- ...this . props ,
129- components : components
130- // Assign render functions.
131- . map ( assignRender )
132- // Remove components not included in the render function map.
133- . filter ( inRenderMap )
134- // Assign remove handler functions.
135- . map ( assignRemoveHandler ) ,
75+ ...childProps ,
76+ ...scope
77+ ? { [ scope ] : { components : currentComponents } }
78+ : { components : currentComponents } ,
13679 } ;
13780
13881 return < WrappedComponent { ...mergedProps } /> ;
@@ -142,28 +85,38 @@ export default (rawRenderMap, rawConfig = {}) => (WrappedComponent) => {
14285 Connect . displayName = `Relocation(${ getDisplayName ( WrappedComponent ) } )` ;
14386
14487 const mapState = ( state , props ) => {
145- const config = typeof rawConfig === 'function' ?
146- rawConfig ( props ) : rawConfig ;
147-
148- const renderMap = typeof rawRenderMap === 'function' ?
149- rawRenderMap ( props ) : rawRenderMap ;
88+ const mergedProps = {
89+ ...defaultProps ,
90+ ...scope ? props [ scope ] : props ,
91+ } ;
15092
151- const { getRelocationState} = config ;
93+ const { components , getRelocationState} = mergedProps ;
15294
153- const selectorProps = getRelocationState ?
154- { getRelocationState, ...props } : props ;
95+ const selectorProps = getRelocationState
96+ ? { getRelocationState, ...props }
97+ : props ;
15598
15699 return {
157- // Put everything in a ___relocation___ namespace to avoid possible
100+ // Put everything in a ___relocationState___ namespace to avoid possible
158101 // conflict with existing props.
159- ___relocation___ : {
160- components : getMergedComponents ( state , selectorProps ) ,
161- previousPath : getPreviousPath ( state , selectorProps ) ,
162- config,
163- renderMap,
102+ ___relocationState___ : {
103+ components : getComponents ( state , selectorProps ) ,
104+ renderMap : components ,
164105 } ,
165106 } ;
166107 } ;
167108
168- return connect ( mapState ) ( hoistStatics ( Connect , WrappedComponent ) ) ;
109+ const mapDispatch = ( dispatch ) => ( {
110+ // Put everything in a ___relocationDispatch___ namespace to avoid
111+ // possible conflict with existing props.
112+ ___relocationDispatch___ : {
113+ removeComponent : ( id ) => dispatch ( removeComponent ( id ) ) ,
114+ updateComponent : ( id , props ) => dispatch ( updateComponent ( id , props ) ) ,
115+ } ,
116+ } ) ;
117+
118+ return connect (
119+ mapState ,
120+ mapDispatch ,
121+ ) ( hoistStatics ( Connect , WrappedComponent ) ) ;
169122} ;
0 commit comments