Skip to content

@vizel/core

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

Installation

bash
npm install @vizel/core

TIP

You typically don't need to install this package directly. It's included as a dependency of @vizel/react, @vizel/vue, and @vizel/svelte.

Styles

Default Styles

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

This stylesheet includes CSS variables and component styles.

Components Only

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

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


Extensions

Vizel provides pre-configured Tiptap extensions.

createVizelExtensions

This function creates the default set of Vizel extensions.

typescript
import { createVizelExtensions } from '@vizel/core';

const extensions = await createVizelExtensions({
  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

VizelEditorOptions

typescript
import type { VizelEditorOptions } from '@vizel/core';

See Type Definitions for full interface.

VizelFeatureOptions

typescript
import type { VizelFeatureOptions } from '@vizel/core';

See Type Definitions for full interface.

VizelMarkdownFlavor

typescript
import type { VizelMarkdownFlavor } from '@vizel/core';

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

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

VizelFlavorConfig

typescript
import type { VizelFlavorConfig } from '@vizel/core';

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

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

VizelCalloutMarkdownFormat

typescript
import type { VizelCalloutMarkdownFormat } from '@vizel/core';

type VizelCalloutMarkdownFormat =
  | "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' }] }
  ],
};

VizelSaveStatus

typescript
import type { VizelSaveStatus } from '@vizel/core';

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

Theme Types

typescript
import type { VizelTheme, VizelResolvedTheme } from '@vizel/core';

type VizelTheme = 'light' | 'dark' | 'system';
type VizelResolvedTheme = '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 '@vizel/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" }],
// ]

resolveVizelFeatures

This function resolves feature options to extension configuration.

typescript
import { resolveVizelFeatures } from '@vizel/core';

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

resolveVizelFlavorConfig

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

typescript
import { resolveVizelFlavorConfig } from '@vizel/core';

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

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

getVizelEditorState

This function returns the current editor state.

typescript
import { getVizelEditorState } from '@vizel/core';

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

formatVizelRelativeTime

This function formats a date as relative time.

typescript
import { formatVizelRelativeTime } from '@vizel/core';

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

Theme Utilities

getVizelSystemTheme

This function returns the system color scheme preference.

typescript
import { getVizelSystemTheme } from '@vizel/core';

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

resolveVizelTheme

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

typescript
import { resolveVizelTheme } from '@vizel/core';

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

applyVizelTheme

This function applies a theme to the DOM.

typescript
import { applyVizelTheme } from '@vizel/core';

applyVizelTheme('dark', 'html');

getVizelThemeInitScript

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

typescript
import { getVizelThemeInitScript } from '@vizel/core';

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

Image Utilities

createVizelImageUploader

This function creates an image upload handler.

typescript
import { createVizelImageUploader } from '@vizel/core';

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

validateVizelImageFile

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

typescript
import { validateVizelImageFile } from '@vizel/core';

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

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

Color Utilities

getVizelRecentColors

This function retrieves recent colors from localStorage.

typescript
import { getVizelRecentColors } from '@vizel/core';

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

addVizelRecentColor

This function adds a color to the recent colors list.

typescript
import { addVizelRecentColor } from '@vizel/core';

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

Embed Utilities

detectVizelEmbedProvider

This function detects the oEmbed provider from a URL.

typescript
import { detectVizelEmbedProvider } from '@vizel/core';

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

Constants

VIZEL_DEFAULT_FLAVOR

This constant defines the default Markdown output flavor.

typescript
import { VIZEL_DEFAULT_FLAVOR } from '@vizel/core';
// "gfm"

VIZEL_TEXT_COLORS

This constant defines the default text color palette.

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

VIZEL_HIGHLIGHT_COLORS

This constant defines the default highlight color palette.

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

vizelDefaultEmbedProviders

This constant defines the default oEmbed providers.

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

Toolbar

VizelToolbarAction

Type definition for a toolbar action.

typescript
import type { VizelToolbarAction } from '@vizel/core';

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

VizelToolbarDropdownAction

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

typescript
import type { VizelToolbarDropdownAction } from '@vizel/core';

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

VizelToolbarActionItem

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

typescript
import type { VizelToolbarActionItem } from '@vizel/core';

type VizelToolbarActionItem = VizelToolbarAction | VizelToolbarDropdownAction;

isVizelToolbarDropdownAction

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

typescript
import { isVizelToolbarDropdownAction } from '@vizel/core';

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

