mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
fix(site/src/pages/WorkspacePage/WorkspaceNotifications): make workspace notification pills keyboard accessible (#24536)
Description: The workspace notification pills were implemented using Tooltip, which is hover-only and not reachable via keyboard navigation. Replace Tooltip/TooltipProvider/TooltipTrigger with Popover/PopoverContent/PopoverTrigger, and change the trigger element from a non-interactive div to a button. This makes the notification pills fully keyboard accessible. Screenshot: **Issue** <img width="640" height="211" alt="not-working" src="https://github.com/user-attachments/assets/3cb12fdf-704b-41a2-ab9c-c198d03158a7" /> **Fix** <img width="640" height="211" alt="working" src="https://github.com/user-attachments/assets/25807a6b-7065-4753-b55e-d8db103ba501" />
This commit is contained in:
@@ -4,11 +4,10 @@ import type { AlertProps } from "#/components/Alert/Alert";
|
||||
import { Button, type ButtonProps } from "#/components/Button/Button";
|
||||
import { Pill } from "#/components/Pill/Pill";
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipProvider,
|
||||
TooltipTrigger,
|
||||
} from "#/components/Tooltip/Tooltip";
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from "#/components/Popover/Popover";
|
||||
import type { ThemeRole } from "#/theme/roles";
|
||||
|
||||
export type NotificationItem = {
|
||||
@@ -33,55 +32,53 @@ export const Notifications: FC<NotificationsProps> = ({
|
||||
const theme = useTheme();
|
||||
|
||||
return (
|
||||
<TooltipProvider>
|
||||
<Tooltip open={isOpen} onOpenChange={setIsOpen} delayDuration={0}>
|
||||
<TooltipTrigger asChild>
|
||||
<div
|
||||
// Adds some spacing from the Tooltip content
|
||||
className="py-2"
|
||||
data-testid={`${severity}-notifications`}
|
||||
>
|
||||
<NotificationPill
|
||||
items={items}
|
||||
severity={severity}
|
||||
icon={icon}
|
||||
isTooltipOpen={isOpen}
|
||||
/>
|
||||
</div>
|
||||
</TooltipTrigger>
|
||||
<TooltipContent
|
||||
align="end"
|
||||
collisionPadding={16}
|
||||
className="max-w-[400px] p-0 bg-surface-secondary border-surface-quaternary text-sm text-content-primary"
|
||||
style={{
|
||||
borderColor: theme.roles[severity].outline,
|
||||
}}
|
||||
<Popover open={isOpen} onOpenChange={setIsOpen}>
|
||||
<PopoverTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
className="py-2 bg-transparent border-none cursor-pointer"
|
||||
data-testid={`${severity}-notifications`}
|
||||
>
|
||||
{items.map((n) => (
|
||||
<NotificationItem notification={n} key={n.title} />
|
||||
))}
|
||||
</TooltipContent>
|
||||
</Tooltip>
|
||||
</TooltipProvider>
|
||||
<NotificationPill
|
||||
items={items}
|
||||
severity={severity}
|
||||
icon={icon}
|
||||
isOpen={isOpen}
|
||||
/>
|
||||
</button>
|
||||
</PopoverTrigger>
|
||||
<PopoverContent
|
||||
align="end"
|
||||
collisionPadding={16}
|
||||
className="max-w-[400px] p-0 w-auto bg-surface-secondary border-surface-quaternary text-sm text-content-primary"
|
||||
style={{
|
||||
borderColor: theme.roles[severity].outline,
|
||||
}}
|
||||
>
|
||||
{items.map((n) => (
|
||||
<NotificationItem notification={n} key={n.title} />
|
||||
))}
|
||||
</PopoverContent>
|
||||
</Popover>
|
||||
);
|
||||
};
|
||||
|
||||
type NotificationPillProps = NotificationsProps & {
|
||||
isTooltipOpen: boolean;
|
||||
isOpen: boolean;
|
||||
};
|
||||
|
||||
const NotificationPill: FC<NotificationPillProps> = ({
|
||||
items,
|
||||
severity,
|
||||
icon,
|
||||
isTooltipOpen,
|
||||
isOpen,
|
||||
}) => {
|
||||
return (
|
||||
<Pill
|
||||
icon={icon}
|
||||
css={(theme) => ({
|
||||
"& svg": { color: theme.roles[severity].outline },
|
||||
borderColor: isTooltipOpen ? theme.roles[severity].outline : undefined,
|
||||
borderColor: isOpen ? theme.roles[severity].outline : undefined,
|
||||
})}
|
||||
>
|
||||
{items.length}
|
||||
|
||||
@@ -270,7 +270,9 @@ export const WorkspaceNotifications: FC<WorkspaceNotificationsProps> = ({
|
||||
<Notifications
|
||||
items={warningNotifications}
|
||||
severity="warning"
|
||||
icon={<TriangleAlertIcon className="size-icon-sm" />}
|
||||
icon={
|
||||
<TriangleAlertIcon aria-hidden="true" className="size-icon-sm" />
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user