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
@@ -0,0 +1,549 @@
1
+ /**
2
+ * Synthetic events. Dispatched capture → target → bubble over the drawn
3
+ * tree by front-to-back hit testing, the same shape React gives you in the
4
+ * DOM. See docs/events.md.
5
+ */
6
+
7
+ import type { RefObject } from 'react';
8
+ import type { DrawnNode, NtkWindow, TextInputNode } from './nodes.js';
9
+ import type { MenuShortcut } from './components.js';
10
+
11
+ /** The raw ntk/X11 event a synthetic one was made from. */
12
+ export interface NativeEvent {
13
+ /** X event type number. */
14
+ type: number;
15
+ name?: string;
16
+ /** Window-relative pointer position. */
17
+ x: number;
18
+ y: number;
19
+ /** Screen coordinates — what you anchor a `<popup>` at. */
20
+ rootx: number;
21
+ rooty: number;
22
+ /** X modifier/button mask. */
23
+ buttons: number;
24
+ keycode?: number;
25
+ codepoint?: number;
26
+ time?: number;
27
+ [key: string]: unknown;
28
+ }
29
+
30
+ export interface SyntheticEvent<T = DrawnNode> {
31
+ type: string;
32
+ /** The node the event was dispatched at (the public instance). */
33
+ target: T;
34
+ /** The node whose handler is running. */
35
+ currentTarget: T | null;
36
+ /** Window coordinates. */
37
+ x: number;
38
+ y: number;
39
+ /** Coordinates relative to `target`'s box. */
40
+ localX: number;
41
+ localY: number;
42
+ nativeEvent: NativeEvent;
43
+ shiftKey: boolean;
44
+ ctrlKey: boolean;
45
+ /**
46
+ * X11 Mod1 — Alt on virtually every keymap, but a convention rather than
47
+ * a rule of the protocol. `nativeEvent.buttons` has the raw mask for a
48
+ * setup that remaps it.
49
+ */
50
+ altKey: boolean;
51
+ /** X11 Mod4 — Super, under the DOM's name for it. Same caveat as `altKey`. */
52
+ metaKey: boolean;
53
+ defaultPrevented: boolean;
54
+ propagationStopped: boolean;
55
+ /** Suppress the element's built-in behaviour (editing, wheel scrolling…). */
56
+ preventDefault(): void;
57
+ stopPropagation(): void;
58
+ /**
59
+ * Route the rest of this gesture's `mousemove`/`mouseup` to this node even
60
+ * once the pointer leaves it. Released on mouseup and on unmount.
61
+ */
62
+ capturePointer(): void;
63
+ releasePointer(): void;
64
+ }
65
+
66
+ export interface MouseEvent<T = DrawnNode> extends SyntheticEvent<T> {
67
+ /** X button number: 1 left, 2 middle, 3 right. */
68
+ button: number;
69
+ /** DOM-style click count — 2 is a double click, 3 a triple. */
70
+ detail: number;
71
+ }
72
+
73
+ /**
74
+ * The pointer looks like it is heading here (ntk#37) — said *before* it
75
+ * arrives, so there is time to do something about it.
76
+ *
77
+ * Not routed like the other pointer events. Nothing is hit tested and there
78
+ * is no capture or bubble phase: nodes that want attention register
79
+ * themselves, the pointer's trajectory is matched against their rectangles,
80
+ * and the one it would enter soonest is the one that hears about it. Only one
81
+ * node in a window holds attention at a time.
82
+ */
83
+ export interface AttentionEvent<T = DrawnNode> extends SyntheticEvent<T> {
84
+ /**
85
+ * Roughly how many milliseconds until the pointer arrives, at the speed it
86
+ * is currently travelling — 0 when it is already inside.
87
+ *
88
+ * This is the number worth branching on. "The pointer is here in 30ms" and
89
+ * "in 220ms" justify very different amounts of speculative work, and the
90
+ * renderer is the only party that knows which one this is.
91
+ */
92
+ eta: number;
93
+ }
94
+
95
+ export interface WheelEvent<T = DrawnNode> extends SyntheticEvent<T> {
96
+ /** Pixels, positive right — one notch of the wheel is 48 of them. */
97
+ deltaX: number;
98
+ /** Pixels, positive down. Fractions of a notch where `smooth`. */
99
+ deltaY: number;
100
+ /**
101
+ * Whether the device measured this scroll rather than clicked it: XI2's
102
+ * scroll valuators (a touchpad, a high-resolution wheel) can report a
103
+ * fraction of a notch, the emulated buttons 4-7 can only ever say one.
104
+ */
105
+ smooth: boolean;
106
+ }
107
+
108
+ export interface KeyboardEvent<T = DrawnNode> extends SyntheticEvent<T> {
109
+ /** X keycode. */
110
+ keycode: number;
111
+ /**
112
+ * X keysym (`XK_*`), or undefined if the map has no entry — **the Latin
113
+ * one**, so a shortcut keeps matching while another layout is typing.
114
+ * `ev.key`/`ev.codepoint` are what the key produced; this is what it is
115
+ * called. See "Layouts" in docs/events.md, and
116
+ * `createRoot({ accelerators })` to turn the resolution off.
117
+ */
118
+ keysym?: number;
119
+ /** Which XKB layout group typed this, 0-3. A layout switch moves the
120
+ * group and sends no other notice. */
121
+ group: number;
122
+ /** Unicode code point, undefined when the key produces no character —
123
+ * which includes every key a composition took (see `composing`). */
124
+ codepoint?: number;
125
+ /** The character the key produced, undefined for non-printing keys and
126
+ * for keys a composition took. */
127
+ key?: string;
128
+ /** Whether this key belongs to an open composition — a dead key, or a key
129
+ * of a Compose sequence. Its text arrives on the composition events
130
+ * instead, so a handler that types from `onKeyDown` should skip it. */
131
+ composing: boolean;
132
+ }
133
+
134
+ /**
135
+ * A composition — text the user is still typing. `onCompositionStart` has
136
+ * no data, `onCompositionUpdate` carries what is showing at the caret, and
137
+ * `onCompositionEnd` carries the text that was committed (empty when the
138
+ * sequence was abandoned).
139
+ */
140
+ export interface CompositionEvent<T = DrawnNode> extends SyntheticEvent<T> {
141
+ data: string;
142
+ }
143
+
144
+ export interface FocusEvent<T = DrawnNode> extends SyntheticEvent<T> {}
145
+
146
+ /** What a drop target's `dropAccept` prop takes: an exact type name
147
+ * (`'image/png'`), a semantic group (`'files' | 'uris' | 'text'`), an
148
+ * array of either, or a predicate over the offered names. Absent means
149
+ * the node accepts anything — a bare `onDrop` is a valid dropzone. */
150
+ export type DropAccept = string | string[] | ((types: string[]) => boolean);
151
+
152
+ export type DropAction = 'copy' | 'move' | 'link' | 'ask' | 'private';
153
+
154
+ /**
155
+ * A drag over a drop target (`onDragEnter` / `onDragOver` /
156
+ * `onDragLeave`). Enter/leave do not bubble, like their mouse
157
+ * counterparts; `onDragOver` dispatches capture → target → bubble.
158
+ */
159
+ export interface DragEvent<T = DrawnNode> extends SyntheticEvent<T> {
160
+ /** Offered payload type names, e.g. `['text/uri-list', 'text/plain']`. */
161
+ types: string[];
162
+ /** Alias-aware membership test: a concrete type or a semantic group. */
163
+ has(type: string): boolean;
164
+ /** The action the source asked for. `'ask'` means it wants the user
165
+ * offered a choice — see `actions`. */
166
+ action: DropAction;
167
+ /** The actions an `'ask'` source will accept, in the order it listed
168
+ * them. Empty for every other action, which is all but a few file
169
+ * managers. */
170
+ actions: Array<'copy' | 'move' | 'link'>;
171
+ /** The source's own words for `actions`, positionally matched, with
172
+ * `null` where it offered none. Empty when `actions` is. */
173
+ actionDescriptions: Array<string | null>;
174
+ /** Where the drag came from: another application, or this one. */
175
+ source: 'internal' | 'external';
176
+ /** Pointer position in screen (root) coordinates. */
177
+ screenX: number;
178
+ screenY: number;
179
+ /** Override the declarative `dropAccept` answer for this position
180
+ * (`onDragOver`), or settle what the drop actually did (`onDrop`, where
181
+ * `accept` picks the action reported to the source and `reject` tells it
182
+ * the drop was not taken after all). Inert elsewhere. */
183
+ accept(action?: 'copy' | 'move' | 'link'): void;
184
+ reject(): void;
185
+ /** Opt into the XdndStatus suppression rectangle for this node's rect:
186
+ * the source stops sending positions while the pointer stays inside.
187
+ * Do not freeze a zone that draws per-position feedback (insertion
188
+ * carets, edge auto-scroll). */
189
+ freeze(): void;
190
+ }
191
+
192
+ /** The drop itself (`onDrop`). The common payloads are prefetched —
193
+ * `files` and `text` read synchronously; everything else is behind
194
+ * `getData`. There is deliberately no `dataTransfer`: X selection
195
+ * transfer is asynchronous, and a sync-looking `getData` would return
196
+ * `"[object Promise]"` silently. */
197
+ export interface DropEvent<T = DrawnNode> extends DragEvent<T> {
198
+ /** One conversion of the drag payload. Text-ish targets decode to a
199
+ * string; anything else stays raw bytes. Semantic groups resolve to
200
+ * the first concretely offered member. */
201
+ getData(type: string): Promise<Uint8Array | string>;
202
+ /** Parsed `text/uri-list` (RFC 2483). `path` is present only for
203
+ * genuinely local `file:` URIs. Empty when no file flavour was
204
+ * offered. */
205
+ files: Array<{ uri: string; path?: string }>;
206
+ /** The best offered text flavour, when there was one. */
207
+ text?: string;
208
+ /** Internal drags only: the dragData values by type name, live — no
209
+ * serialisation happened. Absent for drops from other applications. */
210
+ items?: Record<string, unknown>;
211
+ }
212
+
213
+ /** A drag *source*'s events (`onDragStart` / `onDrag` / `onDragEnd`).
214
+ * `source` and `accepted` describe the transport and the current target's
215
+ * answer; `screenX/screenY` are where the pointer is, in root coordinates
216
+ * — what a preview `<popup>` follows. */
217
+ export interface DragSourceEvent<T = DrawnNode> extends SyntheticEvent<T> {
218
+ types: string[];
219
+ action: DropAction;
220
+ source: 'internal' | 'external';
221
+ screenX: number;
222
+ screenY: number;
223
+ /** Whether whatever is under the pointer currently accepts the drop. */
224
+ accepted?: boolean;
225
+ }
226
+
227
+ /** `onDragEnd`: `action` is what the drop performed, or null when the drag
228
+ * ended nowhere (or was rejected). */
229
+ export interface DragEndEvent<T = DrawnNode> extends Omit<
230
+ DragSourceEvent<T>,
231
+ 'action'
232
+ > {
233
+ action: DropAction | null;
234
+ dropped: boolean;
235
+ }
236
+
237
+ /**
238
+ * The props that make a node draggable. `dragData` maps payload type names
239
+ * to values: strings and bytes are served as-is, thunks are resolved
240
+ * lazily (at delivery for an in-app drop, at promotion for an external
241
+ * one), and any other live value reaches in-app drops by reference
242
+ * (`e.items`) but is JSON-serialised for the wire.
243
+ */
244
+ export interface DragSourceProps<T = DrawnNode> {
245
+ draggable?: boolean;
246
+ dragData?: Record<
247
+ string,
248
+ string | Uint8Array | (() => string | Uint8Array | unknown) | unknown
249
+ >;
250
+ /** Offered actions, preferred first. Defaults to `['copy']`. */
251
+ dragActions?: Array<'copy' | 'move' | 'link'>;
252
+ /** Fires past the drag threshold; `preventDefault()` cancels the drag
253
+ * (the gesture continues as plain mouse events). */
254
+ onDragStart?: (ev: DragSourceEvent<T>) => void;
255
+ /** Per motion while dragging — the source-side mirror of onDragOver. */
256
+ onDrag?: (ev: DragSourceEvent<T>) => void;
257
+ onDragEnd?: (ev: DragEndEvent<T>) => void;
258
+ }
259
+
260
+ /** The props that make a node a drop target. Any drawn element and
261
+ * `<window>`/`<popup>` accept them; their presence registers the node
262
+ * with the XDND router (see docs/events.md). */
263
+ export interface DropTargetProps<T = DrawnNode> {
264
+ dropAccept?: DropAccept;
265
+ /** Does not propagate — synthesized by drag-path diffing, and paired
266
+ * with the `':drag-over'` style state. */
267
+ onDragEnter?: (ev: DragEvent<T>) => void;
268
+ onDragLeave?: (ev: DragEvent<T>) => void;
269
+ onDragOver?: (ev: DragEvent<T>) => void;
270
+ onDragOverCapture?: (ev: DragEvent<T>) => void;
271
+ /** May be async: XdndFinished is held until the returned promise
272
+ * settles (or a ~10 s watchdog fires, so a forgotten await cannot hang
273
+ * the source application's gesture). */
274
+ onDrop?: (ev: DropEvent<T>) => void | Promise<void>;
275
+ onDropCapture?: (ev: DropEvent<T>) => void | Promise<void>;
276
+ }
277
+
278
+ /**
279
+ * `<textinput onChange>` / `<textarea onChange>`. The value is on both
280
+ * `ev.value` and `ev.target.value` — the second is what every DOM form
281
+ * library reads, and it is the *new* value even in controlled mode, where
282
+ * `props.value` is still the old string until the parent re-renders.
283
+ *
284
+ * `nativeEvent` is the X key event when a keystroke drove the edit, and null
285
+ * when nothing did — a paste resolving, an undo, a value the parent pushed
286
+ * back. Guard it.
287
+ */
288
+ /**
289
+ * The document selection in a `selectable` element changed — a drag, a
290
+ * double click, Ctrl+A, or a `selectAll()` from code. Not a pointer event:
291
+ * it reports state, and the gesture that moved it has already been
292
+ * dispatched as one.
293
+ */
294
+ export interface SelectionChangeEvent<T = DrawnNode> {
295
+ type: 'selectionChange';
296
+ target: T;
297
+ currentTarget: T;
298
+ /** The selected text, assembled the way a copy would assemble it. */
299
+ text: string;
300
+ isCollapsed: boolean;
301
+ }
302
+
303
+ export interface ChangeEvent<T = TextInputNode> extends Omit<
304
+ SyntheticEvent<T>,
305
+ 'nativeEvent'
306
+ > {
307
+ type: 'change';
308
+ value: string;
309
+ /** The control's `name` prop, mirrored from `target.name`. */
310
+ name?: string;
311
+ nativeEvent: NativeEvent | null;
312
+ }
313
+
314
+ /**
315
+ * `<textinput onSubmit>` — Enter, or Ctrl+Enter in a `<textarea>`. Same
316
+ * shape as {@link ChangeEvent}; `nativeEvent` is the X key event.
317
+ */
318
+ export interface SubmitEvent<T = TextInputNode> extends Omit<
319
+ ChangeEvent<T>,
320
+ 'type'
321
+ > {
322
+ type: 'submit';
323
+ }
324
+
325
+ /** `<box onScroll>` — a scrolling box or window moved. */
326
+ export interface ScrollEvent {
327
+ scrollX: number;
328
+ scrollY: number;
329
+ contentWidth: number;
330
+ contentHeight: number;
331
+ viewportWidth: number;
332
+ viewportHeight: number;
333
+ }
334
+
335
+ /** `<box onViewport>` — fired from layout, not from scrolling. */
336
+ export interface ViewportEvent {
337
+ width: number;
338
+ height: number;
339
+ contentWidth: number;
340
+ contentHeight: number;
341
+ }
342
+
343
+ /** Handlers every drawn element and `<window>` accepts. */
344
+ export interface PointerHandlers<T = DrawnNode> {
345
+ onClick?: (ev: MouseEvent<T>) => void;
346
+ onClickCapture?: (ev: MouseEvent<T>) => void;
347
+ onMouseDown?: (ev: MouseEvent<T>) => void;
348
+ onMouseDownCapture?: (ev: MouseEvent<T>) => void;
349
+ onMouseUp?: (ev: MouseEvent<T>) => void;
350
+ onMouseUpCapture?: (ev: MouseEvent<T>) => void;
351
+ onMouseMove?: (ev: MouseEvent<T>) => void;
352
+ onMouseMoveCapture?: (ev: MouseEvent<T>) => void;
353
+ /** Does not propagate — synthesized by hover-path diffing. */
354
+ onMouseEnter?: (ev: MouseEvent<T>) => void;
355
+ onMouseLeave?: (ev: MouseEvent<T>) => void;
356
+ /**
357
+ * **Provisional — the `unstable_` prefix is the contract.** A prototype for
358
+ * ntk#37, kept out of `docs/` on purpose: the shape may change or be
359
+ * withdrawn, and dropping the prefix is what would say it had settled.
360
+ *
361
+ * The pointer is heading for this node and has not arrived. For starting
362
+ * work early — warming a cache, decoding an image, sending the query whose
363
+ * answer the click will want.
364
+ *
365
+ * Fires on arrival of attention only. There is no matching "lost" event:
366
+ * work started on a hint does not want undoing because the pointer changed
367
+ * its mind, and anything *visual* belongs in an `:attention` style block,
368
+ * which is cleared automatically. Declaring either one registers the node
369
+ * as a candidate; a tree that declares neither costs nothing per motion
370
+ * event.
371
+ *
372
+ * Does not propagate, and unlike `onMouseEnter` it is not the hover path
373
+ * either — see `AttentionEvent`.
374
+ */
375
+ unstable_onAttention?: (ev: AttentionEvent<T>) => void;
376
+ onWheel?: (ev: WheelEvent<T>) => void;
377
+ onWheelCapture?: (ev: WheelEvent<T>) => void;
378
+ /**
379
+ * Right-click (button 3), dispatched after `onMouseDown` — so suppressing
380
+ * the menu does not also give up whatever mousedown did. `preventDefault()`
381
+ * skips the element's own menu, which today means the edit menu on
382
+ * `<textinput>` and `<textarea>`.
383
+ */
384
+ onContextMenu?: (ev: MouseEvent<T>) => void;
385
+ onContextMenuCapture?: (ev: MouseEvent<T>) => void;
386
+ }
387
+
388
+ export interface KeyboardHandlers<T = DrawnNode> {
389
+ onKeyDown?: (ev: KeyboardEvent<T>) => void;
390
+ onKeyDownCapture?: (ev: KeyboardEvent<T>) => void;
391
+ onKeyUp?: (ev: KeyboardEvent<T>) => void;
392
+ onKeyUpCapture?: (ev: KeyboardEvent<T>) => void;
393
+ /**
394
+ * A composition opened — a dead key was pressed, or the Compose key was.
395
+ * `preventDefault()` on any of the three stops the element acting on it,
396
+ * which for `<textinput>` means showing or committing the text.
397
+ */
398
+ onCompositionStart?: (ev: CompositionEvent<T>) => void;
399
+ onCompositionStartCapture?: (ev: CompositionEvent<T>) => void;
400
+ /** The composition changed: `data` is what is showing at the caret. */
401
+ onCompositionUpdate?: (ev: CompositionEvent<T>) => void;
402
+ onCompositionUpdateCapture?: (ev: CompositionEvent<T>) => void;
403
+ /** The composition finished: `data` is the text it produced, empty if it
404
+ * was abandoned. */
405
+ onCompositionEnd?: (ev: CompositionEvent<T>) => void;
406
+ onCompositionEndCapture?: (ev: CompositionEvent<T>) => void;
407
+ }
408
+
409
+ export interface FocusHandlers<T = DrawnNode> {
410
+ onFocus?: (ev: FocusEvent<T>) => void;
411
+ onBlur?: (ev: FocusEvent<T>) => void;
412
+ }
413
+
414
+ export interface EventHandlers<T = DrawnNode>
415
+ extends
416
+ PointerHandlers<T>,
417
+ KeyboardHandlers<T>,
418
+ FocusHandlers<T>,
419
+ DropTargetProps<T>,
420
+ DragSourceProps<T> {}
421
+
422
+ /**
423
+ * `<window onResize>`: X's ConfigureNotify, handed over as ntk's own event
424
+ * object rather than a synthetic one — there is no capture/bubble phase and
425
+ * nothing to `preventDefault`, because the window manager has already done
426
+ * the thing being reported.
427
+ *
428
+ * It fires for **moves and reparents** as much as for size changes; see
429
+ * docs/elements.md. `x`/`y` are relative to whatever the window's parent is,
430
+ * which is the window manager's frame once it has framed the window — not
431
+ * screen coordinates.
432
+ */
433
+ export interface WindowResizeEvent {
434
+ /** X event type number (22, ConfigureNotify). */
435
+ type: number;
436
+ x: number;
437
+ y: number;
438
+ width: number;
439
+ height: number;
440
+ /** The size differs from the last delivered event's. */
441
+ resized: boolean;
442
+ /** The position does. */
443
+ moved: boolean;
444
+ /**
445
+ * The geometry `moved`/`resized` are measured against, or null when none
446
+ * is known yet.
447
+ */
448
+ previous: { x: number; y: number; width: number; height: number } | null;
449
+ /** Every raw event merged into this one, oldest first. */
450
+ coalesced?: WindowResizeEvent[];
451
+ window: NtkWindow;
452
+ target: NtkWindow;
453
+ }
454
+
455
+ /**
456
+ * `<window onClientMessage>`: a ClientMessage addressed to this window —
457
+ * EWMH, XEmbed, the system tray, or a convention two copies of one
458
+ * application agreed between themselves.
459
+ *
460
+ * Not a synthetic event: a ClientMessage is addressed to a *window*, so
461
+ * there is no node under it, nothing to hit test and no chain to bubble
462
+ * along. Delivered in arrival order, which the chunked protocols depend on.
463
+ */
464
+ export interface ClientMessageEvent {
465
+ /** X event type number (33, ClientMessage). */
466
+ type: number;
467
+ /**
468
+ * The message type atom's **name** — `'_NET_SYSTEM_TRAY_OPCODE'`,
469
+ * `'_XEMBED'`, `'WM_PROTOCOLS'` — which is what a handler branches on.
470
+ *
471
+ * `null` for an atom this connection has never named. An application
472
+ * acting on a protocol has interned its atoms already, so that is the
473
+ * passive-observer case rather than a coin flip; {@link atom} is exact
474
+ * either way.
475
+ */
476
+ messageType: string | null;
477
+ /** The message type atom id, as it arrived. */
478
+ atom: number;
479
+ /** How wide the 20 payload bytes are read. */
480
+ format: 8 | 16 | 32;
481
+ /** 5 values at format 32, 10 at 16, 20 at 8. */
482
+ data: number[];
483
+ /** The window it was delivered to. */
484
+ window: NtkWindow;
485
+ target: NtkWindow;
486
+ /** ntk's raw event. */
487
+ nativeEvent: unknown;
488
+ defaultPrevented: boolean;
489
+ /**
490
+ * Stop react-x11 acting on this message itself — which today means XDND,
491
+ * for a window answering the drag protocol on its own terms. It does not
492
+ * reach the WM close button; `onCloseRequest` is that seam.
493
+ */
494
+ preventDefault(): void;
495
+ }
496
+
497
+ // --------------------------------------------------------------------------
498
+ // Accelerators
499
+ // --------------------------------------------------------------------------
500
+
501
+ export interface AcceleratorOptions {
502
+ /** `false` unbinds the chord without unmounting anything. Defaults true. */
503
+ enabled?: boolean;
504
+ /**
505
+ * The node the binding hangs off, deciding what it is hidden with and what
506
+ * a modal `<popup>` takes it away from. Defaults to the window the
507
+ * component is in, which is what an application-wide shortcut wants; pass
508
+ * a node inside a modal `<Dialog>` to give the dialog a shortcut of its
509
+ * own.
510
+ */
511
+ scope?: RefObject<DrawnNode | null>;
512
+ }
513
+
514
+ /**
515
+ * A shortcut that is not in a menu, on the same chord vocabulary a menu
516
+ * item's `shortcut` uses — so one can be moved into or out of a menu
517
+ * without being rewritten.
518
+ *
519
+ * ```tsx
520
+ * useAccelerator([['Control', 'K']], () => openPalette());
521
+ * ```
522
+ *
523
+ * Exact on Control/Alt/Shift/Super, indifferent to Caps Lock and Num Lock,
524
+ * matched against the Latin keysym so a layout switch does not turn it off,
525
+ * and behind whatever a focused element consumed with `preventDefault()`.
526
+ * See docs/events.md.
527
+ */
528
+ export function useAccelerator(
529
+ shortcut: MenuShortcut,
530
+ handler: (ev: KeyboardEvent) => void,
531
+ options?: AcceleratorOptions,
532
+ ): void;
533
+
534
+ /**
535
+ * Whether a key event presses any alternative of a `shortcut` — the matcher
536
+ * the menus and {@link useAccelerator} both run on, for an application
537
+ * dispatching chords its own way.
538
+ */
539
+ export function matchesShortcut(
540
+ ev: {
541
+ keysym?: number | null;
542
+ codepoint?: number | null;
543
+ ctrlKey?: boolean;
544
+ altKey?: boolean;
545
+ shiftKey?: boolean;
546
+ metaKey?: boolean;
547
+ },
548
+ shortcut: MenuShortcut | undefined,
549
+ ): boolean;