Skip to content
Merged
Show file tree
Hide file tree
Changes from 27 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
9dd6f8e
feat(eventbus): create CopyUIEvent entity
ilyamore88 Apr 17, 2026
b53c482
feat(ui-blocks): subscribe for copy event and pass native event objec…
ilyamore88 Apr 17, 2026
0be2ca4
feat(core): init clipboard plugin
ilyamore88 Apr 17, 2026
10c1c22
feat(core): use ClipboardPlugin
ilyamore88 Apr 17, 2026
ad5b441
Merge branch 'main' of github.com:editor-js/document-model into feat/…
ilyamore88 Apr 17, 2026
e1359c8
Merge branch 'main' of github.com:editor-js/document-model into feat/…
ilyamore88 Apr 23, 2026
500178d
Merge branch 'main' of github.com:editor-js/document-model into feat/…
ilyamore88 May 24, 2026
bc3657c
feat: implement clipboard plugin
ilyamore88 May 24, 2026
00d10ac
fix(clipboard-plugin): prevent native event only after checking selec…
ilyamore88 Jun 9, 2026
d426ae4
chore: fix stryker exception description
ilyamore88 Jun 9, 2026
31a5758
Merge branch 'main' of github.com:editor-js/document-model into feat/…
ilyamore88 Jun 9, 2026
9f44277
feat(clipboard-plugin): update docs, add destroy method implementatio…
ilyamore88 Jul 7, 2026
f63d6dd
Merge branch 'main' of github.com:editor-js/document-model into feat/…
ilyamore88 Jul 7, 2026
55b62c8
chore: use currentSelection in selection manager
ilyamore88 Jul 7, 2026
2681e5b
feat(clipboard-plugin): describe clipboard object
ilyamore88 Jul 8, 2026
2b288dc
refactor(selection-api): return empty array instead of null
ilyamore88 Jul 8, 2026
f2a6067
chore: add docs
ilyamore88 Jul 8, 2026
264f721
chore: update docs
ilyamore88 Jul 8, 2026
f4601a6
fix: make removeEventListener js-private
ilyamore88 Jul 8, 2026
ec4aca5
chore(clipboard-plugin): add unit-tests
ilyamore88 Jul 9, 2026
c144d28
Merge branch 'main' of github.com:editor-js/document-model into feat/…
ilyamore88 Jul 15, 2026
b7b617f
fix(clipboard-plugin-tests): proper mock of esm module with mockModule
ilyamore88 Jul 18, 2026
40a9b2b
refactor(clipboard-plugin): create separate package for plugin
ilyamore88 Jul 19, 2026
9de3ad6
ci: add permissions to ci of clipboard plugin
ilyamore88 Jul 19, 2026
158abf6
fix(clipboard-plugin): don't prevent native event if clipboardData is…
ilyamore88 Jul 19, 2026
c163812
chore(index): remove unused isCompositeIndex from scope
ilyamore88 Jul 19, 2026
2cf7dfe
chore: add more unit-tests to improve mutation testing score
ilyamore88 Jul 19, 2026
a4365c3
chore: address review commits
ilyamore88 Jul 20, 2026
4dff6fa
Merge branch 'main' of github.com:editor-js/document-model into feat/…
ilyamore88 Jul 20, 2026
9d0f896
chore: add spec for clipboard plugin
ilyamore88 Jul 20, 2026
18963e9
chore: address review comments
ilyamore88 Jul 20, 2026
c322b46
test(clipboard-plugin): cover multi-line copy event
ilyamore88 Jul 21, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/clipboard-plugin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
name: Clipboard plugin check
on:
pull_request:
merge_group:

permissions:
contents: read
pull-requests: write
issues: write
actions: read

