Merge branch 'next' of github.com:ueberdosis/tiptap into feature/resizable-node-views

This commit is contained in:
bdbch 2025-05-01 18:47:36 +02:00
commit 4083d5194b
148 changed files with 1899 additions and 193 deletions

View File

@ -0,0 +1,5 @@
---
'@tiptap/core': major
---
This resolves in issue with SSR where the isDestroyed property could not be read while in SSR

View File

@ -0,0 +1,5 @@
---
"@tiptap/core": patch
---
Fixes a bug where you could not unregister multiple plugins.

View File

@ -71,6 +71,7 @@
"chilly-lemons-remember",
"clever-bags-end",
"cool-bananas-breathe",
"cool-singers-call",
"cuddly-impalas-heal",
"curly-adults-move",
"dirty-bats-look",
@ -83,6 +84,7 @@
"healthy-pigs-work",
"large-kangaroos-battle",
"lazy-needles-train",
"lucky-bears-exercise",
"many-laws-vanish",
"moody-geckos-sort",
"nervous-hairs-walk",
@ -93,16 +95,18 @@
"quick-days-matter",
"red-ants-wonder",
"red-rivers-exist",
"selfish-rings-hang",
"seven-llamas-love",
"shaggy-hats-rescue",
"shiny-days-rhyme",
"sixty-news-ring",
"smooth-carrots-beam",
"spotty-cobras-shake",
"tame-worms-applaud",
"thirty-rockets-act",
"tidy-fireants-hang",
"twenty-moose-invent",
"weak-books-eat",
"wise-books-kiss",
"wise-carpets-unite",
"witty-eels-cheer"
]

View File

@ -0,0 +1,6 @@
---
'@tiptap/extension-collaboration-caret': patch
'@tiptap/extension-collaboration': patch
---
Use newer y-prosemirror version to resolve dependency chaos

View File

@ -1,5 +0,0 @@
---
'@tiptap/react': patch
---
Fixed a bug in the EditorContent component that caused a crash in Firefox based browsers because of the editor view not being available when an uninitialized editor is unmounted (for example via Strict mode)

View File

@ -0,0 +1,5 @@
---
"@tiptap/extension-text-align": patch
---
Added new `toggleTextAlign` command to TextAlign extension to make toggling text alignments easier to handle

View File

@ -0,0 +1,5 @@
---
'@tiptap/extension-mention': minor
---
Support multiple triggers in Mention extension

View File

@ -15,7 +15,7 @@
"@lexical/react": "^0.11.3",
"@lifeomic/attempt": "3.1.0",
"@shikijs/core": "1.10.3",
"@tiptap/y-tiptap": "^2.0.0",
"@tiptap/y-tiptap": "^3.0.0-beta.3",
"d3": "^7.9.0",
"fast-glob": "^3.3.2",
"highlight.js": "^11.11.1",
@ -63,7 +63,7 @@
"tailwindcss": "^3.4.17",
"typescript": "^5.7.2",
"uuid": "^8.3.2",
"vite": "^5.4.15",
"vite": "^5.4.17",
"vite-plugin-checker": "^0.6.4",
"vue": "^3.5.13",
"vue-router": "^4.5.0"

View File

@ -106,7 +106,7 @@ context('/src/Commands/SetContent/React/', () => {
editor.commands.setContent('<p><span data-type="mention" data-id="1" data-label="John Doe">@John Doe</span></p>')
cy.get('.tiptap').should(
'contain.html',
'<span data-type="mention" data-id="1" data-label="John Doe" contenteditable="false">@John Doe</span>',
'<span data-type="mention" data-id="1" data-label="John Doe" data-mention-suggestion-char="@" contenteditable="false">@John Doe</span>',
)
})
})

View File

@ -0,0 +1,68 @@
import './MentionList.scss'
import React, { forwardRef, useEffect, useImperativeHandle, useState } from 'react'
export default forwardRef((props, ref) => {
const [selectedIndex, setSelectedIndex] = useState(0)
const selectItem = index => {
const item = props.items[index]
if (item) {
props.command({ id: item })
}
}
const upHandler = () => {
setSelectedIndex((selectedIndex + props.items.length - 1) % props.items.length)
}
const downHandler = () => {
setSelectedIndex((selectedIndex + 1) % props.items.length)
}
const enterHandler = () => {
selectItem(selectedIndex)
}
useEffect(() => setSelectedIndex(0), [props.items])
useImperativeHandle(ref, () => ({
onKeyDown: ({ event }) => {
if (event.key === 'ArrowUp') {
upHandler()
return true
}
if (event.key === 'ArrowDown') {
downHandler()
return true
}
if (event.key === 'Enter') {
enterHandler()
return true
}
return false
},
}))
return (
<div className="dropdown-menu">
{props.items.length ? (
props.items.map((item, index) => (
<button
className={index === selectedIndex ? 'is-selected' : ''}
key={index}
onClick={() => selectItem(index)}
>
{item}
</button>
))
) : (
<div className="item">No result</div>
)}
</div>
)
})

