react-x11 2.8.3 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,207 @@
1
+ /**
2
+ * The calendars the user's desktop already has — EventKit on macOS,
3
+ * Evolution Data Server on a freedesktop session. See
4
+ * docs/desktop-calendar.md.
5
+ */
6
+
7
+ import type { NtkApp } from './nodes.js';
8
+ import type { PermissionStatus } from './permissions.js';
9
+
10
+ /** Which rung answered: the EventKit bridge, an `osascript` child holding
11
+ * an `EKEventStore`, or Evolution Data Server over the session bus. */
12
+ export type CalendarBackend = 'cocoa' | 'osascript' | 'eds';
13
+
14
+ /** One calendar the desktop knows about. */
15
+ export interface DesktopCalendarInfo {
16
+ uid: string;
17
+ /** The name shown in the desktop's own calendar UI. */
18
+ name: string;
19
+ /** Whether the desktop has it switched on. Always true on macOS, which
20
+ * has no such state to report. */
21
+ enabled: boolean;
22
+ /** `'#3584e4'` — the colour that UI draws it in, worth carrying into a
23
+ * day marker. */
24
+ color?: string;
25
+ /** `caldav`, `google`, `local`, `exchange`, `subscription`, `birthday`…
26
+ * the store's own word, lower-cased. */
27
+ backend?: string;
28
+ readOnly: boolean;
29
+ /** The account it came from, where one is named — a GNOME Online Accounts
30
+ * entry, or an `EKSource` (`'iCloud'`, `'Google'`). */
31
+ account?: string;
32
+ }
33
+
34
+ /** One occurrence, with any recurrence already expanded. */
35
+ export interface DesktopEvent {
36
+ uid: string;
37
+ summary: string;
38
+ location?: string;
39
+ description?: string;
40
+ start: Date;
41
+ /** **Exclusive**, on every rung: an all-day event on the 10th ends at
42
+ * midnight on the 11th. The macOS rungs normalise what EventKit reports
43
+ * (the last second of the last day) so a caller never has to ask. */
44
+ end: Date;
45
+ allDay: boolean;
46
+ recurring: boolean;
47
+ calendar: { uid: string; name: string; color?: string };
48
+ }
49
+
50
+ /** A calendar that would not answer. One broken backend is not a failure. */
51
+ export interface DesktopCalendarError {
52
+ calendar: DesktopCalendarInfo;
53
+ message: string;
54
+ }
55
+
56
+ export interface EventsResult {
57
+ events: DesktopEvent[];
58
+ /** Empty on the macOS rungs, where there is one store. */
59
+ errors: DesktopCalendarError[];
60
+ }
61
+
62
+ /**
63
+ * What `watch` reports. Deliberately thin: re-query rather than patch.
64
+ *
65
+ * `'changed'` with a null calendar and no count is EventKit's — its
66
+ * notification names nothing, and a rung must not invent a count.
67
+ */
68
+ export interface CalendarChange {
69
+ calendar: DesktopCalendarInfo | null;
70
+ kind: 'ObjectsAdded' | 'ObjectsModified' | 'ObjectsRemoved' | 'changed';
71
+ count: number | null;
72
+ }
73
+
74
+ export interface EventsOptions {
75
+ /** Restrict to these calendars. Default: every enabled one. */
76
+ calendars?: DesktopCalendarInfo[];
77
+ }
78
+
79
+ /**
80
+ * Nothing on this machine can read a calendar. Raised only by
81
+ * `desktopCalendar({ required: true })`; the default answer is `null`,
82
+ * because a machine with no calendar service is an ordinary machine.
83
+ */
84
+ export declare class NoCalendarServiceError extends Error {
85
+ readonly name: 'NoCalendarServiceError';
86
+ readonly cause?: unknown;
87
+ }
88
+
89
+ /**
90
+ * The app may not read the calendars. `status` says why: `'denied'` and
91
+ * `'restricted'` and `'write-only'` are decisions, and `'prompt'` is a
92
+ * request that came back with nothing — TCC declining to ask, which the
93
+ * hook reports as `'unavailable'` rather than as a refusal.
94
+ */
95
+ export declare class CalendarAccessError extends Error {
96
+ readonly name: 'CalendarAccessError';
97
+ readonly status: PermissionStatus;
98
+ readonly cause?: unknown;
99
+ }
100
+
101
+ /** A handle on the desktop's calendars. `close()` it. */
102
+ export interface DesktopCalendar {
103
+ readonly backend: CalendarBackend;
104
+ /** The grant, without prompting; `'granted'` on a rung with no such gate. */
105
+ access(): Promise<PermissionStatus>;
106
+ /** Raise the system's prompt where there is one. Reads do this on the
107
+ * first one, so a picker the user never opens never prompts. */
108
+ requestAccess(): Promise<PermissionStatus>;
109
+ /** System Settings › Privacy & Security › Calendars. `false` off macOS. */
110
+ openSettings(): Promise<boolean>;
111
+ listCalendars(): Promise<DesktopCalendarInfo[]>;
112
+ /** Occurrences in `[from, to)`, sorted by start. Rejects with
113
+ * {@link CalendarAccessError} where the user said no. */
114
+ eventsBetween(
115
+ from: Date,
116
+ to: Date,
117
+ options?: EventsOptions,
118
+ ): Promise<EventsResult>;
119
+ /** Call `onChange` when something moves; the returned function stops. */
120
+ watch(
121
+ from: Date,
122
+ to: Date,
123
+ onChange: (change: CalendarChange) => void,
124
+ options?: EventsOptions,
125
+ ): Promise<() => Promise<void>>;
126
+ close(): Promise<void>;
127
+ }
128
+
129
+ export interface DesktopCalendarOptions {
130
+ /** The connection whose backend to ask, when there are several. */
131
+ app?: NtkApp;
132
+ /** Pin one rung and fail rather than fall through it. */
133
+ backend?: CalendarBackend;
134
+ /** Reject with {@link NoCalendarServiceError} instead of answering null. */
135
+ required?: boolean;
136
+ }
137
+
138
+ /**
139
+ * The desktop's calendars, on the best rung this machine has — or `null`,
140
+ * which is an ordinary answer about a machine.
141
+ */
142
+ export declare function desktopCalendar(
143
+ options?: DesktopCalendarOptions,
144
+ ): Promise<DesktopCalendar | null>;
145
+
146
+ /** Which rung this machine lands on, without reading anything, spawning
147
+ * anything or prompting. */
148
+ export declare function calendarBackend(
149
+ options?: Pick<DesktopCalendarOptions, 'app'>,
150
+ ): Promise<CalendarBackend | null>;
151
+
152
+ /** The local calendar day a `Date` falls on, as `'YYYY-MM-DD'` — the key
153
+ * `byDay` uses and `<Calendar dayContent>` is handed. */
154
+ export declare function dayKey(date: Date): string;
155
+
156
+ /** Occurrences grouped by the local day they appear on. An event lands
157
+ * under every day it touches, not only under its start. */
158
+ export declare function byDay(
159
+ events: DesktopEvent[],
160
+ ): Map<string, DesktopEvent[]>;
161
+
162
+ /**
163
+ * `'idle'` before anything is asked, `'denied'` for the user's refusal and
164
+ * `'unavailable'` for the machine's silence — separate words, because only
165
+ * one of them has a Settings switch behind it.
166
+ */
167
+ export type DesktopCalendarStatus =
168
+ 'idle' | 'loading' | 'ready' | 'denied' | 'unavailable';
169
+
170
+ export interface UseDesktopCalendarEventsOptions {
171
+ /** Start of the window to read, inclusive. */
172
+ from: Date;
173
+ /** End of the window, exclusive. */
174
+ to: Date;
175
+ /** Restrict to these calendar uids. Default: every enabled calendar. */
176
+ calendars?: string[];
177
+ /** Re-query when the desktop says something changed. */
178
+ watch?: boolean;
179
+ /** Set false to hold off entirely — and to not prompt: a picker that is
180
+ * not open yet has no business asking for the user's calendar. */
181
+ enabled?: boolean;
182
+ }
183
+
184
+ export interface UseDesktopCalendarEventsResult {
185
+ events: DesktopEvent[];
186
+ /** The same events, keyed by `'YYYY-MM-DD'`, ready for `dayContent`. */
187
+ byDay: Map<string, DesktopEvent[]>;
188
+ /** Every calendar found, for a legend or a filter. */
189
+ calendars: DesktopCalendarInfo[];
190
+ /** Calendars that would not answer while others did. Not fatal. */
191
+ errors: DesktopCalendarError[];
192
+ status: DesktopCalendarStatus;
193
+ /** Which rung answered, once one has. */
194
+ backend: CalendarBackend | null;
195
+ /** Why there are no events, when there is a reason worth showing. */
196
+ error: Error | null;
197
+ /** Re-query now. */
198
+ refresh: () => void;
199
+ /** System Settings › Privacy & Security › Calendars — for `'denied'`, and
200
+ * for no other status. */
201
+ openSettings: () => Promise<boolean>;
202
+ }
203
+
204
+ /** The user's desktop calendar events, as rendering state. */
205
+ export declare function useDesktopCalendarEvents(
206
+ options: UseDesktopCalendarEventsOptions,
207
+ ): UseDesktopCalendarEventsResult;
@@ -278,6 +278,47 @@ export type WindowType =
278
278
  | 'desktop'
