From 68a226d8844f8ae8e11a3b507899e7d0a58c3c7c Mon Sep 17 00:00:00 2001 From: Simon Bates Date: Wed, 21 May 2025 10:48:41 -0400 Subject: [PATCH] GH-547: Maintain focus after changing language * In LanguageSelector, use React.forwardRef() to enable users of LanguageSelector to obtain a ref to the LanguageSelector button * Add 2 new instance properties to App: 'languageSelectorRef', a ref to the language selector (forwarded to the button, as above), and 'focusLanguageSelector', a boolean to indicate that focus should be set on the language selector * Add a new language change handler to App that sets 'focusLanguageSelector' when the language is changed and new code to 'componentDidUpdate()' to check 'focusLanguageSelector' and set focus if requested --- src/App.js | 30 ++++++++++++++++++++++++++++-- src/LanguageSelector.js | 21 ++++++++++++--------- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/App.js b/src/App.js index 804a463c..d22842f9 100644 --- a/src/App.js +++ b/src/App.js @@ -145,6 +145,7 @@ export class App extends React.Component { customBackgroundSerializer: CustomBackgroundSerializer; speedLookUp: Array; pushStateTimeoutID: ?TimeoutID; + languageSelectorRef: { current: any }; programBlockEditorRef: { current: any }; sequenceInProgress: Array; announcementBuilder: AnnouncementBuilder; @@ -152,6 +153,7 @@ export class App extends React.Component { designModeCursorDescriptionBuilder: DesignModeCursorDescriptionBuilder; programChangeController: ProgramChangeController; defaultWorld: WorldName; + focusLanguageSelector: boolean; constructor(props: any) { super(props); @@ -180,6 +182,8 @@ export class App extends React.Component { this.defaultWorld = 'Sketchpad'; + this.focusLanguageSelector = false; + // Initialize startingX, startingY, and startingDirection to the world starting position const startingX = getWorldProperties(this.defaultWorld).startingX; const startingY = getWorldProperties(this.defaultWorld).startingY; @@ -247,6 +251,8 @@ export class App extends React.Component { this.programChangeController = new ProgramChangeController(this, this.audioManager); + this.languageSelectorRef = React.createRef(); + this.programBlockEditorRef = React.createRef(); const actionsHandler = new ActionsHandler(this, this.audioManager, @@ -333,6 +339,15 @@ export class App extends React.Component { // Handlers + handleChangeLanguage = (language: LanguageTag) => { + // Changing the language will cause the App to update and for focus to + // be lost. Set this.focusLanguageSelector to true to indicate that we + // want to set focus back to the language selector after the update. + this.focusLanguageSelector = true; + // Call the provided handler + this.props.onChangeLanguage(language); + }; + handleProgramSequenceChange = (programSequence: ProgramSequence) => { this.setState({ programSequence: programSequence @@ -1278,7 +1293,8 @@ export class App extends React.Component {
); } -}; +); + +export default LanguageSelector;