@moku-labs/game 0.15.13 → 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-3_HjYegY.mjs → src-AvZjWoPX.mjs} +481 -92
- 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";
|
|
@@ -8798,8 +8798,11 @@ function schemaOf(types) {
|
|
|
8798
8798
|
//#region src/plugins/world/ecs/systems.ts
|
|
8799
8799
|
/** The one phase that runs in every mode, because `renderer.sync` lives in it. */
|
|
8800
8800
|
const ALWAYS = "sync";
|
|
8801
|
-
/**
|
|
8802
|
-
|
|
8801
|
+
/**
|
|
8802
|
+
* The name of the system that hands the world to Pixi: the last of its phase, so a frame draws what every system
|
|
8803
|
+
* wrote. The renderer registers its system under this name.
|
|
8804
|
+
*/
|
|
8805
|
+
const DRAWS_SYSTEM = "renderer.sync";
|
|
8803
8806
|
/** Rows a timing table holds before it first grows. */
|
|
8804
8807
|
const TIMING_ROWS = 16;
|
|
8805
8808
|
/** The four phases, in frame order. */
|
|
@@ -8898,8 +8901,9 @@ function storeSlots(count) {
|
|
|
8898
8901
|
return slots;
|
|
8899
8902
|
}
|
|
8900
8903
|
/**
|
|
8901
|
-
* Registers a system at the end of its phase list
|
|
8902
|
-
* `scenes` are read here, once: a
|
|
8904
|
+
* Registers a system at the end of its phase list and returns the remover. In phase `sync` it goes
|
|
8905
|
+
* before `renderer.sync`, which stays last. Its query and its `scenes` are read here, once: a
|
|
8906
|
+
* later change to the definition is not seen. A dev build checks
|
|
8903
8907
|
* the `scenes` against the scenes the features declare, once the world started.
|
|
8904
8908
|
*
|
|
8905
8909
|
* @param ctx - Domain context of the world plugin.
|
|
@@ -8928,7 +8932,7 @@ function registerSystem(ctx, definition) {
|
|
|
8928
8932
|
walk: plan.names.length === 0 ? void 0 : new SystemWalk(ctx, plan)
|
|
8929
8933
|
};
|
|
8930
8934
|
const list = state.systems[definition.phase];
|
|
8931
|
-
const draws = list.findIndex((known) => known.definition.name ===
|
|
8935
|
+
const draws = list.findIndex((known) => known.definition.name === DRAWS_SYSTEM);
|
|
8932
8936
|
if (draws === -1) list.push(entry);
|
|
8933
8937
|
else list.splice(draws, 0, entry);
|
|
8934
8938
|
if (state.timing !== void 0) giveRow(state, state.timing, definition.name);
|
|
@@ -29055,8 +29059,12 @@ function watchOverlays(sctx) {
|
|
|
29055
29059
|
}
|
|
29056
29060
|
//#endregion
|
|
29057
29061
|
//#region src/plugins/renderer/sync/system.ts
|
|
29058
|
-
/**
|
|
29059
|
-
|
|
29062
|
+
/**
|
|
29063
|
+
* @file renderer/sync — the one world system the renderer registers. It runs in phase `"sync"`,
|
|
29064
|
+
* which `world` runs in every mode, so a fast walk still sets the picture.
|
|
29065
|
+
*/
|
|
29066
|
+
/** The name the system is registered under, which `world` keeps last in phase `sync`; it shows up in a world error message. */
|
|
29067
|
+
const SYNC_SYSTEM_NAME = DRAWS_SYSTEM;
|
|
29060
29068
|
/**
|
|
29061
29069
|
* Wraps the pass in a world system definition. The system queries nothing: all the work is
|
|
29062
29070
|
* driven by the change sets of the frame.
|
|
@@ -34667,7 +34675,7 @@ function pickVictim(state) {
|
|
|
34667
34675
|
const entry = state.manifest.bundles[name];
|
|
34668
34676
|
if (record.status !== "loaded" || entry === void 0) continue;
|
|
34669
34677
|
if (state.pinned.has(name) || isPermanent(entry.tier)) continue;
|
|
34670
|
-
if (state.sceneNamed.includes(name)) continue;
|
|
34678
|
+
if (state.sceneNamed.includes(name) || state.sceneLeaving.includes(name)) continue;
|
|
34671
34679
|
if (state.queue?.bundles.includes(name) === true) continue;
|
|
34672
34680
|
if (record.lastUsed >= smallest) continue;
|
|
34673
34681
|
smallest = record.lastUsed;
|
|
@@ -34822,8 +34830,9 @@ function featuresOnStack(ctx) {
|
|
|
34822
34830
|
}
|
|
34823
34831
|
/**
|
|
34824
34832
|
* Tells whether a bundle must stay where the game stands now: it is pinned (a bundle of the node
|
|
34825
|
-
* entered last), the mounted scene names it (the last list `sceneBundles` received),
|
|
34826
|
-
* 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.
|
|
34827
34836
|
*
|
|
34828
34837
|
* @param ctx - Domain context of the plugin.
|
|
34829
34838
|
* @param name - Name of the bundle.
|
|
@@ -34833,25 +34842,66 @@ function featuresOnStack(ctx) {
|
|
|
34833
34842
|
*/
|
|
34834
34843
|
function isHeld(ctx, name, entry, onStack) {
|
|
34835
34844
|
const state = ctx.state;
|
|
34836
|
-
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);
|
|
34837
34846
|
}
|
|
34838
34847
|
/**
|
|
34839
|
-
* Unloads every loaded `"leave"` bundle nobody holds any more, with the reason `"leave"
|
|
34840
|
-
*
|
|
34841
|
-
* 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.
|
|
34842
34851
|
*
|
|
34843
34852
|
* @param ctx - Domain context of the plugin.
|
|
34844
34853
|
*/
|
|
34845
34854
|
function releaseLeftBundles(ctx) {
|
|
34846
34855
|
const state = ctx.state;
|
|
34847
34856
|
if (state.io === void 0) return;
|
|
34857
|
+
if (state.sceneLeaving.length > 0 && state.exiting === 0) state.sceneLeaving = [];
|
|
34848
34858
|
const onStack = featuresOnStack(ctx);
|
|
34849
|
-
for (const
|
|
34850
|
-
|
|
34851
|
-
|
|
34852
|
-
|
|
34853
|
-
|
|
34854
|
-
|
|
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");
|
|
34855
34905
|
}
|
|
34856
34906
|
//#endregion
|
|
34857
34907
|
//#region src/plugins/scenes/bundles.ts
|
|
@@ -35329,21 +35379,22 @@ function startPreload(ctx) {
|
|
|
35329
35379
|
//#endregion
|
|
35330
35380
|
//#region src/plugins/assets/lifecycle.ts
|
|
35331
35381
|
/**
|
|
35332
|
-
* @file assets plugin — lifecycle: the
|
|
35382
|
+
* @file assets plugin — lifecycle: the five registrations of `onInit`, the boot of `onStart`
|
|
35333
35383
|
* and the teardown that frees every texture and cancels every fetch.
|
|
35334
35384
|
*/
|
|
35335
35385
|
/**
|
|
35336
|
-
* Resolves the dependency APIs `flow`, `renderer`, `time` and `
|
|
35386
|
+
* Resolves the dependency APIs `flow`, `renderer`, `time`, `model` and `world` with `ctx.require`.
|
|
35337
35387
|
*
|
|
35338
35388
|
* @param ctx - Kernel context of the assets plugin.
|
|
35339
|
-
* @returns The
|
|
35389
|
+
* @returns The five dependency APIs.
|
|
35340
35390
|
*/
|
|
35341
35391
|
function resolveDeps$5(ctx) {
|
|
35342
35392
|
return {
|
|
35343
35393
|
flow: ctx.require(flowPlugin),
|
|
35344
35394
|
renderer: ctx.require(rendererPlugin),
|
|
35345
35395
|
time: ctx.require(timePlugin),
|
|
35346
|
-
model: ctx.require(modelPlugin)
|
|
35396
|
+
model: ctx.require(modelPlugin),
|
|
35397
|
+
world: ctx.require(worldPlugin)
|
|
35347
35398
|
};
|
|
35348
35399
|
}
|
|
35349
35400
|
/**
|
|
@@ -35443,19 +35494,20 @@ async function enterNode(ctx, node, run) {
|
|
|
35443
35494
|
}
|
|
35444
35495
|
/**
|
|
35445
35496
|
* Connects the plugin in `onInit`: the `load` stage of `onEnter`, the handler of the `load`
|
|
35446
|
-
* effect
|
|
35447
|
-
*
|
|
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.
|
|
35448
35500
|
*
|
|
35449
35501
|
* @param ctx - Kernel context of the assets plugin.
|
|
35450
|
-
* @example
|
|
35451
|
-
* ```ts
|
|
35452
|
-
* connectAssets(ctx);
|
|
35453
|
-
* ctx.state.removers.length; // 3
|
|
35454
|
-
* ```
|
|
35455
35502
|
*/
|
|
35456
35503
|
function connectAssets(ctx) {
|
|
35457
35504
|
const assets = withDeps$6(ctx);
|
|
35458
|
-
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
|
+
}));
|
|
35459
35511
|
}
|
|
35460
35512
|
/**
|
|
35461
35513
|
* Picks the I/O seam: the configured one, the browser pair over `renderer.sync.textures` when
|
|
@@ -35531,7 +35583,7 @@ async function startAssets(ctx) {
|
|
|
35531
35583
|
}
|
|
35532
35584
|
/**
|
|
35533
35585
|
* Frees everything in `onStop`: the preload and every running load are aborted, every texture is
|
|
35534
|
-
* destroyed, the
|
|
35586
|
+
* destroyed, the five registrations are removed and the registries are emptied, the companions
|
|
35535
35587
|
* too. A teardown context carries the state and nothing else, so no other plugin is called here:
|
|
35536
35588
|
* no companion's `unload` either, its plugin stopped before this one.
|
|
35537
35589
|
*
|
|
@@ -35563,6 +35615,8 @@ function releaseAll(state) {
|
|
|
35563
35615
|
state.current = void 0;
|
|
35564
35616
|
state.sceneId = void 0;
|
|
35565
35617
|
state.sceneNamed = [];
|
|
35618
|
+
state.sceneLeaving = [];
|
|
35619
|
+
state.exiting = 0;
|
|
35566
35620
|
state.restPending = false;
|
|
35567
35621
|
state.stamps = void 0;
|
|
35568
35622
|
state.swapping = void 0;
|
|
@@ -35709,9 +35763,7 @@ function createAssetsApi(ctx) {
|
|
|
35709
35763
|
font: (key) => loadedRecord(assets, key)?.fonts.get(key),
|
|
35710
35764
|
audio: (key) => loadedRecord(assets, key)?.audio.get(key),
|
|
35711
35765
|
usage: () => usage(assets),
|
|
35712
|
-
sceneBundles: (named) =>
|
|
35713
|
-
ctx.state.sceneNamed = [...named];
|
|
35714
|
-
},
|
|
35766
|
+
sceneBundles: (named) => nameSceneBundles(ctx.state, named),
|
|
35715
35767
|
has: (bundle) => Object.hasOwn(ctx.state.manifest.bundles, bundle),
|
|
35716
35768
|
companions: { add: (companion) => addCompanion(ctx.state, companion) }
|
|
35717
35769
|
};
|
|
@@ -36379,6 +36431,8 @@ function createAssetsState() {
|
|
|
36379
36431
|
stamps: void 0,
|
|
36380
36432
|
swapping: void 0,
|
|
36381
36433
|
sceneNamed: [],
|
|
36434
|
+
sceneLeaving: [],
|
|
36435
|
+
exiting: 0,
|
|
36382
36436
|
companions: [],
|
|
36383
36437
|
restPending: false
|
|
36384
36438
|
};
|
|
@@ -36403,7 +36457,8 @@ const assetsPlugin = /*#__PURE__*/ createPlugin$1("assets", {
|
|
|
36403
36457
|
flowPlugin,
|
|
36404
36458
|
rendererPlugin,
|
|
36405
36459
|
timePlugin,
|
|
36406
|
-
modelPlugin
|
|
36460
|
+
modelPlugin,
|
|
36461
|
+
worldPlugin
|
|
36407
36462
|
],
|
|
36408
36463
|
config: {
|
|
36409
36464
|
manifest: void 0,
|
|
@@ -47923,6 +47978,12 @@ const platformPlugin = /*#__PURE__*/ createPlugin$1("platform", {
|
|
|
47923
47978
|
const FALLBACK_ADVANCE = .6;
|
|
47924
47979
|
/** Line height of a style whose font is not loaded, as a share of the style size. */
|
|
47925
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;
|
|
47926
47987
|
/** Splits a run's text into words, runs of spaces and line breaks, separators kept. */
|
|
47927
47988
|
const TOKENS = /(\n| +)/;
|
|
47928
47989
|
/**
|
|
@@ -48397,13 +48458,33 @@ function emptyKeys() {
|
|
|
48397
48458
|
return /* @__PURE__ */ new Set();
|
|
48398
48459
|
}
|
|
48399
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
|
+
/**
|
|
48400
48478
|
* Lays a block of runs out: the lines, the width of the widest one and the total height. The
|
|
48401
|
-
* 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`.
|
|
48402
48482
|
*
|
|
48403
48483
|
* @param runs - What `parseTags` made of the resolved string.
|
|
48404
48484
|
* @param style - The style of the label.
|
|
48405
48485
|
* @param tables - The advance tables that are loaded, by font key.
|
|
48406
48486
|
* @param options - Where a warning goes.
|
|
48487
|
+
* @param box - The width a `"box"` style wraps at, in reference pixels; 0 for none.
|
|
48407
48488
|
* @returns The lines and the size of the block in reference pixels.
|
|
48408
48489
|
* @example
|
|
48409
48490
|
* ```ts
|
|
@@ -48411,13 +48492,14 @@ function emptyKeys() {
|
|
|
48411
48492
|
* // { lines: [{ runs: [], width: 0 }], width: 0, height: 38.4 }
|
|
48412
48493
|
* ```
|
|
48413
48494
|
*/
|
|
48414
|
-
function layoutRuns(runs, style, tables, options) {
|
|
48495
|
+
function layoutRuns(runs, style, tables, options, box = 0) {
|
|
48415
48496
|
const once = onceOnly(options);
|
|
48416
|
-
const
|
|
48497
|
+
const wrap = wrapOf(style, box);
|
|
48498
|
+
const lines = wrap === void 0 ? layoutFixed(runs, style, tables, once) : layoutWrapped(runs, {
|
|
48417
48499
|
style,
|
|
48418
48500
|
tables,
|
|
48419
48501
|
options: once
|
|
48420
|
-
},
|
|
48502
|
+
}, wrap);
|
|
48421
48503
|
let width = 0;
|
|
48422
48504
|
for (const line of lines) width = Math.max(width, line.width);
|
|
48423
48505
|
return {
|
|
@@ -48712,20 +48794,34 @@ function styleOf$1(ctx, name) {
|
|
|
48712
48794
|
return ctx.state.styles.get("body") ?? builtInStyles(ctx.config.fonts).body;
|
|
48713
48795
|
}
|
|
48714
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
|
+
/**
|
|
48715
48808
|
* The layout of one resolved string in one style, from the cache or freshly laid out. The cache
|
|
48716
|
-
* 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.
|
|
48717
48811
|
*
|
|
48718
48812
|
* @param ctx - Domain context of the text plugin.
|
|
48719
48813
|
* @param resolved - The tagged string.
|
|
48720
48814
|
* @param styleName - The style name.
|
|
48815
|
+
* @param box - The width a `"box"` style wraps at; 0 for one line.
|
|
48721
48816
|
* @returns The lines and the size of the block.
|
|
48722
48817
|
*/
|
|
48723
|
-
function layoutFor(ctx, resolved, styleName) {
|
|
48724
|
-
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}`;
|
|
48725
48821
|
const hit = ctx.state.cache.get(key);
|
|
48726
48822
|
if (hit !== void 0) return hit;
|
|
48727
48823
|
const warn = warnFor(ctx);
|
|
48728
|
-
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);
|
|
48729
48825
|
if (ctx.state.cache.size >= CACHE_LIMIT) {
|
|
48730
48826
|
const oldest = ctx.state.cache.keys().next().value;
|
|
48731
48827
|
if (oldest !== void 0) ctx.state.cache.delete(oldest);
|
|
@@ -48934,7 +49030,8 @@ function remember(ctx, entity, text, frame, unit) {
|
|
|
48934
49030
|
bindRef: text.bind,
|
|
48935
49031
|
bind: bindKeyOf(text.bind),
|
|
48936
49032
|
locale: frame.locale,
|
|
48937
|
-
unit
|
|
49033
|
+
unit,
|
|
49034
|
+
box: text.box
|
|
48938
49035
|
});
|
|
48939
49036
|
return;
|
|
48940
49037
|
}
|
|
@@ -48946,6 +49043,23 @@ function remember(ctx, entity, text, frame, unit) {
|
|
|
48946
49043
|
seen.style = text.style;
|
|
48947
49044
|
seen.locale = frame.locale;
|
|
48948
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;
|
|
48949
49063
|
}
|
|
48950
49064
|
/**
|
|
48951
49065
|
* Keeps the measured size of a label: made once, then overwritten in place.
|
|
@@ -48975,7 +49089,7 @@ function keepSize(ctx, entity, layout) {
|
|
|
48975
49089
|
* @returns True when nothing has to be formatted or written.
|
|
48976
49090
|
*/
|
|
48977
49091
|
function isShown(seen, text, unit, format, frame) {
|
|
48978
|
-
return seen
|
|
49092
|
+
return seen.unit === unit && seen.style === text.style && isSameBind(seen, text.bind) && (format !== "duration" || seen.locale === frame.locale);
|
|
48979
49093
|
}
|
|
48980
49094
|
/**
|
|
48981
49095
|
* Writes the new string of a bound label, its measured size, and for a countdown the time left,
|
|
@@ -48993,7 +49107,7 @@ function showBound(ctx, entity, text, next, value) {
|
|
|
48993
49107
|
ctx.deps.world.ecs.set(entity, Text, { resolved: next });
|
|
48994
49108
|
if (value !== void 0 && text.bind !== void 0 && isCountdownLeft(text.bind)) ctx.deps.world.ecs.set(entity, Countdown, { left: value });
|
|
48995
49109
|
}
|
|
48996
|
-
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));
|
|
48997
49111
|
}
|
|
48998
49112
|
/**
|
|
48999
49113
|
* Writes the string a bound label already shows once more, and measures it again. A mark on a
|
|
@@ -49007,7 +49121,7 @@ function showBound(ctx, entity, text, next, value) {
|
|
|
49007
49121
|
*/
|
|
49008
49122
|
function showAgain(ctx, entity, text) {
|
|
49009
49123
|
ctx.deps.world.ecs.set(entity, Text, { resolved: text.resolved });
|
|
49010
|
-
keepSize(ctx, entity, layoutFor(ctx, text.resolved, text.style));
|
|
49124
|
+
keepSize(ctx, entity, layoutFor(ctx, text.resolved, text.style, text.box));
|
|
49011
49125
|
}
|
|
49012
49126
|
/**
|
|
49013
49127
|
* Reports a bound label whose style is not a digits style, once per style. An unknown style name
|
|
@@ -49025,8 +49139,9 @@ function warnWithoutDigits(ctx, styleName) {
|
|
|
49025
49139
|
* One frame of a bound label: the value read every frame, the string built and written only
|
|
49026
49140
|
* when its unit moved. A label that stands still costs a read and a few compares and keeps
|
|
49027
49141
|
* nothing: no tag is parsed, no key is built. A marked label that stands still is written once
|
|
49028
|
-
* with the string it shows
|
|
49029
|
-
* 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.
|
|
49030
49145
|
*
|
|
49031
49146
|
* @param ctx - Domain context of the text plugin.
|
|
49032
49147
|
* @param entity - The entity.
|
|
@@ -49039,10 +49154,9 @@ function stepBound(ctx, entity, text, bind, frame) {
|
|
|
49039
49154
|
const format = value === void 0 ? "int" : formatOf(ctx, entity, bind, value);
|
|
49040
49155
|
const unit = value === void 0 ? void 0 : unitOf(value, format);
|
|
49041
49156
|
const marked = ctx.state.dirty.delete(entity);
|
|
49042
|
-
|
|
49043
|
-
|
|
49044
|
-
|
|
49045
|
-
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);
|
|
49046
49160
|
return;
|
|
49047
49161
|
}
|
|
49048
49162
|
warnWithoutDigits(ctx, text.style);
|
|
@@ -49050,8 +49164,27 @@ function stepBound(ctx, entity, text, bind, frame) {
|
|
|
49050
49164
|
remember(ctx, entity, text, frame, unit);
|
|
49051
49165
|
}
|
|
49052
49166
|
/**
|
|
49053
|
-
*
|
|
49054
|
-
*
|
|
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`.
|
|
49055
49188
|
*
|
|
49056
49189
|
* @param ctx - Domain context of the text plugin.
|
|
49057
49190
|
* @param entity - The entity.
|
|
@@ -49063,7 +49196,7 @@ function isStale(ctx, entity, text, frame) {
|
|
|
49063
49196
|
if (ctx.state.dirty.has(entity)) return true;
|
|
49064
49197
|
const seen = ctx.state.seen.get(entity);
|
|
49065
49198
|
if (seen === void 0) return true;
|
|
49066
|
-
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);
|
|
49067
49200
|
}
|
|
49068
49201
|
/**
|
|
49069
49202
|
* One frame of one label.
|
|
@@ -49079,7 +49212,7 @@ function stepText(ctx, entity, text, frame) {
|
|
|
49079
49212
|
return;
|
|
49080
49213
|
}
|
|
49081
49214
|
if (!isStale(ctx, entity, text, frame)) return;
|
|
49082
|
-
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));
|
|
49083
49216
|
ctx.state.dirty.delete(entity);
|
|
49084
49217
|
remember(ctx, entity, text, frame);
|
|
49085
49218
|
}
|
|
@@ -49653,15 +49786,19 @@ function buildRun(ctx, pixi, run, style, at) {
|
|
|
49653
49786
|
}
|
|
49654
49787
|
/**
|
|
49655
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.
|
|
49656
49791
|
*
|
|
49657
49792
|
* @param ctx - Domain context of the text plugin.
|
|
49658
49793
|
* @param value - The component value.
|
|
49659
49794
|
* @returns What the container is filled from.
|
|
49660
49795
|
*/
|
|
49661
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 });
|
|
49662
49799
|
return {
|
|
49663
|
-
style
|
|
49664
|
-
layout: layoutFor(ctx, value.resolved, value.style),
|
|
49800
|
+
style,
|
|
49801
|
+
layout: layoutFor(ctx, value.resolved, value.style, value.box),
|
|
49665
49802
|
generation: ctx.state.generation
|
|
49666
49803
|
};
|
|
49667
49804
|
}
|
|
@@ -49778,8 +49915,9 @@ function samePoint(first, second) {
|
|
|
49778
49915
|
/**
|
|
49779
49916
|
* Tells whether a container already shows a value: the string, the style name and the anchor it
|
|
49780
49917
|
* was last updated with, drawn with the style object that is current and under the generation
|
|
49781
|
-
* that is current
|
|
49782
|
-
* 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.
|
|
49783
49921
|
*
|
|
49784
49922
|
* @param ctx - Domain context of the text plugin.
|
|
49785
49923
|
* @param container - The container of this label.
|
|
@@ -49789,7 +49927,8 @@ function samePoint(first, second) {
|
|
|
49789
49927
|
*/
|
|
49790
49928
|
function isCurrent(ctx, container, previous, next) {
|
|
49791
49929
|
const drawn = ctx.state.drawn.get(container);
|
|
49792
|
-
|
|
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;
|
|
49793
49932
|
}
|
|
49794
49933
|
/**
|
|
49795
49934
|
* Draws a changed value into a container that holds a label already. A ticking counter keeps its
|
|
@@ -50046,9 +50185,9 @@ function createTextApi(ctx) {
|
|
|
50046
50185
|
return domain;
|
|
50047
50186
|
};
|
|
50048
50187
|
return {
|
|
50049
|
-
measure: (content, style) => {
|
|
50188
|
+
measure: (content, style, width = 0) => {
|
|
50050
50189
|
const tctx = text();
|
|
50051
|
-
return sizeOf(layoutFor(tctx, sourceOf(tctx, content), style));
|
|
50190
|
+
return sizeOf(layoutFor(tctx, sourceOf(tctx, content), style, width));
|
|
50052
50191
|
},
|
|
50053
50192
|
hasGlyph: (char, style) => hasGlyphOf(text(), char, style),
|
|
50054
50193
|
styles: () => Object.freeze([...ctx.state.styles.keys()]),
|
|
@@ -54781,6 +54920,16 @@ function entitySet(entities) {
|
|
|
54781
54920
|
return new Set(entities);
|
|
54782
54921
|
}
|
|
54783
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
|
+
/**
|
|
54784
54933
|
* Builds the reconcile half of the jsx module: the two systems of the frame and the root
|
|
54785
54934
|
* bookkeeping around them.
|
|
54786
54935
|
*
|
|
@@ -55721,7 +55870,8 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55721
55870
|
/**
|
|
55722
55871
|
* Keeps an element whose spawn has just been applied: the world calls it from the `Box` hook, at
|
|
55723
55872
|
* the flush of phase `layout`. Its enter hook waits for `playEntered`, so the game's systems see
|
|
55724
|
-
* 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.
|
|
55725
55875
|
*
|
|
55726
55876
|
* @param entity - The entity the `Box` was attached to.
|
|
55727
55877
|
*/
|
|
@@ -55730,6 +55880,8 @@ function createReconciler(ctx, modules, fields) {
|
|
|
55730
55880
|
if (entering.count < entering.list.length) entering.list[entering.count] = entity;
|
|
55731
55881
|
else entering.list.push(entity);
|
|
55732
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());
|
|
55733
55885
|
}
|
|
55734
55886
|
/**
|
|
55735
55887
|
* Plays the enter hooks queued since the last call, in the order the elements came. The `ui.enter`
|
|
@@ -56585,6 +56737,203 @@ function watched(handle, span, watch) {
|
|
|
56585
56737
|
};
|
|
56586
56738
|
}
|
|
56587
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
|
+
/**
|
|
56588
56937
|
* Runs one motion hook and keeps the handle it returned, so the exit sweep knows when the
|
|
56589
56938
|
* element is still playing. A motion whose hook started a track that repeats forever is also
|
|
56590
56939
|
* noted as endless: the sweep never waits for it. Without a hook the value the solve wrote stands;
|
|
@@ -57167,23 +57516,38 @@ function shownOf(element, source) {
|
|
|
57167
57516
|
}
|
|
57168
57517
|
/**
|
|
57169
57518
|
* The size a text or an icon takes before Yoga clamps it: an icon is square on one line of its
|
|
57170
|
-
* text style, a bound text measures the string it shows, any other text its content
|
|
57171
|
-
* rounded up to whole units. Yoga rounds a
|
|
57172
|
-
* 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.
|
|
57173
57523
|
*
|
|
57174
57524
|
* @param element - The text or icon element.
|
|
57175
57525
|
* @param source - What it is measured through.
|
|
57526
|
+
* @param width - The width Yoga offers, or `undefined` when it bounds none.
|
|
57176
57527
|
* @returns The width and the height, in whole units.
|
|
57177
57528
|
*/
|
|
57178
|
-
function naturalSize(element, source) {
|
|
57529
|
+
function naturalSize(element, source, width) {
|
|
57179
57530
|
const { content, style } = contentOf$1(element);
|
|
57180
|
-
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);
|
|
57181
57532
|
return {
|
|
57182
57533
|
width: Math.ceil(size.width - WHOLE_EPSILON),
|
|
57183
57534
|
height: Math.ceil(size.height - WHOLE_EPSILON)
|
|
57184
57535
|
};
|
|
57185
57536
|
}
|
|
57186
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
|
+
/**
|
|
57187
57551
|
* Clamps one axis of a measured size to what Yoga offered on that axis.
|
|
57188
57552
|
*
|
|
57189
57553
|
* @param yoga - The loaded Yoga module, for the three measure modes.
|
|
@@ -57219,7 +57583,8 @@ function clampToMode(yoga, measured, asked) {
|
|
|
57219
57583
|
}
|
|
57220
57584
|
/**
|
|
57221
57585
|
* Installs the measure function of a text element, or drops it when the text is fixed. The
|
|
57222
|
-
* 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`.
|
|
57223
57588
|
*
|
|
57224
57589
|
* @param state - The layout state, for the Yoga module and the `measured` counter.
|
|
57225
57590
|
* @param node - The node of the element.
|
|
@@ -57234,9 +57599,11 @@ function installMeasure(state, node, element, source) {
|
|
|
57234
57599
|
return;
|
|
57235
57600
|
}
|
|
57236
57601
|
const measureFunction = (width, widthMode, height, heightMode) => {
|
|
57237
|
-
const
|
|
57602
|
+
const offered = offeredWidth(yoga, width, widthMode);
|
|
57603
|
+
const size = naturalSize(element, source, offered);
|
|
57238
57604
|
state.measured += 1;
|
|
57239
57605
|
element.measuredSize = size;
|
|
57606
|
+
element.measuredWidth = offered;
|
|
57240
57607
|
if (element.type === "icon") state.iconLine = lineOf(source);
|
|
57241
57608
|
return clampToMode(yoga, size, {
|
|
57242
57609
|
width,
|
|
@@ -57258,12 +57625,29 @@ function markMeasured(state, element) {
|
|
|
57258
57625
|
state.byEntity.get(element.entity)?.markDirty();
|
|
57259
57626
|
}
|
|
57260
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
|
+
/**
|
|
57261
57644
|
* Marks the node of a text dirty when what it draws now measures to another size than the node was
|
|
57262
57645
|
* laid out with. `text` writes `Text` when the shown string of a bound label changes, and for
|
|
57263
57646
|
* every label it resolves again: a message after a new locale, any label when its font arrives or
|
|
57264
57647
|
* its style is swapped. So a text without `bind` is measured again too, and a counter that rolls
|
|
57265
|
-
* through digits of one width asks for no solve. A text
|
|
57266
|
-
*
|
|
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.
|
|
57267
57651
|
*
|
|
57268
57652
|
* @param state - The layout state, for the node of the element.
|
|
57269
57653
|
* @param element - An element whose `Text` changed this frame.
|
|
@@ -57275,7 +57659,7 @@ function remeasureShown(state, element, source) {
|
|
|
57275
57659
|
const before = element.measuredSize;
|
|
57276
57660
|
if (node === void 0 || before === void 0) return false;
|
|
57277
57661
|
if (!needsMeasure(element)) return false;
|
|
57278
|
-
const size = naturalSize(element, source);
|
|
57662
|
+
const size = naturalSize(element, source, laidOutWidth(state, node, element));
|
|
57279
57663
|
if (size.width === before.width && size.height === before.height) return false;
|
|
57280
57664
|
node.markDirty();
|
|
57281
57665
|
return true;
|
|
@@ -58131,7 +58515,7 @@ async function loadYogaModule() {
|
|
|
58131
58515
|
*/
|
|
58132
58516
|
function textSourceOf(ctx) {
|
|
58133
58517
|
return {
|
|
58134
|
-
measure: (content, style) => ctx.deps.text.measure(content, style),
|
|
58518
|
+
measure: (content, style, width) => ctx.deps.text.measure(content, style, width),
|
|
58135
58519
|
resolved: (entity) => ctx.deps.world.ecs.get(entity, Text)?.resolved,
|
|
58136
58520
|
duration: (ms) => ctx.deps.i18n.duration(ms)
|
|
58137
58521
|
};
|
|
@@ -58194,9 +58578,11 @@ function createLayoutApi(ctx) {
|
|
|
58194
58578
|
},
|
|
58195
58579
|
enter: (element, span) => {
|
|
58196
58580
|
const hook = element.motion?.enter;
|
|
58197
|
-
|
|
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);
|
|
58198
58583
|
startLoop(ctx, element);
|
|
58199
58584
|
},
|
|
58585
|
+
pose: (element, span) => poseEnter(ctx, element, span),
|
|
58200
58586
|
loop: (element) => startLoop(ctx, element),
|
|
58201
58587
|
change: (element, previous, hint) => {
|
|
58202
58588
|
const hook = element.motion?.change?.Box;
|
|
@@ -58768,18 +59154,21 @@ function registerComponents(ctx, jsx) {
|
|
|
58768
59154
|
for (const feature of ctx.deps.flow.features.all()) for (const entry of feature.description.ui ?? []) if (isComponent(entry)) jsx.register(entry);
|
|
58769
59155
|
}
|
|
58770
59156
|
/**
|
|
58771
|
-
* Opens the two systems of phase `layout`, the `ui.enter`
|
|
58772
|
-
*
|
|
58773
|
-
*
|
|
58774
|
-
*
|
|
58775
|
-
*
|
|
58776
|
-
*
|
|
58777
|
-
*
|
|
58778
|
-
*
|
|
58779
|
-
*
|
|
58780
|
-
*
|
|
58781
|
-
*
|
|
58782
|
-
*
|
|
59157
|
+
* Opens the two systems of phase `layout`, the system `ui.enter` of phase `sync`, the seven world
|
|
59158
|
+
* hooks of `Tree`, `Box`, `Pressed` and `PointerOver`, the two that tell the hosting step a view
|
|
59159
|
+
* lost its `Parent` or its `Held` (a view freed so may hang under its host again), the listener
|
|
59160
|
+
* that asks for every root to be built again after a restore or a load, the two effect handlers,
|
|
59161
|
+
* the hint listener that buffers every released hint for the `change` hooks of the next frame
|
|
59162
|
+
* step, the three tap listeners (the `LocalWrite` patch, the pointer tap that clears the keyboard
|
|
59163
|
+
* focus, and the tap that starts or ends the editing of a text field), the pointer door that opens
|
|
59164
|
+
* the keyboard inside the DOM listener, the key listener of the focus and `LocalWrite` as an input
|
|
59165
|
+
* control, so the cursor shows a hand over a local-state button. On an agent page also the tap
|
|
59166
|
+
* counter of `DebugTrigger` and its check of a view that takes no press.
|
|
59167
|
+
*
|
|
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
|
|
59171
|
+
* closes exactly these, and gives every hosted view its layer back before the ui entities go.
|
|
58783
59172
|
*
|
|
58784
59173
|
* @param ctx - Domain context of the ui plugin.
|
|
58785
59174
|
* @param jsx - The jsx module.
|