mirror of
https://github.com/ueberdosis/tiptap.git
synced 2025-01-18 06:03:22 +08:00
improve new extensions
This commit is contained in:
parent
034ee139a3
commit
c87f49c1fe
@ -27,9 +27,9 @@ export default {
|
||||
|
||||
mounted() {
|
||||
this.html = generateHTML(this.json, [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
])
|
||||
},
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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>
|
||||
|
@ -32,10 +32,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Link(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Link,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
|
@ -37,7 +37,7 @@ export default {
|
||||
`,
|
||||
extensions: [
|
||||
...defaultExtensions(),
|
||||
Highlight(),
|
||||
Highlight,
|
||||
],
|
||||
})
|
||||
},
|
||||
|
@ -22,9 +22,9 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
|
@ -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">
|
||||
|
@ -26,10 +26,10 @@ export default {
|
||||
this.editor = new Editor({
|
||||
content: '<p>I’m running tiptap with Vue.js. This demo is interactive, try to edit the text.</p>',
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Bold(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Bold,
|
||||
],
|
||||
})
|
||||
},
|
||||
|
@ -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,
|
||||
}),
|
||||
|
@ -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',
|
||||
|
@ -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>
|
||||
|
@ -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: `
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -33,10 +33,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
History(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
History,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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,
|
||||
],
|
||||
})
|
||||
},
|
||||
|
@ -30,10 +30,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Bold(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Bold,
|
||||
],
|
||||
content: `
|
||||
<p>This isn’t bold.</p>
|
||||
|
@ -30,10 +30,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Code(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Code,
|
||||
],
|
||||
content: `
|
||||
<p>This isn’t code.</p>
|
||||
|
@ -61,10 +61,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Highlight(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Highlight,
|
||||
],
|
||||
content: `
|
||||
<p>This isn’t highlighted.</s></p>
|
||||
|
@ -30,10 +30,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Italic(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Italic,
|
||||
],
|
||||
content: `
|
||||
<p>This isn’t italic.</p>
|
||||
|
@ -32,10 +32,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Link(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Link,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
|
@ -30,10 +30,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Strike(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Strike,
|
||||
],
|
||||
content: `
|
||||
<p>This isn’t striked through.</s></p>
|
||||
|
@ -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 <span> tag without a style attribute, so it’s thrown away.</span></p>
|
||||
|
@ -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>
|
||||
|
@ -30,10 +30,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Blockquote(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Blockquote,
|
||||
],
|
||||
content: `
|
||||
<blockquote>
|
||||
|
@ -31,11 +31,11 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
BulletList(),
|
||||
ListItem(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
BulletList,
|
||||
ListItem,
|
||||
],
|
||||
content: `
|
||||
<ul>
|
||||
|
@ -30,10 +30,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
CodeBlock(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
CodeBlock,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
|
@ -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>
|
||||
|
@ -30,10 +30,10 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
HardBreak(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
HardBreak,
|
||||
],
|
||||
content: `
|
||||
<p>
|
||||
|
@ -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],
|
||||
}),
|
||||
],
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -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>
|
||||
|
@ -31,11 +31,11 @@ export default {
|
||||
mounted() {
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
OrderedList(),
|
||||
ListItem(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
OrderedList,
|
||||
ListItem,
|
||||
],
|
||||
content: `
|
||||
<ol>
|
||||
|
@ -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 it’s very likely you want to use it. It’s needed to write paragraphs of text. 🤓</p>
|
||||
|
@ -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">
|
||||
|
@ -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">
|
||||
|
@ -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 that’s very likely.</p>
|
||||
|
@ -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)
|
||||
|
@ -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>>) {
|
||||
|
@ -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]
|
||||
}))
|
||||
}
|
||||
|
||||
|
@ -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>>) {
|
||||
|
@ -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>>) {
|
||||
|
@ -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,
|
||||
|
@ -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({
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -19,9 +19,9 @@ describe('generateHTML', () => {
|
||||
}
|
||||
|
||||
const html = generateHTML(json, [
|
||||
Document(),
|
||||
Paragraph(),
|
||||
Text(),
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
])
|
||||
|
||||
expect(html).to.eq('<p>Example Text</p>')
|
||||
|
Loading…
Reference in New Issue
Block a user