('[data-plugin-surface="mini-calendar-marks"]')!;
+ expect(dot.closest('button')).toHaveAttribute('aria-current', 'date');
+ // Its own colour, not the button's text colour, which is white on today.
+ expect(dot.className).not.toMatch(/bg-current/);
+ expect(dot.className).toMatch(/ring-background/);
+ } finally {
+ vi.useRealTimers();
+ }
+ });
});
diff --git a/components/calendar/calendar-month-view.tsx b/components/calendar/calendar-month-view.tsx
index 1164876b5..cd413898a 100644
--- a/components/calendar/calendar-month-view.tsx
+++ b/components/calendar/calendar-month-view.tsx
@@ -380,7 +380,8 @@ export function CalendarMonthView({
>
{formatDayNumber(day)}
- {!isMobile && }
+ {/* Phones have no room for the text: a dot stands in for it. */}
+
{isMobile && !showChips ? (
diff --git a/components/calendar/plugin-day-label.tsx b/components/calendar/plugin-day-label.tsx
index 63ff9aa0f..5fc22e768 100644
--- a/components/calendar/plugin-day-label.tsx
+++ b/components/calendar/plugin-day-label.tsx
@@ -27,10 +27,16 @@ interface PluginDayLabelProps {
/** YYYY-MM-DD */
date: string;
className?: string;
+ /**
+ * calendar-day-header only: no room for text (the phone month view), so a
+ * dot stands for the day's labels; their text is its tooltip and is read
+ * out by screen readers.
+ */
+ compact?: boolean;
}
/** What plugins put on a calendar day. Renders nothing without labels. */
-export function PluginDayLabel({ surface, date, className }: PluginDayLabelProps) {
+export function PluginDayLabel({ surface, date, className, compact }: PluginDayLabelProps) {
const labels = useDayLabels(date);
if (surface === "mini-calendar-marks") {
@@ -42,13 +48,29 @@ export function PluginDayLabel({ surface, date, className }: PluginDayLabelProps
aria-hidden="true"
data-plugin-surface="mini-calendar-marks"
title={tooltip(marks)}
- className={cn("pointer-events-none absolute top-0.5 end-0.5 h-1 w-1 rounded-full bg-current opacity-70", className)}
+ className={cn("pointer-events-none absolute top-0 end-0 h-1.5 w-1.5 rounded-full bg-muted-foreground ring-1 ring-background", className)}
/>
{marks.map((l) => l.title ?? l.text ?? l.pluginName).join(", ")}
>
);
}
+ if (compact) {
+ const shown = labels.filter((l) => l.text || l.dot);
+ if (shown.length === 0) return null;
+ return (
+
+
+ {shown.map((l) => l.text ?? l.title ?? l.pluginName).join(", ")}
+
+ );
+ }
+
const withText = labels.filter((l) => l.text);
if (withText.length === 0) return null;
return (
diff --git a/lib/plugin-slot-catalog.ts b/lib/plugin-slot-catalog.ts
index c633f629b..768e2bb02 100644
--- a/lib/plugin-slot-catalog.ts
+++ b/lib/plugin-slot-catalog.ts
@@ -89,7 +89,7 @@ export const SLOT_CATALOG = {
'calendar-event-actions': S('calendar', 'frame', ['ui:calendar-action'], { eventData: 'calendar:read', setVirtualLocation: null }, 'buttons in the event form', true),
'calendar-event-detail': S('calendar', 'frame', ['ui:calendar-action'], { event: 'calendar:read' }, 'a section in an event\'s details'),
'calendar-event-form': S('calendar', 'frame', ['ui:calendar-action'], { event: 'calendar:read' }, 'a section in the form for a new or edited event'),
- 'calendar-day-header': S('calendar', 'data', ['ui:calendar-action'], { date: null }, 'a short label under a day\'s name in the day and week views (api.ui.setDayLabels)'),
+ 'calendar-day-header': S('calendar', 'data', ['ui:calendar-action'], { date: null }, 'a short label under a day\'s name in the day, week and month views; a dot in the phone month view (api.ui.setDayLabels)'),
'mini-calendar-marks': S('calendar', 'data', ['ui:calendar-action'], { date: null }, 'dots on days in the small month calendar (api.ui.setDayLabels)'),
// ─── Contacts ──────────────────────────────────────────────