vizelDefaultToolbarActions

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

typescript
import { vizelDefaultToolbarActions } from '@vizel/core';
// Array of VizelToolbarAction

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

groupVizelToolbarActions

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

typescript
import { groupVizelToolbarActions } from '@vizel/core';

const groups = groupVizelToolbarActions(actions);
// VizelToolbarActionItem[][] - 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 createVizelExtensions() — you add it manually.

createVizelFindReplaceExtension

This function creates the Find & Replace extension.

typescript
import { createVizelFindReplaceExtension } from '@vizel/core';

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

Options

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

Editor Commands

The extension registers the following commands on the editor:

CommandParametersDescription
openFindReplacemode?: 'find' | 'replace'Open the Find & Replace panel
closeFindReplaceClose the panel
findquery: stringSearch for text in the document
findNextNavigate to the next match
findPreviousNavigate to the previous match
replacetext: stringReplace the current match
replaceAlltext: stringReplace all matches
setFindCaseSensitivecaseSensitive: booleanToggle case-sensitive search
clearFindClear the search state

Keyboard Shortcuts

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

getVizelFindReplaceState

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

typescript
import { getVizelFindReplaceState } from '@vizel/core';

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

Types

typescript
import type {
  VizelFindReplaceOptions,
  VizelFindReplaceState,
  VizelFindMatch,
} from '@vizel/core';

import { vizelFindReplacePluginKey } from '@vizel/core';
TypeDescription
VizelFindReplaceOptionsConfiguration options for the extension
VizelFindReplaceStatePlugin state containing query, matches, activeIndex, and more
VizelFindMatchSingle match with from and to positions
vizelFindReplacePluginKeyProseMirror 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.

createVizelWikiLinkExtension

This function creates a configured Wiki Link extension.

typescript
import { createVizelWikiLinkExtension } from '@vizel/core';

