sjdemartini / mui-tiptap

A Material UI (MUI) styled WYSIWYG rich text editor, using Tiptap
MIT License
237 stars 32 forks source link

Link Edit removes marks (font size, bold, italics, etc) for selected link #237

Open maatMa opened 1 week ago

maatMa commented 1 week ago

Describe the bug

After editing a link, the font style is removed.

Content before changing: <p><a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"http://foo.de\"><span style=\"font-size: 30px\">Bar</span></a></p>

Content after changing: <p> <a target=\"_blank\" rel=\"noopener noreferrer nofollow\" href=\"http://foo.de\">Bar/a></p>

The same behaviour is in the TipTap Showcase.

To Reproduce

Add a Link and give it a specific font size. Edit the link, after you saved the changes, the font size is reseted.

Expected behavior

The font style should be kept

System (please complete the following information)

mui-tiptap version: 1.9.1 tiptap version: 2.4.0 Browser: Chrome

sjdemartini commented 1 week ago

Thanks for reporting. This is true of all marks (not just font size), where editing will remove the existing styling. Unfortunately Tiptap doesn't seem to provide any convenient mechanisms to fetch all marks for the selection (https://github.com/ueberdosis/tiptap/discussions/1511), but perhaps there's some way to still avoid this when editing a link.

semanticist21 commented 1 week ago

May solve the issue by getting direct node from selection. It can be replaced text content with transaction in command chain. Would come with two different logic implmented with inserting link and updating link.

I'm not sure It's safe way. I might have chance to look at it later when the issue still pendings.

maatMa commented 1 week ago

Thank you both for your quick responses. I took a look at the bug and tried to add the solution mentioned by @semanticist21.

After reading all the marks from the selected text node and reassigning them inside the insertContent function, I'm able to edit and create new links without losing the current marks. Unfortunately, editing the Text is not possible anymore. It looks like the marks are overriding the updated Text.

I'm actually completely new to the TipTap Api. Maybe you have some good advice.

semanticist21 commented 1 week ago

Thank you both for your quick responses. I took a look at the bug and tried to add the solution mentioned by @semanticist21.

After reading all the marks from the selected text node and reassigning them inside the insertContent function, I'm able to edit and create new links without losing the current marks. Unfortunately, editing the Text is not possible anymore. It looks like the marks are overriding the updated Text.

I'm actually completely new to the TipTap Api. Maybe you have some good advice.

<EditLinkMenuContent
        editor={editor}
        onCancel={editor.commands.closeLinkBubbleMenu}
        onSave={({ text, link }) => {
          editor
            .chain()
            // Make sure if we're updating a link, we update the link for the
            // full link "mark"
            .extendMarkRange("link")
            // Update the link href and its text content
            .command(({ tr, state }) => {
              const existingHref = editor.isActive("link")
                ? (editor.getAttributes("link").href as string)
                : "";

              const { selection, schema } = state;

              if (existingHref) {
                // Get the resolved position from the selection
                const resolvedPos = state.doc.resolve(selection.from);
                const nodeAfter = resolvedPos.nodeAfter;

                if (nodeAfter?.isText) {
                  // Insert new text without changing the link mark
                  tr.insertText(text, selection.from, selection.to);

                  // Set the link separately to ensure the link mark is applied
                  tr.addMark(
                    selection.from,
                    selection.from + text.length,
                    schema.marks.link.create({ href: link })
                  );
                }
              } else {
                const textNode = schema.text(text, [
                  schema.marks.link.create({ href: link }),
                ]);
                tr.insert(selection.from, textNode);
              }

              return true;
            })
            // Note that as of "@tiptap/extension-link" 2.0.0-beta.37 when
            // `autolink` is on (which we want), adding the link mark directly
            // via `insertContent` above wasn't sufficient for the link mark to
            // be applied (though specifying it above is still necessary), so we
            // insert the content there and call `setLink` separately here.
            // Unclear why this separate command is necessary, but it does the
            // trick.
            .setLink({
              href: link,
            })
            // Place the cursor at the end of the link (which requires "focus"
            // to take effect)
            .focus()
            .run();

          editor.commands.closeLinkBubbleMenu();
        }}

in LinkBubbleMenu > index.tsx at line 98, I edited onSave handler like the above.

It will retain styles applied even with text changed, but It will override following styles if different styles exist in the same link. For example,

Link will be changed to Link. Link will be changed to Link. Link will be changed to Link.

maatMa commented 1 week ago

@semanticist21 This solution would work for me. I tried to keep all the marks in my pull request, but it's hard to decide what mark a updated text should get.

But it looks like there is a issue in your code. When you create a link with selected text, the text is duplicated after saving.

semanticist21 commented 1 week ago

@semanticist21 This solution would work for me. I tried to keep all the marks in my pull request, but it's hard to decide what mark a updated text should get.

But it looks like there is a issue in your code. When you create a link with selected text, the text is duplicated after saving.

Sorry for my mistake. In else statement, replace existing code to

const textNode = schema.text(text, [
                  schema.marks.link.create({ href: link }),
                ]);
tr.replaceRangeWith(selection.from, selection.to, textNode);
maatMa commented 1 week ago

Now the text marks are deleted after creating a link.

semanticist21 commented 1 week ago

Can you detail the situation?

maatMa commented 1 week ago

When I try to create a link out of a text with some sort of style, the style disapears after saving.

Before: image

After: image

Here I tried to make a link out of the word "But". The update is working fine btw.

semanticist21 commented 1 week ago

in Else statement

 tr.insertText(text, selection.from, selection.to);

                tr.addMark(
                  selection.from,
                  selection.from + text.length,
                  schema.marks.link.create({ href: link })
                );

I'm a new to tiptap too, please understand. replaceRangeWith seems works differntly than just inserting text into it. I've tested with your case. updating and inserting new link works fine.

maatMa commented 1 week ago

Looks good now. I will commit that to the associated pull request.

maatMa commented 6 days ago

@sjdemartini Would you run the test process again?