@wordpress/components
Version:
UI components for WordPress.
81 lines (77 loc) • 3.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.useAnimatedOffsetRect = useAnimatedOffsetRect;
var _compose = require("@wordpress/compose");
var _element = require("@wordpress/element");
var _useOnValueUpdate = require("./use-on-value-update");
/* eslint-disable jsdoc/require-param */
/**
* WordPress dependencies
*/
/**
* Internal dependencies
*/
/**
* A utility used to animate something in a container component based on the "offset
* rect" (position relative to the container and size) of a subelement. For example,
* this is useful to render an indicator for the selected option of a component, and
* to animate it when the selected option changes.
*
* Takes in a container element and the up-to-date "offset rect" of the target
* subelement, obtained with `useTrackElementOffsetRect`. Then it does the following:
*
* - Adds CSS variables with rect information to the container, so that the indicator
* can be rendered and animated with them. These are kept up-to-date, enabling CSS
* transitions on change.
* - Sets an attribute (`data-subelement-animated` by default) when the tracked
* element changes, so that the target (e.g. the indicator) can be animated to its
* new size and position.
* - Removes the attribute when the animation is done.
*
* The need for the attribute is due to the fact that the rect might update in
* situations other than when the tracked element changes, e.g. the tracked element
* might be resized. In such cases, there is no need to animate the indicator, and
* the change in size or position of the indicator needs to be reflected immediately.
*/
function useAnimatedOffsetRect(
/**
* The container element.
*/
container,
/**
* The rect of the tracked element.
*/
rect, {
prefix = 'subelement',
dataAttribute = `${prefix}-animated`,
transitionEndFilter = () => true,
roundRect = false
} = {}) {
const setProperties = (0, _compose.useEvent)(() => {
Object.keys(rect).forEach(property => property !== 'element' && container?.style.setProperty(`--${prefix}-${property}`, String(roundRect ? Math.floor(rect[property]) : rect[property])));
});
(0, _element.useLayoutEffect)(() => {
setProperties();
}, [rect, setProperties]);
(0, _useOnValueUpdate.useOnValueUpdate)(rect.element, ({
previousValue
}) => {
// Only enable the animation when moving from one element to another.
if (rect.element && previousValue) {
container?.setAttribute(`data-${dataAttribute}`, '');
}
});
(0, _element.useLayoutEffect)(() => {
function onTransitionEnd(event) {
if (transitionEndFilter(event)) {
container?.removeAttribute(`data-${dataAttribute}`);
}
}
container?.addEventListener('transitionend', onTransitionEnd);
return () => container?.removeEventListener('transitionend', onTransitionEnd);
}, [dataAttribute, container, transitionEndFilter]);
}
/* eslint-enable jsdoc/require-param */
//# sourceMappingURL=use-animated-offset-rect.js.map