Dashboard sipadu mbip
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.

ChildMapping.js 4.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. import { Children, cloneElement, isValidElement } from 'react';
  2. /**
  3. * Given `this.props.children`, return an object mapping key to child.
  4. *
  5. * @param {*} children `this.props.children`
  6. * @return {object} Mapping of key to child
  7. */
  8. export function getChildMapping(children, mapFn) {
  9. var mapper = function mapper(child) {
  10. return mapFn && isValidElement(child) ? mapFn(child) : child;
  11. };
  12. var result = Object.create(null);
  13. if (children) Children.map(children, function (c) {
  14. return c;
  15. }).forEach(function (child) {
  16. // run the map function here instead so that the key is the computed one
  17. result[child.key] = mapper(child);
  18. });
  19. return result;
  20. }
  21. /**
  22. * When you're adding or removing children some may be added or removed in the
  23. * same render pass. We want to show *both* since we want to simultaneously
  24. * animate elements in and out. This function takes a previous set of keys
  25. * and a new set of keys and merges them with its best guess of the correct
  26. * ordering. In the future we may expose some of the utilities in
  27. * ReactMultiChild to make this easy, but for now React itself does not
  28. * directly have this concept of the union of prevChildren and nextChildren
  29. * so we implement it here.
  30. *
  31. * @param {object} prev prev children as returned from
  32. * `ReactTransitionChildMapping.getChildMapping()`.
  33. * @param {object} next next children as returned from
  34. * `ReactTransitionChildMapping.getChildMapping()`.
  35. * @return {object} a key set that contains all keys in `prev` and all keys
  36. * in `next` in a reasonable order.
  37. */
  38. export function mergeChildMappings(prev, next) {
  39. prev = prev || {};
  40. next = next || {};
  41. function getValueForKey(key) {
  42. return key in next ? next[key] : prev[key];
  43. } // For each key of `next`, the list of keys to insert before that key in
  44. // the combined list
  45. var nextKeysPending = Object.create(null);
  46. var pendingKeys = [];
  47. for (var prevKey in prev) {
  48. if (prevKey in next) {
  49. if (pendingKeys.length) {
  50. nextKeysPending[prevKey] = pendingKeys;
  51. pendingKeys = [];
  52. }
  53. } else {
  54. pendingKeys.push(prevKey);
  55. }
  56. }
  57. var i;
  58. var childMapping = {};
  59. for (var nextKey in next) {
  60. if (nextKeysPending[nextKey]) {
  61. for (i = 0; i < nextKeysPending[nextKey].length; i++) {
  62. var pendingNextKey = nextKeysPending[nextKey][i];
  63. childMapping[nextKeysPending[nextKey][i]] = getValueForKey(pendingNextKey);
  64. }
  65. }
  66. childMapping[nextKey] = getValueForKey(nextKey);
  67. } // Finally, add the keys which didn't appear before any key in `next`
  68. for (i = 0; i < pendingKeys.length; i++) {
  69. childMapping[pendingKeys[i]] = getValueForKey(pendingKeys[i]);
  70. }
  71. return childMapping;
  72. }
  73. function getProp(child, prop, props) {
  74. return props[prop] != null ? props[prop] : child.props[prop];
  75. }
  76. export function getInitialChildMapping(props, onExited) {
  77. return getChildMapping(props.children, function (child) {
  78. return cloneElement(child, {
  79. onExited: onExited.bind(null, child),
  80. in: true,
  81. appear: getProp(child, 'appear', props),
  82. enter: getProp(child, 'enter', props),
  83. exit: getProp(child, 'exit', props)
  84. });
  85. });
  86. }
  87. export function getNextChildMapping(nextProps, prevChildMapping, onExited) {
  88. var nextChildMapping = getChildMapping(nextProps.children);
  89. var children = mergeChildMappings(prevChildMapping, nextChildMapping);
  90. Object.keys(children).forEach(function (key) {
  91. var child = children[key];
  92. if (!isValidElement(child)) return;
  93. var hasPrev = key in prevChildMapping;
  94. var hasNext = key in nextChildMapping;
  95. var prevChild = prevChildMapping[key];
  96. var isLeaving = isValidElement(prevChild) && !prevChild.props.in; // item is new (entering)
  97. if (hasNext && (!hasPrev || isLeaving)) {
  98. // console.log('entering', key)
  99. children[key] = cloneElement(child, {
  100. onExited: onExited.bind(null, child),
  101. in: true,
  102. exit: getProp(child, 'exit', nextProps),
  103. enter: getProp(child, 'enter', nextProps)
  104. });
  105. } else if (!hasNext && hasPrev && !isLeaving) {
  106. // item is old (exiting)
  107. // console.log('leaving', key)
  108. children[key] = cloneElement(child, {
  109. in: false
  110. });
  111. } else if (hasNext && hasPrev && isValidElement(prevChild)) {
  112. // item hasn't changed transition states
  113. // copy over the last transition props;
  114. // console.log('unchanged', key)
  115. children[key] = cloneElement(child, {
  116. onExited: onExited.bind(null, child),
  117. in: prevChild.props.in,
  118. exit: getProp(child, 'exit', nextProps),
  119. enter: getProp(child, 'enter', nextProps)
  120. });
  121. }
  122. });
  123. return children;
  124. }