diff options
Diffstat (limited to 'popperjs/package/lib/modifiers')
30 files changed, 2110 insertions, 0 deletions
diff --git a/popperjs/package/lib/modifiers/applyStyles.d.ts b/popperjs/package/lib/modifiers/applyStyles.d.ts new file mode 100644 index 0000000..317306f --- /dev/null +++ b/popperjs/package/lib/modifiers/applyStyles.d.ts @@ -0,0 +1,4 @@ +import type { Modifier } from "../types"; +export declare type ApplyStylesModifier = Modifier<"applyStyles", {}>; +declare const _default: ApplyStylesModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/applyStyles.js b/popperjs/package/lib/modifiers/applyStyles.js new file mode 100644 index 0000000..84ac4ba --- /dev/null +++ b/popperjs/package/lib/modifiers/applyStyles.js @@ -0,0 +1,84 @@ +import getNodeName from "../dom-utils/getNodeName.js"; +import { isHTMLElement } from "../dom-utils/instanceOf.js"; // This modifier takes the styles prepared by the `computeStyles` modifier +// and applies them to the HTMLElements such as popper and arrow + +function applyStyles(_ref) { + var state = _ref.state; + Object.keys(state.elements).forEach(function (name) { + var style = state.styles[name] || {}; + var attributes = state.attributes[name] || {}; + var element = state.elements[name]; // arrow is optional + virtual elements + + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } // Flow doesn't support to extend this property, but it's the most + // effective way to apply styles to an HTMLElement + // $FlowFixMe[cannot-write] + + + Object.assign(element.style, style); + Object.keys(attributes).forEach(function (name) { + var value = attributes[name]; + + if (value === false) { + element.removeAttribute(name); + } else { + element.setAttribute(name, value === true ? '' : value); + } + }); + }); +} + +function effect(_ref2) { + var state = _ref2.state; + var initialStyles = { + popper: { + position: state.options.strategy, + left: '0', + top: '0', + margin: '0' + }, + arrow: { + position: 'absolute' + }, + reference: {} + }; + Object.assign(state.elements.popper.style, initialStyles.popper); + state.styles = initialStyles; + + if (state.elements.arrow) { + Object.assign(state.elements.arrow.style, initialStyles.arrow); + } + + return function () { + Object.keys(state.elements).forEach(function (name) { + var element = state.elements[name]; + var attributes = state.attributes[name] || {}; + var styleProperties = Object.keys(state.styles.hasOwnProperty(name) ? state.styles[name] : initialStyles[name]); // Set all values to an empty string to unset them + + var style = styleProperties.reduce(function (style, property) { + style[property] = ''; + return style; + }, {}); // arrow is optional + virtual elements + + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } + + Object.assign(element.style, style); + Object.keys(attributes).forEach(function (attribute) { + element.removeAttribute(attribute); + }); + }); + }; +} // eslint-disable-next-line import/no-unused-modules + + +export default { + name: 'applyStyles', + enabled: true, + phase: 'write', + fn: applyStyles, + effect: effect, + requires: ['computeStyles'] +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/applyStyles.js.flow b/popperjs/package/lib/modifiers/applyStyles.js.flow new file mode 100644 index 0000000..e976cf0 --- /dev/null +++ b/popperjs/package/lib/modifiers/applyStyles.js.flow @@ -0,0 +1,98 @@ +// @flow +import type { Modifier, ModifierArguments } from '../types'; +import getNodeName from '../dom-utils/getNodeName'; +import { isHTMLElement } from '../dom-utils/instanceOf'; + +// This modifier takes the styles prepared by the `computeStyles` modifier +// and applies them to the HTMLElements such as popper and arrow + +function applyStyles({ state }: ModifierArguments<{||}>) { + Object.keys(state.elements).forEach((name) => { + const style = state.styles[name] || {}; + + const attributes = state.attributes[name] || {}; + const element = state.elements[name]; + + // arrow is optional + virtual elements + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } + + // Flow doesn't support to extend this property, but it's the most + // effective way to apply styles to an HTMLElement + // $FlowFixMe[cannot-write] + Object.assign(element.style, style); + + Object.keys(attributes).forEach((name) => { + const value = attributes[name]; + if (value === false) { + element.removeAttribute(name); + } else { + element.setAttribute(name, value === true ? '' : value); + } + }); + }); +} + +function effect({ state }: ModifierArguments<{||}>) { + const initialStyles = { + popper: { + position: state.options.strategy, + left: '0', + top: '0', + margin: '0', + }, + arrow: { + position: 'absolute', + }, + reference: {}, + }; + + Object.assign(state.elements.popper.style, initialStyles.popper); + state.styles = initialStyles; + + if (state.elements.arrow) { + Object.assign(state.elements.arrow.style, initialStyles.arrow); + } + + return () => { + Object.keys(state.elements).forEach((name) => { + const element = state.elements[name]; + const attributes = state.attributes[name] || {}; + + const styleProperties = Object.keys( + state.styles.hasOwnProperty(name) + ? state.styles[name] + : initialStyles[name] + ); + + // Set all values to an empty string to unset them + const style = styleProperties.reduce((style, property) => { + style[property] = ''; + return style; + }, {}); + + // arrow is optional + virtual elements + if (!isHTMLElement(element) || !getNodeName(element)) { + return; + } + + Object.assign(element.style, style); + + Object.keys(attributes).forEach((attribute) => { + element.removeAttribute(attribute); + }); + }); + }; +} + +// eslint-disable-next-line import/no-unused-modules +export type ApplyStylesModifier = Modifier<'applyStyles', {||}>; +export default ({ + name: 'applyStyles', + enabled: true, + phase: 'write', + fn: applyStyles, + effect, + requires: ['computeStyles'], +}: ApplyStylesModifier); diff --git a/popperjs/package/lib/modifiers/arrow.d.ts b/popperjs/package/lib/modifiers/arrow.d.ts new file mode 100644 index 0000000..7112698 --- /dev/null +++ b/popperjs/package/lib/modifiers/arrow.d.ts @@ -0,0 +1,13 @@ +import type { Modifier, Padding, Rect } from "../types"; +import type { Placement } from "../enums"; +export declare type Options = { + element: HTMLElement | string | null; + padding: Padding | ((arg0: { + popper: Rect; + reference: Rect; + placement: Placement; + }) => Padding); +}; +export declare type ArrowModifier = Modifier<"arrow", Options>; +declare const _default: ArrowModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/arrow.js b/popperjs/package/lib/modifiers/arrow.js new file mode 100644 index 0000000..d0001e2 --- /dev/null +++ b/popperjs/package/lib/modifiers/arrow.js @@ -0,0 +1,101 @@ +import getBasePlacement from "../utils/getBasePlacement.js"; +import getLayoutRect from "../dom-utils/getLayoutRect.js"; +import contains from "../dom-utils/contains.js"; +import getOffsetParent from "../dom-utils/getOffsetParent.js"; +import getMainAxisFromPlacement from "../utils/getMainAxisFromPlacement.js"; +import { within } from "../utils/within.js"; +import mergePaddingObject from "../utils/mergePaddingObject.js"; +import expandToHashMap from "../utils/expandToHashMap.js"; +import { left, right, basePlacements, top, bottom } from "../enums.js"; +import { isHTMLElement } from "../dom-utils/instanceOf.js"; // eslint-disable-next-line import/no-unused-modules + +var toPaddingObject = function toPaddingObject(padding, state) { + padding = typeof padding === 'function' ? padding(Object.assign({}, state.rects, { + placement: state.placement + })) : padding; + return mergePaddingObject(typeof padding !== 'number' ? padding : expandToHashMap(padding, basePlacements)); +}; + +function arrow(_ref) { + var _state$modifiersData$; + + var state = _ref.state, + name = _ref.name, + options = _ref.options; + var arrowElement = state.elements.arrow; + var popperOffsets = state.modifiersData.popperOffsets; + var basePlacement = getBasePlacement(state.placement); + var axis = getMainAxisFromPlacement(basePlacement); + var isVertical = [left, right].indexOf(basePlacement) >= 0; + var len = isVertical ? 'height' : 'width'; + + if (!arrowElement || !popperOffsets) { + return; + } + + var paddingObject = toPaddingObject(options.padding, state); + var arrowRect = getLayoutRect(arrowElement); + var minProp = axis === 'y' ? top : left; + var maxProp = axis === 'y' ? bottom : right; + var endDiff = state.rects.reference[len] + state.rects.reference[axis] - popperOffsets[axis] - state.rects.popper[len]; + var startDiff = popperOffsets[axis] - state.rects.reference[axis]; + var arrowOffsetParent = getOffsetParent(arrowElement); + var clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0; + var centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the popper if the center point is + // outside of the popper bounds + + var min = paddingObject[minProp]; + var max = clientSize - arrowRect[len] - paddingObject[maxProp]; + var center = clientSize / 2 - arrowRect[len] / 2 + centerToReference; + var offset = within(min, center, max); // Prevents breaking syntax highlighting... + + var axisProp = axis; + state.modifiersData[name] = (_state$modifiersData$ = {}, _state$modifiersData$[axisProp] = offset, _state$modifiersData$.centerOffset = offset - center, _state$modifiersData$); +} + +function effect(_ref2) { + var state = _ref2.state, + options = _ref2.options; + var _options$element = options.element, + arrowElement = _options$element === void 0 ? '[data-popper-arrow]' : _options$element; + + if (arrowElement == null) { + return; + } // CSS selector + + + if (typeof arrowElement === 'string') { + arrowElement = state.elements.popper.querySelector(arrowElement); + + if (!arrowElement) { + return; + } + } + + if (process.env.NODE_ENV !== "production") { + if (!isHTMLElement(arrowElement)) { + console.error(['Popper: "arrow" element must be an HTMLElement (not an SVGElement).', 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', 'the arrow.'].join(' ')); + } + } + + if (!contains(state.elements.popper, arrowElement)) { + if (process.env.NODE_ENV !== "production") { + console.error(['Popper: "arrow" modifier\'s `element` must be a child of the popper', 'element.'].join(' ')); + } + + return; + } + + state.elements.arrow = arrowElement; +} // eslint-disable-next-line import/no-unused-modules + + +export default { + name: 'arrow', + enabled: true, + phase: 'main', + fn: arrow, + effect: effect, + requires: ['popperOffsets'], + requiresIfExists: ['preventOverflow'] +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/arrow.js.flow b/popperjs/package/lib/modifiers/arrow.js.flow new file mode 100644 index 0000000..03666f5 --- /dev/null +++ b/popperjs/package/lib/modifiers/arrow.js.flow @@ -0,0 +1,142 @@ +// @flow +import type { Modifier, ModifierArguments, Padding, Rect } from '../types'; +import type { Placement } from '../enums'; +import getBasePlacement from '../utils/getBasePlacement'; +import getLayoutRect from '../dom-utils/getLayoutRect'; +import contains from '../dom-utils/contains'; +import getOffsetParent from '../dom-utils/getOffsetParent'; +import getMainAxisFromPlacement from '../utils/getMainAxisFromPlacement'; +import { within } from '../utils/within'; +import mergePaddingObject from '../utils/mergePaddingObject'; +import expandToHashMap from '../utils/expandToHashMap'; +import { left, right, basePlacements, top, bottom } from '../enums'; +import { isHTMLElement } from '../dom-utils/instanceOf'; + +// eslint-disable-next-line import/no-unused-modules +export type Options = { + element: HTMLElement | string | null, + padding: + | Padding + | (({| + popper: Rect, + reference: Rect, + placement: Placement, + |}) => Padding), +}; + +const toPaddingObject = (padding, state) => { + padding = + typeof padding === 'function' + ? padding({ ...state.rects, placement: state.placement }) + : padding; + + return mergePaddingObject( + typeof padding !== 'number' + ? padding + : expandToHashMap(padding, basePlacements) + ); +}; + +function arrow({ state, name, options }: ModifierArguments<Options>) { + const arrowElement = state.elements.arrow; + const popperOffsets = state.modifiersData.popperOffsets; + const basePlacement = getBasePlacement(state.placement); + const axis = getMainAxisFromPlacement(basePlacement); + const isVertical = [left, right].indexOf(basePlacement) >= 0; + const len = isVertical ? 'height' : 'width'; + + if (!arrowElement || !popperOffsets) { + return; + } + + const paddingObject = toPaddingObject(options.padding, state); + const arrowRect = getLayoutRect(arrowElement); + const minProp = axis === 'y' ? top : left; + const maxProp = axis === 'y' ? bottom : right; + + const endDiff = + state.rects.reference[len] + + state.rects.reference[axis] - + popperOffsets[axis] - + state.rects.popper[len]; + const startDiff = popperOffsets[axis] - state.rects.reference[axis]; + + const arrowOffsetParent = getOffsetParent(arrowElement); + const clientSize = arrowOffsetParent + ? axis === 'y' + ? arrowOffsetParent.clientHeight || 0 + : arrowOffsetParent.clientWidth || 0 + : 0; + + const centerToReference = endDiff / 2 - startDiff / 2; + + // Make sure the arrow doesn't overflow the popper if the center point is + // outside of the popper bounds + const min = paddingObject[minProp]; + const max = clientSize - arrowRect[len] - paddingObject[maxProp]; + const center = clientSize / 2 - arrowRect[len] / 2 + centerToReference; + const offset = within(min, center, max); + + // Prevents breaking syntax highlighting... + const axisProp: string = axis; + state.modifiersData[name] = { + [axisProp]: offset, + centerOffset: offset - center, + }; +} + +function effect({ state, options }: ModifierArguments<Options>) { + let { element: arrowElement = '[data-popper-arrow]' } = options; + + if (arrowElement == null) { + return; + } + + // CSS selector + if (typeof arrowElement === 'string') { + arrowElement = state.elements.popper.querySelector(arrowElement); + + if (!arrowElement) { + return; + } + } + + if (false) { + if (!isHTMLElement(arrowElement)) { + console.error( + [ + 'Popper: "arrow" element must be an HTMLElement (not an SVGElement).', + 'To use an SVG arrow, wrap it in an HTMLElement that will be used as', + 'the arrow.', + ].join(' ') + ); + } + } + + if (!contains(state.elements.popper, arrowElement)) { + if (false) { + console.error( + [ + 'Popper: "arrow" modifier\'s `element` must be a child of the popper', + 'element.', + ].join(' ') + ); + } + + return; + } + + state.elements.arrow = arrowElement; +} + +// eslint-disable-next-line import/no-unused-modules +export type ArrowModifier = Modifier<'arrow', Options>; +export default ({ + name: 'arrow', + enabled: true, + phase: 'main', + fn: arrow, + effect, + requires: ['popperOffsets'], + requiresIfExists: ['preventOverflow'], +}: ArrowModifier); diff --git a/popperjs/package/lib/modifiers/computeStyles.d.ts b/popperjs/package/lib/modifiers/computeStyles.d.ts new file mode 100644 index 0000000..30394b5 --- /dev/null +++ b/popperjs/package/lib/modifiers/computeStyles.d.ts @@ -0,0 +1,38 @@ +import type { PositioningStrategy, Offsets, Modifier, Rect } from "../types"; +import { BasePlacement, Variation } from "../enums"; +export declare type RoundOffsets = (offsets: Partial<{ + x: number; + y: number; + centerOffset: number; +}>) => Offsets; +export declare type Options = { + gpuAcceleration: boolean; + adaptive: boolean; + roundOffsets?: boolean | RoundOffsets; +}; +export declare function mapToStyles({ popper, popperRect, placement, variation, offsets, position, gpuAcceleration, adaptive, roundOffsets, isFixed }: { + popper: HTMLElement; + popperRect: Rect; + placement: BasePlacement; + variation: Variation | null | undefined; + offsets: Partial<{ + x: number; + y: number; + centerOffset: number; + }>; + position: PositioningStrategy; + gpuAcceleration: boolean; + adaptive: boolean; + roundOffsets: boolean | RoundOffsets; + isFixed: boolean; +}): { + transform: string; + top: string; + right: string; + bottom: string; + left: string; + position: PositioningStrategy; +}; +export declare type ComputeStylesModifier = Modifier<"computeStyles", Options>; +declare const _default: ComputeStylesModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/computeStyles.js b/popperjs/package/lib/modifiers/computeStyles.js new file mode 100644 index 0000000..6522eea --- /dev/null +++ b/popperjs/package/lib/modifiers/computeStyles.js @@ -0,0 +1,162 @@ +import { top, left, right, bottom, end } from "../enums.js"; +import getOffsetParent from "../dom-utils/getOffsetParent.js"; +import getWindow from "../dom-utils/getWindow.js"; +import getDocumentElement from "../dom-utils/getDocumentElement.js"; +import getComputedStyle from "../dom-utils/getComputedStyle.js"; +import getBasePlacement from "../utils/getBasePlacement.js"; +import getVariation from "../utils/getVariation.js"; +import { round } from "../utils/math.js"; // eslint-disable-next-line import/no-unused-modules + +var unsetSides = { + top: 'auto', + right: 'auto', + bottom: 'auto', + left: 'auto' +}; // Round the offsets to the nearest suitable subpixel based on the DPR. +// Zooming can change the DPR, but it seems to report a value that will +// cleanly divide the values into the appropriate subpixels. + +function roundOffsetsByDPR(_ref) { + var x = _ref.x, + y = _ref.y; + var win = window; + var dpr = win.devicePixelRatio || 1; + return { + x: round(x * dpr) / dpr || 0, + y: round(y * dpr) / dpr || 0 + }; +} + +export function mapToStyles(_ref2) { + var _Object$assign2; + + var popper = _ref2.popper, + popperRect = _ref2.popperRect, + placement = _ref2.placement, + variation = _ref2.variation, + offsets = _ref2.offsets, + position = _ref2.position, + gpuAcceleration = _ref2.gpuAcceleration, + adaptive = _ref2.adaptive, + roundOffsets = _ref2.roundOffsets, + isFixed = _ref2.isFixed; + + var _ref3 = roundOffsets === true ? roundOffsetsByDPR(offsets) : typeof roundOffsets === 'function' ? roundOffsets(offsets) : offsets, + _ref3$x = _ref3.x, + x = _ref3$x === void 0 ? 0 : _ref3$x, + _ref3$y = _ref3.y, + y = _ref3$y === void 0 ? 0 : _ref3$y; + + var hasX = offsets.hasOwnProperty('x'); + var hasY = offsets.hasOwnProperty('y'); + var sideX = left; + var sideY = top; + var win = window; + + if (adaptive) { + var offsetParent = getOffsetParent(popper); + var heightProp = 'clientHeight'; + var widthProp = 'clientWidth'; + + if (offsetParent === getWindow(popper)) { + offsetParent = getDocumentElement(popper); + + if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') { + heightProp = 'scrollHeight'; + widthProp = 'scrollWidth'; + } + } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it + + + offsetParent = offsetParent; + + if (placement === top || (placement === left || placement === right) && variation === end) { + sideY = bottom; + var offsetY = isFixed && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing] + offsetParent[heightProp]; + y -= offsetY - popperRect.height; + y *= gpuAcceleration ? 1 : -1; + } + + if (placement === left || (placement === top || placement === bottom) && variation === end) { + sideX = right; + var offsetX = isFixed && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing] + offsetParent[widthProp]; + x -= offsetX - popperRect.width; + x *= gpuAcceleration ? 1 : -1; + } + } + + var commonStyles = Object.assign({ + position: position + }, adaptive && unsetSides); + + if (gpuAcceleration) { + var _Object$assign; + + return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign)); + } + + return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2)); +} + +function computeStyles(_ref4) { + var state = _ref4.state, + options = _ref4.options; + var _options$gpuAccelerat = options.gpuAcceleration, + gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat, + _options$adaptive = options.adaptive, + adaptive = _options$adaptive === void 0 ? true : _options$adaptive, + _options$roundOffsets = options.roundOffsets, + roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets; + + if (process.env.NODE_ENV !== "production") { + var transitionProperty = getComputedStyle(state.elements.popper).transitionProperty || ''; + + if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) { + return transitionProperty.indexOf(property) >= 0; + })) { + console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: "transform", "top", "right", "bottom", "left".', '\n\n', 'Disable the "computeStyles" modifier\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\n\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' ')); + } + } + + var commonStyles = { + placement: getBasePlacement(state.placement), + variation: getVariation(state.placement), + popper: state.elements.popper, + popperRect: state.rects.popper, + gpuAcceleration: gpuAcceleration, + isFixed: state.options.strategy === 'fixed' + }; + + if (state.modifiersData.popperOffsets != null) { + state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, { + offsets: state.modifiersData.popperOffsets, + position: state.options.strategy, + adaptive: adaptive, + roundOffsets: roundOffsets + }))); + } + + if (state.modifiersData.arrow != null) { + state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, { + offsets: state.modifiersData.arrow, + position: 'absolute', + adaptive: false, + roundOffsets: roundOffsets + }))); + } + + state.attributes.popper = Object.assign({}, state.attributes.popper, { + 'data-popper-placement': state.placement + }); +} // eslint-disable-next-line import/no-unused-modules + + +export default { + name: 'computeStyles', + enabled: true, + phase: 'beforeWrite', + fn: computeStyles, + data: {} +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/computeStyles.js.flow b/popperjs/package/lib/modifiers/computeStyles.js.flow new file mode 100644 index 0000000..d6f5f23 --- /dev/null +++ b/popperjs/package/lib/modifiers/computeStyles.js.flow @@ -0,0 +1,258 @@ +// @flow +import type { + PositioningStrategy, + Offsets, + Modifier, + ModifierArguments, + Rect, + Window, +} from '../types'; +import { + type BasePlacement, + type Variation, + top, + left, + right, + bottom, + end, +} from '../enums'; +import getOffsetParent from '../dom-utils/getOffsetParent'; +import getWindow from '../dom-utils/getWindow'; +import getDocumentElement from '../dom-utils/getDocumentElement'; +import getComputedStyle from '../dom-utils/getComputedStyle'; +import getBasePlacement from '../utils/getBasePlacement'; +import getVariation from '../utils/getVariation'; +import { round } from '../utils/math'; + +// eslint-disable-next-line import/no-unused-modules +export type RoundOffsets = ( + offsets: $Shape<{ x: number, y: number, centerOffset: number }> +) => Offsets; + +// eslint-disable-next-line import/no-unused-modules +export type Options = { + gpuAcceleration: boolean, + adaptive: boolean, + roundOffsets?: boolean | RoundOffsets, +}; + +const unsetSides = { + top: 'auto', + right: 'auto', + bottom: 'auto', + left: 'auto', +}; + +// Round the offsets to the nearest suitable subpixel based on the DPR. +// Zooming can change the DPR, but it seems to report a value that will +// cleanly divide the values into the appropriate subpixels. +function roundOffsetsByDPR({ x, y }): Offsets { + const win: Window = window; + const dpr = win.devicePixelRatio || 1; + + return { + x: round(x * dpr) / dpr || 0, + y: round(y * dpr) / dpr || 0, + }; +} + +export function mapToStyles({ + popper, + popperRect, + placement, + variation, + offsets, + position, + gpuAcceleration, + adaptive, + roundOffsets, + isFixed, +}: { + popper: HTMLElement, + popperRect: Rect, + placement: BasePlacement, + variation: ?Variation, + offsets: $Shape<{ x: number, y: number, centerOffset: number }>, + position: PositioningStrategy, + gpuAcceleration: boolean, + adaptive: boolean, + roundOffsets: boolean | RoundOffsets, + isFixed: boolean, +}) { + let { x = 0, y = 0 } = + roundOffsets === true + ? roundOffsetsByDPR(offsets) + : typeof roundOffsets === 'function' + ? roundOffsets(offsets) + : offsets; + + const hasX = offsets.hasOwnProperty('x'); + const hasY = offsets.hasOwnProperty('y'); + + let sideX: string = left; + let sideY: string = top; + + const win: Window = window; + + if (adaptive) { + let offsetParent = getOffsetParent(popper); + let heightProp = 'clientHeight'; + let widthProp = 'clientWidth'; + + if (offsetParent === getWindow(popper)) { + offsetParent = getDocumentElement(popper); + + if ( + getComputedStyle(offsetParent).position !== 'static' && + position === 'absolute' + ) { + heightProp = 'scrollHeight'; + widthProp = 'scrollWidth'; + } + } + + // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it + offsetParent = (offsetParent: Element); + + if ( + placement === top || + ((placement === left || placement === right) && variation === end) + ) { + sideY = bottom; + const offsetY = + isFixed && win.visualViewport + ? win.visualViewport.height + : // $FlowFixMe[prop-missing] + offsetParent[heightProp]; + y -= offsetY - popperRect.height; + y *= gpuAcceleration ? 1 : -1; + } + + if ( + placement === left || + ((placement === top || placement === bottom) && variation === end) + ) { + sideX = right; + const offsetX = + isFixed && win.visualViewport + ? win.visualViewport.width + : // $FlowFixMe[prop-missing] + offsetParent[widthProp]; + x -= offsetX - popperRect.width; + x *= gpuAcceleration ? 1 : -1; + } + } + + const commonStyles = { + position, + ...(adaptive && unsetSides), + }; + + if (gpuAcceleration) { + return { + ...commonStyles, + [sideY]: hasY ? '0' : '', + [sideX]: hasX ? '0' : '', + // Layer acceleration can disable subpixel rendering which causes slightly + // blurry text on low PPI displays, so we want to use 2D transforms + // instead + transform: + (win.devicePixelRatio || 1) <= 1 + ? `translate(${x}px, ${y}px)` + : `translate3d(${x}px, ${y}px, 0)`, + }; + } + + return { + ...commonStyles, + [sideY]: hasY ? `${y}px` : '', + [sideX]: hasX ? `${x}px` : '', + transform: '', + }; +} + +function computeStyles({ state, options }: ModifierArguments<Options>) { + const { + gpuAcceleration = true, + adaptive = true, + // defaults to use builtin `roundOffsetsByDPR` + roundOffsets = true, + } = options; + + if (false) { + const transitionProperty = + getComputedStyle(state.elements.popper).transitionProperty || ''; + + if ( + adaptive && + ['transform', 'top', 'right', 'bottom', 'left'].some( + (property) => transitionProperty.indexOf(property) >= 0 + ) + ) { + console.warn( + [ + 'Popper: Detected CSS transitions on at least one of the following', + 'CSS properties: "transform", "top", "right", "bottom", "left".', + '\n\n', + 'Disable the "computeStyles" modifier\'s `adaptive` option to allow', + 'for smooth transitions, or remove these properties from the CSS', + 'transition declaration on the popper element if only transitioning', + 'opacity or background-color for example.', + '\n\n', + 'We recommend using the popper element as a wrapper around an inner', + 'element that can have any CSS property transitioned for animations.', + ].join(' ') + ); + } + } + + const commonStyles = { + placement: getBasePlacement(state.placement), + variation: getVariation(state.placement), + popper: state.elements.popper, + popperRect: state.rects.popper, + gpuAcceleration, + isFixed: state.options.strategy === 'fixed', + }; + + if (state.modifiersData.popperOffsets != null) { + state.styles.popper = { + ...state.styles.popper, + ...mapToStyles({ + ...commonStyles, + offsets: state.modifiersData.popperOffsets, + position: state.options.strategy, + adaptive, + roundOffsets, + }), + }; + } + + if (state.modifiersData.arrow != null) { + state.styles.arrow = { + ...state.styles.arrow, + ...mapToStyles({ + ...commonStyles, + offsets: state.modifiersData.arrow, + position: 'absolute', + adaptive: false, + roundOffsets, + }), + }; + } + + state.attributes.popper = { + ...state.attributes.popper, + 'data-popper-placement': state.placement, + }; +} + +// eslint-disable-next-line import/no-unused-modules +export type ComputeStylesModifier = Modifier<'computeStyles', Options>; +export default ({ + name: 'computeStyles', + enabled: true, + phase: 'beforeWrite', + fn: computeStyles, + data: {}, +}: ComputeStylesModifier); diff --git a/popperjs/package/lib/modifiers/eventListeners.d.ts b/popperjs/package/lib/modifiers/eventListeners.d.ts new file mode 100644 index 0000000..077a7fb --- /dev/null +++ b/popperjs/package/lib/modifiers/eventListeners.d.ts @@ -0,0 +1,8 @@ +import type { Modifier } from "../types"; +export declare type Options = { + scroll: boolean; + resize: boolean; +}; +export declare type EventListenersModifier = Modifier<"eventListeners", Options>; +declare const _default: EventListenersModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/eventListeners.js b/popperjs/package/lib/modifiers/eventListeners.js new file mode 100644 index 0000000..bc68f35 --- /dev/null +++ b/popperjs/package/lib/modifiers/eventListeners.js @@ -0,0 +1,49 @@ +import getWindow from "../dom-utils/getWindow.js"; // eslint-disable-next-line import/no-unused-modules + +var passive = { + passive: true +}; + +function effect(_ref) { + var state = _ref.state, + instance = _ref.instance, + options = _ref.options; + var _options$scroll = options.scroll, + scroll = _options$scroll === void 0 ? true : _options$scroll, + _options$resize = options.resize, + resize = _options$resize === void 0 ? true : _options$resize; + var window = getWindow(state.elements.popper); + var scrollParents = [].concat(state.scrollParents.reference, state.scrollParents.popper); + + if (scroll) { + scrollParents.forEach(function (scrollParent) { + scrollParent.addEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.addEventListener('resize', instance.update, passive); + } + + return function () { + if (scroll) { + scrollParents.forEach(function (scrollParent) { + scrollParent.removeEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.removeEventListener('resize', instance.update, passive); + } + }; +} // eslint-disable-next-line import/no-unused-modules + + +export default { + name: 'eventListeners', + enabled: true, + phase: 'write', + fn: function fn() {}, + effect: effect, + data: {} +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/eventListeners.js.flow b/popperjs/package/lib/modifiers/eventListeners.js.flow new file mode 100644 index 0000000..eab18a5 --- /dev/null +++ b/popperjs/package/lib/modifiers/eventListeners.js.flow @@ -0,0 +1,54 @@ +// @flow +import type { ModifierArguments, Modifier } from '../types'; +import getWindow from '../dom-utils/getWindow'; + +// eslint-disable-next-line import/no-unused-modules +export type Options = { + scroll: boolean, + resize: boolean, +}; + +const passive = { passive: true }; + +function effect({ state, instance, options }: ModifierArguments<Options>) { + const { scroll = true, resize = true } = options; + + const window = getWindow(state.elements.popper); + const scrollParents = [ + ...state.scrollParents.reference, + ...state.scrollParents.popper, + ]; + + if (scroll) { + scrollParents.forEach(scrollParent => { + scrollParent.addEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.addEventListener('resize', instance.update, passive); + } + + return () => { + if (scroll) { + scrollParents.forEach(scrollParent => { + scrollParent.removeEventListener('scroll', instance.update, passive); + }); + } + + if (resize) { + window.removeEventListener('resize', instance.update, passive); + } + }; +} + +// eslint-disable-next-line import/no-unused-modules +export type EventListenersModifier = Modifier<'eventListeners', Options>; +export default ({ + name: 'eventListeners', + enabled: true, + phase: 'write', + fn: () => {}, + effect, + data: {}, +}: EventListenersModifier); diff --git a/popperjs/package/lib/modifiers/flip.d.ts b/popperjs/package/lib/modifiers/flip.d.ts new file mode 100644 index 0000000..0115798 --- /dev/null +++ b/popperjs/package/lib/modifiers/flip.d.ts @@ -0,0 +1,16 @@ +import type { Placement, Boundary, RootBoundary } from "../enums"; +import type { Modifier, Padding } from "../types"; +export declare type Options = { + mainAxis: boolean; + altAxis: boolean; + fallbackPlacements: Array<Placement>; + padding: Padding; + boundary: Boundary; + rootBoundary: RootBoundary; + altBoundary: boolean; + flipVariations: boolean; + allowedAutoPlacements: Array<Placement>; +}; +export declare type FlipModifier = Modifier<"flip", Options>; +declare const _default: FlipModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/flip.js b/popperjs/package/lib/modifiers/flip.js new file mode 100644 index 0000000..2c33216 --- /dev/null +++ b/popperjs/package/lib/modifiers/flip.js @@ -0,0 +1,147 @@ +import getOppositePlacement from "../utils/getOppositePlacement.js"; +import getBasePlacement from "../utils/getBasePlacement.js"; +import getOppositeVariationPlacement from "../utils/getOppositeVariationPlacement.js"; +import detectOverflow from "../utils/detectOverflow.js"; +import computeAutoPlacement from "../utils/computeAutoPlacement.js"; +import { bottom, top, start, right, left, auto } from "../enums.js"; +import getVariation from "../utils/getVariation.js"; // eslint-disable-next-line import/no-unused-modules + +function getExpandedFallbackPlacements(placement) { + if (getBasePlacement(placement) === auto) { + return []; + } + + var oppositePlacement = getOppositePlacement(placement); + return [getOppositeVariationPlacement(placement), oppositePlacement, getOppositeVariationPlacement(oppositePlacement)]; +} + +function flip(_ref) { + var state = _ref.state, + options = _ref.options, + name = _ref.name; + + if (state.modifiersData[name]._skip) { + return; + } + + var _options$mainAxis = options.mainAxis, + checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis, + _options$altAxis = options.altAxis, + checkAltAxis = _options$altAxis === void 0 ? true : _options$altAxis, + specifiedFallbackPlacements = options.fallbackPlacements, + padding = options.padding, + boundary = options.boundary, + rootBoundary = options.rootBoundary, + altBoundary = options.altBoundary, + _options$flipVariatio = options.flipVariations, + flipVariations = _options$flipVariatio === void 0 ? true : _options$flipVariatio, + allowedAutoPlacements = options.allowedAutoPlacements; + var preferredPlacement = state.options.placement; + var basePlacement = getBasePlacement(preferredPlacement); + var isBasePlacement = basePlacement === preferredPlacement; + var fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipVariations ? [getOppositePlacement(preferredPlacement)] : getExpandedFallbackPlacements(preferredPlacement)); + var placements = [preferredPlacement].concat(fallbackPlacements).reduce(function (acc, placement) { + return acc.concat(getBasePlacement(placement) === auto ? computeAutoPlacement(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + padding: padding, + flipVariations: flipVariations, + allowedAutoPlacements: allowedAutoPlacements + }) : placement); + }, []); + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var checksMap = new Map(); + var makeFallbackChecks = true; + var firstFittingPlacement = placements[0]; + + for (var i = 0; i < placements.length; i++) { + var placement = placements[i]; + + var _basePlacement = getBasePlacement(placement); + + var isStartVariation = getVariation(placement) === start; + var isVertical = [top, bottom].indexOf(_basePlacement) >= 0; + var len = isVertical ? 'width' : 'height'; + var overflow = detectOverflow(state, { + placement: placement, + boundary: boundary, + rootBoundary: rootBoundary, + altBoundary: altBoundary, + padding: padding + }); + var mainVariationSide = isVertical ? isStartVariation ? right : left : isStartVariation ? bottom : top; + + if (referenceRect[len] > popperRect[len]) { + mainVariationSide = getOppositePlacement(mainVariationSide); + } + + var altVariationSide = getOppositePlacement(mainVariationSide); + var checks = []; + + if (checkMainAxis) { + checks.push(overflow[_basePlacement] <= 0); + } + + if (checkAltAxis) { + checks.push(overflow[mainVariationSide] <= 0, overflow[altVariationSide] <= 0); + } + + if (checks.every(function (check) { + return check; + })) { + firstFittingPlacement = placement; + makeFallbackChecks = false; + break; + } + + checksMap.set(placement, checks); + } + + if (makeFallbackChecks) { + // `2` may be desired in some cases – research later + var numberOfChecks = flipVariations ? 3 : 1; + + var _loop = function _loop(_i) { + var fittingPlacement = placements.find(function (placement) { + var checks = checksMap.get(placement); + + if (checks) { + return checks.slice(0, _i).every(function (check) { + return check; + }); + } + }); + + if (fittingPlacement) { + firstFittingPlacement = fittingPlacement; + return "break"; + } + }; + + for (var _i = numberOfChecks; _i > 0; _i--) { + var _ret = _loop(_i); + + if (_ret === "break") break; + } + } + + if (state.placement !== firstFittingPlacement) { + state.modifiersData[name]._skip = true; + state.placement = firstFittingPlacement; + state.reset = true; + } +} // eslint-disable-next-line import/no-unused-modules + + +export default { + name: 'flip', + enabled: true, + phase: 'main', + fn: flip, + requiresIfExists: ['offset'], + data: { + _skip: false + } +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/flip.js.flow b/popperjs/package/lib/modifiers/flip.js.flow new file mode 100644 index 0000000..c74b852 --- /dev/null +++ b/popperjs/package/lib/modifiers/flip.js.flow @@ -0,0 +1,177 @@ +// @flow +import type { Placement, Boundary, RootBoundary } from '../enums'; +import type { ModifierArguments, Modifier, Padding } from '../types'; +import getOppositePlacement from '../utils/getOppositePlacement'; +import getBasePlacement from '../utils/getBasePlacement'; +import getOppositeVariationPlacement from '../utils/getOppositeVariationPlacement'; +import detectOverflow from '../utils/detectOverflow'; +import computeAutoPlacement from '../utils/computeAutoPlacement'; +import { bottom, top, start, right, left, auto } from '../enums'; +import getVariation from '../utils/getVariation'; + +// eslint-disable-next-line import/no-unused-modules +export type Options = { + mainAxis: boolean, + altAxis: boolean, + fallbackPlacements: Array<Placement>, + padding: Padding, + boundary: Boundary, + rootBoundary: RootBoundary, + altBoundary: boolean, + flipVariations: boolean, + allowedAutoPlacements: Array<Placement>, +}; + +function getExpandedFallbackPlacements(placement: Placement): Array<Placement> { + if (getBasePlacement(placement) === auto) { + return []; + } + + const oppositePlacement = getOppositePlacement(placement); + + return [ + getOppositeVariationPlacement(placement), + oppositePlacement, + getOppositeVariationPlacement(oppositePlacement), + ]; +} + +function flip({ state, options, name }: ModifierArguments<Options>) { + if (state.modifiersData[name]._skip) { + return; + } + + const { + mainAxis: checkMainAxis = true, + altAxis: checkAltAxis = true, + fallbackPlacements: specifiedFallbackPlacements, + padding, + boundary, + rootBoundary, + altBoundary, + flipVariations = true, + allowedAutoPlacements, + } = options; + + const preferredPlacement = state.options.placement; + const basePlacement = getBasePlacement(preferredPlacement); + const isBasePlacement = basePlacement === preferredPlacement; + + const fallbackPlacements = + specifiedFallbackPlacements || + (isBasePlacement || !flipVariations + ? [getOppositePlacement(preferredPlacement)] + : getExpandedFallbackPlacements(preferredPlacement)); + + const placements = [preferredPlacement, ...fallbackPlacements].reduce( + (acc, placement) => { + return acc.concat( + getBasePlacement(placement) === auto + ? computeAutoPlacement(state, { + placement, + boundary, + rootBoundary, + padding, + flipVariations, + allowedAutoPlacements, + }) + : placement + ); + }, + [] + ); + + const referenceRect = state.rects.reference; + const popperRect = state.rects.popper; + + const checksMap = new Map(); + let makeFallbackChecks = true; + let firstFittingPlacement = placements[0]; + + for (let i = 0; i < placements.length; i++) { + const placement = placements[i]; + const basePlacement = getBasePlacement(placement); + const isStartVariation = getVariation(placement) === start; + const isVertical = [top, bottom].indexOf(basePlacement) >= 0; + const len = isVertical ? 'width' : 'height'; + + const overflow = detectOverflow(state, { + placement, + boundary, + rootBoundary, + altBoundary, + padding, + }); + + let mainVariationSide: any = isVertical + ? isStartVariation + ? right + : left + : isStartVariation + ? bottom + : top; + + if (referenceRect[len] > popperRect[len]) { + mainVariationSide = getOppositePlacement(mainVariationSide); + } + + const altVariationSide: any = getOppositePlacement(mainVariationSide); + + const checks = []; + + if (checkMainAxis) { + checks.push(overflow[basePlacement] <= 0); + } + + if (checkAltAxis) { + checks.push( + overflow[mainVariationSide] <= 0, + overflow[altVariationSide] <= 0 + ); + } + + if (checks.every((check) => check)) { + firstFittingPlacement = placement; + makeFallbackChecks = false; + break; + } + + checksMap.set(placement, checks); + } + + if (makeFallbackChecks) { + // `2` may be desired in some cases – research later + const numberOfChecks = flipVariations ? 3 : 1; + + for (let i = numberOfChecks; i > 0; i--) { + const fittingPlacement = placements.find((placement) => { + const checks = checksMap.get(placement); + if (checks) { + return checks.slice(0, i).every((check) => check); + } + }); + + if (fittingPlacement) { + firstFittingPlacement = fittingPlacement; + break; + } + } + } + + if (state.placement !== firstFittingPlacement) { + state.modifiersData[name]._skip = true; + state.placement = firstFittingPlacement; + state.reset = true; + } +} + +// eslint-disable-next-line import/no-unused-modules +export type FlipModifier = Modifier<'flip', Options>; +export default ({ + name: 'flip', + enabled: true, + phase: 'main', + fn: flip, + requiresIfExists: ['offset'], + data: { _skip: false }, +}: FlipModifier); diff --git a/popperjs/package/lib/modifiers/hide.d.ts b/popperjs/package/lib/modifiers/hide.d.ts new file mode 100644 index 0000000..2d2f2e1 --- /dev/null +++ b/popperjs/package/lib/modifiers/hide.d.ts @@ -0,0 +1,4 @@ +import type { Modifier } from "../types"; +export declare type HideModifier = Modifier<"hide", {}>; +declare const _default: HideModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/hide.js b/popperjs/package/lib/modifiers/hide.js new file mode 100644 index 0000000..799c4a7 --- /dev/null +++ b/popperjs/package/lib/modifiers/hide.js @@ -0,0 +1,61 @@ +import { top, bottom, left, right } from "../enums.js"; +import detectOverflow from "../utils/detectOverflow.js"; + +function getSideOffsets(overflow, rect, preventedOffsets) { + if (preventedOffsets === void 0) { + preventedOffsets = { + x: 0, + y: 0 + }; + } + + return { + top: overflow.top - rect.height - preventedOffsets.y, + right: overflow.right - rect.width + preventedOffsets.x, + bottom: overflow.bottom - rect.height + preventedOffsets.y, + left: overflow.left - rect.width - preventedOffsets.x + }; +} + +function isAnySideFullyClipped(overflow) { + return [top, right, bottom, left].some(function (side) { + return overflow[side] >= 0; + }); +} + +function hide(_ref) { + var state = _ref.state, + name = _ref.name; + var referenceRect = state.rects.reference; + var popperRect = state.rects.popper; + var preventedOffsets = state.modifiersData.preventOverflow; + var referenceOverflow = detectOverflow(state, { + elementContext: 'reference' + }); + var popperAltOverflow = detectOverflow(state, { + altBoundary: true + }); + var referenceClippingOffsets = getSideOffsets(referenceOverflow, referenceRect); + var popperEscapeOffsets = getSideOffsets(popperAltOverflow, popperRect, preventedOffsets); + var isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets); + var hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets); + state.modifiersData[name] = { + referenceClippingOffsets: referenceClippingOffsets, + popperEscapeOffsets: popperEscapeOffsets, + isReferenceHidden: isReferenceHidden, + hasPopperEscaped: hasPopperEscaped + }; + state.attributes.popper = Object.assign({}, state.attributes.popper, { + 'data-popper-reference-hidden': isReferenceHidden, + 'data-popper-escaped': hasPopperEscaped + }); +} // eslint-disable-next-line import/no-unused-modules + + +export default { + name: 'hide', + enabled: true, + phase: 'main', + requiresIfExists: ['preventOverflow'], + fn: hide +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/hide.js.flow b/popperjs/package/lib/modifiers/hide.js.flow new file mode 100644 index 0000000..ee7476a --- /dev/null +++ b/popperjs/package/lib/modifiers/hide.js.flow @@ -0,0 +1,76 @@ +// @flow +import type { + ModifierArguments, + Modifier, + Rect, + SideObject, + Offsets, +} from '../types'; +import { top, bottom, left, right } from '../enums'; +import detectOverflow from '../utils/detectOverflow'; + +function getSideOffsets( + overflow: SideObject, + rect: Rect, + preventedOffsets: Offsets = { x: 0, y: 0 } +): SideObject { + return { + top: overflow.top - rect.height - preventedOffsets.y, + right: overflow.right - rect.width + preventedOffsets.x, + bottom: overflow.bottom - rect.height + preventedOffsets.y, + left: overflow.left - rect.width - preventedOffsets.x, + }; +} + +function isAnySideFullyClipped(overflow: SideObject): boolean { + return [top, right, bottom, left].some((side) => overflow[side] >= 0); +} + +function hide({ state, name }: ModifierArguments<{||}>) { + const referenceRect = state.rects.reference; + const popperRect = state.rects.popper; + const preventedOffsets = state.modifiersData.preventOverflow; + + const referenceOverflow = detectOverflow(state, { + elementContext: 'reference', + }); + const popperAltOverflow = detectOverflow(state, { + altBoundary: true, + }); + + const referenceClippingOffsets = getSideOffsets( + referenceOverflow, + referenceRect + ); + const popperEscapeOffsets = getSideOffsets( + popperAltOverflow, + popperRect, + preventedOffsets + ); + + const isReferenceHidden = isAnySideFullyClipped(referenceClippingOffsets); + const hasPopperEscaped = isAnySideFullyClipped(popperEscapeOffsets); + + state.modifiersData[name] = { + referenceClippingOffsets, + popperEscapeOffsets, + isReferenceHidden, + hasPopperEscaped, + }; + + state.attributes.popper = { + ...state.attributes.popper, + 'data-popper-reference-hidden': isReferenceHidden, + 'data-popper-escaped': hasPopperEscaped, + }; +} + +// eslint-disable-next-line import/no-unused-modules +export type HideModifier = Modifier<'hide', {||}>; +export default ({ + name: 'hide', + enabled: true, + phase: 'main', + requiresIfExists: ['preventOverflow'], + fn: hide, +}: HideModifier); diff --git a/popperjs/package/lib/modifiers/index.d.ts b/popperjs/package/lib/modifiers/index.d.ts new file mode 100644 index 0000000..1b457cd --- /dev/null +++ b/popperjs/package/lib/modifiers/index.d.ts @@ -0,0 +1,9 @@ +export { default as applyStyles } from "./applyStyles"; +export { default as arrow } from "./arrow"; +export { default as computeStyles } from "./computeStyles"; +export { default as eventListeners } from "./eventListeners"; +export { default as flip } from "./flip"; +export { default as hide } from "./hide"; +export { default as offset } from "./offset"; +export { default as popperOffsets } from "./popperOffsets"; +export { default as preventOverflow } from "./preventOverflow"; diff --git a/popperjs/package/lib/modifiers/index.js b/popperjs/package/lib/modifiers/index.js new file mode 100644 index 0000000..1d59909 --- /dev/null +++ b/popperjs/package/lib/modifiers/index.js @@ -0,0 +1,9 @@ +export { default as applyStyles } from "./applyStyles.js"; +export { default as arrow } from "./arrow.js"; +export { default as computeStyles } from "./computeStyles.js"; +export { default as eventListeners } from "./eventListeners.js"; +export { default as flip } from "./flip.js"; +export { default as hide } from "./hide.js"; +export { default as offset } from "./offset.js"; +export { default as popperOffsets } from "./popperOffsets.js"; +export { default as preventOverflow } from "./preventOverflow.js";
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/index.js.flow b/popperjs/package/lib/modifiers/index.js.flow new file mode 100644 index 0000000..e3ee823 --- /dev/null +++ b/popperjs/package/lib/modifiers/index.js.flow @@ -0,0 +1,10 @@ +// @flow +export { default as applyStyles } from './applyStyles'; +export { default as arrow } from './arrow'; +export { default as computeStyles } from './computeStyles'; +export { default as eventListeners } from './eventListeners'; +export { default as flip } from './flip'; +export { default as hide } from './hide'; +export { default as offset } from './offset'; +export { default as popperOffsets } from './popperOffsets'; +export { default as preventOverflow } from './preventOverflow'; diff --git a/popperjs/package/lib/modifiers/offset.d.ts b/popperjs/package/lib/modifiers/offset.d.ts new file mode 100644 index 0000000..081956d --- /dev/null +++ b/popperjs/package/lib/modifiers/offset.d.ts @@ -0,0 +1,18 @@ +import type { Placement } from "../enums"; +import type { Modifier, Rect, Offsets } from "../types"; +export declare type OffsetsFunction = (arg0: { + popper: Rect; + reference: Rect; + placement: Placement; +}) => [number | null | undefined, number | null | undefined]; +declare type Offset = OffsetsFunction | [number | null | undefined, number | null | undefined]; +export declare type Options = { + offset: Offset; +}; +export declare function distanceAndSkiddingToXY(placement: Placement, rects: { + popper: Rect; + reference: Rect; +}, offset: Offset): Offsets; +export declare type OffsetModifier = Modifier<"offset", Options>; +declare const _default: OffsetModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/offset.js b/popperjs/package/lib/modifiers/offset.js new file mode 100644 index 0000000..12fa007 --- /dev/null +++ b/popperjs/package/lib/modifiers/offset.js @@ -0,0 +1,54 @@ +import getBasePlacement from "../utils/getBasePlacement.js"; +import { top, left, right, placements } from "../enums.js"; // eslint-disable-next-line import/no-unused-modules + +export function distanceAndSkiddingToXY(placement, rects, offset) { + var basePlacement = getBasePlacement(placement); + var invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1; + + var _ref = typeof offset === 'function' ? offset(Object.assign({}, rects, { + placement: placement + })) : offset, + skidding = _ref[0], + distance = _ref[1]; + + skidding = skidding || 0; + distance = (distance || 0) * invertDistance; + return [left, right].indexOf(basePlacement) >= 0 ? { + x: distance, + y: skidding + } : { + x: skidding, + y: distance + }; +} + +function offset(_ref2) { + var state = _ref2.state, + options = _ref2.options, + name = _ref2.name; + var _options$offset = options.offset, + offset = _options$offset === void 0 ? [0, 0] : _options$offset; + var data = placements.reduce(function (acc, placement) { + acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset); + return acc; + }, {}); + var _data$state$placement = data[state.placement], + x = _data$state$placement.x, + y = _data$state$placement.y; + + if (state.modifiersData.popperOffsets != null) { + state.modifiersData.popperOffsets.x += x; + state.modifiersData.popperOffsets.y += y; + } + + state.modifiersData[name] = data; +} // eslint-disable-next-line import/no-unused-modules + + +export default { + name: 'offset', + enabled: true, + phase: 'main', + requires: ['popperOffsets'], + fn: offset +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/offset.js.flow b/popperjs/package/lib/modifiers/offset.js.flow new file mode 100644 index 0000000..b39edc4 --- /dev/null +++ b/popperjs/package/lib/modifiers/offset.js.flow @@ -0,0 +1,71 @@ +// @flow +import type { Placement } from '../enums'; +import type { ModifierArguments, Modifier, Rect, Offsets } from '../types'; +import getBasePlacement from '../utils/getBasePlacement'; +import { top, left, right, placements } from '../enums'; + +// eslint-disable-next-line import/no-unused-modules +export type OffsetsFunction = ({ + popper: Rect, + reference: Rect, + placement: Placement, +}) => [?number, ?number]; + +type Offset = OffsetsFunction | [?number, ?number]; + +// eslint-disable-next-line import/no-unused-modules +export type Options = { + offset: Offset, +}; + +export function distanceAndSkiddingToXY( + placement: Placement, + rects: { popper: Rect, reference: Rect }, + offset: Offset +): Offsets { + const basePlacement = getBasePlacement(placement); + const invertDistance = [left, top].indexOf(basePlacement) >= 0 ? -1 : 1; + + let [skidding, distance] = + typeof offset === 'function' + ? offset({ + ...rects, + placement, + }) + : offset; + + skidding = skidding || 0; + distance = (distance || 0) * invertDistance; + + return [left, right].indexOf(basePlacement) >= 0 + ? { x: distance, y: skidding } + : { x: skidding, y: distance }; +} + +function offset({ state, options, name }: ModifierArguments<Options>) { + const { offset = [0, 0] } = options; + + const data = placements.reduce((acc, placement) => { + acc[placement] = distanceAndSkiddingToXY(placement, state.rects, offset); + return acc; + }, {}); + + const { x, y } = data[state.placement]; + + if (state.modifiersData.popperOffsets != null) { + state.modifiersData.popperOffsets.x += x; + state.modifiersData.popperOffsets.y += y; + } + + state.modifiersData[name] = data; +} + +// eslint-disable-next-line import/no-unused-modules +export type OffsetModifier = Modifier<'offset', Options>; +export default ({ + name: 'offset', + enabled: true, + phase: 'main', + requires: ['popperOffsets'], + fn: offset, +}: OffsetModifier); diff --git a/popperjs/package/lib/modifiers/popperOffsets.d.ts b/popperjs/package/lib/modifiers/popperOffsets.d.ts new file mode 100644 index 0000000..831cd55 --- /dev/null +++ b/popperjs/package/lib/modifiers/popperOffsets.d.ts @@ -0,0 +1,4 @@ +import type { Modifier } from "../types"; +export declare type PopperOffsetsModifier = Modifier<"popperOffsets", {}>; +declare const _default: PopperOffsetsModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/popperOffsets.js b/popperjs/package/lib/modifiers/popperOffsets.js new file mode 100644 index 0000000..5440ab7 --- /dev/null +++ b/popperjs/package/lib/modifiers/popperOffsets.js @@ -0,0 +1,25 @@ +import computeOffsets from "../utils/computeOffsets.js"; + +function popperOffsets(_ref) { + var state = _ref.state, + name = _ref.name; + // Offsets are the actual position the popper needs to have to be + // properly positioned near its reference element + // This is the most basic placement, and will be adjusted by + // the modifiers in the next step + state.modifiersData[name] = computeOffsets({ + reference: state.rects.reference, + element: state.rects.popper, + strategy: 'absolute', + placement: state.placement + }); +} // eslint-disable-next-line import/no-unused-modules + + +export default { + name: 'popperOffsets', + enabled: true, + phase: 'read', + fn: popperOffsets, + data: {} +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/popperOffsets.js.flow b/popperjs/package/lib/modifiers/popperOffsets.js.flow new file mode 100644 index 0000000..30b5894 --- /dev/null +++ b/popperjs/package/lib/modifiers/popperOffsets.js.flow @@ -0,0 +1,26 @@ +// @flow +import type { ModifierArguments, Modifier } from '../types'; +import computeOffsets from '../utils/computeOffsets'; + +function popperOffsets({ state, name }: ModifierArguments<{||}>) { + // Offsets are the actual position the popper needs to have to be + // properly positioned near its reference element + // This is the most basic placement, and will be adjusted by + // the modifiers in the next step + state.modifiersData[name] = computeOffsets({ + reference: state.rects.reference, + element: state.rects.popper, + strategy: 'absolute', + placement: state.placement, + }); +} + +// eslint-disable-next-line import/no-unused-modules +export type PopperOffsetsModifier = Modifier<'popperOffsets', {||}>; +export default ({ + name: 'popperOffsets', + enabled: true, + phase: 'read', + fn: popperOffsets, + data: {}, +}: PopperOffsetsModifier); diff --git a/popperjs/package/lib/modifiers/preventOverflow.d.ts b/popperjs/package/lib/modifiers/preventOverflow.d.ts new file mode 100644 index 0000000..393cc8b --- /dev/null +++ b/popperjs/package/lib/modifiers/preventOverflow.d.ts @@ -0,0 +1,30 @@ +import type { Placement, Boundary, RootBoundary } from "../enums"; +import type { Rect, Modifier, Padding } from "../types"; +declare type TetherOffset = ((arg0: { + popper: Rect; + reference: Rect; + placement: Placement; +}) => number | { + mainAxis: number; + altAxis: number; +}) | number | { + mainAxis: number; + altAxis: number; +}; +export declare type Options = { + mainAxis: boolean; + altAxis: boolean; + boundary: Boundary; + rootBoundary: RootBoundary; + altBoundary: boolean; + /** + * Allows the popper to overflow from its boundaries to keep it near its + * reference element + */ + tether: boolean; + tetherOffset: TetherOffset; + padding: Padding; +}; +export declare type PreventOverflowModifier = Modifier<"preventOverflow", Options>; +declare const _default: PreventOverflowModifier; +export default _default; diff --git a/popperjs/package/lib/modifiers/preventOverflow.js b/popperjs/package/lib/modifiers/preventOverflow.js new file mode 100644 index 0000000..729eedd --- /dev/null +++ b/popperjs/package/lib/modifiers/preventOverflow.js @@ -0,0 +1,142 @@ +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, withinMaxClamp } 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 { min as mathMin, max as mathMax } 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 normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? { + mainAxis: tetherOffsetValue, + altAxis: tetherOffsetValue + } : Object.assign({ + mainAxis: 0, + altAxis: 0 + }, tetherOffsetValue); + var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null; + var data = { + x: 0, + y: 0 + }; + + if (!popperOffsets) { + return; + } + + if (checkMainAxis) { + var _offsetModifierState$; + + var mainSide = mainAxis === 'y' ? top : left; + var altSide = mainAxis === 'y' ? bottom : right; + var len = mainAxis === 'y' ? 'height' : 'width'; + var offset = popperOffsets[mainAxis]; + var min = offset + overflow[mainSide]; + var max = offset - 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 - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis; + var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis; + var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow); + var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0; + var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0; + var tetherMin = offset + minOffset - offsetModifierValue - clientOffset; + var tetherMax = offset + maxOffset - offsetModifierValue; + var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max); + popperOffsets[mainAxis] = preventedOffset; + data[mainAxis] = preventedOffset - offset; + } + + if (checkAltAxis) { + var _offsetModifierState$2; + + var _mainSide = mainAxis === 'x' ? top : left; + + var _altSide = mainAxis === 'x' ? bottom : right; + + var _offset = popperOffsets[altAxis]; + + var _len = altAxis === 'y' ? 'height' : 'width'; + + var _min = _offset + overflow[_mainSide]; + + var _max = _offset - overflow[_altSide]; + + var isOriginSide = [top, left].indexOf(basePlacement) !== -1; + + var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0; + + var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis; + + var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max; + + var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _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'] +};
\ No newline at end of file diff --git a/popperjs/package/lib/modifiers/preventOverflow.js.flow b/popperjs/package/lib/modifiers/preventOverflow.js.flow new file mode 100644 index 0000000..d503cb9 --- /dev/null +++ b/popperjs/package/lib/modifiers/preventOverflow.js.flow @@ -0,0 +1,220 @@ +// @flow +import { top, left, right, bottom, start } from '../enums'; +import type { Placement, Boundary, RootBoundary } from '../enums'; +import type { Rect, ModifierArguments, Modifier, Padding } from '../types'; +import getBasePlacement from '../utils/getBasePlacement'; +import getMainAxisFromPlacement from '../utils/getMainAxisFromPlacement'; +import getAltAxis from '../utils/getAltAxis'; +import { within, withinMaxClamp } from '../utils/within'; +import getLayoutRect from '../dom-utils/getLayoutRect'; +import getOffsetParent from '../dom-utils/getOffsetParent'; +import detectOverflow from '../utils/detectOverflow'; +import getVariation from '../utils/getVariation'; +import getFreshSideObject from '../utils/getFreshSideObject'; +import { min as mathMin, max as mathMax } from '../utils/math'; + +type TetherOffset = + | (({ + popper: Rect, + reference: Rect, + placement: Placement, + }) => number | { mainAxis: number, altAxis: number }) + | number + | { mainAxis: number, altAxis: number }; + +// eslint-disable-next-line import/no-unused-modules +export type Options = { + /* Prevents boundaries overflow on the main axis */ + mainAxis: boolean, + /* Prevents boundaries overflow on the alternate axis */ + altAxis: boolean, + /* The area to check the popper is overflowing in */ + boundary: Boundary, + /* If the popper is not overflowing the main area, fallback to this one */ + rootBoundary: RootBoundary, + /* Use the reference's "clippingParents" boundary context */ + altBoundary: boolean, + /** + * Allows the popper to overflow from its boundaries to keep it near its + * reference element + */ + tether: boolean, + /* Offsets when the `tether` option should activate */ + tetherOffset: TetherOffset, + /* Sets a padding to the provided boundary */ + padding: Padding, +}; + +function preventOverflow({ state, options, name }: ModifierArguments<Options>) { + const { + mainAxis: checkMainAxis = true, + altAxis: checkAltAxis = false, + boundary, + rootBoundary, + altBoundary, + padding, + tether = true, + tetherOffset = 0, + } = options; + + const overflow = detectOverflow(state, { + boundary, + rootBoundary, + padding, + altBoundary, + }); + const basePlacement = getBasePlacement(state.placement); + const variation = getVariation(state.placement); + const isBasePlacement = !variation; + const mainAxis = getMainAxisFromPlacement(basePlacement); + const altAxis = getAltAxis(mainAxis); + const popperOffsets = state.modifiersData.popperOffsets; + const referenceRect = state.rects.reference; + const popperRect = state.rects.popper; + const tetherOffsetValue = + typeof tetherOffset === 'function' + ? tetherOffset({ + ...state.rects, + placement: state.placement, + }) + : tetherOffset; + const normalizedTetherOffsetValue = + typeof tetherOffsetValue === 'number' + ? { mainAxis: tetherOffsetValue, altAxis: tetherOffsetValue } + : { mainAxis: 0, altAxis: 0, ...tetherOffsetValue }; + const offsetModifierState = state.modifiersData.offset + ? state.modifiersData.offset[state.placement] + : null; + + const data = { x: 0, y: 0 }; + + if (!popperOffsets) { + return; + } + + if (checkMainAxis) { + const mainSide = mainAxis === 'y' ? top : left; + const altSide = mainAxis === 'y' ? bottom : right; + const len = mainAxis === 'y' ? 'height' : 'width'; + const offset = popperOffsets[mainAxis]; + + const min = offset + overflow[mainSide]; + const max = offset - overflow[altSide]; + + const additive = tether ? -popperRect[len] / 2 : 0; + + const minLen = variation === start ? referenceRect[len] : popperRect[len]; + const 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 + const arrowElement = state.elements.arrow; + const arrowRect = + tether && arrowElement + ? getLayoutRect(arrowElement) + : { width: 0, height: 0 }; + const arrowPaddingObject = state.modifiersData['arrow#persistent'] + ? state.modifiersData['arrow#persistent'].padding + : getFreshSideObject(); + const arrowPaddingMin = arrowPaddingObject[mainSide]; + const 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) + const arrowLen = within(0, referenceRect[len], arrowRect[len]); + + const minOffset = isBasePlacement + ? referenceRect[len] / 2 - + additive - + arrowLen - + arrowPaddingMin - + normalizedTetherOffsetValue.mainAxis + : minLen - + arrowLen - + arrowPaddingMin - + normalizedTetherOffsetValue.mainAxis; + const maxOffset = isBasePlacement + ? -referenceRect[len] / 2 + + additive + + arrowLen + + arrowPaddingMax + + normalizedTetherOffsetValue.mainAxis + : maxLen + + arrowLen + + arrowPaddingMax + + normalizedTetherOffsetValue.mainAxis; + + const arrowOffsetParent = + state.elements.arrow && getOffsetParent(state.elements.arrow); + const clientOffset = arrowOffsetParent + ? mainAxis === 'y' + ? arrowOffsetParent.clientTop || 0 + : arrowOffsetParent.clientLeft || 0 + : 0; + + const offsetModifierValue = offsetModifierState?.[mainAxis] ?? 0; + const tetherMin = offset + minOffset - offsetModifierValue - clientOffset; + const tetherMax = offset + maxOffset - offsetModifierValue; + + const preventedOffset = within( + tether ? mathMin(min, tetherMin) : min, + offset, + tether ? mathMax(max, tetherMax) : max + ); + + popperOffsets[mainAxis] = preventedOffset; + data[mainAxis] = preventedOffset - offset; + } + + if (checkAltAxis) { + const mainSide = mainAxis === 'x' ? top : left; + const altSide = mainAxis === 'x' ? bottom : right; + const offset = popperOffsets[altAxis]; + + const len = altAxis === 'y' ? 'height' : 'width'; + + const min = offset + overflow[mainSide]; + const max = offset - overflow[altSide]; + + const isOriginSide = [top, left].indexOf(basePlacement) !== -1; + + const offsetModifierValue = offsetModifierState?.[altAxis] ?? 0; + const tetherMin = isOriginSide + ? min + : offset - + referenceRect[len] - + popperRect[len] - + offsetModifierValue + + normalizedTetherOffsetValue.altAxis; + const tetherMax = isOriginSide + ? offset + + referenceRect[len] + + popperRect[len] - + offsetModifierValue - + normalizedTetherOffsetValue.altAxis + : max; + + const preventedOffset = + tether && isOriginSide + ? withinMaxClamp(tetherMin, offset, tetherMax) + : within(tether ? tetherMin : min, offset, tether ? tetherMax : max); + + popperOffsets[altAxis] = preventedOffset; + data[altAxis] = preventedOffset - offset; + } + + state.modifiersData[name] = data; +} + +// eslint-disable-next-line import/no-unused-modules +export type PreventOverflowModifier = Modifier<'preventOverflow', Options>; +export default ({ + name: 'preventOverflow', + enabled: true, + phase: 'main', + fn: preventOverflow, + requiresIfExists: ['offset'], +}: PreventOverflowModifier); |