@@ -5,29 +5,33 @@ import ListSeparator from '@ui5/webcomponents/dist/types/ListSeparator.js';
55import TitleLevel from '@ui5/webcomponents/dist/types/TitleLevel.js' ;
66import WrappingType from '@ui5/webcomponents/dist/types/WrappingType.js' ;
77import ValueState from '@ui5/webcomponents-base/dist/types/ValueState.js' ;
8+ import announce from '@ui5/webcomponents-base/dist/util/InvisibleMessage.js' ;
89import iconSlimArrowLeft from '@ui5/webcomponents-icons/dist/slim-arrow-left.js' ;
10+ import type { Ui5DomRef } from '@ui5/webcomponents-react-base' ;
911import { useI18nBundle , useStylesheet , useSyncRef } from '@ui5/webcomponents-react-base' ;
1012import { clsx } from 'clsx' ;
1113import type { ReactElement , ReactNode } from 'react' ;
12- import { Children , forwardRef , Fragment , isValidElement , useCallback , useEffect , useState } from 'react' ;
14+ import { useRef , Children , forwardRef , Fragment , isValidElement , useCallback , useEffect , useState } from 'react' ;
1315import { FlexBoxDirection } from '../../enums/index.js' ;
14- import { ALL , LIST_NO_DATA } from '../../i18n/i18n-defaults.js' ;
16+ import { ALL , LIST_NO_DATA , NAVIGATE_BACK , MESSAGE_DETAILS , MESSAGE_TYPES } from '../../i18n/i18n-defaults.js' ;
17+ import type { SelectedMessage } from '../../internal/MessageViewContext.js' ;
1518import { MessageViewContext } from '../../internal/MessageViewContext.js' ;
1619import type { CommonProps } from '../../types/index.js' ;
1720import { Bar } from '../../webComponents/Bar/index.js' ;
21+ import type { ButtonDomRef } from '../../webComponents/Button/index.js' ;
1822import { Button } from '../../webComponents/Button/index.js' ;
1923import { Icon } from '../../webComponents/Icon/index.js' ;
20- import type { ListPropTypes } from '../../webComponents/List/index.js' ;
24+ import type { ListDomRef , ListPropTypes } from '../../webComponents/List/index.js' ;
2125import { List } from '../../webComponents/List/index.js' ;
2226import { ListItemGroup } from '../../webComponents/ListItemGroup/index.js' ;
23- import type { SegmentedButtonPropTypes } from '../../webComponents/SegmentedButton/index.js' ;
2427import { SegmentedButton } from '../../webComponents/SegmentedButton/index.js' ;
28+ import type { SegmentedButtonPropTypes } from '../../webComponents/SegmentedButton/index.js' ;
2529import { SegmentedButtonItem } from '../../webComponents/SegmentedButtonItem/index.js' ;
2630import { Title } from '../../webComponents/Title/index.js' ;
2731import { FlexBox } from '../FlexBox/index.js' ;
2832import type { MessageItemPropTypes } from './MessageItem.js' ;
2933import { classNames , styleData } from './MessageView.module.css.js' ;
30- import { getIconNameForType } from './utils.js' ;
34+ import { getIconNameForType , getValueStateMap } from './utils.js' ;
3135
3236export interface MessageViewDomRef extends HTMLDivElement {
3337 /**
@@ -107,6 +111,10 @@ export const resolveMessageGroups = (children: ReactElement<MessageItemPropTypes
107111 */
108112const MessageView = forwardRef < MessageViewDomRef , MessageViewPropTypes > ( ( props , ref ) => {
109113 const { children, groupItems, showDetailsPageHeader, className, onItemSelect, ...rest } = props ;
114+ const navBtnRef = useRef < ButtonDomRef > ( null ) ;
115+ const listRef = useRef < ListDomRef > ( null ) ;
116+ const transitionTrigger = useRef < 'btn' | 'list' | null > ( null ) ;
117+ const prevSelectedMessage = useRef < SelectedMessage > ( null ) ;
110118
111119 useStylesheet ( styleData , MessageView . displayName ) ;
112120
@@ -115,7 +123,7 @@ const MessageView = forwardRef<MessageViewDomRef, MessageViewPropTypes>((props,
115123 const i18nBundle = useI18nBundle ( '@ui5/webcomponents-react' ) ;
116124
117125 const [ listFilter , setListFilter ] = useState < ValueState | 'All' > ( 'All' ) ;
118- const [ selectedMessage , setSelectedMessage ] = useState < MessageItemPropTypes > ( null ) ;
126+ const [ selectedMessage , setSelectedMessage ] = useState < SelectedMessage > ( null ) ;
119127
120128 const childrenArray = Children . toArray ( children ) ;
121129 const messageTypes = resolveMessageTypes ( childrenArray as ReactElement < MessageItemPropTypes > [ ] ) ;
@@ -138,8 +146,10 @@ const MessageView = forwardRef<MessageViewDomRef, MessageViewPropTypes>((props,
138146 const groupedMessages = resolveMessageGroups ( filteredChildren as ReactElement < MessageItemPropTypes > [ ] ) ;
139147
140148 const navigateBack = useCallback ( ( ) => {
149+ transitionTrigger . current = 'btn' ;
150+ prevSelectedMessage . current = selectedMessage ;
141151 setSelectedMessage ( null ) ;
142- } , [ setSelectedMessage ] ) ;
152+ } , [ setSelectedMessage , selectedMessage ] ) ;
143153
144154 useEffect ( ( ) => {
145155 if ( internalRef . current ) {
@@ -151,10 +161,37 @@ const MessageView = forwardRef<MessageViewDomRef, MessageViewPropTypes>((props,
151161 setListFilter ( e . detail . selectedItems . at ( 0 ) . dataset . key as never ) ;
152162 } ;
153163
154- const outerClasses = clsx ( classNames . container , className , selectedMessage && classNames . showDetails ) ;
164+ const handleTransitionEnd : MessageViewPropTypes [ 'onTransitionEnd' ] = ( e ) => {
165+ if ( typeof props ?. onTransitionEnd === 'function' ) {
166+ props . onTransitionEnd ( e ) ;
167+ }
168+ if ( showDetailsPageHeader && transitionTrigger . current === 'list' ) {
169+ requestAnimationFrame ( ( ) => {
170+ void navBtnRef . current ?. focus ( ) ;
171+ } ) ;
172+ setTimeout ( ( ) => {
173+ announce ( i18nBundle . getText ( MESSAGE_DETAILS ) , 'Polite' ) ;
174+ } , 300 ) ;
175+ }
176+ if ( transitionTrigger . current === 'btn' ) {
177+ requestAnimationFrame ( ( ) => {
178+ const selectedItem = listRef . current . querySelector < Ui5DomRef > (
179+ `[data-title="${ CSS . escape ( prevSelectedMessage . current . titleTextStr ) } "]`
180+ ) ;
181+ void selectedItem . focus ( ) ;
182+ } ) ;
183+ }
184+ transitionTrigger . current = null ;
185+ } ;
155186
187+ const handleListItemClick : ListPropTypes [ 'onItemClick' ] = ( e ) => {
188+ transitionTrigger . current = 'list' ;
189+ onItemSelect ( e ) ;
190+ } ;
191+
192+ const outerClasses = clsx ( classNames . container , className , selectedMessage && classNames . showDetails ) ;
156193 return (
157- < div ref = { componentRef } { ...rest } className = { outerClasses } >
194+ < div ref = { componentRef } { ...rest } className = { outerClasses } onTransitionEnd = { handleTransitionEnd } >
158195 < MessageViewContext . Provider
159196 value = { {
160197 selectMessage : setSelectedMessage
@@ -166,7 +203,10 @@ const MessageView = forwardRef<MessageViewDomRef, MessageViewPropTypes>((props,
166203 { filledTypes > 1 && (
167204 < Bar
168205 startContent = {
169- < SegmentedButton onSelectionChange = { handleListFilterChange } >
206+ < SegmentedButton
207+ onSelectionChange = { handleListFilterChange }
208+ accessibleName = { i18nBundle . getText ( MESSAGE_TYPES ) }
209+ >
170210 < SegmentedButtonItem data-key = "All" selected = { listFilter === 'All' } >
171211 { i18nBundle . getText ( ALL ) }
172212 </ SegmentedButtonItem >
@@ -182,6 +222,8 @@ const MessageView = forwardRef<MessageViewDomRef, MessageViewPropTypes>((props,
182222 selected = { listFilter === valueState }
183223 icon = { getIconNameForType ( valueState ) }
184224 className = { classNames . button }
225+ tooltip = { getValueStateMap ( i18nBundle ) [ valueState ] }
226+ accessibleName = { getValueStateMap ( i18nBundle ) [ valueState ] }
185227 >
186228 { count }
187229 </ SegmentedButtonItem >
@@ -192,7 +234,8 @@ const MessageView = forwardRef<MessageViewDomRef, MessageViewPropTypes>((props,
192234 />
193235 ) }
194236 < List
195- onItemClick = { onItemSelect }
237+ ref = { listRef }
238+ onItemClick = { handleListItemClick }
196239 noDataText = { i18nBundle . getText ( LIST_NO_DATA ) }
197240 separators = { ListSeparator . Inner }
198241 >
@@ -212,13 +255,21 @@ const MessageView = forwardRef<MessageViewDomRef, MessageViewPropTypes>((props,
212255 </ >
213256 ) }
214257 </ div >
215- < div className = { classNames . detailsContainer } >
258+ < div className = { classNames . detailsContainer } data-component-name = "MessageViewDetailsContainer" >
216259 { childrenArray . length > 0 ? (
217260 < >
218261 { showDetailsPageHeader && selectedMessage && (
219262 < Bar
220263 startContent = {
221- < Button design = { ButtonDesign . Transparent } icon = { iconSlimArrowLeft } onClick = { navigateBack } />
264+ < Button
265+ ref = { navBtnRef }
266+ design = { ButtonDesign . Transparent }
267+ icon = { iconSlimArrowLeft }
268+ onClick = { navigateBack }
269+ tooltip = { i18nBundle . getText ( NAVIGATE_BACK ) }
270+ accessibleName = { i18nBundle . getText ( NAVIGATE_BACK ) }
271+ data-component-name = "MessageViewDetailsNavBackBtn"
272+ />
222273 }
223274 />
224275 ) }
0 commit comments