diff --git a/CHANGELOG.md b/CHANGELOG.md index 3070a801db..f1f2bf2dc9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,7 +23,8 @@ This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.htm ### Fixes - Ensure `Popup` properly flips values of `offset` prop in RTL @kuzhelov ([#612](https://github.com/stardust-ui/react/pull/612)) - Fix `List` - items should be selectable @sophieH29 ([#566](https://github.com/stardust-ui/react/pull/566)) -- Respect `defaultTabbable` element when `FocusZone` container gets focus ([#637](https://github.com/stardust-ui/react/pull/637)) +- Respect `defaultTabbable` element when `FocusZone` container gets focus @sophieH29 ([#637](https://github.com/stardust-ui/react/pull/637)) +- Fix `FocusZone` - fix last breaking changes and make improvements for `Chat` usage @sophieH29 ([#614](https://github.com/stardust-ui/react/pull/614)) ### Features - Add `color` prop to `Text` component @Bugaa92 ([#597](https://github.com/stardust-ui/react/pull/597)) diff --git a/docs/src/prototypes/chatPane/services/messageFactoryMock.tsx b/docs/src/prototypes/chatPane/services/messageFactoryMock.tsx index b0f22acbd6..d506900744 100644 --- a/docs/src/prototypes/chatPane/services/messageFactoryMock.tsx +++ b/docs/src/prototypes/chatPane/services/messageFactoryMock.tsx @@ -119,7 +119,7 @@ function createMessageContentWithAttachments(content: string, messageId: string) icon="file word outline" aria-label={`File attachment ${fileName}. Press tab for more options Press Enter to open the file`} header={fileName} - action={render => render(actionPopup)} + action={actionPopup} data-is-focusable={true} styles={{ '&:focus': { diff --git a/src/lib/accessibility/Behaviors/Chat/chatBehavior.ts b/src/lib/accessibility/Behaviors/Chat/chatBehavior.ts index 5d3f9d71cd..6f067a2b44 100644 --- a/src/lib/accessibility/Behaviors/Chat/chatBehavior.ts +++ b/src/lib/accessibility/Behaviors/Chat/chatBehavior.ts @@ -21,7 +21,7 @@ const ChatBehavior: Accessibility = (props: any) => ({ props: { shouldEnterInnerZone: event => keyboardKey.getCode(event) === keyboardKey.Enter, direction: FocusZoneDirection.vertical, - shouldHandleKeyDownCapture: false, + shouldResetActiveElementWhenTabFromZone: true, defaultTabbableElement: getLastTabbableElement, // select last chat message by default [CHAT_FOCUSZONE_ATTRIBUTE]: '', // allows querying the default active element }, @@ -36,8 +36,11 @@ const ChatBehavior: Accessibility = (props: any) => ({ }) const getLastTabbableElement = (root: HTMLElement): HTMLElement => { + const lastVisibleMessage = root.querySelector('[data-last-visible="true"]') as HTMLElement + if (lastVisibleMessage) return lastVisibleMessage + const chatItemsElements = root.querySelectorAll( - `[${CHAT_FOCUSZONE_ATTRIBUTE}] .ui-chat__item > [${IS_FOCUSABLE_ATTRIBUTE}]`, + `[${CHAT_FOCUSZONE_ATTRIBUTE}] .ui-chat__message[${IS_FOCUSABLE_ATTRIBUTE}="true"]`, ) return chatItemsElements.length > 0 ? (chatItemsElements[chatItemsElements.length - 1] as HTMLElement) diff --git a/src/lib/accessibility/FocusZone/CHANGELOG.md b/src/lib/accessibility/FocusZone/CHANGELOG.md index 2148147902..d75845f0b7 100644 --- a/src/lib/accessibility/FocusZone/CHANGELOG.md +++ b/src/lib/accessibility/FocusZone/CHANGELOG.md @@ -8,6 +8,7 @@ This is a list of changes made to this Stardust copy of FocusZone in comparison - Fix `defaultTabbableElement` prop to be as a function ([#450](https://github.com/stardust-ui/react/pull/450)) - Remove role="presentation" @sophieH29 ([#530](https://github.com/stardust-ui/react/pull/530)) - Respect `defaultTabbable` element when FocusZone container receives focus @sophieH29 ([#637](https://github.com/stardust-ui/react/pull/637)) +- Fix `FocusZone` - add `shouldResetActiveElementWhenTabFromZone` prop @sophieH29 ([#614](https://github.com/stardust-ui/react/pull/614)) ### Features - Add embed mode for FocusZone and new Chat behavior ([#233](https://github.com/stardust-ui/react/pull/233)) diff --git a/src/lib/accessibility/FocusZone/FocusZone.tsx b/src/lib/accessibility/FocusZone/FocusZone.tsx index 4b421ced9d..e5364ca9c3 100644 --- a/src/lib/accessibility/FocusZone/FocusZone.tsx +++ b/src/lib/accessibility/FocusZone/FocusZone.tsx @@ -47,8 +47,8 @@ export class FocusZone extends React.Component implements IFocus direction: PropTypes.number, defaultTabbableElement: PropTypes.func, shouldFocusOnMount: PropTypes.bool, + shouldResetActiveElementWhenTabFromZone: PropTypes.bool, shouldFocusInnerElementWhenReceivedFocus: PropTypes.bool, - shouldHandleKeyDownCapture: PropTypes.bool, disabled: PropTypes.bool, as: customPropTypes.as, isCircularNavigation: PropTypes.bool, @@ -67,7 +67,6 @@ export class FocusZone extends React.Component implements IFocus static defaultProps: FocusZoneProps = { isCircularNavigation: false, direction: FocusZoneDirection.bidirectional, - shouldHandleKeyDownCapture: true, as: 'div', } @@ -105,8 +104,6 @@ export class FocusZone extends React.Component implements IFocus public componentDidMount(): void { _allInstances[this._id] = this - const { shouldHandleKeyDownCapture, defaultTabbableElement, shouldFocusOnMount } = this.props - this.setRef(this) // called here to support functional components, we only need HTMLElement ref anyway if (this._root.current) { this.windowElement = getWindow(this._root.current) @@ -121,19 +118,14 @@ export class FocusZone extends React.Component implements IFocus parentElement = getParent(parentElement) } - if (!this._isInnerZone && shouldHandleKeyDownCapture) { + if (!this._isInnerZone) { this.windowElement.addEventListener('keydown', this.onKeyDownCapture, true) } // Assign initial tab indexes so that we can set initial focus as appropriate. this.updateTabIndexes() - if (defaultTabbableElement) { - const initialActiveElement = defaultTabbableElement(this._root.current) - initialActiveElement && this.setActiveElement(initialActiveElement) - } - - if (shouldFocusOnMount) { + if (this.props.shouldFocusOnMount) { this.focus() } } @@ -141,7 +133,7 @@ export class FocusZone extends React.Component implements IFocus public componentWillUnmount() { delete _allInstances[this._id] - if (this.windowElement && this.props.shouldHandleKeyDownCapture) { + if (this.windowElement) { this.windowElement.removeEventListener('keydown', this.onKeyDownCapture, true) } } @@ -490,6 +482,8 @@ export class FocusZone extends React.Component implements IFocus if (focusChanged) { break } + } else if (this.props.shouldResetActiveElementWhenTabFromZone) { + this._activeElement = null } return undefined @@ -885,6 +879,11 @@ export class FocusZone extends React.Component implements IFocus private updateTabIndexes(onElement?: HTMLElement) { let element = onElement + + if (!this._activeElement && this.props.defaultTabbableElement) { + this._activeElement = this.props.defaultTabbableElement(this._root.current) + } + if (!element && this._root.current) { this._defaultFocusElement = null element = this._root.current diff --git a/src/lib/accessibility/FocusZone/FocusZone.types.ts b/src/lib/accessibility/FocusZone/FocusZone.types.ts index 368ccb27d8..24261b3289 100644 --- a/src/lib/accessibility/FocusZone/FocusZone.types.ts +++ b/src/lib/accessibility/FocusZone/FocusZone.types.ts @@ -60,9 +60,9 @@ export interface FocusZoneProps extends React.HTMLAttributes