gesso-framework 0.8.0 → 0.8.1

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.
@@ -1,5 +1,5 @@
1
1
  import { B as ServedChannel } from "../tools-Bl8LZ7LR.js";
2
- import { Dt as AppLogicEndpoint } from "../index-DocVauCS.js";
2
+ import { Dt as AppLogicEndpoint } from "../index-C08h2Jze.js";
3
3
  //#region src/remote/frames.d.ts
4
4
  /**
5
5
  * The whole wire format, which is deliberately smaller than the
@@ -1465,6 +1465,8 @@ var ShellService = class {
1465
1465
  handler = null;
1466
1466
  /** What `warnOnLeave` last said. */
1467
1467
  leaving = false;
1468
+ /** What `preferColorScheme` last asked for; null until it is asked. */
1469
+ preferred = null;
1468
1470
  scheme = internalState("light");
1469
1471
  contrastState = internalState("standard");
1470
1472
  pointerState = internalState("fine");
@@ -1582,6 +1584,10 @@ var ShellService = class {
1582
1584
  type: "leaveWarning",
1583
1585
  on: true
1584
1586
  });
1587
+ if (handler !== null && this.preferred !== null) handler({
1588
+ type: "colorScheme",
1589
+ preference: this.preferred
1590
+ });
1585
1591
  }
1586
1592
  /**
1587
1593
  * Called by the runtime when the shell reports the appearance.
@@ -1798,6 +1804,33 @@ var ShellService = class {
1798
1804
  on
1799
1805
  });
1800
1806
  }
1807
+ /**
1808
+ * Asks the shell to report this appearance from now on: `light` or
1809
+ * `dark` whatever the platform says, or `auto` to follow the platform
1810
+ * again. `colorScheme` then reports the answer, as it does when the
1811
+ * host calls `setColorScheme`, which is the same switch.
1812
+ *
1813
+ * For an application whose appearance setting is its own and stored:
1814
+ * the host reads the stored choice before the first frame and starts
1815
+ * with it (`createApp({ colorScheme })`), and the application, where
1816
+ * the person changes it, says so here. Without this, an application in
1817
+ * a render worker could not take back an override the host started it
1818
+ * with, and `auto` would keep reporting the stored choice instead of
1819
+ * the platform's. An application that stores nothing can combine its
1820
+ * choice with `colorScheme` instead and never call this.
1821
+ *
1822
+ * A request, because the media query is the window's; and a state,
1823
+ * like `warnOnLeave`, so a shell that arrives after it was asked is
1824
+ * told. Asking for the same thing twice sends nothing.
1825
+ */
1826
+ preferColorScheme(preference) {
1827
+ if (preference === this.preferred) return;
1828
+ this.preferred = preference;
1829
+ this.handler?.({
1830
+ type: "colorScheme",
1831
+ preference
1832
+ });
1833
+ }
1801
1834
  /** Called by the runtime when the shell reports the state. Not for applications. */
