Component-based markdown renderer for CONNECTIVE HTML. The component-based approach allows you to provide your own custom (possibly interactive) components for the markdown conversion:
// my-header.tsx
function MyHeader({ depth, slug }, renderer, content) {
return <div class={'title title-' + depth} id={'header-' + slug}>{content}</div>;
}
// index.tsx
import { marked } from '@connectv/marked';
import { Renderer } from '@connectv/html';
import { MyHeader } from './my-header';
const renderer = new Renderer();
renderer.render(marked('## Hellow World!', {
Heading: MyHeader
})).on(document.body);
//
// Result:
// <div class="title title-2" id="header-hellow-world">Hellow World!</div>
//
npm i @connectv/marked
For providing your own custom components in JSX/TSX, you need to configure your transpiler accordingly. Here is how to do it for Typescript and here you can see how to do it for Babel.
import { Renderer } from '@connectv/html';
import { marked } from '@connectv/marked';
const renderer = new Renderer();
const md = `
# Hellow!
So this is some markdown text with **some features** and stuff.
`;
renderer.render(marked(md)).on(document.body);
Server-side rendering (using CONNECTIVE SDH):
import { compile } from '@connectv/sdh';
import { marked } from '@connectv/marked';
compile(marked(`
# Hellow Again!
Some other [markdown](https://en.wikipedia.org/wiki/Markdown) for you.
`))
.save('dist/index.html');
As mentioned above, the main point of this library is to provide your own custom components for generating DOM from the markdown:
// my-code.tsx
export function MyCode({ lang }, renderer, content) {
return <pre onclick={() => copyToClipboard(content)}>
<code class={'code ' + lang}>{content}</code>
</pre>;
}
// index.tsx
import { marked } from '@connectv/marked';
import { Renderer } from '@connect/html';
import { MyCode } from './my-code';
const renderer = new Renderer();
const md = `
# Example Code:
\`\`\`typescript
export function something() {
console.log('Halo!');
}
\`\`\`
`;
renderer.render(marked(md, {
Code: MyCode
})).on(document.body);
The following components can be overriden, alongside the properties that the markdown parser would pass to each component:
Space
: used for empty spaces. No props passed to this component.Hr
: used for horizontal lines (---
). No props passed to this component.Heading
: used for headings (# Heading
). Props:depth
: depth of the heading, i.e.# Heading 1
,## Heading 2
,### Heading 3
, etc.slug
: a slug associated with this heading. Can be used to set the content's id so that it is linkable.
Code
: used for code blocks (not inline codes). Props:lang
: the language set for this code block, e.g. ```typescript.
BlockQuote
: used for block quotes> something
. No props passed to this component.List
: used for lists. Props:ordered
: whether the list is ordered or unordered.
ListItem
: used for items of a list. No props passed to this component.Html
: used for inline HTML code. Props:content
: the string representation of the HTML code.
Paragraph
: used for plain text. No props passed to this component.Table
: used for tables. Props:header
: HTML element representing the header of the table.body
: HTML element representing body of the table.
TableRow
: used for each row of a table. No props passed to this component.TableCell
: used for body cells of a table (not header cells). Props:align
: the alignment of the cell.
TableHeaderCell
: used for header cells of a table (not body cells). Props:align
: the alignment of the cell.
Link
: used for links, e.g.[content](href "title")
. Props:href
: the URL of the linktitle
: the "title" attribute of the link
Em
: used for emphasized text, e.g._hellow_
. No props passed to this component.Strong
: used for strong text, e.g.**hellow**
. No props passed to this component.Del
: used for deleted text, e.g.~~hellow~~
. No props passed to this component.Image
: used for images, e.g.![alt](src)
. Props:alt
: the alt text passed for the image,src
: the source URL of the image.
CodeSpan
: used for inline code-spans, e.g.`content`
. No props passed to this component.Text
: used for normal text. No props passed to this component.
You can also use custom components (i.e. components that represent custom structural elements):
// tabs.tsx
export function Tabs(_, renderer, content) {
return <div class="tabs">{content}</div>;
}
export function Tab({ name, default }, renderer, content) {
return <div class="tab" data-tab-name={name} data-default-tab={default==='true'}>{content}</div>;
}
// index.tsx
import { compile } from '@connectv/sdh';
import { marked, quotedComponents } from '@connectv/marked';
import { Tabs, Tab } from './tabs';
const markdown = `
# Some markdown content
> :Tabs
> > :Tab name=first tab, default=true
> >
> > content of the first tab
>
> > :Tab name=second tab
> >
> > content of the second tab
`
compile(marked(markdown, {
BlockQuote: quotedComponents({ Tabs, Tab })
}))
.save('dist/index.html');
Result (dist/index.html
):
<html>
<head></head>
<body>
<h1 id="some-markdown-content">Some markdown content</h1>
<div class="tabs">
<div class="tab" data-tab-name="first tab" data-default-tab>
<p>content of the first tab</p>
</div>
<div class="tab" data-tab-name="second tab">
<p>content of the second tab</p>
</div>
</div>
</body>
</html>
The quotedComponents()
method basically provides an override for BlockQuote
. It will look at each block-quote and check if the first line starts with :
, in that case it will find corresponding component from given map, parse its props, and pass the rest of the content of the block-quote as the component's content.
Similar to custom quoted components, you can utilize custom linked components for custom structural elements that are inline (i.e. appear within other text):
// tag.tsx
export function Tag(_, renderer, content) {
return <span class="tag">#{content}</div>;
}
// index.tsx
import { compile } from '@connectv/sdh';
import { marked, linkedComponents } from '@connectv/marked';
import { Tag } from './tag';
const markdown = `
# Some markdown content
Hellow [world](:Tag)
`
compile(marked(markdown, {
Link: linkedComponents({ Tag })
}))
.save('dist/index.html');
Result (dist/index.html
):
<html>
<head></head>
<body>
<h1 id="some-markdown-content">Some markdown content</h1>
<p>
Hellow <span class="tag">#world</span>
</p>
</body>
</html>
marked is used under the hood, so all features supported by marked are supported here.