@moku-labs/game 0.15.7 → 0.15.9
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.
- package/dist/app/page.d.mts +1 -1
- package/dist/app/page.mjs +1 -1
- package/dist/app/system.d.mts +3 -3
- package/dist/app.d.mts +3 -3
- package/dist/app.mjs +1 -1
- package/dist/assets.d.mts +1 -1
- package/dist/{commands-C8aWbThW.d.mts → commands-5woFUxUr.d.mts} +13 -5
- package/dist/control.d.mts +4 -4
- package/dist/control.mjs +1 -1
- package/dist/{define-Bebctfvs.d.mts → define-B8A5IoeS.d.mts} +2 -2
- package/dist/{headless-DobgwTKK.d.mts → headless-CrxofjLt.d.mts} +1 -1
- package/dist/{index-CU4Oc2Qv.d.mts → index-DT9aYVGd.d.mts} +7 -6
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +3 -3
- package/dist/inspect.d.mts +6 -6
- package/dist/inspect.mjs +1 -1
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/{run-DlxDjgOO.mjs → run-BqYmcNo7.mjs} +38 -5
- package/dist/{runtime-Bm_guAJR.d.mts → runtime-BZQQPq56.d.mts} +1 -1
- package/dist/{sources-OvHvyeJS.mjs → sources-QCowxSpC.mjs} +1 -1
- package/dist/{src-nJYt0LMr.mjs → src-Cs1bP3v7.mjs} +1044 -184
- package/dist/testing.d.mts +4 -4
- package/dist/testing.mjs +1 -1
- package/dist/{types-CZGuMhV8.d.mts → types-D8roM1u3.d.mts} +127 -9
- package/dist/{types-BkcgFOoB.d.mts → types-DDmfkONF.d.mts} +59 -7
- package/dist/{types-MocH_igX.d.mts → types-DK-IYk-s.d.mts} +4 -4
- package/dist/{types-Mj75CDO6.d.mts → types-YXykgTOp.d.mts} +2 -2
- package/dist/{types-C4D9UVgb.d.mts → types-i77Nrrv-.d.mts} +29 -16
- package/dist/{visual-BV2A3kpr.d.mts → visual-1doiBOD3.d.mts} +6 -6
- package/dist/{visual-2m4wJL_z.mjs → visual-CIUx49C0.mjs} +26 -6
- package/dist/visual.d.mts +1 -1
- package/dist/visual.mjs +2 -2
- package/llms.txt +8 -7
- package/package.json +1 -1
|
@@ -2,7 +2,7 @@ import { t as __exportAll } from "./rolldown-runtime-8H4AJuhK.mjs";
|
|
|
2
2
|
import { r as systemSource, t as memory } from "./memory-CWlqhS7l.mjs";
|
|
3
3
|
import { a as finishDrafts, i as enableDraftPatches, n as deepFreeze$1, o as openDrafts, r as dropDrafts } from "./drafts-BawpSaVp.mjs";
|
|
4
4
|
import { d as graphHash, f as isRestCheckpoint, h as pushEntry, i as servePaused, l as findNode, m as compact, n as captureFrame, o as collectFlows, p as slotNames, r as serveCaptures, s as describeGraph, t as cancelCaptures, u as framePath } from "./capture-D7XvoHdH.mjs";
|
|
5
|
-
import { A as
|
|
5
|
+
import { A as Now, C as Sprite, E as componentsFor, F as resource, I as system, L as systemsFor, M as Tree, N as component, O as Exiting, R as tag, S as Shape, T as arcDefaults, _ as HudPart, b as OverlayLevel, c as Countdown, d as builtInStyles, g as Display, h as textFor, i as samePose, j as Order, k as Layer, l as Text, m as readStyle, n as drawnRect, o as visualOf$1, r as fitScaleOf, s as visualRectOf, t as CONTENT$1, v as NineSlice, w as Transform, x as Parent, y as Overlay } from "./visual-CIUx49C0.mjs";
|
|
6
6
|
import { a as isDev } from "./dev-BNndV-hU.mjs";
|
|
7
7
|
import { i as isComponentDefinition, n as flatten, r as defineComponent } from "./flatten-BkXuscAV.mjs";
|
|
8
8
|
import { envPlugin, logPlugin } from "@moku-labs/common/browser";
|
|
@@ -3337,7 +3337,7 @@ function deliver$1(state, answer) {
|
|
|
3337
3337
|
* @param ctx - Domain context of the flow plugin.
|
|
3338
3338
|
* @param answer - The answer the closed gate refused.
|
|
3339
3339
|
*/
|
|
3340
|
-
function hold(ctx, answer) {
|
|
3340
|
+
function hold$1(ctx, answer) {
|
|
3341
3341
|
if (ctx.state.fx.mode === "fast") return;
|
|
3342
3342
|
if (!ctx.deps.time.isRunning()) return;
|
|
3343
3343
|
if (ctx.config.holdMs <= 0 && ctx.state.gate.held !== void 0) return;
|
|
@@ -3376,7 +3376,7 @@ function createGateApi(ctx) {
|
|
|
3376
3376
|
return {
|
|
3377
3377
|
answer: (answer) => {
|
|
3378
3378
|
if (ctx.state.gate.open === void 0) {
|
|
3379
|
-
hold(ctx, answer);
|
|
3379
|
+
hold$1(ctx, answer);
|
|
3380
3380
|
return false;
|
|
3381
3381
|
}
|
|
3382
3382
|
if (!accepts(ctx.state.gate, answer)) return false;
|
|
@@ -5506,7 +5506,7 @@ function startDeadline(timeoutMs) {
|
|
|
5506
5506
|
* @param running - The promise of `run()`.
|
|
5507
5507
|
* @returns `true` when the loop settled, `false` when the deadline won and the loop still runs.
|
|
5508
5508
|
*/
|
|
5509
|
-
async function settle$
|
|
5509
|
+
async function settle$2(ctx, running) {
|
|
5510
5510
|
const quiet = running.then(noop, noop);
|
|
5511
5511
|
const deadline = startDeadline(ctx.config.settleTimeoutMs);
|
|
5512
5512
|
try {
|
|
@@ -5535,7 +5535,7 @@ async function stopRunner(ctx) {
|
|
|
5535
5535
|
stop.abort("stop");
|
|
5536
5536
|
state.abort = stop;
|
|
5537
5537
|
}
|
|
5538
|
-
const settled = running === void 0 || await settle$
|
|
5538
|
+
const settled = running === void 0 || await settle$2(ctx, running);
|
|
5539
5539
|
state.running = void 0;
|
|
5540
5540
|
ctx.state.gate.held = void 0;
|
|
5541
5541
|
if (settled) state.abort = void 0;
|
|
@@ -24372,7 +24372,7 @@ function destroyPools(state) {
|
|
|
24372
24372
|
* view with `applyPose`.
|
|
24373
24373
|
*/
|
|
24374
24374
|
/** How deep a parent chain is followed; deeper is treated as a loop. */
|
|
24375
|
-
const MAX_DEPTH$
|
|
24375
|
+
const MAX_DEPTH$6 = 32;
|
|
24376
24376
|
/**
|
|
24377
24377
|
* The parent an entity moves with.
|
|
24378
24378
|
*
|
|
@@ -24394,7 +24394,7 @@ function parentOf$1(ecs, entity) {
|
|
|
24394
24394
|
*/
|
|
24395
24395
|
function isLeaving(ecs, entity) {
|
|
24396
24396
|
let current = entity;
|
|
24397
|
-
for (let depth = 0; depth < MAX_DEPTH$
|
|
24397
|
+
for (let depth = 0; depth < MAX_DEPTH$6 && current !== 0; depth += 1) {
|
|
24398
24398
|
if (ecs.has(current, Exiting)) return true;
|
|
24399
24399
|
current = parentOf$1(ecs, current);
|
|
24400
24400
|
}
|
|
@@ -24500,7 +24500,7 @@ function rootPoseInto(ecs, entity, out, own) {
|
|
|
24500
24500
|
out.pivot.x = start.pivot.x;
|
|
24501
24501
|
out.pivot.y = start.pivot.y;
|
|
24502
24502
|
let current = entity;
|
|
24503
|
-
for (let depth = 0; depth < MAX_DEPTH$
|
|
24503
|
+
for (let depth = 0; depth < MAX_DEPTH$6; depth += 1) {
|
|
24504
24504
|
const parent = parentOf$1(ecs, current);
|
|
24505
24505
|
if (parent === 0) break;
|
|
24506
24506
|
const above = ecs.get(parent, Transform) ?? Transform.defaults;
|
|
@@ -24841,7 +24841,7 @@ const RETAKE_STREAK = 3;
|
|
|
24841
24841
|
/** Frames in a row with no mark in it before a live range is kept as a picture again (spec 23's `CALM_AFTER`). */
|
|
24842
24842
|
const CALM_FRAMES = 8;
|
|
24843
24843
|
/** How deep a walk up the tree goes. */
|
|
24844
|
-
const MAX_DEPTH$
|
|
24844
|
+
const MAX_DEPTH$5 = 32;
|
|
24845
24845
|
/** CSS px a view may fall short of the viewport frame and still cover it: the reference frame rounds by a fraction. */
|
|
24846
24846
|
const COVER_SLACK = 1;
|
|
24847
24847
|
/** The whole-frame reasons after which a kept picture is taken again: the screen changed whole. */
|
|
@@ -25005,7 +25005,7 @@ function sameList$1(left, right) {
|
|
|
25005
25005
|
*/
|
|
25006
25006
|
function inRange(set, node, root) {
|
|
25007
25007
|
let current = node;
|
|
25008
|
-
for (let depth = 0; depth < MAX_DEPTH$
|
|
25008
|
+
for (let depth = 0; depth < MAX_DEPTH$5 && current !== null && current !== root; depth += 1) {
|
|
25009
25009
|
if (set.has(current)) return true;
|
|
25010
25010
|
current = current.parent;
|
|
25011
25011
|
}
|
|
@@ -25527,10 +25527,22 @@ function stopOverlays(state) {
|
|
|
25527
25527
|
}
|
|
25528
25528
|
//#endregion
|
|
25529
25529
|
//#region src/plugins/renderer/sync/shape-path.ts
|
|
25530
|
+
/**
|
|
25531
|
+
* @file renderer/sync — the path of a `Shape`: a rectangle, a rounded rectangle or a triangle,
|
|
25532
|
+
* its fill, and its stroke, solid or dashed, or an arc, a stroke alone. A dashed stroke walks the
|
|
25533
|
+
* outline (straight edges, and rounded corners sampled as arcs) and strokes one open line per dash.
|
|
25534
|
+
* An arc runs on the circle inscribed in its box, from 12 o'clock clockwise.
|
|
25535
|
+
*/
|
|
25530
25536
|
/** Chords per rounded corner of a dashed outline: under 0.3 u off the arc at a 48 u radius. */
|
|
25531
25537
|
const CORNER_SAMPLES = 8;
|
|
25532
25538
|
/** The gap between two dashes, as a fraction of the dash length. */
|
|
25533
25539
|
const GAP_RATIO = .5;
|
|
25540
|
+
/** Segments of a full ring: a ring of 28 u across strays under 0.03 u off its circle. */
|
|
25541
|
+
const RING_SEGMENTS = 48;
|
|
25542
|
+
/** The fewest segments of an arc that draws: a sliver still bends. */
|
|
25543
|
+
const ARC_MIN_SEGMENTS = 2;
|
|
25544
|
+
/** 12 o'clock, where an arc starts: Pixi's angles run clockwise from 3 o'clock. */
|
|
25545
|
+
const TWELVE = -Math.PI / 2;
|
|
25534
25546
|
/**
|
|
25535
25547
|
* The corner radius the rectangle is drawn with: Pixi clamps it to half the shorter side.
|
|
25536
25548
|
*
|
|
@@ -25715,8 +25727,9 @@ function dashesOf(outline, dash) {
|
|
|
25715
25727
|
}
|
|
25716
25728
|
/**
|
|
25717
25729
|
* Draws the path of a shape and fills it in a colour at the alpha given. At alpha 0 the path stays unfilled, so only
|
|
25718
|
-
* a stroke shows. A clip mask is drawn here too, never dashed
|
|
25719
|
-
* object's tint, so a colour change draws
|
|
25730
|
+
* a stroke shows. A clip mask is drawn here too, never dashed; the path of an arc here is its box, which is what it
|
|
25731
|
+
* clips its children to. A fill-only shape is drawn white and coloured by the object's tint, so a colour change draws
|
|
25732
|
+
* no path (spec 26 R2.1).
|
|
25720
25733
|
*
|
|
25721
25734
|
* @param object - The graphics to draw on.
|
|
25722
25735
|
* @param value - The shape value.
|
|
@@ -25726,7 +25739,7 @@ function dashesOf(outline, dash) {
|
|
|
25726
25739
|
function drawShapePath(object, value, fillAlpha, color = value.fill) {
|
|
25727
25740
|
object.clear();
|
|
25728
25741
|
if (value.kind === "triangle") object.moveTo(0, 0).lineTo(value.w, value.h / 2).lineTo(0, value.h).closePath();
|
|
25729
|
-
else if (value.radius > 0) object.roundRect(0, 0, value.w, value.h, value.radius);
|
|
25742
|
+
else if (value.kind === "rect" && value.radius > 0) object.roundRect(0, 0, value.w, value.h, value.radius);
|
|
25730
25743
|
else object.rect(0, 0, value.w, value.h);
|
|
25731
25744
|
if (fillAlpha <= 0) return;
|
|
25732
25745
|
object.fill(fillAlpha < 1 ? {
|
|
@@ -25759,6 +25772,102 @@ function strokeShape(object, value) {
|
|
|
25759
25772
|
}
|
|
25760
25773
|
object.stroke(style);
|
|
25761
25774
|
}
|
|
25775
|
+
/**
|
|
25776
|
+
* The share of the circle an arc sweeps, clamped to 0..1: anything not above 0, `NaN` too, is 0; a whole ring when
|
|
25777
|
+
* the value leaves it out.
|
|
25778
|
+
*
|
|
25779
|
+
* @param value - The shape value.
|
|
25780
|
+
* @returns The share.
|
|
25781
|
+
* @example
|
|
25782
|
+
* ```ts
|
|
25783
|
+
* sweepOf({ ...Shape.defaults, kind: "arc", sweep: 1.4 }); // 1
|
|
25784
|
+
* ```
|
|
25785
|
+
*/
|
|
25786
|
+
function sweepOf(value) {
|
|
25787
|
+
const sweep = value.sweep ?? arcDefaults.sweep;
|
|
25788
|
+
if (Number.isNaN(sweep) || sweep <= 0) return 0;
|
|
25789
|
+
return Math.min(sweep, 1);
|
|
25790
|
+
}
|
|
25791
|
+
/**
|
|
25792
|
+
* The radius of the circle an arc runs on: inscribed in the shorter side of its box, inside its stroke.
|
|
25793
|
+
*
|
|
25794
|
+
* @param value - The shape value.
|
|
25795
|
+
* @returns The radius in reference units; 0 or below when the stroke leaves no circle.
|
|
25796
|
+
* @example
|
|
25797
|
+
* ```ts
|
|
25798
|
+
* arcRadiusOf({ ...Shape.defaults, kind: "arc", w: 28, h: 40, strokeWidth: 2 }); // 13
|
|
25799
|
+
* ```
|
|
25800
|
+
*/
|
|
25801
|
+
function arcRadiusOf(value) {
|
|
25802
|
+
return (Math.min(value.w, value.h) - value.strokeWidth) / 2;
|
|
25803
|
+
}
|
|
25804
|
+
/**
|
|
25805
|
+
* Tells whether an arc draws nothing: no stroke width, no sweep, or no circle inside its stroke.
|
|
25806
|
+
*
|
|
25807
|
+
* @param value - The shape value, an arc.
|
|
25808
|
+
* @returns True for an arc whose `Graphics` would hold no instruction.
|
|
25809
|
+
* @example
|
|
25810
|
+
* ```ts
|
|
25811
|
+
* isEmptyArc({ ...Shape.defaults, kind: "arc", w: 28, h: 28, strokeWidth: 2, sweep: 0 }); // true
|
|
25812
|
+
* ```
|
|
25813
|
+
*/
|
|
25814
|
+
function isEmptyArc(value) {
|
|
25815
|
+
return value.strokeWidth <= 0 || sweepOf(value) <= 0 || arcRadiusOf(value) <= 0;
|
|
25816
|
+
}
|
|
25817
|
+
/**
|
|
25818
|
+
* Strokes an arc: from 12 o'clock clockwise over its share of the circle, in segments as many as its angle needs (48
|
|
25819
|
+
* for a ring, at least 2), ended by its `cap`. A full ring is closed and has no ends. Nothing for an empty arc. Drawn
|
|
25820
|
+
* only when the shape changed: never rebuilt per frame.
|
|
25821
|
+
*
|
|
25822
|
+
* @param object - The graphics, cleared.
|
|
25823
|
+
* @param value - The shape value, an arc.
|
|
25824
|
+
*/
|
|
25825
|
+
function strokeArc(object, value) {
|
|
25826
|
+
if (isEmptyArc(value)) return;
|
|
25827
|
+
const sweep = sweepOf(value);
|
|
25828
|
+
const radius = arcRadiusOf(value);
|
|
25829
|
+
const ring = sweep >= 1;
|
|
25830
|
+
const segments = Math.max(ARC_MIN_SEGMENTS, Math.ceil(sweep * RING_SEGMENTS));
|
|
25831
|
+
const step = sweep * 2 * Math.PI / segments;
|
|
25832
|
+
const centreX = value.w / 2;
|
|
25833
|
+
const centreY = value.h / 2;
|
|
25834
|
+
const last = ring ? segments - 1 : segments;
|
|
25835
|
+
object.moveTo(centreX, centreY - radius);
|
|
25836
|
+
for (let index = 1; index <= last; index += 1) {
|
|
25837
|
+
const angle = TWELVE + index * step;
|
|
25838
|
+
object.lineTo(centreX + radius * Math.cos(angle), centreY + radius * Math.sin(angle));
|
|
25839
|
+
}
|
|
25840
|
+
if (ring) {
|
|
25841
|
+
object.closePath();
|
|
25842
|
+
object.stroke({
|
|
25843
|
+
color: value.stroke,
|
|
25844
|
+
width: value.strokeWidth
|
|
25845
|
+
});
|
|
25846
|
+
return;
|
|
25847
|
+
}
|
|
25848
|
+
object.stroke({
|
|
25849
|
+
color: value.stroke,
|
|
25850
|
+
width: value.strokeWidth,
|
|
25851
|
+
cap: value.cap ?? arcDefaults.cap
|
|
25852
|
+
});
|
|
25853
|
+
}
|
|
25854
|
+
/**
|
|
25855
|
+
* Paints a shape on its graphics: an arc as its stroke alone, every other kind as its path, its fill in a colour at its
|
|
25856
|
+
* own fill alpha, and its stroke. The one call that draws a shape's visual.
|
|
25857
|
+
*
|
|
25858
|
+
* @param object - The graphics.
|
|
25859
|
+
* @param value - The shape value.
|
|
25860
|
+
* @param color - The colour of the fill: white for a tinted shape, the value's own otherwise.
|
|
25861
|
+
*/
|
|
25862
|
+
function paintShape(object, value, color) {
|
|
25863
|
+
if (value.kind === "arc") {
|
|
25864
|
+
object.clear();
|
|
25865
|
+
strokeArc(object, value);
|
|
25866
|
+
return;
|
|
25867
|
+
}
|
|
25868
|
+
drawShapePath(object, value, value.fillAlpha, color);
|
|
25869
|
+
strokeShape(object, value);
|
|
25870
|
+
}
|
|
25762
25871
|
//#endregion
|
|
25763
25872
|
//#region src/plugins/renderer/sync/sizing.ts
|
|
25764
25873
|
/**
|
|
@@ -26738,8 +26847,20 @@ function copyClip(drawn, value) {
|
|
|
26738
26847
|
return drawn;
|
|
26739
26848
|
}
|
|
26740
26849
|
/**
|
|
26850
|
+
* Tells whether an arc was drawn with this value already: only what its stroke is built from, its
|
|
26851
|
+
* box, its stroke, its share and its ends. A new fill, fill alpha, radius or dash builds nothing.
|
|
26852
|
+
*
|
|
26853
|
+
* @param drawn - What the graphics was last drawn with, an arc too.
|
|
26854
|
+
* @param value - The arc now.
|
|
26855
|
+
* @returns True when nothing has to be drawn.
|
|
26856
|
+
*/
|
|
26857
|
+
function sameArc(drawn, value) {
|
|
26858
|
+
return drawn.w === value.w && drawn.h === value.h && drawn.stroke === value.stroke && drawn.strokeWidth === value.strokeWidth && drawn.sweep === value.sweep && drawn.cap === value.cap;
|
|
26859
|
+
}
|
|
26860
|
+
/**
|
|
26741
26861
|
* Tells whether a shape's graphics was drawn with this value already: the path, the fill and the
|
|
26742
|
-
* stroke. Its alpha, its clip and the fill of a tinted shape (its tint)
|
|
26862
|
+
* stroke; for an arc only its stroke. Its alpha, its clip and the fill of a tinted shape (its tint)
|
|
26863
|
+
* are written apart.
|
|
26743
26864
|
*
|
|
26744
26865
|
* @param drawn - What the graphics was last drawn with.
|
|
26745
26866
|
* @param value - The shape value now.
|
|
@@ -26747,7 +26868,9 @@ function copyClip(drawn, value) {
|
|
|
26747
26868
|
* @returns True when nothing has to be drawn.
|
|
26748
26869
|
*/
|
|
26749
26870
|
function sameShape$1(drawn, value, tinted) {
|
|
26750
|
-
|
|
26871
|
+
if (drawn === void 0 || drawn.tinted !== tinted || drawn.kind !== value.kind) return false;
|
|
26872
|
+
if (value.kind === "arc") return sameArc(drawn, value);
|
|
26873
|
+
return (tinted || drawn.fill === value.fill) && drawn.w === value.w && drawn.h === value.h && drawn.fillAlpha === value.fillAlpha && drawn.radius === value.radius && drawn.stroke === value.stroke && drawn.strokeWidth === value.strokeWidth && drawn.dash === value.dash && drawn.sweep === value.sweep && drawn.cap === value.cap;
|
|
26751
26874
|
}
|
|
26752
26875
|
/**
|
|
26753
26876
|
* Keeps what a shape's graphics was drawn with, in the object it had, or in a new one the first
|
|
@@ -26760,7 +26883,7 @@ function sameShape$1(drawn, value, tinted) {
|
|
|
26760
26883
|
*/
|
|
26761
26884
|
function copyShape(drawn, value, tinted) {
|
|
26762
26885
|
if (drawn === void 0) {
|
|
26763
|
-
const { kind, w, h, fill, fillAlpha, radius, stroke, strokeWidth, dash } = value;
|
|
26886
|
+
const { kind, w, h, fill, fillAlpha, radius, stroke, strokeWidth, dash, sweep, cap } = value;
|
|
26764
26887
|
return {
|
|
26765
26888
|
tinted,
|
|
26766
26889
|
kind,
|
|
@@ -26771,7 +26894,9 @@ function copyShape(drawn, value, tinted) {
|
|
|
26771
26894
|
radius,
|
|
26772
26895
|
stroke,
|
|
26773
26896
|
strokeWidth,
|
|
26774
|
-
dash
|
|
26897
|
+
dash,
|
|
26898
|
+
sweep,
|
|
26899
|
+
cap
|
|
26775
26900
|
};
|
|
26776
26901
|
}
|
|
26777
26902
|
const copy = drawn;
|
|
@@ -26785,10 +26910,13 @@ function copyShape(drawn, value, tinted) {
|
|
|
26785
26910
|
copy.stroke = value.stroke;
|
|
26786
26911
|
copy.strokeWidth = value.strokeWidth;
|
|
26787
26912
|
copy.dash = value.dash;
|
|
26913
|
+
copy.sweep = value.sweep;
|
|
26914
|
+
copy.cap = value.cap;
|
|
26788
26915
|
return copy;
|
|
26789
26916
|
}
|
|
26790
26917
|
/**
|
|
26791
|
-
* Tells whether a shape draws nothing: no stroke, and no fill alpha or no area
|
|
26918
|
+
* Tells whether a shape draws nothing: no stroke, and no fill alpha or no area; an arc with no stroke, no sweep or no
|
|
26919
|
+
* circle inside its stroke. Pure.
|
|
26792
26920
|
*
|
|
26793
26921
|
* @param value - The shape value.
|
|
26794
26922
|
* @returns True for a shape whose `Graphics` would hold no instruction.
|
|
@@ -26798,6 +26926,7 @@ function copyShape(drawn, value, tinted) {
|
|
|
26798
26926
|
* ```
|
|
26799
26927
|
*/
|
|
26800
26928
|
function isEmptyShape(value) {
|
|
26929
|
+
if (value.kind === "arc") return isEmptyArc(value);
|
|
26801
26930
|
return value.strokeWidth <= 0 && (value.fillAlpha <= 0 || value.w <= 0 || value.h <= 0);
|
|
26802
26931
|
}
|
|
26803
26932
|
/**
|
|
@@ -26815,8 +26944,7 @@ function drawShape(sctx, entity, view, object, value) {
|
|
|
26815
26944
|
const tinted = value.strokeWidth <= 0;
|
|
26816
26945
|
if (!sameShape$1(view.drawn, value, tinted)) {
|
|
26817
26946
|
markView(sctx, entity);
|
|
26818
|
-
|
|
26819
|
-
strokeShape(object, value);
|
|
26947
|
+
paintShape(object, value, tinted ? WHITE$1 : value.fill);
|
|
26820
26948
|
sctx.ctx.state.sync.redraws += 1;
|
|
26821
26949
|
view.drawn = copyShape(view.drawn, value, tinted);
|
|
26822
26950
|
}
|
|
@@ -27963,7 +28091,7 @@ function installPassCounting(pixi, sinks) {
|
|
|
27963
28091
|
//#endregion
|
|
27964
28092
|
//#region src/plugins/renderer/sync/hit-test.ts
|
|
27965
28093
|
/** How deep a parent chain or a container tree is followed. */
|
|
27966
|
-
const MAX_DEPTH$
|
|
28094
|
+
const MAX_DEPTH$4 = 32;
|
|
27967
28095
|
/** Below this effective alpha a view is treated as not there. */
|
|
27968
28096
|
const MIN_ALPHA = .01;
|
|
27969
28097
|
/**
|
|
@@ -28045,7 +28173,7 @@ function clipBoxOf(sctx, entity) {
|
|
|
28045
28173
|
function clippedOut(sctx, entity, x, y) {
|
|
28046
28174
|
const ecs = sctx.ctx.deps.world.ecs;
|
|
28047
28175
|
let current = parentOf$1(ecs, entity);
|
|
28048
|
-
for (let depth = 0; depth < MAX_DEPTH$
|
|
28176
|
+
for (let depth = 0; depth < MAX_DEPTH$4 && current !== 0; depth += 1) {
|
|
28049
28177
|
const box = clipBoxOf(sctx, current);
|
|
28050
28178
|
if (box !== void 0 && !inBox(box, localPoint(sctx, current, x, y))) return true;
|
|
28051
28179
|
current = parentOf$1(ecs, current);
|
|
@@ -28064,7 +28192,7 @@ function clippedOut(sctx, entity, x, y) {
|
|
|
28064
28192
|
function effectiveAlpha(object, root, off) {
|
|
28065
28193
|
let alpha = 1;
|
|
28066
28194
|
let current = object;
|
|
28067
|
-
for (let depth = 0; depth < MAX_DEPTH$
|
|
28195
|
+
for (let depth = 0; depth < MAX_DEPTH$4 && current !== void 0; depth += 1) {
|
|
28068
28196
|
if (current === root) return alpha;
|
|
28069
28197
|
if (!current.visible || off?.has(current) === true) return 0;
|
|
28070
28198
|
alpha *= current.alpha;
|
|
@@ -28094,7 +28222,7 @@ function isShown$1(object, root, off) {
|
|
|
28094
28222
|
* @returns The same array.
|
|
28095
28223
|
*/
|
|
28096
28224
|
function topFirst(container, out, depth = 0) {
|
|
28097
|
-
if (depth >= MAX_DEPTH$
|
|
28225
|
+
if (depth >= MAX_DEPTH$4) return out;
|
|
28098
28226
|
const ordered = container.children.toSorted((left, right) => left.zIndex - right.zIndex);
|
|
28099
28227
|
for (let index = ordered.length - 1; index >= 0; index -= 1) {
|
|
28100
28228
|
const child = ordered[index];
|
|
@@ -28183,7 +28311,7 @@ function hitAll(sctx, x, y) {
|
|
|
28183
28311
|
* hit test walks, so a box the doors report is the box a click reaches.
|
|
28184
28312
|
*/
|
|
28185
28313
|
/** How deep a parent chain is followed; deeper is treated as a loop. */
|
|
28186
|
-
const MAX_DEPTH$
|
|
28314
|
+
const MAX_DEPTH$3 = 32;
|
|
28187
28315
|
/**
|
|
28188
28316
|
* The four corners of a box, clockwise from the top-left one.
|
|
28189
28317
|
*
|
|
@@ -28277,7 +28405,7 @@ function boundsOf(sctx, entity) {
|
|
|
28277
28405
|
function layerOf(sctx, entity) {
|
|
28278
28406
|
const ecs = sctx.ctx.deps.world.ecs;
|
|
28279
28407
|
let top = entity;
|
|
28280
|
-
for (let depth = 0; depth < MAX_DEPTH$
|
|
28408
|
+
for (let depth = 0; depth < MAX_DEPTH$3; depth += 1) {
|
|
28281
28409
|
const parent = parentOf$1(ecs, top);
|
|
28282
28410
|
if (parent === 0) break;
|
|
28283
28411
|
top = parent;
|
|
@@ -28692,7 +28820,7 @@ function stepParts(sctx) {
|
|
|
28692
28820
|
//#endregion
|
|
28693
28821
|
//#region src/plugins/renderer/sync/overlay.ts
|
|
28694
28822
|
/** How deep a `Parent` chain or a walk up the tree goes. */
|
|
28695
|
-
const MAX_DEPTH$
|
|
28823
|
+
const MAX_DEPTH$2 = 32;
|
|
28696
28824
|
/** The owner `ui` gives the entities it spawns: the only overlays honoured (O4.8). */
|
|
28697
28825
|
const UI_OWNER_NAME = "ui";
|
|
28698
28826
|
/**
|
|
@@ -28761,7 +28889,7 @@ function clampInto(sctx, entity, into, raw) {
|
|
|
28761
28889
|
function rootOf(sctx, entity) {
|
|
28762
28890
|
const ecs = sctx.ctx.deps.world.ecs;
|
|
28763
28891
|
let current = entity;
|
|
28764
|
-
for (let depth = 0; depth < MAX_DEPTH$
|
|
28892
|
+
for (let depth = 0; depth < MAX_DEPTH$2; depth += 1) {
|
|
28765
28893
|
const parent = parentOf$1(ecs, current);
|
|
28766
28894
|
if (parent === 0) return current;
|
|
28767
28895
|
current = parent;
|
|
@@ -28974,7 +29102,7 @@ function drawnAlpha(sctx, record) {
|
|
|
28974
29102
|
const alphaFilter = sctx.deps.host.pixi()?.AlphaFilter;
|
|
28975
29103
|
let alpha = 1;
|
|
28976
29104
|
let node = view.wrapper ?? view.object;
|
|
28977
|
-
for (let depth = 0; depth < MAX_DEPTH$
|
|
29105
|
+
for (let depth = 0; depth < MAX_DEPTH$2 && node !== null; depth += 1) {
|
|
28978
29106
|
if (node === root) return alpha;
|
|
28979
29107
|
if (!node.visible) return 0;
|
|
28980
29108
|
const owner = state.viewOfTop.get(node);
|
|
@@ -36162,7 +36290,7 @@ async function settledRecord(state, bundle) {
|
|
|
36162
36290
|
* @param size - The size of the decoded image.
|
|
36163
36291
|
* @param mips - True for a texture uploaded with its full mip chain.
|
|
36164
36292
|
*/
|
|
36165
|
-
function resize(target, size, mips) {
|
|
36293
|
+
function resize$1(target, size, mips) {
|
|
36166
36294
|
if (target === void 0 || size === void 0) return;
|
|
36167
36295
|
target.width = size.width;
|
|
36168
36296
|
target.height = size.height;
|
|
@@ -36184,7 +36312,7 @@ function storeFont(io, record, owner, font, sizes) {
|
|
|
36184
36312
|
const old = record.fonts.get(file.key);
|
|
36185
36313
|
record.fonts.set(file.key, font);
|
|
36186
36314
|
for (const page of old?.pages ?? []) io.destroyTexture(page);
|
|
36187
|
-
for (const [at, texture] of font.pages.entries()) resize(pages[at], sizes.get(texture), false);
|
|
36315
|
+
for (const [at, texture] of font.pages.entries()) resize$1(pages[at], sizes.get(texture), false);
|
|
36188
36316
|
file.mb = sumMb(pages);
|
|
36189
36317
|
}
|
|
36190
36318
|
/**
|
|
@@ -36209,7 +36337,7 @@ function store(io, record, fresh, sizes) {
|
|
|
36209
36337
|
const old = record.textures.get(file.key);
|
|
36210
36338
|
record.textures.set(file.key, fresh.texture);
|
|
36211
36339
|
if (old !== void 0) io.destroyTexture(old);
|
|
36212
|
-
resize(file, sizes.get(fresh.texture), file.mips === true);
|
|
36340
|
+
resize$1(file, sizes.get(fresh.texture), file.mips === true);
|
|
36213
36341
|
}
|
|
36214
36342
|
/**
|
|
36215
36343
|
* Makes the numbers and the picture follow the files that were stored: the megabytes of the
|
|
@@ -41376,7 +41504,7 @@ function finish(ectx, run, definition, passed) {
|
|
|
41376
41504
|
* @param definition - The definition.
|
|
41377
41505
|
* @param messages - What the compiler said.
|
|
41378
41506
|
*/
|
|
41379
|
-
function settle(ectx, run, definition, messages) {
|
|
41507
|
+
function settle$1(ectx, run, definition, messages) {
|
|
41380
41508
|
const { checks } = ectx.state;
|
|
41381
41509
|
if (checks.run !== run || checks.status.get(definition) !== "pending") return;
|
|
41382
41510
|
const errors = messages.filter((message) => message.type === "error");
|
|
@@ -41402,7 +41530,7 @@ function checkWgsl(ectx, run, definition) {
|
|
|
41402
41530
|
finish(ectx, run, definition, true);
|
|
41403
41531
|
return;
|
|
41404
41532
|
}
|
|
41405
|
-
device.createShaderModule({ code: definition.source }).getCompilationInfo().then((info) => settle(ectx, run, definition, info.messages), () => settle(ectx, run, definition, []));
|
|
41533
|
+
device.createShaderModule({ code: definition.source }).getCompilationInfo().then((info) => settle$1(ectx, run, definition, info.messages), () => settle$1(ectx, run, definition, []));
|
|
41406
41534
|
}
|
|
41407
41535
|
/**
|
|
41408
41536
|
* Reads the errors of a WebGL info log, one per `ERROR: 0:<line>: <message>` line; a summary line
|
|
@@ -43032,7 +43160,7 @@ const EFFECTS_OWNER = Object.freeze({
|
|
|
43032
43160
|
name: "effects"
|
|
43033
43161
|
});
|
|
43034
43162
|
/** How deep a parent chain is followed, as `rootPoseOf` does; deeper is treated as a loop. */
|
|
43035
|
-
const MAX_DEPTH = 32;
|
|
43163
|
+
const MAX_DEPTH$1 = 32;
|
|
43036
43164
|
/**
|
|
43037
43165
|
* The one dynamic set of an emitter container (P9): positions, frames, rotations and colours
|
|
43038
43166
|
* upload every frame; `uvs` stays static, because a frame is set at birth and the same `update()`
|
|
@@ -43075,7 +43203,7 @@ function bornFields(size) {
|
|
|
43075
43203
|
*/
|
|
43076
43204
|
function topOf(ecs, host) {
|
|
43077
43205
|
let top = host;
|
|
43078
|
-
for (let depth = 0; depth < MAX_DEPTH; depth += 1) {
|
|
43206
|
+
for (let depth = 0; depth < MAX_DEPTH$1; depth += 1) {
|
|
43079
43207
|
const parent = parentOf$1(ecs, top);
|
|
43080
43208
|
if (parent === 0) break;
|
|
43081
43209
|
top = parent;
|
|
@@ -45182,6 +45310,10 @@ function submit(ctx, entity, answer) {
|
|
|
45182
45310
|
}
|
|
45183
45311
|
//#endregion
|
|
45184
45312
|
//#region src/plugins/input/components.ts
|
|
45313
|
+
const scrollableDefaults = {
|
|
45314
|
+
axis: "y",
|
|
45315
|
+
moving: false
|
|
45316
|
+
};
|
|
45185
45317
|
/**
|
|
45186
45318
|
* Fresh defaults for a component that names an intent. A function, so each component type gets
|
|
45187
45319
|
* its own payload object instead of sharing one.
|
|
@@ -45281,6 +45413,13 @@ const Pressed = /*#__PURE__*/ tag("Pressed");
|
|
|
45281
45413
|
*/
|
|
45282
45414
|
const PointerOver = /*#__PURE__*/ tag("PointerOver");
|
|
45283
45415
|
/**
|
|
45416
|
+
* On every ui scroll container, internal: ui writes it, input reads it, a game never sees it. A
|
|
45417
|
+
* press that leaves the tap slop along `axis` goes from the pressed view to the innermost scroll
|
|
45418
|
+
* of that axis the view hangs in by its `Parent` chain; a finger that lands on a view inside a
|
|
45419
|
+
* scroll that is `moving` stops it and answers nothing.
|
|
45420
|
+
*/
|
|
45421
|
+
const Scrollable = /*#__PURE__*/ component("Scrollable", scrollableDefaults);
|
|
45422
|
+
/**
|
|
45284
45423
|
* Where the one pointer is, in reference units. Written once per frame by the frame step. `id`
|
|
45285
45424
|
* names the pointer it follows, `-1` at rest.
|
|
45286
45425
|
*/
|
|
@@ -45290,8 +45429,12 @@ const Pointer = /*#__PURE__*/ resource("Pointer", pointerDefaults);
|
|
|
45290
45429
|
/**
|
|
45291
45430
|
* @file input plugin — who is under the finger. Every lookup goes through `renderer.sync.hitTest`,
|
|
45292
45431
|
* which answers `undefined` without a DOM, and every accept function refuses a view that is
|
|
45293
|
-
* already playing its exit. A trace takes a cell only inside a circle smaller than its box.
|
|
45432
|
+
* already playing its exit. A trace takes a cell only inside a circle smaller than its box. The
|
|
45433
|
+
* scroll a press belongs to is found up the pressed view's own `Parent` chain, never under the
|
|
45434
|
+
* point: a view drawn over a scroll from another root keeps its press.
|
|
45294
45435
|
*/
|
|
45436
|
+
/** How deep a `Parent` chain is followed; deeper is treated as a loop. */
|
|
45437
|
+
const MAX_DEPTH = 32;
|
|
45295
45438
|
/**
|
|
45296
45439
|
* Resolves what `app.input.*` was pointed at. A `{ projection, key }` goes through
|
|
45297
45440
|
* `world.projection.entityOf`, which answers for live views only, so a view in the despawn queue
|
|
@@ -45374,6 +45517,44 @@ function findPressed(ctx, x, y) {
|
|
|
45374
45517
|
return ctx.deps.renderer.sync.hitTest(x, y, (entity) => acceptPress(ctx, entity));
|
|
45375
45518
|
}
|
|
45376
45519
|
/**
|
|
45520
|
+
* The innermost scroll a view sits in that moves now: the view itself or the nearest ancestor of
|
|
45521
|
+
* its `Parent` chain that carries a `Scrollable` with `moving` true and is not on its way out. A
|
|
45522
|
+
* finger that lands on the view stops that scroll. A view of another root drawn over the scroll,
|
|
45523
|
+
* a HUD button or a popup, hangs in no chain of it, so it keeps its press. Reads only, allocates
|
|
45524
|
+
* nothing.
|
|
45525
|
+
*
|
|
45526
|
+
* @param ctx - Domain context of the input plugin.
|
|
45527
|
+
* @param entity - The view the hit test found under the finger.
|
|
45528
|
+
* @returns The scroll, or `undefined` when no scroll the view sits in moves.
|
|
45529
|
+
*/
|
|
45530
|
+
function movingScrollOf(ctx, entity) {
|
|
45531
|
+
const { ecs } = ctx.deps.world;
|
|
45532
|
+
let current = entity;
|
|
45533
|
+
for (let depth = 0; depth < MAX_DEPTH && current !== 0; depth += 1) {
|
|
45534
|
+
if (ecs.get(current, Scrollable)?.moving === true && !ecs.has(current, Exiting)) return current;
|
|
45535
|
+
current = parentOf$1(ecs, current);
|
|
45536
|
+
}
|
|
45537
|
+
}
|
|
45538
|
+
/**
|
|
45539
|
+
* The innermost scroll of an axis a pressed view sits in: the view itself or the nearest ancestor
|
|
45540
|
+
* of its `Parent` chain that carries a `Scrollable` of that axis and is not on its way out. A list
|
|
45541
|
+
* under a modal is in no chain of the modal's button, so a drift on that button never pans it.
|
|
45542
|
+
* Reads only, allocates nothing.
|
|
45543
|
+
*
|
|
45544
|
+
* @param ctx - Domain context of the input plugin.
|
|
45545
|
+
* @param entity - The pressed view.
|
|
45546
|
+
* @param axis - The dominant axis of the pan.
|
|
45547
|
+
* @returns The scroll, or `undefined` when the view sits in no scroll of that axis.
|
|
45548
|
+
*/
|
|
45549
|
+
function scrollOnAxisOf(ctx, entity, axis) {
|
|
45550
|
+
const { ecs } = ctx.deps.world;
|
|
45551
|
+
let current = entity;
|
|
45552
|
+
for (let depth = 0; depth < MAX_DEPTH && current !== 0; depth += 1) {
|
|
45553
|
+
if (ecs.get(current, Scrollable)?.axis === axis && !ecs.has(current, Exiting)) return current;
|
|
45554
|
+
current = parentOf$1(ecs, current);
|
|
45555
|
+
}
|
|
45556
|
+
}
|
|
45557
|
+
/**
|
|
45377
45558
|
* The topmost drop target at a point.
|
|
45378
45559
|
*
|
|
45379
45560
|
* @param ctx - Domain context of the input plugin.
|
|
@@ -46397,6 +46578,20 @@ function direction(from, to) {
|
|
|
46397
46578
|
return dy >= 0 ? "down" : "up";
|
|
46398
46579
|
}
|
|
46399
46580
|
/**
|
|
46581
|
+
* The axis a pan moves on: the dominant one, horizontal on an exact diagonal.
|
|
46582
|
+
*
|
|
46583
|
+
* @param from - Where the press started.
|
|
46584
|
+
* @param to - Where the finger is.
|
|
46585
|
+
* @returns The axis of the larger move.
|
|
46586
|
+
* @example
|
|
46587
|
+
* ```ts
|
|
46588
|
+
* axisOf({ x: 0, y: 0 }, { x: 20, y: -5 }); // "x"
|
|
46589
|
+
* ```
|
|
46590
|
+
*/
|
|
46591
|
+
function axisOf$1(from, to) {
|
|
46592
|
+
return Math.abs(to.x - from.x) >= Math.abs(to.y - from.y) ? "x" : "y";
|
|
46593
|
+
}
|
|
46594
|
+
/**
|
|
46400
46595
|
* Takes or releases the pointer capture of the canvas. A pointer that is already gone — a down
|
|
46401
46596
|
* and an up inside one frame — cannot be captured; the browser throws and the gesture goes on.
|
|
46402
46597
|
*
|
|
@@ -46415,7 +46610,7 @@ function capture(ctx, on) {
|
|
|
46415
46610
|
}
|
|
46416
46611
|
/**
|
|
46417
46612
|
* Ends the gesture: the press tag goes, the capture is released and the machine forgets the
|
|
46418
|
-
* pointer, whether it moved, the entity and its key.
|
|
46613
|
+
* pointer, whether it moved or caught a scroll, the entity and its key.
|
|
46419
46614
|
*
|
|
46420
46615
|
* @param ctx - Domain context of the input plugin.
|
|
46421
46616
|
*/
|
|
@@ -46426,16 +46621,30 @@ function toIdle(ctx) {
|
|
|
46426
46621
|
ctx.state.phase = "idle";
|
|
46427
46622
|
ctx.state.pointerId = void 0;
|
|
46428
46623
|
ctx.state.moved = false;
|
|
46624
|
+
ctx.state.caught = false;
|
|
46429
46625
|
ctx.state.entity = void 0;
|
|
46430
46626
|
ctx.state.key = void 0;
|
|
46431
46627
|
ctx.state.pressedMs = 0;
|
|
46432
46628
|
}
|
|
46433
46629
|
/**
|
|
46630
|
+
* Makes a view the pressed one: it is remembered with its projection key and tagged `Pressed`.
|
|
46631
|
+
*
|
|
46632
|
+
* @param ctx - Domain context of the input plugin.
|
|
46633
|
+
* @param entity - The view that takes the press.
|
|
46634
|
+
*/
|
|
46635
|
+
function press(ctx, entity) {
|
|
46636
|
+
ctx.state.entity = entity;
|
|
46637
|
+
ctx.state.key = ctx.deps.world.projection.keyOf(entity);
|
|
46638
|
+
ctx.deps.world.ecs.tag(entity, Pressed);
|
|
46639
|
+
}
|
|
46640
|
+
/**
|
|
46434
46641
|
* Takes the pointer and looks for the view under it. The pointer is taken even where no view is.
|
|
46435
46642
|
* While the finger rests (`rests`) the next finger that goes down takes the pointer over and this
|
|
46436
46643
|
* press is cancelled; once it starts a gesture — a drag, a move past the tap slop, a long press, a
|
|
46437
|
-
* trace — a second finger stays ignored.
|
|
46438
|
-
*
|
|
46644
|
+
* trace — a second finger stays ignored. When the view under the finger sits in a moving scroll,
|
|
46645
|
+
* that scroll takes the press: the finger stops it, and the press is caught. A view drawn over a
|
|
46646
|
+
* moving scroll from another root, a HUD or a popup button, keeps its press. A view that carries
|
|
46647
|
+
* `Traceable` starts a trace instead of a press: it is not tagged `Pressed`.
|
|
46439
46648
|
*
|
|
46440
46649
|
* @param ctx - Domain context of the input plugin.
|
|
46441
46650
|
* @param pointer - The `Pointer` resource of this frame.
|
|
@@ -46443,9 +46652,10 @@ function toIdle(ctx) {
|
|
|
46443
46652
|
* @param sample - The raw sample.
|
|
46444
46653
|
*/
|
|
46445
46654
|
function onDown(ctx, pointer, point, sample) {
|
|
46446
|
-
const { ecs
|
|
46655
|
+
const { ecs } = ctx.deps.world;
|
|
46447
46656
|
ctx.state.pointerId = sample.pointerId;
|
|
46448
46657
|
ctx.state.moved = false;
|
|
46658
|
+
ctx.state.caught = false;
|
|
46449
46659
|
ctx.state.start = {
|
|
46450
46660
|
x: point.x,
|
|
46451
46661
|
y: point.y
|
|
@@ -46457,16 +46667,42 @@ function onDown(ctx, pointer, point, sample) {
|
|
|
46457
46667
|
capture(ctx, true);
|
|
46458
46668
|
const entity = findPressed(ctx, point.x, point.y);
|
|
46459
46669
|
if (entity === void 0) return;
|
|
46670
|
+
const scroll = movingScrollOf(ctx, entity);
|
|
46671
|
+
if (scroll !== void 0) {
|
|
46672
|
+
ctx.state.caught = true;
|
|
46673
|
+
press(ctx, scroll);
|
|
46674
|
+
return;
|
|
46675
|
+
}
|
|
46460
46676
|
if (ecs.has(entity, Traceable)) {
|
|
46461
46677
|
beginTrace(ctx, entity, point);
|
|
46462
46678
|
return;
|
|
46463
46679
|
}
|
|
46464
|
-
ctx
|
|
46465
|
-
ctx.state.key = projection.keyOf(entity);
|
|
46466
|
-
ecs.tag(entity, Pressed);
|
|
46680
|
+
press(ctx, entity);
|
|
46467
46681
|
if (ecs.has(entity, Draggable) && ecs.has(entity, Swipeable)) ctx.log.warn("input: Draggable wins over Swipeable", { view: ctx.state.key });
|
|
46468
46682
|
}
|
|
46469
46683
|
/**
|
|
46684
|
+
* The press just left the tap slop: it goes to the scroll it pans, the innermost `Scrollable` of
|
|
46685
|
+
* the pressed view's own `Parent` chain (the view itself included) that moves on the dominant axis
|
|
46686
|
+
* of the move. The view loses `Pressed`, and the press is marked caught: it is a scroll gesture
|
|
46687
|
+
* now, so its release answers nothing, also when the finger came back inside the slop. A
|
|
46688
|
+
* draggable or swipeable view keeps its gesture, a caught press keeps its scroll, and a view that
|
|
46689
|
+
* sits in no scroll of that axis keeps its press, also a popup button drawn over a list.
|
|
46690
|
+
*
|
|
46691
|
+
* @param ctx - Domain context of the input plugin.
|
|
46692
|
+
* @param point - Where the finger is, in reference units.
|
|
46693
|
+
*/
|
|
46694
|
+
function handOff(ctx, point) {
|
|
46695
|
+
const { caught, entity, start } = ctx.state;
|
|
46696
|
+
const { ecs } = ctx.deps.world;
|
|
46697
|
+
if (entity === void 0 || caught) return;
|
|
46698
|
+
if (ecs.has(entity, Draggable) || ecs.has(entity, Swipeable)) return;
|
|
46699
|
+
const scroll = scrollOnAxisOf(ctx, entity, axisOf$1(start, point));
|
|
46700
|
+
if (scroll === void 0 || scroll === entity) return;
|
|
46701
|
+
ecs.untag(entity, Pressed);
|
|
46702
|
+
ctx.state.caught = true;
|
|
46703
|
+
press(ctx, scroll);
|
|
46704
|
+
}
|
|
46705
|
+
/**
|
|
46470
46706
|
* Turns a press on a draggable view into a drag once the finger left the start by more than
|
|
46471
46707
|
* `dragStartPx`. A draggable view with no projection key cannot be carried: `mute`, `lift` and
|
|
46472
46708
|
* `settle` belong to a projection, so the gesture is reported and given up.
|
|
@@ -46492,13 +46728,15 @@ function onMove(ctx, point) {
|
|
|
46492
46728
|
* Answers the release of a press: a tap when the finger stayed inside the slop, a swipe when it
|
|
46493
46729
|
* went far enough and fast enough. Neither: nothing happened, and nothing has to be undone. Every
|
|
46494
46730
|
* release inside the slop runs the `onTap` listeners first, so a view that carries only
|
|
46495
|
-
* `Touchable` is heard although it answers nothing.
|
|
46731
|
+
* `Touchable` is heard although it answers nothing. A caught press belongs to a scroll — it
|
|
46732
|
+
* stopped a moving one or was handed to one — and answers nothing and runs no listener.
|
|
46496
46733
|
*
|
|
46497
46734
|
* @param ctx - Domain context of the input plugin.
|
|
46498
46735
|
* @param entity - The pressed view.
|
|
46499
46736
|
* @param point - Where the finger let go, in reference units.
|
|
46500
46737
|
*/
|
|
46501
46738
|
function answerRelease(ctx, entity, point) {
|
|
46739
|
+
if (ctx.state.caught) return;
|
|
46502
46740
|
const { ecs } = ctx.deps.world;
|
|
46503
46741
|
const travelled = distance(ctx.state.start, point);
|
|
46504
46742
|
if (travelled <= ctx.config.tapSlopPx) {
|
|
@@ -46565,13 +46803,24 @@ function rests(ctx) {
|
|
|
46565
46803
|
return ctx.state.phase === "pressed" && !ctx.state.moved;
|
|
46566
46804
|
}
|
|
46567
46805
|
/**
|
|
46806
|
+
* Tells whether a sample takes the press past the tap slop for the first time: the press has not
|
|
46807
|
+
* moved yet and the finger is farther than `tapSlopPx` from the start.
|
|
46808
|
+
*
|
|
46809
|
+
* @param ctx - Domain context of the input plugin.
|
|
46810
|
+
* @param point - Where the finger is, in reference units.
|
|
46811
|
+
* @returns True in the one sample that turns the press into a moved one.
|
|
46812
|
+
*/
|
|
46813
|
+
function leavesSlop(ctx, point) {
|
|
46814
|
+
return ctx.state.phase === "pressed" && !ctx.state.moved && distance(ctx.state.start, point) > ctx.config.tapSlopPx;
|
|
46815
|
+
}
|
|
46816
|
+
/**
|
|
46568
46817
|
* Feeds one raw sample to the machine. A leave does nothing here. A sample of another pointer is
|
|
46569
46818
|
* dropped while a pointer is followed: the second finger is ignored. One exception: a press while
|
|
46570
46819
|
* the followed pointer rests takes the pointer over and cancels the resting press, so a resting
|
|
46571
46820
|
* thumb or palm never blocks the finger that plays. A move of an idle mouse or pen hit-tests
|
|
46572
46821
|
* nothing: its point is returned, so the drain moves the hover once per frame. A move of a press
|
|
46573
|
-
* past the tap slop marks the press as moved for good
|
|
46574
|
-
* cancel.
|
|
46822
|
+
* past the tap slop marks the press as moved for good and, in that one sample, hands it to the
|
|
46823
|
+
* scroll it pans. A lost capture ends the gesture like a cancel.
|
|
46575
46824
|
*
|
|
46576
46825
|
* @param ctx - Domain context of the input plugin.
|
|
46577
46826
|
* @param pointer - The `Pointer` resource of this frame.
|
|
@@ -46594,7 +46843,10 @@ function handleSample(ctx, pointer, sample) {
|
|
|
46594
46843
|
break;
|
|
46595
46844
|
case "move":
|
|
46596
46845
|
if (isHover(ctx, pointer, sample)) return point;
|
|
46597
|
-
if (
|
|
46846
|
+
if (leavesSlop(ctx, point)) {
|
|
46847
|
+
ctx.state.moved = true;
|
|
46848
|
+
handOff(ctx, point);
|
|
46849
|
+
}
|
|
46598
46850
|
if (ctx.state.phase === "tracing") extendTrace(ctx, point);
|
|
46599
46851
|
else onMove(ctx, point);
|
|
46600
46852
|
break;
|
|
@@ -46767,6 +47019,7 @@ function createInputState(_ctx) {
|
|
|
46767
47019
|
phase: "idle",
|
|
46768
47020
|
pointerId: void 0,
|
|
46769
47021
|
moved: false,
|
|
47022
|
+
caught: false,
|
|
46770
47023
|
entity: void 0,
|
|
46771
47024
|
key: void 0,
|
|
46772
47025
|
start: {
|
|
@@ -50176,6 +50429,31 @@ const Scroll = /*#__PURE__*/ component("Scroll", {
|
|
|
50176
50429
|
min: 0
|
|
50177
50430
|
});
|
|
50178
50431
|
/**
|
|
50432
|
+
* On every scroll container: where it stands and whether it moves, for a game system and the
|
|
50433
|
+
* read door. `ui` writes it in a frame where the offset or `max` changed, and once more with
|
|
50434
|
+
* `moving: false` when it stops; a game reads it and never writes it.
|
|
50435
|
+
*
|
|
50436
|
+
* @example
|
|
50437
|
+
* ```ts
|
|
50438
|
+
* // A board system dims the events of the order strip while it rests on the orders.
|
|
50439
|
+
* export const stripMist = system({
|
|
50440
|
+
* name: "board.stripMist",
|
|
50441
|
+
* phase: "animate",
|
|
50442
|
+
* query: [ScrollState, OrderStrip],
|
|
50443
|
+
* run: entities => {
|
|
50444
|
+
* for (const [entity, scroll] of entities) {
|
|
50445
|
+
* // scroll: { offset: 318, max: 390, moving: false }
|
|
50446
|
+
* }
|
|
50447
|
+
* }
|
|
50448
|
+
* });
|
|
50449
|
+
* ```
|
|
50450
|
+
*/
|
|
50451
|
+
const ScrollState = /*#__PURE__*/ component("ScrollState", {
|
|
50452
|
+
offset: 0,
|
|
50453
|
+
max: 0,
|
|
50454
|
+
moving: false
|
|
50455
|
+
});
|
|
50456
|
+
/**
|
|
50179
50457
|
* On the root entity of a popup kept beneath another popup (`popup(..., { over })`). Internal to
|
|
50180
50458
|
* `ui`: not exported from the package root. Every element of that root resolves `is.covered`.
|
|
50181
50459
|
*/
|
|
@@ -51908,8 +52186,9 @@ function windowFormOf(node) {
|
|
|
51908
52186
|
}
|
|
51909
52187
|
/**
|
|
51910
52188
|
* Refuses the props of a scroll its windowed form cannot take: some but not all of `rows`,
|
|
51911
|
-
* `rowHeight` and `row`,
|
|
51912
|
-
* patched, so a refused
|
|
52189
|
+
* `rowHeight` and `row`, a row height that is not above 0, or `axis: "x"`, since the rows of a
|
|
52190
|
+
* window stand one below the other. Called before anything is spawned or patched, so a refused
|
|
52191
|
+
* scroll leaves no half-made element.
|
|
51913
52192
|
*
|
|
51914
52193
|
* @param node - The node being placed.
|
|
51915
52194
|
* @throws {Error} For a windowed scroll whose props do not hold.
|
|
@@ -51919,7 +52198,50 @@ function windowFormOf(node) {
|
|
|
51919
52198
|
* ```
|
|
51920
52199
|
*/
|
|
51921
52200
|
function checkWindow(node) {
|
|
51922
|
-
if (node.type
|
|
52201
|
+
if (node.type !== "scroll") return;
|
|
52202
|
+
if (windowFormOf(node) !== void 0 && axisOf(node) === "x") throw new Error("[game] A windowed scroll moves on y only.\n Drop axis \"x\" or use the children form.");
|
|
52203
|
+
}
|
|
52204
|
+
/**
|
|
52205
|
+
* The axis a scroll moves on: `"x"` when its props say so, else `"y"`.
|
|
52206
|
+
*
|
|
52207
|
+
* @param node - The node of a scroll.
|
|
52208
|
+
* @returns The axis.
|
|
52209
|
+
* @example
|
|
52210
|
+
* ```ts
|
|
52211
|
+
* axisOf({ type: "scroll", props: { axis: "x" }, children: [] }); // "x"
|
|
52212
|
+
* ```
|
|
52213
|
+
*/
|
|
52214
|
+
function axisOf(node) {
|
|
52215
|
+
return node.props.axis === "x" ? "x" : "y";
|
|
52216
|
+
}
|
|
52217
|
+
/**
|
|
52218
|
+
* The motion record a scroll spawns with: its axis, still at the start, not placed yet. The
|
|
52219
|
+
* first solve puts it at its `offset` prop.
|
|
52220
|
+
*
|
|
52221
|
+
* @param node - The node of the scroll that enters.
|
|
52222
|
+
* @returns A new record.
|
|
52223
|
+
* @example
|
|
52224
|
+
* ```ts
|
|
52225
|
+
* scrollMotionOf({ type: "scroll", props: { axis: "x" }, children: [] }).mode; // "still"
|
|
52226
|
+
* ```
|
|
52227
|
+
*/
|
|
52228
|
+
function scrollMotionOf(node) {
|
|
52229
|
+
return {
|
|
52230
|
+
axis: axisOf(node),
|
|
52231
|
+
mode: "still",
|
|
52232
|
+
offset: 0,
|
|
52233
|
+
max: 0,
|
|
52234
|
+
velocity: 0,
|
|
52235
|
+
from: 0,
|
|
52236
|
+
to: 0,
|
|
52237
|
+
duration: 0,
|
|
52238
|
+
elapsed: 0,
|
|
52239
|
+
pointer: 0,
|
|
52240
|
+
start: 0,
|
|
52241
|
+
seen: 0,
|
|
52242
|
+
placed: false,
|
|
52243
|
+
atProp: false
|
|
52244
|
+
};
|
|
51923
52245
|
}
|
|
51924
52246
|
/**
|
|
51925
52247
|
* Builds a spacer: an empty node of a fixed height that never shrinks.
|
|
@@ -54345,15 +54667,23 @@ const VISUALS = [
|
|
|
54345
54667
|
];
|
|
54346
54668
|
/**
|
|
54347
54669
|
* The input components of an element and the Escape marker; a disabled or covered button drops
|
|
54348
|
-
* the answering one and the marker.
|
|
54670
|
+
* the answering one and the marker. A scroll's three hold its runtime state.
|
|
54349
54671
|
*/
|
|
54350
54672
|
const INPUTS = [
|
|
54351
54673
|
Tappable,
|
|
54352
54674
|
Touchable,
|
|
54353
54675
|
LocalWrite,
|
|
54354
54676
|
Scroll,
|
|
54677
|
+
Scrollable,
|
|
54678
|
+
ScrollState,
|
|
54355
54679
|
Escapable
|
|
54356
54680
|
];
|
|
54681
|
+
/** The components of a scroll that hold where it stands: added once, never patched by a render. */
|
|
54682
|
+
const SCROLL_STATE = namesOf$1([
|
|
54683
|
+
Scroll,
|
|
54684
|
+
Scrollable,
|
|
54685
|
+
ScrollState
|
|
54686
|
+
]);
|
|
54357
54687
|
/**
|
|
54358
54688
|
* One list of the visual and the input types. Its own function, because lint rule L5 refuses a
|
|
54359
54689
|
* collection built in a module-scope declaration.
|
|
@@ -54368,6 +54698,14 @@ function concatTypes(...lists) {
|
|
|
54368
54698
|
const LIVE_TYPES = concatTypes(VISUALS, INPUTS);
|
|
54369
54699
|
/** The owned fields of a type that gives none to a plugin: one list, never a new one. */
|
|
54370
54700
|
const NO_OWNED = [];
|
|
54701
|
+
/** The time of a reconcile a test steps by hand: no ms pass, so no scroll moves. */
|
|
54702
|
+
const NO_TIME = Object.freeze({
|
|
54703
|
+
delta: 0,
|
|
54704
|
+
elapsed: 0,
|
|
54705
|
+
scale: 1,
|
|
54706
|
+
frame: 0,
|
|
54707
|
+
idle: false
|
|
54708
|
+
});
|
|
54371
54709
|
/**
|
|
54372
54710
|
* Tells whether a list of component values holds one of a type.
|
|
54373
54711
|
*
|
|
@@ -54408,6 +54746,11 @@ const ELEMENT_OWNED = namesOf$1([
|
|
|
54408
54746
|
]);
|
|
54409
54747
|
/** The style of a scroll's content: one object, so a render never reads as a new style. */
|
|
54410
54748
|
const CONTENT_STYLE = Object.freeze({ origin: "topLeft" });
|
|
54749
|
+
/** The style of an x scroll's content: its children stand side by side. */
|
|
54750
|
+
const CONTENT_ROW_STYLE = Object.freeze({
|
|
54751
|
+
origin: "topLeft",
|
|
54752
|
+
direction: "row"
|
|
54753
|
+
});
|
|
54411
54754
|
/**
|
|
54412
54755
|
* The props, besides `style`, `state` and `content`, that a live element is written from: `bind`,
|
|
54413
54756
|
* `texture`, `name` and `fit` reach its visual, `intent`, `payload`, `local` and `escape` its
|
|
@@ -54445,23 +54788,24 @@ function writesSame(previous, next) {
|
|
|
54445
54788
|
/**
|
|
54446
54789
|
* The children one element is diffed against. A scroll container holds exactly one of them: the
|
|
54447
54790
|
* content the finger moves, which keeps the rects of its own children and carries them along. Its
|
|
54448
|
-
* pivot is its top-left corner, so the scroll step writes its offset straight into `y`; it
|
|
54449
|
-
* its children out as a column. The content of a windowed scroll
|
|
54450
|
-
* the two spacers and the rows, instead of the markup's children.
|
|
54791
|
+
* pivot is its top-left corner, so the scroll step writes its offset straight into `x` or `y`; it
|
|
54792
|
+
* lays its children out as a column, or as a row on the `x` axis. The content of a windowed scroll
|
|
54793
|
+
* holds the slots of its window, the two spacers and the rows, instead of the markup's children.
|
|
54451
54794
|
*
|
|
54452
54795
|
* @param node - The node the markup wrote.
|
|
54453
54796
|
* @param slots - The slots of a windowed scroll, top spacer to bottom spacer.
|
|
54797
|
+
* @param axis - The axis of a scroll, the one it spawned with.
|
|
54454
54798
|
* @returns The children of the element.
|
|
54455
54799
|
* @example
|
|
54456
54800
|
* ```ts
|
|
54457
54801
|
* childrenOf({ type: "scroll", props: {}, children: [] }).length; // 1
|
|
54458
54802
|
* ```
|
|
54459
54803
|
*/
|
|
54460
|
-
function childrenOf(node, slots) {
|
|
54804
|
+
function childrenOf(node, slots, axis = "y") {
|
|
54461
54805
|
if (node.type !== "scroll") return node.children;
|
|
54462
54806
|
return [{
|
|
54463
54807
|
type: CONTENT$1,
|
|
54464
|
-
props: { style: CONTENT_STYLE },
|
|
54808
|
+
props: { style: axis === "x" ? CONTENT_ROW_STYLE : CONTENT_STYLE },
|
|
54465
54809
|
children: slots ?? node.children
|
|
54466
54810
|
}];
|
|
54467
54811
|
}
|
|
@@ -54540,16 +54884,15 @@ function styleOf(node) {
|
|
|
54540
54884
|
return typeof style === "object" && style !== null ? style : void 0;
|
|
54541
54885
|
}
|
|
54542
54886
|
/**
|
|
54543
|
-
* Refuses the tags that cannot be placed: a text field that names no local field, a
|
|
54544
|
-
* scroll
|
|
54887
|
+
* Refuses the tags that cannot be placed: a text field that names no local field, and a windowed
|
|
54888
|
+
* scroll whose props do not hold.
|
|
54545
54889
|
*
|
|
54546
54890
|
* @param node - The node being placed.
|
|
54547
|
-
* @throws {Error} For an `input` tag without `local`, for a
|
|
54548
|
-
*
|
|
54891
|
+
* @throws {Error} For an `input` tag without `local`, and for a windowed scroll whose props do
|
|
54892
|
+
* not hold.
|
|
54549
54893
|
*/
|
|
54550
54894
|
function checkTag(node) {
|
|
54551
54895
|
if (node.type === "input" && typeof node.props.local !== "string") throw new Error("[game] An input needs a local field.\n Write <input local=\"name\" />.");
|
|
54552
|
-
if (node.type === "scroll" && node.props.axis === "x") throw new Error("[game] Horizontal scroll arrives after V3.\n Use axis \"y\".");
|
|
54553
54896
|
checkWindow(node);
|
|
54554
54897
|
}
|
|
54555
54898
|
/**
|
|
@@ -54572,16 +54915,28 @@ function answerOf(node) {
|
|
|
54572
54915
|
/**
|
|
54573
54916
|
* The input components of an element: a button answers the gate, writes local state, or only
|
|
54574
54917
|
* swallows the tap; a panel swallows the tap too, so nothing under it answers; a text field takes
|
|
54575
|
-
* the tap that starts its editing; a scroll container takes the press that moves its content
|
|
54576
|
-
*
|
|
54577
|
-
*
|
|
54918
|
+
* the tap that starts its editing; a scroll container takes the press that moves its content and
|
|
54919
|
+
* carries where it stands, on the axis it spawned with. A button of a covered popup answers
|
|
54920
|
+
* nothing, so only the top popup answers the gate. A button with the `escape` prop that answers
|
|
54921
|
+
* also carries `Escapable`, the control the Escape key taps.
|
|
54578
54922
|
*
|
|
54579
54923
|
* @param element - The element to make touchable.
|
|
54580
54924
|
* @returns The component values.
|
|
54581
54925
|
*/
|
|
54582
54926
|
function inputOf(element) {
|
|
54583
54927
|
const { type, node, is } = element;
|
|
54584
|
-
if (type === "scroll")
|
|
54928
|
+
if (type === "scroll") {
|
|
54929
|
+
const axis = element.scroll?.axis ?? "y";
|
|
54930
|
+
return [
|
|
54931
|
+
Touchable(),
|
|
54932
|
+
Scroll({ axis }),
|
|
54933
|
+
Scrollable({
|
|
54934
|
+
axis,
|
|
54935
|
+
moving: false
|
|
54936
|
+
}),
|
|
54937
|
+
ScrollState()
|
|
54938
|
+
];
|
|
54939
|
+
}
|
|
54585
54940
|
if (type === "panel" || type === "input") return [Touchable()];
|
|
54586
54941
|
if (type !== "button") return [];
|
|
54587
54942
|
if (is.disabled || is.covered) return [Touchable()];
|
|
@@ -54800,6 +55155,7 @@ function createReconciler(ctx, modules, fields) {
|
|
|
54800
55155
|
let slotsVersion = -1;
|
|
54801
55156
|
let slotsRoots = -1;
|
|
54802
55157
|
let placedUnder;
|
|
55158
|
+
let rendered = 0;
|
|
54803
55159
|
/**
|
|
54804
55160
|
* Registers the key of an element under its root, so `entityOf` and `find` answer for it. A key
|
|
54805
55161
|
* `ui` gave a node of its own, a spacer's, is never registered.
|
|
@@ -54896,13 +55252,16 @@ function createReconciler(ctx, modules, fields) {
|
|
|
54896
55252
|
trackHost(state, element);
|
|
54897
55253
|
registerKey(root, element);
|
|
54898
55254
|
if (element.type === "input") fields.enter(element);
|
|
54899
|
-
if (element.type === "scroll")
|
|
55255
|
+
if (element.type === "scroll") {
|
|
55256
|
+
state.scrolls.add(entity);
|
|
55257
|
+
element.scroll = scrollMotionOf(node);
|
|
55258
|
+
}
|
|
54900
55259
|
modules.layout.attach(element);
|
|
54901
55260
|
element.basis = {
|
|
54902
55261
|
epoch: state.epoch,
|
|
54903
55262
|
rowHeight: range.rowHeightOf(parent, node)
|
|
54904
55263
|
};
|
|
54905
|
-
diffChildren(root, element, childrenOf(node, range.slotsFor(element)), instance);
|
|
55264
|
+
diffChildren(root, element, childrenOf(node, range.slotsFor(element), element.scroll?.axis), instance);
|
|
54906
55265
|
root.needsSolve = true;
|
|
54907
55266
|
return entity;
|
|
54908
55267
|
}
|
|
@@ -55039,11 +55398,12 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55039
55398
|
/**
|
|
55040
55399
|
* Writes the visual and input components of a live element again. A visual or an input the
|
|
55041
55400
|
* element no longer carries is removed, so a variant can trade the rectangle for a nine-slice and
|
|
55042
|
-
* back, and a button that became disabled stops answering the gate. `Scroll`
|
|
55043
|
-
*
|
|
55044
|
-
*
|
|
55045
|
-
* the
|
|
55046
|
-
*
|
|
55401
|
+
* back, and a button that became disabled stops answering the gate. `Scroll`, `Scrollable` and
|
|
55402
|
+
* `ScrollState` are only ever added: where a scroll stands belongs to the finger and the scroll
|
|
55403
|
+
* step, and a new look or a new rect never resets it. The look written is recorded as the rest
|
|
55404
|
+
* of the visual, so the rest the world holds is always the one the element is drawn with: a
|
|
55405
|
+
* restore brings it back to exactly that. The extras of the `components` prop are diffed last.
|
|
55406
|
+
* Every call is one write pass of `UiCounters`.
|
|
55047
55407
|
*
|
|
55048
55408
|
* @param element - The element that changed.
|
|
55049
55409
|
*/
|
|
@@ -55060,7 +55420,8 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55060
55420
|
}
|
|
55061
55421
|
/**
|
|
55062
55422
|
* Writes one visual or input value onto a live element: added when the entity lacks it, else
|
|
55063
|
-
* its fields patched, but never a tag or
|
|
55423
|
+
* its fields patched, but never a tag or the state of a scroll, and never a field its type gives
|
|
55424
|
+
* to a plugin.
|
|
55064
55425
|
*
|
|
55065
55426
|
* @param element - The live element.
|
|
55066
55427
|
* @param value - The value of this render.
|
|
@@ -55070,7 +55431,7 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55070
55431
|
ecs.add(element.entity, value);
|
|
55071
55432
|
return;
|
|
55072
55433
|
}
|
|
55073
|
-
if (value.value === true || value.type
|
|
55434
|
+
if (value.value === true || SCROLL_STATE.has(value.type.componentName)) return;
|
|
55074
55435
|
const owned = ecs.typeOf(value.type.componentName)?.owned ?? NO_OWNED;
|
|
55075
55436
|
ecs.set(element.entity, asHandle(value.type), livePatch(value.value, owned));
|
|
55076
55437
|
}
|
|
@@ -55149,6 +55510,7 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55149
55510
|
*/
|
|
55150
55511
|
function patch(root, element, node, instance) {
|
|
55151
55512
|
checkWindow(node);
|
|
55513
|
+
warnAxis(element, node);
|
|
55152
55514
|
const change = compare(root, element, node);
|
|
55153
55515
|
const motion = node.props.motion;
|
|
55154
55516
|
const loopChanged = !sameLoop(element.motion?.loop, motion?.loop);
|
|
@@ -55169,7 +55531,22 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55169
55531
|
rowHeight: change.rowHeight
|
|
55170
55532
|
};
|
|
55171
55533
|
}
|
|
55172
|
-
diffChildren(root, element, childrenOf(node, range.slotsFor(element)), instance);
|
|
55534
|
+
diffChildren(root, element, childrenOf(node, range.slotsFor(element), element.scroll?.axis), instance);
|
|
55535
|
+
}
|
|
55536
|
+
/**
|
|
55537
|
+
* Warns once when a render gives a live scroll another `axis`: it keeps the one it spawned with.
|
|
55538
|
+
*
|
|
55539
|
+
* @param element - The element being patched.
|
|
55540
|
+
* @param node - The node of this render.
|
|
55541
|
+
*/
|
|
55542
|
+
function warnAxis(element, node) {
|
|
55543
|
+
const axis = element.scroll?.axis;
|
|
55544
|
+
if (axis === void 0 || axis === axisOf(node) || element.warned.has("scroll-axis-fixed")) return;
|
|
55545
|
+
element.warned.add("scroll-axis-fixed");
|
|
55546
|
+
ctx.log.warn("ui:scroll-axis-fixed", {
|
|
55547
|
+
key: element.key ?? element.identity,
|
|
55548
|
+
axis
|
|
55549
|
+
});
|
|
55173
55550
|
}
|
|
55174
55551
|
/**
|
|
55175
55552
|
* Counts a patch that brings a loop of another reference that is not really another loop: the
|
|
@@ -55826,8 +56203,10 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55826
56203
|
* again, the roots a scene placed again, the popups that may leave, the pull of the text being
|
|
55827
56204
|
* typed, the scroll offsets and the windowed ranges, the bound texts that show a string of
|
|
55828
56205
|
* another size, the viewport, the dirty roots and the hosted views.
|
|
56206
|
+
*
|
|
56207
|
+
* @param time - The frame's `Time`: the scrolls move by its `delta`.
|
|
55829
56208
|
*/
|
|
55830
|
-
function reconcile() {
|
|
56209
|
+
function reconcile(time = NO_TIME) {
|
|
55831
56210
|
sweep();
|
|
55832
56211
|
state.reconciles += 1;
|
|
55833
56212
|
if (state.remount) remountRoots();
|
|
@@ -55835,13 +56214,14 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55835
56214
|
settlePopups(ctx, state, unmountRoot);
|
|
55836
56215
|
fields.pull();
|
|
55837
56216
|
const containers = scrollContainers();
|
|
55838
|
-
modules.layout.scroll(containers, lookup);
|
|
56217
|
+
modules.layout.scroll(containers, lookup, time);
|
|
55839
56218
|
range.step(containers);
|
|
55840
56219
|
markResizedTexts(ctx, state, modules.layout);
|
|
55841
56220
|
markResizedIcons(ctx, state, modules.layout);
|
|
55842
56221
|
const viewportChanged = modules.styles.useViewport(ctx.deps.renderer.viewport.size());
|
|
55843
56222
|
if (viewportChanged) state.epoch += 1;
|
|
55844
56223
|
const count = dirtyRoots(viewportChanged);
|
|
56224
|
+
rendered = count;
|
|
55845
56225
|
for (let index = 0; index < count; index += 1) {
|
|
55846
56226
|
const root = dirtyList[index];
|
|
55847
56227
|
if (root !== void 0) reconcileDirtyRoot(root);
|
|
@@ -55867,16 +56247,22 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55867
56247
|
/**
|
|
55868
56248
|
* The second system of phase `layout`: every root takes its slot, then one solve per marked
|
|
55869
56249
|
* root, a root in a slot after the root of its slot and in its content box, then the rects, the
|
|
55870
|
-
* rest poses and the hooks,
|
|
55871
|
-
* the
|
|
55872
|
-
*
|
|
56250
|
+
* rest poses and the hooks, the scrolls settled on what the solve and the render gave them, and
|
|
56251
|
+
* the hosting of the hosts that came. The hints released since the last frame step are dropped
|
|
56252
|
+
* at its end, so the `change.Box` and `change.Transform` hooks the solve plays get the hint the
|
|
56253
|
+
* reconcile routed, and the next frame starts with none.
|
|
56254
|
+
*
|
|
56255
|
+
* @param time - The frame's `Time`: a scroll left moving asks for a frame only while it runs.
|
|
55873
56256
|
*/
|
|
55874
|
-
function solve() {
|
|
56257
|
+
function solve(time = NO_TIME) {
|
|
55875
56258
|
const viewport = modules.styles.viewport();
|
|
55876
56259
|
viewportBox.w = viewport?.width ?? 0;
|
|
55877
56260
|
viewportBox.h = viewport?.height ?? 0;
|
|
55878
56261
|
assignSlots();
|
|
55879
|
-
|
|
56262
|
+
const changed = layOutRoots(viewportBox);
|
|
56263
|
+
if (changed) ctx.deps.time.wake();
|
|
56264
|
+
if (changed || rendered > 0) modules.layout.settleScroll(scrollContainers(), lookup, time);
|
|
56265
|
+
rendered = 0;
|
|
55880
56266
|
settleOverlays(ctx, state, modules.layout);
|
|
55881
56267
|
if (state.risen.size > 0) {
|
|
55882
56268
|
hostViews(ctx, state, state.risen);
|
|
@@ -56053,7 +56439,8 @@ function sceneLayersOf(ctx) {
|
|
|
56053
56439
|
*
|
|
56054
56440
|
* @param ctx - Domain context of the ui plugin.
|
|
56055
56441
|
* @param modules - The styles and layout modules, injected in that order.
|
|
56056
|
-
* @returns The module: `tree`, `find` and `
|
|
56442
|
+
* @returns The module: `tree`, `find`, `lint`, `fill` and `scroll` reach the game, the rest the
|
|
56443
|
+
* frame.
|
|
56057
56444
|
*/
|
|
56058
56445
|
function createJsxApi(ctx, modules) {
|
|
56059
56446
|
const state = ctx.state.jsx;
|
|
@@ -56070,6 +56457,7 @@ function createJsxApi(ctx, modules) {
|
|
|
56070
56457
|
const frame = createReconciler(ctx, modules, fields);
|
|
56071
56458
|
const focus = createFocus(ctx, frame.markPointer, topRoot, fields);
|
|
56072
56459
|
const resolvedOf = (entity) => ctx.deps.world.ecs.get(entity, Text)?.resolved;
|
|
56460
|
+
const lookup = (entity) => state.elements.get(entity);
|
|
56073
56461
|
const find = (key) => {
|
|
56074
56462
|
for (const root of sortedRoots(state, layerNames())) {
|
|
56075
56463
|
const entity = state.byKey.get(root.entity)?.get(key);
|
|
@@ -56090,12 +56478,25 @@ function createJsxApi(ctx, modules) {
|
|
|
56090
56478
|
fields.fill(entity, value);
|
|
56091
56479
|
return true;
|
|
56092
56480
|
},
|
|
56481
|
+
scroll: (key, to) => {
|
|
56482
|
+
const entity = find(key);
|
|
56483
|
+
const element = entity === void 0 ? void 0 : lookup(entity);
|
|
56484
|
+
if (element?.scroll === void 0) {
|
|
56485
|
+
ctx.log.warn("ui:scroll-without-scroll", { key });
|
|
56486
|
+
return false;
|
|
56487
|
+
}
|
|
56488
|
+
if (!modules.layout.scrollTo(element, to, lookup)) {
|
|
56489
|
+
ctx.log.warn("ui:scroll-before-solve", { key });
|
|
56490
|
+
return false;
|
|
56491
|
+
}
|
|
56492
|
+
return true;
|
|
56493
|
+
},
|
|
56093
56494
|
open: fields.open,
|
|
56094
56495
|
pointer: (sample) => fields.pointer(sample),
|
|
56095
56496
|
tapped: (entity) => focus.tapped(entity),
|
|
56096
56497
|
reconcile: frame.reconcile,
|
|
56097
|
-
solve: () => {
|
|
56098
|
-
frame.solve();
|
|
56498
|
+
solve: (time) => {
|
|
56499
|
+
frame.solve(time);
|
|
56099
56500
|
focus.refresh();
|
|
56100
56501
|
fields.place();
|
|
56101
56502
|
},
|
|
@@ -57200,25 +57601,63 @@ function createPopupHandler(ctx, state, jsx) {
|
|
|
57200
57601
|
//#endregion
|
|
57201
57602
|
//#region src/plugins/ui/layout/scroll.ts
|
|
57202
57603
|
/**
|
|
57203
|
-
* @file ui/layout —
|
|
57204
|
-
*
|
|
57205
|
-
*
|
|
57206
|
-
*
|
|
57604
|
+
* @file ui/layout — scroll. A scroll container moves its content on its axis: with the finger,
|
|
57605
|
+
* then in a fling that slows down, or in a glide to a `snap` stop; it starts at its `offset`
|
|
57606
|
+
* prop, glides when the prop changes, and stays inside the range every solve gives it, with hard
|
|
57607
|
+
* edges. The content moves by one `Transform` write on the axis: no solve, no motion, the children
|
|
57608
|
+
* keep their rects. `Scroll` holds the offset the way the windowed range is cut with (0 and below),
|
|
57609
|
+
* `ScrollState` the way a game reads it (0 to `max`), `Scrollable` whether it moves, for `input`.
|
|
57610
|
+
* The exact numbers live on the element's `scroll` record and the samples of the press in the
|
|
57611
|
+
* layout state, written in place; the components get whole reference units. A frame allocates
|
|
57612
|
+
* nothing.
|
|
57207
57613
|
*/
|
|
57614
|
+
/** How far ahead a release carries its velocity before the nearest `snap` stop is taken, in ms. */
|
|
57615
|
+
const PROJECT_MS = 260;
|
|
57616
|
+
/** What a fling keeps of its velocity per ms. */
|
|
57617
|
+
const DECAY_PER_MS = .998;
|
|
57618
|
+
/** The speed under which a fling stops, in reference units per ms. */
|
|
57619
|
+
const STOP_SPEED = .02;
|
|
57620
|
+
/** The shortest glide, in ms. */
|
|
57621
|
+
const GLIDE_MS = 260;
|
|
57622
|
+
/** The ms each reference unit of distance adds to a glide. */
|
|
57623
|
+
const GLIDE_MS_PER_UNIT = 1.1;
|
|
57624
|
+
/** The longest glide, in ms. */
|
|
57625
|
+
const GLIDE_MAX_MS = 620;
|
|
57626
|
+
/** The samples of the last ms before a release give its velocity. */
|
|
57627
|
+
const VELOCITY_MS = 100;
|
|
57628
|
+
/** A finger that stood still for longer than this before its release lets go with no velocity, in ms. */
|
|
57629
|
+
const STILL_MS = 50;
|
|
57630
|
+
/** The numbers of one sample in the ring: where the finger was on the axis, and when. */
|
|
57631
|
+
const SAMPLE_STRIDE = 2;
|
|
57632
|
+
/** The fewest samples a release velocity is read from. */
|
|
57633
|
+
const MIN_SAMPLES = 2;
|
|
57634
|
+
/**
|
|
57635
|
+
* Keeps an offset from the start inside 0 to `max`.
|
|
57636
|
+
*
|
|
57637
|
+
* @param offset - Where the content would stand, from the start.
|
|
57638
|
+
* @param max - The largest offset.
|
|
57639
|
+
* @returns The offset it stands at.
|
|
57640
|
+
* @example
|
|
57641
|
+
* ```ts
|
|
57642
|
+
* within(420, 390); // 390
|
|
57643
|
+
* ```
|
|
57644
|
+
*/
|
|
57645
|
+
function within(offset, max) {
|
|
57646
|
+
return Math.min(max, Math.max(0, offset));
|
|
57647
|
+
}
|
|
57208
57648
|
/**
|
|
57209
|
-
*
|
|
57210
|
-
* the top.
|
|
57649
|
+
* How far a length runs past a window, in whole reference units: 0 when it fits.
|
|
57211
57650
|
*
|
|
57212
|
-
* @param
|
|
57213
|
-
* @param
|
|
57214
|
-
* @returns The offset
|
|
57651
|
+
* @param length - What is scrolled.
|
|
57652
|
+
* @param window - What shows of it.
|
|
57653
|
+
* @returns The largest offset.
|
|
57215
57654
|
* @example
|
|
57216
57655
|
* ```ts
|
|
57217
|
-
*
|
|
57656
|
+
* extent(696, 306); // 390
|
|
57218
57657
|
* ```
|
|
57219
57658
|
*/
|
|
57220
|
-
function
|
|
57221
|
-
return Math.
|
|
57659
|
+
function extent(length, window) {
|
|
57660
|
+
return Math.max(0, Math.round(length - window));
|
|
57222
57661
|
}
|
|
57223
57662
|
/**
|
|
57224
57663
|
* The content entity of a scroll container: its single child.
|
|
@@ -57232,106 +57671,491 @@ function contentOf(container, lookup) {
|
|
|
57232
57671
|
return first === void 0 ? void 0 : lookup(first);
|
|
57233
57672
|
}
|
|
57234
57673
|
/**
|
|
57235
|
-
* The
|
|
57236
|
-
*
|
|
57674
|
+
* The largest offset of a scroll on its axis: its content's rect past its own, or
|
|
57675
|
+
* `rows × rowHeight` past its height for a windowed scroll.
|
|
57237
57676
|
*
|
|
57238
|
-
* @param container - The scroll element.
|
|
57677
|
+
* @param container - The scroll element, with a solved rect.
|
|
57239
57678
|
* @param content - Its content element.
|
|
57240
|
-
* @
|
|
57679
|
+
* @param axis - The axis it moves on.
|
|
57680
|
+
* @returns The largest offset, in whole reference units.
|
|
57241
57681
|
*/
|
|
57242
|
-
function
|
|
57682
|
+
function maxOf(container, content, axis) {
|
|
57683
|
+
if (axis === "x") return extent(content.rect.w, container.rect.w);
|
|
57243
57684
|
const window = container.window;
|
|
57244
|
-
return window === void 0 ? content.rect.h : window.rows * window.rowHeight;
|
|
57685
|
+
return extent(window === void 0 ? content.rect.h : window.rows * window.rowHeight, container.rect.h);
|
|
57686
|
+
}
|
|
57687
|
+
/**
|
|
57688
|
+
* The `offset` prop of the scroll's last render: 0 when it is left out or is no finite number.
|
|
57689
|
+
*
|
|
57690
|
+
* @param container - The scroll element.
|
|
57691
|
+
* @returns The offset it asks for, from the start.
|
|
57692
|
+
*/
|
|
57693
|
+
function askedOffsetOf(container) {
|
|
57694
|
+
const offset = container.node.props.offset;
|
|
57695
|
+
return typeof offset === "number" && Number.isFinite(offset) ? offset : 0;
|
|
57696
|
+
}
|
|
57697
|
+
/**
|
|
57698
|
+
* The `snap` prop of the scroll's last render.
|
|
57699
|
+
*
|
|
57700
|
+
* @param container - The scroll element.
|
|
57701
|
+
* @returns The stops, or `undefined` when it names none.
|
|
57702
|
+
*/
|
|
57703
|
+
function snapOf(container) {
|
|
57704
|
+
const snap = container.node.props.snap;
|
|
57705
|
+
return Array.isArray(snap) && snap.length > 0 ? snap : void 0;
|
|
57706
|
+
}
|
|
57707
|
+
/**
|
|
57708
|
+
* The stop nearest to an offset, each stop kept inside 0 to `max`; the first of two as near.
|
|
57709
|
+
*
|
|
57710
|
+
* @param snap - The stops the scroll names.
|
|
57711
|
+
* @param offset - Where the release would carry it.
|
|
57712
|
+
* @param max - The largest offset.
|
|
57713
|
+
* @param fallback - Where it stays when no stop is a number.
|
|
57714
|
+
* @returns The stop.
|
|
57715
|
+
* @example
|
|
57716
|
+
* ```ts
|
|
57717
|
+
* nearestStop([0, 318, 390], 300, 390, 300); // 318
|
|
57718
|
+
* ```
|
|
57719
|
+
*/
|
|
57720
|
+
function nearestStop(snap, offset, max, fallback) {
|
|
57721
|
+
let nearest = fallback;
|
|
57722
|
+
let distance = Number.POSITIVE_INFINITY;
|
|
57723
|
+
for (const candidate of snap) {
|
|
57724
|
+
if (typeof candidate !== "number") continue;
|
|
57725
|
+
const kept = within(candidate, max);
|
|
57726
|
+
if (Math.abs(kept - offset) < distance) {
|
|
57727
|
+
nearest = kept;
|
|
57728
|
+
distance = Math.abs(kept - offset);
|
|
57729
|
+
}
|
|
57730
|
+
}
|
|
57731
|
+
return nearest;
|
|
57732
|
+
}
|
|
57733
|
+
/**
|
|
57734
|
+
* Stops a scroll where it stands.
|
|
57735
|
+
*
|
|
57736
|
+
* @param motion - Its motion.
|
|
57737
|
+
*/
|
|
57738
|
+
function stop(motion) {
|
|
57739
|
+
motion.mode = "still";
|
|
57740
|
+
motion.velocity = 0;
|
|
57741
|
+
}
|
|
57742
|
+
/**
|
|
57743
|
+
* Starts a glide to an offset, kept inside the range, on the curve `1 − (1 − p)³` over
|
|
57744
|
+
* `min(620, 260 + distance × 1.1)` ms. A scroll already there stops instead.
|
|
57745
|
+
*
|
|
57746
|
+
* @param motion - Its motion.
|
|
57747
|
+
* @param target - Where it goes, from the start.
|
|
57748
|
+
*/
|
|
57749
|
+
function glideTo(motion, target) {
|
|
57750
|
+
const to = within(target, motion.max);
|
|
57751
|
+
const distance = Math.abs(to - motion.offset);
|
|
57752
|
+
if (distance === 0) {
|
|
57753
|
+
stop(motion);
|
|
57754
|
+
return;
|
|
57755
|
+
}
|
|
57756
|
+
motion.mode = "glide";
|
|
57757
|
+
motion.velocity = 0;
|
|
57758
|
+
motion.from = motion.offset;
|
|
57759
|
+
motion.to = to;
|
|
57760
|
+
motion.elapsed = 0;
|
|
57761
|
+
motion.duration = Math.min(GLIDE_MAX_MS, GLIDE_MS + distance * GLIDE_MS_PER_UNIT);
|
|
57762
|
+
}
|
|
57763
|
+
/**
|
|
57764
|
+
* Where a sample of the press starts in the ring: `back` samples before the newest one, 0 being
|
|
57765
|
+
* the newest. The position is at the index, the time right after it.
|
|
57766
|
+
*
|
|
57767
|
+
* @param state - The layout state, which keeps the samples of the press.
|
|
57768
|
+
* @param back - How many samples before the newest; 0 to the number of slots minus 1.
|
|
57769
|
+
* @returns The index of the sample in `scrollRing`.
|
|
57770
|
+
*/
|
|
57771
|
+
function slotBefore(state, back) {
|
|
57772
|
+
const slots = state.scrollRing.length / SAMPLE_STRIDE;
|
|
57773
|
+
return (state.scrollHead + slots - 1 - back) % slots * SAMPLE_STRIDE;
|
|
57774
|
+
}
|
|
57775
|
+
/**
|
|
57776
|
+
* Follows the finger on a held scroll. The first frame of a press, a hand-off included, takes the
|
|
57777
|
+
* finger where it is as the start, stops a fling or a glide where it stands, and ends the scroll's
|
|
57778
|
+
* standing at its `offset` prop; the offset then moves against the finger, inside 0 to `max`.
|
|
57779
|
+
* Every frame adds the finger's sample to the ring.
|
|
57780
|
+
*
|
|
57781
|
+
* @param state - The layout state, which keeps the samples of the press.
|
|
57782
|
+
* @param container - The held scroll.
|
|
57783
|
+
* @param motion - Its motion.
|
|
57784
|
+
* @param pointer - The `Pointer` resource of this frame.
|
|
57785
|
+
*/
|
|
57786
|
+
function hold(state, container, motion, pointer) {
|
|
57787
|
+
const at = motion.axis === "x" ? pointer.x : pointer.y;
|
|
57788
|
+
const ring = state.scrollRing;
|
|
57789
|
+
const slots = ring.length / SAMPLE_STRIDE;
|
|
57790
|
+
if (motion.mode !== "held" || state.scrolling !== container.entity) {
|
|
57791
|
+
motion.mode = "held";
|
|
57792
|
+
motion.velocity = 0;
|
|
57793
|
+
motion.pointer = at;
|
|
57794
|
+
motion.start = motion.offset;
|
|
57795
|
+
motion.atProp = false;
|
|
57796
|
+
state.scrolling = container.entity;
|
|
57797
|
+
state.scrollSamples = 0;
|
|
57798
|
+
state.scrollMoved = state.scrollClock;
|
|
57799
|
+
}
|
|
57800
|
+
motion.offset = within(motion.start - (at - motion.pointer), motion.max);
|
|
57801
|
+
if (state.scrollSamples > 0 && ring[slotBefore(state, 0)] !== at) state.scrollMoved = state.scrollClock;
|
|
57802
|
+
ring[state.scrollHead * SAMPLE_STRIDE] = at;
|
|
57803
|
+
ring[state.scrollHead * SAMPLE_STRIDE + 1] = state.scrollClock;
|
|
57804
|
+
state.scrollHead = (state.scrollHead + 1) % slots;
|
|
57805
|
+
state.scrollSamples = Math.min(slots, state.scrollSamples + 1);
|
|
57806
|
+
}
|
|
57807
|
+
/**
|
|
57808
|
+
* The velocity of the offset at a release, in units a ms, positive toward `max`: the finger's
|
|
57809
|
+
* move over its samples of the last 100 ms, against the finger. 0 when the finger stood still for
|
|
57810
|
+
* more than 50 ms before it let go, or left a single sample.
|
|
57811
|
+
*
|
|
57812
|
+
* @param state - The layout state, which keeps the samples of the press.
|
|
57813
|
+
* @returns The velocity.
|
|
57814
|
+
*/
|
|
57815
|
+
function releaseVelocity(state) {
|
|
57816
|
+
const ring = state.scrollRing;
|
|
57817
|
+
const now = state.scrollClock;
|
|
57818
|
+
if (state.scrollSamples < MIN_SAMPLES || now - state.scrollMoved > STILL_MS) return 0;
|
|
57819
|
+
const newest = slotBefore(state, 0);
|
|
57820
|
+
let oldest = newest;
|
|
57821
|
+
for (let back = 1; back < state.scrollSamples; back += 1) {
|
|
57822
|
+
const slot = slotBefore(state, back);
|
|
57823
|
+
if ((ring[slot + 1] ?? 0) < now - VELOCITY_MS) break;
|
|
57824
|
+
oldest = slot;
|
|
57825
|
+
}
|
|
57826
|
+
const span = (ring[newest + 1] ?? 0) - (ring[oldest + 1] ?? 0);
|
|
57827
|
+
return span > 0 ? ((ring[oldest] ?? 0) - (ring[newest] ?? 0)) / span : 0;
|
|
57828
|
+
}
|
|
57829
|
+
/**
|
|
57830
|
+
* Lets go of a scroll the finger held. With `snap` it glides to the stop nearest to where its
|
|
57831
|
+
* velocity carries in 260 ms; without, it flings, or stands when it was let go too slowly. A
|
|
57832
|
+
* press whose samples a later press took lets go with no velocity.
|
|
57833
|
+
*
|
|
57834
|
+
* @param state - The layout state, which keeps the samples of the press.
|
|
57835
|
+
* @param container - The scroll that was held.
|
|
57836
|
+
* @param motion - Its motion.
|
|
57837
|
+
* @param owned - Whether the samples are this press's.
|
|
57838
|
+
*/
|
|
57839
|
+
function letGo(state, container, motion, owned) {
|
|
57840
|
+
const velocity = owned ? releaseVelocity(state) : 0;
|
|
57841
|
+
const snap = snapOf(container);
|
|
57842
|
+
if (snap !== void 0) {
|
|
57843
|
+
glideTo(motion, nearestStop(snap, motion.offset + velocity * PROJECT_MS, motion.max, motion.offset));
|
|
57844
|
+
return;
|
|
57845
|
+
}
|
|
57846
|
+
if (Math.abs(velocity) < STOP_SPEED) {
|
|
57847
|
+
stop(motion);
|
|
57848
|
+
return;
|
|
57849
|
+
}
|
|
57850
|
+
motion.mode = "fling";
|
|
57851
|
+
motion.velocity = velocity;
|
|
57852
|
+
}
|
|
57853
|
+
/**
|
|
57854
|
+
* Moves a flinging scroll by the frame: the offset by its velocity, the velocity down by 0.998 a
|
|
57855
|
+
* ms. It stops under 0.02 units a ms, or on an edge: the edges are hard and nothing passes the
|
|
57856
|
+
* rest of the fling to a parent.
|
|
57857
|
+
*
|
|
57858
|
+
* @param motion - Its motion.
|
|
57859
|
+
* @param time - The frame's `Time`.
|
|
57860
|
+
*/
|
|
57861
|
+
function fling(motion, time) {
|
|
57862
|
+
const delta = time.delta;
|
|
57863
|
+
const next = motion.offset + motion.velocity * delta;
|
|
57864
|
+
motion.offset = within(next, motion.max);
|
|
57865
|
+
motion.velocity *= DECAY_PER_MS ** delta;
|
|
57866
|
+
if (motion.offset !== next || Math.abs(motion.velocity) < STOP_SPEED) stop(motion);
|
|
57245
57867
|
}
|
|
57246
57868
|
/**
|
|
57247
|
-
*
|
|
57869
|
+
* Moves a gliding scroll by the frame along `1 − (1 − p)³`; at its end it stands on its target.
|
|
57870
|
+
*
|
|
57871
|
+
* @param motion - Its motion.
|
|
57872
|
+
* @param time - The frame's `Time`.
|
|
57873
|
+
*/
|
|
57874
|
+
function glide(motion, time) {
|
|
57875
|
+
motion.elapsed += time.delta;
|
|
57876
|
+
const progress = Math.min(1, motion.elapsed / motion.duration);
|
|
57877
|
+
if (progress === 1) {
|
|
57878
|
+
motion.offset = motion.to;
|
|
57879
|
+
stop(motion);
|
|
57880
|
+
return;
|
|
57881
|
+
}
|
|
57882
|
+
const left = 1 - progress;
|
|
57883
|
+
motion.offset = motion.from + (motion.to - motion.from) * (1 - left * left * left);
|
|
57884
|
+
}
|
|
57885
|
+
/**
|
|
57886
|
+
* Moves the content to a whole offset on the scroll's axis, from where the solve put it: one
|
|
57887
|
+
* `Transform` write, none when it stands there already. The rects of the solve are whole numbers
|
|
57888
|
+
* that Yoga hands out as doubles; rounded, the pose is a small integer, which `Object.assign`
|
|
57889
|
+
* copies into the world without a box.
|
|
57248
57890
|
*
|
|
57249
57891
|
* @param ctx - Domain context of the ui plugin.
|
|
57892
|
+
* @param state - The layout state, which keeps the patches.
|
|
57250
57893
|
* @param container - The scroll element.
|
|
57251
57894
|
* @param content - Its content element.
|
|
57252
|
-
* @param
|
|
57895
|
+
* @param motion - Its motion.
|
|
57253
57896
|
*/
|
|
57254
|
-
function moveContent(ctx, container, content,
|
|
57897
|
+
function moveContent(ctx, state, container, content, motion) {
|
|
57255
57898
|
const ecs = ctx.deps.world.ecs;
|
|
57256
|
-
ecs.
|
|
57257
|
-
|
|
57258
|
-
|
|
57259
|
-
|
|
57260
|
-
|
|
57899
|
+
const pose = ecs.get(content.entity, Transform);
|
|
57900
|
+
const offset = Math.round(motion.offset);
|
|
57901
|
+
if (pose === void 0) return;
|
|
57902
|
+
if (motion.axis === "x") {
|
|
57903
|
+
const x = Math.round(content.rect.x - container.rect.x) - offset;
|
|
57904
|
+
if (pose.x === x) return;
|
|
57905
|
+
state.scrollPatches.x.x = x;
|
|
57906
|
+
ecs.set(content.entity, Transform, state.scrollPatches.x);
|
|
57907
|
+
return;
|
|
57908
|
+
}
|
|
57909
|
+
const y = Math.round(content.rect.y - container.rect.y) - offset;
|
|
57910
|
+
if (pose.y === y) return;
|
|
57911
|
+
state.scrollPatches.y.y = y;
|
|
57912
|
+
ecs.set(content.entity, Transform, state.scrollPatches.y);
|
|
57261
57913
|
}
|
|
57262
57914
|
/**
|
|
57263
|
-
*
|
|
57264
|
-
* when
|
|
57915
|
+
* Writes what changed of a scroll, in whole units: `Scroll` when its offset or range moved,
|
|
57916
|
+
* `ScrollState` when the offset, `max` or `moving` changed, `Scrollable` when `moving` did, and
|
|
57917
|
+
* the content's pose. A frame where nothing changed writes nothing.
|
|
57265
57918
|
*
|
|
57266
57919
|
* @param ctx - Domain context of the ui plugin.
|
|
57267
|
-
* @param
|
|
57920
|
+
* @param state - The layout state, which keeps the patches.
|
|
57921
|
+
* @param container - The scroll element.
|
|
57268
57922
|
* @param content - Its content element.
|
|
57269
|
-
* @param
|
|
57270
|
-
|
|
57271
|
-
|
|
57272
|
-
|
|
57273
|
-
const
|
|
57274
|
-
|
|
57275
|
-
const
|
|
57276
|
-
const
|
|
57277
|
-
|
|
57278
|
-
|
|
57279
|
-
|
|
57280
|
-
|
|
57281
|
-
|
|
57282
|
-
|
|
57923
|
+
* @param motion - Its motion.
|
|
57924
|
+
*/
|
|
57925
|
+
function show(ctx, state, container, content, motion) {
|
|
57926
|
+
const ecs = ctx.deps.world.ecs;
|
|
57927
|
+
const patches = state.scrollPatches;
|
|
57928
|
+
const offset = Math.round(motion.offset);
|
|
57929
|
+
const moving = motion.mode !== "still";
|
|
57930
|
+
const scroll = ecs.get(container.entity, Scroll);
|
|
57931
|
+
const shown = ecs.get(container.entity, ScrollState);
|
|
57932
|
+
const scrollable = ecs.get(container.entity, Scrollable);
|
|
57933
|
+
const rangeMoved = scroll !== void 0 && (scroll.offset !== 0 - offset || scroll.min !== 0 - motion.max);
|
|
57934
|
+
const stateMoved = shown !== void 0 && (shown.offset !== offset || shown.max !== motion.max || shown.moving !== moving);
|
|
57935
|
+
if (rangeMoved) {
|
|
57936
|
+
patches.scroll.offset = 0 - offset;
|
|
57937
|
+
patches.scroll.min = 0 - motion.max;
|
|
57938
|
+
ecs.set(container.entity, Scroll, patches.scroll);
|
|
57939
|
+
}
|
|
57940
|
+
if (stateMoved) {
|
|
57941
|
+
patches.state.offset = offset;
|
|
57942
|
+
patches.state.max = motion.max;
|
|
57943
|
+
patches.state.moving = moving;
|
|
57944
|
+
ecs.set(container.entity, ScrollState, patches.state);
|
|
57945
|
+
}
|
|
57946
|
+
if (scrollable !== void 0 && scrollable.moving !== moving) {
|
|
57947
|
+
patches.scrollable.moving = moving;
|
|
57948
|
+
ecs.set(container.entity, Scrollable, patches.scrollable);
|
|
57949
|
+
}
|
|
57950
|
+
moveContent(ctx, state, container, content, motion);
|
|
57283
57951
|
}
|
|
57284
57952
|
/**
|
|
57285
|
-
*
|
|
57286
|
-
*
|
|
57953
|
+
* Tells whether a scroll has nothing to do this frame: its first solve has not placed it yet, or
|
|
57954
|
+
* it stands still and no finger is on it.
|
|
57955
|
+
*
|
|
57956
|
+
* @param motion - Its motion.
|
|
57957
|
+
* @param pressed - Whether a finger is on it.
|
|
57958
|
+
* @returns True when the frame leaves it alone.
|
|
57959
|
+
*/
|
|
57960
|
+
function isIdle(motion, pressed) {
|
|
57961
|
+
return !motion.placed || !pressed && motion.mode === "still";
|
|
57962
|
+
}
|
|
57963
|
+
/**
|
|
57964
|
+
* Moves one scroll by the frame: the finger while it is pressed, the release when it lets go,
|
|
57965
|
+
* then a fling or a glide, and writes what changed. A still scroll no finger is on costs a tag
|
|
57966
|
+
* check.
|
|
57287
57967
|
*
|
|
57288
57968
|
* @param ctx - Domain context of the ui plugin.
|
|
57969
|
+
* @param state - The layout state.
|
|
57289
57970
|
* @param container - The live scroll element.
|
|
57290
|
-
* @param contentHeight - `rows × rowHeight` of this render.
|
|
57291
57971
|
* @param lookup - How a child entity becomes its element.
|
|
57292
|
-
* @
|
|
57972
|
+
* @param pointer - The `Pointer` resource of this frame.
|
|
57973
|
+
* @param time - The frame's `Time`.
|
|
57974
|
+
* @returns True while the scroll moves.
|
|
57293
57975
|
*/
|
|
57294
|
-
function
|
|
57976
|
+
function stepOne(ctx, state, container, lookup, pointer, time) {
|
|
57977
|
+
const ecs = ctx.deps.world.ecs;
|
|
57978
|
+
const pressed = ecs.has(container.entity, Pressed);
|
|
57979
|
+
const released = !pressed && state.scrolling === container.entity;
|
|
57980
|
+
if (released) state.scrolling = void 0;
|
|
57981
|
+
const motion = container.scroll;
|
|
57982
|
+
if (motion === void 0 || isIdle(motion, pressed)) return false;
|
|
57295
57983
|
const content = contentOf(container, lookup);
|
|
57296
|
-
if (content === void 0
|
|
57297
|
-
|
|
57984
|
+
if (content === void 0 || !ecs.has(container.entity, Scroll)) return false;
|
|
57985
|
+
if (pressed) hold(state, container, motion, pointer);
|
|
57986
|
+
else if (motion.mode === "held") letGo(state, container, motion, released);
|
|
57987
|
+
if (motion.mode === "fling") fling(motion, time);
|
|
57988
|
+
else if (motion.mode === "glide") glide(motion, time);
|
|
57989
|
+
show(ctx, state, container, content, motion);
|
|
57990
|
+
return motion.mode !== "still";
|
|
57298
57991
|
}
|
|
57299
57992
|
/**
|
|
57300
|
-
* Moves
|
|
57301
|
-
*
|
|
57993
|
+
* Moves every scroll container by the frame: with the finger while it is pressed, then in a
|
|
57994
|
+
* fling or a glide after it lets go. Time is the frame's `delta`, so a time scale and a pause
|
|
57995
|
+
* apply. While a scroll moves, `time.wake()` keeps the frames coming; at a time scale of 0 no
|
|
57996
|
+
* frame is asked for: a fling or a glide stands where it is and goes on once time runs again,
|
|
57997
|
+
* and a finger's samples wake the loop themselves.
|
|
57302
57998
|
*
|
|
57303
57999
|
* @param ctx - Domain context of the ui plugin.
|
|
57304
|
-
* @param state - The layout state, which
|
|
58000
|
+
* @param state - The layout state, which keeps the samples of the press.
|
|
57305
58001
|
* @param containers - The live scroll elements.
|
|
57306
58002
|
* @param lookup - How a child entity becomes its element.
|
|
58003
|
+
* @param time - The frame's `Time`.
|
|
58004
|
+
*/
|
|
58005
|
+
function stepScroll(ctx, state, containers, lookup, time) {
|
|
58006
|
+
const pointer = ctx.deps.world.ecs.resource(Pointer);
|
|
58007
|
+
let moving = false;
|
|
58008
|
+
state.scrollClock += time.delta;
|
|
58009
|
+
for (const container of containers) if (stepOne(ctx, state, container, lookup, pointer, time)) moving = true;
|
|
58010
|
+
if (moving && time.delta > 0) ctx.deps.time.wake();
|
|
58011
|
+
}
|
|
58012
|
+
/**
|
|
58013
|
+
* Takes a new range: the offset keeps inside it at once, and so does a running glide. A scroll
|
|
58014
|
+
* that follows its `offset` prop goes on following it in the new range: standing, it stands at
|
|
58015
|
+
* the prop at once; gliding to it, it glides on to it from where it is. So a prop the first range
|
|
58016
|
+
* was too short for is reached once the content grows, a text measured again when its font
|
|
58017
|
+
* arrives.
|
|
58018
|
+
*
|
|
58019
|
+
* @param motion - The motion of the scroll.
|
|
58020
|
+
* @param max - The largest offset the solve gives it now.
|
|
58021
|
+
*/
|
|
58022
|
+
function resize(motion, max) {
|
|
58023
|
+
if (max === motion.max) return;
|
|
58024
|
+
motion.max = max;
|
|
58025
|
+
motion.offset = within(motion.offset, max);
|
|
58026
|
+
motion.from = within(motion.from, max);
|
|
58027
|
+
motion.to = within(motion.to, max);
|
|
58028
|
+
if (!motion.atProp) return;
|
|
58029
|
+
if (motion.mode === "glide") glideTo(motion, motion.seen);
|
|
58030
|
+
else motion.offset = within(motion.seen, max);
|
|
58031
|
+
}
|
|
58032
|
+
/**
|
|
58033
|
+
* Puts a scroll the solve just spawned at its `offset` prop, inside its range, and lets it follow
|
|
58034
|
+
* the prop from there. Its spawn waits in the queue of the phase: these values replace the queued
|
|
58035
|
+
* ones at the flush, before the first draw.
|
|
58036
|
+
*
|
|
58037
|
+
* @param ctx - Domain context of the ui plugin.
|
|
58038
|
+
* @param container - The scroll element, live since this solve.
|
|
58039
|
+
* @param content - Its content element.
|
|
58040
|
+
* @param motion - Its motion, not placed yet.
|
|
57307
58041
|
*/
|
|
57308
|
-
function
|
|
58042
|
+
function place$1(ctx, container, content, motion) {
|
|
57309
58043
|
const ecs = ctx.deps.world.ecs;
|
|
57310
|
-
const
|
|
58044
|
+
const rest = content.rest;
|
|
58045
|
+
motion.placed = true;
|
|
58046
|
+
motion.atProp = true;
|
|
58047
|
+
motion.max = maxOf(container, content, motion.axis);
|
|
58048
|
+
motion.seen = askedOffsetOf(container);
|
|
58049
|
+
motion.offset = within(motion.seen, motion.max);
|
|
58050
|
+
const offset = Math.round(motion.offset);
|
|
58051
|
+
const pose = motion.axis === "x" ? {
|
|
58052
|
+
...rest,
|
|
58053
|
+
x: content.rect.x - container.rect.x - offset
|
|
58054
|
+
} : {
|
|
58055
|
+
...rest,
|
|
58056
|
+
y: content.rect.y - container.rect.y - offset
|
|
58057
|
+
};
|
|
58058
|
+
ecs.add(container.entity, Scroll({
|
|
58059
|
+
axis: motion.axis,
|
|
58060
|
+
offset: 0 - offset,
|
|
58061
|
+
min: 0 - motion.max
|
|
58062
|
+
}));
|
|
58063
|
+
ecs.add(container.entity, ScrollState({
|
|
58064
|
+
offset,
|
|
58065
|
+
max: motion.max,
|
|
58066
|
+
moving: false
|
|
58067
|
+
}));
|
|
58068
|
+
ecs.add(content.entity, Transform(pose));
|
|
58069
|
+
}
|
|
58070
|
+
/**
|
|
58071
|
+
* Settles a placed scroll on what the solve and the render of this frame gave it: a new range at
|
|
58072
|
+
* once, then a glide to a new `offset` prop, which the scroll follows from then on. A scroll the
|
|
58073
|
+
* finger holds only remembers the prop.
|
|
58074
|
+
*
|
|
58075
|
+
* @param ctx - Domain context of the ui plugin.
|
|
58076
|
+
* @param state - The layout state, which keeps the patches.
|
|
58077
|
+
* @param container - The scroll element.
|
|
58078
|
+
* @param content - Its content element.
|
|
58079
|
+
* @param motion - Its motion, placed.
|
|
58080
|
+
*/
|
|
58081
|
+
function settle(ctx, state, container, content, motion) {
|
|
58082
|
+
resize(motion, maxOf(container, content, motion.axis));
|
|
58083
|
+
const asked = askedOffsetOf(container);
|
|
58084
|
+
if (asked !== motion.seen) {
|
|
58085
|
+
motion.seen = asked;
|
|
58086
|
+
if (motion.mode !== "held") {
|
|
58087
|
+
glideTo(motion, asked);
|
|
58088
|
+
motion.atProp = true;
|
|
58089
|
+
}
|
|
58090
|
+
}
|
|
58091
|
+
show(ctx, state, container, content, motion);
|
|
58092
|
+
}
|
|
58093
|
+
/**
|
|
58094
|
+
* Settles every scroll on what the solve and the render of this frame gave it. A scroll the solve
|
|
58095
|
+
* just spawned takes its place at its `offset` prop. A placed one keeps inside a new range at
|
|
58096
|
+
* once, a running glide's target too, and glides to a new `offset` prop; the same value on a
|
|
58097
|
+
* re-render does nothing, and a scroll the finger holds only remembers it. A scroll left moving
|
|
58098
|
+
* wakes the loop the way `stepScroll` does: not at a time scale of 0, where it stands.
|
|
58099
|
+
*
|
|
58100
|
+
* @param ctx - Domain context of the ui plugin.
|
|
58101
|
+
* @param state - The layout state, which keeps the patches.
|
|
58102
|
+
* @param containers - The live scroll elements.
|
|
58103
|
+
* @param lookup - How a child entity becomes its element.
|
|
58104
|
+
* @param time - The frame's `Time`.
|
|
58105
|
+
*/
|
|
58106
|
+
function settleScroll(ctx, state, containers, lookup, time) {
|
|
58107
|
+
let moving = false;
|
|
57311
58108
|
for (const container of containers) {
|
|
57312
|
-
const
|
|
58109
|
+
const motion = container.scroll;
|
|
57313
58110
|
const content = contentOf(container, lookup);
|
|
57314
|
-
if (
|
|
57315
|
-
if (
|
|
57316
|
-
|
|
57317
|
-
|
|
57318
|
-
continue;
|
|
57319
|
-
}
|
|
57320
|
-
if (state.scrolling !== container.entity) {
|
|
57321
|
-
state.scrolling = container.entity;
|
|
57322
|
-
state.scrollStart = {
|
|
57323
|
-
pointerY: pointer.y,
|
|
57324
|
-
offset: scroll.offset
|
|
57325
|
-
};
|
|
57326
|
-
}
|
|
57327
|
-
const min = Math.min(0, container.rect.h - contentHeightOf(container, content));
|
|
57328
|
-
const offset = clampOffset(state.scrollStart.offset + (pointer.y - state.scrollStart.pointerY), min);
|
|
57329
|
-
moveContent(ctx, container, content, {
|
|
57330
|
-
...scroll,
|
|
57331
|
-
offset,
|
|
57332
|
-
min
|
|
57333
|
-
});
|
|
58111
|
+
if (motion === void 0 || content === void 0) continue;
|
|
58112
|
+
if (motion.placed) settle(ctx, state, container, content, motion);
|
|
58113
|
+
else place$1(ctx, container, content, motion);
|
|
58114
|
+
if (motion.mode !== "still") moving = true;
|
|
57334
58115
|
}
|
|
58116
|
+
if (moving && time.delta > 0) ctx.deps.time.wake();
|
|
58117
|
+
}
|
|
58118
|
+
/**
|
|
58119
|
+
* Re-clamps a live windowed scroll to the content height of its new rows before its range is
|
|
58120
|
+
* cut, so a list that shrank below the window moves up in the same frame.
|
|
58121
|
+
*
|
|
58122
|
+
* @param ctx - Domain context of the ui plugin.
|
|
58123
|
+
* @param state - The layout state, which keeps the patches.
|
|
58124
|
+
* @param container - The live scroll element.
|
|
58125
|
+
* @param contentHeight - `rows × rowHeight` of this render.
|
|
58126
|
+
* @param lookup - How a child entity becomes its element.
|
|
58127
|
+
* @returns The offset the content stands at, 0 and below, as `Scroll` holds it.
|
|
58128
|
+
*/
|
|
58129
|
+
function clampScroll(ctx, state, container, contentHeight, lookup) {
|
|
58130
|
+
const motion = container.scroll;
|
|
58131
|
+
const content = contentOf(container, lookup);
|
|
58132
|
+
if (motion === void 0 || !motion.placed || content === void 0) return 0;
|
|
58133
|
+
resize(motion, extent(contentHeight, container.rect.h));
|
|
58134
|
+
show(ctx, state, container, content, motion);
|
|
58135
|
+
return 0 - Math.round(motion.offset);
|
|
58136
|
+
}
|
|
58137
|
+
/**
|
|
58138
|
+
* Puts a placed scroll at an offset at once, inside its range: a fling or a glide stops, the
|
|
58139
|
+
* scroll no longer follows its `offset` prop, and `ScrollState` says it stands. A finger that
|
|
58140
|
+
* holds it goes on from there.
|
|
58141
|
+
*
|
|
58142
|
+
* @param ctx - Domain context of the ui plugin.
|
|
58143
|
+
* @param state - The layout state, which keeps the patches.
|
|
58144
|
+
* @param container - The scroll element.
|
|
58145
|
+
* @param to - Where it goes, from the start; `NaN` leaves it where it is.
|
|
58146
|
+
* @param lookup - How a child entity becomes its element.
|
|
58147
|
+
* @returns True when the scroll took it; false before its first solve placed it.
|
|
58148
|
+
*/
|
|
58149
|
+
function scrollTo(ctx, state, container, to, lookup) {
|
|
58150
|
+
const motion = container.scroll;
|
|
58151
|
+
const content = contentOf(container, lookup);
|
|
58152
|
+
if (motion === void 0 || !motion.placed || content === void 0) return false;
|
|
58153
|
+
motion.offset = within(Number.isNaN(to) ? motion.offset : to, motion.max);
|
|
58154
|
+
motion.atProp = false;
|
|
58155
|
+
stop(motion);
|
|
58156
|
+
show(ctx, state, container, content, motion);
|
|
58157
|
+
ctx.deps.time.wake();
|
|
58158
|
+
return true;
|
|
57335
58159
|
}
|
|
57336
58160
|
//#endregion
|
|
57337
58161
|
//#region src/plugins/ui/layout/solve.ts
|
|
@@ -57546,7 +58370,9 @@ function textSourceOf(ctx) {
|
|
|
57546
58370
|
};
|
|
57547
58371
|
}
|
|
57548
58372
|
/**
|
|
57549
|
-
* Writes the style of an element onto its node and keeps its measure function in step.
|
|
58373
|
+
* Writes the style of an element onto its node and keeps its measure function in step. An `x`
|
|
58374
|
+
* scroll lays its content out the way a row does: along `x`, as wide as it is, as tall as the
|
|
58375
|
+
* scroll.
|
|
57550
58376
|
*
|
|
57551
58377
|
* @param state - The layout state.
|
|
57552
58378
|
* @param source - What a text element is measured through.
|
|
@@ -57555,7 +58381,8 @@ function textSourceOf(ctx) {
|
|
|
57555
58381
|
function writeStyle(state, source, element) {
|
|
57556
58382
|
const node = state.byEntity.get(element.entity);
|
|
57557
58383
|
if (node === void 0 || state.yoga === void 0) return;
|
|
57558
|
-
|
|
58384
|
+
const tag = element.scroll?.axis === "x" ? "row" : element.type;
|
|
58385
|
+
applyStyleToNode(state.yoga, node, element.style, tag, element.parentType);
|
|
57559
58386
|
installMeasure(state, node, element, source);
|
|
57560
58387
|
}
|
|
57561
58388
|
/**
|
|
@@ -57618,8 +58445,10 @@ function createLayoutApi(ctx) {
|
|
|
57618
58445
|
play(ctx, element, hook);
|
|
57619
58446
|
},
|
|
57620
58447
|
settled: (element) => canDespawn(element),
|
|
57621
|
-
scroll: (containers, lookup) => stepScroll(ctx, state, containers, lookup),
|
|
57622
|
-
|
|
58448
|
+
scroll: (containers, lookup, time) => stepScroll(ctx, state, containers, lookup, time),
|
|
58449
|
+
settleScroll: (containers, lookup, time) => settleScroll(ctx, state, containers, lookup, time),
|
|
58450
|
+
clampScroll: (container, contentHeight, lookup) => clampScroll(ctx, state, container, contentHeight, lookup),
|
|
58451
|
+
scrollTo: (container, to, lookup) => scrollTo(ctx, state, container, to, lookup),
|
|
57623
58452
|
windowOf,
|
|
57624
58453
|
popupHandler: (jsx) => createPopupHandler(ctx, state, jsx),
|
|
57625
58454
|
guideHandler: () => createGuideHandler(ctx),
|
|
@@ -58195,12 +59024,12 @@ function openRegistrations(ctx, jsx, layout) {
|
|
|
58195
59024
|
name: "ui.reconcile",
|
|
58196
59025
|
phase: "layout",
|
|
58197
59026
|
query: [],
|
|
58198
|
-
run: jsx.reconcile
|
|
59027
|
+
run: (_rows, frame) => jsx.reconcile(frame.time)
|
|
58199
59028
|
})), ecs.system(system({
|
|
58200
59029
|
name: "ui.solve",
|
|
58201
59030
|
phase: "layout",
|
|
58202
59031
|
query: [],
|
|
58203
|
-
run: jsx.solve
|
|
59032
|
+
run: (_rows, frame) => jsx.solve(frame.time)
|
|
58204
59033
|
})), ecs.onAdded(Tree, (entity) => {
|
|
58205
59034
|
const place = projection.keyOf(entity);
|
|
58206
59035
|
jsx.mountRoot(entity, place?.projection ?? "ui", ecs.get(entity, Layer)?.name ?? "ui");
|
|
@@ -58247,6 +59076,7 @@ function stopUi(state) {
|
|
|
58247
59076
|
state.layout.nodes = 0;
|
|
58248
59077
|
state.layout.yoga = void 0;
|
|
58249
59078
|
state.layout.scrolling = void 0;
|
|
59079
|
+
state.layout.scrollSamples = 0;
|
|
58250
59080
|
state.layout.iconLine = void 0;
|
|
58251
59081
|
state.jsx.components.clear();
|
|
58252
59082
|
state.jsx.roots.clear();
|
|
@@ -58537,7 +59367,7 @@ function createModules(ctx) {
|
|
|
58537
59367
|
};
|
|
58538
59368
|
}
|
|
58539
59369
|
/**
|
|
58540
|
-
* Creates the ui API: the
|
|
59370
|
+
* Creates the ui API: the five members a game calls, flat.
|
|
58541
59371
|
*
|
|
58542
59372
|
* @param ctx - Kernel context of the ui plugin.
|
|
58543
59373
|
* @returns The plugin API.
|
|
@@ -58548,7 +59378,8 @@ function createUiApi(ctx) {
|
|
|
58548
59378
|
tree: jsx.tree,
|
|
58549
59379
|
find: jsx.find,
|
|
58550
59380
|
lint: jsx.lint,
|
|
58551
|
-
fill: jsx.fill
|
|
59381
|
+
fill: jsx.fill,
|
|
59382
|
+
scroll: jsx.scroll
|
|
58552
59383
|
};
|
|
58553
59384
|
}
|
|
58554
59385
|
//#endregion
|
|
@@ -58650,8 +59481,8 @@ function createJsxState() {
|
|
|
58650
59481
|
//#endregion
|
|
58651
59482
|
//#region src/plugins/ui/layout/state.ts
|
|
58652
59483
|
/**
|
|
58653
|
-
* Creates an empty map. Its own non-exported function, because lint rule L5 refuses a
|
|
58654
|
-
* built inside an exported declaration.
|
|
59484
|
+
* Creates an empty map. Its own non-exported function, because lint rule L5 refuses a
|
|
59485
|
+
* collection built inside an exported declaration.
|
|
58655
59486
|
*
|
|
58656
59487
|
* @returns A map with nothing in it.
|
|
58657
59488
|
*/
|
|
@@ -58659,13 +59490,39 @@ function emptyMap() {
|
|
|
58659
59490
|
return /* @__PURE__ */ new Map();
|
|
58660
59491
|
}
|
|
58661
59492
|
/**
|
|
59493
|
+
* Creates the ring of pointer samples: a position and a time for each of `SAMPLES`. Its own
|
|
59494
|
+
* non-exported function, for the same rule.
|
|
59495
|
+
*
|
|
59496
|
+
* @returns The ring, zeroed.
|
|
59497
|
+
*/
|
|
59498
|
+
function sampleRing() {
|
|
59499
|
+
return /* @__PURE__ */ new Float64Array(10);
|
|
59500
|
+
}
|
|
59501
|
+
/**
|
|
59502
|
+
* Creates the patches the scroll step writes with, every field 0 or false.
|
|
59503
|
+
*
|
|
59504
|
+
* @returns The patches.
|
|
59505
|
+
*/
|
|
59506
|
+
function scrollPatches() {
|
|
59507
|
+
return {
|
|
59508
|
+
scroll: {
|
|
59509
|
+
offset: 0,
|
|
59510
|
+
min: 0
|
|
59511
|
+
},
|
|
59512
|
+
state: {
|
|
59513
|
+
offset: 0,
|
|
59514
|
+
max: 0,
|
|
59515
|
+
moving: false
|
|
59516
|
+
},
|
|
59517
|
+
scrollable: { moving: false },
|
|
59518
|
+
x: { x: 0 },
|
|
59519
|
+
y: { y: 0 }
|
|
59520
|
+
};
|
|
59521
|
+
}
|
|
59522
|
+
/**
|
|
58662
59523
|
* Creates the layout branch of the ui state. Everything starts empty: Yoga arrives in `onStart`.
|
|
58663
59524
|
*
|
|
58664
59525
|
* @returns The module state.
|
|
58665
|
-
* @example
|
|
58666
|
-
* ```ts
|
|
58667
|
-
* createLayoutState().nodes; // 0
|
|
58668
|
-
* ```
|
|
58669
59526
|
*/
|
|
58670
59527
|
function createLayoutState() {
|
|
58671
59528
|
return {
|
|
@@ -58675,10 +59532,12 @@ function createLayoutState() {
|
|
|
58675
59532
|
measured: 0,
|
|
58676
59533
|
solves: 0,
|
|
58677
59534
|
scrolling: void 0,
|
|
58678
|
-
|
|
58679
|
-
|
|
58680
|
-
|
|
58681
|
-
|
|
59535
|
+
scrollClock: 0,
|
|
59536
|
+
scrollRing: sampleRing(),
|
|
59537
|
+
scrollHead: 0,
|
|
59538
|
+
scrollSamples: 0,
|
|
59539
|
+
scrollMoved: 0,
|
|
59540
|
+
scrollPatches: scrollPatches(),
|
|
58682
59541
|
iconLine: void 0,
|
|
58683
59542
|
order: 0,
|
|
58684
59543
|
cleanups: []
|
|
@@ -58740,9 +59599,10 @@ function createUiState(_ctx) {
|
|
|
58740
59599
|
};
|
|
58741
59600
|
}
|
|
58742
59601
|
/**
|
|
58743
|
-
* Ui plugin: `app.ui.tree()`, `app.ui.find(...)`, `app.ui.lint()`, `app.ui.fill(...)`,
|
|
58744
|
-
* text field `<input local>`, the components `Box`, `LocalWrite
|
|
58745
|
-
* `DebugTrigger`, and the helpers `defineComponent`, `defineStyle`,
|
|
59602
|
+
* Ui plugin: `app.ui.tree()`, `app.ui.find(...)`, `app.ui.lint()`, `app.ui.fill(...)`,
|
|
59603
|
+
* `app.ui.scroll(...)`, the text field `<input local>`, the components `Box`, `LocalWrite`,
|
|
59604
|
+
* `DebugTrigger` and `ScrollState`, and the helpers `defineComponent`, `defineStyle`,
|
|
59605
|
+
* `defineTokens` and `popup`.
|
|
58746
59606
|
*
|
|
58747
59607
|
* @example
|
|
58748
59608
|
* ```ts
|
|
@@ -60313,4 +61173,4 @@ const screen = [
|
|
|
60313
61173
|
uiPlugin
|
|
60314
61174
|
];
|
|
60315
61175
|
//#endregion
|
|
60316
|
-
export {
|
|
61176
|
+
export { haptic as $, PERF_LOG_VERSION as $t, types_exports$11 as A, Emitter as At, Box as B, audioPlugin as Bt, types_exports$4 as C, Touchable as Ct, types_exports$8 as D, messageArgument as Dt, types_exports$7 as E, i18nPlugin as Et, types_exports$16 as F, Glow as Ft, defineTokens as G, Animation as Gt, LocalWrite as H, assetsPlugin as Ht, types_exports$17 as I, Noise as It, platformPlugin as J, PASS_KINDS as Jt, defineStyle as K, Frames as Kt, uiPlugin as L, Outline as Lt, types_exports$13 as M, Blur as Mt, types_exports$14 as N, ColorMatrix as Nt, types_exports$9 as O, messageDuration as Ot, types_exports$15 as P, Displacement as Pt, frames as Q, PERF_GAP_BUCKETS as Qt, resolve as R, defineFilter as Rt, types_exports$3 as S, Tappable as St, types_exports$6 as T, Traced as Tt, ScrollState as U, animPlugin as Ut, DebugTrigger as V, scenesPlugin as Vt, popup as W, AnimPlayer as Wt, defineAnimation as X, MONITOR_SECTIONS as Xt, HAPTIC_KINDS as Y, frameAt as Yt, external as Z, PERF_CAUSES as Zt, defineBundles as _, Pointer as _t, cubicBezier as a, refuseStart as an, sfx as at, types_exports$1 as b, Pressed as bt, hint as c, to as cn, stagger as ct, defineScene as d, SaveUnreadableError as dn, wait as dt, PROBLEM_RULES as en, mark as et, tr as f, lifecyclePlugin as fn, inputPlugin as ft, music as g, Hovered as gt, defineEmitter as h, Held as ht, screen as i, flowPlugin as in, set as it, types_exports$12 as j, Alpha as jt, types_exports$10 as k, effectsPlugin as kt, schedule as l, type as ln, tween as lt, flattenFeatures as m, clockPlugin as mn, DropTarget as mt, createPlugin as n, DEMAND_REASONS as nn, play$1 as nt, defineEffect as o, exit as on, spawn as ot, defineFeature as p, timePlugin as pn, Draggable as pt, textPlugin as q, rendererPlugin as qt, defineGame as r, worldPlugin as rn, sequence as rt, guide as s, slot as sn, spawned as st, createApp as t, SHADER_WHATS as tn, parallel as tt, projection as u, modelPlugin as un, use as ut, load as v, PointerOver as vt, types_exports$5 as w, Traceable as wt, types_exports$2 as x, Swipeable as xt, types_exports as y, Pressable as yt, defineMotion as z, debugPlugin as zt };
|