Skip to content

@editu/core ​

Framework-agnostic core package containing Tiptap extensions, types, utilities, and styles.

Installation ​

bash
npm install @editu/core

TIP

You typically don't need to install this package directly. It's included as a dependency of @editu/react.

Styles ​

Default Styles ​

typescript
import '@editu/core/styles.css';

This stylesheet includes CSS variables and component styles.

Components Only ​

typescript
import '@editu/core/components.css';

This stylesheet provides component styles without CSS variable definitions. Use it with custom theming or shadcn/ui.


Extensions ​

Editu provides pre-configured Tiptap extensions.

createEdituExtensions ​

This function creates the default set of Editu extensions.

typescript
import { createEdituExtensions } from '@editu/core';

const extensions = await createEdituExtensions({
  placeholder: 'Start writing...',
  features: {
    markdown: true,
    mathematics: true,
  },
});

Base Extensions (Always Included) ​

ExtensionDescription
DocumentDocument node
ParagraphParagraph node
TextText node
BoldBold mark
ItalicItalic mark
StrikeStrikethrough mark
UnderlineUnderline mark
CodeInline code mark
HeadingH1-H6 headings
BulletListBullet list
OrderedListNumbered list
ListItemList item
BlockquoteBlock quote
HorizontalRuleHorizontal divider
HardBreakLine break
HistoryUndo/redo
PlaceholderPlaceholder text
DropcursorDrop cursor
GapcursorGap cursor

Feature Extensions ​

FeatureExtensions
slashCommandSlashCommand
tableTable, TableRow, TableCell, TableHeader
linkLink
imageImage, ImageResize
codeBlockCodeBlockLowlight
characterCountCharacterCount
textColorColor, Highlight
taskListTaskList, TaskItem
dragHandleDragHandle
markdownMarkdown
mathematicsMathematics
embedEmbed
detailsDetails, DetailsContent, DetailsSummary
diagramDiagram
wikiLinkWikiLink
commentCommentMark
calloutCallout
mentionMention
tableOfContentsTableOfContents
superscriptSuperscript
subscriptSubscript
typographyTypography
collaborationYjs extensions (Collaboration, CollaborationCursor)

Types ​

EdituEditorOptions ​

typescript
import type { EdituEditorOptions } from '@editu/core';

See Type Definitions for full interface.

EdituFeatureOptions ​

typescript
import type { EdituFeatureOptions } from '@editu/core';

See Type Definitions for full interface.

EdituMarkdownFlavor ​

typescript
import type { EdituMarkdownFlavor } from '@editu/core';

type EdituMarkdownFlavor = "commonmark" | "gfm" | "obsidian" | "docusaurus";

Supported Markdown output flavors. Controls how content is serialized when exporting Markdown. The default is "gfm".

EdituFlavorConfig ​

typescript
import type { EdituFlavorConfig } from '@editu/core';

interface EdituFlavorConfig {
  /** How callout/admonition blocks are serialized */
  calloutFormat: EdituCalloutMarkdownFormat;
  /** Whether wiki links are serialized as [[page]] (true) or standard links (false) */
  wikiLinkSerialize: boolean;
}

Flavor-specific configuration resolved from a EdituMarkdownFlavor. Used internally by extensions to determine how to serialize Markdown.

EdituCalloutMarkdownFormat ​

typescript
import type { EdituCalloutMarkdownFormat } from '@editu/core';

type EdituCalloutMarkdownFormat =
  | "github-alerts"
  | "obsidian-callouts"
  | "directives"
  | "blockquote-fallback";

Callout/admonition output format for Markdown serialization.

JSONContent ​

Tiptap's JSON content format. Import directly from @tiptap/core:

typescript
import type { JSONContent } from '@tiptap/core';

const content: JSONContent = {
  type: 'doc',
  content: [
    { type: 'paragraph', content: [{ type: 'text', text: 'Hello' }] }
  ],
};

EdituSaveStatus ​

