
For intervals < ~24ms, the main thread as unable to cope up in handling worker responses due to Mainframe rendering on each execution. To resolve this, this commit delegates all execution-time states to child components, controlled imperatively from Mainframe. This yields huge performance boost, with main thread keeping up with worker responses even at interval of 5ms.
47 lines
1.4 KiB
TypeScript
47 lines
1.4 KiB
TypeScript
import React from "react";
|
|
import { TextArea } from "@blueprintjs/core";
|
|
|
|
/**
|
|
* For aesthetic reasons, we use readonly textarea for displaying output.
|
|
* Textarea displays placeholder if value passed is empty string, which is undesired.
|
|
* This function is a fake-whitespace workaround.
|
|
*
|
|
* @param value Value received from parent. Placeholder shown on `null`.
|
|
* @returns Value to pass as prop to Blueprint TextArea
|
|
*/
|
|
const toTextareaValue = (value: string | null): string | undefined => {
|
|
if (value == null) return undefined; // Placeholder shown
|
|
if (value === "") return "\u0020"; // Fake whitespace to hide placeholder
|
|
return value; // Non-empty output value
|
|
};
|
|
|
|
export interface OutputViewerRef {
|
|
/** Reset output to show placeholder text */
|
|
reset: () => void;
|
|
/** Append string to the displayed output */
|
|
append: (str?: string) => void;
|
|
}
|
|
|
|
const OutputViewerComponent = (_: {}, ref: React.Ref<OutputViewerRef>) => {
|
|
const [value, setValue] = React.useState<string | null>(null);
|
|
|
|
React.useImperativeHandle(ref, () => ({
|
|
reset: () => setValue(null),
|
|
append: (s) => setValue((o) => (o || "") + (s || "")),
|
|
}));
|
|
|
|
return (
|
|
<TextArea
|
|
fill
|
|
large
|
|
readOnly
|
|
growVertically
|
|
value={toTextareaValue(value)}
|
|
placeholder="Run code to see output..."
|
|
style={{ height: "100%", resize: "none", boxShadow: "none" }}
|
|
/>
|
|
);
|
|
};
|
|
|
|
export const OutputViewer = React.forwardRef(OutputViewerComponent);
|