diff --git a/src/components/CodeEmbed/index.jsx b/src/components/CodeEmbed/index.jsx index f2db3c0897..a6a2f63679 100644 --- a/src/components/CodeEmbed/index.jsx +++ b/src/components/CodeEmbed/index.jsx @@ -29,6 +29,7 @@ import { Icon } from "../Icon"; export const CodeEmbed = (props) => { const { ref: liveRegionRef, announce } = useLiveRegion(); const [rendered, setRendered] = useState(false); + const initialCode = props.initialValue ?? ""; // Source code from Google Docs sometimes uses a unicode non-breaking space // instead of a normal one, but these break the code frame, so we replace them here. @@ -54,6 +55,9 @@ export const CodeEmbed = (props) => { } const codeFrameRef = useRef(null); + const editorRef = useRef(null); + const isScrollable = props.scrollable ?? false; + const [hasScrollbar, setHasScrollbar] = useState(false); const updateOrReRun = () => { if (codeString === previewCodeString) { @@ -79,6 +83,18 @@ export const CodeEmbed = (props) => { } }, []); + // only observe scroll when scrollable + useEffect(() => { + if (!rendered || !isScrollable) return; + const scroller = editorRef.current?.querySelector(".cm-scroller"); + if (!scroller) return; + const observer = new ResizeObserver(() => { + setHasScrollbar(scroller.scrollHeight > scroller.clientHeight); + }); + observer.observe(scroller); + return () => observer.disconnect(); + }, [rendered, isScrollable]); + if (!rendered) return
; return ( @@ -125,11 +141,12 @@ export const CodeEmbed = (props) => {
) : null} -
+
{ historyKeymap: true, }} basicSetup={{ - lineNumbers: false, - foldGutter: false, + lineNumbers: hasScrollbar, + foldGutter: true, autocompletion: false, }} indentWithTab={false} - extensions={[javascript(), EditorView.lineWrapping]} + extensions={[javascript(), EditorView.lineWrapping, EditorView.theme({ + ".cm-scroller": { + overflowY: isScrollable ? "auto" : "visible", + }, + })]} onChange={(val) => setCodeString(val)} editable={props.editable} onCreateEditor={(editorView) => (editorView.contentDOM.ariaLabel = "Code Editor") } /> -
+
{ @@ -171,4 +196,4 @@ export const CodeEmbed = (props) => { ); }; -export default CodeEmbed; +export default CodeEmbed; \ No newline at end of file diff --git a/src/components/EditableSketch/index.astro b/src/components/EditableSketch/index.astro index 95e20f27e5..45520d6d0d 100644 --- a/src/components/EditableSketch/index.astro +++ b/src/components/EditableSketch/index.astro @@ -3,24 +3,42 @@ import CodeEmbed from "../CodeEmbed"; interface Props { code: string; + scrollable?: boolean; + cssCode?: string; + bodyCode?: string; width?: number; height?: number; base?: string; scripts?: string[]; } -const { props } = Astro; +const props = Astro.props as Props; let previewWidth = props.width; let previewHeight = props.height; -const match = /createCanvas\(\s*(\d+),\s*(\d+)\s*(?:,\s*(?:P2D|WEBGL)\s*)?\)/m.exec(props.code); +const match = /createCanvas\(\s*(\d+),\s*(\d+)\s*(?:,\s*(?:P2D|WEBGL|WEBGPU)\s*)?\)/m.exec(props.code); if (match) { previewWidth = previewWidth || parseFloat(match[1]); previewHeight = previewHeight || parseFloat(match[2]); } const vertical = !previewWidth || previewWidth > 200 +const scrollable = props.scrollable ?? false; --- - + \ No newline at end of file diff --git a/src/components/SketchEmbed/index.astro b/src/components/SketchEmbed/index.astro index 1a229b15d3..d5e7b9b174 100644 --- a/src/components/SketchEmbed/index.astro +++ b/src/components/SketchEmbed/index.astro @@ -4,6 +4,7 @@ import { CodeFrame } from "../CodeEmbed/frame"; interface Props { code: string; + scrollable?: boolean; cssCode?: string; bodyCode?: string; width?: number | string; @@ -15,17 +16,19 @@ interface Props { const defaultHeight = 400, defaultWidth = "100%"; -const { code, cssCode, bodyCode, height, width, scripts, hideOffscreen } = Astro.props; +const { code, cssCode, bodyCode, height, width, scripts, hideOffscreen, scrollable = false } = Astro.props; // A component that displays a full-width sketch without showing its code. const frameProps = { jsCode: code, cssCode: cssCode, htmlBodyCode: bodyCode, + scrollable: scrollable, height: height || defaultHeight, width: width || defaultWidth, scripts, }; + --- {hideOffscreen ? ( diff --git a/src/content/tutorials/en/typography-2.0.mdx b/src/content/tutorials/en/typography-2.0.mdx index 04d556aa5f..0bbb6f11bd 100644 --- a/src/content/tutorials/en/typography-2.0.mdx +++ b/src/content/tutorials/en/typography-2.0.mdx @@ -1348,7 +1348,7 @@ function draw() { Try experimenting with different offsets to see what kind of effect you get! I've used 50ms here. - { Try wiggling your mouse over the letters! - { // Start a mock server to intercept network requests beforeAll(() => server.listen({ onUnhandledRequest: "error" }));