@moku-labs/game 0.14.10 → 0.14.12
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/system.d.mts +3 -3
- package/dist/app.d.mts +2 -2
- package/dist/app.mjs +1 -1
- package/dist/assets.d.mts +1 -1
- package/dist/{commands-fUjYUA67.d.mts → commands-BaCx2B9j.d.mts} +5 -5
- package/dist/control.d.mts +4 -4
- package/dist/{define-BN15lAWb.d.mts → define-Ce8SVEN-.d.mts} +2 -2
- package/dist/{headless-CrhefcLu.d.mts → headless-CMHNsKjW.d.mts} +1 -1
- package/dist/{index-pXWn22ql.d.mts → index-CLQ8NOTw.d.mts} +4 -4
- package/dist/index.d.mts +5 -5
- package/dist/index.mjs +1 -1
- package/dist/inspect.d.mts +7 -7
- package/dist/jsx-dev-runtime.d.mts +1 -1
- package/dist/jsx-runtime.d.mts +1 -1
- package/dist/{memory-DR1ibF_s.d.mts → memory-pUQ7YZWC.d.mts} +1 -1
- package/dist/{runtime-DhiqvW6v.d.mts → runtime-BCnKn0xf.d.mts} +1 -1
- package/dist/{src-CzfMhkry.mjs → src-CtC8w3_z.mjs} +353 -50
- package/dist/testing.d.mts +100 -5
- package/dist/testing.mjs +88 -2
- package/dist/{types-S8UOeAML.d.mts → types-BX4Ge_j5.d.mts} +2 -2
- package/dist/{types-BT9S_Lo2.d.mts → types-BjTtGSFb.d.mts} +7 -5
- package/dist/{types-Bc9AvZVO.d.mts → types-CAPv9l29.d.mts} +2 -2
- package/dist/{types-6yCbzHHn.d.mts → types-DOlpeuGx.d.mts} +41 -7
- package/dist/{types-DxKupZ6I.d.mts → types-Y_rCuXtj.d.mts} +4 -3
- package/dist/{types-Biehq93s.d.mts → types-gisvSHoC.d.mts} +4 -4
- package/dist/visual.d.mts +6 -6
- package/dist/visual.mjs +6 -5
- package/llms.txt +4 -3
- package/package.json +1 -1
|
@@ -1399,14 +1399,18 @@ function invoke(state, log, descriptor, signal) {
|
|
|
1399
1399
|
}
|
|
1400
1400
|
/**
|
|
1401
1401
|
* Runs the handler of an awaited effect. A missing handler resolves `undefined` instantly, so a
|
|
1402
|
-
* game without `audio` runs
|
|
1402
|
+
* game without `audio` runs. A `cosmetic` descriptor swallows the failure the same way, after one
|
|
1403
|
+
* warn entry `flow:fx-cosmetic-failed`: a broken sound never fails the node, and it is never
|
|
1404
|
+
* silent either. A failure that arrives after the abort of the signal is no failure: the handler
|
|
1405
|
+
* was told to stop, so nothing is written.
|
|
1403
1406
|
*
|
|
1404
1407
|
* @param state - fx module state.
|
|
1408
|
+
* @param log - The engine log.
|
|
1405
1409
|
* @param descriptor - The awaited descriptor.
|
|
1406
|
-
* @param signal - The
|
|
1410
|
+
* @param signal - The signal the handler is called with.
|
|
1407
1411
|
* @returns What the handler resolved with.
|
|
1408
1412
|
*/
|
|
1409
|
-
async function effectValue(state, descriptor, signal) {
|
|
1413
|
+
async function effectValue(state, log, descriptor, signal) {
|
|
1410
1414
|
const entry = handlerFor(state, descriptor.kind);
|
|
1411
1415
|
if (entry === void 0) return;
|
|
1412
1416
|
try {
|
|
@@ -1415,8 +1419,12 @@ async function effectValue(state, descriptor, signal) {
|
|
|
1415
1419
|
mode: state.mode
|
|
1416
1420
|
});
|
|
1417
1421
|
} catch (error) {
|
|
1418
|
-
if (descriptor.cosmetic
|
|
1419
|
-
|
|
1422
|
+
if (descriptor.cosmetic !== true) throw error;
|
|
1423
|
+
if (signal.aborted) return;
|
|
1424
|
+
log.warn("flow:fx-cosmetic-failed", {
|
|
1425
|
+
kind: descriptor.kind,
|
|
1426
|
+
message: asError$5(error).message
|
|
1427
|
+
});
|
|
1420
1428
|
}
|
|
1421
1429
|
}
|
|
1422
1430
|
/**
|
|
@@ -1567,7 +1575,7 @@ function createFxApi(ctx, deps) {
|
|
|
1567
1575
|
const answers = descriptor.answers;
|
|
1568
1576
|
if (answers !== void 0) return openForAnswers(ctx, deps.gate, descriptor, answers, signal);
|
|
1569
1577
|
const shown = descriptor.kind === "guide" ? beginGuide(state, signal) : signal;
|
|
1570
|
-
const work = effectValue(state, descriptor, shown);
|
|
1578
|
+
const work = effectValue(state, ctx.log, descriptor, shown);
|
|
1571
1579
|
if (state.mode === "fast" || !ctx.deps.time.isRunning()) return work;
|
|
1572
1580
|
return enqueue(state, work);
|
|
1573
1581
|
},
|
|
@@ -3340,6 +3348,25 @@ function refuseEffect(signal) {
|
|
|
3340
3348
|
return refused;
|
|
3341
3349
|
}
|
|
3342
3350
|
/**
|
|
3351
|
+
* Refuses a descriptor that `fx.start` may not start: one with `answers`, and a `guide`. Both end
|
|
3352
|
+
* with an answer, and an answer has to be awaited. Every other descriptor passes. The one place
|
|
3353
|
+
* this rule and its message are written: the `fx` of a node context calls it, and so does
|
|
3354
|
+
* `fakeFx` of the testing entry, so a unit test gets the error the game would get.
|
|
3355
|
+
*
|
|
3356
|
+
* @param descriptor - The descriptor a body hands to `fx.start`.
|
|
3357
|
+
* @param path - Runtime path of the node, named in the message.
|
|
3358
|
+
* @throws {Error} When the descriptor has `answers` or is a `guide`.
|
|
3359
|
+
* @example
|
|
3360
|
+
* ```ts
|
|
3361
|
+
* refuseStart({ kind: "sfx" }, "board/place"); // undefined: a sound may be started
|
|
3362
|
+
* refuseStart({ kind: "popup", answers: ["ok"] }, "board/place"); // throws '[game] fx.start() got the effect "popup" in the node "board/place", …'
|
|
3363
|
+
* ```
|
|
3364
|
+
*/
|
|
3365
|
+
function refuseStart(descriptor, path) {
|
|
3366
|
+
if (descriptor.answers === void 0 && descriptor.kind !== "guide") return;
|
|
3367
|
+
throw new Error(`[game] fx.start() got the effect "${descriptor.kind}" in the node "${path}", and its answer has to be awaited.\n Write await fx(...) for a descriptor with answers and for a guide.`);
|
|
3368
|
+
}
|
|
3369
|
+
/**
|
|
3343
3370
|
* Builds the `fx` of a node context: awaited effects by call, effects the body does not wait for
|
|
3344
3371
|
* by `start`, cosmetic hints by `emit`. A `guide` narrows the gate while it runs; the runner lifts
|
|
3345
3372
|
* the narrow when the node is left. A body that was aborted keeps running, since the loop only
|
|
@@ -3373,8 +3400,9 @@ function nodeFx(modules, step) {
|
|
|
3373
3400
|
* Starts one effect and does not wait for it. It takes the path of an awaited effect, so the
|
|
3374
3401
|
* mode and the node's signal apply; only its end is nobody's wait. A failure is the handler's:
|
|
3375
3402
|
* it goes to the log and never to the node. A `cosmetic` descriptor does not get that far: the
|
|
3376
|
-
* gateway swallows its failure
|
|
3377
|
-
*
|
|
3403
|
+
* gateway swallows its failure and writes the warn entry `flow:fx-cosmetic-failed` itself, so
|
|
3404
|
+
* no `flow:fx-start-failed` follows. After the abort of the node nothing is started and nothing
|
|
3405
|
+
* is thrown, not even for a descriptor refused otherwise. An effect that ends with a rejection
|
|
3378
3406
|
* after the abort did not fail: its handler was told to stop, so nothing is logged.
|
|
3379
3407
|
*
|
|
3380
3408
|
* @param descriptor - The descriptor the node starts.
|
|
@@ -3382,7 +3410,7 @@ function nodeFx(modules, step) {
|
|
|
3382
3410
|
*/
|
|
3383
3411
|
const start = (descriptor) => {
|
|
3384
3412
|
if (step.signal.aborted) return;
|
|
3385
|
-
|
|
3413
|
+
refuseStart(descriptor, step.path);
|
|
3386
3414
|
modules.fx.run(descriptor, step.signal).catch((error) => {
|
|
3387
3415
|
if (step.signal.aborted) return;
|
|
3388
3416
|
step.log.error("flow:fx-start-failed", {
|
|
@@ -28265,16 +28293,18 @@ const Covered = /*#__PURE__*/ tag("Covered");
|
|
|
28265
28293
|
*/
|
|
28266
28294
|
const Escapable = /*#__PURE__*/ tag("Escapable");
|
|
28267
28295
|
/**
|
|
28268
|
-
* The three Yoga counters, the reconcile count of the frame
|
|
28269
|
-
*
|
|
28270
|
-
* `app.ui`.
|
|
28296
|
+
* The three Yoga counters, the reconcile count of the frame, the range re-renders of the windowed
|
|
28297
|
+
* lists, and the style and write passes of the reconcile. Written by the two systems of `ui`, read
|
|
28298
|
+
* by the acceptance tests. Not part of `app.ui`.
|
|
28271
28299
|
*/
|
|
28272
28300
|
const UiCounters = /*#__PURE__*/ resource("UiCounters", {
|
|
28273
28301
|
solves: 0,
|
|
28274
28302
|
nodes: 0,
|
|
28275
28303
|
measured: 0,
|
|
28276
28304
|
reconciles: 0,
|
|
28277
|
-
windowRenders: 0
|
|
28305
|
+
windowRenders: 0,
|
|
28306
|
+
styled: 0,
|
|
28307
|
+
written: 0
|
|
28278
28308
|
});
|
|
28279
28309
|
/**
|
|
28280
28310
|
* Builds the effect a node awaits to show a popup. The gate opens for the outcomes of the
|
|
@@ -29850,10 +29880,22 @@ function contentOf$2(element, resolvedOf) {
|
|
|
29850
29880
|
return plain === "" ? void 0 : plain;
|
|
29851
29881
|
}
|
|
29852
29882
|
/**
|
|
29883
|
+
* The text style key a text element was given: its `style` prop while that is a key.
|
|
29884
|
+
*
|
|
29885
|
+
* @param element - The element to read.
|
|
29886
|
+
* @returns The key, or `undefined` for any other element and for a text with a `Style` object or
|
|
29887
|
+
* no style.
|
|
29888
|
+
*/
|
|
29889
|
+
function textStyleOf(element) {
|
|
29890
|
+
if (element.type !== "text") return void 0;
|
|
29891
|
+
const style = element.node.props.style;
|
|
29892
|
+
return typeof style === "string" ? style : void 0;
|
|
29893
|
+
}
|
|
29894
|
+
/**
|
|
29853
29895
|
* Turns one element and its subtree into snapshot nodes. The rect is natural; a fitted element
|
|
29854
|
-
* adds the scale it is drawn at; a text adds the words it draws
|
|
29855
|
-
* windowed scroll adds its window. The spacers of a windowed
|
|
29856
|
-
* lists the live rows.
|
|
29896
|
+
* adds the scale it is drawn at; a text adds the words it draws and the style key of a keyed
|
|
29897
|
+
* text; a text field adds its value; a windowed scroll adds its window. The spacers of a windowed
|
|
29898
|
+
* scroll are left out: its content lists the live rows.
|
|
29857
29899
|
*
|
|
29858
29900
|
* @param state - The jsx state.
|
|
29859
29901
|
* @param element - The element to read.
|
|
@@ -29879,10 +29921,15 @@ function nodeOf(state, element, resolvedOf) {
|
|
|
29879
29921
|
...node,
|
|
29880
29922
|
content
|
|
29881
29923
|
};
|
|
29882
|
-
const
|
|
29924
|
+
const textStyle = textStyleOf(element);
|
|
29925
|
+
const styled = textStyle === void 0 ? worded : {
|
|
29883
29926
|
...worded,
|
|
29927
|
+
textStyle
|
|
29928
|
+
};
|
|
29929
|
+
const fitted = element.style.fit === "contain" ? {
|
|
29930
|
+
...styled,
|
|
29884
29931
|
fitScale: element.fit
|
|
29885
|
-
} :
|
|
29932
|
+
} : styled;
|
|
29886
29933
|
const field = state.fields.get(element.entity);
|
|
29887
29934
|
const valued = field === void 0 ? fitted : {
|
|
29888
29935
|
...fitted,
|
|
@@ -30993,6 +31040,19 @@ function createRange(ctx, layout, reconcile) {
|
|
|
30993
31040
|
return scroll?.window === void 0 ? void 0 : scroll;
|
|
30994
31041
|
}
|
|
30995
31042
|
/**
|
|
31043
|
+
* The height an element is laid out at as a row of a windowed scroll, whatever its style says.
|
|
31044
|
+
* The reconcile keeps it with the resolved style: a row whose scroll names another row height
|
|
31045
|
+
* is laid out again, though its own description says the same.
|
|
31046
|
+
*
|
|
31047
|
+
* @param parent - The parent of the element.
|
|
31048
|
+
* @param node - The node of this render.
|
|
31049
|
+
* @returns The row height, or `undefined` for an element that is no row of a windowed scroll.
|
|
31050
|
+
*/
|
|
31051
|
+
function rowHeightOf(parent, node) {
|
|
31052
|
+
const scroll = windowedScrollOf(parent);
|
|
31053
|
+
return scroll?.window === void 0 || isOwnKey(node.key) ? void 0 : scroll.window.rowHeight;
|
|
31054
|
+
}
|
|
31055
|
+
/**
|
|
30996
31056
|
* The style an element is laid out with, from the style it resolved to. A row of a windowed
|
|
30997
31057
|
* scroll is laid out at the row height, whatever its style says; a row style with another
|
|
30998
31058
|
* height is one warning per scroll.
|
|
@@ -31175,6 +31235,7 @@ function createRange(ctx, layout, reconcile) {
|
|
|
31175
31235
|
}
|
|
31176
31236
|
return {
|
|
31177
31237
|
rowStyle,
|
|
31238
|
+
rowHeightOf,
|
|
31178
31239
|
slotsFor,
|
|
31179
31240
|
step,
|
|
31180
31241
|
dropRow,
|
|
@@ -31185,14 +31246,18 @@ function createRange(ctx, layout, reconcile) {
|
|
|
31185
31246
|
//#endregion
|
|
31186
31247
|
//#region src/plugins/ui/jsx/remeasure.ts
|
|
31187
31248
|
/**
|
|
31188
|
-
* @file ui/jsx — the
|
|
31189
|
-
*
|
|
31249
|
+
* @file ui/jsx — the remeasure step: a text `text` wrote this frame is measured again, and its
|
|
31250
|
+
* root solves only when it takes another size. A bound text is written when the string it shows
|
|
31251
|
+
* changes; any text when `text` resolves it again, after a new locale or when its font arrives.
|
|
31252
|
+
* An icon without a size carries no `Text`: it is measured again when the line it is squared on
|
|
31253
|
+
* moved.
|
|
31190
31254
|
*/
|
|
31191
31255
|
/**
|
|
31192
|
-
* Asks for a solve of every root with a
|
|
31193
|
-
*
|
|
31194
|
-
*
|
|
31195
|
-
*
|
|
31256
|
+
* Asks for a solve of every root with a text that measures to another size now. `text` writes
|
|
31257
|
+
* `resolved` earlier in this phase: for a bound text when the string it shows changed, so a
|
|
31258
|
+
* counter that stands still walks nothing, and for every label it resolved again, a message after
|
|
31259
|
+
* a new locale or any label whose font arrived. No root is reconciled for it and no view runs. A
|
|
31260
|
+
* leaving text is out of the flow: its roll solves nothing.
|
|
31196
31261
|
*
|
|
31197
31262
|
* @param ctx - Domain context of the ui plugin.
|
|
31198
31263
|
* @param state - The jsx state: the elements and their roots.
|
|
@@ -31207,14 +31272,109 @@ function markResizedTexts(ctx, state, layout) {
|
|
|
31207
31272
|
if (layout.remeasure(element)) root.needsSolve = true;
|
|
31208
31273
|
}
|
|
31209
31274
|
}
|
|
31275
|
+
/**
|
|
31276
|
+
* Asks for a solve of every root with an icon that takes another size now. An icon without a
|
|
31277
|
+
* size is square on one line of the `body` text style and carries no `Text`, so `text` never
|
|
31278
|
+
* names it. The layout reads that line once per call, and the icons are walked only when it
|
|
31279
|
+
* moved: the body font arrived, left or was replaced, with or without a text on the screen. A
|
|
31280
|
+
* leaving icon is out of the flow.
|
|
31281
|
+
*
|
|
31282
|
+
* @param ctx - Domain context of the ui plugin.
|
|
31283
|
+
* @param state - The jsx state: the elements and their roots.
|
|
31284
|
+
* @param layout - The layout module, which knows the line and measures the icon again.
|
|
31285
|
+
*/
|
|
31286
|
+
function markResizedIcons(ctx, state, layout) {
|
|
31287
|
+
if (!layout.iconLineMoved()) return;
|
|
31288
|
+
const ecs = ctx.deps.world.ecs;
|
|
31289
|
+
for (const element of state.elements.values()) {
|
|
31290
|
+
const root = state.roots.get(element.root);
|
|
31291
|
+
if (!(element.type === "icon" && !ecs.has(element.entity, Exiting)) || root === void 0) continue;
|
|
31292
|
+
if (layout.remeasure(element)) root.needsSolve = true;
|
|
31293
|
+
}
|
|
31294
|
+
}
|
|
31295
|
+
//#endregion
|
|
31296
|
+
//#region src/plugins/ui/jsx/same.ts
|
|
31297
|
+
/**
|
|
31298
|
+
* @file ui/jsx — the comparison of two prop values of a description. A view builds its props
|
|
31299
|
+
* again at every render, so identity says nothing about plain data: a plain object and an array
|
|
31300
|
+
* are compared by value. Anything else is compared by identity, because only its owner knows what
|
|
31301
|
+
* it holds: a function, a `Set`, a `Map`, a `Date`, a class instance. Pure.
|
|
31302
|
+
*/
|
|
31303
|
+
/**
|
|
31304
|
+
* Tells a plain object from any other: one written as a literal, or made without a prototype.
|
|
31305
|
+
*
|
|
31306
|
+
* @param value - An object that is no array.
|
|
31307
|
+
* @returns True when its own enumerable keys are all it holds.
|
|
31308
|
+
* @example
|
|
31309
|
+
* ```ts
|
|
31310
|
+
* isPlain(new Set(["a"])); // false
|
|
31311
|
+
* ```
|
|
31312
|
+
*/
|
|
31313
|
+
function isPlain(value) {
|
|
31314
|
+
const prototype = Object.getPrototypeOf(value);
|
|
31315
|
+
return prototype === Object.prototype || prototype === null;
|
|
31316
|
+
}
|
|
31317
|
+
/**
|
|
31318
|
+
* Compares two lists by value: the same length and the same entry at every index.
|
|
31319
|
+
*
|
|
31320
|
+
* @param left - The list of the last render.
|
|
31321
|
+
* @param right - What this render wrote in its place.
|
|
31322
|
+
* @returns True when `right` is a list that says the same.
|
|
31323
|
+
* @example
|
|
31324
|
+
* ```ts
|
|
31325
|
+
* sameList(["a", { n: 1 }], ["a", { n: 1 }]); // true
|
|
31326
|
+
* ```
|
|
31327
|
+
*/
|
|
31328
|
+
function sameList(left, right) {
|
|
31329
|
+
return Array.isArray(right) && left.length === right.length && left.every((entry, index) => sameValue(entry, right[index]));
|
|
31330
|
+
}
|
|
31331
|
+
/**
|
|
31332
|
+
* Compares two plain objects by value: the same own keys, each with the same value.
|
|
31333
|
+
*
|
|
31334
|
+
* @param left - The object of the last render.
|
|
31335
|
+
* @param right - The object of this render.
|
|
31336
|
+
* @returns True when both say the same.
|
|
31337
|
+
* @example
|
|
31338
|
+
* ```ts
|
|
31339
|
+
* sameFieldsDeep({ gap: 8, padding: { top: 4 } }, { gap: 8, padding: { top: 4 } }); // true
|
|
31340
|
+
* ```
|
|
31341
|
+
*/
|
|
31342
|
+
function sameFieldsDeep(left, right) {
|
|
31343
|
+
const keys = Object.keys(left);
|
|
31344
|
+
return keys.length === Object.keys(right).length && keys.every((key) => Object.hasOwn(right, key) && sameValue(left[key], right[key]));
|
|
31345
|
+
}
|
|
31346
|
+
/**
|
|
31347
|
+
* Tells whether two prop values say the same. Plain objects and arrays are compared by value,
|
|
31348
|
+
* recursing with this function; everything else by identity: a function, a `Set`, a `Map`, a
|
|
31349
|
+
* `Date`, a typed array, a class instance. So two sets are never the same, whatever they hold,
|
|
31350
|
+
* and a hook built once is the same in every new object around it. `NaN` is the same as `NaN`.
|
|
31351
|
+
*
|
|
31352
|
+
* @param left - The value of the last render.
|
|
31353
|
+
* @param right - The value of this render.
|
|
31354
|
+
* @returns True when nothing has to be done for the difference.
|
|
31355
|
+
* @example
|
|
31356
|
+
* ```ts
|
|
31357
|
+
* sameValue({ gap: 8, is: { hover: { gap: 4 } } }, { gap: 8, is: { hover: { gap: 4 } } }); // true
|
|
31358
|
+
* sameValue({ picked: new Set(["a"]) }, { picked: new Set(["a"]) }); // false
|
|
31359
|
+
* ```
|
|
31360
|
+
*/
|
|
31361
|
+
function sameValue(left, right) {
|
|
31362
|
+
if (left === right) return true;
|
|
31363
|
+
if (!(typeof left === "object" && typeof right === "object" && left !== null && right !== null)) return Number.isNaN(left) && Number.isNaN(right);
|
|
31364
|
+
if (Array.isArray(left)) return sameList(left, right);
|
|
31365
|
+
if (Array.isArray(right) || !isPlain(left) || !isPlain(right)) return false;
|
|
31366
|
+
return sameFieldsDeep(left, right);
|
|
31367
|
+
}
|
|
31210
31368
|
//#endregion
|
|
31211
31369
|
//#region src/plugins/ui/jsx/reconcile.ts
|
|
31212
31370
|
/**
|
|
31213
31371
|
* @file ui/jsx — the reconcile: a description tree diffed by identity into the entities `ui`
|
|
31214
|
-
* owns, and the solve that gives every one of them its rect before it is ever drawn.
|
|
31372
|
+
* owns, and the solve that gives every one of them its rect before it is ever drawn. An element
|
|
31373
|
+
* that stays is compared prop by prop, by value: one that says what it said is neither styled nor
|
|
31374
|
+
* written. Beside it:
|
|
31215
31375
|
* the range of a windowed scroll (`range.ts`), the rest and the motion of the extras
|
|
31216
|
-
* (`extras.ts`), the hint routed to a keyed element (`hints.ts`) and the
|
|
31217
|
-
* (`remeasure.ts`).
|
|
31376
|
+
* (`extras.ts`), the hint routed to a keyed element (`hints.ts`) and the remeasure of the texts
|
|
31377
|
+
* `text` resolved again (`remeasure.ts`).
|
|
31218
31378
|
*/
|
|
31219
31379
|
/** The four components an element may be drawn with; a state change can trade one for another. */
|
|
31220
31380
|
const VISUALS = [
|
|
@@ -31264,6 +31424,43 @@ const ELEMENT_OWNED = namesOf$1([
|
|
|
31264
31424
|
/** The style of a scroll's content: one object, so a render never reads as a new style. */
|
|
31265
31425
|
const CONTENT_STYLE = Object.freeze({ origin: "topLeft" });
|
|
31266
31426
|
/**
|
|
31427
|
+
* The props, besides `style`, `state` and `content`, that a live element is written from: `bind`,
|
|
31428
|
+
* `texture`, `name` and `fit` reach its visual, `intent`, `payload`, `local` and `escape` its
|
|
31429
|
+
* input, `components` its extras and `motion` its hooks. Every other prop is read from the node
|
|
31430
|
+
* where it is used, at every patch: `hosts`, the props of a windowed scroll, the props of a text
|
|
31431
|
+
* field, and the children.
|
|
31432
|
+
*/
|
|
31433
|
+
const WRITTEN = [
|
|
31434
|
+
"bind",
|
|
31435
|
+
"texture",
|
|
31436
|
+
"name",
|
|
31437
|
+
"fit",
|
|
31438
|
+
"components",
|
|
31439
|
+
"motion",
|
|
31440
|
+
"intent",
|
|
31441
|
+
"payload",
|
|
31442
|
+
"local",
|
|
31443
|
+
"escape"
|
|
31444
|
+
];
|
|
31445
|
+
/**
|
|
31446
|
+
* Tells whether two nodes write the same visual, input and extras: every prop of `WRITTEN` says
|
|
31447
|
+
* the same, as `sameValue` reads it.
|
|
31448
|
+
*
|
|
31449
|
+
* @param previous - The node the element was last patched from.
|
|
31450
|
+
* @param next - The node of this render.
|
|
31451
|
+
* @returns True when no component of the element has to be written for these props.
|
|
31452
|
+
* @example
|
|
31453
|
+
* ```ts
|
|
31454
|
+
* writesSame(
|
|
31455
|
+
* { type: "button", props: { intent: "claim", payload: { id: 1 } }, children: [] },
|
|
31456
|
+
* { type: "button", props: { intent: "claim", payload: { id: 2 } }, children: [] }
|
|
31457
|
+
* ); // false
|
|
31458
|
+
* ```
|
|
31459
|
+
*/
|
|
31460
|
+
function writesSame(previous, next) {
|
|
31461
|
+
return WRITTEN.every((name) => sameValue(previous.props[name], next.props[name]));
|
|
31462
|
+
}
|
|
31463
|
+
/**
|
|
31267
31464
|
* The children one element is diffed against. A scroll container holds exactly one of them: the
|
|
31268
31465
|
* content the finger moves, which keeps the rects of its own children and carries them along. Its
|
|
31269
31466
|
* pivot is its top-left corner, so the scroll step writes its offset straight into `y`; it lays
|
|
@@ -31665,6 +31862,7 @@ function createReconciler(ctx, modules, fields) {
|
|
|
31665
31862
|
warned: nameSet(),
|
|
31666
31863
|
scrolledIn: range.isMoving()
|
|
31667
31864
|
};
|
|
31865
|
+
state.styled += 1;
|
|
31668
31866
|
state.elements.set(entity, element);
|
|
31669
31867
|
state.byIdentity.set(identity, entity);
|
|
31670
31868
|
trackHost(state, element);
|
|
@@ -31672,6 +31870,10 @@ function createReconciler(ctx, modules, fields) {
|
|
|
31672
31870
|
if (element.type === "input") fields.enter(element);
|
|
31673
31871
|
if (element.type === "scroll") state.scrolls.add(entity);
|
|
31674
31872
|
modules.layout.attach(element);
|
|
31873
|
+
element.basis = {
|
|
31874
|
+
epoch: state.epoch,
|
|
31875
|
+
rowHeight: range.rowHeightOf(parent, node)
|
|
31876
|
+
};
|
|
31675
31877
|
diffChildren(root, element, childrenOf(node, range.slotsFor(element)), instance);
|
|
31676
31878
|
root.needsSolve = true;
|
|
31677
31879
|
return entity;
|
|
@@ -31774,11 +31976,12 @@ function createReconciler(ctx, modules, fields) {
|
|
|
31774
31976
|
* its offset belongs to the finger, and a new look or a new rect never resets it. The look
|
|
31775
31977
|
* written is recorded as the rest of the visual, so the rest the world holds is always the one
|
|
31776
31978
|
* the element is drawn with: a restore brings it back to exactly that. The extras of the
|
|
31777
|
-
* `components` prop are diffed last.
|
|
31979
|
+
* `components` prop are diffed last. Every call is one write pass of `UiCounters`.
|
|
31778
31980
|
*
|
|
31779
31981
|
* @param element - The element that changed.
|
|
31780
31982
|
*/
|
|
31781
31983
|
function writeLive(element) {
|
|
31984
|
+
state.written += 1;
|
|
31782
31985
|
writeOrder(element);
|
|
31783
31986
|
const visuals = visualOf$1(element);
|
|
31784
31987
|
const values = [...visuals, ...inputOf(element)];
|
|
@@ -31796,41 +31999,99 @@ function createReconciler(ctx, modules, fields) {
|
|
|
31796
31999
|
writeExtras(element);
|
|
31797
32000
|
}
|
|
31798
32001
|
/**
|
|
31799
|
-
*
|
|
32002
|
+
* Compares the node of this render with the one a live element was last patched from. The
|
|
32003
|
+
* resolved style is kept, and `styles.resolveElement` not called, while the raw `style` says the
|
|
32004
|
+
* same by value, the state flags are the same, and what a style is resolved on stands: the
|
|
32005
|
+
* epoch of the jsx state, which a new viewport ends, and the row height of a windowed row. The element is unchanged when its style is kept and its `content` and every
|
|
32006
|
+
* prop of `WRITTEN` say the same too. A plain object and an array are compared by value;
|
|
32007
|
+
* anything else by identity: a function, a `Set`, a `Map`, a `Date`, a class instance. The
|
|
32008
|
+
* same object always says the same: one changed in place is not seen.
|
|
31800
32009
|
*
|
|
31801
|
-
* @param root - The root being reconciled.
|
|
32010
|
+
* @param root - The root being reconciled: its covered flag is one of the state flags.
|
|
31802
32011
|
* @param element - The element that stayed.
|
|
31803
32012
|
* @param node - The node of this render.
|
|
31804
|
-
* @
|
|
32013
|
+
* @returns The flags and the style of this render, and what they change.
|
|
31805
32014
|
*/
|
|
31806
|
-
function
|
|
31807
|
-
|
|
31808
|
-
const
|
|
32015
|
+
function compare(root, element, node) {
|
|
32016
|
+
const previous = element.node;
|
|
32017
|
+
const parent = parentOf(element);
|
|
31809
32018
|
const is = isFlagsOf(node, {
|
|
31810
32019
|
pressed: element.is.pressed,
|
|
31811
32020
|
hover: element.is.hover,
|
|
31812
32021
|
focus: element.is.focus,
|
|
31813
32022
|
covered: root.covered
|
|
31814
32023
|
});
|
|
31815
|
-
const
|
|
31816
|
-
const
|
|
31817
|
-
const
|
|
32024
|
+
const rowHeight = range.rowHeightOf(parent, node);
|
|
32025
|
+
const stands = element.basis?.epoch === state.epoch && element.basis.rowHeight === rowHeight;
|
|
32026
|
+
const sameStyle = sameValue(previous.props.style, node.props.style);
|
|
32027
|
+
const keepsStyle = stands && sameStyle && sameValue(element.is, is);
|
|
32028
|
+
const style = keepsStyle ? element.style : styleFor(parent, node, is);
|
|
32029
|
+
const sameContent = sameValue(previous.props.content, node.props.content);
|
|
32030
|
+
return {
|
|
32031
|
+
is,
|
|
32032
|
+
style,
|
|
32033
|
+
rowHeight,
|
|
32034
|
+
resolved: !keepsStyle,
|
|
32035
|
+
moved: !keepsStyle && modules.layout.affectsRect(element.style, style),
|
|
32036
|
+
measures: !stands || !sameStyle || !sameContent,
|
|
32037
|
+
unchanged: keepsStyle && sameContent && writesSame(previous, node)
|
|
32038
|
+
};
|
|
32039
|
+
}
|
|
32040
|
+
/**
|
|
32041
|
+
* Writes what a patch changed on one element: its style onto the layout node when a rect or a
|
|
32042
|
+
* measure may move, which asks the root for a solve; then, on a live element, its visual, its
|
|
32043
|
+
* input and its extras, and its rest pose when no rect moved.
|
|
32044
|
+
*
|
|
32045
|
+
* @param root - The root being reconciled.
|
|
32046
|
+
* @param element - The element, its node, flags and style of this render already set.
|
|
32047
|
+
* @param change - What the patch found.
|
|
32048
|
+
*/
|
|
32049
|
+
function rewrite(root, element, change) {
|
|
32050
|
+
const applies = change.moved || change.measures;
|
|
32051
|
+
if (change.resolved || applies) state.styled += 1;
|
|
32052
|
+
if (applies) {
|
|
32053
|
+
modules.layout.applyStyle(element);
|
|
32054
|
+
root.needsSolve = true;
|
|
32055
|
+
}
|
|
32056
|
+
if (!element.live) return;
|
|
32057
|
+
writeLive(element);
|
|
32058
|
+
if (!change.moved) modules.layout.repose(element, parentRect(element), false, hintOf(state, element));
|
|
32059
|
+
}
|
|
32060
|
+
/**
|
|
32061
|
+
* Updates one live element from its new node. An element whose description says what it said is
|
|
32062
|
+
* neither styled nor written: no `styles.resolveElement`, no `layout.applyStyle`, no solve asked
|
|
32063
|
+
* for, no component set, no rest recorded, no rest pose moved. What still runs for it reads a
|
|
32064
|
+
* prop the comparison leaves out, or costs nothing: the check of a windowed scroll's props; the
|
|
32065
|
+
* node of this render kept on the element, which the hosts, the rows of a windowed scroll, a
|
|
32066
|
+
* text field and the measure of a text read later; its motion and its instance; the host set;
|
|
32067
|
+
* the props of a text field; the loop of a new motion; and the diff of its children.
|
|
32068
|
+
*
|
|
32069
|
+
* @param root - The root being reconciled.
|
|
32070
|
+
* @param element - The element that stayed.
|
|
32071
|
+
* @param node - The node of this render.
|
|
32072
|
+
* @param instance - The identity of the nearest component instance.
|
|
32073
|
+
*/
|
|
32074
|
+
function patch(root, element, node, instance) {
|
|
32075
|
+
checkWindow(node);
|
|
32076
|
+
const change = compare(root, element, node);
|
|
31818
32077
|
const motion = node.props.motion;
|
|
31819
32078
|
const loopChanged = motion?.loop !== element.motion?.loop;
|
|
32079
|
+
if (!change.unchanged) delete element.basis;
|
|
31820
32080
|
element.node = node;
|
|
31821
|
-
element.is = is;
|
|
31822
|
-
element.style = style;
|
|
32081
|
+
element.is = change.is;
|
|
32082
|
+
element.style = change.style;
|
|
31823
32083
|
element.motion = motion;
|
|
31824
32084
|
element.instance = instance;
|
|
31825
32085
|
trackHost(state, element);
|
|
31826
32086
|
if (element.type === "input") fields.patch(element);
|
|
31827
32087
|
if (loopChanged && element.entered) modules.layout.loop(element);
|
|
31828
|
-
if (
|
|
31829
|
-
|
|
31830
|
-
|
|
32088
|
+
if (!change.unchanged) {
|
|
32089
|
+
rewrite(root, element, change);
|
|
32090
|
+
element.basis = {
|
|
32091
|
+
epoch: state.epoch,
|
|
32092
|
+
rowHeight: change.rowHeight
|
|
32093
|
+
};
|
|
31831
32094
|
}
|
|
31832
|
-
if (element.live) writeLive(element);
|
|
31833
|
-
if (element.live && !moved) modules.layout.repose(element, parentRect(element), false, hintOf(state, element));
|
|
31834
32095
|
diffChildren(root, element, childrenOf(node, range.slotsFor(element)), instance);
|
|
31835
32096
|
}
|
|
31836
32097
|
/**
|
|
@@ -32191,7 +32452,9 @@ function createReconciler(ctx, modules, fields) {
|
|
|
32191
32452
|
modules.layout.scroll(containers, lookup);
|
|
32192
32453
|
range.step(containers);
|
|
32193
32454
|
markResizedTexts(ctx, state, modules.layout);
|
|
32455
|
+
markResizedIcons(ctx, state, modules.layout);
|
|
32194
32456
|
const viewportChanged = modules.styles.useViewport(ctx.deps.renderer.viewport.size());
|
|
32457
|
+
if (viewportChanged) state.epoch += 1;
|
|
32195
32458
|
for (const root of dirtyRoots(viewportChanged)) reconcileDirtyRoot(root);
|
|
32196
32459
|
hostViews(ctx, state);
|
|
32197
32460
|
writeCounters();
|
|
@@ -32207,6 +32470,8 @@ function createReconciler(ctx, modules, fields) {
|
|
|
32207
32470
|
counters.solves = solves;
|
|
32208
32471
|
counters.reconciles = state.reconciles;
|
|
32209
32472
|
counters.windowRenders = state.windowRenders;
|
|
32473
|
+
counters.styled = state.styled;
|
|
32474
|
+
counters.written = state.written;
|
|
32210
32475
|
}
|
|
32211
32476
|
/**
|
|
32212
32477
|
* The second system of phase `layout`: one solve per marked root, then the rects, the rest
|
|
@@ -32308,6 +32573,7 @@ function createReconciler(ctx, modules, fields) {
|
|
|
32308
32573
|
const root = state.roots.get(element.root);
|
|
32309
32574
|
const moved = modules.layout.affectsRect(element.style, style);
|
|
32310
32575
|
element.style = style;
|
|
32576
|
+
state.styled += 1;
|
|
32311
32577
|
if (moved) {
|
|
32312
32578
|
modules.layout.applyStyle(element);
|
|
32313
32579
|
if (root !== void 0) root.needsSolve = true;
|
|
@@ -32436,6 +32702,7 @@ function createJsxApi(ctx, modules) {
|
|
|
32436
32702
|
state.components.set(definition.name, definition);
|
|
32437
32703
|
},
|
|
32438
32704
|
refreshAll: () => {
|
|
32705
|
+
state.epoch += 1;
|
|
32439
32706
|
for (const element of state.elements.values()) modules.layout.markMeasured(element);
|
|
32440
32707
|
for (const root of state.roots.values()) {
|
|
32441
32708
|
root.dirty = true;
|
|
@@ -33171,6 +33438,32 @@ const LINE_SAMPLE = "M";
|
|
|
33171
33438
|
/** Below this a measured length counts as whole: the tolerance Yoga's own rounding uses. */
|
|
33172
33439
|
const WHOLE_EPSILON = 1e-4;
|
|
33173
33440
|
/**
|
|
33441
|
+
* One line of the text style an icon without a size is squared on.
|
|
33442
|
+
*
|
|
33443
|
+
* @param source - What the line is measured through.
|
|
33444
|
+
* @returns The height of that line, as `text` measures it now.
|
|
33445
|
+
*/
|
|
33446
|
+
function lineOf(source) {
|
|
33447
|
+
return source.measure(LINE_SAMPLE, DEFAULT_TEXT_STYLE).height;
|
|
33448
|
+
}
|
|
33449
|
+
/**
|
|
33450
|
+
* Tells whether the line the icons are squared on moved since an icon was last measured: the
|
|
33451
|
+
* body font arrived, left or was replaced, or the style was swapped. Nothing is read before the
|
|
33452
|
+
* first icon without a size was measured, so a screen without one costs nothing; after that a
|
|
33453
|
+
* call is one read of the advance table. A move is told once.
|
|
33454
|
+
*
|
|
33455
|
+
* @param state - The layout state: the line the icons were last measured with.
|
|
33456
|
+
* @param source - What the line is measured through.
|
|
33457
|
+
* @returns True when every icon without a size has to be measured again.
|
|
33458
|
+
*/
|
|
33459
|
+
function iconLineMoved(state, source) {
|
|
33460
|
+
if (state.iconLine === void 0) return false;
|
|
33461
|
+
const line = lineOf(source);
|
|
33462
|
+
if (line === state.iconLine) return false;
|
|
33463
|
+
state.iconLine = line;
|
|
33464
|
+
return true;
|
|
33465
|
+
}
|
|
33466
|
+
/**
|
|
33174
33467
|
* Makes an icon square on the line height of the text next to it.
|
|
33175
33468
|
*
|
|
33176
33469
|
* @param line - What one line of that text style measures.
|
|
@@ -33336,6 +33629,7 @@ function installMeasure(state, node, element, source) {
|
|
|
33336
33629
|
const size = naturalSize(element, source);
|
|
33337
33630
|
state.measured += 1;
|
|
33338
33631
|
element.measuredSize = size;
|
|
33632
|
+
if (element.type === "icon") state.iconLine = lineOf(source);
|
|
33339
33633
|
return clampToMode(yoga, size, {
|
|
33340
33634
|
width,
|
|
33341
33635
|
widthMode,
|
|
@@ -33356,9 +33650,12 @@ function markMeasured(state, element) {
|
|
|
33356
33650
|
state.byEntity.get(element.entity)?.markDirty();
|
|
33357
33651
|
}
|
|
33358
33652
|
/**
|
|
33359
|
-
* Marks the node of a
|
|
33360
|
-
*
|
|
33361
|
-
*
|
|
33653
|
+
* Marks the node of a text dirty when what it draws now measures to another size than the node was
|
|
33654
|
+
* laid out with. `text` writes `Text` when the shown string of a bound label changes, and for
|
|
33655
|
+
* every label it resolves again: a message after a new locale, any label when its font arrives or
|
|
33656
|
+
* its style is swapped. So a text without `bind` is measured again too, and a counter that rolls
|
|
33657
|
+
* through digits of one width asks for no solve. A text with a fixed size has no measure function
|
|
33658
|
+
* and is left alone.
|
|
33362
33659
|
*
|
|
33363
33660
|
* @param state - The layout state, for the node of the element.
|
|
33364
33661
|
* @param element - An element whose `Text` changed this frame.
|
|
@@ -33369,7 +33666,7 @@ function remeasureShown(state, element, source) {
|
|
|
33369
33666
|
const node = state.byEntity.get(element.entity);
|
|
33370
33667
|
const before = element.measuredSize;
|
|
33371
33668
|
if (node === void 0 || before === void 0) return false;
|
|
33372
|
-
if (
|
|
33669
|
+
if (!needsMeasure(element)) return false;
|
|
33373
33670
|
const size = naturalSize(element, source);
|
|
33374
33671
|
if (size.width === before.width && size.height === before.height) return false;
|
|
33375
33672
|
node.markDirty();
|
|
@@ -33813,6 +34110,7 @@ function createLayoutApi(ctx) {
|
|
|
33813
34110
|
markMeasured(state, element);
|
|
33814
34111
|
},
|
|
33815
34112
|
remeasure: (element) => remeasureShown(state, element, source),
|
|
34113
|
+
iconLineMoved: () => iconLineMoved(state, source),
|
|
33816
34114
|
markMeasured: (element) => markMeasured(state, element),
|
|
33817
34115
|
place: (parent, children) => placeChildren(state, parent, children),
|
|
33818
34116
|
free: (element) => freeNode(state, element),
|
|
@@ -34372,6 +34670,7 @@ function stopUi(state) {
|
|
|
34372
34670
|
state.layout.nodes = 0;
|
|
34373
34671
|
state.layout.yoga = void 0;
|
|
34374
34672
|
state.layout.scrolling = void 0;
|
|
34673
|
+
state.layout.iconLine = void 0;
|
|
34375
34674
|
state.jsx.components.clear();
|
|
34376
34675
|
state.jsx.roots.clear();
|
|
34377
34676
|
state.jsx.elements.clear();
|
|
@@ -34727,7 +35026,10 @@ function createJsxState() {
|
|
|
34727
35026
|
hints: [],
|
|
34728
35027
|
scrolls: emptySet(),
|
|
34729
35028
|
windowRenders: 0,
|
|
34730
|
-
remount: false
|
|
35029
|
+
remount: false,
|
|
35030
|
+
epoch: 0,
|
|
35031
|
+
styled: 0,
|
|
35032
|
+
written: 0
|
|
34731
35033
|
};
|
|
34732
35034
|
}
|
|
34733
35035
|
//#endregion
|
|
@@ -34762,6 +35064,7 @@ function createLayoutState() {
|
|
|
34762
35064
|
pointerY: 0,
|
|
34763
35065
|
offset: 0
|
|
34764
35066
|
},
|
|
35067
|
+
iconLine: void 0,
|
|
34765
35068
|
order: 0,
|
|
34766
35069
|
cleanups: []
|
|
34767
35070
|
};
|
|
@@ -36493,4 +36796,4 @@ const screen = [
|
|
|
36493
36796
|
uiPlugin
|
|
36494
36797
|
];
|
|
36495
36798
|
//#endregion
|
|
36496
|
-
export { sfx as $, types_exports$13 as A, Noise as At, defineStyle as B, rendererPlugin as Bt, types_exports$6 as C, effectsPlugin as Ct, types_exports$10 as D, ColorMatrix as Dt, types_exports$9 as E, Blur as Et, resolve as F, assetsPlugin as Ft, external as G,
|
|
36799
|
+
export { sfx as $, types_exports$13 as A, Noise as At, defineStyle as B, rendererPlugin as Bt, types_exports$6 as C, effectsPlugin as Ct, types_exports$10 as D, ColorMatrix as Dt, types_exports$9 as E, Blur as Et, resolve as F, assetsPlugin as Ft, external as G, slot as Gt, platformPlugin as H, flowPlugin as Ht, Box as I, animPlugin as It, mark as J, modelPlugin as Jt, frames as K, to as Kt, LocalWrite as L, AnimPlayer as Lt, types_exports$15 as M, defineFilter as Mt, types_exports$16 as N, audioPlugin as Nt, types_exports$11 as O, Displacement as Ot, uiPlugin as P, scenesPlugin as Pt, set as Q, clockPlugin as Qt, popup as R, Animation as Rt, types_exports$5 as S, messageDuration as St, types_exports$8 as T, Alpha as Tt, HAPTIC_KINDS as U, refuseStart as Ut, textPlugin as V, worldPlugin as Vt, defineAnimation as W, exit as Wt, play$1 as X, lifecyclePlugin as Xt, parallel as Y, SaveUnreadableError as Yt, sequence as Z, timePlugin as Zt, types_exports as _, Touchable as _t, defineMotion as a, wait as at, types_exports$3 as b, i18nPlugin as bt, schedule as c, DropTarget as ct, tr as d, Pointer as dt, spawn as et, defineFeature as f, PointerOver as ft, load as g, Tappable as gt, defineBundles as h, Swipeable as ht, screen as i, use as it, types_exports$14 as j, Outline as jt, types_exports$12 as k, Glow as kt, projection as l, Held as lt, music as m, Pressed as mt, createPlugin as n, stagger as nt, guide as o, inputPlugin as ot, defineEmitter as p, Pressable as pt, haptic as q, type as qt, defineGame as r, tween as rt, hint as s, Draggable as st, createApp as t, spawned as tt, defineScene as u, Hovered as ut, types_exports$1 as v, Traceable as vt, types_exports$7 as w, Emitter as wt, types_exports$4 as x, messageArgument as xt, types_exports$2 as y, Traced as yt, defineTokens as z, Frames as zt };
|