From 429d16048b80b3d32eeabbe66c812141ff7a0396 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Thu, 3 Apr 2025 09:24:14 -0400 Subject: [PATCH 01/10] highlight selection --- src/rich-text/commands/index.ts | 2 +- src/rich-text/plugins/link-editor.ts | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/src/rich-text/commands/index.ts b/src/rich-text/commands/index.ts index fe8fcea4..a4da5317 100644 --- a/src/rich-text/commands/index.ts +++ b/src/rich-text/commands/index.ts @@ -313,7 +313,7 @@ export function insertRichTextLinkCommand( state.selection.content().content.firstChild?.textContent ?? null; const linkMatch = /^http(s)?:\/\/\S+$/.exec(selectedText); - linkUrl = linkMatch?.length > 0 ? linkMatch[0] : ""; + linkUrl = linkMatch?.length > 0 ? linkMatch[0] : "https://"; } showLinkEditor(view, linkUrl, selectedText); diff --git a/src/rich-text/plugins/link-editor.ts b/src/rich-text/plugins/link-editor.ts index ca2d0b8c..3d2ae778 100644 --- a/src/rich-text/plugins/link-editor.ts +++ b/src/rich-text/plugins/link-editor.ts @@ -195,12 +195,15 @@ export class LinkEditor extends PluginInterfaceView< update(view: EditorView): void { super.update(view); + const state = LINK_EDITOR_KEY.getState(view.state); if (this.isShown) { - const state = LINK_EDITOR_KEY.getState(view.state); if (state?.url) { this.hrefInput.value = state.url; - this.validate(state.url); + + if (state.url != "https://") { + this.validate(state.url); + } } if (state?.text) { @@ -608,7 +611,7 @@ export const linkEditorPlugin = (features: CommonmarkParserFeatures) => shouldShow: false, }; }, - apply(tr, value, _, newState): LinkEditorPluginState { + apply(tr, value, state, newState): LinkEditorPluginState { // check if force hide was set and add to value for getDecorations to use const meta = this.getMeta(tr) || value; if ("forceHideTooltip" in meta) { @@ -616,11 +619,23 @@ export const linkEditorPlugin = (features: CommonmarkParserFeatures) => } // update the linkTooltip and get the decorations - const decorations = value.linkTooltip.getDecorations( + let decorations = value.linkTooltip.getDecorations( value, newState ); + //get decoration for current selection + const sel = state.selection; + let selectionDecoration = null; + + if (sel && sel.from !== sel.to) { + selectionDecoration = Decoration.inline(sel.from, sel.to, + { class: 'bg-black-225' } + ); + decorations = decorations.add(newState.doc, [selectionDecoration]); + } + + return { ...meta, forceHideTooltip: @@ -628,7 +643,7 @@ export const linkEditorPlugin = (features: CommonmarkParserFeatures) => linkTooltip: value.linkTooltip, decorations: decorations, }; - }, + }, }, props: { decorations(state: EditorState) { From 040df65a47fd1ece81f12e14278d914336375c5e Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Fri, 4 Apr 2025 11:47:08 -0400 Subject: [PATCH 02/10] keep track of plugin view visibility --- src/rich-text/plugins/link-editor.ts | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/src/rich-text/plugins/link-editor.ts b/src/rich-text/plugins/link-editor.ts index 3d2ae778..8a685d83 100644 --- a/src/rich-text/plugins/link-editor.ts +++ b/src/rich-text/plugins/link-editor.ts @@ -100,7 +100,8 @@ export class LinkEditor extends PluginInterfaceView< this.viewContainer.addEventListener("reset", (e) => { e.preventDefault(); e.stopPropagation(); - const tr = this.tryHideInterfaceTr(view.state); + let tr = this.tryHideInterfaceTr(view.state); + tr = LINK_EDITOR_KEY.updateVisibility(false, tr); if (tr) { view.dispatch(tr); } @@ -164,6 +165,8 @@ export class LinkEditor extends PluginInterfaceView< text: null, }) || view.state.tr; + tr = LINK_EDITOR_KEY.updateVisibility(false, tr); + // set the text first, inheriting all marks tr = tr.replaceSelectionWith(node, true); @@ -218,8 +221,9 @@ export class LinkEditor extends PluginInterfaceView< this.hrefInput.focus(); } else { this.resetEditor(); - const tr = this.tryHideInterfaceTr(view.state); + let tr = this.tryHideInterfaceTr(view.state); if (tr) { + tr = LINK_EDITOR_KEY.updateVisibility(false, tr); view.dispatch(tr); } } @@ -277,6 +281,11 @@ class LinkEditorPluginKey extends ManagedInterfaceKey { meta.forceHideTooltip = true; return this.setMeta(state.tr, meta); } + updateVisibility(visibility: boolean, trans: Transaction): Transaction { + const meta = trans.getMeta(LINK_EDITOR_KEY) as LinkEditorPluginState; + meta.visible = visibility; + return this.setMeta(trans, meta) + } } /** The plugin key the image uploader plugin is tied to */ @@ -628,7 +637,7 @@ export const linkEditorPlugin = (features: CommonmarkParserFeatures) => const sel = state.selection; let selectionDecoration = null; - if (sel && sel.from !== sel.to) { + if (meta.visible && sel && sel.from !== sel.to) { selectionDecoration = Decoration.inline(sel.from, sel.to, { class: 'bg-black-225' } ); @@ -708,11 +717,13 @@ export function showLinkEditor( url?: string, text?: string ): void { - const tr = LINK_EDITOR_KEY.showInterfaceTr(view.state, { + let tr = LINK_EDITOR_KEY.showInterfaceTr(view.state, { url, text, }); + tr = LINK_EDITOR_KEY.updateVisibility(true, tr); + if (tr) { view.dispatch(tr); } @@ -723,11 +734,13 @@ export function showLinkEditor( * @param view The current editor view */ export function hideLinkEditor(view: EditorView): void { - const tr = LINK_EDITOR_KEY.hideInterfaceTr(view.state, { + let tr = LINK_EDITOR_KEY.hideInterfaceTr(view.state, { url: null, text: null, }); + tr = LINK_EDITOR_KEY.updateVisibility(false, tr); + if (tr) { view.dispatch(tr); } From ff07fc102e941354fdb0dab73b769c8e7096b20d Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Fri, 4 Apr 2025 11:55:44 -0400 Subject: [PATCH 03/10] format --- src/rich-text/plugins/link-editor.ts | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/src/rich-text/plugins/link-editor.ts b/src/rich-text/plugins/link-editor.ts index 8a685d83..6303dbe6 100644 --- a/src/rich-text/plugins/link-editor.ts +++ b/src/rich-text/plugins/link-editor.ts @@ -284,7 +284,7 @@ class LinkEditorPluginKey extends ManagedInterfaceKey { updateVisibility(visibility: boolean, trans: Transaction): Transaction { const meta = trans.getMeta(LINK_EDITOR_KEY) as LinkEditorPluginState; meta.visible = visibility; - return this.setMeta(trans, meta) + return this.setMeta(trans, meta); } } @@ -638,12 +638,13 @@ export const linkEditorPlugin = (features: CommonmarkParserFeatures) => let selectionDecoration = null; if (meta.visible && sel && sel.from !== sel.to) { - selectionDecoration = Decoration.inline(sel.from, sel.to, - { class: 'bg-black-225' } - ); - decorations = decorations.add(newState.doc, [selectionDecoration]); + selectionDecoration = Decoration.inline(sel.from, sel.to, { + class: "bg-black-225", + }); + decorations = decorations.add(newState.doc, [ + selectionDecoration, + ]); } - return { ...meta, @@ -652,7 +653,7 @@ export const linkEditorPlugin = (features: CommonmarkParserFeatures) => linkTooltip: value.linkTooltip, decorations: decorations, }; - }, + }, }, props: { decorations(state: EditorState) { From 143e07912009f87b67e8e05b470db9b90374f390 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Mon, 7 Apr 2025 12:08:58 -0400 Subject: [PATCH 04/10] fix test --- test/rich-text/plugins/link-editor.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/rich-text/plugins/link-editor.test.ts b/test/rich-text/plugins/link-editor.test.ts index 8b86ad6f..9ec8bdc1 100644 --- a/test/rich-text/plugins/link-editor.test.ts +++ b/test/rich-text/plugins/link-editor.test.ts @@ -385,7 +385,7 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe(""); + expect(formValue(updatedUploadContainer, "href")).toBe("https://"); expect(formValue(updatedUploadContainer, "text")).toBe(""); // set the values, then submit the form From 7134c6f3d1ba9bdf68ef1fca82e04afb6da41a99 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Mon, 7 Apr 2025 12:14:04 -0400 Subject: [PATCH 05/10] fix tests --- test/rich-text/plugins/link-editor.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test/rich-text/plugins/link-editor.test.ts b/test/rich-text/plugins/link-editor.test.ts index 9ec8bdc1..bcd490ab 100644 --- a/test/rich-text/plugins/link-editor.test.ts +++ b/test/rich-text/plugins/link-editor.test.ts @@ -224,7 +224,7 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe(""); + expect(formValue(updatedUploadContainer, "href")).toBe("https://"); expect(formValue(updatedUploadContainer, "text")).toBe( "test" ); @@ -249,7 +249,7 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe(""); + expect(formValue(updatedUploadContainer, "href")).toBe("https://"); expect(formValue(updatedUploadContainer, "text")).toBe(""); // set the values, then submit the form From 6d499488ff340ab31c6c35d70f449c4502d8d5b9 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Mon, 7 Apr 2025 13:13:37 -0400 Subject: [PATCH 06/10] add highlight test --- test/rich-text/plugins/link-editor.test.ts | 30 ++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/test/rich-text/plugins/link-editor.test.ts b/test/rich-text/plugins/link-editor.test.ts index bcd490ab..08290fb8 100644 --- a/test/rich-text/plugins/link-editor.test.ts +++ b/test/rich-text/plugins/link-editor.test.ts @@ -136,6 +136,36 @@ describe("link-editor", () => { expect(inputContainer.classList).not.toContain("has-error"); }); + it("should highlight selected text in grey when link editor is open", () => { + view = richTextView( + "highlight this text", + () => pluginContainer, + () => menuContainer + ); + + // Select the text we want to highlight + view.editorView.updateState( + applySelection(view.editorView.state, 0, 19) // Select "highlight this text" + ); + + showLinkEditor(view.editorView); + editor.update(view.editorView); + + const decorations = getDecorations(view.editorView.state); + const decoration = decorations.find(0, 19)[0]; + + expect(decoration).toBeDefined(); // The highlight should exist + + // Verify the selection is styled with a decoration containing the correct class + const editorContent = view.editorView.dom; + const highlightedText = editorContent.querySelector(".bg-black-225"); + + expect(highlightedText).toBeTruthy(); + expect(highlightedText.textContent).toBe("highlight this text"); + + + }); + it("should prefill fields when a link is edited via the tooltip", async () => { view = richTextView( "[link text](https://www.example.com)", From f513eeb1292c3c259cca8a07e1504237ca45f1b6 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Mon, 7 Apr 2025 13:14:24 -0400 Subject: [PATCH 07/10] format --- test/rich-text/plugins/link-editor.test.ts | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/test/rich-text/plugins/link-editor.test.ts b/test/rich-text/plugins/link-editor.test.ts index 08290fb8..34cc547e 100644 --- a/test/rich-text/plugins/link-editor.test.ts +++ b/test/rich-text/plugins/link-editor.test.ts @@ -158,12 +158,11 @@ describe("link-editor", () => { // Verify the selection is styled with a decoration containing the correct class const editorContent = view.editorView.dom; - const highlightedText = editorContent.querySelector(".bg-black-225"); + const highlightedText = + editorContent.querySelector(".bg-black-225"); expect(highlightedText).toBeTruthy(); expect(highlightedText.textContent).toBe("highlight this text"); - - }); it("should prefill fields when a link is edited via the tooltip", async () => { @@ -254,7 +253,9 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe("https://"); + expect(formValue(updatedUploadContainer, "href")).toBe( + "https://" + ); expect(formValue(updatedUploadContainer, "text")).toBe( "test" ); @@ -279,7 +280,9 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe("https://"); + expect(formValue(updatedUploadContainer, "href")).toBe( + "https://" + ); expect(formValue(updatedUploadContainer, "text")).toBe(""); // set the values, then submit the form @@ -415,7 +418,9 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe("https://"); + expect(formValue(updatedUploadContainer, "href")).toBe( + "https://" + ); expect(formValue(updatedUploadContainer, "text")).toBe(""); // set the values, then submit the form From f94e623240e787c78ca9c2b0149ce1213315f6ec Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Wed, 9 Apr 2025 10:09:18 -0400 Subject: [PATCH 08/10] placeholder --- src/rich-text/commands/index.ts | 2 +- src/rich-text/plugins/link-editor.ts | 2 +- test/rich-text/plugins/link-editor.test.ts | 6 +++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/rich-text/commands/index.ts b/src/rich-text/commands/index.ts index a4da5317..fe8fcea4 100644 --- a/src/rich-text/commands/index.ts +++ b/src/rich-text/commands/index.ts @@ -313,7 +313,7 @@ export function insertRichTextLinkCommand( state.selection.content().content.firstChild?.textContent ?? null; const linkMatch = /^http(s)?:\/\/\S+$/.exec(selectedText); - linkUrl = linkMatch?.length > 0 ? linkMatch[0] : "https://"; + linkUrl = linkMatch?.length > 0 ? linkMatch[0] : ""; } showLinkEditor(view, linkUrl, selectedText); diff --git a/src/rich-text/plugins/link-editor.ts b/src/rich-text/plugins/link-editor.ts index 6303dbe6..232a7255 100644 --- a/src/rich-text/plugins/link-editor.ts +++ b/src/rich-text/plugins/link-editor.ts @@ -70,7 +70,7 @@ export class LinkEditor extends PluginInterfaceView< - + diff --git a/test/rich-text/plugins/link-editor.test.ts b/test/rich-text/plugins/link-editor.test.ts index 34cc547e..80b77578 100644 --- a/test/rich-text/plugins/link-editor.test.ts +++ b/test/rich-text/plugins/link-editor.test.ts @@ -254,7 +254,7 @@ describe("link-editor", () => { ); expect(formValue(updatedUploadContainer, "href")).toBe( - "https://" + "" ); expect(formValue(updatedUploadContainer, "text")).toBe( "test" @@ -281,7 +281,7 @@ describe("link-editor", () => { ); expect(formValue(updatedUploadContainer, "href")).toBe( - "https://" + "" ); expect(formValue(updatedUploadContainer, "text")).toBe(""); @@ -419,7 +419,7 @@ describe("link-editor", () => { ); expect(formValue(updatedUploadContainer, "href")).toBe( - "https://" + "" ); expect(formValue(updatedUploadContainer, "text")).toBe(""); From 0d6d888aa0e8696a01eaa63c96ae106fa179a679 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Wed, 9 Apr 2025 10:10:27 -0400 Subject: [PATCH 09/10] remove prefiled text --- src/rich-text/plugins/link-editor.ts | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/rich-text/plugins/link-editor.ts b/src/rich-text/plugins/link-editor.ts index 232a7255..5020b7c6 100644 --- a/src/rich-text/plugins/link-editor.ts +++ b/src/rich-text/plugins/link-editor.ts @@ -203,10 +203,7 @@ export class LinkEditor extends PluginInterfaceView< if (this.isShown) { if (state?.url) { this.hrefInput.value = state.url; - - if (state.url != "https://") { - this.validate(state.url); - } + this.validate(state.url); } if (state?.text) { From 2fe98b5337498195be3b52ae72e4ffece3886881 Mon Sep 17 00:00:00 2001 From: Aliza Berger Date: Wed, 9 Apr 2025 10:11:33 -0400 Subject: [PATCH 10/10] format --- test/rich-text/plugins/link-editor.test.ts | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/test/rich-text/plugins/link-editor.test.ts b/test/rich-text/plugins/link-editor.test.ts index 80b77578..64321067 100644 --- a/test/rich-text/plugins/link-editor.test.ts +++ b/test/rich-text/plugins/link-editor.test.ts @@ -253,9 +253,7 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe( - "" - ); + expect(formValue(updatedUploadContainer, "href")).toBe(""); expect(formValue(updatedUploadContainer, "text")).toBe( "test" ); @@ -280,9 +278,7 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe( - "" - ); + expect(formValue(updatedUploadContainer, "href")).toBe(""); expect(formValue(updatedUploadContainer, "text")).toBe(""); // set the values, then submit the form @@ -418,9 +414,7 @@ describe("link-editor", () => { "form.js-link-editor" ); - expect(formValue(updatedUploadContainer, "href")).toBe( - "" - ); + expect(formValue(updatedUploadContainer, "href")).toBe(""); expect(formValue(updatedUploadContainer, "text")).toBe(""); // set the values, then submit the form