Skip to content

Commit 20050af

Browse files
r281GQcarbonrobot
andauthored
fix: wrap preview in boundary (#392)
Co-authored-by: Charles Brown <carbonrobot@gmail.com>
1 parent 7d7ef30 commit 20050af

File tree

9 files changed

+74
-12
lines changed

9 files changed

+74
-12
lines changed

.changeset/silent-ads-sell.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"react-live": patch
3+
---
4+
5+
Wrap preview in error boundary

.github/workflows/code-check.yml

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
name: Code Check
22

33
on:
4-
push:
5-
branches:
6-
- master
74
pull_request:
85
branches:
96
- master
@@ -16,8 +13,11 @@ jobs:
1613
- uses: actions/checkout@v4
1714
- uses: ./.github/actions/setup
1815

19-
- name: Check Code ${{ matrix.node-version }}
16+
- name: Check Code
2017
run: pnpm lint
2118

22-
- name: Build ${{ matrix.node-version }}
19+
- name: Test
20+
run: pnpm test
21+
22+
- name: Build
2323
run: pnpm build

.github/workflows/release.yml

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
name: react-live Release Workflow
1+
name: Release Workflow
22

33
on:
44
push:
@@ -21,6 +21,12 @@ jobs:
2121
- uses: actions/checkout@v4
2222
- uses: ./.github/actions/setup
2323

24+
- name: Check Code
25+
run: pnpm lint
26+
27+
- name: Test
28+
run: pnpm test
29+
2430
- name: Build packages
2531
run: pnpm run build
2632

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
"build:lib": "pnpm run --filter react-live build",
1414
"lint": "pnpm run --parallel lint",
1515
"lint:fix": "pnpm run --parallel lint --fix",
16+
"test": "pnpm run --filter react-live test",
1617
"changeset": "changeset",
1718
"version": "pnpm changeset version && pnpm install --no-frozen-lockfile"
1819
},
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
import { Component, ReactNode } from "react";
2+
3+
type Props = {
4+
children: ReactNode;
5+
onError?: (error: Error) => void;
6+
};
7+
8+
type State = {
9+
hasError: boolean;
10+
};
11+
12+
export class ErrorBoundary extends Component<Props, State> {
13+
static getDerivedStateFromError() {
14+
return { hasError: true };
15+
}
16+
17+
constructor(props: Props) {
18+
super(props);
19+
this.state = { hasError: false };
20+
}
21+
22+
componentDidCatch(err: Error): void {
23+
this.props.onError?.(err);
24+
}
25+
26+
render() {
27+
if (this.state.hasError) {
28+
return null;
29+
}
30+
31+
return this.props.children;
32+
}
33+
}

packages/react-live/src/components/Live/LiveContext.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ type ContextValue = {
55
error?: string;
66
element?: ComponentType | null;
77
code: string;
8+
newCode?: string;
89
disabled: boolean;
910
language: string;
1011
theme?: typeof themes.nightOwl;

packages/react-live/src/components/Live/LivePreview.tsx

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import React, { useContext } from "react";
2+
3+
import { ErrorBoundary } from "./ErrorBoundary";
24
import LiveContext from "./LiveContext";
35

46
type Props<T extends React.ElementType = React.ElementType> = {
@@ -11,7 +13,12 @@ function LivePreview<T extends keyof JSX.IntrinsicElements>(
1113
function LivePreview<T extends React.ElementType>(props: Props<T>): JSX.Element;
1214

1315
function LivePreview({ Component = "div", ...rest }: Props): JSX.Element {
14-
const { element: Element } = useContext(LiveContext);
15-
return <Component {...rest}>{Element ? <Element /> : null}</Component>;
16+
const { element: Element, onError, newCode } = useContext(LiveContext);
17+
18+
return (
19+
<ErrorBoundary key={newCode} onError={onError}>
20+
<Component {...rest}>{Element ? <Element /> : null}</Component>
21+
</ErrorBoundary>
22+
);
1623
}
1724
export default LivePreview;

packages/react-live/src/components/Live/LiveProvider.tsx

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import { themes } from "prism-react-renderer";
66
type ProviderState = {
77
element?: ComponentType | null;
88
error?: string;
9+
newCode?: string;
910
};
1011

1112
type Props = {
@@ -37,7 +38,11 @@ function LiveProvider({
3738

3839
async function transpileAsync(newCode: string) {
3940
const errorCallback = (error: Error) => {
40-
setState({ error: error.toString(), element: undefined });
41+
setState((previousState) => ({
42+
...previousState,
43+
error: error.toString(),
44+
element: undefined,
45+
}));
4146
};
4247

4348
// - transformCode may be synchronous or asynchronous.
@@ -51,7 +56,7 @@ function LiveProvider({
5156
try {
5257
const transformedCode = await Promise.resolve(transformResult);
5358
const renderElement = (element: ComponentType) =>
54-
setState({ error: undefined, element });
59+
setState({ error: undefined, element, newCode });
5560

5661
if (typeof transformedCode !== "string") {
5762
throw new Error("Code failed to transform");
@@ -65,7 +70,11 @@ function LiveProvider({
6570
};
6671

6772
if (noInline) {
68-
setState({ error: undefined, element: null }); // Reset output for async (no inline) evaluation
73+
setState((previousState) => ({
74+
...previousState,
75+
error: undefined,
76+
element: null,
77+
})); // Reset output for async (no inline) evaluation
6978
renderElementAsync(input, renderElement, errorCallback);
7079
} else {
7180
renderElement(generateElement(input, errorCallback));

website/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
"lint": "eslint --ext .js,.ts,.tsx src",
1212
"deploy": "docusaurus deploy",
1313
"clear": "docusaurus clear",
14-
"serve": "docusaurus serve",
14+
"serve": "docusaurus serve --config ./docusaurus.config.js --dir ./build/open-source/react-live --port 3565 --no-open",
1515
"write-translations": "docusaurus write-translations",
1616
"write-heading-ids": "docusaurus write-heading-ids",
1717
"typecheck": "tsc"

0 commit comments

Comments
 (0)