279
279
  | (string & {});
280
280
 
281
+ /**
282
+ * How a window paces its frames when its content changes faster than the
283
+ * display refreshes — a terminal under a flood, a chart on a socket, a
284
+ * simulation. Priced in CPU time, not counted in updates: a frame costs
285
+ * what the flush (and on macOS the present) took of this thread, and a
286
+ * claim waits only while recent frames have spent more than their share.
287
+ * A scroll that is mostly blits keeps the display's rate; only a stream of
288
+ * expensive frames earns a wait (docs/elements.md "frameRate").
289
+ *
290
+ * - `'display'` — every frame the clock gives, after React's own
291
+ * batching. **The default.**
292
+ * - `'adaptive'` — paints stay under a quarter of the time while busy, and
293
+ * the screen is never more than 50ms behind (a 20fps floor). Idle claims
294
+ * and cheap frames never wait.
295
+ * - `'throughput'` — a tenth, a 10fps floor and a 30fps ceiling: fewer,
296
+ * later frames for a window whose output matters more than its display.
297
+ * - a number — a ceiling in frames per second, nothing else.
298
+ * - `{ budget, minFps, maxFps }` — the three numbers the presets are made
299
+ * of, any subset; the rest are `'display'`'s (so name a `minFps` with a
300
+ * `budget` below 1).
301
+ *
302
+ * `createRoot({ frameRate })` sets the default for every window of a root,
303
+ * and `REACT_X11_FRAME_RATE` overrides both from the environment.
304
+ */
305
+ export type FrameRate =
306
+ | 'display'
307
+ | 'adaptive'
308
+ | 'throughput'
309
+ | number
310
+ | {
311
+ /** Share of wall time paints may take while busy, above 0 and at
312
+ * most 1. */
313
+ budget?: number;
314
+ /** The floor: the screen is never more than `1000 / minFps` ms behind
315
+ * the last paint. 0 for none. */
316
+ minFps?: number;
317
+ /** A ceiling in frames per second, cheap frames included. 0 for
318
+ * none. */
319
+ maxFps?: number;
320
+ };
321
+
281
322
  export interface WindowProps
