/svelte-milkdown

πŸ₯› Simple example for using Svelte with Milkdown, a plugin driven WYSIWYG markdown editor framework.

Primary LanguageSvelteMIT LicenseMIT

Svelte πŸ₯› Milkdown

code size repo size commit activity last commit website up?

A simple example for using Milkdown with Svelte.

Github Pages Vercel

deploy to stackblitz

πŸš€ Getting Started

  1. Clone the repo: git clone https://github.com/semanticdata/svelte-milkdown.git.

  2. Install dependencies: pnpm install.

  3. Run the example: pnpm start.

  4. Open http://localhost:5173/ in your browser.

Helpful Links

Interacting with Editor

Register to DOM

By default, milkdown will create editor on the document.body. Alternatively, you can also point out which dom node you want it to load into:

import {rootCtx} from '@milkdown/core'

Editor.make().config((ctx) => {
  ctx.set(rootCtx, document.querySelector('#editor'))
})

It's also possible to just pass a selector to rootCtx:

The selector will be passed to document.querySelector to get the dom.

import {rootCtx} from '@milkdown/core'

Editor.make().config((ctx) => {
  ctx.set(rootCtx, '#editor')
})

Setting Default Value

We support three types of default values:

  • Markdown strings.
  • HTML DOM.
  • Prosemirror documentation JSON.

Markdown

You can set a markdown string as the default value of the editor.

import {defaultValueCtx} from '@milkdown/core'

const defaultValue = '# Hello milkdown'
Editor.make().config((ctx) => {
  ctx.set(defaultValueCtx, defaultValue)
})

And then the editor will be rendered with default value.

DOM

You can also use HTML as default value.

Let's assume that we have the following html snippets:

<div id="pre">
  <h1>Hello milkdown!</h1>
</div>

Then we can use it as a defaultValue with a type specification:

import {defaultValueCtx} from '@milkdown/core'

const defaultValue = {
  type: 'html',
  dom: document.querySelector('#pre')
}
Editor.make().config((ctx) => {
  ctx.set(defaultValueCtx, defaultValue)
})

JSON

We can also use a JSON object as a default value.

This JSON object can be obtained by a listener through the listener-plugin, for example:

import {listener, listenerCtx} from '@milkdown/plugin-listener'

let jsonOutput

Editor.make()
  .config((ctx) => {
    ctx.get(listenerCtx).updated((ctx, doc, prevDoc) => {
      jsonOutput = doc.toJSON()
    })
  })
  .use(listener)

Then we can use this jsonOutput as default Value:

import {defaultValueCtx} from '@milkdown/core'

const defaultValue = {
  type: 'json',
  value: jsonOutput
}
Editor.make().config((ctx) => {
  ctx.set(defaultValueCtx, defaultValue)
})

Inspecting Editor Status

You can inspect the editor's status through the status property.

import {Editor, EditorStatus} from '@milkdown/core'

const editor = Editor.make().use(/*some plugins*/)

assert(editor.status === EditorStatus.Idle)

editor.create().then(() => {
  assert(editor.status === EditorStatus.Created)
})

assert(editor.status === EditorStatus.OnCreate)

editor.destroy().then(() => {
  assert(editor.status === EditorStatus.Destroyed)
})

assert(editor.status === EditorStatus.OnDestroyed)

You can also listen to the status changes:

import { Editor, EditorStatus } from '@milkdown/core';

const editor = Editor.make().use(/*some plugins*/);

editor.onStatusChange((status: EditorStatus) => {
  console.log(status);
});

Adding Listeners

As mentioned above, you can add a listener to the editor, in order to get it's value when needed.

Markdown Listener

You can add markdown listener to get the editor's contents as a markdown string.

You can add as many listeners as you want, all the listeners will be triggered at once.

import {listener, listenerCtx} from '@milkdown/plugin-listener'

let output = ''

Editor.make()
  .config((ctx) => {
    ctx.get(listenerCtx).markdownUpdated((ctx, markdown, prevMarkdown) => {
      output = markdown
    })
  })
  .use(listener)

Doc Listener

You can also listen to the raw prosemirror document node, and do things you want from there.

import {listener, listenerCtx} from '@milkdown/plugin-listener'

let jsonOutput

