Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
104 changes: 81 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,100 @@ npm install --save @readme/markdown

## Usage

By default, the updated markdown package exports a function which takes a string of [ReadMe-flavored markdown](https://docs.readme.com/rdmd/docs/syntax-extensions) and returns a tree of React components:

```jsx
import React from 'react';
import rdmd from '@readme/markdown';
import rmdx from '@readme/markdown';

export default ({ body }) => <div className="markdown-body">{rdmd(body)}</div>;
export default ({ body }) => <div className="markdown-body">{run(compile(body))}</div>;
```

### Export Methods
### API

#### `compile`

Compiles mdx to js. A wrapper around [`mdx.compile`](https://mdxjs.com/packages/mdx/#compilefile-options)

You usually only need this when calling `run` as well. It's been left as a seperate step as a potential caching opportunity.

###### Parameters

- `string` (`string`) -- An mdx document
- `opts` ([`CompileOpts`](#compileopts), optional) -- configuration

###### Returns

compiled code (`string`)

#### `run`

Run compiled code. A wrapper around [`mdx.run`](https://mdxjs.com/packages/mdx/#runcode-options)

> [!CAUTION]
> This `eval`'s JavaScript.

###### Parameters

- `string` (`string`) -- A compiled mdx document
- `opts` (`RunOpts`, optional) -- configuration

###### Returns

A module ([`RMDXModule`](#rmdxmodule)) of renderable components

#### `mdx`

Compiles an ast to mdx.

#### `mdast`

Parses mdx to an mdast.

#### `hast`

Parses mdx to an hast.

#### `plain`

> [!NOTE]
> unimplemented

#### `utils`

Additional defaults, helpers, components, etc.

### `CompileOpts`

Extends [`CompileOptions`](https://mdxjs.com/packages/mdx/#compileoptions)

###### Additional Properties

- `lazyImages` (`boolean`, optional) -- Load images lazily.
- `safeMode` (`boolean`, optional) -- Extract script tags from `HTMLBlock`s
- `components` (`Record<string, string>`, optional) -- An object of tag names to mdx.
- `copyButtons` (`Boolean`, optional) — Automatically insert a button to copy a block of text to the clipboard. Currently used on `<code>` elements.

### `RunOpts`

Extends [`RunOptions`](https://mdxjs.com/packages/mdx/#runoptions)

In addition to the default React processor, the package exports some other methods for transforming ReadMe-flavored markdown:
###### Additional Properties

| Export | Description | Arguments |
| --------: | :--------------------------------------------- | :---------------- |
| _`react`_ | _(default)_ returns a VDOM tree object | `text`, `options` |
| _`md`_ | transform mdast in to ReadMe-flavored markdown | `tree`, `options` |
| _`html`_ | transform markdown in to HTML | `text`, `options` |
| _`mdast`_ | transform markdown to an mdast object | `text`, `options` |
| _`hast`_ | transform markdown to HAST object | `text`, `options` |
| _`plain`_ | transform markdown to plain text | `text`, `options` |
| _`utils`_ | contexts, defaults, helpers, etc. | N/A |
- `components` (`Record<string, MDXModule>`, optional) -- An object of tag names to executed components.
- `imports` (`Record<string, unknown>`, optional) -- An object of modules to import.
- `terms` (`GlossaryTerm[]`, optional)
- `variables` (`Variables`, optional)

### Settings & Options
### `RMDXModule`

Each processor method takes an options object which you can use to adjust the output HTML or React tree. These options include:
###### Properties

- **`compatibilityMode`** — Enable [compatibility features](https://github.com/readmeio/api-explorer/issues/668) from our old markdown engine.
- **`copyButtons`** — Automatically insert a button to copy a block of text to the clipboard. Currently used on `<code>` elements.
- **`correctnewlines`** — Render new line delimeters as `<br>` tags.
- **`markdownOptions`** — Remark [parser options](https://github.com/remarkjs/remark/tree/main/packages/remark-stringify#processorusestringify-options).
- **`safeMode`** — Render html blocks as `<pre>` elements. We normally allow all manner of html attributes that could potentially execute JavaScript.
- `default` (`() => MDXContent`) -- The mdx douments default export
- `toc` (`HastHeading[]`) -- A list of headings in the document
- `Toc` (`() => MDCContent`) -- A table of contents component

## Flavored Syntax

Our old editor rendered "Magic Block" components from a custom, JSON-based syntax. To provide seamless backwards-compatibility, our new processor ships with built in support for parsing this old format, and transpiles it straight in to our new, flavored Markdown.
~~Our old editor rendered "Magic Block" components from a custom, JSON-based syntax. To provide seamless backwards-compatibility, our new processor ships with built in support for parsing this old format, and transpiles it straight in to our new, flavored Markdown.~~

We've also sprinkled a bit of our own syntactic sugar on top to let you supercharge your docs. [**Learn more about ReadMe's flavored syntax!**](https://docs.readme.com/rdmd/docs/syntax-extensions)

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion __tests__/browser/markdown.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ describe('visual regression tests', () => {
async doc => {
const uri = `http://localhost:9966/#/${doc}?ci=true`;
await page.goto(uri, { waitUntil: 'networkidle0' });
await sleep(500);
await sleep(5000);

const image = await page.screenshot({ fullPage: true });

Expand Down
16 changes: 9 additions & 7 deletions __tests__/custom-components/index.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,15 @@ import { render, screen } from '@testing-library/react';
import { execute } from '../helpers';

describe('Custom Components', () => {
const Example = () => <div>It works!</div>;
const Composite = () => (
<>
<div>Does it work?</div>
<Example />
</>
);
const Example = { default: () => <div>It works!</div> };
const Composite = {
default: () => (
<>
<div>Does it work?</div>
<Example.default />
</>
),
};

it('renders custom components', async () => {
const doc = `
Expand Down
49 changes: 49 additions & 0 deletions __tests__/plugins/toc.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import { render, screen } from '@testing-library/react';
import { compile, run } from '../../index';

describe('toc transformer', () => {
it('parses out a toc with max depth of 2', async () => {
const md = `
# Title

## Subheading

### Third

## Second Subheading
`;
const { Toc } = await run(compile(md));

render(<Toc />);

expect(screen.findByText('Title')).toBeDefined();
expect(screen.findByText('Subheading')).toBeDefined();
expect(screen.queryByText('Third')).toBeNull();
expect(screen.findByText('Second Subheading')).toBeDefined();
});

it('parses a toc from components', async () => {
const md = `
# Title

<CommonInfo />

## Subheading
`;
const components = {
CommonInfo: '## Common Heading',
};
const executed = {
CommonInfo: await run(compile('## Common Heading')),
};

const { Toc } = await run(compile(md, { components }), { components: executed });

render(<Toc />);

expect(screen.findByText('Title')).toBeDefined();
expect(screen.findByText('Common Heading')).toBeDefined();
expect(screen.findByText('Subheading')).toBeDefined();
});
});
87 changes: 0 additions & 87 deletions __tests__/transformers/rehype-toc.test.ts

This file was deleted.

11 changes: 8 additions & 3 deletions docs/table-of-contents-tests.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,13 @@
---
title: "Table Of Contents Tests"
title: 'Table Of Contents Tests'
category: 5fdf9fc9c2a7ef443e937315
hidden: true
---
# Variables (<<user>>)

# Glossary Items (<<glossary:demo>>)
# Variables <Variable name="email" />

# Glossary Items <Glossary>demo</Glossary>

## Custom Components

<Demo />
31 changes: 19 additions & 12 deletions example/Doc.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,30 @@
import React, { FunctionComponent, useEffect, useState } from 'react';
import React, { useEffect, useState } from 'react';
import { useParams, useSearchParams } from 'react-router-dom';
import * as mdx from '../index';
import docs from './docs';
import RenderError from './RenderError';
import { MDXContent, MDXModule } from 'mdx/types';
import { MDXContent } from 'mdx/types';

const mdxComponents = {
const components = {
Demo: `
## This is a Demo Component!

> 📘 It can render JSX components!
`,
};

const compiledComponents = {};
const components = {};
Object.keys(mdxComponents).forEach(async comp => {
compiledComponents[comp] = mdx.compile(comp);
components[comp] = (await mdx.run(compiledComponents[comp])).default;
const executedComponents = {};
Object.entries(components).forEach(async ([tag, body]) => {
executedComponents[tag] = await mdx.run(mdx.compile(body));
});

const variables = {
user: {
email: '[email protected]',
},
defaults: [],
};

const terms = [
{
term: 'demo',
Expand All @@ -45,9 +50,9 @@ const Doc = () => {
const [name, doc] =
fixture === 'edited' ? [fixture, searchParams.get('edit') || ''] : [docs[fixture].name, docs[fixture].doc];

const [{ default: Content, toc: Toc }, setContent] = useState<{ default: MDXContent; toc?: MDXContent }>({
const [{ default: Content, Toc }, setContent] = useState<{ default: MDXContent; Toc?: MDXContent }>({
default: null,
toc: null,
Toc: null,
});
const [error, setError] = useState<string>(null);

Expand All @@ -59,8 +64,8 @@ const Doc = () => {
};

try {
const code = mdx.compile(doc, opts);
const content = await mdx.run(code, { components, terms });
const code = mdx.compile(doc, { ...opts, components });
const content = await mdx.run(code, { components: executedComponents, terms, variables });

setError(() => null);
setContent(() => content);
Expand Down Expand Up @@ -91,5 +96,7 @@ const Doc = () => {
</div>
);
};
/*
*/

export default Doc;
Loading