@pubwave/editor 0.1.1-alpha.0

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 ADDED
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Pubwave
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
22
+
package/README.md ADDED
@@ -0,0 +1,661 @@
1
+ # @pubwave/editor
2
+
3
+ A Notion-level block editor built with React and Tiptap.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@pubwave/editor.svg)](https://www.npmjs.com/package/@pubwave/editor)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+
8
+ ## ✨ Features
9
+
10
+ - 📝 **Premium Writing Experience** - Fluid, responsive editing with natural Enter-driven writing flow
11
+ - ✨ **Selection-Only Toolbar** - Contextual formatting that appears only when you select text
12
+ - 🎯 **Block Drag & Drop** - Intuitive reordering with clear visual feedback
13
+ - 🎨 **Theme Tokens** - Full styling control via CSS custom properties
14
+ - ⚡ **SSR Safe** - Works with Next.js and other SSR frameworks
15
+ - 📦 **Lightweight** - Only ships what you need (React + Tiptap peer dependencies)
16
+ - ⌨️ **Slash Commands** - Type `/` to quickly insert blocks and formatting
17
+ - 🎨 **Text & Background Colors** - Rich color picker with recently used colors
18
+ - 🔄 **Turn Into** - Convert blocks between different types (paragraph, headings, lists, etc.)
19
+ - 📋 **Rich Formatting** - Bold, italic, underline, strikethrough, code, and links
20
+ - 📝 **Multiple Block Types** - Paragraphs, headings, lists, quotes, code blocks, and more
21
+ - 🖼️ **Image Support** - Upload images via file picker or paste from clipboard, with base64 or custom upload service
22
+ - 🌐 **Internationalization** - Multi-language support with English as default
23
+
24
+ ---
25
+
26
+ ## 📦 Installation
27
+
28
+ ```bash
29
+ npm install @pubwave/editor
30
+ # or
31
+ yarn add @pubwave/editor
32
+ # or
33
+ pnpm add @pubwave/editor
34
+ ```
35
+
36
+ ---
37
+
38
+ ## 🚀 Quick Start
39
+
40
+ ```tsx
41
+ import { PubwaveEditor } from '@pubwave/editor';
42
+ import '@pubwave/editor/index.css';
43
+
44
+ function MyEditor() {
45
+ const [content, setContent] = useState({
46
+ type: 'doc',
47
+ content: [
48
+ {
49
+ type: 'paragraph',
50
+ content: [{ type: 'text', text: 'Start writing...' }],
51
+ },
52
+ ],
53
+ });
54
+
55
+ return (
56
+ <PubwaveEditor
57
+ content={content}
58
+ onChange={(newContent) => setContent(newContent)}
59
+ />
60
+ );
61
+ }
62
+ ```
63
+
64
+ ---
65
+
66
+ ## 📋 Requirements
67
+
68
+ ### React Versions
69
+
70
+ | React Version | Status |
71
+ |---------------|--------|
72
+ | 18.x | ✅ Tested, Recommended |
73
+ | 19.x | ✅ Supported |
74
+
75
+ ### Browser Support
76
+
77
+ - Chrome (latest)
78
+ - Firefox (latest)
79
+ - Safari (latest)
80
+ - Edge (latest)
81
+
82
+ ---
83
+
84
+ ## 📖 API Reference
85
+
86
+ ### `PubwaveEditor` Component
87
+
88
+ The main React component for rendering the editor.
89
+
90
+ #### Component Props
91
+
92
+ | Prop | Type | Default | Description |
93
+ |------|------|---------|-------------|
94
+ | `content` | `JSONContent` | `undefined` | Initial content in Tiptap JSON format |
95
+ | `editable` | `boolean` | `true` | Whether the editor is in read-only mode |
96
+ | `placeholder` | `string` | `'Start writing...'` | Placeholder text shown when the editor is empty |
97
+ | `theme` | `EditorTheme` | `undefined` | Theme configuration object (see [Theming](#-theming)) |
98
+ | `autofocus` | `boolean \| 'start' \| 'end'` | `false` | Enable autofocus on mount. `true` or `'end'` focuses at the end, `'start'` focuses at the beginning |
99
+ | `imageUpload` | `ImageUploadConfig` | `undefined` | Image upload configuration (see [Image Upload](#-image-upload)) |
100
+ | `width` | `string` | `'100%'` | Editor container width. Can be a CSS value like `'100%'`, `'1200px'`, `'90vw'`, etc. Defaults to `'100%'` (full width of parent container) |
101
+ | `onChange` | `(content: JSONContent) => void` | `undefined` | Callback fired when the editor content changes |
102
+ | `onSelectionChange` | `() => void` | `undefined` | Callback fired when the selection changes |
103
+ | `onFocus` | `() => void` | `undefined` | Callback fired when the editor gains focus |
104
+ | `onBlur` | `() => void` | `undefined` | Callback fired when the editor loses focus |
105
+ | `onReady` | `(api: EditorAPI) => void` | `undefined` | Callback fired when the editor is ready with API access |
106
+ | `className` | `string` | `undefined` | Additional CSS class for the container |
107
+ | `data-testid` | `string` | `'pubwave-editor'` | Test ID for testing purposes |
108
+
109
+ For complete TypeScript type definitions, see the exported types from `@pubwave/editor`:
110
+ - `EditorTheme` - Theme configuration
111
+ - `EditorAPI` - Editor API interface
112
+ - `EditorLocale` - Supported locale codes: `'en' | 'zh' | 'zh-CN' | 'ja' | 'ko' | 'fr' | 'de' | 'es' | 'pt'`
113
+ - `ImageUploadConfig` - Image upload configuration
114
+
115
+ ### `EditorAPI` Methods
116
+
117
+ The editor exposes a public API through the `ref` prop or `onReady` callback:
118
+
119
+ ```tsx
120
+ import { useRef } from 'react';
121
+ import type { EditorAPI } from '@pubwave/editor';
122
+
123
+ const editorRef = useRef<EditorAPI | null>(null);
124
+
125
+ <PubwaveEditor
126
+ ref={editorRef}
127
+ onReady={(api) => {
128
+ editorRef.current = api;
129
+ }}
130
+ />
131
+
132
+ // Later, use the API
133
+ editorRef.current?.setContent(newContent);
134
+ editorRef.current?.getJSON();
135
+ editorRef.current?.toggleBold();
136
+ ```
137
+
138
+ #### Available Methods
139
+
140
+ | Method | Description | Parameters | Returns |
141
+ |--------|-------------|------------|---------|
142
+ | `getState()` | Get current editor state | - | `EditorState` |
143
+ | `getJSON()` | Get content as JSON | - | `JSONContent` |
144
+ | `getHTML()` | Get content as HTML | - | `string` |
145
+ | `getText()` | Get content as plain text | - | `string` |
146
+ | `setContent(content)` | Set new content | `content: JSONContent` | `void` |
147
+ | `clearContent()` | Clear all content | - | `void` |
148
+ | `setEditable(editable)` | Toggle read-only mode | `editable: boolean` | `void` |
149
+ | `focus(position?)` | Focus the editor | `position?: 'start' \| 'end'` | `void` |
150
+ | `blur()` | Blur the editor | - | `void` |
151
+ | `toggleBold()` | Toggle bold formatting | - | `void` |
152
+ | `toggleItalic()` | Toggle italic formatting | - | `void` |
153
+ | `setLink(href)` | Set or remove a link | `href: string \| null` | `void` |
154
+ | `destroy()` | Destroy the editor instance | - | `void` |
155
+
156
+
157
+ ---
158
+
159
+ ## 🖼️ Image Upload
160
+
161
+ The editor supports two image upload modes:
162
+
163
+ 1. **Base64 (Default)** - Images are converted to base64 data URLs and embedded directly
164
+ 2. **Custom Upload Service** - Images are uploaded to your server and URLs are stored
165
+
166
+ ### Base64 Mode (Default)
167
+
168
+ By default, images are converted to base64. No configuration needed:
169
+
170
+ ```tsx
171
+ <PubwaveEditor />
172
+ ```
173
+
174
+ ### Custom Upload Service
175
+
176
+ Configure a custom upload handler to upload images to your server:
177
+
178
+ ```tsx
179
+ <PubwaveEditor
180
+ imageUpload={{
181
+ handler: async (file: File) => {
182
+ const formData = new FormData();
183
+ formData.append('image', file);
184
+
185
+ const response = await fetch('/api/upload', {
186
+ method: 'POST',
187
+ body: formData,
188
+ });
189
+
190
+ const data = await response.json();
191
+ return data.url; // Return the image URL
192
+ },
193
+ maxSize: 5 * 1024 * 1024, // 5MB (optional, default: 10MB)
194
+ accept: ['image/jpeg', 'image/png', 'image/webp'], // Optional, default: ['image/*']
195
+ }}
196
+ />
197
+ ```
198
+
199
+
200
+ ### Image Upload Features
201
+
202
+ - **File Picker**: Use `/image` command in slash menu to open file picker
203
+ - **Paste Support**: Paste images from clipboard (Ctrl/Cmd+V)
204
+ - **Automatic Fallback**: If custom upload fails, automatically falls back to base64
205
+ - **File Validation**: Validates file type and size before upload
206
+ - **Error Handling**: Logs errors to console if upload fails
207
+
208
+ ### Custom Upload Service
209
+
210
+ The `handler` function receives a `File` object and should return a Promise that resolves to the image URL. The editor will automatically fall back to base64 if the upload fails.
211
+
212
+ ```tsx
213
+ <PubwaveEditor
214
+ imageUpload={{
215
+ handler: async (file: File) => {
216
+ // Upload to your server (Cloudinary, AWS S3, etc.)
217
+ const formData = new FormData();
218
+ formData.append('image', file);
219
+
220
+ const response = await fetch('/api/upload', {
221
+ method: 'POST',
222
+ body: formData,
223
+ });
224
+
225
+ const data = await response.json();
226
+ return data.url; // Return the image URL
227
+ },
228
+ maxSize: 10 * 1024 * 1024, // 10MB (optional)
229
+ accept: ['image/jpeg', 'image/png', 'image/webp'], // Optional
230
+ }}
231
+ />
232
+ ```
233
+
234
+ ---
235
+
236
+ ## 🎨 Theming
237
+
238
+ Pubwave Editor supports full theme customization through the `theme` prop. You can customize colors, backgrounds, and more.
239
+
240
+ ### Basic Theme Configuration
241
+
242
+ ```tsx
243
+ import { PubwaveEditor } from '@pubwave/editor';
244
+ import type { EditorTheme } from '@pubwave/editor';
245
+
246
+ const theme: EditorTheme = {
247
+ colors: {
248
+ background: '#ffffff',
249
+ text: '#1f2937',
250
+ textMuted: '#6b7280',
251
+ border: '#e5e7eb',
252
+ primary: '#3b82f6',
253
+ },
254
+ };
255
+
256
+ <PubwaveEditor theme={theme} />
257
+ ```
258
+
259
+ For complete `EditorTheme` interface definition, see TypeScript definitions. Key properties:
260
+ - `colors` - Color configuration (background, text, border, primary, linkColor)
261
+ - `locale` - Locale code for internationalization
262
+ - `backgroundImage` - Optional background image URL
263
+ - `backgroundImageOptions` - Background image display options (size, position, repeat, attachment)
264
+
265
+ ### Predefined Themes
266
+
267
+ The editor includes several predefined themes:
268
+
269
+ #### Light Theme
270
+ ```tsx
271
+ const lightTheme: EditorTheme = {
272
+ colors: {
273
+ background: 'linear-gradient(135deg, #ffffff 0%, #f8fafc 100%)',
274
+ text: '#1f2937',
275
+ textMuted: '#6b7280',
276
+ border: '#e5e7eb',
277
+ primary: '#3b82f6',
278
+ },
279
+ };
280
+ ```
281
+
282
+ #### Dark Theme
283
+ ```tsx
284
+ const darkTheme: EditorTheme = {
285
+ colors: {
286
+ background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 100%)',
287
+ text: '#f1f5f9',
288
+ textMuted: '#94a3b8',
289
+ border: '#334155',
290
+ primary: '#60a5fa',
291
+ linkColor: '#3b82f6',
292
+ },
293
+ };
294
+ ```
295
+
296
+ **Other themes:** Violet, Rose, Sky (gradient themes).
297
+
298
+ ### Background Image
299
+
300
+ You can add a background image to the editor container:
301
+
302
+ ```tsx
303
+ <PubwaveEditor
304
+ theme={{
305
+ colors: {
306
+ background: '#ffffff',
307
+ text: '#1f2937',
308
+ },
309
+ backgroundImage: 'https://example.com/background.jpg',
310
+ backgroundImageOptions: {
311
+ size: 'cover',
312
+ position: 'center',
313
+ repeat: 'no-repeat',
314
+ attachment: 'fixed',
315
+ },
316
+ }}
317
+ />
318
+ ```
319
+
320
+ **Background Image Options:**
321
+ - `size`: `'cover'` (default) | `'contain'` | custom CSS value (e.g., `'100% 100%'`)
322
+ - `position`: CSS position value (default: `'center'`)
323
+ - `repeat`: `'no-repeat'` (default) | `'repeat'` | `'repeat-x'` | `'repeat-y'`
324
+ - `attachment`: `'scroll'` (default) | `'fixed'` | `'local'`
325
+
326
+ **Note:** The background image will be layered on top of the background color. If you want the image to be the only background, set `background: 'transparent'` in the colors.
327
+
328
+ ### Internationalization (i18n)
329
+
330
+ Pubwave Editor supports multiple languages through the `locale` option in the theme configuration. The editor defaults to English (`'en'`).
331
+
332
+ #### Supported Locales
333
+
334
+ The following locale codes are supported:
335
+ - `'en'` - English (default)
336
+ - `'zh'` - Chinese
337
+ - `'zh-CN'` - Simplified Chinese
338
+ - `'ja'` - Japanese
339
+ - `'ko'` - Korean
340
+ - `'fr'` - French
341
+ - `'de'` - German
342
+ - `'es'` - Spanish
343
+ - `'pt'` - Portuguese
344
+
345
+ **Note:** Currently, only English translations are fully implemented. Other languages will fall back to English. The framework is ready for future language additions.
346
+
347
+ #### Setting the Locale
348
+
349
+ ```tsx
350
+ import { PubwaveEditor } from '@pubwave/editor';
351
+ import type { EditorTheme } from '@pubwave/editor';
352
+
353
+ const theme: EditorTheme = {
354
+ locale: 'en', // Default, can be set to any supported locale
355
+ colors: {
356
+ background: '#ffffff',
357
+ text: '#1f2937',
358
+ primary: '#3b82f6',
359
+ },
360
+ };
361
+
362
+ <PubwaveEditor theme={theme} />
363
+ ```
364
+
365
+ The locale affects all user-facing text in the editor, including:
366
+ - Slash command menu items and descriptions
367
+ - Toolbar button labels and tooltips
368
+ - Accessibility labels (ARIA)
369
+ - Block type labels
370
+ - Placeholder text
371
+
372
+ ### CSS Custom Properties
373
+
374
+ The editor also uses CSS custom properties for styling. Define these in your CSS:
375
+
376
+ ```css
377
+ :root {
378
+ --pubwave-bg: #ffffff;
379
+ --pubwave-text: #1a1a1a;
380
+ --pubwave-text-muted: #6b7280;
381
+ --pubwave-border: #e5e7eb;
382
+ --pubwave-primary: #3b82f6;
383
+ --pubwave-hover: rgba(0, 0, 0, 0.05);
384
+ }
385
+ ```
386
+
387
+ ---
388
+
389
+ ## 🎯 Core Features
390
+
391
+ ### Slash Commands
392
+
393
+ Type `/` anywhere in the editor to open the command menu. Filter commands by typing keywords.
394
+
395
+ **Available Commands:**
396
+
397
+ | Command | Aliases | Description |
398
+ |---------|---------|-------------|
399
+ | `/text` or `/paragraph` | `/p`, `/text` | Plain text block |
400
+ | `/heading1` | `/h1`, `/title` | Large section heading |
401
+ | `/heading2` | `/h2`, `/subtitle` | Medium section heading |
402
+ | `/heading3` | `/h3` | Small section heading |
403
+ | `/bullet` | `/ul`, `/bullet`, `/-` | Bulleted list |
404
+ | `/numbered` | `/ol`, `/numbered`, `/1.` | Numbered list |
405
+ | `/todo` | `/task`, `/checkbox`, `/[]` | To-do list with checkboxes |
406
+ | `/image` | `/img`, `/picture`, `/photo`, `/pic` | Upload or paste an image |
407
+ | `/quote` | `/blockquote`, `/>` | Quote block |
408
+ | `/code` | `/pre`, `/snippet`, `/``` | Code block |
409
+ | `/divider` | `/hr`, `/line`, `/---` | Horizontal divider |
410
+
411
+ **Usage:**
412
+ 1. Type `/` to open the menu
413
+ 2. Type to filter (e.g., `/h1` for heading 1, `/img` for image)
414
+ 3. Press `Enter` or click to select
415
+ 4. Use `ArrowUp`/`ArrowDown` to navigate
416
+ 5. Press `Escape` to close
417
+
418
+ ### Selection Toolbar
419
+
420
+ The toolbar appears automatically when you select text, providing quick access to formatting options.
421
+
422
+ **Available Actions:**
423
+ - **Turn Into** - Convert block type (Paragraph, Heading 1-3, Bulleted List, Numbered List)
424
+ - **Bold** (`Cmd/Ctrl+B`) - Make text bold
425
+ - **Italic** (`Cmd/Ctrl+I`) - Make text italic
426
+ - **Underline** - Underline text
427
+ - **Strikethrough** - Strikethrough text
428
+ - **Code** - Inline code formatting
429
+ - **Link** - Add or edit link
430
+ - **Text Color** - Change text color (with recently used colors)
431
+ - **Background Color** - Change background color (with recently used colors)
432
+
433
+ ### Block Types
434
+
435
+ The editor supports the following block types:
436
+
437
+ - **Paragraph** - Default text block
438
+ - **Heading 1-3** - Section headings
439
+ - **Bulleted List** - Unordered list with bullets
440
+ - **Numbered List** - Ordered list with numbers
441
+ - **Task List** - Checklist with checkboxes
442
+ - **Image** - Image block (supports base64 or URL)
443
+ - **Blockquote** - Quote block
444
+ - **Code Block** - Code snippet with syntax highlighting
445
+ - **Horizontal Rule** - Divider line
446
+
447
+ ### Keyboard Shortcuts
448
+
449
+ | Shortcut | Action |
450
+ |----------|--------|
451
+ | `Cmd/Ctrl+B` | Toggle bold |
452
+ | `Cmd/Ctrl+I` | Toggle italic |
453
+ | `Cmd/Ctrl+Z` | Undo |
454
+ | `Cmd/Ctrl+Shift+Z` | Redo |
455
+ | `Cmd/Ctrl+A` | Select all |
456
+ | `Enter` | Create new block |
457
+ | `Arrow Up/Down` | Navigate between blocks |
458
+ | `Shift+Arrow` | Select text |
459
+ | `/` | Open slash command menu |
460
+ | `Escape` | Close menus/cancel drag |
461
+
462
+ ### Drag & Drop
463
+
464
+ - **Drag Handle** - Appears on hover at the left edge of blocks
465
+ - **Visual Feedback** - Clear drop indicators show where blocks will be placed
466
+ - **Cancel** - Press `Escape` to cancel dragging
467
+ - **Multi-block Selection** - Select multiple blocks to drag together
468
+
469
+ ### Color Picker
470
+
471
+ The color picker provides:
472
+ - **Text Colors** - 10 predefined text colors
473
+ - **Background Colors** - 10 predefined background colors
474
+ - **Recently Used** - Global history of recently used colors (persists across sessions)
475
+ - **Visual Distinction** - Background colors shown as solid circles, text colors shown with 'A' icon
476
+ - **Tooltips** - Hover over any color to see its name
477
+ - **Smart Positioning** - Automatically positions above or below based on available space
478
+
479
+ ---
480
+
481
+ ## 🔧 Advanced Usage
482
+
483
+ ### Setting Editor Width
484
+
485
+ By default, the editor takes 100% of the parent container width. You can customize the width using the `width` prop:
486
+
487
+ ```tsx
488
+ // Full width (default)
489
+ <PubwaveEditor width="100%" />
490
+
491
+ // Fixed width
492
+ <PubwaveEditor width="1200px" />
493
+
494
+ // Responsive width
495
+ <PubwaveEditor width="90vw" />
496
+ <PubwaveEditor width="calc(100% - 40px)" />
497
+ ```
498
+
499
+ The `width` prop accepts any valid CSS width value. When set, it will override the default `max-width` constraint.
500
+
501
+ ### Programmatic Content Manipulation
502
+
503
+ ```tsx
504
+ const editorRef = useRef<EditorAPI | null>(null);
505
+
506
+ <PubwaveEditor
507
+ ref={editorRef}
508
+ onReady={(api) => {
509
+ editorRef.current = api;
510
+ }}
511
+ />
512
+
513
+ // Set content programmatically
514
+ editorRef.current?.setContent({
515
+ type: 'doc',
516
+ content: [
517
+ {
518
+ type: 'heading',
519
+ attrs: { level: 1 },
520
+ content: [{ type: 'text', text: 'Hello World' }],
521
+ },
522
+ ],
523
+ });
524
+
525
+ // Get content
526
+ const json = editorRef.current?.getJSON();
527
+ const html = editorRef.current?.getHTML();
528
+ const text = editorRef.current?.getText();
529
+
530
+ // Apply formatting
531
+ editorRef.current?.toggleBold();
532
+ editorRef.current?.setLink('https://example.com');
533
+ ```
534
+
535
+ ### Event Handling
536
+
537
+ ```tsx
538
+ <PubwaveEditor
539
+ onChange={(content) => {
540
+ // Content changed
541
+ console.log('New content:', content);
542
+ }}
543
+ onSelectionChange={() => {
544
+ // Selection changed (toolbar may appear/disappear)
545
+ }}
546
+ onFocus={() => {
547
+ // Editor gained focus
548
+ }}
549
+ onBlur={() => {
550
+ // Editor lost focus
551
+ }}
552
+ onReady={(api) => {
553
+ // Editor is ready, API is available
554
+ console.log('Editor ready:', api);
555
+ }}
556
+ />
557
+ ```
558
+
559
+ ### Read-only Mode
560
+
561
+ ```tsx
562
+ <PubwaveEditor
563
+ editable={false}
564
+ content={readOnlyContent}
565
+ />
566
+ ```
567
+
568
+ In read-only mode:
569
+ - All editing affordances are hidden
570
+ - Toolbar does not appear
571
+ - Slash commands are disabled
572
+ - Drag handles are hidden
573
+ - Content is still selectable and copyable
574
+
575
+ ### Custom Slash Commands
576
+
577
+ You can extend the editor with custom slash commands:
578
+
579
+ ```tsx
580
+ import { PubwaveEditor } from '@pubwave/editor';
581
+ import type { SlashCommand } from '@pubwave/editor';
582
+
583
+ const customCommands: SlashCommand[] = [
584
+ {
585
+ id: 'custom-block',
586
+ title: 'Custom Block',
587
+ description: 'Insert a custom block',
588
+ icon: <CustomIcon />,
589
+ aliases: ['custom', 'cb'],
590
+ group: 'basic',
591
+ action: (editor) => {
592
+ // Your custom action
593
+ },
594
+ },
595
+ ];
596
+
597
+ // Note: Custom slash commands require access to internal APIs
598
+ // This is an advanced feature - see source code for implementation details
599
+ ```
600
+
601
+ ---
602
+
603
+ ## ⚡ SSR Integration (Next.js)
604
+
605
+ The library is SSR-safe and can be imported server-side without errors. The editor component itself renders client-side only.
606
+
607
+ ```tsx
608
+ 'use client';
609
+
610
+ import { PubwaveEditor } from '@pubwave/editor';
611
+ import '@pubwave/editor/index.css';
612
+
613
+ export default function EditorComponent() {
614
+ return <PubwaveEditor />;
615
+ }
616
+ ```
617
+
618
+ ---
619
+
620
+
621
+ ## 🐛 Troubleshooting
622
+
623
+ ### Common Issues
624
+
625
+ **Q: The editor doesn't render in Next.js SSR**
626
+ - Make sure you're using `'use client'` directive
627
+ - Ensure the component is marked as a client component
628
+
629
+ **Q: Styles are not applied**
630
+ - Ensure you've imported the CSS: `import '@pubwave/editor/index.css'`
631
+ - Check that CSS custom properties are defined
632
+
633
+ **Q: Slash commands don't work**
634
+ - Ensure the editor is in editable mode
635
+ - Check that you're typing `/` in a text block (not in code blocks)
636
+
637
+ **Q: Toolbar doesn't appear**
638
+ - Toolbar only appears when text is selected
639
+ - Make sure you have a non-empty selection
640
+
641
+ **Q: Colors don't persist**
642
+ - Text and background colors are stored as marks in the content
643
+ - Ensure you're saving the full JSON content, not just HTML
644
+
645
+ **Q: Image upload doesn't work**
646
+ - Check that `imageUpload.handler` returns a valid URL string
647
+ - Verify file size is within `maxSize` limit
648
+ - Check browser console for error messages
649
+ - If custom upload fails, editor will automatically fall back to base64
650
+
651
+ ---
652
+
653
+ ## 🤝 Contributing
654
+
655
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) for development setup and guidelines.
656
+
657
+ ---
658
+
659
+ ## 📄 License
660
+
661
+ MIT © [Pubwave](https://github.com/pubwave)