diff --git a/spec/text-editor-component-spec.js b/spec/text-editor-component-spec.js index 008b804f5..1fcb8b3c7 100644 --- a/spec/text-editor-component-spec.js +++ b/spec/text-editor-component-spec.js @@ -312,6 +312,20 @@ describe('TextEditorComponent', () => { jasmine.attachToDOM(parent) expect(document.activeElement).toBe(component.refs.hiddenInput) }) + + it('gracefully handles a focus event that occurs prior to detecting the element has become visible', async () => { + assertDocumentFocused() + + const {component, element, editor} = buildComponent({attach: false}) + element.style.display = 'none' + jasmine.attachToDOM(element) + element.style.display = 'block' + console.log('focus in test'); + element.focus() + await component.getNextUpdatePromise() + + expect(document.activeElement).toBe(component.refs.hiddenInput) + }) }) describe('autoscroll on cursor movement', () => { diff --git a/src/text-editor-component.js b/src/text-editor-component.js index 1c0511d70..45a1092f4 100644 --- a/src/text-editor-component.js +++ b/src/text-editor-component.js @@ -676,6 +676,12 @@ class TextEditorComponent { // against that case. if (!this.attached) this.didAttach() + // The element can be focused before the intersection observer detects that + // it has been shown for the first time. If this element is being focused, + // it is necessarily visible, so we call `didShow` to ensure the hidden + // input is rendered before we try to shift focus to it. + if (!this.visible) this.didShow() + if (!this.focused) { this.focused = true this.scheduleUpdate()