View File

@ -0,0 +1,31 @@
/* Dropdown menu */
.dropdown-menu {
background: var(--white);
border: 1px solid var(--gray-1);
border-radius: 0.7rem;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
gap: 0.1rem;
overflow: auto;
padding: 0.4rem;
position: relative;
button {
align-items: center;
background-color: transparent;
display: flex;
gap: 0.25rem;
text-align: left;
width: 100%;
&:hover,
&:hover.is-selected {
background-color: var(--gray-3);
}
&.is-selected {
background-color: var(--gray-2);
}
}
}

View File

@ -0,0 +1,40 @@
import './styles.scss'
import Document from '@tiptap/extension-document'
import Mention from '@tiptap/extension-mention'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import { EditorContent, useEditor } from '@tiptap/react'
import React from 'react'
import suggestions from './suggestions.js'
export default () => {
const editor = useEditor({
extensions: [
Document,
Paragraph,
Text,
Mention.configure({
HTMLAttributes: {
class: 'mention',
},
suggestions,
}),
],
content: `
<p>Hi everyone! Dont forget the daily stand up at 8 AM.</p>
<p>We will talk about the movies: <span data-type="mention" data-id="Dirty Dancing" data-mention-suggestion-char="#"></span>, <span data-type="mention" data-id="Pirates of the Caribbean" data-mention-suggestion-char="#"></span> and <span data-type="mention" data-id="The Matrix" data-mention-suggestion-char="#"></span>.</p>
<p><span data-type="mention" data-id="Jennifer Grey"></span> Would you mind to share what youve been working on lately? We fear not much happened since <span data-type="mention" data-id="Dirty Dancing" data-mention-suggestion-char="#"></span>.</p>
<p><span data-type="mention" data-id="Winona Ryder"></span> <span data-type="mention" data-id="Axl Rose"></span> Lets go through your most important points quickly.</p>
<p>I have a meeting with <span data-type="mention" data-id="Christina Applegate"></span> and dont want to come late.</p>
<p> Thanks, your big boss</p>
`,
})
if (!editor) {
return null
}
return <EditorContent editor={editor} />
}

View File

