rspace-online/modules/rnotes/components/suggestion-marks.ts

102 lines
2.5 KiB
TypeScript

/**
* TipTap mark extensions for track-changes suggestions.
*
* SuggestionInsert: wraps text that was inserted in suggesting mode (green underline).
* SuggestionDelete: wraps text that was marked for deletion in suggesting mode (red strikethrough).
*
* Both marks are stored in the Yjs document and sync in real-time.
* Accept/reject logic is handled by the suggestion-plugin.
*/
import { Mark, mergeAttributes } from '@tiptap/core';
export const SuggestionInsertMark = Mark.create({
name: 'suggestionInsert',
addAttributes() {
return {
suggestionId: { default: null },
authorId: { default: null },
authorName: { default: null },
createdAt: { default: null },
};
},
parseHTML() {
return [
{
tag: 'span[data-suggestion-insert]',
getAttrs: (el) => {
const element = el as HTMLElement;
return {
suggestionId: element.getAttribute('data-suggestion-id'),
authorId: element.getAttribute('data-author-id'),
authorName: element.getAttribute('data-author-name'),
createdAt: Number(element.getAttribute('data-created-at')) || null,
};
},
},
];
},
renderHTML({ HTMLAttributes }) {
return [
'span',
mergeAttributes({
class: 'suggestion-insert',
'data-suggestion-insert': '',
'data-suggestion-id': HTMLAttributes.suggestionId,
'data-author-id': HTMLAttributes.authorId,
'data-author-name': HTMLAttributes.authorName,
'data-created-at': HTMLAttributes.createdAt,
}),
0,
];
},
});
export const SuggestionDeleteMark = Mark.create({
name: 'suggestionDelete',
addAttributes() {
return {
suggestionId: { default: null },
authorId: { default: null },
authorName: { default: null },
createdAt: { default: null },
};
},
parseHTML() {
return [
{
tag: 'span[data-suggestion-delete]',
getAttrs: (el) => {
const element = el as HTMLElement;
return {
suggestionId: element.getAttribute('data-suggestion-id'),
authorId: element.getAttribute('data-author-id'),
authorName: element.getAttribute('data-author-name'),
createdAt: Number(element.getAttribute('data-created-at')) || null,
};
},
},
];
},
renderHTML({ HTMLAttributes }) {
return [
'span',
mergeAttributes({
class: 'suggestion-delete',
'data-suggestion-delete': '',
'data-suggestion-id': HTMLAttributes.suggestionId,
'data-author-id': HTMLAttributes.authorId,
'data-author-name': HTMLAttributes.authorName,
'data-created-at': HTMLAttributes.createdAt,
}),
0,
];
},
});