Merge branch 'main' of github.com:ueberdosis/tiptap-next into main

This commit is contained in:
Hans Pagel 2020-11-18 15:13:37 +01:00
commit 2ff5fc2844
20 changed files with 103 additions and 79 deletions

View File

@ -19,25 +19,25 @@
<button @click="editor.chain().focus().clearNodes().run()">
clear nodes
</button>
<button @click="editor.chain().focus().paragraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
paragraph
</button>
<button @click="editor.chain().focus().heading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
h1
</button>
<button @click="editor.chain().focus().heading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
h2
</button>
<button @click="editor.chain().focus().heading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
h3
</button>
<button @click="editor.chain().focus().heading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
h4
</button>
<button @click="editor.chain().focus().heading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
h5
</button>
<button @click="editor.chain().focus().heading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
h6
</button>
<button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
@ -52,10 +52,10 @@
<button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
blockquote
</button>
<button @click="editor.chain().focus().horizontalRule().run()">
<button @click="editor.chain().focus().setHorizontalRule().run()">
horizontal rule
</button>
<button @click="editor.chain().focus().hardBreak().run()">
<button @click="editor.chain().focus().setHardBreak().run()">
hard break
</button>
<button @click="editor.chain().focus().undo().run()">

View File

@ -19,25 +19,25 @@
<button @click="editor.chain().focus().clearNodes().run()">
clear nodes
</button>
<button @click="editor.chain().focus().paragraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
paragraph
</button>
<button @click="editor.chain().focus().heading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
h1
</button>
<button @click="editor.chain().focus().heading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
h2
</button>
<button @click="editor.chain().focus().heading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
h3
</button>
<button @click="editor.chain().focus().heading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
h4
</button>
<button @click="editor.chain().focus().heading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
h5
</button>
<button @click="editor.chain().focus().heading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
h6
</button>
<button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
@ -52,10 +52,10 @@
<button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
blockquote
</button>
<button @click="editor.chain().focus().horizontalRule().run()">
<button @click="editor.chain().focus().setHorizontalRule().run()">
horizontal rule
</button>
<button @click="editor.chain().focus().hardBreak().run()">
<button @click="editor.chain().focus().setHardBreak().run()">
hard break
</button>
<button @click="editor.chain().focus().undo().run()">

View File

@ -19,25 +19,25 @@
<button @click="editor.chain().focus().clearNodes().run()">
clear nodes
</button>
<button @click="editor.chain().focus().paragraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
paragraph
</button>
<button @click="editor.chain().focus().heading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
h1
</button>
<button @click="editor.chain().focus().heading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
h2
</button>
<button @click="editor.chain().focus().heading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
h3
</button>
<button @click="editor.chain().focus().heading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
h4
</button>
<button @click="editor.chain().focus().heading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
h5
</button>
<button @click="editor.chain().focus().heading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
h6
</button>
<button @click="editor.chain().focus().toggleBulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
@ -52,10 +52,10 @@
<button @click="editor.chain().focus().toggleBlockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
blockquote
</button>
<button @click="editor.chain().focus().horizontalRule().run()">
<button @click="editor.chain().focus().setHorizontalRule().run()">
horizontal rule
</button>
<button @click="editor.chain().focus().hardBreak().run()">
<button @click="editor.chain().focus().setHardBreak().run()">
hard break
</button>
<button @click="editor.chain().focus().undo().run()">

View File

@ -7,28 +7,28 @@
<button @click="editor.chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
italic
</button>
<button @click="editor.chain().focus().heading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
h1
</button>
<button @click="editor.chain().focus().heading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
h2
</button>
<button @click="editor.chain().focus().heading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
h3
</button>
<button @click="editor.chain().focus().paragraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
<button @click="editor.chain().focus().setParagraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
paragraph
</button>
<button @click="editor.chain().focus().textAlign('left').run()">
<button @click="editor.chain().focus().setTextAlign('left').run()">
left
</button>
<button @click="editor.chain().focus().textAlign('center').run()">
<button @click="editor.chain().focus().setTextAlign('center').run()">
center
</button>
<button @click="editor.chain().focus().textAlign('right').run()">
<button @click="editor.chain().focus().setTextAlign('right').run()">
right
</button>
<button @click="editor.chain().focus().textAlign('justify').run()">
<button @click="editor.chain().focus().setTextAlign('justify').run()">
justify
</button>
</div>

View File

@ -1,15 +1,15 @@
<template>
<div v-if="editor">
<button @click="editor.chain().focus().textAlign('left').run()">
<button @click="editor.chain().focus().setTextAlign('left').run()">
left
</button>
<button @click="editor.chain().focus().textAlign('center').run()">
<button @click="editor.chain().focus().setTextAlign('center').run()">
center
</button>
<button @click="editor.chain().focus().textAlign('right').run()">
<button @click="editor.chain().focus().setTextAlign('right').run()">
right
</button>
<button @click="editor.chain().focus().textAlign('justify').run()">
<button @click="editor.chain().focus().setTextAlign('justify').run()">
justify
</button>
<button @click="editor.chain().focus().resetNodeAttributes(['textAlign']).run()">

