feat(core): implement Clipboard Plugin#129
Conversation
There was a problem hiding this comment.
Pull request overview
Implements initial “copy” pipeline support by introducing a UI-level ui:copy event, exposing selected blocks via the Selection API, and adding a Core ClipboardPlugin that writes editor-specific clipboard payloads when blocks are selected.
Changes:
- UI: dispatch a new
CopyUIEventon nativecopywithin the blocks holder. - SDK/Core APIs: add
selection.selectedBlocksand selection logic to derive selected blocks from caret/index state. - Core: auto-register a new
ClipboardPluginthat overrides native copy to populatetext/plain,text/html, andapplication/x-editor-js.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 9 comments.
Show a summary per file
| File | Description |
|---|---|
| packages/ui/src/Blocks/Blocks.ts | Dispatches CopyUIEvent on native copy events from the blocks holder. |
| packages/sdk/src/entities/EventBus/events/ui/index.ts | Re-exports the new UI copy event from the UI events barrel. |
| packages/sdk/src/entities/EventBus/events/ui/CopyUIEvent.ts | Introduces CopyUIEvent, name constant, and payload type carrying the native ClipboardEvent. |
| packages/sdk/src/api/SelectionAPI.ts | Extends public Selection API with selectedBlocks. |
| packages/model/src/entities/Index/index.ts | Adds Index.isCompositeIndex predicate for composite selections. |
| packages/core/src/plugins/ClipboardPlugin.ts | New plugin that intercepts ui:copy and writes multiple clipboard formats, including editor-specific MIME data. |
| packages/core/src/index.ts | Registers ClipboardPlugin in Core default plugin set. |
| packages/core/src/components/SelectionManager.ts | Adds logic to derive selected blocks from caret index (block index or composite segments). |
| packages/core/src/api/SelectionAPI.ts | Implements SDK Selection API selectedBlocks getter via SelectionManager. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| * @todo update doc | ||
| */ | ||
| public destroy(): void { | ||
| // do nothing |
There was a problem hiding this comment.
Could unsubscribe from the copy event
| return ''; | ||
| } | ||
|
|
||
| const container = document.createElement('div'); |
There was a problem hiding this comment.
Template might be better instead of div
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Unit Tests
Mutation Tests
|
…n, replace div with template
gohabereg
left a comment
There was a problem hiding this comment.
Looks good, just fix the code style
| /** | ||
| * | ||
| */ | ||
| get selectedBlocks(): BlockNodeSerialized[] | null; |
|
|
||
| clipboardData.setData('text/plain', selectionAsPlainText); | ||
| clipboardData.setData('text/html', selectionAsHTML); | ||
| clipboardData.setData('application/x-editor-js', JSON.stringify(clipboardEditorJSObject)); |
There was a problem hiding this comment.
The mime type could be a const
| /** | ||
| * Custom EditorJS data-type object for clipboard events | ||
| */ | ||
| interface ClipboardEditorJSObject { |
There was a problem hiding this comment.
Maybe move interfaces to the top
| blocksHolder.addEventListener('copy', (e) => { | ||
| const payload: CopyUIEventPayload = { | ||
| nativeEvent: e, | ||
| }; | ||
|
|
||
| this.#eventBus.dispatchEvent(new CopyUIEvent(payload)); | ||
| }); |
| }); | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
Please, add more cases covering multiline copying:
- select several blocks and copy as text.
Implementation of Clipboard Plugin. Currently it supports the same behaviour from v2, when a user can copy blocks from Editor and then paste it.
During implementation I found a limitation in Safari. The system ignores custom meta data, if user copies and paste data between different domains.
TODO