From 010e19027da2cb93d39d27f6df4edf883d9bdd8c Mon Sep 17 00:00:00 2001 From: WofWca Date: Thu, 28 Nov 2024 18:02:00 +0400 Subject: [PATCH 01/11] improvement: arrow-key navigation in "New Group" ...and "New Broadcast List". Just for the "Members list" section. --- .../components/dialogs/CreateChat/index.tsx | 66 ++++++++++++------- 1 file changed, 42 insertions(+), 24 deletions(-) diff --git a/packages/frontend/src/components/dialogs/CreateChat/index.tsx b/packages/frontend/src/components/dialogs/CreateChat/index.tsx index 84263c5f2..adcb620e0 100644 --- a/packages/frontend/src/components/dialogs/CreateChat/index.tsx +++ b/packages/frontend/src/components/dialogs/CreateChat/index.tsx @@ -419,6 +419,8 @@ export function CreateGroup(props: CreateGroupProps) { const [errorMissingGroupName, setErrorMissingGroupName] = useState(false) const [groupContacts, setGroupContacts] = useState([]) + const groupMemberContactListWrapperRef = useRef(null) + useMemo(() => { BackendRemote.rpc .getContactsByIds(accountId, groupMembers) @@ -459,18 +461,25 @@ export function CreateGroup(props: CreateGroupProps) { quantity: groupMembers.length, })} -
- - { - removeGroupMember(c) - }} - /> +
+ + + { + removeGroupMember(c) + }} + /> +
@@ -525,6 +534,8 @@ function CreateBroadcastList(props: CreateBroadcastListProps) { const [broadcastContacts, setBroadcastContacts] = useState([]) + const groupMemberContactListWrapperRef = useRef(null) + useMemo(() => { BackendRemote.rpc .getContactsByIds(accountId, broadcastRecipients) @@ -585,18 +596,25 @@ function CreateBroadcastList(props: CreateBroadcastListProps) { })}
)} -
- - { - removeBroadcastRecipient(c) - }} - /> +
+ + + { + removeBroadcastRecipient(c) + }} + /> +
From 24c36fed35766bd43bb2553b645d47e5120cb945 Mon Sep 17 00:00:00 2001 From: WofWca Date: Thu, 28 Nov 2024 18:08:29 +0400 Subject: [PATCH 02/11] improvement: arrow-key nav in "Blocked Contacts" --- .../src/components/dialogs/UnblockContacts.tsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/packages/frontend/src/components/dialogs/UnblockContacts.tsx b/packages/frontend/src/components/dialogs/UnblockContacts.tsx index e88f3fbcf..7d53f3d9d 100644 --- a/packages/frontend/src/components/dialogs/UnblockContacts.tsx +++ b/packages/frontend/src/components/dialogs/UnblockContacts.tsx @@ -1,4 +1,4 @@ -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useRef } from 'react' import debounce from 'debounce' import { ContactList } from '../contact/ContactList' @@ -9,6 +9,7 @@ import useConfirmationDialog from '../../hooks/dialog/useConfirmationDialog' import useTranslationFunction from '../../hooks/useTranslationFunction' import type { DialogProps } from '../../contexts/DialogContext' +import { RovingTabindexProvider } from '../../contexts/RovingTabindex' export default function UnblockContacts({ onClose }: DialogProps) { const [blockedContacts, setBlockedContacts] = useState( @@ -41,6 +42,8 @@ export default function UnblockContacts({ onClose }: DialogProps) { } } + const wrapperRef = useRef(null) + if (blockedContacts === null) return null return ( {tx('blocked_empty_hint')}

} {blockedContacts.length > 0 && (
- + + +
)} From fb3db6f3df1eeb749a43807577e01f608bc0394f Mon Sep 17 00:00:00 2001 From: WofWca Date: Thu, 28 Nov 2024 18:15:56 +0400 Subject: [PATCH 03/11] improvement: arrow-key nav in "ViewGroup" --- .../src/components/dialogs/ViewGroup.tsx | 122 ++++++++++-------- 1 file changed, 71 insertions(+), 51 deletions(-) diff --git a/packages/frontend/src/components/dialogs/ViewGroup.tsx b/packages/frontend/src/components/dialogs/ViewGroup.tsx index f13188b15..956cd2b47 100644 --- a/packages/frontend/src/components/dialogs/ViewGroup.tsx +++ b/packages/frontend/src/components/dialogs/ViewGroup.tsx @@ -36,6 +36,7 @@ import type { DialogProps } from '../../contexts/DialogContext' import ImageCropper from '../ImageCropper' import { AddMemberDialog } from './AddMember/AddMemberDialog' import AutoSizer from 'react-virtualized-auto-sizer' +import { RovingTabindexProvider } from '../../contexts/RovingTabindex' export default function ViewGroup( props: { @@ -121,6 +122,9 @@ function ViewGroupInner( const chatDisabled = !chat.canSend + const groupMemberContactListWrapperRef = useRef(null) + const relatedChatsListWrapperRef = useRef(null) + const { group, groupName, @@ -233,34 +237,41 @@ function ViewGroupInner( {isRelatedChatsEnabled && ( <>
{tx('related_chats')}
-
- - {({ width }) => ( - 'key' + chatListIds[index]} - itemHeight={CHATLISTITEM_CHAT_HEIGHT} - > - {({ index, style }) => { - const chatId = chatListIds[index] - return ( -
- -
- ) - }} -
- )} -
+
+ + + {({ width }) => ( + 'key' + chatListIds[index]} + itemHeight={CHATLISTITEM_CHAT_HEIGHT} + > + {({ index, style }) => { + const chatId = chatListIds[index] + return ( +
+ +
+ ) + }} +
+ )} +
+
)} @@ -273,29 +284,38 @@ function ViewGroupInner( quantity: groupMembers.length, })}
-
- {!chatDisabled && ( - <> - showAddMemberDialog()} - isBroadcast={isBroadcast} - /> - {!isBroadcast && ( - showQRDialog()} /> - )} - - )} - { - if (contact.id === C.DC_CONTACT_ID_SELF) { - return - } - setProfileContact(contact) - }} - onRemoveClick={showRemoveGroupMemberConfirmationDialog} - /> +
+ + {!chatDisabled && ( + <> + showAddMemberDialog()} + isBroadcast={isBroadcast} + /> + {!isBroadcast && ( + showQRDialog()} + /> + )} + + )} + { + if (contact.id === C.DC_CONTACT_ID_SELF) { + return + } + setProfileContact(contact) + }} + onRemoveClick={showRemoveGroupMemberConfirmationDialog} + /> +
From ecb7419c5328c250b5e2aaae2bbe194f1781d2bf Mon Sep 17 00:00:00 2001 From: WofWca Date: Thu, 28 Nov 2024 18:26:48 +0400 Subject: [PATCH 04/11] improvement: arrow-key nav in "Add Members" --- .../AddMember/AddMemberInnerDialog.tsx | 104 +++++++++--------- 1 file changed, 54 insertions(+), 50 deletions(-) diff --git a/packages/frontend/src/components/dialogs/AddMember/AddMemberInnerDialog.tsx b/packages/frontend/src/components/dialogs/AddMember/AddMemberInnerDialog.tsx index 0e4ec9fd6..52b1a9b8d 100644 --- a/packages/frontend/src/components/dialogs/AddMember/AddMemberInnerDialog.tsx +++ b/packages/frontend/src/components/dialogs/AddMember/AddMemberInnerDialog.tsx @@ -22,6 +22,7 @@ import InfiniteLoader from 'react-window-infinite-loader' import { AddMemberChip } from './AddMemberDialog' import styles from './styles.module.scss' import classNames from 'classnames' +import { RovingTabindexProvider } from '../../../contexts/RovingTabindex' export function AddMemberInnerDialog({ onCancel, @@ -275,58 +276,61 @@ export function AddMemberInnerDialog({ // minimumBatchSize={100} > {({ onItemsRendered, ref }) => ( - // Not using 'react-window' results in ~5 second rendering time - // if the user has 5000 contacts. - // (see https://github.com/deltachat/deltachat-desktop/issues/1830) - { - const isExtraItem = index >= contactIds.length - return isExtraItem ? 'addContact' : contactIds[index] - }} - onItemsRendered={onItemsRendered} - ref={ref} - height={height} - width='100%' - // TODO fix: The size of each item is determined - // by `--local-avatar-size` and `--local-avatar-vertical-margin`, - // which might be different, e.g. currently they're smaller for - // "Rocket Theme", which results in gaps between the elements. - itemSize={64} - > - {({ index, style, data: contactIds }) => { - const isExtraItem = index >= contactIds.length - if (isExtraItem) { - return renderAddContact() - } + + {/* Not using 'react-window' results in ~5 second rendering time + if the user has 5000 contacts. + (see https://github.com/deltachat/deltachat-desktop/issues/1830) */} + { + const isExtraItem = index >= contactIds.length + return isExtraItem ? 'addContact' : contactIds[index] + }} + onItemsRendered={onItemsRendered} + ref={ref} + height={height} + width='100%' + // TODO fix: The size of each item is determined + // by `--local-avatar-size` and `--local-avatar-vertical-margin`, + // which might be different, e.g. currently they're smaller for + // "Rocket Theme", which results in gaps between the elements. + itemSize={64} + > + {({ index, style, data: contactIds }) => { + const isExtraItem = index >= contactIds.length + if (isExtraItem) { + return renderAddContact() + } - const contact = contactCache[contactIds[index]] - if (!contact) { - // Not loaded yet - return
- } + const contact = contactCache[contactIds[index]] + if (!contact) { + // Not loaded yet + return
+ } - return ( -
- c.id === contact.id) || - contactIdsInGroup.includes(contact.id) - } - disabled={ - contactIdsInGroup.includes(contact.id) || - contact.id === C.DC_CONTACT_ID_SELF - } - onCheckboxClick={toggleMember} - showRemove={false} - /> -
- ) - }} -
+ return ( +
+ c.id === contact.id + ) || contactIdsInGroup.includes(contact.id) + } + disabled={ + contactIdsInGroup.includes(contact.id) || + contact.id === C.DC_CONTACT_ID_SELF + } + onCheckboxClick={toggleMember} + showRemove={false} + /> +
+ ) + }} +
+ )} )} From 20f66edff4f5086772bc9cb18f6cff409644a7ac Mon Sep 17 00:00:00 2001 From: WofWca Date: Thu, 28 Nov 2024 18:54:18 +0400 Subject: [PATCH 05/11] improvement: arrow-key nav in "SelectContactDialog" --- .../dialogs/SelectContact/index.tsx | 67 ++++++++++--------- 1 file changed, 37 insertions(+), 30 deletions(-) diff --git a/packages/frontend/src/components/dialogs/SelectContact/index.tsx b/packages/frontend/src/components/dialogs/SelectContact/index.tsx index 21ccda894..4704d0c24 100644 --- a/packages/frontend/src/components/dialogs/SelectContact/index.tsx +++ b/packages/frontend/src/components/dialogs/SelectContact/index.tsx @@ -16,6 +16,7 @@ import { ContactListItem } from '../../contact/ContactListItem' import { FixedSizeList } from 'react-window' import AutoSizer from 'react-virtualized-auto-sizer' import InfiniteLoader from 'react-window-infinite-loader' +import { RovingTabindexProvider } from '../../../contexts/RovingTabindex' /** * display a dialog with a react-window of contacts @@ -39,6 +40,8 @@ export default function SelectContactDialog({ ) const tx = useTranslationFunction() + const selectContactListRef = useRef(null) + const infiniteLoaderRef = useRef(null) // By default InfiniteLoader assumes that each item's index in the list // never changes. But in our case they do change because of filtering. @@ -66,7 +69,7 @@ export default function SelectContactDialog({ /> -
+
{({ height }) => ( {({ onItemsRendered, ref }) => ( - contactIds[index]} - onItemsRendered={onItemsRendered} - ref={ref} - height={height} - width='100%' - itemSize={64} + - {({ index, style }) => { - const el = (() => { - const item = contactCache[contactIds[index]] - if (!item) { - // It's not loaded yet - return null - } - const contact: T.Contact = item - return ( - - ) - })() + contactIds[index]} + onItemsRendered={onItemsRendered} + ref={ref} + height={height} + width='100%' + itemSize={64} + > + {({ index, style }) => { + const el = (() => { + const item = contactCache[contactIds[index]] + if (!item) { + // It's not loaded yet + return null + } + const contact: T.Contact = item + return ( + + ) + })() - return
{el}
- }} -
+ return
{el}
+ }} +
+ )}
)} From 25f9202fc0f66dca77c2019350f48cbeabd45b63 Mon Sep 17 00:00:00 2001 From: WofWca Date: Fri, 29 Nov 2024 18:36:11 +0400 Subject: [PATCH 06/11] improvement: arrow-key nav in "Send To" dialogs - Mailto - webxdc.sendToChat - Forward Message --- .../dialogs/ForwardMessage/index.tsx | 69 ++++++++++--------- .../components/dialogs/MailtoDialog/index.tsx | 63 +++++++++-------- .../dialogs/WebxdcSendToChat/index.tsx | 63 +++++++++-------- 3 files changed, 109 insertions(+), 86 deletions(-) diff --git a/packages/frontend/src/components/dialogs/ForwardMessage/index.tsx b/packages/frontend/src/components/dialogs/ForwardMessage/index.tsx index dac8f445a..c2177a4a1 100644 --- a/packages/frontend/src/components/dialogs/ForwardMessage/index.tsx +++ b/packages/frontend/src/components/dialogs/ForwardMessage/index.tsx @@ -1,5 +1,5 @@ import AutoSizer from 'react-virtualized-auto-sizer' -import React, { useState } from 'react' +import React, { useRef, useState } from 'react' import { C } from '@deltachat/jsonrpc-client' import ChatListItem from '../../chat/ChatListItem' @@ -20,6 +20,7 @@ import styles from './styles.module.scss' import type { T } from '@deltachat/jsonrpc-client' import type { DialogProps } from '../../../contexts/DialogContext' +import { RovingTabindexProvider } from '../../../contexts/RovingTabindex' type Props = { message: T.Message @@ -42,6 +43,8 @@ export default function ForwardMessage(props: Props) { const { isChatLoaded, loadChats, chatCache } = useLogicVirtualChatList(chatListIds) + const chatListRef = useRef(null) + const onChatClick = async (chatId: number) => { const chat = await BackendRemote.rpc.getFullChatById(accountId, chatId) onClose() @@ -96,37 +99,39 @@ export default function ForwardMessage(props: Props) { spellCheck={false} />
-
- {noResults && queryStr && ( - - )} -
- - {({ width, height }) => ( - 'key' + chatListIds[index]} - itemHeight={CHATLISTITEM_CHAT_HEIGHT} - > - {({ index, style }) => { - const chatId = chatListIds[index] - return ( -
- -
- ) - }} -
- )} -
-
+
+ + {noResults && queryStr && ( + + )} +
+ + {({ width, height }) => ( + 'key' + chatListIds[index]} + itemHeight={CHATLISTITEM_CHAT_HEIGHT} + > + {({ index, style }) => { + const chatId = chatListIds[index] + return ( +
+ +
+ ) + }} +
+ )} +
+
+
diff --git a/packages/frontend/src/components/dialogs/MailtoDialog/index.tsx b/packages/frontend/src/components/dialogs/MailtoDialog/index.tsx index 96c585c0d..bd1ac4c6e 100644 --- a/packages/frontend/src/components/dialogs/MailtoDialog/index.tsx +++ b/packages/frontend/src/components/dialogs/MailtoDialog/index.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react' +import React, { useRef, useState } from 'react' import AutoSizer from 'react-virtualized-auto-sizer' import { C } from '@deltachat/jsonrpc-client' @@ -15,6 +15,7 @@ import useTranslationFunction from '../../../hooks/useTranslationFunction' import styles from './styles.module.scss' import type { DialogProps } from '../../../contexts/DialogContext' +import { RovingTabindexProvider } from '../../../contexts/RovingTabindex' type Props = { messageText: string @@ -32,6 +33,8 @@ export default function MailtoDialog(props: Props & DialogProps) { const { isChatLoaded, loadChats, chatCache } = useLogicVirtualChatList(chatListIds) + const resultsRef = useRef(null) + const onChatClick = async (chatId: number) => { createDraftMessage(accountId, chatId, messageText) onClose() @@ -65,32 +68,38 @@ export default function MailtoDialog(props: Props & DialogProps) { {noResults && queryStr && ( )} -
- - {({ width, height }) => ( - 'key' + chatListIds[index]} - itemHeight={CHATLISTITEM_CHAT_HEIGHT} - > - {({ index, style }) => { - const chatId = chatListIds[index] - return ( -
- -
- ) - }} -
- )} -
+
+ + + {({ width, height }) => ( + 'key' + chatListIds[index]} + itemHeight={CHATLISTITEM_CHAT_HEIGHT} + > + {({ index, style }) => { + const chatId = chatListIds[index] + return ( +
+ +
+ ) + }} +
+ )} +
+
diff --git a/packages/frontend/src/components/dialogs/WebxdcSendToChat/index.tsx b/packages/frontend/src/components/dialogs/WebxdcSendToChat/index.tsx index 3cd941bf8..a2f2c58b7 100644 --- a/packages/frontend/src/components/dialogs/WebxdcSendToChat/index.tsx +++ b/packages/frontend/src/components/dialogs/WebxdcSendToChat/index.tsx @@ -1,4 +1,4 @@ -import React, { useCallback, useState } from 'react' +import React, { useCallback, useRef, useState } from 'react' import { C } from '@deltachat/jsonrpc-client' import AutoSizer from 'react-virtualized-auto-sizer' import classNames from 'classnames' @@ -26,6 +26,7 @@ import useTranslationFunction from '../../../hooks/useTranslationFunction' import styles from './styles.module.scss' import type { DialogProps } from '../../../contexts/DialogContext' +import { RovingTabindexProvider } from '../../../contexts/RovingTabindex' type Props = { messageText: string | null @@ -45,6 +46,8 @@ export default function WebxdcSaveToChatDialog(props: Props) { const { isChatLoaded, loadChats, chatCache } = useLogicVirtualChatList(chatListIds) + const resultsRef = useRef(null) + const onChatClick = async (chatId: number) => { let path = null if (file) { @@ -103,32 +106,38 @@ export default function WebxdcSaveToChatDialog(props: Props) { {noResults && queryStr && ( )} -
- - {({ width, height }) => ( - 'key' + chatListIds[index]} - itemHeight={CHATLISTITEM_CHAT_HEIGHT} - > - {({ index, style }) => { - const chatId = chatListIds[index] - return ( -
- -
- ) - }} -
- )} -
+
+ + + {({ width, height }) => ( + 'key' + chatListIds[index]} + itemHeight={CHATLISTITEM_CHAT_HEIGHT} + > + {({ index, style }) => { + const chatId = chatListIds[index] + return ( +
+ +
+ ) + }} +
+ )} +
+
From 0c298039f0c460ce94a62018d3993878293381a4 Mon Sep 17 00:00:00 2001 From: WofWca Date: Fri, 29 Nov 2024 18:49:08 +0400 Subject: [PATCH 07/11] improvement: arrow-key nav for "Mutual Chats" With this commit now all `ChatListPart`s are wrapped in ``. --- .../components/dialogs/ViewProfile/index.tsx | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/packages/frontend/src/components/dialogs/ViewProfile/index.tsx b/packages/frontend/src/components/dialogs/ViewProfile/index.tsx index 7d2e6507e..9a9350f31 100644 --- a/packages/frontend/src/components/dialogs/ViewProfile/index.tsx +++ b/packages/frontend/src/components/dialogs/ViewProfile/index.tsx @@ -1,5 +1,5 @@ import AutoSizer from 'react-virtualized-auto-sizer' -import React, { useState, useEffect } from 'react' +import React, { useState, useEffect, useRef } from 'react' import moment from 'moment' import { C } from '@deltachat/jsonrpc-client' @@ -28,6 +28,7 @@ import styles from './styles.module.scss' import type { DialogProps } from '../../../contexts/DialogContext' import type { T } from '@deltachat/jsonrpc-client' +import { RovingTabindexProvider } from '../../../contexts/RovingTabindex' const log = getLogger('renderer/dialogs/ViewProfile') @@ -138,6 +139,8 @@ export function ViewProfileInner({ action?: () => void }>(null) + const mutualChatsListRef = useRef(null) + const isDeviceChat = contact.id === C.DC_CONTACT_ID_DEVICE const isSelfChat = contact.id === C.DC_CONTACT_ID_SELF @@ -313,34 +316,37 @@ export function ViewProfileInner({ <>
{tx('profile_shared_chats')}
- - {({ width, height }) => ( - 'key' + chatListIds[index]} - itemHeight={CHATLISTITEM_CHAT_HEIGHT} - > - {({ index, style }) => { - const chatId = chatListIds[index] - return ( -
- -
- ) - }} -
- )} -
+ + + {({ width, height }) => ( + 'key' + chatListIds[index]} + itemHeight={CHATLISTITEM_CHAT_HEIGHT} + > + {({ index, style }) => { + const chatId = chatListIds[index] + return ( +
+ +
+ ) + }} +
+ )} +
+
)} From 949bc478062168d9cc8550e6e475c543b27f628e Mon Sep 17 00:00:00 2001 From: WofWca Date: Fri, 29 Nov 2024 19:22:18 +0400 Subject: [PATCH 08/11] refactor: separate component for ReactionsDialog This is needed so that we can use hooks inside the `ReactionsDialogListItem`, namely the `useRovingTabindex` hook. --- .../dialogs/ReactionsDialog/index.tsx | 70 +++++++++++-------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/packages/frontend/src/components/dialogs/ReactionsDialog/index.tsx b/packages/frontend/src/components/dialogs/ReactionsDialog/index.tsx index 88b468bca..54bdb0d0f 100644 --- a/packages/frontend/src/components/dialogs/ReactionsDialog/index.tsx +++ b/packages/frontend/src/components/dialogs/ReactionsDialog/index.tsx @@ -91,34 +91,48 @@ function ReactionsDialogList({ reactionsByContact, onClose }: Props) { return (
    - {contacts.map(contact => { - const notFromSelf = C.DC_CONTACT_ID_SELF !== contact.id - return ( -
  • - -
  • - ) - })} + {contacts.map(contact => ( +
  • + + openViewProfileDialog(accountId, contactId) + } + /> +
  • + ))}
) } + +function ReactionsDialogListItem(props: { + contact: ContactWithReaction + onClickNonSelf: (contactId: number) => void +}) { + const { contact, onClickNonSelf } = props + const notFromSelf = C.DC_CONTACT_ID_SELF !== contact.id + + return ( + + ) +} From 49465c88318bbaaed1d916eab2a61d37aa9eea68 Mon Sep 17 00:00:00 2001 From: WofWca Date: Fri, 29 Nov 2024 19:28:46 +0400 Subject: [PATCH 09/11] improvement: arrow-key nav in "Reactions List" --- .../dialogs/ReactionsDialog/index.tsx | 49 +++++++++++++------ 1 file changed, 34 insertions(+), 15 deletions(-) diff --git a/packages/frontend/src/components/dialogs/ReactionsDialog/index.tsx b/packages/frontend/src/components/dialogs/ReactionsDialog/index.tsx index 54bdb0d0f..8dc704c88 100644 --- a/packages/frontend/src/components/dialogs/ReactionsDialog/index.tsx +++ b/packages/frontend/src/components/dialogs/ReactionsDialog/index.tsx @@ -1,4 +1,4 @@ -import React, { useEffect, useState } from 'react' +import React, { useEffect, useRef, useState } from 'react' import classNames from 'classnames' import Dialog, { @@ -21,6 +21,10 @@ import type { DialogProps } from '../../../contexts/DialogContext' import { type T, C } from '@deltachat/jsonrpc-client' import useOpenViewProfileDialog from '../../../hooks/dialog/useOpenViewProfileDialog' +import { + RovingTabindexProvider, + useRovingTabindex, +} from '../../../contexts/RovingTabindex' export type Props = { reactionsByContact: T.Reactions['reactionsByContact'] @@ -62,6 +66,8 @@ function ReactionsDialogList({ reactionsByContact, onClose }: Props) { const [contacts, setContacts] = useState([]) const openViewProfileDialog = useOpenViewProfileDialog({ onAction: onClose }) + const ref = useRef(null) + useEffect(() => { const resolveContacts = async () => { const contactIds = Object.keys(reactionsByContact).map(contactId => @@ -90,17 +96,19 @@ function ReactionsDialogList({ reactionsByContact, onClose }: Props) { }, [accountId, reactionsByContact]) return ( -
    - {contacts.map(contact => ( -
  • - - openViewProfileDialog(accountId, contactId) - } - /> -
  • - ))} +
      + + {contacts.map(contact => ( +
    • + + openViewProfileDialog(accountId, contactId) + } + /> +
    • + ))} +
    ) } @@ -112,8 +120,12 @@ function ReactionsDialogListItem(props: { const { contact, onClickNonSelf } = props const notFromSelf = C.DC_CONTACT_ID_SELF !== contact.id + const ref = useRef(null) + const rovingTabindex = useRovingTabindex(ref) + return ( + /> ))}
) } +function StickersListItem(props: { filePath: string; onClick: () => void }) { + const { filePath, onClick } = props + return ( + + ) +} + export const StickerPicker = ({ stickers, chatId, From 5aba6c25f5c08aad2e04912671c1e30ca20fadab Mon Sep 17 00:00:00 2001 From: WofWca Date: Fri, 29 Nov 2024 20:04:18 +0400 Subject: [PATCH 11/11] improvement: arrow-key nav in stickers picker --- .../composer/EmojiAndStickerPicker.tsx | 39 ++++++++++++++----- 1 file changed, 30 insertions(+), 9 deletions(-) diff --git a/packages/frontend/src/components/composer/EmojiAndStickerPicker.tsx b/packages/frontend/src/components/composer/EmojiAndStickerPicker.tsx index 890be8fad..b2a2e7961 100644 --- a/packages/frontend/src/components/composer/EmojiAndStickerPicker.tsx +++ b/packages/frontend/src/components/composer/EmojiAndStickerPicker.tsx @@ -3,6 +3,7 @@ import React, { useEffect, forwardRef, PropsWithChildren, + useRef, } from 'react' import classNames from 'classnames' @@ -17,6 +18,10 @@ import useMessage from '../../hooks/chat/useMessage' import styles from './styles.module.scss' import type { EmojiData } from 'emoji-mart/index' +import { + RovingTabindexProvider, + useRovingTabindex, +} from '../../contexts/RovingTabindex' type Props = { stickerPackName: string @@ -34,6 +39,8 @@ const DisplayedStickerPack = ({ const { jumpToMessage } = useMessage() const accountId = selectedAccountId() + const listRef = useRef(null) + const onClickSticker = (fileName: string) => { const stickerPath = fileName.replace('file://', '') BackendRemote.rpc @@ -47,14 +54,19 @@ const DisplayedStickerPack = ({ return (
{stickerPackName}
-
- {stickerPackImages.map((filePath, index) => ( - onClickSticker(filePath)} - /> - ))} +
+ {/* Yes, we have separate `RovingTabindexProvider` for each + sticker pack, instead of having one for all stickers. + Users probably want to switch between sticker packs with Tab. */} + + {stickerPackImages.map((filePath, index) => ( + onClickSticker(filePath)} + /> + ))} +
) @@ -62,8 +74,17 @@ const DisplayedStickerPack = ({ function StickersListItem(props: { filePath: string; onClick: () => void }) { const { filePath, onClick } = props + const ref = useRef(null) + const rovingTabindex = useRovingTabindex(ref) return ( - )