From 9ed04caf639017f6c2628a53235e7dac04012813 Mon Sep 17 00:00:00 2001 From: cam Date: Sun, 18 Jan 2026 22:52:13 -0800 Subject: [PATCH 1/4] feat(comments): allow highlight customization --- .../assets/styles/elements/prosemirror.css | 14 +++--- .../src/assets/styles/extensions/comments.css | 2 +- .../src/core/types/EditorConfig.ts | 14 ++++++ .../extensions/comment/comments-helpers.js | 43 +++++++++++++++++-- .../src/extensions/comment/comments-plugin.js | 5 ++- packages/superdoc/src/SuperDoc.vue | 28 ++++++++++-- packages/superdoc/src/core/types/index.js | 15 +++++++ 7 files changed, 105 insertions(+), 16 deletions(-) diff --git a/packages/super-editor/src/assets/styles/elements/prosemirror.css b/packages/super-editor/src/assets/styles/elements/prosemirror.css index 5b806eed6d..b56f7f533f 100644 --- a/packages/super-editor/src/assets/styles/elements/prosemirror.css +++ b/packages/super-editor/src/assets/styles/elements/prosemirror.css @@ -226,21 +226,21 @@ https://github.com/ProseMirror/prosemirror-tables/blob/master/demo/index.html } .ProseMirror .track-insert-dec.highlighted { - border-top: 1px dashed #00853d; - border-bottom: 1px dashed #00853d; - background-color: #399c7222; + border-top: 1px dashed var(--sd-track-insert-border, #00853d); + border-bottom: 1px dashed var(--sd-track-insert-border, #00853d); + background-color: var(--sd-track-insert-bg, #399c7222); } .ProseMirror .track-delete-dec.highlighted { - border-top: 1px dashed #cb0e47; - border-bottom: 1px dashed #cb0e47; - background-color: #cb0e4722; + border-top: 1px dashed var(--sd-track-delete-border, #cb0e47); + border-bottom: 1px dashed var(--sd-track-delete-border, #cb0e47); + background-color: var(--sd-track-delete-bg, #cb0e4722); text-decoration: line-through !important; text-decoration-thickness: 2px !important; } .ProseMirror .track-format-dec.highlighted { - border-bottom: 2px solid gold; + border-bottom: 2px solid var(--sd-track-format-border, gold); } .ProseMirror .track-delete-widget { diff --git a/packages/super-editor/src/assets/styles/extensions/comments.css b/packages/super-editor/src/assets/styles/extensions/comments.css index 567b92fdea..9b4ab407e0 100644 --- a/packages/super-editor/src/assets/styles/extensions/comments.css +++ b/packages/super-editor/src/assets/styles/extensions/comments.css @@ -3,7 +3,7 @@ } .sd-editor-comment-highlight:hover { - background-color: #1354ff55; + background-color: var(--sd-comment-highlight-hover, #1354ff55); } .sd-editor-comment-highlight.sd-custom-selection { diff --git a/packages/super-editor/src/core/types/EditorConfig.ts b/packages/super-editor/src/core/types/EditorConfig.ts index 0ed724ed78..020450298f 100644 --- a/packages/super-editor/src/core/types/EditorConfig.ts +++ b/packages/super-editor/src/core/types/EditorConfig.ts @@ -185,6 +185,20 @@ export interface EditorOptions { /** Whether comments are enabled */ isCommentsEnabled?: boolean; + /** Comment highlight configuration */ + comments?: { + highlightColors?: { + internal?: string; + external?: string; + activeInternal?: string; + activeExternal?: string; + }; + highlightOpacity?: { + active?: number; + inactive?: number; + }; + }; + /** Whether this is a new file */ isNewFile?: boolean; diff --git a/packages/super-editor/src/extensions/comment/comments-helpers.js b/packages/super-editor/src/extensions/comment/comments-helpers.js index ff4969563e..feb062327c 100644 --- a/packages/super-editor/src/extensions/comment/comments-helpers.js +++ b/packages/super-editor/src/extensions/comment/comments-helpers.js @@ -718,10 +718,47 @@ export const translateFormatChangesToEnglish = (attrs = {}) => { * @param {EditorView} param0.editor The current editor view * @returns {String} The color to use for the highlight */ +const DEFAULT_ACTIVE_ALPHA = 0x44 / 0xff; +const DEFAULT_INACTIVE_ALPHA = 0x22 / 0xff; + +const clampOpacity = (value) => { + if (!Number.isFinite(value)) return null; + return Math.max(0, Math.min(1, value)); +}; + +const applyAlphaToHex = (color, opacity) => { + if (typeof color !== 'string') return color; + const match = color.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i); + if (!match) return color; + + const hex = + match[1].length === 3 + ? match[1] + .split('') + .map((c) => c + c) + .join('') + : match[1]; + const alpha = Math.round(opacity * 255) + .toString(16) + .padStart(2, '0'); + return `#${hex}${alpha}`; +}; + export const getHighlightColor = ({ activeThreadId, threadId, isInternal, editor }) => { if (!editor.options.isInternal && isInternal) return 'transparent'; const pluginState = CommentsPluginKey.getState(editor.state); - const color = isInternal ? pluginState.internalColor : pluginState.externalColor; - const alpha = activeThreadId == threadId ? '44' : '22'; - return `${color}${alpha}`; + const highlightColors = editor.options.comments?.highlightColors || {}; + const highlightOpacity = editor.options.comments?.highlightOpacity || {}; + const isActive = activeThreadId == threadId; + + const baseColor = isInternal + ? (highlightColors.internal ?? pluginState.internalColor) + : (highlightColors.external ?? pluginState.externalColor); + + const activeOverride = isInternal ? highlightColors.activeInternal : highlightColors.activeExternal; + if (isActive && activeOverride) return activeOverride; + + const resolvedOpacity = clampOpacity(isActive ? highlightOpacity.active : highlightOpacity.inactive); + const opacity = resolvedOpacity ?? (isActive ? DEFAULT_ACTIVE_ALPHA : DEFAULT_INACTIVE_ALPHA); + return applyAlphaToHex(baseColor, opacity); }; diff --git a/packages/super-editor/src/extensions/comment/comments-plugin.js b/packages/super-editor/src/extensions/comment/comments-plugin.js index 721e2ec2ed..024b7e6fda 100644 --- a/packages/super-editor/src/extensions/comment/comments-plugin.js +++ b/packages/super-editor/src/extensions/comment/comments-plugin.js @@ -314,10 +314,11 @@ export const CommentsPlugin = Extension.create({ state: { init() { + const highlightColors = editor.options.comments?.highlightColors || {}; return { activeThreadId: null, - externalColor: '#B1124B', - internalColor: '#078383', + externalColor: highlightColors.external ?? '#B1124B', + internalColor: highlightColors.internal ?? '#078383', decorations: DecorationSet.empty, allCommentPositions: {}, allCommentIds: [], diff --git a/packages/superdoc/src/SuperDoc.vue b/packages/superdoc/src/SuperDoc.vue index 7b6988885f..faa1e1cfff 100644 --- a/packages/superdoc/src/SuperDoc.vue +++ b/packages/superdoc/src/SuperDoc.vue @@ -105,9 +105,27 @@ const commentsModuleConfig = computed(() => { return config; }); -const superdocStyleVars = computed(() => ({ - '--sd-ui-font-family': uiFontFamily.value, -})); +const superdocStyleVars = computed(() => { + const vars = { + '--sd-ui-font-family': uiFontFamily.value, + }; + + const commentsConfig = proxy.$superdoc.config.modules?.comments; + if (!commentsConfig || commentsConfig === false) return vars; + + if (commentsConfig.highlightHoverColor) { + vars['--sd-comment-highlight-hover'] = commentsConfig.highlightHoverColor; + } + + const trackChangeColors = commentsConfig.trackChangeHighlightColors || {}; + if (trackChangeColors.insertBorder) vars['--sd-track-insert-border'] = trackChangeColors.insertBorder; + if (trackChangeColors.insertBackground) vars['--sd-track-insert-bg'] = trackChangeColors.insertBackground; + if (trackChangeColors.deleteBorder) vars['--sd-track-delete-border'] = trackChangeColors.deleteBorder; + if (trackChangeColors.deleteBackground) vars['--sd-track-delete-bg'] = trackChangeColors.deleteBackground; + if (trackChangeColors.formatBorder) vars['--sd-track-format-border'] = trackChangeColors.formatBorder; + + return vars; +}); // Refs const layers = ref(null); @@ -448,6 +466,10 @@ const editorOptions = (doc) => { isCommentsEnabled: Boolean(commentsModuleConfig.value), isAiEnabled: proxy.$superdoc.config.modules?.ai, slashMenuConfig: proxy.$superdoc.config.modules?.slashMenu, + comments: { + highlightColors: commentsModuleConfig.value?.highlightColors, + highlightOpacity: commentsModuleConfig.value?.highlightOpacity, + }, editorCtor: useLayoutEngine ? PresentationEditor : undefined, onBeforeCreate: onEditorBeforeCreate, onCreate: onEditorCreate, diff --git a/packages/superdoc/src/core/types/index.js b/packages/superdoc/src/core/types/index.js index 79efaa263f..f25b53deaa 100644 --- a/packages/superdoc/src/core/types/index.js +++ b/packages/superdoc/src/core/types/index.js @@ -51,6 +51,21 @@ * currentUser?: User | null, * superdoc?: SuperDoc | null, * }) => boolean | undefined} [comments.permissionResolver] Custom permission resolver for comment actions + * @property {Object} [comments.highlightColors] Comment highlight colors (internal/external and active overrides) + * @property {string} [comments.highlightColors.internal] Base highlight color for internal comments + * @property {string} [comments.highlightColors.external] Base highlight color for external comments + * @property {string} [comments.highlightColors.activeInternal] Active highlight color override for internal comments + * @property {string} [comments.highlightColors.activeExternal] Active highlight color override for external comments + * @property {Object} [comments.highlightOpacity] Comment highlight opacity values (0-1) + * @property {number} [comments.highlightOpacity.active] Opacity for active comment highlight + * @property {number} [comments.highlightOpacity.inactive] Opacity for inactive comment highlight + * @property {string} [comments.highlightHoverColor] Hover highlight color for comment marks + * @property {Object} [comments.trackChangeHighlightColors] Track change highlight colors + * @property {string} [comments.trackChangeHighlightColors.insertBorder] Border color for inserted text highlight + * @property {string} [comments.trackChangeHighlightColors.insertBackground] Background color for inserted text highlight + * @property {string} [comments.trackChangeHighlightColors.deleteBorder] Border color for deleted text highlight + * @property {string} [comments.trackChangeHighlightColors.deleteBackground] Background color for deleted text highlight + * @property {string} [comments.trackChangeHighlightColors.formatBorder] Border color for format change highlight * @property {Object} [ai] AI module configuration * @property {string} [ai.apiKey] Harbour API key for AI features * @property {string} [ai.endpoint] Custom endpoint URL for AI services From bbd8ee725519671d698b412d67523d479f2d6e4a Mon Sep 17 00:00:00 2001 From: cam Date: Sun, 18 Jan 2026 22:54:16 -0800 Subject: [PATCH 2/4] feat(comments): add active track change colors --- packages/superdoc/src/SuperDoc.vue | 11 ++++++----- packages/superdoc/src/core/types/index.js | 6 ++++++ 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/superdoc/src/SuperDoc.vue b/packages/superdoc/src/SuperDoc.vue index faa1e1cfff..16287c6329 100644 --- a/packages/superdoc/src/SuperDoc.vue +++ b/packages/superdoc/src/SuperDoc.vue @@ -118,11 +118,12 @@ const superdocStyleVars = computed(() => { } const trackChangeColors = commentsConfig.trackChangeHighlightColors || {}; - if (trackChangeColors.insertBorder) vars['--sd-track-insert-border'] = trackChangeColors.insertBorder; - if (trackChangeColors.insertBackground) vars['--sd-track-insert-bg'] = trackChangeColors.insertBackground; - if (trackChangeColors.deleteBorder) vars['--sd-track-delete-border'] = trackChangeColors.deleteBorder; - if (trackChangeColors.deleteBackground) vars['--sd-track-delete-bg'] = trackChangeColors.deleteBackground; - if (trackChangeColors.formatBorder) vars['--sd-track-format-border'] = trackChangeColors.formatBorder; + const activeTrackChangeColors = commentsConfig.trackChangeActiveHighlightColors || trackChangeColors; + if (activeTrackChangeColors.insertBorder) vars['--sd-track-insert-border'] = activeTrackChangeColors.insertBorder; + if (activeTrackChangeColors.insertBackground) vars['--sd-track-insert-bg'] = activeTrackChangeColors.insertBackground; + if (activeTrackChangeColors.deleteBorder) vars['--sd-track-delete-border'] = activeTrackChangeColors.deleteBorder; + if (activeTrackChangeColors.deleteBackground) vars['--sd-track-delete-bg'] = activeTrackChangeColors.deleteBackground; + if (activeTrackChangeColors.formatBorder) vars['--sd-track-format-border'] = activeTrackChangeColors.formatBorder; return vars; }); diff --git a/packages/superdoc/src/core/types/index.js b/packages/superdoc/src/core/types/index.js index f25b53deaa..0fb542db5f 100644 --- a/packages/superdoc/src/core/types/index.js +++ b/packages/superdoc/src/core/types/index.js @@ -66,6 +66,12 @@ * @property {string} [comments.trackChangeHighlightColors.deleteBorder] Border color for deleted text highlight * @property {string} [comments.trackChangeHighlightColors.deleteBackground] Background color for deleted text highlight * @property {string} [comments.trackChangeHighlightColors.formatBorder] Border color for format change highlight + * @property {Object} [comments.trackChangeActiveHighlightColors] Active track change highlight colors (defaults to trackChangeHighlightColors) + * @property {string} [comments.trackChangeActiveHighlightColors.insertBorder] Active border color for inserted text highlight + * @property {string} [comments.trackChangeActiveHighlightColors.insertBackground] Active background color for inserted text highlight + * @property {string} [comments.trackChangeActiveHighlightColors.deleteBorder] Active border color for deleted text highlight + * @property {string} [comments.trackChangeActiveHighlightColors.deleteBackground] Active background color for deleted text highlight + * @property {string} [comments.trackChangeActiveHighlightColors.formatBorder] Active border color for format change highlight * @property {Object} [ai] AI module configuration * @property {string} [ai.apiKey] Harbour API key for AI features * @property {string} [ai.endpoint] Custom endpoint URL for AI services From 0b4daa073c48c87d085e77ac8c9abc2a6f9c6f96 Mon Sep 17 00:00:00 2001 From: cam Date: Sun, 18 Jan 2026 22:57:31 -0800 Subject: [PATCH 3/4] test(comments): cover highlight customization --- .../src/extensions/comment/comments.test.js | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/super-editor/src/extensions/comment/comments.test.js b/packages/super-editor/src/extensions/comment/comments.test.js index 73a43f0dbe..687717144d 100644 --- a/packages/super-editor/src/extensions/comment/comments.test.js +++ b/packages/super-editor/src/extensions/comment/comments.test.js @@ -350,6 +350,64 @@ describe('comment helpers', () => { const hidden = getHighlightColor({ activeThreadId: null, threadId: 'thread-3', isInternal: true, editor }); expect(hidden).toBe('transparent'); }); + + it('uses configured highlight colors and opacity for inactive comments', () => { + const editor = { + options: { + isInternal: false, + comments: { + highlightColors: { external: '#112233' }, + highlightOpacity: { inactive: 0.25 }, + }, + }, + state: {}, + }; + vi.spyOn(CommentsPluginKey, 'getState').mockReturnValue({ + internalColor: '#123456', + externalColor: '#abcdef', + }); + + const color = getHighlightColor({ activeThreadId: 'thread-2', threadId: 'thread-1', isInternal: false, editor }); + expect(color).toBe('#11223340'); + }); + + it('uses active highlight override color when provided', () => { + const editor = { + options: { + isInternal: false, + comments: { + highlightColors: { external: '#112233', activeExternal: '#ff0000' }, + }, + }, + state: {}, + }; + vi.spyOn(CommentsPluginKey, 'getState').mockReturnValue({ + internalColor: '#123456', + externalColor: '#abcdef', + }); + + const color = getHighlightColor({ activeThreadId: 'thread-1', threadId: 'thread-1', isInternal: false, editor }); + expect(color).toBe('#ff0000'); + }); + + it('falls back to plugin colors with custom opacity', () => { + const editor = { + options: { + isInternal: false, + comments: { + highlightOpacity: { active: 0.2 }, + }, + }, + state: {}, + }; + vi.spyOn(CommentsPluginKey, 'getState').mockReturnValue({ + internalColor: '#123456', + externalColor: '#abcdef', + }); + + const color = getHighlightColor({ activeThreadId: 'thread-1', threadId: 'thread-1', isInternal: false, editor }); + expect(color).toBe('#abcdef33'); + }); }); describe('comments plugin commands', () => { From 30c0a7d3fe0a1accee50a1d9ffc746cef978e033 Mon Sep 17 00:00:00 2001 From: Nick Bernal Date: Tue, 20 Jan 2026 18:25:57 -0800 Subject: [PATCH 4/4] fix(comments): add docs, types, and tests for highlight helpers --- .../src/core/types/EditorConfig.ts | 47 +++++++++++---- .../extensions/comment/comments-helpers.js | 21 ++++++- .../src/extensions/comment/comments.test.js | 60 +++++++++++++++++++ packages/superdoc/src/SuperDoc.test.js | 56 +++++++++++++++++ packages/superdoc/src/SuperDoc.vue | 5 +- 5 files changed, 173 insertions(+), 16 deletions(-) diff --git a/packages/super-editor/src/core/types/EditorConfig.ts b/packages/super-editor/src/core/types/EditorConfig.ts index 020450298f..959ebde62b 100644 --- a/packages/super-editor/src/core/types/EditorConfig.ts +++ b/packages/super-editor/src/core/types/EditorConfig.ts @@ -100,6 +100,40 @@ export interface PermissionParams { trackedChange?: unknown | null; } +/** + * Comment highlight color configuration + */ +export interface CommentHighlightColors { + /** Base highlight color for internal comments */ + internal?: string; + /** Base highlight color for external comments */ + external?: string; + /** Active highlight color override for internal comments */ + activeInternal?: string; + /** Active highlight color override for external comments */ + activeExternal?: string; +} + +/** + * Comment highlight opacity configuration + */ +export interface CommentHighlightOpacity { + /** Opacity for active comment highlight (0-1) */ + active?: number; + /** Opacity for inactive comment highlight (0-1) */ + inactive?: number; +} + +/** + * Comment configuration options + */ +export interface CommentConfig { + /** Comment highlight colors */ + highlightColors?: CommentHighlightColors; + /** Comment highlight opacity values */ + highlightOpacity?: CommentHighlightOpacity; +} + /** * Editor configuration options */ @@ -186,18 +220,7 @@ export interface EditorOptions { isCommentsEnabled?: boolean; /** Comment highlight configuration */ - comments?: { - highlightColors?: { - internal?: string; - external?: string; - activeInternal?: string; - activeExternal?: string; - }; - highlightOpacity?: { - active?: number; - inactive?: number; - }; - }; + comments?: CommentConfig; /** Whether this is a new file */ isNewFile?: boolean; diff --git a/packages/super-editor/src/extensions/comment/comments-helpers.js b/packages/super-editor/src/extensions/comment/comments-helpers.js index feb062327c..3e88271826 100644 --- a/packages/super-editor/src/extensions/comment/comments-helpers.js +++ b/packages/super-editor/src/extensions/comment/comments-helpers.js @@ -718,15 +718,30 @@ export const translateFormatChangesToEnglish = (attrs = {}) => { * @param {EditorView} param0.editor The current editor view * @returns {String} The color to use for the highlight */ + +/** Default opacity for active comment highlights (0x44/0xff ≈ 0.267) */ const DEFAULT_ACTIVE_ALPHA = 0x44 / 0xff; + +/** Default opacity for inactive comment highlights (0x22/0xff ≈ 0.133) */ const DEFAULT_INACTIVE_ALPHA = 0x22 / 0xff; -const clampOpacity = (value) => { +/** + * Clamps an opacity value to the valid range [0, 1]. + * @param {number} value - The opacity value to clamp + * @returns {number|null} The clamped value, or null if input is not a finite number + */ +export const clampOpacity = (value) => { if (!Number.isFinite(value)) return null; return Math.max(0, Math.min(1, value)); }; -const applyAlphaToHex = (color, opacity) => { +/** + * Applies an alpha/opacity value to a hex color string. + * @param {string} color - Hex color in 3-digit (#abc) or 6-digit (#aabbcc) format + * @param {number} opacity - Opacity value between 0 and 1 + * @returns {string} The color with alpha appended (e.g., #aabbcc44), or original color if invalid format + */ +export const applyAlphaToHex = (color, opacity) => { if (typeof color !== 'string') return color; const match = color.match(/^#([0-9a-f]{3}|[0-9a-f]{6})$/i); if (!match) return color; @@ -749,7 +764,7 @@ export const getHighlightColor = ({ activeThreadId, threadId, isInternal, editor const pluginState = CommentsPluginKey.getState(editor.state); const highlightColors = editor.options.comments?.highlightColors || {}; const highlightOpacity = editor.options.comments?.highlightOpacity || {}; - const isActive = activeThreadId == threadId; + const isActive = activeThreadId === threadId; const baseColor = isInternal ? (highlightColors.internal ?? pluginState.internalColor) diff --git a/packages/super-editor/src/extensions/comment/comments.test.js b/packages/super-editor/src/extensions/comment/comments.test.js index 687717144d..47309e89f6 100644 --- a/packages/super-editor/src/extensions/comment/comments.test.js +++ b/packages/super-editor/src/extensions/comment/comments.test.js @@ -18,6 +18,8 @@ const { prepareCommentsForImport, translateFormatChangesToEnglish, getHighlightColor, + clampOpacity, + applyAlphaToHex, } = CommentHelpers; afterEach(() => { @@ -410,6 +412,64 @@ describe('comment helpers', () => { }); }); +describe('clampOpacity', () => { + it('returns the value when within valid range', () => { + expect(clampOpacity(0.5)).toBe(0.5); + expect(clampOpacity(0)).toBe(0); + expect(clampOpacity(1)).toBe(1); + }); + + it('clamps values below 0 to 0', () => { + expect(clampOpacity(-0.5)).toBe(0); + expect(clampOpacity(-100)).toBe(0); + }); + + it('clamps values above 1 to 1', () => { + expect(clampOpacity(1.5)).toBe(1); + expect(clampOpacity(100)).toBe(1); + }); + + it('returns null for non-finite values', () => { + expect(clampOpacity(NaN)).toBeNull(); + expect(clampOpacity(Infinity)).toBeNull(); + expect(clampOpacity(-Infinity)).toBeNull(); + expect(clampOpacity(undefined)).toBeNull(); + expect(clampOpacity(null)).toBeNull(); + }); +}); + +describe('applyAlphaToHex', () => { + it('applies alpha to 6-digit hex colors', () => { + expect(applyAlphaToHex('#aabbcc', 0.5)).toBe('#aabbcc80'); + expect(applyAlphaToHex('#000000', 1)).toBe('#000000ff'); + expect(applyAlphaToHex('#ffffff', 0)).toBe('#ffffff00'); + }); + + it('expands and applies alpha to 3-digit hex colors', () => { + expect(applyAlphaToHex('#abc', 0.5)).toBe('#aabbcc80'); + expect(applyAlphaToHex('#000', 1)).toBe('#000000ff'); + expect(applyAlphaToHex('#fff', 0.25)).toBe('#ffffff40'); + }); + + it('returns original color for invalid hex formats', () => { + expect(applyAlphaToHex('rgb(255,0,0)', 0.5)).toBe('rgb(255,0,0)'); + expect(applyAlphaToHex('#gg0000', 0.5)).toBe('#gg0000'); + expect(applyAlphaToHex('red', 0.5)).toBe('red'); + expect(applyAlphaToHex('#aabbccdd', 0.5)).toBe('#aabbccdd'); + }); + + it('returns original value for non-string input', () => { + expect(applyAlphaToHex(null, 0.5)).toBeNull(); + expect(applyAlphaToHex(undefined, 0.5)).toBeUndefined(); + expect(applyAlphaToHex(123, 0.5)).toBe(123); + }); + + it('handles case-insensitive hex colors', () => { + expect(applyAlphaToHex('#AABBCC', 0.5)).toBe('#AABBCC80'); + expect(applyAlphaToHex('#AbCdEf', 0.5)).toBe('#AbCdEf80'); + }); +}); + describe('comments plugin commands', () => { const setup = () => { const schema = createCommentSchema(); diff --git a/packages/superdoc/src/SuperDoc.test.js b/packages/superdoc/src/SuperDoc.test.js index 071275cd49..e2f99ab414 100644 --- a/packages/superdoc/src/SuperDoc.test.js +++ b/packages/superdoc/src/SuperDoc.test.js @@ -832,4 +832,60 @@ describe('SuperDoc.vue', () => { expect(setupState.toolsMenuPosition.top).toBeNull(); expect(wrapper.vm.showToolsFloatingMenu).toBeFalsy(); }); + + it('merges partial trackChangeActiveHighlightColors with base colors', async () => { + const superdocStub = createSuperdocStub(); + superdocStub.config.modules.comments = { + trackChangeHighlightColors: { + insertBorder: '#00ff00', + deleteBackground: '#0000ff', + }, + trackChangeActiveHighlightColors: { + insertBorder: '#ff0000', // only override this one + }, + }; + + const wrapper = await mountComponent(superdocStub); + await nextTick(); + + const styleVars = wrapper.vm.superdocStyleVars; + + // Active insertBorder should be overridden + expect(styleVars['--sd-track-insert-border']).toBe('#ff0000'); + // deleteBackground should be inherited from base config + expect(styleVars['--sd-track-delete-bg']).toBe('#0000ff'); + }); + + it('sets track change CSS vars from base config when no active config provided', async () => { + const superdocStub = createSuperdocStub(); + superdocStub.config.modules.comments = { + trackChangeHighlightColors: { + insertBorder: '#11ff11', + deleteBorder: '#ff1111', + formatBorder: '#1111ff', + }, + }; + + const wrapper = await mountComponent(superdocStub); + await nextTick(); + + const styleVars = wrapper.vm.superdocStyleVars; + + expect(styleVars['--sd-track-insert-border']).toBe('#11ff11'); + expect(styleVars['--sd-track-delete-border']).toBe('#ff1111'); + expect(styleVars['--sd-track-format-border']).toBe('#1111ff'); + }); + + it('sets comment highlight hover color CSS var', async () => { + const superdocStub = createSuperdocStub(); + superdocStub.config.modules.comments = { + highlightHoverColor: '#abcdef88', + }; + + const wrapper = await mountComponent(superdocStub); + await nextTick(); + + const styleVars = wrapper.vm.superdocStyleVars; + expect(styleVars['--sd-comment-highlight-hover']).toBe('#abcdef88'); + }); }); diff --git a/packages/superdoc/src/SuperDoc.vue b/packages/superdoc/src/SuperDoc.vue index 16287c6329..6c481c45b0 100644 --- a/packages/superdoc/src/SuperDoc.vue +++ b/packages/superdoc/src/SuperDoc.vue @@ -118,7 +118,10 @@ const superdocStyleVars = computed(() => { } const trackChangeColors = commentsConfig.trackChangeHighlightColors || {}; - const activeTrackChangeColors = commentsConfig.trackChangeActiveHighlightColors || trackChangeColors; + const activeTrackChangeColors = { + ...trackChangeColors, + ...(commentsConfig.trackChangeActiveHighlightColors || {}), + }; if (activeTrackChangeColors.insertBorder) vars['--sd-track-insert-border'] = activeTrackChangeColors.insertBorder; if (activeTrackChangeColors.insertBackground) vars['--sd-track-insert-bg'] = activeTrackChangeColors.insertBackground; if (activeTrackChangeColors.deleteBorder) vars['--sd-track-delete-border'] = activeTrackChangeColors.deleteBorder;