@@ -14,17 +14,17 @@ See the License for the specific language governing permissions and
1414limitations under the License.
1515*/
1616
17- import React , { useState } from "react" ;
17+ import React , { useRef , useState } from "react" ;
1818import classNames from "classnames" ;
1919
2020import { _t } from "../../../languageHandler" ;
21- import AccessibleButton from "../elements/AccessibleButton" ;
21+ import AccessibleButton , { ButtonEvent } from "../elements/AccessibleButton" ;
2222
2323interface IProps {
2424 avatarUrl ?: string ;
2525 avatarName : string ; // name of user/room the avatar belongs to
26- uploadAvatar ?: ( e : React . MouseEvent ) => void ;
27- removeAvatar ?: ( e : React . MouseEvent ) => void ;
26+ uploadAvatar ?: ( e : ButtonEvent ) => void ;
27+ removeAvatar ?: ( e : ButtonEvent ) => void ;
2828 avatarAltText : string ;
2929}
3030
@@ -34,12 +34,16 @@ const AvatarSetting: React.FC<IProps> = ({ avatarUrl, avatarAltText, avatarName,
3434 onMouseEnter : ( ) => setIsHovering ( true ) ,
3535 onMouseLeave : ( ) => setIsHovering ( false ) ,
3636 } ;
37+ // TODO: Use useId() as soon as we're using React 18.
38+ // Prevents ID collisions when this component is used more than once on the same page.
39+ const a11yId = useRef ( `hover-text-${ Math . random ( ) } ` ) ;
3740
3841 let avatarElement = (
3942 < AccessibleButton
4043 element = "div"
41- onClick = { uploadAvatar }
44+ onClick = { uploadAvatar ?? null }
4245 className = "mx_AvatarSetting_avatarPlaceholder"
46+ aria-labelledby = { a11yId . current }
4347 { ...hoveringProps }
4448 />
4549 ) ;
@@ -50,7 +54,7 @@ const AvatarSetting: React.FC<IProps> = ({ avatarUrl, avatarAltText, avatarName,
5054 src = { avatarUrl }
5155 alt = { avatarAltText }
5256 aria-label = { avatarAltText }
53- onClick = { uploadAvatar }
57+ onClick = { uploadAvatar ?? null }
5458 { ...hoveringProps }
5559 />
5660 ) ;
@@ -60,7 +64,12 @@ const AvatarSetting: React.FC<IProps> = ({ avatarUrl, avatarAltText, avatarName,
6064 if ( uploadAvatar ) {
6165 // insert an empty div to be the host for a css mask containing the upload.svg
6266 uploadAvatarBtn = (
63- < AccessibleButton onClick = { uploadAvatar } className = "mx_AvatarSetting_uploadButton" { ...hoveringProps } />
67+ < AccessibleButton
68+ onClick = { uploadAvatar }
69+ className = "mx_AvatarSetting_uploadButton"
70+ aria-labelledby = { a11yId . current }
71+ { ...hoveringProps }
72+ />
6473 ) ;
6574 }
6675
@@ -80,9 +89,9 @@ const AvatarSetting: React.FC<IProps> = ({ avatarUrl, avatarAltText, avatarName,
8089 return (
8190 < div className = { avatarClasses } >
8291 { avatarElement }
83- < div className = "mx_AvatarSetting_hover" >
92+ < div className = "mx_AvatarSetting_hover" aria-hidden = "true" >
8493 < div className = "mx_AvatarSetting_hoverBg" />
85- < span > { _t ( "Upload" ) } </ span >
94+ < span id = { a11yId . current } > { _t ( "Upload" ) } </ span >
8695 </ div >
8796 { uploadAvatarBtn }
8897 { removeAvatarBtn }
0 commit comments