### Install Highlight Plugin Source: https://milkdown.dev/docs/guide/code-highlighting Install the highlight plugin using npm. ```bash npm install @milkdown/plugin-highlight ``` -------------------------------- ### Plugin Example Source: https://milkdown.dev/docs/api/ctx Demonstrates the structure of a Milkdown plugin, including setup, run, and optional cleanup phases. Plugins can be synchronous or asynchronous. ```typescript // A full plugin example const plugin1 = (ctx: Ctx) => { // setup return async () => { // run return async () => { // cleanup } } } // A plugin doesn't need to return a cleanup function const plugin2 = (ctx: Ctx) => { // setup return async () => { // run } } // A plugin doesn't need to be async const plugin3 = (ctx: Ctx) => { // setup return () => { // run } } ``` -------------------------------- ### Example Plugin Lifecycle Source: https://milkdown.dev/docs/guide/architecture-overview Shows the typical lifecycle of a Milkdown plugin, including setup, initialization, runtime, and cleanup phases, demonstrating state and dependency management. ```typescript const examplePlugin: MilkdownPlugin = (ctx) => { // 1. Setup Phase ctx.inject(mySlice, defaultValue) ctx.record(myTimer) return async () => { // 2. Initialization Phase await ctx.wait(RequiredTimer) // 3. Runtime Phase const value = ctx.get(mySlice) ctx.set(mySlice, newValue) // 4. Cleanup Phase return () => { ctx.remove(mySlice) } } } ``` -------------------------------- ### Install Crepe and React Packages Source: https://milkdown.dev/docs/recipes/react Install the necessary packages for using Crepe, the React integration, and Milkdown kits. ```bash npm install @milkdown/crepe @milkdown/react @milkdown/kit ``` -------------------------------- ### Install Core Milkdown and Theme Packages Source: https://milkdown.dev/docs/recipes/vue Install the core Milkdown packages along with a theme for basic editor usage. ```bash npm install @milkdown/vue @milkdown/kit @milkdown/theme-nord ``` -------------------------------- ### Install @milkdown/kit Source: https://milkdown.dev/docs/guide/getting-started Install the core Milkdown package for building a custom editor from scratch. ```bash npm install @milkdown/kit ``` -------------------------------- ### Complete Editor Example with Shiki Source: https://milkdown.dev/docs/guide/code-highlighting A full example demonstrating the creation of a Milkdown editor with Shiki syntax highlighting configured. This includes setting up the parser and applying the highlight plugin. ```typescript import { Editor } from '@milkdown/core' import { commonmark } from '@milkdown/preset-commonmark' import { highlight, highlightPluginConfig } from '@milkdown/plugin-highlight' import { createParser } from '@milkdown/plugin-highlight/shiki' async function createHighlightedEditor() { const parser = await createParser({ theme: 'github-light', langs: ['javascript', 'typescript', 'python', 'html', 'css', 'json'], }) const editor = Editor.make() .config((ctx) => { ctx.set(highlightPluginConfig.key, { parser }) }) .use(commonmark) .use(highlight) await editor.create() return editor } ``` -------------------------------- ### Basic Milkdown Editor Implementation in React Source: https://milkdown.dev/docs/recipes/react A minimal example demonstrating the core Milkdown editor setup in a React component. ```tsx import { Editor, rootCtx } from '@milkdown/kit/core' import { commonmark } from '@milkdown/kit/preset/commonmark' import { Milkdown, MilkdownProvider, useEditor } from '@milkdown/react' import { nord } from '@milkdown/theme-nord' const MilkdownEditor: React.FC = () => { const { get } = useEditor((root) => Editor.make() .config(nord) .config((ctx) => { ctx.set(rootCtx, root) }) .use(commonmark) ) return } export const MilkdownEditorWrapper: React.FC = () => { return ( ) } ``` -------------------------------- ### Install Crepe and Vue Packages Source: https://milkdown.dev/docs/recipes/vue Install the necessary Milkdown packages for Crepe and Vue integration. ```bash npm install @milkdown/crepe @milkdown/vue @milkdown/kit ``` -------------------------------- ### Install Crepe Editor Source: https://milkdown.dev/docs/guide/using-crepe Install the Crepe editor package using npm, yarn, or pnpm. ```bash # Using npm npm install @milkdown/crepe # Using yarn yarn add @milkdown/crepe # Using pnpm pnpm add @milkdown/crepe ``` -------------------------------- ### Install @milkdown/crepe Source: https://milkdown.dev/docs/guide/getting-started Install the ready-to-use Milkdown editor package using npm. ```bash npm install @milkdown/crepe ``` -------------------------------- ### Install Milkdown React and Kit Packages Source: https://milkdown.dev/docs/recipes/react Install the core Milkdown React integration and kit packages for basic usage. ```bash npm install @milkdown/react @milkdown/kit ``` -------------------------------- ### Shiki Highlighter Setup Source: https://milkdown.dev/docs/api/plugin-highlight Import and create a Shiki highlighter instance. Ensure themes and languages are specified. ```typescript // For shiki import { getSingletonHighlighter } from 'shiki' import { createParser } from '@milkdown/plugin-highlight/shiki' const highlighter = await getSingletonHighlighter({ themes: ['github-light'], langs: ['javascript', 'typescript', 'python'], }) const parser = createParser(highlighter) ``` -------------------------------- ### Refractor Highlighter Setup Source: https://milkdown.dev/docs/api/plugin-highlight Import and create a Refractor highlighter instance using Prism.js. ```typescript // For refractor import { refractor } from 'refractor/all' import { createParser } from '@milkdown/plugin-highlight/refractor' const parser = createParser(refractor) ``` -------------------------------- ### Lowlight Highlighter Setup Source: https://milkdown.dev/docs/api/plugin-highlight Import and create a Lowlight highlighter instance. Requires CSS import for styles. ```typescript // For lowlight import 'highlight.js/styles/default.css' import { common, createLowlight } from 'lowlight' import { createParser } from '@milkdown/plugin-highlight/lowlight' const lowlight = createLowlight(common) const parser = createParser(lowlight) ``` -------------------------------- ### Highlight Plugin Setup Source: https://milkdown.dev/docs/api/plugin-highlight Demonstrates how to set up the highlight plugin with different parser configurations for Shiki, Lowlight, Refractor, and Sugar High, and then integrate it into a Milkdown editor. ```APIDOC ## Highlight Plugin Setup ### Description This section shows how to configure and use the Milkdown highlight plugin with various syntax highlighting libraries. ### Methods - `highlight`: The Milkdown highlight plugin. - `highlightPluginConfig`: Configuration object for the highlight plugin. ### Usage Examples #### Using Shiki ```typescript import { getSingletonHighlighter } from 'shiki' import { createParser } from '@milkdown/plugin-highlight/shiki' const highlighter = await getSingletonHighlighter({ themes: ['github-light'], langs: ['javascript', 'typescript', 'python'], }) const parser = createParser(highlighter) ``` #### Using Lowlight ```typescript import 'highlight.js/styles/default.css' import { common, createLowlight } from 'lowlight' import { createParser } from '@milkdown/plugin-highlight/lowlight' const lowlight = createLowlight(common) const parser = createParser(lowlight) ``` #### Using Refractor ```typescript import { refractor } from 'refractor/all' import { createParser } from '@milkdown/plugin-highlight/refractor' const parser = createParser(refractor) ``` #### Using Sugar High ```typescript import { createParser } from '@milkdown/plugin-highlight/sugar-high' const parser = createParser() ``` #### Editor Setup ```typescript import { Editor } from '@milkdown/core' import { highlight, highlightPluginConfig } from '@milkdown/plugin-highlight' // Assuming 'parser' is one of the parser instances created above Editor.make() .config((ctx) => { ctx.set(highlightPluginConfig.key, { parser }) }) .use(highlight) .create() ``` ### Parameters #### highlightPluginConfig - **parser** (object) - Required - The parser instance for the chosen highlighting library. ``` -------------------------------- ### OpenAI Provider Configuration Example Source: https://milkdown.dev/docs/api/crepe Example of configuring the OpenAI provider, including custom body parameters and a custom messages builder. The `buildMessages` function allows for fine-grained control over the message array, respecting the `systemPrompt`'s nullability. ```typescript // OpenAI: any chat-completions body fields (temperature, top_p, etc.) // can go in `body`. `buildMessages` lets you fully customize the // messages array — the defaults are passed in so you can wrap them. // `defaults.systemPrompt` is `string | null`: `null` means the user // asked to omit the system message, so don't coerce it to ''. ``` ```typescript createOpenAIProvider({ apiKey, model: 'gpt-4o-mini', body: { temperature: 0.2 }, buildMessages: (context, defaults) => [ ...(defaults.systemPrompt !== null ? [{ role: 'system' as const, content: defaults.systemPrompt }] : []), { role: 'user', content: defaults.userMessage }, ], }) ``` -------------------------------- ### Collab Plugin Setup and Usage Source: https://milkdown.dev/docs/api/plugin-collab Demonstrates how to set up and use the collab plugin for collaborative editing with Yjs. ```APIDOC ## Collab Plugin Setup and Usage ### Description This section shows how to integrate the collab plugin into your Milkdown editor and configure it for collaborative editing using Yjs. ### Method ```typescript import { collab, collabServiceCtx } from '@milkdown/plugin-collab' import { Editor } from '@milkdown/core' import { Doc } from 'yjs' import { WebsocketProvider } from 'y-websocket' async function setup() { const editor = await Editor.make().use(collab).create() const doc = new Doc() const wsProvider = new WebsocketProvider('', 'milkdown', doc) editor.action((ctx) => { const collabService = ctx.get(collabServiceCtx) collabService // bind doc and awareness .bindDoc(doc) .setAwareness(wsProvider.awareness) // connect yjs with milkdown .connect() }) } ``` ### Parameters N/A (This is a setup example) ### Request Example N/A ### Response N/A ``` -------------------------------- ### Create Custom Command with Shortcut Source: https://milkdown.dev/docs/guide/keyboard-shortcuts Example of creating a custom command and then defining a keymap for it, allowing multiple shortcuts. ```typescript import { $command, $useKeymap } from '@milkdown/utils' import { commandsCtx } from '@milkdown/core' // Create a custom command const customCommand = $command('CustomCommand', (ctx) => () => { return (state, dispatch) => { // Command implementation return true } }) // Create a keymap const customKeymap = $useKeymap('customKeymap', { CustomCommand: { shortcuts: ['F1', 'Mod-F1'], // Multiple shortcuts command: (ctx) => { const commands = ctx.get(commandsCtx) return () => commands.call(customCommand.key) }, }, }) // Usage Editor.make().use(customCommand).use(customKeymap) ``` -------------------------------- ### Create Tooltip View Source: https://milkdown.dev/docs/api/plugin-tooltip Example of how to create a custom tooltip view by implementing the Prosemirror Plugin.view. ```typescript import { TooltipProvider } from '@milkdown/kit/plugin/tooltip' function tooltipPluginView(view) { const content = document.createElement('div') const provider = new TooltipProvider({ content: this.content, }) return { update: (updatedView, prevState) => { provider.update(updatedView, prevState) }, destroy: () => { provider.destroy() content.remove() }, } } ``` -------------------------------- ### Basic Crepe Editor Setup Source: https://milkdown.dev/docs/guide/getting-started Initialize a basic Milkdown editor using the Crepe package. Ensure to import the necessary CSS for theming. ```typescript import { Crepe } from '@milkdown/crepe' import '@milkdown/crepe/theme/common/style.css' import '@milkdown/crepe/theme/frame.css' const crepe = new Crepe({ root: '#app', defaultValue: 'Hello, Milkdown!', }) crepe.create() ``` -------------------------------- ### Install Milkdown Dependencies with npm Source: https://milkdown.dev/docs/recipes/angular Install the necessary Milkdown packages for Angular integration using npm. ```bash npm install @milkdown/kit npm install @milkdown/theme-nord ``` -------------------------------- ### Install Collaborative Editing Plugins Source: https://milkdown.dev/docs/guide/collaborative-editing Install the necessary packages for collaborative editing, including the Milkdown collab plugin and Y.js. ```bash npm install @milkdown/plugin-collab npm install yjs y-protocols y-prosemirror ``` -------------------------------- ### Advanced Crepe Editor Setup Source: https://milkdown.dev/docs/guide/getting-started Initialize a Milkdown editor with the Crepe package, including theme and default content. Demonstrates editor creation and destruction. ```typescript import { Crepe } from '@milkdown/crepe' import '@milkdown/crepe/theme/common/style.css' /** * Available themes: * frame, crepe, nord * frame-dark, crepe-dark, nord-dark */ import '@milkdown/crepe/theme/frame.css' const crepe = new Crepe({ root: '#app', defaultValue: 'Hello, Milkdown!', }) crepe.create().then(() => { console.log('Editor created') }) // To destroy the editor crepe.destroy() ``` -------------------------------- ### Remark Plugin Setup Source: https://milkdown.dev/docs/plugin/example-iframe-plugin Import and configure the remark-directive plugin for custom markdown syntax support. ```typescript import directive from 'remark-directive' import { $remark } from '@milkdown/kit/utils' const remarkDirective = $remark('remarkDirective', () => directive) ``` -------------------------------- ### Install Milkdown Dependencies for NuxtJS Source: https://milkdown.dev/docs/recipes/nuxtjs Install the necessary Milkdown packages, including core, Vue integration, and a theme, using npm. ```bash npm install @milkdown/vue npm install @milkdown/kit npm install @milkdown/theme-nord ``` -------------------------------- ### Initialize Editor with Commonmark Preset Source: https://milkdown.dev/docs/api/preset-commonmark Basic setup for initializing the Milkdown editor with the commonmark preset. Ensure you have the necessary imports. ```typescript import { Editor } from '@milkdown/kit/core' import { commonmark } from '@milkdown/kit/preset/commonmark' Editor.make().use(commonmark).create() ``` -------------------------------- ### Anthropic Provider Configuration Example Source: https://milkdown.dev/docs/api/crepe Example of configuring the Anthropic provider, specifying `maxTokens`, `anthropicVersion`, and custom body fields. The `buildMessages` function for Anthropic returns an object with `system` and `messages` fields, as the system prompt is a top-level field. ```typescript // Anthropic: `maxTokens` (default 4096), `anthropicVersion` (default // '2023-06-01'), and any `/v1/messages` body fields via `body`. // `buildMessages` returns `{ system, messages }` since Anthropic puts // the system prompt in a top-level field rather than the messages array. ``` ```typescript createAnthropicProvider({ apiKey, model: 'claude-sonnet-4-5', maxTokens: 2048, body: { temperature: 0.5 }, }) ``` -------------------------------- ### Setup Milkdown with Collab Plugin Source: https://milkdown.dev/docs/api/plugin-collab Demonstrates how to set up a Milkdown editor with the collab plugin and initialize Yjs for collaborative editing. Ensure you have a WebSocket host and room name configured. ```typescript import { collab, collabServiceCtx } from '@milkdown/plugin-collab' async function setup() { const editor = await Editor.make().use(collab).create() const doc = new Doc() const wsProvider = new WebsocketProvider('', 'milkdown', doc) editor.action((ctx) => { const collabService = ctx.get(collabServiceCtx) collabService // bind doc and awareness .bindDoc(doc) .setAwareness(wsProvider.awareness) // connect yjs with milkdown .connect() }) } ``` -------------------------------- ### Sugar High Highlighter Setup Source: https://milkdown.dev/docs/api/plugin-highlight Create a Sugar High parser instance. No external dependencies are required for this parser. ```typescript // For sugar high import { createParser } from '@milkdown/plugin-highlight/sugar-high' const parser = createParser() ``` -------------------------------- ### Stack Open, Push, Close Example Source: https://milkdown.dev/docs/api/transformer Demonstrates how to use the Stack class to build a nested structure. It opens an element, pushes nodes into it, and then closes the element. ```typescript stack.open(A).push(B).push(C).close() ``` -------------------------------- ### @milkdown/plugin-listener Usage Source: https://milkdown.dev/docs/api/plugin-listener Example of how to import and use the listener plugin in a Milkdown editor configuration. ```APIDOC ## Usage ```typescript import { Editor } from '@milkdown/kit/core' import { listener, listenerCtx } from '@milkdown/kit/plugin/listener' import { commonmark } from '@milkdown/kit/preset/commonmark' import { nord } from '@milkdown/theme-nord' Editor.make() .config((ctx) => { const listener = ctx.get(listenerCtx) listener.markdownUpdated((ctx, markdown, prevMarkdown) => { if (markdown !== prevMarkdown) { YourMarkdownUpdater(markdown) } }) }) .use(listener) // use other plugins .create() ``` ``` -------------------------------- ### Accessing Editor Instance with useInstance Hook Source: https://milkdown.dev/docs/recipes/react Demonstrates how to use the `useInstance` hook within a `MilkdownProvider` to get the editor instance for advanced operations. ```tsx import { useInstance } from '@milkdown/react' import { getMarkdown } from '@milkdown/utils' // ❌ This won't work - ParentComponent is outside MilkdownProvider const ParentComponent: React.FC = () => { const [isLoading, getInstance] = useInstance() // This will be [true, () => undefined] return } // ✅ This is the correct way - EditorControls is inside MilkdownProvider const EditorControls: React.FC = () => { const [isLoading, getInstance] = useInstance() const handleSave = () => { if (isLoading) return const editor = getInstance() if (!editor) return const content = editor.action(getMarkdown()) // Do something with the content } return ( ) } // ✅ Proper component structure const EditorWithControls: React.FC = () => { return ( ) } ``` -------------------------------- ### Milkdown Editor Setup with Highlight Plugin Source: https://milkdown.dev/docs/api/plugin-highlight Configure the Milkdown editor to use the highlight plugin. Set the parser in the plugin configuration. ```typescript // Setup import { highlight, highlightPluginConfig } from '@milkdown/plugin-highlight' Editor.make() .config((ctx) => { ctx.set(highlightPluginConfig.key, { parser }) }) .use(highlight) .create() ``` -------------------------------- ### Bind Tooltip View to Editor Source: https://milkdown.dev/docs/api/plugin-tooltip Example of how to bind the created tooltip view to the Milkdown editor configuration. ```typescript import { Editor } from '@milkdown/core' import { tooltipFactory } from '@milkdown/plugin-tooltip' const tooltip = tooltipFactory('my-tooltip') Editor.make() .config((ctx) => { ctx.set(tooltip.key, { view: tooltipPluginView, }) }) .use(tooltip) .create() ``` -------------------------------- ### Insert Initial Content Source: https://milkdown.dev/docs/guide/macros Add initial content to the editor upon mounting using the `insert` macro within the listener plugin. This sets up the starting text for the user. ```typescript import { insert } from '@milkdown/kit/utils' import { listenerCtx } from '@milkdown/kit/plugin/listener' editor.config((ctx) => { ctx.get(listenerCtx).mounted(insert('# Welcome\nStart editing...')) }) ``` -------------------------------- ### Sink List Item Command Example Source: https://milkdown.dev/docs/api/preset-commonmark Demonstrates the `sinkListItemCommand` which indents a list item. This is useful for creating nested lists. ```typescript * List item 1 * List item 2 <- Will get: * List item 1 * List item 2 ``` -------------------------------- ### Custom Uploader Configuration Source: https://milkdown.dev/docs/api/plugin-upload Set up a custom uploader to handle file uploads and process the returned nodes. This example filters for image files and uses a placeholder `YourUploadAPI` function. ```typescript import { upload, uploadConfig, Uploader } from '@milkdown/kit/plugin/upload' import type { Node } from '@milkdown/kit/prose/model' const uploader: Uploader = async (files, schema) => { const images: File[] = [] for (let i = 0; i < files.length; i++) { const file = files.item(i) if (!file) { continue } // You can handle whatever the file type you want, we handle image here. if (!file.type.includes('image')) { continue } images.push(file) } const nodes: Node[] = await Promise.all( images.map(async (image) => { const src = await YourUploadAPI(image) // Replace with your actual upload logic const alt = image.name return schema.nodes.image.createAndFill({ src, alt, }) as Node }) ) return nodes } Editor.make() .config((ctx) => { ctx.set(uploadConfig, { uploader }) }) ``` -------------------------------- ### Initialize and Configure Crepe Editor Source: https://milkdown.dev/docs/api/crepe Demonstrates how to create a Crepe editor instance and add features with configurations. ```typescript import { CrepeBuilder } from '@milkdown/crepe'; const editor = await new CrepeBuilder() .addFeature(feature1, config1) .addFeature(feature2) .create(); ``` -------------------------------- ### Implement a Custom AI Provider Source: https://milkdown.dev/docs/guide/ai-feature Create a custom AI provider as an async generator that yields markdown chunks. This example uses `fetch` to communicate with an AI API. ```typescript import type { AIProvider } from '@milkdown/crepe/feature/ai' const customProvider: AIProvider = async function* (context, signal) { const response = await fetch('/api/ai', { method: 'POST', body: JSON.stringify(context), signal, // forward the abort signal so cancellation works }) if (!response.ok || !response.body) throw new Error('AI request failed') const reader = response.body.getReader() const decoder = new TextDecoder() while (true) { const { done, value } = await reader.read() if (done || signal.aborted) return yield decoder.decode(value, { stream: true }) } } ``` -------------------------------- ### crepe.create() Source: https://milkdown.dev/docs/guide/using-crepe Initialize the Crepe editor instance. ```APIDOC ## crepe.create() ### Description Initialize the editor. ### Usage ```javascript await crepe.create() ``` ``` -------------------------------- ### Initialize Editor with Plugins Source: https://milkdown.dev/docs/plugin/using-plugins Demonstrates how to create a Milkdown editor instance and enable core plugins like commonmark, history, and listener. ```typescript import { Editor } from '@milkdown/kit/core' import { history } from '@milkdown/kit/plugin/history' import { listener } from '@milkdown/kit/plugin/listener' import { commonmark } from '@milkdown/kit/preset/commonmark' Editor.make().use(commonmark).use(history).use(listener).create() ``` -------------------------------- ### Mark Runner Example Source: https://milkdown.dev/docs/api/transformer Example of a `runner` function for a `MarkSerializerSpec`. It opens a new mark with the specified type and value. ```typescript runner: (state, mark, node) => { state.withMark(mark, 'emphasis'); } ``` -------------------------------- ### Mark Matcher Example Source: https://milkdown.dev/docs/api/transformer Example of a `match` function for a `MarkSerializerSpec`. It checks if a mark's type name is 'emphasis'. ```typescript match: (mark) => mark.type.name === 'emphasis' ``` -------------------------------- ### Node Runner Example Source: https://milkdown.dev/docs/api/transformer Example of a `runner` function for a `NodeSerializerSpec`. It opens a node, processes its content, and closes the node. ```typescript runner: (state, node) => { state .openNode(node.type.name) .next(node.content) .closeNode(); } ``` -------------------------------- ### Node Matcher Example Source: https://milkdown.dev/docs/api/transformer Example of a `match` function for a `NodeSerializerSpec`. It checks if a node's type name is 'paragraph'. ```typescript match: (node) => node.type.name === 'paragraph' ``` -------------------------------- ### Install Milkdown Dependencies for Next.js Source: https://milkdown.dev/docs/recipes/nextjs Install the necessary Milkdown packages for React integration in your Next.js project using npm. ```bash npm install @milkdown/react npm install @milkdown/kit npm install @milkdown/theme-nord ``` -------------------------------- ### Rendered Code Block Example Source: https://milkdown.dev/docs/guide/code-highlighting An example of a JavaScript code block within the editor that will be rendered with syntax highlighting applied by the configured Shiki parser. ```javascript console.log('Hello, world!') const greeting = (name) => `Hello, ${name}!` ``` -------------------------------- ### $useKeymap Source: https://milkdown.dev/docs/api/utils Creates a customizable keymap that allows users to define shortcuts and their associated commands. ```APIDOC ## $useKeymap (name: N, userKeymap: UserKeymapConfig) → $UserKeymap ### Description Create a keymap which can be customized by user. It takes two arguments: `name` (the name of the keymap) and `userKeymap` (the keymap config). ### Parameters * `name` (N): The name of the keymap. * `userKeymap` (UserKeymapConfig): The keymap config which contains the shortcuts and the command. ### Returns * `$UserKeymap`: The created user keymap plugin. ``` -------------------------------- ### MarkParserSpec Match Example Source: https://milkdown.dev/docs/api/transformer Defines how to match a specific Markdown AST mark type for parsing. ```typescript match: (mark) => mark.type === 'emphasis' ``` -------------------------------- ### NodeParserSpec Match Example Source: https://milkdown.dev/docs/api/transformer Defines how to match a specific Markdown AST node type for parsing. ```typescript match: (node) => node.type === 'paragraph' ``` -------------------------------- ### Crepe Editor Initialization and Usage Source: https://milkdown.dev/docs/api/crepe Demonstrates how to initialize the Crepe editor with specified features and configurations, retrieve markdown content, set the editor to readonly mode, and listen for markdown update events. ```typescript import { Crepe } from '@milkdown/crepe' const editor = new Crepe({ root: '#editor', // DOM element or selector features: { [Crepe.Feature.Toolbar]: true, [Crepe.Feature.Latex]: true, }, featureConfigs: { [Crepe.Feature.Placeholder]: { text: 'Start writing...', mode: 'block', }, }, defaultValue: '# Hello World', }) // Get markdown content const markdown = editor.getMarkdown() // Set readonly mode editor.setReadonly(true) // Listen to editor events editor.on((listener) => { listener.markdownUpdated((ctx, markdown, prevMarkdown) => { // Handle updates }) }) ``` -------------------------------- ### History Commands Source: https://milkdown.dev/docs/api/plugin-history Describes the programmatic commands for undo and redo and provides an example of how to execute them using `callCommand`. ```APIDOC ## Commands ### `undoCommand` : `$Command` A Milkdown command wrapper for the undo API in prosemirror-history. ### `redoCommand` : `$Command` A Milkdown command wrapper for the redo API in prosemirror-history. ### Programmatic Command Execution Example ```typescript import { Undo, history } from '@milkdown/plugin-history' import { callCommand } from '@milkdown/plugin-utils' const editor = await Editor.make().use(/* ... */).use(history).create() editor.action(callCommand(Undo)) ``` ``` -------------------------------- ### Initialize Milkdown with Link Tooltip Source: https://milkdown.dev/docs/api/component-link-tooltip Configure and use the link tooltip plugin with the Milkdown editor. Ensure commonmark preset is included. ```typescript import { configureLinkTooltip, linkTooltipPlugin, linkTooltipConfig, } from '@milkdown/components/link-tooltip' import { defaultValueCtx, Editor } from '@milkdown/kit/core' import { commonmark, linkSchema } from '@milkdown/kit/preset/commonmark' const editor = await Editor.make() .config(configureLinkTooltip) .use(commonmark) .use(linkTooltipPlugin) .create() ``` -------------------------------- ### Minimal Vanilla '/' Menu Source: https://milkdown.dev/docs/plugin/example-slash-plugin Creates a basic '/' menu in vanilla TypeScript that suggests two commands. The SlashProvider handles positioning and visibility, while the menu rendering and command execution are custom. ```typescript import { SlashProvider, slashFactory } from '@milkdown/plugin-slash' import { Editor } from '@milkdown/kit/core' import { commonmark } from '@milkdown/kit/preset/commonmark' // DOM content of the menu – plain HTML for the demo const menu = document.createElement('div') menu.className = 'slash-menu' menu.style.cssText = ` position:absolute;padding:4px 0;background:white;border:1px solid #eee; box-shadow:0 2px 8px rgba(0,0,0,.15);border-radius:6px;font-size:14px; ` menu.innerHTML = `
  • Heading 1
  • Bullet List