typescript
import type { EdituSaveStatus } from '@editu/core';

type EdituSaveStatus = 'saved' | 'saving' | 'unsaved' | 'error';

Theme Types ​

typescript
import type { EdituTheme, EdituResolvedTheme } from '@editu/core';

type EdituTheme = 'light' | 'dark' | 'system';
type EdituResolvedTheme = 'light' | 'dark';

Utilities ​

groupByConsecutiveField ​

This function groups items into consecutive runs by a string field. Items with the same field value that appear sequentially are placed in the same group. Non-adjacent items with the same value are placed in separate groups.

typescript
import { groupByConsecutiveField } from '@editu/core';

const items = [
  { group: "a", name: "1" },
  { group: "a", name: "2" },
  { group: "b", name: "3" },
  { group: "a", name: "4" },
];

const groups = groupByConsecutiveField(items, "group");
// [
//   [{ group: "a", name: "1" }, { group: "a", name: "2" }],
//   [{ group: "b", name: "3" }],
//   [{ group: "a", name: "4" }],
// ]

resolveEdituFeatures ​

This function resolves feature options to extension configuration.

typescript
import { resolveEdituFeatures } from '@editu/core';

const resolved = resolveEdituFeatures({
  features: {
    markdown: true,
    mathematics: { katexOptions: { strict: false } },
  },
  createSlashMenuRenderer: mySlashMenuRenderer,
});

resolveEdituFlavorConfig ​

This function resolves flavor-specific configuration from a Markdown flavor name.

typescript
import { resolveEdituFlavorConfig } from '@editu/core';

const config = resolveEdituFlavorConfig('obsidian');
// config.calloutFormat === "obsidian-callouts"
// config.wikiLinkSerialize === true

// Defaults to "gfm" when called without arguments
const defaultConfig = resolveEdituFlavorConfig();
// defaultConfig.calloutFormat === "github-alerts"
// defaultConfig.wikiLinkSerialize === false

getEdituEditorState ​

This function returns the current editor state.

typescript
import { getEdituEditorState } from '@editu/core';

const state = getEdituEditorState(editor);
// {
//   isFocused: boolean,
//   isEmpty: boolean,
//   canUndo: boolean,
//   canRedo: boolean,
//   characterCount: number,
//   wordCount: number,
// }

formatEdituRelativeTime ​

This function formats a date as relative time.

typescript
import { formatEdituRelativeTime } from '@editu/core';

formatEdituRelativeTime(new Date(Date.now() - 60000));
// "1m ago"

Theme Utilities ​

getEdituSystemTheme ​

This function returns the system color scheme preference.

typescript
import { getEdituSystemTheme } from '@editu/core';

const theme = getEdituSystemTheme();
// 'light' | 'dark'

resolveEdituTheme ​

This function resolves a theme setting to an actual theme value.

typescript
import { resolveEdituTheme } from '@editu/core';

resolveEdituTheme('system', 'dark');
// 'dark'

applyEdituTheme ​

This function applies a theme to the DOM.

typescript
import { applyEdituTheme } from '@editu/core';

applyEdituTheme('dark', 'html');

getEdituThemeInitScript ​

This function returns an inline script that prevents flash of unstyled content.

typescript
import { getEdituThemeInitScript } from '@editu/core';

const script = getEdituThemeInitScript('my-theme-key');
// Include in <head>

Image Utilities ​

createEdituImageUploader ​

This function creates an image upload handler.

typescript
import { createEdituImageUploader } from '@editu/core';

const upload = createEdituImageUploader({
  onUpload: async (file) => {
    // Upload file
    return 'https://example.com/image.png';
  },
  maxFileSize: 5 * 1024 * 1024,
  allowedTypes: ['image/jpeg', 'image/png'],
});

validateEdituImageFile ​

This function validates an image file against size and type constraints.

typescript
import { validateEdituImageFile } from '@editu/core';

