Skip to content

Commit 12bcbbd

Browse files
author
Dominik Dosoudil
committed
refactor(popup): Move hideOnScroll feature to Portal component to get rid of hacky timout that causes remounting Portal component.
1 parent 53e0d7e commit 12bcbbd

File tree

3 files changed

+40
-52
lines changed

3 files changed

+40
-52
lines changed

src/addons/Portal/Portal.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ export interface StrictPortalProps {
3737
/** Event pool namespace that is used to handle component events. */
3838
eventPool?: string
3939

40+
/** Hide the Popup when scrolling the window. */
41+
hideOnScroll?: boolean
42+
4043
/** The node where the portal should mount. */
4144
mountNode?: any
4245

src/addons/Portal/Portal.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ function Portal(props) {
3838
openOnTriggerClick = true,
3939
openOnTriggerFocus,
4040
openOnTriggerMouseEnter,
41+
hideOnScroll = false,
4142
} = props
4243

4344
const [open, setOpen] = useAutoControlledValue({
@@ -146,6 +147,33 @@ function Portal(props) {
146147
// Component Event Handlers
147148
// ----------------------------------------
148149

150+
React.useEffect(() => {
151+
if (!hideOnScroll) {
152+
return
153+
}
154+
const abortController = new AbortController()
155+
156+
window.addEventListener(
157+
'scroll',
158+
(e) => {
159+
debug('handleHideOnScroll()')
160+
161+
// Do not hide the popup when scroll comes from inside the popup
162+
// https://github.com/Semantic-Org/Semantic-UI-React/issues/4305
163+
if (_.isElement(e.target) && contentRef.current.contains(e.target)) {
164+
return
165+
}
166+
167+
closePortal(e)
168+
},
169+
{ signal: abortController.signal, passive: true },
170+
)
171+
172+
return () => {
173+
abortController.abort()
174+
}
175+
}, [closePortal, hideOnScroll])
176+
149177
const handlePortalMouseLeave = (e) => {
150178
if (!closeOnPortalMouseLeave) {
151179
return
@@ -318,6 +346,9 @@ Portal.propTypes = {
318346
/** Event pool namespace that is used to handle component events */
319347
eventPool: PropTypes.string,
320348

349+
/** Hide the Popup when scrolling the window. */
350+
hideOnScroll: PropTypes.bool,
351+
321352
/** The node where the portal should mount. */
322353
mountNode: PropTypes.any,
323354

src/modules/Popup/Popup.js

Lines changed: 6 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -71,11 +71,10 @@ function getPortalProps(props) {
7171
* Splits props for Portal & Popup.
7272
*
7373
* @param {Object} unhandledProps
74-
* @param {Boolean} closed
7574
* @param {Boolean} disabled
7675
*/
77-
function partitionPortalProps(unhandledProps, closed, disabled) {
78-
if (closed || disabled) {
76+
function partitionPortalProps(unhandledProps, disabled) {
77+
if (disabled) {
7978
return {}
8079
}
8180

@@ -123,7 +122,7 @@ const Popup = React.forwardRef(function (props, ref) {
123122
eventsEnabled = true,
124123
flowing,
125124
header,
126-
hideOnScroll,
125+
hideOnScroll = false,
127126
inverted,
128127
offset,
129128
pinned = false,
@@ -138,18 +137,11 @@ const Popup = React.forwardRef(function (props, ref) {
138137
wide,
139138
} = props
140139

141-
const [closed, setClosed] = React.useState(false)
142-
143140
const unhandledProps = getUnhandledProps(Popup, props)
144-
const { contentRestProps, portalRestProps } = partitionPortalProps(
145-
unhandledProps,
146-
closed,
147-
disabled,
148-
)
141+
const { contentRestProps, portalRestProps } = partitionPortalProps(unhandledProps, disabled)
149142

150143
const elementRef = useMergedRefs(ref)
151144
const positionUpdate = React.useRef()
152-
const timeoutId = React.useRef()
153145
const triggerRef = React.useRef()
154146
const zIndexWasSynced = React.useRef(false)
155147

@@ -159,12 +151,6 @@ const Popup = React.forwardRef(function (props, ref) {
159151

160152
usePositioningEffect(popperDependencies, positionUpdate)
161153

162-
React.useEffect(() => {
163-
return () => {
164-
clearTimeout(timeoutId.current)
165-
}
166-
}, [])
167-
168154
// ----------------------------------------
169155
// Handlers
170156
// ----------------------------------------
@@ -179,39 +165,6 @@ const Popup = React.forwardRef(function (props, ref) {
179165
_.invoke(props, 'onOpen', e, { ...props, open: true })
180166
}
181167

182-
React.useEffect(() => {
183-
if (!hideOnScroll || closed || disabled) {
184-
return
185-
}
186-
const abortController = new AbortController()
187-
188-
window.addEventListener(
189-
'scroll',
190-
(e) => {
191-
debug('handleHideOnScroll()')
192-
193-
// Do not hide the popup when scroll comes from inside the popup
194-
// https://github.com/Semantic-Org/Semantic-UI-React/issues/4305
195-
if (_.isElement(e.target) && elementRef.current.contains(e.target)) {
196-
return
197-
}
198-
199-
setClosed(true)
200-
201-
timeoutId.current = setTimeout(() => {
202-
setClosed(false)
203-
}, 50)
204-
205-
handleClose(e)
206-
},
207-
{ signal: abortController.signal },
208-
)
209-
210-
return () => {
211-
abortController.abort()
212-
}
213-
}, [closed, disabled, elementRef, handleClose, hideOnScroll])
214-
215168
const handlePortalMount = (e) => {
216169
debug('handlePortalMount()')
217170
_.invoke(props, 'onMount', e, props)
@@ -289,7 +242,7 @@ const Popup = React.forwardRef(function (props, ref) {
289242
})
290243
}
291244

292-
if (closed || disabled) {
245+
if (disabled) {
293246
return trigger
294247
}
295248

@@ -348,6 +301,7 @@ const Popup = React.forwardRef(function (props, ref) {
348301
onUnmount={handlePortalUnmount}
349302
trigger={trigger}
350303
triggerRef={triggerRef}
304+
hideOnScroll={hideOnScroll}
351305
>
352306
<Popper
353307
modifiers={modifiers}

0 commit comments

Comments
 (0)