platform/packages/text-editor/src/changeSet.ts
Alexander Onnikov 89bfabb37d
EZQMS-359 Add update highlight command to nodeHighlight plugin (#3997)
Signed-off-by: Alexander Onnikov <alexander.onnikov@xored.com>
2023-11-17 20:00:13 +07:00

169 lines
4.1 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { Extension, Mark, mergeAttributes } from '@tiptap/core'
import { ChangeSet } from '@tiptap/pm/changeset'
import { Plugin } from '@tiptap/pm/state'
export interface ChangeHighlightOptions {
multicolor: boolean
HTMLAttributes: Record<string, any>
}
declare module '@tiptap/core' {
interface Commands<ReturnType> {
changeHighlight: {
/**
* Set a highlight mark
*/
setChangeHighlight: (attributes?: { color: string }) => ReturnType
/**
* Toggle a highlight mark
*/
toggleChangeHighlight: (attributes?: { color: string }) => ReturnType
/**
* Unset a highlight mark
*/
unsetChangeHighlight: () => ReturnType
}
}
}
export const ChangeHighlight = Mark.create<ChangeHighlightOptions>({
name: 'changeHighlight',
addOptions () {
return {
multicolor: true,
HTMLAttributes: {
changeColor: 'yellow'
}
}
},
addAttributes () {
if (!this.options.multicolor) {
return {}
}
return {
color: {
default: null,
parseHTML: (element) => element.getAttribute('color'),
renderHTML: (attributes) => {
// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions
if (!attributes.color) {
return {}
}
const color = attributes.color as string
return {
color,
style: `border-top: 1px solid ${color}; border-bottom: 1px solid ${color}; border-radius: 2px;`
}
}
}
}
},
parseHTML () {
return [
{
tag: 'cmark'
}
]
},
renderHTML ({ HTMLAttributes }) {
return ['cmark', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes), 0]
},
addCommands () {
return {
setChangeHighlight:
(attributes) =>
({ commands }) => {
return commands.setMark(this.name, attributes)
},
toggleChangeHighlight:
(attributes) =>
({ commands }) => {
return commands.toggleMark(this.name, attributes)
},
unsetChangeHighlight:
() =>
({ commands }) => {
return commands.unsetMark(this.name)
}
}
}
})
export interface ChangesetExtensionOptions {
isSuggestMode: () => boolean
}
export const ChangesetExtension = Extension.create<ChangesetExtensionOptions>({
// addInputRules () {
// return [changeSetRule]
// },
addProseMirrorPlugins () {
return [
new Plugin({
appendTransaction: (_transactions, oldState, newState) => {
// no changes
if (newState.doc === oldState.doc) {
return
}
const tr = newState.tr
if (this.options.isSuggestMode()) {
let changes = ChangeSet.create(oldState.doc)
for (const tr of _transactions) {
changes = changes.addSteps(tr.doc, tr.mapping.maps, undefined)
}
for (const r of changes.changes) {
const from = r.fromB
const to = r.toB
if (r.inserted.length > 0 && from !== to) {
tr.addMark(from, to, newState.schema.marks.changeHighlight.create({ color: 'lightblue' }))
}
if (r.deleted.length > 0) {
const deletedText = oldState.doc.textBetween(r.fromA, r.toA)
tr.insertText(deletedText, from)
tr.addMark(
from,
from + deletedText.length,
newState.schema.marks.changeHighlight.create({ color: 'orange' })
)
}
}
}
return tr
}
})
]
},
onCreate () {
// The editor is ready.
},
onUpdate () {
// The content has changed.
},
// onSelectionUpdate ({ editor }) {
// // The selection has changed.
// },
onTransaction ({ transaction }) {
// The editor state has changed.
},
onFocus ({ event }) {
// The editor is focused.
},
onBlur ({ event }) {
// The editor isnt focused anymore.
},
onDestroy () {
// The editor is being destroyed.
}
})