forked from Workday/canvas-kit
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMDXElements.tsx
87 lines (77 loc) · 2.72 KB
/
MDXElements.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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
//@ts-ignore
import {useMDXComponents} from '@mdx-js/react';
import React from 'react';
import MarkdownToJSX from 'markdown-to-jsx';
import {createComponent} from '@workday/canvas-kit-react';
import {HeadingLevelContext, SymbolDialog} from './widgetUtils';
/**
* Special component that taps into @mdx-js/react components that are used by both Storybook and the
* Canvas Site. This means our docs can use the same components used in our MDX files without
* needing to use MDX directly.
*/
export const MDX = createComponent('div')({
Component({children, ...elemProps}, _ref, Element) {
const components = useMDXComponents();
return React.createElement(components[Element] || Element, elemProps, children);
},
});
/**
* Custom component that allows us to convert any `button` in JSDoc that contains a `[data-symbol]`
* to a `<SymbolDialog>` component.
*/
const Button = (props: any) => {
const components = useMDXComponents();
if (props['data-symbol'] !== undefined) {
return (
<code>
<SymbolDialog
value={{
kind: 'symbol',
name: props.children?.[0] || '',
displayName: props['data-symbol'],
value: props.children?.[0] || '',
}}
/>
</code>
);
}
return React.createElement(components['button'] || 'button', props, props.children);
};
/**
* Convert [JSDoc link](https://jsdoc.app/tags-inline-link.html) into a `button` element for later
* processing. This allows us to convert {@link SymbolName Link Text} to a `<SymbolDialog>`!
*/
function convertLinkToSymbolLinks(input: string): string {
return input.replace(
/{@link ([a-z0-9.]+)( [a-z0-9.]+)?}/gi,
(substr, symbol, text = '') =>
`<button href="#" data-symbol="${text.trim()}" class="token symbol">${symbol}</button>`
);
}
/**
* Replace all heading levels in the JSDoc to start at the same heading level as `startingLevel`.
* This allows JSDoc markdown to seamlessly flow into MDX.
*/
function rewriteHeadingLevels(input: string, startingLevel: number) {
const firstHeadingMatch = input.match(/(#+ )[A-Za-z]/);
if (!firstHeadingMatch) {
return input;
}
const firstHeadingLevel = firstHeadingMatch[1];
return input.replace(
new RegExp(firstHeadingLevel, 'g'),
Array.from({length: startingLevel}, () => '#').join('') + ' '
);
}
/**
* Custom MDX to JSX parsing
*/
export const MdxJSToJSX = (props: {children: string}) => {
const components = useMDXComponents();
const headingLevel = React.useContext(HeadingLevelContext);
return (
<MarkdownToJSX options={{overrides: {...components, button: Button}, forceBlock: true}}>
{rewriteHeadingLevels(convertLinkToSymbolLinks(props.children), headingLevel)}
</MarkdownToJSX>
);
};