@@ -148,18 +148,19 @@ function CalendarView({
148148 }
149149
150150 return (
151- < div className = { cn ( "flex flex-col h-full bg-background" , className ) } >
151+ < div role = "region" aria-label = "Calendar" className = { cn ( "flex flex-col h-full bg-background" , className ) } >
152152 { /* Header */ }
153153 < div className = "flex items-center justify-between p-4 border-b" >
154154 < div className = "flex items-center gap-4" >
155155 < div className = "flex items-center bg-muted/50 rounded-lg p-1 gap-1" >
156- < Button variant = "ghost" size = "sm" onClick = { handleToday } className = "h-8" >
156+ < Button variant = "ghost" size = "sm" onClick = { handleToday } className = "h-8" aria-label = "Go to today" >
157157 Today
158158 </ Button >
159159 < div className = "h-4 w-px bg-border mx-1" />
160160 < Button
161161 variant = "ghost"
162162 size = "icon"
163+ aria-label = "Previous period"
163164 onClick = { handlePrevious }
164165 className = "h-8 w-8"
165166 >
@@ -168,6 +169,7 @@ function CalendarView({
168169 < Button
169170 variant = "ghost"
170171 size = "icon"
172+ aria-label = "Next period"
171173 onClick = { handleNext }
172174 className = "h-8 w-8"
173175 >
@@ -179,6 +181,7 @@ function CalendarView({
179181 < PopoverTrigger asChild >
180182 < Button
181183 variant = "ghost"
184+ aria-label = { `Current date: ${ getDateLabel ( ) } ` }
182185 className = { cn (
183186 "text-xl font-semibold h-auto px-3 py-1 hover:bg-muted/50 transition-colors" ,
184187 "flex items-center gap-2"
@@ -393,10 +396,11 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
393396 return (
394397 < div className = "flex flex-col h-full" >
395398 { /* Week day headers */ }
396- < div className = "grid grid-cols-7 border-b" >
399+ < div role = "row" className = "grid grid-cols-7 border-b" >
397400 { weekDays . map ( ( day ) => (
398401 < div
399402 key = { day }
403+ role = "columnheader"
400404 className = "p-2 text-center text-sm font-medium text-muted-foreground border-r last:border-r-0"
401405 >
402406 { day }
@@ -405,7 +409,7 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
405409 </ div >
406410
407411 { /* Calendar days */ }
408- < div className = "grid grid-cols-7 flex-1 auto-rows-fr" >
412+ < div role = "grid" aria-label = "Calendar grid" className = "grid grid-cols-7 flex-1 auto-rows-fr" >
409413 { days . map ( ( day , index ) => {
410414 const dayEvents = getEventsForDate ( day , events )
411415 const isCurrentMonth = day . getMonth ( ) === date . getMonth ( )
@@ -414,6 +418,8 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
414418 return (
415419 < div
416420 key = { index }
421+ role = "gridcell"
422+ aria-label = { `${ day . toLocaleDateString ( "default" , { weekday : "long" , month : "long" , day : "numeric" , year : "numeric" } ) } ${ dayEvents . length > 0 ? `, ${ dayEvents . length } event${ dayEvents . length > 1 ? "s" : "" } ` : "" } ` }
417423 className = { cn (
418424 "border-b border-r last:border-r-0 p-2 min-h-[100px] cursor-pointer hover:bg-accent/50" ,
419425 ! isCurrentMonth && "bg-muted/30 text-muted-foreground" ,
@@ -430,13 +436,16 @@ function MonthView({ date, events, onEventClick, onDateClick, onEventDrop }: Mon
430436 isToday &&
431437 "inline-flex items-center justify-center rounded-full bg-primary text-primary-foreground h-6 w-6"
432438 ) }
439+ { ...( isToday ? { "aria-current" : "date" as const } : { } ) }
433440 >
434441 { day . getDate ( ) }
435442 </ div >
436443 < div className = "space-y-1" >
437444 { dayEvents . slice ( 0 , 3 ) . map ( ( event ) => (
438445 < div
439446 key = { event . id }
447+ role = "button"
448+ aria-label = { event . title }
440449 draggable = { ! ! onEventDrop }
441450 onDragStart = { ( e ) => handleDragStart ( e , event ) }
442451 onDragEnd = { handleDragEnd }
@@ -517,19 +526,23 @@ function WeekView({ date, events, onEventClick, onDateClick }: WeekViewProps) {
517526 </ div >
518527
519528 { /* Week events */ }
520- < div className = "grid grid-cols-7 flex-1" >
529+ < div role = "grid" className = "grid grid-cols-7 flex-1" >
521530 { weekDays . map ( ( day ) => {
522531 const dayEvents = getEventsForDate ( day , events )
523532 return (
524533 < div
525534 key = { day . toISOString ( ) }
535+ role = "gridcell"
536+ aria-label = { `${ day . toLocaleDateString ( "default" , { weekday : "long" , month : "long" , day : "numeric" , year : "numeric" } ) } ${ dayEvents . length > 0 ? `, ${ dayEvents . length } event${ dayEvents . length > 1 ? "s" : "" } ` : "" } ` }
526537 className = "border-r last:border-r-0 p-2 min-h-[400px] cursor-pointer hover:bg-accent/50"
527538 onClick = { ( ) => onDateClick ?.( day ) }
528539 >
529540 < div className = "space-y-2" >
530541 { dayEvents . map ( ( event ) => (
531542 < div
532543 key = { event . id }
544+ role = "button"
545+ aria-label = { event . title }
533546 className = { cn (
534547 "text-sm px-3 py-2 rounded cursor-pointer hover:opacity-80" ,
535548 event . color || DEFAULT_EVENT_COLOR
@@ -576,7 +589,7 @@ function DayView({ date, events, onEventClick }: DayViewProps) {
576589
577590 return (
578591 < div className = "flex flex-col h-full" >
579- < div className = "flex-1 overflow-auto" >
592+ < div role = "list" className = "flex-1 overflow-auto" >
580593 { hours . map ( ( hour ) => {
581594 const hourEvents = dayEvents . filter ( ( event ) => {
582595 if ( event . allDay ) return hour === 0
@@ -585,7 +598,7 @@ function DayView({ date, events, onEventClick }: DayViewProps) {
585598 } )
586599
587600 return (
588- < div key = { hour } className = "flex border-b min-h-[60px]" >
601+ < div key = { hour } role = "listitem" className = "flex border-b min-h-[60px]" >
589602 < div className = "w-20 p-2 text-sm text-muted-foreground border-r" >
590603 { hour === 0
591604 ? "12 AM"
@@ -599,6 +612,7 @@ function DayView({ date, events, onEventClick }: DayViewProps) {
599612 { hourEvents . map ( ( event ) => (
600613 < div
601614 key = { event . id }
615+ aria-label = { event . title }
602616 className = { cn (
603617 "px-3 py-2 rounded cursor-pointer hover:opacity-80" ,
604618 event . color || DEFAULT_EVENT_COLOR
0 commit comments