Merge branch 'main' into feature/extension-code-block-lowlight
This commit is contained in:
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
3
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -18,7 +18,8 @@ Steps to reproduce the behavior:
|
||||
4. See error message
|
||||
|
||||
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?**
|
||||
A clear and concise description of what you expected to happen.
|
||||
|
||||
@@ -33,7 +33,7 @@
|
||||
"y-prosemirror": "^1.0.7",
|
||||
"y-webrtc": "^10.1.7",
|
||||
"y-websocket": "^1.3.11",
|
||||
"yjs": "^13.5.3"
|
||||
"yjs": "^13.5.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@babel/plugin-proposal-class-properties": "^7.13.0",
|
||||
|
||||
@@ -30,13 +30,9 @@ import TaskItem from '@tiptap/extension-task-item'
|
||||
import Highlight from '@tiptap/extension-highlight'
|
||||
import * as Y from 'yjs'
|
||||
import { WebsocketProvider } from 'y-websocket'
|
||||
// import { IndexeddbPersistence } from 'y-indexeddb'
|
||||
import { IndexeddbPersistence } from 'y-indexeddb'
|
||||
import MenuBar from './MenuBar.vue'
|
||||
|
||||
const CustomTaskItem = TaskItem.extend({
|
||||
content: 'paragraph',
|
||||
})
|
||||
|
||||
const getRandomElement = list => {
|
||||
return list[Math.floor(Math.random() * list.length)]
|
||||
}
|
||||
@@ -70,14 +66,17 @@ export default {
|
||||
|
||||
window.ydoc = ydoc
|
||||
|
||||
// this.indexdb = new IndexeddbPersistence('tiptap-collaboration-example', ydoc)
|
||||
this.indexdb = new IndexeddbPersistence('tiptap-collaboration-example', ydoc)
|
||||
|
||||
this.editor = new Editor({
|
||||
extensions: [
|
||||
...defaultExtensions().filter(extension => extension.config.name !== 'history'),
|
||||
Highlight,
|
||||
TaskList,
|
||||
CustomTaskItem,
|
||||
TaskItem,
|
||||
Collaboration.configure({
|
||||
document: ydoc,
|
||||
}),
|
||||
CollaborationCursor.configure({
|
||||
provider: this.provider,
|
||||
user: this.currentUser,
|
||||
@@ -85,9 +84,6 @@ export default {
|
||||
this.users = users
|
||||
},
|
||||
}),
|
||||
Collaboration.configure({
|
||||
document: ydoc,
|
||||
}),
|
||||
],
|
||||
})
|
||||
|
||||
@@ -327,7 +323,7 @@ export default {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> input {
|
||||
> label {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -69,7 +69,7 @@ ul[data-type="taskList"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> input {
|
||||
> label {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -5,7 +5,8 @@
|
||||
</template>
|
||||
|
||||
<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'
|
||||
|
||||
export default {
|
||||
|
||||
@@ -158,7 +158,7 @@ export default {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> input {
|
||||
> label {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -33,6 +33,9 @@ export default {
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Collaboration.configure({
|
||||
document: ydoc,
|
||||
}),
|
||||
CollaborationCursor.configure({
|
||||
provider: this.provider,
|
||||
user: {
|
||||
@@ -40,9 +43,6 @@ export default {
|
||||
color: '#f783ac',
|
||||
},
|
||||
}),
|
||||
Collaboration.configure({
|
||||
document: ydoc,
|
||||
}),
|
||||
],
|
||||
})
|
||||
},
|
||||
|
||||
@@ -6,7 +6,7 @@ context('/demos/Guide/Content/ReadOnly', () => {
|
||||
it('should be read-only', () => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
editor.setEditable(false)
|
||||
editor.commands.insertText('Edited: ')
|
||||
editor.commands.insertContent('Edited: ')
|
||||
|
||||
cy.get('.ProseMirror p:first').should('not.contain', 'Edited: ')
|
||||
})
|
||||
@@ -15,7 +15,7 @@ context('/demos/Guide/Content/ReadOnly', () => {
|
||||
it('should be editable', () => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
editor.setEditable(true)
|
||||
editor.commands.insertText('Edited: ')
|
||||
editor.commands.insertContent('Edited: ')
|
||||
|
||||
cy.get('.ProseMirror p:first').should('contain', 'Edited: ')
|
||||
})
|
||||
|
||||
@@ -16,7 +16,7 @@ export default Node.create({
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['node-view', mergeAttributes(HTMLAttributes)]
|
||||
return ['node-view', mergeAttributes(HTMLAttributes), 0]
|
||||
},
|
||||
|
||||
addNodeView() {
|
||||
|
||||
@@ -18,7 +18,7 @@ export default Node.create({
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['react-component', mergeAttributes(HTMLAttributes)]
|
||||
return ['react-component', mergeAttributes(HTMLAttributes), 0]
|
||||
},
|
||||
|
||||
addNodeView() {
|
||||
|
||||
@@ -18,7 +18,7 @@ export default Node.create({
|
||||
},
|
||||
|
||||
renderHTML({ HTMLAttributes }) {
|
||||
return ['vue-component', mergeAttributes(HTMLAttributes)]
|
||||
return ['vue-component', mergeAttributes(HTMLAttributes), 0]
|
||||
},
|
||||
|
||||
addNodeView() {
|
||||
|
||||
@@ -16,6 +16,7 @@ import Document from '@tiptap/extension-document'
|
||||
import Paragraph from '@tiptap/extension-paragraph'
|
||||
import Text from '@tiptap/extension-text'
|
||||
import Link from '@tiptap/extension-link'
|
||||
import Bold from '@tiptap/extension-bold'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
@@ -34,11 +35,12 @@ export default {
|
||||
Document,
|
||||
Paragraph,
|
||||
Text,
|
||||
Bold,
|
||||
Link,
|
||||
],
|
||||
content: `
|
||||
<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. Isn’t that cool? Let’s 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. Isn’t that cool? Let’s try <a href="https://statamic.com/">another one!</a> Yep, seems to work.
|
||||
</p>
|
||||
<p>
|
||||
By default every link will get a \`rel="noopener noreferrer nofollow"\` attribute. It’s configurable though.
|
||||
|
||||
@@ -1,21 +1,21 @@
|
||||
<template>
|
||||
<div v-if="editor">
|
||||
<button @click="editor.chain().focus(). insertText('✨').run()">
|
||||
<button @click="editor.chain().focus().insertContent('✨').run()">
|
||||
✨
|
||||
</button>
|
||||
<button @click="editor.chain().focus(). insertText('😅').run()">
|
||||
<button @click="editor.chain().focus().insertContent('😅').run()">
|
||||
😅
|
||||
</button>
|
||||
<button @click="editor.chain().focus(). insertText('🎉').run()">
|
||||
<button @click="editor.chain().focus().insertContent('🎉').run()">
|
||||
🎉
|
||||
</button>
|
||||
<button @click="editor.chain().focus(). insertText('💖').run()">
|
||||
<button @click="editor.chain().focus().insertContent('💖').run()">
|
||||
💖
|
||||
</button>
|
||||
<button @click="editor.chain().focus(). insertText('👀').run()">
|
||||
<button @click="editor.chain().focus().insertContent('👀').run()">
|
||||
👀
|
||||
</button>
|
||||
<button @click="editor.chain().focus(). insertText('👍️').run()">
|
||||
<button @click="editor.chain().focus().insertContent('👍️').run()">
|
||||
👍️
|
||||
</button>
|
||||
<editor-content :editor="editor" />
|
||||
|
||||
@@ -56,7 +56,7 @@ ul[data-type="taskList"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> input {
|
||||
> label {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -60,7 +60,7 @@ ul[data-type="taskList"] {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
> input {
|
||||
> label {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0.5rem;
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ addCommands() {
|
||||
|
||||
// Does work:
|
||||
return chain()
|
||||
.insertNode('timecode', attributes)
|
||||
.insertText(' ')
|
||||
.insertContent('foo!')
|
||||
.insertContent('bar!')
|
||||
.run()
|
||||
},
|
||||
}
|
||||
@@ -60,7 +60,7 @@ editor
|
||||
.focus()
|
||||
.command(({ tr }) => {
|
||||
// manipulate the transaction
|
||||
tr.insertText('hey, that’s cool!')
|
||||
tr.insertContent('hey, that’s cool!')
|
||||
|
||||
return true
|
||||
})
|
||||
@@ -91,7 +91,7 @@ Both calls would return `true` if it’s possible to apply the commands, and `fa
|
||||
|
||||
In order to make that work with your custom commands, don’t 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
|
||||
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 what’s possible.
|
||||
|
||||
### Content
|
||||
| Command | Description |
|
||||
| --------------- | ------------------------------------------------ |
|
||||
| .clearContent() | Clear the whole document. |
|
||||
| .insertHTML() | Insert a string of HTML at the current position. |
|
||||
| .insertNode() | Insert a node at the current position. |
|
||||
| .insertText() | Insert a string of text at the current position. |
|
||||
| .setContent() | Replace the whole document with new content. |
|
||||
| Command | Description | Links |
|
||||
| ---------------- | -------------------------------------------------------- | ------------------------------------ |
|
||||
| .clearContent() | Clear the whole document. | [More](/api/commands/clear-content) |
|
||||
| .insertContent() | Insert a node or string of HTML at the current position. | [More](/api/commands/insert-content) |
|
||||
| .setContent() | Replace the whole document with new content. | [More](/api/commands/set-content) |
|
||||
|
||||
### Nodes & Marks
|
||||
| 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. |
|
||||
| .replace() | Replaces text with a node. |
|
||||
| .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. |
|
||||
| .setMark() | Add a mark with new attributes. |
|
||||
| .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. |
|
||||
| .unsetAllMarks() | Remove all marks 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
|
||||
| Command | Description |
|
||||
@@ -220,13 +218,13 @@ this.editor
|
||||
.chain()
|
||||
.focus()
|
||||
.createParagraphNear()
|
||||
.insertText(text)
|
||||
.insertContent(text)
|
||||
.setBlockquote()
|
||||
.insertHTML('<p></p>')
|
||||
.insertContent('<p></p>')
|
||||
.createParagraphNear()
|
||||
.unsetBlockquote()
|
||||
.createParagraphNear()
|
||||
.insertHTML('<p></p>')
|
||||
.insertContent('<p></p>')
|
||||
.run()
|
||||
```
|
||||
|
||||
@@ -237,7 +235,18 @@ addCommands() {
|
||||
insertTimecode: attributes => ({ chain }) => {
|
||||
return chain()
|
||||
.focus()
|
||||
.insertNode('timecode', attributes)
|
||||
.insertContent({
|
||||
type: 'heading',
|
||||
attrs: {
|
||||
level: 2,
|
||||
},
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: 'heading',
|
||||
},
|
||||
],
|
||||
})
|
||||
.insertText(' ')
|
||||
.run();
|
||||
},
|
||||
@@ -249,5 +258,5 @@ addCommands() {
|
||||
## 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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
12
docs/src/docPages/api/commands/clear-content.md
Normal file
12
docs/src/docPages/api/commands/clear-content.md
Normal file
@@ -0,0 +1,12 @@
|
||||
# clearContent
|
||||
|
||||
See also: [setContent](/api/commands/set-content)
|
||||
|
||||
## Parameters
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
this.editor.commands.clearContent()
|
||||
```
|
||||
|
||||
23
docs/src/docPages/api/commands/insert-content.md
Normal file
23
docs/src/docPages/api/commands/insert-content.md
Normal 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',
|
||||
},
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
42
docs/src/docPages/api/commands/set-content.md
Normal file
42
docs/src/docPages/api/commands/set-content.md
Normal 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. It’s 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 what’s allowed according to the [schema](/api/schema).
|
||||
|
||||
`emitUpdate?: Boolean`
|
||||
|
||||
By default, it doesn’t trigger the update event. Passing `true` doesn’t 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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
})
|
||||
```
|
||||
|
||||
@@ -14,7 +14,6 @@ Don’t 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. |
|
||||
| `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. |
|
||||
| `getHTML()` | – | Returns the current content as HTML. |
|
||||
| `getJSON()` | – | Returns the current content as JSON. |
|
||||
@@ -129,7 +128,7 @@ new Editor({
|
||||
| `null` | Disables autofocus. |
|
||||
|
||||
### 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
|
||||
import { Editor } from '@tiptap/core'
|
||||
@@ -143,7 +142,7 @@ new Editor({
|
||||
```
|
||||
|
||||
### 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
|
||||
import { Editor } from '@tiptap/core'
|
||||
|
||||
@@ -19,9 +19,6 @@ const editor = new Editor({
|
||||
onSelectionUpdate({ editor }) {
|
||||
// The selection has changed.
|
||||
},
|
||||
onViewUpdate({ editor }) {
|
||||
// The view has changed.
|
||||
},
|
||||
onTransaction({ editor, transaction }) {
|
||||
// The editor state has changed.
|
||||
},
|
||||
@@ -57,10 +54,6 @@ editor.on('selectionUpdate', ({ editor }) => {
|
||||
// The selection has changed.
|
||||
}
|
||||
|
||||
editor.on('viewUpdate', ({ editor }) => {
|
||||
// The view has changed.
|
||||
}
|
||||
|
||||
editor.on('transaction', ({ editor, transaction }) => {
|
||||
// The editor state has changed.
|
||||
}
|
||||
@@ -113,9 +106,6 @@ const CustomExtension = Extension.create({
|
||||
onSelectionUpdate({ editor }) {
|
||||
// The selection has changed.
|
||||
},
|
||||
onViewUpdate({ editor }) {
|
||||
// The view has changed.
|
||||
},
|
||||
onTransaction({ editor, transaction }) {
|
||||
// The editor state has changed.
|
||||
},
|
||||
|
||||
@@ -51,6 +51,7 @@ const editor = new Editor({
|
||||
Text,
|
||||
// …
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Learn [more about custom extensions in our guide](/guide/extend-extensions).
|
||||
|
||||
@@ -49,6 +49,7 @@ const editor = new Editor({
|
||||
Text,
|
||||
// …
|
||||
],
|
||||
})
|
||||
```
|
||||
|
||||
Learn [more about custom extensions in our guide](/guide/build-extensions).
|
||||
Learn [more about custom extensions in our guide](/guide/custom-extensions).
|
||||
|
||||
@@ -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.
|
||||
|
||||
```js
|
||||
this.editor.chain().focus().insertText('✨').run()
|
||||
this.editor.chain().focus().insertContent('✨').run()
|
||||
```
|
||||
|
||||
<demo name="Nodes/Emoji" />
|
||||
|
||||
@@ -7,7 +7,7 @@ Unlike many other editors, tiptap is based on a [schema](https://prosemirror.net
|
||||
|
||||
This schema is *very* strict. You can’t 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, don’t have any extension that handles `strong` tags registered, you’ll 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 don’t have any extension that handles `strong` tags, you’ll only see `This is important` – without the strong tags.
|
||||
|
||||
## How a schema looks like
|
||||
When you’ll work with the provided extensions only, you don’t have to care that much about the schema. If you’re building your own extensions, it’s probably helpful to understand how the schema works. Let’s look at the most simple schema for a typical ProseMirror editor:
|
||||
|
||||
4
docs/src/docPages/community.md
Normal file
4
docs/src/docPages/community.md
Normal file
@@ -0,0 +1,4 @@
|
||||
# Community
|
||||
* GitHub https://github.com/ueberdosis/tiptap-next
|
||||
* Discord https://discord.gg/WtJ49jGshW
|
||||
* Twitter https://twitter.com/tiptap_editor
|
||||
@@ -158,15 +158,15 @@ const provider = new WebsocketProvider('ws://127.0.0.1:1234', 'example-document'
|
||||
|
||||
const editor = new Editor({
|
||||
extensions: [
|
||||
Collaboration.configure({
|
||||
document: ydoc,
|
||||
}),
|
||||
// Register the collaboration cursor extension
|
||||
CollaborationCursor.configure({
|
||||
provider: provider,
|
||||
name: 'Cyndi Lauper',
|
||||
color: '#f783ac',
|
||||
}),
|
||||
Collaboration.configure({
|
||||
document: ydoc,
|
||||
}),
|
||||
// …
|
||||
],
|
||||
})
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Configure the editor
|
||||
# Configuration
|
||||
|
||||
## toc
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
# Build extensions
|
||||
# Custom extensions
|
||||
|
||||
## toc
|
||||
|
||||
## 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, don’t forget to [share it with the community](https://github.com/ueberdosis/tiptap/issues/819).
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Extend the functionality
|
||||
# Overwrite & extend
|
||||
|
||||
## toc
|
||||
|
||||
@@ -37,7 +37,18 @@ The same applies to every aspect of an existing extension, except to the name. L
|
||||
### Name
|
||||
The extension name is used in a whole lot of places and changing it isn’t 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
|
||||
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:
|
||||
|
||||
@@ -49,7 +49,7 @@ Let’s assume you’ve got the editor running already and you want to add your
|
||||
Oh, that’s a long command, right? Actually, it’s a [chain of commands](/api/commands#chain-commands), so let’s go through this one by one:
|
||||
|
||||
```js
|
||||
editor.chain().toggleBold().focus().run()
|
||||
editor.chain().focus().toggleBold().run()
|
||||
```
|
||||
|
||||
1. `editor` should be a tiptap instance,
|
||||
|
||||
@@ -61,7 +61,7 @@ You can even mix non-editable and editable text. That’s great to build complex
|
||||
**BUT**, that also means the cursor can’t 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
|
||||
But what happens if you [access the editor content](/guide/content)? If you’re working with HTML, you’ll need to tell tiptap how your node should be serialized.
|
||||
But what happens if you [access the editor content](/guide/output)? If you’re working with HTML, you’ll 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 wouldn’t want that anyway.
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ Using frameworks like Vue or React can feel too complex, if you’re used to wor
|
||||
## Render a node view with JavaScript
|
||||
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()`
|
||||
3. Write your render function
|
||||
4. [Configure tiptap to use your new node extension](/guide/configuration)
|
||||
|
||||
@@ -8,7 +8,7 @@ Using plain JavaScript can feel complex if you are used to work in React. Good n
|
||||
## Render a React component
|
||||
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
|
||||
3. Pass that component to the provided `ReactNodeViewRenderer`
|
||||
4. Register it with `addNodeView()`
|
||||
|
||||
@@ -8,7 +8,7 @@ Using plain JavaScript can feel complex if you are used to work in Vue. Good new
|
||||
## Render a Vue component
|
||||
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
|
||||
3. Pass that component to the provided `VueNodeViewRenderer`
|
||||
4. Register it with `addNodeView()`
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Export content
|
||||
# Output
|
||||
|
||||
## toc
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Custom styling
|
||||
# Styling
|
||||
|
||||
## toc
|
||||
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: Alpine WYSIWYG
|
||||
---
|
||||
|
||||
# Alpine.js
|
||||
|
||||
## toc
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: Livewire WYSIWYG
|
||||
---
|
||||
|
||||
# Livewire
|
||||
|
||||
## toc
|
||||
|
||||
@@ -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" />
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: Nuxt.js WYSIWYG
|
||||
---
|
||||
|
||||
# Nuxt.js
|
||||
|
||||
## toc
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: React WYSIWYG
|
||||
---
|
||||
|
||||
# React
|
||||
|
||||
## toc
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: Svelte WYSIWYG
|
||||
---
|
||||
|
||||
# Svelte
|
||||
|
||||
## toc
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: Vue.js 2 WYSIWYG
|
||||
---
|
||||
|
||||
# Vue.js 2
|
||||
|
||||
## toc
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
---
|
||||
title: Vue.js 3 WYSIWYG
|
||||
---
|
||||
|
||||
# Vue.js 3
|
||||
|
||||
## toc
|
||||
|
||||
@@ -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
|
||||
[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:
|
||||
|
||||
@@ -57,6 +57,15 @@
|
||||
<portal :to="sidebarPortal" v-if="showSidebar">
|
||||
<nav class="app__sidebar-menu">
|
||||
<div class="app__link-group" v-for="(linkGroup, i) in linkGroups" :key="i">
|
||||
<template v-if="linkGroup.link && !linkGroup.items">
|
||||
<g-link
|
||||
class="app__link-group__link"
|
||||
:to="linkGroup.redirect || linkGroup.link"
|
||||
>
|
||||
{{ linkGroup.title }}
|
||||
</g-link>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="app__link-group-title">
|
||||
{{ linkGroup.title }}
|
||||
</div>
|
||||
@@ -93,6 +102,7 @@
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</template>
|
||||
</div>
|
||||
</nav>
|
||||
</portal>
|
||||
|
||||
@@ -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
|
||||
items:
|
||||
- title: Installation
|
||||
@@ -82,24 +92,24 @@
|
||||
|
||||
- title: Guide
|
||||
items:
|
||||
- title: Configure the editor
|
||||
- title: Configuration
|
||||
link: /guide/configuration
|
||||
- title: Create menus
|
||||
- title: Menus
|
||||
link: /guide/menus
|
||||
type: new
|
||||
- title: Custom styling
|
||||
- title: Styling
|
||||
link: /guide/styling
|
||||
- title: Output
|
||||
link: /guide/output
|
||||
- title: Accessibility
|
||||
link: /guide/accessibility
|
||||
- title: Export content
|
||||
link: /guide/content
|
||||
- title: Collaborative editing
|
||||
link: /guide/collaborative-editing
|
||||
# type: pro
|
||||
- title: Extend the functionality
|
||||
- title: Custom extensions
|
||||
link: /guide/custom-extensions
|
||||
- title: Overwrite & extend
|
||||
link: /guide/extend-extensions
|
||||
- title: Build extensions
|
||||
link: /guide/build-extensions
|
||||
- title: Interactive node views
|
||||
link: /guide/node-views
|
||||
type: new
|
||||
@@ -125,6 +135,15 @@
|
||||
link: /api/editor
|
||||
- title: 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
|
||||
link: /api/nodes
|
||||
items:
|
||||
|
||||
@@ -1,23 +1,23 @@
|
||||
context('insertHTML', () => {
|
||||
context('insertContent', () => {
|
||||
before(() => {
|
||||
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 }]) => {
|
||||
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)
|
||||
})
|
||||
})
|
||||
|
||||
it('appends the content when using the insertHTML command', () => {
|
||||
it('appends the content when using the insertContent command', () => {
|
||||
cy.get('.ProseMirror').then(([{ editor }]) => {
|
||||
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>')
|
||||
})
|
||||
@@ -3,6 +3,69 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/core
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/core",
|
||||
"description": "headless rich text editor",
|
||||
"version": "2.0.0-beta.14",
|
||||
"version": "2.0.0-beta.20",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
@@ -35,10 +35,10 @@
|
||||
"prosemirror-commands": "^1.1.7",
|
||||
"prosemirror-inputrules": "^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-state": "^1.3.4",
|
||||
"prosemirror-transform": "^1.2.12",
|
||||
"prosemirror-transform": "^1.3.2",
|
||||
"prosemirror-view": "^1.18.2"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,12 +2,12 @@ import {
|
||||
EditorState, Plugin, PluginKey, Transaction,
|
||||
} from 'prosemirror-state'
|
||||
import { EditorView } from 'prosemirror-view'
|
||||
import { Schema, DOMParser, Node } from 'prosemirror-model'
|
||||
import elementFromString from './utilities/elementFromString'
|
||||
import { Schema } from 'prosemirror-model'
|
||||
import getNodeAttributes from './helpers/getNodeAttributes'
|
||||
import getMarkAttributes from './helpers/getMarkAttributes'
|
||||
import isActive from './helpers/isActive'
|
||||
import removeElement from './utilities/removeElement'
|
||||
import createDocument from './helpers/createDocument'
|
||||
import getHTMLFromFragment from './helpers/getHTMLFromFragment'
|
||||
import isNodeEmpty from './helpers/isNodeEmpty'
|
||||
import createStyleTag from './utilities/createStyleTag'
|
||||
@@ -16,7 +16,6 @@ import ExtensionManager from './ExtensionManager'
|
||||
import EventEmitter from './EventEmitter'
|
||||
import {
|
||||
EditorOptions,
|
||||
Content,
|
||||
CanCommands,
|
||||
ChainedCommands,
|
||||
SingleCommands,
|
||||
@@ -62,7 +61,6 @@ export class Editor extends EventEmitter {
|
||||
onCreate: () => null,
|
||||
onUpdate: () => null,
|
||||
onSelectionUpdate: () => null,
|
||||
onViewUpdate: () => null,
|
||||
onTransaction: () => null,
|
||||
onFocus: () => null,
|
||||
onBlur: () => null,
|
||||
@@ -83,7 +81,6 @@ export class Editor extends EventEmitter {
|
||||
this.on('create', this.options.onCreate)
|
||||
this.on('update', this.options.onUpdate)
|
||||
this.on('selectionUpdate', this.options.onSelectionUpdate)
|
||||
this.on('viewUpdate', this.options.onViewUpdate)
|
||||
this.on('transaction', this.options.onTransaction)
|
||||
this.on('focus', this.options.onFocus)
|
||||
this.on('blur', this.options.onBlur)
|
||||
@@ -240,23 +237,14 @@ export class Editor extends EventEmitter {
|
||||
...this.options.editorProps,
|
||||
dispatchTransaction: this.dispatchTransaction.bind(this),
|
||||
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.
|
||||
// Therefore we will add all plugins and node views directly afterwards.
|
||||
const newState = this.state.reconfigure({
|
||||
plugins: [
|
||||
new Plugin({
|
||||
view: () => ({
|
||||
update: () => this.emit('viewUpdate', {
|
||||
editor: this,
|
||||
}),
|
||||
}),
|
||||
}),
|
||||
...this.extensionManager.plugins,
|
||||
],
|
||||
plugins: this.extensionManager.plugins,
|
||||
})
|
||||
|
||||
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
|
||||
|
||||
private capturedTransaction: Transaction | null = null
|
||||
|
||||
@@ -16,6 +16,11 @@ declare module '@tiptap/core' {
|
||||
*/
|
||||
name: string,
|
||||
|
||||
/**
|
||||
* Priority
|
||||
*/
|
||||
priority?: number,
|
||||
|
||||
/**
|
||||
* Default options
|
||||
*/
|
||||
@@ -126,14 +131,6 @@ declare module '@tiptap/core' {
|
||||
editor: Editor,
|
||||
}) => void) | null,
|
||||
|
||||
/**
|
||||
* The view has changed.
|
||||
*/
|
||||
onViewUpdate?: ((this: {
|
||||
options: Options,
|
||||
editor: Editor,
|
||||
}) => void) | null,
|
||||
|
||||
/**
|
||||
* The editor state has changed.
|
||||
*/
|
||||
@@ -188,6 +185,7 @@ export class Extension<Options = any> {
|
||||
|
||||
config: ExtensionConfig = {
|
||||
name: 'extension',
|
||||
priority: 100,
|
||||
defaultOptions: {},
|
||||
}
|
||||
|
||||
|
||||
@@ -25,7 +25,7 @@ export default class ExtensionManager {
|
||||
|
||||
constructor(extensions: Extensions, editor: Editor) {
|
||||
this.editor = editor
|
||||
this.extensions = extensions
|
||||
this.extensions = this.sort(extensions)
|
||||
this.schema = getSchema(this.extensions)
|
||||
|
||||
this.extensions.forEach(extension => {
|
||||
@@ -59,10 +59,6 @@ export default class ExtensionManager {
|
||||
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') {
|
||||
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 {
|
||||
return this.extensions.reduce((commands, extension) => {
|
||||
const context = {
|
||||
|
||||
@@ -21,6 +21,11 @@ declare module '@tiptap/core' {
|
||||
*/
|
||||
name: string,
|
||||
|
||||
/**
|
||||
* Priority
|
||||
*/
|
||||
priority?: number,
|
||||
|
||||
/**
|
||||
* Default options
|
||||
*/
|
||||
@@ -140,15 +145,6 @@ declare module '@tiptap/core' {
|
||||
type: MarkType,
|
||||
}) => void) | null,
|
||||
|
||||
/**
|
||||
* The view has changed.
|
||||
*/
|
||||
onViewUpdate?: ((this: {
|
||||
options: Options,
|
||||
editor: Editor,
|
||||
type: MarkType,
|
||||
}) => void) | null,
|
||||
|
||||
/**
|
||||
* The editor state has changed.
|
||||
*/
|
||||
@@ -263,6 +259,7 @@ export class Mark<Options = any> {
|
||||
|
||||
config: MarkConfig = {
|
||||
name: 'mark',
|
||||
priority: 100,
|
||||
defaultOptions: {},
|
||||
}
|
||||
|
||||
|
||||
@@ -26,6 +26,11 @@ declare module '@tiptap/core' {
|
||||
*/
|
||||
name: string,
|
||||
|
||||
/**
|
||||
* Priority
|
||||
*/
|
||||
priority?: number,
|
||||
|
||||
/**
|
||||
* Default options
|
||||
*/
|
||||
@@ -145,15 +150,6 @@ declare module '@tiptap/core' {
|
||||
type: NodeType,
|
||||
}) => void) | null,
|
||||
|
||||
/**
|
||||
* The view has changed.
|
||||
*/
|
||||
onViewUpdate?: ((this: {
|
||||
options: Options,
|
||||
editor: Editor,
|
||||
type: NodeType,
|
||||
}) => void) | null,
|
||||
|
||||
/**
|
||||
* The editor state has changed.
|
||||
*/
|
||||
@@ -321,6 +317,7 @@ export class Node<Options = any> {
|
||||
|
||||
config: NodeConfig = {
|
||||
name: 'node',
|
||||
priority: 100,
|
||||
defaultOptions: {},
|
||||
}
|
||||
|
||||
|
||||
35
packages/core/src/commands/insertContent.ts
Normal file
35
packages/core/src/commands/insertContent.ts
Normal 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
|
||||
}
|
||||
@@ -15,6 +15,8 @@ declare module '@tiptap/core' {
|
||||
}
|
||||
|
||||
export const insertHTML: RawCommands['insertHTML'] = value => ({ tr, state, dispatch }) => {
|
||||
console.warn('[tiptap warn]: insertHTML() is deprecated. please use insertContent() instead.')
|
||||
|
||||
const { selection } = tr
|
||||
const element = elementFromString(value)
|
||||
const slice = DOMParser.fromSchema(state.schema).parseSlice(element)
|
||||
|
||||
@@ -14,6 +14,8 @@ declare module '@tiptap/core' {
|
||||
}
|
||||
|
||||
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 type = getNodeType(typeOrName, state.schema)
|
||||
|
||||
|
||||
@@ -12,6 +12,8 @@ declare module '@tiptap/core' {
|
||||
}
|
||||
|
||||
export const insertText: RawCommands['insertText'] = value => ({ tr, dispatch }) => {
|
||||
console.warn('[tiptap warn]: insertText() is deprecated. please use insertContent() instead.')
|
||||
|
||||
if (dispatch) {
|
||||
tr.insertText(value)
|
||||
}
|
||||
|
||||
61
packages/core/src/commands/resetAttributes.ts
Normal file
61
packages/core/src/commands/resetAttributes.ts
Normal 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
|
||||
}
|
||||
@@ -15,6 +15,8 @@ declare module '@tiptap/core' {
|
||||
}
|
||||
|
||||
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 { selection } = tr
|
||||
const { ranges } = selection
|
||||
|
||||
@@ -1,5 +1,11 @@
|
||||
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' {
|
||||
interface Commands {
|
||||
@@ -7,15 +13,18 @@ declare module '@tiptap/core' {
|
||||
/**
|
||||
* 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 }) => {
|
||||
const { createDocument } = editor
|
||||
const { doc } = tr
|
||||
const document = createDocument(content, parseOptions)
|
||||
const document = createDocument(content, editor.schema, parseOptions)
|
||||
const selection = TextSelection.create(doc, 0, doc.content.size)
|
||||
|
||||
if (dispatch) {
|
||||
|
||||
66
packages/core/src/commands/updateAttributes.ts
Normal file
66
packages/core/src/commands/updateAttributes.ts
Normal 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
|
||||
}
|
||||
@@ -14,6 +14,8 @@ declare module '@tiptap/core' {
|
||||
}
|
||||
|
||||
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 { selection } = tr
|
||||
const { ranges } = selection
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as exitCode from '../commands/exitCode'
|
||||
import * as extendMarkRange from '../commands/extendMarkRange'
|
||||
import * as first from '../commands/first'
|
||||
import * as focus from '../commands/focus'
|
||||
import * as insertContent from '../commands/insertContent'
|
||||
import * as insertHTML from '../commands/insertHTML'
|
||||
import * as insertNode from '../commands/insertNode'
|
||||
import * as insertText from '../commands/insertText'
|
||||
@@ -23,6 +24,7 @@ import * as liftListItem from '../commands/liftListItem'
|
||||
import * as newlineInCode from '../commands/newlineInCode'
|
||||
import * as replace from '../commands/replace'
|
||||
import * as replaceRange from '../commands/replaceRange'
|
||||
import * as resetAttributes from '../commands/resetAttributes'
|
||||
import * as resetNodeAttributes from '../commands/resetNodeAttributes'
|
||||
import * as scrollIntoView from '../commands/scrollIntoView'
|
||||
import * as selectAll from '../commands/selectAll'
|
||||
@@ -42,6 +44,7 @@ import * as toggleWrap from '../commands/toggleWrap'
|
||||
import * as undoInputRule from '../commands/undoInputRule'
|
||||
import * as unsetAllMarks from '../commands/unsetAllMarks'
|
||||
import * as unsetMark from '../commands/unsetMark'
|
||||
import * as updateAttributes from '../commands/updateAttributes'
|
||||
import * as updateNodeAttributes from '../commands/updateNodeAttributes'
|
||||
import * as wrapIn from '../commands/wrapIn'
|
||||
import * as wrapInList from '../commands/wrapInList'
|
||||
@@ -58,6 +61,7 @@ export { exitCode }
|
||||
export { extendMarkRange }
|
||||
export { first }
|
||||
export { focus }
|
||||
export { insertContent }
|
||||
export { insertHTML }
|
||||
export { insertNode }
|
||||
export { insertText }
|
||||
@@ -70,6 +74,7 @@ export { liftListItem }
|
||||
export { newlineInCode }
|
||||
export { replace }
|
||||
export { replaceRange }
|
||||
export { resetAttributes }
|
||||
export { resetNodeAttributes }
|
||||
export { scrollIntoView }
|
||||
export { selectAll }
|
||||
@@ -89,6 +94,7 @@ export { toggleWrap }
|
||||
export { undoInputRule }
|
||||
export { unsetAllMarks }
|
||||
export { unsetMark }
|
||||
export { updateAttributes }
|
||||
export { updateNodeAttributes }
|
||||
export { wrapIn }
|
||||
export { wrapInList }
|
||||
@@ -110,6 +116,7 @@ export const Commands = Extension.create({
|
||||
...extendMarkRange,
|
||||
...first,
|
||||
...focus,
|
||||
...insertContent,
|
||||
...insertHTML,
|
||||
...insertNode,
|
||||
...insertText,
|
||||
@@ -122,6 +129,7 @@ export const Commands = Extension.create({
|
||||
...newlineInCode,
|
||||
...replace,
|
||||
...replaceRange,
|
||||
...resetAttributes,
|
||||
...resetNodeAttributes,
|
||||
...scrollIntoView,
|
||||
...selectAll,
|
||||
@@ -141,6 +149,7 @@ export const Commands = Extension.create({
|
||||
...undoInputRule,
|
||||
...unsetAllMarks,
|
||||
...unsetMark,
|
||||
...updateAttributes,
|
||||
...updateNodeAttributes,
|
||||
...wrapIn,
|
||||
...wrapInList,
|
||||
|
||||
13
packages/core/src/helpers/createDocument.ts
Normal file
13
packages/core/src/helpers/createDocument.ts
Normal 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
|
||||
}
|
||||
59
packages/core/src/helpers/createNodeFromContent.ts
Normal file
59
packages/core/src/helpers/createNodeFromContent.ts
Normal 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)
|
||||
}
|
||||
@@ -32,7 +32,6 @@ export interface EditorOptions {
|
||||
onBeforeCreate: (props: { editor: Editor }) => void,
|
||||
onCreate: (props: { editor: Editor }) => void,
|
||||
onUpdate: (props: { editor: Editor }) => void,
|
||||
onViewUpdate: (props: { editor: Editor }) => void,
|
||||
onSelectionUpdate: (props: { editor: Editor }) => void,
|
||||
onTransaction: (props: { editor: Editor, transaction: Transaction }) => void,
|
||||
onFocus: (props: { editor: Editor, event: FocusEvent }) => void,
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-collaboration-cursor
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-collaboration-cursor",
|
||||
"description": "collaboration cursor extension for tiptap",
|
||||
"version": "2.0.0-beta.4",
|
||||
"version": "2.0.0-beta.5",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
|
||||
@@ -31,6 +31,8 @@ const awarenessStatesToArray = (states: Map<number, { [key: string]: any }>) =>
|
||||
export const CollaborationCursor = Extension.create<CollaborationCursorOptions>({
|
||||
name: 'collaborationCursor',
|
||||
|
||||
priority: 1000,
|
||||
|
||||
defaultOptions: {
|
||||
provider: null,
|
||||
user: {
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-dropcursor
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-dropcursor",
|
||||
"description": "dropcursor extension for tiptap",
|
||||
"version": "2.0.0-beta.1",
|
||||
"version": "2.0.0-beta.2",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
@@ -26,6 +26,6 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@types/prosemirror-dropcursor": "^1.0.1",
|
||||
"prosemirror-dropcursor": "^1.3.3"
|
||||
"prosemirror-dropcursor": "^1.3.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-horizontal-rule
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-horizontal-rule",
|
||||
"description": "horizontal rule extension for tiptap",
|
||||
"version": "2.0.0-beta.1",
|
||||
"version": "2.0.0-beta.2",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
@@ -22,7 +22,9 @@
|
||||
"dist"
|
||||
],
|
||||
"peerDependencies": {
|
||||
"@tiptap/core": "^2.0.0-beta.1",
|
||||
"prosemirror-commands": "^1.1.3"
|
||||
"@tiptap/core": "^2.0.0-beta.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"prosemirror-state": "^1.3.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import {
|
||||
nodeInputRule,
|
||||
mergeAttributes,
|
||||
} from '@tiptap/core'
|
||||
import { TextSelection } from 'prosemirror-state'
|
||||
|
||||
export interface HorizontalRuleOptions {
|
||||
HTMLAttributes: {
|
||||
@@ -46,6 +47,22 @@ export const HorizontalRule = Node.create<HorizontalRuleOptions>({
|
||||
setHorizontalRule: () => ({ tr, dispatch }) => {
|
||||
if (dispatch) {
|
||||
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
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-link
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-link",
|
||||
"description": "link extension for tiptap",
|
||||
"version": "2.0.0-beta.1",
|
||||
"version": "2.0.0-beta.2",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
|
||||
@@ -38,6 +38,8 @@ export const pasteRegexWithBrackets = /(?:\()https?:\/\/(?:www\.)?[-a-zA-Z0-9@:%
|
||||
export const Link = Mark.create<LinkOptions>({
|
||||
name: 'link',
|
||||
|
||||
priority: 1000,
|
||||
|
||||
inclusive: false,
|
||||
|
||||
defaultOptions: {
|
||||
|
||||
@@ -3,6 +3,57 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-mention
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-mention",
|
||||
"description": "mention extension for tiptap",
|
||||
"version": "2.0.0-beta.14",
|
||||
"version": "2.0.0-beta.20",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
@@ -25,6 +25,6 @@
|
||||
"@tiptap/core": "^2.0.0-beta.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"@tiptap/suggestion": "^2.0.0-beta.14"
|
||||
"@tiptap/suggestion": "^2.0.0-beta.20"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ export const Mention = Node.create<MentionOptions>({
|
||||
.chain()
|
||||
.focus()
|
||||
.replaceRange(range, 'mention', props)
|
||||
.insertText(' ')
|
||||
.insertContent(' ')
|
||||
.run()
|
||||
},
|
||||
allow: ({ editor, range }) => {
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-paragraph
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-paragraph",
|
||||
"description": "paragraph extension for tiptap",
|
||||
"version": "2.0.0-beta.1",
|
||||
"version": "2.0.0-beta.2",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
|
||||
@@ -20,6 +20,8 @@ declare module '@tiptap/core' {
|
||||
export const Paragraph = Node.create<ParagraphOptions>({
|
||||
name: 'paragraph',
|
||||
|
||||
priority: 1000,
|
||||
|
||||
defaultOptions: {
|
||||
HTMLAttributes: {},
|
||||
},
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-placeholder
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-placeholder",
|
||||
"description": "placeholder extension for tiptap",
|
||||
"version": "2.0.0-beta.3",
|
||||
"version": "2.0.0-beta.4",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
@@ -25,7 +25,7 @@
|
||||
"@tiptap/core": "^2.0.0-beta.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"prosemirror-model": "^1.13.3",
|
||||
"prosemirror-model": "^1.14.0",
|
||||
"prosemirror-state": "^1.3.4",
|
||||
"prosemirror-view": "^1.18.2"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,17 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-task-item
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-task-item",
|
||||
"description": "task item extension for tiptap",
|
||||
"version": "2.0.0-beta.1",
|
||||
"version": "2.0.0-beta.2",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
|
||||
@@ -81,11 +81,13 @@ export const TaskItem = Node.create<TaskItemOptions>({
|
||||
}) => {
|
||||
const { view } = editor
|
||||
const listItem = document.createElement('li')
|
||||
const checkboxWrapper = document.createElement('label')
|
||||
const checkboxStyler = document.createElement('span')
|
||||
const checkbox = document.createElement('input')
|
||||
const content = document.createElement('div')
|
||||
|
||||
checkboxWrapper.contentEditable = 'false'
|
||||
checkbox.type = 'checkbox'
|
||||
checkbox.contentEditable = 'false'
|
||||
checkbox.addEventListener('change', event => {
|
||||
const { checked } = event.target as any
|
||||
|
||||
@@ -101,9 +103,12 @@ export const TaskItem = Node.create<TaskItemOptions>({
|
||||
checkbox.setAttribute('checked', 'checked')
|
||||
}
|
||||
|
||||
listItem.append(checkbox, content)
|
||||
checkboxWrapper.append(checkbox, checkboxStyler)
|
||||
listItem.append(checkboxWrapper, content)
|
||||
|
||||
Object.entries(HTMLAttributes).forEach(([key, value]) => {
|
||||
Object
|
||||
.entries(HTMLAttributes)
|
||||
.forEach(([key, value]) => {
|
||||
listItem.setAttribute(key, value)
|
||||
})
|
||||
|
||||
|
||||
@@ -3,6 +3,28 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/extension-text-align
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/extension-text-align",
|
||||
"description": "text align extension for tiptap",
|
||||
"version": "2.0.0-beta.1",
|
||||
"version": "2.0.0-beta.3",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
|
||||
@@ -56,10 +56,10 @@ export const TextAlign = Extension.create<TextAlignOptions>({
|
||||
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 }) => {
|
||||
return this.options.types.every(type => commands.resetNodeAttributes(type, 'textAlign'))
|
||||
return this.options.types.every(type => commands.resetAttributes(type, 'textAlign'))
|
||||
},
|
||||
}
|
||||
},
|
||||
|
||||
@@ -3,6 +3,54 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
**Note:** Version bump only for package @tiptap/html
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/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",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
@@ -22,8 +22,8 @@
|
||||
"dist"
|
||||
],
|
||||
"dependencies": {
|
||||
"@tiptap/core": "^2.0.0-beta.14",
|
||||
"@tiptap/core": "^2.0.0-beta.20",
|
||||
"hostic-dom": "^0.8.6",
|
||||
"prosemirror-model": "^1.13.3"
|
||||
"prosemirror-model": "^1.14.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,22 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@tiptap/react",
|
||||
"description": "React components for tiptap",
|
||||
"version": "2.0.0-beta.14",
|
||||
"version": "2.0.0-beta.16",
|
||||
"homepage": "https://tiptap.dev",
|
||||
"keywords": [
|
||||
"tiptap",
|
||||
@@ -32,6 +32,7 @@
|
||||
"prosemirror-view": "^1.18.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/react": "^17.0.3",
|
||||
"@types/react-dom": "^17.0.3"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import React from 'react'
|
||||
import { useReactNodeView } from './useReactNodeView'
|
||||
|
||||
export interface NodeViewContentProps {
|
||||
className?: string,
|
||||
@@ -7,14 +6,12 @@ export interface NodeViewContentProps {
|
||||
}
|
||||
|
||||
export const NodeViewContent: React.FC<NodeViewContentProps> = props => {
|
||||
const { isEditable } = useReactNodeView()
|
||||
const Tag = props.as || 'div'
|
||||
|
||||
return (
|
||||
<Tag
|
||||
className={props.className}
|
||||
data-node-view-content=""
|
||||
contentEditable={isEditable}
|
||||
style={{ whiteSpace: 'pre-wrap' }}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useState, useEffect } from 'react'
|
||||
import React from 'react'
|
||||
import {
|
||||
NodeView,
|
||||
NodeViewProps,
|
||||
@@ -36,26 +36,15 @@ class ReactNodeView extends NodeView<React.FunctionComponent, Editor> {
|
||||
return string.charAt(0).toUpperCase() + string.substring(1)
|
||||
}
|
||||
|
||||
// @ts-ignore
|
||||
this.component.displayName = capitalizeFirstChar(this.extension.config.name)
|
||||
}
|
||||
|
||||
const ReactNodeViewProvider: React.FunctionComponent = componentProps => {
|
||||
const [isEditable, setIsEditable] = useState(this.editor.isEditable)
|
||||
const onDragStart = this.onDragStart.bind(this)
|
||||
const onViewUpdate = () => setIsEditable(this.editor.isEditable)
|
||||
const Component = this.component
|
||||
|
||||
useEffect(() => {
|
||||
this.editor.on('viewUpdate', onViewUpdate)
|
||||
|
||||
return () => {
|
||||
this.editor.off('viewUpdate', onViewUpdate)
|
||||
}
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<ReactNodeViewContext.Provider value={{ onDragStart, isEditable }}>
|
||||
<ReactNodeViewContext.Provider value={{ onDragStart }}>
|
||||
<Component {...componentProps} />
|
||||
</ReactNodeViewContext.Provider>
|
||||
)
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user