From f6ab8dc36dc4f0cc53f43b14bbda83d9c94ecc54 Mon Sep 17 00:00:00 2001 From: Olaf Sulich Date: Wed, 8 Jan 2025 13:45:15 +0100 Subject: [PATCH 1/4] refactor(KeyboardUtil): handleKeyDown to accept object as a param instead of multiple args --- src/script/auth/page/OAuthPermissions.tsx | 4 +- src/script/components/Avatar/Avatar.tsx | 4 +- .../HistoryImport/BackupFileUpload.tsx | 4 +- .../ContentMessage/asset/AssetLoader.tsx | 4 +- .../asset/FileAssetComponent.tsx | 4 +- .../asset/ImageAsset/ImageAsset.tsx | 6 +- .../asset/LinkPreviewAssetComponent.tsx | 4 +- .../TextMessageRenderer.tsx | 12 +- .../Modals/DetailViewModal/index.tsx | 6 +- .../components/Modals/UserModal/UserModal.tsx | 10 +- .../MentionsPlugin/MentionSuggestionsItem.tsx | 10 +- .../components/SelectText/SelectText.tsx | 10 +- .../ServiceListItem/ServiceListItem.tsx | 10 +- src/script/components/TitleBar/TitleBar.tsx | 10 +- .../components/DeviceCard/DeviceCard.tsx | 10 +- .../CallParticipantsListItem.tsx | 12 +- .../components/calling/DeviceToggleButton.tsx | 10 +- .../calling/FullscreenVideoCall.tsx | 106 +++++++++++++++--- src/script/components/calling/Pagination.tsx | 10 +- .../ConnectionRequests/ConnectionRequests.tsx | 10 +- .../components/groupList/GroupListItem.tsx | 10 +- .../components/topPeople/TopContact.tsx | 11 +- .../Collection/fullSearch/FullSearchItem.tsx | 10 +- .../components/Device/Device.tsx | 10 +- .../accountPreferences/AvatarInput.tsx | 10 +- .../AddParticipants/AddParticipants.tsx | 34 +++++- .../GroupParticipantService.tsx | 18 ++- .../GroupParticipantUser.tsx | 10 +- src/script/util/KeyboardUtil.ts | 15 ++- 29 files changed, 304 insertions(+), 80 deletions(-) diff --git a/src/script/auth/page/OAuthPermissions.tsx b/src/script/auth/page/OAuthPermissions.tsx index 828789fc8a6..47a4d1cb597 100644 --- a/src/script/auth/page/OAuthPermissions.tsx +++ b/src/script/auth/page/OAuthPermissions.tsx @@ -43,7 +43,7 @@ import { import * as Icon from 'Components/Icon'; import {AssetRemoteData} from 'src/script/assets/AssetRemoteData'; import {AssetRepository} from 'src/script/assets/AssetRepository'; -import {handleEscDown, handleKeyDown} from 'Util/KeyboardUtil'; +import {handleEscDown, handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {loadDataUrl} from 'Util/util'; @@ -228,7 +228,7 @@ const OAuthPermissionsComponent = ({ type="button" onClick={onContinue} data-uie-name="do-oauth-allow" - onKeyDown={event => handleKeyDown(event, () => onContinue())} + onKeyDown={event => handleKeyDown({event, callback: onContinue, keys: [KEY.ENTER, KEY.SPACE]})} > {t('oauth.allow')} diff --git a/src/script/components/Avatar/Avatar.tsx b/src/script/components/Avatar/Avatar.tsx index 62e12adb589..c4c5c423774 100644 --- a/src/script/components/Avatar/Avatar.tsx +++ b/src/script/components/Avatar/Avatar.tsx @@ -20,7 +20,7 @@ import {HTMLProps, MouseEvent as ReactMouseEvent, KeyboardEvent as ReactKeyBoardEvent} from 'react'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {handleKeyDown, isKeyboardEvent} from 'Util/KeyboardUtil'; +import {handleKeyDown, isKeyboardEvent, KEY} from 'Util/KeyboardUtil'; import {PlaceholderAvatar} from './PlaceholderAvatar'; import {ServiceAvatar} from './ServiceAvatar'; @@ -97,7 +97,7 @@ const Avatar = ({ const parentNode = event.currentTarget.parentNode; if (parentNode) { if (isKeyboardEvent(event)) { - handleKeyDown(event, () => onAvatarClick?.(participant)); + handleKeyDown({event, callback: () => onAvatarClick?.(participant), keys: [KEY.ENTER, KEY.SPACE]}); return; } onAvatarClick?.(participant); diff --git a/src/script/components/HistoryImport/BackupFileUpload.tsx b/src/script/components/HistoryImport/BackupFileUpload.tsx index afce59a304b..0bfa929ed49 100644 --- a/src/script/components/HistoryImport/BackupFileUpload.tsx +++ b/src/script/components/HistoryImport/BackupFileUpload.tsx @@ -24,7 +24,7 @@ import {TabIndex} from '@wireapp/react-ui-kit/lib/types/enums'; import {Button, ButtonVariant} from '@wireapp/react-ui-kit'; import {CONFIG as HistoryExportConfig} from 'Components/HistoryExport'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; interface BackupFileUploadProps { onFileChange: (event: React.ChangeEvent) => void; @@ -64,7 +64,7 @@ const BackupFileUpload = ({ className={cssClassName} role="button" tabIndex={TabIndex.FOCUSABLE} - onKeyDown={event => handleKeyDown(event, fileInputClick)} + onKeyDown={event => handleKeyDown({event, callback: fileInputClick, keys: [KEY.ENTER, KEY.SPACE]})} onClick={() => fileInputRef.current?.click()} aria-labelledby="do-backup-import" > diff --git a/src/script/components/MessagesList/Message/ContentMessage/asset/AssetLoader.tsx b/src/script/components/MessagesList/Message/ContentMessage/asset/AssetLoader.tsx index 7083b85cddb..bb7bc22dbf8 100644 --- a/src/script/components/MessagesList/Message/ContentMessage/asset/AssetLoader.tsx +++ b/src/script/components/MessagesList/Message/ContentMessage/asset/AssetLoader.tsx @@ -22,7 +22,7 @@ import React from 'react'; import {TabIndex} from '@wireapp/react-ui-kit/lib/types/enums'; import {CloseIcon} from 'Components/Icon'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; export interface AssetLoaderProps { large?: boolean; @@ -47,7 +47,7 @@ const AssetLoader: React.FC = ({large, loadProgress, onCancel} tabIndex={TabIndex.FOCUSABLE} className="media-button" onClick={onClick} - onKeyDown={event => handleKeyDown(event, () => onClick(event))} + onKeyDown={event => handleKeyDown({event, callback: () => onClick(event), keys: [KEY.ENTER, KEY.SPACE]})} data-uie-name="status-loading-media" >
diff --git a/src/script/components/MessagesList/Message/ContentMessage/asset/ImageAsset/ImageAsset.tsx b/src/script/components/MessagesList/Message/ContentMessage/asset/ImageAsset/ImageAsset.tsx index 8e2729e5f66..8e9d2539b89 100644 --- a/src/script/components/MessagesList/Message/ContentMessage/asset/ImageAsset/ImageAsset.tsx +++ b/src/script/components/MessagesList/Message/ContentMessage/asset/ImageAsset/ImageAsset.tsx @@ -24,7 +24,7 @@ import {CSSObject} from '@emotion/react'; import * as Icon from 'Components/Icon'; import {AssetImage} from 'Components/Image'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {ContentMessage} from '../../../../../../entity/message/ContentMessage'; @@ -79,7 +79,9 @@ export const ImageAsset = ({asset, message, onClick}: ImageAssetProps) => { data-uie-name="go-image-detail" data-uie-visible={visible && !isObfuscated} onClick={event => onClick(message, event)} - onKeyDown={event => handleKeyDown(event, onClick.bind(null, message, event))} + onKeyDown={event => + handleKeyDown({event, callback: onClick.bind(null, message, event), keys: [KEY.ENTER, KEY.SPACE]}) + } tabIndex={0} role="button" aria-label={imageAltText} diff --git a/src/script/components/MessagesList/Message/ContentMessage/asset/LinkPreviewAssetComponent.tsx b/src/script/components/MessagesList/Message/ContentMessage/asset/LinkPreviewAssetComponent.tsx index d26b84a5f85..d270dedd9c1 100644 --- a/src/script/components/MessagesList/Message/ContentMessage/asset/LinkPreviewAssetComponent.tsx +++ b/src/script/components/MessagesList/Message/ContentMessage/asset/LinkPreviewAssetComponent.tsx @@ -23,7 +23,7 @@ import cx from 'classnames'; import {Image} from 'Components/Image'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {safeWindowOpen} from 'Util/SanitizationUtil'; import {cleanURL, prependProtocol} from 'Util/UrlUtil'; @@ -89,7 +89,7 @@ const LinkPreviewAsset: React.FC = ({header = false, mess tabIndex={messageFocusedTabIndex} className="link-preview-asset" onClick={onClick} - onKeyDown={e => handleKeyDown(e, () => onClick(e))} + onKeyDown={event => handleKeyDown({event, callback: () => onClick(event), keys: [KEY.ENTER, KEY.SPACE]})} >
{preview && previewImage ? ( diff --git a/src/script/components/MessagesList/Message/ContentMessage/asset/TextMessageRenderer/TextMessageRenderer.tsx b/src/script/components/MessagesList/Message/ContentMessage/asset/TextMessageRenderer/TextMessageRenderer.tsx index 842e40a8133..c6ee4880c15 100644 --- a/src/script/components/MessagesList/Message/ContentMessage/asset/TextMessageRenderer/TextMessageRenderer.tsx +++ b/src/script/components/MessagesList/Message/ContentMessage/asset/TextMessageRenderer/TextMessageRenderer.tsx @@ -22,7 +22,7 @@ import {useEffect, FC, useState, HTMLProps, useRef} from 'react'; import {isKeyDownEvent} from 'src/script/guards/Event'; import {isAuxClickEvent, isClickEvent} from 'src/script/guards/Mouse'; import {getAllFocusableElements, setElementsTabIndex} from 'Util/focusUtil'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {ShowMoreButton} from './ShowMoreButton'; @@ -88,9 +88,13 @@ const TextMessage: FC = ({ messageDetails: MessageDetails, ) => { if (isKeyDownEvent(event) && isFocusable) { - handleKeyDown(event, () => { - event.preventDefault(); - onMessageClick(event, elementType, messageDetails); + handleKeyDown({ + event, + callback: () => { + event.preventDefault(); + onMessageClick(event, elementType, messageDetails); + }, + keys: [KEY.ENTER, KEY.SPACE], }); } else if (isClickEvent(event) || isAuxClickEvent(event)) { event.preventDefault(); diff --git a/src/script/components/Modals/DetailViewModal/index.tsx b/src/script/components/Modals/DetailViewModal/index.tsx index bccf49ce3b7..30cfabc61e3 100644 --- a/src/script/components/Modals/DetailViewModal/index.tsx +++ b/src/script/components/Modals/DetailViewModal/index.tsx @@ -85,7 +85,11 @@ export const DetailViewModal = ({ }; const handleOnClosePress = (event: KeyboardEvent | ReactKeyboardEvent) => { - handleKeyDown(event, onCloseClick); + handleKeyDown({ + event, + callback: onCloseClick, + keys: [KEY.ENTER, KEY.SPACE], + }); }; const onReplyClick = async (conversation: Conversation, message: ContentMessage) => { diff --git a/src/script/components/Modals/UserModal/UserModal.tsx b/src/script/components/Modals/UserModal/UserModal.tsx index 7451ca0805c..817cb366fa1 100644 --- a/src/script/components/Modals/UserModal/UserModal.tsx +++ b/src/script/components/Modals/UserModal/UserModal.tsx @@ -32,7 +32,7 @@ import {EnrichedFields} from 'Components/panel/EnrichedFields'; import {UserActions} from 'Components/panel/UserActions'; import {UserDetails} from 'Components/panel/UserDetails'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {replaceLink, t} from 'Util/LocalizerUtil'; import {useUserModalState} from './UserModal.state'; @@ -197,7 +197,13 @@ const UserModal: React.FC = ({ handleKeyDown(event, hide)} + onKeyDown={event => + handleKeyDown({ + event, + callback: hide, + keys: [KEY.ENTER, KEY.SPACE], + }) + } data-uie-name="do-close" tabIndex={TabIndex.FOCUSABLE} /> diff --git a/src/script/components/RichTextEditor/plugins/MentionsPlugin/MentionSuggestionsItem.tsx b/src/script/components/RichTextEditor/plugins/MentionsPlugin/MentionSuggestionsItem.tsx index 69f7f99822c..df5d33b1567 100644 --- a/src/script/components/RichTextEditor/plugins/MentionsPlugin/MentionSuggestionsItem.tsx +++ b/src/script/components/RichTextEditor/plugins/MentionsPlugin/MentionSuggestionsItem.tsx @@ -25,7 +25,7 @@ import cx from 'classnames'; import {Avatar, AVATAR_SIZE} from 'Components/Avatar'; import * as Icon from 'Components/Icon'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {User} from '../../../../entity/User'; @@ -55,7 +55,13 @@ const MentionSuggestionsItemComponent: React.ForwardRefRenderFunction handleKeyDown(e, () => onClick(e))} + onKeyDown={event => + handleKeyDown({ + event, + callback: () => onClick(event), + keys: [KEY.ENTER, KEY.SPACE], + }) + } onMouseEnter={onMouseEnter} className={cx('mention-suggestion-list__item', {'mention-suggestion-list__item--highlighted': isSelected})} data-uie-name="item-mention-suggestion" diff --git a/src/script/components/SelectText/SelectText.tsx b/src/script/components/SelectText/SelectText.tsx index f780da8b589..2593b69f698 100644 --- a/src/script/components/SelectText/SelectText.tsx +++ b/src/script/components/SelectText/SelectText.tsx @@ -22,7 +22,7 @@ import React from 'react'; import {TabIndex} from '@wireapp/react-ui-kit/lib/types/enums'; import cx from 'classnames'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; export interface SelectTextProps { text: string; @@ -52,7 +52,13 @@ export const SelectText = ({text, className = '', dataUieName = 'select-text'}: css={{wordBreak: 'break-all'}} className={cx('select-text', className)} onClick={onClick} - onKeyDown={event => handleKeyDown(event, () => onClick(event))} + onKeyDown={event => + handleKeyDown({ + event, + callback: () => onClick(event), + keys: [KEY.ENTER, KEY.SPACE], + }) + } > {text}
diff --git a/src/script/components/ServiceList/components/ServiceListItem/ServiceListItem.tsx b/src/script/components/ServiceList/components/ServiceListItem/ServiceListItem.tsx index b3755e336c7..fa7f2fef1df 100644 --- a/src/script/components/ServiceList/components/ServiceListItem/ServiceListItem.tsx +++ b/src/script/components/ServiceList/components/ServiceListItem/ServiceListItem.tsx @@ -23,7 +23,7 @@ import {Avatar, AVATAR_SIZE} from 'Components/Avatar'; import {ParticipantItemContent} from 'Components/ParticipantItemContent'; import {listItem, listWrapper} from 'Components/ParticipantItemContent/ParticipantItem.styles'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {ServiceEntity} from '../../../../integration/ServiceEntity'; @@ -44,7 +44,13 @@ export const ServiceListItem = ({service, onClick}: ServiceListItemProps) => { tabIndex={TabIndex.FOCUSABLE} role="button" onClick={onServiceClick} - onKeyDown={event => handleKeyDown(event, onServiceClick)} + onKeyDown={event => + handleKeyDown({ + event, + callback: onServiceClick, + keys: [KEY.ENTER, KEY.SPACE], + }) + } data-uie-name="item-service" data-uie-value={serviceName} aria-label={t('accessibility.openConversation', {name: serviceName})} diff --git a/src/script/components/TitleBar/TitleBar.tsx b/src/script/components/TitleBar/TitleBar.tsx index 8d70746c9f0..a2689f14301 100644 --- a/src/script/components/TitleBar/TitleBar.tsx +++ b/src/script/components/TitleBar/TitleBar.tsx @@ -35,7 +35,7 @@ import {User} from 'src/script/entity/User'; import {useAppMainState, ViewType} from 'src/script/page/state'; import {ContentState} from 'src/script/page/useAppState'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {matchQualifiedIds} from 'Util/QualifiedId'; import {TIME_IN_MILLIS} from 'Util/TimeUtil'; @@ -252,7 +252,13 @@ export const TitleBar: React.FC = ({ onClick={onClickDetails} title={peopleTooltip} aria-label={peopleTooltip} - onKeyDown={event => handleKeyDown(event, onClickDetails)} + onKeyDown={event => + handleKeyDown({ + event, + callback: onClickDetails, + keys: [KEY.ENTER, KEY.SPACE], + }) + } data-placement="bottom" role="button" tabIndex={TabIndex.FOCUSABLE} diff --git a/src/script/components/UserDevices/components/DeviceCard/DeviceCard.tsx b/src/script/components/UserDevices/components/DeviceCard/DeviceCard.tsx index e700ca53bff..1885508746a 100644 --- a/src/script/components/UserDevices/components/DeviceCard/DeviceCard.tsx +++ b/src/script/components/UserDevices/components/DeviceCard/DeviceCard.tsx @@ -24,7 +24,7 @@ import {DeviceVerificationBadges} from 'Components/Badge'; import {LegalHoldDot} from 'Components/LegalHoldDot'; import {useMessageFocusedTabIndex} from 'Components/MessagesList/Message/util'; import {WireIdentity} from 'src/script/E2EIdentity'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {splitFingerprint} from 'Util/StringUtil'; @@ -62,7 +62,13 @@ const DeviceCard = ({click, getDeviceIdentity, device: clientEntity, showIcon = tabIndex={messageFocusedTabIndex} className={cx('device-card', {'device-card__no-hover': !clickable})} onClick={clickOnDevice} - onKeyDown={e => handleKeyDown(e, clickOnDevice)} + onKeyDown={event => + handleKeyDown({ + event, + callback: clickOnDevice, + keys: [KEY.ENTER, KEY.SPACE], + }) + } data-uie-uid={id} data-uie-name="device-card" > diff --git a/src/script/components/calling/CallParticipantsListItem/CallParticipantsListItem.tsx b/src/script/components/calling/CallParticipantsListItem/CallParticipantsListItem.tsx index 5ca71ef756d..ce10ea10208 100644 --- a/src/script/components/calling/CallParticipantsListItem/CallParticipantsListItem.tsx +++ b/src/script/components/calling/CallParticipantsListItem/CallParticipantsListItem.tsx @@ -26,7 +26,7 @@ import {UserStatusBadges} from 'Components/Badge'; import {CallParticipantsListItemHandRaiseIcon} from 'Components/calling/CallParticipantsListItem/CallParticipantsListItemHandRaiseIcon'; import {Participant} from 'src/script/calling/Participant'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {setContextMenuPosition} from 'Util/util'; @@ -68,9 +68,13 @@ export const CallParticipantsListItem = ({ } = useKoSubscribableChildren(user, ['isDirectGuest', 'is_verified', 'name', 'isExternal']); const handleContextKeyDown = (event: React.KeyboardEvent) => { - handleKeyDown(event, () => { - const newEvent = setContextMenuPosition(event); - onContextMenu?.(newEvent as unknown as React.MouseEvent); + handleKeyDown({ + event, + callback: () => { + const newEvent = setContextMenuPosition(event); + onContextMenu?.(newEvent as unknown as React.MouseEvent); + }, + keys: [KEY.ENTER, KEY.SPACE], }); }; diff --git a/src/script/components/calling/DeviceToggleButton.tsx b/src/script/components/calling/DeviceToggleButton.tsx index 6edda6790ed..c16abee25b8 100644 --- a/src/script/components/calling/DeviceToggleButton.tsx +++ b/src/script/components/calling/DeviceToggleButton.tsx @@ -21,7 +21,7 @@ import React from 'react'; import {css, SerializedStyles} from '@emotion/react'; -import {handleKeyDown} from 'Util/KeyboardUtil'; +import {handleKeyDown, KEY} from 'Util/KeyboardUtil'; export interface DeviceToggleButtonProps { currentDevice: string; devices: string[]; @@ -60,7 +60,13 @@ const DeviceToggleButton: React.FC = ({currentDevice, d data-uie-name="device-toggle-button-indicator-dot" data-uie-value={isCurrentDevice ? 'active' : 'inactive'} onClick={selectNextDevice} - onKeyDown={event => handleKeyDown(event, () => selectNextDevice(event))} + onKeyDown={event => + handleKeyDown({ + event, + callback: () => selectNextDevice(event), + keys: [KEY.ENTER, KEY.SPACE], + }) + } css={{ '&:focus-visible': { backgroundColor: isCurrentDevice diff --git a/src/script/components/calling/FullscreenVideoCall.tsx b/src/script/components/calling/FullscreenVideoCall.tsx index c20b8de3d2c..d6eca9edd31 100644 --- a/src/script/components/calling/FullscreenVideoCall.tsx +++ b/src/script/components/calling/FullscreenVideoCall.tsx @@ -52,7 +52,7 @@ import {useToggleState} from 'src/script/hooks/useToggleState'; import {MediaDeviceType} from 'src/script/media/MediaDeviceType'; import {useKoSubscribableChildren} from 'Util/ComponentUtil'; import {isDetachedCallingFeatureEnabled} from 'Util/isDetachedCallingFeatureEnabled'; -import {handleKeyDown, isEscapeKey} from 'Util/KeyboardUtil'; +import {handleKeyDown, isEscapeKey, KEY} from 'Util/KeyboardUtil'; import {t} from 'Util/LocalizerUtil'; import {preventFocusOutside} from 'Util/util'; @@ -510,7 +510,13 @@ const FullscreenVideoCall = ({ data-uie-name="pagination-previous" type="button" onClick={() => changePage(currentPage - 1, call)} - onKeyDown={event => handleKeyDown(event, () => changePage(currentPage - 1, call))} + onKeyDown={event => + handleKeyDown({ + event, + callback: () => changePage(currentPage - 1, call), + keys: [KEY.ENTER, KEY.SPACE], + }) + } className="button-reset-default" disabled={currentPage === 0} css={{ @@ -531,7 +537,13 @@ const FullscreenVideoCall = ({