Plugin API Reference
Complete API reference for Marzipan plugin development.
MarzipanInstance
The editor instance passed to plugins.
Properties
container
ts
container: HTMLElement
The main editor container element.
Example:
ts
function myPlugin() {
return (editor) => {
editor.container.classList.add('custom-editor');
};
}
textarea
ts
textarea: HTMLTextAreaElement
The markdown input textarea element.
Example:
ts
function myPlugin() {
return (editor) => {
editor.textarea.placeholder = 'Start writing...';
};
}
Methods
updatePreview()
ts
updatePreview(): void
Triggers an update of the preview pane.
Example:
ts
function myPlugin() {
return (editor) => {
editor.textarea.value = '# Hello World';
editor.updatePreview();
};
}
getValue()
ts
getValue(): string
Returns the current markdown content.
Example:
ts
function myPlugin() {
return (editor) => {
const content = editor.getValue();
console.log('Current content:', content);
};
}
setValue()
ts
setValue(value: string): void
Sets the markdown content and updates the preview.
Example:
ts
function myPlugin() {
return (editor) => {
editor.setValue('# New Content\n\nHello!');
};
}
Plugin Types
MarzipanPlugin
ts
type MarzipanPlugin = (editor: MarzipanInstance) => void;
A function that receives the editor instance and modifies it.
PluginFactory
ts
type PluginFactory<T = any> = (options?: T) => MarzipanPlugin;
A function that accepts options and returns a plugin function.
Example:
ts
interface MyPluginOptions {
label: string;
}
const myPlugin: PluginFactory<MyPluginOptions> = (opts) => {
return (editor) => {
console.log(opts.label);
};
};
DOM Selectors
Toolbar
ts
const toolbar = editor.container.querySelector('.marzipan-toolbar');
Preview
ts
const preview = editor.container.querySelector('.marzipan-preview');
Textarea
ts
const textarea = editor.textarea;
// or
const textarea = editor.container.querySelector('.marzipan-textarea');
Common Patterns
Insert Text at Cursor
ts
function insertText(editor: MarzipanInstance, text: string) {
const { textarea, updatePreview } = editor;
const start = textarea.selectionStart ?? 0;
const end = textarea.selectionEnd ?? 0;
textarea.setRangeText(text, start, end, 'end');
updatePreview();
textarea.focus();
}
Wrap Selection
ts
function wrapText(
editor: MarzipanInstance,
prefix: string,
suffix: string
) {
const { textarea, updatePreview } = editor;
const start = textarea.selectionStart ?? 0;
const end = textarea.selectionEnd ?? 0;
const selection = textarea.value.substring(start, end);
textarea.setRangeText(
`${prefix}${selection}${suffix}`,
start,
end,
'end'
);
updatePreview();
textarea.focus();
}
Get Current Line
ts
function getCurrentLine(editor: MarzipanInstance): string {
const { textarea } = editor;
const pos = textarea.selectionStart ?? 0;
const text = textarea.value;
const lineStart = text.lastIndexOf('\n', pos - 1) + 1;
const lineEnd = text.indexOf('\n', pos);
return text.substring(
lineStart,
lineEnd === -1 ? text.length : lineEnd
);
}
Replace Current Line
ts
function replaceCurrentLine(
editor: MarzipanInstance,
newLine: string
) {
const { textarea, updatePreview } = editor;
const pos = textarea.selectionStart ?? 0;
const text = textarea.value;
const lineStart = text.lastIndexOf('\n', pos - 1) + 1;
const lineEnd = text.indexOf('\n', pos);
const actualEnd = lineEnd === -1 ? text.length : lineEnd;
textarea.setRangeText(newLine, lineStart, actualEnd, 'end');
updatePreview();
textarea.focus();
}
CSS Classes
Editor Container
.marzipan-container
Toolbar
.marzipan-toolbar
Toolbar Button
.mz-btn
Textarea
.marzipan-textarea
Preview
.marzipan-preview
Popover
.mz-pop
CSS Variables
Colors
css
--mz-bg /* Background */
--mz-fg /* Foreground text */
--mz-border /* Border color */
--mz-accent /* Accent color */
Toolbar
css
--mz-toolbar-bg /* Toolbar background */
--mz-btn-bg /* Button background */
--mz-btn-fg /* Button text */
--mz-btn-hover /* Button hover state */
Preview
css
--mz-preview-bg /* Preview background */
--mz-preview-fg /* Preview text */
Events
Textarea Events
input
Fired when content changes.
ts
function myPlugin() {
return (editor) => {
editor.textarea.addEventListener('input', () => {
console.log('Content changed');
});
};
}
keydown
Fired on key press.
ts
function myPlugin() {
return (editor) => {
editor.textarea.addEventListener('keydown', (e) => {
if (e.key === 'Tab' && !e.shiftKey) {
e.preventDefault();
// Handle tab
}
});
};
}
Custom Events
marzipan:accent
Fired when accent color changes.
ts
function myPlugin() {
return (editor) => {
editor.container.addEventListener('marzipan:accent', (e) => {
console.log('New accent:', e.detail.color);
});
};
}
Helper Utilities
Debounce
ts
function debounce<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let timeoutId: ReturnType<typeof setTimeout>;
return (...args: Parameters<T>) => {
clearTimeout(timeoutId);
timeoutId = setTimeout(() => fn(...args), delay);
};
}
// Usage
function myPlugin() {
return (editor) => {
const debouncedUpdate = debounce(() => {
console.log('Content updated');
}, 300);
editor.textarea.addEventListener('input', debouncedUpdate);
};
}
Throttle
ts
function throttle<T extends (...args: any[]) => any>(
fn: T,
delay: number
): (...args: Parameters<T>) => void {
let lastCall = 0;
return (...args: Parameters<T>) => {
const now = Date.now();
if (now - lastCall >= delay) {
lastCall = now;
fn(...args);
}
};
}
Complete Examples
Toolbar Button Plugin
ts
import type { MarzipanInstance } from '@pinkpixel/marzipan';
interface ButtonPluginOptions {
label?: string;
title?: string;
action: (editor: MarzipanInstance) => void;
}
export function buttonPlugin(opts: ButtonPluginOptions) {
const { label = '🔧', title = 'Action', action } = opts;
return (editor: MarzipanInstance) => {
const toolbar = editor.container.querySelector('.marzipan-toolbar');
if (!toolbar) return;
const button = document.createElement('button');
button.type = 'button';
button.className = 'mz-btn';
button.textContent = label;
button.title = title;
button.onclick = () => action(editor);
toolbar.appendChild(button);
};
}
// Usage
buttonPlugin({
label: '📝',
title: 'Insert template',
action: (editor) => {
editor.setValue('# Template\n\nContent here...');
}
})
Preview Enhancement Plugin
ts
export function enhancePreview() {
return (editor: MarzipanInstance) => {
const { container, updatePreview } = editor;
const originalUpdate = updatePreview.bind(editor);
editor.updatePreview = function() {
originalUpdate();
const preview = container.querySelector('.marzipan-preview');
if (!preview) return;
// Add syntax highlighting
preview.querySelectorAll('pre code').forEach(block => {
// Highlight code
});
// Add copy buttons
preview.querySelectorAll('pre').forEach(pre => {
if (pre.querySelector('.copy-button')) return;
const button = document.createElement('button');
button.textContent = 'Copy';
button.className = 'copy-button';
button.onclick = () => {
const code = pre.textContent || '';
navigator.clipboard.writeText(code);
};
pre.appendChild(button);
});
};
updatePreview.call(editor);
};
}
Keyboard Shortcut Plugin
ts
interface ShortcutOptions {
key: string;
ctrl?: boolean;
alt?: boolean;
shift?: boolean;
action: (editor: MarzipanInstance) => void;
}
export function shortcutPlugin(opts: ShortcutOptions) {
return (editor: MarzipanInstance) => {
editor.textarea.addEventListener('keydown', (e) => {
const matches =
e.key === opts.key &&
e.ctrlKey === (opts.ctrl ?? false) &&
e.altKey === (opts.alt ?? false) &&
e.shiftKey === (opts.shift ?? false);
if (matches) {
e.preventDefault();
opts.action(editor);
}
});
};
}
// Usage: Ctrl+Shift+B for bold
shortcutPlugin({
key: 'b',
ctrl: true,
shift: true,
action: (editor) => {
const { textarea, updatePreview } = editor;
const start = textarea.selectionStart ?? 0;
const end = textarea.selectionEnd ?? 0;
const selection = textarea.value.substring(start, end);
textarea.setRangeText(`**${selection}**`, start, end, 'end');
updatePreview();
}
})
TypeScript Definitions
Full type definitions:
ts
interface MarzipanInstance {
container: HTMLElement;
textarea: HTMLTextAreaElement;
updatePreview: () => void;
getValue: () => string;
setValue: (value: string) => void;
}
type MarzipanPlugin = (editor: MarzipanInstance) => void;
type PluginFactory<T = any> = (options?: T) => MarzipanPlugin;
interface MarzipanOptions {
toolbar?: boolean;
theme?: 'solar' | 'cave' | 'forest';
value?: string;
placeholder?: string;
minHeight?: string;
plugins?: MarzipanPlugin[];
onChange?: (value: string, instance: MarzipanInstance) => void;
onReady?: (instance: MarzipanInstance) => void;
}
See Also
- Plugin Overview - Plugin system overview
- Plugin Development - Creating plugins
- Examples - Source code examples
Marzipan