UNPKG

@helpscout/hsds-react

Version:

React component library for Help Scout's Design System

326 lines (261 loc) 11.4 kB
"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;