Fix sidebar user menu accessibility and full-width behavior
This commit is contained in:
1 parent
fab78f1610
commit
d336eba27d
4 files changed
+74
-20
No files matched your search
@@ -144,7 +144,7 @@ export function SideNav(props: any) {
|
||||
</Column>
|
||||
)}
|
||||
</Column>
|
||||
<Row paddingTop="2">
|
||||
<Row paddingTop="2" width="100%" style={{ flexShrink: 0 }}>
|
||||
<UserButton showText={!isCollapsed} />
|
||||
</Row>
|
||||
</Column>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import {
|
||||
Button,
|
||||
DialogTrigger,
|
||||
Icon,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuSection,
|
||||
MenuSeparator,
|
||||
MenuTrigger,
|
||||
Popover,
|
||||
Row,
|
||||
Text,
|
||||
@@ -53,7 +53,7 @@ export function TeamsButton() {
|
||||
};
|
||||
|
||||
return (
|
||||
<MenuTrigger>
|
||||
<DialogTrigger>
|
||||
<Button variant="quiet">
|
||||
<Row
|
||||
alignItems="center"
|
||||
@@ -100,6 +100,6 @@ export function TeamsButton() {
|
||||
</MenuSection>
|
||||
</Menu>
|
||||
</Popover>
|
||||
</MenuTrigger>
|
||||
</DialogTrigger>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
import { expect, test, vi } from 'vitest';
|
||||
import { render, screen } from '@/test/render';
|
||||
import { UserButton } from './UserButton';
|
||||
|
||||
vi.mock('next/navigation', () => ({
|
||||
useRouter: () => ({ push: vi.fn() }),
|
||||
}));
|
||||
|
||||
vi.mock('@/components/hooks', () => ({
|
||||
useConfig: () => ({ cloudMode: false }),
|
||||
useLocale: () => ({ locale: 'en-US', saveLocale: vi.fn() }),
|
||||
useLoginQuery: () => ({ user: { username: 'admin', isAdmin: false } }),
|
||||
useMessages: () => ({
|
||||
t: (value: string) => value,
|
||||
labels: {
|
||||
admin: 'Admin',
|
||||
documentation: 'Documentation',
|
||||
language: 'Language',
|
||||
logout: 'Logout',
|
||||
settings: 'Settings',
|
||||
support: 'Support',
|
||||
theme: 'Theme',
|
||||
},
|
||||
}),
|
||||
useMobile: () => ({ isMobile: false }),
|
||||
}));
|
||||
|
||||
test('renders the expanded sidebar control at full width and opens its menu', async () => {
|
||||
const { user } = render(<UserButton />);
|
||||
const button = screen.getByRole('button', { name: 'admin' });
|
||||
|
||||
expect(button).toHaveStyle({ width: '100%' });
|
||||
|
||||
await user.click(button);
|
||||
|
||||
expect(screen.getByRole('menuitem', { name: 'Settings' })).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('keeps the collapsed sidebar control accessible and interactive', async () => {
|
||||
const { user } = render(<UserButton showText={false} />);
|
||||
const button = screen.getByRole('button', { name: 'admin' });
|
||||
|
||||
await user.click(button);
|
||||
|
||||
expect(screen.getByRole('menuitem', { name: 'Settings' })).toBeInTheDocument();
|
||||
});
|
||||
@@ -1,12 +1,12 @@
|
||||
import {
|
||||
Button,
|
||||
Column,
|
||||
DialogTrigger,
|
||||
Icon,
|
||||
Menu,
|
||||
MenuItem,
|
||||
MenuSeparator,
|
||||
MenuTrigger,
|
||||
Popover,
|
||||
Pressable,
|
||||
Row,
|
||||
SubmenuTrigger,
|
||||
Text,
|
||||
@@ -101,15 +101,19 @@ export function UserButton({ showText = true, onClose }: UserButtonProps) {
|
||||
].filter(Boolean);
|
||||
|
||||
const trigger = (
|
||||
<Pressable>
|
||||
<Button
|
||||
variant="zero"
|
||||
aria-label={showText ? undefined : user.username}
|
||||
style={{ padding: 0, width: '100%', justifyContent: 'flex-start' }}
|
||||
>
|
||||
<Row
|
||||
alignItems="center"
|
||||
flexGrow={1}
|
||||
width="100%"
|
||||
hover={{ backgroundColor: 'surface-sunken' }}
|
||||
borderRadius
|
||||
minHeight="40px"
|
||||
role="button"
|
||||
style={{ cursor: 'pointer', textWrap: 'nowrap', overflow: 'hidden', outline: 'none' }}
|
||||
style={{ textWrap: 'nowrap', overflow: 'hidden' }}
|
||||
>
|
||||
<Row alignItems="center" gap padding>
|
||||
<Icon>
|
||||
@@ -118,19 +122,12 @@ export function UserButton({ showText = true, onClose }: UserButtonProps) {
|
||||
{showText && <Text>{user.username}</Text>}
|
||||
</Row>
|
||||
</Row>
|
||||
</Pressable>
|
||||
</Button>
|
||||
);
|
||||
|
||||
return (
|
||||
<MenuTrigger>
|
||||
{showText ? (
|
||||
trigger
|
||||
) : (
|
||||
<TooltipTrigger delay={0}>
|
||||
const menu = (
|
||||
<DialogTrigger>
|
||||
{trigger}
|
||||
<Tooltip placement="right">{user.username}</Tooltip>
|
||||
</TooltipTrigger>
|
||||
)}
|
||||
<Popover side="top" align="start">
|
||||
<Column minWidth="200px">
|
||||
<Menu>
|
||||
@@ -224,6 +221,17 @@ export function UserButton({ showText = true, onClose }: UserButtonProps) {
|
||||
</Menu>
|
||||
</Column>
|
||||
</Popover>
|
||||
</MenuTrigger>
|
||||
</DialogTrigger>
|
||||
);
|
||||
|
||||
if (showText) {
|
||||
return menu;
|
||||
}
|
||||
|
||||
return (
|
||||
<TooltipTrigger delay={0}>
|
||||
<Row width="100%">{menu}</Row>
|
||||
<Tooltip placement="right">{user.username}</Tooltip>
|
||||
</TooltipTrigger>
|
||||
);
|
||||
}
|
||||
Reference in new issue
Block a user