diff --git a/packages/core/package.json b/packages/core/package.json index 73081eff..61663469 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -5,7 +5,7 @@ "main": "dist/index.js", "types": "dist/index.d.ts", "scripts": { - "build": "tsc --build tsconfig.build.json", + "build": "yarn clear && tsc --build tsconfig.build.json", "dev": "yarn build --watch", "lint": "eslint ./src", "lint:ci": "yarn lint --max-warnings 0", diff --git a/packages/core/src/components/BlockManager.ts b/packages/core/src/components/BlockManager.ts index 316dfd71..c44207e7 100644 --- a/packages/core/src/components/BlockManager.ts +++ b/packages/core/src/components/BlockManager.ts @@ -5,8 +5,8 @@ import { BlockToolAdapter, CaretAdapter, FormattingAdapter } from '@editorjs/dom import ToolsManager from '../tools/ToolsManager.js'; import { BlockAPI, BlockToolData } from '@editorjs/editorjs'; import { CoreConfigValidated } from '../entities/Config.js'; -import { BlockAddedCoreEvent, BlockRemovedCoreEvent, EventBus } from './EventBus/index.js'; - +import { BlockAddedCoreEvent, BlockRemovedCoreEvent } from './EventBus/index.js'; +import { EventBus } from '@editorjs/sdk'; /** * Parameters for the BlocksManager.insert() method */ @@ -164,6 +164,7 @@ export class BlocksManager { const blockToolAdapter = new BlockToolAdapter( this.#config, this.#model, + this.#eventBus, this.#caretAdapter, index.blockIndex, this.#formattingAdapter, diff --git a/packages/core/src/components/EventBus/index.ts b/packages/core/src/components/EventBus/index.ts index 6e5534b5..de6b54e0 100644 --- a/packages/core/src/components/EventBus/index.ts +++ b/packages/core/src/components/EventBus/index.ts @@ -1,43 +1,6 @@ -import 'reflect-metadata'; -import { Service } from 'typedi'; - -export type Event = `${Channel}:${Name}`; +import type { Event } from '@editorjs/sdk'; export type CoreEvent = Event<'core', Name>; -/** - * Extension for the EventTarget interface to allow for custom events. - */ -declare global { - /** - * EventTarget interface extension - */ - interface EventTarget { - /** - * Adds an event listener for the specified event type - * @param type - a string representing the event type to listen for - * @param callback - the function to call when the event is triggered - * @param options - an options object that specifies characteristics about the event listener - */ - // eslint-disable-next-line n/no-unsupported-features/node-builtins - addEventListener(type: Event, callback: ((event: CustomEvent) => void) | null, options?: AddEventListenerOptions | boolean): void; - /** - * Removes an event listener for the specified event type - * @param type - a string representing the event type to stop listening for - * @param callback - the event callback to remove - * @param options - an options object that specifies characteristics about the event listener - */ - // eslint-disable-next-line n/no-unsupported-features/node-builtins - removeEventListener(type: Event, callback: ((event: CustomEvent) => void) | null, options?: EventListenerOptions | boolean): void; - } -} - -/** - * EventBus class to handle events between components - * Extends native EventTarget class - */ -@Service() -export class EventBus extends EventTarget {} - export * from './core-events/index.js'; export * from './ui-events/index.js'; diff --git a/packages/core/src/components/SelectionManager.ts b/packages/core/src/components/SelectionManager.ts index be92c9b6..5b5f7d05 100644 --- a/packages/core/src/components/SelectionManager.ts +++ b/packages/core/src/components/SelectionManager.ts @@ -4,7 +4,8 @@ import type { CaretManagerEvents, InlineFragment, InlineToolName } from '@editor import { CaretManagerCaretUpdatedEvent, Index, EditorJSModel, createInlineToolData, createInlineToolName } from '@editorjs/model'; import { EventType } from '@editorjs/model'; import { Service } from 'typedi'; -import { CoreEventType, EventBus, ToolLoadedCoreEvent } from './EventBus/index.js'; +import { CoreEventType, ToolLoadedCoreEvent } from './EventBus/index.js'; +import { EventBus } from '@editorjs/sdk'; import { SelectionChangedCoreEvent } from './EventBus/core-events/SelectionChangedCoreEvent.js'; import { InlineTool, InlineToolFormatData } from '@editorjs/sdk'; diff --git a/packages/core/src/entities/EditorjsPlugin.ts b/packages/core/src/entities/EditorjsPlugin.ts index 649f7956..5f3a68a6 100644 --- a/packages/core/src/entities/EditorjsPlugin.ts +++ b/packages/core/src/entities/EditorjsPlugin.ts @@ -1,4 +1,4 @@ -import type { EventBus } from '../components/EventBus/index.js'; +import { EventBus } from '@editorjs/sdk'; import type { CoreConfigValidated } from './Config.js'; import type { EditorAPI } from '../api/index.js'; diff --git a/packages/core/src/entities/index.ts b/packages/core/src/entities/index.ts index a6ecb24f..45f04ac4 100644 --- a/packages/core/src/entities/index.ts +++ b/packages/core/src/entities/index.ts @@ -1,4 +1,3 @@ export * from './Config.js'; export * from './UnifiedToolConfig.js'; export * from './EditorjsPlugin.js'; -export * from './Ui.js'; diff --git a/packages/core/src/index.ts b/packages/core/src/index.ts index e7ca6040..5f6aca76 100644 --- a/packages/core/src/index.ts +++ b/packages/core/src/index.ts @@ -2,7 +2,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 { CoreEventType } from './components/EventBus/index.js'; +import { EventBus, UiComponentType } from '@editorjs/sdk'; import { composeDataFromVersion2 } from './utils/composeDataFromVersion2.js'; import ToolsManager from './tools/ToolsManager.js'; import { CaretAdapter, FormattingAdapter } from '@editorjs/dom-adapters'; @@ -12,7 +13,6 @@ import { BlocksManager } from './components/BlockManager.js'; import { SelectionManager } from './components/SelectionManager.js'; import type { EditorjsPluginConstructor } from './entities/EditorjsPlugin.js'; import { EditorAPI } from './api/index.js'; -import { UiComponentType } from './entities/Ui.js'; import { generateId } from './utils/uid.js'; /** @@ -79,6 +79,9 @@ export default class Core { this.#iocContainer.set('EditorConfig', this.#config); + const eventBus = new EventBus(); + this.#iocContainer.set(EventBus, eventBus); + this.#model = new EditorJSModel(); this.#iocContainer.set(EditorJSModel, this.#model); @@ -103,8 +106,6 @@ export default class Core { }); } - const eventBus = this.#iocContainer.get(EventBus); - eventBus.addEventListener(`core:${CoreEventType.Undo}`, () => { this.#collaborationManager.undo(); }); diff --git a/packages/core/src/tools/ToolsManager.ts b/packages/core/src/tools/ToolsManager.ts index bfc85669..6d192e7d 100644 --- a/packages/core/src/tools/ToolsManager.ts +++ b/packages/core/src/tools/ToolsManager.ts @@ -20,7 +20,8 @@ import type { UnifiedToolConfig } from '../entities/index.js'; import BoldInlineTool from './internal/inline-tools/bold/index.js'; import ItalicInlineTool from './internal/inline-tools/italic/index.js'; import LinkInlineTool from './internal/inline-tools/link/index.js'; -import { EventBus, ToolLoadedCoreEvent } from '../components/EventBus/index.js'; +import { ToolLoadedCoreEvent } from '../components/EventBus/index.js'; +import { EventBus } from '@editorjs/sdk'; /** * Works with tools diff --git a/packages/dom-adapters/package.json b/packages/dom-adapters/package.json index 084391bc..823ee4c5 100644 --- a/packages/dom-adapters/package.json +++ b/packages/dom-adapters/package.json @@ -6,7 +6,7 @@ "types": "dist/index.d.ts", "type": "module", "scripts": { - "build": "tsc --build tsconfig.build.json", + "build": "yarn clear && tsc --build tsconfig.build.json", "dev": "yarn build --watch", "lint": "eslint ./src", "lint:ci": "yarn lint --max-warnings 0", diff --git a/packages/dom-adapters/src/BlockToolAdapter/index.ts b/packages/dom-adapters/src/BlockToolAdapter/index.ts index dc96b238..5c016a9f 100644 --- a/packages/dom-adapters/src/BlockToolAdapter/index.ts +++ b/packages/dom-adapters/src/BlockToolAdapter/index.ts @@ -22,6 +22,7 @@ import { import { InputType } from './types/InputType.js'; import type { BlockToolAdapter as BlockToolAdapterInterface, CoreConfig } from '@editorjs/sdk'; import type { FormattingAdapter } from '../FormattingAdapter/index.js'; +import type { EventBus } from '@editorjs/sdk'; /** * BlockToolAdapter is using inside Block tools to connect browser DOM elements to the model @@ -64,12 +65,13 @@ export class BlockToolAdapter implements BlockToolAdapterInterface { * * @param config - Editor's config * @param model - EditorJSModel instance + * @param eventBus - Editor EventBus instance * @param caretAdapter - CaretAdapter instance * @param blockIndex - index of the block that this adapter is connected to * @param formattingAdapter - needed to render formatted text * @param toolName - tool name of the block */ - constructor(config: CoreConfig, model: EditorJSModel, caretAdapter: CaretAdapter, blockIndex: number, formattingAdapter: FormattingAdapter, toolName: string) { + constructor(config: CoreConfig, model: EditorJSModel, eventBus: EventBus, caretAdapter: CaretAdapter, blockIndex: number, formattingAdapter: FormattingAdapter, toolName: string) { this.#config = config; this.#model = model; this.#blockIndex = blockIndex; diff --git a/packages/dom-adapters/tsconfig.json b/packages/dom-adapters/tsconfig.json index 57237c43..c1429a27 100644 --- a/packages/dom-adapters/tsconfig.json +++ b/packages/dom-adapters/tsconfig.json @@ -3,7 +3,7 @@ "composite": true, "target": "esnext", "module": "esnext", - "moduleResolution": "Node", + "moduleResolution": "bundler", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, @@ -21,6 +21,6 @@ "references": [ { "path": "../sdk/tsconfig.build.json", - } + }, ] } diff --git a/packages/playground/tsconfig.json b/packages/playground/tsconfig.json index 31f9f624..d608bb21 100644 --- a/packages/playground/tsconfig.json +++ b/packages/playground/tsconfig.json @@ -29,9 +29,6 @@ { "path": "./tsconfig.node.json" }, - { - "path": "../ui/tsconfig.json" - }, { "path": "../core/tsconfig.json" }, diff --git a/packages/playground/vite.config.ts b/packages/playground/vite.config.ts index 2c843219..67e426e8 100644 --- a/packages/playground/vite.config.ts +++ b/packages/playground/vite.config.ts @@ -2,8 +2,6 @@ import { defineConfig } from 'vite' import vue from '@vitejs/plugin-vue' import path from 'node:path'; - -// https://vitejs.dev/config/ export default defineConfig({ plugins: [vue()], resolve: { @@ -11,4 +9,18 @@ export default defineConfig({ '@': path.resolve(__dirname, './src'), }, }, + optimizeDeps: { + exclude: [ + '@editorjs/ui', + '@editorjs/core', + ] + }, + build: { + rollupOptions: { + external: [ + '@editorjs/ui', + '@editorjs/core', + ] + } + } }) diff --git a/packages/sdk/src/entities/EventBus/Event.ts b/packages/sdk/src/entities/EventBus/Event.ts new file mode 100644 index 00000000..f4a716f4 --- /dev/null +++ b/packages/sdk/src/entities/EventBus/Event.ts @@ -0,0 +1,10 @@ +export type Event< + /** + * Channel of the event + */ + Channel extends string = string, + /** + * Name of the event + */ + Name extends string = string +> = `${Channel}:${Name}`; diff --git a/packages/sdk/src/entities/EventBus/index.ts b/packages/sdk/src/entities/EventBus/index.ts new file mode 100644 index 00000000..3978bad5 --- /dev/null +++ b/packages/sdk/src/entities/EventBus/index.ts @@ -0,0 +1,36 @@ +import type { Event } from './Event.js'; + +/** + * Extension for the EventTarget interface to allow for custom events. + */ +declare global { + /** + * EventTarget interface extension + */ + interface EventTarget { + /** + * Adds an event listener for the specified event type + * @param type - a string representing the event type to listen for + * @param callback - the function to call when the event is triggered + * @param options - an options object that specifies characteristics about the event listener + */ + // eslint-disable-next-line n/no-unsupported-features/node-builtins + addEventListener(type: Event, callback: ((event: CustomEvent) => void) | null, options?: AddEventListenerOptions | boolean): void; + /** + * Removes an event listener for the specified event type + * @param type - a string representing the event type to stop listening for + * @param callback - the event callback to remove + * @param options - an options object that specifies characteristics about the event listener + */ + // eslint-disable-next-line n/no-unsupported-features/node-builtins + removeEventListener(type: Event, callback: ((event: CustomEvent) => void) | null, options?: EventListenerOptions | boolean): void; + } +} + +/** + * EventBus class to handle events between components + * Extends native EventTarget class + */ +export class EventBus extends EventTarget {} + +export * from './Event.js'; diff --git a/packages/core/src/entities/Ui.ts b/packages/sdk/src/entities/Ui.ts similarity index 100% rename from packages/core/src/entities/Ui.ts rename to packages/sdk/src/entities/Ui.ts diff --git a/packages/sdk/src/entities/index.ts b/packages/sdk/src/entities/index.ts index 934c95e5..80d7a0e3 100644 --- a/packages/sdk/src/entities/index.ts +++ b/packages/sdk/src/entities/index.ts @@ -2,3 +2,5 @@ export * from './InlineTool.js' export * from './BlockTool.js' export * from './Config.js' export * from './BlockToolAdapter.js' +export * from './EventBus/index.js'; +export * from './Ui.js'; diff --git a/packages/sdk/tsconfig.json b/packages/sdk/tsconfig.json index c2baafdc..6a2685da 100644 --- a/packages/sdk/tsconfig.json +++ b/packages/sdk/tsconfig.json @@ -3,14 +3,18 @@ "composite": true, "target": "esnext", "module": "esnext", - "moduleResolution": "Node", + "moduleResolution": "bundler", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true, "experimentalDecorators": true, "rootDir": "src", - "outDir": "dist" + "outDir": "dist", + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "preserveConstEnums": true }, "include": ["src/**/*"], "exclude": [ diff --git a/packages/ui/package.json b/packages/ui/package.json index 82659efb..eaa20a47 100644 --- a/packages/ui/package.json +++ b/packages/ui/package.json @@ -2,21 +2,22 @@ "name": "@editorjs/ui", "packageManager": "yarn@4.0.1", "type": "module", - "main": "./dist/index.js", - "module": "./dist/index.js", + "main": "./dist/ui.cjs", + "module": "./dist/ui.js", "types": "./dist/index.d.ts", "exports": { ".": { "types": "./dist/index.d.ts", - "import": "./dist/index.js", - "require": "./dist/index.js" + "import": "./dist/ui.js", + "require": "./dist/ui.cjs", + "default": "./dist/ui.js" } }, "files": [ "dist" ], "scripts": { - "build": "vite build", + "build": "yarn clear && vite build", "dev": "vite", "lint": "eslint ./src", "lint:ci": "yarn lint --max-warnings 0", diff --git a/packages/ui/src/Blocks/BeforeInputUIEvent.ts b/packages/ui/src/Blocks/BeforeInputUIEvent.ts new file mode 100644 index 00000000..0de1a1af --- /dev/null +++ b/packages/ui/src/Blocks/BeforeInputUIEvent.ts @@ -0,0 +1,42 @@ +import { UIEventBase } from '@editorjs/core'; + +/** + * Name of the event + */ +export const BeforeInputUIEventName = 'ui:before-input'; + +/** + * Payload of the BeforeInputUIEvent + * Contains InlineToolbar HTML element + */ +export interface BeforeInputUIEventPayload { + /** + * A string with the inserted characters. + * This may be an empty string if the change doesn't insert text + * (for example, when deleting characters). + */ + data: string | null; + + /** + * Same as 'beforeinput' event's inputType + */ + inputType: string; + + /** + * Same as 'beforeinput' event's isComposing + */ + isComposing: boolean; +} + +/** + * Class for event that is being fired after the inline toolbar is rendered + */ +export class BeforeInputUIEvent extends UIEventBase { + /** + * ToolboxRenderedUIEvent constructor function + * @param payload - ToolboxRendered event payload + */ + constructor(payload: BeforeInputUIEventPayload) { + super(BeforeInputUIEventName, payload); + } +} diff --git a/packages/ui/src/Blocks/Blocks.ts b/packages/ui/src/Blocks/Blocks.ts index d20347ec..cc8807bb 100644 --- a/packages/ui/src/Blocks/Blocks.ts +++ b/packages/ui/src/Blocks/Blocks.ts @@ -1,13 +1,15 @@ import type { BlockAddedCoreEvent, BlockRemovedCoreEvent, - EventBus, EditorjsPlugin, EditorjsPluginParams } from '@editorjs/core'; import { - CoreEventType, - UiComponentType + CoreEventType } from '@editorjs/core'; +import type { EventBus } from '@editorjs/sdk'; +import { UiComponentType } from '@editorjs/sdk'; + import Style from './Blocks.module.pcss'; +import { BeforeInputUIEvent } from './BeforeInputUIEvent.js'; /** * Editor's main UI renderer for HTML environment @@ -21,7 +23,6 @@ export class BlocksUI implements EditorjsPlugin { */ public static readonly type = UiComponentType.Blocks; - /** * Blocks holder element */ @@ -74,11 +75,11 @@ export class BlocksUI implements EditorjsPlugin { this.#eventBus.dispatchEvent(new Event('core:undo')); }); - } /** * Prepares blocks holder element + * @param editorHolder - user provided holder element for editor */ #prepareBlocksHolder(editorHolder: HTMLElement): HTMLElement { const blocksHolder = document.createElement('div'); @@ -87,6 +88,14 @@ export class BlocksUI implements EditorjsPlugin { blocksHolder.contentEditable = 'false'; + blocksHolder.addEventListener('beforeinput', (e) => { + this.#eventBus.dispatchEvent(new BeforeInputUIEvent({ + data: e.data, + inputType: e.inputType, + isComposing: e.isComposing, + })); + }); + editorHolder.appendChild(blocksHolder); return blocksHolder; diff --git a/packages/ui/src/InlineToolbar/InlineToolbar.ts b/packages/ui/src/InlineToolbar/InlineToolbar.ts index 910d7839..65d72bac 100644 --- a/packages/ui/src/InlineToolbar/InlineToolbar.ts +++ b/packages/ui/src/InlineToolbar/InlineToolbar.ts @@ -1,19 +1,17 @@ import { make } from '@editorjs/dom'; import { InlineToolbarRenderedUIEvent } from './InlineToolbarRenderedUIEvent.js'; import type { EditorAPI, - EventBus, SelectionChangedCoreEvent, EditorjsPlugin, EditorjsPluginParams } from '@editorjs/core'; +import { UiComponentType } from '@editorjs/sdk'; import { - CoreEventType, - UiComponentType + CoreEventType } from '@editorjs/core'; -import type { InlineTool, InlineToolFormatData } from '@editorjs/sdk'; +import type { InlineTool, InlineToolFormatData, EventBus } from '@editorjs/sdk'; import type { InlineFragment, InlineToolName, TextRange } from '@editorjs/model'; import Style from './InlineToolbar.module.pcss'; - /** * Inline Toolbar UI module * - renders the inline toolbar with available inline tools diff --git a/packages/ui/src/Toolbox/Toolbox.ts b/packages/ui/src/Toolbox/Toolbox.ts index 502194c7..b6812c12 100644 --- a/packages/ui/src/Toolbox/Toolbox.ts +++ b/packages/ui/src/Toolbox/Toolbox.ts @@ -1,15 +1,15 @@ import { make } from '@editorjs/dom'; -import type { EventBus, - ToolLoadedCoreEvent, +import type { ToolLoadedCoreEvent, BlockToolFacade, EditorjsPlugin, EditorjsPluginParams } from '@editorjs/core'; import { - CoreEventType, - UiComponentType + CoreEventType } from '@editorjs/core'; import { ToolboxRenderedUIEvent } from './ToolboxRenderedUIEvent.js'; import type { EditorAPI } from '@editorjs/core'; +import type { EventBus } from '@editorjs/sdk'; +import { UiComponentType } from '@editorjs/sdk'; /** * UI module responsible for rendering the toolbox diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts index 3688e2e3..f31f1b7f 100644 --- a/packages/ui/src/index.ts +++ b/packages/ui/src/index.ts @@ -1,10 +1,10 @@ import type { CoreConfigValidated, - EventBus, EditorjsPlugin, EditorjsPluginParams } from '@editorjs/core'; +import type { EventBus } from '@editorjs/sdk'; import { UiComponentType -} from '@editorjs/core'; +} from '@editorjs/sdk'; import type { ToolboxRenderedUIEvent } from './Toolbox/ToolboxRenderedUIEvent.js'; import type { InlineToolbarRenderedUIEvent } from './InlineToolbar/InlineToolbarRenderedUIEvent.js'; import Style from './main.module.pcss'; @@ -79,3 +79,4 @@ export class EditorjsUI implements EditorjsPlugin { export * from './InlineToolbar/InlineToolbar.js'; export * from './Blocks/Blocks.js'; export * from './Toolbox/Toolbox.js'; +export * from './Blocks/BeforeInputUIEvent.js'; diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json index fc87faa1..1cefbd1d 100644 --- a/packages/ui/tsconfig.json +++ b/packages/ui/tsconfig.json @@ -22,6 +22,9 @@ "references": [ { "path": "../model/tsconfig.build.json" + }, + { + "path": "../sdk/tsconfig.build.json" } ] } diff --git a/packages/ui/vite.config.ts b/packages/ui/vite.config.ts index 06c854ed..89028d98 100644 --- a/packages/ui/vite.config.ts +++ b/packages/ui/vite.config.ts @@ -1,27 +1,31 @@ import { defineConfig } from 'vite'; import { resolve } from 'path'; -import dts from 'vite-plugin-dts' +import dts from 'vite-plugin-dts'; import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; - export default defineConfig({ plugins: [ dts(), - cssInjectedByJsPlugin(), + cssInjectedByJsPlugin() ], build: { lib: { entry: resolve(__dirname, 'src/index.ts'), name: 'EditorUI', - fileName: 'index', formats: ['es', 'cjs'] }, rollupOptions: { external: [ - 'reflect-metadata', - 'typedi', + '@editorjs/core', + '@editorjs/dom', + '@editorjs/dom-adapters', + '@editorjs/editorjs', + '@editorjs/helpers', + '@editorjs/model', + '@editorjs/sdk' ], }, + sourcemap: true }, resolve: { alias: {