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
package/README.md CHANGED
@@ -11,12 +11,14 @@ A React renderer for **desktop applications**, whose host is a display
11
11
  system rather than a document. React's job in a renderer is to compute what
12
12
  changed; the renderer's job is to turn that into side effects on some host —
13
13
  in react-dom those are DOM mutations, here they are **X11 protocol requests**
14
- written to a socket, or **Core Animation layers and CoreGraphics drawing** on
15
- macOS. There is no DOM, no HTML and no browser engine underneath: this is not
16
- Electron with a different skin, and `<div>` is not an element that exists.
17
- Build GUI programs for a Linux desktop, for a display at the other end of an
18
- ssh connection, or as a native Mac app, with your React / React Native
19
- experience — flexbox layout, components, hooks, synthetic events.
14
+ written to a socket, **Core Animation layers and CoreGraphics drawing** on
15
+ macOS, **Direct2D drawing on DirectComposition surfaces** on Windows, or GL
16
+ frames handed to a **Wayland** compositor. There is no DOM and no browser
17
+ engine underneath: this is not Electron with a different skin, and `<div>` is
18
+ not an element that exists. Build GUI programs for a Linux desktop, for a
19
+ display at the other end of an ssh connection, as a native Mac app or a
20
+ Windows one, with your React / React Native experience — flexbox layout,
21
+ components, hooks, synthetic events.
20
22
 
21
23
  ### Four backends, one tree
22
24
 
