@pubwave/editor 0.5.1 → 0.5.2

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/README.md CHANGED
@@ -17,7 +17,7 @@ A Notion-level block editor built with React and Tiptap.
17
17
  - 🎨 **Text & Background Colors** - Rich color picker with recently used colors
18
18
  - 🔄 **Turn Into** - Convert blocks between different types (paragraph, headings, lists, etc.)
19
19
  - 📋 **Rich Formatting** - Bold, italic, underline, strikethrough, code, and links
20
- - 📝 **Multiple Block Types** - Paragraphs, headings, lists, quotes, code blocks, charts, and more
20
+ - 📝 **Multiple Block Types** - Paragraphs, headings, lists, quotes, code blocks, tables, charts, and more
21
21
  - 🖼️ **Image Support** - Upload images via file picker or paste from clipboard, with base64 or custom upload service
22
22
  - 📊 **Chart Support** - Interactive charts powered by Chart.js with editable data
23
23
  - 🌐 **Internationalization** - Multi-language support with English as default
@@ -84,10 +84,10 @@ function MyEditor() {
84
84
 
85
85
  ### React Versions
86
86
 
87
- | React Version | Status |
88
- |---------------|--------|
87
+ | React Version | Status |
88
+ | ------------- | ---------------------- |
89
89
  | 18.x | ✅ Tested, Recommended |
90
- | 19.x | ✅ Supported |
90
+ | 19.x | ✅ Supported |
91
91
 
92
92
  ### Peer Dependencies
93
93
 
@@ -112,26 +112,27 @@ The main React component for rendering the editor.
112
112
 
113
113
  #### Component Props
114
114
 
115
- | Prop | Type | Default | Description |
116
- |------|------|---------|-------------|
117
- | `content` | `JSONContent` | `undefined` | Initial content in Tiptap JSON format |
118
- | `editable` | `boolean` | `true` | Whether the editor is in read-only mode |
119
- | `placeholder` | `string` | `'Start writing...'` | Placeholder text shown when the editor is empty |
120
- | `theme` | `EditorTheme` | `undefined` | Theme configuration object (see [Theming](#-theming)) |
121
- | `autofocus` | `boolean \| 'start' \| 'end'` | `false` | Enable autofocus on mount. `true` or `'end'` focuses at the end, `'start'` focuses at the beginning |
122
- | `imageUpload` | `ImageUploadConfig` | `undefined` | Image upload configuration (see [Image Upload](#-image-upload)) |
123
- | `width` | `string` | `'100%'` | Editor container width. Can be a CSS value like `'100%'`, `'1200px'`, `'90vw'`, etc. Defaults to `'100%'` (full width of parent container) |
124
- | `height` | `string` | `undefined` | Editor container height. Can be a CSS value like `'500px'`, `'80vh'`, `'auto'`, etc. When set, the editor becomes a fixed-height scrollable container |
125
- | `minHeight` | `string` | `undefined` | Editor container minimum height. Can be a CSS value like `'200px'`, `'50vh'`, etc. The editor will expand with content but maintain at least this height |
126
- | `onChange` | `(content: JSONContent) => void` | `undefined` | Callback fired when the editor content changes |
127
- | `onSelectionChange` | `() => void` | `undefined` | Callback fired when the selection changes |
128
- | `onFocus` | `() => void` | `undefined` | Callback fired when the editor gains focus |
129
- | `onBlur` | `() => void` | `undefined` | Callback fired when the editor loses focus |
130
- | `onReady` | `(api: EditorAPI) => void` | `undefined` | Callback fired when the editor is ready with API access |
131
- | `className` | `string` | `undefined` | Additional CSS class for the container |
132
- | `data-testid` | `string` | `'pubwave-editor'` | Test ID for testing purposes |
115
+ | Prop | Type | Default | Description |
116
+ | ------------------- | -------------------------------- | -------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
117
+ | `content` | `JSONContent` | `undefined` | Initial content in Tiptap JSON format |
118
+ | `editable` | `boolean` | `true` | Whether the editor is in read-only mode |
119
+ | `placeholder` | `string` | `'Start writing...'` | Placeholder text shown when the editor is empty |
120
+ | `theme` | `EditorTheme` | `undefined` | Theme configuration object (see [Theming](#-theming)) |
121
+ | `autofocus` | `boolean \| 'start' \| 'end'` | `false` | Enable autofocus on mount. `true` or `'end'` focuses at the end, `'start'` focuses at the beginning |
122
+ | `imageUpload` | `ImageUploadConfig` | `undefined` | Image upload configuration (see [Image Upload](#-image-upload)) |
123
+ | `width` | `string` | `'100%'` | Editor container width. Can be a CSS value like `'100%'`, `'1200px'`, `'90vw'`, etc. Defaults to `'100%'` (full width of parent container) |
124
+ | `height` | `string` | `undefined` | Editor container height. Can be a CSS value like `'500px'`, `'80vh'`, `'auto'`, etc. When set, the editor becomes a fixed-height scrollable container |
125
+ | `minHeight` | `string` | `undefined` | Editor container minimum height. Can be a CSS value like `'200px'`, `'50vh'`, etc. The editor will expand with content but maintain at least this height |
126
+ | `onChange` | `(content: JSONContent) => void` | `undefined` | Callback fired when the editor content changes |
127
+ | `onSelectionChange` | `() => void` | `undefined` | Callback fired when the selection changes |
128
+ | `onFocus` | `() => void` | `undefined` | Callback fired when the editor gains focus |
129
+ | `onBlur` | `() => void` | `undefined` | Callback fired when the editor loses focus |
130
+ | `onReady` | `(api: EditorAPI) => void` | `undefined` | Callback fired when the editor is ready with API access |
131
+ | `className` | `string` | `undefined` | Additional CSS class for the container |
132
+ | `data-testid` | `string` | `'pubwave-editor'` | Test ID for testing purposes |
133
133
 
134
134
  For complete TypeScript type definitions, see the exported types from `@pubwave/editor`:
135
+
135
136
  - `EditorTheme` - Theme configuration
136
137
  - `EditorAPI` - Editor API interface
137
138
  - `EditorLocale` - Supported locale codes: `'en' | 'zh' | 'zh-CN' | 'ja' | 'ko' | 'fr' | 'de' | 'es' | 'pt'`
@@ -152,7 +153,7 @@ const editorRef = useRef<EditorAPI | null>(null);
152
153
  onReady={(api) => {
153
154
  editorRef.current = api;
154
155
  }}
155
- />
156
+ />;
156
157
 
157
158
  // Later, use the API
158
159
  editorRef.current?.setContent(newContent);
@@ -162,22 +163,21 @@ editorRef.current?.toggleBold();
162
163
 
163
164
  #### Available Methods
164
165
 
165
- | Method | Description | Parameters | Returns |
166
- |--------|-------------|------------|---------|
167
- | `getState()` | Get current editor state | - | `EditorState` |
168
- | `getJSON()` | Get content as JSON | - | `JSONContent` |
169
- | `getHTML()` | Get content as HTML | - | `string` |
170
- | `getText()` | Get content as plain text | - | `string` |
171
- | `setContent(content)` | Set new content | `content: JSONContent` | `void` |
172
- | `clearContent()` | Clear all content | - | `void` |
173
- | `setEditable(editable)` | Toggle read-only mode | `editable: boolean` | `void` |
174
- | `focus(position?)` | Focus the editor | `position?: 'start' \| 'end'` | `void` |
175
- | `blur()` | Blur the editor | - | `void` |
176
- | `toggleBold()` | Toggle bold formatting | - | `void` |
177
- | `toggleItalic()` | Toggle italic formatting | - | `void` |
178
- | `setLink(href)` | Set or remove a link | `href: string \| null` | `void` |
179
- | `destroy()` | Destroy the editor instance | - | `void` |
180
-
166
+ | Method | Description | Parameters | Returns |
167
+ | ----------------------- | --------------------------- | ----------------------------- | ------------- |
168
+ | `getState()` | Get current editor state | - | `EditorState` |
169
+ | `getJSON()` | Get content as JSON | - | `JSONContent` |
170
+ | `getHTML()` | Get content as HTML | - | `string` |
171
+ | `getText()` | Get content as plain text | - | `string` |
172
+ | `setContent(content)` | Set new content | `content: JSONContent` | `void` |
173
+ | `clearContent()` | Clear all content | - | `void` |
174
+ | `setEditable(editable)` | Toggle read-only mode | `editable: boolean` | `void` |
175
+ | `focus(position?)` | Focus the editor | `position?: 'start' \| 'end'` | `void` |
176
+ | `blur()` | Blur the editor | - | `void` |
177
+ | `toggleBold()` | Toggle bold formatting | - | `void` |
178
+ | `toggleItalic()` | Toggle italic formatting | - | `void` |
179
+ | `setLink(href)` | Set or remove a link | `href: string \| null` | `void` |
180
+ | `destroy()` | Destroy the editor instance | - | `void` |
181
181
 
182
182
  ---
183
183
 
@@ -206,12 +206,12 @@ Configure a custom upload handler to upload images to your server:
206
206
  handler: async (file: File) => {
207
207
  const formData = new FormData();
208
208
  formData.append('image', file);
209
-
209
+
210
210
  const response = await fetch('/api/upload', {
211
211
  method: 'POST',
212
212
  body: formData,
213
213
  });
214
-
214
+
215
215
  const data = await response.json();
216
216
  return data.url; // Return the image URL
217
217
  },
@@ -221,7 +221,6 @@ Configure a custom upload handler to upload images to your server:
221
221
  />
222
222
  ```
223
223
 
224
-
225
224
  ### Image Upload Features
226
225
 
227
226
  - **File Picker**: Use `/image` command in slash menu to open file picker
@@ -241,12 +240,12 @@ The `handler` function receives a `File` object and should return a Promise that
241
240
  // Upload to your server (Cloudinary, AWS S3, etc.)
242
241
  const formData = new FormData();
243
242
  formData.append('image', file);
244
-
243
+
245
244
  const response = await fetch('/api/upload', {
246
245
  method: 'POST',
247
246
  body: formData,
248
247
  });
249
-
248
+
250
249
  const data = await response.json();
251
250
  return data.url; // Return the image URL
252
251
  },
@@ -278,10 +277,11 @@ const theme: EditorTheme = {
278
277
  },
279
278
  };
280
279
 
281
- <PubwaveEditor theme={theme} />
280
+ <PubwaveEditor theme={theme} />;
282
281
  ```
283
282
 
284
283
  For complete `EditorTheme` interface definition, see TypeScript definitions. Key properties:
284
+
285
285
  - `colors` - Color configuration (background, text, border, primary, linkColor)
286
286
  - `locale` - Locale code for internationalization
287
287
  - `backgroundImage` - Optional background image URL
@@ -292,6 +292,7 @@ For complete `EditorTheme` interface definition, see TypeScript definitions. Key
292
292
  The editor includes several predefined themes:
293
293
 
294
294
  #### Light Theme
295
+
295
296
  ```tsx
296
297
  const lightTheme: EditorTheme = {
297
298
  colors: {
@@ -305,6 +306,7 @@ const lightTheme: EditorTheme = {
305
306
  ```
306
307
 
307
308
  #### Dark Theme
309
+
308
310
  ```tsx
309
311
  const darkTheme: EditorTheme = {
310
312
  colors: {
@@ -343,6 +345,7 @@ You can add a background image to the editor container:
343
345
  ```
344
346
 
345
347
  **Background Image Options:**
348
+
346
349
  - `size`: `'cover'` (default) | `'contain'` | custom CSS value (e.g., `'100% 100%'`)
347
350
  - `position`: CSS position value (default: `'center'`)
348
351
  - `repeat`: `'no-repeat'` (default) | `'repeat'` | `'repeat-x'` | `'repeat-y'`
@@ -357,6 +360,7 @@ Pubwave Editor supports multiple languages through the `locale` option in the th
357
360
  #### Supported Locales
358
361
 
359
362
  The following locale codes are supported:
363
+
360
364
  - `'en'` - English (default)
361
365
  - `'zh'` - Chinese
362
366
  - `'zh-CN'` - Simplified Chinese
@@ -384,10 +388,11 @@ const theme: EditorTheme = {
384
388
  },
385
389
  };
386
390
 
387
- <PubwaveEditor theme={theme} />
391
+ <PubwaveEditor theme={theme} />;
388
392
  ```
389
393
 
390
394
  The locale affects all user-facing text in the editor, including:
395
+
391
396
  - Slash command menu items and descriptions
392
397
  - Toolbar button labels and tooltips
393
398
  - Accessibility labels (ARIA)
@@ -419,21 +424,23 @@ Type `/` anywhere in the editor to open the command menu. Filter commands by typ
419
424
 
420
425
  **Available Commands:**
421
426
 
422
- | Command | Aliases | Description |
423
- |---------|---------|-------------|
424
- | `/text` or `/paragraph` | `/p`, `/text` | Plain text block |
425
- | `/heading1` | `/h1`, `/title` | Large section heading |
426
- | `/heading2` | `/h2`, `/subtitle` | Medium section heading |
427
- | `/heading3` | `/h3` | Small section heading |
428
- | `/bullet` | `/ul`, `/bullet`, `/-` | Bulleted list |
429
- | `/numbered` | `/ol`, `/numbered`, `/1.` | Numbered list |
430
- | `/todo` | `/task`, `/checkbox`, `/[]` | To-do list with checkboxes |
431
- | `/image` | `/img`, `/picture`, `/photo`, `/pic` | Upload or paste an image |
432
- | `/quote` | `/blockquote`, `/>` | Quote block |
433
- | `/code` | `/pre`, `/snippet`, `/``` | Code block |
434
- | `/divider` | `/hr`, `/line`, `/---` | Horizontal divider |
427
+ | Command | Aliases | Description |
428
+ | ----------------------- | ------------------------------------ | -------------------------- |
429
+ | `/text` or `/paragraph` | `/p`, `/text` | Plain text block |
430
+ | `/heading1` | `/h1`, `/title` | Large section heading |
431
+ | `/heading2` | `/h2`, `/subtitle` | Medium section heading |
432
+ | `/heading3` | `/h3` | Small section heading |
433
+ | `/bullet` | `/ul`, `/bullet`, `/-` | Bulleted list |
434
+ | `/numbered` | `/ol`, `/numbered`, `/1.` | Numbered list |
435
+ | `/todo` | `/task`, `/checkbox`, `/[]` | To-do list with checkboxes |
436
+ | `/image` | `/img`, `/picture`, `/photo`, `/pic` | Upload or paste an image |
437
+ | `/quote` | `/blockquote`, `/>` | Quote block |
438
+ | `/code` | `/pre`, `/snippet`, `/``` | Code block |
439
+ | `/divider` | `/hr`, `/line`, `/---` | Horizontal divider |
440
+ | `/table` | `/grid`, `/tbl` | Insert a table |
435
441
 
436
442
  **Usage:**
443
+
437
444
  1. Type `/` to open the menu
438
445
  2. Type to filter (e.g., `/h1` for heading 1, `/img` for image)
439
446
  3. Press `Enter` or click to select
@@ -445,6 +452,7 @@ Type `/` anywhere in the editor to open the command menu. Filter commands by typ
445
452
  The toolbar appears automatically when you select text, providing quick access to formatting options.
446
453
 
447
454
  **Available Actions:**
455
+
448
456
  - **Turn Into** - Convert block type (Paragraph, Heading 1-3, Bulleted List, Numbered List)
449
457
  - **Bold** (`Cmd/Ctrl+B`) - Make text bold
450
458
  - **Italic** (`Cmd/Ctrl+I`) - Make text italic
@@ -464,6 +472,7 @@ The editor supports the following block types:
464
472
  - **Bulleted List** - Unordered list with bullets
465
473
  - **Numbered List** - Ordered list with numbers
466
474
  - **Task List** - Checklist with checkboxes
475
+ - **Table** - Table block (rows/columns with header)
467
476
  - **Image** - Image block (supports base64 or URL)
468
477
  - **Chart** - Interactive chart powered by Chart.js (bar, line, pie, doughnut, radar, polar area)
469
478
  - **Blockquote** - Quote block
@@ -472,18 +481,18 @@ The editor supports the following block types:
472
481
 
473
482
  ### Keyboard Shortcuts
474
483
 
475
- | Shortcut | Action |
476
- |----------|--------|
477
- | `Cmd/Ctrl+B` | Toggle bold |
478
- | `Cmd/Ctrl+I` | Toggle italic |
479
- | `Cmd/Ctrl+Z` | Undo |
480
- | `Cmd/Ctrl+Shift+Z` | Redo |
481
- | `Cmd/Ctrl+A` | Select all |
482
- | `Enter` | Create new block |
483
- | `Arrow Up/Down` | Navigate between blocks |
484
- | `Shift+Arrow` | Select text |
485
- | `/` | Open slash command menu |
486
- | `Escape` | Close menus/cancel drag |
484
+ | Shortcut | Action |
485
+ | ------------------ | ----------------------- |
486
+ | `Cmd/Ctrl+B` | Toggle bold |
487
+ | `Cmd/Ctrl+I` | Toggle italic |
488
+ | `Cmd/Ctrl+Z` | Undo |
489
+ | `Cmd/Ctrl+Shift+Z` | Redo |
490
+ | `Cmd/Ctrl+A` | Select all |
491
+ | `Enter` | Create new block |
492
+ | `Arrow Up/Down` | Navigate between blocks |
493
+ | `Shift+Arrow` | Select text |
494
+ | `/` | Open slash command menu |
495
+ | `Escape` | Close menus/cancel drag |
487
496
 
488
497
  ### Drag & Drop
489
498
 
@@ -495,6 +504,7 @@ The editor supports the following block types:
495
504
  ### Color Picker
496
505
 
497
506
  The color picker provides:
507
+
498
508
  - **Text Colors** - 10 predefined text colors
499
509
  - **Background Colors** - 10 predefined background colors
500
510
  - **Recently Used** - Global history of recently used colors (persists across sessions)
@@ -536,9 +546,9 @@ You can control the editor's height using the `height` and `minHeight` props:
536
546
  <PubwaveEditor minHeight="300px" />
537
547
 
538
548
  // Combined: fixed height with minimum fallback
539
- <PubwaveEditor
540
- height="600px"
541
- minHeight="400px"
549
+ <PubwaveEditor
550
+ height="600px"
551
+ minHeight="400px"
542
552
  />
543
553
 
544
554
  // Using viewport units
@@ -546,6 +556,7 @@ You can control the editor's height using the `height` and `minHeight` props:
546
556
  ```
547
557
 
548
558
  **Important Notes:**
559
+
549
560
  - The editor has default padding of **96px top and bottom** (192px total). Your `height` value should account for this padding to ensure content is visible.
550
561
  - For example, `height="100px"` would leave no space for content (100px - 192px padding = negative space).
551
562
  - **Recommended minimum height:** At least `300px` for desktop to accommodate padding and content.
@@ -563,7 +574,7 @@ const editorRef = useRef<EditorAPI | null>(null);
563
574
  onReady={(api) => {
564
575
  editorRef.current = api;
565
576
  }}
566
- />
577
+ />;
567
578
 
568
579
  // Set content programmatically
569
580
  editorRef.current?.setContent({
@@ -614,13 +625,11 @@ editorRef.current?.setLink('https://example.com');
614
625
  ### Read-only Mode
615
626
 
616
627
  ```tsx
617
- <PubwaveEditor
618
- editable={false}
619
- content={readOnlyContent}
620
- />
628
+ <PubwaveEditor editable={false} content={readOnlyContent} />
621
629
  ```
622
630
 
623
631
  In read-only mode:
632
+
624
633
  - All editing affordances are hidden
625
634
  - Toolbar does not appear
626
635
  - Slash commands are disabled
@@ -662,6 +671,7 @@ The editor includes support for interactive charts powered by Chart.js. Charts a
662
671
  ### Chart Types
663
672
 
664
673
  Supported chart types:
674
+
665
675
  - **Bar Chart** - Vertical/horizontal bars for comparisons
666
676
  - **Line Chart** - Data trends over time
667
677
  - **Pie Chart** - Proportional data representation
@@ -685,13 +695,15 @@ const contentWithChart: JSONContent = {
685
695
  type: 'bar',
686
696
  data: {
687
697
  labels: ['January', 'February', 'March', 'April'],
688
- datasets: [{
689
- label: 'Sales',
690
- data: [65, 59, 80, 81],
691
- backgroundColor: 'rgba(59, 130, 246, 0.7)',
692
- borderColor: 'rgba(59, 130, 246, 1)',
693
- borderWidth: 2,
694
- }],
698
+ datasets: [
699
+ {
700
+ label: 'Sales',
701
+ data: [65, 59, 80, 81],
702
+ backgroundColor: 'rgba(59, 130, 246, 0.7)',
703
+ borderColor: 'rgba(59, 130, 246, 1)',
704
+ borderWidth: 2,
705
+ },
706
+ ],
695
707
  },
696
708
  options: {
697
709
  responsive: true,
@@ -714,7 +726,7 @@ const contentWithChart: JSONContent = {
714
726
  ],
715
727
  };
716
728
 
717
- <PubwaveEditor content={contentWithChart} />
729
+ <PubwaveEditor content={contentWithChart} />;
718
730
  ```
719
731
 
720
732
  ### Chart Features
@@ -765,6 +777,7 @@ interface ChartNodeData {
765
777
  ### Chart Editing
766
778
 
767
779
  When in editable mode:
780
+
768
781
  1. Hover over a chart to reveal the edit button
769
782
  2. Click the edit button to open the chart editor modal
770
783
  3. Modify chart type, title, labels, datasets, and appearance options
@@ -772,51 +785,52 @@ When in editable mode:
772
785
 
773
786
  ---
774
787
 
775
-
776
-
777
-
778
-
779
-
780
788
  ## 🐛 Troubleshooting
781
789
 
782
790
  ### Common Issues
783
791
 
784
792
  **Q: Styles are not applied**
793
+
785
794
  - Ensure you've imported the CSS: `import '@pubwave/editor/style.css'`
786
795
  - Check that CSS custom properties are defined
787
796
 
788
797
  **Q: Slash commands don't work**
798
+
789
799
  - Ensure the editor is in editable mode
790
800
  - Check that you're typing `/` in a text block (not in code blocks)
791
801
 
792
802
  **Q: Toolbar doesn't appear**
803
+
793
804
  - Toolbar only appears when text is selected
794
805
  - Make sure you have a non-empty selection
795
806
 
796
807
  **Q: Colors don't persist**
808
+
797
809
  - Text and background colors are stored as marks in the content
798
810
  - Ensure you're saving the full JSON content, not just HTML
799
811
 
800
812
  **Q: Image upload doesn't work**
813
+
801
814
  - Check that `imageUpload.handler` returns a valid URL string
802
815
  - Verify file size is within `maxSize` limit
803
816
  - Check browser console for error messages
804
817
  - If custom upload fails, editor will automatically fall back to base64
805
818
 
806
819
  **Q: Charts don't render**
820
+
807
821
  - Ensure `chart.js` is installed: `npm install chart.js` (optional peer dependency)
808
822
  - Check that Chart.js is compatible (v4.x or v5.x)
809
823
  - Verify chart data structure is correct
810
824
  - Check browser console for errors
811
825
 
812
826
  **Q: Chart colors don't match theme**
827
+
813
828
  - Charts use CSS variables for colors that adapt to theme changes
814
829
  - Ensure CSS custom properties are defined: `--pubwave-text`, `--pubwave-text-muted`, `--pubwave-border`
815
830
  - Chart colors will automatically update when theme changes
816
831
 
817
832
  ---
818
833
 
819
-
820
834
  ## 📄 License
821
835
 
822
836
  MIT © [Pubwave](https://github.com/pubwave)