You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					150 lines
				
				4.9 KiB
			
		
		
			
		
	
	
					150 lines
				
				4.9 KiB
			| 
											3 years ago
										 | "use strict"; | ||
|  | 
 | ||
|  | exports.__esModule = true; | ||
|  | exports.getChildMapping = getChildMapping; | ||
|  | exports.mergeChildMappings = mergeChildMappings; | ||
|  | exports.getInitialChildMapping = getInitialChildMapping; | ||
|  | exports.getNextChildMapping = getNextChildMapping; | ||
|  | 
 | ||
|  | var _react = require("react"); | ||
|  | 
 | ||
|  | /** | ||
|  |  * Given `this.props.children`, return an object mapping key to child. | ||
|  |  * | ||
|  |  * @param {*} children `this.props.children` | ||
|  |  * @return {object} Mapping of key to child | ||
|  |  */ | ||
|  | function getChildMapping(children, mapFn) { | ||
|  |   var mapper = function mapper(child) { | ||
|  |     return mapFn && (0, _react.isValidElement)(child) ? mapFn(child) : child; | ||
|  |   }; | ||
|  | 
 | ||
|  |   var result = Object.create(null); | ||
|  |   if (children) _react.Children.map(children, function (c) { | ||
|  |     return c; | ||
|  |   }).forEach(function (child) { | ||
|  |     // run the map function here instead so that the key is the computed one
 | ||
|  |     result[child.key] = mapper(child); | ||
|  |   }); | ||
|  |   return result; | ||
|  | } | ||
|  | /** | ||
|  |  * When you're adding or removing children some may be added or removed in the | ||
|  |  * same render pass. We want to show *both* since we want to simultaneously | ||
|  |  * animate elements in and out. This function takes a previous set of keys | ||
|  |  * and a new set of keys and merges them with its best guess of the correct | ||
|  |  * ordering. In the future we may expose some of the utilities in | ||
|  |  * ReactMultiChild to make this easy, but for now React itself does not | ||
|  |  * directly have this concept of the union of prevChildren and nextChildren | ||
|  |  * so we implement it here. | ||
|  |  * | ||
|  |  * @param {object} prev prev children as returned from | ||
|  |  * `ReactTransitionChildMapping.getChildMapping()`. | ||
|  |  * @param {object} next next children as returned from | ||
|  |  * `ReactTransitionChildMapping.getChildMapping()`. | ||
|  |  * @return {object} a key set that contains all keys in `prev` and all keys | ||
|  |  * in `next` in a reasonable order. | ||
|  |  */ | ||
|  | 
 | ||
|  | 
 | ||
|  | function mergeChildMappings(prev, next) { | ||
|  |   prev = prev || {}; | ||
|  |   next = next || {}; | ||
|  | 
 | ||
|  |   function getValueForKey(key) { | ||
|  |     return key in next ? next[key] : prev[key]; | ||
|  |   } // For each key of `next`, the list of keys to insert before that key in
 | ||
|  |   // the combined list
 | ||
|  | 
 | ||
|  | 
 | ||
|  |   var nextKeysPending = Object.create(null); | ||
|  |   var pendingKeys = []; | ||
|  | 
 | ||
|  |   for (var prevKey in prev) { | ||
|  |     if (prevKey in next) { | ||
|  |       if (pendingKeys.length) { | ||
|  |         nextKeysPending[prevKey] = pendingKeys; | ||
|  |         pendingKeys = []; | ||
|  |       } | ||
|  |     } else { | ||
|  |       pendingKeys.push(prevKey); | ||
|  |     } | ||
|  |   } | ||
|  | 
 | ||
|  |   var i; | ||
|  |   var childMapping = {}; | ||
|  | 
 | ||
|  |   for (var nextKey in next) { | ||
|  |     if (nextKeysPending[nextKey]) { | ||
|  |       for (i = 0; i < nextKeysPending[nextKey].length; i++) { | ||
|  |         var pendingNextKey = nextKeysPending[nextKey][i]; | ||
|  |         childMapping[nextKeysPending[nextKey][i]] = getValueForKey(pendingNextKey); | ||
|  |       } | ||
|  |     } | ||
|  | 
 | ||
|  |     childMapping[nextKey] = getValueForKey(nextKey); | ||
|  |   } // Finally, add the keys which didn't appear before any key in `next`
 | ||
|  | 
 | ||
|  | 
 | ||
|  |   for (i = 0; i < pendingKeys.length; i++) { | ||
|  |     childMapping[pendingKeys[i]] = getValueForKey(pendingKeys[i]); | ||
|  |   } | ||
|  | 
 | ||
|  |   return childMapping; | ||
|  | } | ||
|  | 
 | ||
|  | function getProp(child, prop, props) { | ||
|  |   return props[prop] != null ? props[prop] : child.props[prop]; | ||
|  | } | ||
|  | 
 | ||
|  | function getInitialChildMapping(props, onExited) { | ||
|  |   return getChildMapping(props.children, function (child) { | ||
|  |     return (0, _react.cloneElement)(child, { | ||
|  |       onExited: onExited.bind(null, child), | ||
|  |       in: true, | ||
|  |       appear: getProp(child, 'appear', props), | ||
|  |       enter: getProp(child, 'enter', props), | ||
|  |       exit: getProp(child, 'exit', props) | ||
|  |     }); | ||
|  |   }); | ||
|  | } | ||
|  | 
 | ||
|  | function getNextChildMapping(nextProps, prevChildMapping, onExited) { | ||
|  |   var nextChildMapping = getChildMapping(nextProps.children); | ||
|  |   var children = mergeChildMappings(prevChildMapping, nextChildMapping); | ||
|  |   Object.keys(children).forEach(function (key) { | ||
|  |     var child = children[key]; | ||
|  |     if (!(0, _react.isValidElement)(child)) return; | ||
|  |     var hasPrev = (key in prevChildMapping); | ||
|  |     var hasNext = (key in nextChildMapping); | ||
|  |     var prevChild = prevChildMapping[key]; | ||
|  |     var isLeaving = (0, _react.isValidElement)(prevChild) && !prevChild.props.in; // item is new (entering)
 | ||
|  | 
 | ||
|  |     if (hasNext && (!hasPrev || isLeaving)) { | ||
|  |       // console.log('entering', key)
 | ||
|  |       children[key] = (0, _react.cloneElement)(child, { | ||
|  |         onExited: onExited.bind(null, child), | ||
|  |         in: true, | ||
|  |         exit: getProp(child, 'exit', nextProps), | ||
|  |         enter: getProp(child, 'enter', nextProps) | ||
|  |       }); | ||
|  |     } else if (!hasNext && hasPrev && !isLeaving) { | ||
|  |       // item is old (exiting)
 | ||
|  |       // console.log('leaving', key)
 | ||
|  |       children[key] = (0, _react.cloneElement)(child, { | ||
|  |         in: false | ||
|  |       }); | ||
|  |     } else if (hasNext && hasPrev && (0, _react.isValidElement)(prevChild)) { | ||
|  |       // item hasn't changed transition states
 | ||
|  |       // copy over the last transition props;
 | ||
|  |       // console.log('unchanged', key)
 | ||
|  |       children[key] = (0, _react.cloneElement)(child, { | ||
|  |         onExited: onExited.bind(null, child), | ||
|  |         in: prevChild.props.in, | ||
|  |         exit: getProp(child, 'exit', nextProps), | ||
|  |         enter: getProp(child, 'enter', nextProps) | ||
|  |       }); | ||
|  |     } | ||
|  |   }); | ||
|  |   return children; | ||
|  | } |