import { top, left, right, bottom, start } from "../enums.js"; import getBasePlacement from "../utils/getBasePlacement.js"; import getMainAxisFromPlacement from "../utils/getMainAxisFromPlacement.js"; import getAltAxis from "../utils/getAltAxis.js"; import within from "../utils/within.js"; import getLayoutRect from "../dom-utils/getLayoutRect.js"; import getOffsetParent from "../dom-utils/getOffsetParent.js"; import detectOverflow from "../utils/detectOverflow.js"; import getVariation from "../utils/getVariation.js"; import getFreshSideObject from "../utils/getFreshSideObject.js"; import { max as mathMax, min as mathMin } from "../utils/math.js"; function preventOverflow(_ref) { var state = _ref.state, options = _ref.options, name = _ref.name; var _options$mainAxis = options.mainAxis, checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, _options$altAxis = options.altAxis, checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis, boundary = options.boundary, rootBoundary = options.rootBoundary, altBoundary = options.altBoundary, padding = options.padding, _options$tether = options.tether, tether = _options$tether === void 0 ? true : _options$tether, _options$tetherOffset = options.tetherOffset, tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset; var overflow = detectOverflow(state, { boundary: boundary, rootBoundary: rootBoundary, padding: padding, altBoundary: altBoundary }); var basePlacement = getBasePlacement(state.placement); var variation = getVariation(state.placement); var isBasePlacement = !variation; var mainAxis = getMainAxisFromPlacement(basePlacement); var altAxis = getAltAxis(mainAxis); var popperOffsets = state.modifiersData.popperOffsets; var referenceRect = state.rects.reference; var popperRect = state.rects.popper; var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, { placement: state.placement })) : tetherOffset; var data = { x: 0, y: 0 }; if (!popperOffsets) { return; } if (checkMainAxis || checkAltAxis) { var mainSide = mainAxis === 'y' ? top : left; var altSide = mainAxis === 'y' ? bottom : right; var len = mainAxis === 'y' ? 'height' : 'width'; var offset = popperOffsets[mainAxis]; var min = popperOffsets[mainAxis] + overflow[mainSide]; var max = popperOffsets[mainAxis] - overflow[altSide]; var additive = tether ? -popperRect[len] / 2 : 0; var minLen = variation === start ? referenceRect[len] : popperRect[len]; var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go // outside the reference bounds var arrowElement = state.elements.arrow; var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : { width: 0, height: 0 }; var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject(); var arrowPaddingMin = arrowPaddingObject[mainSide]; var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want // to include its full size in the calculation. If the reference is small // and near the edge of a boundary, the popper can overflow even if the // reference is not overflowing as well (e.g. virtual elements with no // width or height) var arrowLen = within(0, referenceRect[len], arrowRect[len]); var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - tetherOffsetValue : minLen - arrowLen - arrowPaddingMin - tetherOffsetValue; var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + tetherOffsetValue : maxLen + arrowLen + arrowPaddingMax + tetherOffsetValue; var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow); var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0; var offsetModifierValue = state.modifiersData.offset ? state.modifiersData.offset[state.placement][mainAxis] : 0; var tetherMin = popperOffsets[mainAxis] + minOffset - offsetModifierValue - clientOffset; var tetherMax = popperOffsets[mainAxis] + maxOffset - offsetModifierValue; if (checkMainAxis) { var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max); popperOffsets[mainAxis] = preventedOffset; data[mainAxis] = preventedOffset - offset; } if (checkAltAxis) { var _mainSide = mainAxis === 'x' ? top : left; var _altSide = mainAxis === 'x' ? bottom : right; var _offset = popperOffsets[altAxis]; var _min = _offset + overflow[_mainSide]; var _max = _offset - overflow[_altSide]; var _preventedOffset = within(tether ? mathMin(_min, tetherMin) : _min, _offset, tether ? mathMax(_max, tetherMax) : _max); popperOffsets[altAxis] = _preventedOffset; data[altAxis] = _preventedOffset - _offset; } } state.modifiersData[name] = data; } // eslint-disable-next-line import/no-unused-modules export default { name: 'preventOverflow', enabled: true, phase: 'main', fn: preventOverflow, requiresIfExists: ['offset'] };