@helpscout/hsds-react
Version:
React component library for Help Scout's Design System
326 lines (261 loc) • 11.4 kB
JavaScript
"use strict";
exports.__esModule = true;
exports.getComputedWidthProps = exports.getComputedHeightProps = exports.getViewportWidth = exports.getViewportHeight = exports.applyStylesToNode = exports.getHeightRelativeToViewport = exports.getViewportPosition = exports.getOptimalViewportPosition = exports.getDirections = exports.getDirectionY = exports.getDirectionX = void 0;
var _other = require("../../utilities/other");
var _node = require("../../utilities/node");
/* istanbul ignore file */
var parseFloatValue = function parseFloatValue(value) {
return parseFloat(value || '0');
};
var getDirectionX = function getDirectionX(direction) {
var defaultDirection = '';
if (typeof direction !== 'string') return defaultDirection; // No defaults
return direction.match(/left/) ? 'left' : direction.match(/right/) ? 'right' : '';
};
exports.getDirectionX = getDirectionX;
var getDirectionY = function getDirectionY(direction) {
var defaultDirection = 'down';
if (typeof direction !== 'string') return defaultDirection; // Default to down
return direction.match(/up/) ? 'up' : direction.match(/down/) ? 'down' : '';
};
exports.getDirectionY = getDirectionY;
var getDirections = function getDirections(direction) {
return {
x: getDirectionX(direction),
y: getDirectionY(direction)
};
};
exports.getDirections = getDirections;
var getOptimalViewportPosition = function getOptimalViewportPosition(options) {
if (!options && typeof options !== 'object') return false;
var triggerNode = options.triggerNode,
contentNode = options.contentNode,
offset = options.offset,
direction = options.direction;
if (!(0, _node.isNodeElement)(triggerNode) || !(0, _node.isNodeElement)(contentNode)) return false;
var pos = triggerNode.getBoundingClientRect();
var nodePos = contentNode.getBoundingClientRect();
var height = nodePos.height;
var width = nodePos.width;
var boundingOffset = 8; // The following vars are tested. However, they can only be tested for pos.top/pos.left vs other
// ternary outcomes. This is due to a limitation of JSDOM not supporting offsetTop/offsetLeft.
// Which is why the ternary begins by checking if the environment is node based.
var offsetTop = (0, _other.isNodeEnv)() ? pos.top : pos.top > triggerNode.offsetTop ? pos.top : triggerNode.offsetTop;
var offsetLeft = (0, _other.isNodeEnv)() ? pos.left : pos.left > triggerNode.offsetLeft ? pos.left : triggerNode.offsetLeft;
var viewportHeight = getViewportHeight();
var viewportWidth = getViewportWidth();
var posSize = offsetTop + pos.height; // Tested, but istanbul isn't picking it up
var triggerOffset = typeof offset !== 'undefined' ? offset : 0;
var triggerWidth = pos.width;
var totalOffset = triggerOffset + boundingOffset;
var directionX = direction && direction.x ? direction.x : '';
var directionY = direction && direction.y ? direction.y : 'down';
var top;
var left;
var totalOffsetWidthRight = offsetLeft + width + totalOffset + triggerWidth;
var totalOffsetWidthLeft = offsetLeft - width - totalOffset;
var totalOffsetHeightDown = posSize + height + totalOffset;
var totalOffsetHeightUp = posSize - height - totalOffset;
directionX = directionX === 'right' && totalOffsetWidthRight > viewportWidth && totalOffsetWidthLeft > 0 ? 'left' : directionX === 'left' && totalOffsetWidthLeft < 0 ? 'right' : directionX;
directionY = directionY === 'down' && totalOffsetHeightDown > viewportHeight && totalOffsetHeightUp > 0 ? 'up' : directionY === 'up' && totalOffsetHeightUp < 0 ? 'down' : directionY;
switch (directionY) {
case 'up':
top = offsetTop - triggerOffset - height;
break;
case 'down':
top = offsetTop + pos.height + triggerOffset;
break;
// Tested. Top is generated in the next switch case
default:
top = null;
break;
}
switch (directionX) {
case 'left':
left = offsetLeft - triggerOffset - nodePos.width;
if (directionY === 'down') {
top = offsetTop;
} else {
top = offsetTop - height + pos.height;
}
break;
case 'right':
left = offsetLeft + pos.width + triggerOffset;
if (directionY === 'down') {
top = offsetTop;
} else {
top = offsetTop - nodePos.height + pos.height;
}
break;
default:
left = offsetLeft;
break;
}
return {
top: parseInt(top, 10),
left: parseInt(left, 10),
offsetTop: parseInt(offsetTop, 10),
offsetLeft: parseInt(offsetLeft, 10),
offset: parseInt(totalOffset, 10),
direction: {
x: directionX,
y: directionY
}
};
}; // This function is temporary. It is a "dumbed down" version of
// getOptimalViewportPosition. This function was created to serve the use-case
// of Dropdown until getOptimalViewportPosition can support 12/16 point
// positioning.
exports.getOptimalViewportPosition = getOptimalViewportPosition;
var getViewportPosition = function getViewportPosition(options) {
if (!options && typeof options !== 'object') return false;
var triggerNode = options.triggerNode,
contentNode = options.contentNode,
offset = options.offset,
direction = options.direction;
if (!(0, _node.isNodeElement)(triggerNode) || !(0, _node.isNodeElement)(contentNode)) return false;
var pos = triggerNode.getBoundingClientRect();
var nodePos = contentNode.getBoundingClientRect();
var height = nodePos.height;
var width = nodePos.width;
var boundingOffset = 8; // The following vars are tested. However, they can only be tested for pos.top/pos.left vs other
// ternary outcomes. This is due to a limitation of JSDOM not supporting offsetTop/offsetLeft.
// Which is why the ternary begins by checking if the environment is node based.
var offsetTop = (0, _other.isNodeEnv)() ? pos.top : pos.top > triggerNode.offsetTop ? pos.top : triggerNode.offsetTop;
var offsetLeft = (0, _other.isNodeEnv)() ? pos.left : pos.left > triggerNode.offsetLeft ? pos.left : triggerNode.offsetLeft;
var viewportHeight = getViewportHeight();
var posSize = offsetTop + pos.height; // Tested, but istanbul isn't picking it up
var triggerOffset = typeof offset !== 'undefined' ? offset : 0;
var totalOffset = triggerOffset + boundingOffset;
var directionX = direction && direction.x ? direction.x : '';
var directionY = direction && direction.y ? direction.y : '';
var top;
var left;
var totalOffsetHeightDown = posSize + height + totalOffset;
var totalOffsetHeightUp = posSize - height - totalOffset;
directionY = directionY === 'down' && totalOffsetHeightDown > viewportHeight && totalOffsetHeightUp > 0 ? 'up' : directionY === 'up' && totalOffsetHeightUp < 0 ? 'down' : directionY; // Ignoring since this method will be removed once getOptimalViewportPosition
// has been enhanced.
switch (directionY) {
case 'up':
top = offsetTop - triggerOffset - height;
break;
case 'down':
top = offsetTop + pos.height + triggerOffset;
break;
default:
top = offsetTop;
break;
} // Ignoring since this method will be removed once getOptimalViewportPosition
// has been enhanced.
switch (directionX) {
case 'left':
left = directionY ? offsetLeft : offsetLeft - triggerOffset - nodePos.width;
break;
case 'right':
left = directionY ? offsetLeft - width + pos.width : offsetLeft + pos.width + triggerOffset;
break;
default:
left = offsetLeft;
break;
}
return {
top: parseInt(top, 10),
left: parseInt(left, 10),
offsetTop: parseInt(offsetTop, 10),
offsetLeft: parseInt(offsetLeft, 10),
offset: parseInt(totalOffset, 10),
direction: {
x: directionX,
y: directionY
}
};
};
exports.getViewportPosition = getViewportPosition;
var getHeightRelativeToViewport = function getHeightRelativeToViewport(options) {
if (!options && typeof options !== 'object') return false;
var offset = options.offset,
node = options.node;
if (!(0, _node.isNodeElement)(node)) return false;
var viewportHeight = getViewportHeight();
var pos = node.getBoundingClientRect();
var nodeOffset = offset !== undefined ? offset : 0;
var isNodeOutsideOfViewport = pos.top + pos.height > viewportHeight;
var newHeight = viewportHeight - pos.top - nodeOffset;
var height = isNodeOutsideOfViewport ? newHeight : null;
return height;
};
exports.getHeightRelativeToViewport = getHeightRelativeToViewport;
var applyStylesToNode = function applyStylesToNode(node, styles) {
if (styles === void 0) {
styles = {};
}
if (!node) return false;
if (!(0, _node.isNodeElement)(node)) return node;
if (typeof styles !== 'object') return node;
Object.keys(styles).forEach(function (prop) {
var value = styles[prop];
node.style[prop] = typeof value === 'number' && prop !== 'zIndex' ? value + "px" : value;
});
return node;
};
exports.applyStylesToNode = applyStylesToNode;
var getViewportHeight = function getViewportHeight(scope) {
var node = (0, _node.getNodeScope)(scope);
var _getComputedHeightPro = getComputedHeightProps(node),
height = _getComputedHeightPro.height,
offset = _getComputedHeightPro.offset;
return height > window.innerHeight ? height : window.innerHeight - offset;
};
exports.getViewportHeight = getViewportHeight;
var getViewportWidth = function getViewportWidth(scope) {
var node = (0, _node.getNodeScope)(scope);
var _getComputedWidthProp = getComputedWidthProps(node),
width = _getComputedWidthProp.width,
offset = _getComputedWidthProp.offset;
return width > window.innerWidth ? width : window.innerWidth - offset;
};
exports.getViewportWidth = getViewportWidth;
var getComputedHeightProps = function getComputedHeightProps(node) {
if (!(0, _node.isNodeElement)(node)) return {
height: 0,
offset: 0
};
var el = node !== document ? node : document.body;
var height = el.offsetHeight;
var _window$getComputedSt = window.getComputedStyle(el),
marginTop = _window$getComputedSt.marginTop,
marginBottom = _window$getComputedSt.marginBottom,
paddingTop = _window$getComputedSt.paddingTop,
paddingBottom = _window$getComputedSt.paddingBottom;
var offset = parseFloatValue(marginTop) + parseFloatValue(marginBottom);
if (!(0, _other.isNodeEnv)()) {
offset = offset + parseFloatValue(paddingTop) + parseFloatValue(paddingBottom);
}
return {
height: height,
offset: offset
};
};
exports.getComputedHeightProps = getComputedHeightProps;
var getComputedWidthProps = function getComputedWidthProps(node) {
if (!(0, _node.isNodeElement)(node)) return {
width: 0,
offset: 0
};
var el = node !== document ? node : document.body;
var width = el.offsetWidth;
var _window$getComputedSt2 = window.getComputedStyle(el),
marginLeft = _window$getComputedSt2.marginLeft,
marginRight = _window$getComputedSt2.marginRight,
paddingLeft = _window$getComputedSt2.paddingLeft,
paddingRight = _window$getComputedSt2.paddingRight;
var offset = parseFloatValue(marginLeft) + parseFloatValue(marginRight);
if (!(0, _other.isNodeEnv)()) {
offset = offset + parseFloatValue(paddingLeft) + parseFloatValue(paddingRight);
}
return {
width: width,
offset: offset
};
};
exports.getComputedWidthProps = getComputedWidthProps;