@ -0,0 +1,226 @@
context('/src/Examples/MultiMention/React/', () => {
beforeEach(() => {
cy.visit('/src/Examples/MultiMention/React/')
})
describe('Person mentions (@)', () => {
it('should insert a person mention', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.setContent('<p><span data-type="mention" data-id="Lea Thompson">@Lea Thompson</span></p>')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Lea Thompson" data-mention-suggestion-char="@" contenteditable="false">@Lea Thompson</span>',
)
})
})
it("should open a dropdown menu when I type '@'", () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
})
it('should display the correct person options in the dropdown menu', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button').should('have.length', 5)
cy.get('.dropdown-menu button:nth-child(1)')
.should('contain.text', 'Lea Thompson')
.and('have.class', 'is-selected')
cy.get('.dropdown-menu button:nth-child(2)').should('contain.text', 'Cyndi Lauper')
cy.get('.dropdown-menu button:nth-child(3)').should('contain.text', 'Tom Cruise')
cy.get('.dropdown-menu button:nth-child(4)').should('contain.text', 'Madonna')
cy.get('.dropdown-menu button:nth-child(5)').should('contain.text', 'Jerry Hall')
})
it('should insert Cyndi Lauper mention when clicking on her option', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button:nth-child(2)').contains('Cyndi Lauper').click()
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Cyndi Lauper" data-mention-suggestion-char="@" contenteditable="false">@Cyndi Lauper</span>',
)
})
it('should close the dropdown menu when I move the cursor outside the editor', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{moveToStart}')
cy.get('.dropdown-menu').should('not.exist')
})
it('should close the dropdown menu when I press the escape key', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{esc}')
cy.get('.dropdown-menu').should('not.exist')
})
it('should insert Tom Cruise when selecting his option with the arrow keys and pressing the enter key', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{downarrow}{downarrow}')
cy.get('.dropdown-menu button:nth-child(3)').should('have.class', 'is-selected')
cy.get('.tiptap').type('{enter}')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Tom Cruise" data-mention-suggestion-char="@" contenteditable="false">@Tom Cruise</span>',
)
})
it('should show a "No result" message when I search for a person that is not in the list', () => {
cy.get('.tiptap').type('{selectall}{backspace}@nonexistent')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu').should('contain.text', 'No result')
})
it('should only show the Madonna option in the dropdown when I type "@mado"', () => {
cy.get('.tiptap').type('{selectall}{backspace}@mado')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button').should('have.length', 1)
cy.get('.dropdown-menu button:nth-child(1)').should('contain.text', 'Madonna')
})
it('should insert Madonna when I type "@mado" and hit enter', () => {
cy.get('.tiptap').type('{selectall}{backspace}@mado{enter}')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Madonna" data-mention-suggestion-char="@" contenteditable="false">@Madonna</span>',
)
})
})
describe('Movie mentions (#)', () => {
it('should insert a movie mention', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.setContent(
'<p><span data-type="mention" data-id="The Matrix" data-mention-suggestion-char="#">#The Matrix</span></p>',
)
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="The Matrix" data-mention-suggestion-char="#" contenteditable="false">#The Matrix</span>',
)
})
})
it("should open a dropdown menu when I type '#'", () => {
cy.get('.tiptap').type('{selectall}{backspace}#')
cy.get('.dropdown-menu').should('exist')
})
it('should display the correct movie options in the dropdown menu', () => {
cy.get('.tiptap').type('{selectall}{backspace}#')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button').should('have.length', 3)
cy.get('.dropdown-menu button:nth-child(1)')
.should('contain.text', 'Dirty Dancing')
.and('have.class', 'is-selected')
cy.get('.dropdown-menu button:nth-child(2)').should('contain.text', 'Pirates of the Caribbean')
cy.get('.dropdown-menu button:nth-child(3)').should('contain.text', 'The Matrix')
})
it('should insert Pirates of the Caribbean mention when clicking on its option', () => {
cy.get('.tiptap').type('{selectall}{backspace}#')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button:nth-child(2)').contains('Pirates of the Caribbean').click()
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Pirates of the Caribbean" data-mention-suggestion-char="#" contenteditable="false">#Pirates of the Caribbean</span>',
)
})
it('should close the dropdown menu when I move the cursor outside the editor', () => {
cy.get('.tiptap').type('{selectall}{backspace}#')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{moveToStart}')
cy.get('.dropdown-menu').should('not.exist')
})
it('should close the dropdown menu when I press the escape key', () => {
cy.get('.tiptap').type('{selectall}{backspace}#')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{esc}')
cy.get('.dropdown-menu').should('not.exist')
})
it('should insert The Matrix when selecting its option with the arrow keys and pressing the enter key', () => {
cy.get('.tiptap').type('{selectall}{backspace}#')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{downarrow}{downarrow}')
cy.get('.dropdown-menu button:nth-child(3)').should('have.class', 'is-selected')
cy.get('.tiptap').type('{enter}')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="The Matrix" data-mention-suggestion-char="#" contenteditable="false">#The Matrix</span>',
)
})
it('should show a "No result" message when I search for a movie that is not in the list', () => {
cy.get('.tiptap').type('{selectall}{backspace}#nonexistent')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu').should('contain.text', 'No result')
})
it('should only show the Dirty Dancing option in the dropdown when I type "#dir"', () => {
cy.get('.tiptap').type('{selectall}{backspace}#dir')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button').should('have.length', 1)
cy.get('.dropdown-menu button:nth-child(1)').should('contain.text', 'Dirty Dancing')
})
it('should insert Dirty Dancing when I type "#dir" and hit enter', () => {
cy.get('.tiptap').type('{selectall}{backspace}#dir{enter}')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Dirty Dancing" data-mention-suggestion-char="#" contenteditable="false">#Dirty Dancing</span>',
)
})
})
describe('Interaction between mention types', () => {
it('should support both mention types in the same document', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.setContent(
'<p><span data-type="mention" data-id="Madonna">@Madonna</span> starred in <span data-type="mention" data-id="Dirty Dancing" data-mention-suggestion-char="#">#Dirty Dancing</span></p>',
)
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Madonna" data-mention-suggestion-char="@" contenteditable="false">@Madonna</span>',
)
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Dirty Dancing" data-mention-suggestion-char="#" contenteditable="false">#Dirty Dancing</span>',
)
})
})
it('should allow switching between mention types', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button:nth-child(1)').should('contain.text', 'Lea Thompson')
// Close the dropdown by moving cursor
cy.get('.tiptap').type('{moveToStart}')
cy.get('.dropdown-menu').should('not.exist')
// Open a new dropdown with #
cy.get('.tiptap').type('{selectall}{backspace}#')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button:nth-child(1)').should('contain.text', 'Dirty Dancing')
})
it('should insert both types of mentions in sequence', () => {
cy.get('.tiptap').type('{selectall}{backspace}@mado{enter} likes #the{enter}')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Madonna" data-mention-suggestion-char="@" contenteditable="false">@Madonna</span> likes <span class="mention" data-type="mention" data-id="The Matrix" data-mention-suggestion-char="#" contenteditable="false">#The Matrix</span>',
)
})
})
})

