react-x11 1.2.0 → 2.0.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 (158) hide show
  1. package/README.md +330 -81
  2. package/package.json +132 -14
  3. package/src/ClickToComponent.js +9 -2
  4. package/src/DevToolsIntegration.js +440 -32
  5. package/src/Reconciler.js +463 -165
  6. package/src/a11y.js +1299 -0
  7. package/src/acceleratorhooks.js +86 -0
  8. package/src/accelerators.js +128 -0
  9. package/src/activate.js +168 -0
  10. package/src/anchor.js +360 -0
  11. package/src/appcontext.js +161 -0
  12. package/src/appearance.js +748 -0
  13. package/src/appearancehooks.js +96 -0
  14. package/src/apphooks.js +73 -0
  15. package/src/application.js +748 -0
  16. package/src/atspi.js +1953 -0
  17. package/src/bus.js +545 -0
  18. package/src/bushooks.js +136 -0
  19. package/src/clientmessage.js +140 -0
  20. package/src/clipboard.js +121 -0
  21. package/src/components/Button.js +148 -33
  22. package/src/components/Checkbox.js +66 -32
  23. package/src/components/Dialog.js +96 -29
  24. package/src/components/FileDialog.js +491 -0
  25. package/src/components/Icon.js +329 -0
  26. package/src/components/Menu.js +797 -133
  27. package/src/components/PasswordInput.js +434 -0
  28. package/src/components/ProgressBar.js +91 -12
  29. package/src/components/Radio.js +78 -35
  30. package/src/components/Select.js +255 -65
  31. package/src/components/Slider.js +102 -41
  32. package/src/components/SplitPane.js +206 -0
  33. package/src/components/Switch.js +100 -22
  34. package/src/components/Table.js +529 -0
  35. package/src/components/Tabs.js +211 -0
  36. package/src/components/Tooltip.js +528 -54
  37. package/src/components/anchor.js +154 -107
  38. package/src/components/change.js +34 -0
  39. package/src/components/dnd.js +103 -0
  40. package/src/components/index.js +16 -3
  41. package/src/components/keys.js +17 -20
  42. package/src/components/scribble.js +247 -0
  43. package/src/components/theme.js +350 -42
  44. package/src/components/typeahead.js +12 -2
  45. package/src/compose.js +868 -0
  46. package/src/compositing.js +224 -0
  47. package/src/dbusmenu.js +384 -0
  48. package/src/debug.d.ts +63 -0
  49. package/src/debug.js +642 -0
  50. package/src/decorations.js +486 -0
  51. package/src/desktopsettings.js +209 -0
  52. package/src/desktopsettingshooks.js +62 -0
  53. package/src/dnd.js +1725 -0
  54. package/src/editmenu.js +272 -0
  55. package/src/errors.js +98 -0
  56. package/src/events.js +1406 -162
  57. package/src/extensions.js +45 -0
  58. package/src/filedialog.js +375 -0
  59. package/src/filedialoghooks.js +132 -0
  60. package/src/fonthooks.js +64 -0
  61. package/src/fonts.js +301 -0
  62. package/src/foreignnodes.js +519 -0
  63. package/src/frame/child.js +33 -0
  64. package/src/frame/childmain.js +274 -0
  65. package/src/frame/env.js +140 -0
  66. package/src/frame/index.js +444 -0
  67. package/src/frame/lifecycle.js +67 -0
  68. package/src/frame/protocol.js +179 -0
  69. package/src/frames.js +73 -0
  70. package/src/glbackend.js +114 -0
  71. package/src/glnodes.js +125 -67
  72. package/src/globalmenu.js +683 -0
  73. package/src/host.d.ts +88 -0
  74. package/src/host.js +42 -0
  75. package/src/idle.js +490 -0
  76. package/src/idlehooks.js +100 -0
  77. package/src/imagesource.js +349 -0
  78. package/src/index.d.ts +475 -0
  79. package/src/index.js +83 -9
  80. package/src/inputtime.js +206 -0
  81. package/src/jsx-dev-runtime.d.ts +21 -0
  82. package/src/jsx-dev-runtime.js +2 -0
  83. package/src/jsx-runtime.d.ts +39 -0
  84. package/src/jsx-runtime.js +6 -0
  85. package/src/keyboard.js +256 -0
  86. package/src/keyboardstate.js +278 -0
  87. package/src/keyboardstatehooks.js +58 -0
  88. package/src/keysyms.d.ts +149 -0
  89. package/src/keysyms.js +270 -0
  90. package/src/locale.js +170 -0
  91. package/src/localehooks.js +47 -0
  92. package/src/menuitem.js +223 -0
  93. package/src/node.d.ts +597 -0
  94. package/src/node.js +44 -0
  95. package/src/nodes.js +9546 -690
  96. package/src/ntk.d.ts +44 -0
  97. package/src/ntk.js +25 -0
  98. package/src/paintcache.js +366 -0
  99. package/src/palette.js +380 -0
  100. package/src/pastestate.js +66 -0
  101. package/src/portal.js +461 -0
  102. package/src/priority.js +26 -0
  103. package/src/refresh/index.d.ts +40 -0
  104. package/src/refresh/index.js +122 -0
  105. package/src/refresh/loader.d.ts +37 -0
  106. package/src/refresh/loader.js +401 -0
  107. package/src/refresh/register.d.ts +5 -0
  108. package/src/refresh/register.js +13 -0
  109. package/src/registry.js +232 -0
  110. package/src/scale.js +626 -0
  111. package/src/scalehooks.js +27 -0
  112. package/src/screencolor.js +640 -0
  113. package/src/screencolorhooks.js +101 -0
  114. package/src/screens.js +754 -0
  115. package/src/screenshooks.js +137 -0
  116. package/src/startup.js +302 -0
  117. package/src/style.d.ts +126 -0
  118. package/src/style.js +33 -0
  119. package/src/styles.js +1482 -6
  120. package/src/svgnodes.js +306 -0
  121. package/src/testing/a11y.js +484 -0
  122. package/src/testing/components.js +414 -0
  123. package/src/testing/events.js +407 -0
  124. package/src/testing/harness.js +455 -0
  125. package/src/testing/index.d.ts +558 -0
  126. package/src/testing/index.js +85 -0
  127. package/src/testing/mock-app.js +463 -0
  128. package/src/testing/pixels.js +152 -0
  129. package/src/testing/queries.js +224 -0
  130. package/src/textrange.js +83 -0
  131. package/src/textselection.js +439 -0
  132. package/src/trace-registry.js +63 -0
  133. package/src/transfer.js +93 -0
  134. package/src/types/appearance.d.ts +84 -0
  135. package/src/types/application.d.ts +173 -0
  136. package/src/types/components.d.ts +820 -0
  137. package/src/types/dbus.d.ts +177 -0
  138. package/src/types/elements.d.ts +897 -0
  139. package/src/types/events.d.ts +549 -0
  140. package/src/types/filedialog.d.ts +260 -0
  141. package/src/types/fonts.d.ts +124 -0
  142. package/src/types/frame.d.ts +146 -0
  143. package/src/types/globalmenu.d.ts +42 -0
  144. package/src/types/nodes.d.ts +199 -0
  145. package/src/types/screencolor.d.ts +84 -0
  146. package/src/types/style.d.ts +434 -0
  147. package/src/types/system.d.ts +287 -0
  148. package/src/windowid.js +151 -0
  149. package/src/windowstate.js +393 -0
  150. package/src/xsettings.js +336 -0
  151. package/src/yoga.d.ts +55 -0
  152. package/src/yoga.js +135 -0
  153. package/src/components/Canvas3D.js +0 -28
  154. package/src/geometry3d.js +0 -223
  155. package/src/pointer3d.js +0 -158
  156. package/src/raycast3d.js +0 -146
  157. package/src/richnodes.js +0 -436
  158. package/src/scene3d.js +0 -683
