Skip to content

Commit 6d96542

Browse files
harish-sethuramandanilowozgaearon
authored
[Beta] Add console to sandboxes (#4672)
* added code for sandpack console * add log * added console for older bundle * Revert "[beta] Sandpack - new bundler (#4458)" This reverts commit 3ab1245. * adds proper console and removes new bundle * modify styles * remove unwanted code * nit * fix types (#4677) * update console * little nits * remove unwanted code changes * update bundler URL * use `message.firstLoad` for clearing console * use `refresh` event to clear logs as well (used when going away and coming back to sandpack) * remove padding for code blocks inside console * small UI revamps * change p to div since the sandpack comes inside the p, add try catch and a try catch for the catch again * tweaks * Fixes * Reset unrelated changes * tweaks * fix * fixes * oops * Fix * fix Co-authored-by: Danilo Woznica <[email protected]> Co-authored-by: Dan Abramov <[email protected]>
1 parent e4d807d commit 6d96542

File tree

3 files changed

+163
-0
lines changed

3 files changed

+163
-0
lines changed

Diff for: beta/src/components/MDX/Sandpack/Console.tsx

+154
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
/*
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*/
4+
import cn from 'classnames';
5+
import * as React from 'react';
6+
import {IconChevron} from 'components/Icon/IconChevron';
7+
8+
import {SandpackCodeViewer, useSandpack} from '@codesandbox/sandpack-react';
9+
import type {SandpackMessageConsoleMethods} from '@codesandbox/sandpack-client';
10+
11+
const getType = (
12+
message: SandpackMessageConsoleMethods
13+
): 'info' | 'warning' | 'error' => {
14+
if (message === 'log' || message === 'info') {
15+
return 'info';
16+
}
17+
18+
if (message === 'warn') {
19+
return 'warning';
20+
}
21+
22+
return 'error';
23+
};
24+
25+
type ConsoleData = Array<{
26+
data: Array<string | Record<string, string>>;
27+
id: string;
28+
method: SandpackMessageConsoleMethods;
29+
}>;
30+
31+
const MAX_MESSAGE_COUNT = 100;
32+
33+
export const SandpackConsole = () => {
34+
const {listen} = useSandpack();
35+
const [logs, setLogs] = React.useState<ConsoleData>([]);
36+
const wrapperRef = React.useRef<HTMLDivElement>(null);
37+
38+
React.useEffect(() => {
39+
const unsubscribe = listen((message) => {
40+
if (
41+
(message.type === 'start' && message.firstLoad) ||
42+
message.type === 'refresh'
43+
) {
44+
setLogs([]);
45+
}
46+
if (message.type === 'console' && message.codesandbox) {
47+
setLogs((prev) => {
48+
const messages = [...prev, ...message.log];
49+
messages.slice(Math.max(0, messages.length - MAX_MESSAGE_COUNT));
50+
51+
return messages.filter(({method}) => method === 'log');
52+
});
53+
}
54+
});
55+
56+
return unsubscribe;
57+
}, [listen]);
58+
59+
const [isExpanded, setIsExpanded] = React.useState(false);
60+
61+
React.useEffect(() => {
62+
if (wrapperRef.current) {
63+
wrapperRef.current.scrollTop = wrapperRef.current.scrollHeight;
64+
}
65+
}, [logs]);
66+
67+
if (logs.length === 0) {
68+
return null;
69+
}
70+
71+
return (
72+
<div className="absolute dark:border-gray-700 bg-white dark:bg-gray-95 border-t bottom-0 w-full dark:text-white">
73+
<div className="flex justify-between">
74+
<button
75+
className="flex items-center p-1"
76+
onClick={() => setIsExpanded(!isExpanded)}>
77+
<IconChevron displayDirection={isExpanded ? 'down' : 'right'} />
78+
<span className="pl-1 text-sm">Console ({logs.length})</span>
79+
</button>
80+
<button
81+
className="p-1"
82+
onClick={() => {
83+
setLogs([]);
84+
setIsExpanded(false);
85+
}}>
86+
<svg
87+
viewBox="0 0 24 24"
88+
width="18"
89+
height="18"
90+
stroke="currentColor"
91+
strokeWidth="2"
92+
fill="none"
93+
strokeLinecap="round"
94+
strokeLinejoin="round">
95+
<circle cx="12" cy="12" r="10"></circle>
96+
<line x1="4.93" y1="4.93" x2="19.07" y2="19.07"></line>
97+
</svg>
98+
</button>
99+
</div>
100+
{isExpanded && (
101+
<div className="w-full h-full border-y bg-white dark:border-gray-700 dark:bg-gray-95 min-h-[28px] console">
102+
<div className="max-h-52 h-auto overflow-auto" ref={wrapperRef}>
103+
{logs.map(({data, id, method}) => {
104+
return (
105+
<div
106+
key={id}
107+
className={cn(
108+
'last:border-none border-b dark:border-gray-700 text-md p-1 pl-2 leading-6 font-mono',
109+
`console-${getType(method)}`
110+
)}>
111+
<span className={cn('console-message')}>
112+
{data.map((msg, index) => {
113+
if (typeof msg === 'string') {
114+
return <span key={`${msg}-${index}`}>{msg}</span>;
115+
}
116+
117+
let children;
118+
if (msg != null && typeof msg['@t'] === 'string') {
119+
// CodeSandbox wraps custom types
120+
children = msg['@t'];
121+
} else {
122+
try {
123+
children = JSON.stringify(msg, null, 2);
124+
} catch (error) {
125+
try {
126+
children = Object.prototype.toString.call(msg);
127+
} catch (err) {
128+
children = '[' + typeof msg + ']';
129+
}
130+
}
131+
}
132+
133+
return (
134+
<span
135+
className={cn('console-span')}
136+
key={`${msg}-${index}`}>
137+
<SandpackCodeViewer
138+
initMode="user-visible"
139+
// fileType="js"
140+
code={children}
141+
/>
142+
</span>
143+
);
144+
})}
145+
</span>
146+
</div>
147+
);
148+
})}
149+
</div>
150+
</div>
151+
)}
152+
</div>
153+
);
154+
};

Diff for: beta/src/components/MDX/Sandpack/Preview.tsx

+2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import * as React from 'react';
77
import {useSandpack, LoadingOverlay} from '@codesandbox/sandpack-react';
88
import cn from 'classnames';
99
import {Error} from './Error';
10+
import {SandpackConsole} from './Console';
1011
import type {LintDiagnostic} from './useSandpackLint';
1112

1213
const generateRandomId = (): string =>
@@ -209,6 +210,7 @@ export function Preview({
209210
loading={!isReady && iframeComputedHeight === null}
210211
/>
211212
</div>
213+
<SandpackConsole />
212214
</div>
213215
);
214216
}

Diff for: beta/src/styles/sandpack.css

+7
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,13 @@ html.dark .sp-code-editor .cm-diagnostic {
154154
overflow: auto !important;
155155
padding: 18px 0 !important;
156156
}
157+
158+
.console .sp-cm,
159+
.console .sp-cm .cm-scroller,
160+
.console .sp-cm .cm-line {
161+
padding: 0px !important;
162+
}
163+
157164
.sp-cm .cm-gutters {
158165
background-color: var(--sp-colors-bg-default);
159166
z-index: 1;

0 commit comments

Comments
 (0)