import { Mark, mergeAttributes } from '@tiptap/core'; import type { CommentAttrs } from '../types.js'; interface CommentOptions { HTMLAttributes: Record; } /** * Comment mark — stores inline comments as marks on text ranges. * Each comment has: id, author, timestamp, text. * Rendered as highlighted spans with data attributes for popover display. */ export const Comment = Mark.create({ name: 'comment', addOptions() { return { HTMLAttributes: {}, }; }, addAttributes() { return { commentId: { default: null, parseHTML: (el: HTMLElement) => el.getAttribute('data-comment-id'), renderHTML: (attrs: Record) => ({ 'data-comment-id': attrs.commentId }), }, author: { default: null, parseHTML: (el: HTMLElement) => el.getAttribute('data-comment-author'), renderHTML: (attrs: Record) => ({ 'data-comment-author': attrs.author }), }, timestamp: { default: null, parseHTML: (el: HTMLElement) => el.getAttribute('data-comment-timestamp'), renderHTML: (attrs: Record) => ({ 'data-comment-timestamp': attrs.timestamp }), }, text: { default: null, parseHTML: (el: HTMLElement) => el.getAttribute('data-comment-text'), renderHTML: (attrs: Record) => ({ 'data-comment-text': attrs.text }), }, }; }, parseHTML() { return [ { tag: 'span[data-comment-id]', }, ]; }, renderHTML({ HTMLAttributes }) { return [ 'span', mergeAttributes(this.options.HTMLAttributes, HTMLAttributes, { class: 'comment-mark', }), 0, ]; }, addCommands() { return { setComment: (attrs: CommentAttrs) => ({ commands }) => { return commands.setMark(this.name, attrs); }, unsetComment: () => ({ commands }) => { return commands.unsetMark(this.name); }, }; }, });