react-x11 2.51.0 → 2.52.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 (91) hide show
  1. package/README.md +87 -54
  2. package/docs/README.md +410 -0
  3. package/docs/accessibility.md +628 -0
  4. package/docs/appearance.md +416 -0
  5. package/docs/architecture/accessibility.md +470 -0
  6. package/docs/architecture/animation.md +707 -0
  7. package/docs/architecture/container-queries.md +525 -0
  8. package/docs/architecture/custom-layout.md +334 -0
  9. package/docs/architecture/drag-and-drop.md +941 -0
  10. package/docs/architecture/element-layer-contents.md +622 -0
  11. package/docs/architecture/frame-pacing.md +255 -0
  12. package/docs/architecture/grid-layout.md +358 -0
  13. package/docs/architecture/protocol-efficiency.md +357 -0
  14. package/docs/architecture/video.md +1149 -0
  15. package/docs/architecture/windowed-regions.md +854 -0
  16. package/docs/click-to-component.md +125 -0
  17. package/docs/clipboard.md +281 -0
  18. package/docs/components.md +1749 -0
  19. package/docs/dbus.md +277 -0
  20. package/docs/debugging.md +464 -0
  21. package/docs/desktop-calendar.md +284 -0
  22. package/docs/desktop.md +648 -0
  23. package/docs/devtools.md +250 -0
  24. package/docs/drag-and-drop.md +663 -0
  25. package/docs/ecosystem/animation.md +394 -0
  26. package/docs/ecosystem/data-fetching.md +201 -0
  27. package/docs/ecosystem/dev-tooling.md +436 -0
  28. package/docs/ecosystem/forms.md +313 -0
  29. package/docs/ecosystem/headless.md +219 -0
  30. package/docs/ecosystem/i18n.md +89 -0
  31. package/docs/ecosystem/icons.md +410 -0
  32. package/docs/ecosystem/layout.md +216 -0
  33. package/docs/ecosystem/routing.md +146 -0
  34. package/docs/ecosystem/state.md +361 -0
  35. package/docs/ecosystem/testing.md +500 -0
  36. package/docs/ecosystem/theming.md +540 -0
  37. package/docs/ecosystem.md +473 -0
  38. package/docs/elements.md +2762 -0
  39. package/docs/embedding.md +288 -0
  40. package/docs/events.md +1025 -0
  41. package/docs/extending.md +2242 -0
  42. package/docs/eyedropper.md +223 -0
  43. package/docs/filedialog.md +258 -0
  44. package/docs/frame.md +580 -0
  45. package/docs/gl.md +170 -0
  46. package/docs/globalmenu.md +278 -0
  47. package/docs/glx.md +137 -0
  48. package/docs/macos.md +3295 -0
  49. package/docs/notifications.md +164 -0
  50. package/docs/packaging.md +611 -0
  51. package/docs/permissions.md +148 -0
  52. package/docs/react-features.md +430 -0
  53. package/docs/remote.md +223 -0
  54. package/docs/scale.md +339 -0
  55. package/docs/security.md +132 -0
  56. package/docs/styling.md +1928 -0
  57. package/docs/system.md +599 -0
  58. package/docs/testing.md +514 -0
  59. package/docs/typescript.md +117 -0
  60. package/docs/uri-schemes.md +380 -0
  61. package/docs/wayland-backend.md +591 -0
  62. package/docs/wayland.md +545 -0
  63. package/docs/windows-embedding.md +271 -0
  64. package/docs/windows-gl.md +221 -0
  65. package/docs/windows-integrations.md +233 -0
  66. package/docs/windows.md +1404 -0
  67. package/package.json +10 -3
  68. package/src/bus.js +39 -26
  69. package/src/cli/create.d.ts +43 -0
  70. package/src/cli/create.js +305 -0
  71. package/src/cli/env.js +484 -0
  72. package/src/cli/index.js +29 -2
  73. package/src/cli/templates/AGENTS.template.md +195 -0
  74. package/src/cli/templates/DESIGN.template.md +269 -0
  75. package/src/desktopintegration.js +2 -1
  76. package/src/desktopsettings.js +193 -24
  77. package/src/filedialog.js +3 -3
  78. package/src/keyboardstate.js +28 -0
  79. package/src/node.d.ts +10 -10
  80. package/src/portal.js +31 -0
  81. package/src/screencolor.js +5 -10
  82. package/src/types/system.d.ts +8 -6
  83. package/src/wayland/app.js +59 -0
  84. package/src/wayland/clipboard.js +14 -7
  85. package/src/wayland/connection.js +3 -0
  86. package/src/wayland/context2d.js +129 -10
  87. package/src/wayland/protocols/index.json +6 -0
  88. package/src/wayland/protocols/xdg-foreign-unstable-v2.json +1 -0
  89. package/src/wayland/seat.js +28 -1
  90. package/src/wayland/swapchain.js +23 -0
  91. package/src/wayland/xkb.js +137 -0
