react-x11 2.11.0 → 2.13.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 (100) hide show
  1. package/README.md +278 -129
  2. package/package.json +12 -4
  3. package/src/Reconciler.js +19 -31
  4. package/src/a11y.js +2 -2
  5. package/src/anchor.js +7 -5
  6. package/src/appcontext.js +59 -30
  7. package/src/bootstrap.js +14 -0
  8. package/src/clientmessage.js +1 -1
  9. package/src/cocoa/app.js +303 -49
  10. package/src/cocoa/bezels.js +175 -30
  11. package/src/cocoa/dnd.js +27 -13
  12. package/src/cocoa/fonts.js +3 -3
  13. package/src/cocoa/glarea.js +24 -5
  14. package/src/cocoa/main.d.ts +8 -0
  15. package/src/cocoa/main.js +43 -0
  16. package/src/cocoa/overlay.js +159 -0
  17. package/src/cocoa/panehost.js +15 -5
  18. package/src/cocoa/presenter.js +13 -9
  19. package/src/cocoa/promotion.js +17 -7
  20. package/src/cocoa/relaunch.js +207 -0
  21. package/src/cocoa/threaded.js +246 -0
  22. package/src/cocoa/window.js +256 -42
  23. package/src/components/Select.js +2 -2
  24. package/src/components/anchor.js +3 -3
  25. package/src/components/native.js +12 -7
  26. package/src/components/theme.js +2 -2
  27. package/src/debug.js +1 -1
  28. package/src/decorations.js +1 -1
  29. package/src/editmenu.js +2 -2
  30. package/src/embedding.js +31 -0
  31. package/src/errors.js +46 -0
  32. package/src/events.js +78 -18
  33. package/src/foreignnodes.js +59 -5
  34. package/src/frames.js +2 -2
  35. package/src/glnodes.js +172 -41
  36. package/src/gloverlay.js +383 -0
  37. package/src/grid.js +1653 -0
  38. package/src/host.d.ts +230 -1
  39. package/src/host.js +11 -3
  40. package/src/imagesource.js +1 -1
  41. package/src/index.d.ts +34 -4
  42. package/src/index.js +9 -1
  43. package/src/layouts.js +721 -0
  44. package/src/node.d.ts +16 -3
  45. package/src/node.js +19 -21
  46. package/src/nodes/animation.js +644 -0
  47. package/src/nodes/box.js +21 -0
  48. package/src/nodes/boxpaint.js +473 -0
  49. package/src/nodes/canvas.js +269 -0
  50. package/src/nodes/cascade.js +600 -0
  51. package/src/nodes/damage.js +183 -0
  52. package/src/nodes/edithistory.js +124 -0
  53. package/src/nodes/editmenupopup.js +260 -0
  54. package/src/nodes/hittest.js +185 -0
  55. package/src/nodes/image.js +266 -0
  56. package/src/nodes/install.js +75 -0
  57. package/src/nodes/invalidate.js +465 -0
  58. package/src/nodes/kinds.js +31 -0
  59. package/src/nodes/layout.js +439 -0
  60. package/src/nodes/layouthost.js +949 -0
  61. package/src/nodes/node.js +868 -0
  62. package/src/nodes/paint.js +466 -0
  63. package/src/nodes/position.js +366 -0
  64. package/src/nodes/preedit.js +127 -0
  65. package/src/nodes/queries.js +330 -0
  66. package/src/nodes/rects.js +102 -0
  67. package/src/nodes/scrollable.js +891 -0
  68. package/src/nodes/scrollbars.js +138 -0
  69. package/src/nodes/scrollblit.js +1034 -0
  70. package/src/nodes/selectable.js +142 -0
  71. package/src/nodes/styling.js +225 -0
  72. package/src/nodes/text.js +649 -0
  73. package/src/nodes/textarea.js +391 -0
  74. package/src/nodes/textinput.js +1146 -0
  75. package/src/nodes/util.js +17 -0
  76. package/src/nodes/window/anchoring.js +161 -0
  77. package/src/nodes/window/capabilities.js +190 -0
  78. package/src/nodes/window/debugpaint.js +83 -0
  79. package/src/nodes/window/droptarget.js +145 -0
  80. package/src/nodes/window/floors.js +577 -0
  81. package/src/nodes/window/flush.js +369 -0
  82. package/src/nodes/window/hints.js +482 -0
  83. package/src/nodes/window/listeners.js +222 -0
  84. package/src/nodes/window/popup.js +71 -0
  85. package/src/nodes/window/size.js +591 -0
  86. package/src/nodes/window/window.js +954 -0
  87. package/src/palette.js +1 -1
  88. package/src/registry.js +7 -3
  89. package/src/styles.js +137 -15
  90. package/src/svgnodes.js +2 -1
  91. package/src/testing/harness.js +2 -2
  92. package/src/textselection.js +5 -3
  93. package/src/trace-registry.js +1 -1
  94. package/src/types/components.d.ts +38 -6
  95. package/src/types/elements.d.ts +26 -14
  96. package/src/types/nodes.d.ts +17 -2
  97. package/src/types/style.d.ts +94 -3
  98. package/src/windowstate.js +1 -1
  99. package/src/yoga.js +1 -1
  100. package/src/nodes.js +0 -13120
