Skip to content

Commit 1e55642

Browse files
moutonjeremyJeremy Mouton
andauthored
Add editor enhancements with undo/redo, media menu, and checklist support (#12)
* feat: add undo/redo buttons and media menu to the editor; enhance sample document with checklist and embed examples * feat: enhance SlashMenu with custom items, item order, and hiding options * feat: add customization options for BubbleMenu, SlashMenu, and ColorPicker components * feat: add new plugins for keyboard shortcuts, checklist, media menu, and history management * feat: add support for check list items and image blocks in blockToNode conversion * feat: add support for check list items in nodeToBlock conversion * feat: add undo and redo functionality to OpenBlockEditor * feat: enhance bubble menu visibility logic for media nodes * feat: implement checklist plugin for handling checkbox interactions and keyboard behavior * feat: add keyboard shortcuts, checklist, and media menu plugins to createPlugins * feat: enhance drag/drop plugin to support positioning for blocks nested in lists * feat: re-export history functions and add media menu plugin to core plugins * feat: add keyboard shortcuts plugin for customizable formatting and block operations * feat: add media menu plugin for handling image and embed node selections * feat: implement MediaMenu component for floating media editing toolbar * feat: update exports in index.ts to include additional properties for menus and color picker * feat: enhance ColorPicker component with customizable color palettes and labels * feat: enhance BubbleMenu component with support for custom items, reordering, and hiding default items * feat: add default slash menu items for image, checklist, and embed options * feat: add hard break, image, checklist, checklist item, and embed nodes to default schema * feat: update index.ts to re-export additional types for image and embed nodes * feat: add check list and check list item node specifications for task tracking * feat: add embed node specification for external content integration * feat: add hard break node specification for line breaks within text blocks * feat: add image node specification for handling images in blocks * feat: add hard break, image, embed, and check list node specifications to index * feat: add media menu, image, embed, and checklist styles to editor * feat: add checklist, image, and embed block styles to editor * feat: add MediaMenu and ColorPicker components, and their associated types to index * feat: enhance README with new components and usage examples for SlashMenu, BubbleMenu, and ColorPicker --------- Co-authored-by: Jeremy Mouton <jeremy.mouton@spendesk.com>
1 parent 46a5abb commit 1e55642

31 files changed

Lines changed: 4057 additions & 226 deletions

docs/react-integration.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -398,6 +398,116 @@ export default function EditorInner({ initialContent }) {
398398
}
399399
```
400400

401+
## Component Customization
402+
403+
### BubbleMenu Customization
404+
405+
The BubbleMenu supports extensive customization for adding, reordering, or hiding items.
406+
407+
```tsx
408+
import { BubbleMenu, BubbleMenuItem, BUBBLE_MENU_ITEMS } from '@labbs/openblock-react';
409+
410+
// Create a custom button
411+
const translateButton: BubbleMenuItem = {
412+
id: 'translate',
413+
label: 'Translate',
414+
icon: (
415+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor">
416+
<path d="M3 5h12M9 3v2m1.048 9.5A18.022 18.022 0 016.412 9m6.088 9h7M11 21l5-10 5 10" />
417+
</svg>
418+
),
419+
action: async (editor, state) => {
420+
const text = editor.pm.state.doc.textBetween(state.from, state.to);
421+
// Handle translation...
422+
},
423+
};
424+
425+
// Use with customization props
426+
<BubbleMenu
427+
editor={editor}
428+
customItems={[translateButton]}
429+
itemOrder={[
430+
'bold', 'italic', 'underline',
431+
'---', // Divider
432+
'translate',
433+
'---',
434+
'link', 'color',
435+
]}
436+
hideItems={['strikethrough', 'code']}
437+
/>
438+
```
439+
440+
**Available default item IDs:**
441+
- Block type: `blockType`
442+
- Alignment: `alignLeft`, `alignCenter`, `alignRight`
443+
- Formatting: `bold`, `italic`, `underline`, `strikethrough`
444+
- Style: `code`, `link`, `color`
445+
446+
### SlashMenu Customization
447+
448+
The SlashMenu supports similar customization patterns.
449+
450+
```tsx
451+
import { SlashMenu, SlashMenuItem } from '@labbs/openblock-react';
452+
453+
const customItems: SlashMenuItem[] = [
454+
{
455+
id: 'emoji',
456+
title: 'Emoji',
457+
description: 'Insert an emoji',
458+
icon: '😀',
459+
action: (editor) => {
460+
// Show emoji picker...
461+
},
462+
},
463+
];
464+
465+
<SlashMenu
466+
editor={editor}
467+
customItems={customItems}
468+
hideItems={['table', 'video']}
469+
itemOrder={['paragraph', 'heading', 'bulletList', 'emoji']}
470+
/>
471+
```
472+
473+
**Available default item IDs:**
474+
- Text: `paragraph`, `heading`
475+
- Lists: `bulletList`, `numberedList`, `checkList`
476+
- Blocks: `blockquote`, `codeBlock`, `callout`, `divider`
477+
- Tables: `table`
478+
- Media: `image`, `video`, `audio`, `file`
479+
480+
### ColorPicker Customization
481+
482+
Customize the color palettes for text and background colors.
483+
484+
```tsx
485+
import { ColorPicker, ColorOption, DEFAULT_TEXT_COLORS } from '@labbs/openblock-react';
486+
487+
const brandTextColors: ColorOption[] = [
488+
{ value: '', label: 'Default' },
489+
{ value: '#0066cc', label: 'Brand Blue' },
490+
{ value: '#00994d', label: 'Brand Green' },
491+
{ value: '#cc3300', label: 'Brand Red' },
492+
];
493+
494+
const brandBackgroundColors: ColorOption[] = [
495+
{ value: '', label: 'None' },
496+
{ value: '#e6f2ff', label: 'Blue Highlight' },
497+
{ value: '#e6ffe6', label: 'Green Highlight' },
498+
];
499+
500+
<ColorPicker
501+
editor={editor}
502+
currentTextColor={textColor}
503+
currentBackgroundColor={bgColor}
504+
textColors={brandTextColors}
505+
backgroundColors={brandBackgroundColors}
506+
textColorLabel="Text Color"
507+
backgroundColorLabel="Highlight"
508+
/>
509+
```
510+
401511
## TypeScript
402512

403513
All components and hooks are fully typed:

examples/basic/src/App.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { useOpenBlock, OpenBlockView, useEditorContent, SlashMenu, BubbleMenu, TableHandles } from '@labbs/openblock-react';
1+
import { useOpenBlock, OpenBlockView, useEditorContent, SlashMenu, BubbleMenu, TableHandles, MediaMenu } from '@labbs/openblock-react';
22
import { sampleDocument } from './data';
33
// CSS is now auto-injected by OpenBlockEditor (injectStyles: true by default)
44
import './styles.css';
@@ -36,6 +36,13 @@ export default function App() {
3636
{'</>'}
3737
</button>
3838
<span className="separator" />
39+
<button onClick={() => editor?.undo()} title="Undo (Cmd+Z)" disabled={!editor}>
40+
41+
</button>
42+
<button onClick={() => editor?.redo()} title="Redo (Cmd+Shift+Z)" disabled={!editor}>
43+
44+
</button>
45+
<span className="separator" />
3946
<button onClick={() => editor && console.log(editor.getDocument())} title="Log document to console" disabled={!editor}>
4047
Log JSON
4148
</button>
@@ -49,6 +56,7 @@ export default function App() {
4956
<SlashMenu editor={editor} />
5057
<BubbleMenu editor={editor} />
5158
<TableHandles editor={editor} />
59+
<MediaMenu editor={editor} />
5260
</div>
5361
</div>
5462

0 commit comments

Comments
 (0)