Skip to content

Editor API ​

Single public API: Editor + plugins on a virtual document kernel. The kernel model is JSON (getJSON / setJSON). For app integrate / persist, prefer HTML (getHTML / setHTML) or Markdown (getMarkdown / setMarkdown) — see Integrate.

ts
import 'on-codemerge/index.css';
import 'on-codemerge/public.css';
import { Editor, createDefaultPlugins, insertText } from 'on-codemerge';

const editor = new Editor(document.getElementById('editor')!, {
  plugins: createDefaultPlugins(),
});
editor.run(insertText('Hello'));

Getting Started ​

This page is the WYSIWYG Editor API. Launch snippets for all three products (WYSIWYG / JSON / Markdown): Editors and the home Getting Started.

  1. Install on-codemerge
  2. Import index.css + public.css
  3. Construct Editor(host, { plugins: [...] })
  4. Load / save with setHTML / getHTML (or Markdown). Use getJSON / setJSON when you need the kernel snapshot.
ts
import { Editor, ToolbarPlugin, AlignmentPlugin, ListsPlugin } from 'on-codemerge';

const editor = new Editor(host, {
  plugins: [ToolbarPlugin(), AlignmentPlugin(), ListsPlugin()],
});

editor.setHTML(localStorage.getItem('doc-html') ?? '<p></p>');
editor.on('docChanged', () => {
  localStorage.setItem('doc-html', editor.getHTML());
});

editor.command('bulletList');

Core owns UI ​

  • Toolbar panel is created by the editor (editor.toolbar.add)
  • Popups: editor.ui.popup / plugin ctx.popup
  • Context menus: editor.ui.menu
  • Toasts: editor.notify(...)
  • i18n: editor.t / editor.setLocale / editor.registerLocale

Plugins never own the panel or reinvent modals. Authoring surface: SDK reference.

Options ​

OptionRole
pluginsPlugin factories (XPlugin() / createDefaultPlugins())
docInitial DocNode / JSON doc
history{ maxDepth?, mergeWindowMs? }
locale / fallbackLocale / messagesi18n bootstrap
colorSchemehost (default — leave <html class="dark"> alone) or system (sync prefers-color-scheme to documentElement)
chromebar (default sticky chrome) or page (popup toolbar) — see Chrome & host
toolbar{ menus?: ToolbarMenuDef[] } — overflow dropdowns. Omit → Insert / Review / Tools. { menus: [] } → flat bar

Document API ​

MethodRole
getJSON() / setJSON(doc)Kernel document (collab / advanced sync)
getHTML() / setHTML(html)Usual app load/save (semantic HTML; atoms as empty data-node shells)
getMarkdown() / setMarkdown(md)Markdown load/save (CommonMark/GFM subset)
getPublishedHTML()Hydrated HTML for published pages (plugin publish.render fills atoms)
getPublishedJS()dist/public.js href when runtimes are needed; otherwise null
getPublishedDocument()Standalone HTML document (public.css + optional public.js)
run(command)Execute a command function
command(name, …args)Named plugin/core command
use(plugin)Register a plugin after construct
on('docChanged' | 'selectionChanged', cb)Subscriptions — callback receives editor state
destroy()Tear down editor + plugins

Boundaries: JSON vs HTML vs Markdown vs published ​

ts
const html = editor.getHTML();
editor.setHTML(html);

const md = editor.getMarkdown();
editor.setMarkdown('# Title\n\nHello **world**');

const json = editor.getJSON(); // optional kernel snapshot
editor.setJSON(json);

const published = editor.getPublishedHTML();
const page = editor.getPublishedDocument();
FormatUse when
getHTML / setHTMLDefault app persistence, paste, SSR shells
MarkdownNotes apps, CMS that store MD, ExportPlugin → .md
JSONCollab, advanced sync, undo internals
getPublished*Public pages, export HTML/PDF, live preview with public.js runtimes

Atoms (timer, calendar, …) stay as data-node="…" + attrs in semantic HTML. Published HTML runs each plugin’s publish.render and may set data-ocm-runtime / data-ocm-config for dist/public.js.

Headless IO (no Editor instance) ​

Same adapters the editor uses, exported from the package root:

ts
import {
  importHTML,
  exportHTML,
  exportPublishedHTML,
  importMarkdown,
  exportMarkdown,
  docToMarkdown,
  markdownToDoc,
  sanitizeHTML,
  serializeJSON,
  parseJSON,
} from 'on-codemerge';

const doc = importMarkdown('# Hi');
const md = exportMarkdown(doc);
const html = exportHTML(doc);

exportPublishedHTML(doc, publishers) needs the publish-node map from plugins (collectPublishNodes in the SDK) — prefer editor.getPublishedHTML() when an editor exists.

Plugin System ​

Plugins are factory functions that return a sealed plugin descriptor (definePlugin). Pass them in the constructor:

ts
import { Editor } from 'on-codemerge';
import { TablePlugin, ImagePlugin } from 'on-codemerge/plugins';

const editor = new Editor(host, {
  plugins: [TablePlugin(), ImagePlugin()],
});

To author a plugin, see Authoring plugins and the SDK reference.

Localization ​

UI copy uses semantic nested keys via @i18n-micro/runtime. Editor core ships shared namespaces (common.*, toolbar.*, …) under packages/editor/src/i18n/locales/. Large plugins ship their own packs under plugins/<Name>Plugin/i18n/locales/ and merge them via wirePluginLocales / registerLocale — only the current non-en locale chunk loads asynchronously.

ts
await editor.setLocale('ru');
await editor.setLocale('en'); // same API
editor.t('toolbar.bold');
editor.t('greeting', { name: 'Ada' });
editor.listLocales();
// Merge overlay (does not skip core locale load):
editor.registerLocale('ru', { myPlugin: { title: 'Заголовок' } });

registerLocale merges messages without marking the locale as base-loaded. Plugin packs register an overlay loader so setLocale awaits them after the core JSON. Missing keys fall back to fallbackLocale (en), then the key string.

LanguagePlugin is optional UI for picking a language; loading does not depend on it.

Released under the MIT License.