diff --git a/packages/core/src/CommandManager.ts b/packages/core/src/CommandManager.ts index 03acf451..bfba5c19 100644 --- a/packages/core/src/CommandManager.ts +++ b/packages/core/src/CommandManager.ts @@ -4,6 +4,7 @@ import { SingleCommands, ChainedCommands, CanCommands, + Commands, CommandSpec, CommandProps, } from './types' @@ -13,35 +14,16 @@ export default class CommandManager { editor: Editor - commands: { [key: string]: any } = {} + commands: Commands methodNames: string[] = [] - constructor(editor: Editor) { + constructor(editor: Editor, commands: Commands) { this.editor = editor + this.commands = commands this.methodNames = getAllMethodNames(this.editor) } - /** - * Register a command. - * - * @param name The name of your command - * @param callback The method of your command - */ - public registerCommand(name: string, callback: CommandSpec): Editor { - if (this.commands[name]) { - throw new Error(`tiptap: command '${name}' is already defined.`) - } - - if (this.methodNames.includes(name)) { - throw new Error(`tiptap: '${name}' is a protected name.`) - } - - this.commands[name] = callback - - return this.editor - } - public createCommands(): SingleCommands { const { commands, editor } = this const { state, view } = editor @@ -73,7 +55,7 @@ export default class CommandManager { const tr = startTr || state.tr return new Proxy({}, { - get: (_, name: string, proxy) => { + get: (_, name: keyof ChainedCommands, proxy) => { if (name === 'run') { if (!hasStartTransaction && shouldDispatch && !tr.getMeta('preventDispatch')) { view.dispatch(tr) @@ -82,13 +64,13 @@ export default class CommandManager { return () => callbacks.every(callback => callback === true) } - const command = commands[name] + const command = commands[name] as CommandSpec if (!command) { throw new Error(`tiptap: command '${name}' not found.`) } - return (...args: any) => { + return (...args: any[]) => { const props = this.buildProps(tr, shouldDispatch) const callback = command(...args)(props) diff --git a/packages/core/src/Editor.ts b/packages/core/src/Editor.ts index 4301ef7d..e4b7ca7d 100644 --- a/packages/core/src/Editor.ts +++ b/packages/core/src/Editor.ts @@ -15,8 +15,6 @@ import EventEmitter from './EventEmitter' import { EditorOptions, EditorContent, - CommandSpec, - Commands, CanCommands, ChainedCommands, SingleCommands, @@ -78,8 +76,8 @@ export class Editor extends EventEmitter { * This method is called after the proxy is initialized. */ private init(): void { - this.createCommandManager() this.createExtensionManager() + this.createCommandManager() this.createSchema() this.createView() this.injectCSS() @@ -164,29 +162,6 @@ export class Editor extends EventEmitter { return this.view.state } - /** - * Register a list of commands. - * - * @param commands A list of commands - */ - public registerCommands(commands: { [key: string]: CommandSpec }): void { - Object - .entries(commands) - .forEach(([name, command]) => this.registerCommand(name, command)) - } - - /** - * Register a command. - * - * @param name The name of your command - * @param callback The method of your command - */ - public registerCommand(name: string, callback: CommandSpec): Editor { - this.commandManager.registerCommand(name, callback) - - return this.proxy - } - /** * Register a ProseMirror plugin. * @@ -233,7 +208,7 @@ export class Editor extends EventEmitter { * Creates an command manager. */ private createCommandManager(): void { - this.commandManager = new CommandManager(this.proxy) + this.commandManager = new CommandManager(this.proxy, this.extensionManager.commands) } /** diff --git a/packages/core/src/ExtensionManager.ts b/packages/core/src/ExtensionManager.ts index 52107553..05375681 100644 --- a/packages/core/src/ExtensionManager.ts +++ b/packages/core/src/ExtensionManager.ts @@ -4,7 +4,7 @@ import { inputRules as inputRulesPlugin } from 'prosemirror-inputrules' import { EditorView, Decoration } from 'prosemirror-view' import { Plugin } from 'prosemirror-state' import { Editor } from './Editor' -import { Extensions, NodeViewRenderer } from './types' +import { Extensions, NodeViewRenderer, Commands } from './types' import getSchema from './helpers/getSchema' import getSchemaTypeByName from './helpers/getSchemaTypeByName' import getNodeType from './helpers/getNodeType' @@ -32,11 +32,6 @@ export default class ExtensionManager { type: getSchemaTypeByName(extension.config.name, this.schema), } - const commands = extension.config.addCommands.bind(context)() - - // @ts-ignore - editor.registerCommands(commands) - if (typeof extension.config.onCreate === 'function') { this.editor.on('create', extension.config.onCreate.bind(context)) } @@ -67,6 +62,21 @@ export default class ExtensionManager { }) } + get commands(): Commands { + return this.extensions.reduce((extensions, extension) => { + const context = { + options: extension.options, + editor: this.editor, + type: getSchemaTypeByName(extension.config.name, this.schema), + } + + return { + ...extensions, + ...extension.config.addCommands.bind(context)(), + } + }, {} as Commands) + } + get plugins(): Plugin[] { return [...this.extensions] .reverse() diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index a04edfdc..c31f59d5 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -120,9 +120,6 @@ export type NodeViewRenderer = (props: NodeViewRendererProps) => (NodeView | {}) export type ValuesOf = T[keyof T]; export type KeysWithTypeOf = ({[P in keyof T]: T[P] extends Type ? P : never })[keyof T] -// export type Commands = UnionToIntersection>>> - -// export type Commands = Commands export type SingleCommands = { [Item in keyof Commands]: Commands[Item] extends (...args: any[]) => any