@@ -0,0 +1,164 @@
1
+ # Notifications
2
+
3
+ A banner outside the app's own windows — "export finished", "update ready" —
4
+ on whatever the machine has.
5
+
6
+ ```jsx
7
+ import { useNotifier } from 'react-x11';
8
+
9
+ function Exporter() {
10
+ const notifier = useNotifier();
11
+
12
+ const run = async () => {
13
+ const file = await exportReport();
14
+ if (!notifier.available) return;
15
+ await notifier.notify({
16
+ summary: 'Export finished',
17
+ body: file.name,
18
+ actions: [{ key: 'open', label: 'Open' }],
19
+ onAction: (key) => key === 'open' && reveal(file),
20
+ });
21
+ };
22
+ return <Button label="Export" onPress={run} />;
23
+ }
24
+ ```
25
+
26
+ An in-app toast is deliberately **not** this. That is layout, and it belongs
27
+ to whoever wants it; this page is about the desktop's own banners.
28
+
29
+ ## The ladder
30
+
31
+ The [file dialog](filedialog.md)'s shape again, four rungs:
32
+
33
+ | | | |
34
+ | --- | ------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
35
+ | 1 | **the backend's notification centre** | The [cocoa backend](macos.md): `UNUserNotificationCenter`, the system's own banners, list and action buttons. Delivers only for a **code-signed app bundle** with a bundle id — see below. On [win32](windows-integrations.md): a tray balloon, which the shell shows as a toast and keeps in the action centre. |
36
+ | 2 | **`org.freedesktop.Notifications`** | The desktop's daemon over D-Bus: updating in place, the daemon's capabilities, and the two signals that say what the user did. What a Linux desktop should get. |
37
+ | 3 | **`osascript`** | `display notification`, on a Mac with neither of the above — the X11 backend under XQuartz, or an unbundled cocoa app. Posted under Script Editor's identity; no actions, no update, no report back. |
38
+ | 4 | **`notify-send`** | libnotify's CLI, for a Linux box where the bus transport is missing (Node 20) but a daemon runs. The same limits, though a new enough one prints an id, which gives `update()` back. |
39
+
40
+ `notificationBackend()` reports which one this machine lands on without
41
+ posting anything. Where none answers, `notify()` rejects with a **typed**
42
+ `NoNotificationServiceError` — the signal to fall back to your own UI, not a
43
+ crash — and `useNotifier().available` is that branch as render state.
44
+
45
+ The top rung is never chosen by naming a backend: `notify()` asks the
46
+ connection the tree renders through whether it has a centre, and whether that
47
+ centre can deliver.
48
+
49
+ ## `notify()` and the handle
50
+
51
+ ```ts
52
+ const banner = await notify({
53
+ summary, // required — the one line every daemon shows
54
+ body?, icon?, urgency?: 'low' | 'normal' | 'critical', timeout?,
55
+ actions?: [{ key, label }], onAction?(key), onClose?(reason),
56
+ subtitle?, silent?, category?, resident?, appName?, appId?, userInfo?,
57
+ backend?, app?,
58
+ });
59
+
60
+ banner.id; // the daemon's id / the centre's identifier / null
61
+ banner.backend; // which rung
62
+ await banner.update({ body }); // in place, where the rung can
63
+ await banner.close(); // take it down, where the rung can
64
+ ```
65
+
66
+ **The daemon's vocabulary is the API's.** `urgency` is
67
+ `low | normal | critical`, an action is `{ key, label }`, a click on the
68
+ banner itself is the action keyed `'default'`, and a banner that went away
69
+ reports `'expired' | 'dismissed' | 'closed' | 'unknown'` — the freedesktop
70
+ words, because it is a published protocol with many daemons and this is one
71
+ of many clients. The cocoa rung translates into them.
72
+
73
+ **Attribution is filled in for you.** On Linux the `desktop-entry` hint is
74
+ the `appId` [`registerApplication()`](uri-schemes.md) established, which is
75
+ what makes the banner show up under your app in the shell's own list of
76
+ them; `appId` overrides it. On macOS the bundle is the attribution, and there
77
+ is nothing to pass.
78
+
79
+ ## What each rung cannot do
80
+
81
+ | rung | update in place | close | actions | what the user did |
82
+ | ------------- | ------------------- | ------- | ----------------- | -------------------- |
83
+ | cocoa | yes | yes | yes | action, dismissal |
84
+ | win32 | no | no | no | nothing |
85
+ | dbus | yes (`replaces_id`) | yes | if the daemon can | action, close reason |
86
+ | `osascript` | posts anew | nothing | no | nothing |
87
+ | `notify-send` | with an id, yes | nothing | no | nothing |
88
+
89
+ `win32` sits with the shell-out rungs on everything but where it is shown:
90
+ a `Shell_NotifyIcon` balloon is a real toast in a real action centre, and
91
+ also a fire-and-forget one. Buttons, replies and a lifetime the app controls
92
+ want the Windows App SDK's notification manager, which will not show anything
93
+ at all until the system knows an AppUserModelID for the process — a
94
+ Start-menu shortcut carrying one, or a registry registration. That is a
95
+ packaging question ([windows.md](windows.md) §"Packaging and identity"), and
96
+ a balloon is what can be shown without asking the user to install anything.
97
+
98
+ The shell-out rungs are the crude floor: they show a banner and know nothing
99
+ afterwards. `handle.backend` says which rung answered, so an app that cares
100
+ can say "open the app to see it" there rather than promise a button it
101
+ cannot deliver.
102
+
103
+ **Actions on the bus are gated by the daemon.** Whether it can show buttons
104
+ is one of its `GetCapabilities`, and an app that sends actions to a daemon
105
+ without `actions` has silently produced a notification nobody can act on —
106
+ so they are dropped with a development warning rather than sent blind.
107
+ Capabilities are read once per bus session.
108
+
109
+ **A refusal is not fallen through.** On the cocoa backend the first post asks
110
+ the system's authorization prompt, once per bundle. A user who declined the
111
+ app's notifications has said something, and `notify()` rejects with the
112
+ platform's error (`NotificationsDeniedError`) rather than posting through
113
+ `osascript` by a side door.
114
+
115
+ **A refusal is an answer; a prompt nobody saw is not.** The two look identical
116
+ from the call — the authorization request comes back refused either way — so
117
+ the rung reads the status again afterwards, because only a prompt moves it off
118
+ `notDetermined`. A bundle macOS has not registered (an ad-hoc signature in a
119
+ temp directory is the usual way to meet this) never gets the prompt, and
120
+ reporting that as a denial would tell the user they declined something they
121
+ were never shown. Nobody has turned anything off, so the ladder carries on to
122
+ `osascript`; only `backend: 'cocoa'` turns it into an error, and that one says
123
+ `notDetermined` rather than blaming the user.
124
+
125
+ Which is why an app that counts progress should ask before it decides. `examples/notify.jsx` (`npm run examples:notify`) is a download manager built around exactly that: it posts one banner and updates it in place where the rung can, and on `osascript` or `notify-send` stays quiet and posts once at the end, because posting per step there would be four banners for one download.
126
+
127
+ ## The bundle, on macOS
128
+
129
+ `UNUserNotificationCenter` attributes every banner to an app bundle — a
130
+ `CFBundleIdentifier` Launch Services can see — and raises in a process that
131
+ is none, which is what a bare `node` is. The bridge probes it once and
132
+ reports `available: false`; `notify()` then takes the `osascript` rung, whose
133
+ banners are Script Editor's. To get the real thing, run as a bundle: the
134
+ executable in `Name.app/Contents/MacOS/`, an `Info.plist` that names it and
135
+ carries `CFBundleIdentifier`, and a signature
136
+ (`codesign --force --sign - Name.app` is enough locally). See
137
+ [packaging.md](packaging.md).
138
+
139
+ ## `useNotifier()`
140
+
141
+ ```ts
142
+ const { notify, available, backend } = useNotifier(defaults?);
143
+ ```
144
+
145
+ `notify` is the bare function bound to the tree's connection; `available`
146
+ settles once the ladder has been probed (one bus round trip, or one read of
147
+ the centre) and is false where `notify()` would reject; `backend` is the rung.
148
+ Options given to the hook are defaults for every call; options given to a
149
+ call win.
150
+
151
+ ## Running it where there is no daemon
152
+
153
+ | where | rung |
154
+ | ----------------------------------------------- | -------------------------------------------------- |
155
+ | macOS, the cocoa backend, as an app bundle | the centre |
156
+ | macOS, the cocoa backend, bare `node` | `osascript` |
157
+ | macOS + XQuartz | `osascript` (a D-Bus daemon on a Mac is rare) |
158
+ | GNOME / KDE / any desktop with a daemon | `org.freedesktop.Notifications` |
159
+ | Node 20 on Linux, where npm skips `dbus-native` | `notify-send` |
160
+ | ssh, `startx`, a container, CI | `NoNotificationServiceError` — draw your own toast |
161
+
162
+ The bus rung holds one session-bus reference while any banner is live and
163
+ releases it when the last one closes, so an app that closed its banners on
164
+ the way out is free to exit.