diff --git a/packages/core/src/Editor.ts b/packages/core/src/Editor.ts index d8760246..90c8f4a3 100644 --- a/packages/core/src/Editor.ts +++ b/packages/core/src/Editor.ts @@ -14,9 +14,7 @@ import createStyleTag from './utils/createStyleTag' import CommandManager from './CommandManager' import ExtensionManager from './ExtensionManager' import EventEmitter from './EventEmitter' -import Extension from './Extension' -import Node from './Node' -import Mark from './Mark' +import { Extensions } from './types' import defaultPlugins from './plugins' import * as coreCommands from './commands' import style from './style' @@ -64,7 +62,7 @@ interface HTMLElement { interface EditorOptions { element: Element, content: EditorContent, - extensions: (Extension | Node | Mark)[], + extensions: Extensions[], injectCSS: boolean, autoFocus: 'start' | 'end' | number | boolean | null, editable: boolean, diff --git a/packages/core/src/Mark.ts b/packages/core/src/Mark.ts index 37ccea81..09ea5345 100644 --- a/packages/core/src/Mark.ts +++ b/packages/core/src/Mark.ts @@ -46,3 +46,73 @@ // } // } + +import { DOMOutputSpec, MarkSpec, Mark } from 'prosemirror-model' +import { ExtensionSpec } from './Extension' + +export interface MarkExtensionSpec extends ExtensionSpec { + inclusive?: MarkSpec['inclusive'], + excludes?: MarkSpec['excludes'], + group?: MarkSpec['group'], + spanning?: MarkSpec['spanning'], + parseHTML?: ( + this: { + options: Options, + }, + ) => MarkSpec['parseDOM'], + renderHTML?: ( + this: { + options: Options, + }, + props: { + node: Mark, + attributes: { + [key: string]: any, + }, + } + ) => DOMOutputSpec, +} + +export type MarkExtension = Required & { + type: string, + options: { + [key: string]: any + }, +}> + +const defaultMark: MarkExtension = { + type: 'mark', + name: 'mark', + options: {}, + inclusive: null, + excludes: null, + group: null, + spanning: null, + createCommands: () => ({}), + parseHTML: () => null, + renderHTML: () => null, +} + +export function createMark(config: MarkExtensionSpec) { + const extend = (extendedConfig: Partial>) => { + return createMark({ + ...config, + ...extendedConfig, + } as MarkExtensionSpec) + } + + const setOptions = (options?: Partial) => { + const { defaultOptions, ...rest } = config + + return { + ...defaultMark, + ...rest, + options: { + ...defaultOptions, + ...options, + } as Options, + } + } + + return Object.assign(setOptions, { config, extend }) +} diff --git a/packages/core/src/Node.ts b/packages/core/src/Node.ts index 73b239b7..1956478a 100644 --- a/packages/core/src/Node.ts +++ b/packages/core/src/Node.ts @@ -84,13 +84,22 @@ export interface NodeExtensionSpec extends Extensio code?: NodeSpec['code'], defining?: NodeSpec['defining'], isolating?: NodeSpec['isolating'], - parseHTML?: () => NodeSpec['parseDOM'], - renderHTML?: (props: { - node: Node, - attributes: { - [key: string]: any, + parseHTML?: ( + this: { + options: Options, }, - }) => DOMOutputSpec, + ) => NodeSpec['parseDOM'], + renderHTML?: ( + this: { + options: Options, + }, + props: { + node: Node, + attributes: { + [key: string]: any, + }, + } + ) => DOMOutputSpec, } export type NodeExtension = Required & { diff --git a/packages/core/src/utils/getSchema.ts b/packages/core/src/utils/getSchema.ts index 6f2f75ca..3d1f0c9b 100644 --- a/packages/core/src/utils/getSchema.ts +++ b/packages/core/src/utils/getSchema.ts @@ -1,4 +1,4 @@ -import { NodeSpec, Schema } from 'prosemirror-model' +import { NodeSpec, MarkSpec, Schema } from 'prosemirror-model' import { Extensions } from '../types' // import getTopNodeFromExtensions from './getTopNodeFromExtensions' // import getNodesFromExtensions from './getNodesFromExtensions' @@ -7,7 +7,7 @@ import { Extensions } from '../types' import splitExtensions from './splitExtensions' export default function getSchema(extensions: Extensions): Schema { - const { nodeExtensions } = splitExtensions(extensions) + const { nodeExtensions, markExtensions } = splitExtensions(extensions) const topNode = nodeExtensions.find(extension => extension.topNode)?.name @@ -38,9 +38,30 @@ export default function getSchema(extensions: Extensions): Schema { return [extension.name, schema] })) + const marks = Object.fromEntries(markExtensions.map(extension => { + const context = { + options: extension.options, + } + + const attributes = { + class: 'test', + } + + const schema: MarkSpec = { + inclusive: extension.inclusive, + excludes: extension.excludes, + group: extension.group, + spanning: extension.spanning, + parseDOM: extension.parseHTML.bind(context)(), + toDOM: node => extension.renderHTML.bind(context)({ node, attributes }), + } + + return [extension.name, schema] + })) + return new Schema({ topNode, nodes, - marks: {}, + marks, }) } diff --git a/packages/core/src/utils/splitExtensions.ts b/packages/core/src/utils/splitExtensions.ts index f5200421..05b50c73 100644 --- a/packages/core/src/utils/splitExtensions.ts +++ b/packages/core/src/utils/splitExtensions.ts @@ -1,16 +1,16 @@ import { Extensions } from '../types' import { Extension } from '../Extension' import { NodeExtension } from '../Node' -// import { MarkExtension } from '../Node' +import { MarkExtension } from '../Mark' export default function splitExtensions(extensions: Extensions) { const baseExtensions = extensions.filter(extension => extension.type === 'extension') as Extension[] const nodeExtensions = extensions.filter(extension => extension.type === 'node') as NodeExtension[] - // const markExtensions = extensions.filter(extension => extension.type === 'mark') as MarkExtension[] + const markExtensions = extensions.filter(extension => extension.type === 'mark') as MarkExtension[] return { baseExtensions, nodeExtensions, - // markExtensions, + markExtensions, } }