Skip to content

Commit

Permalink
improvement: arrow-key navigation for accounts list
Browse files Browse the repository at this point in the history
  • Loading branch information
WofWca committed Nov 22, 2024
1 parent ad56220 commit a5fbfd0
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 17 deletions.
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
## [Unreleased][unreleased]

## Added
- accessibility: arrow-key navigation for the list of chats #4224
- accessibility: arrow-key navigation for the list of chats, list of accounts #4224, #4291
- Add "Learn More" button to "Disappearing Messages" dialog #4330
- new icon for Mac users
- smooth-scroll to newly arriving messages instead of jumping instantly #4125
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import styles from './styles.module.scss'

import { C, type T } from '@deltachat/jsonrpc-client'
import { openMapWebxdc } from '../../system-integration/webxdc'
import { useRovingTabindex } from '../../contexts/RovingTabindex'

type Props = {
account: T.Account
Expand Down Expand Up @@ -187,9 +188,14 @@ export default function AccountItem({
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [isSelected, window.__screen])

const rovingTabindex = useRovingTabindex(ref)
// TODO `rovingTabindex.setAsActiveElement()` when the active account
// gets switched, e.g. via clicking on a message notification
// for a different account, and upon initial render.

return (
<button
className={classNames(styles.account, {
className={classNames(styles.account, 'roving-tabindex', {
[styles.active]: isSelected,
[styles['context-menu-active']]: isContextMenuActive,
})}
Expand All @@ -200,6 +206,9 @@ export default function AccountItem({
x-account-sidebar-account-id={account.id}
data-testid={`account-item-${account.id}`}
ref={ref}
tabIndex={rovingTabindex.tabIndex}
onFocus={rovingTabindex.setAsActiveElement}
onKeyDown={rovingTabindex.onKeydown}
>
{account.kind == 'Configured' ? (
<div className={styles.avatar}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,11 @@ import useChat from '../../hooks/chat/useChat'
import { Screens } from '../../ScreenController'
import { ActionEmitter, KeybindAction } from '../../keybindings'
import useTranslationFunction from '../../hooks/useTranslationFunction'
import {
RovingTabindexProvider,
useRovingTabindex,
} from '../../contexts/RovingTabindex'
import classNames from 'classnames'

type Props = {
onAddAccount: () => Promise<number>
Expand All @@ -41,6 +46,7 @@ export default function AccountListSidebar({
}: Props) {
const tx = useTranslationFunction()

const accountsListRef = useRef<HTMLDivElement>(null)
const { openDialog } = useDialog()
const [accounts, setAccounts] = useState<T.Account[]>([])
const [{ accounts: noficationSettings }] = useAccountNotificationStore()
Expand Down Expand Up @@ -128,20 +134,26 @@ export default function AccountListSidebar({
{runtime.getRuntimeInfo().isMac && !smallScreenMode && (
<div className={styles.macOSTrafficLightBackground} />
)}
<div className={styles.accountList} onScroll={updateHoverInfoPosition}>
{accounts.map(account => (
<AccountItem
key={account.id}
account={account}
isSelected={selectedAccountId === account.id}
onSelectAccount={selectAccount}
openAccountDeletionScreen={openAccountDeletionScreen}
updateAccountForHoverInfo={updateAccountForHoverInfo}
syncAllAccounts={syncAllAccounts}
muted={noficationSettings[account.id]?.muted || false}
/>
))}
<AddAccountButton onClick={onAddAccount} />
<div
ref={accountsListRef}
className={styles.accountList}
onScroll={updateHoverInfoPosition}
>
<RovingTabindexProvider wrapperElementRef={accountsListRef}>
{accounts.map(account => (
<AccountItem
key={account.id}
account={account}
isSelected={selectedAccountId === account.id}
onSelectAccount={selectAccount}
openAccountDeletionScreen={openAccountDeletionScreen}
updateAccountForHoverInfo={updateAccountForHoverInfo}
syncAllAccounts={syncAllAccounts}
muted={noficationSettings[account.id]?.muted || false}
/>
))}
<AddAccountButton onClick={onAddAccount} />
</RovingTabindexProvider>
</div>
{/* The condition is the same as in https://github.com/deltachat/deltachat-desktop/blob/63af023437ff1828a27de2da37bf94ab180ec528/src/renderer/contexts/KeybindingsContext.tsx#L26 */}
{window.__screen === Screens.Main && (
Expand Down Expand Up @@ -176,10 +188,19 @@ export default function AccountListSidebar({
function AddAccountButton(props: { onClick: () => void }) {
const tx = useTranslationFunction()

const ref = useRef<HTMLButtonElement>(null)
// This relies on the existence of `RovingTabindexProvider`.
// This is why this button is a separate component.
const rovingTabindex = useRovingTabindex(ref)

return (
<button
ref={ref}
aria-label={tx('add_account')}
className={styles.addButton}
className={classNames(styles.addButton, 'roving-tabindex')}
tabIndex={rovingTabindex.tabIndex}
onKeyDown={rovingTabindex.onKeydown}
onFocus={rovingTabindex.setAsActiveElement}
{...props}
>
+
Expand Down

0 comments on commit a5fbfd0

Please sign in to comment.