Merge branch 'main' of github.com:ueberdosis/tiptap-next into main

This commit is contained in:
Hans Pagel
2020-09-24 14:08:11 +02:00
142 changed files with 1058 additions and 408 deletions

14
.editorconfig Normal file
View File

@@ -0,0 +1,14 @@
# EditorConfig is awesome: http://EditorConfig.org
root = true
[*]
end_of_line = lf
charset = utf-8
insert_final_newline = true
max_line_length = 100
[*.{html,ts,js,jsx,css,scss,vue}]
trim_trailing_whitespace = true
indent_style = space
indent_size = 2

67
.eslintrc.js Normal file
View File

@@ -0,0 +1,67 @@
module.exports = {
parserOptions: {
parser: '@typescript-eslint/parser',
sourceType: 'module',
},
env: {
es6: true,
node: true,
},
overrides: [
{
files: [
'./**/*.ts',
'./**/*.js',
'./**/*.vue',
],
excludedFiles: [
'dist/**',
],
plugins: [
'html',
'cypress',
'@typescript-eslint',
],
env: {
'cypress/globals': true,
},
globals: {
document: false,
window: false,
},
extends: [
'plugin:vue/strongly-recommended',
'airbnb-base',
],
rules: {
semi: ['error', 'never'],
'import/extensions': 'off',
'import/no-extraneous-dependencies': 'off',
'import/no-unresolved': 'off',
'import/no-dynamic-require': 'off',
'arrow-parens': ['error', 'as-needed'],
'padded-blocks': 'off',
'class-methods-use-this': 'off',
'global-require': 'off',
'func-names': ['error', 'never'],
'arrow-body-style': 'off',
'max-len': 'off',
'vue/this-in-template': ['error', 'never'],
'vue/max-attributes-per-line': ['error', {
singleline: 3,
multiline: {
max: 1,
allowFirstLine: false,
},
}],
'no-param-reassign': 'off',
'import/prefer-default-export': 'off',
'consistent-return': 'off',
'no-unused-vars': 'off',
'@typescript-eslint/no-unused-vars': ['error'],
'no-use-before-define': 'off',
'@typescript-eslint/no-use-before-define': ['error'],
},
},
],
}

View File

@@ -5,4 +5,4 @@ module.exports = {
plugins: [ plugins: [
'@babel/plugin-proposal-optional-chaining', '@babel/plugin-proposal-optional-chaining',
], ],
} }

View File

@@ -6,4 +6,4 @@ module.exports = {
plugins: [ plugins: [
'@babel/plugin-proposal-optional-chaining', '@babel/plugin-proposal-optional-chaining',
], ],
} }

View File

@@ -30,10 +30,10 @@ module.exports = {
autolinkHeadings: { autolinkHeadings: {
content: { content: {
type: 'text', type: 'text',
value: '#' value: '#',
} },
} },
} },
}, },
}, },
{ {

View File

@@ -20,9 +20,9 @@ const packages = globby.sync('../packages/*', { onlyDirectories: true })
excludePrivate: true, excludePrivate: true,
// excludeNotDocumented: true, // excludeNotDocumented: true,
exclude: [ exclude: [
"**/*.test.ts", '**/*.test.ts',
"**/__tests__/*", '**/__tests__/*',
"**/__mocks__/*" '**/__mocks__/*',
], ],
}) })
@@ -68,16 +68,16 @@ module.exports = function (api) {
config.module config.module
.rule('typescript') .rule('typescript')
.test(/\.tsx?$/) .test(/\.tsx?$/)
.use() .use()
.loader('ts-loader') .loader('ts-loader')
.options({ transpileOnly: false, appendTsSuffixTo: [/\.vue$/] }) .options({ transpileOnly: false, appendTsSuffixTo: [/\.vue$/] })
config.module config.module
.rule('jsx') .rule('jsx')
.test(/\.jsx?$/) .test(/\.jsx?$/)
.use() .use()
.loader('babel-loader') .loader('babel-loader')
globby.sync('../packages/*', { onlyDirectories: true }) globby.sync('../packages/*', { onlyDirectories: true })
.map(name => name.replace('../packages/', '')) .map(name => name.replace('../packages/', ''))

View File

@@ -23,7 +23,7 @@
</div> </div>
<div class="demo__meta"> <div class="demo__meta">
<div class="demo__name"> <div class="demo__name">
Demo/{{ this.name }} Demo/{{ name }}
</div> </div>
<a class="demo__link" :href="githubUrl" target="_blank"> <a class="demo__link" :href="githubUrl" target="_blank">
Edit on GitHub Edit on GitHub
@@ -31,7 +31,7 @@
</div> </div>
</template> </template>
<div v-else class="demo__error"> <div v-else class="demo__error">
Could not find a demo called {{ this.name }}. Could not find a demo called {{ name }}.
</div> </div>
</div> </div>
</template> </template>
@@ -66,7 +66,7 @@ export default {
hideSourceCode: { hideSourceCode: {
type: Boolean, type: Boolean,
default: false, default: false,
} },
}, },
data() { data() {
@@ -106,7 +106,7 @@ export default {
}, },
mounted() { mounted() {
this.files = collect(require.context(`~/demos/`, true, /.+\..+$/).keys()) this.files = collect(require.context('~/demos/', true, /.+\..+$/).keys())
.filter(path => path.startsWith(`./${this.name}`)) .filter(path => path.startsWith(`./${this.name}`))
.map(path => path.replace('./', '')) .map(path => path.replace('./', ''))
.map(path => { .map(path => {
@@ -120,13 +120,13 @@ export default {
highlight: this.syntax[extension] || extension, highlight: this.syntax[extension] || extension,
} }
}) })
.filter((item) => { .filter(item => {
return ['vue', 'jsx', 'scss'].includes(item.extension) return ['vue', 'jsx', 'scss'].includes(item.extension)
}) })
.sortBy(item => item.path.split('/').length) .sortBy(item => item.path.split('/').length)
.toArray() .toArray()
} },
} }
</script> </script>
<style lang="scss" src="./style.scss" scoped /> <style lang="scss" src="./style.scss" scoped />

View File

