@samitouri / QOS-React / commits / 2fc03eb151

Fixed keyboard/mouse events inside of extension by using ref.ownerDocument

Brian Vaughn committed Mar 18, 2019 at 15:11 UTC 2fc03eb151758917c0666c971ab89861fdcc9755
4 files changed +52 -19
src/devtools/views/Elements/SearchInput.js
+12 -3
@@ -52,19 +52,28 @@ export default function SearchInput(props: Props) {
52
53 // Auto-focus search input
54 useEffect(() => {
55 - const handleWindowKeyDown = event => {
55 + if (inputRef.current === null) {
56 + return () => {};
57 + }
58 +
59 + const handleWindowKey = (event: KeyboardEvent) => {
60 const { key, metaKey } = event;
61 if (key === 'f' && metaKey) {
62 if (inputRef.current !== null) {
63 inputRef.current.focus();
64 event.preventDefault();
65 + event.stopPropagation();
66 }
67 }
68 };
69
65 - window.addEventListener('keydown', handleWindowKeyDown);
70 + // It's important to listen to the ownerDocument to support the browser extension.
71 + // Here we use portals to render individual tabs (e.g. Profiler),
72 + // and the root document might belong to a different window.
73 + const ownerDocument = inputRef.current.ownerDocument;
74 + ownerDocument.addEventListener('keydown', handleWindowKey);
75
67 - return () => window.removeEventListener('keydown', handleWindowKeyDown);
76 + return () => ownerDocument.removeEventListener('keydown', handleWindowKey);
77 }, [inputRef]);
78
79 return (
src/devtools/views/Elements/Tree.js
+13 -4
@@ -32,6 +32,7 @@ export default function Tree(props: Props) {
32 selectPreviousElementInTree,
33 } = useContext(TreeContext);
34 const listRef = useRef<FixedSizeList<any> | null>(null);
35 + const treeRef = useRef<HTMLDivElement | null>(null);
36
37 const { lineHeight } = useContext(SettingsContext);
38
@@ -45,7 +46,11 @@ export default function Tree(props: Props) {
46
47 // Navigate the tree with up/down arrow keys.
48 useEffect(() => {
48 - const handleKeyDown = event => {
49 + if (treeRef.current === null) {
50 + return () => {};
51 + }
52 +
53 + const handleKeyDown = (event: KeyboardEvent) => {
54 // eslint-disable-next-line default-case
55 switch (event.key) {
56 case 'ArrowDown':
@@ -67,10 +72,14 @@ export default function Tree(props: Props) {
72 }
73 };
74
70 - window.addEventListener('keydown', handleKeyDown);
75 + // It's important to listen to the ownerDocument to support the browser extension.
76 + // Here we use portals to render individual tabs (e.g. Profiler),
77 + // and the root document might belong to a different window.
78 + const ownerDocument = treeRef.current.ownerDocument;
79 + ownerDocument.addEventListener('keydown', handleKeyDown);
80
81 return () => {
73 - window.removeEventListener('keydown', handleKeyDown);
82 + ownerDocument.removeEventListener('keydown', handleKeyDown);
83 };
84 }, [
85 selectNextElementInTree,
@@ -90,7 +99,7 @@ export default function Tree(props: Props) {
99 );
100
101 return (
93 - <div className={styles.Tree}>
102 + <div className={styles.Tree} ref={treeRef}>
103 <div className={styles.SearchInput}>
104 {ownerStack.length > 0 ? <OwnersStack /> : <SearchInput />}
105 <InspectHostNodesToggle />
src/devtools/views/Profiler/SnapshotCommitList.js
+13 -5
@@ -80,6 +80,7 @@ function List({
80 width,
81 }: ListProps) {
82 const listRef = useRef<FixedSizeList<ItemData> | null>(null);
83 + const divRef = useRef<HTMLDivElement | null>(null);
84 const prevCommitIndexRef = useRef<number | null>(null);
85
86 // Make sure a newly selected snapshot is fully visible within the list.
@@ -103,11 +104,17 @@ function List({
104 setIsMouseDown(false);
105 }, []);
106 useEffect(() => {
106 - window.addEventListener('mouseup', handleMouseUp);
107 - return () => {
108 - window.removeEventListener('mouseup', handleMouseUp);
109 - };
110 - }, [handleMouseUp]);
107 + if (divRef.current === null) {
108 + return () => {};
109 + }
110 +
111 + // It's important to listen to the ownerDocument to support the browser extension.
112 + // Here we use portals to render individual tabs (e.g. Profiler),
113 + // and the root document might belong to a different window.
114 + const ownerDocument = divRef.current.ownerDocument;
115 + ownerDocument.addEventListener('mouseup', handleMouseUp);
116 + return () => ownerDocument.removeEventListener('mouseup', handleMouseUp);
117 + }, [divRef, handleMouseUp]);
118
119 const itemSize = useMemo(
120 () => Math.max(minBarWidth, width / filteredCommitIndices.length),
@@ -150,6 +157,7 @@ function List({
157 <div
158 onMouseDown={handleMouseDown}
159 onMouseUp={handleMouseUp}
160 + ref={divRef}
161 style={{ height, width }}
162 >
163 <FixedSizeList
src/devtools/views/hooks.js
+14 -7
@@ -58,6 +58,10 @@ export function useModalDismissSignal(
58 dismissCallback: Function
59 ): void {
60 useEffect(() => {
61 + if (modalRef.current === null) {
62 + return () => {};
63 + }
64 +
65 const handleKeyDown = ({ key }: any) => {
66 if (key === 'Escape') {
67 dismissCallback();
@@ -71,15 +75,18 @@ export function useModalDismissSignal(
75 }
76 };
77
74 - const body = ((document.body: any): HTMLBodyElement);
75 - body.addEventListener('keydown', handleKeyDown);
76 - body.addEventListener('mousedown', handleMouseOrTouch);
77 - body.addEventListener('touchstart', handleMouseOrTouch);
78 + // It's important to listen to the ownerDocument to support the browser extension.
79 + // Here we use portals to render individual tabs (e.g. Profiler),
80 + // and the root document might belong to a different window.
81 + const ownerDocument = modalRef.current.ownerDocument;
82 + ownerDocument.addEventListener('keydown', handleKeyDown);
83 + ownerDocument.addEventListener('mousedown', handleMouseOrTouch);
84 + ownerDocument.addEventListener('touchstart', handleMouseOrTouch);
85
86 return () => {
80 - body.removeEventListener('keydown', handleKeyDown);
81 - body.removeEventListener('mousedown', handleMouseOrTouch);
82 - body.removeEventListener('touchstart', handleMouseOrTouch);
87 + ownerDocument.removeEventListener('keydown', handleKeyDown);
88 + ownerDocument.removeEventListener('mousedown', handleMouseOrTouch);
89 + ownerDocument.removeEventListener('touchstart', handleMouseOrTouch);
90 };
91 }, [modalRef, dismissCallback]);
92 }