From 3cf9fed80a7f6b16fa97d544be13621732d6f910 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Tue, 1 Nov 2022 12:57:43 +0000
Subject: [PATCH] feat: new unregister of events

---
 examples/web/react/app.tsx                    | 32 +++++++++++++----
 examples/web/react/components/modal/modal.tsx |  8 +++--
 .../web/react/components/overlay/overlay.tsx  | 36 ++++++++++++-------
 examples/web/react/components/tiles/tiles.css |  0
 4 files changed, 56 insertions(+), 20 deletions(-)
 create mode 100644 examples/web/react/components/tiles/tiles.css

diff --git a/examples/web/react/app.tsx b/examples/web/react/app.tsx
index 4462d92d..9ab89f28 100644
--- a/examples/web/react/app.tsx
+++ b/examples/web/react/app.tsx
@@ -45,6 +45,14 @@ export class Observable {
         this.events[event] = callbacks;
     }
 
+    unbind(event: string, callback: Callback<this>) {
+        const callbacks = this.events[event] ?? [];
+        if (!callbacks.includes(callback)) return;
+        const index = callbacks.indexOf(callback);
+        callbacks.splice(index, 1);
+        this.events[event] = callbacks;
+    }
+
     trigger(event: string, params?: Record<string, any>) {
         const callbacks = this.events[event] ?? [];
         callbacks.forEach((c) => c(this, params));
@@ -67,6 +75,7 @@ export type BenchmarkResult = {
 
 export interface ObservableI {
     bind(event: string, callback: Callback<this>): void;
+    unbind(event: string, callback: Callback<this>): void;
     trigger(event: string): void;
 }
 
@@ -237,7 +246,7 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
         }
     }, [keyaction]);
     useEffect(() => {
-        document.addEventListener("keydown", (event) => {
+        const onKeyDown = (event: KeyboardEvent) => {
             if (event.key === "Escape") {
                 setKeyaction("Escape");
                 event.stopPropagation();
@@ -248,14 +257,25 @@ export const App: FC<AppProps> = ({ emulator, backgrounds = ["264653"] }) => {
                 event.stopPropagation();
                 event.preventDefault();
             }
-        });
-        emulator.bind("booted", () => {
+        };
+        const onBooted = () => {
             const romInfo = emulator.getRomInfo();
             setRomInfo(romInfo);
-        });
-        emulator.bind("message", (_, params = {}) => {
+        };
+        const onMessage = (
+            emulator: Emulator,
+            params: Record<string, any> = {}
+        ) => {
             showToast(params.text, params.error, params.timeout);
-        });
+        };
+        document.addEventListener("keydown", onKeyDown);
+        emulator.bind("booted", onBooted);
+        emulator.bind("message", onMessage);
+        return () => {
+            document.removeEventListener("keydown", onKeyDown);
+            emulator.unbind("booted", onBooted);
+            emulator.unbind("message", onMessage);
+        };
     }, []);
 
     const getPauseText = () => (paused ? "Resume" : "Pause");
diff --git a/examples/web/react/components/modal/modal.tsx b/examples/web/react/components/modal/modal.tsx
index ce3fdcbe..4ed68660 100644
--- a/examples/web/react/components/modal/modal.tsx
+++ b/examples/web/react/components/modal/modal.tsx
@@ -25,11 +25,15 @@ export const Modal: FC<ModalProps> = ({
     const classes = () =>
         ["modal", visible ? "visible" : "", ...style].join(" ");
     useEffect(() => {
-        document.addEventListener("keydown", (event) => {
+        const onKeyDown = (event: KeyboardEvent) => {
             if (event.key === "Escape") {
                 onCancel && onCancel();
             }
-        });
+        };
+        document.addEventListener("keydown", onKeyDown);
+        return () => {
+            document.removeEventListener("keydown", onKeyDown);
+        };
     }, []);
     const getTextHtml = (separator = /\n/g) => ({
         __html: text.replace(separator, "<br/>")
diff --git a/examples/web/react/components/overlay/overlay.tsx b/examples/web/react/components/overlay/overlay.tsx
index 831fc1c6..c5267fb0 100644
--- a/examples/web/react/components/overlay/overlay.tsx
+++ b/examples/web/react/components/overlay/overlay.tsx
@@ -15,7 +15,7 @@ export const Overlay: FC<OverlayProps> = ({ text, style = [], onFile }) => {
     const classes = () =>
         ["overlay", visible ? "visible" : "", ...style].join(" ");
     useEffect(() => {
-        document.addEventListener("drop", async (event) => {
+        const onDrop = async (event: DragEvent) => {
             if (
                 !event.dataTransfer!.files ||
                 event.dataTransfer!.files.length === 0
@@ -30,25 +30,37 @@ export const Overlay: FC<OverlayProps> = ({ text, style = [], onFile }) => {
 
             const file = event.dataTransfer!.files[0];
             onFile && onFile(file);
-        });
-        document.addEventListener("dragover", async (event) => {
+        };
+        const onDragOver = async (event: DragEvent) => {
             if (!event.dataTransfer!.items || event.dataTransfer!.items[0].type)
                 return;
-
             event.preventDefault();
-
             setVisible(true);
-        });
-        document.addEventListener("dragenter", async (event) => {
+        };
+        const onDragEnter = async (event: DragEvent) => {
             if (!event.dataTransfer!.items || event.dataTransfer!.items[0].type)
                 return;
             setVisible(true);
-        });
-        document.addEventListener("dragleave", async (event) => {
-            if (!event.dataTransfer!.items || event.dataTransfer!.items[0].type)
-                return;
+        };
+        const onDragLeave = async (event: DragEvent) => {
+            if (
+                !event.dataTransfer!.items ||
+                event.dataTransfer!.items[0].type
+            ) {
+            }
+            return;
             setVisible(false);
-        });
+        };
+        document.addEventListener("drop", onDrop);
+        document.addEventListener("dragover", onDragOver);
+        document.addEventListener("dragenter", onDragEnter);
+        document.addEventListener("dragleave", onDragLeave);
+        return () => {
+            document.removeEventListener("drop", onDrop);
+            document.removeEventListener("dragover", onDragOver);
+            document.removeEventListener("dragenter", onDragEnter);
+            document.removeEventListener("dragleave", onDragLeave);
+        };
     }, []);
     return (
         <div className={classes()}>
diff --git a/examples/web/react/components/tiles/tiles.css b/examples/web/react/components/tiles/tiles.css
new file mode 100644
index 00000000..e69de29b
-- 
GitLab