Merge branch 'feature/text-style-mark' of https://github.com/ueberdosis/tiptap-next into feature/text-style-mark

# Conflicts:
#	docs/src/demos/Marks/TextStyle/index.vue
This commit is contained in:
Philipp Kühn
2020-11-06 16:24:20 +01:00
41 changed files with 448 additions and 355 deletions

View File

@@ -1,14 +1,83 @@
<template>
<div>
<button @click="setName">
Set Name
</button>
<button @click="changeName">
Random Name
</button>
<button @click="changeColor">
Random Color
</button>
<div v-if="editor">
<button @click="editor.chain().focus().bold().run()" :class="{ 'is-active': editor.isActive('bold') }">
bold
</button>
<button @click="editor.chain().focus().italic().run()" :class="{ 'is-active': editor.isActive('italic') }">
italic
</button>
<button @click="editor.chain().focus().strike().run()" :class="{ 'is-active': editor.isActive('strike') }">
strike
</button>
<button @click="editor.chain().focus().code().run()" :class="{ 'is-active': editor.isActive('code') }">
code
</button>
<button @click="editor.chain().focus().removeMarks().run()">
clear marks
</button>
<button @click="editor.chain().focus().clearNodes().run()">
clear nodes
</button>
<button @click="editor.chain().focus().paragraph().run()" :class="{ 'is-active': editor.isActive('paragraph') }">
paragraph
</button>
<button @click="editor.chain().focus().heading({ level: 1 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 1 }) }">
h1
</button>
<button @click="editor.chain().focus().heading({ level: 2 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 2 }) }">
h2
</button>
<button @click="editor.chain().focus().heading({ level: 3 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 3 }) }">
h3
</button>
<button @click="editor.chain().focus().heading({ level: 4 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 4 }) }">
h4
</button>
<button @click="editor.chain().focus().heading({ level: 5 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 5 }) }">
h5
</button>
<button @click="editor.chain().focus().heading({ level: 6 }).run()" :class="{ 'is-active': editor.isActive('heading', { level: 6 }) }">
h6
</button>
<button @click="editor.chain().focus().bulletList().run()" :class="{ 'is-active': editor.isActive('bulletList') }">
bullet list
</button>
<button @click="editor.chain().focus().orderedList().run()" :class="{ 'is-active': editor.isActive('orderedList') }">
ordered list
</button>
<button @click="editor.chain().focus().codeBlock().run()" :class="{ 'is-active': editor.isActive('codeBlock') }">
code block
</button>
<button @click="editor.chain().focus().blockquote().run()" :class="{ 'is-active': editor.isActive('blockquote') }">
blockquote
</button>
<button @click="editor.chain().focus().horizontalRule().run()">
horizontal rule
</button>
<button @click="editor.chain().focus().hardBreak().run()">
hard break
</button>
<button @click="editor.chain().focus().undo().run()">
undo
</button>
<button @click="editor.chain().focus().redo().run()">
redo
</button>
<br>
<br>
<button @click="setName">
Set Name
</button>
<button @click="changeName">
Random Name
</button>
<button @click="changeColor">
Random Color
</button>
</div>
<div class="collaboration-status">
{{ users.length }} user{{ users.length === 1 ? '' : 's' }}
@@ -29,7 +98,7 @@
</template>
<script>
import { Editor, EditorContent } from '@tiptap/vue-starter-kit'
import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
@@ -60,21 +129,15 @@ export default {
mounted() {
this.ydoc = new Y.Doc()
this.provider = new WebrtcProvider(this.documentName, this.ydoc)
this.type = this.ydoc.getXmlFragment('prosemirror')
this.indexdb = new IndexeddbPersistence(this.documentName, this.ydoc)
this.provider = new WebrtcProvider(this.documentName, this.ydoc)
this.provider.awareness.on('change', this.updateState)
this.editor = new Editor({
// TODO: This is added by every new user.
// content: `
// <p>Example Text</p>
// `,
extensions: [
Document(),
Paragraph(),
Text(),
...defaultExtensions(),
Collaboration({
provider: this.provider,
type: this.type,

View File

@@ -1,9 +0,0 @@
context('/examples/focus', () => {
before(() => {
cy.visit('/examples/focus')
})
it('should have class', () => {
cy.get('.ProseMirror p:first').should('have.class', 'has-focus')
})
})

View File

@@ -1,66 +0,0 @@
<template>
<div>
<editor-content :editor="editor" />
</div>
</template>
<script>
import { Editor, EditorContent } from '@tiptap/vue-starter-kit'
import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import Code from '@tiptap/extension-code'
import BulletList from '@tiptap/extension-bullet-list'
import ListItem from '@tiptap/extension-list-item'
import Focus from '@tiptap/extension-focus'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
extensions: [
Document(),
Paragraph(),
Text(),
Code(),
BulletList(),
ListItem(),
Focus({
className: 'has-focus',
nested: true,
}),
],
autoFocus: true,
content: `
<p>
The focus extension adds a class to the focused node only. That enables you to add a custom styling to just that node. By default, itll add <code>.has-focus</code>, even to nested nodes.
</p>
<ul>
<li>Nested elements (like this list item) will be focused with the default setting of <code>nested: true</code>.</li>
<li>Otherwise the whole list will get the focus class, even when just a single list item is selected.</li>
</ul>
`,
})
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>
<style lang="scss">
.has-focus {
border-radius: 3px;
box-shadow: 0 0 0 3px #3ea4ffe6;
}
</style>

View File

@@ -1,31 +0,0 @@
context('/examples/history', () => {
before(() => {
cy.visit('/examples/history')
})
beforeEach(() => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.clearContent()
})
})
it('should not have a mistake', () => {
cy.get('.ProseMirror').then(() => {
cy.get('.ProseMirror').should('not.contain', 'Mistake')
})
})
it('should have a mistake', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.insertText('Mistake')
cy.get('.ProseMirror').should('contain', 'Mistake')
})
})
it('the mistake should be removed again', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.undo()
cy.get('.ProseMirror').should('not.contain', 'Mistake')
})
})
})

