Skip to content

Commit 224f920

Browse files
debangshu919masenf
andauthored
[FIX] Clipboard paste handler binding in dynamically rendered components (#6037)
* fix: fixed rx.clipboard paste event handler not binding bug (#6032) * style: remove comments * fix pre-commit formatting issue * Apply suggestions from code review Thanks for the suggestions! Co-authored-by: Masen Furer <[email protected]> * pre-commit fixup --------- Co-authored-by: Masen Furer <[email protected]>
1 parent 1c78196 commit 224f920

File tree

1 file changed

+63
-17
lines changed
  • reflex/.templates/web/utils/helpers

1 file changed

+63
-17
lines changed

reflex/.templates/web/utils/helpers/paste.js

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useEffect } from "react";
1+
import { useEffect, useRef } from "react";
22

33
const handle_paste_data = (clipboardData) =>
44
new Promise((resolve, reject) => {
@@ -35,25 +35,71 @@ const handle_paste_data = (clipboardData) =>
3535
});
3636

3737
export default function usePasteHandler(target_ids, event_actions, on_paste) {
38-
return useEffect(() => {
38+
const onPasteRef = useRef(on_paste);
39+
const eventActionsRef = useRef(event_actions);
40+
41+
useEffect(() => {
42+
onPasteRef.current = on_paste;
43+
}, [on_paste]);
44+
useEffect(() => {
45+
eventActionsRef.current = event_actions;
46+
}, [event_actions]);
47+
48+
useEffect(() => {
3949
const handle_paste = (_ev) => {
40-
event_actions.preventDefault && _ev.preventDefault();
41-
event_actions.stopPropagation && _ev.stopPropagation();
42-
handle_paste_data(_ev.clipboardData).then(on_paste);
50+
eventActionsRef.current?.preventDefault && _ev.preventDefault();
51+
eventActionsRef.current?.stopPropagation && _ev.stopPropagation();
52+
handle_paste_data(_ev.clipboardData).then(onPasteRef.current);
4353
};
44-
const targets = target_ids
45-
.map((id) => document.getElementById(id))
46-
.filter((element) => !!element);
47-
if (target_ids.length === 0) {
48-
targets.push(document);
49-
}
50-
targets.forEach((target) =>
51-
target.addEventListener("paste", handle_paste, false),
52-
);
53-
return () => {
54+
55+
let cleanupListeners = null;
56+
let observer = null;
57+
58+
const attachListeners = (targets) => {
5459
targets.forEach((target) =>
55-
target.removeEventListener("paste", handle_paste, false),
60+
target.addEventListener("paste", handle_paste, false),
5661
);
62+
return () => {
63+
targets.forEach((target) =>
64+
target.removeEventListener("paste", handle_paste, false),
65+
);
66+
};
5767
};
58-
});
68+
69+
const tryAttach = () => {
70+
if (target_ids.length === 0) {
71+
cleanupListeners = attachListeners([document]);
72+
return true;
73+
}
74+
const targets = target_ids
75+
.map((id) => document.getElementById(id))
76+
.filter((element) => !!element);
77+
78+
if (targets.length === target_ids.length) {
79+
cleanupListeners = attachListeners(targets);
80+
return true;
81+
}
82+
83+
return false;
84+
};
85+
86+
if (!tryAttach()) {
87+
observer = new MutationObserver(() => {
88+
if (tryAttach()) {
89+
observer.disconnect();
90+
observer = null;
91+
}
92+
});
93+
observer.observe(document.body, { childList: true, subtree: true });
94+
}
95+
96+
return () => {
97+
if (observer) {
98+
observer.disconnect();
99+
}
100+
if (cleanupListeners) {
101+
cleanupListeners();
102+
}
103+
};
104+
}, [target_ids]);
59105
}

0 commit comments

Comments
 (0)