jobs:
package-check:
uses: ./.github/workflows/package-check.yml
with:
package-name: '@editorjs/clipboard-plugin'
working-directory: './packages/plugins/clipboard-plugin'
include-mutations: true
secrets:
stryker_dashboard_api_key: ${{ secrets.STRYKER_DASHBOARD_API_KEY }}
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
"packageManager": "yarn@4.0.1",
"workspaces": [
"packages/*",
"packages/tools/*"
"packages/tools/*",
"packages/plugins/*"
],
"scripts": {
"build": "yarn workspaces foreach -At run build",
Expand Down
1 change: 1 addition & 0 deletions packages/core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
},
"dependencies": {
"@editorjs/bold": "workspace:^",
"@editorjs/clipboard-plugin": "workspace:^",
"@editorjs/collaboration-manager": "workspace:^",
"@editorjs/dom-adapters": "workspace:^",
"@editorjs/editorjs": "^2.30.5",
Expand Down
9 changes: 8 additions & 1 deletion packages/core/src/api/SelectionAPI.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { inject, injectable } from 'inversify';

import { SelectionManager } from '../components/SelectionManager.js';
import { Caret, EditorJSModel } from '@editorjs/model';
import { CaretManagerEvents, CoreConfigValidated, createInlineToolName, EventType, Index, SelectionAPI as SelectionApiInterface } from '@editorjs/sdk';
import { CaretManagerEvents, CoreConfigValidated, createInlineToolName, EventType, Index, SelectionAPI as SelectionApiInterface, BlockNodeSerialized } from '@editorjs/sdk';
import { TOKENS } from '../tokens.js';

/**
Expand Down Expand Up @@ -88,4 +88,11 @@ export class SelectionAPI implements SelectionApiInterface {
public getCaret(userId = this.#config.userId): Caret | undefined {
return this.#model.getCaret(userId);
}

/**
* Returns array of selected blocks
*/
public get selectedBlocks(): BlockNodeSerialized[] {
return this.#selectionManager.selectedBlocks();
}
}
29 changes: 28 additions & 1 deletion packages/core/src/components/SelectionManager.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import 'reflect-metadata';
import { EditorJSModel } from '@editorjs/model';
import type { InlineFragment } from '@editorjs/sdk';
import type { BlockNodeSerialized, InlineFragment } from '@editorjs/sdk';
import {
CaretManagerCaretUpdatedEvent,
CaretManagerEvents,
Expand Down Expand Up @@ -226,4 +226,31 @@ export class SelectionManager {
}
}
};

/**
* Returns an array of selected blocks using the current selection index
*/
public selectedBlocks(): BlockNodeSerialized[] {
const currentSelectionIndex = this.currentSelection;

if (currentSelectionIndex === null) {
return [];
}

if (currentSelectionIndex.isBlockIndex) {
const { blockIndex } = currentSelectionIndex;

return [this.#model.serialized.blocks[blockIndex!]];
}

if (currentSelectionIndex.compositeSegments !== undefined) {
return currentSelectionIndex.compositeSegments.map((segment) => {
const { blockIndex } = segment;

return this.#model.serialized.blocks[blockIndex!];
});
}

return [];
Comment thread
ilyamore88 marked this conversation as resolved.
}
}
3 changes: 3 additions & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ import { BlockRenderer } from './components/BlockRenderer.js';
import { SelectionManager } from './components/SelectionManager.js';
import { TOKENS } from './tokens.js';
import { UndoRedoManager } from './components/UndoRedoManager.js';
import { ClipboardPlugin } from '@editorjs/clipboard-plugin';

/**
* If no holder is provided via config, the editor will be appended to the element with this id
*/
Expand Down Expand Up @@ -115,6 +117,7 @@ export default class Core {
this.use(ShortcutsPlugin);
this.use(CollaborationManager);
this.use(DOMAdapters);
this.use(ClipboardPlugin);
}