View File

@ -16,10 +16,10 @@
<button @click="editor.chain().focus().toggleItalic().run()" :class="{ 'is-active': editor.isActive('italic') }">
italic
</button>
<button @click="editor.chain().focus().heading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
h1
</button>
<button @click="editor.chain().focus().heading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
h2
</button>
</div>

View File

@ -1,6 +1,6 @@
<template>
<div v-if="editor">
<button @click="editor.chain().focus().hardBreak().run()">
<button @click="editor.chain().focus().setHardBreak().run()">
hardBreak
</button>

View File

@ -1,12 +1,12 @@
<template>
<div v-if="editor">
<button @click="editor.chain().focus().heading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
h1
</button>
<button @click="editor.chain().focus().heading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
h2
</button>
<button @click="editor.chain().focus().heading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
<button @click="editor.chain().focus().toggleHeading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
h3
</button>

View File

@ -1,6 +1,6 @@
<template>
<div v-if="editor">
<button @click="editor.chain().focus().horizontalRule().run()">
<button @click="editor.chain().focus().setHorizontalRule().run()">
horizontalRule
</button>

View File

@ -31,7 +31,7 @@ export default {
addImage() {
const url = window.prompt('URL')
this.editor.chain().focus().image({ src: url }).run()
this.editor.chain().focus().setImage({ src: url }).run()
},
},

View File

