Fix avatar focus highlight

This commit is contained in:
Evan Hahn 2021-10-12 14:07:58 -05:00 committed by GitHub
parent f5cce73611
commit f4b0bade80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 74 additions and 90 deletions

View file

@ -570,14 +570,17 @@
@mixin avatar-colors { @mixin avatar-colors {
@each $color, $value in $avatar-colors { @each $color, $value in $avatar-colors {
&--#{$color} { &--#{$color} {
background-color: map-get($value, 'bg'); --bg: #{map-get($value, 'bg')};
color: map-get($value, 'fg'); --fg: #{map-get($value, 'fg')};
background-color: var(--bg);
color: var(--fg);
&--icon { &--icon {
background-color: map-get($value, 'fg'); background-color: var(--fg);
@include dark-theme { @include dark-theme {
// For specificity // For specificity
background-color: map-get($value, 'fg'); background-color: var(--fg);
} }
} }
} }

View file

@ -1267,22 +1267,6 @@
} }
} }
.module-message__author-avatar {
@include button-reset;
cursor: pointer;
&:focus {
outline: none;
.module-Avatar {
@include keyboard-mode {
box-shadow: 0 0 0 3px $color-ultramarine;
}
}
}
}
.module-message__typing-container { .module-message__typing-container {
height: 16px; height: 16px;

View file

@ -2,39 +2,46 @@
// SPDX-License-Identifier: AGPL-3.0-only // SPDX-License-Identifier: AGPL-3.0-only
.module-Avatar { .module-Avatar {
align-items: center;
border-radius: 100%;
display: inline-flex; display: inline-flex;
justify-content: center;
line-height: 0; line-height: 0;
overflow: hidden;
position: relative; position: relative;
user-select: none; user-select: none;
vertical-align: middle; vertical-align: middle;
&__button { &__contents {
@include button-reset; @include avatar-colors;
position: relative;
align-items: center; overflow: hidden;
display: flex; border-radius: 100%;
height: 100%;
justify-content: center;
width: 100%; width: 100%;
height: 100%;
border: 0;
padding: 0;
margin: 0;
outline: none;
@include keyboard-mode { @at-root button#{&} {
&:focus { @include keyboard-mode {
box-shadow: 0px 0px 0px 2px $color-ultramarine; &:focus {
box-shadow: 0 0 0 3px $color-ultramarine;
}
} }
} }
} }
&__image,
&__label,
&__icon,
&__spinner-container,
&__click-to-view {
width: 100%;
height: 100%;
}
&__image { &__image {
background-position: center center; background-position: center center;
background-size: cover; background-size: cover;
display: flex;
height: 100%;
transition: filter 100ms ease-out; transition: filter 100ms ease-out;
width: 100%;
} }
&__click-to-view { &__click-to-view {
@ -44,12 +51,10 @@
color: $color-white; color: $color-white;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
height: 100%;
justify-content: center; justify-content: center;
left: 0; left: 0;
position: absolute; position: absolute;
top: 0; top: 0;
width: 100%;
&::before { &::before {
@include color-svg( @include color-svg(
@ -78,27 +83,22 @@
} }
&__icon { &__icon {
@mixin avatar-icon($icon) { -webkit-mask-repeat: no-repeat;
-webkit-mask: url($icon) no-repeat center; -webkit-mask-position: center;
-webkit-mask-size: 100%; -webkit-mask-size: 62%;
} background-color: var(--fg);
&--direct { &--direct {
@include avatar-icon('../images/icons/v2/profile-outline-20.svg'); -webkit-mask-image: url('../images/icons/v2/profile-outline-20.svg');
height: 60%; -webkit-mask-size: 60%;
width: 60%;
} }
&--group { &--group {
@include avatar-icon('../images/icons/v2/group-outline-24.svg'); -webkit-mask-image: url('../images/icons/v2/group-outline-24.svg');
height: 62%;
width: 62%;
} }
&--note-to-self { &--note-to-self {
@include avatar-icon('../images/icons/v2/note-24.svg'); -webkit-mask-image: url('../images/icons/v2/note-24.svg');
height: 62%;
width: 62%;
} }
} }
@ -106,8 +106,6 @@
padding: 4px; padding: 4px;
} }
@include avatar-colors();
&--undefined { &--undefined {
background-color: $color-gray-15; background-color: $color-gray-15;
color: $color-gray-75; color: $color-gray-75;

View file

@ -6,6 +6,7 @@
display: flex; display: flex;
flex-direction: column; flex-direction: column;
justify-content: center; justify-content: center;
margin-top: 4px;
&__name { &__name {
@include font-title-2; @include font-title-2;

View file

@ -3,6 +3,8 @@
import React, { import React, {
FunctionComponent, FunctionComponent,
MouseEvent,
ReactChild,
ReactNode, ReactNode,
useEffect, useEffect,
useState, useState,
@ -53,7 +55,7 @@ export type Props = {
title: string; title: string;
unblurredAvatarPath?: string; unblurredAvatarPath?: string;
onClick?: () => unknown; onClick?: (event: MouseEvent<HTMLButtonElement>) => unknown;
// Matches Popper's RefHandler type // Matches Popper's RefHandler type
innerRef?: React.Ref<HTMLDivElement>; innerRef?: React.Ref<HTMLDivElement>;
@ -118,10 +120,10 @@ export const Avatar: FunctionComponent<Props> = ({
const shouldUseInitials = const shouldUseInitials =
!hasImage && conversationType === 'direct' && Boolean(initials); !hasImage && conversationType === 'direct' && Boolean(initials);
let contents: ReactNode; let contentsChildren: ReactNode;
if (loading) { if (loading) {
const svgSize = size < 40 ? 'small' : 'normal'; const svgSize = size < 40 ? 'small' : 'normal';
contents = ( contentsChildren = (
<div className="module-Avatar__spinner-container"> <div className="module-Avatar__spinner-container">
<Spinner <Spinner
size={`${size - 8}px`} size={`${size - 8}px`}
@ -141,7 +143,7 @@ export const Avatar: FunctionComponent<Props> = ({
const isBlurred = const isBlurred =
blur === AvatarBlur.BlurPicture || blur === AvatarBlur.BlurPicture ||
blur === AvatarBlur.BlurPictureWithClickToView; blur === AvatarBlur.BlurPictureWithClickToView;
contents = ( contentsChildren = (
<> <>
<div <div
className="module-Avatar__image" className="module-Avatar__image"
@ -156,17 +158,16 @@ export const Avatar: FunctionComponent<Props> = ({
</> </>
); );
} else if (noteToSelf) { } else if (noteToSelf) {
contents = ( contentsChildren = (
<div <div
className={classNames( className={classNames(
'module-Avatar__icon', 'module-Avatar__icon',
`module-Avatar--${color}--icon`,
'module-Avatar__icon--note-to-self' 'module-Avatar__icon--note-to-self'
)} )}
/> />
); );
} else if (shouldUseInitials) { } else if (shouldUseInitials) {
contents = ( contentsChildren = (
<div <div
aria-hidden="true" aria-hidden="true"
className="module-Avatar__label" className="module-Avatar__label"
@ -176,23 +177,29 @@ export const Avatar: FunctionComponent<Props> = ({
</div> </div>
); );
} else { } else {
contents = ( contentsChildren = (
<div <div
className={classNames( className={classNames(
'module-Avatar__icon', 'module-Avatar__icon',
`module-Avatar--${color}--icon`,
`module-Avatar__icon--${conversationType}` `module-Avatar__icon--${conversationType}`
)} )}
/> />
); );
} }
let contents: ReactChild;
const contentsClassName = classNames(
'module-Avatar__contents',
`module-Avatar__contents--${color}`
);
if (onClick) { if (onClick) {
contents = ( contents = (
<button className="module-Avatar__button" type="button" onClick={onClick}> <button className={contentsClassName} type="button" onClick={onClick}>
{contents} {contentsChildren}
</button> </button>
); );
} else {
contents = <div className={contentsClassName}>{contentsChildren}</div>;
} }
return ( return (
@ -201,9 +208,6 @@ export const Avatar: FunctionComponent<Props> = ({
className={classNames( className={classNames(
'module-Avatar', 'module-Avatar',
hasImage ? 'module-Avatar--with-image' : 'module-Avatar--no-image', hasImage ? 'module-Avatar--with-image' : 'module-Avatar--no-image',
{
[`module-Avatar--${color}`]: !hasImage,
},
className className
)} )}
style={{ style={{

View file

@ -1206,33 +1206,27 @@ export class Message extends React.PureComponent<Props, State> {
'module-message__author-avatar-container--with-reactions': this.hasReactions(), 'module-message__author-avatar-container--with-reactions': this.hasReactions(),
})} })}
> >
<button <Avatar
type="button" acceptedMessageRequest={author.acceptedMessageRequest}
className="module-message__author-avatar" avatarPath={author.avatarPath}
onClick={(event: React.MouseEvent<HTMLButtonElement, MouseEvent>) => { color={author.color}
conversationType="direct"
i18n={i18n}
isMe={author.isMe}
name={author.name}
onClick={event => {
event.stopPropagation(); event.stopPropagation();
event.preventDefault(); event.preventDefault();
showContactModal(author.id); showContactModal(author.id);
}} }}
tabIndex={0} phoneNumber={author.phoneNumber}
> profileName={author.profileName}
<Avatar sharedGroupNames={author.sharedGroupNames}
acceptedMessageRequest={author.acceptedMessageRequest} size={28}
avatarPath={author.avatarPath} title={author.title}
color={author.color} unblurredAvatarPath={author.unblurredAvatarPath}
conversationType="direct" />
i18n={i18n}
isMe={author.isMe}
name={author.name}
phoneNumber={author.phoneNumber}
profileName={author.profileName}
sharedGroupNames={author.sharedGroupNames}
size={28}
title={author.title}
unblurredAvatarPath={author.unblurredAvatarPath}
/>
</button>
</div> </div>
); );
} }