Skip to content

Commit fdbb517

Browse files
committed
fix: make sure DOM handlers work properly
1 parent 675b103 commit fdbb517

File tree

4 files changed

+113
-53
lines changed

4 files changed

+113
-53
lines changed

demo/src/regressions/Regressions.js

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

33
import ButtonOverlay from './ButtonOverlay'
4-
import SameWidth from './SameWidth'
5-
import StickNodeWidth from './StickNodeWidth'
64
import FitOnPage from './FitOnPage'
5+
import SameWidth from './SameWidth'
76
import StickInSvg from './StickInSvg'
7+
import StickNodeWidth from './StickNodeWidth'
8+
import StickOnHover from './StickOnHover'
89
import StyledWithDataAttributes from './StyledWithDataAttributes'
910
import TransportToFixedContainer from './TransportToFixedContainer'
1011

@@ -20,6 +21,7 @@ export default function Regressions() {
2021
<StickInSvg />
2122
<StyledWithDataAttributes />
2223
<TransportToFixedContainer />
24+
<StickOnHover />
2325
</div>
2426
)
2527
}
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import { range } from 'lodash'
2+
import React, { useState } from 'react'
3+
4+
import Stick from '../../../es'
5+
import Regression from './Regression'
6+
7+
function StickOnHover() {
8+
return (
9+
<Regression
10+
allBrowsers
11+
fixed
12+
version="3.0.3"
13+
title="Node does not unmount on mouse leave"
14+
description="Move your mouse over the squares. When you're hovering one another node should be shown. However, there should always only be one node at the same time."
15+
>
16+
<div style={{ display: 'flex', flexWrap: 'wrap' }}>
17+
{range(100).map(i => (
18+
<div key={i} style={{ marginLeft: 20, marginBottom: 20 }}>
19+
<Popover />
20+
</div>
21+
))}
22+
</div>
23+
</Regression>
24+
)
25+
}
26+
27+
function Popover() {
28+
const [hover, setHover] = useState(false)
29+
30+
return (
31+
<Stick
32+
position="top center"
33+
node={hover && <Node />}
34+
onMouseEnter={() => setHover(true)}
35+
onMouseLeave={() => setHover(false)}
36+
>
37+
<Anchor />
38+
</Stick>
39+
)
40+
}
41+
42+
const Anchor = () => (
43+
<div
44+
style={{
45+
height: 30,
46+
width: 30,
47+
backgroundColor: 'rgb(24, 170, 177)'
48+
}}
49+
/>
50+
)
51+
52+
const Node = ({ children }) => (
53+
<div
54+
style={{
55+
backgroundColor: '#ae0d5c',
56+
width: 10,
57+
height: 10
58+
}}
59+
>
60+
{children}
61+
</div>
62+
)
63+
64+
export default StickOnHover

src/Stick.js

Lines changed: 27 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import React, {
88
useContext,
99
useEffect,
1010
useRef,
11-
useState,
11+
useState
1212
} from 'react'
1313
import { type HOC } from 'recompose'
1414
import { type Substyle, defaultStyle } from 'substyle'
@@ -25,7 +25,7 @@ import { getDefaultAlign, getModifiers, scrollX, uniqueId } from './utils'
2525
type PropsT = {|
2626
...ApiPropsT,
2727

28-
style: Substyle,
28+
style: Substyle
2929
|}
3030

