diff --git a/packages/core/package.json b/packages/core/package.json index f2870856..73081eff 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -18,6 +18,7 @@ "typescript": "^5.5.4" }, "dependencies": { + "@editorjs/collaboration-manager": "workspace:^", "@editorjs/dom": "^1.0.0", "@editorjs/dom-adapters": "workspace:^", "@editorjs/editorjs": "^2.30.5", diff --git a/packages/core/src/components/EventBus/core-events/CoreEventType.ts b/packages/core/src/components/EventBus/core-events/CoreEventType.ts index 105251d4..8f7995b5 100644 --- a/packages/core/src/components/EventBus/core-events/CoreEventType.ts +++ b/packages/core/src/components/EventBus/core-events/CoreEventType.ts @@ -23,5 +23,15 @@ export enum CoreEventType { /** * Event is fired when the selection is changed */ - SelectionChanged = 'selection:changed' + SelectionChanged = 'selection:changed', + + /** + * Event is fired when undo action should be performed + */ + Undo = 'undo', + + /** + * Event is fired when redo action should be performed + */ + Redo = 'redo' } diff --git a/packages/core/src/components/EventBus/core-events/RedoCoreEvent.ts b/packages/core/src/components/EventBus/core-events/RedoCoreEvent.ts new file mode 100644 index 00000000..b177c43b --- /dev/null +++ b/packages/core/src/components/EventBus/core-events/RedoCoreEvent.ts @@ -0,0 +1,14 @@ +import { CoreEventBase } from './CoreEventBase.js'; +import { CoreEventType } from './CoreEventType.js'; + +/** + * Event is fired when redo action should be performed. E.g. could be fired from UI modules + */ +export class RedoCoreEvent extends CoreEventBase { + /** + * RedoCoreEvent constructor function + */ + constructor() { + super(CoreEventType.Redo, undefined); + } +} diff --git a/packages/core/src/components/EventBus/core-events/UndoCoreEvent.ts b/packages/core/src/components/EventBus/core-events/UndoCoreEvent.ts new file mode 100644 index 00000000..f5fd82f0 --- /dev/null +++ b/packages/core/src/components/EventBus/core-events/UndoCoreEvent.ts @@ -0,0 +1,14 @@ +import { CoreEventBase } from './CoreEventBase.js'; +import { CoreEventType } from './CoreEventType.js'; + +/** + * Event is fired when undo action should be performed. E.g. could be fired from UI modules + */ +export class UndoCoreEvent extends CoreEventBase { + /** + * UndoCoreEvent constructor function + */ + constructor() { + super(CoreEventType.Undo, undefined); + } +} diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index 7f525593..ed2e5c61 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -1,6 +1,8 @@ +import { CollaborationManager } from '@editorjs/collaboration-manager'; import { EditorJSModel, EventType } from '@editorjs/model'; import type { ContainerInstance } from 'typedi'; import { Container } from 'typedi'; +import { CoreEventType, EventBus } from './components/EventBus/index.js'; import { composeDataFromVersion2 } from './utils/composeDataFromVersion2.js'; import ToolsManager from './tools/ToolsManager.js'; import { CaretAdapter, FormattingAdapter } from '@editorjs/dom-adapters'; @@ -8,7 +10,6 @@ import type { CoreConfigValidated } from './entities/Config.js'; import type { CoreConfig } from '@editorjs/sdk'; import { BlocksManager } from './components/BlockManager.js'; import { SelectionManager } from './components/SelectionManager.js'; -import { EventBus } from './components/EventBus/index.js'; import type { EditorjsPluginConstructor } from './entities/EditorjsPlugin.js'; import { EditorAPI } from './api/index.js'; import { UiComponentType } from './entities/Ui.js'; @@ -58,6 +59,8 @@ export default class Core { */ #formattingAdapter: FormattingAdapter; + #collaborationManager: CollaborationManager; + /** * @param config - Editor configuration */ @@ -79,7 +82,12 @@ export default class Core { this.#caretAdapter = new CaretAdapter(this.#config.holder, this.#model); this.#iocContainer.set(CaretAdapter, this.#caretAdapter); + this.#collaborationManager = new CollaborationManager(this.#model); + + this.#iocContainer.set(CollaborationManager, this.#collaborationManager); + this.#formattingAdapter = new FormattingAdapter(this.#model, this.#caretAdapter); + this.#iocContainer.set(FormattingAdapter, this.#formattingAdapter); this.#iocContainer.get(SelectionManager); this.#iocContainer.get(BlocksManager); @@ -89,6 +97,16 @@ export default class Core { config.onModelUpdate?.(this.#model); }); } + + const eventBus = this.#iocContainer.get(EventBus); + + eventBus.addEventListener(`core:${CoreEventType.Undo}`, () => { + this.#collaborationManager.undo(); + }); + + eventBus.addEventListener(`core:${CoreEventType.Redo}`, () => { + this.#collaborationManager.redo(); + }); } /** diff --git a/packages/playground/package.json b/packages/playground/package.json index 9a356b54..b1c43e7d 100644 --- a/packages/playground/package.json +++ b/packages/playground/package.json @@ -14,7 +14,8 @@ "lint:fix": "yarn lint --fix" }, "dependencies": { - "@editorjs/core": "workspace:*", + "@editorjs/collaboration-manager": "workspace:^", + "@editorjs/core": "workspace:^", "@editorjs/dom-adapters": "workspace:^", "@editorjs/model": "workspace:^", "@editorjs/ui": "workspace:*", diff --git a/packages/playground/src/App.vue b/packages/playground/src/App.vue index c825add5..891a54e9 100644 --- a/packages/playground/src/App.vue +++ b/packages/playground/src/App.vue @@ -26,7 +26,7 @@ onMounted(() => { blocks: [ { type: 'paragraph', data: { - text: 'Hello, World!', + text: 'Hello, World!', }, } ], }, diff --git a/packages/ui/src/Blocks/Blocks.ts b/packages/ui/src/Blocks/Blocks.ts index ede9c32e..ce4d3461 100644 --- a/packages/ui/src/Blocks/Blocks.ts +++ b/packages/ui/src/Blocks/Blocks.ts @@ -54,6 +54,24 @@ export class BlocksUI implements EditorjsPlugin { this.#removeBlock(index); }); + this.#holder.addEventListener('keydown', (e) => { + if (e.key !== 'z') { + return; + } + + if (!(e.metaKey || e.ctrlKey)) { + return; + } + + if (e.shiftKey) { + this.#eventBus.dispatchEvent(new Event('core:redo')); + + return; + } + + this.#eventBus.dispatchEvent(new Event('core:undo')); + }); + this.#prepareBlocksHolder(); } diff --git a/yarn.lock b/yarn.lock index bb6b9469..b7ff2cd4 100644 --- a/yarn.lock +++ b/yarn.lock @@ -640,7 +640,7 @@ __metadata: languageName: node linkType: hard -"@editorjs/collaboration-manager@workspace:packages/collaboration-manager": +"@editorjs/collaboration-manager@workspace:^, @editorjs/collaboration-manager@workspace:packages/collaboration-manager": version: 0.0.0-use.local resolution: "@editorjs/collaboration-manager@workspace:packages/collaboration-manager" dependencies: @@ -662,10 +662,11 @@ __metadata: languageName: unknown linkType: soft -"@editorjs/core@workspace:*, @editorjs/core@workspace:^, @editorjs/core@workspace:packages/core": +"@editorjs/core@workspace:^, @editorjs/core@workspace:packages/core": version: 0.0.0-use.local resolution: "@editorjs/core@workspace:packages/core" dependencies: + "@editorjs/collaboration-manager": "workspace:^" "@editorjs/dom": "npm:^1.0.0" "@editorjs/dom-adapters": "workspace:^" "@editorjs/editorjs": "npm:^2.30.5" @@ -684,7 +685,8 @@ __metadata: version: 0.0.0-use.local resolution: "@editorjs/document-playground@workspace:packages/playground" dependencies: - "@editorjs/core": "workspace:*" + "@editorjs/collaboration-manager": "workspace:^" + "@editorjs/core": "workspace:^" "@editorjs/dom-adapters": "workspace:^" "@editorjs/model": "workspace:^" "@editorjs/ui": "workspace:*"