react-x11 2.51.1 → 2.53.0

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.
Files changed (121) hide show
  1. package/README.md +94 -61
  2. package/docs/README.md +256 -0
  3. package/docs/accessibility.md +575 -0
  4. package/docs/appearance.md +317 -0
  5. package/docs/click-to-component.md +92 -0
  6. package/docs/clipboard.md +262 -0
  7. package/docs/components.md +1231 -0
  8. package/docs/dbus.md +205 -0
  9. package/docs/debugging.md +371 -0
  10. package/docs/desktop-calendar.md +247 -0
  11. package/docs/desktop.md +523 -0
  12. package/docs/devtools.md +133 -0
  13. package/docs/drag-and-drop.md +585 -0
  14. package/docs/ecosystem/animation.md +360 -0
  15. package/docs/ecosystem/data-fetching.md +186 -0
  16. package/docs/ecosystem/dev-tooling.md +393 -0
  17. package/docs/ecosystem/forms.md +277 -0
  18. package/docs/ecosystem/headless.md +194 -0
  19. package/docs/ecosystem/i18n.md +86 -0
  20. package/docs/ecosystem/icons.md +377 -0
  21. package/docs/ecosystem/layout.md +206 -0
  22. package/docs/ecosystem/routing.md +135 -0
  23. package/docs/ecosystem/state.md +344 -0
  24. package/docs/ecosystem/testing.md +474 -0
  25. package/docs/ecosystem/theming.md +494 -0
  26. package/docs/ecosystem.md +439 -0
  27. package/docs/elements.md +2079 -0
  28. package/docs/embedding.md +239 -0
  29. package/docs/events.md +742 -0
  30. package/docs/extending.md +1700 -0
  31. package/docs/eyedropper.md +164 -0
  32. package/docs/filedialog.md +222 -0
  33. package/docs/frame.md +436 -0
  34. package/docs/gl.md +173 -0
  35. package/docs/globalmenu.md +195 -0
  36. package/docs/macos.md +592 -0
  37. package/docs/notifications.md +150 -0
  38. package/docs/packaging.md +468 -0
  39. package/docs/permissions.md +143 -0
  40. package/docs/react-features.md +405 -0
  41. package/docs/remote.md +179 -0
  42. package/docs/scale.md +225 -0
  43. package/docs/security.md +132 -0
  44. package/docs/styling.md +1710 -0
  45. package/docs/system.md +519 -0
  46. package/docs/testing.md +494 -0
  47. package/docs/typescript.md +75 -0
  48. package/docs/uri-schemes.md +340 -0
  49. package/docs/wayland-backend.md +332 -0
  50. package/docs/windows-integrations.md +177 -0
  51. package/docs/windows.md +380 -0
  52. package/package.json +11 -3
  53. package/src/Reconciler.js +2 -2
  54. package/src/a11y.js +1 -1
  55. package/src/backend/context2d.js +3 -3
  56. package/src/bootstrap.js +1 -1
  57. package/src/bus.js +39 -26
  58. package/src/cli/create.d.ts +43 -0
  59. package/src/cli/create.js +305 -0
  60. package/src/cli/env.js +484 -0
  61. package/src/cli/index.js +29 -2
  62. package/src/cli/templates/AGENTS.template.md +195 -0
  63. package/src/cli/templates/DESIGN.template.md +269 -0
  64. package/src/cocoa/app.js +6 -6
  65. package/src/cocoa/bezels.js +1 -1
  66. package/src/cocoa/fonts.js +1 -1
  67. package/src/cocoa/globalmenu.js +1 -1
  68. package/src/cocoa/keymap.js +1 -1
  69. package/src/cocoa/panewindow.js +1 -1
  70. package/src/cocoa/player.js +1 -1
  71. package/src/cocoa/presenter.js +2 -2
  72. package/src/cocoa/promotion.js +1 -1
  73. package/src/cocoa/relaunch.js +1 -1
  74. package/src/cocoa/threaded.js +1 -1
  75. package/src/cocoa/video.js +1 -1
  76. package/src/cocoa/window.js +4 -4
  77. package/src/components/Menu.js +7 -2
  78. package/src/components/Switch.js +1 -1
  79. package/src/components/native.js +1 -1
  80. package/src/desktopintegration.js +2 -1
  81. package/src/desktopsettings.js +193 -24
  82. package/src/dnd.js +2 -2
  83. package/src/filedialog.js +3 -3
  84. package/src/glnodes.js +1 -1
  85. package/src/grid.js +1 -1
  86. package/src/keyboardstate.js +28 -0
  87. package/src/layouts.js +1 -1
  88. package/src/node.d.ts +10 -10
  89. package/src/nodes/animation.js +1 -1
  90. package/src/nodes/invalidate.js +1 -1
  91. package/src/nodes/layouthost.js +1 -1
  92. package/src/nodes/video.js +19 -8
  93. package/src/nodes/window/droptarget.js +1 -1
  94. package/src/pacing.js +1 -1
  95. package/src/portal.js +31 -0
  96. package/src/refresh/index.js +2 -1
  97. package/src/screencolor.js +5 -10
  98. package/src/types/system.d.ts +8 -6
  99. package/src/types/video.d.ts +5 -2
  100. package/src/videobackend.js +28 -0
  101. package/src/videoframes.js +29 -16
  102. package/src/wayland/app.js +86 -0
  103. package/src/wayland/clipboard.js +14 -7
  104. package/src/wayland/connection.js +3 -0
  105. package/src/wayland/context2d.js +129 -10
  106. package/src/wayland/protocols/index.json +6 -0
  107. package/src/wayland/protocols/xdg-foreign-unstable-v2.json +1 -0
  108. package/src/wayland/seat.js +28 -1
  109. package/src/wayland/swapchain.js +23 -0
  110. package/src/wayland/video.js +376 -0
  111. package/src/wayland/xkb.js +137 -0
  112. package/src/win32/a11y.js +1 -1
  113. package/src/win32/app.js +2 -2
  114. package/src/win32/fonts.js +1 -1
  115. package/src/win32/glarea.js +4 -4
  116. package/src/win32/overlay.js +1 -1
  117. package/src/win32/panewindow.js +3 -3
  118. package/src/win32/shell.js +1 -1
  119. package/src/win32/window.js +2 -2
  120. package/src/windowid.js +1 -1
  121. package/src/xvideo.js +189 -0
