improve new extensions

This commit is contained in:
Philipp Kühn 2020-11-16 09:43:17 +01:00
parent 034ee139a3
commit c87f49c1fe
50 changed files with 296 additions and 377 deletions

View File

@ -27,9 +27,9 @@ export default {
mounted() {
this.html = generateHTML(this.json, [
Document(),
Paragraph(),
Text(),
Document,
Paragraph,
Text,
])
},
}

View File

@ -135,11 +135,11 @@ export default {
this.editor = new Editor({
extensions: [
...defaultExtensions(),
Collaboration({
Collaboration.set({
provider: this.provider,
type: this.type,
}),
CollaborationCursor({
CollaborationCursor.set({
provider: this.provider,
name: this.name,
color: this.color,

View File

@ -61,16 +61,16 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Heading({
Document,
Paragraph,
Text,
Heading.set({
level: [1, 2, 3],
}),
Bold(),
Italic(),
TextAlign(),
HardBreak(),
Bold,
Italic,
TextAlign,
HardBreak,
],
content: `
<h3>Girls Just Want to Have Fun (Cyndi Lauper)</h2>

View File

@ -32,10 +32,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Link(),
Document,
Paragraph,
Text,
Link,
],
content: `
<p>

View File

@ -37,7 +37,7 @@ export default {
`,
extensions: [
...defaultExtensions(),
Highlight(),
Highlight,
],
})
},

View File

@ -22,9 +22,9 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Document,
Paragraph,
Text,
],
content: `
<p>

View File

@ -35,11 +35,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
CustomDocument(),
Paragraph(),
Text(),
TaskList(),
CustomTaskItem(),
CustomDocument,
Paragraph,
Text,
TaskList,
CustomTaskItem,
],
content: `
<ul data-type="taskList">

View File

@ -26,10 +26,10 @@ export default {
this.editor = new Editor({
content: '<p>Im running tiptap with Vue.js. This demo is interactive, try to edit the text.</p>',
extensions: [
Document(),
Paragraph(),
Text(),
Bold(),
Document,
Paragraph,
Text,
Bold,
],
})
},

View File

@ -37,10 +37,10 @@ export default {
// <p>Example Text</p>
// `,
extensions: [
Document(),
Paragraph(),
Text(),
Collaboration({
Document,
Paragraph,
Text,
Collaboration.set({
provider: this.provider,
type: this.type,
}),

View File

@ -38,14 +38,14 @@ export default {
// <p>Example Text</p>
// `,
extensions: [
Document(),
Paragraph(),
Text(),
Collaboration({
Document,
Paragraph,
Text,
Collaboration.set({
provider: this.provider,
type: this.type,
}),
CollaborationCursor({
CollaborationCursor.set({
provider: this.provider,
name: 'Cyndi Lauper',
color: '#f783ac',

View File

@ -26,11 +26,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Image(),
Dropcursor(),
Document,
Paragraph,
Text,
Image,
Dropcursor,
],
content: `
<p>Try to drag around the image. While you drag, the editor should show a decoration under your cursor. The so called dropcursor.</p>

View File

@ -28,16 +28,16 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Focus({
Document,
Paragraph,
Text,
Focus.set({
className: 'has-focus',
nested: true,
}),
Code(),
BulletList(),
ListItem(),
Code,
BulletList,
ListItem,
],
autoFocus: true,
content: `

View File

@ -46,11 +46,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
TextStyle(),
FontFamily(),
Document,
Paragraph,
Text,
TextStyle,
FontFamily,
],
content: `
<p><span style="font-family: Inter">Did you know that Inter is a really nice font for interfaces?</span></p>

View File

@ -26,11 +26,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Image(),
Gapcursor(),
Document,
Paragraph,
Text,
Image,
Gapcursor,
],
content: `
<p>Try to set the cursor behind the image with your arrow keys! You should see big blinking cursor right from the image. This is the gapcursor.</p>

View File

@ -33,10 +33,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
History(),
Document,
Paragraph,
Text,
History,
],
content: `
<p>

View File

@ -42,11 +42,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Heading(),
TextAlign(),
Document,
Paragraph,
Text,
Heading,
TextAlign,
],
content: `
<h2>Heading</h2>

View File

@ -25,10 +25,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Typography(),
Document,
Paragraph,
Text,
Typography,
],
content: `
<p>I have been suffering from Typomania all my life, a sickness that is incurable but not lethal.</p>

View File

@ -55,15 +55,15 @@ export default {
this.editor = new Editor({
content: '<h2>Hey there!</h2><p>This editor is based on Prosemirror, fully extendable and headless. You can easily add custom nodes as Vue components.</p>',
extensions: [
Document(),
Paragraph(),
Text(),
CodeBlock(),
History(),
Bold(),
Italic(),
Code(),
Heading(),
Document,
Paragraph,
Text,
CodeBlock,
History,
Bold,
Italic,
Code,
Heading,
],
})
},

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Bold(),
Document,
Paragraph,
Text,
Bold,
],
content: `
<p>This isnt bold.</p>

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Code(),
Document,
Paragraph,
Text,
Code,
],
content: `
<p>This isnt code.</p>

View File

@ -61,10 +61,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Highlight(),
Document,
Paragraph,
Text,
Highlight,
],
content: `
<p>This isnt highlighted.</s></p>

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Italic(),
Document,
Paragraph,
Text,
Italic,
],
content: `
<p>This isnt italic.</p>

View File

@ -32,10 +32,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Link(),
Document,
Paragraph,
Text,
Link,
],
content: `
<p>

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Strike(),
Document,
Paragraph,
Text,
Strike,
],
content: `
<p>This isnt striked through.</s></p>

View File

@ -26,10 +26,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
TextStyle(),
Document,
Paragraph,
Text,
TextStyle,
],
content: `
<p><span>This has a &lt;span&gt; tag without a style attribute, so its thrown away.</span></p>

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Underline(),
Document,
Paragraph,
Text,
Underline,
],
content: `
<p>There is no underline here.</p>

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Blockquote(),
Document,
Paragraph,
Text,
Blockquote,
],
content: `
<blockquote>

View File

@ -31,11 +31,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
BulletList(),
ListItem(),
Document,
Paragraph,
Text,
BulletList,
ListItem,
],
content: `
<ul>

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
CodeBlock(),
Document,
Paragraph,
Text,
CodeBlock,
],
content: `
<p>

View File

@ -25,9 +25,9 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Document,
Paragraph,
Text,
],
content: `
<p>The Document extension is required. Though, you can write your own implementation, e. g. to give it custom name.</p>

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
HardBreak(),
Document,
Paragraph,
Text,
HardBreak,
],
content: `
<p>

View File

@ -36,10 +36,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Heading({
Document,
Paragraph,
Text,
Heading.set({
levels: [1, 2, 3],
}),
],

View File

@ -30,10 +30,10 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
HorizontalRule(),
Document,
Paragraph,
Text,
HorizontalRule,
],
content: `
<p>This is a paragraph.</p>

View File

@ -38,11 +38,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Image(),
Dropcursor(),
Document,
Paragraph,
Text,
Image,
Dropcursor,
],
content: `
<p>This is a basic example of implementing images. Drag to re-order.</p>

View File

@ -35,12 +35,12 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
BulletList(),
OrderedList(),
ListItem(),
Document,
Paragraph,
Text,
BulletList,
OrderedList,
ListItem,
],
content: `
<p>

View File

@ -31,11 +31,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
OrderedList(),
ListItem(),
Document,
Paragraph,
Text,
OrderedList,
ListItem,
],
content: `
<ol>

View File

@ -25,9 +25,9 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Document,
Paragraph,
Text,
],
content: `
<p>The Paragraph extension is not required, but its very likely you want to use it. Its needed to write paragraphs of text. 🤓</p>

View File

@ -27,11 +27,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
TaskList(),
TaskItem(),
Document,
Paragraph,
Text,
TaskList,
TaskItem,
],
content: `
<ul data-type="task_list">

View File

@ -31,11 +31,11 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
TaskList(),
TaskItem(),
Document,
Paragraph,
Text,
TaskList,
TaskItem,
],
content: `
<ul data-type="task_list">

View File

@ -25,9 +25,9 @@ export default {
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Document,
Paragraph,
Text,
],
content: `
<p>The Text extension is required, at least if you want to have text in your text editor and thats very likely.</p>

View File

@ -14,6 +14,9 @@ import createStyleTag from './utils/createStyleTag'
import CommandManager from './CommandManager'
import ExtensionManager from './ExtensionManager'
import EventEmitter from './EventEmitter'
import { Extension } from './Extension'
import { NodeExtension } from './NodeExtension'
import { MarkExtension } from './MarkExtension'
import { Extensions, UnionToIntersection, PickValue } from './types'
import * as extensions from './extensions'
import style from './style'
@ -37,7 +40,62 @@ export interface CommandsSpec {
export interface AllExtensions {}
export type AllCommands = UnionToIntersection<ReturnType<PickValue<ReturnType<AllExtensions[keyof AllExtensions]>, 'addCommands'>>>
// type names = AllExtensions[keyof AllExtensions]
// type onlyExtensions = AllExtensions[keyof AllExtensions] extends Extension ? '1' : '0'
// type onlyExtensions = AllExtensions[keyof AllExtensions extends Extension ? '1' : '0']
// export type OnlyExtensions = {
// [Item in keyof AllExtensions]: AllExtensions[Item] extends Extension
// ? AllExtensions[Item]
// : never
// }
// type ExtractCat<A> = A extends Extension ? A : never
// export type OnlyExtensions = ExtractCat<Item in keyof AllExtensions>
// type ExtractCommands<G> = G extends Extension<any, infer S> ? S : never
// type Test = UnionToIntersection<ExtractCommands<OnlyExtensions[keyof OnlyExtensions]>>
// type SubType<Base, Condition> = Pick<Base, {
// [Key in keyof Base]: Base[Key] extends Condition ? Key : never
// }[keyof Base]>;
// type OnlyExtensions = SubType<AllExtensions, Extension>
// type ExtractCommands<G> = G extends Extension<any, infer S> ? S : never
// type Test = ExtractCommands<OnlyExtensions[keyof OnlyExtensions]>
// type ExtractCommands<G> = G extends Extension<any, infer S>
// ? never
// : G extends NodeExtension<any, infer T>
// ? never
// : G extends MarkExtension<any, infer U>
// ? U
// : never
// export type Bla = {
// [Item in keyof AllExtensions]: AllExtensions[Item] extends Extension<any, infer S>
// ? S
// : AllExtensions[Item] extends NodeExtension<any, infer T>
// ? T
// : AllExtensions[Item] extends MarkExtension<any, infer U>
// ? U
// : never
// }
export type Bla = {
[Item in keyof AllExtensions]: AllExtensions[Item] extends Extension<any, infer ExtensionCommands>
? ExtensionCommands
: AllExtensions[Item] extends NodeExtension<any, infer NodeExtensionCommands>
? NodeExtensionCommands
: AllExtensions[Item] extends MarkExtension<any, infer MarkExtensionCommands>
? MarkExtensionCommands
: never
}
type ValuesOf<T> = T[keyof T];
type KeysWithTypeOf<T, Type> = ({[P in keyof T]: T[P] extends Type ? P : never })[keyof T]
type AllCommands = UnionToIntersection<ValuesOf<Pick<Bla, KeysWithTypeOf<Bla, {}>>>>
export type SingleCommands = {
[Item in keyof AllCommands]: AllCommands[Item] extends (...args: any[]) => any
@ -239,7 +297,7 @@ export class Editor extends EventEmitter {
* Creates an extension manager.
*/
private createExtensionManager() {
const coreExtensions = Object.entries(extensions).map(([, extension]) => extension())
const coreExtensions = Object.entries(extensions).map(([, extension]) => extension)
const allExtensions = [...this.options.extensions, ...coreExtensions]
this.extensionManager = new ExtensionManager(allExtensions, this.proxy)

View File

@ -63,55 +63,6 @@ export interface ExtensionSpec<Options = any, Commands = {}> {
}) => Plugin[],
}
// /**
// * Extension interface for internal usage
// */
// export type Extension = Required<Omit<ExtensionSpec, 'defaultOptions'> & {
// type: string,
// options: {
// [key: string]: any
// },
// }>
// /**
// * Default extension
// */
// export const defaultExtension: Extension = {
// name: 'extension',
// type: 'extension',
// options: {},
// addGlobalAttributes: () => [],
// addCommands: () => ({}),
// addKeyboardShortcuts: () => ({}),
// addInputRules: () => [],
// addPasteRules: () => [],
// addProseMirrorPlugins: () => [],
// }
// export function createExtension<Options extends {}, Commands extends {}>(config: ExtensionSpec<Options, Commands>) {
// const extend = <ExtendedOptions = Options, ExtendedCommands = Commands>(extendedConfig: Partial<ExtensionSpec<ExtendedOptions, ExtendedCommands>>) => {
// return createExtension({
// ...config,
// ...extendedConfig,
// } as ExtensionSpec<ExtendedOptions, ExtendedCommands>)
// }
// const setOptions = (options?: Partial<Options>) => {
// const { defaultOptions, ...rest } = config
// return {
// ...defaultExtension,
// ...rest,
// options: {
// ...defaultOptions,
// ...options,
// } as Options,
// }
// }
// return Object.assign(setOptions, { config, extend })
// }
export class Extension<Options = any, Commands = any> {
config: Required<ExtensionSpec> = {
name: 'extension',
@ -144,6 +95,8 @@ export class Extension<Options = any, Commands = any> {
...this.config.defaultOptions,
...options,
}
return this
}
extend<ExtendedOptions = Options, ExtendedCommands = Commands>(extendedConfig: Partial<ExtensionSpec<ExtendedOptions, ExtendedCommands>>) {

View File

@ -28,10 +28,10 @@ export default class ExtensionManager {
const context = {
options: extension.options,
editor: this.editor,
type: getSchemaTypeByName(extension.name, this.schema),
type: getSchemaTypeByName(extension.config.name, this.schema),
}
const commands = extension.addCommands.bind(context)()
const commands = extension.config.addCommands.bind(context)()
editor.registerCommands(commands)
})
@ -43,10 +43,10 @@ export default class ExtensionManager {
const context = {
options: extension.options,
editor: this.editor,
type: getSchemaTypeByName(extension.name, this.schema),
type: getSchemaTypeByName(extension.config.name, this.schema),
}
return extension.addProseMirrorPlugins.bind(context)()
return extension.config.addProseMirrorPlugins.bind(context)()
})
.flat()
@ -64,10 +64,10 @@ export default class ExtensionManager {
const context = {
options: extension.options,
editor: this.editor,
type: getSchemaTypeByName(extension.name, this.schema),
type: getSchemaTypeByName(extension.config.name, this.schema),
}
return extension.addInputRules.bind(context)()
return extension.config.addInputRules.bind(context)()
})
.flat()
}
@ -78,10 +78,10 @@ export default class ExtensionManager {
const context = {
options: extension.options,
editor: this.editor,
type: getSchemaTypeByName(extension.name, this.schema),
type: getSchemaTypeByName(extension.config.name, this.schema),
}
return extension.addPasteRules.bind(context)()
return extension.config.addPasteRules.bind(context)()
})
.flat()
}
@ -91,10 +91,10 @@ export default class ExtensionManager {
const context = {
options: extension.options,
editor: this.editor,
type: getSchemaTypeByName(extension.name, this.schema),
type: getSchemaTypeByName(extension.config.name, this.schema),
}
return keymap(extension.addKeyboardShortcuts.bind(context)())
return keymap(extension.config.addKeyboardShortcuts.bind(context)())
})
}
@ -104,17 +104,17 @@ export default class ExtensionManager {
const allAttributes = getAttributesFromExtensions(this.extensions)
return Object.fromEntries(nodeExtensions
.filter(extension => !!extension.addNodeView)
.filter(extension => !!extension.config.addNodeView)
.map(extension => {
const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.name)
const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.config.name)
const context = {
options: extension.options,
editor,
type: getSchemaTypeByName(extension.name, this.schema),
type: getSchemaTypeByName(extension.config.name, this.schema),
}
// @ts-ignore
const renderer = extension.addNodeView?.bind(context)?.() as NodeViewRenderer
const renderer = extension.config.addNodeView?.bind(context)?.() as NodeViewRenderer
const nodeview = (
node: ProsemirrorNode,
@ -133,7 +133,7 @@ export default class ExtensionManager {
})
}
return [extension.name, nodeview]
return [extension.config.name, nodeview]
}))
}

View File

@ -106,51 +106,7 @@ export interface MarkExtensionSpec<Options = any, Commands = {}> extends Overwri
}) => Plugin[],
}> {}
// export type MarkExtension = Required<Omit<MarkExtensionSpec, 'defaultOptions'> & {
// type: string,
// options: {
// [key: string]: any
// },
// }>
// const defaultMark: MarkExtension = {
// ...defaultExtension,
// type: 'mark',
// name: 'mark',
// inclusive: null,
// excludes: null,
// group: null,
// spanning: null,
// parseHTML: () => null,
// renderHTML: null,
// addAttributes: () => ({}),
// }
// export function createMark<Options extends {}, Commands extends {}>(config: MarkExtensionSpec<Options, Commands>) {
// const extend = <ExtendedOptions = Options, ExtendedCommands = Commands>(extendedConfig: Partial<MarkExtensionSpec<ExtendedOptions, ExtendedCommands>>) => {
// return createMark({
// ...config,
// ...extendedConfig,
// } as MarkExtensionSpec<ExtendedOptions, ExtendedCommands>)
// }
// const setOptions = (options?: Partial<Options>) => {
// const { defaultOptions, ...rest } = config
// return {
// ...defaultMark,
// ...rest,
// options: {
// ...defaultOptions,
// ...options,
// } as Options,
// }
// }
// return Object.assign(setOptions, { config, extend })
// }
export class MarkExtension<Options = any, Commands = any> {
export class MarkExtension<Options = any, Commands = {}> {
config: Required<MarkExtensionSpec> = {
name: 'mark',
defaultOptions: {},
@ -189,6 +145,8 @@ export class MarkExtension<Options = any, Commands = any> {
...this.config.defaultOptions,
...options,
}
return this
}
extend<ExtendedOptions = Options, ExtendedCommands = Commands>(extendedConfig: Partial<MarkExtensionSpec<ExtendedOptions, ExtendedCommands>>) {

View File

@ -150,59 +150,7 @@ export interface NodeExtensionSpec<Options = any, Commands = {}> extends Overwri
}) => NodeViewRenderer) | null,
}> {}
// export type NodeExtension = Required<Omit<NodeExtensionSpec, 'defaultOptions'> & {
// type: string,
// options: {
// [key: string]: any
// },
// }>
// const defaultNode: NodeExtension = {
// ...defaultExtension,
// type: 'node',
// name: 'node',
// topNode: false,
// content: null,
// marks: null,
// group: null,
// inline: null,
// atom: null,
// selectable: null,
// draggable: null,
// code: null,
// defining: null,
// isolating: null,
// parseHTML: () => null,
// renderHTML: null,
// addAttributes: () => ({}),
// addNodeView: null,
// }
// export function createNode<Options extends {}, Commands extends {}>(config: NodeExtensionSpec<Options, Commands>) {
// const extend = <ExtendedOptions = Options, ExtendedCommands = Commands>(extendedConfig: Partial<NodeExtensionSpec<ExtendedOptions, ExtendedCommands>>) => {
// return createNode({
// ...config,
// ...extendedConfig,
// } as NodeExtensionSpec<ExtendedOptions, ExtendedCommands>)
// }
// const setOptions = (options?: Partial<Options>) => {
// const { defaultOptions, ...rest } = config
// return {
// ...defaultNode,
// ...rest,
// options: {
// ...defaultOptions,
// ...options,
// } as Options,
// }
// }
// return Object.assign(setOptions, { config, extend })
// }
export class NodeExtension<Options = any, Commands = any> {
export class NodeExtension<Options = any, Commands = {}> {
config: Required<NodeExtensionSpec> = {
name: 'node',
defaultOptions: {},
@ -249,6 +197,8 @@ export class NodeExtension<Options = any, Commands = any> {
...this.config.defaultOptions,
...options,
}
return this
}
extend<ExtendedOptions = Options, ExtendedCommands = Commands>(extendedConfig: Partial<NodeExtensionSpec<ExtendedOptions, ExtendedCommands>>) {

View File

@ -27,7 +27,7 @@ export default function getAttributesFromExtensions(extensions: Extensions) {
options: extension.options,
}
const globalAttributes = extension.addGlobalAttributes.bind(context)() as GlobalAttributes
const globalAttributes = extension.config.addGlobalAttributes.bind(context)() as GlobalAttributes
globalAttributes.forEach(globalAttribute => {
globalAttribute.types.forEach(type => {
@ -52,13 +52,13 @@ export default function getAttributesFromExtensions(extensions: Extensions) {
options: extension.options,
}
const attributes = extension.addAttributes.bind(context)() as Attributes
const attributes = extension.config.addAttributes.bind(context)() as Attributes
Object
.entries(attributes)
.forEach(([name, attribute]) => {
extensionAttributes.push({
type: extension.name,
type: extension.config.name,
name,
attribute: {
...defaultAttribute,

View File

@ -21,35 +21,35 @@ function cleanUpSchemaItem<T>(data: T) {
export default function getSchema(extensions: Extensions): Schema {
const allAttributes = getAttributesFromExtensions(extensions)
const { nodeExtensions, markExtensions } = splitExtensions(extensions)
const topNode = nodeExtensions.find(extension => extension.topNode)?.name
const topNode = nodeExtensions.find(extension => extension.config.topNode)?.config.name
const nodes = Object.fromEntries(nodeExtensions.map(extension => {
const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.name)
const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.config.name)
const context = { options: extension.options }
const schema: NodeSpec = cleanUpSchemaItem({
content: callOrReturn(extension.content, context),
marks: callOrReturn(extension.marks, context),
group: callOrReturn(extension.group, context),
inline: callOrReturn(extension.inline, context),
atom: callOrReturn(extension.atom, context),
selectable: callOrReturn(extension.selectable, context),
draggable: callOrReturn(extension.draggable, context),
code: callOrReturn(extension.code, context),
defining: callOrReturn(extension.defining, context),
isolating: callOrReturn(extension.isolating, context),
content: callOrReturn(extension.config.content, context),
marks: callOrReturn(extension.config.marks, context),
group: callOrReturn(extension.config.group, context),
inline: callOrReturn(extension.config.inline, context),
atom: callOrReturn(extension.config.atom, context),
selectable: callOrReturn(extension.config.selectable, context),
draggable: callOrReturn(extension.config.draggable, context),
code: callOrReturn(extension.config.code, context),
defining: callOrReturn(extension.config.defining, context),
isolating: callOrReturn(extension.config.isolating, context),
attrs: Object.fromEntries(extensionAttributes.map(extensionAttribute => {
return [extensionAttribute.name, { default: extensionAttribute?.attribute?.default }]
})),
})
if (extension.parseHTML) {
schema.parseDOM = extension.parseHTML
if (extension.config.parseHTML) {
schema.parseDOM = extension.config.parseHTML
.bind(context)()
?.map(parseRule => injectExtensionAttributesToParseRule(parseRule, extensionAttributes))
}
if (extension.renderHTML) {
schema.toDOM = node => (extension.renderHTML as Function)?.bind(context)({
if (extension.config.renderHTML) {
schema.toDOM = node => (extension.config.renderHTML as Function)?.bind(context)({
node,
HTMLAttributes: mergeAttributes(
extension.options.HTMLAttributes,
@ -58,30 +58,30 @@ export default function getSchema(extensions: Extensions): Schema {
})
}
return [extension.name, schema]
return [extension.config.name, schema]
}))
const marks = Object.fromEntries(markExtensions.map(extension => {
const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.name)
const extensionAttributes = allAttributes.filter(attribute => attribute.type === extension.config.name)
const context = { options: extension.options }
const schema: MarkSpec = cleanUpSchemaItem({
inclusive: callOrReturn(extension.inclusive, context),
excludes: callOrReturn(extension.excludes, context),
group: callOrReturn(extension.group, context),
spanning: callOrReturn(extension.spanning, context),
inclusive: callOrReturn(extension.config.inclusive, context),
excludes: callOrReturn(extension.config.excludes, context),
group: callOrReturn(extension.config.group, context),
spanning: callOrReturn(extension.config.spanning, context),
attrs: Object.fromEntries(extensionAttributes.map(extensionAttribute => {
return [extensionAttribute.name, { default: extensionAttribute?.attribute?.default }]
})),
})
if (extension.parseHTML) {
schema.parseDOM = extension.parseHTML
if (extension.config.parseHTML) {
schema.parseDOM = extension.config.parseHTML
.bind(context)()
?.map(parseRule => injectExtensionAttributesToParseRule(parseRule, extensionAttributes))
}
if (extension.renderHTML) {
schema.toDOM = mark => (extension.renderHTML as Function)?.bind(context)({
if (extension.config.renderHTML) {
schema.toDOM = mark => (extension.config.renderHTML as Function)?.bind(context)({
mark,
HTMLAttributes: mergeAttributes(
extension.options.HTMLAttributes,
@ -90,7 +90,7 @@ export default function getSchema(extensions: Extensions): Schema {
})
}
return [extension.name, schema]
return [extension.config.name, schema]
}))
return new Schema({

View File

@ -4,13 +4,13 @@ import callOrReturn from './callOrReturn'
export default function isList(name: string, extensions: Extensions) {
const { nodeExtensions } = splitExtensions(extensions)
const extension = nodeExtensions.find(item => item.name === name)
const extension = nodeExtensions.find(item => item.config.name === name)
if (!extension) {
return false
}
const groups = callOrReturn(extension.group, { options: extension.options })
const groups = callOrReturn(extension.config.group, { options: extension.options })
if (typeof groups !== 'string') {
return false

View File

@ -4,9 +4,9 @@ import { NodeExtension } from '../NodeExtension'
import { MarkExtension } from '../MarkExtension'
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 baseExtensions = extensions.filter(extension => extension instanceof Extension) as Extension[]
const nodeExtensions = extensions.filter(extension => extension instanceof NodeExtension) as NodeExtension[]
const markExtensions = extensions.filter(extension => extension instanceof MarkExtension) as MarkExtension[]
return {
baseExtensions,

View File

@ -19,9 +19,9 @@ describe('generateHTML', () => {
}
const html = generateHTML(json, [
Document(),
Paragraph(),
Text(),
Document,
Paragraph,
Text,
])
expect(html).to.eq('<p>Example Text</p>')