UNPKG

office-ui-fabric-react

Version:

Reusable React components for building experiences for Office 365.

679 lines • 31.4 kB
var _a; import * as tslib_1 from "tslib"; import { DirectionalHint } from '../../common/DirectionalHint'; import { getScrollbarWidth, getRTL, Rectangle as FullRectangle } from '../../Utilities'; import { RectangleEdge } from './positioning.types'; var Rectangle = /** @class */ (function (_super) { tslib_1.__extends(Rectangle, _super); function Rectangle() { return _super !== null && _super.apply(this, arguments) || this; } return Rectangle; }(FullRectangle)); export { Rectangle }; function _createPositionData(targetEdge, alignmentEdge, isAuto) { return { targetEdge: targetEdge, alignmentEdge: alignmentEdge, isAuto: isAuto }; } // Currently the beakPercent is set to 50 for all positions meaning that it should tend to the center of the target var DirectionalDictionary = (_a = {}, _a[DirectionalHint.topLeftEdge] = _createPositionData(RectangleEdge.top, RectangleEdge.left), _a[DirectionalHint.topCenter] = _createPositionData(RectangleEdge.top), _a[DirectionalHint.topRightEdge] = _createPositionData(RectangleEdge.top, RectangleEdge.right), _a[DirectionalHint.topAutoEdge] = _createPositionData(RectangleEdge.top, undefined, true), _a[DirectionalHint.bottomLeftEdge] = _createPositionData(RectangleEdge.bottom, RectangleEdge.left), _a[DirectionalHint.bottomCenter] = _createPositionData(RectangleEdge.bottom), _a[DirectionalHint.bottomRightEdge] = _createPositionData(RectangleEdge.bottom, RectangleEdge.right), _a[DirectionalHint.bottomAutoEdge] = _createPositionData(RectangleEdge.bottom, undefined, true), _a[DirectionalHint.leftTopEdge] = _createPositionData(RectangleEdge.left, RectangleEdge.top), _a[DirectionalHint.leftCenter] = _createPositionData(RectangleEdge.left), _a[DirectionalHint.leftBottomEdge] = _createPositionData(RectangleEdge.left, RectangleEdge.bottom), _a[DirectionalHint.rightTopEdge] = _createPositionData(RectangleEdge.right, RectangleEdge.top), _a[DirectionalHint.rightCenter] = _createPositionData(RectangleEdge.right), _a[DirectionalHint.rightBottomEdge] = _createPositionData(RectangleEdge.right, RectangleEdge.bottom), _a); function _isRectangleWithinBounds(rect, boundingRect) { if (rect.top < boundingRect.top) { return false; } if (rect.bottom > boundingRect.bottom) { return false; } if (rect.left < boundingRect.left) { return false; } if (rect.right > boundingRect.right) { return false; } return true; } /** * Gets all of the edges of a rectangle that are outside of the given bounds. * If there are no out of bounds edges it returns an empty array. */ function _getOutOfBoundsEdges(rect, boundingRect) { var outOfBounds = new Array(); if (rect.top < boundingRect.top) { outOfBounds.push(RectangleEdge.top); } if (rect.bottom > boundingRect.bottom) { outOfBounds.push(RectangleEdge.bottom); } if (rect.left < boundingRect.left) { outOfBounds.push(RectangleEdge.left); } if (rect.right > boundingRect.right) { outOfBounds.push(RectangleEdge.right); } return outOfBounds; } function _getEdgeValue(rect, edge) { return rect[RectangleEdge[edge]]; } function _setEdgeValue(rect, edge, value) { rect[RectangleEdge[edge]] = value; return rect; } /** * Returns the middle value of an edge. Only returns 1 value rather than xy coordinates as * the itself already contains the other coordinate. * For instance, a bottom edge's current value is it's y coordinate, so the number returned is the x. * * @param {Rectangle} rect * @param {RectangleEdge} edge * @returns {number} */ function _getCenterValue(rect, edge) { var edges = _getFlankingEdges(edge); return (_getEdgeValue(rect, edges.positiveEdge) + _getEdgeValue(rect, edges.negativeEdge)) / 2; } /** * Flips the value depending on the edge. * If the edge is a "positive" edge, Top or Left, then the value should stay as it is. * If the edge is a "negative" edge, Bottom or Right, then the value should be flipped. * This is to account for the fact that the coordinates are effectively reveserved in certain cases for the "negative" edges. * For example, when testing to see if a bottom edge 1 is within the bounds of another bottom edge 2. * If edge 1 is greater than edge 2 then it is out of bounds. This is reversed for top edge 1 and top edge 2. * If top edge 1 is less than edge 2 then it is out of bounds. * * * @param {RectangleEdge} edge * @param {number} value * @returns {number} */ function _getRelativeEdgeValue(edge, value) { if (edge > 0) { return value; } else { return value * -1; } } function _getRelativeRectEdgeValue(edge, rect) { return _getRelativeEdgeValue(edge, _getEdgeValue(rect, edge)); } function _getRelativeEdgeDifference(rect, hostRect, edge) { var edgeDifference = _getEdgeValue(rect, edge) - _getEdgeValue(hostRect, edge); return _getRelativeEdgeValue(edge, edgeDifference); } /** * Moves the edge of a rectangle to the value given. It only moves the edge in a linear direction based on that edge. * For example, if it's a bottom edge it will only change y coordinates. * * @param {Rectangle} rect * @param {RectangleEdge} edge * @param {number} newValue * @returns {Rectangle} */ function _moveEdge(rect, edge, newValue) { var difference = _getEdgeValue(rect, edge) - newValue; rect = _setEdgeValue(rect, edge, newValue); rect = _setEdgeValue(rect, edge * -1, _getEdgeValue(rect, edge * -1) - difference); return rect; } /** * Aligns the edge on the passed in rect to the target. If there is a gap then it will have that space between the two. * * @param {Rectangle} rect * @param {Rectangle} target * @param {RectangleEdge} edge * @param {number} [gap=0] * @returns {Rectangle} */ function _alignEdges(rect, target, edge, gap) { if (gap === void 0) { gap = 0; } return _moveEdge(rect, edge, _getEdgeValue(target, edge) + _getRelativeEdgeValue(edge, gap)); } /** * Aligns the targetEdge on the passed in target to the rects corresponding opposite edge. * For instance if targetEdge is bottom, then the rects top will be moved to match it. * * @param {Rectangle} rect * @param {Rectangle} target * @param {RectangleEdge} targetEdge * @param {number} [gap=0] * @returns {Rectangle} */ function _alignOppositeEdges(rect, target, targetEdge, gap) { if (gap === void 0) { gap = 0; } var oppositeEdge = targetEdge * -1; var adjustedGap = _getRelativeEdgeValue(oppositeEdge, gap); return _moveEdge(rect, targetEdge * -1, _getEdgeValue(target, targetEdge) + adjustedGap); } /** * Tests to see if the given edge is within the bounds of the given rectangle. * * @param {Rectangle} rect * @param {Rectangle} bounds * @param {RectangleEdge} edge * @returns {boolean} */ function _isEdgeInBounds(rect, bounds, edge) { var adjustedRectValue = _getRelativeRectEdgeValue(edge, rect); return adjustedRectValue > _getRelativeRectEdgeValue(edge, bounds); } /** * Attempts to move the rectangle through various sides of the target to find a place to fit. * If no fit is found, the original position should be returned. * * @param {Rectangle} rect * @param {Rectangle} target * @param {Rectangle} bounding * @param {IPositionDirectionalHintData} positionData * @param {number} [gap=0] * @returns {IElementPosition} */ function _flipToFit(rect, target, bounding, positionData, gap) { if (gap === void 0) { gap = 0; } var directions = [RectangleEdge.left, RectangleEdge.right, RectangleEdge.bottom, RectangleEdge.top]; // In RTL page, RectangleEdge.right has a higher priority than RectangleEdge.left, therefore the order should be updated. if (getRTL()) { directions[0] *= -1; directions[1] *= -1; } var currentEstimate = rect; var currentEdge = positionData.targetEdge; var currentAlignment = positionData.alignmentEdge; // Keep switching sides until one is found with enough space. If all sides don't fit then return the unmodified element. for (var i = 0; i < 4; i++) { if (!_isEdgeInBounds(currentEstimate, bounding, currentEdge)) { directions.splice(directions.indexOf(currentEdge), 1); if (directions.length > 0) { if (directions.indexOf(currentEdge * -1) > -1) { currentEdge = currentEdge * -1; } else { currentAlignment = currentEdge; currentEdge = directions.slice(-1)[0]; } currentEstimate = _estimatePosition(rect, target, { targetEdge: currentEdge, alignmentEdge: currentAlignment }, gap); } } else { return { elementRectangle: currentEstimate, targetEdge: currentEdge, alignmentEdge: currentAlignment }; } } return { elementRectangle: rect, targetEdge: positionData.targetEdge, alignmentEdge: currentAlignment }; } /** * Flips only the alignment edge of an element rectangle. This is used instead of nudging the alignment edges into position, * when alignTargetEdge is specified. * @param elementEstimate * @param target * @param bounding * @param gap */ function _flipAlignmentEdge(elementEstimate, target, gap, coverTarget) { var alignmentEdge = elementEstimate.alignmentEdge, targetEdge = elementEstimate.targetEdge, elementRectangle = elementEstimate.elementRectangle; var oppositeEdge = alignmentEdge * -1; var newEstimate = _estimatePosition(elementRectangle, target, { targetEdge: targetEdge, alignmentEdge: oppositeEdge }, gap, coverTarget); return { elementRectangle: newEstimate, targetEdge: targetEdge, alignmentEdge: oppositeEdge }; } /** * Adjusts a element rectangle to fit within the bounds given. If directionalHintFixed or covertarget is passed in * then the element will not flip sides on the target. They will, however, be nudged to fit within the bounds given. * * @param {Rectangle} element * @param {Rectangle} target * @param {Rectangle} bounding * @param {IPositionDirectionalHintData} positionData * @param {number} [gap=0] * @param {boolean} [directionalHintFixed] * @param {boolean} [coverTarget] * @returns {IElementPosition} */ function _adjustFitWithinBounds(element, target, bounding, positionData, gap, directionalHintFixed, coverTarget) { if (gap === void 0) { gap = 0; } var alignmentEdge = positionData.alignmentEdge, alignTargetEdge = positionData.alignTargetEdge; var elementEstimate = { elementRectangle: element, targetEdge: positionData.targetEdge, alignmentEdge: alignmentEdge }; if (!directionalHintFixed && !coverTarget) { elementEstimate = _flipToFit(element, target, bounding, positionData, gap); } var outOfBounds = _getOutOfBoundsEdges(element, bounding); if (alignTargetEdge) { // The edge opposite to the alignment edge might be out of bounds. Flip alignment to see if we can get it within bounds. if (elementEstimate.alignmentEdge && outOfBounds.indexOf(elementEstimate.alignmentEdge * -1) > -1) { var flippedElementEstimate = _flipAlignmentEdge(elementEstimate, target, gap, coverTarget); if (_isRectangleWithinBounds(flippedElementEstimate.elementRectangle, bounding)) { return flippedElementEstimate; } else { // If the flipped elements edges are still out of bounds, try nudging it. elementEstimate = _alignOutOfBoundsEdges(_getOutOfBoundsEdges(flippedElementEstimate.elementRectangle, bounding), elementEstimate, bounding); } } } else { elementEstimate = _alignOutOfBoundsEdges(outOfBounds, elementEstimate, bounding); } return elementEstimate; } /** * Iterates through a list of out of bounds edges and tries to nudge and align them. * @param outOfBoundsEdges Array of edges that are out of bounds * @param elementEstimate The current element positioning estimate * @param bounding The current bounds */ function _alignOutOfBoundsEdges(outOfBoundsEdges, elementEstimate, bounding) { for (var _i = 0, outOfBoundsEdges_1 = outOfBoundsEdges; _i < outOfBoundsEdges_1.length; _i++) { var direction = outOfBoundsEdges_1[_i]; elementEstimate.elementRectangle = _alignEdges(elementEstimate.elementRectangle, bounding, direction); } return elementEstimate; } /** * Moves the middle point on an edge to the point given. * Only moves in one direction. For instance if a bottom edge is passed in, then * the bottom edge will be moved in the x axis to match the point. * * @param {Rectangle} rect * @param {RectangleEdge} edge * @param {number} point * @returns {Rectangle} */ function _centerEdgeToPoint(rect, edge, point) { var positiveEdge = _getFlankingEdges(edge).positiveEdge; var elementMiddle = _getCenterValue(rect, edge); var distanceToMiddle = elementMiddle - _getEdgeValue(rect, positiveEdge); return _moveEdge(rect, positiveEdge, point - distanceToMiddle); } /** * Moves the element rectangle to be appropriately positioned relative to a given target. * Does not flip or adjust the element. * * @param {Rectangle} elementToPosition * @param {Rectangle} target * @param {IPositionDirectionalHintData} positionData * @param {number} [gap=0] * @param {boolean} [coverTarget] * @returns {Rectangle} */ function _estimatePosition(elementToPosition, target, positionData, gap, coverTarget) { if (gap === void 0) { gap = 0; } var estimatedElementPosition; var alignmentEdge = positionData.alignmentEdge, targetEdge = positionData.targetEdge; var elementEdge = coverTarget ? targetEdge : targetEdge * -1; estimatedElementPosition = coverTarget ? _alignEdges(elementToPosition, target, targetEdge, gap) : _alignOppositeEdges(elementToPosition, target, targetEdge, gap); // if no alignment edge is provided it's supposed to be centered. if (!alignmentEdge) { var targetMiddlePoint = _getCenterValue(target, targetEdge); estimatedElementPosition = _centerEdgeToPoint(estimatedElementPosition, elementEdge, targetMiddlePoint); } else { estimatedElementPosition = _alignEdges(estimatedElementPosition, target, alignmentEdge); } return estimatedElementPosition; } /** * Returns the non-opposite edges of the target edge. * For instance if bottom is passed in then left and right will be returned. * * @param {RectangleEdge} edge * @returns {{ firstEdge: RectangleEdge, secondEdge: RectangleEdge }} */ function _getFlankingEdges(edge) { if (edge === RectangleEdge.top || edge === RectangleEdge.bottom) { return { positiveEdge: RectangleEdge.left, negativeEdge: RectangleEdge.right }; } else { return { positiveEdge: RectangleEdge.top, negativeEdge: RectangleEdge.bottom }; } } /** * Retrieve the final value for the return edge of elementRectangle. * If the elementRectangle is closer to one side of the bounds versus the other, the return edge is flipped to grow inward. * * @param elementRectangle * @param targetEdge * @param bounds */ function _finalizeReturnEdge(elementRectangle, returnEdge, bounds) { if (bounds && Math.abs(_getRelativeEdgeDifference(elementRectangle, bounds, returnEdge)) > Math.abs(_getRelativeEdgeDifference(elementRectangle, bounds, returnEdge * -1))) { return returnEdge * -1; } return returnEdge; } /** * Finalizes the element positon based on the hostElement. Only returns the * rectangle values to position such that they are anchored to the target. * This helps prevent resizing from looking very strange. * For instance, if the target edge is top and aligned with the left side then * the bottom and left values are returned so as the callou shrinks it shrinks towards that corner. * * @param {Rectangle} elementRectangle * @param {HTMLElement} hostElement * @param {RectangleEdge} targetEdge * @param {RectangleEdge} bounds * @param {RectangleEdge} [alignmentEdge] * @param {boolean} coverTarget * @returns {IPartialIRectangle} */ function _finalizeElementPosition(elementRectangle, hostElement, targetEdge, bounds, alignmentEdge, coverTarget) { var returnValue = {}; var hostRect = _getRectangleFromElement(hostElement); var elementEdge = coverTarget ? targetEdge : targetEdge * -1; var elementEdgeString = RectangleEdge[elementEdge]; var returnEdge = _finalizeReturnEdge(elementRectangle, alignmentEdge ? alignmentEdge : _getFlankingEdges(targetEdge).positiveEdge, bounds); returnValue[elementEdgeString] = _getRelativeEdgeDifference(elementRectangle, hostRect, elementEdge); returnValue[RectangleEdge[returnEdge]] = _getRelativeEdgeDifference(elementRectangle, hostRect, returnEdge); return returnValue; } // Since the beak is rotated 45 degrees the actual height/width is the length of the diagonal. // We still want to position the beak based on it's midpoint which does not change. It will // be at (beakwidth / 2, beakwidth / 2) function _calculateActualBeakWidthInPixels(beakWidth) { return Math.sqrt(beakWidth * beakWidth * 2); } /** * Returns the appropriate IPositionData based on the props altered for RTL. * If directionalHintForRTL is passed in that is used if the page is RTL. * If a directionalHint is specified and no directionalHintForRTL is available and the page is RTL the hint will be flipped. * For instance bottomLeftEdge would become bottomRightEdge. * If there is no directionalHint passed in bottomAutoEdge is chosen automatically. * * @param {IPositionProps} props * @returns {IPositionDirectionalHintData} */ function _getPositionData(directionalHint, directionalHintForRTL, previousPositions) { if (directionalHint === void 0) { directionalHint = DirectionalHint.bottomAutoEdge; } if (previousPositions) { return { alignmentEdge: previousPositions.alignmentEdge, isAuto: previousPositions.isAuto, targetEdge: previousPositions.targetEdge }; } var positionInformation = tslib_1.__assign({}, DirectionalDictionary[directionalHint]); if (getRTL()) { // If alignment edge exists and that alignment edge is -2 or 2, right or left, then flip it. if (positionInformation.alignmentEdge && positionInformation.alignmentEdge % 2 === 0) { positionInformation.alignmentEdge = positionInformation.alignmentEdge * -1; } return directionalHintForRTL !== undefined ? DirectionalDictionary[directionalHintForRTL] : positionInformation; } return positionInformation; } /** * Get's the alignment data for the given information. This only really matters if the positioning is Auto. * If it is auto then the alignmentEdge should be chosen based on the target edge's position relative to * the center of the page. * * @param {IPositionDirectionalHintData} positionData * @param {Rectangle} target * @param {Rectangle} boundingRect * @param {boolean} [coverTarget] * @returns {IPositionDirectionalHintData} */ function _getAlignmentData(positionData, target, boundingRect, coverTarget, alignTargetEdge) { if (positionData.isAuto) { positionData.alignmentEdge = getClosestEdge(positionData.targetEdge, target, boundingRect); } positionData.alignTargetEdge = alignTargetEdge; return positionData; } function getClosestEdge(targetEdge, target, boundingRect) { var targetCenter = _getCenterValue(target, targetEdge); var boundingCenter = _getCenterValue(boundingRect, targetEdge); var _a = _getFlankingEdges(targetEdge), positiveEdge = _a.positiveEdge, negativeEdge = _a.negativeEdge; if (targetCenter <= boundingCenter) { return positiveEdge; } else { return negativeEdge; } } function _positionElementWithinBounds(elementToPosition, target, bounding, positionData, gap, directionalHintFixed, coverTarget) { var estimatedElementPosition = _estimatePosition(elementToPosition, target, positionData, gap, coverTarget); if (_isRectangleWithinBounds(estimatedElementPosition, bounding)) { return { elementRectangle: estimatedElementPosition, targetEdge: positionData.targetEdge, alignmentEdge: positionData.alignmentEdge }; } else { return _adjustFitWithinBounds(elementToPosition, target, bounding, positionData, gap, directionalHintFixed, coverTarget); } } function _finalizeBeakPosition(elementPosition, positionedBeak, bounds) { var targetEdge = elementPosition.targetEdge * -1; // The "host" element that we will use to help position the beak. var actualElement = new Rectangle(0, elementPosition.elementRectangle.width, 0, elementPosition.elementRectangle.height); var returnValue = {}; var returnEdge = _finalizeReturnEdge(elementPosition.elementRectangle, elementPosition.alignmentEdge ? elementPosition.alignmentEdge : _getFlankingEdges(targetEdge).positiveEdge, bounds); returnValue[RectangleEdge[targetEdge]] = _getEdgeValue(positionedBeak, targetEdge); returnValue[RectangleEdge[returnEdge]] = _getRelativeEdgeDifference(positionedBeak, actualElement, returnEdge); return { elementPosition: tslib_1.__assign({}, returnValue), closestEdge: getClosestEdge(elementPosition.targetEdge, positionedBeak, actualElement), targetEdge: targetEdge }; } function _positionBeak(beakWidth, elementPosition) { var target = elementPosition.targetRectangle; /** * Note about beak positioning: The actual beak width only matters for getting the gap between the callout and * target, it does not impact the beak placement within the callout. For example example, if the beakWidth is 8, * then the actual beakWidth is sqrroot(8^2 + 8^2) = 11.31x11.31. So the callout will need to be an extra 3 pixels * away from its target. While the beak is being positioned in the callout it still acts as though it were 8x8. * */ var _a = _getFlankingEdges(elementPosition.targetEdge), positiveEdge = _a.positiveEdge, negativeEdge = _a.negativeEdge; var beakTargetPoint = _getCenterValue(target, elementPosition.targetEdge); var elementBounds = new Rectangle(beakWidth / 2, elementPosition.elementRectangle.width - beakWidth / 2, beakWidth / 2, elementPosition.elementRectangle.height - beakWidth / 2); var beakPosition = new Rectangle(0, beakWidth, 0, beakWidth); beakPosition = _moveEdge(beakPosition, elementPosition.targetEdge * -1, -beakWidth / 2); beakPosition = _centerEdgeToPoint(beakPosition, elementPosition.targetEdge * -1, beakTargetPoint - _getRelativeRectEdgeValue(positiveEdge, elementPosition.elementRectangle)); if (!_isEdgeInBounds(beakPosition, elementBounds, positiveEdge)) { beakPosition = _alignEdges(beakPosition, elementBounds, positiveEdge); } else if (!_isEdgeInBounds(beakPosition, elementBounds, negativeEdge)) { beakPosition = _alignEdges(beakPosition, elementBounds, negativeEdge); } return beakPosition; } function _getRectangleFromElement(element) { var clientRect = element.getBoundingClientRect(); return new Rectangle(clientRect.left, clientRect.right, clientRect.top, clientRect.bottom); } function _getRectangleFromIRect(rect) { return new Rectangle(rect.left, rect.right, rect.top, rect.bottom); } function _getTargetRect(bounds, target) { var targetRectangle; if (target) { if (target.preventDefault) { var ev = target; targetRectangle = new Rectangle(ev.clientX, ev.clientX, ev.clientY, ev.clientY); } else if (target.getBoundingClientRect) { targetRectangle = _getRectangleFromElement(target); // HTMLImgElements can have x and y values. The check for it being a point must go last. } else { var point = target; targetRectangle = new Rectangle(point.x, point.x, point.y, point.y); } if (!_isRectangleWithinBounds(targetRectangle, bounds)) { var outOfBounds = _getOutOfBoundsEdges(targetRectangle, bounds); for (var _i = 0, outOfBounds_1 = outOfBounds; _i < outOfBounds_1.length; _i++) { var direction = outOfBounds_1[_i]; targetRectangle[RectangleEdge[direction]] = bounds[RectangleEdge[direction]]; } } } else { targetRectangle = new Rectangle(0, 0, 0, 0); } return targetRectangle; } /** * If max height is less than zero it returns the bounds height instead. */ function _getMaxHeightFromTargetRectangle(targetRectangle, targetEdge, gapSpace, bounds, coverTarget) { var maxHeight = 0; var directionalHint = DirectionalDictionary[targetEdge]; // If cover target is set, then the max height should be calculated using the opposite of the target edge since // that's the direction that the callout will expand in. // For instance, if the directionalhint is bottomLeftEdge then the callout will position so it's bottom edge // is aligned with the bottom of the target and expand up towards the top of the screen and the calculated max height // is (bottom of target) - (top of screen) - gapSpace. var target = coverTarget ? directionalHint.targetEdge * -1 : directionalHint.targetEdge; if (target === RectangleEdge.top) { maxHeight = _getEdgeValue(targetRectangle, directionalHint.targetEdge) - bounds.top - gapSpace; } else if (target === RectangleEdge.bottom) { maxHeight = bounds.bottom - _getEdgeValue(targetRectangle, directionalHint.targetEdge) - gapSpace; } else { maxHeight = bounds.bottom - targetRectangle.top - gapSpace; } return maxHeight > 0 ? maxHeight : bounds.height; } function _positionElementRelative(props, elementToPosition, boundingRect, previousPositions) { var gap = props.gapSpace ? props.gapSpace : 0; var targetRect = _getTargetRect(boundingRect, props.target); var positionData = _getAlignmentData(_getPositionData(props.directionalHint, props.directionalHintForRTL, previousPositions), targetRect, boundingRect, props.coverTarget, props.alignTargetEdge); var positionedElement = _positionElementWithinBounds(_getRectangleFromElement(elementToPosition), targetRect, boundingRect, positionData, gap, props.directionalHintFixed, props.coverTarget); return tslib_1.__assign({}, positionedElement, { targetRectangle: targetRect }); } function _finalizePositionData(positionedElement, hostElement, bounds, coverTarget) { var finalizedElement = _finalizeElementPosition(positionedElement.elementRectangle, hostElement, positionedElement.targetEdge, bounds, positionedElement.alignmentEdge, coverTarget); return { elementPosition: finalizedElement, targetEdge: positionedElement.targetEdge, alignmentEdge: positionedElement.alignmentEdge }; } function _positionElement(props, hostElement, elementToPosition, previousPositions) { var boundingRect = props.bounds ? _getRectangleFromIRect(props.bounds) : new Rectangle(0, window.innerWidth - getScrollbarWidth(), 0, window.innerHeight); var positionedElement = _positionElementRelative(props, elementToPosition, boundingRect, previousPositions); return _finalizePositionData(positionedElement, hostElement, boundingRect, props.coverTarget); } function _positionCallout(props, hostElement, callout, previousPositions) { var beakWidth = props.isBeakVisible ? props.beakWidth || 0 : 0; var gap = _calculateActualBeakWidthInPixels(beakWidth) / 2 + (props.gapSpace ? props.gapSpace : 0); var positionProps = props; positionProps.gapSpace = gap; var boundingRect = props.bounds ? _getRectangleFromIRect(props.bounds) : new Rectangle(0, window.innerWidth - getScrollbarWidth(), 0, window.innerHeight); var positionedElement = _positionElementRelative(positionProps, callout, boundingRect, previousPositions); var beakPositioned = _positionBeak(beakWidth, positionedElement); var finalizedBeakPosition = _finalizeBeakPosition(positionedElement, beakPositioned, boundingRect); return tslib_1.__assign({}, _finalizePositionData(positionedElement, hostElement, boundingRect, props.coverTarget), { beakPosition: finalizedBeakPosition }); } // END PRIVATE FUNCTIONS /* tslint:disable:variable-name */ export var __positioningTestPackage = { _finalizePositionData: _finalizePositionData, _finalizeBeakPosition: _finalizeBeakPosition, _calculateActualBeakWidthInPixels: _calculateActualBeakWidthInPixels, _positionElementWithinBounds: _positionElementWithinBounds, _positionBeak: _positionBeak, _getPositionData: _getPositionData, _getMaxHeightFromTargetRectangle: _getMaxHeightFromTargetRectangle }; /* tslint:enable:variable-name */ /** * Used to position an element relative to the given positioning props. * If positioning has been completed before, previousPositioningData * can be passed to ensure that the positioning element repositions based on * its previous targets rather than starting with directionalhint. * * @export * @param {IPositionProps} props * @param {HTMLElement} hostElement * @param {HTMLElement} elementToPosition * @param {IPositionedData} previousPositions * @returns */ export function positionElement(props, hostElement, elementToPosition, previousPositions) { return _positionElement(props, hostElement, elementToPosition, previousPositions); } export function positionCallout(props, hostElement, elementToPosition, previousPositions) { return _positionCallout(props, hostElement, elementToPosition, previousPositions); } /** * Get's the maximum height that a rectangle can have in order to fit below or above a target. * If the directional hint specifies a left or right edge (i.e. leftCenter) it will limit the height to the topBorder * of the target given. * If no bounds are provided then the window is treated as the bounds. */ export function getMaxHeight(target, targetEdge, gapSpace, bounds, coverTarget) { if (gapSpace === void 0) { gapSpace = 0; } var mouseTarget = target; var elementTarget = target; var pointTarget = target; var targetRect; var boundingRectangle = bounds ? _getRectangleFromIRect(bounds) : new Rectangle(0, window.innerWidth - getScrollbarWidth(), 0, window.innerHeight); if (mouseTarget.stopPropagation) { targetRect = new Rectangle(mouseTarget.clientX, mouseTarget.clientX, mouseTarget.clientY, mouseTarget.clientY); } else if (pointTarget.x !== undefined && pointTarget.y !== undefined) { targetRect = new Rectangle(pointTarget.x, pointTarget.x, pointTarget.y, pointTarget.y); } else { targetRect = _getRectangleFromElement(elementTarget); } return _getMaxHeightFromTargetRectangle(targetRect, targetEdge, gapSpace, boundingRectangle, coverTarget); } /** * Returns the opposite edge of the given RectangleEdge. */ export function getOppositeEdge(edge) { return edge * -1; } //# sourceMappingURL=positioning.js.map