Browse Source

[Beta] Don't rely on special MDX props (#4991)

main
dan 2 years ago
committed by GitHub
parent
commit
bc6310fd98
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 1
      beta/package.json
  2. 8
      beta/src/components/Layout/MarkdownPage.tsx
  3. 4
      beta/src/components/MDX/Challenges/Challenges.tsx
  4. 6
      beta/src/components/MDX/CodeDiagram.tsx
  5. 1
      beta/src/components/MDX/Heading.tsx
  6. 2
      beta/src/components/MDX/Link.tsx
  7. 7
      beta/src/components/MDX/MDXComponents.tsx
  8. 4
      beta/src/components/MDX/PackageImport.tsx
  9. 2
      beta/src/components/MDX/Sandpack/createFileMap.ts
  10. 71
      beta/src/pages/[[...markdownPath]].js
  11. 14
      beta/src/utils/prepareMDX.js

1
beta/package.json

@ -26,7 +26,6 @@
"@docsearch/css": "3.0.0-alpha.41",
"@docsearch/react": "3.0.0-alpha.41",
"@headlessui/react": "^1.3.0",
"@mdx-js/react": "^1.6.16",
"body-scroll-lock": "^3.1.3",
"classnames": "^2.2.6",
"date-fns": "^2.16.1",

8
beta/src/components/Layout/MarkdownPage.tsx

@ -3,8 +3,6 @@
*/
import * as React from 'react';
// @ts-ignore
import {MDXContext} from '@mdx-js/react';
import {DocsPageFooter} from 'components/DocsFooter';
import {MDXComponents} from 'components/MDX/MDXComponents';
import {Seo} from 'components/Seo';
@ -45,11 +43,7 @@ export function MarkdownPage<
/>
)}
<div className="px-5 sm:px-12">
<div className="max-w-7xl mx-auto">
<MDXContext.Provider value={MDXComponents}>
{children}
</MDXContext.Provider>
</div>
<div className="max-w-7xl mx-auto">{children}</div>
<DocsPageFooter
route={route}
nextRoute={nextRoute}

4
beta/src/components/MDX/Challenges/Challenges.tsx