Editor.make()
  .config((ctx) => {
    ctx.get(listenerCtx).updated((ctx, doc, prevDoc) => {
      jsonOutput = doc.toJSON()
    })
  })
  .use(listener)

For more details about listeners, please check Using Listeners.

Readonly Mode

You can set the editor to readonly mode by setting the editable property.

import {editorViewOptionsCtx} from '@milkdown/core'

let readonly = false

const editable = () => !readonly

Editor.make().config((ctx) => {
  ctx.update(editorViewOptionsCtx, (prev) => ({
    ...prev,
    editable
  }))
})

// set to readonly after 5 secs.
setTimeout(() => {
  readonly = true
}, 5000)

Using Actions

You can use an action to get the context value in a running editor on demand.

For example, to get the markdown string by running an action:

import {Editor, editorViewCtx, serializerCtx} from '@milkdown/core'

async function playWithEditor() {
  const editor = await Editor.make().use(commonmark).create()

  const getMarkdown = () =>
    editor.action((ctx) => {
      const editorView = ctx.get(editorViewCtx)
      const serializer = ctx.get(serializerCtx)
      return serializer(editorView.state.doc)
    })

  // get markdown string:
  getMarkdown()
}

We provide some macros out of the box, you can use them as actions:

import {insert} from '@milkdown/utils'

editor.action(insert('# Hello milkdown'))

For more details about macros, please check macros.

Destroying

You can call editor.destroy to destroy an existing editor. You can create a new editor again with editor.create.

await editor.destroy()

// Then create again
await editor.create()

If you just want to recreate the editor, you can use editor.create, it will destroy the old editor and create a new one.

await editor.create()

// This equals to call `editor.destroy` and `editor.create` again.
await editor.create()

If you want to clear the plugins and configs for the editor when calling editor.destroy, you can pass true to editor.destroy.

await editor.destroy(true)

Official Plugins

Milkdown provides the following official plugins: | name | description | | :--------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------- | | @milkdown/preset-commonmark | Add commonmark syntax support | | @milkdown/preset-gfm | Add gfm syntax support | | @milkdown/plugin-history | Add undo & redo support | | @milkdown/plugin-clipboard | Add markdown copy & paste support | | @milkdown/plugin-cursor | Add drop & gap cursor | | @milkdown/plugin-listener | Add listener support | | @milkdown/plugin-collaborative | Add collaborative editing support | | @milkdown/plugin-prism | Add prism support for code block highlight | | @milkdown/plugin-math | Add LaTeX support for math | | @milkdown/plugin-tooltip | Add selected tooltip for text | | @milkdown/plugin-slash | Add slash commands support | | @milkdown/plugin-emoji | Add emoji support | | @milkdown/plugin-diagram | Add mermaid diagram support | | @milkdown/plugin-indent | Add tab indent support | | @milkdown/plugin-upload | Add drop and upload support |

Community Plugins

Apps and Integrations

  • milkdown-vscode
    Use milkdown as markdown editor of VSCode.
  • standardnotes
    Use milkdown as editor of Standard Notes, it's made by the official of standardnotes.
  • tagspaces
    Use milkdown as editor of markdown files.
  • MarginNote-Milkdown
    Use milkdown as markdown editor of MarginNote, it's made by the official of MarginNote. MarginNote is a brand new e-reader to better study and digest your books.
  • lactose
    A web based note-taking tool.
  • vite-plugin-book
    A magical vite plugin that helps you to generate and manage documentation website.
  • Howdz Dashboard
    Custom your personal browser start page from some configurable components.
  • Doclea
    Online doc editor.
  • ezone
    δΈ€η«™εΌδΊ‘εŽŸη”ŸδΌδΈšη ”ε‘εεŒδΈŽζ•ˆθƒ½εΉ³ε°.
  • standardnotes-milkdown
    Use milkdown as editor of Standard Notes.
  • typelog
    Microblogging platform for devs. Uses milkdown as the editor for writing posts and comments.

πŸ› οΈ Technology

The site uses various technologies cobbled together. Here's some of them:

  • Vite: next generation frontend tooling.
  • Svelte: s new way to build web applications.
  • Milkdown: plugin driven Markdown framework/editor.
  • Tailwind CSS: utility-first CSS framework.
  • Prettier: opinionated code formatter.

Β© License

Source code in this repository is available under the MIT License.