|
|
import isNumeric from '../utils/isNumeric'; |
|
|
import getClientRect from '../utils/getClientRect'; |
|
|
import find from '../utils/find'; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function toValue(str, measurement, popperOffsets, referenceOffsets) { |
|
|
|
|
|
const split = str.match(/((?:\-|\+)?\d*\.?\d*)(.*)/); |
|
|
const value = +split[1]; |
|
|
const unit = split[2]; |
|
|
|
|
|
|
|
|
if (!value) { |
|
|
return str; |
|
|
} |
|
|
|
|
|
if (unit.indexOf('%') === 0) { |
|
|
let element; |
|
|
switch (unit) { |
|
|
case '%p': |
|
|
element = popperOffsets; |
|
|
break; |
|
|
case '%': |
|
|
case '%r': |
|
|
default: |
|
|
element = referenceOffsets; |
|
|
} |
|
|
|
|
|
const rect = getClientRect(element); |
|
|
return rect[measurement] / 100 * value; |
|
|
} else if (unit === 'vh' || unit === 'vw') { |
|
|
|
|
|
let size; |
|
|
if (unit === 'vh') { |
|
|
size = Math.max( |
|
|
document.documentElement.clientHeight, |
|
|
window.innerHeight || 0 |
|
|
); |
|
|
} else { |
|
|
size = Math.max( |
|
|
document.documentElement.clientWidth, |
|
|
window.innerWidth || 0 |
|
|
); |
|
|
} |
|
|
return size / 100 * value; |
|
|
} else { |
|
|
|
|
|
|
|
|
return value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export function parseOffset( |
|
|
offset, |
|
|
popperOffsets, |
|
|
referenceOffsets, |
|
|
basePlacement |
|
|
) { |
|
|
const offsets = [0, 0]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const useHeight = ['right', 'left'].indexOf(basePlacement) !== -1; |
|
|
|
|
|
|
|
|
|
|
|
const fragments = offset.split(/(\+|\-)/).map(frag => frag.trim()); |
|
|
|
|
|
|
|
|
|
|
|
const divider = fragments.indexOf( |
|
|
find(fragments, frag => frag.search(/,|\s/) !== -1) |
|
|
); |
|
|
|
|
|
if (fragments[divider] && fragments[divider].indexOf(',') === -1) { |
|
|
console.warn( |
|
|
'Offsets separated by white space(s) are deprecated, use a comma (,) instead.' |
|
|
); |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
const splitRegex = /\s*,\s*|\s+/; |
|
|
let ops = divider !== -1 |
|
|
? [ |
|
|
fragments |
|
|
.slice(0, divider) |
|
|
.concat([fragments[divider].split(splitRegex)[0]]), |
|
|
[fragments[divider].split(splitRegex)[1]].concat( |
|
|
fragments.slice(divider + 1) |
|
|
), |
|
|
] |
|
|
: [fragments]; |
|
|
|
|
|
|
|
|
ops = ops.map((op, index) => { |
|
|
|
|
|
const measurement = (index === 1 ? !useHeight : useHeight) |
|
|
? 'height' |
|
|
: 'width'; |
|
|
let mergeWithPrevious = false; |
|
|
return ( |
|
|
op |
|
|
|
|
|
|
|
|
.reduce((a, b) => { |
|
|
if (a[a.length - 1] === '' && ['+', '-'].indexOf(b) !== -1) { |
|
|
a[a.length - 1] = b; |
|
|
mergeWithPrevious = true; |
|
|
return a; |
|
|
} else if (mergeWithPrevious) { |
|
|
a[a.length - 1] += b; |
|
|
mergeWithPrevious = false; |
|
|
return a; |
|
|
} else { |
|
|
return a.concat(b); |
|
|
} |
|
|
}, []) |
|
|
|
|
|
.map(str => toValue(str, measurement, popperOffsets, referenceOffsets)) |
|
|
); |
|
|
}); |
|
|
|
|
|
|
|
|
ops.forEach((op, index) => { |
|
|
op.forEach((frag, index2) => { |
|
|
if (isNumeric(frag)) { |
|
|
offsets[index] += frag * (op[index2 - 1] === '-' ? -1 : 1); |
|
|
} |
|
|
}); |
|
|
}); |
|
|
return offsets; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export default function offset(data, { offset }) { |
|
|
const { placement, offsets: { popper, reference } } = data; |
|
|
const basePlacement = placement.split('-')[0]; |
|
|
|
|
|
let offsets; |
|
|
if (isNumeric(+offset)) { |
|
|
offsets = [+offset, 0]; |
|
|
} else { |
|
|
offsets = parseOffset(offset, popper, reference, basePlacement); |
|
|
} |
|
|
|
|
|
if (basePlacement === 'left') { |
|
|
popper.top += offsets[0]; |
|
|
popper.left -= offsets[1]; |
|
|
} else if (basePlacement === 'right') { |
|
|
popper.top += offsets[0]; |
|
|
popper.left += offsets[1]; |
|
|
} else if (basePlacement === 'top') { |
|
|
popper.left += offsets[0]; |
|
|
popper.top -= offsets[1]; |
|
|
} else if (basePlacement === 'bottom') { |
|
|
popper.left += offsets[0]; |
|
|
popper.top += offsets[1]; |
|
|
} |
|
|
|
|
|
data.popper = popper; |
|
|
return data; |
|
|
} |
|
|
|