diff --git a/packages/website/src/components/editor/LoadedEditor.tsx b/packages/website/src/components/editor/LoadedEditor.tsx index 9bfda6a1c339..07255bfe6b9a 100644 --- a/packages/website/src/components/editor/LoadedEditor.tsx +++ b/packages/website/src/components/editor/LoadedEditor.tsx @@ -8,6 +8,7 @@ import { parseTSConfig, tryParseEslintModule, } from '../config/utils'; +import { useResizeObserver } from '../hooks/useResizeObserver'; import { debounce } from '../lib/debounce'; import type { LintCodeAction } from '../linter/utils'; import { parseLintResults, parseMarkers } from '../linter/utils'; @@ -273,35 +274,19 @@ export const LoadedEditor: React.FC = ({ return debounce(() => sandboxInstance.editor.layout(), 1); }, [sandboxInstance]); - useEffect(() => { - resize(); - }, [resize, showAST]); - - const domNode = sandboxInstance.editor.getContainerDomNode(); - const resizeObserver = useMemo(() => { - return new ResizeObserver(() => { - resize(); - }); - }, [resize]); - - useEffect(() => { - if (domNode) { - resizeObserver.observe(domNode); - - return (): void => resizeObserver.unobserve(domNode); - } - return (): void => {}; - }, [domNode, resizeObserver]); + const container = + sandboxInstance.editor.getContainerDomNode?.() ?? + sandboxInstance.editor.getDomNode(); - useEffect(() => { - window.addEventListener('resize', resize); - return (): void => { - window.removeEventListener('resize', resize); - }; + useResizeObserver(container, () => { + resize(); }); useEffect(() => { - if (code !== tabs.code.getValue()) { + if ( + !sandboxInstance.editor.hasTextFocus() && + code !== tabs.code.getValue() + ) { tabs.code.applyEdits([ { range: tabs.code.getFullModelRange(), @@ -309,10 +294,13 @@ export const LoadedEditor: React.FC = ({ }, ]); } - }, [code, tabs.code]); + }, [sandboxInstance, code, tabs.code]); useEffect(() => { - if (tsconfig !== tabs.tsconfig.getValue()) { + if ( + !sandboxInstance.editor.hasTextFocus() && + tsconfig !== tabs.tsconfig.getValue() + ) { tabs.tsconfig.applyEdits([ { range: tabs.tsconfig.getFullModelRange(), @@ -320,10 +308,13 @@ export const LoadedEditor: React.FC = ({ }, ]); } - }, [tabs.tsconfig, tsconfig]); + }, [sandboxInstance, tabs.tsconfig, tsconfig]); useEffect(() => { - if (eslintrc !== tabs.eslintrc.getValue()) { + if ( + !sandboxInstance.editor.hasTextFocus() && + eslintrc !== tabs.eslintrc.getValue() + ) { tabs.eslintrc.applyEdits([ { range: tabs.eslintrc.getFullModelRange(), @@ -331,7 +322,7 @@ export const LoadedEditor: React.FC = ({ }, ]); } - }, [eslintrc, tabs.eslintrc]); + }, [sandboxInstance, eslintrc, tabs.eslintrc]); useEffect(() => { sandboxInstance.monaco.editor.setTheme( @@ -340,29 +331,27 @@ export const LoadedEditor: React.FC = ({ }, [colorMode, sandboxInstance]); useEffect(() => { - if (sandboxInstance.editor.getModel() === tabs.code) { - setDecorations(prevDecorations => - sandboxInstance.editor.deltaDecorations( - prevDecorations, - decoration && showAST - ? [ - { - range: new sandboxInstance.monaco.Range( - decoration.start.line, - decoration.start.column + 1, - decoration.end.line, - decoration.end.column + 1, - ), - options: { - inlineClassName: 'myLineDecoration', - stickiness: 1, - }, + setDecorations(prevDecorations => + tabs.code.deltaDecorations( + prevDecorations, + decoration && showAST + ? [ + { + range: new sandboxInstance.monaco.Range( + decoration.start.line, + decoration.start.column + 1, + decoration.end.line, + decoration.end.column + 1, + ), + options: { + inlineClassName: 'myLineDecoration', + stickiness: 1, }, - ] - : [], - ), - ); - } + }, + ] + : [], + ), + ); }, [decoration, sandboxInstance, showAST, tabs.code]); return null; diff --git a/packages/website/src/components/editor/useSandboxServices.ts b/packages/website/src/components/editor/useSandboxServices.ts index 20378ca79ffe..a6f4cbb7dfff 100644 --- a/packages/website/src/components/editor/useSandboxServices.ts +++ b/packages/website/src/components/editor/useSandboxServices.ts @@ -1,5 +1,4 @@ import { useColorMode } from '@docusaurus/theme-common'; -import { createCompilerOptions } from '@site/src/components/editor/config'; import type Monaco from 'monaco-editor'; import { useEffect, useState } from 'react'; @@ -9,8 +8,10 @@ import type { } from '../../vendor/sandbox'; import { WebLinter } from '../linter/WebLinter'; import type { RuleDetails } from '../types'; +import { createCompilerOptions } from './config'; import { editorEmbedId } from './EditorEmbed'; import { sandboxSingleton } from './loadSandbox'; +import type { CommonEditorProps } from './types'; export interface SandboxServicesProps { readonly jsx?: boolean; @@ -30,7 +31,7 @@ export interface SandboxServices { } export const useSandboxServices = ( - props: SandboxServicesProps, + props: CommonEditorProps & SandboxServicesProps, ): Error | SandboxServices | undefined => { const { onLoaded } = props; const [services, setServices] = useState(); @@ -52,7 +53,7 @@ export const useSandboxServices = ( const compilerOptions = createCompilerOptions(props.jsx); const sandboxConfig: Partial = { - text: '', + text: props.code, monacoSettings: { minimap: { enabled: false }, fontSize: 13, diff --git a/packages/website/src/components/hooks/useHashState.ts b/packages/website/src/components/hooks/useHashState.ts index 215386428915..c7cc5fb074d1 100644 --- a/packages/website/src/components/hooks/useHashState.ts +++ b/packages/website/src/components/hooks/useHashState.ts @@ -218,9 +218,9 @@ function useHashState( }; useEffect(() => { - window.addEventListener('hashchange', onHashChange); + window.addEventListener('popstate', onHashChange); return (): void => { - window.removeEventListener('hashchange', onHashChange); + window.removeEventListener('popstate', onHashChange); }; }, []); diff --git a/packages/website/src/components/hooks/useResizeObserver.ts b/packages/website/src/components/hooks/useResizeObserver.ts new file mode 100644 index 000000000000..2760776298e9 --- /dev/null +++ b/packages/website/src/components/hooks/useResizeObserver.ts @@ -0,0 +1,25 @@ +import { useEffect, useMemo } from 'react'; + +const useResizeObserver = ( + element: HTMLElement | null, + callback: () => void, +): void => { + const resizeObserver = useMemo(() => { + return new ResizeObserver(() => { + callback(); + }); + }, [callback]); + + useEffect(() => { + if (element) { + resizeObserver.observe(element); + } + return (): void => { + if (element) { + resizeObserver.unobserve(element); + } + }; + }, [element, resizeObserver]); +}; + +export { useResizeObserver };