Skip to content
This repository was archived by the owner on Sep 26, 2024. It is now read-only.

Commit a9156e8

Browse files
committed
Important bugfix: prevent events from bubbling up to leaflet
There are interaction issues around combining React and "native" javascript components. We want to prevent events (eg double-click) on the sidebar from interacting with the underlying leaflet map. However, we can't just add onDoubleClick to our react markup, because React synthesises events by installing a single global event handler at the document, by which time they have already been caught by leaflet. So, we need to attach native javascript handlers for everything we want to stop bubbling up.
1 parent 9089979 commit a9156e8

File tree

1 file changed

+33
-1
lines changed

1 file changed

+33
-1
lines changed

src/Sidebar.js

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,19 @@ class Tab extends React.Component {
3333
}
3434
}
3535

36+
// We need to prevent *native* events bubbling up to leaflet. React
37+
// attaches a global event handler to the document, so using
38+
// stopPropagation on a React synthetic event has no effect because it
39+
// has already been caught by leaflet. Note the ref on our root
40+
// element.
41+
// We don't ignore 'click', because then our onOpen/Close handlers wouldn't work!
42+
const ignoreEvents = ['dblclick',
43+
'mouseover', 'mouseout', 'mousedown', 'mouseup', 'mousemove', 'wheel',
44+
'pointerdown', 'pointermove', 'pointerup',
45+
'MSPointerDown', 'MSPointerMove', 'MSPointerUp',
46+
'touchdown', 'touchmove', 'touchup',
47+
'dragstart', 'drag', 'dragend'];
48+
3649
// https://github.com/facebook/react/issues/2979#issuecomment-222379916
3750
const TabType = PropTypes.shape({
3851
type: PropTypes.oneOf([Tab])
@@ -53,6 +66,11 @@ class Sidebar extends MapComponent<LeafletElement, Props> {
5366
]).isRequired,
5467
}
5568

69+
constructor(props) {
70+
super(props);
71+
this.ignoreEvent = this.ignoreEvent.bind(this);
72+
}
73+
5674
onClose(e) {
5775
e.preventDefault();
5876
e.stopPropagation();
@@ -65,6 +83,19 @@ class Sidebar extends MapComponent<LeafletElement, Props> {
6583
this.props.onOpen && this.props.onOpen(tabid);
6684
}
6785

86+
ignoreEvent(e) {
87+
e.stopPropagation();
88+
e.preventDefault();
89+
}
90+
91+
componentDidMount() {
92+
ignoreEvents.forEach(e => this.rootElement.addEventListener(e, this.ignoreEvent));
93+
}
94+
95+
componentWillUnmount() {
96+
ignoreEvents.forEach(e => this.rootElement.removeEventListener(e, this.ignoreEvent));
97+
}
98+
6899
renderTab(tab) {
69100
var icon;
70101
if (typeof(tab.props.icon) === 'function')
@@ -99,7 +130,8 @@ class Sidebar extends MapComponent<LeafletElement, Props> {
99130
const bottomtabs = tabs.filter(t => t.props.anchor === 'bottom');
100131
const toptabs = tabs.filter(t => t.props.anchor !== 'bottom');
101132
return (
102-
<div id="sidebar" className={"sidebar leaflet-touch" + position + collapsed}>
133+
<div id={this.props.id} className={"sidebar leaflet-touch" + position + collapsed}
134+
ref={el => this.rootElement = el}>
103135
<div className="sidebar-tabs">
104136
<ul role="tablist"> {/* Top-aligned */}
105137
{toptabs.map(t => this.renderTab(t))}

0 commit comments

Comments
 (0)