const wikiLink = createVizelWikiLinkExtension({
  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) => VizelWikiLinkSuggestion[]Return autocomplete suggestions
onLinkClick(pageName: string, event: MouseEvent) => voidCalled when a wiki link is clicked
existingClassstring'vizel-wiki-link--existing'CSS class for existing page links
newClassstring'vizel-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
unsetWikiLinkRemove the wiki link mark from the selection

Types

typescript
import type { VizelWikiLinkOptions, VizelWikiLinkSuggestion } from '@vizel/core';
import { VizelWikiLink, vizelWikiLinkPluginKey } from '@vizel/core';
TypeDescription
VizelWikiLinkOptionsConfiguration options for the extension
VizelWikiLinkSuggestionPage suggestion with name and optional label
VizelWikiLinkTiptap Mark extension class
vizelWikiLinkPluginKeyProseMirror 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.

createVizelCommentHandlers

This function creates comment handler methods for an editor.

typescript
import { createVizelCommentHandlers } from '@vizel/core';
import type { VizelCommentState } from '@vizel/core';

const handlers = createVizelCommentHandlers(
  () => 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
optionsVizelCommentOptionsConfiguration options
onStateChange(state: Partial<VizelCommentState>) => voidCallback to update reactive state

Return Value

MethodSignatureDescription
addComment(text: string, author?: string) => Promise<VizelComment | 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<VizelCommentReply | null>Add a reply to a comment
setActiveComment(commentId: string | null) => voidSet the currently active comment
loadComments() => Promise<VizelComment[]>Load all comments from storage
getCommentById(commentId: string) => VizelComment | undefinedGet a comment by its ID

getVizelCommentStorageBackend

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

typescript
import { getVizelCommentStorageBackend } from '@vizel/core';

const backend = getVizelCommentStorageBackend('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 { createVizelCommentExtension } from '@vizel/core';

const commentExtension = createVizelCommentExtension();

Types

typescript
import type {
  VizelComment,
  VizelCommentReply,
  VizelCommentState,
  VizelCommentOptions,
  VizelCommentStorage,
} from '@vizel/core';

import {
  VIZEL_DEFAULT_COMMENT_OPTIONS,
  vizelCommentPluginKey,
} from '@vizel/core';
TypeDescription
VizelCommentComment annotation with id, text, author, createdAt, resolved, replies
VizelCommentReplyReply with id, text, author, createdAt
VizelCommentStateState object containing comments, activeCommentId, isLoading, error
VizelCommentOptionsConfiguration for enabled, storage, key, and event callbacks
VizelCommentStorage'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.

createVizelVersionHistoryHandlers

This function creates version history handler methods for an editor.

typescript
import { createVizelVersionHistoryHandlers } from '@vizel/core';
import type { VizelVersionHistoryState } from '@vizel/core';

const handlers = createVizelVersionHistoryHandlers(
  () => 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
optionsVizelVersionHistoryOptionsConfiguration options
onStateChange(state: Partial<VizelVersionHistoryState>) => voidCallback to update reactive state

Return Value

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

getVizelVersionStorageBackend

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

typescript
import { getVizelVersionStorageBackend } from '@vizel/core';

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

Types

typescript
import type {
  VizelVersionSnapshot,
  VizelVersionHistoryState,
  VizelVersionHistoryOptions,
  VizelVersionStorage,
} from '@vizel/core';

import { VIZEL_DEFAULT_VERSION_HISTORY_OPTIONS } from '@vizel/core';
TypeDescription
VizelVersionSnapshotSnapshot with id, content (JSONContent), timestamp, description, author
VizelVersionHistoryStateState object containing snapshots, isLoading, error
VizelVersionHistoryOptionsConfiguration for enabled, maxVersions, storage, key, and callbacks
VizelVersionStorage'localStorage' or custom { save, load } backend

Default Options

typescript
VIZEL_DEFAULT_VERSION_HISTORY_OPTIONS = {
  enabled: true,
  maxVersions: 50,
  storage: 'localStorage',
  key: 'vizel-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.

createVizelCollaborationHandlers

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

typescript
import { createVizelCollaborationHandlers } from '@vizel/core';
import type { VizelCollaborationState } from '@vizel/core';

const handlers = createVizelCollaborationHandlers(
  () => 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() => VizelYjsProvider | null | undefinedGetter function for the Yjs provider
optionsVizelCollaborationOptionsCollaboration options including user info
onStateChange(state: Partial<VizelCollaborationState>) => voidCallback to update reactive state

Return Value

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

Types

typescript
import type {
  VizelCollaborationUser,
  VizelCollaborationOptions,
  VizelCollaborationState,
  VizelYjsProvider,
  VizelYjsAwareness,
} from '@vizel/core';

import { VIZEL_DEFAULT_COLLABORATION_OPTIONS } from '@vizel/core';
TypeDescription
VizelCollaborationUserUser info with name and color
VizelCollaborationOptionsConfiguration for enabled, user, and event callbacks
VizelCollaborationStateState containing isConnected, isSynced, peerCount, error
VizelYjsProviderInterface matching the Yjs WebSocket provider API
VizelYjsAwarenessInterface matching the Yjs Awareness API

VizelCollaborationOptions

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

Plugin System

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

VizelPluginManager

The main class for managing plugins.

typescript
import { VizelPluginManager } from '@vizel/core';
import type { VizelPlugin } from '@vizel/core';

const manager = new VizelPluginManager();

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

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

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

// Clean up
manager.destroy();

Methods

MethodSignatureDescription
register(plugin: VizelPlugin) => 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) => VizelPlugin | undefinedGet a registered plugin by name
listPlugins() => VizelPlugin[]List all registered plugins
hasPlugin(name: string) => booleanCheck whether a plugin is registered

VizelPlugin Interface

typescript
import type { VizelPlugin } from '@vizel/core';

const myPlugin: VizelPlugin = {
  name: 'my-vizel-plugin',
  version: '1.0.0',
  description: 'Adds cool feature to Vizel',
  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

validateVizelPlugin

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

typescript
import { validateVizelPlugin } from '@vizel/core';

validateVizelPlugin(myPlugin); // throws if invalid

resolveVizelPluginDependencies

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

typescript
import { resolveVizelPluginDependencies } from '@vizel/core';

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

Internationalization (i18n)

VizelLocale

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

typescript
import type { VizelLocale } from '@vizel/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

vizelEnLocale

The default English locale constant.

typescript
import { vizelEnLocale } from '@vizel/core';

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

createVizelLocale

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

typescript
import { createVizelLocale } from '@vizel/core';

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

VizelLocalePartial

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

typescript
import type { VizelLocalePartial } from '@vizel/core';

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

Importing from Tiptap

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

typescript
// Option 1: Import from @vizel/core (convenience re-exports)
import { createVizelExtensions, getVizelEditorState } from '@vizel/core';
import type { Editor, JSONContent, Extensions, VizelEditorOptions } from '@vizel/core';

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

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


Next Steps

Released under the MIT License.