package/src/index.d.ts ADDED
@@ -0,0 +1,475 @@
1
+ /**
2
+ * react-x11 — a React renderer whose host environment is an X11 server.
3
+ *
4
+ * These declarations are hand-written against the JavaScript in `src/`. The
5
+ * host elements (`<window>`, `<box>`, `<text>`, …) are added to React's JSX
6
+ * namespace below, so JSX type-checks with no tsconfig changes beyond
7
+ * `"jsx": "react-jsx"`.
8
+ */
9
+
10
+ import type { ReactNode, RefObject } from 'react';
11
+ import type { DrawnNode, NtkApp, NtkWindow } from './types/nodes.js';
12
+ import type { ReactX11Elements } from './types/elements.js';
13
+
14
+ export * from './types/style.js';
15
+ export * from './types/events.js';
16
+ export * from './types/nodes.js';
17
+ export * from './types/elements.js';
18
+ export * from './types/components.js';
19
+ export * from './types/frame.js';
20
+ export * from './types/globalmenu.js';
21
+ export * from './types/dbus.js';
22
+ export * from './types/application.js';
23
+ export * from './types/filedialog.js';
24
+ export * from './types/screencolor.js';
25
+ export * from './types/appearance.js';
26
+ export * from './types/fonts.js';
27
+ export * from './types/system.js';
28
+
29
+ /**
30
+ * The XID of the X11 window a ref points at, or `null` if there is not one
31
+ * yet. Accepts a `<window>`/`<popup>` ref (whose `current` is the live ntk
32
+ * window), a ref to any drawn node (resolved to the window that owns it),
33
+ * the ref object itself, or a raw XID.
34
+ *
35
+ * This is the walk `transientFor` resolves its prop through, and the one an
36
+ * xdg-desktop-portal `parent_window` handle needs — `x11:` followed by
37
+ * lowercase hex with no `0x` prefix.
38
+ */
39
+ export function windowIdOf(
40
+ target:
41
+ | NtkWindow
42
+ | DrawnNode
43
+ | RefObject<NtkWindow | DrawnNode | null>
44
+ | number
45
+ | null
46
+ | undefined,
47
+ ): number | null;
48
+
49
+ /**
50
+ * `windowIdOf` bound to a ref. Returns a **getter**, stable across renders,
51
+ * the same shape {@link useAnchor} has — refs attach after the commit that
52
+ * created the window, so a value read during render would be null on the
53
+ * render that matters.
54
+ */
55
+ export function useWindowId(
56
+ ref: RefObject<NtkWindow | DrawnNode | null>,
57
+ ): () => number | null;
58
+
59
+ /**
60
+ * Parse a `text/uri-list` payload (RFC 2483): CRLF-separated,
61
+ * percent-encoded, `#` lines are comments. What `DropEvent.files` is made
62
+ * of; exported for handling `getData('text/uri-list')` results yourself.
63
+ * `path` is present only for genuinely local `file:` URIs.
64
+ */
65
+ export function parseUriList(
66
+ text: string | Uint8Array,
67
+ ): Array<{ uri: string; path?: string }>;
68
+
69
+ /** A semantic group, or any concrete type name the owner offers. */
70
+ export type TransferType = 'text' | 'files' | 'uris' | (string & {});
71
+
72
+ export interface ClipboardOptions {
73
+ /** Selection atom name; `'CLIPBOARD'` by default, `'PRIMARY'` for the
74
+ * middle-click buffer. Any name works. */
75
+ selection?: string;
76
+ /** ms to wait for the owner at each protocol step. */
77
+ timeout?: number;
78
+ /** The server timestamp of the event behind this (ICCCM 2.1 / 2.4).
79
+ * Defaults to the last input event seen on this connection, which is
80
+ * almost always what you want. */
81
+ time?: number;
82
+ }
83
+
84
+ export interface SelectionChange {
85
+ selection: string;
86
+ /** Window now owning it, or `0` when nothing does — the case an edit
87
+ * menu wants. */
88
+ owner: number;
89
+ timestamp?: number;
90
+ selectionTimestamp?: number;
91
+ reason?: 'new-owner' | 'destroyed' | 'closed';
92
+ }
93
+
94
+ /** What `useClipboard()` returns. See docs/clipboard.md. */
95
+ export interface Clipboard {
96
+ /** Offer several flavours of one thing: type name to string or bytes. */
97
+ write(
98
+ data: string | Record<string, string | Uint8Array>,
99
+ options?: ClipboardOptions,
100
+ ): Promise<void>;
101
+ writeText(text: string, options?: ClipboardOptions): Promise<void>;
102
+ /** Stop owning the selection, so nothing is served for it any more. */
103
+ clear(selection?: string): Promise<void>;
104
+ /** What the current owner can convert to; `[]` when nothing owns it. */
105
+ targets(options?: ClipboardOptions): Promise<string[]>;
106
+ /** Plain text, via the owner's `UTF8_STRING`/`STRING` targets. Rejects
107
+ * when there is no owner or it offers neither — `read('text')` is the
108
+ * interop-hardened version. */
109
+ readText(options?: ClipboardOptions): Promise<string>;
110
+ /** One type, decoded, or `null` when the owner has nothing of that kind.
111
+ * Text-ish types resolve to a string, anything else to bytes. */
112
+ read(
113
+ type: TransferType,
114
+ options?: ClipboardOptions,
115
+ ): Promise<string | Uint8Array | null>;
116
+ /** Files copied in a file manager, parsed; `[]` when there are none. */
117
+ readFiles(
118
+ options?: ClipboardOptions,
119
+ ): Promise<Array<{ uri: string; path?: string }>>;
120
+ /** Called whenever the selection changes hands. Resolves to an
121
+ * unsubscribe function. Rejects on a server without XFixes. */
122
+ watch(handler: (change: SelectionChange) => void): Promise<() => void>;
123
+ watch(
124
+ selection: string,
125
+ handler: (change: SelectionChange) => void,
126
+ ): Promise<() => void>;
127
+ }
128
+
129
+ /**
130
+ * The ntk connection this tree renders onto — `app.fonts`, `app.cursors`,
131
+ * `app.X` and the rest. Throws outside a tree rendered by `createRoot()`.
132
+ *
133
+ * The same type {@link Root.app} has, so what `createRoot()` hands back and
134
+ * what a component reaches for are one thing; ntk's own surface is behind an
135
+ * index signature rather than declared here.
136
+ */
137
+ export function useApp(): NtkApp;
138
+
139
+ /** The clipboard, scoped to this tree's connection. */
140
+ export function useClipboard(): Clipboard;
141
+
142
+ /**
143
+ * Features `useSupports()` can be asked about.
144
+ *
145
+ * `'shaders'` is whether 3D can run your own GLSL — that is, whether this
146
+ * connection draws through the direct rendering backend. Ask it before
147
+ * rendering a `<shaderMaterial>`, which throws where there is no pipeline to
148
+ * compile it. It needs `createRoot({ glPolicy: 'auto' })`: under the default
149
+ * policy it is false whatever the machine could do, because the indirect
150
+ * backend is what draws. `app.glCapabilities()` is the machine's answer, and
151
+ * says why.
152
+ */
153
+ export type SupportsFeature = 'transparency' | 'shaders';
154
+
155
+ /**
156
+ * Can this **display** do something? `'transparency'` is true when the
157
+ * server has a 32-bit visual to draw on *and* a compositor is running to
158
+ * blend it; it re-renders when a compositor starts or stops.
159
+ *
160
+ * The companion is the `'@supports transparency'` style block, which asks
161
+ * about the window a node is actually in. Reach for that first — this is
162
+ * for decisions that are not styling, and that have to be made before a
163
+ * window exists (sizing a popup to hold a client-drawn shadow, say).
164
+ */
165
+ export function useSupports(feature: SupportsFeature): boolean;
166
+
167
+ /** What React reports alongside an error it caught. */
168
+ export interface ErrorInfo {
169
+ componentStack?: string;
170
+ }
171
+
172
+ export interface RootOptions {
173
+ /** `':1'`, `'host:0.0'`, or a unix socket path. Defaults to `$DISPLAY`. */
174
+ display?: string;
175
+ /**
176
+ * Render into a connection you already have — tests, embedding, a client
177
+ * built with options this bag does not carry. A borrowed connection is
178
+ * never closed by {@link Root.unmount}.
179
+ */
180
+ app?: NtkApp;
181
+ /** An already-connected duplex stream, instead of dialling `$DISPLAY`. */
182
+ stream?: unknown;
183
+ /** Pluggable system-font lookup; see ntk's docs/fonts.md. */
184
+ fontSource?: unknown;
185
+ /** A visual id for `getContext('opengl')`, instead of querying for one. */
186
+ glxVisual?: unknown;
187
+ /**
188
+ * Which OpenGL backend `<glarea>` draws through — see
189
+ * docs/gl.md. `'indirect'` (the default) is indirect GLX; `'auto'` prefers
190
+ * the GPU where it is available, which is what `<shaderMaterial>` needs.
191
+ * It has to be set here rather than later: ntk probes for the direct
192
+ * backend during the connection handshake.
193
+ */
194
+ glPolicy?:
195
+ | 'auto'
196
+ | 'direct'
197
+ | 'indirect'
198
+ | 'off'
199
+ | {
200
+ mode?: 'auto' | 'direct' | 'indirect' | 'off';
201
+ devicePath?: string | null;
202
+ maxInFlight?: number;
203
+ linearFallback?: boolean;
204
+ };
205
+ /**
206
+ * Device pixels per logical pixel — the display scale (docs/scale.md).
207
+ *
208
+ * `'auto'` (the default) resolves it from the connection: environment
209
+ * overrides (`REACT_X11_SCALE`, `GDK_SCALE`, `QT_SCALE_FACTOR`), then the
210
+ * desktop's own configuration (XSETTINGS `Gdk/WindowScalingFactor` and
211
+ * `Xft/DPI`, `Xft.dpi` from `RESOURCE_MANAGER`), then the panel's RandR
212
+ * millimetres under mutter's viewing-distance model — with EDIDs that lie
213
+ * (every virtual machine's does) audited out — and finally the resolution
214
+ * class of the pixel grid itself. A number pins it; `REACT_X11_SCALE` in
215
+ * the environment outranks even that, as the user's accessibility escape
216
+ * hatch.
217
+ *
218
+ * Every length the app writes stays logical — styles, `fontSize`, window
219
+ * geometry, event coordinates, `getClientRects`, `useScreens` — and the
220
+ * renderer multiplies exactly once on the way to the server. Resolved
221
+ * before the first window realizes and static for the life of the root.
222
+ */
223
+ scale?: 'auto' | number;
224
+ /** X protocol errors no request callback claimed. Default warns. */
225
+ onXError?: (err: Error) => void;
226
+ onUncaughtError?: (error: unknown, errorInfo: ErrorInfo) => void;
227
+ onCaughtError?: (error: unknown, errorInfo: ErrorInfo) => void;
228
+ onRecoverableError?: (error: unknown, errorInfo: ErrorInfo) => void;
229
+ /**
230
+ * The X connection ended without being asked to — server exit, ssh drop,
231
+ * kill. Not called for a connection this root closed itself.
232
+ *
233
+ * A reconnect is not a reconnect: every window id, pixmap, glyph set and
234
+ * font is invalidated with the connection. Tear the root down and build a
235
+ * new one; nothing survives.
236
+ */
237
+ onDisconnect?: (reason: 'closed' | 'error', err?: Error) => void;
238
+ /**
239
+ * Startup notification (freedesktop), on by default. Reads
240
+ * `DESKTOP_STARTUP_ID`, sets `_NET_STARTUP_ID` and `_NET_WM_USER_TIME` on
241
+ * the first toplevel before it maps, and ends the launcher's startup
242
+ * sequence when the app is up — which stops the busy cursor and gives
243
+ * focus-stealing prevention the evidence it asks for.
244
+ *
245
+ * `false` turns it off entirely, for an app that runs its own sequence or
246
+ * an embedder that owns the toplevel. A string supplies the id for a
247
+ * launch where it did not arrive in the environment.
248
+ *
249
+ * See {@link StartupNotificationOptions.completeOn} for *when* the app
250
+ * counts as up, and docs/desktop.md.
251
+ */
252
+ startupNotification?: boolean | string | StartupNotificationOptions;
253
+ /**
254
+ * Dead keys and the Compose key — what `dead_acute` then `e` types, and
255
+ * what `Compose o c` does (docs/events.md).
256
+ *
257
+ * The default is a built-in table: every dead key composed through
258
+ * Unicode, so it covers every base letter in every script, plus the
259
+ * `Multi_key` symbol sequences. It needs no configuration and reads
260
+ * nothing from disk.
261
+ *
262
+ * - `'system'` adds this machine's Compose file — `$XCOMPOSEFILE`, a
263
+ * personal `~/.XCompose`, or the locale's file under
264
+ * `/usr/share/X11/locale`. There is usually none on macOS.
265
+ * - `{ file }` adds one you name, `{ sequences }` adds or overrides
266
+ * individual ones; later definitions win.
267
+ * - `false` turns composition off, for an app doing its own.
268
+ */
269
+ compose?: false | 'system' | ComposeOptions;
270
+ /**
271
+ * Which keysym `ev.keysym` reports, and so which one a shortcut matches
272
+ * (docs/events.md, issue #85).
273
+ *
274
+ * `'latin'`, the default: the Latin keysym for the key, taken from the
275
+ * Latin group when the keymap has one and from the physical position when
276
+ * it does not — so Ctrl+Z keeps undoing while the user types Russian, on
277
+ * Linux and under XQuartz alike. Typing is unaffected: `ev.key` and
278
+ * `ev.codepoint` always follow the active layout.
279
+ *
280
+ * - `'layout'` reports the keysym the layout actually put on the key, for
281
+ * an application matching shortcuts its own way.
282
+ * - An object is a keycode→Latin keysym table of your own, for a server
283
+ * whose keycodes are neither evdev's nor macOS's. Values may be given as
284
+ * a character: `{ 52: 'z' }`.
285
+ */
286
+ accelerators?: 'latin' | 'layout' | Record<number, number | string>;
287
+ /**
288
+ * Whether a subtree coming back out of hiding takes the keyboard back with
289
+ * it (docs/events.md, "Focus and visibility"). Default `true`.
290
+ *
291
+ * Hiding a subtree — `<Suspense>` showing its fallback, `<Activity
292
+ * mode="hidden">`, a `display: 'none'` — always releases focus inside it,
293
+ * since keys must not land on a control nobody can see. Revealing it puts
294
+ * focus back where it was, but only when nothing else has taken the
295
+ * keyboard in the meantime.
296
+ *
297
+ * `false` is the browser's answer: focus that fell to nothing stays there,
298
+ * and coming back is the user's own Tab.
299
+ */
300
+ restoreFocusOnReveal?: boolean;
301
+ }
302
+
303
+ export interface ComposeOptions {
304
+ /** A Compose file to load on top of the built-ins, or `'system'` to look
305
+ * for this machine's. */
306
+ file?: string | 'system';
307
+ /** Sequences to add or override: `[[keysyms], text]`, where a keysym may
308
+ * be given as a character. */
309
+ sequences?: Array<[Array<number | string>, string]>;
310
+ }
311
+
312
+ export interface StartupNotificationOptions {
313
+ /** The launch id, when it did not come from `DESKTOP_STARTUP_ID`. */
314
+ id?: string;
315
+ /**
316
+ * What counts as "started". Default `'paint'`.
317
+ *
318
+ * - `'paint'` — the first frame that actually drew. This renderer maps a
319
+ * window and paints it a frame later, so the map is an empty rectangle;
320
+ * ending there stops the busy cursor over a blank window.
321
+ * - `'map'` — the first toplevel mapping, which is what GTK does. Earlier,
322
+ * and right for an app whose first frame is expensive enough that it
323
+ * would rather the cursor stopped before it.
324
+ * - `'manual'` — nothing automatic; call {@link notifyStartupComplete}.
325
+ * For an app that is not up until it says so, such as one restoring a
326
+ * session behind a splash.
327
+ *
328
+ * A backstop timer ends the sequence regardless, so an app that never
329
+ * paints — or never calls — cannot leave the cursor spinning.
330
+ */
331
+ completeOn?: 'paint' | 'map' | 'manual';
332
+ }
333
+
334
+ /**
335
+ * The X server timestamp of the user action that launched this app, from
336
+ * the startup id, or `null` when there was none.
337
+ *
338
+ * `null` is a real answer rather than a failure: an app started from a
339
+ * shell has no launch timestamp and never will. It is the "when" that a
340
+ * legitimate request to come forward is weighed against, and `0` is not a
341
+ * substitute — EWMH gives zero its own meaning.
342
+ */
343
+ export function launchTimestamp(): number | null;
344
+
345
+ /**
346
+ * End the startup sequence now. Idempotent, and a no-op when there is none,
347
+ * so it may be called unconditionally. The seam behind
348
+ * `startupNotification: { completeOn: 'manual' }`.
349
+ */
350
+ export function notifyStartupComplete(): void;
351
+
352
+ /**
353
+ * The server timestamp of the last input event this connection saw, or
354
+ * `undefined` when none has arrived yet.
355
+ *
356
+ * ICCCM's "the timestamp of the event that caused this" and EWMH's
357
+ * `_NET_WM_USER_TIME`, which is what a selection acquired *because the user
358
+ * did something* has to be stamped with. Never substitute `0` for the
359
+ * `undefined`: that is `CurrentTime`, which ICCCM 2.1 forbids and which
360
+ * leaves two clients racing for one selection unable to be ordered. Where
361
+ * there is no user action to name, {@link serverTime} is the answer.
362
+ */
363
+ export function lastInputTime(app: NtkApp): number | undefined;
364
+
365
+ /**
366
+ * A current timestamp from this connection's server, for an operation no
367
+ * user action caused — a tray taking its manager selection at startup, say.
368
+ *
369
+ * One round trip: there is no request that asks for the time, so this
370
+ * appends zero bytes to a property on a 1x1 window of ours and reads the
371
+ * time off the resulting `PropertyNotify`. Resolves `0` (`CurrentTime`) if
372
+ * the server has not answered within five seconds; never rejects.
373
+ */
374
+ export function serverTime(app: NtkApp): Promise<number>;
375
+
376
+ /** A mounted tree, as returned by {@link createRoot}. */
377
+ export interface Root {
378
+ /** The ntk `App` this root renders through. */
379
+ readonly app: NtkApp;
380
+ render(element: ReactNode, callback?: () => void): void;
381
+ /** Unmounts, then closes the connection unless `app` was passed in. */
382
+ unmount(): Promise<void>;
383
+ }
384
+
385
+ /**
386
+ * Connect to the X server and make a root:
387
+ *
388
+ * ```tsx
389
+ * const root = await createRoot(); // connects via $DISPLAY
390
+ * const other = await createRoot({ display: ':1' });
391
+ * root.render(<App />);
392
+ * await root.unmount();
393
+ * ```
394
+ *
395
+ * Each root without `app` opens its own connection and owns it, so two
396
+ * roots are two independent trees.
397
+ */
398
+ export function createRoot(options?: RootOptions): Promise<Root>;
399
+
400
+ /**
401
+ * Say something through the screen reader without moving focus — the
402
+ * explicit counterpart of an ARIA live region ("saved", "3 results").
403
+ * Returns `true` when an AT-SPI bridge was live to carry it; `false` means
404
+ * nobody was listening and a visible fallback may be warranted.
405
+ */
406
+ export function announce(text: string, opts?: { assertive?: boolean }): boolean;
407
+
408
+ /**
409
+ * The verbs the standard edit menu is opened with — what a target can do,
410
+ * and what each of those is worth right now.
411
+ *
412
+ * **A verb left out is a row that is not there**, rather than a greyed one:
413
+ * a password field passes no `copy` and no `cut`, a read-only surface passes
414
+ * only `copy` and `selectAll`, and neither shows a dead row explaining
415
+ * itself. Enablement is not the caller's to decide row by row — Cut and Copy
416
+ * follow `hasSelection`, Paste follows what the server says about the
417
+ * clipboard — which is the point of sharing the implementation.
418
+ */
419
+ export interface EditMenuActions {
420
+ /** Whether there is a selection: what Cut and Copy are enabled by. */
421
+ hasSelection?: boolean;
422
+ /** Whether there is anything to undo. Undo is greyed without it. */
423
+ canUndo?: boolean;
424
+ undo?(): void;
425
+ canRedo?: boolean;
426
+ redo?(): void;
427
+ cut?(): void;
428
+ copy?(): void;
429
+ paste?(): void;
430
+ /** Defaults to `true`. `false` greys Select All — the surface is empty, or
431
+ * all of it is selected already. */
432
+ canSelectAll?: boolean;
433
+ selectAll?(): void;
434
+ }
435
+
436
+ /**
437
+ * Open the standard Undo / Redo / Cut / Copy / Paste / Select All menu on a
438
+ * node, for a target that speaks {@link EditMenuActions}.
439
+ *
440
+ * This is `<textinput>`'s own right-click menu, exported because everything
441
+ * about it except the verbs is worth having once: the enablement rules,
442
+ * Paste watching selection ownership rather than asking the server on the
443
+ * way to opening a menu, the arrow keys and Escape, the pointer grab that
444
+ * dismisses it, and handing the keyboard back afterwards. See
445
+ * [extending.md](../docs/extending.md).
446
+ *
447
+ * `at` is where the pointer was, in the **owner window's** coordinates —
448
+ * `ev.x`/`ev.y` from the event that asked for the menu, which is what a
449
+ * surface with no caret of its own already has.
450
+ */
451
+ export function openEditMenu(
452
+ node: DrawnNode,
453
+ at: { x: number; y: number },
454
+ actions: EditMenuActions,
455
+ ): void;
456
+
457
+ /** Whether `node` has the standard edit menu open. An element that paints a
458
+ * selection asks: the popup holds the keyboard, so the element is not
459
+ * focused, and the text the menu is about to act on has to stay lit. */
460
+ export function editMenuOpen(node: DrawnNode): boolean;
461
+
462
+ /** Close it, if it is open. The menu already closes itself on a choice, a
463
+ * press outside and Escape; this is for an element that has decided the menu
464
+ * no longer applies — its content changed underneath it, or it scrolled. */
465
+ export function closeEditMenu(node: DrawnNode): void;
466
+
467
+ /** The react-reconciler instance. Escape hatch; not a stable API. */
468
+ export const Renderer: any;
469
+
470
+ declare const ReactX11: {
471
+ createRoot: typeof createRoot;
472
+ };
473
+ export default ReactX11;
474
+
475
+ export type { ReactX11Elements };
package/src/index.js CHANGED
@@ -1,14 +1,78 @@
1
+ export { createRoot, Renderer } from './Reconciler.js';
2
+ export { createStyles, flattenStyle } from './styles.js';
3
+ export { windowIdOf, useWindowId, useTopLevelWindow } from './windowid.js';
4
+ export { launchTimestamp, notifyStartupComplete } from './startup.js';
5
+ export { activateWindow } from './activate.js';
6
+ export { lastInputTime, serverTime } from './inputtime.js';
1
7
  export {
2
- render,
3
- createRoot,
4
- unmountComponentAtNode,
5
- Renderer,
6
- } from './Reconciler.js';
8
+ onAppActivate,
9
+ onAppOpen,
10
+ registerApplication,
11
+ } from './application.js';
12
+ export { useAppActivate, useAppOpen } from './apphooks.js';
13
+ export { parseUriList } from './transfer.js';
14
+ export { useApp, useClipboard, useSupports } from './appcontext.js';
15
+ export { BusUnavailableError, closeBus, sessionBus, systemBus } from './bus.js';
16
+ export { announce } from './a11y.js';
17
+ // the standard Undo/Cut/Copy/Paste menu, for an element that edits or
18
+ // selects text of its own — `<textinput>`'s own menu is a caller of it
19
+ export { closeEditMenu, editMenuOpen, openEditMenu } from './nodes.js';
20
+ export { useSessionBus, useSystemBus } from './bushooks.js';
21
+ export { REGISTRAR_NAME, useGlobalMenu } from './globalmenu.js';
7
22
  export {
23
+ NoPortalError,
24
+ PortalCancelledError,
25
+ hasService,
26
+ portalRequest,
27
+ portalVersion,
28
+ } from './portal.js';
29
+ export {
30
+ NoFileDialogError,
31
+ fileDialogBackend,
32
+ openFile,
33
+ saveFile,
34
+ selectFolder,
35
+ } from './filedialog.js';
36
+ export { useFileDialog } from './filedialoghooks.js';
37
+ export {
38
+ NoScreenColorError,
39
+ pickScreenColor,
40
+ screenColorBackend,
41
+ } from './screencolor.js';
42
+ export { useEyedropper } from './screencolorhooks.js';
43
+ export { systemAppearance } from './appearance.js';
44
+ export { useSystemAppearance } from './appearancehooks.js';
45
+ export { useScreens } from './screenshooks.js';
46
+ export { useScale } from './scalehooks.js';
47
+ export { useWindowState } from './windowstate.js';
48
+ export { keepAwake } from './idle.js';
49
+ export { useIdle, useKeepAwake } from './idlehooks.js';
50
+ export { useKeyboardState } from './keyboardstatehooks.js';
51
+ // menu accelerators, and the same chord vocabulary for a shortcut that is
52
+ // not in a menu (#351)
53
+ export { matchesShortcut } from './accelerators.js';
54
+ export { useAccelerator } from './acceleratorhooks.js';
55
+ export { useDesktopSettings } from './desktopsettingshooks.js';
56
+ export { loadFont, openFont } from './fonts.js';
57
+ export { useFont } from './fonthooks.js';
58
+ export { systemLocale } from './locale.js';
59
+ export { useLocale } from './localehooks.js';
60
+ export {
61
+ useDropTarget,
62
+ useDragSource,
8
63
  Select,
9
- SelectThemeProvider,
64
+ Tabs,
65
+ Table,
66
+ SplitPane,
10
67
  ThemeProvider,
68
+ useDirection,
69
+ useTheme,
70
+ Icon,
71
+ icons,
72
+ iconNames,
73
+ iconSize,
11
74
  Button,
75
+ PasswordInput,
12
76
  Checkbox,
13
77
  Radio,
14
78
  RadioGroup,
@@ -20,11 +84,21 @@ export {
20
84
  MenuBar,
21
85
  ContextMenu,
22
86
  useAnchor,
87
+ useAnchorTracking,
88
+ anchorArea,
23
89
  anchorRect,
24
90
  centerRect,
25
- Canvas3D,
91
+ screenRect,
26
92
  } from './components/index.js';
27
93
 
28
- import { render, createRoot, unmountComponentAtNode } from './Reconciler.js';
94
+ // A pane of this application in its own process, and the context bridge
95
+ // that follows the app into it (docs/frame.md). `useFrameClose`/`isFramed`
96
+ // are the pane's side, exported here so a module can be a pane and an
97
+ // application with one import.
98
+ export { Frame } from './frame/index.js';
99
+ export { createFrameContext } from './frame/env.js';
100
+ export { isFramed, useFrameClose } from './frame/lifecycle.js';
101
+
102
+ import { createRoot } from './Reconciler.js';
29
103
 
30
- export default { render, createRoot, unmountComponentAtNode };
104
+ export default { createRoot };