UNPKG

@react-md/utils

Version:
151 lines 6.5 kB
import { scrollbarSize } from "../layout/scrollbarSize"; import { BELOW_CENTER_ANCHOR } from "./constants"; import { createHorizontalPosition } from "./createHorizontalPosition"; import { createVerticalPosition } from "./createVerticalPosition"; import { findSizingContainer } from "./findSizingContainer"; import { getElementRect } from "./getElementRect"; import { getTransformOrigin } from "./getTransformOrigin"; /** * This is used when there is no `container` element so that some styles can * still be created. The main use-case for this is context menus and when the * `initialX` and `initialY` options have been provided. * * @internal * @remarks \@since 5.0.0 */ var FALLBACK_DOM_RECT = { x: 0, y: 0, height: 0, width: 0, left: 0, right: 0, top: 0, bottom: 0, toJSON: function () { // do nothing }, }; /** * One of the most complicated functions in this project that will attempt to * position an element relative to another container element while still being * visible within the viewport. Below is the logical flow for attempting to fix * the element to the container: * * No Container: If there is no container element, return the provided x and y * positions and no styles since there's nothing we can use to calculate the * position. * * No Element: If the container was provided but the element to position does * not exist, return an style object containing the `left` and `top` values for * the container and apply as many of the positioning options as possible so * that the styles are "as close as possible" before the fixed element is added * to the DOM. This will also return the provided x and y positions since * nothing could be swapped around yet. * * Container and Element: If both the container and fixed element were provided, * apply all the positioning options to the `left` and `top` values of the * container based on the sizes of both elements. * * Now that the `left` and `top` values were applied, check to see if the * element is fully visible within the viewport with the provided positioning * options. If it is fully visible, do nothing else. If it isn't... follow the * next flow: * * First, check the horizontal sizes and make sure that the element is still * within the viewport with the provided view width margin. If it isn't, first * try to swap only to a `right` style instead of left to see if that fixes it, * otherwise keep both the `left` and `right` styles. */ export function getFixedPosition(options) { var _a; var element = options.element, _b = options.anchor, anchor = _b === void 0 ? BELOW_CENTER_ANCHOR : _b, initialX = options.initialX, _c = options.vwMargin, vwMargin = _c === void 0 ? 16 : _c, _d = options.vhMargin, vhMargin = _d === void 0 ? 16 : _d, _e = options.xMargin, xMargin = _e === void 0 ? 0 : _e, _f = options.yMargin, yMargin = _f === void 0 ? 0 : _f, _g = options.width, widthType = _g === void 0 ? "auto" : _g, _h = options.preventOverlap, preventOverlap = _h === void 0 ? false : _h, _j = options.transformOrigin, transformOrigin = _j === void 0 ? false : _j, _k = options.disableSwapping, disableSwapping = _k === void 0 ? false : _k, _l = options.disableVHBounds, disableVHBounds = _l === void 0 ? false : _l; var initialY = options.initialY; var container = findSizingContainer(options.container); if (process.env.NODE_ENV !== "production") { if (preventOverlap && anchor.y !== "above" && anchor.y !== "below") { throw new Error('Unable to prevent overlap when the vertical anchor is not `"above"` or `"below"`'); } } if (!element) { return { actualX: anchor.x, actualY: anchor.y, style: { left: initialX, top: initialY, position: disableVHBounds ? "absolute" : "fixed", transformOrigin: transformOrigin ? getTransformOrigin({ x: anchor.x, y: anchor.y }) : undefined, }, }; } var containerRect = (_a = container === null || container === void 0 ? void 0 : container.getBoundingClientRect()) !== null && _a !== void 0 ? _a : FALLBACK_DOM_RECT; var vh = window.innerHeight; var vw = window.innerWidth; var elMinWidth = element.style.minWidth; // Note: This makes it "min-content" or "min-container-width" if (widthType === "min") { element.style.overflow = "visible"; element.style.minWidth = ""; } var elementRect = getElementRect(element); var height = elementRect.height; var elWidth = elementRect.width; if (widthType === "min") { elWidth += scrollbarSize(); element.style.overflow = ""; element.style.minWidth = elMinWidth; } if (disableVHBounds) { var dialog = element.closest("[role='dialog']"); if (!dialog) { initialY = (initialY !== null && initialY !== void 0 ? initialY : 0) + window.scrollY; } } var _m = createHorizontalPosition({ x: anchor.x, vw: vw, vwMargin: vwMargin, xMargin: xMargin, width: widthType, elWidth: elWidth, initialX: initialX, containerRect: containerRect, disableSwapping: disableSwapping, }), left = _m.left, right = _m.right, width = _m.width, minWidth = _m.minWidth, actualX = _m.actualX; var _o = createVerticalPosition({ y: anchor.y, vh: vh, vhMargin: vhMargin, yMargin: yMargin, initialY: initialY, elHeight: height, containerRect: containerRect, disableSwapping: disableSwapping, preventOverlap: preventOverlap, disableVHBounds: disableVHBounds, }), top = _o.top, bottom = _o.bottom, actualY = _o.actualY, transformOriginY = _o.transformOriginY; return { actualX: actualX, actualY: actualY, style: { left: left, top: top, right: right, bottom: bottom, width: width, minWidth: minWidth, position: disableVHBounds ? "absolute" : "fixed", transformOrigin: transformOrigin ? getTransformOrigin({ x: actualX, y: actualY, transformOriginY: transformOriginY, }) : undefined, }, }; } //# sourceMappingURL=getFixedPosition.js.map