@@ -47,21 +49,28 @@ main thread ([docs/macos.md](docs/macos.md#js-on-a-worker-a-ui-thread-of-the-bri
47
49
 
48
50
  Two more backends exist beside these, serving the goal of **full
49
51
  cross-platform support**, and both are younger than the two above.
50
- **native Wayland** ([docs/wayland.md](docs/wayland.md)) is opt-in rather than
51
- automatic, because X11 stays the default on Linux — the remote case is the
52
- flagship reason this project exists and Wayland has no network transparency.
53
- **Windows** ([docs/windows.md](docs/windows.md)) — Win32 windows, Direct2D
54
- and DirectWrite, DWM compositing through DirectComposition — renders and
55
- takes mouse input, with the desktop integrations still to come. Each is a
56
- backend beside the others rather than a replacement for any of them: the
57
- same tree, the same components, the same `style` objects.
52
+ **native Wayland** ([docs/wayland-backend.md](docs/wayland-backend.md)) —
53
+ the wire protocol in JavaScript and a GLES rasterizer of its own, on mutter,
54
+ sway and labwc, with no Xwayland in the path — is opt-in
55
+ (`REACT_X11_BACKEND=wayland`) rather than automatic, because X11 stays the
56
+ default on Linux: the remote case is the flagship reason this project exists
57
+ and Wayland has no network transparency. **Windows**
58
+ ([docs/windows.md](docs/windows.md)) — Win32 windows, Direct2D and
59
+ DirectWrite, DWM compositing through DirectComposition — is the default on
60
+ Windows, with the keyboard, an IME, a screen-reader bridge and most of the
61
+ desktop integrations in place
62
+ ([docs/windows-integrations.md](docs/windows-integrations.md) is the
63
+ measured list). Each is a backend beside the others rather than a
64
+ replacement for any of them: the same tree, the same components, the same
65
+ `style` objects.
58
66
 
59
67
  Layout is [yoga-layout](https://www.npmjs.com/package/yoga-layout) (WASM) on
60
- both, and text shaping is [fontkit](https://github.com/foliojs/fontkit) on
61
- the X11 side, CoreText on the Cocoa one. **`npm install` never compiles
62
- anything**: the X11 stack is JavaScript all the way down, and the two native
63
- addons in the tree — the Cocoa bridge and `x11-dri` for direct GL — are
64
- optional dependencies that ship prebuilt. And `npm test` doesn't even need
68
+ every backend, and text shaping is [fontkit](https://github.com/foliojs/fontkit)
69
+ through ntk on X11 and Wayland, CoreText on Cocoa and DirectWrite on Windows.
70
+ **`npm install` never compiles anything**: the X11 stack is JavaScript all
71
+ the way down, and the native addons in the tree — the Cocoa and win32
72
+ bridges, and `x11-dri` for direct GL and the Wayland socket — are optional
73
+ dependencies that ship prebuilt. And `npm test` doesn't even need
65
74
  an X server (node-x11 ships an in-process pure-JS X server that the tests
66
75
  render into and read pixels back from; every screenshot below was rendered
67
76
  that way too, by driving the real examples through the real event
@@ -92,7 +101,7 @@ composites and the pixel area those composites touch, against a checked-in
92
101
  baseline (`scripts/bench/baseline.json`, which is where the numbers in these
93
102
  docs come from).
94
103
 
95
- The Cocoa backend inverts this, and [docs/macos.md](docs/macos.md) is the
104
+ The Cocoa backend inverts this, and [design/macos.md](design/macos.md) is the
96
105
  design record for why: there is no wire, the WindowServer is a retained
97
106
  compositor, and a React commit maps onto property mutations of persistent
98
107
  objects. Scrolling is a layer's `bounds.origin` rather than a repaint,
@@ -141,30 +150,41 @@ three:
141
150
  Drag and drop works both ways with the desktop, and the taskbar's own
142
151
  surfaces — a thumbnail toolbar, a jump list, recent documents — are there
143
152
  behind a capability, so an app that also runs elsewhere asks
144
- `useSupports()` rather than the platform. What it does not have is **IME
145
- and screen-reader support**: an app is unusable with a screen reader and
146
- in CJK input. So an app that needs either on Windows _this month_ still
147
- wants Electron or Tauri.
153
+ `useSupports()` rather than the platform. CJK input goes through an
154
+ IMM32 input method and screen readers through a UI Automation provider of
155
+ the project's own, both with gaps worth reading before you rely on them:
156
+ no voice typing or handwriting (those want a TSF text store), and no
157
+ caret-by-caret reading inside a text field yet. Nor is there activation —
158
+ file associations, URL schemes and second launches — so an app that needs
159
+ any of that on Windows _this month_ still wants Electron or Tauri.
148
160
  [docs/windows-integrations.md](docs/windows-integrations.md) is the
149
- measured status and [docs/windows.md](docs/windows.md) the design. The three
161
+ measured status and [design/windows.md](design/windows.md) the design. The three
150
162
  targets are not the same app: the desktop-shell half of X11 (`<foreign>`
151
163
  embedding, panel struts, substructure redirect, the window-manager example
152
164
  below) has no macOS or Windows equivalent, and `react-x11/test` drives the
153
165
  X11 backend only. [docs/macos.md](docs/macos.md) says which is which.
154
- - **native Wayland — today.** There is no Wayland backend yet. Ordinary
155
- application windows work fine on a Wayland desktop through Xwayland, which
156
- is not going away — but the desktop-shell half of X11 (panel struts,
157
- global key grabs, screen capture, and the window-manager example below)
158
- needs a real X session. A native backend is coming too, as a **target
159
- beside X11, not a migration**: [docs/wayland.md](docs/wayland.md) is the
160
- RFC, from the fd transport up to what the rendering would ride on.
166
+ - **native Wayland — today.** The native backend is opt-in and young:
167
+ windows, text, input, an input method, the clipboard, popups, drag and
168
+ drop and layer-shell docks and panels run on mutter, sway and labwc, and
169
+ [docs/wayland-backend.md](docs/wayland-backend.md#not-supported-yet) lists what
170
+ is left — no multisampling, no `<Frame>` panes, no drag icon. Ordinary
171
+ application windows also work on a Wayland desktop through Xwayland, which
172
+ is not going away — but the desktop-shell half of X11 (`<foreign>`
173
+ embedding, global key grabs, and the window-manager example below) needs a
174
+ real X session. It is a **target beside X11, not a migration**;
175
+ [design/wayland.md](design/wayland.md) is the RFC it was built from.
161
176
  - **reusing web components.** There is no DOM. Your MUI, your Tailwind and
162
177
  your `recharts` do not come with you; the state, data-fetching, validation
163
178
  and math libraries mostly do. [docs/ecosystem.md](docs/ecosystem.md) says
164
179
  which is which, and what the failure looks like when it is the wrong one.
165
- - **rendering HTML.** There is no HTML element and no webview. Rich
166
- documents are markdown, through `<Markdown>` in
167
- [`@react-x11/components`](https://github.com/sidorares/react-x11-components).
180
+ - **being a browser.** There is no webview and no browser engine to embed.
181
+ HTML is a component rather than a substrate: `<Html>` in
182
+ [`@react-x11/components`](https://github.com/sidorares/react-x11-components)
183
+ renders an HTML + CSS document with a layout engine of its own — selectable,
184
+ with real widgets for its form controls, and with a page's scripts run
185
+ against a DOM when `scripts` turns them on — and `<Markdown>` beside it
186
+ renders markdown. Both are for documents an app shows; an app that _is_ a
187
+ web app still wants Electron or Tauri.
168
188
  - **text entry outside Latin.** See [Known issues](#known-issues).
169
189
 
170
190
  The screenshots below are the X11 backend, rendered headlessly into
@@ -184,7 +204,7 @@ protocol sent over the X connection, geometry compiled into a display list,
184
204
  a frame costing two matrices and one `CallList`. No native bindings, no GPU
185
205
  driver bindings — the same "JavaScript all the way down" story as the rest.
186
206
  (GL renders where the X server cannot read it back, so there is no
187
- screenshot of it here; see [docs/glx.md](docs/glx.md).)
207
+ screenshot of it here; see [docs/gl.md](docs/gl.md#testing).)
188
208
 
189
209
  ## Quick start
190
210
 
@@ -258,6 +278,7 @@ drawn tree. See [docs/elements.md](docs/elements.md) for the full reference.
258
278
  | `<textarea>` | the same editor, wrapped and multi-line, scrolling with its content |
259
279
  | `<image>` | PNG/JPEG/WebP from `src` (more formats under Bun), natural-size aware; also pixels the server already has |
260
280
  | `<canvas>` | escape hatch: `onDraw={(ctx, {width, height}) => …}` with a canvas-like 2d context (XRender-backed on X11, CoreGraphics on Cocoa) |
281
+ | `<video>` | decoded frames the app pushes, on every backend, or a `src` the platform plays itself where it has a player |
261
282
  | `<svg>` | static SVG (paths, shapes, gradients, transforms), sized like `<image>` |
262
283
  | `<glarea>` | an OpenGL surface in the layout — see [3D](#3d) |
263
284
  | `<foreign>` | another application's X window, laid out as an element. **X11 only** ([docs/embedding.md](docs/embedding.md)) |
@@ -303,8 +324,9 @@ entry just blinks. The OAuth redirect this is for has an easier answer that
303
324
  needs none of it, and the page says so first. See
304
325
  [docs/uri-schemes.md](docs/uri-schemes.md).
305
326
 
306
- **Drag and drop** works with the rest of the desktop on both backends —
307
- XDND on X11, `NSDraggingSession` on Cocoa. `<box dropAccept={['files']}
327
+ **Drag and drop** works with the rest of the desktop on every backend —
328
+ XDND on X11, `NSDraggingSession` on Cocoa, OLE on Windows, `wl_data_device`
329
+ on Wayland. `<box dropAccept={['files']}
308
330
  onDrop={…}>` takes a file dragged out of Nautilus or Finder, and
309
331
  `<box draggable dragData={…}>` can be dropped into a file manager or an
310
332
  editor. Drags that stay inside the app never touch the wire and hand their
@@ -318,16 +340,16 @@ Everything an app does outside its own windows is a **ladder**: the best
318
340
  rung the machine actually has, the same hook whichever one answers, and a
319
341
  first-class "this desktop cannot" rather than a throw.
320
342
 
321
- | what | rungs, best first |
322
- | ---------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
323
- | [open/save panels](docs/filedialog.md) `useFileDialog()` | `NSOpenPanel` · the XDG portal · `osascript` · one react-x11 draws |
324
- | [notifications](docs/notifications.md) `notify()` | UNUserNotificationCenter · `org.freedesktop.Notifications` · `osascript` · `notify-send` |
325
- | [light/dark, accent](docs/appearance.md) `useSystemAppearance()` | the settings portal · macOS · XSETTINGS — remembered on disk, so the first frame is not a flash |
326
- | [permissions](docs/permissions.md) `usePermission()` | TCC on macOS · the Settings pane · `'unknown'` on Linux until the device portals land |
327
- | [the user's real events](docs/desktop-calendar.md) | EventKit through the bridge · EventKit through `osascript` · Evolution Data Server |
328
- | [sample a screen colour](docs/eyedropper.md) `useEyedropper()` | `NSColorSampler` · the portal's picker · a crosshair grab on plain X11 |
329
- | a badge on the icon `setBadge()` | `NSDockTile.badgeLabel` · `com.canonical.Unity.LauncherEntry` |
330
- | a tray icon `useTray()` | `NSStatusItem`. **Cocoa only today** — `available` is false on X11 until StatusNotifierItem lands ([#353](https://github.com/sidorares/react-x11/issues/353)) |
343
+ | what | rungs, best first |
344
+ | ---------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------- |
345
+ | [open/save panels](docs/filedialog.md) `useFileDialog()` | `NSOpenPanel` / the Common Item Dialog · the XDG portal · `osascript` · one react-x11 draws |
346
+ | [notifications](docs/notifications.md) `notify()` | UNUserNotificationCenter / a tray balloon on Windows · `org.freedesktop.Notifications` · `osascript` · `notify-send` |
347
+ | [light/dark, accent](docs/appearance.md) `useSystemAppearance()` | the settings portal · macOS · XSETTINGS — remembered on disk, so the first frame is not a flash |
348
+ | [permissions](docs/permissions.md) `usePermission()` | TCC on macOS · the Settings pane · `'unknown'` on Linux until the device portals land |
349
+ | [the user's real events](docs/desktop-calendar.md) | EventKit through the bridge · EventKit through `osascript` · Evolution Data Server |
350
+ | [sample a screen colour](docs/eyedropper.md) `useEyedropper()` | `NSColorSampler` · the portal's picker · a crosshair grab on plain X11 |
351
+ | a badge on the icon `setBadge()` | `NSDockTile.badgeLabel` / a taskbar overlay icon · `com.canonical.Unity.LauncherEntry` |
352
+ | a tray icon `useTray()` | `NSStatusItem` / `Shell_NotifyIcon` · `org.kde.StatusNotifierItem` — `available` is false on a desktop with no tray host, such as stock GNOME |
331
353
 
332
354
  [docs/system.md](docs/system.md) is the rest of the machine — monitors,
333
355
  window state, idle, keyboard layout, locale — and
@@ -336,8 +358,8 @@ itself.
336
358
 
337
359
  ### 3D
338
360
 
339
- `<glarea>` is a GL surface in the layout, with three ways underneath it and
340
- the same `onDraw` over all three:
361
+ `<glarea>` is a GL surface in the layout, with the same `onDraw` over every
362
+ way underneath it — three on the mature backends:
341
363
 
342
364
  - **indirect GLX** (the X11 default) — the GL protocol encoded into the X
343
365
  connection, no native bindings and no GPU driver bindings, the same
@@ -352,6 +374,10 @@ the same `onDraw` over all three:
352
374
  sublayer of the window; shaders and render targets, on any Mac, with no
353
375
  X server involved.
354
376
 
377
+ The two younger backends have their own: WGL on Windows, composited through
378
+ DirectComposition ([design/windows-gl.md](design/windows-gl.md)), and on Wayland
379
+ a viewport into the window's own GLES target.
380
+
355
381
  ```jsx
356
382
  <glarea
357
383
  style={{ flexGrow: 1 }}
@@ -364,7 +390,7 @@ the same `onDraw` over all three:
364
390
  A scene graph over it — `<mesh>`, geometries, materials, lights, and shaders
365
391
  or post-processing where the backend has them — is
366
392
  [`@react-x11/components/three`](https://github.com/sidorares/react-x11-components).
367
- See [docs/gl.md](docs/gl.md) and [docs/glx.md](docs/glx.md).
393
+ See [docs/gl.md](docs/gl.md).
368
394
 
369
395
  Events are synthetic with capture/bubble phases and hit testing over the
370
396
  drawn tree: `onClick` (with DOM-style `detail` click counting),
@@ -376,8 +402,8 @@ a scroll container from scrolling, like the DOM.
376
402
 
377
403
  ## Examples
378
404
 
379
- On macOS these run natively, with no X server; everywhere else they need
380
- one — and "an X server" is a broader thing than it sounds: your Linux
405
+ On macOS and Windows these run natively, with no X server; everywhere else
406
+ they need one — and "an X server" is a broader thing than it sounds: your Linux
381
407
  desktop, XQuartz, `Xvfb` for automation, `Xephyr` for a disposable screen, a
382
408
  VNC server, or your own display reached over `ssh -X` from wherever the
383
409
  program actually runs — see [docs/remote.md](docs/remote.md), which is the
@@ -419,8 +445,8 @@ neither.
419
445
  ### Window manager
420
446
 
421
447
  `examples:wm` is a real reparenting window manager, and it is **X11 only** —
422
- substructure redirect has no macOS equivalent, so this is one of the places
423
- the two backends are not the same app. It takes over the root window, puts
448
+ substructure redirect has no macOS, Windows or Wayland-client equivalent, so
449
+ this is one of the places the backends are not the same app. It takes over the root window, puts
424
450
  every application's window inside a frame it draws, and moves, resizes,
425
451
  focuses and closes them. The frames are ordinary react-x11 `<window>`s — the
426
452
  titlebar, the buttons and the eight resize handles are components with
@@ -475,7 +501,7 @@ an element by clicking it in the app; "highlight updates when components
475
501
  render" outlines the rects that just re-rendered; the style editor edits a
476
502
  selected element's style live; and the Profiler can restart the app to
477
503
  record its mount. All of it is above the display system, so it works the
478
- same on both backends. `REACT_X11_DEVTOOLS_HOST` /
504
+ same on every backend. `REACT_X11_DEVTOOLS_HOST` /
479
505
  `REACT_X11_DEVTOOLS_PORT` override the default `localhost:8097`. See
480
506
  [docs/devtools.md](docs/devtools.md).
481
507
 
@@ -570,8 +596,8 @@ indirect GLX.
570
596
 
571
597
  See [AGENTS.md](AGENTS.md) for architecture notes and contributor/agent
572
598
  guidance, [docs/](docs/README.md) for API documentation,
573
- [docs/architecture/](docs/architecture/) for the design records behind the
574
- bigger pieces, and [NEXT_STEPS.md](NEXT_STEPS.md) for the older roadmap it
599
+ [design/](design/README.md) for the design records behind the bigger
600
+ pieces and the backends, and [NEXT_STEPS.md](NEXT_STEPS.md) for the older roadmap it
575
601
  grew out of.
576
602
 
577
603
  The [documentation site](https://sidorares.github.io/react-x11/) lives in
@@ -602,10 +628,17 @@ the character that was actually typed.
602
628
  Cocoa the character arrives with the event, so AltGr-style levels type;
603
629
  an `NSTextInputClient` IME for CJK is not built there either.
604
630
 
631
+ On the other two backends the input method is the platform's: the
632
+ Wayland backend speaks `zwp_text_input_v3` to the compositor's IME, and the
633
+ Windows one answers IMM32, so CJK composes on both
634
+ ([docs/windows-integrations.md](docs/windows-integrations.md) has Windows'
635
+ limits).
636
+
605
637
  Two more places the backends genuinely differ, so you can plan around them
606
638
  rather than discover them: `react-x11/test` drives the **X11** backend only,
607
- and the AT-SPI accessibility bridge is X11's — on Cocoa `createRoot()`
608
- leaves it off, and an `NSAccessibility` bridge is not built yet
639
+ and the accessibility bridges are AT-SPI on Linux and UI Automation on
640
+ Windows — on Cocoa `createRoot()` leaves accessibility off, and an
641
+ `NSAccessibility` bridge is not built yet
609
642
  ([docs/accessibility.md](docs/accessibility.md)).
610
643
 
611
644
  ## Security
@@ -650,7 +683,7 @@ against, is [docs/security.md](docs/security.md). To report something,
650
683
  desktop platforms for React Native. On Windows the new architecture's
651
684
  renderer targets Composition from the start, in Windows App SDK apps by
652
685
  default, with XAML islands for advanced controls; on macOS a fork of React
653
- Native maps its UIKit views onto AppKit. [docs/windows.md](docs/windows.md)
686
+ Native maps its UIKit views onto AppKit. [design/windows.md](design/windows.md)
654
687
  cites its threading as prior art: JS on a thread of its own, and every
655
688
  mount posted to the UI thread that alone touches the visuals.
656
689
  - [React Native Skia](https://github.com/Shopify/react-native-skia) — 2D
package/docs/README.md ADDED
@@ -0,0 +1,256 @@
1
+ # react-x11 documentation
2
+
3
+ react-x11 renders one React tree to four backends: **X11** (a Linux desktop,
4
+ a forwarded display, XQuartz), **Cocoa** (a native Mac app, no X server
5
+ anywhere), **win32**, and an opt-in native **Wayland** backend. The same
6
+ tree, components, styles and hooks run on all of them, and `createRoot()`
7
+ picks — Cocoa on macOS and win32 on Windows where their bridges are
8
+ installed, X11 otherwise. Every page below is about every backend unless it
9
+ says otherwise; where a backend changes the answer, it is called out where
10
+ the answer is.
11
+
12
+ - [macos.md](macos.md) — the Cocoa backend: choosing it, its options,
13
+ windowing, text, input, native controls, the menu bar, app bundles, and
14
+ what does not map (no window manager, no cross-process embedding).
15
+ - [elements.md](elements.md) — the host elements (`<window>`, `<popup>`,
16
+ `<box>`, `<text>`, `<textinput>`, `<textarea>`, `<image>`, `<canvas>`,
17
+ `<svg>`, `<foreign>`), their props and refs — including
18
+ [selecting read-only text](elements.md#selecting-text) with `selectable`.
19
+ - [styling.md](styling.md) — the `style` prop: layout and paint properties,
20
+ state blocks, transitions, theme tokens, container queries, `createStyles`,
21
+ and [a font file of your own](styling.md#a-font-file-of-your-own).
22
+ - [components.md](components.md) — the widgets (`Button`, `Checkbox`,
23
+ `Radio`, `Switch`, `ProgressBar`, `Select`, `Slider`, `Tooltip`, `Dialog`,
24
+ `MenuBar`/`ContextMenu`, `Tabs`, `Table`, `SplitPane`), theming, and the
25
+ `useAnchor` popup placement hook.
26
+ - [globalmenu.md](globalmenu.md) — a `MenuBar` handed to wherever the
27
+ platform keeps menus: the macOS menu bar, a desktop panel over
28
+ `com.canonical.dbusmenu`, or the drawn bar.
29
+ - [events.md](events.md) — the synthetic event system: dispatch phases,
30
+ event objects, focus, cursors, default actions.
31
+ - [accessibility.md](accessibility.md) — screen readers: the AT-SPI2 bridge,
32
+ `role`/`aria-*` on every element, what the widgets announce, `announce()`,
33
+ and testing it all without a desktop.
34
+ - [react-features.md](react-features.md) — where React knowledge carries
35
+ over and where a DOM habit breaks: effects, measuring a node, refs,
36
+ `<popup>` instead of `createPortal`, error boundaries, missing APIs.
37
+ - [drag-and-drop.md](drag-and-drop.md) — accepting drops and starting drags,
38
+ in-app and with other applications: `dropAccept`, payloads,
39
+ `useDropTarget`/`useDragSource`, previews, and driving a drag in a test.
40
+ - [clipboard.md](clipboard.md) — `useClipboard()`: CLIPBOARD and PRIMARY,
41
+ several flavours of one payload, the `text`/`files`/`uris` groups,
42
+ `watch()`, and the macOS pasteboard.
43
+ - [typescript.md](typescript.md) — the bundled types: one tsconfig option,
44
+ and JSX from `react-x11/jsx-runtime`.
45
+ - [extending.md](extending.md) — `registerElement()` and the subpath
46
+ exports: a host element from outside the package, the node contract, and
47
+ the damage seam for an element that draws a whole scene.
48
+ - [gl.md](gl.md) — `<glarea>`, a GL surface in the layout: `glPolicy`, the
49
+ backends underneath, `<shaderMaterial>` and `<effectComposer>`.
50
+ - [embedding.md](embedding.md) — `<foreign>`: another application's window
51
+ inside yours, over XEmbed or a plain reparent. **X11 only.**
52
+ - [frame.md](frame.md) — `<Frame>`: a pane of your own app in a process of
53
+ its own; what the process boundary buys, and that it is not a security
54
+ boundary.
55
+ - [testing.md](testing.md) — `react-x11/test`: render, query, drive and
56
+ assert on real pixels against an in-process X server. No display, and
57
+ always the **X11** backend.
58
+ - [desktop.md](desktop.md) — what an app tells the desktop beyond drawing:
59
+ startup notification, the launcher badge and Dock menu, the tray, feature
60
+ discovery, and turning it all off.
61
+ - [dbus.md](dbus.md) — the session and system bus: `useSessionBus()` /
62
+ `useSystemBus()`, `sessionBus()`, and "no bus" as a normal configuration.
63
+ - [uri-schemes.md](uri-schemes.md) — being the app a `myapp://…` link
64
+ opens: `registerApplication()`, `useAppOpen()`, single-instance
65
+ forwarding, and the `.desktop` half.
66
+ - [filedialog.md](filedialog.md) — `useFileDialog()`: open, save and pick a
67
+ folder, through a native panel, the desktop portal, `osascript` or a drawn
68
+ browser; cancelling is `null`.
69
+ - [permissions.md](permissions.md) — `usePermission()` for the camera, the
70
+ microphone, the screen and the accessibility APIs, and its five-word
71
+ status vocabulary.
72
+ - [notifications.md](notifications.md) — `notify()` and `useNotifier()`:
73
+ banners through the best available rung, updated in place, and what the
74
+ user did with them.
75
+ - [desktop-calendar.md](desktop-calendar.md) — `useDesktopCalendarEvents()`:
76
+ the user's real events, with no credential, via EventKit or Evolution
77
+ Data Server.
78
+ - [eyedropper.md](eyedropper.md) — `useEyedropper()`/`pickScreenColor()`:
79
+ sample a colour from the screen.
80
+ - [appearance.md](appearance.md) — light or dark, accent, contrast, reduced
81
+ motion: `useSystemAppearance()` and `<ThemeProvider dark>`.
82
+ - [scale.md](scale.md) — HiDPI: logical pixels, `createRoot({ scale: 'auto'
83
+ })`, `useScale()`, and per-monitor answers.
84
+ - [system.md](system.md) — the machine around the app: `useScreens()`,
85
+ `useWindowState()`, `useIdle()`/`useKeepAwake()`, `useKeyboardState()`,
86
+ `useDesktopSettings()`, `useLocale()`.
87
+ - [remote.md](remote.md) — running on one machine and drawing to a display
88
+ on another: `ssh -X` vs `-Y`, what the protocol costs on a link, the other
89
+ X servers.
90
+ - [wayland-backend.md](wayland-backend.md) — the opt-in native Wayland
91
+ backend: what runs, and what is still open.
92
+ - [windows.md](windows.md) — the win32 backend: choosing it, installing the
93
+ bridge, what maps and what does not.
94
+ - [windows-integrations.md](windows-integrations.md) — what an app on
95
+ Windows can reach today, and the gaps.
96
+ - [security.md](security.md) — the threat model: X11 has no isolation
97
+ between clients, `$XAUTHORITY` is a password, and what react-x11 does and
98
+ does not defend against.
99
+ - [packaging.md](packaging.md) — five ways to ship an app, the load-bearing
100
+ esbuild flags, and macOS signing for Developer ID and the App Store.
101
+ - [devtools.md](devtools.md) — React DevTools integration and other
102
+ debugging aids.
103
+ - [debugging.md](debugging.md) — runtime diagnostics: `REACT_X11_TRACE` and
104
+ `startTrace()`, `REACT_X11_DEBUG_PAINT`, invalidation reasons, and the
105
+ switches that turn one optimisation off.
106
+ - [click-to-component.md](click-to-component.md) — Alt+Click a rendered
107
+ element to open its JSX source line in your editor.
108
+ - [ecosystem.md](ecosystem.md) — which npm packages work with react-x11 and
109
+ which do not, and why. Per category:
110
+ [state](ecosystem/state.md), [data fetching](ecosystem/data-fetching.md),
111
+ [forms](ecosystem/forms.md), [icons](ecosystem/icons.md),
112
+ [theming](ecosystem/theming.md), [animation](ecosystem/animation.md),
113
+ [headless components](ecosystem/headless.md),
114
+ [layout](ecosystem/layout.md), [routing](ecosystem/routing.md),
115
+ [i18n](ecosystem/i18n.md), [testing](ecosystem/testing.md),
116
+ [dev tooling](ecosystem/dev-tooling.md).
117
+
118
+ Contributors: the design records behind these pages — history, rejected
119
+ alternatives, measurements, plans — are in
120
+ [design/README.md](../design/README.md), which does not ship.
121
+
122
+ ## Entry points
123
+
124
+ ```js
125
+ import { createRoot, Select } from 'react-x11';
126
+ ```
127
+
128
+ ### `await createRoot(options?)` → `{ app, render(element), unmount() }`
129
+
130
+ The entry point. With no options it opens a connection to whichever backend
131
+ this machine has: the **Cocoa** bridge on macOS, the **win32** bridge on
132
+ Windows, or the X server named by `$DISPLAY`. Without the bridge installed
133
+ it falls back to X11, once and out loud, so an XQuartz, WSLg or Cygwin
134
+ setup keeps working. The returned `app` is that backend's app object — the
135
+ [ntk](https://github.com/sidorares/ntk) App and its one X connection on
136
+ X11.
137
+
138
+ **Every root without `app` opens its own connection and owns it**, so two
139
+ roots are two independent trees, and `await root.unmount()` closes what it
140
+ opened — without which the socket stays up and the process does not exit.
141
+ A root given an `app` borrows it and never closes it: that connection
142
+ belongs to whoever made it.
143
+
144
+ On macOS `'auto'` answers Cocoa, and **`$DISPLAY` in the environment does
145
+ not change that.** Naming an X endpoint _in code_ — `display` or `stream` —
146
+ does; from the environment, say `REACT_X11_BACKEND=x11`
147
+ ([remote.md](remote.md)).
148
+
149
+ | option | |
150
+ | ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
151
+ | `backend` | `'auto'` (default), `'x11'`, `'cocoa'`, `'win32'` or `'wayland'` (opt-in; `'auto'` never picks it). Naming a bridge backend makes the bridge required rather than preferred |
152
+ | `app` | render into a connection you already have — the option a backend choice is ignored for |
153
+ | `cocoa` | that backend's knobs: `presenter`, `promote`, `frameInterval`, `pumpInterval`, `appName`, `activationPolicy`, `exitOnQuit` ([macos.md](macos.md)) |
154
+ | `scale` | device pixels per logical pixel: `'auto'` (default) or a number ([scale.md](scale.md)) |
155
+ | `frameRate` | how windows pace frames under a flood: `'display'` (default) or `'adaptive'` ([elements.md](elements.md#framerate--pacing-the-frames-under-a-flood)) |
156
+ | `desktop` | `false`, or `{ appearance, a11y, globalMenu }` — the three things that dial the session bus ([desktop.md](desktop.md)) |
157
+ | `startupNotification` | freedesktop startup notification, on by default; `false`, or the id ([desktop.md](desktop.md)) |
158
+ | `compose` | dead keys and Compose: the built-in table by default, `'system'`, `{ file }`/`{ sequences }`, or `false` |
159
+ | `accelerators` | which keysym a shortcut matches: `'latin'` (default), `'layout'`, or a table |
160
+ | `restoreFocusOnReveal` | whether a revealed subtree takes the keyboard back. Default `true` |
161
+ | `textStripBelow` | the size under which `<text>` paints as a strip of ink rather than glyphs. Default 6; `0` never |
162
+ | `display` | **X11.** `':1'`, `'host:0.0'`, a socket path. Default `$DISPLAY`. Naming one chooses the X11 backend |
163
+ | `stream` | **X11.** an already-connected duplex stream — also a backend choice |
164
+ | `fontSource` | **X11.** pluggable system-font lookup — ntk's docs/fonts.md |
165
+ | `glPolicy` `glxVisual` | **X11.** which GL backend `<glarea>` draws through, and a visual for it ([gl.md](gl.md)) |
166
+ | `onXError` | **X11.** protocol errors nothing claimed. Default warns |
167
+ | `onUncaughtError` `onCaughtError` `onRecoverableError` | `(error, errorInfo)`; default logs the component stack |
168
+ | `onDisconnect(reason, err)` | **X11.** the connection ended — `'closed'` or `'error'` |
169
+
170
+ `display`, `stream`, `fontSource`, `glxVisual`, `glPolicy` and `onXError` go
171
+ straight to ntk's `createClient`. For anything else it understands, build
172
+ the client yourself and pass it as `app`. A `stream` reaches a server that
173
+ is not on `$DISPLAY` — node-x11's in-process one, for instance:
174
+
175
+ ```js
176
+ import xserver from 'x11/lib/xserver/index.js';
177
+
178
+ const server = xserver.createServer({ width: 640, height: 480 });
179
+ const [serverEnd, clientEnd] = xserver.createStreamPair();
180
+ server.addClientStream(serverEnd);
181
+ const root = await createRoot({ stream: clientEnd }); // no $DISPLAY needed
182
+ ```
183
+
184
+ `onUncaughtError` covers one channel React does not: a throw from an **event
185
+ handler**, which no error boundary can catch because the handler ran from an
186
+ input event rather than a render. See
187
+ [events.md](events.md#when-a-handler-throws).
188
+
189
+ `onDisconnect` fires when an X connection ends without being asked to —
190
+ server exit, ssh drop, kill — and not for one this root closed. **A
191
+ reconnect is not a reconnect:** every window id, pixmap, glyph set and font
192
+ is invalidated with the connection, so tear the root down and build a new
193
+ one.
194
+
195
+ `root.render(element, callback?)` flushes the mount or update
196
+ synchronously (`updateContainerSync` + `flushSyncWork`); painting happens a
197
+ frame later on the window's frame clock.
198
+
199
+ ## Environment variables
200
+
201
+ Every one of these has an option or a prop that says the same thing in code;
202
+ the variable is for when you cannot edit the call — someone else's app, a
203
+ `.desktop` launcher, an A/B run. `npx react-x11 help` prints every one the
204
+ renderer reads, the diagnostic switches included.
205
+
206
+ **Choosing a backend and a display**
207
+
208
+ | variable | effect |
209
+ | ---------------------------- | -------------------------------------------------------------------------- |
210
+ | `DISPLAY` | X server to connect to (standard X11) |
211
+ | `REACT_X11_BACKEND` | `x11`, `cocoa`, `win32` or `wayland`, overriding `backend` and the default |
212
+ | `REACT_X11_GL_DEVICE` | Wayland: the DRM node to render on, where `glPolicy.devicePath` is unset |
213
+ | `REACT_X11_SCALE` | device pixels per logical pixel; outranks even a pinned `scale` number |
214
+ | `REACT_X11_FRAME_RATE` | `display` or `adaptive`, overriding `frameRate` and the props |
215
+ | `REACT_X11_TEXT_STRIP_BELOW` | the `textStripBelow` size, for a process that cannot pass the option |
216
+
217
+ **Turning desktop integration off**
218
+
219
+ | variable | effect |
220
+ | ----------------------------- | ---------------------------------------------------------------------------------------- |
221
+ | `REACT_X11_A11Y` | set at all: log why the AT-SPI bridge did not start. `0` turns it off |
222
+ | `NO_AT_BRIDGE=1` | the freedesktop spelling of the same off switch |
223
+ | `REACT_X11_NO_GLOBAL_MENU=1` | `MenuBar` always draws its own bar |
224
+ | `REACT_X11_NO_TRANSPARENCY=1` | pretend there is no compositor ([debugging.md](debugging.md#react_x11_no_transparency1)) |
225
+
226
+ **Development and diagnostics**
227
+
228
+ | variable | effect |
229
+ | -------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
230
+ | `REACT_X11_DEVTOOLS=1` | connect to a running `react-devtools` (see devtools.md); on by default under `react-x11 dev`, `=0` turns it off |
231
+ | `REACT_X11_DEVTOOLS_HOST` | devtools host (default `localhost`) |
232
+ | `REACT_X11_DEVTOOLS_PORT` | devtools port (default `8097`) |
233
+ | `REACT_X11_DEBUG_LAYOUT=1` | outline every laid-out node, color-coded by tree depth |
234
+ | `REACT_X11_DEBUG_PAINT=1` | stroke each frame's damage rects in a rotating colour; `=full` also warns on full-window repaints |
235
+ | `REACT_X11_TRACE` | record the X11 protocol — see [debugging.md](debugging.md) for the grammar |
236
+ | `REACT_X11_CLICK_TO_COMPONENT=1` | Alt+Click opens the clicked element's source, using `cursor` (see click-to-component.md); on by default under `react-x11 dev`, `=0` turns it off |
237
+ | `REACT_X11_EDITOR` | editor CLI for click-to-component — setting this alone also enables it |
238
+ | `REACT_X11_STRICT_TOKENS=1` | a `$token` the theme does not define is fatal instead of dropped |
239
+
240
+ **The Cocoa backend**
241
+
242
+ | variable | effect |
243
+ | ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------ |
244
+ | `REACT_X11_COCOA_PRESENTER` | `surface` (the measured default) or `layers` |
245
+ | `REACT_X11_COCOA_PROMOTE` | `1`/`0`, forcing layer promotion on or off |
246
+ | `REACT_X11_COCOA_PANE_STRETCH` | `behind` (default), `never` or `always`: when a `<Frame>` pane's last frame is stretched while a resize waits on the next ([frame.md](frame.md)) |
247
+ | `REACT_X11_CALAYERS_PATH` | load the bridge from a checkout or an extracted tarball instead of the package |
248
+
249
+ A handful more exist only to switch off one optimisation while measuring it
250
+ — `REACT_X11_NO_PAINT_CACHE`, `REACT_X11_NO_SCROLL_BLIT`,
251
+ `REACT_X11_NO_PANE_SHAPE`, `REACT_X11_NO_BOUNDS_CACHE`,
252
+ `REACT_X11_NO_STROKE_CHUNKING`, `REACT_X11_NO_SCOPED_FLOORS`,
253
+ `REACT_X11_NO_UNREAD_WIDTHS`, `REACT_X11_NO_REFIT_HOLD`,
254
+ `REACT_X11_NO_APPEARANCE_CACHE`. They are development instruments, not API,
255
+ documented in [debugging.md](debugging.md) or where the thing they disable
256
+ is.