Full document, spreadsheet, slideshow, and diagram tooling
1import { Mark, mergeAttributes } from '@tiptap/core';
2import type { SuggestionMarkAttrs } from '../types.js';
3
4interface SuggestionInsertOptions {
5 HTMLAttributes: Record<string, string>;
6}
7
8/**
9 * Suggestion Insert mark — tracks suggested insertions.
10 * Rendered as underlined text with author color.
11 */
12export const SuggestionInsert = Mark.create<SuggestionInsertOptions>({
13 name: 'suggestionInsert',
14
15 addOptions() {
16 return {
17 HTMLAttributes: {},
18 };
19 },
20
21 addAttributes() {
22 return {
23 suggestionId: {
24 default: null,
25 parseHTML: (el: HTMLElement) => el.getAttribute('data-suggestion-id'),
26 renderHTML: (attrs: Record<string, string | null>) => ({ 'data-suggestion-id': attrs.suggestionId }),
27 },
28 author: {
29 default: null,
30 parseHTML: (el: HTMLElement) => el.getAttribute('data-suggestion-author'),
31 renderHTML: (attrs: Record<string, string | null>) => ({ 'data-suggestion-author': attrs.author }),
32 },
33 timestamp: {
34 default: null,
35 parseHTML: (el: HTMLElement) => el.getAttribute('data-suggestion-timestamp'),
36 renderHTML: (attrs: Record<string, string | null>) => ({ 'data-suggestion-timestamp': attrs.timestamp }),
37 },
38 };
39 },
40
41 parseHTML() {
42 return [
43 { tag: 'span[data-suggestion-id][data-suggestion-type="insert"]' },
44 { tag: 'span.suggestion-insert' },
45 ];
46 },
47
48 renderHTML({ HTMLAttributes }) {
49 return [
50 'span',
51 mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, {
52 class: 'suggestion-insert',
53 'data-suggestion-type': 'insert',
54 }),
55 0,
56 ];
57 },
58
59 addCommands() {
60 return {
61 setSuggestionInsert: (attrs: SuggestionMarkAttrs) => ({ commands }) => {
62 return commands.setMark(this.name, attrs);
63 },
64 unsetSuggestionInsert: () => ({ commands }) => {
65 return commands.unsetMark(this.name);
66 },
67 };
68 },
69});