CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-milkdown--core

The core module of milkdown - a plugin-driven WYSIWYG markdown Editor built on top of prosemirror and remark

Pending
Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

SecuritybySnyk

Pending

The risk profile of this skill

Overview
Eval results
Files

editor-management.mddocs/

Editor Management

The Editor class is the central orchestrator of the Milkdown editor, managing the complete lifecycle from initialization through destruction. It provides a fluent API for configuration and plugin management.

Capabilities

Editor Class

The main editor class that manages the entire editor lifecycle.

/**
 * The milkdown editor class that orchestrates editor lifecycle
 */
class Editor {
  /** Create a new editor instance */
  static make(): Editor;
  
  /** Enable or disable inspector for debugging (default: true) */
  enableInspector(enable?: boolean): Editor;
  
  /** Subscribe to status change events - replaces previous subscription */
  onStatusChange(onChange: OnStatusChange): Editor;
  
  /** Add a configuration function to be executed during initialization */
  config(configure: Config): Editor;
  
  /** Remove a previously added configuration function */
  removeConfig(configure: Config): Editor;
  
  /** Add plugin(s) to the editor - can be single plugin or array */
  use(plugins: MilkdownPlugin | MilkdownPlugin[]): Editor;
  
  /** Remove plugin(s) from the editor - returns Promise for async cleanup */
  remove(plugins: MilkdownPlugin | MilkdownPlugin[]): Promise<Editor>;
  
  /** Create/initialize the editor with current config and plugins */
  create(): Promise<Editor>;
  
  /** Destroy the editor, optionally clearing all plugins */
  destroy(clearPlugins?: boolean): Promise<Editor>;
  
  /** Execute an action with access to the editor context */
  action<T>(action: (ctx: Ctx) => T): T;
  
  /** Get inspection data - requires inspector to be enabled */
  inspect(): Telemetry[];
  
  /** Get the editor's context instance */
  readonly ctx: Ctx;
  
  /** Get the current editor status */
  readonly status: EditorStatus;
}

Usage Examples:

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

// Basic editor creation
const editor = Editor.make()
  .config((ctx) => {
    // Configure context slices
    ctx.set(rootCtx, document.getElementById('editor'));
  })
  .use([plugin1, plugin2]) // Add multiple plugins
  .create(); // Returns Promise<Editor>

// Monitor status changes
editor.onStatusChange((status) => {
  if (status === EditorStatus.Created) {
    console.log('Editor ready!');
  }
});

// Execute commands
editor.action((ctx) => {
  const commandManager = ctx.get(commandsCtx);
  commandManager.call(someCommand, payload);
});

// Cleanup
await editor.destroy(true); // Clear all plugins

Editor Status

Enum representing the current state of the editor lifecycle.

/**
 * The status of the editor throughout its lifecycle
 */
enum EditorStatus {
  /** The editor is not initialized */
  Idle = 'Idle',
  /** The editor is in the process of being created */
  OnCreate = 'OnCreate', 
  /** The editor has been created and is ready to use */
  Created = 'Created',
  /** The editor is in the process of being destroyed */
  OnDestroy = 'OnDestroy',
  /** The editor has been destroyed */
  Destroyed = 'Destroyed'
}

Status Change Callback

Type for functions that respond to editor status changes.

/**
 * Callback function type for editor status changes
 * @param status - The new editor status
 */
type OnStatusChange = (status: EditorStatus) => void;

Usage Examples:

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

const editor = Editor.make()
  .onStatusChange((status) => {
    switch (status) {
      case EditorStatus.OnCreate:
        showLoadingSpinner();
        break;
      case EditorStatus.Created:
        hideLoadingSpinner();
        enableEditorFeatures();
        break;
      case EditorStatus.OnDestroy:
        disableEditorFeatures();
        break;
      case EditorStatus.Destroyed:
        cleanup();
        break;
    }
  });

// Status is initially Idle
console.log(editor.status); // EditorStatus.Idle

// Status changes to OnCreate, then Created
await editor.create();
console.log(editor.status); // EditorStatus.Created

// Status changes to OnDestroy, then Destroyed  
await editor.destroy();
console.log(editor.status); // EditorStatus.Destroyed

Configuration Management

Configuration Function Type

Type for configuration functions that modify the editor context during initialization.

/**
 * Configuration function type for customizing editor initialization
 * @param ctx - The editor context to configure
 */
type Config = (ctx: Ctx) => void | Promise<void>;

Usage Examples:

import { Editor, defaultValueCtx, rootCtx } from "@milkdown/core";

// Synchronous configuration
const syncConfig: Config = (ctx) => {
  ctx.set(defaultValueCtx, '# Hello World\n\nThis is **bold** text.');
  ctx.set(rootCtx, document.getElementById('editor'));
};

// Asynchronous configuration
const asyncConfig: Config = async (ctx) => {
  const content = await fetch('/api/initial-content').then(r => r.text());
  ctx.set(defaultValueCtx, content);
};

const editor = Editor.make()
  .config(syncConfig)
  .config(asyncConfig)
  .removeConfig(syncConfig) // Remove if needed
  .create();

Plugin Management

Adding Plugins:

import { Editor } from "@milkdown/core";
import { somePlugin, anotherPlugin } from "@milkdown/preset-plugins";

const editor = Editor.make()
  .use(somePlugin) // Single plugin
  .use([anotherPlugin, somePlugin]) // Multiple plugins
  .create();

Removing Plugins:

// Remove plugins after creation (async operation)
await editor.remove(somePlugin);
await editor.remove([plugin1, plugin2]);

Inspector and Debugging

Enable Inspector:

const editor = Editor.make()
  .enableInspector(true) // Enable debugging
  .create();

// Get telemetry data
const telemetry = editor.inspect();
console.log('Plugin telemetry:', telemetry);

Error Handling

The editor provides several safeguards for common error scenarios:

  • Concurrent Operations: If you try to remove plugins while editor is creating, it will wait and retry
  • Multiple Creations: Creating an already-created editor will destroy and recreate it
  • Missing Inspector: Calling inspect() without enabling inspector will log a warning and return empty array
  • Context Access: The action() method ensures you have proper context access for operations

Example Error Handling:

try {
  const editor = Editor.make()
    .config((ctx) => {
      // Configuration that might throw
      if (!document.getElementById('editor')) {
        throw new Error('Editor root element not found');
      }
      ctx.set(rootCtx, document.getElementById('editor'));
    })
    .create();
    
  // Safe action execution
  editor.action((ctx) => {
    const commands = ctx.get(commandsCtx);
    if (!commands.call(someCommand, payload)) {
      console.warn('Command execution failed');
    }
  });
} catch (error) {
  console.error('Editor setup failed:', error);
}

docs

command-system.md

context-system.md

editor-management.md

index.md

internal-plugins.md

keymap-management.md

tile.json