View File

@ -0,0 +1,17 @@
/* Basic editor styles */
.tiptap {
:first-child {
margin-top: 0;
}
.mention {
background-color: var(--purple-light);
border-radius: 0.4rem;
box-decoration-break: clone;
color: var(--purple);
padding: 0.1rem 0.3rem;
&::after {
content: '\200B';
}
}
}

View File

@ -0,0 +1,159 @@
import { computePosition, flip, shift } from '@floating-ui/dom'
import { posToDOMRect, ReactRenderer } from '@tiptap/react'
import MentionList from './MentionList.jsx'
const updatePosition = (editor, element) => {
const virtualElement = {
getBoundingClientRect: () => posToDOMRect(editor.view, editor.state.selection.from, editor.state.selection.to),
}
computePosition(virtualElement, element, {
placement: 'bottom-start',
strategy: 'absolute',
middleware: [shift(), flip()],
}).then(({ x, y, strategy }) => {
element.style.width = 'max-content'
element.style.position = strategy
element.style.left = `${x}px`
element.style.top = `${y}px`
})
}
export default [
{
items: ({ query }) => {
return [
'Lea Thompson',
'Cyndi Lauper',
'Tom Cruise',
'Madonna',
'Jerry Hall',
'Joan Collins',
'Winona Ryder',
'Christina Applegate',
'Alyssa Milano',
'Molly Ringwald',
'Ally Sheedy',
'Debbie Harry',
'Olivia Newton-John',
'Elton John',
'Michael J. Fox',
'Axl Rose',
'Emilio Estevez',
'Ralph Macchio',
'Rob Lowe',
'Jennifer Grey',
'Mickey Rourke',
'John Cusack',
'Matthew Broderick',
'Justine Bateman',
'Lisa Bonet',
]
.filter(item => item.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5)
},
render: () => {
let component
return {
onStart: props => {
component = new ReactRenderer(MentionList, {
props,
editor: props.editor,
})
if (!props.clientRect) {
return
}
component.element.style.position = 'absolute'
document.body.appendChild(component.element)
updatePosition(props.editor, component.element)
},
onUpdate(props) {
component.updateProps(props)
if (!props.clientRect) {
return
}
updatePosition(props.editor, component.element)
},
onKeyDown(props) {
if (props.event.key === 'Escape') {
component.destroy()
return true
}
return component.ref?.onKeyDown(props)
},
onExit() {
component.destroy()
},
}
},
},
{
char: '#',
items: ({ query }) => {
return ['Dirty Dancing', 'Pirates of the Caribbean', 'The Matrix']
.filter(item => item.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5)
},
render: () => {
let component
return {
onStart: props => {
component = new ReactRenderer(MentionList, {
props,
editor: props.editor,
})
if (!props.clientRect) {
return
}
component.element.style.position = 'absolute'
document.body.appendChild(component.element)
updatePosition(props.editor, component.element)
},
onUpdate(props) {
component.updateProps(props)
if (!props.clientRect) {
return
}
updatePosition(props.editor, component.element)
},
onKeyDown(props) {
if (props.event.key === 'Escape') {
component.destroy()
return true
}
return component.ref?.onKeyDown(props)
},
onExit() {
component.destroy()
},
}
},
},
]

View File

