add focus extension

This commit is contained in:
Philipp Kühn 2019-07-31 10:10:40 +02:00
parent ae33e76feb
commit c991e1f017
5 changed files with 161 additions and 0 deletions

View File

@ -0,0 +1,97 @@
<template>
<div class="editor">
<editor-content class="editor__content" :editor="editor" />
</div>
</template>
<script>
import Icon from 'Components/Icon'
import { Editor, EditorContent, EditorMenuBar } from 'tiptap'
import {
Blockquote,
CodeBlock,
HardBreak,
Heading,
HorizontalRule,
OrderedList,
BulletList,
ListItem,
TodoItem,
TodoList,
Bold,
Code,
Italic,
Link,
Strike,
Underline,
History,
Focus,
} from 'tiptap-extensions'
export default {
components: {
EditorContent,
EditorMenuBar,
Icon,
},
data() {
return {
editor: new Editor({
extensions: [
new Blockquote(),
new BulletList(),
new CodeBlock(),
new HardBreak(),
new Heading({ levels: [1, 2, 3] }),
new HorizontalRule(),
new ListItem(),
new OrderedList(),
new TodoItem(),
new TodoList(),
new Link(),
new Bold(),
new Code(),
new Italic(),
new Strike(),
new Underline(),
new History(),
new Focus({
className: 'has-focus',
nested: true,
}),
],
autoFocus: true,
content: `
<h2>
Focus classes
</h2>
<p>
With the focus extension you can add custom classes to focused nodes. Default options:
</p>
<pre><code>{\n className: 'has-focus',\n nested: true,\n}</code></pre>
<ul>
<li>
When set <code>nested</code> to <code>true</code> also nested elements like this list item will be captured.
</li>
<li>
Otherwise only the wrapping list will get this class.
</li>
</ul>
`,
}),
}
},
beforeDestroy() {
this.editor.destroy()
},
}
</script>
<style lang="scss">
@import "~variables";
.has-focus {
border-radius: 3px;
box-shadow: 0 0 0 3px #3ea4ffe6;
}
</style>

View File

@ -48,6 +48,9 @@
<router-link class="subnavigation__link" to="/placeholder">
Placeholder
</router-link>
<router-link class="subnavigation__link" to="/focus">
Focus
</router-link>
<router-link class="subnavigation__link" to="/collaboration">
Collaboration
</router-link>

View File

@ -123,6 +123,13 @@ const routes = [
githubUrl: 'https://github.com/scrumpy/tiptap/tree/master/examples/Components/Routes/Placeholder',
},
},
{
path: '/focus',
component: () => import('Components/Routes/Focus'),
meta: {
githubUrl: 'https://github.com/scrumpy/tiptap/tree/master/examples/Components/Routes/Focus',
},
},
{
path: '/collaboration',
component: () => import('Components/Routes/Collaboration'),

View File

@ -0,0 +1,53 @@
import { Extension, Plugin } from 'tiptap'
import { DecorationSet, Decoration } from 'prosemirror-view'
export default class Focus extends Extension {
get name() {
return 'focus'
}
get defaultOptions() {
return {
className: 'has-focus',
nested: false,
}
}
get plugins() {
return [
new Plugin({
props: {
decorations: ({ doc, plugins, selection }) => {
const editablePlugin = plugins.find(plugin => plugin.key.startsWith('editable$'))
const editable = editablePlugin.props.editable()
const active = editable && this.options.className
const { focused } = this.editor
const { anchor } = selection
const decorations = []
if (!active || !focused) {
return false
}
doc.descendants((node, pos) => {
const hasAnchor = anchor >= pos && anchor <= (pos + node.nodeSize)
if (hasAnchor && !node.isText) {
const decoration = Decoration.node(pos, pos + node.nodeSize, {
class: this.options.className,
})
decorations.push(decoration)
}
return this.options.nested
})
return DecorationSet.create(doc, decorations)
},
},
}),
]
}
}

View File

@ -24,6 +24,7 @@ export { default as Strike } from './marks/Strike'
export { default as Underline } from './marks/Underline'
export { default as Collaboration } from './extensions/Collaboration'
export { default as Focus } from './extensions/Focus'
export { default as History } from './extensions/History'
export { default as Placeholder } from './extensions/Placeholder'
export { default as Search } from './extensions/Search'