@atlaskit/motion
Version:
A set of utilities to apply motion in your application.
102 lines (98 loc) • 4.58 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useResizingHeight = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _react = require("react");
var _curves = require("../utils/curves");
var _durations = require("../utils/durations");
var _isReducedMotion = require("../utils/is-reduced-motion");
var _useElementRef3 = require("../utils/use-element-ref");
var _useLayoutEffect = require("../utils/use-layout-effect");
var _useRequestAnimationFrame = require("../utils/use-request-animation-frame");
var _useSetTimeout = require("../utils/use-set-timeout");
var _useSnapshotBeforeUpdate = require("../utils/use-snapshot-before-update");
/* eslint-disable @repo/internal/deprecations/deprecation-ticket-required */
/**
* `useResizingHeight` animates height changes over state changes. If the height hasn't changed nothing will happen.
*
* __WARNING__: Potentially janky. This hook animates height which is
* [notoriously unperformant](https://firefox-source-docs.mozilla.org/performance/bestpractices.html#Get_familiar_with_the_pipeline_that_gets_pixels_to_the_screen).
* Test your app over low powered devices, you may want to avoid this if you can see it impacting FPS.
*
* See [examples](https://atlaskit.atlassian.com/packages/design-system/motion/docs/resizing-motions).
*
* @deprecated Use `useResizing` from `@atlaskit/motion/resizing` instead. Pass `dimension: 'height'`
* to animate height changes. The new hook supports `'width'`, `'height'`, or `'both'`.
*/
var useResizingHeight = exports.useResizingHeight = function useResizingHeight() {
var _ref = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {},
_ref$duration = _ref.duration,
calcDuration = _ref$duration === void 0 ? function () {
return _durations.durations.medium;
} : _ref$duration,
_ref$timingFunction = _ref.timingFunction,
calcTimingFunction = _ref$timingFunction === void 0 ? function () {
return _curves.easeInOut;
} : _ref$timingFunction;
var prevDimensions = (0, _react.useRef)();
var _useElementRef = (0, _useElementRef3.useElementRef)(),
_useElementRef2 = (0, _slicedToArray2.default)(_useElementRef, 2),
element = _useElementRef2[0],
setElementRef = _useElementRef2[1];
// We cleanup on the next effect to prevent the previous timeout being called during
// the next motion - as now the timeout has essentially been extended!
var setTimeout = (0, _useSetTimeout.useSetTimeout)({
cleanup: 'next-effect'
});
var requestAnimationFrame = (0, _useRequestAnimationFrame.useRequestAnimationFrame)();
(0, _useSnapshotBeforeUpdate.useSnapshotBeforeUpdate)(function () {
if ((0, _isReducedMotion.isReducedMotion)() || !element) {
return;
}
prevDimensions.current = element.getBoundingClientRect();
});
(0, _useLayoutEffect.useLayoutEffect)(function () {
if ((0, _isReducedMotion.isReducedMotion)() || !element || !prevDimensions.current) {
return;
}
// We might already be animating.
// Because of that we need to expand to the destination height first.
element.setAttribute('style', '');
var nextDimensions = element.getBoundingClientRect();
if (nextDimensions.height === prevDimensions.current.height) {
return;
}
var duration = calcDuration(prevDimensions.current.height, nextDimensions.height);
var newStyles = {
height: "".concat(prevDimensions.current.height, "px"),
willChange: 'height',
transitionProperty: 'height',
transitionDuration: "".concat(duration, "ms"),
boxSizing: 'border-box',
transitionTimingFunction: calcTimingFunction(prevDimensions.current.height, nextDimensions.height, duration)
};
Object.assign(element.style, newStyles);
// We split this over two animation frames so the DOM has enough time to flush the changes.
// We are deliberately not skipping this frame if another render happens - if we do the motion doesn't finish properly.
requestAnimationFrame(function () {
requestAnimationFrame(function () {
if (!element) {
return;
}
element.style.height = "".concat(nextDimensions.height, "px");
setTimeout(function () {
if (!element) {
return;
}
element.setAttribute('style', '');
}, duration);
});
});
});
return {
ref: setElementRef
};
};