Skip to content

feat(core): implement Clipboard Plugin#129

Draft
ilyamore88 wants to merge 8 commits into
mainfrom
feat/clipboard-plugin
Draft

feat(core): implement Clipboard Plugin#129
ilyamore88 wants to merge 8 commits into
mainfrom
feat/clipboard-plugin

Conversation

@ilyamore88
Copy link
Copy Markdown
Member

WIP

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

⏭️ No files to mutate for ./packages/model

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

Coverage report for ./packages/dom-adapters

St.
Category Percentage Covered / Total
🟢 Statements 96.43% 27/28
🟢 Branches 86.96% 20/23
🟢 Functions 100% 5/5
🟢 Lines 96.43% 27/28

Test suite run success

11 tests passing in 2 suites.

Report generated by 🧪jest coverage report action from bc3657c

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

Coverage report for ./packages/core

St.
Category Percentage Covered / Total
🟢 Statements
90.85% (-9.15% 🔻)
129/142
🟢 Branches
90.38% (-9.62% 🔻)
47/52
🟢 Functions
90% (-10% 🔻)
27/30
🟢 Lines
90.23% (-9.77% 🔻)
120/133
Show new covered files 🐣
St.
File Statements Branches Functions Lines
🟡 api/SelectionAPI.ts 80% 100% 66.67% 75%
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟡
... / SelectionManager.ts
80% (-20% 🔻)
80% (-20% 🔻)
66.67% (-33.33% 🔻)
79.31% (-20.69% 🔻)

Test suite run success

75 tests passing in 7 suites.

Report generated by 🧪jest coverage report action from bc3657c

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

Coverage report for ./packages/model

St.
Category Percentage Covered / Total
🟢 Statements
99.7% (-0.1% 🔻)
988/991
🟢 Branches
97.01% (-1.97% 🔻)
292/301
🟢 Functions
97.03% (-0.41% 🔻)
229/236
🟢 Lines
99.68% (-0.1% 🔻)
948/951
Show files with reduced coverage 🔻
St.
File Statements Branches Functions Lines
🟢
... / index.ts
98.9% (-1.1% 🔻)
94.23% (-5.77% 🔻)
93.75% (-6.25% 🔻)
98.86% (-1.14% 🔻)

Test suite run success

538 tests passing in 25 suites.

Report generated by 🧪jest coverage report action from bc3657c

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

⏭️ No files to mutate for ./packages/dom-adapters

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

Coverage report for ./packages/ot-server

St.
Category Percentage Covered / Total
🟡 Statements 70.97% 22/31
🔴 Branches 20% 1/5
🟡 Functions 75% 6/8
🟡 Lines 68.97% 20/29

Test suite run success

4 tests passing in 1 suite.

Report generated by 🧪jest coverage report action from bc3657c

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

⏭️ No files to mutate for ./packages/core

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Apr 17, 2026

Coverage report for ./packages/collaboration-manager

St.
Category Percentage Covered / Total
🟢 Statements 92.51% 358/387
🟢 Branches 85.51% 118/138
🟢 Functions 98.15% 53/54
🟢 Lines 92.41% 353/382

Test suite run success

117 tests passing in 7 suites.

Report generated by 🧪jest coverage report action from bc3657c

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 CopyUIEvent on native copy within the blocks holder.
  • SDK/Core APIs: add selection.selectedBlocks and selection logic to derive selected blocks from caret/index state.
  • Core: auto-register a new ClipboardPlugin that overrides native copy to populate text/plain, text/html, and application/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.

Comment on lines +33 to +46
nativeEvent.preventDefault();

const currentDOMSelection = window.getSelection();

if (!currentDOMSelection) {
return;
}

const selectionAsPlainText = currentDOMSelection?.toString() ?? '';
const selectionAsHTML = this.#parseDOMSelectionToHTML(currentDOMSelection);

nativeEvent.clipboardData?.setData('text/plain', selectionAsPlainText);
nativeEvent.clipboardData?.setData('text/html', selectionAsHTML);
nativeEvent.clipboardData?.setData('application/x-editor-js', JSON.stringify(selectedBlocks));
Comment on lines +44 to +46
nativeEvent.clipboardData?.setData('text/plain', selectionAsPlainText);
nativeEvent.clipboardData?.setData('text/html', selectionAsHTML);
nativeEvent.clipboardData?.setData('application/x-editor-js', JSON.stringify(selectedBlocks));
Comment on lines +199 to +203
return index.compositeSegments.map((segment) => {
const { blockIndex } = segment;

return this.#model.serialized.blocks[blockIndex!];
});
Comment on lines +284 to +287
*
*/
public get isCompositeIndex(): boolean {
/* Stryker disable next-line ConditionalExpression, LogicalOperator -- compound data-index predicate; .isDataIndex specs cover field combinations */
Comment on lines +15 to +16
/**
*
Comment on lines +9 to +24
* Payload @todo update doc
*/
export interface CopyUIEventPayload {
/**
* Native ClipboardEvent
* UI does not call .preventDefault() for this event
*/
nativeEvent: ClipboardEvent;
}

/**
* Delegated copy event from the editor @todo update doc
*/
export class CopyUIEvent extends UIEventBase<CopyUIEventPayload> {
/**
* @param payload - carries the original DOM `ClipboardEvent` as `nativeEvent` for providing rich clipboard data
Comment on lines +19 to +22
/**
* Delegated copy event from the editor @todo update doc
*/
export class CopyUIEvent extends UIEventBase<CopyUIEventPayload> {
Comment on lines +5 to +16
/**
* @todo update doc
*/
export class ClipboardPlugin implements EditorjsPlugin {
public static readonly type = PluginType.Plugin;

readonly #api: EditorAPI;

/**
* @param params @todo update doc
*/
constructor(params: EditorjsPluginParams) {
Comment on lines +286 to +288
public get isCompositeIndex(): boolean {
/* Stryker disable next-line ConditionalExpression, LogicalOperator -- compound data-index predicate; .isDataIndex specs cover field combinations */
return this.compositeSegments !== undefined && this.compositeSegments.length > 0 && this.blockIndex === undefined && this.tuneName === undefined && this.dataKey === undefined && this.textRange === undefined;
* @todo update doc
*/
public destroy(): void {
// do nothing
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could unsubscribe from the copy event

return '';
}

const container = document.createElement('div');
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Template might be better instead of div

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants