@pinkpixel/marzipan 1.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +201 -0
- package/README.md +133 -0
- package/dist/favicon.png +0 -0
- package/dist/index.js +3212 -0
- package/dist/index.js.map +1 -0
- package/dist/logo.png +0 -0
- package/docs/README.md +33 -0
- package/docs/TABLE_OF_CONTENTS.md +19 -0
- package/docs/api.md +749 -0
- package/docs/plugins.md +57 -0
- package/docs/quick-start.md +90 -0
- package/docs/types.d.ts +231 -0
- package/package.json +66 -0
package/docs/api.md
ADDED
|
@@ -0,0 +1,749 @@
|
|
|
1
|
+
# Marzipan API Reference
|
|
2
|
+
|
|
3
|
+
A comprehensive guide to the core Marzipan class, bundled action toolkit, and first-party plugin exports.
|
|
4
|
+
|
|
5
|
+
## Table of Contents
|
|
6
|
+
|
|
7
|
+
- [Quick Start](#quick-start)
|
|
8
|
+
- [Constructor](#constructor)
|
|
9
|
+
- [Instance Methods](#instance-methods)
|
|
10
|
+
- [Static Methods](#static-methods)
|
|
11
|
+
- [Actions API](#actions-api)
|
|
12
|
+
- [Options](#options)
|
|
13
|
+
- [Themes](#themes)
|
|
14
|
+
- [Plugin Exports](#plugin-exports)
|
|
15
|
+
- [Events](#events)
|
|
16
|
+
- [Examples](#examples)
|
|
17
|
+
|
|
18
|
+
## Quick Start
|
|
19
|
+
|
|
20
|
+
```javascript
|
|
21
|
+
// Import Marzipan
|
|
22
|
+
import { Marzipan } from '@pinkpixel/marzipan';
|
|
23
|
+
|
|
24
|
+
// Initialize single editor
|
|
25
|
+
const [editor] = new Marzipan('#my-editor');
|
|
26
|
+
|
|
27
|
+
// Or use the static helper for multiple elements
|
|
28
|
+
const editors = Marzipan.init('.markdown-editor');
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## Constructor
|
|
32
|
+
|
|
33
|
+
### `new Marzipan(target, options)`
|
|
34
|
+
|
|
35
|
+
Creates one or more Marzipan editor instances.
|
|
36
|
+
|
|
37
|
+
**Parameters:**
|
|
38
|
+
- `target` *(string|Element|NodeList|Array)* - Target element(s) to initialize
|
|
39
|
+
- `string` - CSS selector
|
|
40
|
+
- `Element` - Single DOM element
|
|
41
|
+
- `NodeList` - Collection of DOM elements
|
|
42
|
+
- `Array` - Array of DOM elements
|
|
43
|
+
- `options` *(Object)* - Configuration options (see [Options](#options))
|
|
44
|
+
|
|
45
|
+
**Returns:** `Array<Marzipan>` - Array of Marzipan instances
|
|
46
|
+
|
|
47
|
+
**Example:**
|
|
48
|
+
```javascript
|
|
49
|
+
// Single element by selector
|
|
50
|
+
const editors = new Marzipan('#editor');
|
|
51
|
+
|
|
52
|
+
// Multiple elements
|
|
53
|
+
const editors = new Marzipan('.markdown-editor');
|
|
54
|
+
|
|
55
|
+
// With options
|
|
56
|
+
const editors = new Marzipan('#editor', {
|
|
57
|
+
fontSize: '16px',
|
|
58
|
+
toolbar: true,
|
|
59
|
+
showStats: true
|
|
60
|
+
});
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Instance Methods
|
|
64
|
+
|
|
65
|
+
### Content Management
|
|
66
|
+
|
|
67
|
+
#### `getValue()`
|
|
68
|
+
Get the current markdown content from the editor.
|
|
69
|
+
|
|
70
|
+
**Returns:** `string` - Current markdown content
|
|
71
|
+
|
|
72
|
+
```javascript
|
|
73
|
+
const content = editor.getValue();
|
|
74
|
+
console.log(content); // "# Hello World\n\nThis is markdown content"
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
#### `setValue(value)`
|
|
78
|
+
Set the markdown content in the editor.
|
|
79
|
+
|
|
80
|
+
**Parameters:**
|
|
81
|
+
- `value` *(string)* - Markdown content to set
|
|
82
|
+
|
|
83
|
+
```javascript
|
|
84
|
+
editor.setValue('# New Content\n\nThis replaces the existing content.');
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
#### `getRenderedHTML(options)`
|
|
88
|
+
Get the rendered HTML of the current content.
|
|
89
|
+
|
|
90
|
+
**Parameters:**
|
|
91
|
+
- `options` *(Object)* - Rendering options
|
|
92
|
+
- `cleanHTML` *(boolean)* - Remove syntax markers and Marzipan-specific classes
|
|
93
|
+
|
|
94
|
+
**Returns:** `string` - Rendered HTML
|
|
95
|
+
|
|
96
|
+
```javascript
|
|
97
|
+
// Get HTML with syntax highlighting
|
|
98
|
+
const html = editor.getRenderedHTML();
|
|
99
|
+
|
|
100
|
+
// Get clean HTML for export
|
|
101
|
+
const cleanHtml = editor.getRenderedHTML({ cleanHTML: true });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
#### `getPreviewHTML()`
|
|
105
|
+
Get the current preview element's HTML (includes all syntax markers).
|
|
106
|
+
|
|
107
|
+
**Returns:** `string` - Current preview HTML as displayed
|
|
108
|
+
|
|
109
|
+
#### `getCleanHTML()`
|
|
110
|
+
Get clean HTML without any Marzipan-specific markup. Shorthand for `getRenderedHTML({ cleanHTML: true })`.
|
|
111
|
+
|
|
112
|
+
**Returns:** `string` - Clean HTML suitable for export
|
|
113
|
+
|
|
114
|
+
### Focus Management
|
|
115
|
+
|
|
116
|
+
#### `focus()`
|
|
117
|
+
Focus the editor textarea.
|
|
118
|
+
|
|
119
|
+
```javascript
|
|
120
|
+
editor.focus();
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
#### `blur()`
|
|
124
|
+
Blur the editor textarea.
|
|
125
|
+
|
|
126
|
+
```javascript
|
|
127
|
+
editor.blur();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Display Modes
|
|
131
|
+
|
|
132
|
+
#### `showPlainTextarea(show)`
|
|
133
|
+
Toggle between plain textarea and overlay markdown preview.
|
|
134
|
+
|
|
135
|
+
**Parameters:**
|
|
136
|
+
- `show` *(boolean)* - `true` to show plain textarea, `false` to show overlay
|
|
137
|
+
|
|
138
|
+
**Returns:** `boolean` - Current plain textarea state
|
|
139
|
+
|
|
140
|
+
```javascript
|
|
141
|
+
// Show plain textarea (hide markdown preview)
|
|
142
|
+
editor.showPlainTextarea(true);
|
|
143
|
+
|
|
144
|
+
// Show markdown overlay
|
|
145
|
+
editor.showPlainTextarea(false);
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
#### `showPreviewMode(show)`
|
|
149
|
+
Toggle between edit and preview-only modes.
|
|
150
|
+
|
|
151
|
+
**Parameters:**
|
|
152
|
+
- `show` *(boolean)* - `true` for preview mode, `false` for edit mode
|
|
153
|
+
|
|
154
|
+
**Returns:** `boolean` - Current preview mode state
|
|
155
|
+
|
|
156
|
+
```javascript
|
|
157
|
+
// Switch to preview-only mode
|
|
158
|
+
editor.showPreviewMode(true);
|
|
159
|
+
|
|
160
|
+
// Switch back to edit mode
|
|
161
|
+
editor.showPreviewMode(false);
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
#### `showStats(show)`
|
|
165
|
+
Show or hide the statistics bar.
|
|
166
|
+
|
|
167
|
+
**Parameters:**
|
|
168
|
+
- `show` *(boolean)* - Whether to show statistics
|
|
169
|
+
|
|
170
|
+
```javascript
|
|
171
|
+
editor.showStats(true); // Show character/word/line counts
|
|
172
|
+
editor.showStats(false); // Hide statistics
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Editor State
|
|
176
|
+
|
|
177
|
+
#### `updatePreview()`
|
|
178
|
+
Manually update the markdown preview. Usually called automatically.
|
|
179
|
+
|
|
180
|
+
```javascript
|
|
181
|
+
editor.updatePreview();
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
#### `isInitialized()`
|
|
185
|
+
Check if the editor is fully initialized.
|
|
186
|
+
|
|
187
|
+
**Returns:** `boolean` - Initialization status
|
|
188
|
+
|
|
189
|
+
```javascript
|
|
190
|
+
if (editor.isInitialized()) {
|
|
191
|
+
console.log('Editor is ready!');
|
|
192
|
+
}
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
#### `reinit(options)`
|
|
196
|
+
Re-initialize the editor with new options.
|
|
197
|
+
|
|
198
|
+
**Parameters:**
|
|
199
|
+
- `options` *(Object)* - New options to apply (merged with existing options)
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
editor.reinit({
|
|
203
|
+
fontSize: '18px',
|
|
204
|
+
toolbar: false
|
|
205
|
+
});
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
#### `destroy()`
|
|
209
|
+
Destroy the editor instance and cleanup resources.
|
|
210
|
+
|
|
211
|
+
```javascript
|
|
212
|
+
editor.destroy();
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
## Static Methods
|
|
216
|
+
|
|
217
|
+
### `Marzipan.init(target, options)`
|
|
218
|
+
Convenience method to create new instances. Equivalent to `new Marzipan()`.
|
|
219
|
+
|
|
220
|
+
**Parameters:**
|
|
221
|
+
- `target` *(string|Element|NodeList|Array)* - Target element(s)
|
|
222
|
+
- `options` *(Object)* - Configuration options
|
|
223
|
+
|
|
224
|
+
**Returns:** `Array<Marzipan>` - Array of instances
|
|
225
|
+
|
|
226
|
+
### `Marzipan.getInstance(element)`
|
|
227
|
+
Get existing Marzipan instance from a DOM element.
|
|
228
|
+
|
|
229
|
+
**Parameters:**
|
|
230
|
+
- `element` *(Element)* - DOM element
|
|
231
|
+
|
|
232
|
+
**Returns:** `Marzipan|null` - Instance or null if not found
|
|
233
|
+
|
|
234
|
+
```javascript
|
|
235
|
+
const element = document.getElementById('my-editor');
|
|
236
|
+
const instance = Marzipan.getInstance(element);
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
### `Marzipan.destroyAll()`
|
|
240
|
+
Destroy all existing Marzipan instances.
|
|
241
|
+
|
|
242
|
+
```javascript
|
|
243
|
+
Marzipan.destroyAll();
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### `Marzipan.setTheme(theme, customColors)`
|
|
247
|
+
Set global theme for all Marzipan instances.
|
|
248
|
+
|
|
249
|
+
**Parameters:**
|
|
250
|
+
- `theme` *(string|Object)* - Theme name or custom theme object
|
|
251
|
+
- `customColors` *(Object)* - Optional color overrides
|
|
252
|
+
|
|
253
|
+
```javascript
|
|
254
|
+
// Use built-in theme
|
|
255
|
+
Marzipan.setTheme('cave');
|
|
256
|
+
|
|
257
|
+
// Use custom theme
|
|
258
|
+
Marzipan.setTheme({
|
|
259
|
+
name: 'custom',
|
|
260
|
+
colors: {
|
|
261
|
+
background: '#1a1a1a',
|
|
262
|
+
text: '#ffffff'
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
// Override colors
|
|
267
|
+
Marzipan.setTheme('solar', {
|
|
268
|
+
background: '#002b36'
|
|
269
|
+
});
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
### `Marzipan.injectStyles(force)`
|
|
273
|
+
Manually inject Marzipan styles into the document.
|
|
274
|
+
|
|
275
|
+
**Parameters:**
|
|
276
|
+
- `force` *(boolean)* - Force re-injection even if already injected
|
|
277
|
+
|
|
278
|
+
```javascript
|
|
279
|
+
Marzipan.injectStyles(true); // Force style re-injection
|
|
280
|
+
```
|
|
281
|
+
|
|
282
|
+
## Actions API
|
|
283
|
+
|
|
284
|
+
Marzipan ships a zero-dependency markdown action toolkit alongside the core class. Import the helpers from `@pinkpixel/marzipan` and pass the target `HTMLTextAreaElement`.
|
|
285
|
+
|
|
286
|
+
```ts
|
|
287
|
+
import { actions } from '@pinkpixel/marzipan';
|
|
288
|
+
|
|
289
|
+
const textarea = document.querySelector('textarea');
|
|
290
|
+
if (textarea) {
|
|
291
|
+
actions.toggleBold(textarea);
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
Available helpers include:
|
|
296
|
+
- `toggleBold(textarea)`
|
|
297
|
+
- `toggleItalic(textarea)`
|
|
298
|
+
- `toggleCode(textarea)`
|
|
299
|
+
- `insertLink(textarea, options?)`
|
|
300
|
+
- `toggleBulletList(textarea)`
|
|
301
|
+
- `toggleNumberedList(textarea)`
|
|
302
|
+
- `toggleQuote(textarea)`
|
|
303
|
+
- `toggleTaskList(textarea)`
|
|
304
|
+
- `toggleH1/H2/H3(textarea)`
|
|
305
|
+
- `applyCustomFormat(textarea, format)`
|
|
306
|
+
- `getActiveFormats(textarea)`
|
|
307
|
+
- `setUndoMethod(method)` / `getUndoMethod()`
|
|
308
|
+
|
|
309
|
+
These functions mirror the toolbar and keyboard shortcut behaviour, making it easy to build custom UI without extra dependencies.
|
|
310
|
+
|
|
311
|
+
## Options
|
|
312
|
+
|
|
313
|
+
Default options and their descriptions:
|
|
314
|
+
|
|
315
|
+
```javascript
|
|
316
|
+
const defaultOptions = {
|
|
317
|
+
// Typography
|
|
318
|
+
fontSize: '14px', // Font size
|
|
319
|
+
lineHeight: 1.6, // Line height multiplier
|
|
320
|
+
fontFamily: '...', // Monospace font stack
|
|
321
|
+
padding: '16px', // Internal padding
|
|
322
|
+
|
|
323
|
+
// Mobile-specific styles
|
|
324
|
+
mobile: {
|
|
325
|
+
fontSize: '16px', // Font size on mobile (prevents zoom)
|
|
326
|
+
padding: '12px', // Reduced padding on mobile
|
|
327
|
+
lineHeight: 1.5 // Adjusted line height
|
|
328
|
+
},
|
|
329
|
+
|
|
330
|
+
// Textarea properties
|
|
331
|
+
textareaProps: {}, // Native textarea attributes
|
|
332
|
+
|
|
333
|
+
// Behavior
|
|
334
|
+
autofocus: false, // Auto-focus on initialization
|
|
335
|
+
autoResize: false, // Auto-expand height with content
|
|
336
|
+
minHeight: '100px', // Minimum height (autoResize mode)
|
|
337
|
+
maxHeight: null, // Maximum height (autoResize mode)
|
|
338
|
+
placeholder: 'Start typing...', // Placeholder text
|
|
339
|
+
value: '', // Initial content
|
|
340
|
+
|
|
341
|
+
// Callbacks
|
|
342
|
+
onChange: null, // Content change callback
|
|
343
|
+
onKeydown: null, // Keydown event callback
|
|
344
|
+
|
|
345
|
+
// Features
|
|
346
|
+
showActiveLineRaw: false, // Show active line without markdown rendering
|
|
347
|
+
showStats: false, // Show statistics bar
|
|
348
|
+
toolbar: false, // Show toolbar (true/false or config object)
|
|
349
|
+
statsFormatter: null, // Custom stats formatter function
|
|
350
|
+
smartLists: true, // Enable smart list continuation
|
|
351
|
+
|
|
352
|
+
// Themes (applied per-instance)
|
|
353
|
+
theme: null // Instance-specific theme override
|
|
354
|
+
};
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
### Option Details
|
|
358
|
+
|
|
359
|
+
#### `textareaProps`
|
|
360
|
+
Apply native textarea attributes:
|
|
361
|
+
|
|
362
|
+
```javascript
|
|
363
|
+
new Marzipan('#editor', {
|
|
364
|
+
textareaProps: {
|
|
365
|
+
'data-testid': 'markdown-input',
|
|
366
|
+
'aria-label': 'Markdown editor',
|
|
367
|
+
maxlength: 5000,
|
|
368
|
+
style: { border: '2px solid blue' }
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
```
|
|
372
|
+
|
|
373
|
+
#### `onChange(value, instance)`
|
|
374
|
+
Called when content changes:
|
|
375
|
+
|
|
376
|
+
```javascript
|
|
377
|
+
new Marzipan('#editor', {
|
|
378
|
+
onChange: (value, instance) => {
|
|
379
|
+
console.log('Content changed:', value.length, 'characters');
|
|
380
|
+
// Save to localStorage, send to server, etc.
|
|
381
|
+
}
|
|
382
|
+
});
|
|
383
|
+
```
|
|
384
|
+
|
|
385
|
+
#### `onKeydown(event, instance)`
|
|
386
|
+
Called for keydown events:
|
|
387
|
+
|
|
388
|
+
```javascript
|
|
389
|
+
new Marzipan('#editor', {
|
|
390
|
+
onKeydown: (event, instance) => {
|
|
391
|
+
if (event.key === 'Enter' && event.ctrlKey) {
|
|
392
|
+
console.log('Ctrl+Enter pressed');
|
|
393
|
+
// Custom save logic
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
#### `statsFormatter(stats)`
|
|
400
|
+
Custom statistics display:
|
|
401
|
+
|
|
402
|
+
```javascript
|
|
403
|
+
new Marzipan('#editor', {
|
|
404
|
+
showStats: true,
|
|
405
|
+
statsFormatter: (stats) => {
|
|
406
|
+
return `📝 ${stats.words} words • 📏 ${stats.chars} chars • 📄 ${stats.lines} lines`;
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
```
|
|
410
|
+
|
|
411
|
+
Stats object contains:
|
|
412
|
+
- `chars` *(number)* - Character count
|
|
413
|
+
- `words` *(number)* - Word count
|
|
414
|
+
- `lines` *(number)* - Line count
|
|
415
|
+
- `line` *(number)* - Current line number
|
|
416
|
+
- `column` *(number)* - Current column number
|
|
417
|
+
|
|
418
|
+
#### `toolbar`
|
|
419
|
+
Enable toolbar with default buttons:
|
|
420
|
+
|
|
421
|
+
```javascript
|
|
422
|
+
// Enable with defaults
|
|
423
|
+
new Marzipan('#editor', { toolbar: true });
|
|
424
|
+
|
|
425
|
+
// Custom button configuration
|
|
426
|
+
new Marzipan('#editor', {
|
|
427
|
+
toolbar: {
|
|
428
|
+
buttons: ['bold', 'italic', 'code', '|', 'link', 'quote', '|', 'bulletList', 'orderedList']
|
|
429
|
+
}
|
|
430
|
+
});
|
|
431
|
+
```
|
|
432
|
+
|
|
433
|
+
Available toolbar buttons:
|
|
434
|
+
- `bold` – **Bold** text
|
|
435
|
+
- `italic` – *Italic* text
|
|
436
|
+
- `code` – `Inline code`
|
|
437
|
+
- `link` – Insert or edit links
|
|
438
|
+
- `quote` – Blockquotes
|
|
439
|
+
- `bulletList` – Unordered lists
|
|
440
|
+
- `orderedList` – Ordered lists
|
|
441
|
+
- `taskList` – Task list checkboxes
|
|
442
|
+
- `h1` / `h2` / `h3` – Heading levels
|
|
443
|
+
- `toggle-view-menu` – Opens the view dropdown (plain/preview/normal)
|
|
444
|
+
- `toggle-plain` – Direct plain/preview toggle (legacy name)
|
|
445
|
+
- `separator` (`|`) – Visual divider
|
|
446
|
+
|
|
447
|
+
## Themes
|
|
448
|
+
|
|
449
|
+
Marzipan includes built-in themes and supports custom themes.
|
|
450
|
+
|
|
451
|
+
### Built-in Themes
|
|
452
|
+
|
|
453
|
+
- `solar` - Light theme with warm colors (default)
|
|
454
|
+
- `cave` - Dark theme with cool colors
|
|
455
|
+
|
|
456
|
+
### Using Themes
|
|
457
|
+
|
|
458
|
+
```javascript
|
|
459
|
+
// Global theme (affects all instances)
|
|
460
|
+
Marzipan.setTheme('cave');
|
|
461
|
+
|
|
462
|
+
// Instance-specific theme
|
|
463
|
+
new Marzipan('#editor', {
|
|
464
|
+
theme: 'cave' // Only this instance uses cave theme
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
// Custom theme
|
|
468
|
+
const myTheme = {
|
|
469
|
+
name: 'purple',
|
|
470
|
+
colors: {
|
|
471
|
+
background: '#2d1b69',
|
|
472
|
+
text: '#e1d5f7',
|
|
473
|
+
comment: '#9c88c4',
|
|
474
|
+
keyword: '#bb9af7',
|
|
475
|
+
string: '#9ece6a',
|
|
476
|
+
number: '#ff9e64',
|
|
477
|
+
// ... more colors
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
|
|
481
|
+
Marzipan.setTheme(myTheme);
|
|
482
|
+
```
|
|
483
|
+
|
|
484
|
+
### Theme Color Properties
|
|
485
|
+
|
|
486
|
+
```javascript
|
|
487
|
+
const themeColors = {
|
|
488
|
+
// Base colors
|
|
489
|
+
background: '#ffffff', // Main background
|
|
490
|
+
text: '#333333', // Primary text
|
|
491
|
+
textMuted: '#666666', // Secondary text
|
|
492
|
+
|
|
493
|
+
// Syntax highlighting
|
|
494
|
+
comment: '#93a1a1', // Comments
|
|
495
|
+
keyword: '#859900', // Keywords (bold, headers)
|
|
496
|
+
string: '#2aa198', // Strings and links
|
|
497
|
+
number: '#d33682', // Numbers
|
|
498
|
+
punctuation: '#586e75', // Punctuation
|
|
499
|
+
|
|
500
|
+
// UI elements
|
|
501
|
+
selection: '#eee8d5', // Text selection
|
|
502
|
+
border: '#e1e1e1', // Borders
|
|
503
|
+
toolbar: '#f8f8f8', // Toolbar background
|
|
504
|
+
|
|
505
|
+
// Interactive elements
|
|
506
|
+
linkHover: '#0066cc', // Link hover color
|
|
507
|
+
buttonActive: '#007acc', // Active button background
|
|
508
|
+
};
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
## Events
|
|
512
|
+
|
|
513
|
+
### Content Events
|
|
514
|
+
|
|
515
|
+
#### Change Event
|
|
516
|
+
Triggered when content changes via the `onChange` callback:
|
|
517
|
+
|
|
518
|
+
```javascript
|
|
519
|
+
new Marzipan('#editor', {
|
|
520
|
+
onChange: (value, instance) => {
|
|
521
|
+
console.log('Content:', value);
|
|
522
|
+
console.log('Instance ID:', instance.instanceId);
|
|
523
|
+
}
|
|
524
|
+
});
|
|
525
|
+
```
|
|
526
|
+
|
|
527
|
+
#### Input Events
|
|
528
|
+
Access native textarea events through the `textarea` property:
|
|
529
|
+
|
|
530
|
+
```javascript
|
|
531
|
+
const editor = new Marzipan('#editor')[0];
|
|
532
|
+
|
|
533
|
+
editor.textarea.addEventListener('focus', () => {
|
|
534
|
+
console.log('Editor focused');
|
|
535
|
+
});
|
|
536
|
+
|
|
537
|
+
editor.textarea.addEventListener('blur', () => {
|
|
538
|
+
console.log('Editor blurred');
|
|
539
|
+
});
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
### Keyboard Events
|
|
543
|
+
|
|
544
|
+
#### Global Keyboard Handler
|
|
545
|
+
Use the `onKeydown` callback:
|
|
546
|
+
|
|
547
|
+
```javascript
|
|
548
|
+
new Marzipan('#editor', {
|
|
549
|
+
onKeydown: (event, instance) => {
|
|
550
|
+
// Handle custom shortcuts
|
|
551
|
+
if (event.ctrlKey && event.key === 's') {
|
|
552
|
+
event.preventDefault();
|
|
553
|
+
saveContent(instance.getValue());
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
});
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
#### Built-in Shortcuts
|
|
560
|
+
Marzipan includes built-in keyboard shortcuts:
|
|
561
|
+
|
|
562
|
+
- `Tab` / `Shift+Tab` - Indent/outdent text
|
|
563
|
+
- `Enter` - Smart list continuation
|
|
564
|
+
- `Ctrl+B` / `Cmd+B` - Toggle bold (with toolbar)
|
|
565
|
+
- `Ctrl+I` / `Cmd+I` - Toggle italic (with toolbar)
|
|
566
|
+
- `Ctrl+K` / `Cmd+K` - Insert link (with toolbar)
|
|
567
|
+
|
|
568
|
+
## Examples
|
|
569
|
+
|
|
570
|
+
### Basic Editor
|
|
571
|
+
|
|
572
|
+
```javascript
|
|
573
|
+
// Simple editor
|
|
574
|
+
const editors = new Marzipan('#editor', {
|
|
575
|
+
placeholder: 'Write your markdown here...',
|
|
576
|
+
value: '# Hello World\n\nStart writing!'
|
|
577
|
+
});
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
### Full-Featured Editor
|
|
581
|
+
|
|
582
|
+
```javascript
|
|
583
|
+
// Editor with all features
|
|
584
|
+
const editors = new Marzipan('#advanced-editor', {
|
|
585
|
+
// Appearance
|
|
586
|
+
fontSize: '16px',
|
|
587
|
+
lineHeight: 1.7,
|
|
588
|
+
theme: 'cave',
|
|
589
|
+
|
|
590
|
+
// Features
|
|
591
|
+
toolbar: true,
|
|
592
|
+
showStats: true,
|
|
593
|
+
autoResize: true,
|
|
594
|
+
minHeight: '200px',
|
|
595
|
+
maxHeight: '600px',
|
|
596
|
+
|
|
597
|
+
// Behavior
|
|
598
|
+
autofocus: true,
|
|
599
|
+
smartLists: true,
|
|
600
|
+
showActiveLineRaw: true,
|
|
601
|
+
|
|
602
|
+
// Events
|
|
603
|
+
onChange: (value, instance) => {
|
|
604
|
+
localStorage.setItem('markdown-content', value);
|
|
605
|
+
},
|
|
606
|
+
|
|
607
|
+
// Custom stats
|
|
608
|
+
statsFormatter: ({ words, chars, lines, line, column }) => {
|
|
609
|
+
const readingTime = Math.ceil(words / 200);
|
|
610
|
+
return `${words} words (${readingTime} min read) • Line ${line}:${column}`;
|
|
611
|
+
}
|
|
612
|
+
});
|
|
613
|
+
|
|
614
|
+
const editor = editors[0];
|
|
615
|
+
```
|
|
616
|
+
|
|
617
|
+
### Multiple Editors
|
|
618
|
+
|
|
619
|
+
```javascript
|
|
620
|
+
// Initialize multiple editors with different configs
|
|
621
|
+
const editors = Marzipan.init('.editor', {
|
|
622
|
+
toolbar: true,
|
|
623
|
+
showStats: true
|
|
624
|
+
});
|
|
625
|
+
|
|
626
|
+
// Customize individual editors
|
|
627
|
+
editors[0].reinit({ theme: 'solar' });
|
|
628
|
+
editors[1].reinit({ theme: 'cave' });
|
|
629
|
+
|
|
630
|
+
// Handle all editors
|
|
631
|
+
editors.forEach((editor, index) => {
|
|
632
|
+
editor.setValue(`# Editor ${index + 1}\n\nContent here...`);
|
|
633
|
+
});
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
### Custom Theme
|
|
637
|
+
|
|
638
|
+
```javascript
|
|
639
|
+
// Create custom theme
|
|
640
|
+
const darkTheme = {
|
|
641
|
+
name: 'dark-purple',
|
|
642
|
+
colors: {
|
|
643
|
+
background: '#1a1a2e',
|
|
644
|
+
text: '#eee',
|
|
645
|
+
comment: '#888',
|
|
646
|
+
keyword: '#9d65ff',
|
|
647
|
+
string: '#5fb3d4',
|
|
648
|
+
number: '#f093a3',
|
|
649
|
+
selection: '#2d2d4d',
|
|
650
|
+
border: '#333',
|
|
651
|
+
toolbar: '#16213e'
|
|
652
|
+
}
|
|
653
|
+
};
|
|
654
|
+
|
|
655
|
+
// Apply globally
|
|
656
|
+
Marzipan.setTheme(darkTheme);
|
|
657
|
+
|
|
658
|
+
// Or per instance
|
|
659
|
+
new Marzipan('#editor', {
|
|
660
|
+
theme: darkTheme
|
|
661
|
+
});
|
|
662
|
+
```
|
|
663
|
+
|
|
664
|
+
### Integration Example
|
|
665
|
+
|
|
666
|
+
```javascript
|
|
667
|
+
// Complete integration example
|
|
668
|
+
class MarkdownApp {
|
|
669
|
+
constructor() {
|
|
670
|
+
this.editors = new Marzipan('.markdown-editor', {
|
|
671
|
+
toolbar: true,
|
|
672
|
+
showStats: true,
|
|
673
|
+
autoResize: true,
|
|
674
|
+
onChange: this.handleChange.bind(this)
|
|
675
|
+
});
|
|
676
|
+
|
|
677
|
+
this.editor = this.editors[0];
|
|
678
|
+
this.setupCustomButtons();
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
handleChange(value, instance) {
|
|
682
|
+
// Auto-save
|
|
683
|
+
clearTimeout(this.saveTimeout);
|
|
684
|
+
this.saveTimeout = setTimeout(() => {
|
|
685
|
+
this.saveToServer(value);
|
|
686
|
+
}, 1000);
|
|
687
|
+
|
|
688
|
+
// Update word count display
|
|
689
|
+
this.updateWordCount(value);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
setupCustomButtons() {
|
|
693
|
+
// Add custom save button
|
|
694
|
+
const toolbar = this.editor.container.querySelector('.marzipan-toolbar');
|
|
695
|
+
const saveBtn = document.createElement('button');
|
|
696
|
+
saveBtn.textContent = '💾 Save';
|
|
697
|
+
saveBtn.onclick = () => this.saveToServer(this.editor.getValue());
|
|
698
|
+
toolbar.appendChild(saveBtn);
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
saveToServer(content) {
|
|
702
|
+
fetch('/api/save', {
|
|
703
|
+
method: 'POST',
|
|
704
|
+
headers: { 'Content-Type': 'application/json' },
|
|
705
|
+
body: JSON.stringify({ content })
|
|
706
|
+
});
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
updateWordCount(content) {
|
|
710
|
+
const words = content.split(/\s+/).filter(w => w.length > 0).length;
|
|
711
|
+
document.getElementById('word-count').textContent = `${words} words`;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
// Initialize app
|
|
716
|
+
const app = new MarkdownApp();
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
## Plugin Exports
|
|
720
|
+
|
|
721
|
+
Every plugin located in `src/plugins` publishes as `@pinkpixel/marzipan/plugins/<name>`. Each export is a factory so you can configure behaviour before passing it to the editor:
|
|
722
|
+
|
|
723
|
+
```ts
|
|
724
|
+
import { tablePlugin } from '@pinkpixel/marzipan/plugins/tablePlugin';
|
|
725
|
+
import { mermaidPlugin } from '@pinkpixel/marzipan/plugins/mermaidPlugin';
|
|
726
|
+
|
|
727
|
+
new Marzipan('#editor', {
|
|
728
|
+
plugins: [tablePlugin(), mermaidPlugin({ theme: 'dark' })],
|
|
729
|
+
});
|
|
730
|
+
```
|
|
731
|
+
|
|
732
|
+
Refer to [docs/plugins.md](./plugins.md) for the full catalogue and configuration options.
|
|
733
|
+
|
|
734
|
+
## Browser Support
|
|
735
|
+
|
|
736
|
+
Marzipan supports modern browsers:
|
|
737
|
+
|
|
738
|
+
- Chrome 60+
|
|
739
|
+
- Firefox 55+
|
|
740
|
+
- Safari 11+
|
|
741
|
+
- Edge 79+
|
|
742
|
+
|
|
743
|
+
Key requirements:
|
|
744
|
+
- CSS Custom Properties (CSS Variables)
|
|
745
|
+
- ES6 Classes
|
|
746
|
+
- Template Literals
|
|
747
|
+
- Modern DOM APIs
|
|
748
|
+
|
|
749
|
+
For older browser support, consider using appropriate polyfills and transpilation.
|