3131
function Stick({
@@ -132,18 +132,6 @@ function Stick({
132132
}
133133
}, [checkAlignment])
134134

135-
if (!node) {
136-
const Component = component || 'div'
137-
138-
return (
139-
<StickContext.Provider value={nestingKey}>
140-
<Component {...resolvedStyle} {...rest}>
141-
{children}
142-
</Component>
143-
</StickContext.Provider>
144-
)
145-
}
146-
147135
if (inline) {
148136
return (
149137
<StickContext.Provider value={nestingKey}>
@@ -153,15 +141,17 @@ function Stick({
153141
align={resolvedAlign}
154142
style={resolvedStyle}
155143
node={
156-
<StickNode
157-
width={width}
158-
position={resolvedPosition}
159-
align={resolvedAlign}
160-
sameWidth={!!sameWidth}
161-
nodeRef={nodeRef}
162-
>
163-
{node}
164-
</StickNode>
144+
node && (
145+
<StickNode
146+
width={width}
147+
position={resolvedPosition}
148+
align={resolvedAlign}
149+
sameWidth={!!sameWidth}
150+
nodeRef={nodeRef}
151+
>
152+
{node}
153+
</StickNode>
154+
)
165155
}
166156
nestingKey={nestingKey}
167157
containerRef={node => {
@@ -193,15 +183,17 @@ function Stick({
193183
}}
194184
position={resolvedPosition}
195185
node={
196-
<StickNode
197-
width={width}
198-
position={resolvedPosition}
199-
align={resolvedAlign}
200-
sameWidth={!!sameWidth}
201-
nodeRef={nodeRef}
202-
>
203-
{node}
204-
</StickNode>
186+
node && (
187+
<StickNode
188+
width={width}
189+
position={resolvedPosition}
190+
align={resolvedAlign}
191+
sameWidth={!!sameWidth}
192+
nodeRef={nodeRef}
193+
>
194+
{node}
195+
</StickNode>
196+
)
205197
}
206198
style={resolvedStyle}
207199
nestingKey={nestingKey}
@@ -261,7 +253,7 @@ function calculateWidth(
261253
const positionAdjustments = {
262254
left,
263255
center: left + width / 2,
264-
right,
256+
right
265257
}
266258

267259
const absLeft = scrollX(anchorRef) + positionAdjustments[horizontalPosition]
@@ -286,8 +278,8 @@ const styled: HOC<*, ApiPropsT> = defaultStyle(
286278
node: {
287279
position: 'absolute',
288280
zIndex: 99,
289-
textAlign: 'left',
290-
},
281+
textAlign: 'left'
282+
}
291283
},
292284
getModifiers
293285
)

src/StickPortal.js

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
// @flow
22
import 'requestidlecallback'
33

4+
import invariant from 'invariant'
45
import React, {
56
createContext,
67
forwardRef,
78
useCallback,
89
useContext,
910
useEffect,
11+
useLayoutEffect,
1012
useRef,
11-
useState,
13+
useState
1214
} from 'react'
1315
import { createPortal } from 'react-dom'
1416

@@ -36,14 +38,24 @@ function StickPortal(
3638
const [top, setTop] = useState(0)
3739
const [left, setLeft] = useState(0)
3840

39-
const host = useHost(transportTo)
41+
const [host, hostParent] = useHost(transportTo)
4042

4143
useEffect(() => {
4244
if (nodeRef.current) {
4345
onReposition(nodeRef.current)
4446
}
4547
}, [onReposition, top, left])
4648

49+
useLayoutEffect(() => {
50+
if (node) {
51+
hostParent.appendChild(host)
52+
53+
return () => {
54+
hostParent.removeChild(host)
55+
}
56+
}
57+
}, [host, hostParent, node])
58+
4759
const measure = useCallback(() => {
4860
if (!nodeRef.current) {
4961
return
@@ -101,7 +113,7 @@ function StickPortal(
101113
// $FlowFixMe
102114
...nodeStyle,
103115
top,
104-
left,
116+
left
105117
}}
106118
>
107119
{node}
@@ -122,21 +134,11 @@ function useHost(transportTo) {
122134

123135
const portalHost = useContext(PortalContext)
124136

125-
useEffect(() => {
126-
const hostParent = transportTo || portalHost || document.body
137+
const hostParent = transportTo || portalHost || document.body
127138

128-
if (hostParent) {
129-
hostParent.appendChild(host)
130-
}
131-
132-
return () => {
133-
if (hostParent) {
134-
hostParent.removeChild(host)
135-
}
136-
}
137-
}, [host, portalHost, transportTo])
139+
invariant(hostParent, 'Could not determine a parent for the host node.')
138140

139-
return host
141+
return [host, hostParent]
140142
}
141143

142144
function calculateTop(

0 commit comments

Comments
 (0)