44 */
55const BLOB_PADDING_TOP = 8
66
7- /**
8- * Calculates the desired position of the hover overlay depending on the container,
9- * the hover target and the size of the hover overlay
10- *
11- * @param scrollable The closest container that is scrollable
12- * @param target The DOM Node that was hovered
13- * @param tooltip The DOM Node of the tooltip
14- */
15- export const calculateOverlayPosition = (
7+ const calculateOverlayPositionWithinScrollable = (
168 scrollable : HTMLElement ,
179 target : HTMLElement ,
1810 tooltip : HTMLElement
@@ -25,18 +17,68 @@ export const calculateOverlayPosition = (
2517 // changes to vertical height if the tooltip is at the edge of the viewport.
2618 const relLeft = targetBound . left - scrollableBounds . left
2719
20+ const scrollTop = scrollable === document . documentElement ? window . pageYOffset : scrollable . scrollTop
21+
2822 // Anchor the tooltip vertically.
2923 const tooltipBound = tooltip . getBoundingClientRect ( )
30- const relTop = targetBound . top + scrollable . scrollTop - scrollableBounds . top
24+ const relTop = targetBound . top + scrollTop - scrollableBounds . top
3125 // This is the padding-top of the blob element
3226 let tooltipTop = relTop - ( tooltipBound . height - BLOB_PADDING_TOP )
33- if ( tooltipTop - scrollable . scrollTop < 0 ) {
27+ if ( tooltipTop - scrollTop < 0 ) {
3428 // Tooltip wouldn't be visible from the top, so display it at the
3529 // bottom.
36- const relBottom = targetBound . bottom + scrollable . scrollTop - scrollableBounds . top
30+ const relBottom = targetBound . bottom + scrollTop - scrollableBounds . top
3731 tooltipTop = relBottom
3832 } else {
3933 tooltipTop -= BLOB_PADDING_TOP
4034 }
4135 return { left : relLeft , top : tooltipTop }
4236}
37+
38+ const calculateOverlayPositionWithoutScrollable = (
39+ container : HTMLElement ,
40+ target : HTMLElement ,
41+ tooltip : HTMLElement
42+ ) : { left : number ; top : number } => {
43+ const containerBound = container . getBoundingClientRect ( )
44+
45+ // Anchor it horizontally, prior to rendering to account for wrapping
46+ // changes to vertical height if the tooltip is at the edge of the viewport.
47+ const targetBound = target . getBoundingClientRect ( )
48+ const tooltipLeft = targetBound . left - containerBound . left + window . scrollX
49+
50+ // Anchor the tooltip vertically.
51+ const tooltipBound = tooltip . getBoundingClientRect ( )
52+ const relTop = targetBound . top - containerBound . top + container . offsetTop
53+
54+ let tooltipTop = relTop - tooltipBound . height
55+ if ( tooltipTop - window . scrollY < 0 ) {
56+ // Tooltip wouldn't be visible from the top, so display it at the bottom.
57+ const relBottom = relTop + targetBound . height
58+ tooltipTop = relBottom
59+ }
60+
61+ return { top : tooltipTop , left : tooltipLeft }
62+ }
63+
64+ /**
65+ * Calculates the desired position of the hover overlay depending on the container,
66+ * the hover target and the size of the hover overlay
67+ *
68+ * @param container The container. If the code view is scrollable, it's the scrollable element, otherwise its the codeView itself.
69+ * @param target The DOM Node that was hovered.
70+ * @param tooltip The DOM Node of the tooltip.
71+ * @param isScrollable Whether the code view is scrollable or not.
72+ */
73+ export const calculateOverlayPosition = (
74+ container : HTMLElement ,
75+ target : HTMLElement ,
76+ tooltip : HTMLElement ,
77+ isScrollable ?: boolean
78+ ) : { left : number ; top : number } => {
79+ if ( isScrollable ) {
80+ return calculateOverlayPositionWithinScrollable ( container , target , tooltip )
81+ }
82+
83+ return calculateOverlayPositionWithoutScrollable ( container , target , tooltip )
84+ }
0 commit comments