@ -0,0 +1,118 @@
<template>
<div class="dropdown-menu">
<template v-if="items.length">
<button
:class="{ 'is-selected': index === selectedIndex }"
v-for="(item, index) in items"
:key="index"
@click="selectItem(index)"
>
{{ item }}
</button>
</template>
<div class="item" v-else>No result</div>
</div>
</template>
<script>
export default {
props: {
items: {
type: Array,
required: true,
},
command: {
type: Function,
required: true,
},
},
data() {
return {
selectedIndex: 0,
}
},
watch: {
items() {
this.selectedIndex = 0
},
},
methods: {
onKeyDown({ event }) {
if (event.key === 'ArrowUp') {
this.upHandler()
return true
}
if (event.key === 'ArrowDown') {
this.downHandler()
return true
}
if (event.key === 'Enter') {
this.enterHandler()
return true
}
return false
},
upHandler() {
this.selectedIndex = (this.selectedIndex + this.items.length - 1) % this.items.length
},
downHandler() {
this.selectedIndex = (this.selectedIndex + 1) % this.items.length
},
enterHandler() {
this.selectItem(this.selectedIndex)
},
selectItem(index) {
const item = this.items[index]
if (item) {
this.command({ id: item })
}
},
},
}
</script>
<style lang="scss">
/* Dropdown menu */
.dropdown-menu {
background: var(--white);
border: 1px solid var(--gray-1);
border-radius: 0.7rem;
box-shadow: var(--shadow);
display: flex;
flex-direction: column;
gap: 0.1rem;
overflow: auto;
padding: 0.4rem;
position: relative;
button {
align-items: center;
background-color: transparent;
display: flex;
gap: 0.25rem;
text-align: left;
width: 100%;
&:hover,
&:hover.is-selected {
background-color: var(--gray-3);
}
&.is-selected {
background-color: var(--gray-2);
}
}
}
</style>

View File

@ -0,0 +1,7 @@
context('/src/Nodes/Mention/Vue/', () => {
beforeEach(() => {
cy.visit('/src/Nodes/Mention/Vue/')
})
// TODO: Write tests
})

View File

@ -0,0 +1,72 @@
<template>
<div v-if="editor">
<editor-content :editor="editor" />
</div>
</template>
<script>
import Document from '@tiptap/extension-document'
import Mention from '@tiptap/extension-mention'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import { Editor, EditorContent } from '@tiptap/vue-3'
import suggestions from './suggestions.js'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
extensions: [
Document,
Paragraph,
Text,
Mention.configure({
HTMLAttributes: {
class: 'mention',
},
suggestions,
}),
],
content: `
<p>Hi everyone! Dont forget the daily stand up at 8 AM.</p>
<p>We will talk about the movies: <span data-type="mention" data-id="Dirty Dancing" data-mention-suggestion-char="#"></span>, <span data-type="mention" data-id="Pirates of the Caribbean" data-mention-suggestion-char="#"></span> and <span data-type="mention" data-id="The Matrix" data-mention-suggestion-char="#"></span>.</p>
<p><span data-type="mention" data-id="Jennifer Grey"></span> Would you mind to share what youve been working on lately? We fear not much happened since <span data-type="mention" data-id="Dirty Dancing" data-mention-suggestion-char="#"></span>.</p>
<p><span data-type="mention" data-id="Winona Ryder"></span> <span data-type="mention" data-id="Axl Rose"></span> Lets go through your most important points quickly.</p>
<p>I have a meeting with <span data-type="mention" data-id="Christina Applegate"></span> and dont want to come late.</p>
<p> Thanks, your big boss</p>
`,
})
},
beforeUnmount() {
this.editor.destroy()
},
}
</script>
<style lang="scss">
/* Basic editor styles */
.tiptap {
:first-child {
margin-top: 0;
}
.mention {
background-color: var(--purple-light);
border-radius: 0.4rem;
box-decoration-break: clone;
color: var(--purple);
padding: 0.1rem 0.3rem;
}
}
</style>

View File

