From e7ae5eff9673f27ee4b63bc8aab865eb8ab9a13c Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Mon, 29 Jul 2024 13:27:36 +0000 Subject: [PATCH 1/3] Make tabs scrollable if necessary --- gui/src/app/components/TabWidget.tsx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/gui/src/app/components/TabWidget.tsx b/gui/src/app/components/TabWidget.tsx index 3c941e8d..2691aa9a 100644 --- a/gui/src/app/components/TabWidget.tsx +++ b/gui/src/app/components/TabWidget.tsx @@ -31,7 +31,12 @@ const TabWidget: FunctionComponent = ({ labels, children }) => { return ( - + {labels.map((label, i) => ( ))} From 0c71c674533a0ba3ce88cf4890dfbadb040489eb Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Mon, 29 Jul 2024 13:50:31 +0000 Subject: [PATCH 2/3] Use a splitter that keeps children mounted --- gui/package.json | 2 +- gui/src/app/FileEditor/StanFileEditor.tsx | 36 ++++++----- .../app/Scripting/PlottingScriptEditor.tsx | 6 +- gui/src/app/Scripting/ScriptEditor.tsx | 6 +- gui/src/app/components/Splitter.tsx | 62 ------------------- gui/src/app/pages/HomePage/HomePage.tsx | 17 ++--- gui/yarn.lock | 43 ++++++++++--- 7 files changed, 66 insertions(+), 106 deletions(-) delete mode 100644 gui/src/app/components/Splitter.tsx diff --git a/gui/package.json b/gui/package.json index a5cd407e..20a2fcbf 100644 --- a/gui/package.json +++ b/gui/package.json @@ -20,11 +20,11 @@ "test-watch": "vitest" }, "dependencies": { - "@devbookhq/splitter": "^1.4.2", "@emotion/react": "^11.11.4", "@emotion/styled": "^11.11.5", "@fi-sci/misc": "^0.0.8", "@fi-sci/modal-window": "^0.0.2", + "@geoffcox/react-splitter": "^2.1.2", "@monaco-editor/react": "^4.6.0", "@mui/icons-material": "^5.15.17", "@mui/material": "^5.15.17", diff --git a/gui/src/app/FileEditor/StanFileEditor.tsx b/gui/src/app/FileEditor/StanFileEditor.tsx index 47e1a081..a3c111f6 100644 --- a/gui/src/app/FileEditor/StanFileEditor.tsx +++ b/gui/src/app/FileEditor/StanFileEditor.tsx @@ -1,5 +1,5 @@ +import { Split } from "@geoffcox/react-splitter"; import { AutoFixHigh, Cancel, Settings } from "@mui/icons-material"; -import { SplitDirection, Splitter } from "@SpComponents/Splitter"; import StanCompileResultWindow from "@SpComponents/StanCompileResultWindow"; import TextEditor from "@SpComponents/TextEditor"; import { ToolbarItem } from "@SpComponents/ToolBar"; @@ -216,25 +216,27 @@ const StanFileEditor: FunctionComponent = ({ <> ); - const initialSizes = syntaxWindowVisible ? [60, 40] : [100, 0]; + const editor = ( + + ); + if (!syntaxWindowVisible) return editor; return ( - - + + {editor} {window} - + ); }; diff --git a/gui/src/app/Scripting/PlottingScriptEditor.tsx b/gui/src/app/Scripting/PlottingScriptEditor.tsx index 0a6028bc..64aed71c 100644 --- a/gui/src/app/Scripting/PlottingScriptEditor.tsx +++ b/gui/src/app/Scripting/PlottingScriptEditor.tsx @@ -1,15 +1,15 @@ import { FunctionComponent, RefObject } from "react"; import ScriptEditor, { ScriptEditorProps } from "./ScriptEditor"; -import { SplitDirection, Splitter } from "@SpComponents/Splitter"; +import { Split } from "@geoffcox/react-splitter"; const PlottingScriptEditor: FunctionComponent< ScriptEditorProps & { imagesRef: RefObject } > = (props) => { return ( - + - + ); }; diff --git a/gui/src/app/Scripting/ScriptEditor.tsx b/gui/src/app/Scripting/ScriptEditor.tsx index b96c4960..86969d64 100644 --- a/gui/src/app/Scripting/ScriptEditor.tsx +++ b/gui/src/app/Scripting/ScriptEditor.tsx @@ -1,5 +1,4 @@ import { Help, PlayArrow } from "@mui/icons-material"; -import { SplitDirection, Splitter } from "@SpComponents/Splitter"; import TextEditor from "@SpComponents/TextEditor"; import { ToolbarItem } from "@SpComponents/ToolBar"; import { FileNames } from "@SpCore/FileMapping"; @@ -13,6 +12,7 @@ import { useMemo, } from "react"; import { InterpreterStatus } from "./InterpreterTypes"; +import { Split } from "@geoffcox/react-splitter"; const interpreterNames = { python: "pyodide", r: "webR" } as const; @@ -92,7 +92,7 @@ const ScriptEditor: FunctionComponent = ({ ]); return ( - + = ({ contentOnEmpty={contentOnEmpty} /> - + ); }; diff --git a/gui/src/app/components/Splitter.tsx b/gui/src/app/components/Splitter.tsx deleted file mode 100644 index d167b3f3..00000000 --- a/gui/src/app/components/Splitter.tsx +++ /dev/null @@ -1,62 +0,0 @@ -// @devbookhq/splitter has a known issue, https://github.com/DevbookHQ/splitter/issues/11, -// where re-renders of internal components can cause the splitter to lose its state. -// This wrapper captures the splitter sizes and stores them in a state to avoid this issue. -import DevbookSplit, { - SplitDirection as DevbookSplitDirection, - GutterTheme as DevbookGutterTheme, -} from "@devbookhq/splitter"; -import { - FunctionComponent, - useState, - useCallback, - PropsWithChildren, - useEffect, -} from "react"; - -interface SplitterProps { - direction?: keyof typeof DevbookSplitDirection; - minWidths?: number[]; - minHeights?: number[]; - initialSizes?: number[]; - gutterTheme?: keyof typeof DevbookGutterTheme; - gutterClassName?: string; - draggerClassName?: string; - onResizeStarted?: (pairIdx: number) => void; - onResizeFinished?: (pairIdx: number, newSizes: number[]) => void; - classes?: string[]; -} - -export const SplitDirection = DevbookSplitDirection; -export const GutterTheme = DevbookGutterTheme; - -export const Splitter: FunctionComponent> = ({ - direction = "Horizontal", - gutterTheme = "Light", - children, - initialSizes, - ...props -}) => { - const [persistentSizes, setPersistentSizes] = useState( - initialSizes, - ); - - useEffect(() => { - setPersistentSizes(initialSizes); - }, [initialSizes]); - - const handleResizeFinished = useCallback((_: number, newSizes: number[]) => { - setPersistentSizes(newSizes); - }, []); - - return ( - - {children} - - ); -}; diff --git a/gui/src/app/pages/HomePage/HomePage.tsx b/gui/src/app/pages/HomePage/HomePage.tsx index bcd116ec..75042619 100644 --- a/gui/src/app/pages/HomePage/HomePage.tsx +++ b/gui/src/app/pages/HomePage/HomePage.tsx @@ -1,7 +1,6 @@ import Box from "@mui/material/Box"; import styled from "@mui/material/styles/styled"; import useMediaQuery from "@mui/material/useMediaQuery"; -import { GutterTheme, SplitDirection, Splitter } from "@SpComponents/Splitter"; import StanFileEditor from "@SpComponents/StanFileEditor"; import { ProjectContext } from "@SpCore/ProjectContextProvider"; import { @@ -23,6 +22,7 @@ import { FileNames } from "@SpCore/FileMapping"; import DataRWindow from "@SpScripting/DataGeneration/DataRWindow"; import DataPyWindow from "@SpScripting/DataGeneration/DataPyWindow"; import TextEditor from "@SpComponents/TextEditor"; +import { Split } from "@geoffcox/react-splitter"; type Props = { // @@ -63,14 +63,10 @@ const HomePage: FunctionComponent = () => { /> - + - + ); @@ -103,10 +99,7 @@ const LeftView: FunctionComponent = ({ }) => { const { data, update } = useContext(ProjectContext); return ( - + = ({ readOnly={false} contentOnEmpty={"Enter JSON data or use the data generation tab"} /> - + ); }; diff --git a/gui/yarn.lock b/gui/yarn.lock index 093d2dc5..d923faec 100644 --- a/gui/yarn.lock +++ b/gui/yarn.lock @@ -185,6 +185,13 @@ dependencies: regenerator-runtime "^0.14.0" +"@babel/runtime@^7.2.0": + version "7.25.0" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.25.0.tgz#3af9a91c1b739c569d5d80cc917280919c544ecb" + integrity sha512-7dRy4DwXwtzBrPbZflqxnvfxLF8kdZXPkhymtDeFoFqE6ldzjQFgYTtYIFARcLEYDrqfBfYcZt1WqFxRoyC9Rw== + dependencies: + regenerator-runtime "^0.14.0" + "@babel/template@^7.24.7": version "7.24.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.7.tgz#02efcee317d0609d2c07117cb70ef8fb17ab7315" @@ -288,13 +295,6 @@ style-mod "^4.1.0" w3c-keyname "^2.2.4" -"@devbookhq/splitter@^1.4.2": - version "1.4.2" - resolved "https://registry.yarnpkg.com/@devbookhq/splitter/-/splitter-1.4.2.tgz#97fb5d015ca605847511f7420cb9d59d70b0eb89" - integrity sha512-DqJXsL7WNeDn/DyCeyoeeSpFHHoYBXscYlKNd3cJQ5d1xur73MPezHpyR2OID6Kh40TZ4KAb4hYjl5nL2+5M1g== - dependencies: - react-is "^17.0.2" - "@emotion/babel-plugin@^11.11.0": version "11.11.0" resolved "https://registry.yarnpkg.com/@emotion/babel-plugin/-/babel-plugin-11.11.0.tgz#c2d872b6a7767a9d176d007f5b31f7d504bb5d6c" @@ -589,6 +589,13 @@ resolved "https://registry.yarnpkg.com/@floating-ui/utils/-/utils-0.2.4.tgz#1d459cee5031893a08a0e064c406ad2130cced7c" integrity sha512-dWO2pw8hhi+WrXq1YJy2yCuWoL20PddgGaqTgVe4cOS9Q6qklXCiA1tJEqX6BEwRNSCP84/afac9hd4MS+zEUA== +"@geoffcox/react-splitter@^2.1.2": + version "2.1.2" + resolved "https://registry.yarnpkg.com/@geoffcox/react-splitter/-/react-splitter-2.1.2.tgz#cce71c0a034029714172af30df5c462b73aabf1e" + integrity sha512-+9d+VlhS/YCxqzFVqAG8+c2umDhahuR/jpykpTWtSVIcvcf42gVcyMe7tD0w+KAvZj12IJdV1dO7K1hLg15Yrg== + dependencies: + react-measure "^2.5.2" + "@humanwhocodes/config-array@^0.11.14": version "0.11.14" resolved "https://registry.yarnpkg.com/@humanwhocodes/config-array/-/config-array-0.11.14.tgz#d78e481a039f7566ecc9660b4ea7fe6b1fec442b" @@ -2329,6 +2336,11 @@ get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.3, get-intrinsic@ has-symbols "^1.0.3" hasown "^2.0.0" +get-node-dimensions@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/get-node-dimensions/-/get-node-dimensions-1.2.1.tgz#fb7b4bb57060fb4247dd51c9d690dfbec56b0823" + integrity sha512-2MSPMu7S1iOTL+BOa6K1S62hB2zUAYNF/lV0gSVlOaacd087lc6nR1H1r0e3B1CerTo+RceOmi1iJW+vp21xcQ== + get-stream@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-8.0.1.tgz#def9dfd71742cd7754a7761ed43749a27d02eca2" @@ -3490,7 +3502,7 @@ react-is@^16.13.1, react-is@^16.7.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== -react-is@^17.0.1, react-is@^17.0.2: +react-is@^17.0.1: version "17.0.2" resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== @@ -3500,6 +3512,16 @@ react-is@^18.0.0, react-is@^18.2.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.3.1.tgz#e83557dc12eae63a99e003a46388b1dcbb44db7e" integrity sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg== +react-measure@^2.5.2: + version "2.5.2" + resolved "https://registry.yarnpkg.com/react-measure/-/react-measure-2.5.2.tgz#4ffc410e8b9cb836d9455a9ff18fc1f0fca67f89" + integrity sha512-M+rpbTLWJ3FD6FXvYV6YEGvQ5tMayQ3fGrZhRPHrE9bVlBYfDCLuDcgNttYfk8IqfOI03jz6cbpqMRTUclQnaA== + dependencies: + "@babel/runtime" "^7.2.0" + get-node-dimensions "^1.2.1" + prop-types "^15.6.2" + resize-observer-polyfill "^1.5.0" + react-plotly.js@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/react-plotly.js/-/react-plotly.js-2.6.0.tgz#ad6b68ee64f1b5cfa142ee92c59687f9c2c09209" @@ -3602,6 +3624,11 @@ requires-port@^1.0.0: resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" integrity sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ== +resize-observer-polyfill@^1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464" + integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" From 03e304dbd23254d80c1ddd6aea425c70ab41deeb Mon Sep 17 00:00:00 2001 From: Brian Ward Date: Mon, 29 Jul 2024 18:33:22 +0000 Subject: [PATCH 3/3] Fix main.stan rerendering --- gui/src/app/FileEditor/StanFileEditor.tsx | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/gui/src/app/FileEditor/StanFileEditor.tsx b/gui/src/app/FileEditor/StanFileEditor.tsx index a3c111f6..50c10173 100644 --- a/gui/src/app/FileEditor/StanFileEditor.tsx +++ b/gui/src/app/FileEditor/StanFileEditor.tsx @@ -231,9 +231,12 @@ const StanFileEditor: FunctionComponent = ({ /> ); - if (!syntaxWindowVisible) return editor; return ( - + {editor} {window}