fix(quick-260921-jt4): Kalender-Tageszelle wird echte Schaltflaeche fuer Tage mit Terminen
- Zelle rendert als <button type="button"> NUR wenn hasEvents gilt, sonst unveraendert als <div> ohne Handler (D-01) — 42 neue Tab-Stopps waeren eine Verschlechterung - onFocus/onBlur mit demselben Rumpf wie onMouseEnter/onMouseLeave, damit die Termin-Einblendung auch per Tastatur erscheint/verschwindet - cellClass unveraendert uebernommen, nur w-full text-left ergaenzt (D-04, kein optischer Unterschied); widgetNoDrag bleibt erhalten - aria-label nennt Datum und Terminzahl ueber neue Katalogschluessel widgets.calendar.dayEventsOne/dayEventsMany (Mehrzahl-Konvention wie configMaxEventsOne/Many, D-05) - Neue Tests: Tag mit Terminen ist <button> und reagiert auf Fokus/Weggehen wie auf Maus-Hover; Tag ohne Termine bleibt <div>; Einzahl-/Mehrzahl-Beschriftung; echter Tab-Stopp nachgewiesen Nach diesem Umbau: klick-regeln 5 (nur die vier <img onError> + Taschenrechner-Rahmen), semantic 0, a11y gesamt 14, errors 0 — Aufgabe 1 des Plans vollstaendig. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01TPPB4ApQxzSU1rwV2Ffj9J
This commit is contained in:
@@ -249,20 +249,8 @@ export function CalendarWidget({ config }: WidgetProps) {
|
||||
.filter(Boolean)
|
||||
.join(' ');
|
||||
|
||||
return (
|
||||
<div
|
||||
key={day.key}
|
||||
data-testid="calendar-day"
|
||||
data-date={day.key}
|
||||
data-today={day.isToday || undefined}
|
||||
data-outside={!day.inCurrentMonth || undefined}
|
||||
className={cellClass}
|
||||
onMouseEnter={(e) =>
|
||||
hasEvents &&
|
||||
setHover({ key: day.key, rect: e.currentTarget.getBoundingClientRect() })
|
||||
}
|
||||
onMouseLeave={() => setHover(null)}
|
||||
>
|
||||
const cellContent = (
|
||||
<>
|
||||
<span>{day.date.getDate()}</span>
|
||||
{hasEvents && (
|
||||
// Wrapper traegt die Positionierung, die einzelnen Kreise nicht
|
||||
@@ -298,6 +286,61 @@ export function CalendarWidget({ config }: WidgetProps) {
|
||||
})}
|
||||
</span>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
|
||||
// Nur Tage MIT Terminen werden zu Tab-Stopps (D-01) — ein
|
||||
// Widget mit 42 zusaetzlichen Tab-Stopps waere eine
|
||||
// Verschlechterung. Wer nicht mit der Maus arbeitet, bekam
|
||||
// die Termin-Einblendung bislang gar nicht zu sehen; die
|
||||
// Schaltflaeche traegt deshalb zusaetzlich onFocus/onBlur mit
|
||||
// demselben Rumpf wie onMouseEnter/onMouseLeave.
|
||||
if (hasEvents) {
|
||||
const dayLabel = new Intl.DateTimeFormat('de-DE', {
|
||||
weekday: 'short',
|
||||
day: '2-digit',
|
||||
month: '2-digit',
|
||||
}).format(day.date);
|
||||
const eventCount = day.events.length;
|
||||
const ariaLabel =
|
||||
eventCount === 1
|
||||
? t('calendar.dayEventsOne', { date: dayLabel })
|
||||
: t('calendar.dayEventsMany', { date: dayLabel, count: eventCount });
|
||||
|
||||
return (
|
||||
<button
|
||||
key={day.key}
|
||||
type="button"
|
||||
data-testid="calendar-day"
|
||||
data-date={day.key}
|
||||
data-today={day.isToday || undefined}
|
||||
data-outside={!day.inCurrentMonth || undefined}
|
||||
className={`${cellClass} w-full text-left`}
|
||||
aria-label={ariaLabel}
|
||||
onMouseEnter={(e) =>
|
||||
setHover({ key: day.key, rect: e.currentTarget.getBoundingClientRect() })
|
||||
}
|
||||
onMouseLeave={() => setHover(null)}
|
||||
onFocus={(e) =>
|
||||
setHover({ key: day.key, rect: e.currentTarget.getBoundingClientRect() })
|
||||
}
|
||||
onBlur={() => setHover(null)}
|
||||
>
|
||||
{cellContent}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
key={day.key}
|
||||
data-testid="calendar-day"
|
||||
data-date={day.key}
|
||||
data-today={day.isToday || undefined}
|
||||
data-outside={!day.inCurrentMonth || undefined}
|
||||
className={cellClass}
|
||||
>
|
||||
{cellContent}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
|
||||
Reference in New Issue
Block a user