Merge branch 'main' into feature/extension-code-block-lowlight

This commit is contained in:
Philipp Kühn
2021-04-07 22:39:39 +02:00
125 changed files with 1230 additions and 1389 deletions

View File

@@ -18,7 +18,8 @@ Steps to reproduce the behavior:
4. See error message 4. See error message
Create a new Codesandbox replicating your error Create a new Codesandbox replicating your error
https://codesandbox.io/s/tiptap-issue-template-b83rr?file=/src/components/Tiptap.vue https://codesandbox.io/s/tiptap-issue-template-b83rr?file=/src/components/Tiptap.vue (Vue)
https://codesandbox.io/s/tiptap-react-08yxr (React)
**What behavior did you expect?** **What behavior did you expect?**
A clear and concise description of what you expected to happen. A clear and concise description of what you expected to happen.

View File

@@ -33,7 +33,7 @@
"y-prosemirror": "^1.0.7", "y-prosemirror": "^1.0.7",
"y-webrtc": "^10.1.7", "y-webrtc": "^10.1.7",
"y-websocket": "^1.3.11", "y-websocket": "^1.3.11",
"yjs": "^13.5.3" "yjs": "^13.5.4"
}, },
"devDependencies": { "devDependencies": {
"@babel/plugin-proposal-class-properties": "^7.13.0", "@babel/plugin-proposal-class-properties": "^7.13.0",

View File

@@ -30,13 +30,9 @@ import TaskItem from '@tiptap/extension-task-item'
import Highlight from '@tiptap/extension-highlight' import Highlight from '@tiptap/extension-highlight'
import * as Y from 'yjs' import * as Y from 'yjs'
import { WebsocketProvider } from 'y-websocket' import { WebsocketProvider } from 'y-websocket'
// import { IndexeddbPersistence } from 'y-indexeddb' import { IndexeddbPersistence } from 'y-indexeddb'
import MenuBar from './MenuBar.vue' import MenuBar from './MenuBar.vue'
const CustomTaskItem = TaskItem.extend({
content: 'paragraph',
})
const getRandomElement = list => { const getRandomElement = list => {
return list[Math.floor(Math.random() * list.length)] return list[Math.floor(Math.random() * list.length)]
} }
@@ -70,14 +66,17 @@ export default {
window.ydoc = ydoc window.ydoc = ydoc
// this.indexdb = new IndexeddbPersistence('tiptap-collaboration-example', ydoc) this.indexdb = new IndexeddbPersistence('tiptap-collaboration-example', ydoc)
this.editor = new Editor({ this.editor = new Editor({
extensions: [ extensions: [
...defaultExtensions().filter(extension => extension.config.name !== 'history'), ...defaultExtensions().filter(extension => extension.config.name !== 'history'),
Highlight, Highlight,
TaskList, TaskList,
CustomTaskItem, TaskItem,
Collaboration.configure({
document: ydoc,
}),
CollaborationCursor.configure({ CollaborationCursor.configure({
provider: this.provider, provider: this.provider,
user: this.currentUser, user: this.currentUser,
@@ -85,9 +84,6 @@ export default {
this.users = users this.users = users
}, },
}), }),
Collaboration.configure({
document: ydoc,
}),
], ],
}) })
@@ -327,7 +323,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
> input { > label {
flex: 0 0 auto; flex: 0 0 auto;
margin-right: 0.5rem; margin-right: 0.5rem;
} }

View File

@@ -69,7 +69,7 @@ ul[data-type="taskList"] {
display: flex; display: flex;
align-items: center; align-items: center;
> input { > label {
flex: 0 0 auto; flex: 0 0 auto;
margin-right: 0.5rem; margin-right: 0.5rem;
} }

View File

@@ -5,7 +5,8 @@
</template> </template>
<script> <script>
import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit' import { Editor, EditorContent } from '@tiptap/vue-2'
import { defaultExtensions } from '@tiptap/starter-kit'
import DragHandle from './DragHandle.js' import DragHandle from './DragHandle.js'
export default { export default {

View File

@@ -158,7 +158,7 @@ export default {
display: flex; display: flex;
align-items: center; align-items: center;
> input { > label {
flex: 0 0 auto; flex: 0 0 auto;
margin-right: 0.5rem; margin-right: 0.5rem;
} }

View File

@@ -33,6 +33,9 @@ export default {
Document, Document,
Paragraph, Paragraph,
Text, Text,
Collaboration.configure({
document: ydoc,
}),
CollaborationCursor.configure({ CollaborationCursor.configure({
provider: this.provider, provider: this.provider,
user: { user: {
@@ -40,9 +43,6 @@ export default {
color: '#f783ac', color: '#f783ac',
}, },
}), }),
Collaboration.configure({
document: ydoc,
}),
], ],
}) })
}, },

View File

