diff --git a/CHANGELOG.md b/CHANGELOG.md index 10964d0a6a..934e87b955 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Fixes - Require `name` prop in `Icon` component @lucivpav ([#1723](https://github.com/stardust-ui/react/pull/1723)) - Export `broadcast` icon in Teams theme @miroslavstastny ([#1737](https://github.com/stardust-ui/react/pull/1737)) +- `FocusZone` should respect elements with `contenteditable` attribute on Home/End key press @sophieH29 ([#1749](https://github.com/stardust-ui/react/pull/1749)) ### Features - Expose `isFromKeyboard` in `Grid` component @sophieH29 ([#1729](https://github.com/stardust-ui/react/pull/1729)) diff --git a/packages/react/src/lib/accessibility/FocusZone/CHANGELOG.md b/packages/react/src/lib/accessibility/FocusZone/CHANGELOG.md index 532a4b1391..2ef38ac023 100644 --- a/packages/react/src/lib/accessibility/FocusZone/CHANGELOG.md +++ b/packages/react/src/lib/accessibility/FocusZone/CHANGELOG.md @@ -11,6 +11,7 @@ This is a list of changes made to this Stardust copy of FocusZone in comparison - Fix `FocusZone` - add `shouldResetActiveElementWhenTabFromZone` prop @sophieH29 ([#614](https://github.com/stardust-ui/react/pull/614)) - Make `FocusZoneTabbableElements` a usual enum @layershifter ([#867](https://github.com/stardust-ui/react/pull/867)) - Update tabindexes and focus alignment when item is focused programatically @sophieH29 ([#1098](https://github.com/stardust-ui/react/pull/1098)) +- `FocusZone` should respect elements with `contenteditable` attribute on Home/End key press @sophieH29 ([#1749](https://github.com/stardust-ui/react/pull/1749)) ### Features - Add embed mode for FocusZone and new Chat behavior ([#233](https://github.com/stardust-ui/react/pull/233)) diff --git a/packages/react/src/lib/accessibility/FocusZone/FocusZone.tsx b/packages/react/src/lib/accessibility/FocusZone/FocusZone.tsx index 1053dd4904..a4997e5a86 100644 --- a/packages/react/src/lib/accessibility/FocusZone/FocusZone.tsx +++ b/packages/react/src/lib/accessibility/FocusZone/FocusZone.tsx @@ -501,8 +501,9 @@ export default class FocusZone extends React.Component implement case keyboardKey.Home: if ( - this.isElementInput(ev.target as HTMLElement) && - !this.shouldInputLoseFocus(ev.target as HTMLInputElement, false) + this.isContentEditableElement(ev.target as HTMLElement) || + (this.isElementInput(ev.target as HTMLElement) && + !this.shouldInputLoseFocus(ev.target as HTMLInputElement, false)) ) { return false } @@ -519,8 +520,9 @@ export default class FocusZone extends React.Component implement case keyboardKey.End: if ( - this.isElementInput(ev.target as HTMLElement) && - !this.shouldInputLoseFocus(ev.target as HTMLInputElement, true) + this.isContentEditableElement(ev.target as HTMLElement) || + (this.isElementInput(ev.target as HTMLElement) && + !this.shouldInputLoseFocus(ev.target as HTMLInputElement, false)) ) { return false } @@ -957,6 +959,10 @@ export default class FocusZone extends React.Component implement } } + isContentEditableElement(element: HTMLElement): boolean { + return element && element.getAttribute('contenteditable') === 'true' + } + isElementInput(element: HTMLElement): boolean { if ( element && diff --git a/packages/react/test/specs/lib/FocusZone-test.tsx b/packages/react/test/specs/lib/FocusZone-test.tsx index 083a36cea6..a485ea7ae8 100644 --- a/packages/react/test/specs/lib/FocusZone-test.tsx +++ b/packages/react/test/specs/lib/FocusZone-test.tsx @@ -1420,4 +1420,51 @@ describe('FocusZone', () => { expect(buttonB.tabIndex).toBe(0) expect(buttonA.tabIndex).toBe(-1) }) + + it('remains focus in element with "contenteditable=true" attribute on Home/End keys', () => { + const component = ReactTestUtils.renderIntoDocument<{}, React.Component>( +
+ +
+ + +
, + ) + + const focusZone = ReactDOM.findDOMNode(component)!.firstChild as Element + + const contentEditableA = focusZone.querySelector('#a') as HTMLElement + const buttonB = focusZone.querySelector('#b') as HTMLElement + + setupElement(contentEditableA, { + clientRect: { + top: 0, + bottom: 20, + left: 20, + right: 40, + }, + }) + + setupElement(buttonB, { + clientRect: { + top: 0, + bottom: 20, + left: 20, + right: 40, + }, + }) + + // contentEditableA should be focused. + contentEditableA.focus() + expect(lastFocusedElement).toBe(contentEditableA) + + ReactTestUtils.Simulate.keyDown(contentEditableA, { which: keyboardKey.Home }) + expect(lastFocusedElement).toBe(contentEditableA) + ReactTestUtils.Simulate.keyDown(contentEditableA, { which: keyboardKey.End }) + expect(lastFocusedElement).toBe(contentEditableA) + + // change focus to buttonB + buttonB.focus() + expect(lastFocusedElement).toBe(buttonB) + }) })