|
|
import getClientRect from '../utils/getClientRect'; |
|
|
import getOuterSizes from '../utils/getOuterSizes'; |
|
|
import isModifierRequired from '../utils/isModifierRequired'; |
|
|
import getStyleComputedProperty from '../utils/getStyleComputedProperty'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default function arrow(data, options) { |
|
|
|
|
|
if (!isModifierRequired(data.instance.modifiers, 'arrow', 'keepTogether')) { |
|
|
return data; |
|
|
} |
|
|
|
|
|
let arrowElement = options.element; |
|
|
|
|
|
|
|
|
if (typeof arrowElement === 'string') { |
|
|
arrowElement = data.instance.popper.querySelector(arrowElement); |
|
|
|
|
|
|
|
|
if (!arrowElement) { |
|
|
return data; |
|
|
} |
|
|
} else { |
|
|
|
|
|
|
|
|
if (!data.instance.popper.contains(arrowElement)) { |
|
|
console.warn( |
|
|
'WARNING: `arrow.element` must be child of its popper element!' |
|
|
); |
|
|
return data; |
|
|
} |
|
|
} |
|
|
|
|
|
const placement = data.placement.split('-')[0]; |
|
|
const { popper, reference } = data.offsets; |
|
|
const isVertical = ['left', 'right'].indexOf(placement) !== -1; |
|
|
|
|
|
const len = isVertical ? 'height' : 'width'; |
|
|
const sideCapitalized = isVertical ? 'Top' : 'Left'; |
|
|
const side = sideCapitalized.toLowerCase(); |
|
|
const altSide = isVertical ? 'left' : 'top'; |
|
|
const opSide = isVertical ? 'bottom' : 'right'; |
|
|
const arrowElementSize = getOuterSizes(arrowElement)[len]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (reference[opSide] - arrowElementSize < popper[side]) { |
|
|
data.offsets.popper[side] -= |
|
|
popper[side] - (reference[opSide] - arrowElementSize); |
|
|
} |
|
|
|
|
|
if (reference[side] + arrowElementSize > popper[opSide]) { |
|
|
data.offsets.popper[side] += |
|
|
reference[side] + arrowElementSize - popper[opSide]; |
|
|
} |
|
|
data.offsets.popper = getClientRect(data.offsets.popper); |
|
|
|
|
|
|
|
|
const center = reference[side] + reference[len] / 2 - arrowElementSize / 2; |
|
|
|
|
|
|
|
|
|
|
|
const css = getStyleComputedProperty(data.instance.popper); |
|
|
const popperMarginSide = parseFloat(css[`margin${sideCapitalized}`]); |
|
|
const popperBorderSide = parseFloat(css[`border${sideCapitalized}Width`]); |
|
|
let sideValue = |
|
|
center - data.offsets.popper[side] - popperMarginSide - popperBorderSide; |
|
|
|
|
|
|
|
|
sideValue = Math.max(Math.min(popper[len] - arrowElementSize, sideValue), 0); |
|
|
|
|
|
data.arrowElement = arrowElement; |
|
|
data.offsets.arrow = { |
|
|
[side]: Math.round(sideValue), |
|
|
[altSide]: '', |
|
|
}; |
|
|
|
|
|
return data; |
|
|
} |
|
|
|