add new syntax to all extensions
This commit is contained in:
@@ -3,11 +3,7 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
// import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit'
|
import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit'
|
||||||
import { Editor, EditorContent } from '@tiptap/vue-starter-kit'
|
|
||||||
import Document from '@tiptap/extension-document'
|
|
||||||
import Paragraph from '@tiptap/extension-paragraph'
|
|
||||||
import Text from '@tiptap/extension-text'
|
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
components: {
|
components: {
|
||||||
@@ -23,12 +19,7 @@ export default {
|
|||||||
mounted() {
|
mounted() {
|
||||||
this.editor = new Editor({
|
this.editor = new Editor({
|
||||||
content: '<p>I’m running tiptap with Vue.js. 🎉</p>',
|
content: '<p>I’m running tiptap with Vue.js. 🎉</p>',
|
||||||
// extensions: defaultExtensions(),
|
extensions: defaultExtensions(),
|
||||||
extensions: [
|
|
||||||
new Document(),
|
|
||||||
new Paragraph(),
|
|
||||||
new Text(),
|
|
||||||
],
|
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -1,141 +1,73 @@
|
|||||||
// import cloneDeep from 'clone-deep'
|
import { Plugin } from 'prosemirror-state'
|
||||||
// import { Plugin } from 'prosemirror-state'
|
|
||||||
// import { Editor, CommandsSpec } from './Editor'
|
|
||||||
|
|
||||||
// type AnyObject = {
|
|
||||||
// [key: string]: any
|
|
||||||
// }
|
|
||||||
|
|
||||||
// type NoInfer<T> = [T][T extends any ? 0 : never]
|
|
||||||
|
|
||||||
// type MergeStrategy = 'extend' | 'overwrite'
|
|
||||||
|
|
||||||
// type Configs = {
|
|
||||||
// [key: string]: {
|
|
||||||
// stategy: MergeStrategy
|
|
||||||
// value: any
|
|
||||||
// }[]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface ExtensionProps<Options> {
|
|
||||||
// name: string
|
|
||||||
// editor: Editor
|
|
||||||
// options: Options
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export interface ExtensionMethods<Props, Options> {
|
|
||||||
// name: string
|
|
||||||
// options: Options
|
|
||||||
// commands: (params: Props) => CommandsSpec
|
|
||||||
// inputRules: (params: Props) => any[]
|
|
||||||
// pasteRules: (params: Props) => any[]
|
|
||||||
// keys: (params: Props) => {
|
|
||||||
// [key: string]: Function
|
|
||||||
// }
|
|
||||||
// plugins: (params: Props) => Plugin[]
|
|
||||||
// }
|
|
||||||
|
|
||||||
// export default class Extension<
|
|
||||||
// Options = {},
|
|
||||||
// Props = ExtensionProps<Options>,
|
|
||||||
// Methods extends ExtensionMethods<Props, Options> = ExtensionMethods<Props, Options>,
|
|
||||||
// > {
|
|
||||||
// type = 'extension'
|
|
||||||
|
|
||||||
// config: AnyObject = {}
|
|
||||||
|
|
||||||
// configs: Configs = {}
|
|
||||||
|
|
||||||
// options: Partial<Options> = {}
|
|
||||||
|
|
||||||
// protected storeConfig(key: string, value: any, stategy: MergeStrategy) {
|
|
||||||
// const item = {
|
|
||||||
// stategy,
|
|
||||||
// value,
|
|
||||||
// }
|
|
||||||
|
|
||||||
// if (this.configs[key]) {
|
|
||||||
// this.configs[key].push(item)
|
|
||||||
// } else {
|
|
||||||
// this.configs[key] = [item]
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public configure(options: Partial<Options>) {
|
|
||||||
// this.options = { ...this.options, ...options }
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public name(value: Methods['name']) {
|
|
||||||
// this.storeConfig('name', value, 'overwrite')
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public defaults(value: Options) {
|
|
||||||
// this.storeConfig('defaults', value, 'overwrite')
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public commands(value: Methods['commands']) {
|
|
||||||
// this.storeConfig('commands', value, 'overwrite')
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public keys(value: Methods['keys']) {
|
|
||||||
// this.storeConfig('keys', value, 'overwrite')
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public inputRules(value: Methods['inputRules']) {
|
|
||||||
// this.storeConfig('inputRules', value, 'overwrite')
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public pasteRules(value: Methods['pasteRules']) {
|
|
||||||
// this.storeConfig('pasteRules', value, 'overwrite')
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public plugins(value: Methods['plugins']) {
|
|
||||||
// this.storeConfig('plugins', value, 'overwrite')
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public extend<T extends Extract<keyof Methods, string>>(key: T, value: Methods[T]) {
|
|
||||||
// this.storeConfig(key, value, 'extend')
|
|
||||||
// return this
|
|
||||||
// }
|
|
||||||
|
|
||||||
// public create() {
|
|
||||||
// return <NewOptions = Options>(options?: Partial<NoInfer<NewOptions>>) => {
|
|
||||||
// return cloneDeep(this, true).configure(options as NewOptions)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
import { Editor } from './Editor'
|
import { Editor } from './Editor'
|
||||||
import { GlobalAttributes } from './types'
|
import { GlobalAttributes } from './types'
|
||||||
|
|
||||||
export interface ExtensionSpec<Options = {}, Commands = {}> {
|
export interface ExtensionSpec<Options = {}, Commands = {}> {
|
||||||
|
/**
|
||||||
|
* The name of your extension
|
||||||
|
*/
|
||||||
name: string,
|
name: string,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default options
|
||||||
|
*/
|
||||||
defaultOptions?: Options,
|
defaultOptions?: Options,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Global attributes
|
||||||
|
*/
|
||||||
addGlobalAttributes?: (
|
addGlobalAttributes?: (
|
||||||
this: {
|
this: {
|
||||||
options: Options,
|
options: Options,
|
||||||
},
|
},
|
||||||
) => GlobalAttributes,
|
) => GlobalAttributes,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Commands
|
||||||
|
*/
|
||||||
addCommands?: (this: {
|
addCommands?: (this: {
|
||||||
options: Options,
|
options: Options,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
}) => Commands,
|
}) => Commands,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Keyboard shortcuts
|
||||||
|
*/
|
||||||
addKeyboardShortcuts?: (this: {
|
addKeyboardShortcuts?: (this: {
|
||||||
options: Options,
|
options: Options,
|
||||||
editor: Editor,
|
editor: Editor,
|
||||||
}) => {
|
}) => {
|
||||||
[key: string]: any
|
[key: string]: any
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Input rules
|
||||||
|
*/
|
||||||
|
addInputRules?: (this: {
|
||||||
|
options: Options,
|
||||||
|
editor: Editor,
|
||||||
|
}) => any[],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Paste rules
|
||||||
|
*/
|
||||||
|
addPasteRules?: (this: {
|
||||||
|
options: Options,
|
||||||
|
editor: Editor,
|
||||||
|
}) => any[],
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ProseMirror plugins
|
||||||
|
*/
|
||||||
|
addProseMirrorPlugins?: (this: {
|
||||||
|
options: Options,
|
||||||
|
editor: Editor,
|
||||||
|
}) => Plugin[],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Extension interface for internal usage
|
||||||
|
*/
|
||||||
export type Extension = Required<Omit<ExtensionSpec, 'defaultOptions'> & {
|
export type Extension = Required<Omit<ExtensionSpec, 'defaultOptions'> & {
|
||||||
type: string,
|
type: string,
|
||||||
options: {
|
options: {
|
||||||
@@ -143,6 +75,9 @@ export type Extension = Required<Omit<ExtensionSpec, 'defaultOptions'> & {
|
|||||||
},
|
},
|
||||||
}>
|
}>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default extension
|
||||||
|
*/
|
||||||
export const defaultExtension: Extension = {
|
export const defaultExtension: Extension = {
|
||||||
type: 'extension',
|
type: 'extension',
|
||||||
name: 'extension',
|
name: 'extension',
|
||||||
@@ -150,6 +85,9 @@ export const defaultExtension: Extension = {
|
|||||||
addGlobalAttributes: () => [],
|
addGlobalAttributes: () => [],
|
||||||
addCommands: () => ({}),
|
addCommands: () => ({}),
|
||||||
addKeyboardShortcuts: () => ({}),
|
addKeyboardShortcuts: () => ({}),
|
||||||
|
addInputRules: () => [],
|
||||||
|
addPasteRules: () => [],
|
||||||
|
addProseMirrorPlugins: () => [],
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createExtension<Options extends {}, Commands extends {}>(config: ExtensionSpec<Options, Commands>) {
|
export function createExtension<Options extends {}, Commands extends {}>(config: ExtensionSpec<Options, Commands>) {
|
||||||
|
|||||||
@@ -1,37 +1,52 @@
|
|||||||
import { Command, Node } from '@tiptap/core'
|
import { Command, createNode } from '@tiptap/core'
|
||||||
import { wrappingInputRule } from 'prosemirror-inputrules'
|
import { wrappingInputRule } from 'prosemirror-inputrules'
|
||||||
|
|
||||||
export type BlockquoteCommand = () => Command
|
// export type BlockquoteCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
blockquote: BlockquoteCommand,
|
// blockquote: BlockquoteCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const inputRegex = /^\s*>\s$/gm
|
export const inputRegex = /^\s*>\s$/gm
|
||||||
|
|
||||||
export default new Node()
|
export default createNode({
|
||||||
.name('blockquote')
|
name: 'blockquote',
|
||||||
.schema(() => ({
|
|
||||||
content: 'block*',
|
content: 'block*',
|
||||||
group: 'block',
|
|
||||||
defining: true,
|
group: 'block',
|
||||||
draggable: false,
|
|
||||||
parseDOM: [
|
defining: true,
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
{ tag: 'blockquote' },
|
{ tag: 'blockquote' },
|
||||||
],
|
]
|
||||||
toDOM: () => ['blockquote', 0],
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ attributes }) {
|
||||||
[name]: () => ({ commands }) => {
|
return ['blockquote', attributes, 0]
|
||||||
return commands.toggleWrap(name)
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ editor }) => ({
|
return {
|
||||||
'Shift-Mod-9': () => editor.blockquote(),
|
blockquote: () => ({ commands }) => {
|
||||||
}))
|
return commands.toggleWrap('blockquote')
|
||||||
.inputRules(({ type }) => [
|
},
|
||||||
wrappingInputRule(inputRegex, type),
|
}
|
||||||
])
|
},
|
||||||
.create()
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
'Shift-Mod-9': () => this.editor.blockquote(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
wrappingInputRule(inputRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
import {
|
import {
|
||||||
Command, Mark, markInputRule, markPasteRule,
|
Command, createMark, markInputRule, markPasteRule,
|
||||||
} from '@tiptap/core'
|
} from '@tiptap/core'
|
||||||
|
|
||||||
export type BoldCommand = () => Command
|
// export type BoldCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
bold: BoldCommand,
|
// bold: BoldCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const starInputRegex = /(?:^|\s)((?:\*\*)((?:[^*]+))(?:\*\*))$/gm
|
export const starInputRegex = /(?:^|\s)((?:\*\*)((?:[^*]+))(?:\*\*))$/gm
|
||||||
export const starPasteRegex = /(?:^|\s)((?:\*\*)((?:[^*]+))(?:\*\*))/gm
|
export const starPasteRegex = /(?:^|\s)((?:\*\*)((?:[^*]+))(?:\*\*))/gm
|
||||||
export const underscoreInputRegex = /(?:^|\s)((?:__)((?:[^__]+))(?:__))$/gm
|
export const underscoreInputRegex = /(?:^|\s)((?:__)((?:[^__]+))(?:__))$/gm
|
||||||
export const underscorePasteRegex = /(?:^|\s)((?:__)((?:[^__]+))(?:__))/gm
|
export const underscorePasteRegex = /(?:^|\s)((?:__)((?:[^__]+))(?:__))/gm
|
||||||
|
|
||||||
export default new Mark()
|
export default createMark({
|
||||||
.name('bold')
|
name: 'bold',
|
||||||
.schema(() => ({
|
|
||||||
parseDOM: [
|
parseHTML() {
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
tag: 'strong',
|
tag: 'strong',
|
||||||
},
|
},
|
||||||
@@ -30,23 +31,38 @@ export default new Mark()
|
|||||||
style: 'font-weight',
|
style: 'font-weight',
|
||||||
getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value as string) && null,
|
getAttrs: value => /^(bold(er)?|[5-9]\d{2,})$/.test(value as string) && null,
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
toDOM: () => ['strong', 0],
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ attributes }) {
|
||||||
bold: () => ({ commands }) => {
|
return ['strong', attributes, 0]
|
||||||
return commands.toggleMark(name)
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ editor }) => ({
|
return {
|
||||||
'Mod-b': () => editor.bold(),
|
bold: () => ({ commands }) => {
|
||||||
}))
|
return commands.toggleMark('bold')
|
||||||
.inputRules(({ type }) => [
|
},
|
||||||
markInputRule(starInputRegex, type),
|
}
|
||||||
markInputRule(underscoreInputRegex, type),
|
},
|
||||||
])
|
|
||||||
.pasteRules(({ type }) => [
|
addKeyboardShortcuts() {
|
||||||
markPasteRule(starPasteRegex, type),
|
return {
|
||||||
markPasteRule(underscorePasteRegex, type),
|
'Mod-b': () => this.editor.bold(),
|
||||||
])
|
}
|
||||||
.create()
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
markInputRule(starInputRegex, this.type),
|
||||||
|
markInputRule(underscoreInputRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addPasteRules() {
|
||||||
|
return [
|
||||||
|
markPasteRule(starPasteRegex, this.type),
|
||||||
|
markPasteRule(underscorePasteRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,33 +1,48 @@
|
|||||||
import { Command, Node } from '@tiptap/core'
|
import { Command, createNode } from '@tiptap/core'
|
||||||
import { wrappingInputRule } from 'prosemirror-inputrules'
|
import { wrappingInputRule } from 'prosemirror-inputrules'
|
||||||
|
|
||||||
export type BulletListCommand = () => Command
|
// export type BulletListCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
bulletList: BulletListCommand,
|
// bulletList: BulletListCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default new Node()
|
export default createNode({
|
||||||
.name('bullet_list')
|
name: 'bullet_list',
|
||||||
.schema(() => ({
|
|
||||||
content: 'list_item+',
|
content: 'list_item+',
|
||||||
group: 'block',
|
|
||||||
parseDOM: [
|
group: 'block',
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
{ tag: 'ul' },
|
{ tag: 'ul' },
|
||||||
],
|
]
|
||||||
toDOM: () => ['ul', 0],
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ attributes }) {
|
||||||
bulletList: () => ({ commands }) => {
|
return ['ul', attributes, 0]
|
||||||
return commands.toggleList(name, 'list_item')
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ editor }) => ({
|
return {
|
||||||
'Shift-Control-8': () => editor.bulletList(),
|
bulletList: () => ({ commands }) => {
|
||||||
}))
|
return commands.toggleList('bullet_list', 'list_item')
|
||||||
.inputRules(({ type }) => [
|
},
|
||||||
wrappingInputRule(/^\s*([-+*])\s$/, type),
|
}
|
||||||
])
|
},
|
||||||
.create()
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
'Shift-Control-8': () => this.editor.bulletList(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
wrappingInputRule(/^\s*([-+*])\s$/, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,69 +1,91 @@
|
|||||||
import { Command, Node } from '@tiptap/core'
|
import { Command, createNode } from '@tiptap/core'
|
||||||
import { textblockTypeInputRule } from 'prosemirror-inputrules'
|
import { textblockTypeInputRule } from 'prosemirror-inputrules'
|
||||||
|
|
||||||
export interface CodeBlockOptions {
|
export interface CodeBlockOptions {
|
||||||
languageClassPrefix: string,
|
languageClassPrefix: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type CodeBlockCommand = () => Command
|
// export type CodeBlockCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
codeBlock: CodeBlockCommand,
|
// codeBlock: CodeBlockCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const backtickInputRegex = /^```(?<language>[a-z]*)? $/
|
export const backtickInputRegex = /^```(?<language>[a-z]*)? $/
|
||||||
export const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/
|
export const tildeInputRegex = /^~~~(?<language>[a-z]*)? $/
|
||||||
|
|
||||||
export default new Node<CodeBlockOptions>()
|
export default createNode({
|
||||||
.name('code_block')
|
name: 'code_block',
|
||||||
.defaults({
|
|
||||||
|
defaultOptions: <CodeBlockOptions>{
|
||||||
languageClassPrefix: 'language-',
|
languageClassPrefix: 'language-',
|
||||||
})
|
},
|
||||||
.schema(({ options }) => ({
|
|
||||||
attrs: {
|
content: 'text*',
|
||||||
|
|
||||||
|
marks: '',
|
||||||
|
|
||||||
|
group: 'block',
|
||||||
|
|
||||||
|
code: true,
|
||||||
|
|
||||||
|
defining: true,
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
language: {
|
language: {
|
||||||
default: null,
|
default: null,
|
||||||
|
rendered: false,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
content: 'text*',
|
},
|
||||||
marks: '',
|
|
||||||
group: 'block',
|
parseHTML() {
|
||||||
code: true,
|
return [
|
||||||
defining: true,
|
|
||||||
draggable: false,
|
|
||||||
parseDOM: [
|
|
||||||
{
|
{
|
||||||
tag: 'pre',
|
tag: 'pre',
|
||||||
preserveWhitespace: 'full',
|
preserveWhitespace: 'full',
|
||||||
getAttrs(node) {
|
getAttrs: node => {
|
||||||
const classAttribute = (node as Element).firstElementChild?.getAttribute('class')
|
const classAttribute = (node as Element).firstElementChild?.getAttribute('class')
|
||||||
|
|
||||||
if (!classAttribute) {
|
if (!classAttribute) {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
const regexLanguageClassPrefix = new RegExp(`^(${options.languageClassPrefix})`)
|
const regexLanguageClassPrefix = new RegExp(`^(${this.options.languageClassPrefix})`)
|
||||||
|
|
||||||
return { language: classAttribute.replace(regexLanguageClassPrefix, '') }
|
return { language: classAttribute.replace(regexLanguageClassPrefix, '') }
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
toDOM: node => ['pre', ['code', {
|
},
|
||||||
class: node.attrs.language && options.languageClassPrefix + node.attrs.language,
|
|
||||||
}, 0]],
|
renderHTML({ node, attributes }) {
|
||||||
}))
|
return ['pre', attributes, ['code', {
|
||||||
.commands(({ name }) => ({
|
class: node.attrs.language && this.options.languageClassPrefix + node.attrs.language,
|
||||||
codeBlock: attrs => ({ commands }) => {
|
}, 0]]
|
||||||
return commands.toggleBlockType(name, 'paragraph', attrs)
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ editor }) => ({
|
return {
|
||||||
'Mod-Shift-c': () => editor.codeBlock(),
|
codeBlock: attrs => ({ commands }) => {
|
||||||
}))
|
return commands.toggleBlockType('code_block', 'paragraph', attrs)
|
||||||
.inputRules(({ type }) => [
|
},
|
||||||
textblockTypeInputRule(backtickInputRegex, type, ({ groups }: any) => groups),
|
}
|
||||||
textblockTypeInputRule(tildeInputRegex, type, ({ groups }: any) => groups),
|
},
|
||||||
])
|
|
||||||
.create()
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
'Mod-Shift-c': () => this.editor.codeBlock(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
textblockTypeInputRule(backtickInputRegex, this.type, ({ groups }: any) => groups),
|
||||||
|
textblockTypeInputRule(tildeInputRegex, this.type, ({ groups }: any) => groups),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,39 +1,56 @@
|
|||||||
import {
|
import {
|
||||||
Command, Mark, markInputRule, markPasteRule,
|
Command, createMark, markInputRule, markPasteRule,
|
||||||
} from '@tiptap/core'
|
} from '@tiptap/core'
|
||||||
|
|
||||||
export type CodeCommand = () => Command
|
// export type CodeCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
code: CodeCommand,
|
// code: CodeCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const inputRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))$/gm
|
export const inputRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))$/gm
|
||||||
export const pasteRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))/gm
|
export const pasteRegex = /(?:^|\s)((?:`)((?:[^`]+))(?:`))/gm
|
||||||
|
|
||||||
export default new Mark()
|
export default createMark({
|
||||||
.name('code')
|
name: 'code',
|
||||||
.schema(() => ({
|
|
||||||
excludes: '_',
|
excludes: '_',
|
||||||
parseDOM: [
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
{ tag: 'code' },
|
{ tag: 'code' },
|
||||||
],
|
]
|
||||||
toDOM: () => ['code', 0],
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ attributes }) {
|
||||||
code: () => ({ commands }) => {
|
return ['strong', attributes, 0]
|
||||||
return commands.toggleMark(name)
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ editor }) => ({
|
return {
|
||||||
'Mod-`': () => editor.code(),
|
code: () => ({ commands }) => {
|
||||||
}))
|
return commands.toggleMark('code')
|
||||||
.inputRules(({ type }) => [
|
},
|
||||||
markInputRule(inputRegex, type),
|
}
|
||||||
])
|
},
|
||||||
.pasteRules(({ type }) => [
|
|
||||||
markPasteRule(inputRegex, type),
|
addKeyboardShortcuts() {
|
||||||
])
|
return {
|
||||||
.create()
|
'Mod-`': () => this.editor.code(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
markInputRule(inputRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addPasteRules() {
|
||||||
|
return [
|
||||||
|
markPasteRule(inputRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Extension, Command } from '@tiptap/core'
|
import { createExtension, Command } from '@tiptap/core'
|
||||||
import { yCursorPlugin } from 'y-prosemirror'
|
import { yCursorPlugin } from 'y-prosemirror'
|
||||||
|
|
||||||
export interface CollaborationCursorOptions {
|
export interface CollaborationCursorOptions {
|
||||||
@@ -8,27 +8,21 @@ export interface CollaborationCursorOptions {
|
|||||||
render (user: { name: string, color: string }): HTMLElement,
|
render (user: { name: string, color: string }): HTMLElement,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type UserCommand = (attributes: {
|
// export type UserCommand = (attributes: {
|
||||||
name: string,
|
// name: string,
|
||||||
color: string,
|
// color: string,
|
||||||
}) => Command
|
// }) => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
user: UserCommand,
|
// user: UserCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default new Extension<CollaborationCursorOptions>()
|
export default createExtension({
|
||||||
.name('collaboration_cursor')
|
name: 'collaboration_cursor',
|
||||||
.commands(({ options }) => ({
|
|
||||||
user: attributes => () => {
|
|
||||||
options.provider.awareness.setLocalStateField('user', attributes)
|
|
||||||
|
|
||||||
return true
|
defaultOptions: <CollaborationCursorOptions>{
|
||||||
},
|
|
||||||
}))
|
|
||||||
.defaults({
|
|
||||||
provider: null,
|
provider: null,
|
||||||
name: 'Someone',
|
name: 'Someone',
|
||||||
color: '#cccccc',
|
color: '#cccccc',
|
||||||
@@ -45,19 +39,32 @@ export default new Extension<CollaborationCursorOptions>()
|
|||||||
|
|
||||||
return cursor
|
return cursor
|
||||||
},
|
},
|
||||||
})
|
},
|
||||||
.plugins(({ options }) => [
|
|
||||||
yCursorPlugin((() => {
|
|
||||||
options.provider.awareness.setLocalStateField('user', {
|
|
||||||
name: options.name,
|
|
||||||
color: options.color,
|
|
||||||
})
|
|
||||||
|
|
||||||
return options.provider.awareness
|
addCommands() {
|
||||||
})(),
|
return {
|
||||||
// @ts-ignore
|
user: attributes => () => {
|
||||||
{
|
this.options.provider.awareness.setLocalStateField('user', attributes)
|
||||||
cursorBuilder: options.render,
|
|
||||||
}),
|
return true
|
||||||
])
|
},
|
||||||
.create()
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addProseMirrorPlugins() {
|
||||||
|
return [
|
||||||
|
yCursorPlugin((() => {
|
||||||
|
this.options.provider.awareness.setLocalStateField('user', {
|
||||||
|
name: this.options.name,
|
||||||
|
color: this.options.color,
|
||||||
|
})
|
||||||
|
|
||||||
|
return this.options.provider.awareness
|
||||||
|
})(),
|
||||||
|
// @ts-ignore
|
||||||
|
{
|
||||||
|
cursorBuilder: this.options.render,
|
||||||
|
}),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Extension } from '@tiptap/core'
|
import { createExtension } from '@tiptap/core'
|
||||||
import {
|
import {
|
||||||
redo, undo, ySyncPlugin, yUndoPlugin,
|
redo, undo, ySyncPlugin, yUndoPlugin,
|
||||||
} from 'y-prosemirror'
|
} from 'y-prosemirror'
|
||||||
@@ -8,21 +8,26 @@ export interface CollaborationOptions {
|
|||||||
type: any,
|
type: any,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Extension<CollaborationOptions>()
|
export default createExtension({
|
||||||
.name('collaboration')
|
name: 'collaboration',
|
||||||
.defaults({
|
|
||||||
|
defaultOptions: <CollaborationOptions>{
|
||||||
provider: null,
|
provider: null,
|
||||||
type: null,
|
type: null,
|
||||||
})
|
},
|
||||||
.plugins(({ options }) => [
|
|
||||||
ySyncPlugin(options.type),
|
addProseMirrorPlugins() {
|
||||||
yUndoPlugin(),
|
return [
|
||||||
])
|
ySyncPlugin(this.options.type),
|
||||||
.keys(() => {
|
yUndoPlugin(),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
return {
|
return {
|
||||||
'Mod-z': undo,
|
'Mod-z': undo,
|
||||||
'Mod-y': redo,
|
'Mod-y': redo,
|
||||||
'Mod-Shift-z': redo,
|
'Mod-Shift-z': redo,
|
||||||
}
|
}
|
||||||
})
|
},
|
||||||
.create()
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Extension } from '@tiptap/core'
|
import { createExtension } from '@tiptap/core'
|
||||||
import { Plugin } from 'prosemirror-state'
|
import { Plugin } from 'prosemirror-state'
|
||||||
import { DecorationSet, Decoration } from 'prosemirror-view'
|
import { DecorationSet, Decoration } from 'prosemirror-view'
|
||||||
|
|
||||||
@@ -7,40 +7,44 @@ export interface FocusOptions {
|
|||||||
nested: boolean,
|
nested: boolean,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Extension<FocusOptions>()
|
export default createExtension({
|
||||||
.name('focus')
|
name: 'focus',
|
||||||
.defaults({
|
|
||||||
|
defaultOptions: <FocusOptions>{
|
||||||
className: 'has-focus',
|
className: 'has-focus',
|
||||||
nested: false,
|
nested: false,
|
||||||
})
|
},
|
||||||
.plugins(({ editor, options }) => [
|
|
||||||
new Plugin({
|
|
||||||
props: {
|
|
||||||
decorations: ({ doc, selection }) => {
|
|
||||||
const { isEditable, isFocused } = editor
|
|
||||||
const { anchor } = selection
|
|
||||||
const decorations: Decoration[] = []
|
|
||||||
|
|
||||||
if (!isEditable || !isFocused) {
|
addProseMirrorPlugins() {
|
||||||
return DecorationSet.create(doc, [])
|
return [
|
||||||
}
|
new Plugin({
|
||||||
|
props: {
|
||||||
|
decorations: ({ doc, selection }) => {
|
||||||
|
const { isEditable, isFocused } = this.editor
|
||||||
|
const { anchor } = selection
|
||||||
|
const decorations: Decoration[] = []
|
||||||
|
|
||||||
doc.descendants((node, pos) => {
|
if (!isEditable || !isFocused) {
|
||||||
const hasAnchor = anchor >= pos && anchor <= (pos + node.nodeSize)
|
return DecorationSet.create(doc, [])
|
||||||
|
|
||||||
if (hasAnchor && !node.isText) {
|
|
||||||
const decoration = Decoration.node(pos, pos + node.nodeSize, {
|
|
||||||
class: options.className,
|
|
||||||
})
|
|
||||||
decorations.push(decoration)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return options.nested
|
doc.descendants((node, pos) => {
|
||||||
})
|
const hasAnchor = anchor >= pos && anchor <= (pos + node.nodeSize)
|
||||||
|
|
||||||
return DecorationSet.create(doc, decorations)
|
if (hasAnchor && !node.isText) {
|
||||||
|
const decoration = Decoration.node(pos, pos + node.nodeSize, {
|
||||||
|
class: this.options.className,
|
||||||
|
})
|
||||||
|
decorations.push(decoration)
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.options.nested
|
||||||
|
})
|
||||||
|
|
||||||
|
return DecorationSet.create(doc, decorations)
|
||||||
|
},
|
||||||
},
|
},
|
||||||
},
|
}),
|
||||||
}),
|
]
|
||||||
])
|
},
|
||||||
.create()
|
})
|
||||||
|
|||||||
@@ -1,37 +1,50 @@
|
|||||||
import { Command, Node } from '@tiptap/core'
|
import { Command, createNode } from '@tiptap/core'
|
||||||
import { chainCommands, exitCode } from 'prosemirror-commands'
|
import { chainCommands, exitCode } from 'prosemirror-commands'
|
||||||
|
|
||||||
export type HardBreakCommand = () => Command
|
// export type HardBreakCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
hardBreak: HardBreakCommand,
|
// hardBreak: HardBreakCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default new Node()
|
export default createNode({
|
||||||
.name('hardBreak')
|
name: 'hardBreak',
|
||||||
.schema(() => ({
|
|
||||||
inline: true,
|
inline: true,
|
||||||
group: 'inline',
|
|
||||||
selectable: false,
|
group: 'inline',
|
||||||
parseDOM: [
|
|
||||||
|
selectable: false,
|
||||||
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
{ tag: 'br' },
|
{ tag: 'br' },
|
||||||
],
|
]
|
||||||
toDOM: () => ['br'],
|
},
|
||||||
}))
|
|
||||||
.commands(({ type }) => ({
|
renderHTML({ attributes }) {
|
||||||
hardBreak: () => ({
|
return ['br', attributes]
|
||||||
tr, state, dispatch, view,
|
},
|
||||||
}) => {
|
|
||||||
return chainCommands(exitCode, () => {
|
addCommands() {
|
||||||
dispatch(tr.replaceSelectionWith(type.create()).scrollIntoView())
|
return {
|
||||||
return true
|
hardBreak: () => ({
|
||||||
})(state, dispatch, view)
|
tr, state, dispatch, view,
|
||||||
},
|
}) => {
|
||||||
}))
|
return chainCommands(exitCode, () => {
|
||||||
.keys(({ editor }) => ({
|
dispatch(tr.replaceSelectionWith(this.type.create()).scrollIntoView())
|
||||||
'Mod-Enter': () => editor.hardBreak(),
|
return true
|
||||||
'Shift-Enter': () => editor.hardBreak(),
|
})(state, dispatch, view)
|
||||||
}))
|
},
|
||||||
.create()
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
'Mod-Enter': () => this.editor.hardBreak(),
|
||||||
|
'Shift-Enter': () => this.editor.hardBreak(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { Command, Node } from '@tiptap/core'
|
import { Command, createNode } from '@tiptap/core'
|
||||||
import { textblockTypeInputRule } from 'prosemirror-inputrules'
|
import { textblockTypeInputRule } from 'prosemirror-inputrules'
|
||||||
|
|
||||||
type Level = 1 | 2 | 3 | 4 | 5 | 6
|
type Level = 1 | 2 | 3 | 4 | 5 | 6
|
||||||
@@ -7,52 +7,68 @@ export interface HeadingOptions {
|
|||||||
levels: Level[],
|
levels: Level[],
|
||||||
}
|
}
|
||||||
|
|
||||||
export type HeadingCommand = (options: { level: Level }) => Command
|
// export type HeadingCommand = (options: { level: Level }) => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
heading: HeadingCommand,
|
// heading: HeadingCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default new Node<HeadingOptions>()
|
export default createNode({
|
||||||
.name('heading')
|
name: 'heading',
|
||||||
.defaults({
|
|
||||||
|
defaultOptions: <HeadingOptions>{
|
||||||
levels: [1, 2, 3, 4, 5, 6],
|
levels: [1, 2, 3, 4, 5, 6],
|
||||||
})
|
},
|
||||||
.schema(({ options }) => ({
|
|
||||||
attrs: {
|
content: 'inline*',
|
||||||
|
|
||||||
|
group: 'block',
|
||||||
|
|
||||||
|
defining: true,
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
level: {
|
level: {
|
||||||
default: 1,
|
default: 1,
|
||||||
|
rendered: false,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
content: 'inline*',
|
},
|
||||||
group: 'block',
|
|
||||||
defining: true,
|
parseHTML() {
|
||||||
draggable: false,
|
return this.options.levels
|
||||||
parseDOM: options.levels
|
|
||||||
.map((level: Level) => ({
|
.map((level: Level) => ({
|
||||||
tag: `h${level}`,
|
tag: `h${level}`,
|
||||||
attrs: { level },
|
attrs: { level },
|
||||||
})),
|
}))
|
||||||
toDOM: node => [`h${node.attrs.level}`, 0],
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ node, attributes }) {
|
||||||
heading: attrs => ({ commands }) => {
|
return [`h${node.attrs.level}`, attributes, 0]
|
||||||
return commands.toggleBlockType(name, 'paragraph', attrs)
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ name, options, editor }) => {
|
return {
|
||||||
return options.levels.reduce((items, level) => ({
|
heading: attrs => ({ commands }) => {
|
||||||
|
return commands.toggleBlockType('heading', 'paragraph', attrs)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return this.options.levels.reduce((items, level) => ({
|
||||||
...items,
|
...items,
|
||||||
...{
|
...{
|
||||||
[`Mod-Alt-${level}`]: () => editor.setBlockType(name, { level }),
|
[`Mod-Alt-${level}`]: () => this.editor.setBlockType('heading', { level }),
|
||||||
},
|
},
|
||||||
}), {})
|
}), {})
|
||||||
})
|
},
|
||||||
.inputRules(({ options, type }) => {
|
|
||||||
return options.levels.map((level: Level) => {
|
addInputRules() {
|
||||||
return textblockTypeInputRule(new RegExp(`^(#{1,${level}})\\s$`), type, { level })
|
return this.options.levels.map(level => {
|
||||||
|
return textblockTypeInputRule(new RegExp(`^(#{1,${level}})\\s$`), this.type, { level })
|
||||||
})
|
})
|
||||||
})
|
},
|
||||||
.create()
|
})
|
||||||
|
|||||||
@@ -1,42 +1,52 @@
|
|||||||
import { Command, Extension } from '@tiptap/core'
|
import { Command, createExtension } from '@tiptap/core'
|
||||||
import {
|
import {
|
||||||
history,
|
history,
|
||||||
undo,
|
undo,
|
||||||
redo,
|
redo,
|
||||||
} from 'prosemirror-history'
|
} from 'prosemirror-history'
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
undo: () => Command,
|
// undo: () => Command,
|
||||||
redo: () => Command,
|
// redo: () => Command,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export interface HistoryOptions {
|
export interface HistoryOptions {
|
||||||
depth: number,
|
depth: number,
|
||||||
newGroupDelay: number,
|
newGroupDelay: number,
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new Extension<HistoryOptions>()
|
export default createExtension({
|
||||||
.name('history')
|
name: 'history',
|
||||||
.defaults({
|
|
||||||
|
defaultOptions: <HistoryOptions>{
|
||||||
depth: 100,
|
depth: 100,
|
||||||
newGroupDelay: 500,
|
newGroupDelay: 500,
|
||||||
})
|
},
|
||||||
.commands(() => ({
|
|
||||||
undo: () => ({ state, dispatch }) => {
|
addCommands() {
|
||||||
return undo(state, dispatch)
|
return {
|
||||||
},
|
undo: () => ({ state, dispatch }) => {
|
||||||
redo: () => ({ state, dispatch }) => {
|
return undo(state, dispatch)
|
||||||
return redo(state, dispatch)
|
},
|
||||||
},
|
redo: () => ({ state, dispatch }) => {
|
||||||
}))
|
return redo(state, dispatch)
|
||||||
.keys(({ editor }) => ({
|
},
|
||||||
'Mod-z': () => editor.undo(),
|
}
|
||||||
'Mod-y': () => editor.redo(),
|
},
|
||||||
'Shift-Mod-z': () => editor.redo(),
|
|
||||||
}))
|
addProseMirrorPlugins() {
|
||||||
.plugins(({ options }) => [
|
return [
|
||||||
history(options),
|
history(this.options),
|
||||||
])
|
]
|
||||||
.create()
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
'Mod-z': () => this.editor.undo(),
|
||||||
|
'Mod-y': () => this.editor.redo(),
|
||||||
|
'Shift-Mod-z': () => this.editor.redo(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,28 +1,41 @@
|
|||||||
import { Command, Node, nodeInputRule } from '@tiptap/core'
|
import { Command, createNode, nodeInputRule } from '@tiptap/core'
|
||||||
|
|
||||||
export type HorizontalRuleCommand = () => Command
|
// export type HorizontalRuleCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
horizontalRule: HorizontalRuleCommand,
|
// horizontalRule: HorizontalRuleCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default new Node()
|
export default createNode({
|
||||||
.name('horizontalRule')
|
name: 'horizontalRule',
|
||||||
.schema(() => ({
|
|
||||||
group: 'block',
|
|
||||||
parseDOM: [{ tag: 'hr' }],
|
|
||||||
toDOM: () => ['hr'],
|
|
||||||
}))
|
|
||||||
.commands(({ type }) => ({
|
|
||||||
horizontalRule: () => ({ tr }) => {
|
|
||||||
tr.replaceSelectionWith(type.create())
|
|
||||||
|
|
||||||
return true
|
group: 'block',
|
||||||
},
|
|
||||||
}))
|
parseHTML() {
|
||||||
.inputRules(({ type }) => [
|
return [
|
||||||
nodeInputRule(/^(?:---|___\s|\*\*\*\s)$/, type),
|
{ tag: 'hr' },
|
||||||
])
|
]
|
||||||
.create()
|
},
|
||||||
|
|
||||||
|
renderHTML({ attributes }) {
|
||||||
|
return ['hr', attributes]
|
||||||
|
},
|
||||||
|
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
horizontalRule: () => ({ tr }) => {
|
||||||
|
tr.replaceSelectionWith(this.type.create())
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
nodeInputRule(/^(?:---|___\s|\*\*\*\s)$/, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,24 +1,25 @@
|
|||||||
import {
|
import {
|
||||||
Command, Mark, markInputRule, markPasteRule,
|
Command, createMark, markInputRule, markPasteRule,
|
||||||
} from '@tiptap/core'
|
} from '@tiptap/core'
|
||||||
|
|
||||||
export type ItalicCommand = () => Command
|
// export type ItalicCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
italic: ItalicCommand,
|
// italic: ItalicCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const starInputRegex = /(?:^|\s)((?:\*)((?:[^*]+))(?:\*))$/gm
|
export const starInputRegex = /(?:^|\s)((?:\*)((?:[^*]+))(?:\*))$/gm
|
||||||
export const starPasteRegex = /(?:^|\s)((?:\*)((?:[^*]+))(?:\*))/gm
|
export const starPasteRegex = /(?:^|\s)((?:\*)((?:[^*]+))(?:\*))/gm
|
||||||
export const underscoreInputRegex = /(?:^|\s)((?:_)((?:[^_]+))(?:_))$/gm
|
export const underscoreInputRegex = /(?:^|\s)((?:_)((?:[^_]+))(?:_))$/gm
|
||||||
export const underscorePasteRegex = /(?:^|\s)((?:_)((?:[^_]+))(?:_))/gm
|
export const underscorePasteRegex = /(?:^|\s)((?:_)((?:[^_]+))(?:_))/gm
|
||||||
|
|
||||||
export default new Mark()
|
export default createMark({
|
||||||
.name('italic')
|
name: 'italic',
|
||||||
.schema(() => ({
|
|
||||||
parseDOM: [
|
parseHTML() {
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
tag: 'em',
|
tag: 'em',
|
||||||
},
|
},
|
||||||
@@ -29,23 +30,38 @@ export default new Mark()
|
|||||||
{
|
{
|
||||||
style: 'font-style=italic',
|
style: 'font-style=italic',
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
toDOM: () => ['em', 0],
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ attributes }) {
|
||||||
italic: () => ({ commands }) => {
|
return ['em', attributes, 0]
|
||||||
return commands.toggleMark(name)
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ editor }) => ({
|
return {
|
||||||
'Mod-i': () => editor.italic(),
|
italic: () => ({ commands }) => {
|
||||||
}))
|
return commands.toggleMark('italic')
|
||||||
.inputRules(({ type }) => [
|
},
|
||||||
markInputRule(starInputRegex, type),
|
}
|
||||||
markInputRule(underscoreInputRegex, type),
|
},
|
||||||
])
|
|
||||||
.pasteRules(({ type }) => [
|
addKeyboardShortcuts() {
|
||||||
markPasteRule(starPasteRegex, type),
|
return {
|
||||||
markPasteRule(underscorePasteRegex, type),
|
'Mod-i': () => this.editor.italic(),
|
||||||
])
|
}
|
||||||
.create()
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
markInputRule(starInputRegex, this.type),
|
||||||
|
markInputRule(underscoreInputRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addPasteRules() {
|
||||||
|
return [
|
||||||
|
markPasteRule(starPasteRegex, this.type),
|
||||||
|
markPasteRule(underscorePasteRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import {
|
import {
|
||||||
Command, Mark, markPasteRule,
|
Command, createMark, markPasteRule,
|
||||||
} from '@tiptap/core'
|
} from '@tiptap/core'
|
||||||
import { Plugin, PluginKey } from 'prosemirror-state'
|
import { Plugin, PluginKey } from 'prosemirror-state'
|
||||||
|
|
||||||
@@ -9,34 +9,42 @@ export interface LinkOptions {
|
|||||||
rel: string,
|
rel: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LinkCommand = (options: {href?: string, target?: string}) => Command
|
// export type LinkCommand = (options: {href?: string, target?: string}) => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
link: LinkCommand,
|
// link: LinkCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%_+.~#?&//=]*)/gi
|
export const pasteRegex = /https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z]{2,}\b(?:[-a-zA-Z0-9@:%_+.~#?&//=]*)/gi
|
||||||
|
|
||||||
export default new Mark<LinkOptions>()
|
export default createMark({
|
||||||
.name('link')
|
name: 'link',
|
||||||
.defaults({
|
|
||||||
|
inclusive: false,
|
||||||
|
|
||||||
|
defaultOptions: <LinkOptions>{
|
||||||
openOnClick: true,
|
openOnClick: true,
|
||||||
target: '_blank',
|
target: '_blank',
|
||||||
rel: 'noopener noreferrer nofollow',
|
rel: 'noopener noreferrer nofollow',
|
||||||
})
|
},
|
||||||
.schema(({ options }) => ({
|
|
||||||
attrs: {
|
addAttributes() {
|
||||||
|
return {
|
||||||
href: {
|
href: {
|
||||||
default: null,
|
default: null,
|
||||||
|
rendered: false,
|
||||||
},
|
},
|
||||||
target: {
|
target: {
|
||||||
default: null,
|
default: null,
|
||||||
|
rendered: false,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
inclusive: false,
|
},
|
||||||
parseDOM: [
|
|
||||||
|
parseHTML() {
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
tag: 'a[href]',
|
tag: 'a[href]',
|
||||||
getAttrs: node => ({
|
getAttrs: node => ({
|
||||||
@@ -44,27 +52,44 @@ export default new Mark<LinkOptions>()
|
|||||||
target: (node as HTMLElement).getAttribute('target'),
|
target: (node as HTMLElement).getAttribute('target'),
|
||||||
}),
|
}),
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
toDOM: node => ['a', {
|
},
|
||||||
...node.attrs,
|
|
||||||
rel: options.rel,
|
|
||||||
target: node.attrs.target ? node.attrs.target : options.target,
|
|
||||||
}, 0],
|
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
|
||||||
link: attributes => ({ commands }) => {
|
|
||||||
if (!attributes.href) {
|
|
||||||
return commands.removeMark(name)
|
|
||||||
}
|
|
||||||
|
|
||||||
return commands.updateMark(name, attributes)
|
renderHTML({ mark, attributes }) {
|
||||||
},
|
return ['a', {
|
||||||
}))
|
...attributes,
|
||||||
.pasteRules(({ type }) => [
|
...mark.attrs,
|
||||||
markPasteRule(pasteRegex, type, (url: string) => ({ href: url })),
|
rel: this.options.rel,
|
||||||
])
|
target: mark.attrs.target ? mark.attrs.target : this.options.target,
|
||||||
.plugins(({ editor, options, name }) => {
|
}, 0]
|
||||||
if (!options.openOnClick) {
|
},
|
||||||
|
|
||||||
|
addCommands() {
|
||||||
|
return {
|
||||||
|
link: attributes => ({ commands }) => {
|
||||||
|
if (!attributes.href) {
|
||||||
|
return commands.removeMark('link')
|
||||||
|
}
|
||||||
|
|
||||||
|
return commands.updateMark('link', attributes)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
'Mod-i': () => this.editor.italic(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addPasteRules() {
|
||||||
|
return [
|
||||||
|
markPasteRule(pasteRegex, this.type, (url: string) => ({ href: url })),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addProseMirrorPlugins() {
|
||||||
|
if (!this.options.openOnClick) {
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,7 +98,7 @@ export default new Mark<LinkOptions>()
|
|||||||
key: new PluginKey('handleClick'),
|
key: new PluginKey('handleClick'),
|
||||||
props: {
|
props: {
|
||||||
handleClick: (view, pos, event) => {
|
handleClick: (view, pos, event) => {
|
||||||
const attrs = editor.getMarkAttrs(name)
|
const attrs = this.editor.getMarkAttrs('link')
|
||||||
|
|
||||||
if (attrs.href && event.target instanceof HTMLAnchorElement) {
|
if (attrs.href && event.target instanceof HTMLAnchorElement) {
|
||||||
window.open(attrs.href, attrs.target)
|
window.open(attrs.href, attrs.target)
|
||||||
@@ -86,5 +111,5 @@ export default new Mark<LinkOptions>()
|
|||||||
},
|
},
|
||||||
}),
|
}),
|
||||||
]
|
]
|
||||||
})
|
},
|
||||||
.create()
|
})
|
||||||
|
|||||||
@@ -1,17 +1,27 @@
|
|||||||
import { Node } from '@tiptap/core'
|
import { createNode } from '@tiptap/core'
|
||||||
|
|
||||||
export default new Node()
|
export default createNode({
|
||||||
.name('list_item')
|
name: 'list_item',
|
||||||
.schema(() => ({
|
|
||||||
content: 'paragraph block*',
|
content: 'paragraph block*',
|
||||||
defining: true,
|
|
||||||
draggable: false,
|
defining: true,
|
||||||
parseDOM: [{ tag: 'li' }],
|
|
||||||
toDOM: () => ['li', 0],
|
parseHTML() {
|
||||||
}))
|
return [
|
||||||
.keys(({ editor, name }) => ({
|
{ tag: 'li' },
|
||||||
Enter: () => editor.splitListItem(name),
|
]
|
||||||
Tab: () => editor.sinkListItem(name),
|
},
|
||||||
'Shift-Tab': () => editor.liftListItem(name),
|
|
||||||
}))
|
renderHTML({ attributes }) {
|
||||||
.create()
|
return ['li', attributes, 0]
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
Enter: () => this.editor.splitListItem('list_item'),
|
||||||
|
Tab: () => this.editor.sinkListItem('list_item'),
|
||||||
|
'Shift-Tab': () => this.editor.liftListItem('list_item'),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,51 +1,71 @@
|
|||||||
import { Command, Node } from '@tiptap/core'
|
import { Command, createNode } from '@tiptap/core'
|
||||||
import { wrappingInputRule } from 'prosemirror-inputrules'
|
import { wrappingInputRule } from 'prosemirror-inputrules'
|
||||||
|
|
||||||
export type OrderedListCommand = () => Command
|
// export type OrderedListCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
orderedList: OrderedListCommand,
|
// orderedList: OrderedListCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default new Node()
|
export default createNode({
|
||||||
.name('ordered_list')
|
name: 'ordered_list',
|
||||||
.schema(() => ({
|
|
||||||
attrs: {
|
content: 'list_item+',
|
||||||
|
|
||||||
|
group: 'block',
|
||||||
|
|
||||||
|
addAttributes() {
|
||||||
|
return {
|
||||||
order: {
|
order: {
|
||||||
default: 1,
|
default: 1,
|
||||||
|
rendered: false,
|
||||||
},
|
},
|
||||||
},
|
}
|
||||||
content: 'list_item+',
|
},
|
||||||
group: 'block',
|
|
||||||
parseDOM: [{
|
parseHTML() {
|
||||||
tag: 'ol',
|
return [
|
||||||
getAttrs: node => ({
|
{
|
||||||
order: (node as HTMLElement).hasAttribute('start')
|
tag: 'ol',
|
||||||
? parseInt((node as HTMLElement).getAttribute('start') || '', 10)
|
getAttrs: node => ({
|
||||||
: 1,
|
order: (node as HTMLElement).hasAttribute('start')
|
||||||
}),
|
? parseInt((node as HTMLElement).getAttribute('start') || '', 10)
|
||||||
}],
|
: 1,
|
||||||
toDOM: node => (node.attrs.order === 1
|
}),
|
||||||
? ['ol', 0]
|
},
|
||||||
: ['ol', { start: node.attrs.order }, 0]
|
]
|
||||||
),
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ node, attributes }) {
|
||||||
orderedList: () => ({ commands }) => {
|
return node.attrs.order === 1
|
||||||
return commands.toggleList(name, 'list_item')
|
? ['ol', attributes, 0]
|
||||||
},
|
: ['ol', { ...attributes, start: node.attrs.order }, 0]
|
||||||
}))
|
},
|
||||||
.keys(({ editor }) => ({
|
|
||||||
'Shift-Control-9': () => editor.orderedList(),
|
addCommands() {
|
||||||
}))
|
return {
|
||||||
.inputRules(({ type }) => [
|
orderedList: () => ({ commands }) => {
|
||||||
wrappingInputRule(
|
return commands.toggleList('ordered_list', 'list_item')
|
||||||
/^(\d+)\.\s$/,
|
},
|
||||||
type,
|
}
|
||||||
match => ({ order: +match[1] }),
|
},
|
||||||
(match, node) => node.childCount + node.attrs.order === +match[1],
|
|
||||||
),
|
addKeyboardShortcuts() {
|
||||||
])
|
return {
|
||||||
.create()
|
'Shift-Control-9': () => this.editor.orderedList(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
wrappingInputRule(
|
||||||
|
/^(\d+)\.\s$/,
|
||||||
|
this.type,
|
||||||
|
match => ({ order: +match[1] }),
|
||||||
|
(match, node) => node.childCount + node.attrs.order === +match[1],
|
||||||
|
),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -16,35 +16,35 @@ export default createNode({
|
|||||||
|
|
||||||
content: 'inline*',
|
content: 'inline*',
|
||||||
|
|
||||||
addGlobalAttributes() {
|
// addGlobalAttributes() {
|
||||||
return [
|
// return [
|
||||||
{
|
// {
|
||||||
types: ['paragraph'],
|
// types: ['paragraph'],
|
||||||
attributes: {
|
// attributes: {
|
||||||
align: {
|
// align: {
|
||||||
default: 'right',
|
// default: 'right',
|
||||||
renderHTML: attributes => ({
|
// renderHTML: attributes => ({
|
||||||
class: 'global',
|
// class: 'global',
|
||||||
style: `text-align: ${attributes.align}`,
|
// style: `text-align: ${attributes.align}`,
|
||||||
}),
|
// }),
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
},
|
// },
|
||||||
]
|
// ]
|
||||||
},
|
// },
|
||||||
|
|
||||||
addAttributes() {
|
// addAttributes() {
|
||||||
return {
|
// return {
|
||||||
id: {
|
// id: {
|
||||||
default: '123',
|
// default: '123',
|
||||||
rendered: true,
|
// rendered: true,
|
||||||
renderHTML: attributes => ({
|
// renderHTML: attributes => ({
|
||||||
class: `foo-${attributes.id}`,
|
// class: `foo-${attributes.id}`,
|
||||||
id: 'foo',
|
// id: 'foo',
|
||||||
}),
|
// }),
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
},
|
// },
|
||||||
|
|
||||||
parseHTML() {
|
parseHTML() {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -1,22 +1,23 @@
|
|||||||
import {
|
import {
|
||||||
Command, Mark, markInputRule, markPasteRule,
|
Command, createMark, markInputRule, markPasteRule,
|
||||||
} from '@tiptap/core'
|
} from '@tiptap/core'
|
||||||
|
|
||||||
type StrikeCommand = () => Command
|
// type StrikeCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
strike: StrikeCommand,
|
// strike: StrikeCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export const inputRegex = /(?:^|\s)((?:~~)((?:[^~]+))(?:~~))$/gm
|
export const inputRegex = /(?:^|\s)((?:~~)((?:[^~]+))(?:~~))$/gm
|
||||||
export const pasteRegex = /(?:^|\s)((?:~~)((?:[^~]+))(?:~~))/gm
|
export const pasteRegex = /(?:^|\s)((?:~~)((?:[^~]+))(?:~~))/gm
|
||||||
|
|
||||||
export default new Mark()
|
export default createMark({
|
||||||
.name('strike')
|
name: 'strike',
|
||||||
.schema(() => ({
|
|
||||||
parseDOM: [
|
parseHTML() {
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
tag: 's',
|
tag: 's',
|
||||||
},
|
},
|
||||||
@@ -30,21 +31,36 @@ export default new Mark()
|
|||||||
style: 'text-decoration',
|
style: 'text-decoration',
|
||||||
getAttrs: node => (node === 'line-through' ? {} : false),
|
getAttrs: node => (node === 'line-through' ? {} : false),
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
toDOM: () => ['s', 0],
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ attributes }) {
|
||||||
strike: () => ({ commands }) => {
|
return ['s', attributes, 0]
|
||||||
return commands.toggleMark(name)
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ editor }) => ({
|
return {
|
||||||
'Mod-d': () => editor.strike(),
|
strike: () => ({ commands }) => {
|
||||||
}))
|
return commands.toggleMark('strike')
|
||||||
.inputRules(({ type }) => [
|
},
|
||||||
markInputRule(inputRegex, type),
|
}
|
||||||
])
|
},
|
||||||
.pasteRules(({ type }) => [
|
|
||||||
markPasteRule(inputRegex, type),
|
addKeyboardShortcuts() {
|
||||||
])
|
return {
|
||||||
.create()
|
'Mod-d': () => this.editor.strike(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addInputRules() {
|
||||||
|
return [
|
||||||
|
markInputRule(inputRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
addPasteRules() {
|
||||||
|
return [
|
||||||
|
markPasteRule(inputRegex, this.type),
|
||||||
|
]
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
import { Command, Mark } from '@tiptap/core'
|
import { Command, createMark } from '@tiptap/core'
|
||||||
|
|
||||||
export type UnderlineCommand = () => Command
|
// export type UnderlineCommand = () => Command
|
||||||
|
|
||||||
declare module '@tiptap/core/src/Editor' {
|
// declare module '@tiptap/core/src/Editor' {
|
||||||
interface Commands {
|
// interface Commands {
|
||||||
underline: UnderlineCommand,
|
// underline: UnderlineCommand,
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
export default new Mark()
|
export default createMark({
|
||||||
.name('underline')
|
name: 'underline',
|
||||||
.schema(() => ({
|
|
||||||
parseDOM: [
|
parseHTML() {
|
||||||
|
return [
|
||||||
{
|
{
|
||||||
tag: 'u',
|
tag: 'u',
|
||||||
},
|
},
|
||||||
@@ -19,15 +20,24 @@ export default new Mark()
|
|||||||
style: 'text-decoration',
|
style: 'text-decoration',
|
||||||
getAttrs: node => (node === 'underline' ? {} : false),
|
getAttrs: node => (node === 'underline' ? {} : false),
|
||||||
},
|
},
|
||||||
],
|
]
|
||||||
toDOM: () => ['u', 0],
|
},
|
||||||
}))
|
|
||||||
.commands(({ name }) => ({
|
renderHTML({ attributes }) {
|
||||||
underline: () => ({ commands }) => {
|
return ['u', attributes, 0]
|
||||||
return commands.toggleMark(name)
|
},
|
||||||
},
|
|
||||||
}))
|
addCommands() {
|
||||||
.keys(({ editor }) => ({
|
return {
|
||||||
'Mod-u': () => editor.underline(),
|
underline: () => ({ commands }) => {
|
||||||
}))
|
return commands.toggleMark('underline')
|
||||||
.create()
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
addKeyboardShortcuts() {
|
||||||
|
return {
|
||||||
|
'Mod-u': () => this.editor.underline(),
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|||||||
@@ -1,16 +1,7 @@
|
|||||||
// import originalDefaultExtensions from '@tiptap/starter-kit'
|
import originalDefaultExtensions from '@tiptap/starter-kit'
|
||||||
|
|
||||||
import Document from '@tiptap/extension-document'
|
|
||||||
import Text from '@tiptap/extension-text'
|
|
||||||
import Paragraph from '@tiptap/extension-paragraph'
|
|
||||||
|
|
||||||
export * from '@tiptap/vue'
|
export * from '@tiptap/vue'
|
||||||
|
|
||||||
export function defaultExtensions() {
|
export function defaultExtensions() {
|
||||||
return [
|
return originalDefaultExtensions()
|
||||||
Document(),
|
|
||||||
Text(),
|
|
||||||
Paragraph(),
|
|
||||||
]
|
|
||||||
// return originalDefaultExtensions()
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user