WordPress / gutenberg

The Block Editor project for WordPress and beyond. Plugin is available from the official repository.
https://wordpress.org/gutenberg/
Other
10.53k stars 4.21k forks source link

LinkControl crashing block in Pattern Editor #65874

Open StYankov opened 1 month ago

StYankov commented 1 month ago

Description

The LinkControl component from the @wordpress/block-editor package does not work as expected when used inside the Pattern Editor. The block crashes with some JS errors in the console: Image

Here's the error with SCRIPT_DEBUG set to true Image

Step-by-step reproduction instructions

Steps to Reproduce

  1. Create a Pattern with a block that contains a LinkControl Image

  2. Open Pattern Editor

  3. Open the Pattern with the LinkControlImage

All I know is that the error is caused by the useCopyToClipboard hook inside used by LinkPreview component internally in LinkControl. I tried installing the Gutenberg Plugin 19.3 but it still crashes.

Screenshots, screen recording, code snippet

I created a simple test repo with WP and a theme with block that contains a LinkControl to reproduce the issue: repo block edit.js

Environment info

WordPress Version: 6.6.2 Browser: Chrome 127

Please confirm that you have searched existing issues in the repo.

Please confirm that you have tested with all plugins deactivated except Gutenberg.

UPDATE: The issue appears after WP 6.5. Before that the example block doesn't crash in the Pattern Editor. Update: Added a comment describing the problem and a possible solution

github-actions[bot] commented 2 weeks ago

Hi, This issue has gone 30 days without any activity. This means it is time for a check-in to make sure it is still relevant. If you are still experiencing this issue with the latest versions, you can help the project by responding to confirm the problem and by providing any updated reproduction steps. Thanks for helping out.

StYankov commented 2 weeks ago

Hello. I have some progress with the investigation of the issue. Here's what I found. In Gutenberg v17.6 a new feature was added to the component through this commit (PR #58170) . Here a new "Copy to Clipboard" button is added in the LinkPreview component used internally in the LinkControl. The feature itself works great in the normal editor for pages/posts and so on.

The issue happens only in the Patterns Editor and here's why: The copy to clipboard functionality is performed through the useCopyToClipboard hook from @wordpress/compose The useCopyToClipboard hook uses clipboard.js npm library (code reference).
clipboard.js uses the good-listener npm library to attach the click event to the button (code reference).

Before good-listener attached the event to the node it does some checks to ensure that the passed target is valid. Here's where it get's wrong: This check is.node(target) always returns false.

Here's how the is.node expanded:

exports.node = function(value) {
    return value !== undefined
        && value instanceof HTMLElement
        && value.nodeType === 1;
};

At first sight it shouldn't return false because: a) value is not undefined. It's a <button> b) HTMLButtonElement is an instance of HTMLElement c) value.nodeType === 1

However, the pattern editor is rendered inside an iframe. Thus the check value instanceof HTMLElement checks if the value is instance of iframe's parent window.HTMLElement instead of the iframe's window.HTMLElement which will always be false. Image

After the target validity check is made and the target is deemed invalid the clipboard.js throws an Error and breaks the component.

Possible fixes I don't think we have any chance of changing the good-listener npm library to add support for iframes. The last update has been 7 years ago and it seems to be abandoned/not maintained anymore. Another approach would be to enable this "Copy to clipboard" feature only in the block editor. It will not be rendered in the patterns editor and the error should be fixed.

Mamaduka commented 2 weeks ago

cc @draganescu, @getdave

getdave commented 2 weeks ago

Thanks for reporting this.

I wasn't able to replicate. I created a Pattern containing a Button block but saw no error when trying to edit the original of the Pattern.

Is there anything else I missed here?

StYankov commented 2 weeks ago

@getdave Hello and thank you for your time. You are right that when you create a paragraph with a link for example it works in the pattern editor. With further testing I discovered that the inline links in Paragraphs or Buttons are places inside a Popover component. What this does it it moves the LinkControl component outside the iframe. This way the is.node check passes because the HTMLElement is from the right context (The host page). Image

So maybe the solution would be to always wrap the LinkControl inside a Popover if we want it to work inside the Pattern Editor ?

Here's an example where it breaks EXAMPLE (It's a custom component)

getdave commented 2 weeks ago

@StYankov Thanks for narrowing down the cause. LinkControl should ideally be useable within the iframe. So this is a bug but as you say one that is very difficult to fix due to the dependency graph.

getdave commented 2 weeks ago

Looks like there are a lot of usages of copyToClipboard() see here which means this bug might also manifest for those situations.