Merge branch 'main' into feature/vue-node-views

This commit is contained in:
Philipp Kühn
2020-11-23 17:30:45 +01:00
46 changed files with 530 additions and 491 deletions

View File

@@ -1,4 +1,5 @@
const path = require('path')
const visit = require('unist-util-visit')
function addStyleResource(rule) {
rule.use('style-resource')
@@ -10,6 +11,28 @@ function addStyleResource(rule) {
})
}
function tableWrapper() {
return async tree => {
visit(
tree,
'table',
(node, index, parent) => {
if (node.type === 'table' && parent.type === 'root') {
const original = { ...node }
node.type = 'div'
node.children = [original]
node.data = {
hProperties: {
class: 'table-wrapper',
},
}
}
},
)
}
}
module.exports = {
siteName: 'tiptap',
titleTemplate: '%s | tiptap',
@@ -26,6 +49,7 @@ module.exports = {
'@gridsome/remark-prismjs',
'remark-container',
'remark-toc',
tableWrapper,
],
remark: {
autolinkHeadings: {

View File

@@ -10,11 +10,11 @@
"@gridsome/remark-prismjs": "^0.5.0",
"@gridsome/source-filesystem": "^0.6.2",
"@gridsome/transformer-json": "^0.2.1",
"@gridsome/vue-remark": "^0.2.5",
"@gridsome/vue-remark": "^0.2.6",
"@mvasilkov/outdent": "^1.0.4",
"collect.js": "^4.28.5",
"collect.js": "^4.28.6",
"globby": "^11.0.0",
"gridsome": "0.7.22",
"gridsome": "0.7.23",
"gridsome-plugin-simple-analytics": "^1.1.0",
"portal-vue": "^2.1.7",
"raw-loader": "^4.0.2",
@@ -22,18 +22,17 @@
"react-dom": "^17.0.1",
"remark-container": "^0.1.2",
"remark-toc": "^7.0.0",
"typescript": "^4.0.5",
"vue-github-button": "^1.1.2",
"vue-live": "^1.15.1",
"vue-live": "^1.16.0",
"y-indexeddb": "^9.0.5",
"y-webrtc": "^10.1.6",
"y-websocket": "^1.3.6",
"yjs": "^13.4.4"
"y-websocket": "^1.3.7",
"yjs": "^13.4.5"
},
"devDependencies": {
"@babel/plugin-proposal-optional-chaining": "^7.11.0",
"@babel/preset-env": "^7.11.5",
"@babel/preset-react": "^7.10.4",
"@babel/plugin-proposal-optional-chaining": "^7.12.7",
"@babel/preset-env": "^7.12.7",
"@babel/preset-react": "^7.12.7",
"html-loader": "^1.3.2",
"node-sass": "^5.0.0",
"sass-loader": "^10.0.3",

View File

@@ -100,6 +100,10 @@ export default {
},
githubUrl() {
if (process.env.NODE_ENV === 'development') {
return `vscode://file${this.cwd}/src/demos/${this.name}/${this.files[0].name}`
}
return `https://github.com/ueberdosis/tiptap-next/tree/main/docs/src/demos/${this.name}`
},
},

View File

@@ -13,7 +13,7 @@
<button @click="editor.chain().focus().toggleCode().run()" :class="{ 'is-active': editor.isActive('code') }">
code
</button>
<button @click="editor.chain().focus().unsetMarks().run()">
<button @click="editor.chain().focus().unsetAllMarks().run()">
clear marks
</button>
<button @click="editor.chain().focus().clearNodes().run()">

View File

@@ -0,0 +1,25 @@
context('clearContent', () => {
before(() => {
cy.visit('/examples/basic')
})
it('returns true for the clearContent command', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.commands.setContent('<p>Example Text</p>')
const command = editor.commands.clearContent()
expect(command).to.be.eq(true)
})
})
it('clears the content when using the clearContent command', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.commands.setContent('<p>Example Text</p>')
editor.commands.clearContent()
expect(editor.getHTML()).to.be.eq('<p></p>')
})
})
})

View File

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

View File

@@ -0,0 +1,21 @@
context('setContent', () => {
before(() => {
cy.visit('/examples/basic')
})
it('returns true for the setContent command', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
const command = editor.commands.setContent('<p>Example Text</p>')
expect(command).to.be.eq(true)
})
})
it('clears the content when using the setContent command', () => {
cy.get('.ProseMirror').then(([{ editor }]) => {
editor.commands.setContent('<p>Cindy Lauper</p>')
expect(editor.getHTML()).to.be.eq('<p>Cindy Lauper</p>')
})
})
})

