UIMarkdownEditor
lives in its own module,
@meekojs/ui/editor, because Crepe weighs 347 KB of gzipped JS: inside the main module it would be a chunk of every site. The JavaScript of Crepe loads in the browser, when the component mounts, and never enters the server bundle. Until then, the HTML of the server paints a placeholder with the final height.
Setup
Crepe and CodeMirror are optional dependencies of
@meekojs/ui: an application without the module does not install them.
// pnpm add @milkdown/crepe @milkdown/kit @codemirror/language @codemirror/view \
// @codemirror/lang-javascript @codemirror/lang-html @codemirror/lang-css @codemirror/lang-json @lezer/highlight
// meeko.config.ts
export default defineMeekoConfig({
modules: ['@meekojs/ui', '@meekojs/ui/editor'],
})Usage
Visual mode: 144 characters.
<script lang="ts">
const markdown = signal('# Title')
const mode = signal<'visual' | 'code'>('visual')
</script>
<template>
<UIMarkdownEditor label="Content" model="markdown" model:mode="mode" />
</template>Block-level saving
Crepe serializes a document in its own format, so saving its output would rewrite tables and blank lines nobody touched. That is why the model only changes with a real edit, and then it keeps the bytes of the original outside the edited blocks.
-
Without editing,
modelstays the received text, byte by byte. Typing and undoing too. - An edited block comes out of Crepe. A list is one block.
- The frontmatter never reaches Crepe: it is kept as it is.
- The event waits for a pause while typing, and comes early when leaving the editor, before a click on «save» reads the model.
- If a document does not match its serialization block by block, it opens in code mode with a notice.
API
| Name | Type / default | Description |
|---|---|---|
model
|
Signal<string>
| The text. If the parent writes another one, the editor starts over with it. |
model:mode
|
Signal<visual | code>
visual
| The mode. |
label
|
string
| Required. Visible label and accessible name. |
id
|
string
| id of the text area of the code mode. |
readonly
|
boolean
false
| It can be read and selected, but not changed. |
disabled
|
boolean
false
| Like readonly, and it also looks disabled. |
describedBy
|
string
| id of the text that describes it. |
placeholder
|
string
| Text of the empty document. |
class
|
string
| Class of the root. |
The
tools
snippet goes in the bar, between the label and the switcher. The height is set with
--ui-markdown-editor-height
and the content scrolls inside. Its texts, also those of the menus of Crepe, are in
ui.messages.<language>.markdownEditor.
splitMarkdownSource
and
createMarkdownSplicer
are exported from
@meekojs/ui/editor, without Crepe.