Skip to content

Commit b49a9b7

Browse files
Afterall, we can solve it :)
1 parent a004b70 commit b49a9b7

File tree

4 files changed

+45
-23
lines changed

4 files changed

+45
-23
lines changed

docs/src/pages/components/click-away-listener/click-away-listener.md

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -17,22 +17,3 @@ For instance, if you need to hide a menu dropdown when people click anywhere els
1717

1818
Notice that the component only accepts one child element.
1919
You can find a more advanced demo on the [Menu documentation section](/components/menus/#menulist-composition).
20-
21-
## Limitations
22-
23-
If a page contains an element/component that gets removed from DOM when clicked, the `ClickAwayListener` will not be able to raise the `onClickAway` event due to a check trying to prevent raising the event for already removed `ClickAwayListener` children.
24-
25-
The workaround for this is to either use css/style to hide the clicked element or delay the removal of the element.
26-
Check the example below
27-
28-
```jsx
29-
// Instead of removing from DOM
30-
{showButton && (<Button onClick={handleClick}>
31-
Click to hide
32-
</Button>)}
33-
34-
// Use styles prop
35-
<Button style={showButton ? { display: 'block' } : { display: 'none' }} onClick={handleClick}>
36-
Click to hide
37-
</Button>)
38-
```

packages/material-ui/src/ClickAwayListener/ClickAwayListener.js

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,10 +63,20 @@ const ClickAwayListener = React.forwardRef(function ClickAwayListener(props, ref
6363
return;
6464
}
6565

66-
// Multi window support
67-
const doc = ownerDocument(nodeRef.current);
66+
let insideDOM;
6867

69-
if (doc.documentElement.contains(event.target) && !nodeRef.current.contains(event.target)) {
68+
// If not enough, can use https://github.com/DieterHolvoet/event-propagation-path/blob/master/propagationPath.js
69+
if (event.composedPath) {
70+
insideDOM = event.composedPath().indexOf(nodeRef.current) > -1;
71+
} else {
72+
const doc = ownerDocument(nodeRef.current);
73+
// TODO v6 remove dead logic https://caniuse.com/#search=composedPath.
74+
insideDOM =
75+
!(doc.documentElement && doc.documentElement.contains(event.target)) ||
76+
nodeRef.current.contains(event.target);
77+
}
78+
79+
if (!insideDOM) {
7080
onClickAway(event);
7181
}
7282
});

packages/material-ui/src/ClickAwayListener/ClickAwayListener.test.js

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,4 +140,34 @@ describe('<ClickAwayListener />', () => {
140140
fireEvent.click(document.body);
141141
expect(handleClickAway.callCount).to.equal(0);
142142
});
143+
144+
it.only('should support removed element child', () => {
145+
const Demo = () => {
146+
const [visible, setVisible] = React.useState(true);
147+
148+
console.log('visible', visible);
149+
150+
return visible ? (
151+
<button
152+
type="button"
153+
onClick={() => {
154+
setVisible(false);
155+
}}
156+
>
157+
Will be removed from DOM
158+
</button>
159+
) : null;
160+
};
161+
const handleClickAway = spy();
162+
const { getByText } = render(
163+
<div>
164+
<Demo />
165+
<ClickAwayListener onClickAway={handleClickAway}>
166+
<div />
167+
</ClickAwayListener>
168+
</div>,
169+
);
170+
fireEvent.click(getByText('Will be removed from DOM'));
171+
expect(handleClickAway.callCount).to.equal(1);
172+
});
143173
});

packages/material-ui/src/Tooltip/Tooltip.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -444,6 +444,7 @@ const Tooltip = React.forwardRef(function Tooltip(props, ref) {
444444
...other,
445445
...children.props,
446446
className: clsx(other.className, children.props.className),
447+
ref: handleRef,
447448
};
448449

449450
const interactiveWrapperListeners = {};
@@ -502,7 +503,7 @@ const Tooltip = React.forwardRef(function Tooltip(props, ref) {
502503

503504
return (
504505
<React.Fragment>
505-
{React.cloneElement(children, { ref: handleRef, ...childrenProps })}
506+
{React.cloneElement(children, childrenProps)}
506507
<Popper
507508
className={clsx(classes.popper, {
508509
[classes.popperInteractive]: interactive,

0 commit comments

Comments
 (0)