const result = validateEdituImageFile(file, {
  maxFileSize: 5 * 1024 * 1024,
  allowedTypes: ['image/jpeg', 'image/png'],
});

if (!result.valid) {
  console.error(result.error);
}

Color Utilities ​

getEdituRecentColors ​

This function retrieves recent colors from localStorage.

typescript
import { getEdituRecentColors } from '@editu/core';

const colors = getEdituRecentColors('text');
// ['#ff0000', '#00ff00', ...]

addEdituRecentColor ​

This function adds a color to the recent colors list.

typescript
import { addEdituRecentColor } from '@editu/core';

addEdituRecentColor('text', '#ff0000');

Embed Utilities ​

detectEdituEmbedProvider ​

This function detects the oEmbed provider from a URL.

typescript
import { detectEdituEmbedProvider } from '@editu/core';

const provider = detectEdituEmbedProvider('https://www.youtube.com/watch?v=dQw4w9WgXcQ');
// { name: 'YouTube', ... }

Constants ​

EDITU_DEFAULT_FLAVOR ​

This constant defines the default Markdown output flavor.

typescript
import { EDITU_DEFAULT_FLAVOR } from '@editu/core';
// "gfm"

EDITU_TEXT_COLORS ​

This constant defines the default text color palette.

typescript
import { EDITU_TEXT_COLORS } from '@editu/core';
// Array of { name: string, color: string }

EDITU_HIGHLIGHT_COLORS ​

This constant defines the default highlight color palette.

typescript
import { EDITU_HIGHLIGHT_COLORS } from '@editu/core';
// Array of { name: string, color: string }

edituDefaultEmbedProviders ​

This constant defines the default oEmbed providers.

typescript
import { edituDefaultEmbedProviders } from '@editu/core';
// YouTube, Vimeo, Twitter, etc.

Toolbar ​

EdituToolbarAction ​

Type definition for a toolbar action.

typescript
import type { EdituToolbarAction } from '@editu/core';

interface EdituToolbarAction {
  id: string;
  label: string;
  icon: EdituIconName;
  group: string;
  isActive: (editor: Editor) => boolean;
  isEnabled: (editor: Editor) => boolean;
  run: (editor: Editor) => void;
  shortcut?: string;
}

EdituToolbarDropdownAction ​

Type definition for a dropdown toolbar action that groups multiple sub-actions.

typescript
import type { EdituToolbarDropdownAction } from '@editu/core';

interface EdituToolbarDropdownAction {
  id: string;
  label: string;
  icon: EdituIconName;
  group: string;
  type: 'dropdown';
  options: EdituToolbarAction[];
  getActiveOption?: (editor: Editor) => EdituToolbarAction | undefined;
}

EdituToolbarActionItem ​

Union type for any toolbar item — either a simple action or a dropdown.

typescript
import type { EdituToolbarActionItem } from '@editu/core';

type EdituToolbarActionItem = EdituToolbarAction | EdituToolbarDropdownAction;

isEdituToolbarDropdownAction ​

Type guard to check if a toolbar item is a dropdown action.

typescript
import { isEdituToolbarDropdownAction } from '@editu/core';

if (isEdituToolbarDropdownAction(action)) {
  // action is EdituToolbarDropdownAction
  action.options.forEach(opt => /* ... */);
}

edituDefaultToolbarActions ​

This constant provides the default toolbar actions including undo/redo, formatting, headings, lists, and blocks.

typescript
import { edituDefaultToolbarActions } from '@editu/core';
// Array of EdituToolbarAction

Default groups: history, format, heading, list, block

groupEdituToolbarActions ​

This function groups toolbar actions by their group property for rendering with dividers. Supports both simple actions and dropdown actions.

typescript
import { groupEdituToolbarActions } from '@editu/core';

const groups = groupEdituToolbarActions(actions);
// EdituToolbarActionItem[][] - each sub-array is a group

Find & Replace ​

