feat: accessibility pass - semantic HTML, ARIA, focus indicators, high contrast
This commit is contained in:
@@ -248,14 +248,49 @@ export function BoardView() {
|
||||
|
||||
const columnIds = board.columns.map((c) => c.id);
|
||||
|
||||
const [announcement, setAnnouncement] = useState("");
|
||||
|
||||
const handleDragEndWithAnnouncement = useCallback(
|
||||
(event: DragEndEvent) => {
|
||||
handleDragEnd(event);
|
||||
const { active, over } = event;
|
||||
if (over && board) {
|
||||
const type = active.data.current?.type;
|
||||
if (type === "card") {
|
||||
const card = board.cards[active.id as string];
|
||||
const targetCol = over.data.current?.type === "column"
|
||||
? board.columns.find((c) => c.id === (over.data.current?.columnId ?? over.id))
|
||||
: findColumnByCardId(board, over.id as string);
|
||||
if (card && targetCol) {
|
||||
setAnnouncement(`Moved card "${card.title}" to ${targetCol.title}`);
|
||||
}
|
||||
} else if (type === "column") {
|
||||
const col = board.columns.find((c) => c.id === (active.id as string));
|
||||
if (col) {
|
||||
setAnnouncement(`Reordered column "${col.title}"`);
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
[handleDragEnd, board]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* Visually hidden live region for drag-and-drop announcements */}
|
||||
<div
|
||||
aria-live="polite"
|
||||
aria-atomic="true"
|
||||
className="sr-only"
|
||||
>
|
||||
{announcement}
|
||||
</div>
|
||||
<DndContext
|
||||
sensors={sensors}
|
||||
collisionDetection={closestCorners}
|
||||
onDragStart={handleDragStart}
|
||||
onDragOver={handleDragOver}
|
||||
onDragEnd={handleDragEnd}
|
||||
onDragEnd={handleDragEndWithAnnouncement}
|
||||
>
|
||||
<SortableContext
|
||||
items={columnIds}
|
||||
|
||||
Reference in New Issue
Block a user