@@ -6,7 +6,7 @@ context('/demos/Guide/Content/ReadOnly', () => {
it('should be read-only', () => { it('should be read-only', () => {
cy.get('.ProseMirror').then(([{ editor }]) => { cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setEditable(false) editor.setEditable(false)
editor.commands.insertText('Edited: ') editor.commands.insertContent('Edited: ')
cy.get('.ProseMirror p:first').should('not.contain', 'Edited: ') cy.get('.ProseMirror p:first').should('not.contain', 'Edited: ')
}) })
@@ -15,7 +15,7 @@ context('/demos/Guide/Content/ReadOnly', () => {
it('should be editable', () => { it('should be editable', () => {
cy.get('.ProseMirror').then(([{ editor }]) => { cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setEditable(true) editor.setEditable(true)
editor.commands.insertText('Edited: ') editor.commands.insertContent('Edited: ')
cy.get('.ProseMirror p:first').should('contain', 'Edited: ') cy.get('.ProseMirror p:first').should('contain', 'Edited: ')
}) })

View File

@@ -16,7 +16,7 @@ export default Node.create({
}, },
renderHTML({ HTMLAttributes }) { renderHTML({ HTMLAttributes }) {
return ['node-view', mergeAttributes(HTMLAttributes)] return ['node-view', mergeAttributes(HTMLAttributes), 0]
}, },
addNodeView() { addNodeView() {

View File

@@ -18,7 +18,7 @@ export default Node.create({
}, },
renderHTML({ HTMLAttributes }) { renderHTML({ HTMLAttributes }) {
return ['react-component', mergeAttributes(HTMLAttributes)] return ['react-component', mergeAttributes(HTMLAttributes), 0]
}, },
addNodeView() { addNodeView() {

View File

@@ -18,7 +18,7 @@ export default Node.create({
}, },
renderHTML({ HTMLAttributes }) { renderHTML({ HTMLAttributes }) {
return ['vue-component', mergeAttributes(HTMLAttributes)] return ['vue-component', mergeAttributes(HTMLAttributes), 0]
}, },
addNodeView() { addNodeView() {

View File

@@ -16,6 +16,7 @@ import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph' import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text' import Text from '@tiptap/extension-text'
import Link from '@tiptap/extension-link' import Link from '@tiptap/extension-link'
import Bold from '@tiptap/extension-bold'
export default { export default {
components: { components: {
@@ -34,11 +35,12 @@ export default {
Document, Document,
Paragraph, Paragraph,
Text, Text,
Bold,
Link, Link,
], ],
content: ` content: `
<p> <p>
Wow, this editor has support for links to the whole <a href="https://en.wikipedia.org/wiki/World_Wide_Web">world wide web</a>. We tested a lot of URLs and I think you can add *every URL* you want. Isnt that cool? Lets try <a href="https://statamic.com/">another one!</a> Yep, seems to work. Wow, this editor has support for links to the whole <strong><a href="https://en.wikipedia.org/wiki/World_Wide_Web">world wide web</a></strong>. We tested a lot of URLs and I think you can add *every URL* you want. Isnt that cool? Lets try <a href="https://statamic.com/">another one!</a> Yep, seems to work.
</p> </p>
<p> <p>
By default every link will get a \`rel="noopener noreferrer nofollow"\` attribute. Its configurable though. By default every link will get a \`rel="noopener noreferrer nofollow"\` attribute. Its configurable though.

View File

@@ -1,21 +1,21 @@
<template> <template>
<div v-if="editor"> <div v-if="editor">
<button @click="editor.chain().focus(). insertText('✨').run()"> <button @click="editor.chain().focus().insertContent('✨').run()">
</button> </button>
<button @click="editor.chain().focus(). insertText('😅').run()"> <button @click="editor.chain().focus().insertContent('😅').run()">
😅 😅
</button> </button>
<button @click="editor.chain().focus(). insertText('🎉').run()"> <button @click="editor.chain().focus().insertContent('🎉').run()">
🎉 🎉
</button> </button>
<button @click="editor.chain().focus(). insertText('💖').run()"> <button @click="editor.chain().focus().insertContent('💖').run()">
💖 💖
</button> </button>
<button @click="editor.chain().focus(). insertText('👀').run()"> <button @click="editor.chain().focus().insertContent('👀').run()">
👀 👀
</button> </button>
<button @click="editor.chain().focus(). insertText('👍️').run()"> <button @click="editor.chain().focus().insertContent('👍️').run()">
👍 👍
</button> </button>
<editor-content :editor="editor" /> <editor-content :editor="editor" />

View File

@@ -56,7 +56,7 @@ ul[data-type="taskList"] {
display: flex; display: flex;
align-items: center; align-items: center;
> input { > label {
flex: 0 0 auto; flex: 0 0 auto;
margin-right: 0.5rem; margin-right: 0.5rem;
} }

View File

@@ -60,7 +60,7 @@ ul[data-type="taskList"] {
display: flex; display: flex;
align-items: center; align-items: center;
> input { > label {
flex: 0 0 auto; flex: 0 0 auto;
margin-right: 0.5rem; margin-right: 0.5rem;
} }

View File

@@ -43,8 +43,8 @@ addCommands() {
// Does work: // Does work:
return chain() return chain()
.insertNode('timecode', attributes) .insertContent('foo!')
.insertText(' ') .insertContent('bar!')
.run() .run()
}, },
} }
@@ -60,7 +60,7 @@ editor
.focus() .focus()
.command(({ tr }) => { .command(({ tr }) => {
// manipulate the transaction // manipulate the transaction
tr.insertText('hey, thats cool!') tr.insertContent('hey, thats cool!')
return true return true
}) })
@@ -91,7 +91,7 @@ Both calls would return `true` if its possible to apply the commands, and `fa
In order to make that work with your custom commands, dont forget to return `true` or `false`. In order to make that work with your custom commands, dont forget to return `true` or `false`.
For some of your own commands, you probably want to work with the raw [transaction](/api/concept). To make them work with `.can()` you should check if the transaction should be dispatched. Here is how we do that within `.insertText()`: For some of your own commands, you probably want to work with the raw [transaction](/api/concept). To make them work with `.can()` you should check if the transaction should be dispatched. Here is how you can create a simple `.insertText()` command:
```js ```js
export default (value: string): Command => ({ tr, dispatch }) => { export default (value: string): Command => ({ tr, dispatch }) => {
@@ -148,13 +148,11 @@ commands.first([
Have a look at all of the core commands listed below. They should give you a good first impression of whats possible. Have a look at all of the core commands listed below. They should give you a good first impression of whats possible.
### Content ### Content
| Command | Description | | Command | Description | Links |
| --------------- | ------------------------------------------------ | | ---------------- | -------------------------------------------------------- | ------------------------------------ |
| .clearContent() | Clear the whole document. | | .clearContent() | Clear the whole document. | [More](/api/commands/clear-content) |
| .insertHTML() | Insert a string of HTML at the current position. | | .insertContent() | Insert a node or string of HTML at the current position. | [More](/api/commands/insert-content) |
| .insertNode() | Insert a node at the current position. | | .setContent() | Replace the whole document with new content. | [More](/api/commands/set-content) |
| .insertText() | Insert a string of text at the current position. |
| .setContent() | Replace the whole document with new content. |
### Nodes & Marks ### Nodes & Marks
| Command | Description | | Command | Description |
@@ -170,7 +168,7 @@ Have a look at all of the core commands listed below. They should give you a goo
| .newlineInCode() | Add a newline character in code. | | .newlineInCode() | Add a newline character in code. |
| .replace() | Replaces text with a node. | | .replace() | Replaces text with a node. |
| .replaceRange() | Replaces text with a node within a range. | | .replaceRange() | Replaces text with a node within a range. |
| .resetNodeAttributes() | Resets all node attributes to the default value. | | .resetAttributes() | Resets some node or mark attributes to the default value. |
| .selectParentNode() | Select the parent node. | | .selectParentNode() | Select the parent node. |
| .setMark() | Add a mark with new attributes. | | .setMark() | Add a mark with new attributes. |
| .setNode() | Replace a given range with a node. | | .setNode() | Replace a given range with a node. |
@@ -181,7 +179,7 @@ Have a look at all of the core commands listed below. They should give you a goo
| .undoInputRule() | Undo an input rule. | | .undoInputRule() | Undo an input rule. |
| .unsetAllMarks() | Remove all marks in the current selection. | | .unsetAllMarks() | Remove all marks in the current selection. |
| .unsetMark() | Remove a mark in the current selection. | | .unsetMark() | Remove a mark in the current selection. |
| .updateNodeAttributes() | Update attributes of a node. | | .updateAttributes() | Update attributes of a node or mark. |
### Lists ### Lists
| Command | Description | | Command | Description |
@@ -220,13 +218,13 @@ this.editor
.chain() .chain()
.focus() .focus()
.createParagraphNear() .createParagraphNear()
.insertText(text) .insertContent(text)
.setBlockquote() .setBlockquote()
.insertHTML('<p></p>') .insertContent('<p></p>')
.createParagraphNear() .createParagraphNear()
.unsetBlockquote() .unsetBlockquote()
.createParagraphNear() .createParagraphNear()
.insertHTML('<p></p>') .insertContent('<p></p>')
.run() .run()
``` ```
@@ -237,7 +235,18 @@ addCommands() {
insertTimecode: attributes => ({ chain }) => { insertTimecode: attributes => ({ chain }) => {
return chain() return chain()
.focus() .focus()
.insertNode('timecode', attributes) .insertContent({
type: 'heading',
attrs: {
level: 2,
},
content: [
{
type: 'text',
text: 'heading',
},
],
})
.insertText(' ') .insertText(' ')
.run(); .run();
}, },
@@ -249,5 +258,5 @@ addCommands() {
## Add custom commands ## Add custom commands
All extensions can add additional commands (and most do), check out the specific [documentation for the provided nodes](/api/nodes), [marks](/api/marks), and [extensions](/api/extensions) to learn more about those. All extensions can add additional commands (and most do), check out the specific [documentation for the provided nodes](/api/nodes), [marks](/api/marks), and [extensions](/api/extensions) to learn more about those.
Of course, you can [add your custom extensions](/guide/build-extensions) with custom commands aswell. Of course, you can [add your custom extensions](/guide/custom-extensions) with custom commands aswell.

View File

@@ -0,0 +1,12 @@
# clearContent
See also: [setContent](/api/commands/set-content)
## Parameters
## Usage
```js
this.editor.commands.clearContent()
```

View File

@@ -0,0 +1,23 @@
# insertContent
## Parameters
## Usage
```js
this.editor.commands.insertContent('text')
this.editor.commands.insertContent('<p>HTML</p>')
this.editor.commands.insertContent({
type: 'heading',
attrs: {
level: 2,
},
content: [
{
type: 'text',
text: 'nested nodes',
},
],
})
```

View File

@@ -0,0 +1,42 @@
# setContent
The `setContent` command replaces the document with a new one. You can pass JSON or HTML, both work fine. Its basically the same as setting the `content` on initialization.
See also: [clearContent](/api/commands/clear-content)
## Parameters
`content: string`
Pass a string (JSON or HTML) as [content](/guide/output). The editor will only render whats allowed according to the [schema](/api/schema).
`emitUpdate?: Boolean`
By default, it doesnt trigger the update event. Passing `true` doesnt prevent triggering the update event.
`parseOptions?: AnyObject`
Options to configure the parsing can be passed during initialization and/or with setContent. Read more about parseOptions in the [ProseMirror documentation](https://prosemirror.net/docs/ref/#model.ParseOptions).
## Usage
```js
// HTML
this.editor.commands.setContent('<p>Example Text</p>')
// JSON
this.editor.commands.setContent({
"type": "doc",
"content": [
{
"type": "paragraph",
"content": [
{
"type": "text",
"text": "Example Text"
}
]
}
]
})
```

View File

@@ -14,7 +14,6 @@ Dont confuse methods with [commands](/api/commands). Commands are used to cha
| --------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- | | --------------------- | ----------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------- |
| `can()` | - | Check if a command or a command chain can be executed. Without executing it. | | `can()` | - | Check if a command or a command chain can be executed. Without executing it. |
| `chain()` | - | Create a command chain to call multiple commands at once. | | `chain()` | - | Create a command chain to call multiple commands at once. |
| `createDocument()` | `content` EditorContent<br>`parseOptions` | Creates a ProseMirror document. |
| `destroy()` | | Stops the editor instance and unbinds all events. | | `destroy()` | | Stops the editor instance and unbinds all events. |
| `getHTML()` | | Returns the current content as HTML. | | `getHTML()` | | Returns the current content as HTML. |
| `getJSON()` | | Returns the current content as JSON. | | `getJSON()` | | Returns the current content as JSON. |
@@ -129,7 +128,7 @@ new Editor({
| `null` | Disables autofocus. | | `null` | Disables autofocus. |
### Enable input rules ### Enable input rules
By default, tiptap enables all [input rules](/guide/build-extensions/#input-rules). With `enableInputRules` you can disable that. By default, tiptap enables all [input rules](/guide/custom-extensions/#input-rules). With `enableInputRules` you can disable that.
```js ```js
import { Editor } from '@tiptap/core' import { Editor } from '@tiptap/core'
@@ -143,7 +142,7 @@ new Editor({
``` ```
### Enable paste rules ### Enable paste rules
By default, tiptap enables all [paste rules](/guide/build-extensions/#paste-rules). With `enablePasteRules` you can disable that. By default, tiptap enables all [paste rules](/guide/custom-extensions/#paste-rules). With `enablePasteRules` you can disable that.
```js ```js
import { Editor } from '@tiptap/core' import { Editor } from '@tiptap/core'

View File

@@ -19,9 +19,6 @@ const editor = new Editor({
onSelectionUpdate({ editor }) { onSelectionUpdate({ editor }) {
// The selection has changed. // The selection has changed.
}, },
onViewUpdate({ editor }) {
// The view has changed.
},
onTransaction({ editor, transaction }) { onTransaction({ editor, transaction }) {
// The editor state has changed. // The editor state has changed.
}, },
@@ -57,10 +54,6 @@ editor.on('selectionUpdate', ({ editor }) => {
// The selection has changed. // The selection has changed.
} }
editor.on('viewUpdate', ({ editor }) => {
// The view has changed.
}
editor.on('transaction', ({ editor, transaction }) => { editor.on('transaction', ({ editor, transaction }) => {
// The editor state has changed. // The editor state has changed.
} }
@@ -113,9 +106,6 @@ const CustomExtension = Extension.create({
onSelectionUpdate({ editor }) { onSelectionUpdate({ editor }) {
// The selection has changed. // The selection has changed.
}, },
onViewUpdate({ editor }) {
// The view has changed.
},
onTransaction({ editor, transaction }) { onTransaction({ editor, transaction }) {
// The editor state has changed. // The editor state has changed.
}, },

View File

@@ -51,6 +51,7 @@ const editor = new Editor({
Text, Text,
// … // …
], ],
})
``` ```
Learn [more about custom extensions in our guide](/guide/extend-extensions). Learn [more about custom extensions in our guide](/guide/extend-extensions).

View File

@@ -49,6 +49,7 @@ const editor = new Editor({
Text, Text,
// … // …
], ],
})
``` ```
Learn [more about custom extensions in our guide](/guide/build-extensions). Learn [more about custom extensions in our guide](/guide/custom-extensions).

View File

@@ -13,7 +13,7 @@ We need your support to maintain, update, support and develop tiptap 2. If you
You can use any emoji picker, or build your own. Just use [commands](/api/commands) to insert the picked emojis. You can use any emoji picker, or build your own. Just use [commands](/api/commands) to insert the picked emojis.
```js ```js
this.editor.chain().focus().insertText('✨').run() this.editor.chain().focus().insertContent('✨').run()
``` ```
<demo name="Nodes/Emoji" /> <demo name="Nodes/Emoji" />

View File

@@ -7,7 +7,7 @@ Unlike many other editors, tiptap is based on a [schema](https://prosemirror.net
This schema is *very* strict. You cant use any HTML element or attribute that is not defined in your schema. This schema is *very* strict. You cant use any HTML element or attribute that is not defined in your schema.
Let me give you one example: If you paste something like `This is <strong>important</strong>` into tiptap, dont have any extension that handles `strong` tags registered, youll only see `This is important` without the strong tags. Let me give you one example: If you paste something like `This is <strong>important</strong>` into tiptap, but dont have any extension that handles `strong` tags, youll only see `This is important` without the strong tags.
## How a schema looks like ## How a schema looks like
When youll work with the provided extensions only, you dont have to care that much about the schema. If youre building your own extensions, its probably helpful to understand how the schema works. Lets look at the most simple schema for a typical ProseMirror editor: When youll work with the provided extensions only, you dont have to care that much about the schema. If youre building your own extensions, its probably helpful to understand how the schema works. Lets look at the most simple schema for a typical ProseMirror editor:

View File

@@ -0,0 +1,4 @@
# Community
* GitHub https://github.com/ueberdosis/tiptap-next
* Discord https://discord.gg/WtJ49jGshW
* Twitter https://twitter.com/tiptap_editor

View File

@@ -158,15 +158,15 @@ const provider = new WebsocketProvider('ws://127.0.0.1:1234', 'example-document'
const editor = new Editor({ const editor = new Editor({
extensions: [ extensions: [
Collaboration.configure({
document: ydoc,
}),
// Register the collaboration cursor extension // Register the collaboration cursor extension
CollaborationCursor.configure({ CollaborationCursor.configure({
provider: provider, provider: provider,
name: 'Cyndi Lauper', name: 'Cyndi Lauper',
color: '#f783ac', color: '#f783ac',
}), }),
Collaboration.configure({
document: ydoc,
}),
// … // …
], ],
}) })

View File

@@ -1,4 +1,4 @@
# Configure the editor # Configuration
## toc ## toc

View File

@@ -1,9 +1,9 @@
# Build extensions # Custom extensions
## toc ## toc
## Introduction ## Introduction
You can build your own extensions from scratch with the `Node`, `Mark`, and `Extension` classes. Just pass an object with your configuration and custom code. Read the guide on [extending the functionality](/guide/extend-extensions) to learn more about all the things you can control. You can build your own extensions from scratch with the `Node`, `Mark`, and `Extension` classes. Just pass an object with your configuration and custom code. Read the [ovewrite & extend](/guide/extend-extensions) guide to learn more about all the things you can control.
And if everything is working fine, dont forget to [share it with the community](https://github.com/ueberdosis/tiptap/issues/819). And if everything is working fine, dont forget to [share it with the community](https://github.com/ueberdosis/tiptap/issues/819).

View File

@@ -1,4 +1,4 @@
# Extend the functionality # Overwrite & extend
## toc ## toc
@@ -37,7 +37,18 @@ The same applies to every aspect of an existing extension, except to the name. L
### Name ### Name
The extension name is used in a whole lot of places and changing it isnt too easy. If you want to change the name of an existing extension, we would recommended to copy the whole extension and change the name in all occurrences. The extension name is used in a whole lot of places and changing it isnt too easy. If you want to change the name of an existing extension, we would recommended to copy the whole extension and change the name in all occurrences.
The extension name is also part of the JSON. If you [store your content as JSON](/guide/content#option-1-json), you need to change the name there too. The extension name is also part of the JSON. If you [store your content as JSON](/guide/output#option-1-json), you need to change the name there too.
### Priority
With the priority you can specify the order of the extensions. This has an impact on the schema and ProseMirror plugins. Default priority is `100`. A higher value means that the extension will be loaded earlier.
```js
import Link from '@tiptap/extension-link'
const CustomLink = Link.extend({
priority: 1000,
})
```
### Settings ### Settings
All settings can be configured through the extension anyway, but if you want to change the default settings, for example to provide a library on top of tiptap for other developers, you can do it like that: All settings can be configured through the extension anyway, but if you want to change the default settings, for example to provide a library on top of tiptap for other developers, you can do it like that:

View File

@@ -49,7 +49,7 @@ Lets assume youve got the editor running already and you want to add your
Oh, thats a long command, right? Actually, its a [chain of commands](/api/commands#chain-commands), so lets go through this one by one: Oh, thats a long command, right? Actually, its a [chain of commands](/api/commands#chain-commands), so lets go through this one by one:
```js ```js
editor.chain().toggleBold().focus().run() editor.chain().focus().toggleBold().run()
``` ```
1. `editor` should be a tiptap instance, 1. `editor` should be a tiptap instance,

View File

@@ -61,7 +61,7 @@ You can even mix non-editable and editable text. Thats great to build complex
**BUT**, that also means the cursor cant just move from outside of the node view to the inside. Users have to manually place their cursor to edit the content inside the node view. Just so you know. **BUT**, that also means the cursor cant just move from outside of the node view to the inside. Users have to manually place their cursor to edit the content inside the node view. Just so you know.
## Markup ## Markup
But what happens if you [access the editor content](/guide/content)? If youre working with HTML, youll need to tell tiptap how your node should be serialized. But what happens if you [access the editor content](/guide/output)? If youre working with HTML, youll need to tell tiptap how your node should be serialized.
The editor **does not** export the rendered JavaScript node, and for a lot of use cases you wouldnt want that anyway. The editor **does not** export the rendered JavaScript node, and for a lot of use cases you wouldnt want that anyway.

View File

@@ -8,7 +8,7 @@ Using frameworks like Vue or React can feel too complex, if youre used to wor
## Render a node view with JavaScript ## Render a node view with JavaScript
Here is what you need to do to render a node view inside your editor: Here is what you need to do to render a node view inside your editor:
1. [Create a node extension](/guide/build-extensions) 1. [Create a node extension](/guide/custom-extensions)
2. Register a new node view with `addNodeView()` 2. Register a new node view with `addNodeView()`
3. Write your render function 3. Write your render function
4. [Configure tiptap to use your new node extension](/guide/configuration) 4. [Configure tiptap to use your new node extension](/guide/configuration)

View File

@@ -8,7 +8,7 @@ Using plain JavaScript can feel complex if you are used to work in React. Good n
## Render a React component ## Render a React component
Here is what you need to do to render React components inside your editor: Here is what you need to do to render React components inside your editor:
1. [Create a node extension](/guide/build-extensions) 1. [Create a node extension](/guide/custom-extensions)
2. Create a React component 2. Create a React component
3. Pass that component to the provided `ReactNodeViewRenderer` 3. Pass that component to the provided `ReactNodeViewRenderer`
4. Register it with `addNodeView()` 4. Register it with `addNodeView()`

View File

@@ -8,7 +8,7 @@ Using plain JavaScript can feel complex if you are used to work in Vue. Good new
## Render a Vue component ## Render a Vue component
Here is what you need to do to render Vue components inside your editor: Here is what you need to do to render Vue components inside your editor:
1. [Create a node extension](/guide/build-extensions) 1. [Create a node extension](/guide/custom-extensions)
2. Create a Vue component 2. Create a Vue component
3. Pass that component to the provided `VueNodeViewRenderer` 3. Pass that component to the provided `VueNodeViewRenderer`
4. Register it with `addNodeView()` 4. Register it with `addNodeView()`

View File

@@ -1,4 +1,4 @@
# Export content # Output
## toc ## toc

View File

@@ -1,4 +1,4 @@
# Custom styling # Styling
## toc ## toc

View File

@@ -1,3 +1,7 @@
---
title: Alpine WYSIWYG
---
# Alpine.js # Alpine.js
## toc ## toc

View File

@@ -1,3 +1,7 @@
---
title: Livewire WYSIWYG
---
# Livewire # Livewire
## toc ## toc

View File

@@ -1,10 +0,0 @@
# Next.js
## toc
## Introduction
The following guide describes how to integrate tiptap with your [Next.js](https://nextjs.org/) project.
TODO
<demo name="React" />

View File

@@ -1,3 +1,7 @@
---
title: Nuxt.js WYSIWYG
---
# Nuxt.js # Nuxt.js
## toc ## toc

View File

@@ -1,3 +1,7 @@
---
title: React WYSIWYG
---
# React # React
## toc ## toc

View File

@@ -1,3 +1,7 @@
---
title: Svelte WYSIWYG
---
# Svelte # Svelte
## toc ## toc

View File

@@ -1,3 +1,7 @@
---
title: Vue.js 2 WYSIWYG
---
# Vue.js 2 # Vue.js 2
## toc ## toc

View File

@@ -1,3 +1,7 @@
---
title: Vue.js 3 WYSIWYG
---
# Vue.js 3 # Vue.js 3
## toc ## toc

View File

@@ -110,7 +110,7 @@ const CustomExtension = Node.create({
}) })
``` ```
Read more about [all the nifty details building custom extensions](/guide/build-extensions) in our guide. Read more about [all the nifty details building custom extensions](/guide/custom-extensions) in our guide.
### Renamed settings and methods ### Renamed settings and methods
[We renamed a lot of settings and methods](/api/editor). Hopefully you can migrate to the new API with search & replace. Here is a list of what changed: [We renamed a lot of settings and methods](/api/editor). Hopefully you can migrate to the new API with search & replace. Here is a list of what changed:

View File

@@ -57,42 +57,52 @@
<portal :to="sidebarPortal" v-if="showSidebar"> <portal :to="sidebarPortal" v-if="showSidebar">
<nav class="app__sidebar-menu"> <nav class="app__sidebar-menu">
<div class="app__link-group" v-for="(linkGroup, i) in linkGroups" :key="i"> <div class="app__link-group" v-for="(linkGroup, i) in linkGroups" :key="i">
<div class="app__link-group-title"> <template v-if="linkGroup.link && !linkGroup.items">
{{ linkGroup.title }} <g-link
</div> class="app__link-group__link"
<ul class="app__link-list"> :to="linkGroup.redirect || linkGroup.link"
<li v-for="(item, j) in linkGroup.items" :key="j"> >
<g-link {{ linkGroup.title }}
:class="{ </g-link>
'app__link': true, </template>
'app__link--exact': $router.currentRoute.path === item.link, <template v-else>
'app__link--active': $router.currentRoute.path.startsWith(item.link), <div class="app__link-group-title">
[`app__link--${item.type}`]: item.type !== null, {{ linkGroup.title }}
'app__link--with-children': !!item.items </div>
}" <ul class="app__link-list">
:to="item.redirect || item.link" <li v-for="(item, j) in linkGroup.items" :key="j">
> <g-link
{{ item.title }} :class="{
</g-link> 'app__link': true,
'app__link--exact': $router.currentRoute.path === item.link,
'app__link--active': $router.currentRoute.path.startsWith(item.link),
[`app__link--${item.type}`]: item.type !== null,
'app__link--with-children': !!item.items
}"
:to="item.redirect || item.link"
>
{{ item.title }}
</g-link>
<ul v-if="item.items" class="app__link-list"> <ul v-if="item.items" class="app__link-list">
<li v-for="(item, k) in item.items" :key="k"> <li v-for="(item, k) in item.items" :key="k">
<g-link <g-link
:class="{ :class="{
'app__link': true, 'app__link': true,
'app__link--exact': $router.currentRoute.path === item.link, 'app__link--exact': $router.currentRoute.path === item.link,
'app__link--active': $router.currentRoute.path.startsWith(item.link), 'app__link--active': $router.currentRoute.path.startsWith(item.link),
[`app__link--${item.type}`]: item.type !== null, [`app__link--${item.type}`]: item.type !== null,
}" }"
:to="item.link" :to="item.link"
exact exact
> >
{{ item.title }} {{ item.title }}
</g-link> </g-link>
</li> </li>
</ul> </ul>
</li> </li>
</ul> </ul>
</template>
</div> </div>
</nav> </nav>
</portal> </portal>

View File

@@ -1,3 +1,13 @@
# - title: Documentation
# link: introduction
# - title: Examples
# link: /examples
# redirect: /examples/default
# - title: Community
# link: community
# - title: Sponsor
# link: https://github.com/ueberdosis/sponsor
- title: Overview - title: Overview
items: items:
- title: Installation - title: Installation
@@ -82,24 +92,24 @@
- title: Guide - title: Guide
items: items:
- title: Configure the editor - title: Configuration
link: /guide/configuration link: /guide/configuration
- title: Create menus - title: Menus
link: /guide/menus link: /guide/menus
type: new type: new
- title: Custom styling - title: Styling
link: /guide/styling link: /guide/styling
- title: Output
link: /guide/output
- title: Accessibility - title: Accessibility
link: /guide/accessibility link: /guide/accessibility
- title: Export content
link: /guide/content
- title: Collaborative editing - title: Collaborative editing
link: /guide/collaborative-editing link: /guide/collaborative-editing
# type: pro # type: pro
- title: Extend the functionality - title: Custom extensions
link: /guide/custom-extensions
- title: Overwrite & extend
link: /guide/extend-extensions link: /guide/extend-extensions
- title: Build extensions
link: /guide/build-extensions
- title: Interactive node views - title: Interactive node views
link: /guide/node-views link: /guide/node-views
type: new type: new
@@ -125,6 +135,15 @@
link: /api/editor link: /api/editor
- title: Commands - title: Commands
link: /api/commands link: /api/commands
items:
- title: clearContent
link: /api/commands/clear-content
type: draft
- title: insertContent
link: /api/commands/insert-content
type: draft
- title: setContent
link: /api/commands/set-content
- title: Nodes - title: Nodes
link: /api/nodes link: /api/nodes
items: items:

View File

@@ -1,23 +1,23 @@
context('insertHTML', () => { context('insertContent', () => {
before(() => { before(() => {
cy.visit('/demos/Examples/Default/Vue') cy.visit('/demos/Examples/Default/Vue')
}) })
it('returns true for the insertHTML command', () => { it('returns true for the insertContent command', () => {
cy.get('.ProseMirror').then(([{ editor }]) => { cy.get('.ProseMirror').then(([{ editor }]) => {
editor.commands.setContent('<p>Example Text</p>') editor.commands.setContent('<p>Example Text</p>')
const command = editor.commands.insertHTML('<p>Cindy Lauper</p>') const command = editor.commands.insertContent('<p>Cindy Lauper</p>')
expect(command).to.be.eq(true) expect(command).to.be.eq(true)
}) })
}) })
it('appends the content when using the insertHTML command', () => { it('appends the content when using the insertContent command', () => {
cy.get('.ProseMirror').then(([{ editor }]) => { cy.get('.ProseMirror').then(([{ editor }]) => {
editor.commands.setContent('<p>Example Text</p>') editor.commands.setContent('<p>Example Text</p>')
editor.commands.insertHTML('<p>Cindy Lauper</p>') editor.commands.insertContent('<p>Cindy Lauper</p>')
expect(editor.getHTML()).to.be.eq('<p>Example Text</p><p>Cindy Lauper</p>') expect(editor.getHTML()).to.be.eq('<p>Example Text</p><p>Cindy Lauper</p>')
}) })

View File

@@ -3,6 +3,69 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.20](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/core@2.0.0-beta.19...@tiptap/core@2.0.0-beta.20) (2021-04-07)
### Features
* add resetAttributes() command, deprecate resetNodeAttributes() ([3334d93](https://github.com/ueberdosis/tiptap-next/commit/3334d930f30bd4acb5c314b4ec1934b6a1e0b712))
# [2.0.0-beta.19](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/core@2.0.0-beta.18...@tiptap/core@2.0.0-beta.19) (2021-04-07)
### Features
* add updateAttributes() command, deprecate updateNodeAttributes(), fix [#254](https://github.com/ueberdosis/tiptap-next/issues/254) ([aac32b4](https://github.com/ueberdosis/tiptap-next/commit/aac32b4df6a1dfd93500e09d3433fcd8acad5fbe))
# [2.0.0-beta.18](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/core@2.0.0-beta.17...@tiptap/core@2.0.0-beta.18) (2021-04-07)
### Features
* add priority option to extensions ([bb1ae65](https://github.com/ueberdosis/tiptap-next/commit/bb1ae659a463e97a7ada15af711347b5c004897a))
# [2.0.0-beta.17](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/core@2.0.0-beta.16...@tiptap/core@2.0.0-beta.17) (2021-04-07)
### Bug Fixes
* remove debug log ([beb96c5](https://github.com/ueberdosis/tiptap-next/commit/beb96c5cbfdb81869763e23f82f5ab270c30f0ea))
# [2.0.0-beta.16](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/core@2.0.0-beta.15...@tiptap/core@2.0.0-beta.16) (2021-04-07)
### Features
* add insertContent() command, deprecate insertText(), insertHTML() and insertNode() ([b8d9b7d](https://github.com/ueberdosis/tiptap-next/commit/b8d9b7d4c70b38fb9eec3c079be8243d30166e5e))
# [2.0.0-beta.15](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/core@2.0.0-beta.14...@tiptap/core@2.0.0-beta.15) (2021-04-06)
**Note:** Version bump only for package @tiptap/core
# [2.0.0-beta.14](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/core@2.0.0-beta.13...@tiptap/core@2.0.0-beta.14) (2021-04-04) # [2.0.0-beta.14](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/core@2.0.0-beta.13...@tiptap/core@2.0.0-beta.14) (2021-04-04)
**Note:** Version bump only for package @tiptap/core **Note:** Version bump only for package @tiptap/core

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/core", "name": "@tiptap/core",
"description": "headless rich text editor", "description": "headless rich text editor",
"version": "2.0.0-beta.14", "version": "2.0.0-beta.20",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",
@@ -35,10 +35,10 @@
"prosemirror-commands": "^1.1.7", "prosemirror-commands": "^1.1.7",
"prosemirror-inputrules": "^1.1.3", "prosemirror-inputrules": "^1.1.3",
"prosemirror-keymap": "^1.1.3", "prosemirror-keymap": "^1.1.3",
"prosemirror-model": "^1.13.3", "prosemirror-model": "^1.14.0",
"prosemirror-schema-list": "^1.1.4", "prosemirror-schema-list": "^1.1.4",
"prosemirror-state": "^1.3.4", "prosemirror-state": "^1.3.4",
"prosemirror-transform": "^1.2.12", "prosemirror-transform": "^1.3.2",
"prosemirror-view": "^1.18.2" "prosemirror-view": "^1.18.2"
} }
} }

View File

@@ -2,12 +2,12 @@ import {
EditorState, Plugin, PluginKey, Transaction, EditorState, Plugin, PluginKey, Transaction,
} from 'prosemirror-state' } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view' import { EditorView } from 'prosemirror-view'
import { Schema, DOMParser, Node } from 'prosemirror-model' import { Schema } from 'prosemirror-model'
import elementFromString from './utilities/elementFromString'
import getNodeAttributes from './helpers/getNodeAttributes' import getNodeAttributes from './helpers/getNodeAttributes'
import getMarkAttributes from './helpers/getMarkAttributes' import getMarkAttributes from './helpers/getMarkAttributes'
import isActive from './helpers/isActive' import isActive from './helpers/isActive'
import removeElement from './utilities/removeElement' import removeElement from './utilities/removeElement'
import createDocument from './helpers/createDocument'
import getHTMLFromFragment from './helpers/getHTMLFromFragment' import getHTMLFromFragment from './helpers/getHTMLFromFragment'
import isNodeEmpty from './helpers/isNodeEmpty' import isNodeEmpty from './helpers/isNodeEmpty'
import createStyleTag from './utilities/createStyleTag' import createStyleTag from './utilities/createStyleTag'
@@ -16,7 +16,6 @@ import ExtensionManager from './ExtensionManager'
import EventEmitter from './EventEmitter' import EventEmitter from './EventEmitter'
import { import {
EditorOptions, EditorOptions,
Content,
CanCommands, CanCommands,
ChainedCommands, ChainedCommands,
SingleCommands, SingleCommands,
@@ -62,7 +61,6 @@ export class Editor extends EventEmitter {
onCreate: () => null, onCreate: () => null,
onUpdate: () => null, onUpdate: () => null,
onSelectionUpdate: () => null, onSelectionUpdate: () => null,
onViewUpdate: () => null,
onTransaction: () => null, onTransaction: () => null,
onFocus: () => null, onFocus: () => null,
onBlur: () => null, onBlur: () => null,
@@ -83,7 +81,6 @@ export class Editor extends EventEmitter {
this.on('create', this.options.onCreate) this.on('create', this.options.onCreate)
this.on('update', this.options.onUpdate) this.on('update', this.options.onUpdate)
this.on('selectionUpdate', this.options.onSelectionUpdate) this.on('selectionUpdate', this.options.onSelectionUpdate)
this.on('viewUpdate', this.options.onViewUpdate)
this.on('transaction', this.options.onTransaction) this.on('transaction', this.options.onTransaction)
this.on('focus', this.options.onFocus) this.on('focus', this.options.onFocus)
this.on('blur', this.options.onBlur) this.on('blur', this.options.onBlur)
@@ -240,23 +237,14 @@ export class Editor extends EventEmitter {
...this.options.editorProps, ...this.options.editorProps,
dispatchTransaction: this.dispatchTransaction.bind(this), dispatchTransaction: this.dispatchTransaction.bind(this),
state: EditorState.create({ state: EditorState.create({
doc: this.createDocument(this.options.content), doc: createDocument(this.options.content, this.schema, this.options.parseOptions),
}), }),
}) })
// `editor.view` is not yet available at this time. // `editor.view` is not yet available at this time.
// Therefore we will add all plugins and node views directly afterwards. // Therefore we will add all plugins and node views directly afterwards.
const newState = this.state.reconfigure({ const newState = this.state.reconfigure({
plugins: [ plugins: this.extensionManager.plugins,
new Plugin({
view: () => ({
update: () => this.emit('viewUpdate', {
editor: this,
}),
}),
}),
...this.extensionManager.plugins,
],
}) })
this.view.updateState(newState) this.view.updateState(newState)
@@ -278,34 +266,6 @@ export class Editor extends EventEmitter {
}) })
} }
/**
* Creates a ProseMirror document.
*/
public createDocument = (content: Content, parseOptions = this.options.parseOptions): Node => {
if (content && typeof content === 'object') {
try {
return this.schema.nodeFromJSON(content)
} catch (error) {
console.warn(
'[tiptap warn]: Invalid content.',
'Passed value:',
content,
'Error:',
error,
)
return this.createDocument('')
}
}
if (typeof content === 'string') {
return DOMParser
.fromSchema(this.schema)
.parse(elementFromString(content), parseOptions)
}
return this.createDocument('')
}
public isCapturingTransaction = false public isCapturingTransaction = false
private capturedTransaction: Transaction | null = null private capturedTransaction: Transaction | null = null

View File

@@ -16,6 +16,11 @@ declare module '@tiptap/core' {
*/ */
name: string, name: string,
/**
* Priority
*/
priority?: number,
/** /**
* Default options * Default options
*/ */
@@ -126,14 +131,6 @@ declare module '@tiptap/core' {
editor: Editor, editor: Editor,
}) => void) | null, }) => void) | null,
/**
* The view has changed.
*/
onViewUpdate?: ((this: {
options: Options,
editor: Editor,
}) => void) | null,
/** /**
* The editor state has changed. * The editor state has changed.
*/ */
@@ -188,6 +185,7 @@ export class Extension<Options = any> {
config: ExtensionConfig = { config: ExtensionConfig = {
name: 'extension', name: 'extension',
priority: 100,
defaultOptions: {}, defaultOptions: {},
} }

View File

@@ -25,7 +25,7 @@ export default class ExtensionManager {
constructor(extensions: Extensions, editor: Editor) { constructor(extensions: Extensions, editor: Editor) {
this.editor = editor this.editor = editor
this.extensions = extensions this.extensions = this.sort(extensions)
this.schema = getSchema(this.extensions) this.schema = getSchema(this.extensions)
this.extensions.forEach(extension => { this.extensions.forEach(extension => {
@@ -59,10 +59,6 @@ export default class ExtensionManager {
this.editor.on('selectionUpdate', extension.config.onSelectionUpdate.bind(context)) this.editor.on('selectionUpdate', extension.config.onSelectionUpdate.bind(context))
} }
if (typeof extension.config.onViewUpdate === 'function') {
this.editor.on('viewUpdate', extension.config.onViewUpdate.bind(context))
}
if (typeof extension.config.onTransaction === 'function') { if (typeof extension.config.onTransaction === 'function') {
this.editor.on('transaction', extension.config.onTransaction.bind(context)) this.editor.on('transaction', extension.config.onTransaction.bind(context))
} }
@@ -81,6 +77,22 @@ export default class ExtensionManager {
}) })
} }
private sort(extensions: Extensions) {
const defaultPriority = 100
return extensions.sort((a, b) => {
if ((a.config.priority || defaultPriority) > (b.config.priority || defaultPriority)) {
return -1
}
if ((a.config.priority || defaultPriority) < (b.config.priority || defaultPriority)) {
return 1
}
return 0
})
}
get commands(): RawCommands { get commands(): RawCommands {
return this.extensions.reduce((commands, extension) => { return this.extensions.reduce((commands, extension) => {
const context = { const context = {

View File

@@ -21,6 +21,11 @@ declare module '@tiptap/core' {
*/ */
name: string, name: string,
/**
* Priority
*/
priority?: number,
/** /**
* Default options * Default options
*/ */
@@ -140,15 +145,6 @@ declare module '@tiptap/core' {
type: MarkType, type: MarkType,
}) => void) | null, }) => void) | null,
/**
* The view has changed.
*/
onViewUpdate?: ((this: {
options: Options,
editor: Editor,
type: MarkType,
}) => void) | null,
/** /**
* The editor state has changed. * The editor state has changed.
*/ */
@@ -263,6 +259,7 @@ export class Mark<Options = any> {
config: MarkConfig = { config: MarkConfig = {
name: 'mark', name: 'mark',
priority: 100,
defaultOptions: {}, defaultOptions: {},
} }

View File

@@ -26,6 +26,11 @@ declare module '@tiptap/core' {
*/ */
name: string, name: string,
/**
* Priority
*/
priority?: number,
/** /**
* Default options * Default options
*/ */
@@ -139,16 +144,7 @@ declare module '@tiptap/core' {
/** /**
* The selection has changed. * The selection has changed.
*/ */
onSelectionUpdate?: ((this: { onSelectionUpdate?: ((this: {
options: Options,
editor: Editor,
type: NodeType,
}) => void) | null,
/**
* The view has changed.
*/
onViewUpdate?: ((this: {
options: Options, options: Options,
editor: Editor, editor: Editor,
type: NodeType, type: NodeType,
@@ -321,6 +317,7 @@ export class Node<Options = any> {
config: NodeConfig = { config: NodeConfig = {
name: 'node', name: 'node',
priority: 100,
defaultOptions: {}, defaultOptions: {},
} }

View File

@@ -0,0 +1,35 @@
import createNodeFromContent from '../helpers/createNodeFromContent'
import selectionToInsertionEnd from '../helpers/selectionToInsertionEnd'
import { Command, RawCommands, Content } from '../types'
declare module '@tiptap/core' {
interface Commands {
insertContent: {
/**
* Insert a node or string of HTML at the current position.
*/
insertContent: (value: Content) => Command,
}
}
}
export const insertContent: RawCommands['insertContent'] = value => ({ tr, dispatch, editor }) => {
if (dispatch) {
const content = createNodeFromContent(value, editor.schema)
if (typeof content === 'string') {
tr.insertText(content)
return true
}
if (!tr.selection.empty) {
tr.deleteSelection()
}
tr.insert(tr.selection.anchor, content)
selectionToInsertionEnd(tr, tr.steps.length - 1, -1)
}
return true
}

View File

@@ -15,6 +15,8 @@ declare module '@tiptap/core' {
} }
export const insertHTML: RawCommands['insertHTML'] = value => ({ tr, state, dispatch }) => { export const insertHTML: RawCommands['insertHTML'] = value => ({ tr, state, dispatch }) => {
console.warn('[tiptap warn]: insertHTML() is deprecated. please use insertContent() instead.')
const { selection } = tr const { selection } = tr
const element = elementFromString(value) const element = elementFromString(value)
const slice = DOMParser.fromSchema(state.schema).parseSlice(element) const slice = DOMParser.fromSchema(state.schema).parseSlice(element)

View File

@@ -14,6 +14,8 @@ declare module '@tiptap/core' {
} }
export const insertNode: RawCommands['insertNode'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => { export const insertNode: RawCommands['insertNode'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
console.warn('[tiptap warn]: insertNode() is deprecated. please use insertContent() instead.')
const { selection } = tr const { selection } = tr
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)

View File

@@ -12,6 +12,8 @@ declare module '@tiptap/core' {
} }
export const insertText: RawCommands['insertText'] = value => ({ tr, dispatch }) => { export const insertText: RawCommands['insertText'] = value => ({ tr, dispatch }) => {
console.warn('[tiptap warn]: insertText() is deprecated. please use insertContent() instead.')
if (dispatch) { if (dispatch) {
tr.insertText(value) tr.insertText(value)
} }

View File

@@ -0,0 +1,61 @@
import { NodeType, MarkType } from 'prosemirror-model'
import getNodeType from '../helpers/getNodeType'
import getMarkType from '../helpers/getMarkType'
import getSchemaTypeNameByName from '../helpers/getSchemaTypeNameByName'
import deleteProps from '../utilities/deleteProps'
import { Command, RawCommands } from '../types'
declare module '@tiptap/core' {
interface Commands {
resetAttributes: {
/**
* Resets some node attributes to the default value.
*/
resetAttributes: (typeOrName: string | NodeType | MarkType, attributes: string | string[]) => Command,
}
}
}
export const resetAttributes: RawCommands['resetAttributes'] = (typeOrName, attributes) => ({ tr, state, dispatch }) => {
let nodeType: NodeType | null = null
let markType: MarkType | null = null
const schemaType = getSchemaTypeNameByName(
typeof typeOrName === 'string'
? typeOrName
: typeOrName.name,
state.schema,
)
if (!schemaType) {
return false
}
if (schemaType === 'node') {
nodeType = getNodeType(typeOrName as NodeType, state.schema)
}
if (schemaType === 'mark') {
markType = getMarkType(typeOrName as MarkType, state.schema)
}
if (dispatch) {
tr.selection.ranges.forEach(range => {
state.doc.nodesBetween(range.$from.pos, range.$to.pos, (node, pos) => {
if (nodeType && nodeType === node.type) {
tr.setNodeMarkup(pos, undefined, deleteProps(node.attrs, attributes))
}
if (markType && node.marks.length) {
node.marks.forEach(mark => {
if (markType === mark.type) {
tr.addMark(pos, pos + node.nodeSize, markType.create(deleteProps(mark.attrs, attributes)))
}
})
}
})
})
}
return true
}

View File

@@ -15,6 +15,8 @@ declare module '@tiptap/core' {
} }
export const resetNodeAttributes: RawCommands['resetNodeAttributes'] = (typeOrName, attributes) => ({ tr, state, dispatch }) => { export const resetNodeAttributes: RawCommands['resetNodeAttributes'] = (typeOrName, attributes) => ({ tr, state, dispatch }) => {
console.warn('[tiptap warn]: resetNodeAttributes() is deprecated. please use resetAttributes() instead.')
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
const { selection } = tr const { selection } = tr
const { ranges } = selection const { ranges } = selection

View File

@@ -1,5 +1,11 @@
import { TextSelection } from 'prosemirror-state' import { TextSelection } from 'prosemirror-state'
import { AnyObject, Command, RawCommands } from '../types' import createDocument from '../helpers/createDocument'
import {
AnyObject,
Command,
RawCommands,
Content,
} from '../types'
declare module '@tiptap/core' { declare module '@tiptap/core' {
interface Commands { interface Commands {
@@ -7,15 +13,18 @@ declare module '@tiptap/core' {
/** /**
* Replace the whole document with new content. * Replace the whole document with new content.
*/ */
setContent: (content: string, emitUpdate?: Boolean, parseOptions?: AnyObject) => Command, setContent: (
content: Content,
emitUpdate?: Boolean,
parseOptions?: AnyObject,
) => Command,
} }
} }
} }
export const setContent: RawCommands['setContent'] = (content, emitUpdate = false, parseOptions = {}) => ({ tr, editor, dispatch }) => { export const setContent: RawCommands['setContent'] = (content, emitUpdate = false, parseOptions = {}) => ({ tr, editor, dispatch }) => {
const { createDocument } = editor
const { doc } = tr const { doc } = tr
const document = createDocument(content, parseOptions) const document = createDocument(content, editor.schema, parseOptions)
const selection = TextSelection.create(doc, 0, doc.content.size) const selection = TextSelection.create(doc, 0, doc.content.size)
if (dispatch) { if (dispatch) {

View File

@@ -0,0 +1,66 @@
import { NodeType, MarkType } from 'prosemirror-model'
import getNodeType from '../helpers/getNodeType'
import getMarkType from '../helpers/getMarkType'
import getSchemaTypeNameByName from '../helpers/getSchemaTypeNameByName'
import { AnyObject, Command, RawCommands } from '../types'
declare module '@tiptap/core' {
interface Commands {
updateAttributes: {
/**
* Update attributes of a node or mark.
*/
updateAttributes: (typeOrName: string | NodeType | MarkType, attributes: AnyObject) => Command,
}
}
}
export const updateAttributes: RawCommands['updateAttributes'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
let nodeType: NodeType | null = null
let markType: MarkType | null = null
const schemaType = getSchemaTypeNameByName(
typeof typeOrName === 'string'
? typeOrName
: typeOrName.name,
state.schema,
)
if (!schemaType) {
return false
}
if (schemaType === 'node') {
nodeType = getNodeType(typeOrName as NodeType, state.schema)
}
if (schemaType === 'mark') {
markType = getMarkType(typeOrName as MarkType, state.schema)
}
if (dispatch) {
tr.selection.ranges.forEach(range => {
state.doc.nodesBetween(range.$from.pos, range.$to.pos, (node, pos) => {
if (nodeType && nodeType === node.type) {
tr.setNodeMarkup(pos, undefined, {
...node.attrs,
...attributes,
})
}
if (markType && node.marks.length) {
node.marks.forEach(mark => {
if (markType === mark.type) {
tr.addMark(pos, pos + node.nodeSize, markType.create({
...mark.attrs,
...attributes,
}))
}
})
}
})
})
}
return true
}

View File

@@ -14,6 +14,8 @@ declare module '@tiptap/core' {
} }
export const updateNodeAttributes: RawCommands['updateNodeAttributes'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => { export const updateNodeAttributes: RawCommands['updateNodeAttributes'] = (typeOrName, attributes = {}) => ({ tr, state, dispatch }) => {
console.warn('[tiptap warn]: updateNodeAttributes() is deprecated. please use updateAttributes() instead.')
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
const { selection } = tr const { selection } = tr
const { ranges } = selection const { ranges } = selection

View File

@@ -11,6 +11,7 @@ import * as exitCode from '../commands/exitCode'
import * as extendMarkRange from '../commands/extendMarkRange' import * as extendMarkRange from '../commands/extendMarkRange'
import * as first from '../commands/first' import * as first from '../commands/first'
import * as focus from '../commands/focus' import * as focus from '../commands/focus'
import * as insertContent from '../commands/insertContent'
import * as insertHTML from '../commands/insertHTML' import * as insertHTML from '../commands/insertHTML'
import * as insertNode from '../commands/insertNode' import * as insertNode from '../commands/insertNode'
import * as insertText from '../commands/insertText' import * as insertText from '../commands/insertText'
@@ -23,6 +24,7 @@ import * as liftListItem from '../commands/liftListItem'
import * as newlineInCode from '../commands/newlineInCode' import * as newlineInCode from '../commands/newlineInCode'
import * as replace from '../commands/replace' import * as replace from '../commands/replace'
import * as replaceRange from '../commands/replaceRange' import * as replaceRange from '../commands/replaceRange'
import * as resetAttributes from '../commands/resetAttributes'
import * as resetNodeAttributes from '../commands/resetNodeAttributes' import * as resetNodeAttributes from '../commands/resetNodeAttributes'
import * as scrollIntoView from '../commands/scrollIntoView' import * as scrollIntoView from '../commands/scrollIntoView'
import * as selectAll from '../commands/selectAll' import * as selectAll from '../commands/selectAll'
@@ -42,6 +44,7 @@ import * as toggleWrap from '../commands/toggleWrap'
import * as undoInputRule from '../commands/undoInputRule' import * as undoInputRule from '../commands/undoInputRule'
import * as unsetAllMarks from '../commands/unsetAllMarks' import * as unsetAllMarks from '../commands/unsetAllMarks'
import * as unsetMark from '../commands/unsetMark' import * as unsetMark from '../commands/unsetMark'
import * as updateAttributes from '../commands/updateAttributes'
import * as updateNodeAttributes from '../commands/updateNodeAttributes' import * as updateNodeAttributes from '../commands/updateNodeAttributes'
import * as wrapIn from '../commands/wrapIn' import * as wrapIn from '../commands/wrapIn'
import * as wrapInList from '../commands/wrapInList' import * as wrapInList from '../commands/wrapInList'
@@ -58,6 +61,7 @@ export { exitCode }
export { extendMarkRange } export { extendMarkRange }
export { first } export { first }
export { focus } export { focus }
export { insertContent }
export { insertHTML } export { insertHTML }
export { insertNode } export { insertNode }
export { insertText } export { insertText }
@@ -70,6 +74,7 @@ export { liftListItem }
export { newlineInCode } export { newlineInCode }
export { replace } export { replace }
export { replaceRange } export { replaceRange }
export { resetAttributes }
export { resetNodeAttributes } export { resetNodeAttributes }
export { scrollIntoView } export { scrollIntoView }
export { selectAll } export { selectAll }
@@ -89,6 +94,7 @@ export { toggleWrap }
export { undoInputRule } export { undoInputRule }
export { unsetAllMarks } export { unsetAllMarks }
export { unsetMark } export { unsetMark }
export { updateAttributes }
export { updateNodeAttributes } export { updateNodeAttributes }
export { wrapIn } export { wrapIn }
export { wrapInList } export { wrapInList }
@@ -110,6 +116,7 @@ export const Commands = Extension.create({
...extendMarkRange, ...extendMarkRange,
...first, ...first,
...focus, ...focus,
...insertContent,
...insertHTML, ...insertHTML,
...insertNode, ...insertNode,
...insertText, ...insertText,
@@ -122,6 +129,7 @@ export const Commands = Extension.create({
...newlineInCode, ...newlineInCode,
...replace, ...replace,
...replaceRange, ...replaceRange,
...resetAttributes,
...resetNodeAttributes, ...resetNodeAttributes,
...scrollIntoView, ...scrollIntoView,
...selectAll, ...selectAll,
@@ -141,6 +149,7 @@ export const Commands = Extension.create({
...undoInputRule, ...undoInputRule,
...unsetAllMarks, ...unsetAllMarks,
...unsetMark, ...unsetMark,
...updateAttributes,
...updateNodeAttributes, ...updateNodeAttributes,
...wrapIn, ...wrapIn,
...wrapInList, ...wrapInList,

View File

@@ -0,0 +1,13 @@
import { Schema, Node as ProseMirrorNode } from 'prosemirror-model'
import { AnyObject } from '../types'
import createNodeFromContent from './createNodeFromContent'
export type Content = string | JSON | null
export default function createDocument(
content: Content,
schema: Schema,
parseOptions: AnyObject = {},
): ProseMirrorNode {
return createNodeFromContent(content, schema, { slice: false, parseOptions }) as ProseMirrorNode
}

View File

@@ -0,0 +1,59 @@
import {
Schema,
DOMParser,
Node as ProseMirrorNode,
Fragment,
} from 'prosemirror-model'
import elementFromString from '../utilities/elementFromString'
import { AnyObject } from '../types'
export type Content = string | JSON | null
export type CreateNodeFromContentOptions = {
slice?: boolean,
parseOptions?: AnyObject,
}
export default function createNodeFromContent(
content: Content,
schema: Schema,
options?: CreateNodeFromContentOptions,
): string | ProseMirrorNode | Fragment {
options = {
slice: true,
parseOptions: {},
...options,
}
if (content && typeof content === 'object') {
try {
return schema.nodeFromJSON(content)
} catch (error) {
console.warn(
'[tiptap warn]: Invalid content.',
'Passed value:',
content,
'Error:',
error,
)
return createNodeFromContent('', schema, options)
}
}
if (typeof content === 'string') {
const isHTML = content.trim().startsWith('<') && content.trim().endsWith('>')
if (isHTML || !options.slice) {
const parser = DOMParser.fromSchema(schema)
return options.slice
? parser.parseSlice(elementFromString(content), options.parseOptions).content
: parser.parse(elementFromString(content), options.parseOptions)
}
return content
}
return createNodeFromContent('', schema, options)
}

View File

@@ -32,7 +32,6 @@ export interface EditorOptions {
onBeforeCreate: (props: { editor: Editor }) => void, onBeforeCreate: (props: { editor: Editor }) => void,
onCreate: (props: { editor: Editor }) => void, onCreate: (props: { editor: Editor }) => void,
onUpdate: (props: { editor: Editor }) => void, onUpdate: (props: { editor: Editor }) => void,
onViewUpdate: (props: { editor: Editor }) => void,
onSelectionUpdate: (props: { editor: Editor }) => void, onSelectionUpdate: (props: { editor: Editor }) => void,
onTransaction: (props: { editor: Editor, transaction: Transaction }) => void, onTransaction: (props: { editor: Editor, transaction: Transaction }) => void,
onFocus: (props: { editor: Editor, event: FocusEvent }) => void, onFocus: (props: { editor: Editor, event: FocusEvent }) => void,

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.5](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-collaboration-cursor@2.0.0-beta.4...@tiptap/extension-collaboration-cursor@2.0.0-beta.5) (2021-04-07)
### Features
* add priority option to extensions ([bb1ae65](https://github.com/ueberdosis/tiptap-next/commit/bb1ae659a463e97a7ada15af711347b5c004897a))
# [2.0.0-beta.4](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-collaboration-cursor@2.0.0-beta.3...@tiptap/extension-collaboration-cursor@2.0.0-beta.4) (2021-03-16) # [2.0.0-beta.4](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-collaboration-cursor@2.0.0-beta.3...@tiptap/extension-collaboration-cursor@2.0.0-beta.4) (2021-03-16)
**Note:** Version bump only for package @tiptap/extension-collaboration-cursor **Note:** Version bump only for package @tiptap/extension-collaboration-cursor

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-collaboration-cursor", "name": "@tiptap/extension-collaboration-cursor",
"description": "collaboration cursor extension for tiptap", "description": "collaboration cursor extension for tiptap",
"version": "2.0.0-beta.4", "version": "2.0.0-beta.5",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",

View File

@@ -31,6 +31,8 @@ const awarenessStatesToArray = (states: Map<number, { [key: string]: any }>) =>
export const CollaborationCursor = Extension.create<CollaborationCursorOptions>({ export const CollaborationCursor = Extension.create<CollaborationCursorOptions>({
name: 'collaborationCursor', name: 'collaborationCursor',
priority: 1000,
defaultOptions: { defaultOptions: {
provider: null, provider: null,
user: { user: {

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.2](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-dropcursor@2.0.0-beta.1...@tiptap/extension-dropcursor@2.0.0-beta.2) (2021-04-06)
**Note:** Version bump only for package @tiptap/extension-dropcursor
# [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-dropcursor@2.0.0-alpha.11...@tiptap/extension-dropcursor@2.0.0-beta.1) (2021-03-05) # [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-dropcursor@2.0.0-alpha.11...@tiptap/extension-dropcursor@2.0.0-beta.1) (2021-03-05)
**Note:** Version bump only for package @tiptap/extension-dropcursor **Note:** Version bump only for package @tiptap/extension-dropcursor

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-dropcursor", "name": "@tiptap/extension-dropcursor",
"description": "dropcursor extension for tiptap", "description": "dropcursor extension for tiptap",
"version": "2.0.0-beta.1", "version": "2.0.0-beta.2",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",
@@ -26,6 +26,6 @@
}, },
"dependencies": { "dependencies": {
"@types/prosemirror-dropcursor": "^1.0.1", "@types/prosemirror-dropcursor": "^1.0.1",
"prosemirror-dropcursor": "^1.3.3" "prosemirror-dropcursor": "^1.3.4"
} }
} }

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.2](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-horizontal-rule@2.0.0-beta.1...@tiptap/extension-horizontal-rule@2.0.0-beta.2) (2021-04-07)
### Bug Fixes
* improve handling of horizontal rule at document end, fix [#248](https://github.com/ueberdosis/tiptap-next/issues/248) ([af17f2c](https://github.com/ueberdosis/tiptap-next/commit/af17f2c65794767e4b7ddfd1c1277a567acd898d))
# [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-horizontal-rule@2.0.0-alpha.11...@tiptap/extension-horizontal-rule@2.0.0-beta.1) (2021-03-05) # [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-horizontal-rule@2.0.0-alpha.11...@tiptap/extension-horizontal-rule@2.0.0-beta.1) (2021-03-05)
**Note:** Version bump only for package @tiptap/extension-horizontal-rule **Note:** Version bump only for package @tiptap/extension-horizontal-rule

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-horizontal-rule", "name": "@tiptap/extension-horizontal-rule",
"description": "horizontal rule extension for tiptap", "description": "horizontal rule extension for tiptap",
"version": "2.0.0-beta.1", "version": "2.0.0-beta.2",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",
@@ -22,7 +22,9 @@
"dist" "dist"
], ],
"peerDependencies": { "peerDependencies": {
"@tiptap/core": "^2.0.0-beta.1", "@tiptap/core": "^2.0.0-beta.1"
"prosemirror-commands": "^1.1.3" },
"dependencies": {
"prosemirror-state": "^1.3.4"
} }
} }

View File

@@ -4,6 +4,7 @@ import {
nodeInputRule, nodeInputRule,
mergeAttributes, mergeAttributes,
} from '@tiptap/core' } from '@tiptap/core'
import { TextSelection } from 'prosemirror-state'
export interface HorizontalRuleOptions { export interface HorizontalRuleOptions {
HTMLAttributes: { HTMLAttributes: {
@@ -46,6 +47,22 @@ export const HorizontalRule = Node.create<HorizontalRuleOptions>({
setHorizontalRule: () => ({ tr, dispatch }) => { setHorizontalRule: () => ({ tr, dispatch }) => {
if (dispatch) { if (dispatch) {
tr.replaceSelectionWith(this.type.create()) tr.replaceSelectionWith(this.type.create())
const { parent, pos } = tr.selection.$from
const posAfter = pos + 1
const nodeAfter = tr.doc.nodeAt(posAfter)
// end of document
if (!nodeAfter) {
const node = parent.type.contentMatch.defaultType?.create()
if (node) {
tr.insert(posAfter, node)
tr.setSelection(TextSelection.create(tr.doc, posAfter))
}
}
tr.scrollIntoView()
} }
return true return true

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.2](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-link@2.0.0-beta.1...@tiptap/extension-link@2.0.0-beta.2) (2021-04-07)
### Features
* add priority option to extensions ([bb1ae65](https://github.com/ueberdosis/tiptap-next/commit/bb1ae659a463e97a7ada15af711347b5c004897a))
# [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-link@2.0.0-alpha.11...@tiptap/extension-link@2.0.0-beta.1) (2021-03-05) # [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-link@2.0.0-alpha.11...@tiptap/extension-link@2.0.0-beta.1) (2021-03-05)
**Note:** Version bump only for package @tiptap/extension-link **Note:** Version bump only for package @tiptap/extension-link

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-link", "name": "@tiptap/extension-link",
"description": "link extension for tiptap", "description": "link extension for tiptap",
"version": "2.0.0-beta.1", "version": "2.0.0-beta.2",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",

View File

@@ -38,6 +38,8 @@ export const pasteRegexWithBrackets = /(?:\()https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%
export const Link = Mark.create<LinkOptions>({ export const Link = Mark.create<LinkOptions>({
name: 'link', name: 'link',
priority: 1000,
inclusive: false, inclusive: false,
defaultOptions: { defaultOptions: {

View File

@@ -3,6 +3,57 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.20](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-mention@2.0.0-beta.19...@tiptap/extension-mention@2.0.0-beta.20) (2021-04-07)
**Note:** Version bump only for package @tiptap/extension-mention
# [2.0.0-beta.19](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-mention@2.0.0-beta.18...@tiptap/extension-mention@2.0.0-beta.19) (2021-04-07)
**Note:** Version bump only for package @tiptap/extension-mention
# [2.0.0-beta.18](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-mention@2.0.0-beta.17...@tiptap/extension-mention@2.0.0-beta.18) (2021-04-07)
**Note:** Version bump only for package @tiptap/extension-mention
# [2.0.0-beta.17](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-mention@2.0.0-beta.16...@tiptap/extension-mention@2.0.0-beta.17) (2021-04-07)
**Note:** Version bump only for package @tiptap/extension-mention
# [2.0.0-beta.16](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-mention@2.0.0-beta.15...@tiptap/extension-mention@2.0.0-beta.16) (2021-04-07)
### Features
* add insertContent() command, deprecate insertText(), insertHTML() and insertNode() ([b8d9b7d](https://github.com/ueberdosis/tiptap-next/commit/b8d9b7d4c70b38fb9eec3c079be8243d30166e5e))
# [2.0.0-beta.15](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-mention@2.0.0-beta.14...@tiptap/extension-mention@2.0.0-beta.15) (2021-04-06)
**Note:** Version bump only for package @tiptap/extension-mention
# [2.0.0-beta.14](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-mention@2.0.0-beta.13...@tiptap/extension-mention@2.0.0-beta.14) (2021-04-04) # [2.0.0-beta.14](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-mention@2.0.0-beta.13...@tiptap/extension-mention@2.0.0-beta.14) (2021-04-04)
**Note:** Version bump only for package @tiptap/extension-mention **Note:** Version bump only for package @tiptap/extension-mention

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-mention", "name": "@tiptap/extension-mention",
"description": "mention extension for tiptap", "description": "mention extension for tiptap",
"version": "2.0.0-beta.14", "version": "2.0.0-beta.20",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",
@@ -25,6 +25,6 @@
"@tiptap/core": "^2.0.0-beta.1" "@tiptap/core": "^2.0.0-beta.1"
}, },
"dependencies": { "dependencies": {
"@tiptap/suggestion": "^2.0.0-beta.14" "@tiptap/suggestion": "^2.0.0-beta.20"
} }
} }

View File

@@ -20,7 +20,7 @@ export const Mention = Node.create<MentionOptions>({
.chain() .chain()
.focus() .focus()
.replaceRange(range, 'mention', props) .replaceRange(range, 'mention', props)
.insertText(' ') .insertContent(' ')
.run() .run()
}, },
allow: ({ editor, range }) => { allow: ({ editor, range }) => {

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.2](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-paragraph@2.0.0-beta.1...@tiptap/extension-paragraph@2.0.0-beta.2) (2021-04-07)
### Features
* add priority option to extensions ([bb1ae65](https://github.com/ueberdosis/tiptap-next/commit/bb1ae659a463e97a7ada15af711347b5c004897a))
# [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-paragraph@2.0.0-alpha.11...@tiptap/extension-paragraph@2.0.0-beta.1) (2021-03-05) # [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-paragraph@2.0.0-alpha.11...@tiptap/extension-paragraph@2.0.0-beta.1) (2021-03-05)
**Note:** Version bump only for package @tiptap/extension-paragraph **Note:** Version bump only for package @tiptap/extension-paragraph

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-paragraph", "name": "@tiptap/extension-paragraph",
"description": "paragraph extension for tiptap", "description": "paragraph extension for tiptap",
"version": "2.0.0-beta.1", "version": "2.0.0-beta.2",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",

View File

@@ -20,6 +20,8 @@ declare module '@tiptap/core' {
export const Paragraph = Node.create<ParagraphOptions>({ export const Paragraph = Node.create<ParagraphOptions>({
name: 'paragraph', name: 'paragraph',
priority: 1000,
defaultOptions: { defaultOptions: {
HTMLAttributes: {}, HTMLAttributes: {},
}, },

View File

@@ -3,6 +3,14 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.4](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-placeholder@2.0.0-beta.3...@tiptap/extension-placeholder@2.0.0-beta.4) (2021-04-06)
**Note:** Version bump only for package @tiptap/extension-placeholder
# [2.0.0-beta.3](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-placeholder@2.0.0-beta.2...@tiptap/extension-placeholder@2.0.0-beta.3) (2021-03-31) # [2.0.0-beta.3](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-placeholder@2.0.0-beta.2...@tiptap/extension-placeholder@2.0.0-beta.3) (2021-03-31)
**Note:** Version bump only for package @tiptap/extension-placeholder **Note:** Version bump only for package @tiptap/extension-placeholder

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-placeholder", "name": "@tiptap/extension-placeholder",
"description": "placeholder extension for tiptap", "description": "placeholder extension for tiptap",
"version": "2.0.0-beta.3", "version": "2.0.0-beta.4",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",
@@ -25,7 +25,7 @@
"@tiptap/core": "^2.0.0-beta.1" "@tiptap/core": "^2.0.0-beta.1"
}, },
"dependencies": { "dependencies": {
"prosemirror-model": "^1.13.3", "prosemirror-model": "^1.14.0",
"prosemirror-state": "^1.3.4", "prosemirror-state": "^1.3.4",
"prosemirror-view": "^1.18.2" "prosemirror-view": "^1.18.2"
} }

View File

@@ -3,6 +3,17 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.2](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-task-item@2.0.0-beta.1...@tiptap/extension-task-item@2.0.0-beta.2) (2021-04-06)
### Bug Fixes
* fix checkbox in firefox, fix [#251](https://github.com/ueberdosis/tiptap-next/issues/251) ([5622dec](https://github.com/ueberdosis/tiptap-next/commit/5622deca30397170bae341a000b9fe4693280c9b))
# [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-task-item@2.0.0-alpha.12...@tiptap/extension-task-item@2.0.0-beta.1) (2021-03-05) # [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-task-item@2.0.0-alpha.12...@tiptap/extension-task-item@2.0.0-beta.1) (2021-03-05)
**Note:** Version bump only for package @tiptap/extension-task-item **Note:** Version bump only for package @tiptap/extension-task-item

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-task-item", "name": "@tiptap/extension-task-item",
"description": "task item extension for tiptap", "description": "task item extension for tiptap",
"version": "2.0.0-beta.1", "version": "2.0.0-beta.2",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",

View File

@@ -81,11 +81,13 @@ export const TaskItem = Node.create<TaskItemOptions>({
}) => { }) => {
const { view } = editor const { view } = editor
const listItem = document.createElement('li') const listItem = document.createElement('li')
const checkboxWrapper = document.createElement('label')
const checkboxStyler = document.createElement('span')
const checkbox = document.createElement('input') const checkbox = document.createElement('input')
const content = document.createElement('div') const content = document.createElement('div')
checkboxWrapper.contentEditable = 'false'
checkbox.type = 'checkbox' checkbox.type = 'checkbox'
checkbox.contentEditable = 'false'
checkbox.addEventListener('change', event => { checkbox.addEventListener('change', event => {
const { checked } = event.target as any const { checked } = event.target as any
@@ -101,11 +103,14 @@ export const TaskItem = Node.create<TaskItemOptions>({
checkbox.setAttribute('checked', 'checked') checkbox.setAttribute('checked', 'checked')
} }
listItem.append(checkbox, content) checkboxWrapper.append(checkbox, checkboxStyler)
listItem.append(checkboxWrapper, content)
Object.entries(HTMLAttributes).forEach(([key, value]) => { Object
listItem.setAttribute(key, value) .entries(HTMLAttributes)
}) .forEach(([key, value]) => {
listItem.setAttribute(key, value)
})
return { return {
dom: listItem, dom: listItem,

View File

@@ -3,6 +3,28 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.3](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-text-align@2.0.0-beta.2...@tiptap/extension-text-align@2.0.0-beta.3) (2021-04-07)
### Features
* add resetAttributes() command, deprecate resetNodeAttributes() ([3334d93](https://github.com/ueberdosis/tiptap-next/commit/3334d930f30bd4acb5c314b4ec1934b6a1e0b712))
# [2.0.0-beta.2](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-text-align@2.0.0-beta.1...@tiptap/extension-text-align@2.0.0-beta.2) (2021-04-07)
### Features
* add updateAttributes() command, deprecate updateNodeAttributes(), fix [#254](https://github.com/ueberdosis/tiptap-next/issues/254) ([aac32b4](https://github.com/ueberdosis/tiptap-next/commit/aac32b4df6a1dfd93500e09d3433fcd8acad5fbe))
# [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-text-align@2.0.0-alpha.12...@tiptap/extension-text-align@2.0.0-beta.1) (2021-03-05) # [2.0.0-beta.1](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/extension-text-align@2.0.0-alpha.12...@tiptap/extension-text-align@2.0.0-beta.1) (2021-03-05)
**Note:** Version bump only for package @tiptap/extension-text-align **Note:** Version bump only for package @tiptap/extension-text-align

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/extension-text-align", "name": "@tiptap/extension-text-align",
"description": "text align extension for tiptap", "description": "text align extension for tiptap",
"version": "2.0.0-beta.1", "version": "2.0.0-beta.3",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",

View File

@@ -56,10 +56,10 @@ export const TextAlign = Extension.create<TextAlignOptions>({
return false return false
} }
return this.options.types.every(type => commands.updateNodeAttributes(type, { textAlign: alignment })) return this.options.types.every(type => commands.updateAttributes(type, { textAlign: alignment }))
}, },
unsetTextAlign: () => ({ commands }) => { unsetTextAlign: () => ({ commands }) => {
return this.options.types.every(type => commands.resetNodeAttributes(type, 'textAlign')) return this.options.types.every(type => commands.resetAttributes(type, 'textAlign'))
}, },
} }
}, },

View File

@@ -3,6 +3,54 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.20](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/html@2.0.0-beta.19...@tiptap/html@2.0.0-beta.20) (2021-04-07)
**Note:** Version bump only for package @tiptap/html
# [2.0.0-beta.19](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/html@2.0.0-beta.18...@tiptap/html@2.0.0-beta.19) (2021-04-07)
**Note:** Version bump only for package @tiptap/html
# [2.0.0-beta.18](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/html@2.0.0-beta.17...@tiptap/html@2.0.0-beta.18) (2021-04-07)
**Note:** Version bump only for package @tiptap/html
# [2.0.0-beta.17](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/html@2.0.0-beta.16...@tiptap/html@2.0.0-beta.17) (2021-04-07)
**Note:** Version bump only for package @tiptap/html
# [2.0.0-beta.16](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/html@2.0.0-beta.15...@tiptap/html@2.0.0-beta.16) (2021-04-07)
**Note:** Version bump only for package @tiptap/html
# [2.0.0-beta.15](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/html@2.0.0-beta.14...@tiptap/html@2.0.0-beta.15) (2021-04-06)
**Note:** Version bump only for package @tiptap/html
# [2.0.0-beta.14](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/html@2.0.0-beta.13...@tiptap/html@2.0.0-beta.14) (2021-04-04) # [2.0.0-beta.14](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/html@2.0.0-beta.13...@tiptap/html@2.0.0-beta.14) (2021-04-04)
**Note:** Version bump only for package @tiptap/html **Note:** Version bump only for package @tiptap/html

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/html", "name": "@tiptap/html",
"description": "utility package to render tiptap JSON as HTML", "description": "utility package to render tiptap JSON as HTML",
"version": "2.0.0-beta.14", "version": "2.0.0-beta.20",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",
@@ -22,8 +22,8 @@
"dist" "dist"
], ],
"dependencies": { "dependencies": {
"@tiptap/core": "^2.0.0-beta.14", "@tiptap/core": "^2.0.0-beta.20",
"hostic-dom": "^0.8.6", "hostic-dom": "^0.8.6",
"prosemirror-model": "^1.13.3" "prosemirror-model": "^1.14.0"
} }
} }

View File

@@ -3,6 +3,22 @@
All notable changes to this project will be documented in this file. All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
# [2.0.0-beta.16](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/react@2.0.0-beta.15...@tiptap/react@2.0.0-beta.16) (2021-04-07)
**Note:** Version bump only for package @tiptap/react
# [2.0.0-beta.15](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/react@2.0.0-beta.14...@tiptap/react@2.0.0-beta.15) (2021-04-07)
**Note:** Version bump only for package @tiptap/react
# [2.0.0-beta.14](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/react@2.0.0-beta.13...@tiptap/react@2.0.0-beta.14) (2021-04-04) # [2.0.0-beta.14](https://github.com/ueberdosis/tiptap-next/compare/@tiptap/react@2.0.0-beta.13...@tiptap/react@2.0.0-beta.14) (2021-04-04)

View File

@@ -1,7 +1,7 @@
{ {
"name": "@tiptap/react", "name": "@tiptap/react",
"description": "React components for tiptap", "description": "React components for tiptap",
"version": "2.0.0-beta.14", "version": "2.0.0-beta.16",
"homepage": "https://tiptap.dev", "homepage": "https://tiptap.dev",
"keywords": [ "keywords": [
"tiptap", "tiptap",
@@ -32,6 +32,7 @@
"prosemirror-view": "^1.18.2" "prosemirror-view": "^1.18.2"
}, },
"devDependencies": { "devDependencies": {
"@types/react": "^17.0.3",
"@types/react-dom": "^17.0.3" "@types/react-dom": "^17.0.3"
} }
} }

View File

@@ -1,5 +1,4 @@
import React from 'react' import React from 'react'
import { useReactNodeView } from './useReactNodeView'
export interface NodeViewContentProps { export interface NodeViewContentProps {
className?: string, className?: string,
@@ -7,14 +6,12 @@ export interface NodeViewContentProps {
} }
export const NodeViewContent: React.FC<NodeViewContentProps> = props => { export const NodeViewContent: React.FC<NodeViewContentProps> = props => {
const { isEditable } = useReactNodeView()
const Tag = props.as || 'div' const Tag = props.as || 'div'
return ( return (
<Tag <Tag
className={props.className} className={props.className}
data-node-view-content="" data-node-view-content=""
contentEditable={isEditable}
style={{ whiteSpace: 'pre-wrap' }} style={{ whiteSpace: 'pre-wrap' }}
/> />
) )

View File

@@ -1,4 +1,4 @@
import React, { useState, useEffect } from 'react' import React from 'react'
import { import {
NodeView, NodeView,
NodeViewProps, NodeViewProps,
@@ -36,26 +36,15 @@ class ReactNodeView extends NodeView<React.FunctionComponent, Editor> {
return string.charAt(0).toUpperCase() + string.substring(1) return string.charAt(0).toUpperCase() + string.substring(1)
} }
// @ts-ignore
this.component.displayName = capitalizeFirstChar(this.extension.config.name) this.component.displayName = capitalizeFirstChar(this.extension.config.name)
} }
const ReactNodeViewProvider: React.FunctionComponent = componentProps => { const ReactNodeViewProvider: React.FunctionComponent = componentProps => {
const [isEditable, setIsEditable] = useState(this.editor.isEditable)
const onDragStart = this.onDragStart.bind(this) const onDragStart = this.onDragStart.bind(this)
const onViewUpdate = () => setIsEditable(this.editor.isEditable)
const Component = this.component const Component = this.component
useEffect(() => {
this.editor.on('viewUpdate', onViewUpdate)
return () => {
this.editor.off('viewUpdate', onViewUpdate)
}
}, [])
return ( return (
<ReactNodeViewContext.Provider value={{ onDragStart, isEditable }}> <ReactNodeViewContext.Provider value={{ onDragStart }}>
<Component {...componentProps} /> <Component {...componentProps} />
</ReactNodeViewContext.Provider> </ReactNodeViewContext.Provider>
) )

Some files were not shown because too many files have changed in this diff Show More