282
323
  extends
283
324
  CommonProps,
@@ -289,6 +330,10 @@ export interface WindowProps
289
330
  ref?: Ref<NtkWindow>;
290
331
  /** Window title (UTF-8, via `WM_NAME` + `_NET_WM_NAME`). */
291
332
  title?: string;
333
+ /** How this window paces its frames under a stream of changes — see
334
+ * {@link FrameRate}. `'display'` unless the root or the environment says
335
+ * otherwise. A `<popup>` paces itself the same way. */
336
+ frameRate?: FrameRate;
292
337
  /**
293
338
  * Created but never self-mapped: this window is waiting to be embedded
294
339
  * (XEmbed / `<foreign>` on the other side), and from the reparent on,
@@ -865,6 +910,15 @@ export interface GlAreaProps extends DrawnProps<DrawnNode> {
865
910
  clearColor?: Color | [number, number, number, number];
866
911
  /** `'demand'` (default) redraws on change; `'always'` runs continuously. */
867
912
  frameLoop?: FrameLoop;
913
+ /**
914
+ * How the surface's frames are paced when they are expensive — the same
915
+ * vocabulary as {@link WindowProps.frameRate}, priced by what `onDraw`
916
+ * and the swap cost this thread. Defaults to the owning window's, so a
917
+ * `<window frameRate="adaptive">` paces the scene inside it too; set it
918
+ * here for a scene that wants every frame (`'display'`) while the window
919
+ * around it streams, or the other way round.
920
+ */
921
+ frameRate?: FrameRate;
868
922
  /** Visual spec for ntk's `chooseGLXConfig`, e.g. `{ DEPTH_SIZE: 24 }`. */