@@ -0,0 +1,247 @@
1
+ # The desktop's calendar
2
+
3
+ The user's real events — iCloud, Google, Microsoft, CalDAV, a subscribed
4
+ feed, the local one — without asking for a single credential and without an
5
+ OAuth flow, because the desktop already did all of that. Every account in
6
+ System Settings › Internet Accounts, every account in GNOME's Online
7
+ Accounts, is in a store this can read.
8
+
9
+ ```jsx
10
+ import { useDesktopCalendarEvents } from 'react-x11';
11
+
12
+ function Month({ from, to }) {
13
+ const { byDay, status, openSettings } = useDesktopCalendarEvents({
14
+ from,
15
+ to,
16
+ watch: true,
17
+ });
18
+
19
+ if (status === 'unavailable') return null; // no calendar on this machine
20
+ if (status === 'denied')
21
+ return <Button label="Open Settings" onPress={openSettings} />;
22
+
23
+ return (
24
+ <Calendar
25
+ dayContent={(day) =>
26
+ byDay
27
+ .get(day)
28
+ ?.slice(0, 3)
29
+ .map((ev) => (
30
+ <box
31
+ key={ev.uid}
32
+ style={{
33
+ width: 4,
34
+ height: 4,
35
+ borderRadius: 2,
36
+ backgroundColor: ev.calendar.color ?? '$accent',
37
+ }}
38
+ />
39
+ ))
40
+ }
41
+ />
42
+ );
43
+ }
44
+ ```
45
+
46
+ `<Calendar>` is the grid from [`@react-x11/components`](ecosystem.md); the
47
+ `'YYYY-MM-DD'` keys of `byDay` are the contract between the two. Nothing here
48
+ draws anything.
49
+
50
+ ## The ladder
51
+
52
+ Chosen in order, like the [file dialog](filedialog.md)'s, never by naming a
53
+ backend:
54
+
55
+ | | | |
56
+ | --- | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
57
+ | 1 | **EventKit through the bridge** | The [cocoa backend](macos.md) with `@windowkit/appkit` >= 0.8. One `EKEventStore` for every account, recurrences expanded by the framework, and one notification for any change. |
58
+ | 2 | **EventKit through `osascript`** | A Mac with no bridge — every XQuartz install, and a cocoa app over an older bridge. A long-lived `osascript -l JavaScript` child holds the same store. Same framework, slower transport. |
59
+ | 3 | **EDS over the session bus** | `org.gnome.evolution.dataserver.Sources5` / `Calendar8` — the store every GNOME calendar UI reads, and the one GNOME Online Accounts feeds. Recurrences are expanded here, with `ical.js`. |
60
+ | 4 | **nothing** | `desktopCalendar()` answers `null` and the hook says `'unavailable'`. An ordinary answer about a machine, not a failure. |
61
+
62
+ ```ts
63
+ await calendarBackend(); // 'cocoa' | 'osascript' | 'eds' | null
64
+ ```
65
+
66
+ `calendarBackend()` reads nothing, spawns nothing and prompts nothing, so it
67
+ is safe on a settings screen that wants to say where the events come from.
68
+
69
+ **Rung 2 outranks rung 3 on a Mac**: EventKit is that machine's real store,
70
+ and an Evolution Data Server installed beside it would be a second, emptier
71
+ one.
72
+
73
+ ## The imperative half
74
+
75
+ ```ts
76
+ import { desktopCalendar } from 'react-x11';
77
+
78
+ const cal = await desktopCalendar(); // DesktopCalendar | null, never rejects
79
+ if (!cal) return; // nothing on this machine
80
+ try {
81
+ const calendars = await cal.listCalendars();
82
+ const { events, errors } = await cal.eventsBetween(from, to, { calendars });
83
+ const stop = await cal.watch(from, to, () => reload());
84
+ } finally {
85
+ await cal.close();
86
+ }
87
+ ```
88
+
89
+ Call `close()` on every rung; it releases what the rung holds (EDS views, this
90
+ handle's share of the `osascript` child, the bus reference). `useDesktopCalendarEvents` does it for
91
+ you.
92
+
93
+ `{ required: true }` turns the `null` into a typed `NoCalendarServiceError`
94
+ for a caller who would rather branch in a `catch`, and `{ backend }` pins one
95
+ rung and fails rather than falling past it — for a test, or a "why is this
96
+ slow" investigation.
97
+
98
+ ## One shape, whichever rung answered
99
+
100
+ ```ts
101
+ interface DesktopCalendarInfo {
102
+ uid: string;
103
+ name: string;
104
+ enabled: boolean; // always true on macOS: no such state to report
105
+ color?: string; // '#3584e4'
106
+ backend?: string; // 'caldav' | 'local' | 'exchange' | 'subscription' | …
107
+ readOnly: boolean;
108
+ account?: string; // the Online Accounts / EKSource entry it came from
109
+ }
110
+
111
+ interface DesktopEvent {
112
+ uid: string;
113
+ summary: string;
114
+ location?: string;
115
+ description?: string;
116
+ start: Date;
117
+ end: Date; // exclusive
118
+ allDay: boolean;
119
+ recurring: boolean;
120
+ calendar: { uid: string; name: string; color?: string };
121
+ }
122
+ ```
123
+
124
+ - **`end` is exclusive** on every rung — an all-day event ends at the next
125
+ midnight (the macOS rungs normalise EventKit's 23:59:59), so `byDay` may
126
+ assume it.
127
+ - **A change is "something moved", not a patch.** `watch` reports that the
128
+ range changed; the only correct answer is to query again.
129
+ - **"Not allowed to look" is not "no events".** Without the grant a read
130
+ rejects; it never returns an empty list.
131
+
132
+ ## `byDay`
133
+
134
+ ```ts
135
+ const days = byDay(events); // Map<'YYYY-MM-DD', DesktopEvent[]>
136
+ days.get(dayKey(new Date())); // today's
137
+ ```
138
+
139
+ Keyed by **local** day, because a grid draws the user's days. An event lands
140
+ under every day it touches, not only under its start — an all-day span
141
+ crosses several and a timed one can cross midnight. The hook returns the same
142
+ map as `byDay` on its result, already memoised.
143
+
144
+ ## The grant
145
+
146
+ Only the macOS rungs have one; EDS is reachable or it is not.
147
+
148
+ ```ts
149
+ await cal.access(); // the permission vocabulary; never prompts
150
+ await cal.requestAccess(); // the system's prompt, once
151
+ await cal.openSettings(); // System Settings › Privacy & Security › Calendars
152
+ ```
153
+
154
+ **The first read asks.** `listCalendars()` and `eventsBetween()` raise the
155
+ prompt when the status is `'prompt'` — so a picker the user never opens never
156
+ prompts, and `enabled: false` on the hook is how a button defers it. A refusal
157
+ is a typed `CalendarAccessError` carrying the status, never an empty list.
158
+
159
+ `'denied'` is the **user's** answer and `'unavailable'` is the **machine's**.
160
+ Show an Open Settings button on `'denied'` and on nothing else
161
+ ([permissions.md](permissions.md) has the same rule for `'unknown'`).
162
+
163
+ `'write-only'` — macOS 14's partial grant — is a refusal to a reader, so it
164
+ rejects like a denial, but by its own name: an app that also saves events can
165
+ tell the two apart.
166
+
167
+ ### Attribution, and what raises the prompt
168
+
169
+ macOS keys the grant on the process that owns the process tree, and the
170
+ dialog names that process:
171
+
172
+ - The `osascript` rung's grant is **shared with everything that terminal or
173
+ IDE runs** — not with this app alone. Two react-x11 apps started from the
174
+ same terminal share one answer; the same app launched from Finder asks
175
+ again.
176
+ - A bare `node` on the bridge rung lands in the same place: attributed to its
177
+ responsible process, or to `node` itself where it has none.
178
+ - **A bundled app is its own responsible process**, which is the only way to
179
+ get a prompt that names the app and a grant that is the app's — and it must
180
+ carry `NSCalendarsFullAccessUsageDescription` (plus
181
+ `NSCalendarsWriteOnlyAccessUsageDescription` where it asks for the narrower
182
+ grant) or the request never prompts. See [packaging.md](packaging.md).
183
+
184
+ Reading the status and opening the store never prompt; only a request (or the
185
+ first read) does.
186
+
187
+ ## `useDesktopCalendarEvents()`
188
+
189
+ ```ts
190
+ const {
191
+ events,
192
+ byDay,
193
+ calendars,
194
+ errors,
195
+ status,
196
+ backend,
197
+ error,
198
+ refresh,
199
+ openSettings,
200
+ } = useDesktopCalendarEvents({ from, to, calendars?, watch?, enabled? });
201
+ ```
202
+
203
+ | `status` | |
204
+ | --------------- | ---------------------------------------------------------------------------------------------------------------------- |
205
+ | `'idle'` | `enabled: false` — nothing has been asked, including the grant |
206
+ | `'loading'` | a read is in flight; the first one may be showing the system's prompt |
207
+ | `'ready'` | `events` is this range |
208
+ | `'denied'` | the user's answer. `openSettings()` is the way back |
209
+ | `'unavailable'` | the machine's answer: no rung — or a request TCC would not even ask (above). Hide the feature rather than reporting it |
210
+
211
+ `errors` is none of those: calendars that would not answer while others did
212
+ (one unreachable CalDAV server does not blank the user's local calendar). It
213
+ is always empty on the macOS rungs, where there is one store.
214
+
215
+ **`from` and `to` are read by their timestamps, not their identity**, so
216
+ `from={new Date(y, m, 1)}` inline in the render body is fine and does not
217
+ re-query every paint.
218
+
219
+ ## What differs between the rungs
220
+
221
+ - **Recurrences.** EventKit expands them; EDS answers with unexpanded masters
222
+ and `ical.js` expands them here. A malformed `RRULE` with no `UNTIL` is
223
+ guarded at 2000 occurrences on that rung.
224
+ - **`enabled`.** EDS reports whether the user switched a calendar off;
225
+ EventKit has no such state (a calendar unchecked in Calendar.app is still in
226
+ the store), so it is always `true` there.
227
+ - **The change signal.** EDS names the calendar, the kind (`ObjectsAdded`,
228
+ `ObjectsModified`, `ObjectsRemoved`) and a count; EventKit's is one
229
+ `'changed'` with a null calendar and no count.
230
+ - **The range.** EventKit's predicate spans at most four years, so a longer
231
+ one is asked for in pieces and merged (an occurrence on a seam is reported
232
+ once). EDS takes any range.
233
+ - **What the app is on the bus.** The EDS rung borrows react-x11's shared
234
+ session bus ([dbus.md](dbus.md)), so an app is one name on the bus however
235
+ many features it turns on.
236
+
237
+ ## `ical.js`
238
+
239
+ A regular dependency (MPL-2.0, no native code, no install script), loaded
240
+ lazily and only by the EDS rung, through a static `import('ical.js')` that a
241
+ bundler or single-executable build can follow.
242
+
243
+ ## Writing
244
+
245
+ Not supported yet: this module reads.
246
+
247
+ Design notes: [design/desktop-calendar.md](../design/desktop-calendar.md).