UNPKG

react-native-walkthrough-tooltip

Version:

An inline wrapper for calling out React Native components via tooltip

372 lines (327 loc) 9 kB
class Point { constructor(x, y) { this.x = x; this.y = y; } } class Size { constructor(width, height) { this.width = width; this.height = height; } } class Rect { constructor(x, y, width, height) { this.x = x; this.y = y; this.width = width; this.height = height; } } const swapSizeDimmensions = (size) => new Size(size.height, size.width); const makeChildlessRect = ({ displayInsets, windowDims, placement }) => { switch (placement) { case "bottom": return new Rect(windowDims.width / 2, displayInsets.top, 0, 0); case "right": return new Rect(displayInsets.left, windowDims.height / 2, 0, 0); case "left": return new Rect( windowDims.width - displayInsets.right, windowDims.height / 2, 0, 0 ); case "top": default: return new Rect( windowDims.width / 2, windowDims.height - displayInsets.bottom, 0, 0 ); } }; const computeCenterGeometry = ({ childRect, contentSize, displayInsets, windowDims }) => { const maxWidth = windowDims.width - (displayInsets.left + displayInsets.right); const maxHeight = windowDims.height - (displayInsets.top + displayInsets.bottom); const adjustedContentSize = new Size( contentSize.width >= maxWidth ? maxWidth : -1, contentSize.height >= maxHeight ? maxHeight : -1 ); const tooltipOrigin = new Point( adjustedContentSize.width === -1 ? (maxWidth - contentSize.width) / 2 + displayInsets.left : displayInsets.left, adjustedContentSize.height === -1 ? (maxHeight - contentSize.height) / 2 + displayInsets.top : displayInsets.top ); const anchorPoint = new Point( childRect.x + childRect.width / 2.0, childRect.y ); return { tooltipOrigin, anchorPoint, placement: "center", adjustedContentSize }; }; const computeTopGeometry = ({ childRect, contentSize, arrowSize, displayInsets, windowDims, childContentSpacing }) => { const maxWidth = windowDims.width - (displayInsets.left + displayInsets.right); const adjustedContentSize = new Size( Math.min(maxWidth, contentSize.width), contentSize.height ); const tooltipOrigin = new Point( contentSize.width >= maxWidth ? displayInsets.left : Math.max( displayInsets.left, childRect.x + (childRect.width - contentSize.width) / 2 ), Math.max( displayInsets.top - childContentSpacing, childRect.y - contentSize.height - arrowSize.height - childContentSpacing ) ); const anchorPoint = new Point( childRect.x + childRect.width / 2.0, childRect.y - childContentSpacing ); // make sure arrow does not extend beyond displayInsets if ( anchorPoint.x + arrowSize.width > windowDims.width - displayInsets.right ) { anchorPoint.x = windowDims.width - displayInsets.right - Math.abs(arrowSize.width - arrowSize.height) - 8; } else if (anchorPoint.x - arrowSize.width < displayInsets.left) { anchorPoint.x = displayInsets.left + Math.abs(arrowSize.width - arrowSize.height) + 8; } const topPlacementBottomBound = anchorPoint.y - arrowSize.height; if (tooltipOrigin.y + contentSize.height > topPlacementBottomBound) { adjustedContentSize.height = topPlacementBottomBound - tooltipOrigin.y; } if (tooltipOrigin.x + contentSize.width > maxWidth) { tooltipOrigin.x = displayInsets.left; } return { tooltipOrigin, anchorPoint, placement: "top", adjustedContentSize }; }; const computeBottomGeometry = ({ childRect, contentSize, arrowSize, displayInsets, windowDims, childContentSpacing }) => { const maxWidth = windowDims.width - (displayInsets.left + displayInsets.right); const adjustedContentSize = new Size( Math.min(maxWidth, contentSize.width), contentSize.height ); const tooltipOrigin = new Point( contentSize.width >= maxWidth ? displayInsets.left : Math.max( displayInsets.left, childRect.x + (childRect.width - contentSize.width) / 2 ), Math.min( windowDims.height - displayInsets.bottom + childContentSpacing, childRect.y + childRect.height + arrowSize.height + childContentSpacing ) ); const anchorPoint = new Point( childRect.x + childRect.width / 2.0, childRect.y + childRect.height + childContentSpacing ); // make sure arrow does not extend beyond displayInsets if ( anchorPoint.x + arrowSize.width > windowDims.width - displayInsets.right ) { anchorPoint.x = windowDims.width - displayInsets.right - Math.abs(arrowSize.width - arrowSize.height) - 8; } else if (anchorPoint.x - arrowSize.width < displayInsets.left) { anchorPoint.x = displayInsets.left + Math.abs(arrowSize.width - arrowSize.height) + 8; } if ( tooltipOrigin.y + contentSize.height > windowDims.height - displayInsets.bottom ) { adjustedContentSize.height = windowDims.height - displayInsets.bottom - tooltipOrigin.y; } if (tooltipOrigin.x + contentSize.width > maxWidth) { tooltipOrigin.x = displayInsets.left; } return { tooltipOrigin, anchorPoint, placement: "bottom", adjustedContentSize }; }; const computeLeftGeometry = ({ childRect, contentSize, arrowSize, displayInsets, windowDims, childContentSpacing }) => { const maxHeight = windowDims.height - (displayInsets.top + displayInsets.bottom); const adjustedContentSize = new Size( contentSize.width, Math.min(maxHeight, contentSize.height) ); const tooltipOrigin = new Point( Math.max( displayInsets.left - childContentSpacing, childRect.x - contentSize.width - arrowSize.width - childContentSpacing ), contentSize.height >= maxHeight ? displayInsets.top : Math.max( displayInsets.top, childRect.y + (childRect.height - contentSize.height) / 2 ) ); const anchorPoint = new Point( childRect.x - childContentSpacing, childRect.y + childRect.height / 2.0 ); // make sure arrow does not extend beyond displayInsets if ( anchorPoint.y + arrowSize.width > windowDims.height - displayInsets.bottom ) { anchorPoint.y = windowDims.height - displayInsets.bottom - Math.abs(arrowSize.height - arrowSize.width) - 8; } else if (anchorPoint.y - arrowSize.height < displayInsets.top) { anchorPoint.y = displayInsets.top + Math.abs(arrowSize.height - arrowSize.width) + 8; } const leftPlacementRightBound = anchorPoint.x - arrowSize.width; if (tooltipOrigin.x + contentSize.width > leftPlacementRightBound) { adjustedContentSize.width = leftPlacementRightBound - tooltipOrigin.x; } if (tooltipOrigin.y + contentSize.height > maxHeight) { tooltipOrigin.y = displayInsets.top; } return { tooltipOrigin, anchorPoint, placement: "left", adjustedContentSize }; }; const computeRightGeometry = ({ childRect, contentSize, arrowSize, displayInsets, windowDims, childContentSpacing }) => { const maxHeight = windowDims.height - (displayInsets.top + displayInsets.bottom); const adjustedContentSize = new Size( contentSize.width, Math.min(maxHeight, contentSize.height) ); const tooltipOrigin = new Point( Math.min( windowDims.width - displayInsets.right + childContentSpacing, childRect.x + childRect.width + arrowSize.width + childContentSpacing ), contentSize.height >= maxHeight ? displayInsets.top : Math.max( displayInsets.top, childRect.y + (childRect.height - contentSize.height) / 2 ) ); const anchorPoint = new Point( childRect.x + childRect.width + childContentSpacing, childRect.y + childRect.height / 2.0 ); // make sure arrow does not extend beyond displayInsets if ( anchorPoint.y + arrowSize.width > windowDims.height - displayInsets.bottom ) { anchorPoint.y = windowDims.height - displayInsets.bottom - Math.abs(arrowSize.height - arrowSize.width) - 8; } else if (anchorPoint.y - arrowSize.height < displayInsets.top) { anchorPoint.y = displayInsets.top + Math.abs(arrowSize.height - arrowSize.width) + 8; } if ( tooltipOrigin.x + contentSize.width > windowDims.width - displayInsets.right ) { adjustedContentSize.width = windowDims.width - displayInsets.right - tooltipOrigin.x; } if (tooltipOrigin.y + contentSize.height > maxHeight) { tooltipOrigin.y = displayInsets.top; } return { tooltipOrigin, anchorPoint, placement: "right", adjustedContentSize }; }; export { Point, Size, Rect, swapSizeDimmensions, makeChildlessRect, computeCenterGeometry, computeTopGeometry, computeBottomGeometry, computeLeftGeometry, computeRightGeometry };