UNPKG

@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
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 }; }