View File

@@ -1,47 +0,0 @@
<template>
<div>
<div v-if="editor">
<button @click="editor.chain().focus().undo().run()">
undo
</button>
<button @click="editor.chain().focus().redo().run()">
redo
</button>
</div>
<editor-content :editor="editor" />
</div>
</template>
<script>
import { Editor, EditorContent, defaultExtensions } from '@tiptap/vue-starter-kit'
export default {
components: {
EditorContent,
},
data() {
return {
editor: null,
}
},
mounted() {
this.editor = new Editor({
content: `
<p>
With the <code>History</code> extension the Editor will keep track of your changes. And if you think you made a mistake, you can redo your changes. Try it out, change the content and hit the undo button!
</p>
<p>
And yes, you can also use a keyboard shortcut to undo changes (<code>Control/Cmd</code> <code>Z</code>) or redo changes (<code>Control/Cmd</code> <code>Shift</code> <code>Z</code>).
</p>
`,
extensions: defaultExtensions(),
})
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>

View File

@@ -17,6 +17,10 @@ const CustomDocument = Document.extend({
content: 'taskList',
})
const CustomTaskItem = TaskItem.extend({
content: 'paragraph',
})
export default {
components: {
EditorContent,
@@ -35,10 +39,10 @@ export default {
Paragraph(),
Text(),
TaskList(),
TaskItem(),
CustomTaskItem(),
],
content: `
<ul data-type="task_list">
<ul data-type="taskList">
<li data-type="taskItem" data-checked="true">A list item</li>
<li data-type="taskItem" data-checked="false">And another one</li>
</ul>

View File

@@ -10,6 +10,9 @@ import Document from '@tiptap/extension-document'
import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text'
import Focus from '@tiptap/extension-focus'
import Code from '@tiptap/extension-code'
import BulletList from '@tiptap/extension-bullet-list'
import ListItem from '@tiptap/extension-list-item'
export default {
components: {
@@ -32,15 +35,19 @@ export default {
className: 'has-focus',
nested: true,
}),
Code(),
BulletList(),
ListItem(),
],
autoFocus: true,
content: `
<p>
The focus extension adds a class to the focused node only. That enables you to add a custom styling to just that node. By default, itll add <code>.has-focus</code>, even to nested nodes.
</p>
<p>
Nested elements will be focused with the default setting nested: true. Otherwise the whole item will get the focus class, even when just a single nested item is selected.
</p>
<ul>
<li>Nested elements (like this list item) will be focused with the default setting of <code>nested: true</code>.</li>
<li>Otherwise the whole list will get the focus class, even when just a single list item is selected.</li>
</ul>
`,
})
},

View File

@@ -39,7 +39,12 @@ export default {
History(),
],
content: `
<p>Edit this text and press undo to test this extension.</p>
<p>
With the History extension the Editor will keep track of your changes. And if you think you made a mistake, you can redo your changes. Try it out, change the content and hit the undo button!
</p>
<p>
And yes, you can also use a keyboard shortcut to undo changes (Control/Cmd Z) or redo changes (Control/Cmd Shift Z).
</p>
`,
})
},

View File

@@ -1,18 +1,84 @@
context('/api/nodes/text', () => {
context('/api/extensions/text-align', () => {
before(() => {
cy.visit('/api/nodes/text')
cy.visit('/api/extensions/text-align')
})
beforeEach(() => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.clearContent()
editor.setContent('<p>Example Text</p>')
})
})
it('text should be wrapped in a paragraph by default', () => {
it('should parse left align text correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p style="text-align: left">Example Text</p>')
expect(editor.getHTML()).to.eq('<p style="text-align: left">Example Text</p>')
})
})
it('should parse center align text correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p style="text-align: center">Example Text</p>')
expect(editor.getHTML()).to.eq('<p style="text-align: center">Example Text</p>')
})
})
it('should parse right align text correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p style="text-align: right">Example Text</p>')
expect(editor.getHTML()).to.eq('<p style="text-align: right">Example Text</p>')
})
})
it('should parse left justify text correctly', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.setContent('<p style="text-align: justify">Example Text</p>')
expect(editor.getHTML()).to.eq('<p style="text-align: justify">Example Text</p>')
})
})
it('aligns the text left on the 1st button', () => {
cy.get('.demo__preview button:nth-child(1)')
.click()
cy.get('.ProseMirror')
.type('Example Text')
.find('p')
.should('contain', 'Example Text')
.should('have.css', 'text-align', 'left')
})
it('aligns the text center on the 2nd button', () => {
cy.get('.demo__preview button:nth-child(2)')
.click()
cy.get('.ProseMirror')
.find('p')
.should('have.css', 'text-align', 'center')
})
it('aligns the text right on the 3rd button', () => {
cy.get('.demo__preview button:nth-child(3)')
.click()
cy.get('.ProseMirror')
.find('p')
.should('have.css', 'text-align', 'right')
})
it('aligns the text justified on the 4th button', () => {
cy.get('.demo__preview button:nth-child(4)')
.click()
cy.get('.ProseMirror')
.find('p')
.should('have.css', 'text-align', 'justify')
})
it('aligns the text default on the 5th button', () => {
cy.get('.demo__preview button:nth-child(5)')
.click()
cy.get('.ProseMirror')
.find('p')
.should('have.css', 'text-align', 'left')
})
})

View File

@@ -9,6 +9,9 @@
<button @click="editor.chain().focus().textAlign('right').run()">
right
</button>
<button @click="editor.chain().focus().textAlign('justify').run()">
justify
</button>
<button @click="editor.chain().focus().resetNodeAttributes(['textAlign']).run()">
set default
</button>

View File

@@ -98,4 +98,28 @@ context('/api/extensions/typography', () => {
.type('>> raquorow')
.should('contain', '» raquo')
})
it('should make a multiplication sign from an asterisk', () => {
cy.get('.ProseMirror')
.type('1*1 multiplication')
.should('contain', '1×1 multiplication')
})
it('should make a multiplication sign from an x', () => {
cy.get('.ProseMirror')
.type('1x1 multiplication')
.should('contain', '1×1 multiplication')
})
it('should make a multiplication sign from an asterisk with spaces', () => {
cy.get('.ProseMirror')
.type('1 * 1 multiplication')
.should('contain', '1 × 1 multiplication')
})
it('should make a multiplication sign from an x with spaces', () => {
cy.get('.ProseMirror')
.type('1 x 1 multiplication')
.should('contain', '1 × 1 multiplication')
})
})

View File

@@ -0,0 +1,5 @@
context('/api/marks/text-style', () => {
before(() => {
cy.visit('/api/marks/text-style')
})
})

View File

@@ -1,13 +1,34 @@
<template>
<div v-if="editor">
<button
@click="editor.chain().focus().fontFamily('Comic Sans MS').run()"
:class="{ 'is-active': editor.isActive('textStyle', { fontFamily: 'Comic Sans MS' }) }"
@click="editor.chain().focus().fontFamily('Inter').run()"
:class="{ 'is-active': editor.isActive('textStyle', { fontFamily: 'Inter' }) }"
>
Inter
</button>
<button
@click="editor.chain().focus().fontFamily('Comic Sans MS, Comic Sans').run()"
:class="{ 'is-active': editor.isActive('textStyle', { fontFamily: 'Comic Sans MS, Comic Sans' }) }"
>
Comic Sans
</button>
<button @click="editor.chain().focus().fontFamily().run()">
Remove font-family
<button
@click="editor.chain().focus().fontFamily('serif').run()"
:class="{ 'is-active': editor.isActive('textStyle', { fontFamily: 'serif' }) }"
>
serif
</button>
<button
@click="editor.chain().focus().fontFamily('monospace').run()"
:class="{ 'is-active': editor.isActive('textStyle', { fontFamily: 'monospace' }) }"
>
monospace
</button>
<button
@click="editor.chain().focus().fontFamily('cursive').run()"
:class="{ 'is-active': editor.isActive('textStyle', { fontFamily: 'cursive' }) }"
>
cursive
</button>
<editor-content :editor="editor" />
@@ -44,7 +65,11 @@ export default {
FontFamily(),
],
content: `
<p><span style="font-family: Comic Sans MS">Welcome to the internet.</span></p>
<p><span style="font-family: Inter">Inter</span></p>
<p><span style="font-family: Comic Sans MS, Comic Sans">Comic Sans</span></p>
<p><span style="font-family: serif">serif</span></p>
<p><span style="font-family: monospace">monospace</span></p>
<p><span style="font-family: cursive">cursive</span></p>
`,
})
},