feat(web): improve keyboard navigation in RootAppSidebar (#2256)

Co-authored-by: Himself65 <himself65@outlook.com>
This commit is contained in:
Doma
2023-05-08 09:57:14 -05:00
committed by GitHub
co-authored by Himself65
parent d040a7fb50
commit d1457075b3
4 changed files with 52 additions and 10 deletions
@@ -2,6 +2,7 @@ import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
import { CloudWorkspaceIcon, LocalWorkspaceIcon } from '@blocksuite/icons'; import { CloudWorkspaceIcon, LocalWorkspaceIcon } from '@blocksuite/icons';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
import type React from 'react'; import type React from 'react';
import { useCallback } from 'react';
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace'; import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
import type { AllWorkspace } from '../../../../shared'; import type { AllWorkspace } from '../../../../shared';
@@ -18,6 +19,10 @@ export type WorkspaceSelectorProps = {
onClick: () => void; onClick: () => void;
}; };
/**
* @todo-Doma Co-locate WorkspaceListModal with {@link WorkspaceSelector},
* because it's never used elsewhere.
*/
export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({ export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
currentWorkspace, currentWorkspace,
onClick, onClick,
@@ -26,8 +31,28 @@ export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
currentWorkspace?.blockSuiteWorkspace ?? null currentWorkspace?.blockSuiteWorkspace ?? null
); );
const [workspace] = useCurrentWorkspace(); const [workspace] = useCurrentWorkspace();
// Open dialog when `Enter` or `Space` pressed
// TODO-Doma Refactor with `@radix-ui/react-dialog` or other libraries that handle these out of the box and be accessible by default
const handleKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
// TODO-Doma Rename this callback to `onOpenDialog` or something to reduce ambiguity.
onClick();
}
},
[onClick]
);
return ( return (
<StyledSelectorContainer onClick={onClick} data-testid="current-workspace"> <StyledSelectorContainer
role="button"
tabIndex={0}
onClick={onClick}
onKeyDown={handleKeyDown}
data-testid="current-workspace"
>
<WorkspaceAvatar <WorkspaceAvatar
data-testid="workspace-avatar" data-testid="workspace-avatar"
className={workspaceAvatarStyle} className={workspaceAvatarStyle}
@@ -36,14 +36,6 @@ export const Favorite = ({
(currentWorkspaceId && paths.favorite(currentWorkspaceId)) (currentWorkspaceId && paths.favorite(currentWorkspaceId))
} }
> >
<StyledCollapseButton
onClick={useCallback(() => {
setOpenSubFavorite(!showSubFavorite);
}, [showSubFavorite])}
collapse={showSubFavorite}
>
<ArrowDownSmallIcon />
</StyledCollapseButton>
<StyledLink <StyledLink
href={{ href={{
pathname: currentWorkspaceId && paths.favorite(currentWorkspaceId), pathname: currentWorkspaceId && paths.favorite(currentWorkspaceId),
@@ -52,6 +44,14 @@ export const Favorite = ({
<FavoriteIcon /> <FavoriteIcon />
{t['Favorites']()} {t['Favorites']()}
</StyledLink> </StyledLink>
<StyledCollapseButton
onClick={useCallback(() => {
setOpenSubFavorite(!showSubFavorite);
}, [showSubFavorite])}
collapse={showSubFavorite}
>
<ArrowDownSmallIcon />
</StyledCollapseButton>
</StyledListItem> </StyledListItem>
<FavoriteList <FavoriteList
currentPageId={currentPageId} currentPageId={currentPageId}
@@ -63,6 +63,9 @@ export const StyledCollapseButton = styled('button')<{
':hover': { ':hover': {
opacity: '1', opacity: '1',
}, },
':focus-visible': {
outline: '-webkit-focus-ring-color auto 1px',
},
}; };
}); });
@@ -17,7 +17,8 @@ import {
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
import type { ReactElement, UIEvent } from 'react'; import type { ReactElement, UIEvent } from 'react';
import React, { useCallback, useEffect, useState } from 'react'; import type React from 'react';
import { useCallback, useEffect, useState } from 'react';
import type { AllWorkspace } from '../../shared'; import type { AllWorkspace } from '../../shared';
import ChangeLog from '../pure/workspace-slider-bar/changeLog'; import ChangeLog from '../pure/workspace-slider-bar/changeLog';
@@ -80,6 +81,16 @@ export const RootAppSidebar = ({
} }
}, [sidebarOpen]); }, [sidebarOpen]);
const [ref, setRef] = useState<HTMLElement | null>(null); const [ref, setRef] = useState<HTMLElement | null>(null);
const handleQuickSearchButtonKeyDown = useCallback(
(e: React.KeyboardEvent) => {
if (e.key === 'Enter' || e.key === ' ') {
e.preventDefault();
onOpenQuickSearchModal();
}
},
[onOpenQuickSearchModal]
);
return ( return (
<> <>
<AppSidebar <AppSidebar
@@ -104,8 +115,11 @@ export const RootAppSidebar = ({
onClick={useCallback(() => { onClick={useCallback(() => {
onOpenQuickSearchModal(); onOpenQuickSearchModal();
}, [onOpenQuickSearchModal])} }, [onOpenQuickSearchModal])}
onKeyDown={handleQuickSearchButtonKeyDown}
> >
<div <div
role="button"
tabIndex={0}
style={{ style={{
display: 'flex', display: 'flex',
flex: 1, flex: 1,