@@ -35,7 +35,7 @@ export default {
computed: { computed: {
items() { items() {
return this.linkGroups.reduce((acc, group) => (acc.push(...group.items), acc), []) return this.linkGroups.reduce((acc, group) => ((acc.push(...group.items), acc)), [])
}, },
currentIndex() { currentIndex() {
@@ -51,8 +51,8 @@ export default {
previousPage() { previousPage() {
return this.items[this.currentIndex - 1] return this.items[this.currentIndex - 1]
}, },
} },
} }
</script> </script>
<style lang="scss" src="./style.scss" scoped></style> <style lang="scss" src="./style.scss" scoped></style>

View File

@@ -34,11 +34,11 @@ export default {
methods: { methods: {
highlightCode() { highlightCode() {
Prism.highlightAllUnder(this.$el) Prism.highlightAllUnder(this.$el)
} },
}, },
mounted() { mounted() {
this.highlightCode() this.highlightCode()
}, },
} }
</script> </script>

View File

@@ -10,7 +10,7 @@ export default {
props: { props: {
component: { component: {
required: true, required: true,
} },
}, },
mounted() { mounted() {
@@ -21,4 +21,4 @@ export default {
ReactDOM.unmountComponentAtNode(this.$el) ReactDOM.unmountComponentAtNode(this.$el)
}, },
} }
</script> </script>

View File

@@ -8,18 +8,18 @@ import { outdent } from '@mvasilkov/outdent'
export default { export default {
data() { data() {
return { return {
formattedCode: null formattedCode: null,
} }
}, },
methods: { methods: {
updateCode() { updateCode() {
const text = this.$slots.default[0].text const { text } = this.$slots.default[0]
if (text) { if (text) {
this.formattedCode = outdent(text) this.formattedCode = outdent(text)
} }
} },
}, },
beforeUpdate() { beforeUpdate() {
@@ -30,4 +30,4 @@ export default {
this.updateCode() this.updateCode()
}, },
} }
</script> </script>

View File

@@ -1,5 +1,5 @@
<template> <template>
<pre>{{ this.html }}</pre> <pre>{{ html }}</pre>
</template> </template>
<script> <script>
@@ -9,22 +9,21 @@ import Paragraph from '@tiptap/extension-paragraph'
import Text from '@tiptap/extension-text' import Text from '@tiptap/extension-text'
export default { export default {
data() { data() {
return { return {
doc: { doc: {
'type': 'document', type: 'document',
'content': [{ content: [{
'type': 'paragraph', type: 'paragraph',
'attrs': { attrs: {
'align': 'left' align: 'left',
}, },
'content': [{ content: [{
'type': 'text', type: 'text',
'text': 'Example Text' text: 'Example Text',
}] }],
}] }],
} },
} }
}, },
@@ -35,8 +34,7 @@ export default {
Paragraph(), Paragraph(),
Text(), Text(),
]) ])
} },
} },
} }
</script> </script>

View File

@@ -83,7 +83,7 @@ export default {
mounted() { mounted() {
this.editor = new Editor({ this.editor = new Editor({
extensions: defaultExtensions(), extensions: defaultExtensions(),
content: ` content: `
<h2> <h2>
Hi there, Hi there,
</h2> </h2>
@@ -112,4 +112,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -8,44 +8,44 @@ context('/examples/export-html-or-json', () => {
const json = editor.json() const json = editor.json()
expect(json).to.deep.equal({ expect(json).to.deep.equal({
'type': 'document', type: 'document',
'content': [ content: [
{ {
'type': 'paragraph', type: 'paragraph',
'content': [ content: [
{ {
'type': 'text', type: 'text',
'text': 'You are able to export your data as ' text: 'You are able to export your data as ',
}, },
{ {
'type': 'text', type: 'text',
'marks': [ marks: [
{ {
'type': 'code' type: 'code',
} },
], ],
'text': 'HTML' text: 'HTML',
}, },
{ {
'type': 'text', type: 'text',
'text': ' or ' text: ' or ',
}, },
{ {
'type': 'text', type: 'text',
'marks': [ marks: [
{ {
'type': 'code' type: 'code',
} },
], ],
'text': 'JSON' text: 'JSON',
}, },
{ {
'type': 'text', type: 'text',
'text': '.' text: '.',
} },
] ],
} },
] ],
}) })
}) })
}) })
@@ -57,4 +57,4 @@ context('/examples/export-html-or-json', () => {
expect(html).to.equal('<p>You are able to export your data as <code>HTML</code> or <code>JSON</code>.</p>') expect(html).to.equal('<p>You are able to export your data as <code>HTML</code> or <code>JSON</code>.</p>')
}) })
}) })
}) })

View File

@@ -88,4 +88,4 @@ export default {
} }
</script> </script>
<style lang="scss" src="./style.scss"> <style lang="scss" src="./style.scss">

View File

@@ -10,4 +10,4 @@ context('/examples/focus', () => {
cy.get('.ProseMirror p:first').should('have.class', 'has-focus') cy.get('.ProseMirror p:first').should('have.class', 'has-focus')
}) })
}) })
}) })

View File

@@ -55,4 +55,4 @@ export default {
} }
</script> </script>
<style lang="scss" src="./style.scss"> <style lang="scss" src="./style.scss">

View File

@@ -4,7 +4,7 @@ context('/examples/history', () => {
}) })
it('should not have a mistake', () => { it('should not have a mistake', () => {
cy.get('.ProseMirror').then(([{ editor }]) => { cy.get('.ProseMirror').then(() => {
cy.get('.ProseMirror h2:first').should('not.contain', 'Mistake') cy.get('.ProseMirror h2:first').should('not.contain', 'Mistake')
}) })
}) })
@@ -22,4 +22,4 @@ context('/examples/history', () => {
cy.get('.ProseMirror h2:first').should('not.contain', 'Mistake') cy.get('.ProseMirror h2:first').should('not.contain', 'Mistake')
}) })
}) })
}) })

View File

@@ -28,7 +28,7 @@ export default {
mounted() { mounted() {
this.editor = new Editor({ this.editor = new Editor({
content: ` content: `
<h2> <h2>
History History
</h2> </h2>
@@ -44,4 +44,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -99,4 +99,4 @@ context('/examples/markdown-shortcuts', () => {
.find('blockquote') .find('blockquote')
.should('contain', 'foobar') .should('contain', 'foobar')
}) })
}) })

View File

@@ -20,7 +20,7 @@ export default {
mounted() { mounted() {
this.editor = new Editor({ this.editor = new Editor({
content: ` content: `
<p> <p>
Start a new line and type <code>#</code> followed by a space to get a headline. Try <code>#</code>, <code>##</code>, <code>###</code>, <code>####</code>, <code>#####</code>, <code>######</code> for different levels. Start a new line and type <code>#</code> followed by a space to get a headline. Try <code>#</code>, <code>##</code>, <code>###</code>, <code>####</code>, <code>#####</code>, <code>######</code> for different levels.
</p> </p>
@@ -39,4 +39,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -22,4 +22,4 @@ context('/examples/read-only', () => {
cy.get('.ProseMirror p:first').should('contain', 'Edited: ') cy.get('.ProseMirror p:first').should('contain', 'Edited: ')
}) })
}) })
}) })

View File

@@ -49,4 +49,4 @@ export default {
} }
</script> </script>
<style lang="scss" src="./style.scss"> <style lang="scss" src="./style.scss">

View File

@@ -2,4 +2,4 @@ context('/examples/simple', () => {
before(() => { before(() => {
cy.visit('/examples/simple') cy.visit('/examples/simple')
}) })
}) })

View File

@@ -41,4 +41,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -38,4 +38,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -73,4 +73,4 @@ context('/api/extensions/blockquote', () => {
.find('blockquote') .find('blockquote')
.should('contain', 'Quote') .should('contain', 'Quote')
}) })
}) })

