From 8840fba5c48f1f50c4bfbcee61c73bb266850d91 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jo=C3=A3o=20Magalh=C3=A3es?= <joamag@gmail.com>
Date: Sun, 17 Jul 2022 11:23:28 +0100
Subject: [PATCH] feat: initial react infrastructure

---
 examples/web/index.css                        | 106 +-----------------
 examples/web/index.html                       |  30 ++---
 examples/web/index.ts                         |  10 +-
 examples/web/package.json                     |   9 +-
 examples/web/react/app.css                    |   0
 examples/web/react/app.tsx                    |  18 +++
 .../web/react/components/button/button.css    | 105 +++++++++++++++++
 .../web/react/components/button/button.tsx    |  13 +++
 examples/web/react/components/index.ts        |   1 +
 examples/web/shims-vue.d.ts                   |   4 -
 examples/web/tsconfig.json                    |   1 +
 examples/web/vue/app.vue                      |  23 ----
 examples/web/vue/components/button/button.vue |  16 ---
 examples/web/vue/components/index.ts          |  13 ---
 examples/web/vue/index.ts                     |  11 --
 15 files changed, 165 insertions(+), 195 deletions(-)
 create mode 100644 examples/web/react/app.css
 create mode 100644 examples/web/react/app.tsx
 create mode 100644 examples/web/react/components/button/button.css
 create mode 100644 examples/web/react/components/button/button.tsx
 create mode 100644 examples/web/react/components/index.ts
 delete mode 100644 examples/web/shims-vue.d.ts
 delete mode 100644 examples/web/vue/app.vue
 delete mode 100644 examples/web/vue/components/button/button.vue
 delete mode 100644 examples/web/vue/components/index.ts
 delete mode 100644 examples/web/vue/index.ts

diff --git a/examples/web/index.css b/examples/web/index.css
index 850d93f7..760e06b7 100644
--- a/examples/web/index.css
+++ b/examples/web/index.css
@@ -308,108 +308,6 @@ p {
     -webkit-transform: scale(1.0, 1.0);
 }
 
