From 3d9b6b4c0162aafb4c4c61a632a26d2cef51a749 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 28 Aug 2023 10:28:45 +0200 Subject: [PATCH 1/5] [TS migration] Migrate 'getTooltipStyles.js' style to TypeScript --- .../Tooltip/TooltipRenderedOnPageBody.js | 2 +- ...etTooltipStyles.js => getTooltipStyles.ts} | 98 ++++++++++--------- 2 files changed, 53 insertions(+), 47 deletions(-) rename src/styles/{getTooltipStyles.js => getTooltipStyles.ts} (78%) diff --git a/src/components/Tooltip/TooltipRenderedOnPageBody.js b/src/components/Tooltip/TooltipRenderedOnPageBody.js index 8c717e17c424..724a56162f86 100644 --- a/src/components/Tooltip/TooltipRenderedOnPageBody.js +++ b/src/components/Tooltip/TooltipRenderedOnPageBody.js @@ -86,6 +86,7 @@ const TooltipRenderedOnPageBody = (props) => { const {animationStyle, rootWrapperStyle, textStyle, pointerWrapperStyle, pointerStyle} = useMemo( () => getTooltipStyles( + rootWrapper.current, props.animation, props.windowWidth, props.xOffset, @@ -97,7 +98,6 @@ const TooltipRenderedOnPageBody = (props) => { wrapperMeasuredHeight, props.shiftHorizontal, props.shiftVertical, - rootWrapper.current, ), [ props.animation, diff --git a/src/styles/getTooltipStyles.js b/src/styles/getTooltipStyles.ts similarity index 78% rename from src/styles/getTooltipStyles.js rename to src/styles/getTooltipStyles.ts index bc5fcfe807aa..bbc6ab9942e8 100644 --- a/src/styles/getTooltipStyles.js +++ b/src/styles/getTooltipStyles.ts @@ -1,3 +1,5 @@ +import {CSSProperties, RefObject} from 'react'; +import {TextStyle, View, ViewStyle} from 'react-native'; import spacing from './utilities/spacing'; import styles from './styles'; import colors from './colors'; @@ -6,30 +8,29 @@ import fontFamily from './fontFamily'; import variables from './variables'; import roundToNearestMultipleOfFour from './roundToNearestMultipleOfFour'; -// This defines the proximity with the edge of the window in which tooltips should not be displayed. -// If a tooltip is too close to the edge of the screen, we'll shift it towards the center. +/** This defines the proximity with the edge of the window in which tooltips should not be displayed. + * If a tooltip is too close to the edge of the screen, we'll shift it towards the center. */ const GUTTER_WIDTH = variables.gutterWidth; -// The height of a tooltip pointer +/** The height of a tooltip pointer */ const POINTER_HEIGHT = 4; -// The width of a tooltip pointer +/** The width of a tooltip pointer */ const POINTER_WIDTH = 12; /** * Compute the amount the tooltip needs to be horizontally shifted in order to keep it from displaying in the gutters. * - * @param {Number} windowWidth - The width of the window. - * @param {Number} xOffset - The distance between the left edge of the window + * @param windowWidth - The width of the window. + * @param xOffset - The distance between the left edge of the window * and the left edge of the wrapped component. - * @param {Number} componentWidth - The width of the wrapped component. - * @param {Number} tooltipWidth - The width of the tooltip itself. - * @param {Number} [manualShiftHorizontal] - Any additional amount to manually shift the tooltip to the left or right. + * @param componentWidth - The width of the wrapped component. + * @param tooltipWidth - The width of the tooltip itself. + * @param [manualShiftHorizontal] - Any additional amount to manually shift the tooltip to the left or right. * A positive value shifts it to the right, * and a negative value shifts it to the left. - * @returns {Number} */ -function computeHorizontalShift(windowWidth, xOffset, componentWidth, tooltipWidth, manualShiftHorizontal) { +function computeHorizontalShift(windowWidth: number, xOffset: number, componentWidth: number, tooltipWidth: number, manualShiftHorizontal: number): number { // First find the left and right edges of the tooltip (by default, it is centered on the component). const componentCenter = xOffset + componentWidth / 2 + manualShiftHorizontal; const tooltipLeftEdge = componentCenter - tooltipWidth / 2; @@ -61,16 +62,15 @@ function computeHorizontalShift(windowWidth, xOffset, componentWidth, tooltipWid * | | * |_ _ _ _ _| * - * @param {Number} xOffset - The distance between the left edge of the window + * @param xOffset - The distance between the left edge of the window * and the left edge of the wrapped component. - * @param {Number} yOffset - The distance between the top edge of the window + * @param yOffset - The distance between the top edge of the window * and the top edge of the wrapped component. - * @param {Element} [tooltip] - The reference to the tooltip's root element - * @param {Number} tooltipTargetWidth - The width of the tooltip's target - * @param {Number} tooltipTargetHeight - The height of the tooltip's target - * @returns {Boolean} + * @param [tooltip] - The reference to the tooltip's root element + * @param tooltipTargetWidth - The width of the tooltip's target + * @param tooltipTargetHeight - The height of the tooltip's target */ -function isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetWidth, tooltipTargetHeight) { +function isOverlappingAtTop(tooltip: RefObject, xOffset: number, yOffset: number, tooltipTargetWidth: number, tooltipTargetHeight: number) { if (typeof document.elementFromPoint !== 'function') { return false; } @@ -79,10 +79,9 @@ function isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetWidth, toolt // in case the target has a border radius or is a multiline text. const targetCenterX = xOffset + tooltipTargetWidth / 2; const elementAtTargetCenterX = document.elementFromPoint(targetCenterX, yOffset); - const tooltipRef = (tooltip && tooltip.current) || tooltip; // Ensure it's not the already rendered element of this very tooltip, so the tooltip doesn't try to "avoid" itself - if (!elementAtTargetCenterX || (tooltipRef && tooltipRef.contains(elementAtTargetCenterX))) { + if (!elementAtTargetCenterX) { return false; } @@ -95,42 +94,49 @@ function isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetWidth, toolt return isOverlappingAtTargetCenterX; } +type TooltipStyles = { + animationStyle: ViewStyle; + rootWrapperStyle: Omit | Pick; + textStyle: TextStyle; + pointerWrapperStyle: Omit | Pick; + pointerStyle: ViewStyle; +}; + /** * Generate styles for the tooltip component. * - * @param {Number} currentSize - The current size of the tooltip used in the scaling animation. - * @param {Number} windowWidth - The width of the window. - * @param {Number} xOffset - The distance between the left edge of the window + * @param tooltip - The reference to the tooltip's root element + * @param currentSize - The current size of the tooltip used in the scaling animation. + * @param windowWidth - The width of the window. + * @param xOffset - The distance between the left edge of the window * and the left edge of the wrapped component. - * @param {Number} yOffset - The distance between the top edge of the window + * @param yOffset - The distance between the top edge of the window * and the top edge of the wrapped component. - * @param {Number} tooltipTargetWidth - The width of the tooltip's target - * @param {Number} tooltipTargetHeight - The height of the tooltip's target - * @param {Number} maxWidth - The tooltip's max width. - * @param {Number} tooltipContentWidth - The tooltip's inner content measured width. - * @param {Number} tooltipWrapperHeight - The tooltip's wrapper measured height. - * @param {Number} [manualShiftHorizontal] - Any additional amount to manually shift the tooltip to the left or right. + * @param tooltipTargetWidth - The width of the tooltip's target + * @param tooltipTargetHeight - The height of the tooltip's target + * @param maxWidth - The tooltip's max width. + * @param tooltipContentWidth - The tooltip's inner content measured width. + * @param tooltipWrapperHeight - The tooltip's wrapper measured height. + * @param [manualShiftHorizontal] - Any additional amount to manually shift the tooltip to the left or right. * A positive value shifts it to the right, * and a negative value shifts it to the left. - * @param {Number} [manualShiftVertical] - Any additional amount to manually shift the tooltip up or down. + * @param [manualShiftVertical] - Any additional amount to manually shift the tooltip up or down. * A positive value shifts it down, and a negative value shifts it up. - * @param {Element} tooltip - The reference to the tooltip's root element - * @returns {Object} */ export default function getTooltipStyles( - currentSize, - windowWidth, - xOffset, - yOffset, - tooltipTargetWidth, - tooltipTargetHeight, - maxWidth, - tooltipContentWidth, - tooltipWrapperHeight, + tooltip: RefObject, + currentSize: number, + windowWidth: number, + xOffset: number, + yOffset: number, + tooltipTargetWidth: number, + tooltipTargetHeight: number, + maxWidth: number, + tooltipContentWidth: number, + tooltipWrapperHeight: number, manualShiftHorizontal = 0, manualShiftVertical = 0, - tooltip, -) { +): TooltipStyles { const tooltipVerticalPadding = spacing.pv1; // We calculate tooltip width based on the tooltip's content width @@ -141,7 +147,7 @@ export default function getTooltipStyles( const isTooltipSizeReady = tooltipWidth !== undefined && tooltipHeight !== undefined; - // Set the scale to 1 to be able to measure the toolip size correctly when it's not ready yet. + // Set the scale to 1 to be able to measure the tooltip size correctly when it's not ready yet. let scale = 1; let shouldShowBelow = false; let horizontalShift = 0; @@ -157,7 +163,7 @@ export default function getTooltipStyles( // If either a tooltip will try to render within GUTTER_WIDTH logical pixels of the top of the screen, // Or the wrapped component is overlapping at top-center with another element // we'll display it beneath its wrapped component rather than above it as usual. - shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(xOffset, yOffset, tooltip, tooltipTargetWidth, tooltipTargetHeight); + shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(tooltip, xOffset, yOffset, tooltipTargetWidth, tooltipTargetHeight); // When the tooltip size is ready, we can start animating the scale. scale = currentSize; From 5a3d97b4c32b563360281ad34570c1a5989c47f5 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 28 Aug 2023 12:31:13 +0200 Subject: [PATCH 2/5] Improve TooltipStyles types --- src/styles/getTooltipStyles.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/styles/getTooltipStyles.ts b/src/styles/getTooltipStyles.ts index bbc6ab9942e8..bf3091bc49b3 100644 --- a/src/styles/getTooltipStyles.ts +++ b/src/styles/getTooltipStyles.ts @@ -70,7 +70,7 @@ function computeHorizontalShift(windowWidth: number, xOffset: number, componentW * @param tooltipTargetWidth - The width of the tooltip's target * @param tooltipTargetHeight - The height of the tooltip's target */ -function isOverlappingAtTop(tooltip: RefObject, xOffset: number, yOffset: number, tooltipTargetWidth: number, tooltipTargetHeight: number) { +function isOverlappingAtTop(xOffset: number, yOffset: number, tooltipTargetWidth: number, tooltipTargetHeight: number) { if (typeof document.elementFromPoint !== 'function') { return false; } @@ -96,9 +96,9 @@ function isOverlappingAtTop(tooltip: RefObject, xOffset: number, yOffset: type TooltipStyles = { animationStyle: ViewStyle; - rootWrapperStyle: Omit | Pick; + rootWrapperStyle: ViewStyle | CSSProperties; textStyle: TextStyle; - pointerWrapperStyle: Omit | Pick; + pointerWrapperStyle: ViewStyle | CSSProperties; pointerStyle: ViewStyle; }; @@ -163,7 +163,7 @@ export default function getTooltipStyles( // If either a tooltip will try to render within GUTTER_WIDTH logical pixels of the top of the screen, // Or the wrapped component is overlapping at top-center with another element // we'll display it beneath its wrapped component rather than above it as usual. - shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(tooltip, xOffset, yOffset, tooltipTargetWidth, tooltipTargetHeight); + shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(xOffset, yOffset, tooltipTargetWidth, tooltipTargetHeight); // When the tooltip size is ready, we can start animating the scale. scale = currentSize; From 7c4ed797ce3a5676a9fb76489173caf6373922f0 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 28 Aug 2023 12:32:39 +0200 Subject: [PATCH 3/5] Remove unused variable --- src/components/Tooltip/TooltipRenderedOnPageBody.js | 1 - src/styles/getTooltipStyles.ts | 5 ++--- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/src/components/Tooltip/TooltipRenderedOnPageBody.js b/src/components/Tooltip/TooltipRenderedOnPageBody.js index 724a56162f86..67b3e39b264f 100644 --- a/src/components/Tooltip/TooltipRenderedOnPageBody.js +++ b/src/components/Tooltip/TooltipRenderedOnPageBody.js @@ -86,7 +86,6 @@ const TooltipRenderedOnPageBody = (props) => { const {animationStyle, rootWrapperStyle, textStyle, pointerWrapperStyle, pointerStyle} = useMemo( () => getTooltipStyles( - rootWrapper.current, props.animation, props.windowWidth, props.xOffset, diff --git a/src/styles/getTooltipStyles.ts b/src/styles/getTooltipStyles.ts index bf3091bc49b3..d96cfe12f346 100644 --- a/src/styles/getTooltipStyles.ts +++ b/src/styles/getTooltipStyles.ts @@ -1,5 +1,5 @@ -import {CSSProperties, RefObject} from 'react'; -import {TextStyle, View, ViewStyle} from 'react-native'; +import {CSSProperties} from 'react'; +import {TextStyle, ViewStyle} from 'react-native'; import spacing from './utilities/spacing'; import styles from './styles'; import colors from './colors'; @@ -124,7 +124,6 @@ type TooltipStyles = { * A positive value shifts it down, and a negative value shifts it up. */ export default function getTooltipStyles( - tooltip: RefObject, currentSize: number, windowWidth: number, xOffset: number, From 8f2a22c7c8ee62d5c8b35a9d3e71b311e8908d87 Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Mon, 28 Aug 2023 16:16:53 +0200 Subject: [PATCH 4/5] Improve types --- src/components/Tooltip/TooltipRenderedOnPageBody.js | 1 + src/styles/getTooltipStyles.ts | 9 +++++---- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/components/Tooltip/TooltipRenderedOnPageBody.js b/src/components/Tooltip/TooltipRenderedOnPageBody.js index 67b3e39b264f..724a56162f86 100644 --- a/src/components/Tooltip/TooltipRenderedOnPageBody.js +++ b/src/components/Tooltip/TooltipRenderedOnPageBody.js @@ -86,6 +86,7 @@ const TooltipRenderedOnPageBody = (props) => { const {animationStyle, rootWrapperStyle, textStyle, pointerWrapperStyle, pointerStyle} = useMemo( () => getTooltipStyles( + rootWrapper.current, props.animation, props.windowWidth, props.xOffset, diff --git a/src/styles/getTooltipStyles.ts b/src/styles/getTooltipStyles.ts index d96cfe12f346..5bdedbd7b0c0 100644 --- a/src/styles/getTooltipStyles.ts +++ b/src/styles/getTooltipStyles.ts @@ -1,5 +1,5 @@ import {CSSProperties} from 'react'; -import {TextStyle, ViewStyle} from 'react-native'; +import {TextStyle, View, ViewStyle} from 'react-native'; import spacing from './utilities/spacing'; import styles from './styles'; import colors from './colors'; @@ -70,7 +70,7 @@ function computeHorizontalShift(windowWidth: number, xOffset: number, componentW * @param tooltipTargetWidth - The width of the tooltip's target * @param tooltipTargetHeight - The height of the tooltip's target */ -function isOverlappingAtTop(xOffset: number, yOffset: number, tooltipTargetWidth: number, tooltipTargetHeight: number) { +function isOverlappingAtTop(tooltip: View | HTMLDivElement, xOffset: number, yOffset: number, tooltipTargetWidth: number, tooltipTargetHeight: number) { if (typeof document.elementFromPoint !== 'function') { return false; } @@ -81,7 +81,7 @@ function isOverlappingAtTop(xOffset: number, yOffset: number, tooltipTargetWidth const elementAtTargetCenterX = document.elementFromPoint(targetCenterX, yOffset); // Ensure it's not the already rendered element of this very tooltip, so the tooltip doesn't try to "avoid" itself - if (!elementAtTargetCenterX) { + if (!elementAtTargetCenterX || ('contains' in tooltip && tooltip.contains(elementAtTargetCenterX))) { return false; } @@ -124,6 +124,7 @@ type TooltipStyles = { * A positive value shifts it down, and a negative value shifts it up. */ export default function getTooltipStyles( + tooltip: View | HTMLDivElement, currentSize: number, windowWidth: number, xOffset: number, @@ -162,7 +163,7 @@ export default function getTooltipStyles( // If either a tooltip will try to render within GUTTER_WIDTH logical pixels of the top of the screen, // Or the wrapped component is overlapping at top-center with another element // we'll display it beneath its wrapped component rather than above it as usual. - shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(xOffset, yOffset, tooltipTargetWidth, tooltipTargetHeight); + shouldShowBelow = yOffset - tooltipHeight < GUTTER_WIDTH || isOverlappingAtTop(tooltip, xOffset, yOffset, tooltipTargetWidth, tooltipTargetHeight); // When the tooltip size is ready, we can start animating the scale. scale = currentSize; From 21320d3ec78fbbbe340cf65e7d37a0938bb6af1a Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Thu, 7 Sep 2023 10:06:43 +0200 Subject: [PATCH 5/5] Fix isOverlappingAtTop JSDoc --- src/styles/getTooltipStyles.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/styles/getTooltipStyles.ts b/src/styles/getTooltipStyles.ts index 5bdedbd7b0c0..3f9de9c78b97 100644 --- a/src/styles/getTooltipStyles.ts +++ b/src/styles/getTooltipStyles.ts @@ -62,11 +62,11 @@ function computeHorizontalShift(windowWidth: number, xOffset: number, componentW * | | * |_ _ _ _ _| * + * @param tooltip - The reference to the tooltip's root element * @param xOffset - The distance between the left edge of the window * and the left edge of the wrapped component. * @param yOffset - The distance between the top edge of the window * and the top edge of the wrapped component. - * @param [tooltip] - The reference to the tooltip's root element * @param tooltipTargetWidth - The width of the tooltip's target * @param tooltipTargetHeight - The height of the tooltip's target */