react-x11 2.1.1 → 2.1.2

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 (2) hide show
  1. package/package.json +1 -1
  2. package/src/nodes.js +30 -9
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-x11",
3
- "version": "2.1.1",
3
+ "version": "2.1.2",
4
4
  "description": "react renderer with X11 as a target",
5
5
  "main": "./src/index.js",
6
6
  "files": [
package/src/nodes.js CHANGED
@@ -2244,8 +2244,19 @@ export class Node {
2244
2244
  }
2245
2245
 
2246
2246
  /** The theme above or on this node changed: drop the caches and restyle
2247
- * the subtree, since a token can appear at any depth. */
2248
- _themeChanged() {
2247
+ * the subtree, since a token can appear at any depth.
2248
+ *
2249
+ * `mounting` is `insertBefore` attaching a subtree that has never been in
2250
+ * the tree: the walk still resolves every token — the nodes can see their
2251
+ * ancestors now — but it claims no damage (issue #402). A node that has
2252
+ * never painted has no stale pixels to cover, and the rect it is about to
2253
+ * occupy is claimed by the child-list/layout-diff protocol like any other
2254
+ * inserted child's; the unbounded claims below would turn every commit
2255
+ * that mounts a token-styled node into a full-window repaint — which is
2256
+ * every re-slice of a virtualized list whose rows follow the palette. A
2257
+ * live theme *swap* is the other caller and keeps them: it moves pixels
2258
+ * that are already on screen, anywhere in the subtree. */
2259
+ _themeChanged(mounting = false) {
2249
2260
  // This walk visits every node itself, so the per-node re-resolution below
2250
2261
  // is enough — a style swap it causes must not start a second walk of the
2251
2262
  // same subtree from halfway down.
@@ -2269,19 +2280,23 @@ export class Node {
2269
2280
  if (localTextStyleChanged(this.style, before)) {
2270
2281
  this._textContentChanged();
2271
2282
  }
2272
- this.root?.invalidate(true, null, 'theme');
2283
+ if (!mounting) this.root?.invalidate(true, null, 'theme');
2273
2284
  }
2274
2285
  // The palette is the floor under the cascade, so a theme swap moves the
2275
2286
  // resolved style of every node that named none of its own — and none of
2276
2287
  // that is in a style object, so nothing above would have noticed. A
2277
2288
  // swap that only changes `fontFamily` is the case that made this worth
2278
2289
  // having: nothing else about the node changes, and a cached layout
2279
- // carries the face it was shaped with.
2280
- if (this._retext() !== 0) this.root?.invalidate(true, null, 'theme');
2290
+ // carries the face it was shaped with. `_retext` runs on a mount too —
2291
+ // its own claims are bounded — but cannot answer non-zero there: a
2292
+ // node that was never attached has never resolved a text style.
2293
+ if (this._retext() !== 0 && !mounting) {
2294
+ this.root?.invalidate(true, null, 'theme');
2295
+ }
2281
2296
  if (wasDirection !== undefined && this.direction !== wasDirection) {
2282
2297
  this._directionMoved();
2283
2298
  }
2284
- for (const child of this.children) child._themeChanged();
2299
+ for (const child of this.children) child._themeChanged(mounting);
2285
2300
  } finally {
2286
2301
  inThemeWalk--;
2287
2302
  }
@@ -2447,9 +2462,10 @@ export class Node {
2447
2462
  // popups live anywhere in the JSX tree but are independent
2448
2463
  // override-redirect windows: bookkeeping only, no yoga, no paint —
2449
2464
  // but they do inherit the theme of where they are written
2465
+ const mounting = child.parent == null;
2450
2466
  this._spliceChild(child, beforeChild);
2451
2467
  child.parent = this;
2452
- if (this.theme || child.props.theme) child._themeChanged();
2468
+ if (this.theme || child.props.theme) child._themeChanged(mounting);
2453
2469
  a11yHooks.attached?.(this, child);
2454
2470
  return;
2455
2471
  }
@@ -2495,6 +2511,10 @@ export class Node {
2495
2511
  if (child.parent === this && this._joinsYoga(child)) {
2496
2512
  this.yoga.removeChild(child.yoga);
2497
2513
  }
2514
+ // no parent means never attached: this insert is a mount, and the theme
2515
+ // walk resolves without claiming — a keyed reorder arrives here too, with
2516
+ // its parent still set, and that one keeps the claims (issue #402)
2517
+ const mounting = child.parent == null;
2498
2518
  const index = this._spliceChild(child, beforeChild);
2499
2519
  child.parent = this;
2500
2520
  if (this._joinsYoga(child)) {
@@ -2504,7 +2524,7 @@ export class Node {
2504
2524
  child._registerSizeQueries();
2505
2525
  // it can see its ancestors now, so any token in its style can resolve.
2506
2526
  // With no theme anywhere there is nothing to resolve and nothing to walk
2507
- if (this.theme || child.props.theme) child._themeChanged();
2527
+ if (this.theme || child.props.theme) child._themeChanged(mounting);
2508
2528
  this._textContentChanged();
2509
2529
  this._childListChanged(before);
2510
2530
  a11yHooks.attached?.(this, child);
@@ -9743,6 +9763,7 @@ export class WindowNode extends Scrollable(Node) {
9743
9763
  return;
9744
9764
  }
9745
9765
  if (child.isWindow) {
9766
+ const mounting = child.parent == null;
9746
9767
  this._spliceChild(child, beforeChild);
9747
9768
  child.parent = this;
9748
9769
  // Initial children are realized when this window realizes; a child
@@ -9754,7 +9775,7 @@ export class WindowNode extends Scrollable(Node) {
9754
9775
  child.realize(this.window);
9755
9776
  if (child.window) this._xStack.push(child.window.id);
9756
9777
  }
9757
- if (this.theme || child.props.theme) child._themeChanged();
9778
+ if (this.theme || child.props.theme) child._themeChanged(mounting);
9758
9779
  // React reorders a keyed list with one insertBefore per moved child;
9759
9780
  // restacking once at the end of the commit skips the intermediate
9760
9781
  // orders, which nobody ever sees.