move history plugin to extension package

This commit is contained in:
Philipp Kühn 2018-08-25 21:33:06 +02:00
parent bf1a091c94
commit deb8cb33b0
21 changed files with 108 additions and 42 deletions

View File

@ -46,7 +46,7 @@ export default {
## Editor Properties
| **Property** | **Type** | **Default** | **Description** |
| --- | :---: | :---: | --- |
| --- | :---: | :---: | --- |
| `editable` | `Boolean` | `true` | When set to `false` the editor is read-only. |
| `doc` | `Object` | `null` | The editor state object used by Prosemirror. You can also pass HTML to the `content` slot. When used both, the `content` slot will be ignored. |
| `extensions` | `Array` | `[]` | A list of extensions used, by the editor. This can be `Nodes`, `Marks` or `Plugins`. |
@ -56,7 +56,7 @@ export default {
By default the editor will only support some boring paragraphs. Other nodes and marks are available as **extensions**. There is a package called `tiptap-extensions` with the most basic nodes, marks and plugins.
### Available Extensions
### Available Extensions
```vue
<template>
@ -84,6 +84,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
export default {
@ -106,6 +107,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
],
}
},
@ -113,12 +115,12 @@ export default {
</script>
```
### Create Custom Extensions
### Create Custom Extensions
The most powerful feature of tiptap is that you can create you own extensions. There are 3 basic types of extensions.
| **Type** | **Description** |
| --- | --- |
| --- | --- |
| `Extension` | The most basic type. It's useful to register some [Prosemirror plugins](https://prosemirror.net/docs/guide/) or some input rules. |
| `Node` | Add a custom node. Nodes are basically block elements like a headline or a paragraph. |
| `Mark` | Add a custom mark. Marks are used to add extra styling or other information to inline content like a strong tag or links. |
@ -126,16 +128,17 @@ The most powerful feature of tiptap is that you can create you own extensions. T
### Extension Class
| **Method** | **Type** | **Default** | **Description** |
| --- | :---: | :---: | --- |
| --- | :---: | :---: | --- |
| `get name()` | `String` | `null` | Define a name for your extension. |
| `get defaultOptions()` | `Object` | `{}` | Define some default options. The options are available as `this.$options`. |
| `get plugins()` | `Array` | `[]` | Define a list of [Prosemirror plugins](https://prosemirror.net/docs/guide/). |
| `get inputRules()` | `Array` | `[]` | Define a list of input rules. |
| `keys({ schema })` | `Object` | `null` | Define some keybindings. |
| `inputRules({ schema })` | `Array` | `[]` | Define a list of input rules. |
### Node|Mark Class
| **Method** | **Type** | **Default** | **Description** |
| --- | :---: | :---: | --- |
| --- | :---: | :---: | --- |
| `get name()` | `String` | `null` | Define a name for your node or mark. |
| `get defaultOptions()` | `Object` | `{}` | Define some default options. The options are available as `this.$options`. |
| `get schema()` | `Object` | `null` | Define a [schema](https://prosemirror.net/docs/guide/#schema). |
@ -154,12 +157,12 @@ import { Node } from 'tiptap'
import { wrappingInputRule, setBlockType, wrapIn } from 'tiptap-commands'
export default class BlockquoteNode extends Node {
// choose a unique name
get name() {
return 'blockquote'
}
// the prosemirror schema object
// take a look at https://prosemirror.net/docs/guide/#schema for a detailed explanation
get schema() {
@ -179,14 +182,14 @@ export default class BlockquoteNode extends Node {
toDOM: () => ['blockquote', { class: 'awesome-blockquote' }, 0],
}
}
// this command will be called from menus to add a blockquote
// `type` is the prosemirror schema object for this blockquote
// `schema` is a collection of all registered nodes and marks
command({ type, schema }) {
return wrapIn(type)
}
// here you can register some shortcuts
// in this case you can create a blockquote with `ctrl` + `>`
keys({ type }) {
@ -194,7 +197,7 @@ export default class BlockquoteNode extends Node {
'Ctrl->': wrapIn(type),
}
}
// a blockquote will be created when you are on a new line and type `>` followed by a space
inputRules({ type }) {
return [
@ -242,7 +245,7 @@ export default class IframeNode extends Node {
}],
}
}
// return a vue component
// this can be an object or an imported component
get view() {
@ -261,7 +264,7 @@ export default class IframeNode extends Node {
methods: {
onChange(event) {
this.url = event.target.value
// update the iframe url
this.updateAttrs({
src: this.url,

View File

@ -132,6 +132,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
export default {
@ -155,6 +156,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
],
}
},

View File

@ -33,6 +33,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
import Iframe from './Iframe.js'
@ -57,6 +58,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
// custom extension
new Iframe(),
],

View File

@ -118,6 +118,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
export default {
@ -141,6 +142,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
],
}
},

View File

@ -53,6 +53,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
export default {
@ -76,6 +77,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
],
linkUrl: null,
linkMenuIsActive: false,

View File

@ -35,6 +35,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
export default {
@ -58,6 +59,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
],
}
},

View File

@ -62,6 +62,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
export default {
@ -85,6 +86,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
],
}
},

View File

@ -32,6 +32,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
export default {
@ -55,6 +56,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
],
}
},

View File

@ -84,6 +84,7 @@ import {
Code,
Italic,
Link,
History,
} from 'tiptap-extensions'
export default {
@ -107,6 +108,7 @@ export default {
new Code(),
new Italic(),
new Link(),
new History(),
],
}
},

View File

