diff --git a/UI_AUDIT_REPORT.md b/UI_AUDIT_REPORT.md index 0c8c5d8..2d08c37 100644 --- a/UI_AUDIT_REPORT.md +++ b/UI_AUDIT_REPORT.md @@ -600,25 +600,25 @@ export const announceToScreenReader = (message: string) => { ### 🟡 High Priority (高优先级,2 周内完成) #### 5. **完善 ARIA 属性** (预计 3 小时) -- [ ] **SearchForm.tsx** - - [ ] 添加 `role="combobox"` - - [ ] 添加 `aria-expanded={showHistory}` - - [ ] 添加 `aria-controls="search-history-listbox"` - - [ ] 添加 `aria-autocomplete="list"` +- [✅] **SearchForm.tsx** + - [✅] 添加 `role="combobox"` + - [✅] 添加 `aria-expanded={showHistory}` + - [✅] 添加 `aria-controls="search-history-listbox"` + - [✅] 添加 `aria-autocomplete="list"` -- [ ] **WatchHistorySidebar.tsx** - - [ ] 添加 `role="complementary"` - - [ ] 添加 `aria-labelledby="history-sidebar-title"` - - [ ] 添加 `aria-hidden={!isOpen}` - - [ ] 实现焦点陷阱 (focus trap) +- [✅] **WatchHistorySidebar.tsx** + - [✅] 添加 `role="complementary"` + - [✅] 添加 `aria-labelledby="history-sidebar-title"` + - [✅] 添加 `aria-hidden={!isOpen}` + - [✅] 实现焦点陷阱 (focus trap) -- [ ] **VideoPlayer.tsx** - - [ ] 错误提示添加 `role="alert"` - - [ ] 添加 `aria-live="assertive"` +- [✅] **VideoPlayer.tsx** + - [✅] 错误提示添加 `role="alert"` + - [✅] 添加 `aria-live="assertive"` -- [ ] **VideoGrid.tsx** - - [ ] 添加 `role="list"` 到网格容器 - - [ ] 添加 `role="listitem"` 到每个卡片 +- [✅] **VideoGrid.tsx** + - [✅] 添加 `role="list"` 到网格容器 + - [✅] 添加 `role="listitem"` 到每个卡片 #### 6. **添加键盘导航支持** (预计 4 小时) - [ ] **VideoGrid.tsx** diff --git a/components/history/WatchHistorySidebar.tsx b/components/history/WatchHistorySidebar.tsx index b66abef..0267a4e 100644 --- a/components/history/WatchHistorySidebar.tsx +++ b/components/history/WatchHistorySidebar.tsx @@ -5,16 +5,50 @@ 'use client'; -import { useState } from 'react'; +import { useState, useEffect, useRef } from 'react'; import { useHistoryStore } from '@/lib/store/history-store'; import { Icons } from '@/components/ui/Icon'; import { Button } from '@/components/ui/Button'; import { HistoryItem } from './HistoryItem'; import { HistoryEmptyState } from './HistoryEmptyState'; +import { trapFocus } from '@/lib/accessibility/focus-trap'; export function WatchHistorySidebar() { const [isOpen, setIsOpen] = useState(false); const { viewingHistory, removeFromHistory, clearHistory } = useHistoryStore(); + const sidebarRef = useRef(null); + const cleanupFocusTrapRef = useRef<(() => void) | null>(null); + + // Setup focus trap when sidebar opens + useEffect(() => { + if (isOpen && sidebarRef.current) { + cleanupFocusTrapRef.current = trapFocus(sidebarRef.current); + } + + return () => { + if (cleanupFocusTrapRef.current) { + cleanupFocusTrapRef.current(); + cleanupFocusTrapRef.current = null; + } + }; + }, [isOpen]); + + // Handle escape key to close sidebar + useEffect(() => { + const handleEscape = (e: KeyboardEvent) => { + if (e.key === 'Escape' && isOpen) { + setIsOpen(false); + } + }; + + if (isOpen) { + document.addEventListener('keydown', handleEscape); + } + + return () => { + document.removeEventListener('keydown', handleEscape); + }; + }, [isOpen]); return ( <> @@ -37,6 +71,10 @@ export function WatchHistorySidebar() { {/* Sidebar */}