diff --git a/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts b/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts index 834fd0bb05a2..f3cf0be67ca9 100644 --- a/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts +++ b/apps/meteor/app/ui-utils/client/lib/messageActionDefault.ts @@ -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 } }) { diff --git a/apps/meteor/app/ui/client/lib/ChatMessages.ts b/apps/meteor/app/ui/client/lib/ChatMessages.ts index 59efeff49af1..5d78fd1e1d98 100644 --- a/apps/meteor/app/ui/client/lib/ChatMessages.ts +++ b/apps/meteor/app/ui/client/lib/ChatMessages.ts @@ -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'; @@ -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; @@ -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, diff --git a/apps/meteor/client/components/GazzodownText.tsx b/apps/meteor/client/components/GazzodownText.tsx index 76232984a594..f69bbe1abdc0 100644 --- a/apps/meteor/client/components/GazzodownText.tsx +++ b/apps/meteor/client/components/GazzodownText.tsx @@ -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'; @@ -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) { @@ -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(); @@ -124,6 +124,7 @@ const GazzodownText = ({ mentions, channels, searchText, children }: GazzodownTe isMobile, ownUserId, showMentionSymbol, + triggerProps, }} > {children} diff --git a/apps/meteor/client/components/UserCard/UserCard.tsx b/apps/meteor/client/components/UserCard/UserCard.tsx index 2d440427ccbd..bf143229cf65 100644 --- a/apps/meteor/client/components/UserCard/UserCard.tsx +++ b/apps/meteor/client/components/UserCard/UserCard.tsx @@ -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'; @@ -35,35 +35,32 @@ type UserCardProps = { localTime?: ReactNode; onClose?: () => void; nickname?: string; -} & ComponentProps; +} & ComponentProps; -const UserCard = forwardRef(function UserCard( - { - onOpenUserInfo, - name, - username, - etag, - customStatus, - roles, - bio, - status = , - actions, - localTime, - onClose, - nickname, - ...props - }, - ref, -) { +const UserCard = ({ + onOpenUserInfo, + name, + username, + etag, + customStatus, + roles, + bio, + status = , + actions, + localTime, + onClose, + nickname, + ...props +}: UserCardProps) => { const t = useTranslation(); const isLayoutEmbedded = useEmbeddedLayout(); return ( - +
{username && } - {actions} + {actions}
@@ -100,8 +97,8 @@ const UserCard = forwardRef(function UserCard( )} {onClose && } -
+ ); -}); +}; export default UserCard; diff --git a/apps/meteor/client/components/UserCard/UserCardContainer.tsx b/apps/meteor/client/components/UserCard/UserCardContainer.tsx deleted file mode 100644 index 2434077922e3..000000000000 --- a/apps/meteor/client/components/UserCard/UserCardContainer.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import { Box } from '@rocket.chat/fuselage'; -import type { ComponentProps } from 'react'; -import React, { forwardRef } from 'react'; - -const UserCardContainer = forwardRef(function UserCardContainer(props: ComponentProps, ref) { - return ( - - ); -}); - -export default UserCardContainer; diff --git a/apps/meteor/client/components/UserCard/UserCardDialog.tsx b/apps/meteor/client/components/UserCard/UserCardDialog.tsx new file mode 100644 index 000000000000..0f1c66e4a6e6 --- /dev/null +++ b/apps/meteor/client/components/UserCard/UserCardDialog.tsx @@ -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; + +const UserCardDialog = (props: UserCardDialogProps) => { + const ref = useRef(null); + const { dialogProps } = useDialog(props, ref); + + return ( + + ); +}; + +export default UserCardDialog; diff --git a/apps/meteor/client/components/UserCard/UserCardSkeleton.tsx b/apps/meteor/client/components/UserCard/UserCardSkeleton.tsx index 9339eca8f665..b85f672caa12 100644 --- a/apps/meteor/client/components/UserCard/UserCardSkeleton.tsx +++ b/apps/meteor/client/components/UserCard/UserCardSkeleton.tsx @@ -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>(function UserCardSkeleton(props, ref) { +const UserCardSkeleton = (props: ComponentProps) => { return ( - + @@ -27,8 +27,8 @@ const UserCardSkeleton = forwardRef ))} - + ); -}); +}; export default UserCardSkeleton; diff --git a/apps/meteor/client/components/message/MessageHeader.tsx b/apps/meteor/client/components/message/MessageHeader.tsx index d708d933ac6d..a6ad5feaff96 100644 --- a/apps/meteor/client/components/message/MessageHeader.tsx +++ b/apps/meteor/client/components/message/MessageHeader.tsx @@ -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'; @@ -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) }; @@ -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 ( chat?.userCard.openUserCard(e, message.u.username), - onKeyDown: (e: KeyboardEvent) => { - (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) => { + (e.code === 'Enter' || e.code === 'Space') && openUserCard(e, message.u.username); + }} + style={{ cursor: 'pointer' }} + {...triggerProps} > chat?.userCard.openUserCard(e, message.u.username), - style: { cursor: 'pointer' }, - })} + onClick={(e) => openUserCard(e, message.u.username)} + style={{ cursor: 'pointer' }} + role='button' + {...triggerProps} /> )} {selecting && } diff --git a/apps/meteor/client/components/message/variants/SystemMessage.tsx b/apps/meteor/client/components/message/variants/SystemMessage.tsx index 9bb254beaec5..d69b1ada10dc 100644 --- a/apps/meteor/client/components/message/variants/SystemMessage.tsx +++ b/apps/meteor/client/components/message/variants/SystemMessage.tsx @@ -14,7 +14,7 @@ import { import { UserAvatar } from '@rocket.chat/ui-avatar'; import type { TranslationKey } from '@rocket.chat/ui-contexts'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import type { ComponentProps, ReactElement } from 'react'; +import type { ComponentProps, ReactElement, KeyboardEvent } from 'react'; import React, { memo } from 'react'; import { MessageTypes } from '../../../../app/ui-utils/client'; @@ -29,7 +29,7 @@ import { useIsSelectedMessage, useCountSelected, } from '../../../views/room/MessageList/contexts/SelectedMessagesContext'; -import { useChat } from '../../../views/room/contexts/ChatContext'; +import { useUserCard } from '../../../views/room/contexts/UserCardContext'; import Attachments from '../content/Attachments'; import MessageActions from '../content/MessageActions'; import { useMessageListShowRealName, useMessageListShowUsername } from '../list/MessageListContext'; @@ -43,7 +43,7 @@ const SystemMessage = ({ message, showUserAvatar, ...props }: SystemMessageProps const t = useTranslation(); const formatTime = useFormatTime(); const formatDateAndTime = useFormatDateAndTime(); - const chat = useChat(); + const { triggerProps, openUserCard } = useUserCard(); const showRealName = useMessageListShowRealName(); const user: UserPresence = { ...message.u, roles: [], ...useUserData(message.u._id) }; @@ -74,31 +74,18 @@ const SystemMessage = ({ message, showUserAvatar, ...props }: SystemMessageProps - - user.username && chat?.userCard.openUserCard(e, user.username), - style: { cursor: 'pointer' }, - })} - > - {getUserDisplayName(user.name, user.username, showRealName)} - - {showUsername && ( - <> - {' '} - user.username && chat?.userCard.openUserCard(e, user.username), - style: { cursor: 'pointer' }, - })} - > - @{user.username} - - - )} + user.username && openUserCard(e, user.username)} + onKeyDown={(e: KeyboardEvent) => { + (e.code === 'Enter' || e.code === 'Space') && openUserCard(e, message.u.username); + }} + style={{ cursor: 'pointer' }} + {...triggerProps} + > + {getUserDisplayName(user.name, user.username, showRealName)} + {showUsername && @{user.username}} {messageType && ( chat?.userCard.openUserCard(e, message.u.username), - style: { cursor: 'pointer' }, - })} + onClick={(e) => openUserCard(e, message.u.username)} + style={{ cursor: 'pointer' }} + role='button' + {...triggerProps} /> )} {sequential && } diff --git a/apps/meteor/client/lib/chats/ChatAPI.ts b/apps/meteor/client/lib/chats/ChatAPI.ts index d2364cfcd72c..ceffab987a64 100644 --- a/apps/meteor/client/lib/chats/ChatAPI.ts +++ b/apps/meteor/client/lib/chats/ChatAPI.ts @@ -1,6 +1,5 @@ import type { IMessage, IRoom, ISubscription } from '@rocket.chat/core-typings'; import type { IActionManager } from '@rocket.chat/ui-contexts'; -import type { UIEvent } from 'react'; import type { FormattingButton } from '../../../app/ui-message/client/messageBox/messageBoxFormatting'; import type { Subscribable } from '../../definitions/Subscribable'; @@ -126,11 +125,6 @@ export type ChatAPI = { } | undefined; - readonly userCard: { - openUserCard(event: UIEvent, username: string): void; - closeUserCard(): void; - }; - readonly emojiPicker: { open(el: Element, cb: (emoji: string) => void): void; close(): void; diff --git a/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx b/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx index a1b9ba1ca3af..9c779d1d5ea3 100644 --- a/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx +++ b/apps/meteor/client/views/omnichannel/contactHistory/MessageList/ContactHistoryMessage.tsx @@ -29,7 +29,7 @@ import Attachments from '../../../../components/message/content/Attachments'; import UiKitMessageBlock from '../../../../components/message/uikit/UiKitMessageBlock'; import { useFormatDate } from '../../../../hooks/useFormatDate'; import { useFormatTime } from '../../../../hooks/useFormatTime'; -import { useChat } from '../../../room/contexts/ChatContext'; +import { useUserCard } from '../../../room/contexts/UserCardContext'; const ContactHistoryMessage: FC<{ message: IMessage; @@ -37,12 +37,12 @@ const ContactHistoryMessage: FC<{ isNewDay: boolean; showUserAvatar: boolean; }> = ({ message, sequential, isNewDay, showUserAvatar }) => { + const t = useTranslation(); + const { triggerProps, openUserCard } = useUserCard(); + const format = useFormatDate(); const formatTime = useFormatTime(); - const t = useTranslation(); - const chat = useChat(); - if (message.t === 'livechat-close') { return ( @@ -52,8 +52,10 @@ const ContactHistoryMessage: FC<{ url={message.avatar} username={message.u.username} size='x18' - onClick={(e) => chat?.userCard.openUserCard(e, message.u.username)} + onClick={(e) => openUserCard(e, message.u.username)} style={{ cursor: 'pointer' }} + role='button' + {...triggerProps} /> )} @@ -80,8 +82,10 @@ const ContactHistoryMessage: FC<{ url={message.avatar} username={message.u.username} size='x36' - onClick={(e) => chat?.userCard.openUserCard(e, message.u.username)} + onClick={(e) => openUserCard(e, message.u.username)} style={{ cursor: 'pointer' }} + role='button' + {...triggerProps} /> )} {sequential && } diff --git a/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx b/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx index 0337c794f245..40244b04beba 100644 --- a/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx +++ b/apps/meteor/client/views/room/UserCard/UserCardWithData.tsx @@ -1,12 +1,10 @@ import type { IRoom } from '@rocket.chat/core-typings'; -import { PositionAnimated, AnimatedVisibility } from '@rocket.chat/fuselage'; -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import { useSetting, useRolesDescription, useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement } from 'react'; -import React, { useMemo, useRef } from 'react'; +import React, { useMemo } from 'react'; import { getUserDisplayName } from '../../../../lib/getUserDisplayName'; -import { Backdrop } from '../../../components/Backdrop'; import GenericMenu from '../../../components/GenericMenu/GenericMenu'; import LocalTime from '../../../components/LocalTime'; import { UserCard, UserCardAction, UserCardRole, UserCardSkeleton } from '../../../components/UserCard'; @@ -16,22 +14,18 @@ import { useUserInfoActions } from '../hooks/useUserInfoActions'; type UserCardWithDataProps = { username: string; - target: Element; rid: IRoom['_id']; onOpenUserInfo: () => void; onClose: () => void; }; -const UserCardWithData = ({ username, target, rid, onOpenUserInfo, onClose }: UserCardWithDataProps) => { +const UserCardWithData = ({ username, rid, onOpenUserInfo, onClose }: UserCardWithDataProps) => { const t = useTranslation(); - const ref = useRef(target); const getRoles = useRolesDescription(); const showRealNames = Boolean(useSetting('UI_Use_Real_Name')); const { data, isLoading } = useUserInfoQuery({ username }); - ref.current = target; - const user = useMemo(() => { const defaultValue = isLoading ? undefined : null; @@ -60,7 +54,7 @@ const UserCardWithData = ({ username, target, rid, onOpenUserInfo, onClose }: Us }; }, [data, username, showRealNames, isLoading, getRoles]); - const handleOpenUserInfo = useMutableCallback(() => { + const handleOpenUserInfo = useEffectEvent(() => { onOpenUserInfo(); onClose(); }); @@ -86,14 +80,11 @@ const UserCardWithData = ({ username, target, rid, onOpenUserInfo, onClose }: Us return [...actionsDefinition.map(mapAction), menu].filter(Boolean); }, [actionsDefinition, menu]); - return ( - <> - - - {isLoading ? : } - - - ); + if (isLoading) { + return ; + } + + return ; }; export default UserCardWithData; diff --git a/apps/meteor/client/views/room/body/LeaderBar.tsx b/apps/meteor/client/views/room/body/LeaderBar.tsx index 6de7c3d52e8e..4cf5266b89d8 100644 --- a/apps/meteor/client/views/room/body/LeaderBar.tsx +++ b/apps/meteor/client/views/room/body/LeaderBar.tsx @@ -5,6 +5,7 @@ import { UserAvatar } from '@rocket.chat/ui-avatar'; import { useTranslation } from '@rocket.chat/ui-contexts'; import type { ReactElement, UIEvent } from 'react'; import React, { memo, useCallback, useMemo } from 'react'; +import type { AriaButtonProps } from 'react-aria'; import { isTruthy } from '../../../../lib/isTruthy'; import { ReactiveUserStatus } from '../../../components/UserStatus'; @@ -16,9 +17,10 @@ type LeaderBarProps = { username: IUser['username']; visible: boolean; onAvatarClick?: (event: UIEvent, username: IUser['username']) => void; + triggerProps: AriaButtonProps<'button'>; }; -const LeaderBar = ({ _id, name, username, visible, onAvatarClick }: LeaderBarProps): ReactElement => { +const LeaderBar = ({ _id, name, username, visible, onAvatarClick, triggerProps }: LeaderBarProps): ReactElement => { const t = useTranslation(); const chatNowLink = useMemo(() => roomCoordinator.getRouteLink('d', { name: username }) || undefined, [username]); @@ -64,7 +66,7 @@ const LeaderBar = ({ _id, name, username, visible, onAvatarClick }: LeaderBarPro className={[roomLeaderStyle, 'room-leader', !visible && 'animated-hidden'].filter(isTruthy)} > - + diff --git a/apps/meteor/client/views/room/body/RoomBody.tsx b/apps/meteor/client/views/room/body/RoomBody.tsx index 4ec51aa67fda..983695b1fa70 100644 --- a/apps/meteor/client/views/room/body/RoomBody.tsx +++ b/apps/meteor/client/views/room/body/RoomBody.tsx @@ -35,6 +35,7 @@ import RoomComposer from '../composer/RoomComposer/RoomComposer'; import { useChat } from '../contexts/ChatContext'; import { useRoom, useRoomSubscription, useRoomMessages } from '../contexts/RoomContext'; import { useRoomToolbox } from '../contexts/RoomToolboxContext'; +import { useUserCard } from '../contexts/UserCardContext'; import { useMessageListNavigation } from '../hooks/useMessageListNavigation'; import { useScrollMessageList } from '../hooks/useScrollMessageList'; import DropTargetOverlay from './DropTargetOverlay'; @@ -75,6 +76,7 @@ const RoomBody = (): ReactElement => { const lastScrollTopRef = useRef(0); const chat = useChat(); + const { openUserCard, triggerProps } = useUserCard(); if (!chat) { throw new Error('No ChatContext provided'); @@ -181,9 +183,9 @@ const RoomBody = (): ReactElement => { return; } - chat?.userCard.openUserCard(event, username); + openUserCard(event, username); }, - [chat?.userCard], + [openUserCard], ); const handleUnreadBarJumpToButtonClick = useCallback(() => { @@ -588,6 +590,7 @@ const RoomBody = (): ReactElement => { name={roomLeader.name} visible={!hideLeaderHeader} onAvatarClick={handleOpenUserCard} + triggerProps={triggerProps} /> ) : null}
void; closeUserCard: () => void; + triggerProps: AriaButtonProps<'button'>; + triggerRef: MutableRefObject; + state: OverlayTriggerState; }; export const UserCardContext = createContext({ openUserCard: () => undefined, closeUserCard: () => undefined, + triggerProps: {}, + triggerRef: { current: null }, + state: { isOpen: false, setOpen: () => undefined, open: () => undefined, close: () => undefined, toggle: () => undefined }, }); export const useUserCard = () => useContext(UserCardContext); diff --git a/apps/meteor/client/views/room/modals/ReactionListModal/ReactionListModal.tsx b/apps/meteor/client/views/room/modals/ReactionListModal/ReactionListModal.tsx index 596d74977b3d..70a91df0e555 100644 --- a/apps/meteor/client/views/room/modals/ReactionListModal/ReactionListModal.tsx +++ b/apps/meteor/client/views/room/modals/ReactionListModal/ReactionListModal.tsx @@ -1,6 +1,6 @@ import type { IMessage } from '@rocket.chat/core-typings'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import type { ReactElement, UIEvent } from 'react'; +import type { ReactElement } from 'react'; import React from 'react'; import GenericModal from '../../../../components/GenericModal'; @@ -8,16 +8,15 @@ import Reactions from './Reactions'; type ReactionListModalProps = { reactions: Required['reactions']; - onOpenUserCard?: (e: UIEvent, username: string) => void; onClose: () => void; }; -const ReactionListModal = ({ reactions, onOpenUserCard, onClose }: ReactionListModalProps): ReactElement => { +const ReactionListModal = ({ reactions, onClose }: ReactionListModalProps): ReactElement => { const t = useTranslation(); return ( - + ); }; diff --git a/apps/meteor/client/views/room/modals/ReactionListModal/ReactionUserTag.tsx b/apps/meteor/client/views/room/modals/ReactionListModal/ReactionUserTag.tsx index 4c13ac8af532..0cc2ef3aa4bc 100644 --- a/apps/meteor/client/views/room/modals/ReactionListModal/ReactionUserTag.tsx +++ b/apps/meteor/client/views/room/modals/ReactionListModal/ReactionUserTag.tsx @@ -1,30 +1,11 @@ -import type { IUser } from '@rocket.chat/core-typings'; import { Box, Tag } from '@rocket.chat/fuselage'; -import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; -import type { ReactElement, UIEvent } from 'react'; +import type { ReactElement } from 'react'; import React from 'react'; -type ReactionUserTagProps = { - username: IUser['username']; - displayName: string; - onOpenUserCard?: (e: UIEvent, username: string) => void; -}; +const ReactionUserTag = ({ displayName }: { displayName: string }): ReactElement => ( + + {displayName} + +); -const ReactionUserTag = ({ username, displayName, onOpenUserCard }: ReactionUserTagProps): ReactElement => { - const handleOpenCard = useEffectEvent((e: UIEvent) => { - if (!username) { - return; - } - - onOpenUserCard?.(e, username); - }); - - return ( - - - {displayName} - - - ); -}; export default ReactionUserTag; diff --git a/apps/meteor/client/views/room/modals/ReactionListModal/Reactions.tsx b/apps/meteor/client/views/room/modals/ReactionListModal/Reactions.tsx index d766661de3e5..1e4d997bdfbc 100644 --- a/apps/meteor/client/views/room/modals/ReactionListModal/Reactions.tsx +++ b/apps/meteor/client/views/room/modals/ReactionListModal/Reactions.tsx @@ -1,18 +1,13 @@ import type { IMessage } from '@rocket.chat/core-typings'; import { Box } from '@rocket.chat/fuselage'; import { useSetting } from '@rocket.chat/ui-contexts'; -import type { ReactElement, UIEvent } from 'react'; +import type { ReactElement } from 'react'; import React from 'react'; import Emoji from '../../../../components/Emoji'; import ReactionUserTag from './ReactionUserTag'; -type ReactionsProps = { - reactions: Required['reactions']; - onOpenUserCard?: (e: UIEvent, username: string) => void; -}; - -const Reactions = ({ reactions, onOpenUserCard }: ReactionsProps): ReactElement => { +const Reactions = ({ reactions }: { reactions: Required['reactions'] }): ReactElement => { const useRealName = useSetting('UI_Use_Real_Name'); return ( @@ -22,12 +17,7 @@ const Reactions = ({ reactions, onOpenUserCard }: ReactionsProps): ReactElement {usernames.map((username, i: number) => ( - + ))} diff --git a/apps/meteor/client/views/room/providers/UserCardProvider.tsx b/apps/meteor/client/views/room/providers/UserCardProvider.tsx index 47a9f1cd744e..004cfbfda5aa 100644 --- a/apps/meteor/client/views/room/providers/UserCardProvider.tsx +++ b/apps/meteor/client/views/room/providers/UserCardProvider.tsx @@ -1,6 +1,9 @@ -import { useMutableCallback } from '@rocket.chat/fuselage-hooks'; +import { Popover } from '@rocket.chat/fuselage'; +import { useEffectEvent } from '@rocket.chat/fuselage-hooks'; import type { ComponentProps, ReactNode } from 'react'; -import React, { Suspense, lazy, useCallback, useMemo, useState } from 'react'; +import React, { Suspense, lazy, useCallback, useMemo, useRef, useState } from 'react'; +import { useOverlayTrigger } from 'react-aria'; +import { useOverlayTriggerState } from 'react-stately'; import { useRoom } from '../contexts/RoomContext'; import { useRoomToolbox } from '../contexts/RoomToolboxContext'; @@ -12,9 +15,14 @@ const UserCardProvider = ({ children }: { children: ReactNode }) => { const room = useRoom(); const [userCardData, setUserCardData] = useState | null>(null); + const triggerRef = useRef(null); + const state = useOverlayTriggerState({}); + const { triggerProps, overlayProps } = useOverlayTrigger({ type: 'dialog' }, state, triggerRef); + delete triggerProps.onPress; + const { openTab } = useRoomToolbox(); - const openUserInfo = useMutableCallback((username?: string) => { + const openUserInfo = useEffectEvent((username?: string) => { switch (room.t) { case 'l': openTab('room-info', username); @@ -36,31 +44,37 @@ const UserCardProvider = ({ children }: { children: ReactNode }) => { const handleSetUserCard = useCallback( (e, username) => { + triggerRef.current = e.target; + state.open(); setUserCardData({ username, rid: room._id, - target: e.target, onOpenUserInfo: () => openUserInfo(username), onClose: () => setUserCardData(null), }); }, - [openUserInfo, room._id], + [openUserInfo, room._id, state], ); const contextValue = useMemo( () => ({ openUserCard: handleSetUserCard, closeUserCard: () => setUserCardData(null), + triggerProps, + triggerRef, + state, }), - [handleSetUserCard], + [handleSetUserCard, state, triggerProps], ); return ( {children} - {userCardData && ( + {state.isOpen && userCardData && ( - + + + )} diff --git a/apps/meteor/client/views/room/providers/hooks/useChatMessagesInstance.ts b/apps/meteor/client/views/room/providers/hooks/useChatMessagesInstance.ts index 023e99a99dd9..290b1c4be680 100644 --- a/apps/meteor/client/views/room/providers/hooks/useChatMessagesInstance.ts +++ b/apps/meteor/client/views/room/providers/hooks/useChatMessagesInstance.ts @@ -7,7 +7,6 @@ import { useEmojiPicker } from '../../../../contexts/EmojiPickerContext'; import type { ChatAPI } from '../../../../lib/chats/ChatAPI'; import { useUiKitActionManager } from '../../../../uikit/hooks/useUiKitActionManager'; import { useRoomSubscription } from '../../contexts/RoomContext'; -import { useUserCard } from '../../contexts/UserCardContext'; import { useInstance } from './useInstance'; export function useChatMessagesInstance({ rid, tmid }: { rid: IRoom['_id']; tmid?: IMessage['_id'] }): ChatAPI { @@ -27,7 +26,6 @@ export function useChatMessagesInstance({ rid, tmid }: { rid: IRoom['_id']; tmid }, [subscription, chatMessages?.readStateManager]); chatMessages.emojiPicker = useEmojiPicker(); - chatMessages.userCard = useUserCard(); return chatMessages; } diff --git a/apps/meteor/package.json b/apps/meteor/package.json index de5e4eacb9b8..0d9d0ecd3b70 100644 --- a/apps/meteor/package.json +++ b/apps/meteor/package.json @@ -240,7 +240,7 @@ "@rocket.chat/favicon": "workspace:^", "@rocket.chat/forked-matrix-appservice-bridge": "^4.0.2", "@rocket.chat/forked-matrix-bot-sdk": "^0.6.0-beta.3", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/fuselage-hooks": "^0.33.0", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/fuselage-toastbar": "~0.31.25", diff --git a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json index 60ffa84825f0..f54d8c1aac28 100644 --- a/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json +++ b/apps/meteor/packages/rocketchat-i18n/i18n/en.i18n.json @@ -5439,6 +5439,7 @@ "Use_url_for_avatar": "Use URL for avatar", "Use_User_Preferences_or_Global_Settings": "Use User Preferences or Global Settings", "User": "User", + "User_card_actions": "User card actions", "User_menu": "User menu", "User Search": "User Search", "User Search (Group Validation)": "User Search (Group Validation)", diff --git a/apps/meteor/tests/e2e/messaging.spec.ts b/apps/meteor/tests/e2e/messaging.spec.ts index a333e3d5b3ce..4fa248e72183 100644 --- a/apps/meteor/tests/e2e/messaging.spec.ts +++ b/apps/meteor/tests/e2e/messaging.spec.ts @@ -61,6 +61,32 @@ test.describe.serial('Messaging', () => { await expect(poHomeChannel.composer).toBeFocused(); }); + test('should navigate properly on the user card', async ({ page }) => { + await poHomeChannel.sidenav.openChat(targetChannel); + + // open UserCard + await page.keyboard.press('Shift+Tab'); + await page.keyboard.press('ArrowUp'); + await page.keyboard.press('Tab'); + await page.keyboard.press('Space'); + await expect(poHomeChannel.userCardToolbar).toBeVisible(); + + // close UserCard with Esc + await page.keyboard.press('Escape'); + await expect(poHomeChannel.userCardToolbar).not.toBeVisible(); + + // with focus restored reopen toolbar + await page.keyboard.press('Space'); + await expect(poHomeChannel.userCardToolbar).toBeVisible(); + + // close UserCard with button + await page.keyboard.press('Tab'); + await page.keyboard.press('Tab'); + await page.keyboard.press('Tab'); + await page.keyboard.press('Space'); + await expect(poHomeChannel.userCardToolbar).not.toBeVisible(); + }) + test('should not restore focus on the last focused if it was triggered by click', async ({ page }) => { await poHomeChannel.sidenav.openChat(targetChannel); await page.locator('[data-qa-type="message"]:has-text("msg1")').click(); diff --git a/apps/meteor/tests/e2e/page-objects/home-channel.ts b/apps/meteor/tests/e2e/page-objects/home-channel.ts index 01dcc302d3e0..3b17d7d7ddcc 100644 --- a/apps/meteor/tests/e2e/page-objects/home-channel.ts +++ b/apps/meteor/tests/e2e/page-objects/home-channel.ts @@ -45,6 +45,10 @@ export class HomeChannel { return this.page.locator('textarea[name="msg"]'); } + get userCardToolbar(): Locator { + return this.page.locator('[role=toolbar][aria-label="User card actions"]'); + } + get composerToolbar(): Locator { return this.page.locator('[role=toolbar][aria-label="Composer Primary Actions"]'); } diff --git a/ee/packages/ui-theming/package.json b/ee/packages/ui-theming/package.json index 87cab03460df..63732ae16db5 100644 --- a/ee/packages/ui-theming/package.json +++ b/ee/packages/ui-theming/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/fuselage-hooks": "^0.33.0", "@rocket.chat/icons": "^0.33.0", "@rocket.chat/ui-contexts": "workspace:~", diff --git a/packages/fuselage-ui-kit/package.json b/packages/fuselage-ui-kit/package.json index ecd7e25fa256..69a1f1525edd 100644 --- a/packages/fuselage-ui-kit/package.json +++ b/packages/fuselage-ui-kit/package.json @@ -63,7 +63,7 @@ "@babel/preset-typescript": "~7.22.15", "@rocket.chat/apps-engine": "1.41.0", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/fuselage-hooks": "^0.33.0", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/icons": "^0.33.0", diff --git a/packages/gazzodown/package.json b/packages/gazzodown/package.json index 108329360d05..da2d978b46c5 100644 --- a/packages/gazzodown/package.json +++ b/packages/gazzodown/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@rocket.chat/core-typings": "workspace:^", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/fuselage-tokens": "~0.32.0", "@rocket.chat/message-parser": "workspace:^", "@rocket.chat/styled": "~0.31.25", diff --git a/packages/gazzodown/src/MarkupInteractionContext.ts b/packages/gazzodown/src/MarkupInteractionContext.ts index 70fc32d33496..b2fb11f5378b 100644 --- a/packages/gazzodown/src/MarkupInteractionContext.ts +++ b/packages/gazzodown/src/MarkupInteractionContext.ts @@ -1,6 +1,7 @@ import type { MessageMention } from '@rocket.chat/core-typings'; import type * as MessageParser from '@rocket.chat/message-parser'; import { createContext, FormEvent, UIEvent } from 'react'; +import { AriaButtonProps } from 'react-aria'; export type UserMention = MessageMention; export type ChannelMention = MessageMention; @@ -20,6 +21,7 @@ type MarkupInteractionContextValue = { isMobile?: boolean; ownUserId?: string | null; showMentionSymbol?: boolean; + triggerProps?: AriaButtonProps<'button'>; }; export const MarkupInteractionContext = createContext({}); diff --git a/packages/gazzodown/src/mentions/ChannelMentionElement.tsx b/packages/gazzodown/src/mentions/ChannelMentionElement.tsx index c871b332824a..6b8e8518a422 100644 --- a/packages/gazzodown/src/mentions/ChannelMentionElement.tsx +++ b/packages/gazzodown/src/mentions/ChannelMentionElement.tsx @@ -1,6 +1,6 @@ import { Message } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import { memo, ReactElement, useContext, useMemo } from 'react'; +import { memo, ReactElement, useContext, useMemo, KeyboardEvent } from 'react'; import { MarkupInteractionContext } from '../MarkupInteractionContext'; @@ -22,7 +22,17 @@ const ChannelMentionElement = ({ mention }: ChannelMentionElementProps): ReactEl } return ( - + ): void => { + (e.code === 'Enter' || e.code === 'Space') && handleClick?.(e); + }} + > {handleChannelMention(resolved.fname ?? mention, showMentionSymbol)} ); diff --git a/packages/gazzodown/src/mentions/UserMentionElement.tsx b/packages/gazzodown/src/mentions/UserMentionElement.tsx index a25106918af8..a9ba5567541f 100644 --- a/packages/gazzodown/src/mentions/UserMentionElement.tsx +++ b/packages/gazzodown/src/mentions/UserMentionElement.tsx @@ -1,6 +1,6 @@ import { Message } from '@rocket.chat/fuselage'; import { useTranslation } from '@rocket.chat/ui-contexts'; -import { memo, ReactElement, useContext, useMemo } from 'react'; +import { memo, ReactElement, useContext, useMemo, KeyboardEvent } from 'react'; import { MarkupInteractionContext } from '../MarkupInteractionContext'; @@ -13,7 +13,8 @@ const handleUserMention = (mention: string | undefined, withSymbol: boolean | un const UserMentionElement = ({ mention }: UserMentionElementProps): ReactElement => { const t = useTranslation(); - const { resolveUserMention, onUserMentionClick, ownUserId, useRealName, showMentionSymbol } = useContext(MarkupInteractionContext); + const { resolveUserMention, onUserMentionClick, ownUserId, useRealName, showMentionSymbol, triggerProps } = + useContext(MarkupInteractionContext); const resolved = useMemo(() => resolveUserMention?.(mention), [mention, resolveUserMention]); const handleClick = useMemo(() => (resolved ? onUserMentionClick?.(resolved) : undefined), [resolved, onUserMentionClick]); @@ -43,7 +44,13 @@ const UserMentionElement = ({ mention }: UserMentionElementProps): ReactElement variant={resolved._id === ownUserId ? 'critical' : 'other'} title={resolved._id === ownUserId ? t('Mentions_you') : t('Mentions_user')} clickable + tabIndex={0} + role='button' onClick={handleClick} + onKeyDown={(e: KeyboardEvent): void => { + (e.code === 'Enter' || e.code === 'Space') && handleClick?.(e); + }} + {...triggerProps} data-uid={resolved._id} > {handleUserMention((useRealName ? resolved.name : resolved.username) ?? mention, showMentionSymbol)} diff --git a/packages/ui-avatar/package.json b/packages/ui-avatar/package.json index 853178aae3a9..e968d4567d9c 100644 --- a/packages/ui-avatar/package.json +++ b/packages/ui-avatar/package.json @@ -4,7 +4,7 @@ "private": true, "devDependencies": { "@babel/core": "~7.22.20", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/ui-contexts": "workspace:^", "@types/babel__core": "~7.20.3", "@types/react": "~17.0.69", diff --git a/packages/ui-client/package.json b/packages/ui-client/package.json index 85b3fac423ac..64b39555e3a2 100644 --- a/packages/ui-client/package.json +++ b/packages/ui-client/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@react-aria/toolbar": "^3.0.0-beta.1", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/fuselage-hooks": "^0.33.0", "@rocket.chat/icons": "^0.33.0", "@rocket.chat/mock-providers": "workspace:^", diff --git a/packages/ui-composer/package.json b/packages/ui-composer/package.json index a1fbe39a6142..f3ac9ea3d555 100644 --- a/packages/ui-composer/package.json +++ b/packages/ui-composer/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@react-aria/toolbar": "^3.0.0-beta.1", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/icons": "^0.33.0", "@storybook/addon-actions": "~6.5.16", "@storybook/addon-docs": "~6.5.16", diff --git a/packages/ui-video-conf/package.json b/packages/ui-video-conf/package.json index 283630b6e9d6..156d5594fabe 100644 --- a/packages/ui-video-conf/package.json +++ b/packages/ui-video-conf/package.json @@ -6,7 +6,7 @@ "@babel/core": "~7.22.20", "@rocket.chat/css-in-js": "~0.31.25", "@rocket.chat/eslint-config": "workspace:^", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/fuselage-hooks": "^0.33.0", "@rocket.chat/icons": "^0.33.0", "@rocket.chat/styled": "~0.31.25", diff --git a/packages/uikit-playground/package.json b/packages/uikit-playground/package.json index f623c71210bf..6028c769f189 100644 --- a/packages/uikit-playground/package.json +++ b/packages/uikit-playground/package.json @@ -15,7 +15,7 @@ "@codemirror/tooltip": "^0.19.16", "@lezer/highlight": "^1.1.6", "@rocket.chat/css-in-js": "~0.31.25", - "@rocket.chat/fuselage": "^0.47.0", + "@rocket.chat/fuselage": "^0.47.1", "@rocket.chat/fuselage-hooks": "^0.33.0", "@rocket.chat/fuselage-polyfills": "~0.31.25", "@rocket.chat/fuselage-toastbar": "^0.31.25", diff --git a/yarn.lock b/yarn.lock index 066187e54b31..8b8833493494 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8717,7 +8717,7 @@ __metadata: "@babel/preset-typescript": ~7.22.15 "@rocket.chat/apps-engine": 1.41.0 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/fuselage-hooks": ^0.33.0 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/gazzodown": "workspace:^" @@ -8772,9 +8772,9 @@ __metadata: languageName: unknown linkType: soft -"@rocket.chat/fuselage@npm:^0.47.0": - version: 0.47.0 - resolution: "@rocket.chat/fuselage@npm:0.47.0" +"@rocket.chat/fuselage@npm:^0.47.1": + version: 0.47.1 + resolution: "@rocket.chat/fuselage@npm:0.47.1" dependencies: "@rocket.chat/css-in-js": ^0.31.25 "@rocket.chat/css-supports": ^0.31.25 @@ -8792,7 +8792,7 @@ __metadata: react: ^17.0.2 react-dom: ^17.0.2 react-virtuoso: 1.2.4 - checksum: 4ca06bd467db88b5c4c3eed70bbd8879923cfbe7f5a92bd934ed0f800b37825592d84753e124a3f2c70d4e9d82bf5dac6bc2735ea93ccfa26fddc6ab49ea8094 + checksum: d812e4ed52b53372268b4f5d396fb8d6aeb3f46a4f7e276642edf287ca2038f88e2a6d8bc0264f95fee1772aadc849419f7695e35cc6a278111efcbc18e1472d languageName: node linkType: hard @@ -8803,7 +8803,7 @@ __metadata: "@babel/core": ~7.22.20 "@rocket.chat/core-typings": "workspace:^" "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/fuselage-tokens": ~0.32.0 "@rocket.chat/message-parser": "workspace:^" "@rocket.chat/styled": ~0.31.25 @@ -9158,7 +9158,7 @@ __metadata: "@rocket.chat/favicon": "workspace:^" "@rocket.chat/forked-matrix-appservice-bridge": ^4.0.2 "@rocket.chat/forked-matrix-bot-sdk": ^0.6.0-beta.3 - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/fuselage-hooks": ^0.33.0 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/fuselage-toastbar": ~0.31.25 @@ -10037,7 +10037,7 @@ __metadata: resolution: "@rocket.chat/ui-avatar@workspace:packages/ui-avatar" dependencies: "@babel/core": ~7.22.20 - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/ui-contexts": "workspace:^" "@types/babel__core": ~7.20.3 "@types/react": ~17.0.69 @@ -10063,7 +10063,7 @@ __metadata: "@babel/core": ~7.22.20 "@react-aria/toolbar": ^3.0.0-beta.1 "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/fuselage-hooks": ^0.33.0 "@rocket.chat/icons": ^0.33.0 "@rocket.chat/mock-providers": "workspace:^" @@ -10116,7 +10116,7 @@ __metadata: "@babel/core": ~7.22.20 "@react-aria/toolbar": ^3.0.0-beta.1 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/icons": ^0.33.0 "@storybook/addon-actions": ~6.5.16 "@storybook/addon-docs": ~6.5.16 @@ -10208,7 +10208,7 @@ __metadata: resolution: "@rocket.chat/ui-theming@workspace:ee/packages/ui-theming" dependencies: "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/fuselage-hooks": ^0.33.0 "@rocket.chat/icons": ^0.33.0 "@rocket.chat/ui-contexts": "workspace:~" @@ -10251,7 +10251,7 @@ __metadata: "@rocket.chat/css-in-js": ~0.31.25 "@rocket.chat/emitter": ~0.31.25 "@rocket.chat/eslint-config": "workspace:^" - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/fuselage-hooks": ^0.33.0 "@rocket.chat/icons": ^0.33.0 "@rocket.chat/styled": ~0.31.25 @@ -10296,7 +10296,7 @@ __metadata: "@codemirror/tooltip": ^0.19.16 "@lezer/highlight": ^1.1.6 "@rocket.chat/css-in-js": ~0.31.25 - "@rocket.chat/fuselage": ^0.47.0 + "@rocket.chat/fuselage": ^0.47.1 "@rocket.chat/fuselage-hooks": ^0.33.0 "@rocket.chat/fuselage-polyfills": ~0.31.25 "@rocket.chat/fuselage-toastbar": ^0.31.25