@ -0,0 +1,168 @@
import { computePosition, flip, shift } from '@floating-ui/dom'
import { posToDOMRect, VueRenderer } from '@tiptap/vue-3'
import MentionList from './MentionList.vue'
const updatePosition = (editor, element) => {
const virtualElement = {
getBoundingClientRect: () => posToDOMRect(editor.view, editor.state.selection.from, editor.state.selection.to),
}
computePosition(virtualElement, element, {
placement: 'bottom-start',
strategy: 'absolute',
middleware: [shift(), flip()],
}).then(({ x, y, strategy }) => {
element.style.width = 'max-content'
element.style.position = strategy
element.style.left = `${x}px`
element.style.top = `${y}px`
})
}
export default [
{
char: '@',
items: ({ query }) => {
return [
'Lea Thompson',
'Cyndi Lauper',
'Tom Cruise',
'Madonna',
'Jerry Hall',
'Joan Collins',
'Winona Ryder',
'Christina Applegate',
'Alyssa Milano',
'Molly Ringwald',
'Ally Sheedy',
'Debbie Harry',
'Olivia Newton-John',
'Elton John',
'Michael J. Fox',
'Axl Rose',
'Emilio Estevez',
'Ralph Macchio',
'Rob Lowe',
'Jennifer Grey',
'Mickey Rourke',
'John Cusack',
'Matthew Broderick',
'Justine Bateman',
'Lisa Bonet',
]
.filter(item => item.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5)
},
render: () => {
let component
return {
onStart: props => {
component = new VueRenderer(MentionList, {
// using vue 2:
// parent: this,
// propsData: props,
// using vue 3:
props,
editor: props.editor,
})
if (!props.clientRect) {
return
}
component.element.style.position = 'absolute'
document.body.appendChild(component.element)
updatePosition(props.editor, component.element)
},
onUpdate(props) {
component.updateProps(props)
if (!props.clientRect) {
return
}
updatePosition(props.editor, component.element)
},
onKeyDown(props) {
if (props.event.key === 'Escape') {
component.destroy()
return true
}
return component.ref?.onKeyDown(props)
},
onExit() {
component.destroy()
},
}
},
},
{
char: '#',
items: ({ query }) => {
return ['Dirty Dancing', 'Pirates of the Caribbean', 'The Matrix']
.filter(item => item.toLowerCase().startsWith(query.toLowerCase()))
.slice(0, 5)
},
render: () => {
let component
return {
onStart: props => {
component = new VueRenderer(MentionList, {
// using vue 2:
// parent: this,
// propsData: props,
// using vue 3:
props,
editor: props.editor,
})
if (!props.clientRect) {
return
}
component.element.style.position = 'absolute'
document.body.appendChild(component.element)
updatePosition(props.editor, component.element)
},
onUpdate(props) {
component.updateProps(props)
if (!props.clientRect) {
return
}
updatePosition(props.editor, component.element)
},
onKeyDown(props) {
if (props.event.key === 'Escape') {
component.destroy()
return true
}
return component.ref?.onKeyDown(props)
},
onExit() {
component.destroy()
},
}
},
},
]

View File

