Skip to content

Commit

Permalink
chore: UserCard focus improvements (#31812)
Browse files Browse the repository at this point in the history
  • Loading branch information
dougfabris authored Feb 23, 2024
1 parent 7d331f1 commit f577751
Show file tree
Hide file tree
Showing 38 changed files with 247 additions and 236 deletions.
4 changes: 2 additions & 2 deletions apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts
Original file line number Diff line number Diff line change
Expand Up @@ -266,10 +266,10 @@ Meteor.startup(async () => {
label: 'Reactions',
context: ['message', 'message-mobile', 'threads', 'videoconf', 'videoconf-threads'],
type: 'interaction',
action(this: unknown, _, { message: { reactions = {} } = messageArgs(this).msg, chat }) {
action(this: unknown, _, { message: { reactions = {} } = messageArgs(this).msg }) {
imperativeModal.open({
component: ReactionListModal,
props: { reactions, onOpenUserCard: chat?.userCard.openUserCard, onClose: imperativeModal.close },
props: { reactions, onClose: imperativeModal.close },
});
},
condition({ message: { reactions } }) {
Expand Down
11 changes: 0 additions & 11 deletions apps/meteor/app/ui/client/lib/ChatMessages.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import type { IMessage, IRoom, IUser } from '@rocket.chat/core-typings';
import { isVideoConfMessage } from '@rocket.chat/core-typings';
import type { IActionManager } from '@rocket.chat/ui-contexts';
import type { UIEvent } from 'react';

import type { ChatAPI, ComposerAPI, DataAPI, UploadsAPI } from '../../../../client/lib/chats/ChatAPI';
import { createDataAPI } from '../../../../client/lib/chats/data';
Expand Down Expand Up @@ -45,11 +44,6 @@ export class ChatMessages implements ChatAPI {

public ActionManager: any;

public userCard: {
openUserCard(event: UIEvent, username: string): void;
closeUserCard(): void;
};

public emojiPicker: {
open(el: Element, cb: (emoji: string) => void): void;
close(): void;
Expand Down Expand Up @@ -162,11 +156,6 @@ export class ChatMessages implements ChatAPI {

this.readStateManager = new ReadStateManager(rid);

this.userCard = {
openUserCard: unimplemented,
closeUserCard: unimplemented,
};

this.emojiPicker = {
open: unimplemented,
close: unimplemented,
Expand Down
9 changes: 5 additions & 4 deletions apps/meteor/client/components/GazzodownText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import React, { useCallback, memo, useMemo } from 'react';

import { detectEmoji } from '../lib/utils/detectEmoji';
import { fireGlobalEvent } from '../lib/utils/fireGlobalEvent';
import { useChat } from '../views/room/contexts/ChatContext';
import { useUserCard } from '../views/room/contexts/UserCardContext';
import { useGoToRoom } from '../views/room/hooks/useGoToRoom';
import { useMessageListHighlights } from './message/list/MessageListContext';

Expand All @@ -25,8 +25,8 @@ type GazzodownTextProps = {
};

const GazzodownText = ({ mentions, channels, searchText, children }: GazzodownTextProps) => {
const chat = useChat();
const highlights = useMessageListHighlights();
const { triggerProps, openUserCard } = useUserCard();

const highlightRegex = useMemo(() => {
if (!highlights?.length) {
Expand Down Expand Up @@ -75,10 +75,10 @@ const GazzodownText = ({ mentions, channels, searchText, children }: GazzodownTe

return (event: UIEvent): void => {
event.stopPropagation();
chat?.userCard.openUserCard(event, username);
openUserCard(event, username);
};
},
[chat?.userCard],
[openUserCard],
);

const goToRoom = useGoToRoom();
Expand Down Expand Up @@ -124,6 +124,7 @@ const GazzodownText = ({ mentions, channels, searchText, children }: GazzodownTe
isMobile,
ownUserId,
showMentionSymbol,
triggerProps,
}}
>
{children}
Expand Down
47 changes: 22 additions & 25 deletions apps/meteor/client/components/UserCard/UserCard.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,13 @@ import { Box, Button, IconButton } from '@rocket.chat/fuselage';
import { UserAvatar } from '@rocket.chat/ui-avatar';
import { useTranslation } from '@rocket.chat/ui-contexts';
import type { ReactNode, ComponentProps } from 'react';
import React, { forwardRef } from 'react';
import React from 'react';

import { useEmbeddedLayout } from '../../hooks/useEmbeddedLayout';
import MarkdownText from '../MarkdownText';
import * as Status from '../UserStatus';
import UserCardActions from './UserCardActions';
import UserCardContainer from './UserCardContainer';
import UserCardDialog from './UserCardDialog';
import UserCardInfo from './UserCardInfo';
import UserCardRoles from './UserCardRoles';
import UserCardUsername from './UserCardUsername';
Expand All @@ -35,35 +35,32 @@ type UserCardProps = {
localTime?: ReactNode;
onClose?: () => void;
nickname?: string;
} & ComponentProps<typeof UserCardContainer>;
} & ComponentProps<typeof UserCardDialog>;

const UserCard = forwardRef<HTMLElement, UserCardProps>(function UserCard(
{
onOpenUserInfo,
name,
username,
etag,
customStatus,
roles,
bio,
status = <Status.Offline />,
actions,
localTime,
onClose,
nickname,
...props
},
ref,
) {
const UserCard = ({
onOpenUserInfo,
name,
username,
etag,
customStatus,
roles,
bio,
status = <Status.Offline />,
actions,
localTime,
onClose,
nickname,
...props
}: UserCardProps) => {
const t = useTranslation();
const isLayoutEmbedded = useEmbeddedLayout();

return (
<UserCardContainer data-qa='UserCard' ref={ref} {...props}>
<UserCardDialog data-qa='UserCard' {...props}>
<div>
{username && <UserAvatar username={username} etag={etag} size='x124' />}
<Box flexGrow={0} display='flex' mbs={12} alignItems='center' justifyContent='center'>
<UserCardActions>{actions}</UserCardActions>
<UserCardActions aria-label={t('User_card_actions')}>{actions}</UserCardActions>
</Box>
</div>
<Box display='flex' flexDirection='column' flexGrow={1} flexShrink={1} mis={16} width='1px'>
Expand Down Expand Up @@ -100,8 +97,8 @@ const UserCard = forwardRef<HTMLElement, UserCardProps>(function UserCard(
)}
</Box>
{onClose && <IconButton mis={16} small aria-label={t('Close')} icon='cross' onClick={onClose} />}
</UserCardContainer>
</UserCardDialog>
);
});
};

export default UserCard;
23 changes: 0 additions & 23 deletions apps/meteor/client/components/UserCard/UserCardContainer.tsx

This file was deleted.

30 changes: 30 additions & 0 deletions apps/meteor/client/components/UserCard/UserCardDialog.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { Box } from '@rocket.chat/fuselage';
import type { ComponentProps } from 'react';
import React, { useRef } from 'react';
import type { AriaDialogProps } from 'react-aria';
import { useDialog } from 'react-aria';

type UserCardDialogProps = AriaDialogProps & ComponentProps<typeof Box>;

const UserCardDialog = (props: UserCardDialogProps) => {
const ref = useRef(null);
const { dialogProps } = useDialog(props, ref);

return (
<Box
ref={ref}
minHeight='x214'
rcx-user-card
bg='surface'
elevation='2'
p={24}
display='flex'
borderRadius='x4'
width='439px'
{...props}
{...dialogProps}
/>
);
};

export default UserCardDialog;
12 changes: 6 additions & 6 deletions apps/meteor/client/components/UserCard/UserCardSkeleton.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import { Box, Skeleton } from '@rocket.chat/fuselage';
import type { ComponentProps } from 'react';
import React, { forwardRef } from 'react';
import React from 'react';

import UserCardContainer from './UserCardContainer';
import UserCardDialog from './UserCardDialog';

const UserCardSkeleton = forwardRef<HTMLElement, ComponentProps<typeof UserCardContainer>>(function UserCardSkeleton(props, ref) {
const UserCardSkeleton = (props: ComponentProps<typeof UserCardDialog>) => {
return (
<UserCardContainer ref={ref} {...props}>
<UserCardDialog {...props}>
<Box>
<Skeleton borderRadius='x4' width='x124' height='x124' variant='rect' />
<Box flexGrow={0} display='flex' mbs={12} alignItems='center' justifyContent='center'>
Expand All @@ -27,8 +27,8 @@ const UserCardSkeleton = forwardRef<HTMLElement, ComponentProps<typeof UserCardC
<Skeleton key={i} width='100%' />
))}
</Box>
</UserCardContainer>
</UserCardDialog>
);
});
};

export default UserCardSkeleton;
19 changes: 8 additions & 11 deletions apps/meteor/client/components/message/MessageHeader.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { useFormatDateAndTime } from '../../hooks/useFormatDateAndTime';
import { useFormatTime } from '../../hooks/useFormatTime';
import { useUserData } from '../../hooks/useUserData';
import type { UserPresence } from '../../lib/presence';
import { useChat } from '../../views/room/contexts/ChatContext';
import { useUserCard } from '../../views/room/contexts/UserCardContext';
import StatusIndicators from './StatusIndicators';
import MessageRoles from './header/MessageRoles';
import { useMessageRoles } from './header/hooks/useMessageRoles';
Expand All @@ -31,6 +31,7 @@ const MessageHeader = ({ message }: MessageHeaderProps): ReactElement => {

const formatTime = useFormatTime();
const formatDateAndTime = useFormatDateAndTime();
const { triggerProps, openUserCard } = useUserCard();

const showRealName = useMessageListShowRealName();
const user: UserPresence = { ...message.u, roles: [], ...useUserData(message.u._id) };
Expand All @@ -41,22 +42,18 @@ const MessageHeader = ({ message }: MessageHeaderProps): ReactElement => {
const roles = useMessageRoles(message.u._id, message.rid, showRoles);
const shouldShowRolesList = roles.length > 0;

const chat = useChat();

return (
<FuselageMessageHeader>
<MessageNameContainer
tabIndex={0}
role='button'
aria-label={getUserDisplayName(user.name, user.username, showRealName)}
{...(user.username !== undefined &&
chat?.userCard && {
onClick: (e) => chat?.userCard.openUserCard(e, message.u.username),
onKeyDown: (e: KeyboardEvent<HTMLSpanElement>) => {
(e.code === 'Enter' || e.code === 'Space') && chat?.userCard.openUserCard(e, message.u.username);
},
style: { cursor: 'pointer' },
})}
onClick={(e) => openUserCard(e, message.u.username)}
onKeyDown={(e: KeyboardEvent<HTMLSpanElement>) => {
(e.code === 'Enter' || e.code === 'Space') && openUserCard(e, message.u.username);
}}
style={{ cursor: 'pointer' }}
{...triggerProps}
>
<MessageName
{...(!showUsername && { 'data-qa-type': 'username' })}
Expand Down
13 changes: 6 additions & 7 deletions apps/meteor/client/components/message/variants/RoomMessage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
useCountSelected,
} from '../../../views/room/MessageList/contexts/SelectedMessagesContext';
import { useJumpToMessage } from '../../../views/room/MessageList/hooks/useJumpToMessage';
import { useChat } from '../../../views/room/contexts/ChatContext';
import { useUserCard } from '../../../views/room/contexts/UserCardContext';
import Emoji from '../../Emoji';
import IgnoredContent from '../IgnoredContent';
import MessageHeader from '../MessageHeader';
Expand Down Expand Up @@ -51,15 +51,14 @@ const RoomMessage = ({
const editing = useIsMessageHighlight(message._id);
const [displayIgnoredMessage, toggleDisplayIgnoredMessage] = useToggle(false);
const ignored = (ignoredUser || message.ignored) && !displayIgnoredMessage;
const chat = useChat();
const messageRef = useRef(null);
const { openUserCard, triggerProps } = useUserCard();

const selecting = useIsSelecting();
const toggleSelected = useToggleSelect(message._id);
const selected = useIsSelectedMessage(message._id);

useCountSelected();

useJumpToMessage(message._id, messageRef);

return (
Expand Down Expand Up @@ -91,10 +90,10 @@ const RoomMessage = ({
avatarUrl={message.avatar}
username={message.u.username}
size='x36'
{...(chat?.userCard && {
onClick: (e) => chat?.userCard.openUserCard(e, message.u.username),
style: { cursor: 'pointer' },
})}
onClick={(e) => openUserCard(e, message.u.username)}
style={{ cursor: 'pointer' }}
role='button'
{...triggerProps}
/>
)}
{selecting && <CheckBox checked={selected} onChange={toggleSelected} />}
Expand Down
Loading

0 comments on commit f577751

Please sign in to comment.