diff --git a/packages/block-editor/src/components/block-list-appender/index.js b/packages/block-editor/src/components/block-list-appender/index.js index 94cc4505dd0b0..eadb324270223 100644 --- a/packages/block-editor/src/components/block-list-appender/index.js +++ b/packages/block-editor/src/components/block-list-appender/index.js @@ -12,7 +12,6 @@ import { getDefaultBlockName } from '@wordpress/blocks'; /** * Internal dependencies */ -import IgnoreNestedEvents from '../ignore-nested-events'; import DefaultBlockAppender from '../default-block-appender'; import ButtonBlockAppender from '../button-block-appender'; @@ -51,26 +50,10 @@ function BlockListAppender( { ); } - // IgnoreNestedEvents is used to treat interactions within the appender as - // subject to the same conditions as those which occur within nested blocks. - // Notably, this effectively prevents event bubbling to block ancestors - // which can otherwise interfere with the intended behavior of the appender - // (e.g. focus handler on the ancestor block). - // - // A `tabIndex` is used on the wrapping `div` element in order to force a - // focus event to occur when an appender `button` element is clicked. In - // some browsers (Firefox, Safari), button clicks do not emit a focus event, - // which could cause this event to propagate unexpectedly. The `tabIndex` - // ensures that the interaction is captured as a focus, without also adding - // an extra tab stop. - // - // See: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button#Clicking_and_focus return ( - -
- { appender } -
-
+
+ { appender } +
); } diff --git a/packages/block-editor/src/components/ignore-nested-events/index.js b/packages/block-editor/src/components/ignore-nested-events/index.js deleted file mode 100644 index c419d282a7602..0000000000000 --- a/packages/block-editor/src/components/ignore-nested-events/index.js +++ /dev/null @@ -1,95 +0,0 @@ -/** - * External dependencies - */ -import { reduce } from 'lodash'; - -/** - * WordPress dependencies - */ -import { Component, forwardRef, createElement } from '@wordpress/element'; - -/** - * Component which renders a div with passed props applied except the optional - * `childHandledEvents` prop. Event prop handlers are replaced with a proxying - * event handler to capture and prevent events from being handled by ancestor - * `IgnoreNestedEvents` elements by testing the presence of a private property - * assigned on the event object. - * - * Optionally accepts an `childHandledEvents` prop array, which can be used in - * instances where an inner `IgnoreNestedEvents` element exists and the outer - * element should stop propagation but not invoke a callback handler, since it - * would be assumed these are invoked by the child element. - * - * @type {WPComponent} - */ -export class IgnoreNestedEvents extends Component { - constructor() { - super( ...arguments ); - - this.proxyEvent = this.proxyEvent.bind( this ); - - // The event map is responsible for tracking an event type to a React - // component prop name, since it is easy to determine event type from - // a React prop name, but not the other way around. - this.eventMap = {}; - } - - /** - * General event handler which only calls to its original props callback if - * it has not already been handled by a descendant IgnoreNestedEvents. - * - * @param {Event} event Event object. - */ - proxyEvent( event ) { - // Skip if already handled (i.e. assume nested block) - if ( event.nativeEvent._blockHandled ) { - return; - } - - // Assign into the native event, since React will reuse their synthetic - // event objects and this property assignment could otherwise leak. - // - // See: https://reactjs.org/docs/events.html#event-pooling - event.nativeEvent._blockHandled = true; - - // Invoke original prop handler - const propKey = this.eventMap[ event.type ]; - - if ( this.props[ propKey ] ) { - this.props[ propKey ]( event ); - } - } - - render() { - const { childHandledEvents = [], forwardedRef, tagName = 'div', ...props } = this.props; - - const eventHandlers = reduce( [ - ...childHandledEvents, - ...Object.keys( props ), - ], ( result, key ) => { - // Try to match prop key as event handler - const match = key.match( /^on([A-Z][a-zA-Z]+)$/ ); - if ( match ) { - // Re-map the prop to the local proxy handler to check whether - // the event has already been handled. - result[ key ] = this.proxyEvent; - - // Assign event -> propName into an instance variable, so as to - // avoid re-renders which could be incurred either by setState - // or in mapping values to a newly created function. - this.eventMap[ match[ 1 ].toLowerCase() ] = key; - } - - return result; - }, {} ); - - return createElement( tagName, { ref: forwardedRef, ...props, ...eventHandlers } ); - } -} - -const forwardedIgnoreNestedEvents = ( props, ref ) => { - return ; -}; -forwardedIgnoreNestedEvents.displayName = 'IgnoreNestedEvents'; - -export default forwardRef( forwardedIgnoreNestedEvents ); diff --git a/packages/block-editor/src/components/ignore-nested-events/test/index.js b/packages/block-editor/src/components/ignore-nested-events/test/index.js deleted file mode 100644 index 367570c89646e..0000000000000 --- a/packages/block-editor/src/components/ignore-nested-events/test/index.js +++ /dev/null @@ -1,54 +0,0 @@ -/** - * External dependencies - */ -import { shallow } from 'enzyme'; - -/** - * Internal dependencies - */ -import { IgnoreNestedEvents } from '../'; - -describe( 'IgnoreNestedEvents', () => { - it( 'passes props to its rendered div', () => { - const wrapper = shallow( - - ); - - expect( wrapper.type() ).toBe( 'div' ); - expect( wrapper.prop( 'className' ) ).toBe( 'foo' ); - } ); - - it( 'stops propagation of events to ancestor IgnoreNestedEvents', () => { - const spyOuter = jest.fn(); - const spyInner = jest.fn(); - const wrapper = shallow( - - - - ); - - wrapper.childAt( 0 ).simulate( 'click' ); - - expect( spyInner ).toHaveBeenCalled(); - expect( spyOuter ).not.toHaveBeenCalled(); - } ); - - it( 'stops propagation of child handled events', () => { - const spyOuter = jest.fn(); - const spyInner = jest.fn(); - const wrapper = shallow( - - -
- - - - ); - - const div = wrapper.childAt( 0 ).childAt( 0 ); - div.simulate( 'click' ); - - expect( spyInner ).not.toHaveBeenCalled(); - expect( spyOuter ).not.toHaveBeenCalled(); - } ); -} );