import { Plugin, Transaction } from 'prosemirror-state' import { Command as ProseMirrorCommand } from 'prosemirror-commands' import { InputRule } from 'prosemirror-inputrules' import { Editor } from './Editor' import { Node } from './Node' import mergeDeep from './utilities/mergeDeep' import { GlobalAttributes, RawCommands, ParentConfig } from './types' import { ExtensionConfig } from '.' declare module '@tiptap/core' { interface ExtensionConfig { [key: string]: any; /** * Name */ name: string, /** * Priority */ priority?: number, /** * Default options */ defaultOptions?: Options, /** * Global attributes */ addGlobalAttributes?: (this: { options: Options, parent: ParentConfig>['addGlobalAttributes'], }) => GlobalAttributes | {}, /** * Raw */ addCommands?: (this: { options: Options, editor: Editor, parent: ParentConfig>['addCommands'], }) => Partial, /** * Keyboard shortcuts */ addKeyboardShortcuts?: (this: { options: Options, editor: Editor, parent: ParentConfig>['addKeyboardShortcuts'], }) => { [key: string]: ProseMirrorCommand, }, /** * Input rules */ addInputRules?: (this: { options: Options, editor: Editor, parent: ParentConfig>['addInputRules'], }) => InputRule[], /** * Paste rules */ addPasteRules?: (this: { options: Options, editor: Editor, parent: ParentConfig>['addPasteRules'], }) => Plugin[], /** * ProseMirror plugins */ addProseMirrorPlugins?: (this: { options: Options, editor: Editor, parent: ParentConfig>['addProseMirrorPlugins'], }) => Plugin[], /** * Extend Node Schema */ extendNodeSchema?: (( this: { options: Options, parent: ParentConfig>['extendNodeSchema'], }, extension: Node, ) => { [key: string]: any, }) | null, /** * Extend Mark Schema */ extendMarkSchema?: (( this: { options: Options, parent: ParentConfig>['extendMarkSchema'], }, extension: Node, ) => { [key: string]: any, }) | null, /** * The editor is not ready yet. */ onBeforeCreate?: ((this: { options: Options, editor: Editor, parent: ParentConfig>['onBeforeCreate'], }) => void) | null, /** * The editor is ready. */ onCreate?: ((this: { options: Options, editor: Editor, parent: ParentConfig>['onCreate'], }) => void) | null, /** * The content has changed. */ onUpdate?: ((this: { options: Options, editor: Editor, parent: ParentConfig>['onUpdate'], }) => void) | null, /** * The selection has changed. */ onSelectionUpdate?: ((this: { options: Options, editor: Editor, parent: ParentConfig>['onSelectionUpdate'], }) => void) | null, /** * The editor state has changed. */ onTransaction?: (( this: { options: Options, editor: Editor, parent: ParentConfig>['onTransaction'], }, props: { transaction: Transaction, }, ) => void) | null, /** * The editor is focused. */ onFocus?: (( this: { options: Options, editor: Editor, parent: ParentConfig>['onFocus'], }, props: { event: FocusEvent, }, ) => void) | null, /** * The editor isn’t focused anymore. */ onBlur?: (( this: { options: Options, editor: Editor, parent: ParentConfig>['onBlur'], }, props: { event: FocusEvent, }, ) => void) | null, /** * The editor is destroyed. */ onDestroy?: ((this: { options: Options, editor: Editor, parent: ParentConfig>['onDestroy'], }) => void) | null, } } export class Extension { type = 'extension' config: ExtensionConfig = { name: 'extension', priority: 100, defaultOptions: {}, } options: Options parent: Extension | null = null child: Extension | null = null constructor(config: Partial> = {}) { this.config = { ...this.config, ...config, } this.options = this.config.defaultOptions } static create(config: Partial> = {}) { return new Extension(config) } configure(options: Partial = {}) { this.options = mergeDeep(this.options, options) as Options return this } extend(extendedConfig: Partial> = {}) { const extension = new Extension(extendedConfig) extension.parent = this this.child = extension extension.options = { ...extension.parent.options, ...extension.options, } return extension } }