@ -20,6 +20,7 @@
"url": "https://github.com/heyscrumpy/tiptap/issues"
},
"dependencies": {
"prosemirror-history": "^1.0.2",
"tiptap": "^0.5.1",
"tiptap-commands": "^0.2.0"
}

View File

@ -0,0 +1,30 @@
import { Extension } from 'tiptap'
import { history, undo, redo } from 'prosemirror-history'
export default class HistoryExtension extends Extension {
get name() {
return 'history'
}
keys() {
const isMac = typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : false
const keymap = {
'Mod-z': undo,
'Shift-Mod-z': redo,
}
if (!isMac) {
keymap['Mod-y'] = redo
}
return keymap
}
get plugins() {
return [
history(),
]
}
}

View File

@ -12,3 +12,5 @@ export { default as Bold } from './marks/Bold'
export { default as Code } from './marks/Code'
export { default as Italic } from './marks/Italic'
export { default as Link } from './marks/Link'
export { default as History } from './extensions/History'

View File

@ -26,7 +26,6 @@
"dependencies": {
"prosemirror-commands": "^1.0.7",
"prosemirror-gapcursor": "^1.0.2",
"prosemirror-history": "^1.0.2",
"prosemirror-inputrules": "^1.0.1",
"prosemirror-keymap": "^1.0.1",
"prosemirror-model": "^1.5.0",

View File

@ -2,7 +2,6 @@ import { EditorState, Plugin } from 'prosemirror-state'
import { EditorView } from 'prosemirror-view'
import { Schema, DOMParser } from 'prosemirror-model'
import { gapCursor } from 'prosemirror-gapcursor'
import { history } from 'prosemirror-history'
import { keymap } from 'prosemirror-keymap'
import { baseKeymap } from 'prosemirror-commands'
import { inputRules } from 'prosemirror-inputrules'
@ -165,7 +164,6 @@ export default {
keymap(builtInKeymap),
keymap(baseKeymap),
gapCursor(),
history(),
new Plugin({
props: {
editable: () => this.editable,

View File

@ -35,6 +35,7 @@ export default class ExtensionManager {
get views() {
return this.extensions
.filter(extension => ['node', 'mark'].includes(extension.type))
.filter(extension => extension.view)
.reduce((views, { name, view }) => ({
...views,
@ -43,30 +44,60 @@ export default class ExtensionManager {
}
keymaps({ schema }) {
return this.extensions
const extensionKeymaps = this.extensions
.filter(extension => ['extension'].includes(extension.type))
.filter(extension => extension.keys)
.map(extension => extension.keys({ schema }))
const nodeMarkKeymaps = this.extensions
.filter(extension => ['node', 'mark'].includes(extension.type))
.filter(extension => extension.keys)
.map(extension => extension.keys({
type: schema[`${extension.type}s`][extension.name],
schema,
}))
.map(keys => keymap(keys))
return [
...extensionKeymaps,
...nodeMarkKeymaps,
].map(keys => keymap(keys))
// return this.extensions
// .filter(extension => ['node', 'mark'].includes(extension.type))
// .filter(extension => extension.keys)
// .map(extension => extension.keys({
// type: schema[`${extension.type}s`][extension.name],
// schema,
// }))
// .map(keys => keymap(keys))
}
inputRules({ schema }) {
return this.extensions
const extensionInputRules = this.extensions
.filter(extension => ['extension'].includes(extension.type))
.filter(extension => extension.inputRules)
.map(extension => extension.inputRules({ schema }))
const nodeMarkInputRules = this.extensions
.filter(extension => ['node', 'mark'].includes(extension.type))
.filter(extension => extension.inputRules)
.map(extension => extension.inputRules({
type: schema[`${extension.type}s`][extension.name],
schema,
}))
.reduce((allInputRules, inputRules) => ([
...allInputRules,
...inputRules,
]), [])
return [
...extensionInputRules,
...nodeMarkInputRules,
].reduce((allInputRules, inputRules) => ([
...allInputRules,
...inputRules,
]), [])
}
commands({ schema, view }) {
return this.extensions
.filter(extension => ['node', 'mark'].includes(extension.type))
.filter(extension => extension.command)
.reduce((commands, { name, type, command }) => ({
...commands,

View File

@ -1,18 +1,10 @@
import { lift, selectParentNode } from 'prosemirror-commands'
import { undo, redo } from 'prosemirror-history'
import { undoInputRule } from 'prosemirror-inputrules'
import isMac from './isMac'
const keymap = {
'Mod-z': undo,
'Shift-Mod-z': undo,
'Mod-BracketLeft': lift,
Backspace: undoInputRule,
Escape: selectParentNode,
}
if (!isMac) {
keymap['Mod-y'] = redo
}
export default keymap

View File

@ -27,4 +27,8 @@ export default class Extension {
return []
}
keys() {
return {}
}
}

View File

@ -2,6 +2,5 @@ export { default as buildMenuActions } from './buildMenuActions'
export { default as builtInKeymap } from './builtInKeymap'
export { default as ComponentView } from './ComponentView'
export { default as initNodeViews } from './initNodeViews'
export { default as isMac } from './isMac'
export { default as menuBubble } from './menuBubble'
export { default as ExtensionManager } from './ExtensionManager'

View File

@ -1 +0,0 @@
export default typeof navigator !== 'undefined' ? /Mac/.test(navigator.platform) : false

View File

@ -22,8 +22,4 @@ export default class Mark extends Extension {
return () => {}
}
keys() {
return {}
}
}

View File

@ -22,8 +22,4 @@ export default class Node extends Extension {
return () => {}
}
keys() {
return {}
}
}