From 2e5926f72083f25c8784879a45d36992ea566d89 Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Thu, 1 Aug 2024 16:20:57 -0400 Subject: [PATCH 01/31] Created new files --- demo/src/AppTwo.tsx | 0 demo/src/output.tsx | 0 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 demo/src/AppTwo.tsx create mode 100644 demo/src/output.tsx diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx new file mode 100644 index 00000000..e69de29b diff --git a/demo/src/output.tsx b/demo/src/output.tsx new file mode 100644 index 00000000..e69de29b From 1f6b418e3e200bd3e5afd6c67f7dca2cb57271f1 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Thu, 1 Aug 2024 16:42:47 -0400 Subject: [PATCH 02/31] setting up website --- demo/src/AppTwo.tsx | 10 ++++++++++ demo/src/html/index.html | 6 ++++++ demo/src/index.tsx | 19 ++++++++++++++++++- 3 files changed, 34 insertions(+), 1 deletion(-) diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx index e69de29b..c3741539 100644 --- a/demo/src/AppTwo.tsx +++ b/demo/src/AppTwo.tsx @@ -0,0 +1,10 @@ +import React from "react"; +import { Typography } from "@mui/material"; + +export default function AppTwo() { + return ( + <> + Hello MemoryViz! + + ); +} diff --git a/demo/src/html/index.html b/demo/src/html/index.html index cfe91ced..b1c59fbb 100644 --- a/demo/src/html/index.html +++ b/demo/src/html/index.html @@ -3,6 +3,12 @@ <%= htmlWebpackPlugin.options.title %> + + +
diff --git a/demo/src/index.tsx b/demo/src/index.tsx index 6aa66ed1..9abdf5e3 100644 --- a/demo/src/index.tsx +++ b/demo/src/index.tsx @@ -4,9 +4,26 @@ import App from "./App"; import "@picocss/pico"; import "./css/styles"; +import AppTwo from "./AppTwo"; +import { ThemeProvider, createTheme } from "@mui/material/styles"; +const theme = createTheme({ + palette: { + primary: { + main: "#2a6b2c", + dark: "#005ea5", + light: "#72ac56", + }, + }, + typography: { + fontFamily: "Open Sans, Arial, sans-serif", + }, +}); + const root = createRoot(document.getElementById("app")); root.render( - + + + ); From d29e2e8888b3037291a842abcdc10e089af33d44 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Thu, 1 Aug 2024 17:22:35 -0400 Subject: [PATCH 03/31] change global font --- demo/src/css/styles.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/demo/src/css/styles.css b/demo/src/css/styles.css index 61ac33e6..51fa35d1 100644 --- a/demo/src/css/styles.css +++ b/demo/src/css/styles.css @@ -6,3 +6,6 @@ input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } +body { + font-family: "Open Sans", Arial, sans-serif; +} From c7ed1f67df9608a5a1c96a0d8da5b4672b59d876 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Sat, 10 Aug 2024 16:12:26 -0400 Subject: [PATCH 04/31] NEVER BACK DOWN NEVER WHAT --- demo/src/AppTwo.tsx | 51 +++++++++++- demo/src/Header.tsx | 34 ++++++++ demo/src/SampleInputMenu.tsx | 77 ++++++++++++++++++ demo/src/UserInput.tsx | 147 +++++++++++++++++++++++++++++++++++ demo/src/css/styles.css | 8 ++ demo/src/html/index.html | 16 +--- demo/src/index.tsx | 2 +- demo/src/output.tsx | 0 8 files changed, 316 insertions(+), 19 deletions(-) create mode 100644 demo/src/Header.tsx create mode 100644 demo/src/SampleInputMenu.tsx create mode 100644 demo/src/UserInput.tsx delete mode 100644 demo/src/output.tsx diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx index c3741539..2926d043 100644 --- a/demo/src/AppTwo.tsx +++ b/demo/src/AppTwo.tsx @@ -1,10 +1,55 @@ -import React from "react"; -import { Typography } from "@mui/material"; +import React, { useState } from "react"; +import { configDataPropTypes } from "./MemoryModelsUserInput"; +import UserInput from "./UserInput"; +import Header from "./Header"; +import { Box } from "@mui/material"; export default function AppTwo() { + const [textData, setTextData] = useState(""); + const [configData, setConfigData] = useState({ + useAutomation: true, + overallDrawConfig: { + seed: 0, + }, + }); + const [jsonResult, setJsonResult] = useState(null); + const [svgResult, setSvgResult] = useState(null); + const [failureBanner, setFailureBanner] = useState(""); + + const onTextDataSubmit = (event?) => { + event?.preventDefault(); + try { + setJsonResult(JSON.parse(textData)); + setFailureBanner(""); + } catch (error) { + const errorMessage = `Error parsing inputted JSON: ${error.message}`; + console.error(errorMessage); + setFailureBanner(errorMessage); + setJsonResult(null); + } + }; + return ( <> - Hello MemoryViz! +
+ + + + {/* Put your component here! (And feel free to get rid of the border) */} + + ); } diff --git a/demo/src/Header.tsx b/demo/src/Header.tsx new file mode 100644 index 00000000..d838eb49 --- /dev/null +++ b/demo/src/Header.tsx @@ -0,0 +1,34 @@ +import React from "react"; +import { Box, Link, Typography } from "@mui/material"; + +export default function Header() { + return ( + + + MemoryViz Demo + + + Demos of the{" "} + + MemoryViz + {" "} + Javascript library for visualizing Python memory. Click{" "} + + here + {" "} + for documentation. + + + ); +} diff --git a/demo/src/SampleInputMenu.tsx b/demo/src/SampleInputMenu.tsx new file mode 100644 index 00000000..727813f1 --- /dev/null +++ b/demo/src/SampleInputMenu.tsx @@ -0,0 +1,77 @@ +import React, { useState, useEffect } from "react"; +import { Button, Menu, MenuItem } from "@mui/material"; +import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded"; +import { SAMPLES } from "./sample"; + +type MemoryModelsSamplePropTypes = { + setTextData: React.Dispatch>; + setConfigData: React.Dispatch>; + onTextDataSubmit: () => void; +}; + +export default function SampleInputMenu(props: MemoryModelsSamplePropTypes) { + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + const [clickedBtnIndex, setClickedBtnIndex] = useState(null); + + useEffect(() => { + if (clickedBtnIndex !== null) { + props.onTextDataSubmit(); + } + }, [clickedBtnIndex]); + + const classes = { + button: { + textTransform: "none", + "& .MuiSvgIcon-root": { + transition: "transform 0.2s ease-in-out", + transform: open ? "rotate(180deg)" : "rotate(0deg)", + }, + }, + }; + + const handleButtonClick = (index: Number, sample: Object) => { + // Note: the following conversion to a string is inefficient, as the data is later parsed + // back into JSON for rendering. + // TODO: fix this. + props.setTextData(JSON.stringify(sample["data"], null, 4)); + props.setConfigData((prevConfigData) => ({ + ...prevConfigData, + ...sample["config"], + })); + setClickedBtnIndex(index); + }; + + return ( +
+ + + {SAMPLES.map((sample, index) => ( + handleButtonClick(index, sample)} + > + {sample["name"]} + + ))} + +
+ ); +} diff --git a/demo/src/UserInput.tsx b/demo/src/UserInput.tsx new file mode 100644 index 00000000..cd7707dc --- /dev/null +++ b/demo/src/UserInput.tsx @@ -0,0 +1,147 @@ +import React from "react"; +import { Box, Button, Link, Input, Typography, TextField } from "@mui/material"; +import SampleInputMenu from "./SampleInputMenu"; + +interface configDataPropTypes { + useAutomation: boolean; + overallDrawConfig: { + [key: string]: any; + }; +} + +type MemoryModelsConfigInputPropTypes = { + configData: configDataPropTypes; + setConfigData: React.Dispatch>; +}; + +type MemoryModelsFileInputPropTypes = { + setTextData: React.Dispatch>; + textData: string; + setFailureBanner: React.Dispatch>; + jsonResult: string | null; +}; + +type MemoryModelsTextInputPropTypes = { + setTextData: React.Dispatch>; + textData: string; +}; + +type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes & + MemoryModelsTextInputPropTypes & + MemoryModelsConfigInputPropTypes & { + onTextDataSubmit: () => void; + }; + +export default function UserInput(props: MemoryModelsUserInputPropTypes) { + const classes = { + inputBox: { + display: "flex", + flexDirection: "column", + }, + title: { + fontWeight: "600", + mb: "1rem", + }, + button1: { + width: "auto", + textTransform: "none", + }, + fileInputBox: { + display: "flex", + justifyContent: "space-between", + }, + textField: { + height: "auto", + "& .MuiInputBase-input": { + fontFamily: "Consolas, monospace", + background: "none !important", + }, + }, + inputBottomBox: { + display: "flex", + justifyContent: "space-between", + }, + input: { + width: "50%", + }, + }; + + const onChange = (event) => { + try { + const uploadedFile = event.target.files[0]; + const fileReader = new global.FileReader(); + fileReader.readAsText(uploadedFile, "UTF-8"); + fileReader.onload = (event) => { + const fileString = event.target.result as string; + props.setTextData(fileString); + }; + } catch (error) { + const errorMessage = `Error reading uploaded file as text. Please ensure it's in UTF-8 encoding: ${error.message}`; + console.error(errorMessage); + props.setTextData(null); + props.setFailureBanner(errorMessage); + } + }; + + const file = new Blob([JSON.stringify(props.jsonResult, null, 2)], { + type: "application/JSON", + }); + + const handleTextFieldChange = (event) => { + props.setTextData(event.target.value); + }; + + return ( + + + Input + + + + + + + + + + Download JSON + + + + + ); +} diff --git a/demo/src/css/styles.css b/demo/src/css/styles.css index 51fa35d1..54b4787c 100644 --- a/demo/src/css/styles.css +++ b/demo/src/css/styles.css @@ -6,6 +6,14 @@ input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } +input:not([type="checkbox"], [type="radio"]), +select, +textarea { + margin-bottom: 0; +} body { font-family: "Open Sans", Arial, sans-serif; } +#root { + padding: 1rem; +} diff --git a/demo/src/html/index.html b/demo/src/html/index.html index b1c59fbb..26dbc639 100644 --- a/demo/src/html/index.html +++ b/demo/src/html/index.html @@ -11,20 +11,6 @@ /> -
-
-

<%= htmlWebpackPlugin.options.title %>

-

- Demos of the - MemoryViz - Javascript library for visualizing Python memory. -