A standalone Tiptap extension for text search and replacement within the editor. This extension is not included in createEdituExtensions() — you add it manually.

createEdituFindReplaceExtension ​

This function creates the Find & Replace extension.

typescript
import { createEdituFindReplaceExtension } from '@editu/core';

const findReplace = createEdituFindReplaceExtension({
  caseSensitive: false,
  onResultsChange: ({ total, current }) => {
    console.log(`Match ${current} of ${total}`);
  },
});

Options ​

OptionTypeDefaultDescription
caseSensitivebooleanfalseEnable case-sensitive search
onResultsChange(results: { total: number; current: number }) => void—Called when search results change

Editor Commands ​

The extension registers the following commands on the editor:

CommandParametersDescription
openFindReplacemode?: 'find' | 'replace'Open the Find & Replace panel
closeFindReplace—Close the panel
findquery: stringSearch for text in the document
findNext—Navigate to the next match
findPrevious—Navigate to the previous match
replacetext: stringReplace the current match
replaceAlltext: stringReplace all matches
setFindCaseSensitivecaseSensitive: booleanToggle case-sensitive search
clearFind—Clear the search state

Keyboard Shortcuts ​

ShortcutAction
Mod-fOpen Find panel
Mod-Shift-hOpen Replace panel

getEdituFindReplaceState ​

This function returns the current Find & Replace plugin state from the editor.

typescript
import { getEdituFindReplaceState } from '@editu/core';

const state = getEdituFindReplaceState(editor.state);
// {
//   query: string,
//   matches: EdituFindMatch[],
//   activeIndex: number,
//   caseSensitive: boolean,
//   isOpen: boolean,
//   mode: 'find' | 'replace',
// }

Types ​

typescript
import type {
  EdituFindReplaceOptions,
  EdituFindReplaceState,
  EdituFindMatch,
} from '@editu/core';

import { edituFindReplacePluginKey } from '@editu/core';
TypeDescription
EdituFindReplaceOptionsConfiguration options for the extension
EdituFindReplaceStatePlugin state containing query, matches, activeIndex, and more
EdituFindMatchSingle match with from and to positions
edituFindReplacePluginKeyProseMirror PluginKey for accessing the plugin state

A mark extension for wiki-style [[page-name]] links. Supports display text aliases with [[page-name|display text]] syntax.

createEdituWikiLinkExtension ​

This function creates a configured Wiki Link extension.

typescript
import { createEdituWikiLinkExtension } from '@editu/core';

const wikiLink = createEdituWikiLinkExtension({
  resolveLink: (page) => `/wiki/${encodeURIComponent(page)}`,
  pageExists: (page) => knownPages.has(page),
  onLinkClick: (page, event) => {
    event.preventDefault();
    router.push(`/wiki/${page}`);
  },
});

Options ​

OptionTypeDefaultDescription
resolveLink(pageName: string) => string(p) => '#' + pResolve a page name to a URL
pageExists(pageName: string) => boolean() => trueCheck whether a page exists (for visual differentiation)
getPageSuggestions(query: string) => EdituWikiLinkSuggestion[]—Return autocomplete suggestions
onLinkClick(pageName: string, event: MouseEvent) => void—Called when a wiki link is clicked
existingClassstring'editu-wiki-link--existing'CSS class for existing page links
newClassstring'editu-wiki-link--new'CSS class for non-existing page links
HTMLAttributesRecord<string, unknown>{}Additional HTML attributes

Editor Commands ​

CommandParametersDescription
setWikiLinkpageName: string, displayText?: stringInsert a wiki link at the current position
unsetWikiLink—Remove the wiki link mark from the selection

Types ​

typescript
import type { EdituWikiLinkOptions, EdituWikiLinkSuggestion } from '@editu/core';
import { EdituWikiLink, edituWikiLinkPluginKey } from '@editu/core';
TypeDescription
EdituWikiLinkOptionsConfiguration options for the extension
EdituWikiLinkSuggestionPage suggestion with name and optional label
EdituWikiLinkTiptap Mark extension class
edituWikiLinkPluginKeyProseMirror PluginKey for the wiki link plugin