@ -37,8 +37,8 @@ const parseChallengeContents = (
let challenge: Partial<ChallengeContents> = {};
let content: React.ReactElement[] = [];
React.Children.forEach(children, (child) => {
const {props} = child;
switch (props.mdxType) {
const {props, type} = child;
switch ((type as any).mdxName) {
case 'Solution': {
challenge.solution = child;
challenge.content = content;

6
beta/src/components/MDX/CodeDiagram.tsx

@ -12,10 +12,10 @@ interface CodeDiagramProps {
export function CodeDiagram({children, flip = false}: CodeDiagramProps) {
const illustration = React.Children.toArray(children).filter((child: any) => {
return child.props?.mdxType === 'img';
return child.type?.mdxName === 'img';
});
const content = React.Children.toArray(children).map((child: any) => {
if (child.props?.mdxType === 'pre') {
if (child.type?.mdxName === 'pre') {
return (
<CodeBlock
{...child.props.children.props}
@ -23,7 +23,7 @@ export function CodeDiagram({children, flip = false}: CodeDiagramProps) {
noMarkers={true}
/>
);
} else if (child.props?.mdxType === 'img') {
} else if (child.type?.mdxName === 'img') {
return null;
} else {
return child;

1
beta/src/components/MDX/Heading.tsx

@ -71,6 +71,7 @@ export const H2 = ({className, ...props}: HeadingProps) => (
{...props}
/>
);
export const H3 = ({className, ...props}: HeadingProps) => (
<Heading
as="h3"

2
beta/src/components/MDX/Link.tsx

@ -18,7 +18,7 @@ function Link({
'inline text-link dark:text-link-dark break-normal border-b border-link border-opacity-0 hover:border-opacity-100 duration-100 ease-in transition leading-normal';
const modifiedChildren = React.Children.toArray(children).map(
(child: any) => {
if (child.props?.mdxType && child.props?.mdxType === 'inlineCode') {
if (child.type?.mdxName && child.type?.mdxName === 'inlineCode') {
return React.cloneElement(child, {
isLink: true,
});

7
beta/src/components/MDX/MDXComponents.tsx

@ -325,3 +325,10 @@ export const MDXComponents = {
Solution,
CodeStep,
};
for (let key in MDXComponents) {
if (MDXComponents.hasOwnProperty(key)) {
const MDXComponent: any = (MDXComponents as any)[key];
MDXComponent.mdxName = key;
}
}

4
beta/src/components/MDX/PackageImport.tsx

@ -11,10 +11,10 @@ interface PackageImportProps {
export function PackageImport({children}: PackageImportProps) {
const terminal = React.Children.toArray(children).filter((child: any) => {
return child.props?.mdxType !== 'pre';
return child.type?.mdxName !== 'pre';
});
const code = React.Children.toArray(children).map((child: any, i: number) => {
if (child.props?.mdxType === 'pre') {
if (child.type?.mdxName === 'pre') {
return (
<CodeBlock
{...child.props.children.props}

2
beta/src/components/MDX/Sandpack/createFileMap.ts

@ -7,7 +7,7 @@ import type {SandpackFile} from '@codesandbox/sandpack-react';
export const createFileMap = (codeSnippets: any) => {
return codeSnippets.reduce(
(result: Record<string, SandpackFile>, codeSnippet: React.ReactElement) => {
if (codeSnippet.props.mdxType !== 'pre') {
if ((codeSnippet.type as any).mdxName !== 'pre') {
return result;
}
const {props} = codeSnippet.props.children;

71
beta/src/pages/[[...markdownPath]].js

@ -2,15 +2,17 @@
* Copyright (c) Facebook, Inc. and its affiliates.
*/
import {createElement, Children, useMemo} from 'react';
import {createElement, Children, Fragment, useMemo} from 'react';
import {MDXComponents} from 'components/MDX/MDXComponents';
import {MarkdownPage} from 'components/Layout/MarkdownPage';
import {Page} from 'components/Layout/Page';
import {mdx} from '@mdx-js/react';
import {prepareMDX} from '../utils/prepareMDX';
export default function Layout({content, meta}) {
const decoded = useMemo(() => JSON.parse(content, reviveMDX), [content]);
const decoded = useMemo(
() => JSON.parse(content, reviveNodeOnClient),
[content]
);
const {toc, children} = useMemo(
() => prepareMDX(decoded.props.children),
[decoded]
@ -24,20 +26,48 @@ export default function Layout({content, meta}) {
);
}
// Create a React tree from server JSON.
function reviveMDX(key, val) {
if (val && val.$m) {
// This is an MDX node we need to revive.
let args = val.$m;
if (args[0] == null) {
// First argument to createElement() is a type.
// If it didn't serialize, this is a custom MDX component.
args[0] = MDXComponents[args[1].mdxType];
if (args[0] == null) {
throw Error('Unknown type: ' + args[1].mdxType);
}
// Deserialize a client React tree from JSON.
function reviveNodeOnClient(key, val) {
if (Array.isArray(val) && val[0] == '$r') {
// Assume it's a React element.
let type = val[1];
let key = val[2];
let props = val[3];
if (type === 'wrapper') {
type = Fragment;
props = {children: props.children};
}
if (MDXComponents[type]) {
type = MDXComponents[type];
}
if (!type) {
console.error('Unknown type: ' + type);
type = Fragment;
}
return mdx.apply(null, args);
return {
$$typeof: Symbol.for('react.element'),
type: type,
key: key,
ref: null,
props: props,
_owner: null,
};
} else {
return val;
}
}
// Serialize a server React tree node to JSON.
function stringifyNodeOnServer(key, val) {
if (val != null && val.$$typeof === Symbol.for('react.element')) {
// Remove fake MDX props.
const {mdxType, originalType, parentName, ...cleanProps} = val.props;
return [
'$r',
typeof val.type === 'string' ? val.type : mdxType,
val.key,
cleanProps,
];
} else {
return val;
}
@ -72,14 +102,11 @@ export async function getStaticProps(context) {
// Run it to get JSON for render output
const run = new Function('exports', 'mdx', js);
let outputExports = {};
function createJSONNode(...args) {
return {$m: args}; // Marker to turn this into createElement on the client
}
run(outputExports, createJSONNode);
const json = outputExports.default({});
run(outputExports, createElement);
const reactTree = outputExports.default({});
return {
props: {
content: JSON.stringify(json),
content: JSON.stringify(reactTree, stringifyNodeOnServer),
meta,
},
};

14
beta/src/utils/prepareMDX.js

@ -44,7 +44,7 @@ function wrapChildrenInMaxWidthContainers(children) {
wrapQueue.push(child);
return;
}
if (fullWidthTypes.includes(child.props.mdxType)) {
if (fullWidthTypes.includes(child.type.mdxName)) {
flushWrapper(key);
finalChildren.push(child);
} else {
@ -59,22 +59,22 @@ function wrapChildrenInMaxWidthContainers(children) {
function getTableOfContents(children) {
const anchors = Children.toArray(children)
.filter((child) => {
if (child.props?.mdxType) {
if (child.type?.mdxName) {
return ['h1', 'h2', 'h3', 'Challenges', 'Recap'].includes(
child.props.mdxType
child.type.mdxName
);
}
return false;
})
.map((child) => {
if (child.props.mdxType === 'Challenges') {
if (child.type.mdxName === 'Challenges') {
return {
url: '#challenges',
depth: 0,
text: 'Challenges',
};
}
if (child.props.mdxType === 'Recap') {
if (child.type.mdxName === 'Recap') {
return {
url: '#recap',
depth: 0,
@ -84,8 +84,8 @@ function getTableOfContents(children) {
return {
url: '#' + child.props.id,
depth:
(child.props?.mdxType &&
parseInt(child.props.mdxType.replace('h', ''), 0)) ??
(child.type?.mdxName &&
parseInt(child.type.mdxName.replace('h', ''), 0)) ??
0,
text: child.props.children,
};

Loading…
Cancel
Save