@wordpress/components
Version:
UI components for WordPress.
85 lines (84 loc) • 3.23 kB
JavaScript
// packages/components/src/utils/element-rect.ts
import { useLayoutEffect, useRef, useState } from "@wordpress/element";
import { useEvent, useResizeObserver } from "@wordpress/compose";
var NULL_ELEMENT_OFFSET_RECT = {
element: void 0,
top: 0,
right: 0,
bottom: 0,
left: 0,
width: 0,
height: 0
};
function getElementOffsetRect(element) {
var _offsetParent$getBoun, _offsetParent$scrollL, _offsetParent$scrollT;
const rect = element.getBoundingClientRect();
if (rect.width === 0 || rect.height === 0) {
return;
}
const offsetParent = element.offsetParent;
const offsetParentRect = (_offsetParent$getBoun = offsetParent?.getBoundingClientRect()) !== null && _offsetParent$getBoun !== void 0 ? _offsetParent$getBoun : NULL_ELEMENT_OFFSET_RECT;
const offsetParentScrollX = (_offsetParent$scrollL = offsetParent?.scrollLeft) !== null && _offsetParent$scrollL !== void 0 ? _offsetParent$scrollL : 0;
const offsetParentScrollY = (_offsetParent$scrollT = offsetParent?.scrollTop) !== null && _offsetParent$scrollT !== void 0 ? _offsetParent$scrollT : 0;
const computedWidth = parseFloat(getComputedStyle(element).width);
const computedHeight = parseFloat(getComputedStyle(element).height);
const scaleX = computedWidth / rect.width;
const scaleY = computedHeight / rect.height;
return {
element,
// To obtain the adjusted values for the position:
// 1. Compute the element's position relative to the offset parent.
// 2. Correct for the scale factor.
// 3. Adjust for the scroll position of the offset parent.
top: (rect.top - offsetParentRect?.top) * scaleY + offsetParentScrollY,
right: (offsetParentRect?.right - rect.right) * scaleX - offsetParentScrollX,
bottom: (offsetParentRect?.bottom - rect.bottom) * scaleY - offsetParentScrollY,
left: (rect.left - offsetParentRect?.left) * scaleX + offsetParentScrollX,
// Computed dimensions don't need any adjustments.
width: computedWidth,
height: computedHeight
};
}
var POLL_RATE = 100;
function useTrackElementOffsetRect(targetElement, deps = []) {
const [indicatorPosition, setIndicatorPosition] = useState(NULL_ELEMENT_OFFSET_RECT);
const intervalRef = useRef();
const measure = useEvent(() => {
if (targetElement && targetElement.isConnected) {
const elementOffsetRect = getElementOffsetRect(targetElement);
if (elementOffsetRect) {
setIndicatorPosition(elementOffsetRect);
clearInterval(intervalRef.current);
return true;
}
} else {
clearInterval(intervalRef.current);
}
return false;
});
const setElement = useResizeObserver(() => {
if (!measure()) {
requestAnimationFrame(() => {
if (!measure()) {
intervalRef.current = setInterval(measure, POLL_RATE);
}
});
}
});
useLayoutEffect(() => {
setElement(targetElement);
if (!targetElement) {
setIndicatorPosition(NULL_ELEMENT_OFFSET_RECT);
}
}, [setElement, targetElement]);
useLayoutEffect(() => {
measure();
}, deps);
return indicatorPosition;
}
export {
NULL_ELEMENT_OFFSET_RECT,
getElementOffsetRect,
useTrackElementOffsetRect
};
//# sourceMappingURL=element-rect.js.map