add focus extension

This commit is contained in:
Philipp Kühn 2020-08-21 17:32:47 +02:00
parent 0513fd6ce2
commit 71c3927b28
6 changed files with 112 additions and 14 deletions

View File

@ -6,6 +6,9 @@ context('focus', () => {
describe('focus class', () => {
it('should have class', () => {
cy.get('.ProseMirror').window().then(window => {
const { editor } = window
editor.focus('start')
cy.get('.ProseMirror p:first').should('have.class', 'has-focus')
})
})

View File

@ -15,7 +15,7 @@ import Italic from '@tiptap/extension-italic'
import Code from '@tiptap/extension-code'
import CodeBlock from '@tiptap/extension-codeblock'
import Heading from '@tiptap/extension-heading'
// import Focus from '@tiptap/extension-focus'
import Focus from '@tiptap/extension-focus'
export default {
components: {
@ -40,12 +40,12 @@ export default {
new Code(),
new CodeBlock(),
new Heading(),
// new Focus({
// className: 'has-focus',
// nested: true,
// }),
new Focus({
className: 'has-focus',
nested: true,
}),
],
// autoFocus: true,
autoFocus: true,
content: `
<p>
With the focus extension you can add custom classes to focused nodes. Default options:
@ -65,14 +65,6 @@ export default {
window.editor = this.editor
},
watch: {
editable() {
this.editor.setOptions({
editable: this.editable,
})
},
},
beforeDestroy() {
this.editor.destroy()
},

View File

@ -22,6 +22,7 @@ import Mark from './Mark'
import EventEmitter from './EventEmitter'
import ComponentRenderer from './ComponentRenderer'
// commands
import clearContent from './commands/clearContent'
import deleteSelection from './commands/deleteSelection'
import focus from './commands/focus'
@ -37,6 +38,9 @@ import toggleMark from './commands/toggleMark'
import toggleNode from './commands/toggleNode'
import updateMark from './commands/updateMark'
// plugins
import focusPlugin from './plugins/focus'
export type Command = (next: Function, editor: Editor) => (...args: any) => any
export interface CommandSpec {
@ -70,6 +74,8 @@ export class Editor extends EventEmitter {
injectCSS: true,
extensions: [],
}
public isFocused = false
public isEditable = true
constructor(options: Partial<EditorOptions> = {}) {
super()
@ -175,6 +181,7 @@ export class Editor extends EventEmitter {
keymap(baseKeymap),
dropCursor(),
gapCursor(),
focusPlugin(this.proxy),
]
}

View File

@ -0,0 +1,28 @@
import { Plugin } from 'prosemirror-state'
import Editor from '../..'
export default (editor: Editor) => new Plugin({
props: {
attributes: {
tabindex: '0',
},
handleDOMEvents: {
focus: () => {
editor.isFocused = true
const transaction = editor.state.tr.setMeta('focused', true)
editor.view.dispatch(transaction)
return true
},
blur: () => {
editor.isFocused = false
const transaction = editor.state.tr.setMeta('focused', false)
editor.view.dispatch(transaction)
return true
},
},
},
})

View File

@ -0,0 +1,50 @@
import { Extension } from '@tiptap/core'
import { Plugin } from 'prosemirror-state'
import { DecorationSet, Decoration } from 'prosemirror-view'
export default class Focus extends Extension {
name = 'focus'
defaultOptions() {
return {
className: 'has-focus',
nested: false,
}
}
plugins() {
return [
new Plugin({
props: {
decorations: ({ doc, plugins, selection }) => {
const { isFocused, isEditable } = this.editor
const isActive = isEditable && this.options.className
const { anchor } = selection
const decorations: Decoration[] = []
if (!isActive || !isFocused) {
return
}
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

@ -0,0 +1,18 @@
{
"name": "@tiptap/extension-focus",
"version": "1.0.0",
"source": "index.ts",
"main": "dist/tiptap-extension-focus.js",
"umd:main": "dist/tiptap-extension-focus.umd.js",
"module": "dist/tiptap-extension-focus.mjs",
"unpkg": "dist/tiptap-extension-focus.js",
"jsdelivr": "dist/tiptap-extension-focus.js",
"files": [
"src",
"dist"
],
"peerDependencies": {
"@tiptap/core": "2.x",
"prosemirror-state": "^1.3.3"
}
}