/**
Expand Down
3 changes: 3 additions & 0 deletions packages/core/tsconfig.build.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@
},
{
"path": "../tools/inline-link/tsconfig.build.json"
},
{
"path": "../plugins/clipboard-plugin/tsconfig.build.json"
}
]
}
3 changes: 3 additions & 0 deletions packages/core/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
},
{
"path": "../tools/inline-link/tsconfig.build.json"
},
{
"path": "../plugins/clipboard-plugin/tsconfig.build.json"
}
]
}
24 changes: 24 additions & 0 deletions packages/plugins/clipboard-plugin/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
.yarn/*
!.yarn/patches
!.yarn/plugins
!.yarn/releases
!.yarn/sdks
!.yarn/versions

# Swap the comments on the following lines if you don't wish to use zero-installs
# Documentation here: https://yarnpkg.com/features/zero-installs
#!.yarn/cache
#.pnp.*

# IDE
.idea/*

node_modules/*
dist/*

# tests
coverage/
reports/

# stryker temp files
.stryker-tmp
3 changes: 3 additions & 0 deletions packages/plugins/clipboard-plugin/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Clipboard Plugin

Built-in Editor.js Plugin for rich clipboard copy support.
39 changes: 39 additions & 0 deletions packages/plugins/clipboard-plugin/eslint.config.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import CodeX from 'eslint-config-codex';

export default [
...CodeX,
{
languageOptions: {
parserOptions: {
project: './tsconfig.eslint.json',
tsconfigRootDir: import.meta.dirname,
sourceType: 'module',
},
},
rules: {
'n/no-unpublished-import': ['error', {
allowModules: [
'eslint-config-codex',
],
ignoreTypeImport: true,
}],
'n/no-missing-import': 'off',
'@typescript-eslint/unbound-method': 'off',
'n/no-unsupported-features/node-builtins': ['error', {
version: '>=24.0.0',
ignores: [],
}],
},
},
{
files: ['**/*.spec.ts'],
rules: {
/**
* For test files allow dev dependencies imports
*/
'n/no-unpublished-import': ['error', {
allowModules: ['@jest/globals'],
}],
},
},
];
31 changes: 31 additions & 0 deletions packages/plugins/clipboard-plugin/jest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import type { JestConfigWithTsJest } from 'ts-jest';

export default {
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: [ '<rootDir>/src/**/*.spec.ts' ],
extensionsToTreatAsEsm: [ '.ts' ],
moduleNameMapper: {
'^(\\.{1,2}/.*)\\.js$': '$1',
},
coverageReporters: ['lcov', 'json-summary', 'text-summary'],
transform: {
'^.+\\.tsx?$': [
'ts-jest',
{
useESM: true,
},
],
'^.+\\.jsx?$': [
'babel-jest',
{
presets: [
['@babel/preset-env', { targets: { node: 'current' } }],
],
},
],
},
transformIgnorePatterns: [
'node_modules/(?!@editorjs)',
],
} as JestConfigWithTsJest;
42 changes: 42 additions & 0 deletions packages/plugins/clipboard-plugin/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"name": "@editorjs/clipboard-plugin",
"version": "0.0.0",
"packageManager": "yarn@4.0.1",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"type": "module",
"scripts": {
"build": "yarn clear && tsc --build tsconfig.build.json",
"build:declaration": "yarn build --emitDeclarationOnly",
"lint": "eslint ./src",
"lint:ci": "yarn lint --max-warnings 0",
"lint:fix": "yarn lint --fix",
"test": "node --experimental-vm-modules $(yarn bin jest)",
"test:coverage": "yarn test --coverage=true",
"test:mutations": "NODE_OPTIONS=\"$NODE_OPTIONS --experimental-vm-modules\" stryker run",
"clear": "rm -rf dist && rm -f tsconfig.build.tsbuildinfo && rm -f tsconfig.tsbuildinfo"
},
"devDependencies": {
"@babel/core": "^7.29.0",
"@babel/preset-env": "^7.29.2",
"@jest/globals": "^29.7.0",
"@stryker-mutator/core": "^7.0.2",
"@stryker-mutator/jest-runner": "^7.0.2",
"@stryker-mutator/typescript-checker": "^7.0.2",
"@types/eslint": "^9.6.1",
"@types/jest": "^29.5.12",
"@types/node": "^22.10.2",
"babel-jest": "^29.7.0",
"eslint": "^9.24.0",
"eslint-config-codex": "^2.0.3",
"eslint-plugin-import": "^2.31.0",
"jest": "^29.7.0",
"stryker-cli": "^1.0.2",
"ts-jest": "^29.2.5",
"ts-node": "^10.9.2",
"typescript": "^5.5.4"
},
"dependencies": {
"@editorjs/sdk": "workspace:^"
}
}
Loading
Loading