View File

@@ -46,6 +46,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -58,4 +58,4 @@ context('/api/extensions/bold', () => {
.find('strong') .find('strong')
.should('contain', 'Bold') .should('contain', 'Bold')
}) })
}) })

View File

@@ -49,6 +49,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -128,4 +128,4 @@ context('/api/extensions/bullet-list', () => {
.find('p') .find('p')
.should('contain', '* Example') .should('contain', '* Example')
}) })
}) })

View File

@@ -48,6 +48,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -32,4 +32,4 @@ context('/api/extensions/code', () => {
cy.get('.ProseMirror code') cy.get('.ProseMirror code')
.should('not.exist') .should('not.exist')
}) })
}) })

View File

@@ -44,6 +44,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -64,4 +64,4 @@ context('/api/extensions/code-block', () => {
.find('pre') .find('pre')
.should('contain', 'Code') .should('contain', 'Code')
}) })
}) })

View File

@@ -59,6 +59,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -2,4 +2,4 @@ context('/api/extensions/document', () => {
before(() => { before(() => {
cy.visit('/api/extensions/document') cy.visit('/api/extensions/document')
}) })
}) })

View File

@@ -37,6 +37,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -41,4 +41,4 @@ context('/api/extensions/hard-break', () => {
cy.get('.ProseMirror br') cy.get('.ProseMirror br')
.should('exist') .should('exist')
}) })
}) })

View File

@@ -52,6 +52,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -74,4 +74,4 @@ context('/api/extensions/heading', () => {
.find('h1') .find('h1')
.should('contain', 'Headline') .should('contain', 'Headline')
}) })
}) })

View File

@@ -54,6 +54,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -37,7 +37,7 @@ context('/api/extensions/history', () => {
.should('not.contain', 'Mistake') .should('not.contain', 'Mistake')
cy.get('.demo__preview button:nth-child(2)') cy.get('.demo__preview button:nth-child(2)')
.click() .click()
cy.get('.ProseMirror') cy.get('.ProseMirror')
.should('contain', 'Mistake') .should('contain', 'Mistake')

View File

@@ -46,6 +46,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -49,4 +49,4 @@ context('/api/extensions/horizontal-rule', () => {
.should('exist') .should('exist')
}) })
}) })
}) })

View File

@@ -47,6 +47,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -47,4 +47,4 @@ context('/api/extensions/italic', () => {
.find('em') .find('em')
.should('not.exist') .should('not.exist')
}) })
}) })

View File

@@ -46,6 +46,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -9,4 +9,4 @@ context('/api/extensions/link', () => {
editor.selectAll() editor.selectAll()
}) })
}) })
}) })

View File

@@ -41,6 +41,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -2,4 +2,4 @@ context('/api/extensions/list-item', () => {
before(() => { before(() => {
cy.visit('/api/extensions/list-item') cy.visit('/api/extensions/list-item')
}) })
}) })

View File

@@ -68,6 +68,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -94,4 +94,4 @@ context('/api/extensions/ordered-list', () => {
.find('p') .find('p')
.should('contain', '1. Example') .should('contain', '1. Example')
}) })
}) })

View File

@@ -48,6 +48,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -42,4 +42,4 @@ context('/api/extensions/paragraph', () => {
.find('p') .find('p')
.should('have.length', 1) .should('have.length', 1)
}) })
}) })

View File

@@ -37,6 +37,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -55,4 +55,4 @@ context('/api/extensions/strike', () => {
.find('s') .find('s')
.should('contain', 'Strike') .should('contain', 'Strike')
}) })
}) })

View File

@@ -47,6 +47,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -15,4 +15,4 @@ context('/api/extensions/text', () => {
.find('p') .find('p')
.should('contain', 'Example Text') .should('contain', 'Example Text')
}) })
}) })

View File

@@ -37,6 +37,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -48,4 +48,4 @@ context('/api/extensions/underline', () => {
.find('u') .find('u')
.should('not.exist') .should('not.exist')
}) })
}) })

View File

@@ -45,6 +45,6 @@ export default {
beforeDestroy() { beforeDestroy() {
this.editor.destroy() this.editor.destroy()
} },
} }
</script> </script>

View File

