@vimeo/iris
Version:
Vimeo Design System
106 lines (103 loc) • 5.47 kB
JavaScript
import { a as __makeTemplateObject, b as __rest, _ as __read, c as __assign } from '../../../tslib.es6-7f0e734f.js';
import React__default, { useState, useCallback, useLayoutEffect } from 'react';
import styled, { css } from 'styled-components';
import { rem } from 'polished';
function Anchor(_a) {
var anchor = _a.anchor, anchorToWindow = _a.anchorToWindow, attach = _a.attach, childRef = _a.childRef, children = _a.children, margin = _a.margin, style = _a.style, props = __rest(_a, ["anchor", "anchorToWindow", "attach", "childRef", "children", "margin", "style"]);
var _b = __read(useState({}), 2), state = _b[0], setState = _b[1];
var onResize = useCallback(function () {
var childElement = childRef === null || childRef === void 0 ? void 0 : childRef.current;
if (!childElement)
return;
var viewport = anchorToWindow && windowRect();
var childRect = calcRect(childRef);
var rect = viewport || calcRect(anchor, window);
var _a = remPos({
attach: attach,
margin: margin,
rect: rect,
childRect: childRect,
}), top = _a.top, left = _a.left;
setState(function (state) { return (__assign(__assign({}, state), { top: top, left: left, rect: rect, childRect: childRect })); });
}, [anchor, anchorToWindow, attach, childRef, margin]);
// eslint-disable-next-line react-hooks/exhaustive-deps
useLayoutEffect(function () { return onResize(); }, []);
useLayoutEffect(function () {
var childElement = childRef === null || childRef === void 0 ? void 0 : childRef.current;
window.addEventListener('resize', onResize);
window.addEventListener('scroll', onResize);
childElement === null || childElement === void 0 ? void 0 : childElement.addEventListener('transitionend', onResize);
return function () {
window.removeEventListener('resize', onResize);
window.removeEventListener('scroll', onResize);
childElement === null || childElement === void 0 ? void 0 : childElement.removeEventListener('transitionend', onResize);
};
}, [childRef, onResize]);
useLayoutEffect(function () {
if (!top && !left)
onResize();
});
var top = state.top, left = state.left;
var zIndex = useChildZIndex(children);
return (React__default.createElement(AnchorStyled, __assign({ anchorToWindow: anchorToWindow, attach: attach, childRect: state.childRect, children: children, margin: margin, rect: state.rect, style: __assign(__assign({}, style), { top: top, left: left, zIndex: zIndex }) }, props)));
}
function useChildZIndex(children) {
var _a;
if ((_a = children === null || children === void 0 ? void 0 : children.ref) === null || _a === void 0 ? void 0 : _a.current) {
var style = getComputedStyle(children.ref.current);
var zIndex = parseInt(style.zIndex);
if (zIndex > 0)
return zIndex;
}
return 5000;
}
function calcRect(ref, _a) {
var _b = _a === void 0 ? {} : _a, _c = _b.scrollX, scrollX = _c === void 0 ? 0 : _c, _d = _b.scrollY, scrollY = _d === void 0 ? 0 : _d;
if (ref && ref.current) {
var _e = ref.current, offsetHeight = _e.offsetHeight, offsetWidth = _e.offsetWidth;
var _f = ref.current.getBoundingClientRect(), x = _f.x, y = _f.y;
var height = offsetHeight;
var left = x + scrollX;
var top_1 = y + scrollY;
var width = offsetWidth;
return {
bottom: top_1 + height,
height: height,
left: left,
right: left + width,
top: top_1,
width: width,
};
}
return null;
}
function windowRect() {
return {
bottom: 0,
height: window.innerHeight,
left: 0,
right: 0,
top: 0,
width: window.innerWidth,
};
}
function remPos(_a) {
var _b = __read(_a.attach, 2), a = _b[0], b = _b[1], margin = _a.margin, rect = _a.rect, childRect = _a.childRect;
if (!rect || !childRect)
return { top: null, left: null };
var top = rect.top +
rect.height * (a[0] / 100) -
(childRect.height + margin * 2) * (b[0] / 100);
var left = rect.left +
rect.width * (a[1] / 100) -
(childRect.width + margin * 2) * (b[1] / 100);
return {
top: rem(top <= 0 ? rect.bottom : top),
left: rem(left <= 0 ? rect.right : left),
};
}
var AnchorStyled = styled.div(templateObject_2 || (templateObject_2 = __makeTemplateObject(["\n position: fixed;\n margin: ", ";\n overflow: visible;\n max-width: calc(100vw - 1.5rem) !important;\n\n ", "\n"], ["\n position: fixed;\n margin: ", ";\n overflow: visible;\n max-width: calc(100vw - 1.5rem) !important;\n\n ", "\n"])), function (p) { return rem(p.margin); }, function (p) {
return !p.anchorToWindow && css(templateObject_1 || (templateObject_1 = __makeTemplateObject(["\n position: absolute;\n\n > div {\n max-width: 100%;\n\n > div {\n max-width: 100%;\n\n > * {\n max-width: 100%;\n }\n }\n }\n "], ["\n position: absolute;\n\n > div {\n max-width: 100%;\n\n > div {\n max-width: 100%;\n\n > * {\n max-width: 100%;\n }\n }\n }\n "])));
});
var templateObject_1, templateObject_2;
export { Anchor };