Comments ​

Comment management module for adding, resolving, and replying to text annotations. This module provides a handler factory pattern with pluggable storage backends.

createEdituCommentHandlers ​

This function creates comment handler methods for an editor.

typescript
import { createEdituCommentHandlers } from '@editu/core';
import type { EdituCommentState } from '@editu/core';

const handlers = createEdituCommentHandlers(
  () => editor,
  {
    storage: 'localStorage',
    key: 'my-comments',
    onAdd: (comment) => console.log('Added:', comment.id),
  },
  (partial) => setState((prev) => ({ ...prev, ...partial }))
);

// Add a comment to the current text selection
await handlers.addComment('Needs clarification', 'Alice');

// Resolve a comment
await handlers.resolveComment(commentId);

// Reply to a comment
await handlers.replyToComment(commentId, 'Fixed in latest commit', 'Bob');

Parameters ​

ParameterTypeDescription
getEditor() => Editor | null | undefinedGetter function for the editor instance
optionsEdituCommentOptionsConfiguration options
onStateChange(state: Partial<EdituCommentState>) => voidCallback to update reactive state

Return Value ​

MethodSignatureDescription
addComment(text: string, author?: string) => Promise<EdituComment | null>Add a comment to the current selection
removeComment(commentId: string) => Promise<void>Remove a comment and its mark
resolveComment(commentId: string) => Promise<boolean>Mark a comment as resolved
reopenComment(commentId: string) => Promise<boolean>Reopen a resolved comment
replyToComment(commentId: string, text: string, author?: string) => Promise<EdituCommentReply | null>Add a reply to a comment
setActiveComment(commentId: string | null) => voidSet the currently active comment
loadComments() => Promise<EdituComment[]>Load all comments from storage
getCommentById(commentId: string) => EdituComment | undefinedGet a comment by its ID

getEdituCommentStorageBackend ​

This function creates a normalized storage backend from the storage option.

typescript
import { getEdituCommentStorageBackend } from '@editu/core';

const backend = getEdituCommentStorageBackend('localStorage', 'my-comments');
const comments = await backend.load();
await backend.save(comments);

Comment Extension ​

This extension adds a mark to the editor for highlighting commented text.

typescript
import { createEdituCommentExtension } from '@editu/core';

const commentExtension = createEdituCommentExtension();

Types ​

typescript
import type {
  EdituComment,
  EdituCommentReply,
  EdituCommentState,
  EdituCommentOptions,
  EdituCommentStorage,
} from '@editu/core';

import {
  EDITU_DEFAULT_COMMENT_OPTIONS,
  edituCommentPluginKey,
} from '@editu/core';
TypeDescription
EdituCommentComment annotation with id, text, author, createdAt, resolved, replies
EdituCommentReplyReply with id, text, author, createdAt
EdituCommentStateState object containing comments, activeCommentId, isLoading, error
EdituCommentOptionsConfiguration for enabled, storage, key, and event callbacks
EdituCommentStorage'localStorage' or custom { save, load } backend

Version History ​

Version history module for saving, restoring, and managing document snapshots. This module uses the same handler factory pattern and pluggable storage backends as Comments.

createEdituVersionHistoryHandlers ​

This function creates version history handler methods for an editor.

typescript
import { createEdituVersionHistoryHandlers } from '@editu/core';
import type { EdituVersionHistoryState } from '@editu/core';

const handlers = createEdituVersionHistoryHandlers(
  () => editor,
  {
    maxVersions: 20,
    storage: 'localStorage',
    onSave: (snapshot) => console.log('Saved version:', snapshot.id),
  },
  (partial) => setState((prev) => ({ ...prev, ...partial }))
);

// Save the current document state
await handlers.saveVersion('Initial draft', 'Alice');

