@moku-labs/game 0.14.11 → 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-d5Zlh9hf.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-0GIP3tgm.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-aLkoeoGj.d.mts → runtime-BCnKn0xf.d.mts} +1 -1
- package/dist/{src-Do697seR.mjs → src-CtC8w3_z.mjs} +331 -45
- package/dist/testing.d.mts +100 -5
- package/dist/testing.mjs +88 -2
- package/dist/{types-DMoi447V.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-BZa187kz.d.mts → types-DOlpeuGx.d.mts} +25 -3
- package/dist/{types-kNiV7iFj.d.mts → types-Y_rCuXtj.d.mts} +4 -3
- package/dist/{types-yiHtzg1Y.d.mts → types-gisvSHoC.d.mts} +4 -4
- package/dist/visual.d.mts +6 -6
- 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
|
|
@@ -31010,6 +31040,19 @@ function createRange(ctx, layout, reconcile) {
|
|
|
31010
31040
|
return scroll?.window === void 0 ? void 0 : scroll;
|
|
31011
31041
|
}
|
|
31012
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
|
+
/**
|
|
31013
31056
|
* The style an element is laid out with, from the style it resolved to. A row of a windowed
|
|
31014
31057
|
* scroll is laid out at the row height, whatever its style says; a row style with another
|
|
31015
31058
|
* height is one warning per scroll.
|
|
@@ -31192,6 +31235,7 @@ function createRange(ctx, layout, reconcile) {
|
|
|
31192
31235
|
}
|
|
31193
31236
|
return {
|
|
31194
31237
|
rowStyle,
|
|
31238
|
+
rowHeightOf,
|
|
31195
31239
|
slotsFor,
|
|
31196
31240
|
step,
|
|
31197
31241
|
dropRow,
|
|
@@ -31202,14 +31246,18 @@ function createRange(ctx, layout, reconcile) {
|
|
|
31202
31246
|
//#endregion
|
|
31203
31247
|
//#region src/plugins/ui/jsx/remeasure.ts
|
|
31204
31248
|
/**
|
|
31205
|
-
* @file ui/jsx — the
|
|
31206
|
-
*
|
|
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.
|
|
31207
31254
|
*/
|
|
31208
31255
|
/**
|
|
31209
|
-
* Asks for a solve of every root with a
|
|
31210
|
-
*
|
|
31211
|
-
*
|
|
31212
|
-
*
|
|
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.
|
|
31213
31261
|
*
|
|
31214
31262
|
* @param ctx - Domain context of the ui plugin.
|
|
31215
31263
|
* @param state - The jsx state: the elements and their roots.
|
|
@@ -31224,14 +31272,109 @@ function markResizedTexts(ctx, state, layout) {
|
|
|
31224
31272
|
if (layout.remeasure(element)) root.needsSolve = true;
|
|
31225
31273
|
}
|
|
31226
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
|
+
}
|
|
31227
31368
|
//#endregion
|
|
31228
31369
|
//#region src/plugins/ui/jsx/reconcile.ts
|
|
31229
31370
|
/**
|
|
31230
31371
|
* @file ui/jsx — the reconcile: a description tree diffed by identity into the entities `ui`
|
|
31231
|
-
* 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:
|
|
31232
31375
|
* the range of a windowed scroll (`range.ts`), the rest and the motion of the extras
|
|
31233
|
-
* (`extras.ts`), the hint routed to a keyed element (`hints.ts`) and the
|
|
31234
|
-
* (`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`).
|
|
31235
31378
|
*/
|
|
31236
31379
|
/** The four components an element may be drawn with; a state change can trade one for another. */
|
|
31237
31380
|
const VISUALS = [
|
|
@@ -31281,6 +31424,43 @@ const ELEMENT_OWNED = namesOf$1([
|
|
|
31281
31424
|
/** The style of a scroll's content: one object, so a render never reads as a new style. */
|
|
31282
31425
|
const CONTENT_STYLE = Object.freeze({ origin: "topLeft" });
|
|
31283
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
|
+
/**
|
|
31284
31464
|
* The children one element is diffed against. A scroll container holds exactly one of them: the
|
|
31285
31465
|
* content the finger moves, which keeps the rects of its own children and carries them along. Its
|
|
31286
31466
|
* pivot is its top-left corner, so the scroll step writes its offset straight into `y`; it lays
|
|
@@ -31682,6 +31862,7 @@ function createReconciler(ctx, modules, fields) {
|
|
|
31682
31862
|
warned: nameSet(),
|
|
31683
31863
|
scrolledIn: range.isMoving()
|
|
31684
31864
|
};
|
|
31865
|
+
state.styled += 1;
|
|
31685
31866
|
state.elements.set(entity, element);
|
|
31686
31867
|
state.byIdentity.set(identity, entity);
|
|
31687
31868
|
trackHost(state, element);
|
|
@@ -31689,6 +31870,10 @@ function createReconciler(ctx, modules, fields) {
|
|
|
31689
31870
|
if (element.type === "input") fields.enter(element);
|
|
31690
31871
|
if (element.type === "scroll") state.scrolls.add(entity);
|
|
31691
31872
|
modules.layout.attach(element);
|
|
31873
|
+
element.basis = {
|
|
31874
|
+
epoch: state.epoch,
|
|
31875
|
+
rowHeight: range.rowHeightOf(parent, node)
|
|
31876
|
+
};
|
|
31692
31877
|
diffChildren(root, element, childrenOf(node, range.slotsFor(element)), instance);
|
|
31693
31878
|
root.needsSolve = true;
|
|
31694
31879
|
return entity;
|
|
@@ -31791,11 +31976,12 @@ function createReconciler(ctx, modules, fields) {
|
|
|
31791
31976
|
* its offset belongs to the finger, and a new look or a new rect never resets it. The look
|
|
31792
31977
|
* written is recorded as the rest of the visual, so the rest the world holds is always the one
|
|
31793
31978
|
* the element is drawn with: a restore brings it back to exactly that. The extras of the
|
|
31794
|
-
* `components` prop are diffed last.
|
|
31979
|
+
* `components` prop are diffed last. Every call is one write pass of `UiCounters`.
|
|
31795
31980
|
*
|
|
31796
31981
|
* @param element - The element that changed.
|
|
31797
31982
|
*/
|
|
31798
31983
|
function writeLive(element) {
|
|
31984
|
+
state.written += 1;
|
|
31799
31985
|
writeOrder(element);
|
|
31800
31986
|
const visuals = visualOf$1(element);
|
|
31801
31987
|
const values = [...visuals, ...inputOf(element)];
|
|
@@ -31813,41 +31999,99 @@ function createReconciler(ctx, modules, fields) {
|
|
|
31813
31999
|
writeExtras(element);
|
|
31814
32000
|
}
|
|
31815
32001
|
/**
|
|
31816
|
-
*
|
|
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.
|
|
31817
32009
|
*
|
|
31818
|
-
* @param root - The root being reconciled.
|
|
32010
|
+
* @param root - The root being reconciled: its covered flag is one of the state flags.
|
|
31819
32011
|
* @param element - The element that stayed.
|
|
31820
32012
|
* @param node - The node of this render.
|
|
31821
|
-
* @
|
|
32013
|
+
* @returns The flags and the style of this render, and what they change.
|
|
31822
32014
|
*/
|
|
31823
|
-
function
|
|
31824
|
-
|
|
31825
|
-
const
|
|
32015
|
+
function compare(root, element, node) {
|
|
32016
|
+
const previous = element.node;
|
|
32017
|
+
const parent = parentOf(element);
|
|
31826
32018
|
const is = isFlagsOf(node, {
|
|
31827
32019
|
pressed: element.is.pressed,
|
|
31828
32020
|
hover: element.is.hover,
|
|
31829
32021
|
focus: element.is.focus,
|
|
31830
32022
|
covered: root.covered
|
|
31831
32023
|
});
|
|
31832
|
-
const
|
|
31833
|
-
const
|
|
31834
|
-
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);
|
|
31835
32077
|
const motion = node.props.motion;
|
|
31836
32078
|
const loopChanged = motion?.loop !== element.motion?.loop;
|
|
32079
|
+
if (!change.unchanged) delete element.basis;
|
|
31837
32080
|
element.node = node;
|
|
31838
|
-
element.is = is;
|
|
31839
|
-
element.style = style;
|
|
32081
|
+
element.is = change.is;
|
|
32082
|
+
element.style = change.style;
|
|
31840
32083
|
element.motion = motion;
|
|
31841
32084
|
element.instance = instance;
|
|
31842
32085
|
trackHost(state, element);
|
|
31843
32086
|
if (element.type === "input") fields.patch(element);
|
|
31844
32087
|
if (loopChanged && element.entered) modules.layout.loop(element);
|
|
31845
|
-
if (
|
|
31846
|
-
|
|
31847
|
-
|
|
32088
|
+
if (!change.unchanged) {
|
|
32089
|
+
rewrite(root, element, change);
|
|
32090
|
+
element.basis = {
|
|
32091
|
+
epoch: state.epoch,
|
|
32092
|
+
rowHeight: change.rowHeight
|
|
32093
|
+
};
|
|
31848
32094
|
}
|
|
31849
|
-
if (element.live) writeLive(element);
|
|
31850
|
-
if (element.live && !moved) modules.layout.repose(element, parentRect(element), false, hintOf(state, element));
|
|
31851
32095
|
diffChildren(root, element, childrenOf(node, range.slotsFor(element)), instance);
|
|
31852
32096
|
}
|
|
31853
32097
|
/**
|
|
@@ -32208,7 +32452,9 @@ function createReconciler(ctx, modules, fields) {
|
|
|
32208
32452
|
modules.layout.scroll(containers, lookup);
|
|
32209
32453
|
range.step(containers);
|
|
32210
32454
|
markResizedTexts(ctx, state, modules.layout);
|
|
32455
|
+
markResizedIcons(ctx, state, modules.layout);
|
|
32211
32456
|
const viewportChanged = modules.styles.useViewport(ctx.deps.renderer.viewport.size());
|
|
32457
|
+
if (viewportChanged) state.epoch += 1;
|
|
32212
32458
|
for (const root of dirtyRoots(viewportChanged)) reconcileDirtyRoot(root);
|
|
32213
32459
|
hostViews(ctx, state);
|
|
32214
32460
|
writeCounters();
|
|
@@ -32224,6 +32470,8 @@ function createReconciler(ctx, modules, fields) {
|
|
|
32224
32470
|
counters.solves = solves;
|
|
32225
32471
|
counters.reconciles = state.reconciles;
|
|
32226
32472
|
counters.windowRenders = state.windowRenders;
|
|
32473
|
+
counters.styled = state.styled;
|
|
32474
|
+
counters.written = state.written;
|
|
32227
32475
|
}
|
|
32228
32476
|
/**
|
|
32229
32477
|
* The second system of phase `layout`: one solve per marked root, then the rects, the rest
|
|
@@ -32325,6 +32573,7 @@ function createReconciler(ctx, modules, fields) {
|
|
|
32325
32573
|
const root = state.roots.get(element.root);
|
|
32326
32574
|
const moved = modules.layout.affectsRect(element.style, style);
|
|
32327
32575
|
element.style = style;
|
|
32576
|
+
state.styled += 1;
|
|
32328
32577
|
if (moved) {
|
|
32329
32578
|
modules.layout.applyStyle(element);
|
|
32330
32579
|
if (root !== void 0) root.needsSolve = true;
|
|
@@ -32453,6 +32702,7 @@ function createJsxApi(ctx, modules) {
|
|
|
32453
32702
|
state.components.set(definition.name, definition);
|
|
32454
32703
|
},
|
|
32455
32704
|
refreshAll: () => {
|
|
32705
|
+
state.epoch += 1;
|
|
32456
32706
|
for (const element of state.elements.values()) modules.layout.markMeasured(element);
|
|
32457
32707
|
for (const root of state.roots.values()) {
|
|
32458
32708
|
root.dirty = true;
|
|
@@ -33188,6 +33438,32 @@ const LINE_SAMPLE = "M";
|
|
|
33188
33438
|
/** Below this a measured length counts as whole: the tolerance Yoga's own rounding uses. */
|
|
33189
33439
|
const WHOLE_EPSILON = 1e-4;
|
|
33190
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
|
+
/**
|
|
33191
33467
|
* Makes an icon square on the line height of the text next to it.
|
|
33192
33468
|
*
|
|
33193
33469
|
* @param line - What one line of that text style measures.
|
|
@@ -33353,6 +33629,7 @@ function installMeasure(state, node, element, source) {
|
|
|
33353
33629
|
const size = naturalSize(element, source);
|
|
33354
33630
|
state.measured += 1;
|
|
33355
33631
|
element.measuredSize = size;
|
|
33632
|
+
if (element.type === "icon") state.iconLine = lineOf(source);
|
|
33356
33633
|
return clampToMode(yoga, size, {
|
|
33357
33634
|
width,
|
|
33358
33635
|
widthMode,
|
|
@@ -33373,9 +33650,12 @@ function markMeasured(state, element) {
|
|
|
33373
33650
|
state.byEntity.get(element.entity)?.markDirty();
|
|
33374
33651
|
}
|
|
33375
33652
|
/**
|
|
33376
|
-
* Marks the node of a
|
|
33377
|
-
*
|
|
33378
|
-
*
|
|
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.
|
|
33379
33659
|
*
|
|
33380
33660
|
* @param state - The layout state, for the node of the element.
|
|
33381
33661
|
* @param element - An element whose `Text` changed this frame.
|
|
@@ -33386,7 +33666,7 @@ function remeasureShown(state, element, source) {
|
|
|
33386
33666
|
const node = state.byEntity.get(element.entity);
|
|
33387
33667
|
const before = element.measuredSize;
|
|
33388
33668
|
if (node === void 0 || before === void 0) return false;
|
|
33389
|
-
if (
|
|
33669
|
+
if (!needsMeasure(element)) return false;
|
|
33390
33670
|
const size = naturalSize(element, source);
|
|
33391
33671
|
if (size.width === before.width && size.height === before.height) return false;
|
|
33392
33672
|
node.markDirty();
|
|
@@ -33830,6 +34110,7 @@ function createLayoutApi(ctx) {
|
|
|
33830
34110
|
markMeasured(state, element);
|
|
33831
34111
|
},
|
|
33832
34112
|
remeasure: (element) => remeasureShown(state, element, source),
|
|
34113
|
+
iconLineMoved: () => iconLineMoved(state, source),
|
|
33833
34114
|
markMeasured: (element) => markMeasured(state, element),
|
|
33834
34115
|
place: (parent, children) => placeChildren(state, parent, children),
|
|
33835
34116
|
free: (element) => freeNode(state, element),
|
|
@@ -34389,6 +34670,7 @@ function stopUi(state) {
|
|
|
34389
34670
|
state.layout.nodes = 0;
|
|
34390
34671
|
state.layout.yoga = void 0;
|
|
34391
34672
|
state.layout.scrolling = void 0;
|
|
34673
|
+
state.layout.iconLine = void 0;
|
|
34392
34674
|
state.jsx.components.clear();
|
|
34393
34675
|
state.jsx.roots.clear();
|
|
34394
34676
|
state.jsx.elements.clear();
|
|
@@ -34744,7 +35026,10 @@ function createJsxState() {
|
|
|
34744
35026
|
hints: [],
|
|
34745
35027
|
scrolls: emptySet(),
|
|
34746
35028
|
windowRenders: 0,
|
|
34747
|
-
remount: false
|
|
35029
|
+
remount: false,
|
|
35030
|
+
epoch: 0,
|
|
35031
|
+
styled: 0,
|
|
35032
|
+
written: 0
|
|
34748
35033
|
};
|
|
34749
35034
|
}
|
|
34750
35035
|
//#endregion
|
|
@@ -34779,6 +35064,7 @@ function createLayoutState() {
|
|
|
34779
35064
|
pointerY: 0,
|
|
34780
35065
|
offset: 0
|
|
34781
35066
|
},
|
|
35067
|
+
iconLine: void 0,
|
|
34782
35068
|
order: 0,
|
|
34783
35069
|
cleanups: []
|
|
34784
35070
|
};
|
|
@@ -36510,4 +36796,4 @@ const screen = [
|
|
|
36510
36796
|
uiPlugin
|
|
36511
36797
|
];
|
|
36512
36798
|
//#endregion
|
|
36513
|
-
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 };
|