From 9f6618d72faf17ed4155cdc2f3f42a7793a6eaf5 Mon Sep 17 00:00:00 2001 From: Jonathan Olson Date: Wed, 26 Apr 2023 14:31:14 -0600 Subject: [PATCH] Handle reentrant focus/blur events correctly, see https://github.com/phetsims/scenery/issues/1550 (details below) 1. PDOMTree before/after op uses all Displays, and moves blockFocusCallbacks from Display to BrowserEvents (to catch before batching) 2. Adds EventContext, replaced with Event in many cases, so we can store activeElement (or other future things) from when the event fired 3. Adds a better way of synthesizing fake events (EventContext.createSynthetic()), so that we don't need conditionals on events. Pointer.lastEventContext should be guaranteed once it's set up once. 4. Adds activeElement to SceneryEvent 5. ComboBox ListBox selection doesn't rely on seeing if the box gets focus. We directly focus the item instead instead of the redirection 6. Regenerated phet-io APIs --- js/ComboBox.ts | 2 +- js/ComboBoxListBox.ts | 19 +++++++++---------- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/js/ComboBox.ts b/js/ComboBox.ts index 73c31b89..9dca07e7 100644 --- a/js/ComboBox.ts +++ b/js/ComboBox.ts @@ -354,7 +354,7 @@ export default class ComboBox extends WidthSizable( Node ) { // Clicking on the button toggles visibility of the list box this.button.addListener( () => { this.listBox.visibleProperty.value = !this.listBox.visibleProperty.value; - this.listBox.visibleProperty.value && this.listBox.focus(); + this.listBox.focusListItemNode( property.value ); } ); this.display = null; diff --git a/js/ComboBoxListBox.ts b/js/ComboBoxListBox.ts index 3681c37a..3e872f15 100644 --- a/js/ComboBoxListBox.ts +++ b/js/ComboBoxListBox.ts @@ -220,16 +220,6 @@ export default class ComboBoxListBox extends Panel { // pdom listener for the entire list box this.addInputListener( { - - // When the list box gets focus, transfer focus to the ComboBoxListItemNode that matches property.value. - focus: () => { - if ( this.visible ) { - const listItemNode = this.getListItemNode( property.value ); - listItemNode.supplyOpenResponseOnNextFocus(); - listItemNode.focus(); - } - }, - // Handle keydown keydown: event => { if ( event.domEvent && KeyboardUtils.isAnyKeyEvent( event.domEvent, [ KeyboardUtils.KEY_ESCAPE, KeyboardUtils.KEY_TAB ] ) ) { @@ -324,6 +314,15 @@ export default class ComboBoxListBox extends Panel { return listItemNode; } + /** + * Focuses the ComboBoxListItemNode that corresponds to a specified value + */ + public focusListItemNode( value: T ): void { + const listItemNode = this.getListItemNode( value ); + listItemNode.supplyOpenResponseOnNextFocus(); + listItemNode.focus(); + } + /** * voice the response from selecting a new item Node. The response will differ depending on if the selection * changed the Property.