// List all versions
const versions = await handlers.loadVersions();

// Restore a specific version
await handlers.restoreVersion(versions[0].id);

Parameters ​

ParameterTypeDescription
getEditor() => Editor | null | undefinedGetter function for the editor instance
optionsEdituVersionHistoryOptionsConfiguration options
onStateChange(state: Partial<EdituVersionHistoryState>) => voidCallback to update reactive state

Return Value ​

MethodSignatureDescription
saveVersion(description?: string, author?: string) => Promise<EdituVersionSnapshot | null>Save the current document as a new version
restoreVersion(versionId: string) => Promise<boolean>Restore the document to a specific version
loadVersions() => Promise<EdituVersionSnapshot[]>Load all versions from storage
deleteVersion(versionId: string) => Promise<void>Delete a specific version
clearVersions() => Promise<void>Delete all versions

getEdituVersionStorageBackend ​

This function creates a normalized storage backend from the storage option.

typescript
import { getEdituVersionStorageBackend } from '@editu/core';

const backend = getEdituVersionStorageBackend('localStorage', 'my-versions');
const snapshots = await backend.load();
await backend.save(snapshots);

Types ​

typescript
import type {
  EdituVersionSnapshot,
  EdituVersionHistoryState,
  EdituVersionHistoryOptions,
  EdituVersionStorage,
} from '@editu/core';

import { EDITU_DEFAULT_VERSION_HISTORY_OPTIONS } from '@editu/core';
TypeDescription
EdituVersionSnapshotSnapshot with id, content (JSONContent), timestamp, description, author
EdituVersionHistoryStateState object containing snapshots, isLoading, error
EdituVersionHistoryOptionsConfiguration for enabled, maxVersions, storage, key, and callbacks
EdituVersionStorage'localStorage' or custom { save, load } backend

Default Options ​

typescript
EDITU_DEFAULT_VERSION_HISTORY_OPTIONS = {
  enabled: true,
  maxVersions: 50,
  storage: 'localStorage',
  key: 'editu-versions',
};

Collaboration ​

Real-time multi-user editing module built on Yjs. This module provides types, state management, and lifecycle utilities for integrating Yjs-based collaboration.

WARNING

You must install your own compatible versions of yjs, a Yjs provider (e.g. y-websocket), @tiptap/extension-collaboration, and @tiptap/extension-collaboration-cursor.

createEdituCollaborationHandlers ​

This function creates collaboration handler methods for tracking provider state and managing lifecycle.

typescript
import { createEdituCollaborationHandlers } from '@editu/core';
import type { EdituCollaborationState } from '@editu/core';

const handlers = createEdituCollaborationHandlers(
  () => wsProvider,
  {
    user: { name: 'Alice', color: '#ff0000' },
    onConnect: () => console.log('Connected'),
    onPeersChange: (count) => console.log('Peers:', count),
  },
  (partial) => setState((prev) => ({ ...prev, ...partial }))
);

// Start listening to provider events
const unsubscribe = handlers.subscribe();

// Connect to the server
handlers.connect();

// Later, clean up
unsubscribe();

Parameters ​

ParameterTypeDescription
getProvider() => EdituYjsProvider | null | undefinedGetter function for the Yjs provider
optionsEdituCollaborationOptionsCollaboration options including user info
onStateChange(state: Partial<EdituCollaborationState>) => voidCallback to update reactive state

Return Value ​

MethodSignatureDescription
connect() => voidConnect to the collaboration server
disconnect() => voidDisconnect from the server
updateUser(user: EdituCollaborationUser) => voidUpdate the current user's cursor information
subscribe() => () => voidSubscribe to provider events; returns an unsubscribe function

Types ​

typescript
import type {
  EdituCollaborationUser,
  EdituCollaborationOptions,
  EdituCollaborationState,
  EdituYjsProvider,
  EdituYjsAwareness,
} from '@editu/core';