1802
1835
  applyFullscreen(active) {
1803
1836
  if (this.isFullscreen.value !== active) this.isFullscreen.value = active;
@@ -2928,6 +2961,20 @@ var EditingService = class {
2928
2961
  return this.controller.caretRectOf(node, offset);
2929
2962
  }
2930
2963
  /**
2964
+ * The caret position nearest a point in a field, the point given as a
2965
+ * pointer event gives it: where a press there would put the caret.
2966
+ *
2967
+ * What a field opened over text the person pointed at uses to start
2968
+ * the caret where they pointed: ask once the field is laid out, then
2969
+ * `select` that offset. Null when the node is not an editable, when it
2970
+ * has not been laid out yet, or before the runtime has wired the
2971
+ * controller: "ask again next frame", as for `caretRectOf`.
2972
+ */
2973
+ offsetNear(node, x, y) {
2974
+ if (node === null || this.controller === null) return null;
2975
+ return this.controller.offsetNear(node, x, y);
2976
+ }
2977
+ /**
2931
2978
  * Selects from `anchor` to `focus` and focuses the field the focus is
2932
2979
  * in: within one field, or across the fields of an editing group (see
2933
2980
  * `UiEditingGroup`). What an editor does after a command over a
@@ -3457,6 +3504,17 @@ var InspectionService = class {
3457
3504
  return this.host.inspect(node);
3458
3505
  }
3459
3506
  /**
3507
+ * Why the node has the size it has, as the layout decided it: for
3508
+ * each axis, the rule that fixed it (`decidedBy`: its own length, a
3509
+ * flex share, a stretch across its parent, its content, a clamp) and
3510
+ * the sentences that say so. What a design tool needs to tell an
3511
+ * element that fills its parent from one that only happens to be as
3512
+ * wide, which the box alone cannot. Null before the node is laid out.
3513
+ */
3514
+ explain(node) {
3515
+ return this.host?.explain?.(node) ?? null;
3516
+ }
3517
+ /**
3460
3518
  * Where the node is drawn, as `inspect(node).box` reports it, without
3461
3519
  * the rest of the report: for an editor that reads the boxes of many
3462
3520
  * nodes as its view moves (a minimap of a board of frames), where
@@ -4101,6 +4159,10 @@ var GessoRuntime = class {
4101
4159
  * lays out, whichever comes first; see `resize`.
4102
4160
  */
4103
4161
  laidOutOnce = false;
4162
+ /** Frames in a row that threw; see `reportFrameError`. */
4163
+ framesFailed = 0;
4164
+ /** Nodes that declare `holdUnseen`, as frames have found them; see `updateHolds`. */
4165
+ holdable = /* @__PURE__ */ new Set();
4104
4166
  constructor(options) {
4105
4167
  this.services = options.services ?? new ServiceRegistry();
4106
4168
  this.channels = options.channels ?? new ChannelRegistry();
@@ -4293,6 +4355,7 @@ var GessoRuntime = class {
4293
4355
  this.services.get(InspectionService).attach({
4294
4356
  nodesAt: (x, y) => this.hitTester.hitStack(x, y),
4295
4357
  inspect: (node) => this.inspectNode(node),
4358
+ explain: (node) => this.engine.explain(node),
4296
4359
  box: (node) => {
4297
4360
  const box = this.engine.visibleBox(node);
4298
4361
  return {
@@ -4380,6 +4443,7 @@ var GessoRuntime = class {
4380
4443
  this.frameErrorListener = listener;
4381
4444
  }
4382
4445
  reportFrameError(error) {
4446
+ if (this.framesFailed++ === 0) this.requestRepaint();
4383
4447
  const message = error instanceof Error ? error.message : String(error);
4384
4448
  const stack = error instanceof Error ? error.stack : void 0;
4385
4449
  if (this.frameErrorListener !== null) {
@@ -5380,7 +5444,9 @@ var GessoRuntime = class {
5380
5444
  * reconciles rather than recreating, so a component whose class is
5381
5445
  * the same object as before keeps its host and its `internalState`;
5382
5446
  * one whose module was replaced is a different class, and its host
5383
- * is disposed and mounted again. Scroll offsets on containers that
5447
+ * is disposed and mounted again with everything it rendered: its body
5448
+ * made new objects for its children, and a child kept from before
5449
+ * would go on holding the old ones. Scroll offsets on containers that
5384
5450
  * survive are kept, because the node is kept. Component state in a
5385
5451
  * replaced module is lost, which is the honest cost and the reason
5386
5452
  * this is a development tool.
@@ -5514,7 +5580,10 @@ var GessoRuntime = class {
5514
5580
  if (isObservable(definition)) throw new Error("Root definition cannot be an Observable. Wrap it in a component or static element.");
5515
5581
  if (isComponentLikeElement(definition)) {
5516
5582
  if (depth > MAX_ROOT_COMPONENT_DEPTH) throw new Error(`Root component chain exceeded ${MAX_ROOT_COMPONENT_DEPTH} levels without producing an element.`);
5517
- const output = this.resolver.resolve(definition, `app:component:${depth}`);
5583
+ const anchorId = `app:component:${depth}`;
5584
+ const before = this.resolver.hostFor(anchorId);
5585
+ if (before !== void 0 && before.component !== definition.component && this.root !== void 0) this.builder.reconcileChildren(this.root, []);
5586
+ const output = this.resolver.resolve(definition, anchorId);
5518
5587
  return this.resolveRootElement(output, depth + 1);
5519
5588
  }
5520
5589
  return definition;
@@ -6245,6 +6314,7 @@ var GessoRuntime = class {
6245
6314
  childX = x - (rec.scrollable ? rec.scrollX : 0);
6246
6315
  childY = y - (rec.scrollable ? rec.scrollY : 0);
6247
6316
  }
6317
+ if (node.hold !== null && !(focused != null && focused.heldBy === node)) continue;
6248
6318
  for (let child = node.lastChild; child !== null; child = child.previousSibling) stack.push([
6249
6319
  child,
6250
6320
  childX,
@@ -6605,6 +6675,39 @@ var GessoRuntime = class {
6605
6675
  this.warnedLayoutPasses = true;
6606
6676
  console.warn(`Gesso: a frame laid out ${MAX_LAYOUT_PASSES} times and its layout listeners were still changing it, so it was painted unsettled and the rest left for the next frame. Something on \`host.onLayout\` (a breakpoint, a sizeContainer, a Responsive, a modifier of your own) is writing a property that changes the box it is listening to, back and forth. Shown once.`);
6607
6677
  }
6678
+ /**
6679
+ * Holds each subtree that declares `holdUnseen` while it cannot be
6680
+ * read, and lets it go on the frame it can (see `UiGraph.hold`).
6681
+ *
6682
+ * Decided after the frame is drawn, from where it was drawn: a subtree
6683
+ * is only ever held once it has been laid out and painted, so what is
6684
+ * kept of it is what it showed, and one let go catches up on the next
6685
+ * frame, which its own marks arm. Only frames that moved or laid
6686
+ * something out can change the answer, so the rest pay nothing.
6687
+ */
6688
+ updateHolds(frame, laidOut) {
6689
+ let found = false;
6690
+ for (const [node, flags] of frame.entries()) if ((flags & DirtyFlags.Properties) !== 0 && node.properties.get("holdUnseen") !== void 0 && !this.holdable.has(node)) {
6691
+ this.holdable.add(node);
6692
+ found = true;
6693
+ }
6694
+ if (this.holdable.size === 0 || !laidOut && !found) return;
6695
+ for (const node of this.holdable) {
6696
+ const how = node.properties.get("holdUnseen");
6697
+ if (how === void 0 || this.graph.getNode(node.id) !== node) {
6698
+ this.graph.release(node);
6699
+ this.holdable.delete(node);
6700
+ continue;
6701
+ }
6702
+ const rec = this.engine.recordFor(node);
6703
+ if (rec === void 0 || !(rec.width > 0) || !(rec.height > 0)) continue;
6704
+ const box = this.engine.screenBox(node);
6705
+ const margin = how === true ? 0 : how.margin ?? 0;
6706
+ const below = how === true ? 0 : how.belowScale ?? 0;
6707
+ if (box.x + box.width > -margin && box.y + box.height > -margin && box.x < this.width + margin && box.y < this.height + margin && box.width / rec.width >= below) this.graph.release(node);
6708
+ else this.graph.hold(node);
6709
+ }
6710
+ }
6608
6711
  handleFrame(collected) {
6609
6712
  const root = this.root;
6610
6713
  if (root === void 0) return;
@@ -6636,11 +6739,13 @@ var GessoRuntime = class {
6636
6739
  overlay: overlay?.shapes,
6637
6740
  changes
6638
6741
  }));
6742
+ this.updateHolds(frame, laidOut);
6639
6743
  if (overlay !== null) {
6640
6744
  if (laidOut) this.sendInspection();
6641
6745
  this.scheduleInspectorRepaint(overlay.nextChange);
6642
6746
  }
6643
6747
  this.sendDevtoolsUpdates(frame);
6748
+ this.framesFailed = 0;
6644
6749
  const finished = now();
6645
6750
  const elapsed = finished - (this.frameBegan ?? started);
6646
6751
  this.frameBegan = null;
@@ -7307,4 +7412,4 @@ function failure(text) {
7307
7412
  //#endregion
7308
7413
  export { ComponentHostResolver as A, ChannelRegistry as B, ShellService as C, isDiscreteInputMessage as D, epochNow as E, FocusService as F, Input as G, Channel as H, boundFocus as I, BoundsCell as J, Output as K, OverlayScopeKey as L, StartingInputsKey as M, OverlayLayer as N, isInputMessage as O, __decorate as P, OverlayService as R, FrameService as S, epochFromEvent as T, Define as U, ChannelReplica as V, Inject as W, ServiceRegistry as X, bounds as Y, Component as Z, parsePattern as _, UI_FRAME_PHASES as a, AudioService as b, TextService as c, ScrollService as d, EditingService as f, formatUrl as g, buildPath as h, GessoRuntime as i, ComponentHost as j, modifiersFrom as k, FontService as l, RouterService as m, renderFrame as n, InspectionService as o, FindService as p, liveInput as q, isClaimedError as r, AnimationService as s, renderModule as t, MediaService as u, parseUrl as v, shellFilesUnsupported as w, treeText as x, RouteState as y, isClassComponent as z };
7309
7414
 
7310
- //# sourceMappingURL=render-W2XO444K.js.map
7415
+ //# sourceMappingURL=render-DlhL5y0d.js.map