mirror of
https://github.com/ueberdosis/tiptap.git
synced 2024-12-15 11:09:01 +08:00
move highlight plugin to its own file
This commit is contained in:
parent
59d37f5697
commit
71ab0e0c9d
@ -27,3 +27,4 @@ export { default as History } from './extensions/History'
|
||||
export { default as Placeholder } from './extensions/Placeholder'
|
||||
|
||||
export { default as Suggestions } from './plugins/Suggestions'
|
||||
export { default as Highlight } from './plugins/Highlight'
|
||||
|
@ -1,65 +1,7 @@
|
||||
import { Node, Plugin } from 'tiptap'
|
||||
import { Decoration, DecorationSet } from 'prosemirror-view'
|
||||
import { toggleBlockType, setBlockType, textblockTypeInputRule } from 'tiptap-commands'
|
||||
import { findBlockNodes } from 'prosemirror-utils'
|
||||
import { Node } from 'tiptap'
|
||||
import low from 'lowlight/lib/core'
|
||||
|
||||
function getDecorations(doc) {
|
||||
const decorations = []
|
||||
|
||||
const blocks = findBlockNodes(doc)
|
||||
.filter(item => item.node.type.name === 'code_block')
|
||||
|
||||
const flatten = list => list.reduce(
|
||||
(a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [],
|
||||
)
|
||||
|
||||
function parseNodes(nodes, className = []) {
|
||||
return nodes.map(node => {
|
||||
|
||||
const classes = [
|
||||
...className,
|
||||
...node.properties ? node.properties.className : [],
|
||||
]
|
||||
|
||||
if (node.children) {
|
||||
return parseNodes(node.children, classes)
|
||||
}
|
||||
|
||||
return {
|
||||
text: node.value,
|
||||
classes,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
blocks.forEach(block => {
|
||||
let startPos = block.pos + 1
|
||||
const nodes = low.highlightAuto(block.node.textContent).value
|
||||
|
||||
flatten(parseNodes(nodes))
|
||||
.map(node => {
|
||||
const from = startPos
|
||||
const to = from + node.text.length
|
||||
|
||||
startPos = to
|
||||
|
||||
return {
|
||||
...node,
|
||||
from,
|
||||
to,
|
||||
}
|
||||
})
|
||||
.forEach(node => {
|
||||
const decoration = Decoration.inline(node.from, node.to, {
|
||||
class: node.classes.join(' '),
|
||||
})
|
||||
decorations.push(decoration)
|
||||
})
|
||||
})
|
||||
|
||||
return DecorationSet.create(doc, decorations)
|
||||
}
|
||||
import { toggleBlockType, setBlockType, textblockTypeInputRule } from 'tiptap-commands'
|
||||
import HighlightPlugin from '../plugins/Highlight'
|
||||
|
||||
export default class CodeBlockHighlight extends Node {
|
||||
|
||||
@ -74,16 +16,16 @@ export default class CodeBlockHighlight extends Node {
|
||||
}
|
||||
}
|
||||
|
||||
get name() {
|
||||
return 'code_block'
|
||||
}
|
||||
|
||||
get defaultOptions() {
|
||||
return {
|
||||
languages: {},
|
||||
}
|
||||
}
|
||||
|
||||
get name() {
|
||||
return 'code_block'
|
||||
}
|
||||
|
||||
get schema() {
|
||||
return {
|
||||
content: 'text*',
|
||||
@ -117,31 +59,7 @@ export default class CodeBlockHighlight extends Node {
|
||||
|
||||
get plugins() {
|
||||
return [
|
||||
new Plugin({
|
||||
state: {
|
||||
init(_, { doc }) {
|
||||
return getDecorations(doc)
|
||||
},
|
||||
apply(transaction, decorationSet, oldState, state) {
|
||||
// TODO: find way to cache decorations
|
||||
// see: https://discuss.prosemirror.net/t/how-to-update-multiple-inline-decorations-on-node-change/1493
|
||||
|
||||
const nodeName = state.selection.$head.parent.type.name
|
||||
const previousNodeName = oldState.selection.$head.parent.type.name
|
||||
|
||||
if (transaction.docChanged && [nodeName, previousNodeName].includes('code_block')) {
|
||||
return getDecorations(transaction.doc)
|
||||
}
|
||||
|
||||
return decorationSet.map(transaction.mapping, transaction.doc)
|
||||
},
|
||||
},
|
||||
props: {
|
||||
decorations(state) {
|
||||
return this.getState(state)
|
||||
},
|
||||
},
|
||||
}),
|
||||
HighlightPlugin({ name: this.name }),
|
||||
]
|
||||
}
|
||||
|
||||
|
85
packages/tiptap-extensions/src/plugins/Highlight.js
Normal file
85
packages/tiptap-extensions/src/plugins/Highlight.js
Normal file
@ -0,0 +1,85 @@
|
||||
import { Plugin, PluginKey } from 'tiptap'
|
||||
import { Decoration, DecorationSet } from 'prosemirror-view'
|
||||
import { findBlockNodes } from 'prosemirror-utils'
|
||||
import low from 'lowlight/lib/core'
|
||||
|
||||
function getDecorations({ doc, name }) {
|
||||
const decorations = []
|
||||
const blocks = findBlockNodes(doc).filter(item => item.node.type.name === name)
|
||||
const flatten = list => list.reduce(
|
||||
(a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [],
|
||||
)
|
||||
|
||||
function parseNodes(nodes, className = []) {
|
||||
return nodes.map(node => {
|
||||
|
||||
const classes = [
|
||||
...className,
|
||||
...node.properties ? node.properties.className : [],
|
||||
]
|
||||
|
||||
if (node.children) {
|
||||
return parseNodes(node.children, classes)
|
||||
}
|
||||
|
||||
return {
|
||||
text: node.value,
|
||||
classes,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
blocks.forEach(block => {
|
||||
let startPos = block.pos + 1
|
||||
const nodes = low.highlightAuto(block.node.textContent).value
|
||||
|
||||
flatten(parseNodes(nodes))
|
||||
.map(node => {
|
||||
const from = startPos
|
||||
const to = from + node.text.length
|
||||
|
||||
startPos = to
|
||||
|
||||
return {
|
||||
...node,
|
||||
from,
|
||||
to,
|
||||
}
|
||||
})
|
||||
.forEach(node => {
|
||||
const decoration = Decoration.inline(node.from, node.to, {
|
||||
class: node.classes.join(' '),
|
||||
})
|
||||
decorations.push(decoration)
|
||||
})
|
||||
})
|
||||
|
||||
return DecorationSet.create(doc, decorations)
|
||||
}
|
||||
|
||||
export default function HighlightPlugin({ name }) {
|
||||
return new Plugin({
|
||||
name: new PluginKey('highlight'),
|
||||
state: {
|
||||
init: (_, { doc }) => getDecorations({ doc, name }),
|
||||
apply: (transaction, decorationSet, oldState, state) => {
|
||||
// TODO: find way to cache decorations
|
||||
// see: https://discuss.prosemirror.net/t/how-to-update-multiple-inline-decorations-on-node-change/1493
|
||||
|
||||
const nodeName = state.selection.$head.parent.type.name
|
||||
const previousNodeName = oldState.selection.$head.parent.type.name
|
||||
|
||||
if (transaction.docChanged && [nodeName, previousNodeName].includes(name)) {
|
||||
return getDecorations({ doc: transaction.doc, name })
|
||||
}
|
||||
|
||||
return decorationSet.map(transaction.mapping, transaction.doc)
|
||||
},
|
||||
},
|
||||
props: {
|
||||
decorations(state) {
|
||||
return this.getState(state)
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
Loading…
Reference in New Issue
Block a user