import { EDITU_DEFAULT_COLLABORATION_OPTIONS } from '@editu/core';
TypeDescription
EdituCollaborationUserUser info with name and color
EdituCollaborationOptionsConfiguration for enabled, user, and event callbacks
EdituCollaborationStateState containing isConnected, isSynced, peerCount, error
EdituYjsProviderInterface matching the Yjs WebSocket provider API
EdituYjsAwarenessInterface matching the Yjs Awareness API

EdituCollaborationOptions ​

OptionTypeDefaultDescription
enabledbooleantrueEnable collaboration tracking
userEdituCollaborationUser—Current user info for cursor display (required)
onConnect() => void—Called when connected
onDisconnect() => void—Called when disconnected
onSynced() => void—Called when initial document sync completes
onError(error: Error) => void—Called when an error occurs
onPeersChange(count: number) => void—Called when the number of connected peers changes

Plugin System ​

A plugin architecture for extending Editu with third-party functionality. The plugin system supports dependency resolution, lifecycle hooks, style injection, and transaction handling.

EdituPluginManager ​

The main class for managing plugins.

typescript
import { EdituPluginManager } from '@editu/core';
import type { EdituPlugin } from '@editu/core';

const manager = new EdituPluginManager();

// Register a plugin
manager.register(myPlugin);

// Pass plugin extensions to the editor
const editor = useEdituEditor({
  extensions: manager.getExtensions(),
});

// Connect the editor to enable lifecycle hooks
if (editor) manager.setEditor(editor);

// Clean up
manager.destroy();

Methods ​

MethodSignatureDescription
register(plugin: EdituPlugin) => voidRegister a plugin (validates, injects styles, calls onInstall if the editor is connected)
unregister(pluginName: string) => voidUnregister a plugin (checks dependents, removes styles, calls onUninstall)
setEditor(editor: Editor) => voidConnect an editor instance and call onInstall on all plugins
destroy() => voidDisconnect the editor and clean up all plugins
getExtensions() => ExtensionsReturn aggregated extensions from all plugins in dependency order
getPlugin(name: string) => EdituPlugin | undefinedGet a registered plugin by name
listPlugins() => EdituPlugin[]List all registered plugins
hasPlugin(name: string) => booleanCheck whether a plugin is registered

EdituPlugin Interface ​

typescript
import type { EdituPlugin } from '@editu/core';

const myPlugin: EdituPlugin = {
  name: 'my-editu-plugin',
  version: '1.0.0',
  description: 'Adds cool feature to Editu',
  extensions: [MyExtension],
  styles: '.my-plugin { color: red; }',
  dependencies: ['other-plugin'],
  onInstall: (editor) => console.log('Installed'),
  onUninstall: (editor) => console.log('Uninstalled'),
  onTransaction: ({ editor, transaction }) => { /* handle transaction */ },
};
FieldTypeRequiredDescription
namestringYesUnique identifier (kebab-case)
versionstringYesSemver version (e.g. '1.0.0')
descriptionstringNoHuman-readable description
extensionsExtensionsNoTiptap extensions to add
stylesstringNoCSS styles to inject
onInstall(editor: Editor) => voidNoCalled when the editor installs the plugin
onUninstall(editor: Editor) => voidNoCalled when the editor uninstalls the plugin
onTransaction(props: { editor: Editor; transaction: Transaction }) => voidNoCalled on each editor transaction
dependenciesstring[]NoPlugin names that you must register first

validateEdituPlugin ​

This function validates a plugin's required fields and format. It throws a descriptive error if validation fails.

typescript
import { validateEdituPlugin } from '@editu/core';

validateEdituPlugin(myPlugin); // throws if invalid

resolveEdituPluginDependencies ​

This function resolves plugin dependencies via topological sort. It throws if it detects a circular dependency or a missing dependency.

typescript
import { resolveEdituPluginDependencies } from '@editu/core';

const ordered = resolveEdituPluginDependencies(plugins);
// Returns plugins in dependency-first order

