markdown/inline_svg.js

/** @module */
import split from '../helpers/split'
import wrapTokens from '../helpers/wrap_tokens'
import marpitPlugin from '../plugin'

/**
 * Marpit Inline SVG plugin.
 *
 * @alias module:markdown/inline_svg
 * @param {MarkdownIt} md markdown-it instance.
 */
function inlineSVG(md) {
  const { marpit } = md

  md.core.ruler.after(
    'marpit_directives_parse',
    'marpit_inline_svg',
    (state) => {
      if (!marpit.options.inlineSVG || state.inlineMode) return

      const { themeSet, lastGlobalDirectives } = marpit
      const w = themeSet.getThemeProp(lastGlobalDirectives.theme, 'widthPixel')
      const h = themeSet.getThemeProp(lastGlobalDirectives.theme, 'heightPixel')
      const newTokens = []

      for (const tokens of split(
        state.tokens,
        (t) => t.meta && t.meta.marpitSlideElement === 1,
        true
      )) {
        if (tokens.length > 0) {
          for (const t of tokens)
            if (t.meta && t.meta.marpitSlideElement)
              delete t.meta.marpitSlideElement

          newTokens.push(
            ...wrapTokens(
              state.Token,
              'marpit_inline_svg',
              {
                tag: 'svg',
                'data-marpit-svg': '',
                viewBox: `0 0 ${w} ${h}`,
                open: { meta: { marpitSlideElement: 1 } },
                close: { meta: { marpitSlideElement: -1 } },
              },
              wrapTokens(
                state.Token,
                'marpit_inline_svg_content',
                { tag: 'foreignObject', width: w, height: h },
                tokens
              )
            )
          )
        }
      }

      state.tokens = newTokens
    }
  )
}

export default marpitPlugin(inlineSVG)