@ -12,15 +12,15 @@ context('/api/nodes/task-list', () => {
it('should parse unordered lists correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.commands.setContent('<ul data-type="task_list"><li data-checked="true" data-type="taskItem"><p>Example Text</p></li></ul>')
expect(editor.getHTML()).to.eq('<ul data-type="task_list"><li data-checked="true" data-type="taskItem"><p>Example Text</p></li></ul>')
editor.commands.setContent('<ul data-type="taskList"><li data-checked="true" data-type="taskItem"><p>Example Text</p></li></ul>')
expect(editor.getHTML()).to.eq('<ul data-type="taskList"><li data-checked="true" data-type="taskItem"><p>Example Text</p></li></ul>')
})
})
it('should parse unordered lists without paragraphs correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.commands.setContent('<ul data-type="task_list"><li data-checked="false" data-type="taskItem">Example Text</li></ul>')
expect(editor.getHTML()).to.eq('<ul data-type="task_list"><li data-checked="false" data-type="taskItem"><p>Example Text</p></li></ul>')
editor.commands.setContent('<ul data-type="taskList"><li data-checked="false" data-type="taskItem">Example Text</li></ul>')
expect(editor.getHTML()).to.eq('<ul data-type="taskList"><li data-checked="false" data-type="taskItem"><p>Example Text</p></li></ul>')
})
})
@ -35,11 +35,11 @@ context('/api/nodes/task-list', () => {
.click()
cy.get('.ProseMirror')
.find('ul[data-type="task_list"]')
.find('ul[data-type="taskList"]')
.should('contain', 'Example Text')
cy.get('.ProseMirror')
.find('ul[data-type="task_list"] li')
.find('ul[data-type="taskList"] li')
.should('contain', 'Example Text')
})
@ -51,7 +51,7 @@ context('/api/nodes/task-list', () => {
.click()
cy.get('.ProseMirror')
.find('ul[data-type="task_list"]')
.find('ul[data-type="taskList"]')
.should('contain', 'Example Text')
cy.get('.demo__preview button:nth-child(1)')

View File

@ -14,7 +14,7 @@ If youre using TypeScript in your project and want to extend tiptap, there ar
## Options type
To extend or create default options for an extension, youll need to define a custom type, here is an example:
```js
```ts
import { Extension } from '@tiptap/core'
export interface CustomExtensionOptions {
@ -31,7 +31,7 @@ const CustomExtension = Extension.create({
## Command type
The core package also exports a `Command` type, which needs to be added to all commands that you specify in your code. Here is an example:
```js
```ts
import { Command, Extension } from '@tiptap/core'
const CustomExtension = Extension.create({

View File

@ -1,6 +1,7 @@
// eslint-disable-next-line
import Prism from 'prismjs'
import 'prismjs/components/prism-jsx.js'
import 'prismjs/components/prism-typescript.js'
import 'prismjs/components/prism-scss.js'
import PortalVue from 'portal-vue'
import App from '~/layouts/App'

View File

@ -1,11 +1,14 @@
import { NodeType } from 'prosemirror-model'
import getNodeType from '../utils/getNodeType'
import { Command } from '../types'
export default (attributes: {}): Command => ({ tr, state, dispatch }) => {
export default (typeOrName: string | NodeType, attributes: {}): Command => ({ tr, state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema)
const { selection } = tr
const { from, to } = selection
state.doc.nodesBetween(from, to, (node, pos) => {
if (!node.type.isText && dispatch) {
if (node.type === type && dispatch) {
tr.setNodeMarkup(pos, undefined, {
...node.attrs,
...attributes,

View File

@ -25,7 +25,7 @@ const HardBreak = Node.create({
/**
* Add a hard break
*/
hardBreak: (): Command => ({ commands, state, dispatch }) => {
setHardBreak: (): Command => ({ commands, state, dispatch }) => {
return commands.try([
() => exitCode(state, dispatch),
() => {
@ -42,8 +42,8 @@ const HardBreak = Node.create({
addKeyboardShortcuts() {
return {
'Mod-Enter': () => this.editor.commands.hardBreak(),
'Shift-Enter': () => this.editor.commands.hardBreak(),
'Mod-Enter': () => this.editor.commands.setHardBreak(),
'Shift-Enter': () => this.editor.commands.setHardBreak(),
}
},
})

View File

@ -53,14 +53,24 @@ const Heading = Node.create({
addCommands() {
return {
/**
* Toggle a heading node
* Set a heading node
*/
heading: (options: { level: Level }): Command => ({ commands }) => {
if (!this.options.levels.includes(options.level)) {
setHeading: (attributes: { level: Level }): Command => ({ commands }) => {
if (!this.options.levels.includes(attributes.level)) {
return false
}
return commands.toggleBlockType('heading', 'paragraph', options)
return commands.setBlockType('heading', attributes)
},
/**
* Toggle a heading node
*/
toggleHeading: (attributes: { level: Level }): Command => ({ commands }) => {
if (!this.options.levels.includes(attributes.level)) {
return false
}
return commands.toggleBlockType('heading', 'paragraph', attributes)
},
}
},
@ -69,7 +79,7 @@ const Heading = Node.create({
return this.options.levels.reduce((items, level) => ({
...items,
...{
[`Mod-Alt-${level}`]: () => this.editor.commands.setBlockType('heading', { level }),
[`Mod-Alt-${level}`]: () => this.editor.commands.toggleHeading({ level }),
},
}), {})
},

View File

@ -30,8 +30,10 @@ const HorizontalRule = Node.create({
/**
* Add a horizontal rule
*/
horizontalRule: (): Command => ({ tr }) => {
tr.replaceSelectionWith(this.type.create())
setHorizontalRule: (): Command => ({ tr, dispatch }) => {
if (dispatch) {
tr.replaceSelectionWith(this.type.create())
}
return true
},

View File

@ -58,11 +58,13 @@ const Image = Node.create({
/**
* Add an image
*/
image: (options: { src: string, alt?: string, title?: string }): Command => ({ tr }) => {
setImage: (options: { src: string, alt?: string, title?: string }): Command => ({ tr, dispatch }) => {
const { selection } = tr
const node = this.type.create(options)
tr.replaceRangeWith(selection.from, selection.to, node)
if (dispatch) {
tr.replaceRangeWith(selection.from, selection.to, node)
}
return true
},

View File

@ -32,7 +32,7 @@ const Paragraph = Node.create({
/**
* Toggle a paragraph
*/
paragraph: (): Command => ({ commands }) => {
setParagraph: (): Command => ({ commands }) => {
return commands.toggleBlockType('paragraph', 'paragraph')
},
}
@ -40,7 +40,7 @@ const Paragraph = Node.create({
addKeyboardShortcuts() {
return {
'Mod-Alt-0': () => this.editor.commands.paragraph(),
'Mod-Alt-0': () => this.editor.commands.setParagraph(),
}
},
})

View File

@ -35,14 +35,20 @@ const TextAlign = Extension.create({
addCommands() {
return {
/**
* Update the text align attribute
* Set the text align attribute
*/
textAlign: (alignment: string): Command => ({ commands }) => {
setTextAlign: (alignment: string): Command => ({ commands }) => {
if (!this.options.alignments.includes(alignment)) {
return false
}
return commands.updateNodeAttributes({ textAlign: alignment })
return this.options.types.every(type => commands.updateNodeAttributes(type, { textAlign: alignment }))
},
/**
* Unset the text align attribute
*/
unsetTextAlign: (): Command => ({ commands }) => {
return this.options.types.every(type => commands.updateNodeAttributes(type, { textAlign: null }))
},
}
},
@ -55,10 +61,10 @@ const TextAlign = Extension.create({
Enter: () => this.editor.commands.splitBlock({
withAttributes: true,
}),
'Ctrl-Shift-l': () => this.editor.commands.textAlign('left'),
'Ctrl-Shift-e': () => this.editor.commands.textAlign('center'),
'Ctrl-Shift-r': () => this.editor.commands.textAlign('right'),
'Ctrl-Shift-j': () => this.editor.commands.textAlign('justify'),
'Ctrl-Shift-l': () => this.editor.commands.setTextAlign('left'),
'Ctrl-Shift-e': () => this.editor.commands.setTextAlign('center'),
'Ctrl-Shift-r': () => this.editor.commands.setTextAlign('right'),
'Ctrl-Shift-j': () => this.editor.commands.setTextAlign('justify'),
}
},
})