diff --git a/packages/core/src/Editor.ts b/packages/core/src/Editor.ts index 8afab00d..5843a5e1 100644 --- a/packages/core/src/Editor.ts +++ b/packages/core/src/Editor.ts @@ -8,7 +8,7 @@ import markIsActive from './utils/markIsActive' import getNodeAttrs from './utils/getNodeAttrs' import getMarkAttrs from './utils/getMarkAttrs' import removeElement from './utils/removeElement' -import getSchemaTypeByName from './utils/getSchemaTypeByName' +import getSchemaTypeNameByName from './utils/getSchemaTypeNameByName' import getHtmlFromFragment from './utils/getHtmlFromFragment' import createStyleTag from './utils/createStyleTag' import CommandManager from './CommandManager' @@ -109,7 +109,6 @@ export class Editor extends EventEmitter { this.createCommandManager() this.createExtensionManager() this.createSchema() - // this.extensionManager.resolveConfigs() this.createView() this.registerCommands(coreCommands) this.injectCSS() @@ -338,7 +337,7 @@ export class Editor extends EventEmitter { * @param attrs Attributes of the node or mark */ public isActive(name: string, attrs = {}) { - const schemaType = getSchemaTypeByName(name, this.schema) + const schemaType = getSchemaTypeNameByName(name, this.schema) if (schemaType === 'node') { return nodeIsActive(this.state, this.schema.nodes[name], attrs) diff --git a/packages/core/src/Extension.ts b/packages/core/src/Extension.ts index 1d823141..e06520b2 100644 --- a/packages/core/src/Extension.ts +++ b/packages/core/src/Extension.ts @@ -1,3 +1,4 @@ +import { MarkType, NodeType } from 'prosemirror-model' import { Plugin } from 'prosemirror-state' import { Editor } from './Editor' import { GlobalAttributes } from './types' @@ -16,11 +17,9 @@ export interface ExtensionSpec { /** * Global attributes */ - addGlobalAttributes?: ( - this: { - options: Options, - }, - ) => GlobalAttributes, + addGlobalAttributes?: (this: { + options: Options, + }) => GlobalAttributes, /** * Commands @@ -28,6 +27,7 @@ export interface ExtensionSpec { addCommands?: (this: { options: Options, editor: Editor, + type: NodeType | MarkType, }) => Commands, /** @@ -36,6 +36,7 @@ export interface ExtensionSpec { addKeyboardShortcuts?: (this: { options: Options, editor: Editor, + type: NodeType | MarkType, }) => { [key: string]: any }, @@ -46,6 +47,7 @@ export interface ExtensionSpec { addInputRules?: (this: { options: Options, editor: Editor, + // type: NodeType | MarkType, }) => any[], /** @@ -54,6 +56,7 @@ export interface ExtensionSpec { addPasteRules?: (this: { options: Options, editor: Editor, + type: NodeType | MarkType, }) => any[], /** @@ -62,6 +65,7 @@ export interface ExtensionSpec { addProseMirrorPlugins?: (this: { options: Options, editor: Editor, + type: NodeType | MarkType, }) => Plugin[], } diff --git a/packages/core/src/ExtensionManager.ts b/packages/core/src/ExtensionManager.ts index 7f08808c..9a152bf0 100644 --- a/packages/core/src/ExtensionManager.ts +++ b/packages/core/src/ExtensionManager.ts @@ -3,11 +3,11 @@ import { keymap } from 'prosemirror-keymap' // import { Schema, Node as ProsemirrorNode } from 'prosemirror-model' import { inputRules } from 'prosemirror-inputrules' // import { EditorView, Decoration } from 'prosemirror-view' - import { Editor } from './Editor' // import capitalize from './utils/capitalize' import { Extensions } from './types' import getSchema from './utils/getSchema' +import getSchemaTypeByName from './utils/getSchemaTypeByName' export default class ExtensionManager { @@ -18,54 +18,39 @@ export default class ExtensionManager { constructor(extensions: Extensions, editor: Editor) { this.editor = editor this.extensions = extensions + + this.extensions.forEach(extension => { + const context = { + options: extension.options, + editor: this.editor, + type: getSchemaTypeByName(extension.name, this.schema), + } + + const commands = extension.addCommands.bind(context)() + + editor.registerCommands(commands) + }) } - // resolveConfigs() { - // this.extensions.forEach(extension => { - // const { editor } = this - // const { name } = extension.config - // const options = { - // ...extension.config.defaults, - // ...extension.options, - // } - // const type = extension.type === 'node' - // ? editor.schema.nodes[name] - // : editor.schema.marks[name] - - // resolveExtensionConfig(extension, 'commands', { - // name, options, editor, type, - // }) - // resolveExtensionConfig(extension, 'inputRules', { - // name, options, editor, type, - // }) - // resolveExtensionConfig(extension, 'pasteRules', { - // name, options, editor, type, - // }) - // resolveExtensionConfig(extension, 'keys', { - // name, options, editor, type, - // }) - // resolveExtensionConfig(extension, 'plugins', { - // name, options, editor, type, - // }) - - // if (extension.config.commands) { - // editor.registerCommands(extension.config.commands) - // } - // }) - // } - get schema() { return getSchema(this.extensions) } get plugins(): Plugin[] { - // const plugins = collect(this.extensions) - // .flatMap(extension => extension.config.plugins) - // .filter(plugin => plugin) - // .toArray() + const plugins = this.extensions + .map(extension => { + const context = { + options: extension.options, + editor: this.editor, + type: getSchemaTypeByName(extension.name, this.schema), + } + + return extension.addProseMirrorPlugins.bind(context)() + }) + .flat() return [ - // ...plugins, + ...plugins, ...this.keymaps, ...this.pasteRules, inputRules({ rules: this.inputRules }), @@ -73,19 +58,31 @@ export default class ExtensionManager { } get inputRules(): any { - return [] - // return collect(this.extensions) - // .flatMap(extension => extension.config.inputRules) - // .filter(plugin => plugin) - // .toArray() + return this.extensions + .map(extension => { + const context = { + options: extension.options, + editor: this.editor, + type: getSchemaTypeByName(extension.name, this.schema), + } + + return extension.addInputRules.bind(context)() + }) + .flat() } get pasteRules(): any { - return [] - // return collect(this.extensions) - // .flatMap(extension => extension.config.pasteRules) - // .filter(plugin => plugin) - // .toArray() + return this.extensions + .map(extension => { + const context = { + options: extension.options, + editor: this.editor, + type: getSchemaTypeByName(extension.name, this.schema), + } + + return extension.addPasteRules.bind(context)() + }) + .flat() } get keymaps() { @@ -93,6 +90,7 @@ export default class ExtensionManager { const context = { options: extension.options, editor: this.editor, + type: getSchemaTypeByName(extension.name, this.schema), } return keymap(extension.addKeyboardShortcuts.bind(context)()) diff --git a/packages/core/src/MarkExtension.ts b/packages/core/src/MarkExtension.ts index a75aa057..7fee6359 100644 --- a/packages/core/src/MarkExtension.ts +++ b/packages/core/src/MarkExtension.ts @@ -1,17 +1,44 @@ -import { DOMOutputSpec, MarkSpec, Mark } from 'prosemirror-model' +import { + DOMOutputSpec, MarkSpec, Mark, MarkType, +} from 'prosemirror-model' +import { Plugin } from 'prosemirror-state' import { ExtensionSpec, defaultExtension } from './Extension' import { Attributes } from './types' +import { Editor } from './Editor' export interface MarkExtensionSpec extends ExtensionSpec { + /** + * Inclusive + */ inclusive?: MarkSpec['inclusive'], + + /** + * Excludes + */ excludes?: MarkSpec['excludes'], + + /** + * Group + */ group?: MarkSpec['group'], + + /** + * Spanning + */ spanning?: MarkSpec['spanning'], + + /** + * Parse HTML + */ parseHTML?: ( this: { options: Options, }, ) => MarkSpec['parseDOM'], + + /** + * Render HTML + */ renderHTML?: ( this: { options: Options, @@ -21,11 +48,62 @@ export interface MarkExtensionSpec extends Extensio attributes: { [key: string]: any }, } ) => DOMOutputSpec, + + /** + * Attributes + */ addAttributes?: ( this: { options: Options, }, ) => Attributes, + + /** + * Commands + */ + addCommands?: (this: { + options: Options, + editor: Editor, + type: MarkType, + }) => Commands, + + /** + * Keyboard shortcuts + */ + addKeyboardShortcuts?: (this: { + options: Options, + editor: Editor, + type: MarkType, + }) => { + [key: string]: any + }, + + /** + * Input rules + */ + addInputRules?: (this: { + options: Options, + editor: Editor, + type: MarkType, + }) => any[], + + /** + * Paste rules + */ + addPasteRules?: (this: { + options: Options, + editor: Editor, + type: MarkType, + }) => any[], + + /** + * ProseMirror plugins + */ + addProseMirrorPlugins?: (this: { + options: Options, + editor: Editor, + type: MarkType, + }) => Plugin[], } export type MarkExtension = Required & { diff --git a/packages/core/src/NodeExtension.ts b/packages/core/src/NodeExtension.ts index b3a839fc..a8df82ab 100644 --- a/packages/core/src/NodeExtension.ts +++ b/packages/core/src/NodeExtension.ts @@ -1,28 +1,79 @@ -import { DOMOutputSpec, NodeSpec, Node } from 'prosemirror-model' +import { + DOMOutputSpec, NodeSpec, Node, NodeType, +} from 'prosemirror-model' +import { Plugin } from 'prosemirror-state' import { ExtensionSpec, defaultExtension } from './Extension' import { Attributes } from './types' +import { Editor } from './Editor' export interface NodeExtensionSpec extends ExtensionSpec { + /** + * TopNode + */ topNode?: boolean, /** - * content + * Content */ content?: NodeSpec['content'], + + /** + * Marks + */ marks?: NodeSpec['marks'], + + /** + * Group + */ group?: NodeSpec['group'], + + /** + * Inline + */ inline?: NodeSpec['inline'], + + /** + * Atom + */ atom?: NodeSpec['atom'], + + /** + * Selectable + */ selectable?: NodeSpec['selectable'], + + /** + * Draggable + */ draggable?: NodeSpec['draggable'], + + /** + * Code + */ code?: NodeSpec['code'], + + /** + * Defining + */ defining?: NodeSpec['defining'], + + /** + * Isolating + */ isolating?: NodeSpec['isolating'], + + /** + * Parse HTML + */ parseHTML?: ( this: { options: Options, }, ) => NodeSpec['parseDOM'], + + /** + * Render HTML + */ renderHTML?: ( this: { options: Options, @@ -32,11 +83,62 @@ export interface NodeExtensionSpec extends Extensio attributes: { [key: string]: any }, } ) => DOMOutputSpec, + + /** + * Add Attributes + */ addAttributes?: ( this: { options: Options, }, ) => Attributes, + + /** + * Commands + */ + addCommands?: (this: { + options: Options, + editor: Editor, + type: NodeType, + }) => Commands, + + /** + * Keyboard shortcuts + */ + addKeyboardShortcuts?: (this: { + options: Options, + editor: Editor, + type: NodeType, + }) => { + [key: string]: any + }, + + /** + * Input rules + */ + addInputRules?: (this: { + options: Options, + editor: Editor, + type: NodeType, + }) => any[], + + /** + * Paste rules + */ + addPasteRules?: (this: { + options: Options, + editor: Editor, + type: NodeType, + }) => any[], + + /** + * ProseMirror plugins + */ + addProseMirrorPlugins?: (this: { + options: Options, + editor: Editor, + type: NodeType, + }) => Plugin[], } export type NodeExtension = Required & { diff --git a/packages/core/src/utils/getSchemaTypeByName.ts b/packages/core/src/utils/getSchemaTypeByName.ts index bf8250f0..95166080 100644 --- a/packages/core/src/utils/getSchemaTypeByName.ts +++ b/packages/core/src/utils/getSchemaTypeByName.ts @@ -2,11 +2,11 @@ import { Schema } from 'prosemirror-model' export default function getSchemaTypeByName(name: string, schema: Schema) { if (schema.nodes[name]) { - return 'node' + return schema.nodes[name] } if (schema.marks[name]) { - return 'mark' + return schema.marks[name] } return null diff --git a/packages/core/src/utils/getSchemaTypeNameByName.ts b/packages/core/src/utils/getSchemaTypeNameByName.ts new file mode 100644 index 00000000..5af5bdf3 --- /dev/null +++ b/packages/core/src/utils/getSchemaTypeNameByName.ts @@ -0,0 +1,13 @@ +import { Schema } from 'prosemirror-model' + +export default function getSchemaTypeNameByName(name: string, schema: Schema) { + if (schema.nodes[name]) { + return 'node' + } + + if (schema.marks[name]) { + return 'mark' + } + + return null +} diff --git a/packages/extension-code/index.ts b/packages/extension-code/index.ts index 84baa6a4..7dcc8f5d 100644 --- a/packages/extension-code/index.ts +++ b/packages/extension-code/index.ts @@ -17,7 +17,7 @@ const Code = createMark({ }, renderHTML({ attributes }) { - return ['strong', attributes, 0] + return ['code', attributes, 0] }, addCommands() {