` // Click handler – replace with real commands menu.addEventListener('click', (e) => { const target = e.target as HTMLElement const cmd = target.dataset.cmd alert(`Run command: ${cmd}`) }) // Provider positions & shows above DOM element const provider = new SlashProvider({ content: menu, // show the menu when the last character before caret is '/' shouldShow(view) { return provider.getContent(view)?.endsWith('/') ?? false }, offset: 8, }) const slash = slashFactory('demo') const slashConfig = (ctx: Ctx) => { ctx.set(slash.key, { view: () => ({ update: provider.update, destroy: provider.destroy, }), }) } Editor.make().config(slashConfig).use(commonmark).use(slash).create() ``` -------------------------------- ### Initializing the Editor Source: https://milkdown.dev/docs/guide/using-crepe Initialize the Crepe editor instance. This is a required step before using other editor functionalities. ```javascript await crepe.create() ``` -------------------------------- ### Initialize Upload Plugin Source: https://milkdown.dev/docs/api/plugin-upload Import and use the upload plugin with the Milkdown editor. No additional configuration is needed for basic image uploads. ```typescript import { Editor } from '@milkdown/kit/core' import { upload } from '@milkdown/kit/plugin/upload' Editor.make().use(upload).create() ``` -------------------------------- ### Get Markdown Content (Crepe) Source: https://milkdown.dev/docs/guide/faq Retrieve the current Markdown content from the editor when using the Crepe API. ```typescript const markdown = editor.getMarkdown() ``` -------------------------------- ### Initialize Editor with Table Block Source: https://milkdown.dev/docs/api/component-table-block Demonstrates how to import and use the tableBlock component when creating a Milkdown editor. Ensure commonmark and gfm presets are included if needed. ```typescript import { tableBlock, tableBlockConfig } from '@milkdown/components/table-block' import { Editor } from '@milkdown/kit/core' import { commonmark } from '@milkdown/kit/preset/commonmark' import { gfm } from '@milkdown/kit/preset/gfm' await Editor.make().use(commonmark).use(gfm).use(tableBlock).create() ``` -------------------------------- ### Timer Management Source: https://milkdown.dev/docs/api/ctx Manages timers, which are promises that can be resolved. Allows getting, removing, and checking for the existence of timers. ```APIDOC ## Class: Clock ### Description Represents a map of timers. ### Methods - **`get(timer: TimerType): Timer`** Get a timer from the clock by timer type. - **`remove(timer: TimerType): void`** Remove a timer from the clock by timer type. - **`has(timer: TimerType): boolean`** Check if the clock has a timer by timer type. ## Class: TimerType ### Description Used to create timers in different clocks. ### Constructors - **`new TimerType(name: string, timeout?: number = 3000)`** Create a timer type with a name and a timeout. The name should be unique in the clock. ### Properties - **`id: Symbol`** The unique id of the timer type. - **`name: string`** The name of the timer type. - **`timeout: number`** The timeout of the timer type. ### Methods - **`create(clock: TimerMap): Timer`** Create a timer with a clock. ## Class: Timer ### Description A promise that can be resolved by calling done. ### Properties - **`type: TimerType`** The type of the timer. - **`status: TimerStatus`** The status of the timer. Can be `pending`, `resolved` or `rejected`. ### Methods - **`start(): Promise`** Start the timer, which will return a promise. If the timer is already started, it will return the same promise. If the timer is not resolved in the timeout, it will reject the promise. - **`done(): void`** Resolve the timer. ## Function: createTimer(name: string, timeout?: number = 3000): TimerType ### Description Create a timer type with a name and a timeout. This is equivalent to `new TimerType(name, timeout)`. ``` -------------------------------- ### Initialize CrepeBuilder with Features Source: https://milkdown.dev/docs/api/crepe Use CrepeBuilder to manually add features for optimized bundle size. Import necessary features and styles, then create the editor instance. ```typescript import { CrepeBuilder } from '@milkdown/crepe/builder' import { blockEdit } from '@milkdown/crepe/feature/block-edit' import { toolbar } from '@milkdown/crepe/feature/toolbar' import { topBar } from '@milkdown/crepe/feature/top-bar' // You may also want to import styles by feature import '@milkdown/crepe/theme/common/prosemirror.css' import '@milkdown/crepe/theme/common/reset.css' import '@milkdown/crepe/theme/common/block-edit.css' import '@milkdown/crepe/theme/common/toolbar.css' import '@milkdown/crepe/theme/common/top-bar.css' // And introduce the theme import '@milkdown/crepe/theme/crepe.css' const builder = new CrepeBuilder({ root: '#editor', defaultValue: '# Hello World', }) // Add features manually builder.addFeature(blockEdit).addFeature(toolbar).addFeature(topBar) // Create the editor const editor = await builder.create() // Get markdown content const markdown = builder.getMarkdown() // Set readonly mode builder.setReadonly(true) // Listen to editor events builder.on((listener) => { listener.markdownUpdated((ctx, markdown, prevMarkdown) => { // Handle updates }) }) ``` -------------------------------- ### Keymap Structure Definition Source: https://milkdown.dev/docs/guide/keyboard-shortcuts Illustrates the structure for defining a keymap, including command name, shortcuts, optional priority, and the command to execute. ```javascript $useKeymap('keymapName', { CommandName: { shortcuts: string | string[], // Single shortcut or array of shortcuts priority?: number, // (Optional) Priority of the shortcut command: (ctx) => () => { // Command to execute const commands = ctx.get(commandsCtx); return () => commands.call(commandKey, ...args); }, }, }); ``` -------------------------------- ### MarkParserSpec Runner Example Source: https://milkdown.dev/docs/api/transformer Specifies the logic for transforming a matched Markdown AST mark into a Prosemirror mark using the ParserState. ```typescript runner: (state, node, type) => { state .openMark(type) .next(node.children) .closeMark(type) } ``` -------------------------------- ### Initialize Milkdown Editor with Cursor Plugin Source: https://milkdown.dev/docs/api/plugin-cursor This snippet shows how to import and use the cursor plugin when creating a Milkdown editor. Ensure necessary presets and themes are also included. ```typescript import { Editor } from '@milkdown/kit/core' import { cursor } from '@milkdown/kit/plugin/cursor' import { commonmark } from '@milkdown/kit/preset/commonmark' import { nord } from '@milkdown/theme-nord' Editor.make().use(nord).use(commonmark).use(cursor).create() ``` -------------------------------- ### NodeParserSpec Runner Example Source: https://milkdown.dev/docs/api/transformer Specifies the logic for transforming a matched Markdown AST node into a Prosemirror node using the ParserState. ```typescript runner: (state, node, type) => { state .openNode(type) .next(node.children) .closeNode(); } ``` -------------------------------- ### Initialize Editor with Image Block Component Source: https://milkdown.dev/docs/api/component-image-block Import and use the `imageBlockComponent` along with `commonmark` preset to enable image block functionality in the editor. ```typescript import { imageBlockComponent, imageBlockConfig, } from '@milkdown/components/image-block' import { defaultValueCtx, Editor } from '@milkdown/kit/core' import { commonmark } from '@milkdown/kit/preset/commonmark' await Editor.make().use(commonmark).use(imageBlockComponent).create() ``` -------------------------------- ### Get Document Outline Source: https://milkdown.dev/docs/guide/macros Retrieve the document's outline using the `outline` macro. This is useful for understanding the structure of the content. ```typescript import { outline } from '@milkdown/kit/utils' const docOutline = editor.action(outline()) ``` -------------------------------- ### Initialize Crepe Editor Source: https://milkdown.dev/docs/guide/interacting-with-editor Create a new Crepe editor instance, optionally specifying the root element and default content. The editor must be created asynchronously. ```typescript import { Crepe } from '@milkdown/crepe' // Create a new editor instance const editor = new Crepe({ // Optional: specify root element (DOM node or selector) root: '#editor', // Optional: set default content, supports markdown, json and dom. defaultValue: '# Hello Crepe!', }) // Create the editor await editor.create() // Get markdown content const markdown = editor.getMarkdown() // Set readonly mode editor.setReadonly(true) // Register event listeners editor.on((listener) => { listener.markdownUpdated((ctx, markdown, prevMarkdown) => { console.log('Content updated:', markdown) }) listener.focus((ctx) => { console.log('Editor focused') }) listener.blur((ctx) => { console.log('Editor blurred') }) listener.selectionUpdated((ctx, selection, prevSelection) => { console.log('Selection updated:', selection) ``` -------------------------------- ### Get Markdown Content (Kit API) Source: https://milkdown.dev/docs/guide/faq Retrieve the current Markdown content from the editor using the Kit API and `serializerCtx`. ```typescript import { editorViewCtx, serializerCtx } from '@milkdown/kit/core' const getMarkdown = (editor) => editor.action((ctx) => { const serializer = ctx.get(serializerCtx) const view = ctx.get(editorViewCtx) return serializer(view.state.doc) }) ``` -------------------------------- ### Slice Management Source: https://milkdown.dev/docs/api/ctx Manages slices, which are typed values within a container. Allows getting, removing, and checking for the existence of slices. ```APIDOC ## Class: Container ### Description Represents a map of slices. ### Methods - **`get(slice: SliceType | N): Slice`** Get a slice from the container by slice type or slice name. - **`remove(slice: SliceType | N): void`** Remove a slice from the container by slice type or slice name. - **`has(slice: SliceType | N): boolean`** Check if the container has a slice by slice type or slice name. ## Class: SliceType ### Description Used to create slices in different containers. ### Constructors - **`new SliceType(value: T, name: N)`** Create a slice type with a default value and a name. The name should be unique in the container. ### Properties - **`id: Symbol`** The unique id of the slice type. - **`name: N`** The name of the slice type. ### Methods - **`create(container: SliceMap, value?: T = this._defaultValue): Slice`** Create a slice with a container. You can also pass a value to override the default value. ## Class: Slice ### Description Represents a value of a slice type. ### Properties - **`type: SliceType`** The type of the slice. ### Methods - **`on(watcher: fn(value: T) => unknown): fn()`** Add a watcher for changes in the slice. Returns a function to remove the watcher. - **`once(watcher: fn(value: T) => unknown): fn()`** Add a one-time watcher for changes in the slice. The watcher will be removed after it is called. Returns a function to remove the watcher. - **`off(watcher: fn(value: T) => unknown): void`** Remove a watcher. - **`offAll(): void`** Remove all watchers. - **`set(value: T): void`** Set the value of the slice. - **`get(): T`** Get the value of the slice. - **`update(updater: fn(prev: T) => T): void`** Update the value of the slice with a callback. ## Function: createSlice(value: T, name: N): SliceType ### Description Create a slice type with a default value and a name. This is equivalent to `new SliceType(value, name)`. ``` -------------------------------- ### Basic Upload Plugin Usage Source: https://milkdown.dev/docs/api/plugin-upload Demonstrates the basic integration of the upload plugin into a Milkdown editor. ```APIDOC ## Basic Upload Plugin Usage ### Description This snippet shows how to import and use the upload plugin in a Milkdown editor. ### Method Editor Configuration ### Endpoint N/A ### Parameters N/A ### Request Example ```typescript import { Editor } from '@milkdown/kit/core' import { upload } from '@milkdown/kit/plugin/upload' Editor.make().use(upload).create() ``` ### Response N/A ``` -------------------------------- ### Create an Async Shortcut Plugin Source: https://milkdown.dev/docs/api/utils Use $shortcutAsync for the asynchronous version of $shortcut. You can use `await` in the factory function when creating the keymap. The timer will resolve when the plugin is ready. ```typescript const asyncShortcutPlugin = $shortcutAsync(async (ctx) => await keymap); ``` -------------------------------- ### Configuring Cursor Feature in Crepe Source: https://milkdown.dev/docs/api/crepe Example of configuring the Cursor feature, allowing customization of color, width, and virtual cursor behavior. ```typescript const config: CrepeConfig = { features: { [Crepe.Feature.Cursor]: true, }, featureConfigs: { [Crepe.Feature.Cursor]: { color: '#ff0000', width: 2, virtual: true, }, }, } ``` -------------------------------- ### Working with Transactions in Milkdown Source: https://milkdown.dev/docs/guide/prosemirror-api Manipulate the editor's state by creating and dispatching transactions. This example demonstrates inserting text into the editor. ```typescript editor.action((ctx) => { const view = ctx.get(editorViewCtx) const { tr } = view.state // Apply transformations view.dispatch(tr.insertText('Hello')) }) ``` -------------------------------- ### Trailing Plugin Usage Source: https://milkdown.dev/docs/api/plugin-trailing Demonstrates how to import and use the trailing plugin with the Milkdown editor. ```APIDOC ## Import and Use Trailing Plugin ### Description This snippet shows the basic import and usage of the `trailing` plugin within a Milkdown editor instance. ### Method ```typescript import { Editor } from '@milkdown/kit/core' import { trailing } from '@milkdown/kit/plugin/trailing' Editor.make().use(trailing).create() ``` ### Plugin #### `trailing` : `MilkdownPlugin[]` All plugins exported by this package. ``` -------------------------------- ### Initialize Milkdown with Clipboard Plugin Source: https://milkdown.dev/docs/api/plugin-clipboard Use this snippet to initialize the Milkdown editor with the clipboard plugin enabled. Ensure the plugin is imported correctly. ```typescript import { Editor } from '@milkdown/kit/core' import { clipboard } from '@milkdown/kit/plugin/clipboard' Editor.make().use(clipboard).create() ``` -------------------------------- ### Configure CodeMirror Languages and Theme Source: https://milkdown.dev/docs/api/crepe Set a custom theme and specify available languages for the CodeMirror feature. This example loads only the Markdown language. ```typescript import { oneDark } from '@codemirror/theme-one-dark' import { LanguageDescription } from '@codemirror/language' import { markdown } from '@codemirror/lang-markdown' const config: CrepeConfig = { features: { [Crepe.Feature.CodeMirror]: true, }, featureConfigs: { [Crepe.Feature.CodeMirror]: { theme: oneDark, languages: [ // Only load markdown language LanguageDescription.of({ name: 'Markdown', extensions: ['md', 'markdown'], load() { return import('@codemirror/lang-markdown').then((m) => m.markdown()) }, }), ], }, }, } ``` -------------------------------- ### Initialize Crepe with OpenAI Provider Source: https://milkdown.dev/docs/guide/ai-feature This snippet shows how to initialize the Crepe editor with the AI feature enabled and configured to use OpenAI's Chat Completions API via a custom backend proxy. Ensure the AI feature is explicitly enabled and a provider is supplied. ```typescript import { Crepe, CrepeFeature } from '@milkdown/crepe' import { createOpenAIProvider } from '@milkdown/crepe/llm-providers/openai' import '@milkdown/crepe/theme/common/style.css' import '@milkdown/crepe/theme/frame.css' const crepe = new Crepe({ root: '#app', features: { [CrepeFeature.AI]: true, }, featureConfigs: { [CrepeFeature.AI]: { provider: createOpenAIProvider({ // Route through your backend so the key never reaches the browser. baseURL: 'https://your-app.example.com/openai-proxy', model: 'gpt-4o-mini', }), }, }, }) await crepe.create() ``` -------------------------------- ### Accessing Crepe Editor Instance in Plugin Source: https://milkdown.dev/docs/api/crepe Shows how to get the Crepe editor instance within a Milkdown plugin using the useCrepe utility. ```typescript import { Ctx } from '@milkdown/core'; import { crepeCtx, useCrepe } from '@milkdown/crepe'; const plugin = (ctx: Ctx) => { return () => { const crepe = useCrepe(ctx); crepe.setReadonly(true); }; } ```