Skip to content

Commit cf9fd34

Browse files
committed
Merge branch 'main' of github.com:reactjs/reactjs.org
2 parents 31d2c6e + 5d1cac5 commit cf9fd34

File tree

7 files changed

+227
-68
lines changed

7 files changed

+227
-68
lines changed

beta/src/components/MDX/Sandpack/Error.tsx renamed to beta/src/components/MDX/Sandpack/ErrorMessage.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ interface ErrorType {
1010
path?: string;
1111
}
1212

13-
export function Error({error}: {error: ErrorType}) {
13+
export function ErrorMessage({error, ...props}: {error: ErrorType}) {
1414
const {message, title} = error;
1515

1616
return (
17-
<div className={'bg-white border-2 border-red-40 rounded-lg p-6'}>
17+
<div className="bg-white border-2 border-red-40 rounded-lg p-6" {...props}>
1818
<h2 className="text-red-40 text-xl mb-4">{title || 'Error'}</h2>
19-
<pre className="text-secondary whitespace-pre-wrap break-words">
19+
<pre className="text-secondary whitespace-pre-wrap break-words leading-tight">
2020
{message}
2121
</pre>
2222
</div>
Lines changed: 142 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,142 @@
1+
import {useState} from 'react';
2+
3+
import {
4+
LoadingOverlayState,
5+
OpenInCodeSandboxButton,
6+
useSandpack,
7+
} from '@codesandbox/sandpack-react';
8+
import {useEffect} from 'react';
9+
10+
const FADE_ANIMATION_DURATION = 200;
11+
12+
export const LoadingOverlay = ({
13+
clientId,
14+
dependenciesLoading,
15+
forceLoading,
16+
}: {
17+
clientId: string;
18+
dependenciesLoading: boolean;
19+
forceLoading: boolean;
20+
} & React.HTMLAttributes<HTMLDivElement>): JSX.Element | null => {
21+
const loadingOverlayState = useLoadingOverlayState(
22+
clientId,
23+
dependenciesLoading,
24+
forceLoading
25+
);
26+
27+
if (loadingOverlayState === 'HIDDEN') {
28+
return null;
29+
}
30+
31+
if (loadingOverlayState === 'TIMEOUT') {
32+
return (
33+
<div className="sp-overlay sp-error">
34+
<div className="sp-error-message">
35+
Unable to establish connection with the sandpack bundler. Make sure
36+
you are online or try again later. If the problem persists, please
37+
report it via{' '}
38+
<a
39+
className="sp-error-message"
40+
href="mailto:hello@codesandbox.io?subject=Sandpack Timeout Error">
41+
email
42+
</a>{' '}
43+
or submit an issue on{' '}
44+
<a
45+
className="sp-error-message"
46+
href="https://github.com/codesandbox/sandpack/issues"
47+
rel="noreferrer noopener"
48+
target="_blank">
49+
GitHub.
50+
</a>
51+
</div>
52+
</div>
53+
);
54+
}
55+
56+
const stillLoading =
57+
loadingOverlayState === 'LOADING' || loadingOverlayState === 'PRE_FADING';
58+
59+
return (
60+
<div
61+
className="sp-overlay sp-loading"
62+
style={{
63+
opacity: stillLoading ? 1 : 0,
64+
transition: `opacity ${FADE_ANIMATION_DURATION}ms ease-out`,
65+
}}>
66+
<div className="sp-cube-wrapper" title="Open in CodeSandbox">
67+
<OpenInCodeSandboxButton />
68+
<div className="sp-cube">
69+
<div className="sp-sides">
70+
<div className="top" />
71+
<div className="right" />
72+
<div className="bottom" />
73+
<div className="left" />
74+
<div className="front" />
75+
<div className="back" />
76+
</div>
77+
</div>
78+
</div>
79+
</div>
80+
);
81+
};
82+
83+
const useLoadingOverlayState = (
84+
clientId: string,
85+
dependenciesLoading: boolean,
86+
forceLoading: boolean
87+
): LoadingOverlayState => {
88+
const {sandpack, listen} = useSandpack();
89+
const [state, setState] = useState<LoadingOverlayState>('HIDDEN');
90+
91+
if (state !== 'LOADING' && forceLoading) {
92+
setState('LOADING');
93+
}
94+
95+
/**
96+
* Sandpack listener
97+
*/
98+
const sandpackIdle = sandpack.status === 'idle';
99+
useEffect(() => {
100+
const unsubscribe = listen((message) => {
101+
if (message.type === 'done') {
102+
setState((prev) => {
103+
return prev === 'LOADING' ? 'PRE_FADING' : 'HIDDEN';
104+
});
105+
}
106+
}, clientId);
107+
108+
return () => {
109+
unsubscribe();
110+
};
111+
}, [listen, clientId, sandpackIdle]);
112+
113+
/**
114+
* Fading transient state
115+
*/
116+
useEffect(() => {
117+
let fadeTimeout: ReturnType<typeof setTimeout>;
118+
119+
if (state === 'PRE_FADING' && !dependenciesLoading) {
120+
setState('FADING');
121+
} else if (state === 'FADING') {
122+
fadeTimeout = setTimeout(
123+
() => setState('HIDDEN'),
124+
FADE_ANIMATION_DURATION
125+
);
126+
}
127+
128+
return () => {
129+
clearTimeout(fadeTimeout);
130+
};
131+
}, [state, dependenciesLoading]);
132+
133+
if (sandpack.status === 'timeout') {
134+
return 'TIMEOUT';
135+
}
136+
137+
if (sandpack.status !== 'running') {
138+
return 'HIDDEN';
139+
}
140+
141+
return state;
142+
};

beta/src/components/MDX/Sandpack/NavigationBar.tsx

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import {DownloadButton} from './DownloadButton';
2222
import {IconChevron} from '../../Icon/IconChevron';
2323
import {Listbox} from '@headlessui/react';
2424

25-
// TODO: Replace with real useEvent.
2625
export function useEvent(fn: any): any {
2726
const ref = useRef(null);
2827
useInsertionEffect(() => {
@@ -94,9 +93,20 @@ export function NavigationBar({providedFiles}: {providedFiles: Array<string>}) {
9493
}, [isMultiFile]);
9594

9695
const handleReset = () => {
97-
if (confirm('Reset all your edits too?')) {
96+
/**
97+
* resetAllFiles must come first, otherwise
98+
* the previous content will appears for a second
99+
* when the iframe loads.
100+
*
101+
* Plus, it should only prompts if there's any file changes
102+
*/
103+
if (
104+
sandpack.editorState === 'dirty' &&
105+
confirm('Reset all your edits too?')
106+
) {
98107
sandpack.resetAllFiles();
99108
}
109+
100110
refresh();
101111
};
102112

0 commit comments

Comments
 (0)