react-tooltip
Version:
react tooltip component
273 lines (242 loc) • 7.97 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = function (e, target, node, place, desiredPlace, effect, offset) {
var _getDimensions = getDimensions(node),
tipWidth = _getDimensions.width,
tipHeight = _getDimensions.height;
var _getDimensions2 = getDimensions(target),
targetWidth = _getDimensions2.width,
targetHeight = _getDimensions2.height;
var _getCurrentOffset = getCurrentOffset(e, target, effect),
mouseX = _getCurrentOffset.mouseX,
mouseY = _getCurrentOffset.mouseY;
var defaultOffset = getDefaultPosition(effect, targetWidth, targetHeight, tipWidth, tipHeight);
var _calculateOffset = calculateOffset(offset),
extraOffset_X = _calculateOffset.extraOffset_X,
extraOffset_Y = _calculateOffset.extraOffset_Y;
var windowWidth = window.innerWidth;
var windowHeight = window.innerHeight;
var _getParent = getParent(node),
parentTop = _getParent.parentTop,
parentLeft = _getParent.parentLeft;
// Get the edge offset of the tooltip
var getTipOffsetLeft = function getTipOffsetLeft(place) {
var offset_X = defaultOffset[place].l;
return mouseX + offset_X + extraOffset_X;
};
var getTipOffsetRight = function getTipOffsetRight(place) {
var offset_X = defaultOffset[place].r;
return mouseX + offset_X + extraOffset_X;
};
var getTipOffsetTop = function getTipOffsetTop(place) {
var offset_Y = defaultOffset[place].t;
return mouseY + offset_Y + extraOffset_Y;
};
var getTipOffsetBottom = function getTipOffsetBottom(place) {
var offset_Y = defaultOffset[place].b;
return mouseY + offset_Y + extraOffset_Y;
};
//
// Functions to test whether the tooltip's sides are inside
// the client window for a given orientation p
//
// _____________
// | | <-- Right side
// | p = 'left' |\
// | |/ |\
// |_____________| |_\ <-- Mouse
// / \ |
// |
// |
// Bottom side
//
var outsideLeft = function outsideLeft(p) {
return getTipOffsetLeft(p) < 0;
};
var outsideRight = function outsideRight(p) {
return getTipOffsetRight(p) > windowWidth;
};
var outsideTop = function outsideTop(p) {
return getTipOffsetTop(p) < 0;
};
var outsideBottom = function outsideBottom(p) {
return getTipOffsetBottom(p) > windowHeight;
};
// Check whether the tooltip with orientation p is completely inside the client window
var outside = function outside(p) {
return outsideLeft(p) || outsideRight(p) || outsideTop(p) || outsideBottom(p);
};
var inside = function inside(p) {
return !outside(p);
};
var placesList = ['top', 'bottom', 'left', 'right'];
var insideList = [];
for (var i = 0; i < 4; i++) {
var p = placesList[i];
if (inside(p)) {
insideList.push(p);
}
}
var isNewState = false;
var newPlace = void 0;
if (inside(desiredPlace) && desiredPlace !== place) {
isNewState = true;
newPlace = desiredPlace;
} else if (insideList.length > 0 && outside(desiredPlace) && outside(place)) {
isNewState = true;
newPlace = insideList[0];
}
if (isNewState) {
return {
isNewState: true,
newState: { place: newPlace }
};
}
return {
isNewState: false,
position: {
left: parseInt(getTipOffsetLeft(place) - parentLeft, 10),
top: parseInt(getTipOffsetTop(place) - parentTop, 10)
}
};
};
var getDimensions = function getDimensions(node) {
var _node$getBoundingClie = node.getBoundingClientRect(),
height = _node$getBoundingClie.height,
width = _node$getBoundingClie.width;
return {
height: parseInt(height, 10),
width: parseInt(width, 10)
};
};
// Get current mouse offset
/**
* Calculate the position of tooltip
*
* @params
* - `e` {Event} the event of current mouse
* - `target` {Element} the currentTarget of the event
* - `node` {DOM} the react-tooltip object
* - `place` {String} top / right / bottom / left
* - `effect` {String} float / solid
* - `offset` {Object} the offset to default position
*
* @return {Object}
* - `isNewState` {Bool} required
* - `newState` {Object}
* - `position` {Object} {left: {Number}, top: {Number}}
*/
var getCurrentOffset = function getCurrentOffset(e, currentTarget, effect) {
var boundingClientRect = currentTarget.getBoundingClientRect();
var targetTop = boundingClientRect.top;
var targetLeft = boundingClientRect.left;
var _getDimensions3 = getDimensions(currentTarget),
targetWidth = _getDimensions3.width,
targetHeight = _getDimensions3.height;
if (effect === 'float') {
return {
mouseX: e.clientX,
mouseY: e.clientY
};
}
return {
mouseX: targetLeft + targetWidth / 2,
mouseY: targetTop + targetHeight / 2
};
};
// List all possibility of tooltip final offset
// This is useful in judging if it is necessary for tooltip to switch position when out of window
var getDefaultPosition = function getDefaultPosition(effect, targetWidth, targetHeight, tipWidth, tipHeight) {
var top = void 0;
var right = void 0;
var bottom = void 0;
var left = void 0;
var disToMouse = 3;
var triangleHeight = 2;
var cursorHeight = 12; // Optimize for float bottom only, cause the cursor will hide the tooltip
if (effect === 'float') {
top = {
l: -(tipWidth / 2),
r: tipWidth / 2,
t: -(tipHeight + disToMouse + triangleHeight),
b: -disToMouse
};
bottom = {
l: -(tipWidth / 2),
r: tipWidth / 2,
t: disToMouse + cursorHeight,
b: tipHeight + disToMouse + triangleHeight + cursorHeight
};
left = {
l: -(tipWidth + disToMouse + triangleHeight),
r: -disToMouse,
t: -(tipHeight / 2),
b: tipHeight / 2
};
right = {
l: disToMouse,
r: tipWidth + disToMouse + triangleHeight,
t: -(tipHeight / 2),
b: tipHeight / 2
};
} else if (effect === 'solid') {
top = {
l: -(tipWidth / 2),
r: tipWidth / 2,
t: -(targetHeight / 2 + tipHeight + triangleHeight),
b: -(targetHeight / 2)
};
bottom = {
l: -(tipWidth / 2),
r: tipWidth / 2,
t: targetHeight / 2,
b: targetHeight / 2 + tipHeight + triangleHeight
};
left = {
l: -(tipWidth + targetWidth / 2 + triangleHeight),
r: -(targetWidth / 2),
t: -(tipHeight / 2),
b: tipHeight / 2
};
right = {
l: targetWidth / 2,
r: tipWidth + targetWidth / 2 + triangleHeight,
t: -(tipHeight / 2),
b: tipHeight / 2
};
}
return { top: top, bottom: bottom, left: left, right: right };
};
// Consider additional offset into position calculation
var calculateOffset = function calculateOffset(offset) {
var extraOffset_X = 0;
var extraOffset_Y = 0;
if (Object.prototype.toString.apply(offset) === '[object String]') {
offset = JSON.parse(offset.toString().replace(/\'/g, '\"'));
}
for (var key in offset) {
if (key === 'top') {
extraOffset_Y -= parseInt(offset[key], 10);
} else if (key === 'bottom') {
extraOffset_Y += parseInt(offset[key], 10);
} else if (key === 'left') {
extraOffset_X -= parseInt(offset[key], 10);
} else if (key === 'right') {
extraOffset_X += parseInt(offset[key], 10);
}
}
return { extraOffset_X: extraOffset_X, extraOffset_Y: extraOffset_Y };
};
// Get the offset of the parent elements
var getParent = function getParent(currentTarget) {
var currentParent = currentTarget;
while (currentParent) {
if (window.getComputedStyle(currentParent).getPropertyValue('transform') !== 'none') break;
currentParent = currentParent.parentElement;
}
var parentTop = currentParent && currentParent.getBoundingClientRect().top || 0;
var parentLeft = currentParent && currentParent.getBoundingClientRect().left || 0;
return { parentTop: parentTop, parentLeft: parentLeft };
};