unified

Project: medfreeman/remark-generic-extensions

Package: remark-generic-extensions@1.4.0

  1. !Extension[Content](Argument){Properties} -> 🎉 — commonmark generic directive extension for remark
  1. remark 213
  2. markdown 152
  3. html 123
  4. remark-plugin 81
  5. react 14
  6. commonmark 6

remark-generic-extensions

npm version npm CircleCI Coverage Status Greenkeeper badge dependencies Status devDependencies Status

styled with prettier

Allows the use of commonmark generic directive extension in markdown, generating components through remark-html or remark-react.

This module also works in browser environments.

📖 Release Notes

Demo

Here's a demo using remark-react and react-toolbox. It is made using create-react-app, the source is here and can also be run locally.

Edit medfreeman/remark-generic-extensions: react-toolbox-icon

Disclaimer

Remember that the following syntax is experimental in regards to the commonmark spec, and will perhaps never be supported officialy.

Generic Directives is still in active discussion in http://talk.commonmark.org/t/generic-directives-plugins-syntax . But for brainstorming purposes, here is some possible extensions to support, or at least adhere to if not included.

It might look like !extensionName[](){} for inline

and for block (Current talk page at http://talk.commonmark.org/t/block-directives/802 )

extentionNames: argumentField 
:::
...BlockContent...
:::
{ #id .class key1=value key2=value }

There is a known bug in remark-react < 4.0.1, that wrongly coerces non-string values to strings.

Make sure to use at least v4.0.1.

Syntax

Inline extensions

!Extension[Content](Argument){Properties}

ℹī¸ The extension syntax is validated through regexes, that you can inspect here if needed

Block extensions

Extension: Argument
:::
[Content]
:::
{Properties}

ℹī¸ The extension syntax is validated through regexes, that you can inspect here if needed

Available properties

Installation

npm install remark-generic-extensions

OR

yarn add remark-generic-extensions

Usage (es6)

with remark-react

See demo

with remark-html

Say we have the following file, example.md:

# Alpha

!alert[My message!](my subtext is rad){ #my-alert .custom-alert }

youtube: C8NAYW-Z54o
:::
My featured video!
:::
{ #my-video .custom-video-style spanClassName=custom-span-class }

## Bravo

## Delta

And our script, example.js, looks as follows:

import vfile from "to-vfile"
import remark from "remark"
import genericExtensions from "remark-generic-extensions"
import html from "remark-html"

remark()
.use(genericExtensions,
  {
    elements: {
      alert: {
        html: {
          tagName: "span",
          children: [
            {
              type: "element",
              tagName: "i",
              properties: {
                className: "fa fa-exclamation",
                ariaHidden: true
              }
            },
            {
              type: "element",
              tagName: "span",
              children: [
                {
                  type: "text",
                  value: "::content::"
                }
              ]
            },
            {
              type: "element",
              tagName: "span",
              properties: {
                className: "subtext"
              },
              children: [
                {
                  type: "text",
                  value: "::argument::"
                }
              ]
            }
          ]
        }
      }
    },
    youtube: {
      html: {
        tagName: "div",
        children: [
          {
            type: "element",
            tagName: "iframe",
            properties: {
              width: 420,
              height: 315,
              src: "https://www.youtube.com/embed/::argument::"
            }
          },
          {
            tagName: "span",
            properties: {
              className: "::prop::spanClassName::"
            },
            children: [
              {
                type: "text",
                value: "::content::"
              }
            ]
          }
        ]
      }
    }
  }
)
.use(html)
.process(vfile.readSync('example.md'), (err, file) => {
  if (err) throw err
  console.log(String(file))
})

Now, running node example yields (indented):

<h1>Alpha</h1>

<p>
  <span id="my-alert" class="custom-alert">
    <i class="fa fa-exclamation" aria-hidden="true"></i>
    <span>My message!</span>
    <span class="subtext">my subtext is rad</span>
  </span>
</p>

<div class="custom-video-style" id="my-video">
  <iframe width="420" height="315" src="https://www.youtube.com/embed/C8NAYW-Z54o"></iframe>
  <span class="custom-span-class">My featured video!</span>
</div>

<h2>Bravo</h2>

<h2>Delta</h2>

API

remark().use(genericExtensions[, options])

Convert generic extensions in a markdown document to an hast syntax tree, suitable for rendering to html / react.

options (object)

All options are validated through joi. You can find the schema here. In case of error, it will be logged to the console and this module bypassed by remark.

Properties

Elements (object)

This object defines the extensions configuration.

The keys are strings corresponding to the inline extension names (i.e. Icon).

You can define one or more extensions if needed.

Properties

Hast (array[object])

This structure is a hast tree, with a few restrictions.

It is recursive, the children property also being of Hast type.

Properties

HastProperties (object)

This object pairs are mapped to hast properties, and thus follow the same rules.

Properties

ℹī¸ Any property present in a markdown extension and not referenced by a placeholder will be applied to the top-level element.

ℹī¸ If the content property is not referenced on a block element, it will be applied to a child text node of the top-level element.

Placeholders

The value property and all properties members in Hast children support placeholders.

The available placeholders are:

ℹī¸ the available properties are id, className or any other property defined in your markdown.

Specifying the placeholderAffix option allows changing the placeholders. For example, using "||" would make the available placeholders become "||content||", "||argument||" and "||prop||property||".

Logging

All logging, except the options validation that is directly logged to the console, takes place through vfile-reporter.

It allows having nice error messages with positional information, and is also the standard way of logging with unifiedjs.

By default, this module logs warnings, but enabling the debug option will also log debug messages, useful for troubleshooting.

logging example (es6)

import remark from "remark"
import genericExtensions "remark-generic-extensions"
import html from "remark-html"
import report from "vfile-reporter"

remark()
.use(genericExtensions, {})
.use(html)
.process(input, function(err, file) {
  console.log(report(err || file))
})

debugging example (es6)

import remark from "remark"
import genericExtensions "remark-generic-extensions"
import html from "remark-html"
import report from "vfile-reporter"

remark()
.use(genericExtensions, { debug: true })
.use(html)
.process(input, function(err, file) {
  console.log(report(err || file))
})


CONTRIBUTING

LICENSE

Apache License 2.0

Copyright (c) Mehdi Lahlou mlahlou@protonmail.ch