869
923
  glx?: Record<string, unknown>;
870
924
  /** Runs once, with the context current: one-time state, uploads, lists. */
@@ -12,7 +12,9 @@ export type PermissionKind =
12
12
  | 'accessibility'
13
13
  | 'input-monitoring'
14
14
  | 'automation'
15
- | 'location';
15
+ | 'location'
16
+ | 'calendars'
17
+ | 'reminders';
16
18
 
17
19
  /** The panes `openPrivacySettings` reaches: every kind, plus the two with no
18
20
  * API because reading the folder is the prompt. */
@@ -23,10 +25,12 @@ export type PrivacyPane =
23
25
  * `'granted'`, `'denied'` and `'restricted'` (MDM or parental controls — the
24
26
  * user cannot grant it) are the platform's; `'prompt'` is not decided yet, a
25
27
  * request would ask; `'unknown'` is "nothing here can say", a fact about the
26
- * machine rather than the permission.
28
+ * machine rather than the permission. `'write-only'` is macOS 14's partial
29
+ * grant for `calendars`/`reminders`: a grant to a writer, a refusal to a
30
+ * reader, and only the caller knows which it is.
27
31
  */
28
32
  export type PermissionStatus =
29
- 'granted' | 'denied' | 'restricted' | 'prompt' | 'unknown';
33
+ 'granted' | 'denied' | 'restricted' | 'prompt' | 'write-only' | 'unknown';
30
34
 
31
35
  export interface PermissionOptions {
32
36
  /** The connection whose backend to ask, when there are several. */
@@ -34,6 +38,10 @@ export interface PermissionOptions {
34
38
  /** `automation` only: the bundle id of the app to send Apple Events to.
35
39
  * Only a running target has an answer. */
36
40
  target?: string;
41
+ /** `calendars` only: which grant to ask for. `'write-only'` is macOS 14's
42
+ * narrower prompt — the app may save events it cannot read. `reminders`
43
+ * has no such grant and refuses one. */
44
+ access?: 'full' | 'write-only';
37
45
  }
38
46
 
39
47
  /**
@@ -96,5 +104,5 @@ export interface Permission {
96
104
  /** A permission for a component: the status as render state. */
97
105
  export declare function usePermission(
98
106
  kind: PermissionKind,
99
- options?: Pick<PermissionOptions, 'target'>,
107
+ options?: Pick<PermissionOptions, 'target' | 'access'>,
100
108
  ): Permission;