Internationalization (i18n) ​

EdituLocale ​

Type definition for all translatable UI strings. The locale is organized by component section:

typescript
import type { EdituLocale } from '@editu/core';
SectionDescriptionKey Fields
toolbarToolbar button labelsariaLabel, undo, redo, bold, italic, strikethrough, underline, code, heading1-heading3, bulletList, numberedList, taskList, quote, codeBlock, horizontalRule, moreActions
nodeTypesNode type selector labelstext, heading1-heading6, bulletList, numberedList, taskList, quote, code
blockMenuBlock context menulabel, delete, duplicate, copy, cut, turnInto
slashMenuSlash command menunoResults, groups, items, enterImageUrl, enterUrl, enterEmbedUrl
findReplaceFind and replace panellabel, findPlaceholder, replacePlaceholder, noResults, and button labels
codeBlockCode block UIlanguagePlaceholder, hideLineNumbers, showLineNumbers, copyCode, copied
dragHandleDrag handleariaLabel
saveIndicatorSave indicatorsaved, saving, unsaved, error
nodeSelectorNode selector dropdownchangeBlockType, blockTypes, currentBlockType
relativeTimeRelative time formattingjustNow, secondsAgo, minutesAgo, hoursAgo, daysAgo
bubbleMenuBubble menu labelsariaLabel, bold, italic, strikethrough, underline, code, link, superscript, subscript
colorPickerColor picker labelstextColor, highlight, textColorPalette, highlightPalette, recent, hexPlaceholder, apply, applyAriaLabel
linkEditorLink editor popupurlPlaceholder, apply, applyAriaLabel, removeLink, removeLinkAriaLabel, openInNewTab, visit, visitTitle, embedAsRichContent

edituEnLocale ​

The default English locale constant.

typescript
import { edituEnLocale } from '@editu/core';

console.log(edituEnLocale.toolbar.bold); // "Bold"
console.log(edituEnLocale.bubbleMenu.superscript); // "Superscript"
console.log(edituEnLocale.colorPicker.textColor); // "Text Color"
console.log(edituEnLocale.linkEditor.urlPlaceholder); // "Enter URL..."

createEdituLocale ​

This function merges a partial locale with the English defaults, producing a complete EdituLocale.

typescript
import { createEdituLocale } from '@editu/core';

const jaLocale = createEdituLocale({
  toolbar: { ariaLabel: '書式設定', bold: '太字', italic: '斜体' },
  bubbleMenu: { ariaLabel: 'テキスト書式', bold: '太字', italic: '斜体', link: 'リンク', superscript: '上付き', subscript: '下付き' },
  colorPicker: { textColor: '文字色', highlight: 'ハイライト' },
  linkEditor: { urlPlaceholder: 'URLを入力...', apply: '適用' },
});

EdituLocalePartial ​

Deep partial type that makes all nested locale properties optional. Used as the parameter type for createEdituLocale().

typescript
import type { EdituLocalePartial } from '@editu/core';

const partial: EdituLocalePartial = {
  bubbleMenu: { superscript: 'Hochgestellt' },
  colorPicker: { textColor: 'Textfarbe' },
};

Importing from Tiptap ​

For convenience, @editu/core re-exports commonly used Tiptap types and classes: Editor, Extensions, JSONContent, BubbleMenuPlugin, SuggestionOptions, and SuggestionProps. You can import them from either @editu/core or directly from @tiptap/core:

typescript
// Option 1: Import from @editu/core (convenience re-exports)
import { createEdituExtensions, getEdituEditorState } from '@editu/core';
import type { Editor, JSONContent, Extensions, EdituEditorOptions } from '@editu/core';

// Option 2: Import Tiptap types directly
import type { Editor, JSONContent, Extensions } from '@tiptap/core';

For types not re-exported by Editu, import them directly from the relevant @tiptap/* package.


Next Steps ​

Released under the MIT License.