diff --git a/examples/web/react/app.tsx b/examples/web/react/app.tsx index 4462d92dbc3f4c0ed4456ca5e99dfe5f5c522a3e..9ab89f28e8e58fa4793a38c498ef29d15d746bd8 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 ce3fdcbe89226c054c0d34caf93653176dcaf9a3..4ed686608c0bd83a3f0452ac6c1add2980081514 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 831fc1c61067e79ec37923403783fb427548e4bc..c5267fb06bbdd4cdb1b6e54401f50f7572f13b85 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 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391