diff --git a/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-child-tests-without-surprises-1-snap.png b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-child-tests-without-surprises-1-snap.png
new file mode 100644
index 000000000..ceddb0867
Binary files /dev/null and b/__tests__/browser/__image_snapshots__/markdown-test-js-visual-regression-tests-rdmd-syntax-renders-child-tests-without-surprises-1-snap.png differ
diff --git a/__tests__/browser/markdown.test.js b/__tests__/browser/markdown.test.js
index 5ee938bc4..b350b3a1f 100644
--- a/__tests__/browser/markdown.test.js
+++ b/__tests__/browser/markdown.test.js
@@ -13,6 +13,7 @@ describe('visual regression tests', () => {
const docs = [
'callouts',
'calloutTests',
+ 'childTests',
'codeBlocks',
// skipping this because they sporadically failure with network timing
// issues
diff --git a/__tests__/custom-components/index.test.tsx b/__tests__/custom-components/index.test.tsx
index 743158e49..c8926b5f5 100644
--- a/__tests__/custom-components/index.test.tsx
+++ b/__tests__/custom-components/index.test.tsx
@@ -3,13 +3,13 @@ import type { RMDXModule } from '../../types';
import { render, screen } from '@testing-library/react';
import React from 'react';
-import { execute } from '../helpers';
import { compile, run } from '../../lib';
-import { RMDXModule } from '../../types';
+import { execute } from '../helpers';
describe('Custom Components', () => {
let Example;
let Multiple;
+ let Nesting;
beforeEach(async () => {
Example = await execute('It works!', {}, {}, { getDefault: false });
@@ -22,6 +22,16 @@ export const Second = () =>
Second
;
{},
{ getDefault: false },
);
+ Nesting = await execute(
+ `
+export const WithChildren = ({ children }) => {children}
;
+
+{props.children}
+`,
+ {},
+ {},
+ { getDefault: false },
+ );
});
it('renders custom components', async () => {
@@ -47,9 +57,17 @@ export const Second = () => Second
;
expect(screen.getByText('Second')).toBeVisible();
});
+ it('renders a nested exported custom component', async () => {
+ const doc = 'Hello, Test User!';
+ const Page = (await execute(doc, undefined, { components: { Nesting } })) as RMDXModule['default'];
+ render();
+
+ expect(screen.getByText('Hello, Test User!')).toBeVisible();
+ });
+
it('renders the default export of a custom component and passes through props', async () => {
- const Test = (await run(await compile(`{props.attr}`))) as RMDXModule;
- const doc = ``;
+ const Test = (await run(await compile('{props.attr}'))) as RMDXModule;
+ const doc = '';
const Page = await run(await compile(doc), { components: { Test } });
render();
diff --git a/__tests__/fixtures/child-tests.mdx b/__tests__/fixtures/child-tests.mdx
new file mode 100644
index 000000000..818dee83d
--- /dev/null
+++ b/__tests__/fixtures/child-tests.mdx
@@ -0,0 +1,4 @@
+
+ Step One
+ Step Two
+
diff --git a/example/components.ts b/example/components.ts
index 15d3ec068..547619e5f 100644
--- a/example/components.ts
+++ b/example/components.ts
@@ -25,6 +25,21 @@ export const StyledComponent = () => {
;
}
`,
+ Steps: `
+export const Step = ({ children }) => {
+ return (
+
+ );
+};
+
+
+ {props.children}
+
+ `,
};
export default components;
diff --git a/example/docs.ts b/example/docs.ts
index be2b01b35..2aa9abbae 100644
--- a/example/docs.ts
+++ b/example/docs.ts
@@ -1,4 +1,5 @@
import calloutTests from '../__tests__/fixtures/callout-tests.md';
+import childTests from '../__tests__/fixtures/child-tests.mdx';
import codeBlockTests from '../__tests__/fixtures/code-block-tests.md';
import exportTests from '../__tests__/fixtures/export-tests.mdx';
import imageTests from '../__tests__/fixtures/image-tests.mdx';
@@ -25,6 +26,7 @@ const lowerCase = (str: string) =>
const fixtures = Object.entries({
calloutTests,
callouts,
+ childTests,
codeBlockTests,
codeBlocks,
embeds,
diff --git a/lib/run.tsx b/lib/run.tsx
index c53a8d895..8c363e2a8 100644
--- a/lib/run.tsx
+++ b/lib/run.tsx
@@ -12,7 +12,7 @@ import * as runtime from 'react/jsx-runtime';
import * as Components from '../components';
import Contexts from '../contexts';
-import { tocToMdx } from '../processor/plugin/toc';
+import { tocHastToMdx } from '../processor/plugin/toc';
import User from '../utils/user';
import compile from './compile';
@@ -54,10 +54,13 @@ const makeUseMDXComponents = (more: ReturnType = {}): UseMdxCo
const run = async (string: string, _opts: RunOpts = {}) => {
const { Fragment } = runtime;
const { components = {}, terms, variables, baseUrl, imports = {}, ...opts } = _opts;
+
+ const tocsByTag: Record = {};
const exportedComponents = Object.entries(components).reduce((memo, [tag, mod]) => {
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { default: Content, toc, Toc, stylesheets, ...rest } = mod;
memo[tag] = Content;
+ tocsByTag[tag] = toc;
if (rest) {
Object.entries(rest).forEach(([subTag, component]) => {
@@ -83,7 +86,7 @@ const run = async (string: string, _opts: RunOpts = {}) => {
const { Toc: _Toc, toc, default: Content, stylesheet, ...exports } = await exec(string);
let Toc: React.FC | undefined;
- const tocMdx = tocToMdx(toc, components);
+ const tocMdx = tocHastToMdx(toc, tocsByTag);
if (tocMdx) {
const compiledToc = await compile(tocMdx);
const tocModule = await exec(compiledToc, { useMDXComponents: () => ({ p: Fragment }) });
diff --git a/processor/plugin/toc.ts b/processor/plugin/toc.ts
index 1e1b95643..3eb85d0b4 100644
--- a/processor/plugin/toc.ts
+++ b/processor/plugin/toc.ts
@@ -1,4 +1,4 @@
-import type { CustomComponents, HastHeading, IndexableElements, TocList, TocListItem } from '../../types';
+import type { CustomComponents, HastHeading, IndexableElements, RMDXModule, TocList, TocListItem } from '../../types';
import type { Root } from 'hast';
import type { MdxjsEsm } from 'mdast-util-mdxjs-esm';
import type { Transformer } from 'unified';
@@ -89,11 +89,11 @@ const tocToHast = (headings: HastHeading[] = []): TocList => {
return ast;
};
-export const tocToMdx = (toc: IndexableElements[], components: CustomComponents) => {
+export const tocHastToMdx = (toc: IndexableElements[], components: Record) => {
const tree: Root = { type: 'root', children: toc };
visit(tree, 'mdxJsxFlowElement', (node, index, parent) => {
- const subToc = components[node.name].toc || [];
+ const subToc = components[node.name] || [];
parent.children.splice(index, 1, ...subToc);
});