View File

@@ -13,7 +13,7 @@
<button @click="editor.chain().focus().toggleCode().run()" :class="{ 'is-active': editor.isActive('code') }">
code
</button>
<button @click="editor.chain().focus().unsetMarks().run()">
<button @click="editor.chain().focus().unsetAllMarks().run()">
clear marks
</button>
<button @click="editor.chain().focus().clearNodes().run()">

View File

@@ -13,7 +13,7 @@
<button @click="editor.chain().focus().toggleCode().run()" :class="{ 'is-active': editor.isActive('code') }">
code
</button>
<button @click="editor.chain().focus().unsetMarks().run()">
<button @click="editor.chain().focus().unsetAllMarks().run()">
clear marks
</button>
<button @click="editor.chain().focus().clearNodes().run()">

View File

@@ -1,7 +1,7 @@
<template>
<div>
<div v-if="editor">
<button @click="editor.chain().focus().unsetMarks().run()">
<button @click="editor.chain().focus().unsetAllMarks().run()">
clear formatting
</button>
<button @click="editor.chain().focus().undo().run()">

View File

@@ -56,14 +56,14 @@ context('/api/marks/bold', () => {
cy.get('.ProseMirror strong').should('not.exist')
})
it('the keyboard shortcut should make the selected text bold', () => {
it('should make the selected text bold when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, key: 'b' })
.find('strong')
.should('contain', 'Example Text')
})
it('the keyboard shortcut should toggle the selected text bold', () => {
it('should toggle the selected text bold when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, key: 'b' })
.find('strong')

View File

@@ -43,6 +43,25 @@ context('/api/marks/code', () => {
.should('not.exist')
})
it('should make the selected text bold when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, key: 'e' })
.find('code')
.should('contain', 'Example Text')
})
it('should toggle the selected text bold when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, key: 'e' })
.find('code')
.should('contain', 'Example Text')
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, key: 'e' })
cy.get('.ProseMirror code').should('not.exist')
})
it('should make inline code from the markdown shortcut', () => {
cy.get('.ProseMirror')
.type('`Example`')

View File

@@ -122,14 +122,14 @@ context('/api/marks/highlight', () => {
.should('not.exist')
})
it('the keyboard shortcut should highlight the selected text', () => {
it('should highlight the selected text when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, shiftKey: true, key: 'h' })
.find('mark')
.should('contain', 'Example Text')
})
it('the keyboard shortcut should toggle the selected text highlighted', () => {
it('should toggle the selected text highlighted when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, shiftKey: true, key: 'h' })
.trigger('keydown', { modKey: true, shiftKey: true, key: 'h' })

View File

@@ -62,14 +62,14 @@ context('/api/marks/strike', () => {
.should('not.exist')
})
it('the keyboard shortcut should strike the selected text', () => {
it('should strike the selected text when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, shiftKey: true, key: 'x' })
.find('s')
.should('contain', 'Example Text')
})
it('the keyboard shortcut should toggle the selected text striked', () => {
it('should toggle the selected text striked when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, shiftKey: true, key: 'x' })
.trigger('keydown', { modKey: true, shiftKey: true, key: 'x' })

View File

@@ -48,14 +48,14 @@ context('/api/marks/underline', () => {
.should('not.exist')
})
it('the keyboard shortcut should underline the selected text', () => {
it('should underline the selected text when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, key: 'u' })
.find('u')
.should('contain', 'Example Text')
})
it('the keyboard shortcut should toggle the selected text underline', () => {
it('should toggle the selected text underline when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { modKey: true, key: 'u' })
.trigger('keydown', { modKey: true, key: 'u' })

View File

@@ -71,14 +71,14 @@ context('/api/nodes/blockquote', () => {
.should('not.exist')
})
it('the keyboard shortcut should make the selected line a blockquote', () => {
it('should make the selected line a blockquote when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror')
.trigger('keydown', { shiftKey: true, modKey: true, key: 'b' })
.find('blockquote')
.should('contain', 'Example Text')
})
it('the keyboard shortcut should toggle the blockquote', () => {
it('should toggle the blockquote when the keyboard shortcut is pressed', () => {
cy.get('.ProseMirror blockquote')
.should('not.exist')

View File

@@ -9,7 +9,7 @@ const MenuBar = () => {
return (
<>
<button onClick={() => editor.chain().focus().unsetMarks().run()}>
<button onClick={() => editor.chain().focus().unsetAllMarks().run()}>
Clear formatting
</button>
<button

View File

@@ -110,14 +110,14 @@ Have a look at all of the core commands listed below. They should give you a goo
| .extendMarkRange() | Extends the text selection to the current mark. |
| .resetNodeAttributes() | Resets all node attributes to the default value. |
| .selectParentNode() | Select the parent node. |
| .setBlockType() | Replace a given range with a node. |
| .setMark() | Add a mark with new attributes. |
| .setNode() | Replace a given range with a node. |
| .splitBlock() | Forks a new node from an existing node. |
| .toggleBlockType() | Toggle a node with another node. |
| .toggleMark() | Toggle a mark on and off. |
| .toggleNode() | Toggle a node with another node. |
| .toggleWrap() | Wraps nodes in another node, or removes an existing wrap. |
| .unsetAllMarks() | Remove all marks in the current selection. |
| .unsetMark() | Remove a mark in the current selection. |
| .unsetMarks() | Remove all marks in the current selection. |
| .updateNodeAttributes() | Update attributes of a node. |
### Lists

View File

@@ -100,6 +100,33 @@ new Editor({
| `false` | Disables autofocus. |
| `null` | Disables autofocus. |
### Enable input rules
By default, tiptap enables all [input rules](/guide/build-custom-extensions/#input-rules). With `enableInputRules` you can disable that.
```js
import { Editor } from '@tiptap/core'
import { defaultExtensions } from '@tiptap/starter-kit'
new Editor({
content: `<p>Example Text</p>`,
extensions: defaultExtensions(),
enableInputRules: false,
})
```
### Enable paste rules
By default, tiptap enables all [paste rules](/guide/build-custom-extensions/#paste-rules). With `enablePasteRules` you can disable that.
```js
import { Editor } from '@tiptap/core'
import { defaultExtensions } from '@tiptap/starter-kit'
new Editor({
content: `<p>Example Text</p>`,
extensions: defaultExtensions(),
enablePasteRules: false,
})
```
### Inject CSS
By default, tiptap injects [a little bit of CSS](https://github.com/ueberdosis/tiptap-next/tree/main/packages/core/src/style.ts). With `injectCSS` you can disable that.

View File

@@ -275,7 +275,7 @@ const CustomParagraph = Paragraph.extend({
addCommands() {
return {
paragraph: () => ({ commands }) => {
return commands.toggleBlockType('paragraph', 'paragraph')
return commands.toggleNode('paragraph', 'paragraph')
},
}
},

View File

@@ -82,7 +82,7 @@
> p code,
> ul code,
> ol code,
> table code,
> .table-wrapper code,
> .remark-container code {
color: $colorYellow;
background-color: rgba($colorYellow, 0.1);
@@ -92,7 +92,7 @@
> p a,
> ul a,
> ol a,
> table a,
> .table-wrapper a,
> .remark-container a {
text-decoration: underline;
@@ -187,46 +187,55 @@
}
}
> table {
> .table-wrapper {
display: block;
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
text-align: left;
overflow-x: auto;
-webkit-overflow-scrolling: touch;
th,
td {
padding: 0.5rem;
> table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
text-align: left;
&:first-child {
padding-left: 0;
th,
td {
padding: 0.5rem;
min-width: 8rem;
&:first-child {
padding-left: 0;
}
&:last-child {
padding-right: 0;
}
}
&:last-child {
padding-right: 0;
th {
white-space: nowrap;
color: $colorWhite;
font-weight: 500;
border-bottom: 1px solid rgba($colorWhite, 0.2);
}
}
th {
color: $colorWhite;
font-weight: 500;
border-bottom: 1px solid rgba($colorWhite, 0.2);
}
td {
border-bottom: 1px solid rgba($colorWhite, 0.1);
}
td {
border-bottom: 1px solid rgba($colorWhite, 0.1);
}
tr:last-child td {
border-bottom: 0;
}
tbody tr {
&:last-child td {
tr:last-child td {
border-bottom: 0;
}
&:hover {
background: rgba($colorWhite, 0.02);
tbody tr {
&:last-child td {
border-bottom: 0;
}
&:hover {
background: rgba($colorWhite, 0.02);
}
}
}
}