Markdown Renderer

Inkdrop's markdown rendering system is built on top of remark, a markdown processor powered by plugins part of the unified collective. You can access a global instance of this class using the code provided below.

const { markdownRenderer } = require('inkdrop')

remarkPlugins

An array of custom Remark plugins.

See also: math plugin

Here is a plugin that adds your custom Remark plugin:

Example plugin

const { markdownRenderer } = require('inkdrop')

module.exports = {
  activate() {
    if (markdownRenderer) {
      markdownRenderer.remarkPlugins.push(YOUR_PLUGIN)
    }
  },
  deactivate() {
    if (markdownRenderer) {
      markdownRenderer.remarkPlugins = markdownRenderer.remarkPlugins.filter(
        plugin => YOUR_PLUGIN !== plugin
      )
    }
  }
}

rehypePlugins

The Markdown notes are converted from Markdown to HTML. The HTML data is then processed with Rehype. You can extend the process by adding your custom Rehype plugins.

Here is a plugin that adds your custom Rehype plugin:

Example plugin

const { markdownRenderer } = require('inkdrop')

module.exports = {
  activate() {
    if (markdownRenderer) {
      markdownRenderer.rehypePlugins.push(YOUR_PLUGIN)
    }
  },
  deactivate() {
    if (markdownRenderer) {
      markdownRenderer.rehypePlugins = markdownRenderer.remarkPlugins.filter(
        plugin => YOUR_PLUGIN !== plugin
      )
    }
  }
}

remarkReactComponents

This property is an object that maps HTML element names to React components. You can override default elements (such as a, p, etc.) by passing your custom components.

Check out rehype-react for more details.

  • Example plugin: toc

If you want to override the rendering of a HTML elements with a custom component, you can do it as shown:

Override Anchor Element

class Anchor extends React.Component {
  render() {
    // ...
  }
}
markdownRenderer.remarkReactComponents.a = Anchor

remarkCodeComponents

Allows you to render code blocks with custom React components. You can define a component for a specific language as demonstrated:

JavaScript Code Block

const JSCodeBlock = props => {
  const { lang, title, lineAt } = props
  const code = props.children[0]
  return (
    <pre>
      {/* Custom JS block */}
    </pre>
  )
}

markdownRenderer.remarkCodeComponents['javascript'] = JSCodeBlock

events

The events property allows you to listen to events emitted by the renderer. An event handler can be an async function. Here is a list of events that you can listen to:

  • Name
    a:click
    Type
    Description

    Emitted when a link is clicked. Returns true if the event is handled.

    • Name
      event
      Type
      React.MouseEvent<HTMLAnchorElement, MouseEvent>
      Description

      Mouse event

  • Name
    checkbox:change
    Type
    Description

    Emitted when checkbox is clicked. Returns true if the event is handled.

    • Name
      event
      Type
      React.ChangeEvent<HTMLInputElement>
      Description

      Change event

    • Name
      detail
      Type
      { checked: boolean numLine: number }
      Description

      checked indicates whether the checkbox is checked or not. numLine is the line number of the checkbox.

Listening to the renderer events

useEffect(() => {
  const app = getApp()
  const disposables = [
    events.on('checkbox:change', (_e, { checked, numLine }) => {
      console.log(`checkbox ${checked ? 'checked' : 'unchecked'} at line ${numLine}`)
    }),
    events.on('a:click', e => {
      const target = e.target as HTMLAnchorElement
      const { href } = target

      console.log(`clicked link: ${href}`)
      // Should return true if the event is handled
      return true
    })
  ]
  return () => {
    disposables.forEach(d => d())
  }
}, [])
Can you help us improve the docs? 🙏

The source of these docs is here on GitHub. If you see a way these docs can be improved, please fork us!