package/src/host.d.ts CHANGED
@@ -21,7 +21,6 @@ import type { NtkApp } from './types/nodes.js';
21
21
  export interface HostContext {
22
22
  isInsideText: boolean;
23
23
  isInsideSvg: boolean;
24
- isInside3d: boolean;
25
24
  }
26
25
 
27
26
  export interface ElementDefinition {
@@ -86,3 +85,233 @@ export function knownElements(): string[];
86
85
 
87
86
  /** Kinds that lay out with yoga and paint into the owning window (a copy). */
88
87
  export function drawnKinds(): string[];
88
+
89
+ // --- layouts and positions (docs/extending.md) ------------------------------
90
+
91
+ /**
92
+ * What an option of a layout or a position may be. A `'length'` is written
93
+ * in logical pixels, like every length in a style, and handed to the
94
+ * algorithm in device pixels. An array is the values the option may take.
95
+ */
96
+ export type OptionType =
97
+ | 'length'
98
+ | 'number'
99
+ | 'integer'
100
+ | 'boolean'
101
+ | 'string'
102
+ | 'any'
103
+ | readonly (string | number | boolean)[];
104
+
105
+ export interface OptionSpec {
106
+ type: OptionType;
107
+ default?: unknown;
108
+ }
109
+
110
+ /** The options a layout or a position takes, by name. */
111
+ export type OptionSchema = Record<string, OptionSpec>;
112
+
113
+ export type MeasureMode = 'exactly' | 'at-most' | 'unconstrained';
114
+
115
+ /** The room on offer, in the vocabulary `measureContent` speaks: device
116
+ * pixels, and `Infinity` on an axis with no bound. */
117
+ export interface LayoutConstraints {
118
+ width: number;
119
+ height: number;
120
+ widthMode: MeasureMode;
121
+ heightMode: MeasureMode;
122
+ }
123
+
124
+ /**
125
+ * A child, as a layout algorithm sees it: something to measure and read
126
+ * options off, never a node. Every size is the child's **margin box**, in
127
+ * device pixels.
128
+ */
129
+ export interface LayoutChild {
130
+ /** Where it is in the list the algorithm was handed. */
131
+ readonly index: number;
132
+ /** Its `layoutItem`, against the layout's `childOptions`: defaults filled
133
+ * in, lengths in device pixels. */
134
+ readonly options: Readonly<Record<string, any>>;
135
+ /**
136
+ * The size it takes under `constraints`. An axis given a number and no
137
+ * mode is `'exactly'` that; an axis left out is `'unconstrained'`;
138
+ * `'at-most'` is CSS's fit-content, never below its content floor.
139
+ */
140
+ measure(constraints?: Partial<LayoutConstraints>): {
141
+ width: number;
142
+ height: number;
143
+ };
144
+ /** The narrowest it can be drawn at — its content floor — and the width
145
+ * it would take with no bound at all. */
146
+ intrinsicSizes(): { minContentWidth: number; maxContentWidth: number };
147
+ /** Its own resolved style, in device pixels — what a grid places it by
148
+ * (`gridColumn`, `gridArea`) and aligns it with (`alignSelf`,
149
+ * `justifySelf`). */
150
+ readonly style: Readonly<import('./types/style.js').StyleProperties>;
151
+ }
152
+
153
+ /** Where one child goes, from the content box's corner. A `width` or
154
+ * `height` left out is the child's own. */
155
+ export interface LayoutRect {
156
+ x: number;
157
+ y: number;
158
+ width?: number;
159
+ height?: number;
160
+ }
161
+
162
+ export interface LayoutResult {
163
+ /** The content box's size, device pixels. */
164
+ width: number;
165
+ height: number;
166
+ /** One rect per child — required of the call that places, the one with
167
+ * both modes `'exactly'`. */
168
+ children?: readonly LayoutRect[];
169
+ }
170
+
171
+ export interface LayoutInfo {
172
+ /** The box's own resolved style — `gap`, `justifyContent`, `alignItems`
173
+ * — in device pixels. */
174
+ style: Readonly<import('./types/style.js').StyleProperties>;
175
+ scale: number;
176
+ /**
177
+ * Say that something in the style is wrong but can be laid out around —
178
+ * a grid area nobody named — the way a bad style value is said: once,
179
+ * on the console and to the test harness. `consequence` is what happens
180
+ * instead. A throw is for what cannot be laid out at all.
181
+ */
182
+ report(message: string, consequence: string): void;
183
+ }
184
+
185
+ export interface LayoutDefinition {
186
+ options?: OptionSchema;
187
+ /** What a child's `layoutItem` may say to this layout. */
188
+ childOptions?: OptionSchema;
189
+ /**
190
+ * How big the box's content is for `constraints` — asked several times
191
+ * per pass, so a pure function of its arguments — and, when both modes
192
+ * are `'exactly'`, where each child goes.
193
+ */
194
+ layout(
195
+ children: readonly LayoutChild[],
196
+ constraints: LayoutConstraints,
197
+ options: Readonly<Record<string, any>>,
198
+ info: LayoutInfo,
199
+ ): LayoutResult;
200
+ /** Replace an existing registration. Off by default. */
201
+ override?: boolean;
202
+ }
203
+
204
+ /** Teach react-x11 a layout algorithm, for `style={{ layout: name }}`
205
+ * (docs/extending.md, "A layout algorithm of your own"). */
206
+ export function registerLayout(
207
+ name: string,
208
+ definition: LayoutDefinition,
209
+ ): void;
210
+
211
+ /** Undo a registration; true if there was one. The built-in layouts stay. */
212
+ export function unregisterLayout(name: string): boolean;
213
+
214
+ /** Registered layout names, the built-in ones first. */
215
+ export function registeredLayouts(): string[];
216
+
217
+ export interface Edges {
218
+ left: number;
219
+ top: number;
220
+ right: number;
221
+ bottom: number;
222
+ }
223
+
224
+ /** What a position's `place` is handed: window coordinates, device
225
+ * pixels, the space `abs` is in. */
226
+ export interface PositionContext {
227
+ /** Where layout put the node, before any placement moved it. */
228
+ laidOut: { x: number; y: number; width: number; height: number };
229
+ /** The nearest scroll pane above the node — its scrollport is inside its
230
+ * border and over its padding — or null when nothing above scrolls. */
231
+ pane: { scrollport: Edges; scrollX: number; scrollY: number } | null;
232
+ /** The box it is contained by: its parent's content box, or the whole
233
+ * scrolled content for a direct child of the pane. */
234
+ container: Edges;
235
+ margin: Edges;
236
+ direction: 'ltr' | 'rtl';
237
+ scale: number;
238
+ /** The frame clock, in ms. */
239
+ now: number;
240
+ options: Readonly<Record<string, any>>;
241
+ }
242
+
243
+ export interface PositionDefinition {
244
+ options?: OptionSchema;
245
+ /**
246
+ * How far to move the node from where layout put it, or null for not at
247
+ * all. `again: true` asks for another frame, for a position that
248
+ * animates. Runs after every layout pass; resizes nothing.
249
+ */
250
+ place(
251
+ node: Node,
252
+ context: PositionContext,
253
+ ): { x: number; y: number; again?: boolean } | null;
254
+ /** Replace an existing registration. Off by default. */
255
+ override?: boolean;
256
+ }
257
+
258
+ /** Teach react-x11 a positioning scheme, for `style={{ position: name }}`
259
+ * (docs/extending.md, "A position of your own"). CSS's own names —
260
+ * `static`, `relative`, `absolute`, `fixed`, `sticky` — are not available. */
261
+ export function registerPosition(
262
+ name: string,
263
+ definition: PositionDefinition,
264
+ ): void;
265
+
266
+ /** Undo a registration; true if there was one. */
267
+ export function unregisterPosition(name: string): boolean;
268
+
269
+ /** Registered position names, in registration order. */
270
+ export function registeredPositions(): string[];
271
+
272
+ /**
273
+ * The layouts a style can name, each with the options it takes. Augment it
274
+ * to add yours:
275
+ *
276
+ * ```ts
277
+ * declare module 'react-x11/host' {
278
+ * interface CustomLayouts {
279
+ * radial: { radius?: number };
280
+ * }
281
+ * }
282
+ * ```
283
+ */
284
+ export interface CustomLayouts {
285
+ masonry: { columns?: number; columnWidth?: number };
286
+ 'equal-row': Record<never, never>;
287
+ /** CSS grid — `layout: 'grid'` is `display: 'grid'`. It takes no options:
288
+ * its tracks are the box's own style, `gridTemplateColumns` and the rest. */
289
+ grid: Record<never, never>;
290
+ }
291
+
292
+ /** What a child's `layoutItem` may tell the layout arranging it — augmented
293
+ * the same way. */
294
+ export interface CustomLayoutItem {
295
+ /** `masonry`: how many columns the child is laid across. */
296
+ span?: number;
297
+ }
298
+
299
+ /** The registered positions a style can name, each with its options —
300
+ * augmented the same way as `CustomLayouts`. */
301
+ // eslint-disable-next-line @typescript-eslint/no-empty-object-type
302
+ export interface CustomPositions {}
303
+
304
+ /** A layout, by name or written with its options. */
305
+ export type LayoutValue = {
306
+ [K in keyof CustomLayouts]: K | ({ name: K } & CustomLayouts[K]);
307
+ }[keyof CustomLayouts];
308
+
309
+ /** CSS's positions, and the registered ones by name or with their options. */
310
+ export type PositionValue =
311
+ | 'static'
312
+ | 'relative'
313
+ | 'absolute'
314
+ | 'sticky'
315
+ | {
316
+ [K in keyof CustomPositions]: K | ({ name: K } & CustomPositions[K]);
317
+ }[keyof CustomPositions];
package/src/host.js CHANGED
@@ -1,13 +1,21 @@
1
1
  // `react-x11/host` — the seam a package that is not react-x11 uses to add
2
- // a host element. See docs/extending.md for the node contract; this file is
3
- // only the entry point.
2
+ // a host element, a layout algorithm or a positioning scheme. See
3
+ // docs/extending.md for the contracts; this file is only the entry point.
4
4
  export {
5
5
  registerElement,
6
6
  unregisterElement,
7
7
  registeredElements,
8
8
  } from './registry.js';
9
+ export {
10
+ registerLayout,
11
+ unregisterLayout,
12
+ registeredLayouts,
13
+ registerPosition,
14
+ unregisterPosition,
15
+ registeredPositions,
16
+ } from './layouts.js';
9
17
 
10
- import { DRAWN_KINDS as DRAWN } from './nodes.js';
18
+ import { DRAWN_KINDS as DRAWN } from './nodes/kinds.js';
11
19
  import { registeredElements } from './registry.js';
12
20
 
13
21
  const BUILT_IN = Object.freeze([
@@ -4,7 +4,7 @@
4
4
  //
5
5
  // The split follows `decorations.js`: classification, validation, decoding
6
6
  // and the `cacheKey` cache live here, where a test needs no server; the node
7
- // half in nodes.js is only lifecycle — when to resolve, when to claim
7
+ // half in nodes/image.js is only lifecycle — when to resolve, when to claim
8
8
  // damage, when to let go.
9
9
  import { Image, Picture, decodeImage } from 'ntk';
10
10
 
package/src/index.d.ts CHANGED
@@ -76,7 +76,10 @@ export type TransferType = 'text' | 'files' | 'uris' | (string & {});
76
76
 
77
77
  export interface ClipboardOptions {
78
78
  /** Selection atom name; `'CLIPBOARD'` by default, `'PRIMARY'` for the
79
- * middle-click buffer. Any name works. */
79
+ * middle-click buffer. Any name works on X11. On the Cocoa backend only
80
+ * `'CLIPBOARD'` is the pasteboard: every other name is a selection nobody
81
+ * can paste from — writes resolve and change nothing, reads find it
82
+ * empty. */
80
83
  selection?: string;
81
84
  /** ms to wait for the owner at each protocol step. */
82
85
  timeout?: number;
@@ -154,8 +157,27 @@ export function useClipboard(): Clipboard;
154
157
  * policy it is false whatever the machine could do, because the indirect
155
158
  * backend is what draws. `app.glCapabilities()` is the machine's answer, and
156
159
  * says why.
160
+ *
161
+ * `'nativeControls'` is whether this backend renders the platform's own
162
+ * control bezels — the Cocoa backend, never X11. The widget set already
163
+ * branches on it through the theme's `controls: 'auto'` policy; this is for
164
+ * application code composing its own controls to sit beside native ones. It
165
+ * is a property of the backend and never changes over the app's life.
166
+ *
167
+ * `'embedding'` is whether this connection can take another process's window
168
+ * into its own — X11, never Cocoa or the headless mock. Ask it before
169
+ * rendering a `<foreign>`, which refuses with one `onError` where it is
170
+ * false. Also a property of the backend, and it never changes either.
171
+ *
172
+ * `'glOverlay'` is whether the children of a `<glarea>` are drawn above its
173
+ * GL surface — laid out in its box, painted on panes stacked over it, hit
174
+ * before it. Both backends draw them; translucency is the difference,
175
+ * composited by Core Animation on Cocoa and opaque on X11, where what a
176
+ * child leaves unpainted shows the surface's `clearColor` (docs/elements.md).
177
+ * Ask it before handing a surface its HUD. A property of the backend.
157
178
  */
158
- export type SupportsFeature = 'transparency' | 'shaders';
179
+ export type SupportsFeature =
180
+ 'transparency' | 'shaders' | 'nativeControls' | 'embedding' | 'glOverlay';
159
181
 
160
182
  /**
161
183
  * Can this **display** do something? `'transparency'` is true when the
@@ -206,11 +228,18 @@ export interface RootOptions {
206
228
  * as the bridge reports it, 16 where the OS cannot say. A number here
207
229
  * applies to every window instead. `pumpInterval` is the AppKit event
208
230
  * pump's cadence, in ms (8 by default), which is the floor under input
209
- * latency. `appName` is what the Dock, ⌘-Tab and the app menu print for
231
+ * latency; an app started under `react-x11/cocoa-main` has no pump.
232
+ * `resizeWait` is how long, in ms, AppKit may hold a live-resize tick for
233
+ * the app's frame at the new size under `react-x11/cocoa-main`, where
234
+ * the frame is painted on another thread (50 by default; 0 lets the edge
235
+ * move without waiting). `appName` is what the Dock, ⌘-Tab and the app menu print for
210
236
  * an unbundled process (a bundle's Info.plist wins); `activationPolicy`
211
237
  * is `'regular'` (a Dock tile, a ⌘-Tab entry — the default),
212
238
  * `'accessory'` (a menu-bar app: windows but no tile) or `'prohibited'`,
213
- * fixed before the app finishes launching. `exitOnQuit` (default `true`)
239
+ * fixed before the app finishes launching under `react-x11/cocoa-main`
240
+ * the app launches before its code runs, so there the launch policy is
241
+ * `APPKIT_ACTIVATION_POLICY`'s, and this one a switch once the code
242
+ * runs. `exitOnQuit` (default `true`)
214
243
  * ends the process once a quit request — the Dock's Quit, ⌘Q, a logout —
215
244
  * has closed the app: the request routes through the primary window's
216
245
  * close request first, so `onCloseRequest` there is where an app
@@ -222,6 +251,7 @@ export interface RootOptions {
222
251
  promote?: boolean;
223
252
  frameInterval?: number;
224
253
  pumpInterval?: number;
254
+ resizeWait?: number;
225
255
  appName?: string;
226
256
  activationPolicy?: 'regular' | 'accessory' | 'prohibited';
227
257
  exitOnQuit?: boolean;
package/src/index.js CHANGED
@@ -1,3 +1,7 @@
1
+ // First, before anything else in the package: on macOS it moves the app
2
+ // onto a worker before the app's own code runs (src/bootstrap.js).
3
+ import './bootstrap.js';
4
+
1
5
  export { createRoot, Renderer } from './Reconciler.js';
2
6
  export { createStyles, flattenStyle } from './styles.js';
3
7
  export { windowIdOf, useWindowId, useTopLevelWindow } from './windowid.js';
@@ -42,7 +46,11 @@ export { BusUnavailableError, closeBus, sessionBus, systemBus } from './bus.js';
42
46
  export { announce } from './a11y.js';
43
47
  // the standard Undo/Cut/Copy/Paste menu, for an element that edits or
44
48
  // selects text of its own — `<textinput>`'s own menu is a caller of it
45
- export { closeEditMenu, editMenuOpen, openEditMenu } from './nodes.js';
49
+ export {
50
+ closeEditMenu,
51
+ editMenuOpen,
52
+ openEditMenu,
53
+ } from './nodes/editmenupopup.js';
46
54
  export { useSessionBus, useSystemBus } from './bushooks.js';
47
55
  export { REGISTRAR_NAME, useGlobalMenu } from './globalmenu.js';
48
56
  export {