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.
249 lines
9.0 KiB
249 lines
9.0 KiB
2 years ago
|
'use strict';
|
||
|
|
||
|
Object.defineProperty(exports, "__esModule", {
|
||
|
value: true
|
||
|
});
|
||
|
exports.createTransitionString = exports.getNativeNode = exports.updateHeightPlaceholder = exports.removeNodeFromDOMFlow = exports.getPositionDelta = exports.getRelativeBoundingBox = undefined;
|
||
|
|
||
|
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
|
||
|
/**
|
||
|
* React Flip Move
|
||
|
* (c) 2016-present Joshua Comeau
|
||
|
*
|
||
|
* These methods read from and write to the DOM.
|
||
|
* They almost always have side effects, and will hopefully become the
|
||
|
* only spot in the codebase with impure functions.
|
||
|
*/
|
||
|
|
||
|
|
||
|
exports.applyStylesToDOMNode = applyStylesToDOMNode;
|
||
|
exports.whichTransitionEvent = whichTransitionEvent;
|
||
|
|
||
|
var _reactDom = require('react-dom');
|
||
|
|
||
|
var _helpers = require('./helpers');
|
||
|
|
||
|
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
||
|
|
||
|
function applyStylesToDOMNode(_ref) {
|
||
|
var domNode = _ref.domNode,
|
||
|
styles = _ref.styles;
|
||
|
|
||
|
// Can't just do an object merge because domNode.styles is no regular object.
|
||
|
// Need to do it this way for the engine to fire its `set` listeners.
|
||
|
Object.keys(styles).forEach(function (key) {
|
||
|
domNode.style.setProperty((0, _helpers.hyphenate)(key), styles[key]);
|
||
|
});
|
||
|
}
|
||
|
|
||
|
// Modified from Modernizr
|
||
|
function whichTransitionEvent() {
|
||
|
var transitions = {
|
||
|
transition: 'transitionend',
|
||
|
'-o-transition': 'oTransitionEnd',
|
||
|
'-moz-transition': 'transitionend',
|
||
|
'-webkit-transition': 'webkitTransitionEnd'
|
||
|
};
|
||
|
|
||
|
// If we're running in a browserless environment (eg. SSR), it doesn't apply.
|
||
|
// Return a placeholder string, for consistent type return.
|
||
|
if (typeof document === 'undefined') return '';
|
||
|
|
||
|
var el = document.createElement('fakeelement');
|
||
|
|
||
|
var match = Object.keys(transitions).find(function (t) {
|
||
|
return el.style.getPropertyValue(t) !== undefined;
|
||
|
});
|
||
|
|
||
|
// If no `transition` is found, we must be running in a browser so ancient,
|
||
|
// React itself won't run. Return an empty string, for consistent type return
|
||
|
return match ? transitions[match] : '';
|
||
|
}
|
||
|
|
||
|
var getRelativeBoundingBox = exports.getRelativeBoundingBox = function getRelativeBoundingBox(_ref2) {
|
||
|
var childDomNode = _ref2.childDomNode,
|
||
|
parentDomNode = _ref2.parentDomNode,
|
||
|
getPosition = _ref2.getPosition;
|
||
|
|
||
|
var parentBox = getPosition(parentDomNode);
|
||
|
|
||
|
var _getPosition = getPosition(childDomNode),
|
||
|
top = _getPosition.top,
|
||
|
left = _getPosition.left,
|
||
|
right = _getPosition.right,
|
||
|
bottom = _getPosition.bottom,
|
||
|
width = _getPosition.width,
|
||
|
height = _getPosition.height;
|
||
|
|
||
|
return {
|
||
|
top: top - parentBox.top,
|
||
|
left: left - parentBox.left,
|
||
|
right: parentBox.right - right,
|
||
|
bottom: parentBox.bottom - bottom,
|
||
|
width: width,
|
||
|
height: height
|
||
|
};
|
||
|
};
|
||
|
|
||
|
/** getPositionDelta
|
||
|
* This method returns the delta between two bounding boxes, to figure out
|
||
|
* how many pixels on each axis the element has moved.
|
||
|
*
|
||
|
*/
|
||
|
var getPositionDelta = exports.getPositionDelta = function getPositionDelta(_ref3) {
|
||
|
var childDomNode = _ref3.childDomNode,
|
||
|
childBoundingBox = _ref3.childBoundingBox,
|
||
|
parentBoundingBox = _ref3.parentBoundingBox,
|
||
|
getPosition = _ref3.getPosition;
|
||
|
|
||
|
// TEMP: A mystery bug is sometimes causing unnecessary boundingBoxes to
|
||
|
var defaultBox = { top: 0, left: 0, right: 0, bottom: 0, height: 0, width: 0 };
|
||
|
|
||
|
// Our old box is its last calculated position, derived on mount or at the
|
||
|
// start of the previous animation.
|
||
|
var oldRelativeBox = childBoundingBox || defaultBox;
|
||
|
var parentBox = parentBoundingBox || defaultBox;
|
||
|
|
||
|
// Our new box is the new final resting place: Where we expect it to wind up
|
||
|
// after the animation. First we get the box in absolute terms (AKA relative
|
||
|
// to the viewport), and then we calculate its relative box (relative to the
|
||
|
// parent container)
|
||
|
var newAbsoluteBox = getPosition(childDomNode);
|
||
|
var newRelativeBox = {
|
||
|
top: newAbsoluteBox.top - parentBox.top,
|
||
|
left: newAbsoluteBox.left - parentBox.left
|
||
|
};
|
||
|
|
||
|
return [oldRelativeBox.left - newRelativeBox.left, oldRelativeBox.top - newRelativeBox.top];
|
||
|
};
|
||
|
|
||
|
/** removeNodeFromDOMFlow
|
||
|
* This method does something very sneaky: it removes a DOM node from the
|
||
|
* document flow, but without actually changing its on-screen position.
|
||
|
*
|
||
|
* It works by calculating where the node is, and then applying styles
|
||
|
* so that it winds up being positioned absolutely, but in exactly the
|
||
|
* same place.
|
||
|
*
|
||
|
* This is a vital part of the FLIP technique.
|
||
|
*/
|
||
|
var removeNodeFromDOMFlow = exports.removeNodeFromDOMFlow = function removeNodeFromDOMFlow(childData, verticalAlignment) {
|
||
|
var domNode = childData.domNode,
|
||
|
boundingBox = childData.boundingBox;
|
||
|
|
||
|
|
||
|
if (!domNode || !boundingBox) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// For this to work, we have to offset any given `margin`.
|
||
|
var computed = window.getComputedStyle(domNode);
|
||
|
|
||
|
// We need to clean up margins, by converting and removing suffix:
|
||
|
// eg. '21px' -> 21
|
||
|
var marginAttrs = ['margin-top', 'margin-left', 'margin-right'];
|
||
|
var margins = marginAttrs.reduce(function (acc, margin) {
|
||
|
var propertyVal = computed.getPropertyValue(margin);
|
||
|
|
||
|
return _extends({}, acc, _defineProperty({}, margin, Number(propertyVal.replace('px', ''))));
|
||
|
}, {});
|
||
|
|
||
|
// If we're bottom-aligned, we need to add the height of the child to its
|
||
|
// top offset. This is because, when the container is bottom-aligned, its
|
||
|
// height shrinks from the top, not the bottom. We're removing this node
|
||
|
// from the flow, so the top is going to drop by its height.
|
||
|
var topOffset = verticalAlignment === 'bottom' ? boundingBox.top - boundingBox.height : boundingBox.top;
|
||
|
|
||
|
var styles = {
|
||
|
position: 'absolute',
|
||
|
top: topOffset - margins['margin-top'] + 'px',
|
||
|
left: boundingBox.left - margins['margin-left'] + 'px',
|
||
|
right: boundingBox.right - margins['margin-right'] + 'px'
|
||
|
};
|
||
|
|
||
|
applyStylesToDOMNode({ domNode: domNode, styles: styles });
|
||
|
};
|
||
|
|
||
|
/** updateHeightPlaceholder
|
||
|
* An optional property to FlipMove is a `maintainContainerHeight` boolean.
|
||
|
* This property creates a node that fills space, so that the parent
|
||
|
* container doesn't collapse when its children are removed from the
|
||
|
* document flow.
|
||
|
*/
|
||
|
var updateHeightPlaceholder = exports.updateHeightPlaceholder = function updateHeightPlaceholder(_ref4) {
|
||
|
var domNode = _ref4.domNode,
|
||
|
parentData = _ref4.parentData,
|
||
|
getPosition = _ref4.getPosition;
|
||
|
|
||
|
var parentDomNode = parentData.domNode;
|
||
|
var parentBoundingBox = parentData.boundingBox;
|
||
|
|
||
|
if (!parentDomNode || !parentBoundingBox) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// We need to find the height of the container *without* the placeholder.
|
||
|
// Since it's possible that the placeholder might already be present,
|
||
|
// we first set its height to 0.
|
||
|
// This allows the container to collapse down to the size of just its
|
||
|
// content (plus container padding or borders if any).
|
||
|
applyStylesToDOMNode({ domNode: domNode, styles: { height: '0' } });
|
||
|
|
||
|
// Find the distance by which the container would be collapsed by elements
|
||
|
// leaving. We compare the freshly-available parent height with the original,
|
||
|
// cached container height.
|
||
|
var originalParentHeight = parentBoundingBox.height;
|
||
|
var collapsedParentHeight = getPosition(parentDomNode).height;
|
||
|
var reductionInHeight = originalParentHeight - collapsedParentHeight;
|
||
|
|
||
|
// If the container has become shorter, update the padding element's
|
||
|
// height to take up the difference. Otherwise set its height to zero,
|
||
|
// so that it has no effect.
|
||
|
var styles = {
|
||
|
height: reductionInHeight > 0 ? reductionInHeight + 'px' : '0'
|
||
|
};
|
||
|
|
||
|
applyStylesToDOMNode({ domNode: domNode, styles: styles });
|
||
|
};
|
||
|
|
||
|
var getNativeNode = exports.getNativeNode = function getNativeNode(element) {
|
||
|
// When running in a windowless environment, abort!
|
||
|
if (typeof HTMLElement === 'undefined') {
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
// `element` may already be a native node.
|
||
|
if (element instanceof HTMLElement) {
|
||
|
return element;
|
||
|
}
|
||
|
|
||
|
// While ReactDOM's `findDOMNode` is discouraged, it's the only
|
||
|
// publicly-exposed way to find the underlying DOM node for
|
||
|
// composite components.
|
||
|
var foundNode = (0, _reactDom.findDOMNode)(element);
|
||
|
|
||
|
if (!(foundNode instanceof HTMLElement)) {
|
||
|
// Text nodes are not supported
|
||
|
return null;
|
||
|
}
|
||
|
|
||
|
return foundNode;
|
||
|
};
|
||
|
|
||
|
var createTransitionString = exports.createTransitionString = function createTransitionString(index, props) {
|
||
|
var delay = props.delay,
|
||
|
duration = props.duration;
|
||
|
var staggerDurationBy = props.staggerDurationBy,
|
||
|
staggerDelayBy = props.staggerDelayBy,
|
||
|
easing = props.easing;
|
||
|
|
||
|
|
||
|
delay += index * staggerDelayBy;
|
||
|
duration += index * staggerDurationBy;
|
||
|
|
||
|
var cssProperties = ['transform', 'opacity'];
|
||
|
|
||
|
return cssProperties.map(function (prop) {
|
||
|
return prop + ' ' + duration + 'ms ' + easing + ' ' + delay + 'ms';
|
||
|
}).join(', ');
|
||
|
};
|