Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Consider to find a solid way to avoid events conflicts with nested components #1973

Closed
afercia opened this issue Jul 21, 2017 · 6 comments
Closed
Labels
[Type] Bug An existing feature does not function as intended [Type] Developer Documentation Documentation for developers
Milestone

Comments

@afercia
Copy link
Contributor

afercia commented Jul 21, 2017

DOM events (especially keyboard events since a single keypress has many different events that fire) when used on multiple and nested components may lead to unexpected behaviors. For example, while working on the DropDown menu currently used in the table block:

screen shot 2017-07-21 at 15 20 40

at first, I couldn't realize why pressing Escape when the menu is open closed the menu and also made the whole toolbar disappear. Turns out the VisualEditorBlock component is using a few events including keydown and keyup.

At the same time, the menu is using keydown and it's correctly preventing its propagation. However, when pressing and releasing Escape, that's also a keyup event that propagates to the block, making the toolbar disappear.

With nested components, this kind of behaviors might happen in other scenarios too, leading to unexpected behaviors and time spent in debugging.

There are solutions, but not so ideal because ideally any component should be "isolated" and work outside of the box without having the need to have some knowledge about other components.

See also https://wordpress.slack.com/archives/C02QB2JS7/p1500643535380467.

Trying to find a solid high-level solution for the future would be great.

@jeffpaul jeffpaul added the [Type] Bug An existing feature does not function as intended label Jan 18, 2018
@jeffpaul jeffpaul added this to the Needs to happen milestone Jan 18, 2018
@afercia
Copy link
Contributor Author

afercia commented Mar 8, 2018

I understand this issue is too generic. I’d rather consider to mention this as a best practice in the documentation for plugin authors.

@jeffpaul
Copy link
Member

This ticket was mentioned in Slack in #core-editor by jeffpaul. View the logs.

@jeffpaul jeffpaul added the [Type] Developer Documentation Documentation for developers label Mar 15, 2018
@jeffpaul jeffpaul modified the milestones: Merge Proposal, Feature Complete Mar 15, 2018
@mtias mtias modified the milestones: Feature Complete, Merge Proposal: Editor Apr 12, 2018
@noisysocks
Copy link
Member

I've definitely noticed that bugs due to a missing event.stopPropagation() keep popping up.

It would be nice to have a generic solution to this. I don't think we can use portals because having a component render outside of its parent's DOM will break styling in a lot of cases.

Maybe a component that stops its children from propagating key and form events would suffice?

function stopEventPropagation( event ) {
	event.stopPropagation();
}

function EventBoundary( { children } ) {
	return (
		<div
			// Key events
			onKeyDown={ stopEventPropagation }
			onKeyPress={ stopEventPropagation }
			onKeyUp={ stopEventPropagation }

			// Form events
			onChange={ stopEventPropagation }
			onInput={ stopEventPropagation }
			onInvalid={ stopEventPropagation }
			onSubmit={ stopEventPropagation }
		>
			{ children }
		</div>
	);
}

// Usage:

<EventBoundary>
    <input type="text" placeholder="Go ahead, press arrow keys in me" />
</EventBoundary>

Alternatively, we could try to make <ObserveTyping> smarter in some cases. For example, we might not trigger startTyping() if the event target is nested within a <Toolbar> or <InspectorControl>.

I recall @aduth worked on something to do with ignoring descendent events which might also help here.

@aduth
Copy link
Member

aduth commented Apr 19, 2018

This is what the IgnoreNestedEvents component is meant to achieve. But it's also a very challenging problem, with subtleties like those discovered at #5658 (comment) and #5289.

@designsimply
Copy link
Member

I couldn't realize why pressing Escape when the menu is open closed the menu and also made the whole toolbar disappear.

I tested just now with Firefox 61.0.1 on macOS 10.13.6 and found that the escape key correctly closes toolbar dropdown without closing the toolbar. (24s)

With nested components, this kind of behaviors might happen in other scenarios too, leading to unexpected behaviors and time spent in debugging.

@afercia I also tested a table block nested inside a columns block and didn't see the problem there either. I am going to close this issue because it seems resolved based on my testing today. Please do let me know if you can think of additional scenarios to test and I'll re-open. 🙂

@afercia
Copy link
Contributor Author

afercia commented Jul 24, 2018

@designsimply agree. It's my opinion that we'll see more errors like these ones though. At the very least there should be a recommendation to always stop events propagation. This should be clearly explained in the documentation. As noted above, a built-in solution would be nice.

Tug pushed a commit that referenced this issue Mar 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
[Type] Bug An existing feature does not function as intended [Type] Developer Documentation Documentation for developers
Projects
None yet
Development

No branches or pull requests

6 participants