@moku-labs/game 0.15.14 → 0.15.16
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-aLTGwuyk.d.mts → commands-Ay-OfSPt.d.mts} +5 -5
- package/dist/control.d.mts +4 -4
- package/dist/{define-DbxBzO-G.d.mts → define-BfWdvNHC.d.mts} +2 -2
- package/dist/{headless-DHtavbqk.d.mts → headless-ByFLyHxx.d.mts} +1 -1
- package/dist/{index-YUceiUFm.d.mts → index-rLpq23uS.d.mts} +7 -6
- package/dist/index.d.mts +4 -4
- package/dist/index.mjs +2 -2
- 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/{runtime-B5OD9JTT.d.mts → runtime-DkhhsFss.d.mts} +1 -1
- package/dist/{sources-Fbq_PFVH.mjs → sources-24TY22DK.mjs} +1 -1
- package/dist/{src-Co5sO4z1.mjs → src-AvZjWoPX.mjs} +454 -75
- package/dist/testing.d.mts +4 -4
- package/dist/testing.mjs +1 -1
- package/dist/{types-CuEK0Vam.d.mts → types-DOldmhIw.d.mts} +21 -5
- package/dist/{types-3bEK86Z1.d.mts → types-De1AZYym.d.mts} +2 -53
- package/dist/{types-xmH1X8qd.d.mts → types-DklpXQQk.d.mts} +132 -15
- package/dist/{types-Dm4tM5nH.d.mts → types-WqPbnC6B.d.mts} +4 -4
- package/dist/{types-_a6-ALzz.d.mts → types-qsE-I59e.d.mts} +2 -2
- package/dist/{visual-DExHHx-a.d.mts → visual-B1mq5n-9.d.mts} +6 -6
- package/dist/{visual-CbGKzlj0.mjs → visual-BStMZRVc.mjs} +28 -10
- package/dist/visual.d.mts +1 -1
- package/dist/visual.mjs +1 -1
- package/llms.txt +1 -1
- 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 { $ as component, A as localPoseOf, B as OverlayLevel, C as builtInStyles, D as textFor, E as readStyle, F as rootPoseOf, G as arcDefaults, H as Shape, I as Display, J as Exiting, K as componentsFor, L as HudPart, M as poseUnder, N as rootPointOf, O as applyPose, P as rootPoseInto, Q as Tree, R as NineSlice, U as Sprite, V as Parent, W as Transform, X as Now, Y as Layer, Z as Order, _ as uiFor, a as visualOf$1, b as Countdown, c as Covered, d as LocalWrite, f as Scroll, h as UiCounters, i as samePose, it as tag, j as parentOf$1, k as isLeaving, l as DebugTrigger, m as UI_OWNER, n as drawnRect, nt as system, o as visualRectOf, p as ScrollState, r as fitScaleOf, rt as systemsFor, s as Box, t as CONTENT$1, tt as resource, u as Escapable, x as Text, z as Overlay } from "./visual-
|
|
5
|
+
import { $ as component, A as localPoseOf, B as OverlayLevel, C as builtInStyles, D as textFor, E as readStyle, F as rootPoseOf, G as arcDefaults, H as Shape, I as Display, J as Exiting, K as componentsFor, L as HudPart, M as poseUnder, N as rootPointOf, O as applyPose, P as rootPoseInto, Q as Tree, R as NineSlice, U as Sprite, V as Parent, W as Transform, X as Now, Y as Layer, Z as Order, _ as uiFor, a as visualOf$1, b as Countdown, c as Covered, d as LocalWrite, f as Scroll, h as UiCounters, i as samePose, it as tag, j as parentOf$1, k as isLeaving, l as DebugTrigger, m as UI_OWNER, n as drawnRect, nt as system, o as visualRectOf, p as ScrollState, r as fitScaleOf, rt as systemsFor, s as Box, t as CONTENT$1, tt as resource, u as Escapable, x as Text, z as Overlay } from "./visual-BStMZRVc.mjs";
|
|
6
6
|
import { a as isDev } from "./dev-BNndV-hU.mjs";
|
|
7
7
|
import { n as isComponentDefinition } from "./component-DGg5DqKK.mjs";
|
|
8
8
|
import { n as flatten } from "./flatten-nUX9PpGo.mjs";
|
|
@@ -34675,7 +34675,7 @@ function pickVictim(state) {
|
|
|
34675
34675
|
const entry = state.manifest.bundles[name];
|
|
34676
34676
|
if (record.status !== "loaded" || entry === void 0) continue;
|
|
34677
34677
|
if (state.pinned.has(name) || isPermanent(entry.tier)) continue;
|
|
34678
|
-
if (state.sceneNamed.includes(name)) continue;
|
|
34678
|
+
if (state.sceneNamed.includes(name) || state.sceneLeaving.includes(name)) continue;
|
|
34679
34679
|
if (state.queue?.bundles.includes(name) === true) continue;
|
|
34680
34680
|
if (record.lastUsed >= smallest) continue;
|
|
34681
34681
|
smallest = record.lastUsed;
|
|
@@ -34830,8 +34830,9 @@ function featuresOnStack(ctx) {
|
|
|
34830
34830
|
}
|
|
34831
34831
|
/**
|
|
34832
34832
|
* Tells whether a bundle must stay where the game stands now: it is pinned (a bundle of the node
|
|
34833
|
-
* entered last), the mounted scene names it (the last list `sceneBundles` received),
|
|
34834
|
-
* is in `onStack`, or its tier
|
|
34833
|
+
* entered last), the mounted scene names it (the last list `sceneBundles` received), a leaving
|
|
34834
|
+
* scene named it and its elements still play their exit, its feature is in `onStack`, or its tier
|
|
34835
|
+
* is permanent.
|
|
34835
34836
|
*
|
|
34836
34837
|
* @param ctx - Domain context of the plugin.
|
|
34837
34838
|
* @param name - Name of the bundle.
|
|
@@ -34841,25 +34842,66 @@ function featuresOnStack(ctx) {
|
|
|
34841
34842
|
*/
|
|
34842
34843
|
function isHeld(ctx, name, entry, onStack) {
|
|
34843
34844
|
const state = ctx.state;
|
|
34844
|
-
return state.pinned.has(name) || state.sceneNamed.includes(name) || onStack.has(entry.feature) || isPermanent(entry.tier);
|
|
34845
|
+
return state.pinned.has(name) || state.sceneNamed.includes(name) || state.sceneLeaving.includes(name) || onStack.has(entry.feature) || isPermanent(entry.tier);
|
|
34845
34846
|
}
|
|
34846
34847
|
/**
|
|
34847
|
-
* Unloads every loaded `"leave"` bundle nobody holds any more, with the reason `"leave"
|
|
34848
|
-
*
|
|
34849
|
-
* nothing.
|
|
34848
|
+
* Unloads every loaded `"leave"` bundle nobody holds any more, with the reason `"leave"`; a
|
|
34849
|
+
* leaving scene holds its bundles only while anything carries `Exiting`. A running load is never
|
|
34850
|
+
* aborted by it, and a `"budget"` bundle is never touched. Headless it does nothing.
|
|
34850
34851
|
*
|
|
34851
34852
|
* @param ctx - Domain context of the plugin.
|
|
34852
34853
|
*/
|
|
34853
34854
|
function releaseLeftBundles(ctx) {
|
|
34854
34855
|
const state = ctx.state;
|
|
34855
34856
|
if (state.io === void 0) return;
|
|
34857
|
+
if (state.sceneLeaving.length > 0 && state.exiting === 0) state.sceneLeaving = [];
|
|
34856
34858
|
const onStack = featuresOnStack(ctx);
|
|
34857
|
-
for (const
|
|
34858
|
-
|
|
34859
|
-
|
|
34860
|
-
|
|
34861
|
-
|
|
34862
|
-
|
|
34859
|
+
for (const name of state.records.keys()) unloadIfLeft(ctx, name, onStack);
|
|
34860
|
+
}
|
|
34861
|
+
/**
|
|
34862
|
+
* Takes the list the mounted scene names now. A bundle the list named before and names no more
|
|
34863
|
+
* stays held as a leaving scene's, until nothing carries `Exiting` (F51); a name the list takes
|
|
34864
|
+
* again is the mounted scene's once more.
|
|
34865
|
+
*
|
|
34866
|
+
* @param state - The plugin state.
|
|
34867
|
+
* @param named - The bundles the mounted scene names now.
|
|
34868
|
+
*/
|
|
34869
|
+
function nameSceneBundles(state, named) {
|
|
34870
|
+
const leaving = state.sceneLeaving.filter((name) => !named.includes(name));
|
|
34871
|
+
for (const name of state.sceneNamed) if (!named.includes(name) && !leaving.includes(name)) leaving.push(name);
|
|
34872
|
+
state.sceneLeaving = leaving;
|
|
34873
|
+
state.sceneNamed = [...named];
|
|
34874
|
+
}
|
|
34875
|
+
/**
|
|
34876
|
+
* Lets the bundles a leaving scene named go once nothing carries `Exiting` any more: each loaded
|
|
34877
|
+
* `"leave"` bundle among them that nothing else holds is unloaded with the reason `"leave"`, at
|
|
34878
|
+
* once, not at the next rest. A bundle of another release stays, as it would have. The world calls
|
|
34879
|
+
* it through `onRemoved(Exiting)`, so the check costs a length read while no scene leaves, and
|
|
34880
|
+
* a count read while one does.
|
|
34881
|
+
*
|
|
34882
|
+
* @param ctx - Domain context of the plugin.
|
|
34883
|
+
*/
|
|
34884
|
+
function releaseSceneLeft(ctx) {
|
|
34885
|
+
const state = ctx.state;
|
|
34886
|
+
if (state.sceneLeaving.length === 0 || state.exiting > 0) return;
|
|
34887
|
+
const names = state.sceneLeaving;
|
|
34888
|
+
state.sceneLeaving = [];
|
|
34889
|
+
if (state.io === void 0) return;
|
|
34890
|
+
const onStack = featuresOnStack(ctx);
|
|
34891
|
+
for (const name of names) unloadIfLeft(ctx, name, onStack);
|
|
34892
|
+
}
|
|
34893
|
+
/**
|
|
34894
|
+
* Unloads one bundle with the reason `"leave"` when it is a loaded `"leave"` bundle nobody holds.
|
|
34895
|
+
*
|
|
34896
|
+
* @param ctx - Domain context of the plugin.
|
|
34897
|
+
* @param name - Name of the bundle.
|
|
34898
|
+
* @param onStack - The features on the stack, from `featuresOnStack`.
|
|
34899
|
+
*/
|
|
34900
|
+
function unloadIfLeft(ctx, name, onStack) {
|
|
34901
|
+
const entry = ctx.state.manifest.bundles[name];
|
|
34902
|
+
if (ctx.state.records.get(name)?.status !== "loaded" || entry?.release !== "leave") return;
|
|
34903
|
+
if (isHeld(ctx, name, entry, onStack)) return;
|
|
34904
|
+
unloadBundle(ctx, name, "leave");
|
|
34863
34905
|
}
|
|
34864
34906
|
//#endregion
|
|
34865
34907
|
//#region src/plugins/scenes/bundles.ts
|
|
@@ -35337,21 +35379,22 @@ function startPreload(ctx) {
|
|
|
35337
35379
|
//#endregion
|
|
35338
35380
|
//#region src/plugins/assets/lifecycle.ts
|
|
35339
35381
|
/**
|
|
35340
|
-
* @file assets plugin — lifecycle: the
|
|
35382
|
+
* @file assets plugin — lifecycle: the five registrations of `onInit`, the boot of `onStart`
|
|
35341
35383
|
* and the teardown that frees every texture and cancels every fetch.
|
|
35342
35384
|
*/
|
|
35343
35385
|
/**
|
|
35344
|
-
* Resolves the dependency APIs `flow`, `renderer`, `time` and `
|
|
35386
|
+
* Resolves the dependency APIs `flow`, `renderer`, `time`, `model` and `world` with `ctx.require`.
|
|
35345
35387
|
*
|
|
35346
35388
|
* @param ctx - Kernel context of the assets plugin.
|
|
35347
|
-
* @returns The
|
|
35389
|
+
* @returns The five dependency APIs.
|
|
35348
35390
|
*/
|
|
35349
35391
|
function resolveDeps$5(ctx) {
|
|
35350
35392
|
return {
|
|
35351
35393
|
flow: ctx.require(flowPlugin),
|
|
35352
35394
|
renderer: ctx.require(rendererPlugin),
|
|
35353
35395
|
time: ctx.require(timePlugin),
|
|
35354
|
-
model: ctx.require(modelPlugin)
|
|
35396
|
+
model: ctx.require(modelPlugin),
|
|
35397
|
+
world: ctx.require(worldPlugin)
|
|
35355
35398
|
};
|
|
35356
35399
|
}
|
|
35357
35400
|
/**
|
|
@@ -35451,19 +35494,20 @@ async function enterNode(ctx, node, run) {
|
|
|
35451
35494
|
}
|
|
35452
35495
|
/**
|
|
35453
35496
|
* Connects the plugin in `onInit`: the `load` stage of `onEnter`, the handler of the `load`
|
|
35454
|
-
* effect
|
|
35455
|
-
*
|
|
35497
|
+
* effect, the texture provider of `renderer`, and the start and the end of an exit in `world`,
|
|
35498
|
+
* counted so a leaving scene's bundles go when the last exit ends (F51). The five removers go to
|
|
35499
|
+
* the state, because `onStop` has nothing but the state.
|
|
35456
35500
|
*
|
|
35457
35501
|
* @param ctx - Kernel context of the assets plugin.
|
|
35458
|
-
* @example
|
|
35459
|
-
* ```ts
|
|
35460
|
-
* connectAssets(ctx);
|
|
35461
|
-
* ctx.state.removers.length; // 3
|
|
35462
|
-
* ```
|
|
35463
35502
|
*/
|
|
35464
35503
|
function connectAssets(ctx) {
|
|
35465
35504
|
const assets = withDeps$6(ctx);
|
|
35466
|
-
assets.state.removers.push(assets.deps.flow.onEnter("load", (node, run) => enterNode(assets, node, run)), assets.deps.flow.fx.handle("load", (descriptor, run) => runLoadEffect(assets, descriptor, run), { runInFast: true }), assets.deps.renderer.sync.textures.provide((key) => lookupTexture(assets, key)))
|
|
35505
|
+
assets.state.removers.push(assets.deps.flow.onEnter("load", (node, run) => enterNode(assets, node, run)), assets.deps.flow.fx.handle("load", (descriptor, run) => runLoadEffect(assets, descriptor, run), { runInFast: true }), assets.deps.renderer.sync.textures.provide((key) => lookupTexture(assets, key)), assets.deps.world.ecs.onAdded(Exiting, () => {
|
|
35506
|
+
assets.state.exiting += 1;
|
|
35507
|
+
}), assets.deps.world.ecs.onRemoved(Exiting, () => {
|
|
35508
|
+
assets.state.exiting -= 1;
|
|
35509
|
+
releaseSceneLeft(assets);
|
|
35510
|
+
}));
|
|
35467
35511
|
}
|
|
35468
35512
|
/**
|
|
35469
35513
|
* Picks the I/O seam: the configured one, the browser pair over `renderer.sync.textures` when
|
|
@@ -35539,7 +35583,7 @@ async function startAssets(ctx) {
|
|
|
35539
35583
|
}
|
|
35540
35584
|
/**
|
|
35541
35585
|
* Frees everything in `onStop`: the preload and every running load are aborted, every texture is
|
|
35542
|
-
* destroyed, the
|
|
35586
|
+
* destroyed, the five registrations are removed and the registries are emptied, the companions
|
|
35543
35587
|
* too. A teardown context carries the state and nothing else, so no other plugin is called here:
|
|
35544
35588
|
* no companion's `unload` either, its plugin stopped before this one.
|
|
35545
35589
|
*
|
|
@@ -35571,6 +35615,8 @@ function releaseAll(state) {
|
|
|
35571
35615
|
state.current = void 0;
|
|
35572
35616
|
state.sceneId = void 0;
|
|
35573
35617
|
state.sceneNamed = [];
|
|
35618
|
+
state.sceneLeaving = [];
|
|
35619
|
+
state.exiting = 0;
|
|
35574
35620
|
state.restPending = false;
|
|
35575
35621
|
state.stamps = void 0;
|
|
35576
35622
|
state.swapping = void 0;
|
|
@@ -35717,9 +35763,7 @@ function createAssetsApi(ctx) {
|
|
|
35717
35763
|
font: (key) => loadedRecord(assets, key)?.fonts.get(key),
|
|
35718
35764
|
audio: (key) => loadedRecord(assets, key)?.audio.get(key),
|
|
35719
35765
|
usage: () => usage(assets),
|
|
35720
|
-
sceneBundles: (named) =>
|
|
35721
|
-
ctx.state.sceneNamed = [...named];
|
|
35722
|
-
},
|
|
35766
|
+
sceneBundles: (named) => nameSceneBundles(ctx.state, named),
|
|
35723
35767
|
has: (bundle) => Object.hasOwn(ctx.state.manifest.bundles, bundle),
|
|
35724
35768
|
companions: { add: (companion) => addCompanion(ctx.state, companion) }
|
|
35725
35769
|
};
|
|
@@ -36387,6 +36431,8 @@ function createAssetsState() {
|
|
|
36387
36431
|
stamps: void 0,
|
|
36388
36432
|
swapping: void 0,
|
|
36389
36433
|
sceneNamed: [],
|
|
36434
|
+
sceneLeaving: [],
|
|
36435
|
+
exiting: 0,
|
|
36390
36436
|
companions: [],
|
|
36391
36437
|
restPending: false
|
|
36392
36438
|
};
|
|
@@ -36411,7 +36457,8 @@ const assetsPlugin = /*#__PURE__*/ createPlugin$1("assets", {
|
|
|
36411
36457
|
flowPlugin,
|
|
36412
36458
|
rendererPlugin,
|
|
36413
36459
|
timePlugin,
|
|
36414
|
-
modelPlugin
|
|
36460
|
+
modelPlugin,
|
|
36461
|
+
worldPlugin
|
|
36415
36462
|
],
|
|
36416
36463
|
config: {
|
|
36417
36464
|
manifest: void 0,
|
|
@@ -47931,6 +47978,12 @@ const platformPlugin = /*#__PURE__*/ createPlugin$1("platform", {
|
|
|
47931
47978
|
const FALLBACK_ADVANCE = .6;
|
|
47932
47979
|
/** Line height of a style whose font is not loaded, as a share of the style size. */
|
|
47933
47980
|
const FALLBACK_LINE = 1.2;
|
|
47981
|
+
/**
|
|
47982
|
+
* How much wider than its box a line of a `"box"` style may be. `ui` lays a text out in whole units
|
|
47983
|
+
* and rounds its measure with this tolerance, so a line that adds up to a hair over a whole unit
|
|
47984
|
+
* (ten glyphs of 14.4 are 144.00000000000003) stays on the line the measure kept it on.
|
|
47985
|
+
*/
|
|
47986
|
+
const BOX_SLACK = 1e-4;
|
|
47934
47987
|
/** Splits a run's text into words, runs of spaces and line breaks, separators kept. */
|
|
47935
47988
|
const TOKENS = /(\n| +)/;
|
|
47936
47989
|
/**
|
|
@@ -48405,13 +48458,33 @@ function emptyKeys() {
|
|
|
48405
48458
|
return /* @__PURE__ */ new Set();
|
|
48406
48459
|
}
|
|
48407
48460
|
/**
|
|
48461
|
+
* The width a block of a style wraps at: the width of the style, the box for a `"box"` style that
|
|
48462
|
+
* has one, or nothing for one line per `\n` segment.
|
|
48463
|
+
*
|
|
48464
|
+
* @param style - The style of the label.
|
|
48465
|
+
* @param box - The laid-out width of the text element; 0 when it has none.
|
|
48466
|
+
* @returns The wrap width in reference pixels, or `undefined` for no wrapping.
|
|
48467
|
+
* @example
|
|
48468
|
+
* ```ts
|
|
48469
|
+
* wrapOf({ ...bodyStyle, wrap: "box" }, 0); // undefined: no box, one line
|
|
48470
|
+
* ```
|
|
48471
|
+
*/
|
|
48472
|
+
function wrapOf(style, box) {
|
|
48473
|
+
if (style.wrap === "none") return void 0;
|
|
48474
|
+
if (style.wrap !== "box") return style.wrap;
|
|
48475
|
+
return box > 0 ? box + BOX_SLACK : void 0;
|
|
48476
|
+
}
|
|
48477
|
+
/**
|
|
48408
48478
|
* Lays a block of runs out: the lines, the width of the widest one and the total height. The
|
|
48409
|
-
* alignment of the style changes nothing here; it moves the lines when they are drawn.
|
|
48479
|
+
* alignment of the style changes nothing here; it moves the lines when they are drawn. A style
|
|
48480
|
+
* with `wrap: "box"` wraps at `box`, the width `ui` laid its text element out at, and is one line
|
|
48481
|
+
* without one; any other style ignores `box`.
|
|
48410
48482
|
*
|
|
48411
48483
|
* @param runs - What `parseTags` made of the resolved string.
|
|
48412
48484
|
* @param style - The style of the label.
|
|
48413
48485
|
* @param tables - The advance tables that are loaded, by font key.
|
|
48414
48486
|
* @param options - Where a warning goes.
|
|
48487
|
+
* @param box - The width a `"box"` style wraps at, in reference pixels; 0 for none.
|
|
48415
48488
|
* @returns The lines and the size of the block in reference pixels.
|
|
48416
48489
|
* @example
|
|
48417
48490
|
* ```ts
|
|
@@ -48419,13 +48492,14 @@ function emptyKeys() {
|
|
|
48419
48492
|
* // { lines: [{ runs: [], width: 0 }], width: 0, height: 38.4 }
|
|
48420
48493
|
* ```
|
|
48421
48494
|
*/
|
|
48422
|
-
function layoutRuns(runs, style, tables, options) {
|
|
48495
|
+
function layoutRuns(runs, style, tables, options, box = 0) {
|
|
48423
48496
|
const once = onceOnly(options);
|
|
48424
|
-
const
|
|
48497
|
+
const wrap = wrapOf(style, box);
|
|
48498
|
+
const lines = wrap === void 0 ? layoutFixed(runs, style, tables, once) : layoutWrapped(runs, {
|
|
48425
48499
|
style,
|
|
48426
48500
|
tables,
|
|
48427
48501
|
options: once
|
|
48428
|
-
},
|
|
48502
|
+
}, wrap);
|
|
48429
48503
|
let width = 0;
|
|
48430
48504
|
for (const line of lines) width = Math.max(width, line.width);
|
|
48431
48505
|
return {
|
|
@@ -48720,20 +48794,34 @@ function styleOf$1(ctx, name) {
|
|
|
48720
48794
|
return ctx.state.styles.get("body") ?? builtInStyles(ctx.config.fonts).body;
|
|
48721
48795
|
}
|
|
48722
48796
|
/**
|
|
48797
|
+
* Tells whether a style wraps at the box of its text element. An unknown name is drawn as `body`,
|
|
48798
|
+
* so it answers for `body`. Two map reads, no warning: the frame step asks it.
|
|
48799
|
+
*
|
|
48800
|
+
* @param ctx - Domain context of the text plugin.
|
|
48801
|
+
* @param styleName - The style name a component wrote.
|
|
48802
|
+
* @returns True for a style with `wrap: "box"`.
|
|
48803
|
+
*/
|
|
48804
|
+
function wrapsAtBox(ctx, styleName) {
|
|
48805
|
+
return (ctx.state.styles.get(styleName) ?? ctx.state.styles.get("body"))?.wrap === "box";
|
|
48806
|
+
}
|
|
48807
|
+
/**
|
|
48723
48808
|
* The layout of one resolved string in one style, from the cache or freshly laid out. The cache
|
|
48724
|
-
* is what makes `measure` cheap enough for `ui` to ask per invalidation.
|
|
48809
|
+
* is what makes `measure` cheap enough for `ui` to ask per invalidation. A `"box"` style with a
|
|
48810
|
+
* box is cached per width too; any other style ignores the box and keeps one layout.
|
|
48725
48811
|
*
|
|
48726
48812
|
* @param ctx - Domain context of the text plugin.
|
|
48727
48813
|
* @param resolved - The tagged string.
|
|
48728
48814
|
* @param styleName - The style name.
|
|
48815
|
+
* @param box - The width a `"box"` style wraps at; 0 for one line.
|
|
48729
48816
|
* @returns The lines and the size of the block.
|
|
48730
48817
|
*/
|
|
48731
|
-
function layoutFor(ctx, resolved, styleName) {
|
|
48732
|
-
const
|
|
48818
|
+
function layoutFor(ctx, resolved, styleName, box = 0) {
|
|
48819
|
+
const width = box > 0 && wrapsAtBox(ctx, styleName) ? box : 0;
|
|
48820
|
+
const key = width > 0 ? `${styleName}${CACHE_SEPARATOR}${width}${CACHE_SEPARATOR}${resolved}` : `${styleName}${CACHE_SEPARATOR}${resolved}`;
|
|
48733
48821
|
const hit = ctx.state.cache.get(key);
|
|
48734
48822
|
if (hit !== void 0) return hit;
|
|
48735
48823
|
const warn = warnFor(ctx);
|
|
48736
|
-
const layout = layoutRuns(parseTags(resolved, warn), styleOf$1(ctx, styleName), ctx.state.tables, { warn });
|
|
48824
|
+
const layout = layoutRuns(parseTags(resolved, warn), styleOf$1(ctx, styleName), ctx.state.tables, { warn }, width);
|
|
48737
48825
|
if (ctx.state.cache.size >= CACHE_LIMIT) {
|
|
48738
48826
|
const oldest = ctx.state.cache.keys().next().value;
|
|
48739
48827
|
if (oldest !== void 0) ctx.state.cache.delete(oldest);
|
|
@@ -48942,7 +49030,8 @@ function remember(ctx, entity, text, frame, unit) {
|
|
|
48942
49030
|
bindRef: text.bind,
|
|
48943
49031
|
bind: bindKeyOf(text.bind),
|
|
48944
49032
|
locale: frame.locale,
|
|
48945
|
-
unit
|
|
49033
|
+
unit,
|
|
49034
|
+
box: text.box
|
|
48946
49035
|
});
|
|
48947
49036
|
return;
|
|
48948
49037
|
}
|
|
@@ -48954,6 +49043,23 @@ function remember(ctx, entity, text, frame, unit) {
|
|
|
48954
49043
|
seen.style = text.style;
|
|
48955
49044
|
seen.locale = frame.locale;
|
|
48956
49045
|
seen.unit = unit;
|
|
49046
|
+
seen.box = text.box;
|
|
49047
|
+
}
|
|
49048
|
+
/**
|
|
49049
|
+
* Tells whether a label of a `"box"` style was laid out at another box than it carries now. The
|
|
49050
|
+
* box of a label of any other style is only noted: it draws the same at every width, so a resize
|
|
49051
|
+
* resolves nothing. A label whose box stands costs one compare.
|
|
49052
|
+
*
|
|
49053
|
+
* @param ctx - Domain context of the text plugin.
|
|
49054
|
+
* @param seen - What was resolved for the label last.
|
|
49055
|
+
* @param text - Its component value.
|
|
49056
|
+
* @returns True when the label has to be laid out at its new box.
|
|
49057
|
+
*/
|
|
49058
|
+
function boxMoved(ctx, seen, text) {
|
|
49059
|
+
if (seen.box === text.box) return false;
|
|
49060
|
+
if (wrapsAtBox(ctx, text.style)) return true;
|
|
49061
|
+
seen.box = text.box;
|
|
49062
|
+
return false;
|
|
48957
49063
|
}
|
|
48958
49064
|
/**
|
|
48959
49065
|
* Keeps the measured size of a label: made once, then overwritten in place.
|
|
@@ -48983,7 +49089,7 @@ function keepSize(ctx, entity, layout) {
|
|
|
48983
49089
|
* @returns True when nothing has to be formatted or written.
|
|
48984
49090
|
*/
|
|
48985
49091
|
function isShown(seen, text, unit, format, frame) {
|
|
48986
|
-
return seen
|
|
49092
|
+
return seen.unit === unit && seen.style === text.style && isSameBind(seen, text.bind) && (format !== "duration" || seen.locale === frame.locale);
|
|
48987
49093
|
}
|
|
48988
49094
|
/**
|
|
48989
49095
|
* Writes the new string of a bound label, its measured size, and for a countdown the time left,
|
|
@@ -49001,7 +49107,7 @@ function showBound(ctx, entity, text, next, value) {
|
|
|
49001
49107
|
ctx.deps.world.ecs.set(entity, Text, { resolved: next });
|
|
49002
49108
|
if (value !== void 0 && text.bind !== void 0 && isCountdownLeft(text.bind)) ctx.deps.world.ecs.set(entity, Countdown, { left: value });
|
|
49003
49109
|
}
|
|
49004
|
-
if (changed || !ctx.state.measured.has(entity)) keepSize(ctx, entity, layoutFor(ctx, next, text.style));
|
|
49110
|
+
if (changed || !ctx.state.measured.has(entity)) keepSize(ctx, entity, layoutFor(ctx, next, text.style, text.box));
|
|
49005
49111
|
}
|
|
49006
49112
|
/**
|
|
49007
49113
|
* Writes the string a bound label already shows once more, and measures it again. A mark on a
|
|
@@ -49015,7 +49121,7 @@ function showBound(ctx, entity, text, next, value) {
|
|
|
49015
49121
|
*/
|
|
49016
49122
|
function showAgain(ctx, entity, text) {
|
|
49017
49123
|
ctx.deps.world.ecs.set(entity, Text, { resolved: text.resolved });
|
|
49018
|
-
keepSize(ctx, entity, layoutFor(ctx, text.resolved, text.style));
|
|
49124
|
+
keepSize(ctx, entity, layoutFor(ctx, text.resolved, text.style, text.box));
|
|
49019
49125
|
}
|
|
49020
49126
|
/**
|
|
49021
49127
|
* Reports a bound label whose style is not a digits style, once per style. An unknown style name
|
|
@@ -49033,8 +49139,9 @@ function warnWithoutDigits(ctx, styleName) {
|
|
|
49033
49139
|
* One frame of a bound label: the value read every frame, the string built and written only
|
|
49034
49140
|
* when its unit moved. A label that stands still costs a read and a few compares and keeps
|
|
49035
49141
|
* nothing: no tag is parsed, no key is built. A marked label that stands still is written once
|
|
49036
|
-
* with the string it shows
|
|
49037
|
-
* a label on a wrong style
|
|
49142
|
+
* with the string it shows; one of a `"box"` style that ui laid out at another box is measured at
|
|
49143
|
+
* it. The style is checked for digits only when the label is written, so a label on a wrong style
|
|
49144
|
+
* builds no warning key per frame.
|
|
49038
49145
|
*
|
|
49039
49146
|
* @param ctx - Domain context of the text plugin.
|
|
49040
49147
|
* @param entity - The entity.
|
|
@@ -49047,10 +49154,9 @@ function stepBound(ctx, entity, text, bind, frame) {
|
|
|
49047
49154
|
const format = value === void 0 ? "int" : formatOf(ctx, entity, bind, value);
|
|
49048
49155
|
const unit = value === void 0 ? void 0 : unitOf(value, format);
|
|
49049
49156
|
const marked = ctx.state.dirty.delete(entity);
|
|
49050
|
-
|
|
49051
|
-
|
|
49052
|
-
|
|
49053
|
-
showAgain(ctx, entity, text);
|
|
49157
|
+
const seen = ctx.state.seen.get(entity);
|
|
49158
|
+
if (seen !== void 0 && isShown(seen, text, unit, format, frame)) {
|
|
49159
|
+
standStill(ctx, entity, text, seen, marked);
|
|
49054
49160
|
return;
|
|
49055
49161
|
}
|
|
49056
49162
|
warnWithoutDigits(ctx, text.style);
|
|
@@ -49058,8 +49164,27 @@ function stepBound(ctx, entity, text, bind, frame) {
|
|
|
49058
49164
|
remember(ctx, entity, text, frame, unit);
|
|
49059
49165
|
}
|
|
49060
49166
|
/**
|
|
49061
|
-
*
|
|
49062
|
-
*
|
|
49167
|
+
* One frame of a bound label whose unit stands still: a marked one is written once as it is, one of
|
|
49168
|
+
* a `"box"` style that ui laid out at another box is measured at it. Either way the box is noted.
|
|
49169
|
+
*
|
|
49170
|
+
* @param ctx - Domain context of the text plugin.
|
|
49171
|
+
* @param entity - The entity.
|
|
49172
|
+
* @param text - Its component value.
|
|
49173
|
+
* @param seen - What was resolved for the label last.
|
|
49174
|
+
* @param marked - Whether the label was marked this frame.
|
|
49175
|
+
*/
|
|
49176
|
+
function standStill(ctx, entity, text, seen, marked) {
|
|
49177
|
+
if (marked) {
|
|
49178
|
+
warnWithoutDigits(ctx, text.style);
|
|
49179
|
+
showAgain(ctx, entity, text);
|
|
49180
|
+
} else if (boxMoved(ctx, seen, text)) keepSize(ctx, entity, layoutFor(ctx, text.resolved, text.style, text.box));
|
|
49181
|
+
else return;
|
|
49182
|
+
seen.box = text.box;
|
|
49183
|
+
}
|
|
49184
|
+
/**
|
|
49185
|
+
* Tells whether a label has to be resolved again: its content, style, bind or locale moved, or
|
|
49186
|
+
* ui laid a label of a `"box"` style out at another box. Change sets are cleared every frame and
|
|
49187
|
+
* `ui` writes `Text` after this system, so the comparison is against what was seen, not `changed`.
|
|
49063
49188
|
*
|
|
49064
49189
|
* @param ctx - Domain context of the text plugin.
|
|
49065
49190
|
* @param entity - The entity.
|
|
@@ -49071,7 +49196,7 @@ function isStale(ctx, entity, text, frame) {
|
|
|
49071
49196
|
if (ctx.state.dirty.has(entity)) return true;
|
|
49072
49197
|
const seen = ctx.state.seen.get(entity);
|
|
49073
49198
|
if (seen === void 0) return true;
|
|
49074
|
-
return seen.content !== text.content || seen.style !== text.style || !isSameBind(seen, text.bind) || seen.locale !== frame.locale;
|
|
49199
|
+
return seen.content !== text.content || seen.style !== text.style || !isSameBind(seen, text.bind) || seen.locale !== frame.locale || boxMoved(ctx, seen, text);
|
|
49075
49200
|
}
|
|
49076
49201
|
/**
|
|
49077
49202
|
* One frame of one label.
|
|
@@ -49087,7 +49212,7 @@ function stepText(ctx, entity, text, frame) {
|
|
|
49087
49212
|
return;
|
|
49088
49213
|
}
|
|
49089
49214
|
if (!isStale(ctx, entity, text, frame)) return;
|
|
49090
|
-
keepSize(ctx, entity, layoutFor(ctx, resolveContent(ctx, entity, text), text.style));
|
|
49215
|
+
keepSize(ctx, entity, layoutFor(ctx, resolveContent(ctx, entity, text), text.style, text.box));
|
|
49091
49216
|
ctx.state.dirty.delete(entity);
|
|
49092
49217
|
remember(ctx, entity, text, frame);
|
|
49093
49218
|
}
|
|
@@ -49661,15 +49786,19 @@ function buildRun(ctx, pixi, run, style, at) {
|
|
|
49661
49786
|
}
|
|
49662
49787
|
/**
|
|
49663
49788
|
* The style and the laid-out block of one component value, under the generation of this moment.
|
|
49789
|
+
* A `"box"` style wraps at the box `ui` wrote; with none (a label outside a ui layout) it is one
|
|
49790
|
+
* line, and a dev warning says so once per style.
|
|
49664
49791
|
*
|
|
49665
49792
|
* @param ctx - Domain context of the text plugin.
|
|
49666
49793
|
* @param value - The component value.
|
|
49667
49794
|
* @returns What the container is filled from.
|
|
49668
49795
|
*/
|
|
49669
49796
|
function labelOf(ctx, value) {
|
|
49797
|
+
const style = styleOf$1(ctx, value.style);
|
|
49798
|
+
if (style.wrap === "box" && value.box <= 0 && value.resolved !== "") warnOnce(ctx, `wrap-box:${value.style}`, "text: wrap \"box\" outside layout", { style: value.style });
|
|
49670
49799
|
return {
|
|
49671
|
-
style
|
|
49672
|
-
layout: layoutFor(ctx, value.resolved, value.style),
|
|
49800
|
+
style,
|
|
49801
|
+
layout: layoutFor(ctx, value.resolved, value.style, value.box),
|
|
49673
49802
|
generation: ctx.state.generation
|
|
49674
49803
|
};
|
|
49675
49804
|
}
|
|
@@ -49786,8 +49915,9 @@ function samePoint(first, second) {
|
|
|
49786
49915
|
/**
|
|
49787
49916
|
* Tells whether a container already shows a value: the string, the style name and the anchor it
|
|
49788
49917
|
* was last updated with, drawn with the style object that is current and under the generation
|
|
49789
|
-
* that is current
|
|
49790
|
-
* hot swap replaced moves the generation, because the
|
|
49918
|
+
* that is current, and for a `"box"` style at the same box. A replaced style is a new object under
|
|
49919
|
+
* the same name. A font or an icon a dev hot swap replaced moves the generation, because the
|
|
49920
|
+
* objects hold textures that are destroyed. The box of any other style changes nothing drawn.
|
|
49791
49921
|
*
|
|
49792
49922
|
* @param ctx - Domain context of the text plugin.
|
|
49793
49923
|
* @param container - The container of this label.
|
|
@@ -49797,7 +49927,8 @@ function samePoint(first, second) {
|
|
|
49797
49927
|
*/
|
|
49798
49928
|
function isCurrent(ctx, container, previous, next) {
|
|
49799
49929
|
const drawn = ctx.state.drawn.get(container);
|
|
49800
|
-
|
|
49930
|
+
const boxStands = previous.box === next.box || drawn?.style.wrap !== "box";
|
|
49931
|
+
return previous.resolved === next.resolved && previous.style === next.style && samePoint(previous.anchor, next.anchor) && drawn?.style === styleOf$1(ctx, next.style) && drawn.generation === ctx.state.generation && boxStands;
|
|
49801
49932
|
}
|
|
49802
49933
|
/**
|
|
49803
49934
|
* Draws a changed value into a container that holds a label already. A ticking counter keeps its
|
|
@@ -50054,9 +50185,9 @@ function createTextApi(ctx) {
|
|
|
50054
50185
|
return domain;
|
|
50055
50186
|
};
|
|
50056
50187
|
return {
|
|
50057
|
-
measure: (content, style) => {
|
|
50188
|
+
measure: (content, style, width = 0) => {
|
|
50058
50189
|
const tctx = text();
|
|
50059
|
-
return sizeOf(layoutFor(tctx, sourceOf(tctx, content), style));
|
|
50190
|
+
return sizeOf(layoutFor(tctx, sourceOf(tctx, content), style, width));
|
|
50060
50191
|
},
|
|
50061
50192
|
hasGlyph: (char, style) => hasGlyphOf(text(), char, style),
|
|
50062
50193
|
styles: () => Object.freeze([...ctx.state.styles.keys()]),
|
|
@@ -54789,6 +54920,16 @@ function entitySet(entities) {
|
|
|
54789
54920
|
return new Set(entities);
|
|
54790
54921
|
}
|
|
54791
54922
|
/**
|
|
54923
|
+
* Tells whether an element whose `Box` just came arrives with an enter: new, and not a row a
|
|
54924
|
+
* range change scrolled in.
|
|
54925
|
+
*
|
|
54926
|
+
* @param element - The element, if it is still known.
|
|
54927
|
+
* @returns True when its enter hook is to play.
|
|
54928
|
+
*/
|
|
54929
|
+
function arrives(element) {
|
|
54930
|
+
return element !== void 0 && !element.entered && !element.scrolledIn;
|
|
54931
|
+
}
|
|
54932
|
+
/**
|
|
54792
54933
|
* Builds the reconcile half of the jsx module: the two systems of the frame and the root
|
|
54793
54934
|
* bookkeeping around them.
|
|
54794
54935
|
*
|
|
@@ -55729,7 +55870,8 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55729
55870
|
/**
|
|
55730
55871
|
* Keeps an element whose spawn has just been applied: the world calls it from the `Box` hook, at
|
|
55731
55872
|
* the flush of phase `layout`. Its enter hook waits for `playEntered`, so the game's systems see
|
|
55732
|
-
* the entity first (F48).
|
|
55873
|
+
* the entity first (F48). The hook itself plays at once, so they see the start pose it writes (F49);
|
|
55874
|
+
* `ui.enter` plays it again when one of them changed what it read.
|
|
55733
55875
|
*
|
|
55734
55876
|
* @param entity - The entity the `Box` was attached to.
|
|
55735
55877
|
*/
|
|
@@ -55738,6 +55880,8 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55738
55880
|
if (entering.count < entering.list.length) entering.list[entering.count] = entity;
|
|
55739
55881
|
else entering.list.push(entity);
|
|
55740
55882
|
entering.count += 1;
|
|
55883
|
+
const element = state.elements.get(entity);
|
|
55884
|
+
if (arrives(element)) modules.layout.pose(element, overlayOf(element) === void 0 ? void 0 : createSpan());
|
|
55741
55885
|
}
|
|
55742
55886
|
/**
|
|
55743
55887
|
* Plays the enter hooks queued since the last call, in the order the elements came. The `ui.enter`
|
|
@@ -56593,6 +56737,203 @@ function watched(handle, span, watch) {
|
|
|
56593
56737
|
};
|
|
56594
56738
|
}
|
|
56595
56739
|
/**
|
|
56740
|
+
* A handle that keeps what an enter hook read and wrote: the components it read with `get`, the
|
|
56741
|
+
* components it wrote, and every `set` with the values it wrote over. Everything goes on to the
|
|
56742
|
+
* real handle.
|
|
56743
|
+
*
|
|
56744
|
+
* @param handle - The handle the hook plays on.
|
|
56745
|
+
* @param posed - Where it is kept.
|
|
56746
|
+
* @returns The recording handle.
|
|
56747
|
+
*/
|
|
56748
|
+
function recording(handle, posed) {
|
|
56749
|
+
const wrote = (component) => {
|
|
56750
|
+
if (!posed.written.includes(component.componentName)) posed.written.push(component.componentName);
|
|
56751
|
+
};
|
|
56752
|
+
return {
|
|
56753
|
+
entity: handle.entity,
|
|
56754
|
+
key: handle.key,
|
|
56755
|
+
get: (component) => {
|
|
56756
|
+
if (!posed.reads.some((read) => read.component === component)) posed.reads.push({
|
|
56757
|
+
component: asAnyComponent(component),
|
|
56758
|
+
seen: {}
|
|
56759
|
+
});
|
|
56760
|
+
return handle.get(component);
|
|
56761
|
+
},
|
|
56762
|
+
rest: (component) => handle.rest(component),
|
|
56763
|
+
set: (component, patch) => {
|
|
56764
|
+
wrote(component);
|
|
56765
|
+
keepWrite(posed, asAnyComponent(component), patch, handle.get(component));
|
|
56766
|
+
handle.set(component, patch);
|
|
56767
|
+
},
|
|
56768
|
+
tween: (component, to, options) => {
|
|
56769
|
+
wrote(component);
|
|
56770
|
+
return handle.tween(component, to, options);
|
|
56771
|
+
},
|
|
56772
|
+
toRest: (component, options) => {
|
|
56773
|
+
wrote(component);
|
|
56774
|
+
return handle.toRest(component, options);
|
|
56775
|
+
},
|
|
56776
|
+
all: (handles) => handle.all(handles),
|
|
56777
|
+
peer: (key) => handle.peer(key)
|
|
56778
|
+
};
|
|
56779
|
+
}
|
|
56780
|
+
/**
|
|
56781
|
+
* Keeps one `set` of an enter hook with the values its fields had before it. A component the
|
|
56782
|
+
* entity does not carry yet has nothing to go back to: a replay writes it again.
|
|
56783
|
+
*
|
|
56784
|
+
* @param posed - Where the write is kept.
|
|
56785
|
+
* @param component - The component the hook wrote.
|
|
56786
|
+
* @param patch - The fields it wrote.
|
|
56787
|
+
* @param current - The component's value before the write, if the entity carries it.
|
|
56788
|
+
*/
|
|
56789
|
+
function keepWrite(posed, component, patch, current) {
|
|
56790
|
+
if (current === void 0) return;
|
|
56791
|
+
const wrote = { ...patch };
|
|
56792
|
+
const was = current;
|
|
56793
|
+
const before = {};
|
|
56794
|
+
for (const field of Object.keys(wrote)) before[field] = was[field];
|
|
56795
|
+
posed.writes.push({
|
|
56796
|
+
component,
|
|
56797
|
+
wrote,
|
|
56798
|
+
before
|
|
56799
|
+
});
|
|
56800
|
+
}
|
|
56801
|
+
/**
|
|
56802
|
+
* A component type as the record of an enter play keeps it.
|
|
56803
|
+
*
|
|
56804
|
+
* @param component - The component type a hook used.
|
|
56805
|
+
* @returns The same type, read as a record of fields.
|
|
56806
|
+
*/
|
|
56807
|
+
function asAnyComponent(component) {
|
|
56808
|
+
return component;
|
|
56809
|
+
}
|
|
56810
|
+
/**
|
|
56811
|
+
* Plays the enter hook of an element at its `Box`, before the game's systems of phase `sync` see
|
|
56812
|
+
* the element, so they see its start pose (F49). What the hook read and wrote is kept on the
|
|
56813
|
+
* element: `enterPosed` plays it again in `ui.enter` when a game system changed a component it
|
|
56814
|
+
* read (F48), and keeps this play otherwise.
|
|
56815
|
+
*
|
|
56816
|
+
* @param ctx - Domain context of the ui plugin.
|
|
56817
|
+
* @param element - The element whose `Box` was just attached.
|
|
56818
|
+
* @param span - Notes the longest finite track the hook starts, for the level of an overlay.
|
|
56819
|
+
*/
|
|
56820
|
+
function poseEnter(ctx, element, span) {
|
|
56821
|
+
const hook = element.motion?.enter;
|
|
56822
|
+
if (hook === void 0) return;
|
|
56823
|
+
const posed = {
|
|
56824
|
+
motion: void 0,
|
|
56825
|
+
reads: [],
|
|
56826
|
+
written: [],
|
|
56827
|
+
writes: [],
|
|
56828
|
+
span
|
|
56829
|
+
};
|
|
56830
|
+
posed.motion = play(ctx, element, (view) => hook(recording(view, posed), element.node, void 0, element.cause), span);
|
|
56831
|
+
element.posed = posed;
|
|
56832
|
+
const ecs = ctx.deps.world.ecs;
|
|
56833
|
+
for (const read of posed.reads) {
|
|
56834
|
+
if (posed.written.includes(read.component.componentName)) continue;
|
|
56835
|
+
read.seen = { ...ecs.get(element.entity, read.component) };
|
|
56836
|
+
}
|
|
56837
|
+
}
|
|
56838
|
+
/**
|
|
56839
|
+
* Tells whether a game system changed a component the enter hook read at the `Box`.
|
|
56840
|
+
*
|
|
56841
|
+
* @param ctx - Domain context of the ui plugin.
|
|
56842
|
+
* @param element - The element.
|
|
56843
|
+
* @param posed - What the play at the `Box` kept.
|
|
56844
|
+
* @returns True when a field the hook could have read is not what it was.
|
|
56845
|
+
*/
|
|
56846
|
+
function readChanged(ctx, element, posed) {
|
|
56847
|
+
const ecs = ctx.deps.world.ecs;
|
|
56848
|
+
for (const read of posed.reads) {
|
|
56849
|
+
if (posed.written.includes(read.component.componentName)) continue;
|
|
56850
|
+
if (fieldsDiffer(read.seen, ecs.get(element.entity, read.component))) return true;
|
|
56851
|
+
}
|
|
56852
|
+
return false;
|
|
56853
|
+
}
|
|
56854
|
+
/**
|
|
56855
|
+
* Tells whether a component's value is not the one a play saw: a field differs, one came or went,
|
|
56856
|
+
* or the component itself went.
|
|
56857
|
+
*
|
|
56858
|
+
* @param seen - The fields as the play saw them.
|
|
56859
|
+
* @param now - The value now, or nothing when the entity lost the component.
|
|
56860
|
+
* @returns True when they differ.
|
|
56861
|
+
* @example
|
|
56862
|
+
* ```ts
|
|
56863
|
+
* fieldsDiffer({ dy: 300 }, { dy: 180 }); // true
|
|
56864
|
+
* ```
|
|
56865
|
+
*/
|
|
56866
|
+
function fieldsDiffer(seen, now) {
|
|
56867
|
+
if (now === void 0) return Object.keys(seen).length > 0;
|
|
56868
|
+
const value = now;
|
|
56869
|
+
const fields = /* @__PURE__ */ new Set([...Object.keys(seen), ...Object.keys(value)]);
|
|
56870
|
+
for (const field of fields) if (value[field] !== seen[field]) return true;
|
|
56871
|
+
return false;
|
|
56872
|
+
}
|
|
56873
|
+
/**
|
|
56874
|
+
* Undoes the play at the `Box` before the hook plays again: its motion is cancelled and forgotten,
|
|
56875
|
+
* and a field still holding what a `set` wrote gets its value from before. A field written since
|
|
56876
|
+
* keeps the new value. The later writes go back first, so the first one's value is what stays.
|
|
56877
|
+
*
|
|
56878
|
+
* @param ctx - Domain context of the ui plugin.
|
|
56879
|
+
* @param element - The element.
|
|
56880
|
+
* @param posed - What the play at the `Box` kept.
|
|
56881
|
+
*/
|
|
56882
|
+
function undoPosed(ctx, element, posed) {
|
|
56883
|
+
forgetMotion(element, posed.motion);
|
|
56884
|
+
for (const write of posed.writes.toReversed()) revertWrite(ctx, element, write);
|
|
56885
|
+
}
|
|
56886
|
+
/**
|
|
56887
|
+
* Cancels the motion of a play that is undone and takes it out of the element's handles.
|
|
56888
|
+
*
|
|
56889
|
+
* @param element - The element.
|
|
56890
|
+
* @param motion - The motion the play returned, if any.
|
|
56891
|
+
*/
|
|
56892
|
+
function forgetMotion(element, motion) {
|
|
56893
|
+
if (motion === void 0) return;
|
|
56894
|
+
motion.cancel();
|
|
56895
|
+
const at = element.handles.indexOf(motion);
|
|
56896
|
+
if (at !== -1) element.handles.splice(at, 1);
|
|
56897
|
+
element.endless?.delete(motion);
|
|
56898
|
+
}
|
|
56899
|
+
/**
|
|
56900
|
+
* Gives one `set` of an undone play back: each field still holding what it wrote gets the value it
|
|
56901
|
+
* had before.
|
|
56902
|
+
*
|
|
56903
|
+
* @param ctx - Domain context of the ui plugin.
|
|
56904
|
+
* @param element - The element.
|
|
56905
|
+
* @param write - The write to take back.
|
|
56906
|
+
*/
|
|
56907
|
+
function revertWrite(ctx, element, write) {
|
|
56908
|
+
const ecs = ctx.deps.world.ecs;
|
|
56909
|
+
const current = ecs.get(element.entity, write.component);
|
|
56910
|
+
if (current === void 0) return;
|
|
56911
|
+
const kept = Object.keys(write.wrote).filter((field) => current[field] === write.wrote[field]);
|
|
56912
|
+
if (kept.length === 0) return;
|
|
56913
|
+
ecs.set(element.entity, write.component, Object.fromEntries(kept.map((field) => [field, write.before[field]])));
|
|
56914
|
+
}
|
|
56915
|
+
/**
|
|
56916
|
+
* Settles the enter hook an element played at its `Box`, in `ui.enter`: when a game system of
|
|
56917
|
+
* `sync` changed a component the hook read, the play is undone and the hook plays again on what
|
|
56918
|
+
* the system wrote (F48); otherwise the play stands, and an overlay's span gets what it noted.
|
|
56919
|
+
*
|
|
56920
|
+
* @param ctx - Domain context of the ui plugin.
|
|
56921
|
+
* @param element - The element whose enter plays now.
|
|
56922
|
+
* @param span - Where the longest finite track is noted, for the level of an overlay.
|
|
56923
|
+
* @returns True when the play at the `Box` stands; false when there was none, or it was undone.
|
|
56924
|
+
*/
|
|
56925
|
+
function enterPosed(ctx, element, span) {
|
|
56926
|
+
const posed = element.posed;
|
|
56927
|
+
if (posed === void 0) return false;
|
|
56928
|
+
element.posed = void 0;
|
|
56929
|
+
if (readChanged(ctx, element, posed)) {
|
|
56930
|
+
undoPosed(ctx, element, posed);
|
|
56931
|
+
return false;
|
|
56932
|
+
}
|
|
56933
|
+
if (span !== void 0 && posed.span !== void 0) Object.assign(span, posed.span);
|
|
56934
|
+
return true;
|
|
56935
|
+
}
|
|
56936
|
+
/**
|
|
56596
56937
|
* Runs one motion hook and keeps the handle it returned, so the exit sweep knows when the
|
|
56597
56938
|
* element is still playing. A motion whose hook started a track that repeats forever is also
|
|
56598
56939
|
* noted as endless: the sweep never waits for it. Without a hook the value the solve wrote stands;
|
|
@@ -57175,23 +57516,38 @@ function shownOf(element, source) {
|
|
|
57175
57516
|
}
|
|
57176
57517
|
/**
|
|
57177
57518
|
* The size a text or an icon takes before Yoga clamps it: an icon is square on one line of its
|
|
57178
|
-
* text style, a bound text measures the string it shows, any other text its content
|
|
57179
|
-
* rounded up to whole units. Yoga rounds a
|
|
57180
|
-
* parent from the unrounded length, so a
|
|
57519
|
+
* text style, a bound text measures the string it shows, any other text its content, wrapped at
|
|
57520
|
+
* `width` when its style wraps at its box. The size is rounded up to whole units. Yoga rounds a
|
|
57521
|
+
* node with a measure function outward but sizes its parent from the unrounded length, so a
|
|
57522
|
+
* fractional size would run into the parent's padding.
|
|
57181
57523
|
*
|
|
57182
57524
|
* @param element - The text or icon element.
|
|
57183
57525
|
* @param source - What it is measured through.
|
|
57526
|
+
* @param width - The width Yoga offers, or `undefined` when it bounds none.
|
|
57184
57527
|
* @returns The width and the height, in whole units.
|
|
57185
57528
|
*/
|
|
57186
|
-
function naturalSize(element, source) {
|
|
57529
|
+
function naturalSize(element, source, width) {
|
|
57187
57530
|
const { content, style } = contentOf$1(element);
|
|
57188
|
-
const size = element.type === "icon" ? squareOf(source.measure(LINE_SAMPLE, style)) : source.measure(shownOf(element, source) ?? content, style);
|
|
57531
|
+
const size = element.type === "icon" ? squareOf(source.measure(LINE_SAMPLE, style)) : source.measure(shownOf(element, source) ?? content, style, width);
|
|
57189
57532
|
return {
|
|
57190
57533
|
width: Math.ceil(size.width - WHOLE_EPSILON),
|
|
57191
57534
|
height: Math.ceil(size.height - WHOLE_EPSILON)
|
|
57192
57535
|
};
|
|
57193
57536
|
}
|
|
57194
57537
|
/**
|
|
57538
|
+
* The width Yoga bounds a measure with: what it offers in an exact or an at-most mode, nothing in
|
|
57539
|
+
* an undefined one, where a text is as wide as one line of it.
|
|
57540
|
+
*
|
|
57541
|
+
* @param yoga - The loaded Yoga module, for the measure modes.
|
|
57542
|
+
* @param width - What Yoga offered on the width.
|
|
57543
|
+
* @param mode - How to read that width.
|
|
57544
|
+
* @returns The width, or `undefined` when none is bounded.
|
|
57545
|
+
*/
|
|
57546
|
+
function offeredWidth(yoga, width, mode) {
|
|
57547
|
+
if (mode === yoga.MEASURE_MODE_UNDEFINED || !Number.isFinite(width)) return void 0;
|
|
57548
|
+
return width;
|
|
57549
|
+
}
|
|
57550
|
+
/**
|
|
57195
57551
|
* Clamps one axis of a measured size to what Yoga offered on that axis.
|
|
57196
57552
|
*
|
|
57197
57553
|
* @param yoga - The loaded Yoga module, for the three measure modes.
|
|
@@ -57227,7 +57583,8 @@ function clampToMode(yoga, measured, asked) {
|
|
|
57227
57583
|
}
|
|
57228
57584
|
/**
|
|
57229
57585
|
* Installs the measure function of a text element, or drops it when the text is fixed. The
|
|
57230
|
-
* function keeps the size it answered on the element, for
|
|
57586
|
+
* function keeps the size it answered and the width it was offered on the element, for
|
|
57587
|
+
* `remeasureShown`.
|
|
57231
57588
|
*
|
|
57232
57589
|
* @param state - The layout state, for the Yoga module and the `measured` counter.
|
|
57233
57590
|
* @param node - The node of the element.
|
|
@@ -57242,9 +57599,11 @@ function installMeasure(state, node, element, source) {
|
|
|
57242
57599
|
return;
|
|
57243
57600
|
}
|
|
57244
57601
|
const measureFunction = (width, widthMode, height, heightMode) => {
|
|
57245
|
-
const
|
|
57602
|
+
const offered = offeredWidth(yoga, width, widthMode);
|
|
57603
|
+
const size = naturalSize(element, source, offered);
|
|
57246
57604
|
state.measured += 1;
|
|
57247
57605
|
element.measuredSize = size;
|
|
57606
|
+
element.measuredWidth = offered;
|
|
57248
57607
|
if (element.type === "icon") state.iconLine = lineOf(source);
|
|
57249
57608
|
return clampToMode(yoga, size, {
|
|
57250
57609
|
width,
|
|
@@ -57266,12 +57625,29 @@ function markMeasured(state, element) {
|
|
|
57266
57625
|
state.byEntity.get(element.entity)?.markDirty();
|
|
57267
57626
|
}
|
|
57268
57627
|
/**
|
|
57628
|
+
* The width a text that was measured inside a bound width is laid out at now: its node's content
|
|
57629
|
+
* width from the last solve. Yoga may serve a width it measured before from its own cache without
|
|
57630
|
+
* calling the measure function, so the width that function was offered last can be another one.
|
|
57631
|
+
*
|
|
57632
|
+
* @param state - The layout state, for the edge enums of Yoga.
|
|
57633
|
+
* @param node - The node of the text.
|
|
57634
|
+
* @param element - The text element.
|
|
57635
|
+
* @returns The content width, or `undefined` when the text was measured unbounded.
|
|
57636
|
+
*/
|
|
57637
|
+
function laidOutWidth(state, node, element) {
|
|
57638
|
+
const yoga = state.yoga;
|
|
57639
|
+
if (element.measuredWidth === void 0 || yoga === void 0) return void 0;
|
|
57640
|
+
const padding = node.getComputedPadding(yoga.EDGE_LEFT) + node.getComputedPadding(yoga.EDGE_RIGHT);
|
|
57641
|
+
return node.getComputedWidth() - padding;
|
|
57642
|
+
}
|
|
57643
|
+
/**
|
|
57269
57644
|
* Marks the node of a text dirty when what it draws now measures to another size than the node was
|
|
57270
57645
|
* laid out with. `text` writes `Text` when the shown string of a bound label changes, and for
|
|
57271
57646
|
* every label it resolves again: a message after a new locale, any label when its font arrives or
|
|
57272
57647
|
* its style is swapped. So a text without `bind` is measured again too, and a counter that rolls
|
|
57273
|
-
* through digits of one width asks for no solve. A text
|
|
57274
|
-
*
|
|
57648
|
+
* through digits of one width asks for no solve. A text whose width was bounded is measured at
|
|
57649
|
+
* the width it is laid out at now, so one that wraps at its box compares the same lines. A text
|
|
57650
|
+
* with a fixed size has no measure function and is left alone.
|
|
57275
57651
|
*
|
|
57276
57652
|
* @param state - The layout state, for the node of the element.
|
|
57277
57653
|
* @param element - An element whose `Text` changed this frame.
|
|
@@ -57283,7 +57659,7 @@ function remeasureShown(state, element, source) {
|
|
|
57283
57659
|
const before = element.measuredSize;
|
|
57284
57660
|
if (node === void 0 || before === void 0) return false;
|
|
57285
57661
|
if (!needsMeasure(element)) return false;
|
|
57286
|
-
const size = naturalSize(element, source);
|
|
57662
|
+
const size = naturalSize(element, source, laidOutWidth(state, node, element));
|
|
57287
57663
|
if (size.width === before.width && size.height === before.height) return false;
|
|
57288
57664
|
node.markDirty();
|
|
57289
57665
|
return true;
|
|
@@ -58139,7 +58515,7 @@ async function loadYogaModule() {
|
|
|
58139
58515
|
*/
|
|
58140
58516
|
function textSourceOf(ctx) {
|
|
58141
58517
|
return {
|
|
58142
|
-
measure: (content, style) => ctx.deps.text.measure(content, style),
|
|
58518
|
+
measure: (content, style, width) => ctx.deps.text.measure(content, style, width),
|
|
58143
58519
|
resolved: (entity) => ctx.deps.world.ecs.get(entity, Text)?.resolved,
|
|
58144
58520
|
duration: (ms) => ctx.deps.i18n.duration(ms)
|
|
58145
58521
|
};
|
|
@@ -58202,9 +58578,11 @@ function createLayoutApi(ctx) {
|
|
|
58202
58578
|
},
|
|
58203
58579
|
enter: (element, span) => {
|
|
58204
58580
|
const hook = element.motion?.enter;
|
|
58205
|
-
|
|
58581
|
+
const played = hook === void 0 ? void 0 : (view) => hook(view, element.node, void 0, element.cause);
|
|
58582
|
+
if (!enterPosed(ctx, element, span)) play(ctx, element, played, span);
|
|
58206
58583
|
startLoop(ctx, element);
|
|
58207
58584
|
},
|
|
58585
|
+
pose: (element, span) => poseEnter(ctx, element, span),
|
|
58208
58586
|
loop: (element) => startLoop(ctx, element),
|
|
58209
58587
|
change: (element, previous, hint) => {
|
|
58210
58588
|
const hook = element.motion?.change?.Box;
|
|
@@ -58787,8 +59165,9 @@ function registerComponents(ctx, jsx) {
|
|
|
58787
59165
|
* control, so the cursor shows a hand over a local-state button. On an agent page also the tap
|
|
58788
59166
|
* counter of `DebugTrigger` and its check of a view that takes no press.
|
|
58789
59167
|
*
|
|
58790
|
-
* The `Box` hook
|
|
58791
|
-
*
|
|
59168
|
+
* The `Box` hook plays an element's enter hook and queues it, so the game's systems see its start
|
|
59169
|
+
* pose (F49); `ui.enter` starts its loop after them and before the frame is drawn, and plays the
|
|
59170
|
+
* hook again when a system changed what it read (F48). Every remover goes into the state, so the teardown
|
|
58792
59171
|
* closes exactly these, and gives every hosted view its layer back before the ui entities go.
|
|
58793
59172
|
*
|
|
58794
59173
|
* @param ctx - Domain context of the ui plugin.
|