-.tiny-button {
-    border-radius: 96px 96px 96px 96px;
-    -o-border-radius: 96px 96px 96px 96px;
-    -ms-border-radius: 96px 96px 96px 96px;
-    -moz-border-radius: 96px 96px 96px 96px;
-    -khtml-border-radius: 96px 96px 96px 96px;
-    -webkit-border-radius: 96px 96px 96px 96px;
-    cursor: pointer;
-    display: inline-block;
-    padding: 0px 8px 0px 8px;
-    user-select: none;
-    -o-user-select: none;
-    -ms-user-select: none;
-    -moz-user-select: none;
-    -khtml-user-select: none;
-    -webkit-user-select: none;
-}
-
-.tiny-button.border {
-    border: 1px solid #ffffff;
-}
-
-.tiny-button.padded {
-    padding: 4px 10px 4px 10px;
-}
-
-.tiny-button.padded-large {
-    padding: 4px 14px 4px 14px;
-}
-
-.tiny-button.rounded {
-    padding: 6px 6px 6px 6px;
-}
-
-.tiny-button.enabled {
-    background-color: #50cb93;
-}
-
-.tiny-button.file {
-    position: relative;
-}
-
-.tiny-button:hover {
-    background-color: #50cb93;
-}
-
-.tiny-button.red:hover {
-    background-color: #e63946;
-}
-
-.tiny-button:active {
-    background-color: #2a9d8f;
-}
-
-.tiny-button.red:active {
-    background-color: #bf2a37;
-}
-
-.tiny-button > img {
-    margin-right: 6px;
-    margin-top: 2px;
-    vertical-align: top;
-    width: 13px;
-}
-
-.tiny-button > img.medium {
-    width: 20px;
-}
-
-.tiny-button > img.large {
-    width: 28px;
-}
-
-.tiny-button > img.very-large {
-    width: 38px;
-}
-
-.tiny-button.no-text > img {
-    margin-right: 0px;
-    margin-top: 0px;
-}
-
-.tiny-button.file > input[type="file"] {
-    cursor: pointer;
-    height: 100%;
-    left: 0px;
-    opacity: 0;
-    -o-opacity: 0;
-    -ms-opacity: 0;
-    -moz-opacity: 0;
-    -khtml-opacity: 0;
-    -webkit-opacity: 0;
-    position: absolute;
-    top: 0px;
-    vertical-align: top;
-    width: 100%;
-}
-
-.tiny-button.file > input[type="file"]::-webkit-file-upload-button {
-    cursor: pointer;
-}
-
 .overlay {
     align-items: center;
     background-color: rgba(80, 203, 147, 0.95);
@@ -575,12 +473,12 @@ p {
     -webkit-user-select: none;
 }
 
-.modal-container > .modal .modal-buttons > .tiny-button {
+.modal-container > .modal .modal-buttons > .button.tiny {
     margin-right: 12px;
     min-width: 120px;
 }
 
-.modal-container > .modal .modal-buttons > .tiny-button:last-child {
+.modal-container > .modal .modal-buttons > .button.tiny:last-child {
     margin-right: 0px;
 }
 
diff --git a/examples/web/index.html b/examples/web/index.html
index cf2eabe0..96e55af5 100644
--- a/examples/web/index.html
+++ b/examples/web/index.html
@@ -77,16 +77,16 @@
             <div id="section-diag" class="section">
                 <dl class="diag">
                     <dt>Engine</dt>
-                    <dd id="engine" class="tiny-button">-</dd>
+                    <dd id="engine" class="button tiny">-</dd>
                     <dt>ROM</dt>
                     <dd id="rom-name">-</dd>
                     <dt>ROM Size</dt>
                     <dd><span id="rom-size">-</span> bytes</dd>
                     <dt>CPU Frequency</dt>
                     <dd>
-                        <span id="logic-frequency-minus" class="tiny-button">-</span>
+                        <span id="logic-frequency-minus" class="button tiny">-</span>
                         <span id="logic-frequency">-</span> Hz
-                        <span id="logic-frequency-plus" class="tiny-button">+</span></dd>
+                        <span id="logic-frequency-plus" class="button tiny">+</span></dd>
                     <dt>Framerate</dt>
                     <dd><span id="fps-count">-</span> fps</dd>
                 </dl>
@@ -94,31 +94,31 @@
             <div id="separator-diag" class="separator"></div>
             <div class="section">
                 <div class="button-area">
-                    <span id="button-pause" class="tiny-button border padded">
+                    <span id="button-pause" class="button tiny border padded">
                         <img src="res/pause.svg" alt="pause" /><span>Pause</span>
                     </span>
-                    <span id="button-reset" class="tiny-button border padded">
+                    <span id="button-reset" class="button tiny border padded">
                         <img src="res/reset.svg" alt="reset" /><span>Reset</span>
                     </span>
-                    <span id="button-benchmark" class="tiny-button border padded">
+                    <span id="button-benchmark" class="button tiny border padded">
                         <img src="res/bolt.svg" alt="bolt" /><span>Benchmark</span>
                     </span>
-                    <span id="button-fullscreen" class="tiny-button border padded">
+                    <span id="button-fullscreen" class="button tiny border padded">
                         <img src="res/maximise.svg" alt="maximise" /><span>Fullscreen</span>
                     </span>
-                    <span id="button-keyboard" class="tiny-button border padded">
+                    <span id="button-keyboard" class="button tiny border padded">
                         <img src="res/dialpad.svg" alt="info" /><span>Keyboard</span>
                     </span>
-                    <span id="button-information" class="tiny-button border padded enabled">
+                    <span id="button-information" class="button tiny border padded enabled">
                         <img src="res/info.svg" alt="info" /><span>Information</span>
                     </span>
-                    <span id="button-debug" class="tiny-button border padded">
+                    <span id="button-debug" class="button tiny border padded">
                         <img src="res/bug.svg" alt="bug" /><span>Debug</span>
                     </span>
-                    <span id="button-theme" class="tiny-button border padded">
+                    <span id="button-theme" class="button tiny border padded">
                         <img src="res/marker.svg" alt="marker" /><span>Theme</span>
                     </span>
-                    <span id="button-upload" class="tiny-button border padded file">
+                    <span id="button-upload" class="button tiny border padded file">
                         <img src="res/upload.svg" alt="upload" /><span>Load ROM</span>
                         <input type="file" id="button-upload-file" name="button-upload-file" accept=".gb">
                     </span>
@@ -133,15 +133,15 @@
 <div id="modal-container" class="modal-container">
     <div id="modal" class="modal">
         <div class="modal-top-buttons">
-            <span id="modal-close" class="tiny-button rounded no-text">
+            <span id="modal-close" class="button tiny rounded no-text">
                 <img class="medium" src="res/close.svg" alt="close" />
             </span>
         </div>
         <h2 id="modal-title" class="modal-title"></h2>
         <p id="modal-text" class="modal-text"></p>
         <div class="modal-buttons">
-            <span id="modal-cancel" class="tiny-button red border padded-large">Cancel</span>
-            <span id="modal-confirm" class="tiny-button border padded-large">Confirm</span>
+            <span id="modal-cancel" class="button tiny red border padded-large">Cancel</span>
+            <span id="modal-confirm" class="button tiny border padded-large">Confirm</span>
         </div>
     </div>
 </div>
diff --git a/examples/web/index.ts b/examples/web/index.ts
index 270a8246..a690c1f6 100644
--- a/examples/web/index.ts
+++ b/examples/web/index.ts
@@ -1,5 +1,5 @@
-import { createApp } from "vue";
-import Boytacean from "./vue/app.vue";
+import { startApp } from "./react/app";
+
 import { default as _wasm, GameBoy, PadKey, PpuMode } from "./lib/boytacean.js";
 import info from "./package.json";
 
@@ -11,7 +11,7 @@ const TIMER_HZ = 60;
 const IDLE_HZ = 10;
 
 const FREQUENCY_DELTA = 60;
- 
+
 const DISPLAY_WIDTH = 160;
 const DISPLAY_HEIGHT = 144;
 const DISPLAY_RATIO = DISPLAY_WIDTH / DISPLAY_HEIGHT;
@@ -1099,9 +1099,7 @@ const wasm = async () => {
 };
 
 (async () => {
-    (globalThis as any).__VUE_OPTIONS_API__ = true;
-    (globalThis as any).__VUE_PROD_DEVTOOLS__ = false;
-    createApp(Boytacean).mount("#app");
+    startApp("app");
 
     const emulator = new Emulator();
     await emulator.main();
diff --git a/examples/web/package.json b/examples/web/package.json
index cb5ebe54..bd9fcb70 100644
--- a/examples/web/package.json
+++ b/examples/web/package.json
@@ -17,10 +17,13 @@
     "source": "index.ts",
     "devDependencies": {
         "@parcel/transformer-typescript-tsc": "^2.6.2",
-        "@parcel/transformer-vue": "^2.6.2",
+        "@types/react": "^18.0.15",
+        "@types/react-dom": "^18.0.6",
         "parcel": "^2.6.2",
         "prettier": "^2.7.1",
-        "typescript": "^4.7.4",
-        "vue": "^3.2.37"
+        "process": "^0.11.10",
+        "react": "^18.2.0",
+        "react-dom": "^18.2.0",
+        "typescript": "^4.7.4"
     }
 }
diff --git a/examples/web/react/app.css b/examples/web/react/app.css
new file mode 100644
index 00000000..e69de29b
diff --git a/examples/web/react/app.tsx b/examples/web/react/app.tsx
new file mode 100644
index 00000000..64bc0bf0
--- /dev/null
+++ b/examples/web/react/app.tsx
@@ -0,0 +1,18 @@
+import React from "react";
+import ReactDOM from "react-dom/client";
+
+import { Button } from "./components";
+
+import "./app.css";
+
+export const App = () => {
+    const getText = () => "Hello World";
+    return <Button text={ getText() } />;
+}
+
+export const startApp = (element: string) => {
+    const root = ReactDOM.createRoot(document.getElementById(element)!);
+    root.render(<App />);
+}
+
+export default App;
diff --git a/examples/web/react/components/button/button.css b/examples/web/react/components/button/button.css
new file mode 100644
index 00000000..ccb443e8
--- /dev/null
+++ b/examples/web/react/components/button/button.css
@@ -0,0 +1,105 @@
+.button {
+    font-size: 12px;
+    cursor: pointer;
+}
+
+.button.tiny {
+    border-radius: 96px 96px 96px 96px;
+    -o-border-radius: 96px 96px 96px 96px;
+    -ms-border-radius: 96px 96px 96px 96px;
+    -moz-border-radius: 96px 96px 96px 96px;
+    -khtml-border-radius: 96px 96px 96px 96px;
+    -webkit-border-radius: 96px 96px 96px 96px;
+    display: inline-block;
+    padding: 0px 8px 0px 8px;
+    user-select: none;
+    -o-user-select: none;
+    -ms-user-select: none;
+    -moz-user-select: none;
+    -khtml-user-select: none;
+    -webkit-user-select: none;
+}
+
+.button.tiny.border {
+    border: 1px solid #ffffff;
+}
+
+.button.tiny.padded {
+    padding: 4px 10px 4px 10px;
+}
+
+.button.tiny.padded-large {
+    padding: 4px 14px 4px 14px;
+}
+
+.button.tiny.rounded {
+    padding: 6px 6px 6px 6px;
+}
+
+.button.tiny.enabled {
+    background-color: #50cb93;
+}
+
+.button.tiny.file {
+    position: relative;
+}
+
+.button.tiny:hover {
+    background-color: #50cb93;
+}
+
+.button.tiny.red:hover {
+    background-color: #e63946;
+}
+
+.button.tiny:active {
+    background-color: #2a9d8f;
+}
+
+.button.tiny.red:active {
+    background-color: #bf2a37;
+}
+
+.button.tiny > img {
+    margin-right: 6px;
+    margin-top: 2px;
+    vertical-align: top;
+    width: 13px;
+}
+
+.button.tiny > img.medium {
+    width: 20px;
+}
+
+.button.tiny > img.large {
+    width: 28px;
+}
+
+.button.tiny > img.very-large {
+    width: 38px;
+}
+
+.button.tiny.no-text > img {
+    margin-right: 0px;
+    margin-top: 0px;
+}
+
+.button.tiny.file > input[type="file"] {
+    cursor: pointer;
+    height: 100%;
+    left: 0px;
+    opacity: 0;
+    -o-opacity: 0;
+    -ms-opacity: 0;
+    -moz-opacity: 0;
+    -khtml-opacity: 0;
+    -webkit-opacity: 0;
+    position: absolute;
+    top: 0px;
+    vertical-align: top;
+    width: 100%;
+}
+
+.button.tiny.file > input[type="file"]::-webkit-file-upload-button {
+    cursor: pointer;
+}
\ No newline at end of file
diff --git a/examples/web/react/components/button/button.tsx b/examples/web/react/components/button/button.tsx
new file mode 100644
index 00000000..c8dda14c
--- /dev/null
+++ b/examples/web/react/components/button/button.tsx
@@ -0,0 +1,13 @@
+import React, { FC } from "react";
+
+import "./button.css";
+
+export const Button: FC<{ text: string, style?: string[] }> = ({ text, style = ["tiny", "border"] }) => {
+    const onClick = () => {
+        alert("Hello World");
+    }
+
+    const classes = () => ["button", ...style].join(" ")
+
+    return <span className={classes()} onClick={onClick}>{ text }</span>;
+}
diff --git a/examples/web/react/components/index.ts b/examples/web/react/components/index.ts
new file mode 100644
index 00000000..34aa90a0
--- /dev/null
+++ b/examples/web/react/components/index.ts
@@ -0,0 +1 @@
+export * from "./button/button";
diff --git a/examples/web/shims-vue.d.ts b/examples/web/shims-vue.d.ts
deleted file mode 100644
index ce8ffebf..00000000
--- a/examples/web/shims-vue.d.ts
+++ /dev/null
@@ -1,4 +0,0 @@
-declare module "*.vue" {
-    import Vue from "vue";
-    export default Vue;
-}
diff --git a/examples/web/tsconfig.json b/examples/web/tsconfig.json
index 8fbd457e..8f83dd8e 100644
--- a/examples/web/tsconfig.json
+++ b/examples/web/tsconfig.json
@@ -13,6 +13,7 @@
         "strictFunctionTypes": true,
         "strictPropertyInitialization": true,
         "sourceMap": true,
+        "jsx": "react",
         "outDir": ".",
         "baseUrl": ".",
         "lib": ["es2017", "dom"],
diff --git a/examples/web/vue/app.vue b/examples/web/vue/app.vue
deleted file mode 100644
index f9265d49..00000000
--- a/examples/web/vue/app.vue
+++ /dev/null
@@ -1,23 +0,0 @@
-<template>
-    <div v-bind:class="'hello'" v-on:click="() => count++">Hello {{ name }} {{ count}}!</div>
-</template>
-
-<style scoped>
-.hello {
-    cursor: pointer;
-    user-select: none;
-}
-</style>
-
-<script lang="ts">
-export const Boytacean = {
-    data() {
-        return {
-            name: "Vue",
-            count: 1
-        };
-    }
-};
-
-export default Boytacean;
-</script>
diff --git a/examples/web/vue/components/button/button.vue b/examples/web/vue/components/button/button.vue
deleted file mode 100644
index fe4c1679..00000000
--- a/examples/web/vue/components/button/button.vue
+++ /dev/null
@@ -1,16 +0,0 @@
-<template>
-    <div v-on:click="() => count++">Hello {{ name }} {{ count}}!</div>
-</template>
-
-<script>
-export const Button = {
-    data() {
-        return {
-            name: "Vue",
-            count: 1
-        };
-    }
-};
-
-export default Button;
-</script>
diff --git a/examples/web/vue/components/index.ts b/examples/web/vue/components/index.ts
deleted file mode 100644
index d54b4044..00000000
--- a/examples/web/vue/components/index.ts
+++ /dev/null
@@ -1,13 +0,0 @@
-import { App } from "vue";
-
-import Button from "./button/button.vue";
-
-const install = (Vue: App) => {
-    Vue.component("vue", Button);
-};
-
-export {
-    Button
-};
-
-export default install;
diff --git a/examples/web/vue/index.ts b/examples/web/vue/index.ts
deleted file mode 100644
index 3b2fc528..00000000
--- a/examples/web/vue/index.ts
+++ /dev/null
@@ -1,11 +0,0 @@
-import { App } from "vue";
-
-import Components from "./components";
-
-const install = (Vue: App) => {
-    Vue.use(Components);
-};
-
-export * from "./components";
-
-export default install;
-- 
GitLab