Skip to main content

Desktop calendar

import { useDesktopCalendarEvents } from '@react-x11/components/desktop-calendar';

The user's real calendars — Google, Microsoft, CalDAV, local — read through Evolution Data Server over D-Bus.

Your app never sees a credential and never runs an OAuth flow, because the desktop did that already, in Settings. This is a hook and a couple of plain functions, not a component: what to draw with the events is the app's business.

useDesktopCalendarEvents(options)

import { Calendar, useDesktopCalendarEvents } from '@react-x11/components';

function Month({ from, to }) {
const { byDay } = useDesktopCalendarEvents({ from, to, watch: true });

return (
<Calendar
dayContent={(day, state) =>
(byDay.get(day) ?? []).slice(0, 3).map((ev, i) => (
<box
key={i}
style={{
width: 4,
height: 4,
borderRadius: 2,
backgroundColor: state.selected
? state.color
: (ev.calendar.color ?? '$accent'),
}}
/>
))
}
/>
);
}

The keys byDay uses are exactly the 'YYYY-MM-DD' days <Calendar>'s dayContent is handed, so nothing sits between the two.

Options

OptionTypeNotes
fromDateStart of the window to read, inclusive. Required.
toDateEnd of the window, exclusive. Required.
calendarsstring[]Restrict to these calendar UIDs. Default: every enabled one.
watchbooleanRe-query when the desktop says something in the range changed.
enabledbooleanSet false to hold off entirely — a picker that is not open yet.

Result

FieldTypeNotes
eventsDesktopEvent[]
byDayMap<string, DesktopEvent[]>The same events keyed by 'YYYY-MM-DD', ready for dayContent.
calendarsDesktopCalendarInfo[]Every calendar found, for a legend or a filter.
errorsDesktopCalendarError[]Backends that would not answer. Not fatal — the rest still loaded.
status'idle' | 'loading' | 'ready' | 'unavailable'
errorError | nullWhy there are no events: no bus, or no ical.js.
refresh() => voidRe-query now.

Types

interface DesktopEvent {
uid: string;
summary: string;
location?: string;
description?: string;
start: Date;
end: Date;
allDay: boolean;
recurring: boolean;
calendar: { uid: string; name: string; color?: string };
}

interface DesktopCalendarInfo {
uid: string;
name: string; // as the desktop's own calendar UI shows it
enabled: boolean;
color?: string; // worth carrying into a day marker
backend?: string; // 'caldav', 'google', 'local', 'webcal'…
readOnly: boolean;
account?: string; // set when it came from an Online Accounts login
}

ical.js is optional, and so is having a calendar at all

Expanding recurring events needs ical.js:

npm install ical.js

Without it, or with no session bus, or on a desktop with no Evolution Data Server, status is 'unavailable' and a calendar simply renders without dots. None of those is an error — they are ordinary states of a healthy machine, which is why the hook reports them through status and error rather than throwing. IcalUnavailableError is exported so the missing-module case can be told apart from the missing-bus one.

Lower-level exports

  • DesktopCalendar — the EDS client on its own, without React: list the sources, open a calendar, query a range.
  • byDay(events) — the grouping, as a plain function, for events that came from somewhere else.
  • parseKeyFile(text) — EDS stores its source definitions as GLib key files; this reads one. Exported because it is useful and testable on its own.

Example

npm run examples:calendar is the whole thing working: a real month grid with the machine's real events dotted onto it. It needs a $DISPLAY and a session bus.