-
-
Notifications
You must be signed in to change notification settings - Fork 9.1k
/
DocsRenderer.tsx
72 lines (61 loc) · 2.02 KB
/
DocsRenderer.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
import React, { Component } from 'react';
import { renderElement, unmountElement } from '@storybook/react-dom-shim';
import type { Renderer, Parameters, DocsContextProps, DocsRenderFunction } from '@storybook/types';
import { Docs, CodeOrSourceMdx, AnchorMdx, HeadersMdx } from '@storybook/blocks';
// TS doesn't like that we export a component with types that it doesn't know about (TS4203)
export const defaultComponents: Record<string, any> = {
code: CodeOrSourceMdx,
a: AnchorMdx,
...HeadersMdx,
};
class ErrorBoundary extends Component<{
showException: (err: Error) => void;
}> {
state = { hasError: false };
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(err: Error) {
const { showException } = this.props;
showException(err);
}
render() {
const { hasError } = this.state;
const { children } = this.props;
return hasError ? null : children;
}
}
export class DocsRenderer<TRenderer extends Renderer> {
public render: DocsRenderFunction<TRenderer>;
public unmount: (element: HTMLElement) => void;
constructor() {
this.render = async (
context: DocsContextProps<TRenderer>,
docsParameter: Parameters,
element: HTMLElement
): Promise<void> => {
const components = {
...defaultComponents,
...docsParameter?.components,
};
return new Promise((resolve, reject) => {
import('@mdx-js/react')
.then(({ MDXProvider }) =>
// We use a `key={}` here to reset the `hasError` state each time we render ErrorBoundary
renderElement(
<ErrorBoundary showException={reject} key={Math.random()}>
<MDXProvider components={components}>
<Docs context={context} docsParameter={docsParameter} />
</MDXProvider>
</ErrorBoundary>,
element
)
)
.then(resolve);
});
};
this.unmount = (element: HTMLElement) => {
unmountElement(element);
};
}
}