import getOffsetParent from '../utils/getOffsetParent';
|
import getBoundaries from '../utils/getBoundaries';
|
import getSupportedPropertyName from '../utils/getSupportedPropertyName';
|
|
/**
|
* @function
|
* @memberof Modifiers
|
* @argument {Object} data - The data object generated by `update` method
|
* @argument {Object} options - Modifiers configuration and options
|
* @returns {Object} The data object, properly modified
|
*/
|
export default function preventOverflow(data, options) {
|
let boundariesElement =
|
options.boundariesElement || getOffsetParent(data.instance.popper);
|
|
// If offsetParent is the reference element, we really want to
|
// go one step up and use the next offsetParent as reference to
|
// avoid to make this modifier completely useless and look like broken
|
if (data.instance.reference === boundariesElement) {
|
boundariesElement = getOffsetParent(boundariesElement);
|
}
|
|
// NOTE: DOM access here
|
// resets the popper's position so that the document size can be calculated excluding
|
// the size of the popper element itself
|
const transformProp = getSupportedPropertyName('transform');
|
const popperStyles = data.instance.popper.style; // assignment to help minification
|
const { top, left, [transformProp]: transform } = popperStyles;
|
popperStyles.top = '';
|
popperStyles.left = '';
|
popperStyles[transformProp] = '';
|
|
const boundaries = getBoundaries(
|
data.instance.popper,
|
data.instance.reference,
|
options.padding,
|
boundariesElement,
|
data.positionFixed
|
);
|
|
// NOTE: DOM access here
|
// restores the original style properties after the offsets have been computed
|
popperStyles.top = top;
|
popperStyles.left = left;
|
popperStyles[transformProp] = transform;
|
|
options.boundaries = boundaries;
|
|
const order = options.priority;
|
let popper = data.offsets.popper;
|
|
const check = {
|
primary(placement) {
|
let value = popper[placement];
|
if (
|
popper[placement] < boundaries[placement] &&
|
!options.escapeWithReference
|
) {
|
value = Math.max(popper[placement], boundaries[placement]);
|
}
|
return { [placement]: value };
|
},
|
secondary(placement) {
|
const mainSide = placement === 'right' ? 'left' : 'top';
|
let value = popper[mainSide];
|
if (
|
popper[placement] > boundaries[placement] &&
|
!options.escapeWithReference
|
) {
|
value = Math.min(
|
popper[mainSide],
|
boundaries[placement] -
|
(placement === 'right' ? popper.width : popper.height)
|
);
|
}
|
return { [mainSide]: value };
|
},
|
};
|
|
order.forEach(placement => {
|
const side =
|
['left', 'top'].indexOf(placement) !== -1 ? 'primary' : 'secondary';
|
popper = { ...popper, ...check[side](placement) };
|
});
|
|
data.offsets.popper = popper;
|
|
return data;
|
}
|