@@ -27,4 +27,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -72,4 +72,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -27,4 +27,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -1,11 +1,15 @@
import React, { useState, useRef, useEffect, createContext, useContext } from 'react' import {
useState, useRef, useEffect, createContext, useContext,
} from 'react'
import { Editor as Tiptap } from '@tiptap/core' import { Editor as Tiptap } from '@tiptap/core'
export const EditorContext = createContext({}) export const EditorContext = createContext({})
export const useEditor = () => useContext(EditorContext) export const useEditor = () => useContext(EditorContext)
export const Editor = ({ value, onChange, children, ...props }) => { export const Editor = ({
value, onChange, children, ...props
}) => {
const [editor, setEditor] = useState(null) const [editor, setEditor] = useState(null)
const editorRef = useRef(null) const editorRef = useRef(null)

View File

@@ -1,6 +1,6 @@
import React, { useState } from 'react' import { useState } from 'react'
import { useEditor, Editor } from './components/Editor'
import extensions from '@tiptap/starter-kit' import extensions from '@tiptap/starter-kit'
import { useEditor, Editor } from './components/Editor'
// Menu bar example component // Menu bar example component
// useEditor only works for child components of <Editor /> // useEditor only works for child components of <Editor />
@@ -24,39 +24,39 @@ const MenuBar = () => {
export default () => { export default () => {
const [value, setValue] = useState({ const [value, setValue] = useState({
'type': 'document', type: 'document',
'content': [ content: [
{ {
'type': 'paragraph', type: 'paragraph',
'content': [ content: [
{ {
'type': 'text', type: 'text',
'text': 'rendered in ' text: 'rendered in ',
}, },
{ {
'type': 'text', type: 'text',
'marks': [ marks: [
{ {
'type': 'bold' type: 'bold',
} },
], ],
'text': 'react' text: 'react',
}, },
{ {
'type': 'text', type: 'text',
'text': '!' text: '!',
} },
] ],
} },
] ],
}) })
return ( return (
<> <>
<p> <p>
<button onClick={() => alert(JSON.stringify(value))}>Alert state</button> <button onClick={() => alert(JSON.stringify(value))}>Alert state</button>
</p> </p>
<hr style={{ margin: '0.85rem 0'}} /> <hr style={{ margin: '0.85rem 0' }} />
<Editor <Editor
value={value} value={value}
onChange={setValue} onChange={setValue}

View File

@@ -41,4 +41,4 @@ export default {
this.editor.destroy() this.editor.destroy()
}, },
} }
</script> </script>

View File

@@ -6,7 +6,7 @@
{{ $static.metadata.siteName }} {{ $static.metadata.siteName }}
</g-link> </g-link>
<div> <div>
<input class="search" type="search" placeholder="Search" /> <input class="search" type="search" placeholder="Search">
<a href="https://github.com/sponsors/ueberdosis"> <a href="https://github.com/sponsors/ueberdosis">
Sponsor Sponsor
</a> </a>
@@ -58,9 +58,9 @@
</nav> </nav>
</div> </div>
<main class="app__main"> <main class="app__main">
<slot/> <slot />
<p> <p>
<br /> <br>
<a :href="editLink" target="_blank"> <a :href="editLink" target="_blank">
<span>Edit this page on GitHub</span> <span>Edit this page on GitHub</span>
</a> </a>
@@ -103,11 +103,11 @@ export default {
}, },
computed: { computed: {
currentPath () { currentPath() {
return this.$route.matched[0].path return this.$route.matched[0].path
}, },
editLink () { editLink() {
const currentPath = this.currentPath const { currentPath } = this
const filePath = currentPath === '' ? '/introduction' : currentPath const filePath = currentPath === '' ? '/introduction' : currentPath
return `https://github.com/ueberdosis/tiptap-next/blob/main/docs/src/docPages${filePath}.md` return `https://github.com/ueberdosis/tiptap-next/blob/main/docs/src/docPages${filePath}.md`
@@ -116,13 +116,14 @@ export default {
methods: { methods: {
initSearch() { initSearch() {
// eslint-disable-next-line
docsearch({ docsearch({
apiKey: '1abe7fb0f0dac150d0e963d2eda930fe', apiKey: '1abe7fb0f0dac150d0e963d2eda930fe',
indexName: 'ueberdosis_tiptap', indexName: 'ueberdosis_tiptap',
inputSelector: '.search', inputSelector: '.search',
debug: false, debug: false,
}) })
} },
}, },
mounted() { mounted() {
@@ -134,4 +135,4 @@ export default {
<style lang="scss" src="./fonts.scss"></style> <style lang="scss" src="./fonts.scss"></style>
<style lang="scss" src="./base.scss"></style> <style lang="scss" src="./base.scss"></style>
<style lang="scss" src="./prism.scss"></style> <style lang="scss" src="./prism.scss"></style>
<style lang="scss" src="./style.scss" scoped></style> <style lang="scss" src="./style.scss" scoped></style>

View File

@@ -1,3 +1,4 @@
// eslint-disable-next-line
import Prism from 'prismjs' import Prism from 'prismjs'
import 'prismjs/components/prism-jsx.js' import 'prismjs/components/prism-jsx.js'
import 'prismjs/components/prism-scss.js' import 'prismjs/components/prism-scss.js'
@@ -6,7 +7,7 @@ import Demo from '~/components/Demo'
import Tab from '~/components/Tab' import Tab from '~/components/Tab'
import ReactRenderer from '~/components/ReactRenderer' import ReactRenderer from '~/components/ReactRenderer'
export default function (Vue, { router, head, isClient }) { export default function (Vue) {
Vue.component('Layout', App) Vue.component('Layout', App)
Vue.component('Demo', Demo) Vue.component('Demo', Demo)
Vue.component('Tab', Tab) Vue.component('Tab', Tab)

View File

@@ -35,4 +35,4 @@ export default {
} }
</script> </script>
<style lang="scss" src="./style.scss" scoped></style> <style lang="scss" src="./style.scss" scoped></style>

View File

@@ -6,4 +6,4 @@
</Layout> </Layout>
</template> </template>
<style lang="scss" src="./style.scss" scoped></style> <style lang="scss" src="./style.scss" scoped></style>

View File

@@ -15,6 +15,7 @@
"build:docs": "yarn --cwd ./docs build", "build:docs": "yarn --cwd ./docs build",
"build:packages": "yarn clean:packages && lerna exec --parallel -- microbundle --compress", "build:packages": "yarn clean:packages && lerna exec --parallel -- microbundle --compress",
"clean:packages": "rm -rf ./packages/*/dist", "clean:packages": "rm -rf ./packages/*/dist",
"lint": "eslint --quiet --no-error-on-unmatched-pattern ./",
"test:open": "cypress open --project tests", "test:open": "cypress open --project tests",
"test": "cypress run --project tests", "test": "cypress run --project tests",
"reset": "yarn clean:packages && rm -rf ./**/.cache && rm -rf ./**/node_modules && rm -rf ./yarn.lock && yarn install" "reset": "yarn clean:packages && rm -rf ./**/.cache && rm -rf ./**/node_modules && rm -rf ./yarn.lock && yarn install"
@@ -30,7 +31,15 @@
"@types/prosemirror-state": "^1.2.5", "@types/prosemirror-state": "^1.2.5",
"@types/prosemirror-transform": "^1.1.1", "@types/prosemirror-transform": "^1.1.1",
"@types/prosemirror-view": "^1.15.0", "@types/prosemirror-view": "^1.15.0",
"@typescript-eslint/eslint-plugin": "^4.2.0",
"@typescript-eslint/parser": "^4.2.0",
"cypress": "^5.2.0", "cypress": "^5.2.0",
"eslint": "^7.9.0",
"eslint-config-airbnb-base": "^14.2.0",
"eslint-plugin-cypress": "^2.11.1",
"eslint-plugin-html": "^6.1.0",
"eslint-plugin-import": "^2.22.0",
"eslint-plugin-vue": "^6.2.2",
"lerna": "^3.22.1", "lerna": "^3.22.1",
"microbundle": "^0.12.3", "microbundle": "^0.12.3",
"sass-loader": "^9.0.3", "sass-loader": "^9.0.3",

View File

@@ -1,14 +1,18 @@
import { EditorState, Transaction } from "prosemirror-state" import { EditorState, Transaction } from 'prosemirror-state'
import { ChainedCommands, Editor, CommandSpec } from "./Editor" import { ChainedCommands, Editor, CommandSpec } from './Editor'
import getAllMethodNames from './utils/getAllMethodNames' import getAllMethodNames from './utils/getAllMethodNames'
export default class CommandManager { export default class CommandManager {
editor: Editor editor: Editor
commands: { [key: string]: any } = {} commands: { [key: string]: any } = {}
methodNames: string[] = []
constructor(editor: Editor) { constructor(editor: Editor) {
this.editor = editor this.editor = editor
this.methodNames = getAllMethodNames(this.editor)
} }
/** /**
@@ -22,7 +26,7 @@ export default class CommandManager {
throw new Error(`tiptap: command '${name}' is already defined.`) throw new Error(`tiptap: command '${name}' is already defined.`)
} }
if (getAllMethodNames(this.editor).includes(name)) { if (this.methodNames.includes(name)) {
throw new Error(`tiptap: '${name}' is a protected name.`) throw new Error(`tiptap: '${name}' is a protected name.`)
} }
@@ -35,13 +39,13 @@ export default class CommandManager {
const { commands, editor } = this const { commands, editor } = this
const { state, view } = editor const { state, view } = editor
const command = commands[name] const command = commands[name]
if (!command) { if (!command) {
// TODO: prevent vue devtools to throw error // TODO: prevent vue devtools to throw error
// throw new Error(`tiptap: command '${name}' not found.`) // throw new Error(`tiptap: command '${name}' not found.`)
return return
} }
return (...args: any) => { return (...args: any) => {
const { tr } = state const { tr } = state
const props = this.buildProps(tr) const props = this.buildProps(tr)
@@ -87,7 +91,7 @@ export default class CommandManager {
return proxy return proxy
} }
} },
}) as ChainedCommands }) as ChainedCommands
} }
@@ -108,16 +112,16 @@ export default class CommandManager {
.map(([name, command]) => { .map(([name, command]) => {
return [name, (...args: any[]) => command(...args)(props)] return [name, (...args: any[]) => command(...args)(props)]
})) }))
} },
} }
return props return props
} }
public chainableState(tr: Transaction, state: EditorState): EditorState { public chainableState(tr: Transaction, state: EditorState): EditorState {
let selection = tr.selection let { selection } = tr
let doc = tr.doc let { doc } = tr
let storedMarks = tr.storedMarks let { storedMarks } = tr
return { return {
...state, ...state,
@@ -143,7 +147,7 @@ export default class CommandManager {
return tr return tr
}, },
}; }
} }
} }

View File

@@ -2,4 +2,4 @@ export default abstract class ComponentRenderer {
static type: string static type: string
} }

View File

@@ -1,6 +1,6 @@
import { EditorState, Plugin, Transaction } from 'prosemirror-state' import { EditorState, Plugin, Transaction } from 'prosemirror-state'
import { EditorView} from 'prosemirror-view' import { EditorView } from 'prosemirror-view'
import { Schema, DOMParser, DOMSerializer } from 'prosemirror-model' import { Schema, DOMParser } from 'prosemirror-model'
import magicMethods from './utils/magicMethods' import magicMethods from './utils/magicMethods'
import elementFromString from './utils/elementFromString' import elementFromString from './utils/elementFromString'
import nodeIsActive from './utils/nodeIsActive' import nodeIsActive from './utils/nodeIsActive'
@@ -16,9 +16,8 @@ import EventEmitter from './EventEmitter'
import Extension from './Extension' import Extension from './Extension'
import Node from './Node' import Node from './Node'
import Mark from './Mark' import Mark from './Mark'
import ComponentRenderer from './ComponentRenderer'
import defaultPlugins from './plugins' import defaultPlugins from './plugins'
import * as commands from './commands' import * as coreCommands from './commands'
export type Command = (props: { export type Command = (props: {
editor: Editor, editor: Editor,
@@ -41,14 +40,14 @@ export interface Commands {}
export type CommandNames = Extract<keyof Commands, string> export type CommandNames = Extract<keyof Commands, string>
export type SingleCommands = { export type SingleCommands = {
[Command in keyof Commands]: Commands[Command] extends (...args: any[]) => any [Item in keyof Commands]: Commands[Item] extends (...args: any[]) => any
? (...args: Parameters<Commands[Command]>) => boolean ? (...args: Parameters<Commands[Item]>) => boolean
: never : never
} }
export type ChainedCommands = { export type ChainedCommands = {
[Command in keyof Commands]: Commands[Command] extends (...args: any[]) => any [Item in keyof Commands]: Commands[Item] extends (...args: any[]) => any
? (...args: Parameters<Commands[Command]>) => ChainedCommands ? (...args: Parameters<Commands[Item]>) => ChainedCommands
: never : never
} & { } & {
run: () => boolean run: () => boolean
@@ -77,14 +76,23 @@ declare module './Editor' {
export class Editor extends EventEmitter { export class Editor extends EventEmitter {
public renderer!: any public renderer!: any
private proxy!: Editor private proxy!: Editor
private commandManager!: CommandManager private commandManager!: CommandManager
private extensionManager!: ExtensionManager private extensionManager!: ExtensionManager
private css!: HTMLStyleElement private css!: HTMLStyleElement
public schema!: Schema public schema!: Schema
public view!: EditorView public view!: EditorView
public selection = { from: 0, to: 0 } public selection = { from: 0, to: 0 }
public isFocused = false public isFocused = false
public options: EditorOptions = { public options: EditorOptions = {
element: document.createElement('div'), element: document.createElement('div'),
content: '', content: '',
@@ -109,7 +117,7 @@ export class Editor extends EventEmitter {
this.createSchema() this.createSchema()
this.extensionManager.resolveConfigs() this.extensionManager.resolveConfigs()
this.createView() this.createView()
this.registerCommands(commands) this.registerCommands(coreCommands)
if (this.options.injectCSS) { if (this.options.injectCSS) {
require('./style.css') require('./style.css')
@@ -123,6 +131,7 @@ export class Editor extends EventEmitter {
* *
* @param name The name of the command * @param name The name of the command
*/ */
// eslint-disable-next-line
private __get(name: string) { private __get(name: string) {
return this.commandManager.runSingleCommand(name) return this.commandManager.runSingleCommand(name)
} }
@@ -190,7 +199,7 @@ export class Editor extends EventEmitter {
* @param plugin A ProseMirror plugin * @param plugin A ProseMirror plugin
* @param handlePlugins Control how to merge the plugin into the existing plugins. * @param handlePlugins Control how to merge the plugin into the existing plugins.
*/ */
public registerPlugin(plugin: Plugin, handlePlugins?: (plugin: Plugin, plugins: Plugin[]) => Plugin[]) { public registerPlugin(plugin: Plugin, handlePlugins?: (newPlugin: Plugin, plugins: Plugin[]) => Plugin[]) {
const plugins = typeof handlePlugins === 'function' const plugins = typeof handlePlugins === 'function'
? handlePlugins(plugin, this.state.plugins) ? handlePlugins(plugin, this.state.plugins)
: [plugin, ...this.state.plugins] : [plugin, ...this.state.plugins]
@@ -333,7 +342,7 @@ export class Editor extends EventEmitter {
if (schemaType === 'node') { if (schemaType === 'node') {
return nodeIsActive(this.state, this.schema.nodes[name], attrs) return nodeIsActive(this.state, this.schema.nodes[name], attrs)
} else if (schemaType === 'mark') { } if (schemaType === 'mark') {
return markIsActive(this.state, this.schema.marks[name]) return markIsActive(this.state, this.schema.marks[name])
} }
@@ -381,5 +390,5 @@ export class Editor extends EventEmitter {
this.removeAllListeners() this.removeAllListeners()
removeElement(this.css) removeElement(this.css)
} }
} }

View File

@@ -1,19 +1,19 @@
export default class EventEmitter { export default class EventEmitter {
_callbacks: { [key: string]: Function[] } = {} private callbacks: { [key: string]: Function[] } = {}
on(event: string, fn: Function) { public on(event: string, fn: Function) {
if (!this._callbacks[event]) { if (!this.callbacks[event]) {
this._callbacks[event] = [] this.callbacks[event] = []
} }
this._callbacks[event].push(fn) this.callbacks[event].push(fn)
return this return this
} }
emit(event: string, ...args: any) { protected emit(event: string, ...args: any) {
const callbacks = this._callbacks[event] const callbacks = this.callbacks[event]
if (callbacks) { if (callbacks) {
callbacks.forEach(callback => callback.apply(this, args)) callbacks.forEach(callback => callback.apply(this, args))
@@ -22,21 +22,21 @@ export default class EventEmitter {
return this return this
} }
off(event: string, fn?: Function) { public off(event: string, fn?: Function) {
const callbacks = this._callbacks[event] const callbacks = this.callbacks[event]
if (callbacks) { if (callbacks) {
if (fn) { if (fn) {
this._callbacks[event] = callbacks.filter(callback => callback !== fn) this.callbacks[event] = callbacks.filter(callback => callback !== fn)
} else { } else {
delete this._callbacks[event] delete this.callbacks[event]
} }
} }
return this return this
} }
removeAllListeners() { protected removeAllListeners() {
this._callbacks = {} this.callbacks = {}
} }
} }

View File

@@ -41,8 +41,11 @@ export default class Extension<
Methods extends ExtensionMethods<Props, Options> = ExtensionMethods<Props, Options> Methods extends ExtensionMethods<Props, Options> = ExtensionMethods<Props, Options>
> { > {
type = 'extension' type = 'extension'
config: AnyObject = {} config: AnyObject = {}
configs: Configs = {}
configs: Configs = {}
options: Partial<Options> = {} options: Partial<Options> = {}
protected storeConfig(key: string, value: any, stategy: MergeStrategy) { protected storeConfig(key: string, value: any, stategy: MergeStrategy) {
@@ -102,12 +105,10 @@ export default class Extension<
this.storeConfig(key, value, 'extend') this.storeConfig(key, value, 'extend')
return this return this
} }
public create() {
type ParentOptions = Options
return <Options = ParentOptions>(options?: Partial<NoInfer<Options>>) => { public create() {
return cloneDeep(this, true).configure(options as Options) return <NewOptions = Options>(options?: Partial<NoInfer<NewOptions>>) => {
return cloneDeep(this, true).configure(options as NewOptions)
} }
} }
} }

View File

@@ -3,11 +3,12 @@ import collect from 'collect.js'
import { Plugin } from 'prosemirror-state' import { Plugin } from 'prosemirror-state'
import { keymap } from 'prosemirror-keymap' import { keymap } from 'prosemirror-keymap'
import { Schema } from 'prosemirror-model' import { Schema } from 'prosemirror-model'
// import { Schema, Node as ProsemirrorNode } from 'prosemirror-model'
import { inputRules } from 'prosemirror-inputrules' import { inputRules } from 'prosemirror-inputrules'
import { EditorView, Decoration } from 'prosemirror-view' // import { EditorView, Decoration } from 'prosemirror-view'
import { Node as ProsemirrorNode } from 'prosemirror-model'
import { Editor } from './Editor' import { Editor } from './Editor'
import capitalize from './utils/capitalize' // import capitalize from './utils/capitalize'
import { Extensions } from './types' import { Extensions } from './types'
import getTopNodeFromExtensions from './utils/getTopNodeFromExtensions' import getTopNodeFromExtensions from './utils/getTopNodeFromExtensions'
import getNodesFromExtensions from './utils/getNodesFromExtensions' import getNodesFromExtensions from './utils/getNodesFromExtensions'
@@ -18,6 +19,7 @@ import getSchema from './utils/getSchema'
export default class ExtensionManager { export default class ExtensionManager {
editor: Editor editor: Editor
extensions: Extensions extensions: Extensions
constructor(extensions: Extensions, editor: Editor) { constructor(extensions: Extensions, editor: Editor) {
@@ -28,17 +30,27 @@ export default class ExtensionManager {
resolveConfigs() { resolveConfigs() {
this.extensions.forEach(extension => { this.extensions.forEach(extension => {
const { editor } = this const { editor } = this
const name = extension.config.name const { name } = extension.config
const options = deepmerge(extension.config.defaults, extension.options) const options = deepmerge(extension.config.defaults, extension.options)
const type = extension.type === 'node' const type = extension.type === 'node'
? editor.schema.nodes[name] ? editor.schema.nodes[name]
: editor.schema.marks[name] : editor.schema.marks[name]
resolveExtensionConfig(extension, 'commands', { name, options, editor, type }) resolveExtensionConfig(extension, 'commands', {
resolveExtensionConfig(extension, 'inputRules', { name, options, editor, type }) name, options, editor, type,
resolveExtensionConfig(extension, 'pasteRules', { name, options, editor, type }) })
resolveExtensionConfig(extension, 'keys', { name, options, editor, type }) resolveExtensionConfig(extension, 'inputRules', {
resolveExtensionConfig(extension, 'plugins', { name, options, editor, type }) name, options, editor, type,
})
resolveExtensionConfig(extension, 'pasteRules', {
name, options, editor, type,
})
resolveExtensionConfig(extension, 'keys', {
name, options, editor, type,
})
resolveExtensionConfig(extension, 'plugins', {
name, options, editor, type,
})
if (extension.config.commands) { if (extension.config.commands) {
editor.registerCommands(extension.config.commands) editor.registerCommands(extension.config.commands)
@@ -57,7 +69,7 @@ export default class ExtensionManager {
get nodes(): any { get nodes(): any {
return getNodesFromExtensions(this.extensions) return getNodesFromExtensions(this.extensions)
} }
get marks(): any { get marks(): any {
return getMarksFromExtensions(this.extensions) return getMarksFromExtensions(this.extensions)
} }

View File

@@ -25,4 +25,4 @@ export default class Mark<
this.storeConfig('schema', value, 'overwrite') this.storeConfig('schema', value, 'overwrite')
return this return this
} }
} }

View File

@@ -1,5 +1,5 @@
import { Command } from '../Editor'
import { deleteSelection as originalDeleteSelection } from 'prosemirror-commands' import { deleteSelection as originalDeleteSelection } from 'prosemirror-commands'
import { Command } from '../Editor'
type DeleteSelectionCommand = () => Command type DeleteSelectionCommand = () => Command

View File

@@ -1,7 +1,8 @@
import { Editor, Command } from '../Editor'
import { TextSelection } from 'prosemirror-state' import { TextSelection } from 'prosemirror-state'
import { Editor, Command } from '../Editor'
import minMax from '../utils/minMax' import minMax from '../utils/minMax'
type Position = 'start' | 'end' | number | boolean | null
type FocusCommand = (position?: Position) => Command type FocusCommand = (position?: Position) => Command
declare module '../Editor' { declare module '../Editor' {
@@ -15,8 +16,6 @@ interface ResolvedSelection {
to: number, to: number,
} }
type Position = 'start' | 'end' | number | boolean | null
function resolveSelection(editor: Editor, position: Position = null): ResolvedSelection { function resolveSelection(editor: Editor, position: Position = null): ResolvedSelection {
if (position === null) { if (position === null) {
return editor.selection return editor.selection
@@ -31,7 +30,7 @@ function resolveSelection(editor: Editor, position: Position = null): ResolvedSe
if (position === 'end') { if (position === 'end') {
const { size } = editor.state.doc.content const { size } = editor.state.doc.content
return { return {
from: size, from: size,
to: size - 1, // TODO: -1 only for nodes with content to: size - 1, // TODO: -1 only for nodes with content
@@ -54,9 +53,9 @@ export const focus: FocusCommand = (position = null) => ({ editor, view, tr }) =
const resolvedFrom = minMax(from, 0, doc.content.size) const resolvedFrom = minMax(from, 0, doc.content.size)
const resolvedEnd = minMax(to, 0, doc.content.size) const resolvedEnd = minMax(to, 0, doc.content.size)
const selection = TextSelection.create(doc, resolvedFrom, resolvedEnd) const selection = TextSelection.create(doc, resolvedFrom, resolvedEnd)
tr.setSelection(selection) tr.setSelection(selection)
view.focus() view.focus()
return true return true
} }

View File

@@ -1,8 +1,8 @@
import { DOMParser } from 'prosemirror-model' import { DOMParser } from 'prosemirror-model'
import { Selection, Transaction } from 'prosemirror-state' import { Selection, Transaction } from 'prosemirror-state'
import { ReplaceStep, ReplaceAroundStep } from 'prosemirror-transform'
import { Command } from '../Editor' import { Command } from '../Editor'
import elementFromString from '../utils/elementFromString' import elementFromString from '../utils/elementFromString'
import {ReplaceStep, ReplaceAroundStep} from "prosemirror-transform"
type InsertHTMLCommand = (value: string) => Command type InsertHTMLCommand = (value: string) => Command
@@ -15,13 +15,13 @@ declare module '../Editor' {
// TODO: move to utils // TODO: move to utils
// https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.js#L466 // https://github.com/ProseMirror/prosemirror-state/blob/master/src/selection.js#L466
function selectionToInsertionEnd(tr: Transaction, startLen: number, bias: number) { function selectionToInsertionEnd(tr: Transaction, startLen: number, bias: number) {
let last = tr.steps.length - 1 const last = tr.steps.length - 1
if (last < startLen) return if (last < startLen) return
let step = tr.steps[last] const step = tr.steps[last]
if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep)) return if (!(step instanceof ReplaceStep || step instanceof ReplaceAroundStep)) return
let map = tr.mapping.maps[last] const map = tr.mapping.maps[last]
let end = 0 let end = 0
map.forEach((_from, _to, _newFrom, newTo) => { if (end == 0) end = newTo }) map.forEach((_from, _to, _newFrom, newTo) => { if (end === 0) end = newTo })
tr.setSelection(Selection.near(tr.doc.resolve(end as unknown as number), bias)) tr.setSelection(Selection.near(tr.doc.resolve(end as unknown as number), bias))
} }
@@ -34,4 +34,4 @@ export const insertHTML: InsertHTMLCommand = value => ({ tr, state }) => {
selectionToInsertionEnd(tr, tr.steps.length - 1, -1) selectionToInsertionEnd(tr, tr.steps.length - 1, -1)
return true return true
} }

View File

@@ -1,6 +1,6 @@
import { Command } from '../Editor'
import { liftListItem as originalLiftListItem } from 'prosemirror-schema-list' import { liftListItem as originalLiftListItem } from 'prosemirror-schema-list'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../Editor'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
type LiftListItem = (typeOrName: string | NodeType) => Command type LiftListItem = (typeOrName: string | NodeType) => Command
@@ -11,7 +11,7 @@ declare module '../Editor' {
} }
} }
export const liftListItem: LiftListItem = (typeOrName) => ({ state, dispatch }) => { export const liftListItem: LiftListItem = typeOrName => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
return originalLiftListItem(type)(state, dispatch) return originalLiftListItem(type)(state, dispatch)

View File

@@ -1,5 +1,5 @@
import { Command } from '../Editor'
import { MarkType } from 'prosemirror-model' import { MarkType } from 'prosemirror-model'
import { Command } from '../Editor'
import getMarkType from '../utils/getMarkType' import getMarkType from '../utils/getMarkType'
import getMarkRange from '../utils/getMarkRange' import getMarkRange from '../utils/getMarkRange'
@@ -11,10 +11,11 @@ declare module '../Editor' {
} }
} }
export const removeMark: RemoveMarkCommand = (typeOrName) => ({ tr, state }) => { export const removeMark: RemoveMarkCommand = typeOrName => ({ tr, state }) => {
const { selection } = tr const { selection } = tr
const type = getMarkType(typeOrName, state.schema) const type = getMarkType(typeOrName, state.schema)
let { from, to, $from, empty } = selection let { from, to } = selection
const { $from, empty } = selection
if (empty) { if (empty) {
const range = getMarkRange($from, type) const range = getMarkRange($from, type)

View File

@@ -8,7 +8,7 @@ declare module '../Editor' {
} }
} }
export const removeMarks: RemoveMarksCommand = () => ({ tr, state, view }) => { export const removeMarks: RemoveMarksCommand = () => ({ tr, state }) => {
const { selection } = tr const { selection } = tr
const { from, to, empty } = selection const { from, to, empty } = selection
@@ -18,7 +18,7 @@ export const removeMarks: RemoveMarksCommand = () => ({ tr, state, view }) => {
Object Object
.entries(state.schema.marks) .entries(state.schema.marks)
.forEach(([name, mark]) => { .forEach(([, mark]) => {
tr.removeMark(from, to, mark as any) tr.removeMark(from, to, mark as any)
}) })

View File

@@ -1,5 +1,5 @@
import { Command } from '../Editor'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../Editor'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
interface Range { interface Range {
@@ -29,7 +29,7 @@ export const replaceWithNode: ReplaceWithNodeCommand = (typeOrName, attrs = {},
if (!$from.parent.canReplaceWith(index, index, type)) { if (!$from.parent.canReplaceWith(index, index, type)) {
return false return false
} }
view.dispatch(tr.replaceWith(from, to, type.create(attrs))) view.dispatch(tr.replaceWith(from, to, type.create(attrs)))
return true return true

View File

@@ -1,5 +1,5 @@
import { Command } from '../Editor'
import { selectAll as originalSelectAll } from 'prosemirror-commands' import { selectAll as originalSelectAll } from 'prosemirror-commands'
import { Command } from '../Editor'
type SelectAllCommand = () => Command type SelectAllCommand = () => Command

View File

@@ -1,5 +1,5 @@
import { Command } from '../Editor'
import { selectParentNode as originalSelectParentNode } from 'prosemirror-commands' import { selectParentNode as originalSelectParentNode } from 'prosemirror-commands'
import { Command } from '../Editor'
type SelectParentNodeCommand = () => Command type SelectParentNodeCommand = () => Command

View File

@@ -1,5 +1,5 @@
import { Command } from '../Editor'
import { TextSelection } from 'prosemirror-state' import { TextSelection } from 'prosemirror-state'
import { Command } from '../Editor'
type SetContentCommand = ( type SetContentCommand = (
content: string, content: string,
@@ -18,7 +18,7 @@ export const setContent: SetContentCommand = (content = '', emitUpdate = false,
const { doc } = tr const { doc } = tr
const document = createDocument(content, parseOptions) const document = createDocument(content, parseOptions)
const selection = TextSelection.create(doc, 0, doc.content.size) const selection = TextSelection.create(doc, 0, doc.content.size)
tr.setSelection(selection) tr.setSelection(selection)
.replaceSelectionWith(document, false) .replaceSelectionWith(document, false)
.setMeta('preventUpdate', !emitUpdate) .setMeta('preventUpdate', !emitUpdate)

View File

@@ -1,6 +1,6 @@
import { Command } from '../Editor'
import { sinkListItem as originalSinkListItem } from 'prosemirror-schema-list' import { sinkListItem as originalSinkListItem } from 'prosemirror-schema-list'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../Editor'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
type SinkListItem = (typeOrName: string | NodeType) => Command type SinkListItem = (typeOrName: string | NodeType) => Command
@@ -11,7 +11,7 @@ declare module '../Editor' {
} }
} }
export const sinkListItem: SinkListItem = (typeOrName) => ({ state, dispatch }) => { export const sinkListItem: SinkListItem = typeOrName => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
return originalSinkListItem(type)(state, dispatch) return originalSinkListItem(type)(state, dispatch)

View File

@@ -1,6 +1,6 @@
import { Command } from '../Editor'
import { splitListItem as originalSplitListItem } from 'prosemirror-schema-list' import { splitListItem as originalSplitListItem } from 'prosemirror-schema-list'
import { NodeType } from 'prosemirror-model' import { NodeType } from 'prosemirror-model'
import { Command } from '../Editor'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
type SplitListItem = (typeOrName: string | NodeType) => Command type SplitListItem = (typeOrName: string | NodeType) => Command
@@ -11,7 +11,7 @@ declare module '../Editor' {
} }
} }
export const splitListItem: SplitListItem = (typeOrName) => ({ state, dispatch }) => { export const splitListItem: SplitListItem = typeOrName => ({ state, dispatch }) => {
const type = getNodeType(typeOrName, state.schema) const type = getNodeType(typeOrName, state.schema)
return originalSplitListItem(type)(state, dispatch) return originalSplitListItem(type)(state, dispatch)

View File

@@ -1,7 +1,7 @@
import { Command } from '../Editor'
import { wrapInList, liftListItem } from 'prosemirror-schema-list' import { wrapInList, liftListItem } from 'prosemirror-schema-list'
import { findParentNode } from 'prosemirror-utils' import { findParentNode } from 'prosemirror-utils'
import { Node, NodeType, Schema } from 'prosemirror-model' import { Node, NodeType, Schema } from 'prosemirror-model'
import { Command } from '../Editor'
import getNodeType from '../utils/getNodeType' import getNodeType from '../utils/getNodeType'
type ToggleListCommand = ( type ToggleListCommand = (

View File

@@ -1,6 +1,6 @@
import { Command } from '../Editor'
import { toggleMark as originalToggleMark } from 'prosemirror-commands' import { toggleMark as originalToggleMark } from 'prosemirror-commands'
import { MarkType } from 'prosemirror-model' import { MarkType } from 'prosemirror-model'
import { Command } from '../Editor'
import getMarkType from '../utils/getMarkType' import getMarkType from '../utils/getMarkType'
type ToggleMarkCommand = (typeOrName: string | MarkType) => Command type ToggleMarkCommand = (typeOrName: string | MarkType) => Command
@@ -11,7 +11,7 @@ declare module '../Editor' {
} }
} }
export const toggleMark: ToggleMarkCommand = (typeOrName) => ({ state, dispatch }) => { export const toggleMark: ToggleMarkCommand = typeOrName => ({ state, dispatch }) => {
const type = getMarkType(typeOrName, state.schema) const type = getMarkType(typeOrName, state.schema)
return originalToggleMark(type)(state, dispatch) return originalToggleMark(type)(state, dispatch)

View File

@@ -23,7 +23,7 @@ export const toggleNode: ToggleNodeCommand = (typeOrName, toggleTypeOrName, attr
if (isActive) { if (isActive) {
return setBlockType(toggleType)(state, dispatch) return setBlockType(toggleType)(state, dispatch)
} else {
return setBlockType(type, attrs)(state, dispatch)
} }
return setBlockType(type, attrs)(state, dispatch)
} }

View File

@@ -1,5 +1,5 @@
import { Command } from '../Editor'
import { MarkType } from 'prosemirror-model' import { MarkType } from 'prosemirror-model'
import { Command } from '../Editor'
import getMarkType from '../utils/getMarkType' import getMarkType from '../utils/getMarkType'
import getMarkRange from '../utils/getMarkRange' import getMarkRange from '../utils/getMarkRange'
@@ -16,7 +16,8 @@ declare module '../Editor' {
export const updateMark: UpdateMarkCommand = (typeOrName, attrs = {}) => ({ tr, state }) => { export const updateMark: UpdateMarkCommand = (typeOrName, attrs = {}) => ({ tr, state }) => {
const { selection, doc } = tr const { selection, doc } = tr
let { from, to, $from, empty } = selection let { from, to } = selection
const { $from, empty } = selection
const type = getMarkType(typeOrName, state.schema) const type = getMarkType(typeOrName, state.schema)
if (empty) { if (empty) {

View File

@@ -12,4 +12,4 @@ export default function (regexp: RegExp, type: NodeType, getAttrs?: Function) {
return tr return tr
}) })
} }

View File

@@ -5,13 +5,13 @@ export default function (regexp: RegExp, type: MarkType, getAttrs?: Function) {
const handler = (fragment: Fragment, parent?: any) => { const handler = (fragment: Fragment, parent?: any) => {
const nodes: any[] = [] const nodes: any[] = []
fragment.forEach(child => { fragment.forEach(child => {
if (child.isText && child.text) { if (child.isText && child.text) {
const { text } = child const { text } = child
let pos = 0 let pos = 0
let match let match
// eslint-disable-next-line // eslint-disable-next-line
while ((match = regexp.exec(text)) !== null) { while ((match = regexp.exec(text)) !== null) {
const m = match.length - 1 const m = match.length - 1

View File

@@ -6,4 +6,4 @@ export default (editor: Editor) => new Plugin({
props: { props: {
editable: () => editor.options.editable, editable: () => editor.options.editable,
}, },
}) })

View File

@@ -25,4 +25,4 @@ export default (editor: Editor) => new Plugin({
}, },
}, },
}, },
}) })

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