@ -1,6 +1,5 @@
import { Extension } from '@tiptap/core'
import { NodeSelection, Plugin } from '@tiptap/pm/state'
import { EditorView } from '@tiptap/pm/view'
function removeNode(node) {
node.parentNode.removeChild(node)
@ -63,7 +62,7 @@ export default Extension.create({
// from: view.nodeDOM(view.state.selection.from),
// to: view.nodeDOM(view.state.selection.to),
// })
const { dom, text } = EditorView.serializeForClipboard(view, slice)
const { dom, text } = view.serializeForClipboard(slice)
e.dataTransfer.clearData()
e.dataTransfer.setData('text/html', dom.innerHTML)

View File

@ -59,6 +59,12 @@ export default () => {
Justify
</button>
<button onClick={() => editor.chain().focus().unsetTextAlign().run()}>Unset text align</button>
<button
onClick={() => editor.chain().focus().toggleTextAlign('right').run()}
className={editor.isActive({ textAlign: 'right' }) ? 'is-active' : ''}
>
Toggle Right
</button>
<button
onClick={() => editor.chain().focus().toggleHeading({ level: 1 }).run()}
className={editor.isActive({ level: 1 }) ? 'is-active' : ''}

View File

@ -89,6 +89,14 @@ context('/src/Extensions/TextAlign/React/', () => {
cy.get('.tiptap').find('p').should('not.have.css', 'text-align', 'left')
})
it('toggle the text to right on the 6rd button', () => {
cy.get('button:nth-child(6)').click()
cy.get('.tiptap').find('p').should('not.have.css', 'text-align', 'right')
cy.get('button:nth-child(6)').click()
cy.get('.tiptap').find('p').should('not.have.css', 'text-align', 'left')
})
it('aligns the text left when pressing the keyboard shortcut', () => {
cy.get('.tiptap')
.trigger('keydown', { modKey: true, shiftKey: true, key: 'l' })

View File

@ -89,6 +89,16 @@ context('/src/Extensions/TextAlign/Vue/', () => {
cy.get('.tiptap').find('p').should('not.have.css', 'text-align', 'left')
})
it('toggle the text to right on the 6rd button', () => {
cy.get('button:nth-child(6)').click()
cy.get('.tiptap').find('p').should('have.css', 'text-align', 'right')
cy.get('button:nth-child(6)').click()
cy.get('.tiptap').find('p').should('have.css', 'text-align', 'left')
})
it('aligns the text left when pressing the keyboard shortcut', () => {
cy.get('.tiptap')
.trigger('keydown', { modKey: true, shiftKey: true, key: 'l' })

View File

@ -27,6 +27,12 @@
Justify
</button>
<button @click="editor.chain().focus().unsetTextAlign().run()">Unset text align</button>
<button
@click="editor.chain().focus().toggleTextAlign('right').run()"
:class="{ 'is-active': editor.isActive({ textAlign: 'right' }) }"
>
Toggle Right
</button>
</div>
</div>
<editor-content :editor="editor" />

View File

@ -3,5 +3,110 @@ context('/src/Nodes/Mention/React/', () => {
cy.visit('/src/Nodes/Mention/React/')
})
// TODO: Write tests
it('should insert a mention', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.setContent('<p><span data-type="mention" data-id="1" data-label="John Doe">@John Doe</span></p>')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="1" data-label="John Doe" data-mention-suggestion-char="@" contenteditable="false">@John Doe</span>',
)
})
})
it('should insert multiple mentions', () => {
cy.get('.tiptap').then(([{ editor }]) => {
editor.commands.setContent(
'<p><span data-type="mention" data-id="1" data-label="John Doe">@John Doe</span> and <span data-type="mention" data-id="2" data-label="Jane Smith">@Jane Smith</span></p>',
)
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="1" data-label="John Doe" data-mention-suggestion-char="@" contenteditable="false">@John Doe</span> and <span class="mention" data-type="mention" data-id="2" data-label="Jane Smith" data-mention-suggestion-char="@" contenteditable="false">@Jane Smith</span>',
)
})
})
it("should open a dropdown menu when I type '@'", () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
})
it('should display the correct options in the dropdown menu', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button').should('have.length', 5)
cy.get('.dropdown-menu button:nth-child(1)').should('contain.text', 'Lea Thompson').and('have.class', 'is-selected')
cy.get('.dropdown-menu button:nth-child(2)').should('contain.text', 'Cyndi Lauper')
cy.get('.dropdown-menu button:nth-child(3)').should('contain.text', 'Tom Cruise')
cy.get('.dropdown-menu button:nth-child(4)').should('contain.text', 'Madonna')
cy.get('.dropdown-menu button:nth-child(5)').should('contain.text', 'Jerry Hall')
})
it('should insert Cyndi Lauper mention when clicking on her option', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button:nth-child(2)').contains('Cyndi Lauper').click()
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Cyndi Lauper" data-mention-suggestion-char="@" contenteditable="false">@Cyndi Lauper</span>',
)
})
it('should close the dropdown menu when I move the cursor outside the editor', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{moveToStart}')
cy.get('.dropdown-menu').should('not.exist')
})
it('should close the dropdown menu when I press the exit key', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{esc}')
cy.get('.dropdown-menu').should('not.exist')
})
it('should insert Tom Cruise when selecting his option with the arrow keys and pressing the enter key', () => {
cy.get('.tiptap').type('{selectall}{backspace}@')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').type('{downarrow}{downarrow}')
cy.get('.dropdown-menu button:nth-child(3)').should('have.class', 'is-selected')
cy.get('.tiptap').type('{enter}')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Tom Cruise" data-mention-suggestion-char="@" contenteditable="false">@Tom Cruise</span>',
)
})
it('should show a "No result" message when I search for an option that is not in the list', () => {
cy.get('.tiptap').type('{selectall}{backspace}@nonexistent')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu').should('contain.text', 'No result')
})
it('should not hide the dropdown or insert any mention if I search for an option that is not in the list and hit enter', () => {
cy.get('.tiptap').type('{selectall}{backspace}@nonexistent')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu').should('contain.text', 'No result')
cy.get('.tiptap').type('{enter}')
cy.get('.dropdown-menu').should('exist')
cy.get('.tiptap').should('have.text', '@nonexistent')
cy.get('.tiptap span.mention').should('not.exist')
})
it('should only show the Madonna option in the dropdown when I type "@mado"', () => {
cy.get('.tiptap').type('{selectall}{backspace}@mado')
cy.get('.dropdown-menu').should('exist')
cy.get('.dropdown-menu button').should('have.length', 1)
cy.get('.dropdown-menu button:nth-child(1)').should('contain.text', 'Madonna')
})
it('should insert Madonna when I type "@mado" and hit enter', () => {
cy.get('.tiptap').type('{selectall}{backspace}@mado{enter}')
cy.get('.tiptap').should(
'contain.html',
'<span class="mention" data-type="mention" data-id="Madonna" data-mention-suggestion-char="@" contenteditable="false">@Madonna</span>',
)
})
})

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extensions@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-character-count",
"description": "font family extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extensions@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extensions@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-focus",
"description": "focus extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",
@ -31,10 +31,10 @@
"dist"
],
"devDependencies": {
"@tiptap/extensions": "3.0.0-beta.3"
"@tiptap/extensions": "3.0.0-beta.4"
},
"peerDependencies": {
"@tiptap/extensions": "3.0.0-beta.3"
"@tiptap/extensions": "3.0.0-beta.4"
},
"repository": {
"type": "git",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extensions@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extensions@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-list@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-list-item",
"description": "list item extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-list@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-list-keymap",
"description": "list keymap extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extensions@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-table@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-table-cell",
"description": "table cell extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-table@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-table-header",
"description": "table cell extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-table@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-table-row",
"description": "table row extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-list@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-list@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-task-list",
"description": "task list extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,16 @@
# Change Log
## 3.0.0-beta.4
### Major Changes
- 5e957e5: This resolves in issue with SSR where the isDestroyed property could not be read while in SSR
### Patch Changes
- 9f207a6: Fixes a bug where you could not unregister multiple plugins.
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/core",
"description": "headless rich text editor",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -287,6 +287,7 @@ export class Editor extends EventEmitter<EditorEvents> {
composing: false,
dragging: null,
editable: true,
isDestroyed: false,
} as EditorView,
{
get: (obj, key) => {
@ -361,7 +362,7 @@ export class Editor extends EventEmitter<EditorEvents> {
const name = typeof nameOrPluginKey === 'string' ? `${nameOrPluginKey}$` : nameOrPluginKey.key
// @ts-ignore
plugins = prevPlugins.filter(plugin => !plugin.key.startsWith(name))
plugins = plugins.filter(plugin => !plugin.key.startsWith(name))
})
if (prevPlugins.length === plugins.length) {
@ -717,8 +718,7 @@ export class Editor extends EventEmitter<EditorEvents> {
* Check if the editor is already destroyed.
*/
public get isDestroyed(): boolean {
// @ts-ignore
return !this.view?.docView
return this.editorView?.isDestroyed ?? true
}
public $node(selector: string, attributes?: { [key: string]: any }): NodePos | null {

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,14 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-bubble-menu",
"description": "bubble-menu extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-list@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-bullet-list",
"description": "bullet list extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,15 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/extension-code-block@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-code-block-lowlight",
"description": "code block extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,14 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-code-block",
"description": "code block extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,15 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- f43b2e5: Use newer y-prosemirror version to resolve dependency chaos
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-collaboration-caret",
"description": "collaboration caret extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",
@ -33,12 +33,12 @@
"devDependencies": {
"@tiptap/core": "workspace:*",
"@tiptap/pm": "workspace:*",
"@tiptap/y-tiptap": "^2.0.0"
"@tiptap/y-tiptap": "^3.0.0-beta.3"
},
"peerDependencies": {
"@tiptap/core": "workspace:*",
"@tiptap/pm": "workspace:*",
"@tiptap/y-tiptap": "^2.0.0"
"@tiptap/y-tiptap": "^3.0.0-beta.3"
},
"repository": {
"type": "git",

View File

@ -1,5 +1,15 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- f43b2e5: Use newer y-prosemirror version to resolve dependency chaos
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-collaboration",
"description": "collaboration extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",
@ -33,12 +33,12 @@
"devDependencies": {
"@tiptap/core": "workspace:*",
"@tiptap/pm": "workspace:*",
"@tiptap/y-tiptap": "^2.0.0"
"@tiptap/y-tiptap": "^3.0.0-beta.3"
},
"peerDependencies": {
"@tiptap/core": "workspace:*",
"@tiptap/pm": "workspace:*",
"@tiptap/y-tiptap": "^2.0.0",
"@tiptap/y-tiptap": "^3.0.0-beta.3",
"yjs": "^13"
},
"repository": {

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-text-style@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,14 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-floating-menu",
"description": "floating-menu extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,11 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- @tiptap/extension-text-style@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-font-family",
"description": "font family extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-hard-break",
"description": "hard break extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,14 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-horizontal-rule",
"description": "horizontal rule extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,13 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,14 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

View File

@ -1,5 +1,14 @@
# Change Log
## 3.0.0-beta.4
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

@ -1,7 +1,7 @@
{
"name": "@tiptap/extension-list",
"description": "List extension for tiptap",
"version": "3.0.0-beta.3",
"version": "3.0.0-beta.4",
"homepage": "https://tiptap.dev",
"keywords": [
"tiptap",

View File

@ -1,5 +1,19 @@
# Change Log
## 3.0.0-beta.4
### Minor Changes
- 68034ab: Support multiple triggers in Mention extension
### Patch Changes
- Updated dependencies [5e957e5]
- Updated dependencies [9f207a6]
- @tiptap/core@3.0.0-beta.4
- @tiptap/suggestion@3.0.0-beta.4
- @tiptap/pm@3.0.0-beta.4
## 3.0.0-beta.3
### Patch Changes

View File

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

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