Skip to content

Commit 6888a17

Browse files
committed
fix: issues with ResizeObserver
1 parent 0eeeddf commit 6888a17

File tree

6 files changed

+201
-195
lines changed

6 files changed

+201
-195
lines changed

examples/simple/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"private": true,
33
"scripts": {
4-
"start": "rescripts start",
5-
"build": "rescripts build",
4+
"start": "SKIP_PREFLIGHT_CHECK=true rescripts start",
5+
"build": "SKIP_PREFLIGHT_CHECK=true rescripts build",
66
"test": "rescripts test",
77
"eject": "rescripts eject",
88
"serve": "serve build -s -p 3001"

src/components/Cursors.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -69,8 +69,12 @@ export default function Cursors<TDatum>() {
6969

7070
return (
7171
<>
72-
{resolvedPrimaryOptions.show && <Cursor primary options={resolvedPrimaryOptions} />}
73-
{resolvedSecondaryOptions.show && <Cursor options={resolvedSecondaryOptions} />}
72+
{resolvedPrimaryOptions.show && (
73+
<Cursor primary options={resolvedPrimaryOptions} />
74+
)}
75+
{resolvedSecondaryOptions.show && (
76+
<Cursor options={resolvedSecondaryOptions} />
77+
)}
7478
</>
7579
)
7680
}

src/components/Tooltip.tsx

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -82,25 +82,21 @@ export default function Tooltip<TDatum>(): React.ReactPortal | null {
8282
const width = anchorRect.width ?? 0
8383
const height = anchorRect.height ?? 0
8484

85-
const box = {
86-
x: translateY,
87-
y: translateX,
88-
top: translateY,
89-
left: translateX,
90-
bottom: translateY + width,
91-
right: translateX + height,
92-
width: width,
93-
height: height,
94-
toJSON: () => ({} as DOMRect),
95-
}
96-
97-
box.toJSON = () => box
98-
99-
return {
100-
getBoundingClientRect: () => {
101-
return box
102-
},
103-
}
85+
const el = document.createElement('div')
86+
87+
el.getBoundingClientRect = () =>
88+
({
89+
x: translateX,
90+
y: translateY,
91+
width: width,
92+
height: height,
93+
top: translateY,
94+
left: translateX,
95+
bottom: translateY + width,
96+
right: translateX + height,
97+
} as any)
98+
99+
return el
104100
}, [latestFocusedDatum?.element, svgRect])
105101

106102
const anchor = useAnchor({

src/hooks/useAnchor.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import React from 'react'
22

3-
import useRect, { HasBoundingClientRect } from './useRect'
3+
import useRect from './useRect'
44

55
//
66

@@ -76,9 +76,9 @@ export function useAnchor(options: {
7676
show: boolean
7777
useLargest?: boolean
7878
side: SideOption | SideOption[]
79-
portalEl: HasBoundingClientRect | null | undefined
80-
anchorEl: HasBoundingClientRect | null | undefined
81-
tooltipEl: HasBoundingClientRect | null | undefined
79+
portalEl: Element | null | undefined
80+
anchorEl: Element | null | undefined
81+
tooltipEl: Element | null | undefined
8282
}) {
8383
const portalDims = useRect(options.portalEl, options.show)
8484
const anchorDims = useRect(options.anchorEl, options.show)

src/hooks/useRect.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,53 +1,59 @@
11
import React from 'react'
22

3-
import useIsomorphicLayoutEffect from './useIsomorphicLayoutEffect'
4-
5-
export type HasBoundingClientRect = {
6-
getBoundingClientRect: () => DOMRect
7-
}
8-
93
export default function useRect(
10-
node: HasBoundingClientRect | null | undefined,
4+
element: Element | null | undefined,
115
enabled: boolean
126
) {
13-
const [element, setElement] = React.useState(node)
7+
const rerender = React.useReducer(() => ({}), [])[1]
148

15-
let [rect, setRect] = React.useState<DOMRect>({
16-
width: 0,
17-
height: 0,
18-
} as DOMRect)
9+
const rectRef = React.useRef<DOMRect>()
1910

20-
const rectRef = React.useRef(rect)
11+
const measure = React.useCallback(() => {
12+
if (element) {
13+
rectRef.current = element.getBoundingClientRect()
14+
}
15+
}, [element])
16+
17+
if (!rectRef.current) {
18+
measure()
19+
}
2120

22-
rectRef.current = rect
21+
React.useEffect(() => {
22+
if (!element || !enabled) {
23+
return
24+
}
2325

24-
useIsomorphicLayoutEffect(() => {
25-
if (node !== element) {
26-
setElement(node)
26+
const cb = () => {
27+
measure()
28+
rerender()
2729
}
28-
})
2930

30-
useIsomorphicLayoutEffect(() => {
31-
if (enabled && element) {
32-
setRect(element.getBoundingClientRect())
31+
document.addEventListener('scroll', cb)
32+
33+
return () => {
34+
document.removeEventListener('scroll', cb)
3335
}
34-
}, [element, enabled])
36+
}, [element, enabled, measure, rerender])
3537

3638
React.useEffect(() => {
3739
if (!element || !enabled) {
3840
return
3941
}
4042

41-
const observer = new ResizeObserver((entries) => {
42-
setRect(entries[0]?.contentRect)
43+
measure()
44+
rerender()
45+
46+
const observer = new ResizeObserver(entries => {
47+
measure()
48+
rerender()
4349
})
4450

4551
observer.observe(element as Element)
4652

4753
return () => {
4854
observer.unobserve(element as Element)
4955
}
50-
}, [element, enabled])
56+
}, [element, enabled, measure, rerender])
5157

5258
// const resolvedRect = React.useMemo(() => {
5359
// if (!element || !(element as Element).tagName) {
@@ -74,5 +80,5 @@ export default function useRect(
7480
// }
7581
// }, [element, rect])
7682

77-
return rect
83+
return rectRef.current
7884
}

0 commit comments

Comments
 (0)