-
-
-
-
-
+
diff --git a/demo/src/index.tsx b/demo/src/index.tsx index 9abdf5e3..692f8af3 100644 --- a/demo/src/index.tsx +++ b/demo/src/index.tsx @@ -19,7 +19,7 @@ const theme = createTheme({ }, }); -const root = createRoot(document.getElementById("app")); +const root = createRoot(document.getElementById("root")); root.render( diff --git a/demo/src/output.tsx b/demo/src/output.tsx deleted file mode 100644 index e69de29b..00000000 From b1c779c326f1c39f6d85099e3fbba75893045ed7 Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Sun, 11 Aug 2024 02:13:49 -0400 Subject: [PATCH 05/31] Set up output component for horizontal layout --- demo/src/output.tsx | 85 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 85 insertions(+) diff --git a/demo/src/output.tsx b/demo/src/output.tsx index e69de29b..f3a3eafe 100644 --- a/demo/src/output.tsx +++ b/demo/src/output.tsx @@ -0,0 +1,85 @@ +import React, { useRef, useEffect, useState } from "react"; +import SvgDisplay from "./SvgDisplay"; +import { configDataPropTypes } from "./MemoryModelsUserInput"; +import { + Box, + Typography, + Link, + Grid, + TextField, + FormControlLabel, + Checkbox, +} from "@mui/material"; + +type OutputPropTypes = { + jsonResult: object | null; + configData: configDataPropTypes; + setConfigData: React.Dispatch>; + setSvgResult: React.Dispatch>; + svgResult: string; +}; + +export default function Output(props: OutputPropTypes) { + const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); + + const handleSeedChange = (event) => { + props.setConfigData({ + ...props.configData, + overallDrawConfig: { + ...props.configData.overallDrawConfig, + seed: Number(event.target.value), + }, + }); + }; + + const handleAutomationChange = (event) => { + // Calling the common (among React event handlers) event.preventDefault() here + // will cause the checkbox to require double instead of single clicks, as verified by both UI and tests. + // Explained in https://grrr.tech/posts/2022/event-prevent-failure/#but-huh-why-does-this-work + props.setConfigData({ + ...props.configData, + useAutomation: event.target.checked, + }); + }; + + return ( + <> + +

Output

+
+ + + + } + label="Use automatic layout" + sx={{ marginLeft: 15, marginTop: 6 }} + /> + + + + {"Download SVG"} + + + ); +} From 065ab84a744983751e312dc2ec3d1492a5a054cb Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Sun, 11 Aug 2024 02:14:22 -0400 Subject: [PATCH 06/31] Adjust SvgDisplay for horizontal layout --- demo/src/SvgDisplay.tsx | 42 ++++++++++++++++++++++++++++++++++------- 1 file changed, 35 insertions(+), 7 deletions(-) diff --git a/demo/src/SvgDisplay.tsx b/demo/src/SvgDisplay.tsx index 5dbdcb76..bedb5d42 100644 --- a/demo/src/SvgDisplay.tsx +++ b/demo/src/SvgDisplay.tsx @@ -1,6 +1,7 @@ -import React, { useRef, useEffect } from "react"; +import React, { useRef, useEffect, useState } from "react"; import mem from "memory-viz"; import { configDataPropTypes } from "./MemoryModelsUserInput"; +import { Box, Button } from "@mui/material"; type SvgDisplayPropTypes = { jsonResult: object | null; @@ -12,6 +13,7 @@ export default function SvgDisplay(props: SvgDisplayPropTypes) { const canvasRef = useRef(null); const canvasWidth = 1300; const canvasHeight = 1000; + const scale = 0.8; useEffect(() => { if (props.jsonResult !== null) { @@ -29,11 +31,37 @@ export default function SvgDisplay(props: SvgDisplayPropTypes) { }, [props.jsonResult]); return ( - + <> + + + + + + ); } + +export type { SvgDisplayPropTypes }; From c9bc9e16cee2a64552038e05ecc45eb05442d05b Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Sun, 11 Aug 2024 02:21:26 -0400 Subject: [PATCH 07/31] add output to horizontal layout --- demo/src/AppTwo.tsx | 22 +++++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx index 2926d043..66ebed52 100644 --- a/demo/src/AppTwo.tsx +++ b/demo/src/AppTwo.tsx @@ -3,6 +3,9 @@ import { configDataPropTypes } from "./MemoryModelsUserInput"; import UserInput from "./UserInput"; import Header from "./Header"; import { Box } from "@mui/material"; +import { ErrorBoundary } from "react-error-boundary"; +import DownloadSVGButton from "./DownloadSVGButton"; +import SvgDisplay from "./SvgDisplay"; export default function AppTwo() { const [textData, setTextData] = useState(""); @@ -46,7 +49,24 @@ export default function AppTwo() { setFailureBanner={setFailureBanner} jsonResult={jsonResult} /> - + +

Output

+ + + This is valid JSON but not valid Memory Models + JSON. Please refer to the repo for more details. +

+ } + key={jsonResult} + > + +
{/* Put your component here! (And feel free to get rid of the border) */}
From d707090ad828d92e290ce17dc66f4640b2d60051 Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Sun, 11 Aug 2024 03:42:52 -0400 Subject: [PATCH 08/31] adjust formatting a bit --- demo/src/AppTwo.tsx | 27 +++------ demo/src/SvgDisplay.tsx | 2 +- demo/src/UserOutput.tsx | 122 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 19 deletions(-) create mode 100644 demo/src/UserOutput.tsx diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx index 66ebed52..853f1241 100644 --- a/demo/src/AppTwo.tsx +++ b/demo/src/AppTwo.tsx @@ -6,6 +6,7 @@ import { Box } from "@mui/material"; import { ErrorBoundary } from "react-error-boundary"; import DownloadSVGButton from "./DownloadSVGButton"; import SvgDisplay from "./SvgDisplay"; +import UserOutput from "./UserOutput"; export default function AppTwo() { const [textData, setTextData] = useState(""); @@ -49,24 +50,14 @@ export default function AppTwo() { setFailureBanner={setFailureBanner} jsonResult={jsonResult} /> - -

Output

- - - This is valid JSON but not valid Memory Models - JSON. Please refer to the repo for more details. -

- } - key={jsonResult} - > - -
+ + {/* Put your component here! (And feel free to get rid of the border) */}
diff --git a/demo/src/SvgDisplay.tsx b/demo/src/SvgDisplay.tsx index bedb5d42..14999feb 100644 --- a/demo/src/SvgDisplay.tsx +++ b/demo/src/SvgDisplay.tsx @@ -38,7 +38,7 @@ export default function SvgDisplay(props: SvgDisplayPropTypes) { height={400} width={700} sx={[ - { border: 1, borderRadius: 2 }, + { border: 1, borderRadius: 1, borderColor: "gray" }, { "&:hover": { border: 2, diff --git a/demo/src/UserOutput.tsx b/demo/src/UserOutput.tsx new file mode 100644 index 00000000..3497b63e --- /dev/null +++ b/demo/src/UserOutput.tsx @@ -0,0 +1,122 @@ +import React from "react"; +import SvgDisplay from "./SvgDisplay"; +import { configDataPropTypes } from "./MemoryModelsUserInput"; +import { + Box, + Typography, + Link, + TextField, + FormControlLabel, + Checkbox, +} from "@mui/material"; + +type OutputPropTypes = { + jsonResult: object | null; + configData: configDataPropTypes; + setConfigData: React.Dispatch>; + svgResult: string; + setSvgResult: React.Dispatch>; +}; + +export default function Output(props: OutputPropTypes) { + const classes = { + inputBox: { + display: "flex", + flexDirection: "column", + }, + title: { + fontWeight: "600", + mb: "1rem", + }, + button1: { + width: "auto", + textTransform: "none", + }, + fileInputBox: { + display: "flex", + justifyContent: "space-between", + }, + textField: { + height: "auto", + "& .MuiInputBase-input": { + fontFamily: "Consolas, monospace", + background: "none !important", + }, + }, + inputBottomBox: { + display: "flex", + justifyContent: "space-between", + }, + input: { + width: "50%", + }, + }; + + const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); + + const handleSeedChange = (event) => { + props.setConfigData({ + ...props.configData, + overallDrawConfig: { + ...props.configData.overallDrawConfig, + seed: Number(event.target.value), + }, + }); + }; + + const handleAutomationChange = (event) => { + // Calling the common (among React event handlers) event.preventDefault() here + // will cause the checkbox to require double instead of single clicks, as verified by both UI and tests. + // Explained in https://grrr.tech/posts/2022/event-prevent-failure/#but-huh-why-does-this-work + props.setConfigData({ + ...props.configData, + useAutomation: event.target.checked, + }); + }; + + return ( + <> + + Output + + + + + } + label="Use automatic layout" + sx={{ marginLeft: 15 }} + /> + + + + {"Download SVG"} + + + ); +} From df01e6fd22f1cd6a1bc00cadc4edc501a0daa069 Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Sun, 11 Aug 2024 04:04:11 -0400 Subject: [PATCH 09/31] small style changes --- demo/src/AppTwo.tsx | 2 +- demo/src/SvgDisplay.tsx | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx index 853f1241..8559dfdf 100644 --- a/demo/src/AppTwo.tsx +++ b/demo/src/AppTwo.tsx @@ -50,7 +50,7 @@ export default function AppTwo() { setFailureBanner={setFailureBanner} jsonResult={jsonResult} /> - + Date: Sun, 11 Aug 2024 19:41:15 -0400 Subject: [PATCH 10/31] draft 1 --- demo/src/App.tsx | 69 ++++---- demo/src/AppTwo.tsx | 66 -------- demo/src/DownloadJSONButton.tsx | 28 ---- demo/src/DownloadSVGButton.tsx | 25 --- demo/src/MemoryModelsSample.tsx | 78 --------- demo/src/MemoryModelsUserInput.tsx | 249 ----------------------------- demo/src/UserInput.tsx | 76 ++++----- demo/src/UserOutput.tsx | 38 +---- demo/src/index.tsx | 3 +- demo/src/output.tsx | 85 ---------- 10 files changed, 66 insertions(+), 651 deletions(-) delete mode 100644 demo/src/AppTwo.tsx delete mode 100644 demo/src/DownloadJSONButton.tsx delete mode 100644 demo/src/DownloadSVGButton.tsx delete mode 100644 demo/src/MemoryModelsSample.tsx delete mode 100644 demo/src/MemoryModelsUserInput.tsx delete mode 100644 demo/src/output.tsx diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 4a0c3c4d..98aaeef9 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -1,11 +1,10 @@ import React, { useState } from "react"; -import SvgDisplay from "./SvgDisplay"; -import MemoryModelsUserInput from "./MemoryModelsUserInput"; +import { configDataPropTypes } from "./UserInput"; +import UserInput from "./UserInput"; +import Header from "./Header"; +import { Box } from "@mui/material"; import { ErrorBoundary } from "react-error-boundary"; -import DownloadSVGButton from "./DownloadSVGButton"; -import { Alert } from "@mui/material"; -import { configDataPropTypes } from "./MemoryModelsUserInput"; -import MemoryModelsSample from "./MemoryModelsSample"; +import UserOutput from "./UserOutput"; export default function App() { const [textData, setTextData] = useState(""); @@ -34,44 +33,34 @@ export default function App() { return ( <> - {failureBanner && ( - - {failureBanner} - - )} - - -
-

Output

- - - This is valid JSON but not valid Memory Models JSON. - Please refer to the repo for more details. -

- } - key={jsonResult} - > - + + + + + + -
-
+
+
); } diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx deleted file mode 100644 index 8559dfdf..00000000 --- a/demo/src/AppTwo.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useState } from "react"; -import { configDataPropTypes } from "./MemoryModelsUserInput"; -import UserInput from "./UserInput"; -import Header from "./Header"; -import { Box } from "@mui/material"; -import { ErrorBoundary } from "react-error-boundary"; -import DownloadSVGButton from "./DownloadSVGButton"; -import SvgDisplay from "./SvgDisplay"; -import UserOutput from "./UserOutput"; - -export default function AppTwo() { - const [textData, setTextData] = useState(""); - const [configData, setConfigData] = useState({ - useAutomation: true, - overallDrawConfig: { - seed: 0, - }, - }); - const [jsonResult, setJsonResult] = useState(null); - const [svgResult, setSvgResult] = useState(null); - const [failureBanner, setFailureBanner] = useState(""); - - const onTextDataSubmit = (event?) => { - event?.preventDefault(); - try { - setJsonResult(JSON.parse(textData)); - setFailureBanner(""); - } catch (error) { - const errorMessage = `Error parsing inputted JSON: ${error.message}`; - console.error(errorMessage); - setFailureBanner(errorMessage); - setJsonResult(null); - } - }; - - return ( - <> -
- - - - - {/* Put your component here! (And feel free to get rid of the border) */} - - - - ); -} diff --git a/demo/src/DownloadJSONButton.tsx b/demo/src/DownloadJSONButton.tsx deleted file mode 100644 index 838613a9..00000000 --- a/demo/src/DownloadJSONButton.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import React from "react"; -import { Button } from "@mui/material"; - -type DownloadJSONButtonPropTypes = { - jsonResult: string; - sx: object; -}; -export default function DownloadJSONButton(props: DownloadJSONButtonPropTypes) { - const file = new Blob([JSON.stringify(props.jsonResult, null, 2)], { - type: "application/JSON", - }); - - return ( - - ); -} diff --git a/demo/src/DownloadSVGButton.tsx b/demo/src/DownloadSVGButton.tsx deleted file mode 100644 index 00cf0a96..00000000 --- a/demo/src/DownloadSVGButton.tsx +++ /dev/null @@ -1,25 +0,0 @@ -import React from "react"; -import { Button } from "@mui/material"; - -type DownloadSVGButtonPropTypes = { - svgResult: string; -}; -export default function DownloadSVGButton(props: DownloadSVGButtonPropTypes) { - const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); - - return ( - - ); -} diff --git a/demo/src/MemoryModelsSample.tsx b/demo/src/MemoryModelsSample.tsx deleted file mode 100644 index fe528583..00000000 --- a/demo/src/MemoryModelsSample.tsx +++ /dev/null @@ -1,78 +0,0 @@ -import React, { useEffect, useState } from "react"; -import { - Accordion, - AccordionDetails, - AccordionSummary, - Button, - Card, - CardContent, - Grid, -} from "@mui/material"; -import { ExpandMore } from "@mui/icons-material"; - -import { SAMPLES } from "./sample"; - -type MemoryModelsSamplePropTypes = { - setTextData: React.Dispatch>; - setConfigData: React.Dispatch>; - onTextDataSubmit: () => void; -}; - -export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) { - const [clickedBtnIndex, setClickedBtnIndex] = useState(null); - - useEffect(() => { - if (clickedBtnIndex !== null) { - props.onTextDataSubmit(); - } - }, [clickedBtnIndex]); - - const handleButtonClick = (index: Number, sample: Object) => { - // Note: the following conversion to a string is inefficient, as the data is later parsed - // back into JSON for rendering. - // TODO: fix this. - props.setTextData(JSON.stringify(sample["data"], null, 4)); - props.setConfigData((prevConfigData) => ({ - ...prevConfigData, - ...sample["config"], - })); - setClickedBtnIndex(index); - }; - - return ( - - } - data-testid="sample-inputs-accordion" - > - Sample Inputs - - - - - - {SAMPLES.map((sample, index) => ( - - - - ))} - - - - - - ); -} diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx deleted file mode 100644 index 1f392135..00000000 --- a/demo/src/MemoryModelsUserInput.tsx +++ /dev/null @@ -1,249 +0,0 @@ -import React, { useState } from "react"; -import { - Accordion, - AccordionDetails, - AccordionSummary, - Button, - Card, - CardContent, - Checkbox, - FormControlLabel, - Grid, - Input, - Stack, - TextField, - Tooltip, -} from "@mui/material"; -import DownloadJSONButton from "./DownloadJSONButton"; -import { ExpandMore } from "@mui/icons-material"; - -interface configDataPropTypes { - useAutomation: boolean; - overallDrawConfig: { - [key: string]: any; - }; -} - -type MemoryModelsConfigInputPropTypes = { - configData: configDataPropTypes; - setConfigData: React.Dispatch>; -}; - -type MemoryModelsFileInputPropTypes = { - setTextData: React.Dispatch>; - textData: string; - setFailureBanner: React.Dispatch>; - jsonResult: string | null; -}; - -type MemoryModelsTextInputPropTypes = { - setTextData: React.Dispatch>; - textData: string; -}; - -type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes & - MemoryModelsTextInputPropTypes & - MemoryModelsConfigInputPropTypes & { - onTextDataSubmit: (event: React.MouseEvent) => void; - }; - -function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { - const [uploadedFileString, setUploadedFileString] = useState(""); - - const onChange = (event) => { - try { - const uploadedFile = event.target.files[0]; - const fileReader = new global.FileReader(); - fileReader.readAsText(uploadedFile, "UTF-8"); - fileReader.onload = (event) => { - const fileString = event.target.result as string; - setUploadedFileString(fileString); - props.setTextData(fileString); - }; - } catch (error) { - const errorMessage = `Error reading uploaded file as text. Please ensure it's in UTF-8 encoding: ${error.message}`; - console.error(errorMessage); - props.setTextData(null); - props.setFailureBanner(errorMessage); - } - }; - - const onLoadButtonClick = () => { - props.setTextData(uploadedFileString); - }; - - return ( - - - - - - - - ); -} - -function MemoryModelsTextInput(props: MemoryModelsTextInputPropTypes) { - const handleTextFieldChange = (event) => { - props.setTextData(event.target.value); - }; - - return ( - - - - ); -} - -//TODO: Retrieve min and max seeds from memory-viz -function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { - const handleSeedChange = (event) => { - event.preventDefault(); - props.setConfigData({ - ...props.configData, - overallDrawConfig: { - ...props.configData.overallDrawConfig, - seed: Number(event.target.value), - }, - }); - }; - - const handleAutomationChange = (event) => { - // Calling the common (among React event handlers) event.preventDefault() here - // will cause the checkbox to require double instead of single clicks, as verified by both UI and tests. - // Explained in https://grrr.tech/posts/2022/event-prevent-failure/#but-huh-why-does-this-work - props.setConfigData({ - ...props.configData, - useAutomation: event.target.checked, - }); - }; - - return ( - - - - - } - label="Use automatic layout" - sx={{ width: "50%" }} - /> - - - ); -} - -export default function MemoryModelsUserInput( - props: MemoryModelsUserInputPropTypes -) { - return ( -
- - - - - - - } - data-testid="rendering-options-accordion" - > - Rendering Options - - - - - - - - - - - - - - - -
- ); -} - -export { MemoryModelsFileInput }; -export type { configDataPropTypes }; diff --git a/demo/src/UserInput.tsx b/demo/src/UserInput.tsx index cd7707dc..18410dfd 100644 --- a/demo/src/UserInput.tsx +++ b/demo/src/UserInput.tsx @@ -2,7 +2,7 @@ import React from "react"; import { Box, Button, Link, Input, Typography, TextField } from "@mui/material"; import SampleInputMenu from "./SampleInputMenu"; -interface configDataPropTypes { +export interface configDataPropTypes { useAutomation: boolean; overallDrawConfig: { [key: string]: any; @@ -33,39 +33,6 @@ type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes & }; export default function UserInput(props: MemoryModelsUserInputPropTypes) { - const classes = { - inputBox: { - display: "flex", - flexDirection: "column", - }, - title: { - fontWeight: "600", - mb: "1rem", - }, - button1: { - width: "auto", - textTransform: "none", - }, - fileInputBox: { - display: "flex", - justifyContent: "space-between", - }, - textField: { - height: "auto", - "& .MuiInputBase-input": { - fontFamily: "Consolas, monospace", - background: "none !important", - }, - }, - inputBottomBox: { - display: "flex", - justifyContent: "space-between", - }, - input: { - width: "50%", - }, - }; - const onChange = (event) => { try { const uploadedFile = event.target.files[0]; @@ -92,11 +59,22 @@ export default function UserInput(props: MemoryModelsUserInputPropTypes) { }; return ( - - + <> + Input - + - + Draw Diagram - + ); } diff --git a/demo/src/UserOutput.tsx b/demo/src/UserOutput.tsx index 3497b63e..a390a814 100644 --- a/demo/src/UserOutput.tsx +++ b/demo/src/UserOutput.tsx @@ -1,6 +1,6 @@ import React from "react"; import SvgDisplay from "./SvgDisplay"; -import { configDataPropTypes } from "./MemoryModelsUserInput"; +import { configDataPropTypes } from "./UserInput"; import { Box, Typography, @@ -19,39 +19,6 @@ type OutputPropTypes = { }; export default function Output(props: OutputPropTypes) { - const classes = { - inputBox: { - display: "flex", - flexDirection: "column", - }, - title: { - fontWeight: "600", - mb: "1rem", - }, - button1: { - width: "auto", - textTransform: "none", - }, - fileInputBox: { - display: "flex", - justifyContent: "space-between", - }, - textField: { - height: "auto", - "& .MuiInputBase-input": { - fontFamily: "Consolas, monospace", - background: "none !important", - }, - }, - inputBottomBox: { - display: "flex", - justifyContent: "space-between", - }, - input: { - width: "50%", - }, - }; - const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); const handleSeedChange = (event) => { @@ -76,13 +43,12 @@ export default function Output(props: OutputPropTypes) { return ( <> - + Output diff --git a/demo/src/index.tsx b/demo/src/index.tsx index 692f8af3..b3ec1e30 100644 --- a/demo/src/index.tsx +++ b/demo/src/index.tsx @@ -4,7 +4,6 @@ import App from "./App"; import "@picocss/pico"; import "./css/styles"; -import AppTwo from "./AppTwo"; import { ThemeProvider, createTheme } from "@mui/material/styles"; const theme = createTheme({ palette: { @@ -23,7 +22,7 @@ const root = createRoot(document.getElementById("root")); root.render( - + ); diff --git a/demo/src/output.tsx b/demo/src/output.tsx deleted file mode 100644 index f3a3eafe..00000000 --- a/demo/src/output.tsx +++ /dev/null @@ -1,85 +0,0 @@ -import React, { useRef, useEffect, useState } from "react"; -import SvgDisplay from "./SvgDisplay"; -import { configDataPropTypes } from "./MemoryModelsUserInput"; -import { - Box, - Typography, - Link, - Grid, - TextField, - FormControlLabel, - Checkbox, -} from "@mui/material"; - -type OutputPropTypes = { - jsonResult: object | null; - configData: configDataPropTypes; - setConfigData: React.Dispatch>; - setSvgResult: React.Dispatch>; - svgResult: string; -}; - -export default function Output(props: OutputPropTypes) { - const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); - - const handleSeedChange = (event) => { - props.setConfigData({ - ...props.configData, - overallDrawConfig: { - ...props.configData.overallDrawConfig, - seed: Number(event.target.value), - }, - }); - }; - - const handleAutomationChange = (event) => { - // Calling the common (among React event handlers) event.preventDefault() here - // will cause the checkbox to require double instead of single clicks, as verified by both UI and tests. - // Explained in https://grrr.tech/posts/2022/event-prevent-failure/#but-huh-why-does-this-work - props.setConfigData({ - ...props.configData, - useAutomation: event.target.checked, - }); - }; - - return ( - <> - -

Output

-
- - - - } - label="Use automatic layout" - sx={{ marginLeft: 15, marginTop: 6 }} - /> - - - - {"Download SVG"} - - - ); -} From 743771e9f10d6f595d6fd238eae1ae0fdb6bf1e1 Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Sun, 11 Aug 2024 19:44:16 -0400 Subject: [PATCH 11/31] update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5142b9da..3e662145 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,8 @@ and adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ### 📚 Documentation and demo website changes +- Reformatted demo website to horizontal layout. + ### 🔧 Internal changes ## [0.3.0] - 2024-08-02 From 2494bfb11c8168080f8ee754fc6632db275f5b09 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Mon, 12 Aug 2024 16:05:31 -0400 Subject: [PATCH 12/31] NEVER GIVE UP --- demo/src/App.tsx | 69 ++++---- demo/src/AppTwo.tsx | 66 ++++++++ demo/src/DownloadJSONButton.tsx | 28 ++++ demo/src/DownloadSVGButton.tsx | 25 +++ demo/src/MemoryModelsSample.tsx | 78 +++++++++ demo/src/MemoryModelsUserInput.tsx | 249 +++++++++++++++++++++++++++++ demo/src/UserInput.tsx | 1 - demo/src/css/styles.css | 3 + 8 files changed, 490 insertions(+), 29 deletions(-) create mode 100644 demo/src/AppTwo.tsx create mode 100644 demo/src/DownloadJSONButton.tsx create mode 100644 demo/src/DownloadSVGButton.tsx create mode 100644 demo/src/MemoryModelsSample.tsx create mode 100644 demo/src/MemoryModelsUserInput.tsx diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 98aaeef9..7b67ab0c 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -1,10 +1,12 @@ import React, { useState } from "react"; -import { configDataPropTypes } from "./UserInput"; -import UserInput from "./UserInput"; -import Header from "./Header"; -import { Box } from "@mui/material"; +import SvgDisplay from "./SvgDisplay"; +import MemoryModelsUserInput from "./MemoryModelsUserInput"; import { ErrorBoundary } from "react-error-boundary"; -import UserOutput from "./UserOutput"; +import DownloadSVGButton from "./DownloadSVGButton"; +import { Alert } from "@mui/material"; +import { configDataPropTypes } from "./MemoryModelsUserInput"; +import MemoryModelsSample from "./MemoryModelsSample"; +import Header from "./Header"; export default function App() { const [textData, setTextData] = useState(""); @@ -34,33 +36,44 @@ export default function App() { return ( <>
- - - - - - + {failureBanner} + + )} + + +
+

Output

+ + + This is valid JSON but not valid Memory Models JSON. + Please refer to the repo for more details. +

+ } + key={jsonResult} + > + - - +
+
); } diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx new file mode 100644 index 00000000..81791b82 --- /dev/null +++ b/demo/src/AppTwo.tsx @@ -0,0 +1,66 @@ +import React, { useState } from "react"; +import { configDataPropTypes } from "./UserInput"; +import UserInput from "./UserInput"; +import Header from "./Header"; +import { Box } from "@mui/material"; +import { ErrorBoundary } from "react-error-boundary"; +import UserOutput from "./UserOutput"; + +export default function AppTwo() { + const [textData, setTextData] = useState(""); + const [configData, setConfigData] = useState({ + useAutomation: true, + overallDrawConfig: { + seed: 0, + }, + }); + const [jsonResult, setJsonResult] = useState(null); + const [svgResult, setSvgResult] = useState(null); + const [failureBanner, setFailureBanner] = useState(""); + + const onTextDataSubmit = (event?) => { + event?.preventDefault(); + try { + setJsonResult(JSON.parse(textData)); + setFailureBanner(""); + } catch (error) { + const errorMessage = `Error parsing inputted JSON: ${error.message}`; + console.error(errorMessage); + setFailureBanner(errorMessage); + setJsonResult(null); + } + }; + + return ( + <> +
+ + + + + + + + + + ); +} diff --git a/demo/src/DownloadJSONButton.tsx b/demo/src/DownloadJSONButton.tsx new file mode 100644 index 00000000..838613a9 --- /dev/null +++ b/demo/src/DownloadJSONButton.tsx @@ -0,0 +1,28 @@ +import React from "react"; +import { Button } from "@mui/material"; + +type DownloadJSONButtonPropTypes = { + jsonResult: string; + sx: object; +}; +export default function DownloadJSONButton(props: DownloadJSONButtonPropTypes) { + const file = new Blob([JSON.stringify(props.jsonResult, null, 2)], { + type: "application/JSON", + }); + + return ( + + ); +} diff --git a/demo/src/DownloadSVGButton.tsx b/demo/src/DownloadSVGButton.tsx new file mode 100644 index 00000000..00cf0a96 --- /dev/null +++ b/demo/src/DownloadSVGButton.tsx @@ -0,0 +1,25 @@ +import React from "react"; +import { Button } from "@mui/material"; + +type DownloadSVGButtonPropTypes = { + svgResult: string; +}; +export default function DownloadSVGButton(props: DownloadSVGButtonPropTypes) { + const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); + + return ( + + ); +} diff --git a/demo/src/MemoryModelsSample.tsx b/demo/src/MemoryModelsSample.tsx new file mode 100644 index 00000000..fe528583 --- /dev/null +++ b/demo/src/MemoryModelsSample.tsx @@ -0,0 +1,78 @@ +import React, { useEffect, useState } from "react"; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Button, + Card, + CardContent, + Grid, +} from "@mui/material"; +import { ExpandMore } from "@mui/icons-material"; + +import { SAMPLES } from "./sample"; + +type MemoryModelsSamplePropTypes = { + setTextData: React.Dispatch>; + setConfigData: React.Dispatch>; + onTextDataSubmit: () => void; +}; + +export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) { + const [clickedBtnIndex, setClickedBtnIndex] = useState(null); + + useEffect(() => { + if (clickedBtnIndex !== null) { + props.onTextDataSubmit(); + } + }, [clickedBtnIndex]); + + const handleButtonClick = (index: Number, sample: Object) => { + // Note: the following conversion to a string is inefficient, as the data is later parsed + // back into JSON for rendering. + // TODO: fix this. + props.setTextData(JSON.stringify(sample["data"], null, 4)); + props.setConfigData((prevConfigData) => ({ + ...prevConfigData, + ...sample["config"], + })); + setClickedBtnIndex(index); + }; + + return ( + + } + data-testid="sample-inputs-accordion" + > + Sample Inputs + + + + + + {SAMPLES.map((sample, index) => ( + + + + ))} + + + + + + ); +} diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx new file mode 100644 index 00000000..1f392135 --- /dev/null +++ b/demo/src/MemoryModelsUserInput.tsx @@ -0,0 +1,249 @@ +import React, { useState } from "react"; +import { + Accordion, + AccordionDetails, + AccordionSummary, + Button, + Card, + CardContent, + Checkbox, + FormControlLabel, + Grid, + Input, + Stack, + TextField, + Tooltip, +} from "@mui/material"; +import DownloadJSONButton from "./DownloadJSONButton"; +import { ExpandMore } from "@mui/icons-material"; + +interface configDataPropTypes { + useAutomation: boolean; + overallDrawConfig: { + [key: string]: any; + }; +} + +type MemoryModelsConfigInputPropTypes = { + configData: configDataPropTypes; + setConfigData: React.Dispatch>; +}; + +type MemoryModelsFileInputPropTypes = { + setTextData: React.Dispatch>; + textData: string; + setFailureBanner: React.Dispatch>; + jsonResult: string | null; +}; + +type MemoryModelsTextInputPropTypes = { + setTextData: React.Dispatch>; + textData: string; +}; + +type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes & + MemoryModelsTextInputPropTypes & + MemoryModelsConfigInputPropTypes & { + onTextDataSubmit: (event: React.MouseEvent) => void; + }; + +function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { + const [uploadedFileString, setUploadedFileString] = useState(""); + + const onChange = (event) => { + try { + const uploadedFile = event.target.files[0]; + const fileReader = new global.FileReader(); + fileReader.readAsText(uploadedFile, "UTF-8"); + fileReader.onload = (event) => { + const fileString = event.target.result as string; + setUploadedFileString(fileString); + props.setTextData(fileString); + }; + } catch (error) { + const errorMessage = `Error reading uploaded file as text. Please ensure it's in UTF-8 encoding: ${error.message}`; + console.error(errorMessage); + props.setTextData(null); + props.setFailureBanner(errorMessage); + } + }; + + const onLoadButtonClick = () => { + props.setTextData(uploadedFileString); + }; + + return ( + + + + + + + + ); +} + +function MemoryModelsTextInput(props: MemoryModelsTextInputPropTypes) { + const handleTextFieldChange = (event) => { + props.setTextData(event.target.value); + }; + + return ( + + + + ); +} + +//TODO: Retrieve min and max seeds from memory-viz +function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { + const handleSeedChange = (event) => { + event.preventDefault(); + props.setConfigData({ + ...props.configData, + overallDrawConfig: { + ...props.configData.overallDrawConfig, + seed: Number(event.target.value), + }, + }); + }; + + const handleAutomationChange = (event) => { + // Calling the common (among React event handlers) event.preventDefault() here + // will cause the checkbox to require double instead of single clicks, as verified by both UI and tests. + // Explained in https://grrr.tech/posts/2022/event-prevent-failure/#but-huh-why-does-this-work + props.setConfigData({ + ...props.configData, + useAutomation: event.target.checked, + }); + }; + + return ( + + + + + } + label="Use automatic layout" + sx={{ width: "50%" }} + /> + + + ); +} + +export default function MemoryModelsUserInput( + props: MemoryModelsUserInputPropTypes +) { + return ( +
+ + + + + + + } + data-testid="rendering-options-accordion" + > + Rendering Options + + + + + + + + + + + + + + + +
+ ); +} + +export { MemoryModelsFileInput }; +export type { configDataPropTypes }; diff --git a/demo/src/UserInput.tsx b/demo/src/UserInput.tsx index 18410dfd..610d019b 100644 --- a/demo/src/UserInput.tsx +++ b/demo/src/UserInput.tsx @@ -97,7 +97,6 @@ export default function UserInput(props: MemoryModelsUserInputPropTypes) { variant="outlined" multiline fullWidth - rows={10} value={props.textData} onChange={handleTextFieldChange} sx={{ diff --git a/demo/src/css/styles.css b/demo/src/css/styles.css index 54b4787c..a8ea656a 100644 --- a/demo/src/css/styles.css +++ b/demo/src/css/styles.css @@ -17,3 +17,6 @@ body { #root { padding: 1rem; } +:where(input, select, textarea):not([type="week"])[aria-invalid="false"] { + background-image: none; +} From 1df981b44ae882c2f67bf75f3fcb7489fcca1f97 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Mon, 12 Aug 2024 16:42:54 -0400 Subject: [PATCH 13/31] destruction, part 1 of any --- demo/src/App.tsx | 67 ++++++++++++++------------- demo/src/MemoryModelsUserInput.tsx | 74 +++++++++++------------------- 2 files changed, 64 insertions(+), 77 deletions(-) diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 7b67ab0c..d93b174f 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -7,6 +7,7 @@ import { Alert } from "@mui/material"; import { configDataPropTypes } from "./MemoryModelsUserInput"; import MemoryModelsSample from "./MemoryModelsSample"; import Header from "./Header"; +import { Box } from "@mui/material"; export default function App() { const [textData, setTextData] = useState(""); @@ -41,39 +42,43 @@ export default function App() { {failureBanner} )} - - -
-

Output

- - - This is valid JSON but not valid Memory Models JSON. - Please refer to the repo for more details. -

- } - key={jsonResult} - > - + + + -
-
+ + +

Output

+ + + This is valid JSON but not valid Memory Models + JSON. Please refer to the repo for more details. +

+ } + key={jsonResult} + > + +
+
+ ); } diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx index 1f392135..68ab9aa5 100644 --- a/demo/src/MemoryModelsUserInput.tsx +++ b/demo/src/MemoryModelsUserInput.tsx @@ -195,52 +195,34 @@ export default function MemoryModelsUserInput( ) { return (
- - - - - - - } - data-testid="rendering-options-accordion" - > - Rendering Options - - - - - - - - - - - - - - - + + + + + + + + ); } From 17e41df7ee0067e5ab18375b50ba20fa648da2d0 Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Mon, 12 Aug 2024 17:39:29 -0400 Subject: [PATCH 14/31] update buttons --- demo/src/App.tsx | 2 +- demo/src/DownloadJSONButton.tsx | 4 ++-- demo/src/DownloadSVGButton.tsx | 3 +-- demo/src/MemoryModelsUserInput.tsx | 8 ++++---- 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/demo/src/App.tsx b/demo/src/App.tsx index d93b174f..98953593 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -61,7 +61,6 @@ export default function App() {

Output

- @@ -77,6 +76,7 @@ export default function App() { setSvgResult={setSvgResult} /> +
diff --git a/demo/src/DownloadJSONButton.tsx b/demo/src/DownloadJSONButton.tsx index 838613a9..0ac0b339 100644 --- a/demo/src/DownloadJSONButton.tsx +++ b/demo/src/DownloadJSONButton.tsx @@ -12,7 +12,7 @@ export default function DownloadJSONButton(props: DownloadJSONButtonPropTypes) { return ( diff --git a/demo/src/DownloadSVGButton.tsx b/demo/src/DownloadSVGButton.tsx index 00cf0a96..9ee36855 100644 --- a/demo/src/DownloadSVGButton.tsx +++ b/demo/src/DownloadSVGButton.tsx @@ -9,8 +9,7 @@ export default function DownloadSVGButton(props: DownloadSVGButtonPropTypes) { return ( - ); @@ -211,6 +207,10 @@ export default function MemoryModelsUserInput( /> + - + ); From 1fcc51b65152189cd33559c67cc42edd7683cf47 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Mon, 12 Aug 2024 17:57:33 -0400 Subject: [PATCH 16/31] updated styling on input, slight modification to tests --- demo/src/MemoryModelsSample.tsx | 82 +++---- demo/src/MemoryModelsUserInput.tsx | 229 ++++++++++-------- demo/src/SampleInputMenu.tsx | 77 ------ .../src/__tests__/MemoryModelsSample.spec.tsx | 12 +- .../__tests__/MemoryModelsUserInput.spec.tsx | 3 + 5 files changed, 176 insertions(+), 227 deletions(-) delete mode 100644 demo/src/SampleInputMenu.tsx diff --git a/demo/src/MemoryModelsSample.tsx b/demo/src/MemoryModelsSample.tsx index fe528583..cead1b4d 100644 --- a/demo/src/MemoryModelsSample.tsx +++ b/demo/src/MemoryModelsSample.tsx @@ -1,14 +1,6 @@ import React, { useEffect, useState } from "react"; -import { - Accordion, - AccordionDetails, - AccordionSummary, - Button, - Card, - CardContent, - Grid, -} from "@mui/material"; -import { ExpandMore } from "@mui/icons-material"; +import { Button, Menu, MenuItem } from "@mui/material"; +import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded"; import { SAMPLES } from "./sample"; @@ -20,6 +12,14 @@ type MemoryModelsSamplePropTypes = { export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) { const [clickedBtnIndex, setClickedBtnIndex] = useState(null); + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; useEffect(() => { if (clickedBtnIndex !== null) { @@ -40,39 +40,39 @@ export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) { }; return ( - - } + <> + - - ))} - - - - - + + + + {SAMPLES.map((sample, index) => ( + handleButtonClick(index, sample)} + > + {sample["name"]} + + ))} + + ); } diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx index fa1d4613..5b7980bc 100644 --- a/demo/src/MemoryModelsUserInput.tsx +++ b/demo/src/MemoryModelsUserInput.tsx @@ -1,22 +1,17 @@ import React, { useState } from "react"; import { - Accordion, - AccordionDetails, - AccordionSummary, - Button, Box, - Card, - CardContent, + Button, Checkbox, FormControlLabel, - Grid, Input, - Stack, TextField, Tooltip, + Menu, + MenuItem, } from "@mui/material"; import DownloadJSONButton from "./DownloadJSONButton"; -import { ExpandMore } from "@mui/icons-material"; +import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded"; interface configDataPropTypes { useAutomation: boolean; @@ -74,32 +69,27 @@ function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { }; return ( - - + + - - + Load file data + + ); } @@ -109,29 +99,35 @@ function MemoryModelsTextInput(props: MemoryModelsTextInputPropTypes) { }; return ( - - - + ); } //TODO: Retrieve min and max seeds from memory-viz function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; const handleSeedChange = (event) => { event.preventDefault(); props.setConfigData({ @@ -154,36 +150,62 @@ function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { }; return ( - - - - - } - label="Use automatic layout" - sx={{ width: "50%" }} - /> - - + <> + + + + + + + + } + label="Use automatic layout" + sx={{ width: "50%" }} + /> + + + ); } @@ -206,29 +228,26 @@ export default function MemoryModelsUserInput( textData={props.textData} setTextData={props.setTextData} /> - - - - - - + + + + + + + + ); } diff --git a/demo/src/SampleInputMenu.tsx b/demo/src/SampleInputMenu.tsx deleted file mode 100644 index 727813f1..00000000 --- a/demo/src/SampleInputMenu.tsx +++ /dev/null @@ -1,77 +0,0 @@ -import React, { useState, useEffect } from "react"; -import { Button, Menu, MenuItem } from "@mui/material"; -import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded"; -import { SAMPLES } from "./sample"; - -type MemoryModelsSamplePropTypes = { - setTextData: React.Dispatch>; - setConfigData: React.Dispatch>; - onTextDataSubmit: () => void; -}; - -export default function SampleInputMenu(props: MemoryModelsSamplePropTypes) { - const [anchorEl, setAnchorEl] = useState(null); - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; - const [clickedBtnIndex, setClickedBtnIndex] = useState(null); - - useEffect(() => { - if (clickedBtnIndex !== null) { - props.onTextDataSubmit(); - } - }, [clickedBtnIndex]); - - const classes = { - button: { - textTransform: "none", - "& .MuiSvgIcon-root": { - transition: "transform 0.2s ease-in-out", - transform: open ? "rotate(180deg)" : "rotate(0deg)", - }, - }, - }; - - const handleButtonClick = (index: Number, sample: Object) => { - // Note: the following conversion to a string is inefficient, as the data is later parsed - // back into JSON for rendering. - // TODO: fix this. - props.setTextData(JSON.stringify(sample["data"], null, 4)); - props.setConfigData((prevConfigData) => ({ - ...prevConfigData, - ...sample["config"], - })); - setClickedBtnIndex(index); - }; - - return ( -
- - - {SAMPLES.map((sample, index) => ( - handleButtonClick(index, sample)} - > - {sample["name"]} - - ))} - -
- ); -} diff --git a/demo/src/__tests__/MemoryModelsSample.spec.tsx b/demo/src/__tests__/MemoryModelsSample.spec.tsx index 933207c7..6f9b0028 100644 --- a/demo/src/__tests__/MemoryModelsSample.spec.tsx +++ b/demo/src/__tests__/MemoryModelsSample.spec.tsx @@ -44,16 +44,20 @@ describe("MemoryModelsSample", () => { expect(screen.getByText("Sample Inputs")).toBeDefined(); }); - it("renders all sample buttons", () => { + it("renders all sample buttons", async () => { // sx for MUI comps or non-inline CSS in general will not be loaded into Jest by default // might be achievable with some libs but this test makes sure the base texts are present. // Therefore, we can't test for capitalization (via sx) here - SAMPLES.map((sample) => - expect(screen.getByText(sample["name"])).toBeDefined() - ); + fireEvent.click(screen.getByText("Sample Inputs")); + await waitFor(() => { + SAMPLES.map((sample) => + expect(screen.getByText(sample["name"])).toBeDefined() + ); + }); }); it("handles sample button click", async () => { + fireEvent.click(screen.getByText("Sample Inputs")); const button = screen.getByText("Automated Layout"); fireEvent.click(button); diff --git a/demo/src/__tests__/MemoryModelsUserInput.spec.tsx b/demo/src/__tests__/MemoryModelsUserInput.spec.tsx index 9f580016..245b7327 100644 --- a/demo/src/__tests__/MemoryModelsUserInput.spec.tsx +++ b/demo/src/__tests__/MemoryModelsUserInput.spec.tsx @@ -223,6 +223,7 @@ describe("MemoryModelsUserInput", () => { }); it("renders a number input with correct props and checkbox that is checked by default", () => { + fireEvent.click(screen.getByText("Rendering Options")); const seedInput: HTMLInputElement = screen.getByTestId("config-seed"); [ @@ -242,6 +243,7 @@ describe("MemoryModelsUserInput", () => { }); it("handles seed change", () => { + fireEvent.click(screen.getByText("Rendering Options")); const seedInput: HTMLInputElement = screen.getByTestId("config-seed"); const mockSeed = "123"; @@ -256,6 +258,7 @@ describe("MemoryModelsUserInput", () => { }); it("handles automation change", () => { + fireEvent.click(screen.getByText("Rendering Options")); const automationCheckbox: HTMLInputElement = screen.getByLabelText( "Use automatic layout" ); From 6bbacee67c3083ecd331ea791bd76d32571534bb Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Mon, 12 Aug 2024 18:17:35 -0400 Subject: [PATCH 17/31] input updates part 2 --- demo/src/App.tsx | 5 -- demo/src/MemoryModelsUserInput.tsx | 25 ++++-- demo/src/UserInput.tsx | 138 ----------------------------- 3 files changed, 16 insertions(+), 152 deletions(-) delete mode 100644 demo/src/UserInput.tsx diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 98953593..eaf5be9b 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -44,11 +44,6 @@ export default function App() { )} - ) => void; + onTextDataSubmit: () => void; }; function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { @@ -69,7 +70,7 @@ function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { }; return ( - <> + - + ); } @@ -220,10 +220,17 @@ export default function MemoryModelsUserInput( setFailureBanner={props.setFailureBanner} jsonResult={props.jsonResult} /> - + + + + >; -}; - -type MemoryModelsFileInputPropTypes = { - setTextData: React.Dispatch>; - textData: string; - setFailureBanner: React.Dispatch>; - jsonResult: string | null; -}; - -type MemoryModelsTextInputPropTypes = { - setTextData: React.Dispatch>; - textData: string; -}; - -type MemoryModelsUserInputPropTypes = MemoryModelsFileInputPropTypes & - MemoryModelsTextInputPropTypes & - MemoryModelsConfigInputPropTypes & { - onTextDataSubmit: () => void; - }; - -export default function UserInput(props: MemoryModelsUserInputPropTypes) { - const onChange = (event) => { - try { - const uploadedFile = event.target.files[0]; - const fileReader = new global.FileReader(); - fileReader.readAsText(uploadedFile, "UTF-8"); - fileReader.onload = (event) => { - const fileString = event.target.result as string; - props.setTextData(fileString); - }; - } catch (error) { - const errorMessage = `Error reading uploaded file as text. Please ensure it's in UTF-8 encoding: ${error.message}`; - console.error(errorMessage); - props.setTextData(null); - props.setFailureBanner(errorMessage); - } - }; - - const file = new Blob([JSON.stringify(props.jsonResult, null, 2)], { - type: "application/JSON", - }); - - const handleTextFieldChange = (event) => { - props.setTextData(event.target.value); - }; - - return ( - <> - - Input - - - - - - - - - - Download JSON - - - - - ); -} From d9aaecf29bd61e7c1f08989b9f81970bcdbd37b3 Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Mon, 12 Aug 2024 18:28:43 -0400 Subject: [PATCH 18/31] make seed shorter --- demo/src/MemoryModelsUserInput.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx index f6cf1d61..fa815af8 100644 --- a/demo/src/MemoryModelsUserInput.tsx +++ b/demo/src/MemoryModelsUserInput.tsx @@ -180,8 +180,8 @@ function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { id="config-seed" variant="outlined" value={props.configData.overallDrawConfig.seed} - onChange={handleSeedChange} type="number" + onChange={handleSeedChange} InputProps={{ inputProps: { min: 0, @@ -189,7 +189,10 @@ function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { "data-testid": "config-seed", }, }} - sx={{ width: "50%" }} + sx={{ + width: "50%", + "& .MuiInputBase-input": { height: "10%" }, + }} /> From c564312705481c6a68df886be29d71243f6d4f46 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Mon, 12 Aug 2024 18:34:53 -0400 Subject: [PATCH 19/31] delete obsolete files --- demo/src/AppTwo.tsx | 66 ------------------------------- demo/src/UserOutput.tsx | 88 ----------------------------------------- 2 files changed, 154 deletions(-) delete mode 100644 demo/src/AppTwo.tsx delete mode 100644 demo/src/UserOutput.tsx diff --git a/demo/src/AppTwo.tsx b/demo/src/AppTwo.tsx deleted file mode 100644 index 81791b82..00000000 --- a/demo/src/AppTwo.tsx +++ /dev/null @@ -1,66 +0,0 @@ -import React, { useState } from "react"; -import { configDataPropTypes } from "./UserInput"; -import UserInput from "./UserInput"; -import Header from "./Header"; -import { Box } from "@mui/material"; -import { ErrorBoundary } from "react-error-boundary"; -import UserOutput from "./UserOutput"; - -export default function AppTwo() { - const [textData, setTextData] = useState(""); - const [configData, setConfigData] = useState({ - useAutomation: true, - overallDrawConfig: { - seed: 0, - }, - }); - const [jsonResult, setJsonResult] = useState(null); - const [svgResult, setSvgResult] = useState(null); - const [failureBanner, setFailureBanner] = useState(""); - - const onTextDataSubmit = (event?) => { - event?.preventDefault(); - try { - setJsonResult(JSON.parse(textData)); - setFailureBanner(""); - } catch (error) { - const errorMessage = `Error parsing inputted JSON: ${error.message}`; - console.error(errorMessage); - setFailureBanner(errorMessage); - setJsonResult(null); - } - }; - - return ( - <> -
- - - - - - - - - - ); -} diff --git a/demo/src/UserOutput.tsx b/demo/src/UserOutput.tsx deleted file mode 100644 index a390a814..00000000 --- a/demo/src/UserOutput.tsx +++ /dev/null @@ -1,88 +0,0 @@ -import React from "react"; -import SvgDisplay from "./SvgDisplay"; -import { configDataPropTypes } from "./UserInput"; -import { - Box, - Typography, - Link, - TextField, - FormControlLabel, - Checkbox, -} from "@mui/material"; - -type OutputPropTypes = { - jsonResult: object | null; - configData: configDataPropTypes; - setConfigData: React.Dispatch>; - svgResult: string; - setSvgResult: React.Dispatch>; -}; - -export default function Output(props: OutputPropTypes) { - const file = new global.Blob([props.svgResult], { type: "image/svg+xml" }); - - const handleSeedChange = (event) => { - props.setConfigData({ - ...props.configData, - overallDrawConfig: { - ...props.configData.overallDrawConfig, - seed: Number(event.target.value), - }, - }); - }; - - const handleAutomationChange = (event) => { - // Calling the common (among React event handlers) event.preventDefault() here - // will cause the checkbox to require double instead of single clicks, as verified by both UI and tests. - // Explained in https://grrr.tech/posts/2022/event-prevent-failure/#but-huh-why-does-this-work - props.setConfigData({ - ...props.configData, - useAutomation: event.target.checked, - }); - }; - - return ( - <> - - Output - - - - - } - label="Use automatic layout" - sx={{ marginLeft: 15 }} - /> - - - - {"Download SVG"} - - - ); -} From 3611462627749af7cfcda8a43d080c458aff6dc7 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Mon, 12 Aug 2024 19:04:39 -0400 Subject: [PATCH 20/31] add box to header --- demo/src/Header.tsx | 59 ++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 25 deletions(-) diff --git a/demo/src/Header.tsx b/demo/src/Header.tsx index d838eb49..9ea2ae7b 100644 --- a/demo/src/Header.tsx +++ b/demo/src/Header.tsx @@ -3,32 +3,41 @@ import { Box, Link, Typography } from "@mui/material"; export default function Header() { return ( - - - MemoryViz Demo - - - Demos of the{" "} - + + - MemoryViz - {" "} - Javascript library for visualizing Python memory. Click{" "} - - here - {" "} - for documentation. - + MemoryViz Demo + + + Demos of the{" "} + + MemoryViz + {" "} + Javascript library for visualizing Python memory. Click{" "} + + here + {" "} + for documentation. + + + ); } From 15d95c080c84d4f2674e40125c0f511bf432d158 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Mon, 12 Aug 2024 19:15:36 -0400 Subject: [PATCH 21/31] menu reordering --- demo/src/App.tsx | 5 +++++ demo/src/MemoryModelsUserInput.tsx | 18 +++++------------- 2 files changed, 10 insertions(+), 13 deletions(-) diff --git a/demo/src/App.tsx b/demo/src/App.tsx index eaf5be9b..98953593 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -44,6 +44,11 @@ export default function App() { )} + void; + onTextDataSubmit: (event: React.MouseEvent) => void; }; function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { @@ -223,17 +222,10 @@ export default function MemoryModelsUserInput( setFailureBanner={props.setFailureBanner} jsonResult={props.jsonResult} /> - - - - + Date: Tue, 13 Aug 2024 01:57:57 -0400 Subject: [PATCH 22/31] add image and related files, rename tests --- demo/jest.config.ts | 3 + demo/src/App.tsx | 11 ++-- demo/src/DownloadJSONButton.tsx | 2 +- demo/src/DownloadSVGButton.tsx | 2 +- demo/src/Header.tsx | 11 +++- demo/src/MemoryModelsSample.tsx | 12 +--- demo/src/MemoryModelsUserInput.tsx | 14 +---- demo/src/SvgDisplay.tsx | 55 +++++++++---------- demo/src/__tests__/App.spec.tsx | 2 +- .../src/__tests__/DownloadJSONButton.spec.tsx | 2 +- demo/src/__tests__/DownloadSVGButton.spec.tsx | 2 +- .../src/__tests__/MemoryModelsSample.spec.tsx | 8 +-- .../__tests__/MemoryModelsUserInput.spec.tsx | 4 +- demo/src/declerations.d.ts | 5 ++ demo/src/mocks/fileMock.js | 2 + 15 files changed, 67 insertions(+), 68 deletions(-) create mode 100644 demo/src/declerations.d.ts create mode 100644 demo/src/mocks/fileMock.js diff --git a/demo/jest.config.ts b/demo/jest.config.ts index 2b313f7c..0a1fabdf 100644 --- a/demo/jest.config.ts +++ b/demo/jest.config.ts @@ -93,6 +93,9 @@ const config: Config = { // Force module roughjs to resolve with the CJS entry point, because Jest does not support package.json.exports. Elaborated in PR#15. roughjs: require.resolve("roughjs"), "memory-viz": require.resolve("../memory-viz/src"), + // Mocks a file (see fileMock.js) each time any of the below file types are imported. + "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": + "./mocks/fileMock.js", }, // An array of regexp pattern strings, matched against all module paths before considered 'visible' to the module loader diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 98953593..fb625df5 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -1,4 +1,5 @@ import React, { useState } from "react"; +import { Box } from "@mui/material"; import SvgDisplay from "./SvgDisplay"; import MemoryModelsUserInput from "./MemoryModelsUserInput"; import { ErrorBoundary } from "react-error-boundary"; @@ -7,7 +8,6 @@ import { Alert } from "@mui/material"; import { configDataPropTypes } from "./MemoryModelsUserInput"; import MemoryModelsSample from "./MemoryModelsSample"; import Header from "./Header"; -import { Box } from "@mui/material"; export default function App() { const [textData, setTextData] = useState(""); @@ -42,8 +42,9 @@ export default function App() { {failureBanner} )} - - + + +

Input

- -

Output

+ +

Output

diff --git a/demo/src/DownloadJSONButton.tsx b/demo/src/DownloadJSONButton.tsx index 0ac0b339..96d316f8 100644 --- a/demo/src/DownloadJSONButton.tsx +++ b/demo/src/DownloadJSONButton.tsx @@ -22,7 +22,7 @@ export default function DownloadJSONButton(props: DownloadJSONButtonPropTypes) { href={window.URL.createObjectURL(file)} sx={{ ...props.sx, textTransform: "none", textAlign: "center" }} > - Download This JSON + Download JSON ); } diff --git a/demo/src/DownloadSVGButton.tsx b/demo/src/DownloadSVGButton.tsx index 9ee36855..c7e79271 100644 --- a/demo/src/DownloadSVGButton.tsx +++ b/demo/src/DownloadSVGButton.tsx @@ -18,7 +18,7 @@ export default function DownloadSVGButton(props: DownloadSVGButtonPropTypes) { download="output.svg" sx={{ textTransform: "none" }} > - Download This SVG + Download SVG ); } diff --git a/demo/src/Header.tsx b/demo/src/Header.tsx index 9ea2ae7b..d762e573 100644 --- a/demo/src/Header.tsx +++ b/demo/src/Header.tsx @@ -1,5 +1,6 @@ import React from "react"; import { Box, Link, Typography } from "@mui/material"; +import image from "../../assets/logo_square.png"; export default function Header() { return ( @@ -7,6 +8,7 @@ export default function Header() { sx={{ display: "flex", justifyContent: "space-between", + alignItems: "center", mb: "1rem", }} > @@ -37,7 +39,14 @@ export default function Header() { for documentation.
- + MemoryViz Logo
); } diff --git a/demo/src/MemoryModelsSample.tsx b/demo/src/MemoryModelsSample.tsx index cead1b4d..39e1c75d 100644 --- a/demo/src/MemoryModelsSample.tsx +++ b/demo/src/MemoryModelsSample.tsx @@ -43,7 +43,7 @@ export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) { <> - + {SAMPLES.map((sample, index) => ( - + - - - - - - + + + ); } diff --git a/demo/src/__tests__/App.spec.tsx b/demo/src/__tests__/App.spec.tsx index 315abcc8..1c99ec2d 100644 --- a/demo/src/__tests__/App.spec.tsx +++ b/demo/src/__tests__/App.spec.tsx @@ -9,7 +9,7 @@ describe("App", () => { }); it("renders Output heading", () => { - expect(screen.getByText("Output").nodeName).toEqual("H2"); + expect(screen.getByText("Output").nodeName).toEqual("H3"); }); it("renders ErrorBoundary fallback element when draw function throws error", () => { diff --git a/demo/src/__tests__/DownloadJSONButton.spec.tsx b/demo/src/__tests__/DownloadJSONButton.spec.tsx index 82b5d00b..8313fce9 100644 --- a/demo/src/__tests__/DownloadJSONButton.spec.tsx +++ b/demo/src/__tests__/DownloadJSONButton.spec.tsx @@ -10,7 +10,7 @@ describe("DownloadJSONButton", () => { }); test("renders with correct text", () => { - const downloadButton = screen.getByText("Download This JSON"); + const downloadButton = screen.getByText("Download JSON"); expect(downloadButton).toBeDefined(); }); }); diff --git a/demo/src/__tests__/DownloadSVGButton.spec.tsx b/demo/src/__tests__/DownloadSVGButton.spec.tsx index 00bc9d97..fe4d0baa 100644 --- a/demo/src/__tests__/DownloadSVGButton.spec.tsx +++ b/demo/src/__tests__/DownloadSVGButton.spec.tsx @@ -9,7 +9,7 @@ describe("DownloadSVGButton", () => { }); test("renders with correct text", () => { - const downloadButton = screen.getByText("Download This SVG"); + const downloadButton = screen.getByText("Download SVG"); expect(downloadButton).toBeDefined(); }); }); diff --git a/demo/src/__tests__/MemoryModelsSample.spec.tsx b/demo/src/__tests__/MemoryModelsSample.spec.tsx index 6f9b0028..6871c7c6 100644 --- a/demo/src/__tests__/MemoryModelsSample.spec.tsx +++ b/demo/src/__tests__/MemoryModelsSample.spec.tsx @@ -37,10 +37,10 @@ describe("MemoryModelsSample", () => { ); }); - it("renders Accordion", () => { - expect( - screen.getByTestId("sample-inputs-accordion").textContent - ).toEqual("Sample Inputs"); + it("renders Menu", () => { + expect(screen.getByTestId("sample-inputs-menu").textContent).toEqual( + "Sample Inputs" + ); expect(screen.getByText("Sample Inputs")).toBeDefined(); }); diff --git a/demo/src/__tests__/MemoryModelsUserInput.spec.tsx b/demo/src/__tests__/MemoryModelsUserInput.spec.tsx index 245b7327..924d6ec7 100644 --- a/demo/src/__tests__/MemoryModelsUserInput.spec.tsx +++ b/demo/src/__tests__/MemoryModelsUserInput.spec.tsx @@ -21,7 +21,7 @@ describe("MemoryModelsUserInput", () => { textDataMock = ""; }); - it("renders Accordion for MemoryModelsConfigInput", () => { + it("renders Menu for MemoryModelsConfigInput", () => { render( { /> ); expect( - screen.getByTestId("rendering-options-accordion").textContent + screen.getByTestId("rendering-options-menu").textContent ).toEqual("Rendering Options"); }); diff --git a/demo/src/declerations.d.ts b/demo/src/declerations.d.ts new file mode 100644 index 00000000..a860a74b --- /dev/null +++ b/demo/src/declerations.d.ts @@ -0,0 +1,5 @@ +// Prevents module not found errors when importing images +declare module "*.png" { + const value: any; + export default value; +} diff --git a/demo/src/mocks/fileMock.js b/demo/src/mocks/fileMock.js new file mode 100644 index 00000000..b2e9f045 --- /dev/null +++ b/demo/src/mocks/fileMock.js @@ -0,0 +1,2 @@ +// Mock file for Jest tests which include images +module.exports = ""; From 5ab0898126816ce4f570304cd3a11b6328337a55 Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Wed, 14 Aug 2024 20:18:05 -0400 Subject: [PATCH 23/31] remame file, update wepback --- demo/src/{declerations.d.ts => index.d.ts} | 0 demo/webpack.common.js | 4 ++++ 2 files changed, 4 insertions(+) rename demo/src/{declerations.d.ts => index.d.ts} (100%) diff --git a/demo/src/declerations.d.ts b/demo/src/index.d.ts similarity index 100% rename from demo/src/declerations.d.ts rename to demo/src/index.d.ts diff --git a/demo/webpack.common.js b/demo/webpack.common.js index ace98fef..0090834b 100644 --- a/demo/webpack.common.js +++ b/demo/webpack.common.js @@ -28,6 +28,10 @@ module.exports = { use: ["style-loader", "css-loader"], }, { test: /\.json$/, type: "json" }, + { + test: /\.(png|svg|jpg|jpeg|gif)$/i, + type: "asset/resource", + }, ], }, externals: { From 2bcdce0929062a287134f93888c7773f85a9ba9e Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Wed, 14 Aug 2024 21:12:56 -0400 Subject: [PATCH 24/31] refactor menu component --- demo/src/MemoryModelsMenu.tsx | 42 +++++++++ demo/src/MemoryModelsSample.tsx | 50 +++------- demo/src/MemoryModelsUserInput.tsx | 103 +++++++++------------ demo/src/{index.d.ts => declarations.d.ts} | 0 4 files changed, 98 insertions(+), 97 deletions(-) create mode 100644 demo/src/MemoryModelsMenu.tsx rename demo/src/{index.d.ts => declarations.d.ts} (100%) diff --git a/demo/src/MemoryModelsMenu.tsx b/demo/src/MemoryModelsMenu.tsx new file mode 100644 index 00000000..2638a2c5 --- /dev/null +++ b/demo/src/MemoryModelsMenu.tsx @@ -0,0 +1,42 @@ +import React, { ReactNode, useState } from "react"; +import { Box, Button, Menu } from "@mui/material"; +import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded"; + +type MemoryModelsMenuPropTypes = { + menuName: string; + testId: string; + menuItems: ReactNode; +}; + +export default function MemoryModelsMenu(props: MemoryModelsMenuPropTypes) { + const [anchorEl, setAnchorEl] = useState(null); + const open = Boolean(anchorEl); + const handleClick = (event: React.MouseEvent) => { + setAnchorEl(event.currentTarget); + }; + const handleClose = () => { + setAnchorEl(null); + }; + + return ( + <> + + + {props.menuItems} + + + ); +} diff --git a/demo/src/MemoryModelsSample.tsx b/demo/src/MemoryModelsSample.tsx index 39e1c75d..04a89ff8 100644 --- a/demo/src/MemoryModelsSample.tsx +++ b/demo/src/MemoryModelsSample.tsx @@ -1,6 +1,6 @@ import React, { useEffect, useState } from "react"; -import { Button, Menu, MenuItem } from "@mui/material"; -import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded"; +import { Box, MenuItem } from "@mui/material"; +import MemoryModelsMenu from "./MemoryModelsMenu"; import { SAMPLES } from "./sample"; @@ -12,14 +12,6 @@ type MemoryModelsSamplePropTypes = { export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) { const [clickedBtnIndex, setClickedBtnIndex] = useState(null); - const [anchorEl, setAnchorEl] = useState(null); - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; useEffect(() => { if (clickedBtnIndex !== null) { @@ -40,31 +32,17 @@ export default function MemoryModelsSample(props: MemoryModelsSamplePropTypes) { }; return ( - <> - - - {SAMPLES.map((sample, index) => ( - handleButtonClick(index, sample)} - > - {sample["name"]} - - ))} - - + ( + handleButtonClick(index, sample)} + > + {sample["name"]} + + ))} + /> ); } diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx index 6855f504..4c66b45d 100644 --- a/demo/src/MemoryModelsUserInput.tsx +++ b/demo/src/MemoryModelsUserInput.tsx @@ -7,11 +7,10 @@ import { Input, TextField, Tooltip, - Menu, MenuItem, } from "@mui/material"; -import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded"; import DownloadJSONButton from "./DownloadJSONButton"; +import MemoryModelsMenu from "./MemoryModelsMenu"; interface configDataPropTypes { useAutomation: boolean; @@ -119,14 +118,6 @@ function MemoryModelsTextInput(props: MemoryModelsTextInputPropTypes) { //TODO: Retrieve min and max seeds from memory-viz function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { - const [anchorEl, setAnchorEl] = useState(null); - const open = Boolean(anchorEl); - const handleClick = (event: React.MouseEvent) => { - setAnchorEl(event.currentTarget); - }; - const handleClose = () => { - setAnchorEl(null); - }; const handleSeedChange = (event) => { event.preventDefault(); props.setConfigData({ @@ -149,57 +140,47 @@ function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { }; return ( - <> - - - - - - - - } - label="Use automatic layout" - sx={{ width: "50%" }} - /> - - - + + + + + + + } + label="Use automatic layout" + sx={{ width: "50%" }} + /> + + + } + /> ); } diff --git a/demo/src/index.d.ts b/demo/src/declarations.d.ts similarity index 100% rename from demo/src/index.d.ts rename to demo/src/declarations.d.ts From ad94b544684d3885da5dddcefe1b259fd9f70bbf Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Wed, 14 Aug 2024 21:15:27 -0400 Subject: [PATCH 25/31] review changes --- demo/src/App.tsx | 10 +++++----- demo/src/DownloadSVGButton.tsx | 1 + demo/src/Header.tsx | 9 ++------- demo/src/SvgDisplay.tsx | 22 ++++++++-------------- demo/src/__tests__/App.spec.tsx | 2 +- demo/src/css/styles.css | 11 ----------- demo/src/html/index.html | 8 +------- 7 files changed, 18 insertions(+), 45 deletions(-) diff --git a/demo/src/App.tsx b/demo/src/App.tsx index fb625df5..7acfb577 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -1,5 +1,5 @@ import React, { useState } from "react"; -import { Box } from "@mui/material"; +import { Box, Stack } from "@mui/material"; import SvgDisplay from "./SvgDisplay"; import MemoryModelsUserInput from "./MemoryModelsUserInput"; import { ErrorBoundary } from "react-error-boundary"; @@ -42,9 +42,9 @@ export default function App() { {failureBanner} )} - + -

Input

+

Input

-

Output

+

Output

@@ -79,7 +79,7 @@ export default function App() {
-
+ ); } diff --git a/demo/src/DownloadSVGButton.tsx b/demo/src/DownloadSVGButton.tsx index c7e79271..2ca8ba0d 100644 --- a/demo/src/DownloadSVGButton.tsx +++ b/demo/src/DownloadSVGButton.tsx @@ -9,6 +9,7 @@ export default function DownloadSVGButton(props: DownloadSVGButtonPropTypes) { return ( diff --git a/demo/src/Header.tsx b/demo/src/Header.tsx index 82b9902b..d198326b 100644 --- a/demo/src/Header.tsx +++ b/demo/src/Header.tsx @@ -37,7 +37,6 @@ export default function Header() { src={image} alt="MemoryViz Logo" style={{ - marginRight: "1rem", width: "12%", }} /> diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx index 110c8266..e800d91a 100644 --- a/demo/src/MemoryModelsUserInput.tsx +++ b/demo/src/MemoryModelsUserInput.tsx @@ -84,7 +84,7 @@ function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { variant="contained" disabled={!uploadedFileString} onClick={onLoadButtonClick} - sx={{ width: "auto", textTransform: "none" }} + sx={{ textTransform: "none" }} > Load file data @@ -108,11 +108,6 @@ function MemoryModelsTextInput(props: MemoryModelsTextInputPropTypes) { variant="outlined" value={props.textData} onChange={handleTextFieldChange} - style={{ - width: "100%", - height: "80%", - fontFamily: "Monospace", - }} /> ); } @@ -161,10 +156,6 @@ function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { "data-testid": "config-seed", }, }} - sx={{ - width: "50%", - "& .MuiInputBase-input": { height: "10%" }, - }} />
@@ -176,7 +167,6 @@ function MemoryModelsConfigInput(props: MemoryModelsConfigInputPropTypes) { /> } label="Use automatic layout" - sx={{ width: "50%" }} /> diff --git a/demo/src/css/styles.css b/demo/src/css/styles.css index bb9469de..61ac33e6 100644 --- a/demo/src/css/styles.css +++ b/demo/src/css/styles.css @@ -6,6 +6,3 @@ input[type="number"]::-webkit-outer-spin-button { -webkit-appearance: none; margin: 0; } -#root { - padding: 1rem; -} diff --git a/demo/src/index.tsx b/demo/src/index.tsx index b3ec1e30..bbe295e7 100644 --- a/demo/src/index.tsx +++ b/demo/src/index.tsx @@ -13,9 +13,6 @@ const theme = createTheme({ light: "#72ac56", }, }, - typography: { - fontFamily: "Open Sans, Arial, sans-serif", - }, }); const root = createRoot(document.getElementById("root")); From 53d843f23163fb6b1e712452696d5f28033d839c Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Fri, 16 Aug 2024 13:46:20 -0400 Subject: [PATCH 28/31] update layout --- demo/src/App.tsx | 4 +-- demo/src/Header.tsx | 73 ++++++++++++++++++++++----------------------- 2 files changed, 37 insertions(+), 40 deletions(-) diff --git a/demo/src/App.tsx b/demo/src/App.tsx index 982c45a7..ac85dca4 100644 --- a/demo/src/App.tsx +++ b/demo/src/App.tsx @@ -34,7 +34,7 @@ export default function App() { }; return ( - <> +
{failureBanner && ( @@ -74,6 +74,6 @@ export default function App() { - +
); } diff --git a/demo/src/Header.tsx b/demo/src/Header.tsx index d198326b..65eaf5b4 100644 --- a/demo/src/Header.tsx +++ b/demo/src/Header.tsx @@ -1,45 +1,42 @@ import React from "react"; -import { Box, Link, Typography } from "@mui/material"; +import { Box, Link, Stack, Typography } from "@mui/material"; import image from "../../assets/logo_square.png"; export default function Header() { return ( - - - MemoryViz Demo - - Demos of the{" "} - - MemoryViz - {" "} - Javascript library for visualizing Python memory. Click{" "} - - here - {" "} - for documentation. - - - MemoryViz Logo - +
+ + +

MemoryViz Demo

+ + Demos of the{" "} + + MemoryViz + {" "} + Javascript library for visualizing Python memory. Click{" "} + + here + {" "} + for documentation. + +
+ MemoryViz Logo +
+
); } From 506d91f91da48d54330acd9b05e53bac730c71f0 Mon Sep 17 00:00:00 2001 From: yoonie-jang Date: Fri, 16 Aug 2024 13:49:53 -0400 Subject: [PATCH 29/31] review changes --- demo/src/DownloadJSONButton.tsx | 3 +- demo/src/MemoryModelsUserInput.tsx | 85 ++++++++++++++++-------------- 2 files changed, 46 insertions(+), 42 deletions(-) diff --git a/demo/src/DownloadJSONButton.tsx b/demo/src/DownloadJSONButton.tsx index 09d463f3..bbbfd8bf 100644 --- a/demo/src/DownloadJSONButton.tsx +++ b/demo/src/DownloadJSONButton.tsx @@ -3,7 +3,6 @@ import { Button } from "@mui/material"; type DownloadJSONButtonPropTypes = { jsonResult: string; - sx: object; }; export default function DownloadJSONButton(props: DownloadJSONButtonPropTypes) { const file = new Blob([JSON.stringify(props.jsonResult, null, 2)], { @@ -20,7 +19,7 @@ export default function DownloadJSONButton(props: DownloadJSONButtonPropTypes) { target="_blank" rel="noreferrer" href={window.URL.createObjectURL(file)} - sx={{ ...props.sx, textTransform: "none" }} + sx={{ textTransform: "none" }} > Download JSON diff --git a/demo/src/MemoryModelsUserInput.tsx b/demo/src/MemoryModelsUserInput.tsx index e800d91a..bab34cfe 100644 --- a/demo/src/MemoryModelsUserInput.tsx +++ b/demo/src/MemoryModelsUserInput.tsx @@ -8,6 +8,7 @@ import { TextField, Tooltip, MenuItem, + Stack, } from "@mui/material"; import DownloadJSONButton from "./DownloadJSONButton"; import MemoryModelsMenu from "./MemoryModelsMenu"; @@ -69,7 +70,7 @@ function MemoryModelsFileInput(props: MemoryModelsFileInputPropTypes) { }; return ( - + Load file data - + ); } @@ -107,6 +108,7 @@ function MemoryModelsTextInput(props: MemoryModelsTextInputPropTypes) { rows={10} variant="outlined" value={props.textData} + style={{ fontFamily: "Monospace" }} onChange={handleTextFieldChange} /> ); @@ -180,47 +182,50 @@ export default function MemoryModelsUserInput( ) { return (
- - - + - - - - - - - - - - - + + + + + + + + + + + + + + ); } From 828d2e9311144e8da69b3c683a5f7e705144a6ab Mon Sep 17 00:00:00 2001 From: Sarah Wang Date: Sat, 17 Aug 2024 22:54:53 -0400 Subject: [PATCH 30/31] update styling --- demo/jest.config.ts | 2 +- demo/src/MemoryModelsMenu.tsx | 9 ++------- demo/src/MemoryModelsUserInput.tsx | 1 - demo/src/SvgDisplay.tsx | 4 ---- demo/src/css/styles.css | 14 ++++++++++++++ demo/src/mocks/fileMock.js | 2 +- 6 files changed, 18 insertions(+), 14 deletions(-) diff --git a/demo/jest.config.ts b/demo/jest.config.ts index 0a1fabdf..76676a39 100644 --- a/demo/jest.config.ts +++ b/demo/jest.config.ts @@ -94,7 +94,7 @@ const config: Config = { roughjs: require.resolve("roughjs"), "memory-viz": require.resolve("../memory-viz/src"), // Mocks a file (see fileMock.js) each time any of the below file types are imported. - "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": + "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga|css|less|sass|scss)$": "./mocks/fileMock.js", }, diff --git a/demo/src/MemoryModelsMenu.tsx b/demo/src/MemoryModelsMenu.tsx index 2638a2c5..26d03c4b 100644 --- a/demo/src/MemoryModelsMenu.tsx +++ b/demo/src/MemoryModelsMenu.tsx @@ -1,6 +1,7 @@ import React, { ReactNode, useState } from "react"; import { Box, Button, Menu } from "@mui/material"; import ExpandMoreRoundedIcon from "@mui/icons-material/ExpandMoreRounded"; +import "./css/styles.css"; type MemoryModelsMenuPropTypes = { menuName: string; @@ -23,13 +24,7 @@ export default function MemoryModelsMenu(props: MemoryModelsMenuPropTypes) {