@awsui/components-react
Version:
AWS UI is a collection of [React](https://reactjs.org/) components that help create intuitive, responsive, and accessible user experiences for web applications. It is developed by Amazon Web Services (AWS). This work is available under the terms of the [A
101 lines (100 loc) • 5.18 kB
JavaScript
import { __assign } from "tslib";
import React, { useCallback, useLayoutEffect, useRef, useState } from 'react';
import clsx from 'clsx';
import { getContainingBlock } from '../internal/utils/dom';
import { useContainerQuery } from '../internal/hooks/container-queries';
import { calculatePosition } from './utils/positions';
import styles from './styles.css.js';
var INITIAL_STYLES = { position: 'absolute', top: -9999, left: -9999 };
export default function PopoverContainer(_a) {
var position = _a.position, track = _a.track, arrow = _a.arrow, children = _a.children, zIndex = _a.zIndex;
var _b = useContainerQuery(function (rect, prev) {
var roundedRect = { width: Math.round(rect.width), height: Math.round(rect.height) };
return (prev === null || prev === void 0 ? void 0 : prev.width) === roundedRect.width && (prev === null || prev === void 0 ? void 0 : prev.height) === roundedRect.height ? prev : rect;
}), popoverRect = _b[0], ref = _b[1];
var bodyRef = useRef(null);
var arrowRef = useRef(null);
var onMount = useCallback(function (element) {
bodyRef.current = element;
ref.current = element;
}, [ref]);
var _c = useState(INITIAL_STYLES), inlineStyle = _c[0], setInlineStyle = _c[1];
var _d = useState(null), internalPosition = _d[0], setInternalPosition = _d[1];
useLayoutEffect(function () {
var positionBody = function () {
if (!track || !bodyRef.current || !arrowRef.current) {
return function () { };
}
var body = bodyRef.current;
var arrow = arrowRef.current;
var containingBlock = getContainingBlock(body);
if (body.offsetWidth === 0 || body.offsetHeight === 0) {
return function () { };
}
var prevTop = body.style.top;
var prevLeft = body.style.left;
body.style.top = '0';
body.style.left = '0';
var viewportRect = getViewportRect();
var trackRect = track.getBoundingClientRect();
var arrowRect = {
width: parseFloat(getComputedStyle(arrow).width),
height: parseFloat(getComputedStyle(arrow).height)
};
var containingBlockRect = containingBlock ? containingBlock.getBoundingClientRect() : viewportRect;
var bodyRect = body.getBoundingClientRect();
var bodyRectCeil = {
top: bodyRect.top,
left: bodyRect.left,
width: Math.ceil(bodyRect.width),
height: Math.ceil(bodyRect.height)
};
var _a = calculatePosition(position, trackRect, arrowRect, bodyRectCeil, containingBlock ? containingBlockRect : document.documentElement.getBoundingClientRect(), viewportRect), newInternalPosition = _a.internalPosition, boundingOffset = _a.boundingOffset;
var popoverOffset = toRelativePosition(boundingOffset, containingBlockRect);
var trackRelativeOffset = toRelativePosition(popoverOffset, toRelativePosition(trackRect, containingBlockRect));
body.style.top = prevTop;
body.style.left = prevLeft;
setInternalPosition(newInternalPosition);
setInlineStyle({ top: popoverOffset.top, left: popoverOffset.left });
return function () {
var newTrackOffset = toRelativePosition(track.getBoundingClientRect(), containingBlock ? containingBlock.getBoundingClientRect() : viewportRect);
setInlineStyle({
top: newTrackOffset.top + trackRelativeOffset.top,
left: newTrackOffset.left + trackRelativeOffset.left
});
};
};
var onScroll = { callback: positionBody() };
var onScrollListener = function () { return onScroll.callback(); };
var onClick = function () {
return requestAnimationFrame(function () {
onScroll.callback = positionBody();
});
};
window.addEventListener('resize', positionBody);
window.addEventListener('scroll', onScrollListener, true);
window.addEventListener('click', onClick);
return function () {
window.removeEventListener('resize', positionBody);
window.removeEventListener('scroll', onScrollListener, true);
window.removeEventListener('click', onClick);
};
}, [position, track, popoverRect]);
return (React.createElement("div", { ref: onMount, style: __assign(__assign({}, inlineStyle), { zIndex: zIndex }), className: styles.container },
React.createElement("div", { ref: arrowRef, className: clsx(styles["container-arrow"], styles["container-arrow-position-" + internalPosition]), "aria-hidden": true }, arrow(internalPosition)),
children));
}
function toRelativePosition(element, parent) {
return {
top: element.top - parent.top,
left: element.left - parent.left
};
}
function getViewportRect() {
return {
top: 0,
left: 0,
width: window.innerWidth,
height: window.innerHeight
};
}