@grahlnn/comps 0.1.8 → 0.1.10
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/index.js +1948 -1148
- package/dist/torph/index.d.ts +2 -1
- package/dist/torph/src/components/Torph.d.ts +3 -112
- package/dist/torph/src/core/dom-measurement.d.ts +42 -0
- package/dist/torph/src/core/finalize-barrier.d.ts +13 -0
- package/dist/torph/src/core/layout-observer.d.ts +10 -0
- package/dist/torph/src/core/math.d.ts +1 -0
- package/dist/torph/src/core/measurement-policy.d.ts +23 -0
- package/dist/torph/src/core/render.d.ts +16 -0
- package/dist/torph/src/core/root-motion-bridge.d.ts +6 -0
- package/dist/torph/src/core/session.d.ts +81 -0
- package/dist/torph/src/core/snapshot.d.ts +3 -0
- package/dist/torph/src/core/types.d.ts +108 -0
- package/dist/torph/src/debug/trace.d.ts +121 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// torph/src/components/Torph.tsx
|
|
2
2
|
import {
|
|
3
|
-
useLayoutEffect,
|
|
3
|
+
useLayoutEffect as useLayoutEffect2,
|
|
4
4
|
useMemo,
|
|
5
|
-
useRef,
|
|
6
|
-
useState
|
|
5
|
+
useRef as useRef2,
|
|
6
|
+
useState as useState2
|
|
7
7
|
} from "react";
|
|
8
8
|
|
|
9
9
|
// torph/src/vendor/pretext/bidi.ts
|
|
@@ -2516,8 +2516,12 @@ function measureMorphSnapshotWithPretext(text, layoutContext) {
|
|
|
2516
2516
|
};
|
|
2517
2517
|
}
|
|
2518
2518
|
|
|
2519
|
-
// torph/src/
|
|
2520
|
-
|
|
2519
|
+
// torph/src/core/math.ts
|
|
2520
|
+
function nearlyEqual(a, b, epsilon = 0.5) {
|
|
2521
|
+
return Math.abs(a - b) <= epsilon;
|
|
2522
|
+
}
|
|
2523
|
+
|
|
2524
|
+
// torph/src/core/types.ts
|
|
2521
2525
|
var MORPH = {
|
|
2522
2526
|
durationMs: 280,
|
|
2523
2527
|
maxFadeMs: 150,
|
|
@@ -2526,8 +2530,6 @@ var MORPH = {
|
|
|
2526
2530
|
contentWidthLockEpsilon: 2,
|
|
2527
2531
|
lineGroupingEpsilon: 1
|
|
2528
2532
|
};
|
|
2529
|
-
var MORPH_SEGMENT_CACHE_LIMIT = 256;
|
|
2530
|
-
var DOM_MEASUREMENT_SNAPSHOT_CACHE_LIMIT = 8;
|
|
2531
2533
|
var EMPTY_STATE = {
|
|
2532
2534
|
stage: "idle",
|
|
2533
2535
|
measurement: null,
|
|
@@ -2548,22 +2550,19 @@ var ZERO_BRIDGE = {
|
|
|
2548
2550
|
offsetY: 0
|
|
2549
2551
|
};
|
|
2550
2552
|
var EMPTY_SEGMENTS = [];
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2553
|
+
function resolveContentWidthLockInlineSize(layoutHint) {
|
|
2554
|
+
if (layoutHint.flowInlineSize !== null) {
|
|
2555
|
+
return layoutHint.flowInlineSize;
|
|
2556
|
+
}
|
|
2557
|
+
return layoutHint.snapshot.width;
|
|
2558
|
+
}
|
|
2559
|
+
|
|
2560
|
+
// torph/src/core/render.ts
|
|
2561
|
+
var OVERLAY_STYLE = {
|
|
2557
2562
|
position: "absolute",
|
|
2558
|
-
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
padding: 0,
|
|
2562
|
-
border: 0,
|
|
2563
|
-
clip: "rect(0 0 0 0)",
|
|
2564
|
-
clipPath: "inset(50%)",
|
|
2565
|
-
overflow: "hidden",
|
|
2566
|
-
whiteSpace: "nowrap"
|
|
2563
|
+
inset: 0,
|
|
2564
|
+
minWidth: 0,
|
|
2565
|
+
pointerEvents: "none"
|
|
2567
2566
|
};
|
|
2568
2567
|
var MEASUREMENT_LAYER_STYLE = {
|
|
2569
2568
|
pointerEvents: "none",
|
|
@@ -2574,299 +2573,721 @@ var MEASUREMENT_LAYER_STYLE = {
|
|
|
2574
2573
|
right: 0,
|
|
2575
2574
|
display: "block"
|
|
2576
2575
|
};
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
gridArea: "1 / 1"
|
|
2580
|
-
};
|
|
2581
|
-
var OVERLAY_STYLE = {
|
|
2582
|
-
position: "absolute",
|
|
2583
|
-
inset: 0,
|
|
2584
|
-
minWidth: 0,
|
|
2585
|
-
pointerEvents: "none"
|
|
2586
|
-
};
|
|
2587
|
-
var SHARED_GLYPH_TYPOGRAPHY_STYLE = {
|
|
2588
|
-
font: "inherit",
|
|
2589
|
-
fontKerning: "inherit",
|
|
2590
|
-
fontFeatureSettings: "inherit",
|
|
2591
|
-
fontOpticalSizing: "inherit",
|
|
2592
|
-
fontStretch: "inherit",
|
|
2593
|
-
fontStyle: "inherit",
|
|
2594
|
-
fontVariant: "inherit",
|
|
2595
|
-
fontVariantNumeric: "inherit",
|
|
2596
|
-
fontVariationSettings: "inherit",
|
|
2597
|
-
fontWeight: "inherit",
|
|
2598
|
-
letterSpacing: "inherit",
|
|
2599
|
-
textTransform: "inherit",
|
|
2600
|
-
wordSpacing: "inherit",
|
|
2601
|
-
direction: "inherit"
|
|
2602
|
-
};
|
|
2603
|
-
var ABSOLUTE_GLYPH_STYLE = {
|
|
2604
|
-
position: "absolute",
|
|
2605
|
-
display: "block",
|
|
2606
|
-
overflow: "hidden",
|
|
2607
|
-
transformOrigin: "left top"
|
|
2608
|
-
};
|
|
2609
|
-
var CONTEXT_SLICE_TEXT_STYLE = {
|
|
2610
|
-
...SHARED_GLYPH_TYPOGRAPHY_STYLE,
|
|
2611
|
-
position: "absolute",
|
|
2612
|
-
display: "block",
|
|
2613
|
-
minWidth: 0,
|
|
2614
|
-
whiteSpace: "inherit"
|
|
2615
|
-
};
|
|
2616
|
-
var graphemeSegmenter = null;
|
|
2617
|
-
var domMeasurementService = null;
|
|
2618
|
-
var torphDebugInstanceOrdinal = 0;
|
|
2619
|
-
var TORPH_TRACE_MAX_BYTES = 4 * 1024 * 1024;
|
|
2620
|
-
var TORPH_TRACE_MAX_LINES = 4000;
|
|
2621
|
-
var TORPH_TRACE_SCHEMA_VERSION = 2;
|
|
2622
|
-
function nextTorphDebugInstanceId() {
|
|
2623
|
-
torphDebugInstanceOrdinal += 1;
|
|
2624
|
-
return torphDebugInstanceOrdinal;
|
|
2625
|
-
}
|
|
2626
|
-
function readTorphDebugConfig() {
|
|
2627
|
-
const scope = globalThis;
|
|
2628
|
-
return scope.__TORPH_DEBUG__ ?? null;
|
|
2576
|
+
function getFadeDuration(fraction) {
|
|
2577
|
+
return Math.min(MORPH.durationMs * fraction, MORPH.maxFadeMs);
|
|
2629
2578
|
}
|
|
2630
|
-
function
|
|
2631
|
-
if (
|
|
2632
|
-
return
|
|
2579
|
+
function getOverlayStyle(stage, plan) {
|
|
2580
|
+
if (stage === "idle") {
|
|
2581
|
+
return OVERLAY_STYLE;
|
|
2633
2582
|
}
|
|
2634
|
-
|
|
2635
|
-
|
|
2583
|
+
return {
|
|
2584
|
+
...OVERLAY_STYLE,
|
|
2585
|
+
right: "auto",
|
|
2586
|
+
bottom: "auto",
|
|
2587
|
+
width: plan.frameWidth,
|
|
2588
|
+
height: plan.frameHeight
|
|
2589
|
+
};
|
|
2590
|
+
}
|
|
2591
|
+
function getLiveTransform(item, stage, visualBridge) {
|
|
2592
|
+
if (stage !== "prepare") {
|
|
2593
|
+
return "translate(0px, 0px)";
|
|
2636
2594
|
}
|
|
2637
|
-
if (
|
|
2638
|
-
return
|
|
2595
|
+
if (item.kind === "move") {
|
|
2596
|
+
return `translate(${(item.fromLeft ?? item.left) - item.left + visualBridge.offsetX}px, ${(item.fromTop ?? item.top) - item.top + visualBridge.offsetY}px)`;
|
|
2639
2597
|
}
|
|
2640
|
-
return
|
|
2598
|
+
return `translate(${visualBridge.offsetX}px, ${visualBridge.offsetY}px)`;
|
|
2641
2599
|
}
|
|
2642
|
-
function
|
|
2643
|
-
if (
|
|
2644
|
-
return
|
|
2600
|
+
function getLiveTransition(item, stage) {
|
|
2601
|
+
if (stage !== "animate") {
|
|
2602
|
+
return;
|
|
2645
2603
|
}
|
|
2646
|
-
if (
|
|
2647
|
-
return
|
|
2604
|
+
if (item.kind === "enter") {
|
|
2605
|
+
return `opacity ${getFadeDuration(0.5)}ms linear ${getFadeDuration(0.25)}ms`;
|
|
2648
2606
|
}
|
|
2649
|
-
|
|
2650
|
-
|
|
2607
|
+
return `transform ${MORPH.durationMs}ms ${MORPH.ease}, opacity ${getFadeDuration(0.25)}ms linear`;
|
|
2608
|
+
}
|
|
2609
|
+
function getExitTransform(visualBridge) {
|
|
2610
|
+
return `translate(${visualBridge.offsetX}px, ${visualBridge.offsetY}px)`;
|
|
2611
|
+
}
|
|
2612
|
+
function getExitTransition(stage) {
|
|
2613
|
+
if (stage !== "animate") {
|
|
2614
|
+
return;
|
|
2651
2615
|
}
|
|
2652
|
-
return
|
|
2616
|
+
return `transform ${MORPH.durationMs}ms ${MORPH.ease}, opacity ${getFadeDuration(0.25)}ms linear`;
|
|
2653
2617
|
}
|
|
2654
|
-
function
|
|
2655
|
-
|
|
2618
|
+
function supportsIntrinsicWidthLock(display, parentDisplay) {
|
|
2619
|
+
let parentNeedsReservation = false;
|
|
2620
|
+
if (parentDisplay === "flex" || parentDisplay === "inline-flex" || parentDisplay === "grid" || parentDisplay === "inline-grid") {
|
|
2621
|
+
parentNeedsReservation = true;
|
|
2622
|
+
}
|
|
2623
|
+
if (display === "inline" || display === "inline-block" || display === "inline-flex" || display === "inline-grid") {
|
|
2656
2624
|
return true;
|
|
2657
2625
|
}
|
|
2658
|
-
return
|
|
2626
|
+
return parentNeedsReservation;
|
|
2659
2627
|
}
|
|
2660
|
-
function
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
if (store !== undefined) {
|
|
2664
|
-
return store;
|
|
2628
|
+
function getRootDisplay(layoutContext) {
|
|
2629
|
+
if (layoutContext === null) {
|
|
2630
|
+
return "grid";
|
|
2665
2631
|
}
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
};
|
|
2671
|
-
scope.__TORPH_TRACE_STORE__ = store;
|
|
2672
|
-
return store;
|
|
2673
|
-
}
|
|
2674
|
-
function getTorphTraceText() {
|
|
2675
|
-
return getTorphTraceStore().lines.join("");
|
|
2676
|
-
}
|
|
2677
|
-
function clearTorphTrace() {
|
|
2678
|
-
const store = getTorphTraceStore();
|
|
2679
|
-
store.lines = [];
|
|
2680
|
-
store.nextSeq = 1;
|
|
2681
|
-
store.totalBytes = 0;
|
|
2632
|
+
if (supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay)) {
|
|
2633
|
+
return "inline-grid";
|
|
2634
|
+
}
|
|
2635
|
+
return "grid";
|
|
2682
2636
|
}
|
|
2683
|
-
function
|
|
2684
|
-
|
|
2685
|
-
|
|
2637
|
+
function getRootStyle(stage, plan, measurement, layoutContext) {
|
|
2638
|
+
let width = measurement?.reservedInlineSize;
|
|
2639
|
+
if (measurement !== null && measurement.flowInlineSize !== null) {
|
|
2640
|
+
width = measurement.layoutInlineSize;
|
|
2686
2641
|
}
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
const href = URL.createObjectURL(blob);
|
|
2690
|
-
const anchor = document.createElement("a");
|
|
2691
|
-
let resolvedFilename = filename;
|
|
2692
|
-
if (resolvedFilename === undefined) {
|
|
2693
|
-
resolvedFilename = `torph-trace-${new Date().toISOString().replaceAll(":", "-")}.jsonl`;
|
|
2642
|
+
if (plan !== null) {
|
|
2643
|
+
width = plan.layoutInlineSizeTo;
|
|
2694
2644
|
}
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
window.setTimeout(() => {
|
|
2699
|
-
URL.revokeObjectURL(href);
|
|
2700
|
-
}, 0);
|
|
2701
|
-
return resolvedFilename;
|
|
2702
|
-
}
|
|
2703
|
-
function ensureTorphTraceApi() {
|
|
2704
|
-
const scope = globalThis;
|
|
2705
|
-
if (scope.__TORPH_TRACE__ !== undefined) {
|
|
2706
|
-
return scope.__TORPH_TRACE__;
|
|
2645
|
+
let height;
|
|
2646
|
+
if (plan !== null) {
|
|
2647
|
+
height = plan.frameHeight;
|
|
2707
2648
|
}
|
|
2708
|
-
const
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
download: downloadTorphTrace,
|
|
2712
|
-
text: getTorphTraceText
|
|
2649
|
+
const style = {
|
|
2650
|
+
position: "relative",
|
|
2651
|
+
display: getRootDisplay(layoutContext)
|
|
2713
2652
|
};
|
|
2714
|
-
|
|
2715
|
-
|
|
2653
|
+
if (width !== null && width !== undefined) {
|
|
2654
|
+
style.width = width;
|
|
2655
|
+
}
|
|
2656
|
+
if (height !== undefined) {
|
|
2657
|
+
style.height = height;
|
|
2658
|
+
}
|
|
2659
|
+
return style;
|
|
2716
2660
|
}
|
|
2717
|
-
function
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
seq: store.nextSeq,
|
|
2725
|
-
time: new Date().toISOString()
|
|
2726
|
-
};
|
|
2727
|
-
store.nextSeq += 1;
|
|
2728
|
-
const line = `${JSON.stringify(entry)}
|
|
2729
|
-
`;
|
|
2730
|
-
store.lines.push(line);
|
|
2731
|
-
store.totalBytes += line.length;
|
|
2732
|
-
while (store.lines.length > TORPH_TRACE_MAX_LINES || store.totalBytes > TORPH_TRACE_MAX_BYTES) {
|
|
2733
|
-
const removed = store.lines.shift();
|
|
2734
|
-
if (removed === undefined) {
|
|
2735
|
-
break;
|
|
2661
|
+
function getMeasurementLayerStyle(layoutContext, useContentInlineSize = false) {
|
|
2662
|
+
let intrinsicWidthLock = false;
|
|
2663
|
+
if (layoutContext !== null) {
|
|
2664
|
+
if (useContentInlineSize) {
|
|
2665
|
+
intrinsicWidthLock = true;
|
|
2666
|
+
} else if (supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay)) {
|
|
2667
|
+
intrinsicWidthLock = true;
|
|
2736
2668
|
}
|
|
2737
|
-
store.totalBytes = Math.max(0, store.totalBytes - removed.length);
|
|
2738
2669
|
}
|
|
2670
|
+
if (!intrinsicWidthLock) {
|
|
2671
|
+
return MEASUREMENT_LAYER_STYLE;
|
|
2672
|
+
}
|
|
2673
|
+
return {
|
|
2674
|
+
...MEASUREMENT_LAYER_STYLE,
|
|
2675
|
+
right: "auto",
|
|
2676
|
+
width: "max-content"
|
|
2677
|
+
};
|
|
2739
2678
|
}
|
|
2740
|
-
function
|
|
2741
|
-
|
|
2742
|
-
|
|
2679
|
+
function resolveFlowText(committedMeasurement, stateMeasurement, text) {
|
|
2680
|
+
return stateMeasurement?.snapshot.text ?? committedMeasurement?.snapshot.text ?? text;
|
|
2681
|
+
}
|
|
2682
|
+
function shouldRenderGlyphLayer(stage, plan, measurement) {
|
|
2683
|
+
if (stage === "idle") {
|
|
2684
|
+
return measurement !== null;
|
|
2743
2685
|
}
|
|
2744
|
-
return
|
|
2686
|
+
return plan !== null;
|
|
2745
2687
|
}
|
|
2746
|
-
function
|
|
2688
|
+
function resolveGlyphSliceWhiteSpace(snapshot) {
|
|
2747
2689
|
if (snapshot === null) {
|
|
2748
|
-
return
|
|
2690
|
+
return "inherit";
|
|
2749
2691
|
}
|
|
2692
|
+
return "nowrap";
|
|
2693
|
+
}
|
|
2694
|
+
function toSteadyLiveItem(grapheme) {
|
|
2750
2695
|
return {
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
graphemes: snapshot.graphemes.length
|
|
2696
|
+
...grapheme,
|
|
2697
|
+
kind: "move",
|
|
2698
|
+
fromLeft: grapheme.left,
|
|
2699
|
+
fromTop: grapheme.top
|
|
2756
2700
|
};
|
|
2757
2701
|
}
|
|
2758
|
-
function
|
|
2759
|
-
|
|
2760
|
-
return null;
|
|
2761
|
-
}
|
|
2702
|
+
function createSteadyGlyphPlan(measurement) {
|
|
2703
|
+
const snapshot = measurement.snapshot;
|
|
2762
2704
|
return {
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2705
|
+
frameWidth: snapshot.width,
|
|
2706
|
+
frameHeight: snapshot.height,
|
|
2707
|
+
layoutInlineSizeFrom: measurement.layoutInlineSize,
|
|
2708
|
+
layoutInlineSizeTo: measurement.layoutInlineSize,
|
|
2709
|
+
sourceRenderText: snapshot.renderText,
|
|
2710
|
+
targetRenderText: snapshot.renderText,
|
|
2711
|
+
sourceRootOrigin: measurement.rootOrigin,
|
|
2712
|
+
visualBridge: ZERO_BRIDGE,
|
|
2713
|
+
liveItems: snapshot.graphemes.map(toSteadyLiveItem),
|
|
2714
|
+
exitItems: []
|
|
2771
2715
|
};
|
|
2772
2716
|
}
|
|
2773
|
-
|
|
2774
|
-
|
|
2717
|
+
|
|
2718
|
+
// torph/src/core/snapshot.ts
|
|
2719
|
+
function isSingleLineSnapshot(snapshot) {
|
|
2720
|
+
if (snapshot.graphemes.length <= 1) {
|
|
2721
|
+
return true;
|
|
2722
|
+
}
|
|
2723
|
+
const firstTop = snapshot.graphemes[0].top;
|
|
2724
|
+
return snapshot.graphemes.every((grapheme) => nearlyEqual(grapheme.top, firstTop, MORPH.lineGroupingEpsilon));
|
|
2725
|
+
}
|
|
2726
|
+
function assertSingleLineSnapshot(snapshot) {
|
|
2727
|
+
if (isSingleLineSnapshot(snapshot)) {
|
|
2728
|
+
return snapshot;
|
|
2729
|
+
}
|
|
2730
|
+
throw new Error(`Torph only supports single-line text layout. Received wrapped text: "${snapshot.renderText}"`);
|
|
2731
|
+
}
|
|
2732
|
+
|
|
2733
|
+
// torph/src/core/measurement-policy.ts
|
|
2734
|
+
var MORPH_SEGMENT_CACHE_LIMIT = 256;
|
|
2735
|
+
var morphSegmentCache = new Map;
|
|
2736
|
+
var pretextMorphTrustCache = new Map;
|
|
2737
|
+
var morphMeasurementEpoch = 1;
|
|
2738
|
+
var graphemeSegmenter = null;
|
|
2739
|
+
function getGraphemeSegmenter() {
|
|
2740
|
+
if (graphemeSegmenter !== null) {
|
|
2741
|
+
return graphemeSegmenter;
|
|
2742
|
+
}
|
|
2743
|
+
graphemeSegmenter = new Intl.Segmenter(undefined, {
|
|
2744
|
+
granularity: "grapheme"
|
|
2745
|
+
});
|
|
2746
|
+
return graphemeSegmenter;
|
|
2747
|
+
}
|
|
2748
|
+
function clearPretextMorphTrustCache() {
|
|
2749
|
+
pretextMorphTrustCache.clear();
|
|
2750
|
+
}
|
|
2751
|
+
function clearMorphMeasurementCaches() {
|
|
2752
|
+
morphSegmentCache.clear();
|
|
2753
|
+
clearPretextMorphTrustCache();
|
|
2754
|
+
clearPretextMorphCaches();
|
|
2755
|
+
}
|
|
2756
|
+
function bumpMorphMeasurementEpoch() {
|
|
2757
|
+
morphMeasurementEpoch += 1;
|
|
2758
|
+
}
|
|
2759
|
+
function getMorphMeasurementEpoch() {
|
|
2760
|
+
return morphMeasurementEpoch;
|
|
2761
|
+
}
|
|
2762
|
+
function readCachedMorphSegments(text) {
|
|
2763
|
+
const cached = morphSegmentCache.get(text);
|
|
2764
|
+
if (cached !== undefined) {
|
|
2765
|
+
morphSegmentCache.delete(text);
|
|
2766
|
+
morphSegmentCache.set(text, cached);
|
|
2767
|
+
return cached;
|
|
2768
|
+
}
|
|
2769
|
+
const segments = Array.from(getGraphemeSegmenter().segment(text), (segment, index) => ({
|
|
2770
|
+
glyph: segment.segment,
|
|
2771
|
+
key: `${segment.segment}:${index}`
|
|
2772
|
+
}));
|
|
2773
|
+
morphSegmentCache.set(text, segments);
|
|
2774
|
+
if (morphSegmentCache.size > MORPH_SEGMENT_CACHE_LIMIT) {
|
|
2775
|
+
const oldest = morphSegmentCache.keys().next();
|
|
2776
|
+
if (!oldest.done) {
|
|
2777
|
+
morphSegmentCache.delete(oldest.value);
|
|
2778
|
+
}
|
|
2779
|
+
}
|
|
2780
|
+
return segments;
|
|
2781
|
+
}
|
|
2782
|
+
function shouldMeasureUsingContentInlineSize(layoutContext, layoutHint) {
|
|
2783
|
+
if (supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay)) {
|
|
2784
|
+
return true;
|
|
2785
|
+
}
|
|
2786
|
+
if (layoutContext.whiteSpace === "nowrap") {
|
|
2787
|
+
return true;
|
|
2788
|
+
}
|
|
2789
|
+
if (layoutHint === null) {
|
|
2790
|
+
return false;
|
|
2791
|
+
}
|
|
2792
|
+
if (!isSingleLineSnapshot(layoutHint.snapshot)) {
|
|
2793
|
+
return false;
|
|
2794
|
+
}
|
|
2795
|
+
return nearlyEqual(layoutHint.layoutInlineSize, resolveContentWidthLockInlineSize(layoutHint), MORPH.contentWidthLockEpsilon);
|
|
2796
|
+
}
|
|
2797
|
+
function getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize) {
|
|
2798
|
+
const backend = getPretextMorphMeasurementBackend(text, layoutContext);
|
|
2799
|
+
if (backend !== "probe") {
|
|
2800
|
+
return backend;
|
|
2801
|
+
}
|
|
2802
|
+
const signature = getPretextMorphTrustSignature({
|
|
2803
|
+
renderText,
|
|
2804
|
+
layoutContext,
|
|
2805
|
+
useContentInlineSize
|
|
2806
|
+
});
|
|
2807
|
+
if (signature === null) {
|
|
2808
|
+
return "dom";
|
|
2809
|
+
}
|
|
2810
|
+
const trusted = pretextMorphTrustCache.get(signature);
|
|
2811
|
+
if (trusted === undefined) {
|
|
2812
|
+
return "probe";
|
|
2813
|
+
}
|
|
2814
|
+
if (trusted) {
|
|
2815
|
+
return "pretext";
|
|
2816
|
+
}
|
|
2817
|
+
return "dom";
|
|
2818
|
+
}
|
|
2819
|
+
function getDomMeasurementRequestKey(text, renderText, layoutContext, useContentInlineSize) {
|
|
2820
|
+
let inlineSizeMode = "container";
|
|
2821
|
+
if (useContentInlineSize) {
|
|
2822
|
+
inlineSizeMode = "content";
|
|
2823
|
+
}
|
|
2824
|
+
return `dom\x00${inlineSizeMode}\x00${text}\x00${renderText}\x00${layoutContext.measurementVersion}\x00${getMorphMeasurementEpoch()}`;
|
|
2825
|
+
}
|
|
2826
|
+
function needsMeasurementLayer(measurementBackend, renderText) {
|
|
2827
|
+
if (measurementBackend === "pretext") {
|
|
2828
|
+
return false;
|
|
2829
|
+
}
|
|
2830
|
+
return renderText.length > 0;
|
|
2831
|
+
}
|
|
2832
|
+
function canCacheMeasurementLayerSnapshot(measurementBackend) {
|
|
2833
|
+
return measurementBackend === "dom";
|
|
2834
|
+
}
|
|
2835
|
+
function createMorphMeasurementRequest({
|
|
2836
|
+
text,
|
|
2837
|
+
layoutContext,
|
|
2838
|
+
layoutHint
|
|
2839
|
+
}) {
|
|
2840
|
+
if (layoutContext === null) {
|
|
2775
2841
|
return null;
|
|
2776
2842
|
}
|
|
2843
|
+
const renderText = getPretextMorphRenderedText(text, layoutContext);
|
|
2844
|
+
const useContentInlineSize = shouldMeasureUsingContentInlineSize(layoutContext, layoutHint);
|
|
2845
|
+
const measurementBackend = getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize);
|
|
2846
|
+
let segments = readCachedMorphSegments(renderText);
|
|
2847
|
+
if (measurementBackend === "pretext") {
|
|
2848
|
+
segments = EMPTY_SEGMENTS;
|
|
2849
|
+
}
|
|
2850
|
+
let domMeasurementKey = null;
|
|
2851
|
+
if (needsMeasurementLayer(measurementBackend, renderText)) {
|
|
2852
|
+
domMeasurementKey = getDomMeasurementRequestKey(text, renderText, layoutContext, useContentInlineSize);
|
|
2853
|
+
}
|
|
2777
2854
|
return {
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2855
|
+
text,
|
|
2856
|
+
renderText,
|
|
2857
|
+
segments,
|
|
2858
|
+
measurementBackend,
|
|
2859
|
+
useContentInlineSize,
|
|
2860
|
+
domMeasurementKey
|
|
2782
2861
|
};
|
|
2783
2862
|
}
|
|
2784
|
-
function
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2863
|
+
function rememberPretextMeasurementTrust({
|
|
2864
|
+
renderText,
|
|
2865
|
+
layoutContext,
|
|
2866
|
+
useContentInlineSize,
|
|
2867
|
+
trusted
|
|
2868
|
+
}) {
|
|
2869
|
+
const signature = getPretextMorphTrustSignature({
|
|
2870
|
+
renderText,
|
|
2871
|
+
layoutContext,
|
|
2872
|
+
useContentInlineSize
|
|
2873
|
+
});
|
|
2874
|
+
if (signature === null) {
|
|
2875
|
+
return;
|
|
2788
2876
|
}
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2792
|
-
|
|
2877
|
+
pretextMorphTrustCache.set(signature, trusted);
|
|
2878
|
+
}
|
|
2879
|
+
function areSnapshotsEquivalentForPretextTrust(left, right) {
|
|
2880
|
+
if (left.renderText !== right.renderText || left.graphemes.length !== right.graphemes.length) {
|
|
2881
|
+
return false;
|
|
2793
2882
|
}
|
|
2794
|
-
if (
|
|
2795
|
-
|
|
2883
|
+
if (Math.abs(left.width - right.width) > MORPH.geometryEpsilon) {
|
|
2884
|
+
return false;
|
|
2796
2885
|
}
|
|
2797
|
-
|
|
2798
|
-
|
|
2886
|
+
if (Math.abs(left.height - right.height) > MORPH.geometryEpsilon) {
|
|
2887
|
+
return false;
|
|
2888
|
+
}
|
|
2889
|
+
for (let index = 0;index < left.graphemes.length; index += 1) {
|
|
2890
|
+
const from = left.graphemes[index];
|
|
2891
|
+
const to = right.graphemes[index];
|
|
2892
|
+
if (from.glyph !== to.glyph) {
|
|
2893
|
+
return false;
|
|
2894
|
+
}
|
|
2895
|
+
if (Math.abs(from.left - to.left) > MORPH.geometryEpsilon) {
|
|
2896
|
+
return false;
|
|
2897
|
+
}
|
|
2898
|
+
if (Math.abs(from.top - to.top) > MORPH.geometryEpsilon) {
|
|
2899
|
+
return false;
|
|
2900
|
+
}
|
|
2901
|
+
if (Math.abs(from.width - to.width) > MORPH.geometryEpsilon) {
|
|
2902
|
+
return false;
|
|
2903
|
+
}
|
|
2904
|
+
if (Math.abs(from.height - to.height) > MORPH.geometryEpsilon) {
|
|
2905
|
+
return false;
|
|
2906
|
+
}
|
|
2907
|
+
}
|
|
2908
|
+
return true;
|
|
2799
2909
|
}
|
|
2800
|
-
|
|
2801
|
-
|
|
2802
|
-
|
|
2910
|
+
|
|
2911
|
+
// torph/src/core/finalize-barrier.ts
|
|
2912
|
+
function createMorphFinalizeBarrier(hasMoveTransitions) {
|
|
2913
|
+
return {
|
|
2914
|
+
waitForLiveTransform: hasMoveTransitions,
|
|
2915
|
+
sawLiveTransform: false
|
|
2916
|
+
};
|
|
2917
|
+
}
|
|
2918
|
+
function recordMorphFinalizeSignal(barrier, signal) {
|
|
2919
|
+
return {
|
|
2920
|
+
...barrier,
|
|
2921
|
+
sawLiveTransform: signal === "live-transform"
|
|
2922
|
+
};
|
|
2923
|
+
}
|
|
2924
|
+
function isMorphFinalizeBarrierSatisfied(barrier) {
|
|
2925
|
+
if (barrier.waitForLiveTransform && !barrier.sawLiveTransform) {
|
|
2926
|
+
return false;
|
|
2803
2927
|
}
|
|
2804
|
-
|
|
2805
|
-
|
|
2806
|
-
|
|
2807
|
-
|
|
2808
|
-
|
|
2928
|
+
return true;
|
|
2929
|
+
}
|
|
2930
|
+
function summarizeMorphFinalizeBarrier(barrier) {
|
|
2931
|
+
return {
|
|
2932
|
+
waitForLiveTransform: barrier.waitForLiveTransform,
|
|
2933
|
+
sawLiveTransform: barrier.sawLiveTransform,
|
|
2934
|
+
satisfied: isMorphFinalizeBarrierSatisfied(barrier)
|
|
2935
|
+
};
|
|
2936
|
+
}
|
|
2937
|
+
|
|
2938
|
+
// torph/src/core/session.ts
|
|
2939
|
+
function bucketByGlyph(graphemes) {
|
|
2940
|
+
const buckets = new Map;
|
|
2941
|
+
for (const grapheme of graphemes) {
|
|
2942
|
+
const bucket = buckets.get(grapheme.glyph);
|
|
2943
|
+
if (bucket !== undefined) {
|
|
2944
|
+
bucket.push(grapheme);
|
|
2809
2945
|
continue;
|
|
2810
2946
|
}
|
|
2811
|
-
|
|
2812
|
-
index,
|
|
2813
|
-
glyph: grapheme.glyph,
|
|
2814
|
-
left: roundDebugValue(rootRect.left + grapheme.left),
|
|
2815
|
-
top: roundDebugValue(rootRect.top + grapheme.top),
|
|
2816
|
-
width: roundDebugValue(grapheme.width),
|
|
2817
|
-
height: roundDebugValue(grapheme.height)
|
|
2818
|
-
});
|
|
2947
|
+
buckets.set(grapheme.glyph, [grapheme]);
|
|
2819
2948
|
}
|
|
2820
|
-
return
|
|
2949
|
+
return buckets;
|
|
2821
2950
|
}
|
|
2822
|
-
function
|
|
2823
|
-
|
|
2824
|
-
|
|
2951
|
+
function pairMorphCharacters(previous, next) {
|
|
2952
|
+
const previousBuckets = bucketByGlyph(previous);
|
|
2953
|
+
const nextBuckets = bucketByGlyph(next);
|
|
2954
|
+
const pairings = [];
|
|
2955
|
+
for (const [glyph, previousItems] of previousBuckets) {
|
|
2956
|
+
const nextItems = nextBuckets.get(glyph) ?? [];
|
|
2957
|
+
const shared = Math.min(previousItems.length, nextItems.length);
|
|
2958
|
+
for (let index = 0;index < shared; index += 1) {
|
|
2959
|
+
pairings.push({
|
|
2960
|
+
kind: "move",
|
|
2961
|
+
from: previousItems[index],
|
|
2962
|
+
to: nextItems[index]
|
|
2963
|
+
});
|
|
2964
|
+
}
|
|
2965
|
+
for (let index = shared;index < previousItems.length; index += 1) {
|
|
2966
|
+
pairings.push({
|
|
2967
|
+
kind: "exit",
|
|
2968
|
+
from: previousItems[index]
|
|
2969
|
+
});
|
|
2970
|
+
}
|
|
2971
|
+
}
|
|
2972
|
+
for (const [glyph, nextItems] of nextBuckets) {
|
|
2973
|
+
const previousItems = previousBuckets.get(glyph) ?? [];
|
|
2974
|
+
const shared = Math.min(previousItems.length, nextItems.length);
|
|
2975
|
+
for (let index = shared;index < nextItems.length; index += 1) {
|
|
2976
|
+
pairings.push({
|
|
2977
|
+
kind: "enter",
|
|
2978
|
+
to: nextItems[index]
|
|
2979
|
+
});
|
|
2980
|
+
}
|
|
2825
2981
|
}
|
|
2982
|
+
return pairings;
|
|
2983
|
+
}
|
|
2984
|
+
function resolveMorphFrameBounds(previous, next) {
|
|
2826
2985
|
return {
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
actualLeft: roundDebugValue(rootRect.left),
|
|
2830
|
-
actualTop: roundDebugValue(rootRect.top),
|
|
2831
|
-
deltaLeft: roundDebugValue(rootRect.left - measurement.rootOrigin.left),
|
|
2832
|
-
deltaTop: roundDebugValue(rootRect.top - measurement.rootOrigin.top)
|
|
2986
|
+
width: Math.max(previous.width, next.width),
|
|
2987
|
+
height: Math.max(previous.height, next.height)
|
|
2833
2988
|
};
|
|
2834
2989
|
}
|
|
2835
|
-
function
|
|
2990
|
+
function buildMorphPlan(previous, next, visualBridge = ZERO_BRIDGE) {
|
|
2991
|
+
const pairings = pairMorphCharacters(previous.snapshot.graphemes, next.snapshot.graphemes);
|
|
2992
|
+
const movesByDestinationKey = new Map;
|
|
2993
|
+
const exitItems = [];
|
|
2994
|
+
for (const pairing of pairings) {
|
|
2995
|
+
if (pairing.kind === "move") {
|
|
2996
|
+
movesByDestinationKey.set(pairing.to.key, pairing);
|
|
2997
|
+
continue;
|
|
2998
|
+
}
|
|
2999
|
+
if (pairing.kind === "exit") {
|
|
3000
|
+
exitItems.push(pairing.from);
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
const frame = resolveMorphFrameBounds(previous.snapshot, next.snapshot);
|
|
2836
3004
|
return {
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
3005
|
+
frameWidth: frame.width,
|
|
3006
|
+
frameHeight: frame.height,
|
|
3007
|
+
layoutInlineSizeFrom: previous.layoutInlineSize,
|
|
3008
|
+
layoutInlineSizeTo: next.layoutInlineSize,
|
|
3009
|
+
sourceRenderText: previous.snapshot.renderText,
|
|
3010
|
+
targetRenderText: next.snapshot.renderText,
|
|
3011
|
+
sourceRootOrigin: previous.rootOrigin,
|
|
3012
|
+
visualBridge,
|
|
3013
|
+
liveItems: next.snapshot.graphemes.map((grapheme) => {
|
|
3014
|
+
const move = movesByDestinationKey.get(grapheme.key);
|
|
3015
|
+
if (move !== undefined) {
|
|
3016
|
+
return {
|
|
3017
|
+
...grapheme,
|
|
3018
|
+
kind: "move",
|
|
3019
|
+
fromLeft: move.from.left,
|
|
3020
|
+
fromTop: move.from.top
|
|
3021
|
+
};
|
|
3022
|
+
}
|
|
3023
|
+
return {
|
|
3024
|
+
...grapheme,
|
|
3025
|
+
kind: "enter",
|
|
3026
|
+
fromLeft: null,
|
|
3027
|
+
fromTop: null
|
|
3028
|
+
};
|
|
3029
|
+
}),
|
|
3030
|
+
exitItems
|
|
3031
|
+
};
|
|
3032
|
+
}
|
|
3033
|
+
function sameSnapshot(a, b) {
|
|
3034
|
+
if (a === b) {
|
|
3035
|
+
return true;
|
|
3036
|
+
}
|
|
3037
|
+
if (a.text !== b.text || a.renderText !== b.renderText || a.graphemes.length !== b.graphemes.length) {
|
|
3038
|
+
return false;
|
|
3039
|
+
}
|
|
3040
|
+
if (!nearlyEqual(a.width, b.width, MORPH.geometryEpsilon)) {
|
|
3041
|
+
return false;
|
|
3042
|
+
}
|
|
3043
|
+
if (!nearlyEqual(a.height, b.height, MORPH.geometryEpsilon)) {
|
|
3044
|
+
return false;
|
|
3045
|
+
}
|
|
3046
|
+
for (let index = 0;index < a.graphemes.length; index += 1) {
|
|
3047
|
+
const left = a.graphemes[index];
|
|
3048
|
+
const right = b.graphemes[index];
|
|
3049
|
+
if (left.glyph !== right.glyph || left.key !== right.key) {
|
|
3050
|
+
return false;
|
|
3051
|
+
}
|
|
3052
|
+
if (!nearlyEqual(left.left, right.left, MORPH.geometryEpsilon)) {
|
|
3053
|
+
return false;
|
|
3054
|
+
}
|
|
3055
|
+
if (!nearlyEqual(left.top, right.top, MORPH.geometryEpsilon)) {
|
|
3056
|
+
return false;
|
|
3057
|
+
}
|
|
3058
|
+
if (!nearlyEqual(left.width, right.width, MORPH.geometryEpsilon)) {
|
|
3059
|
+
return false;
|
|
3060
|
+
}
|
|
3061
|
+
if (!nearlyEqual(left.height, right.height, MORPH.geometryEpsilon)) {
|
|
3062
|
+
return false;
|
|
3063
|
+
}
|
|
3064
|
+
}
|
|
3065
|
+
return true;
|
|
3066
|
+
}
|
|
3067
|
+
function sameMeasurement(a, b) {
|
|
3068
|
+
const sameReservedInlineSize = a.reservedInlineSize === null && b.reservedInlineSize === null || a.reservedInlineSize !== null && b.reservedInlineSize !== null && nearlyEqual(a.reservedInlineSize, b.reservedInlineSize, MORPH.geometryEpsilon);
|
|
3069
|
+
const sameFlowInlineSize = a.flowInlineSize === null && b.flowInlineSize === null || a.flowInlineSize !== null && b.flowInlineSize !== null && nearlyEqual(a.flowInlineSize, b.flowInlineSize, MORPH.geometryEpsilon);
|
|
3070
|
+
return sameSnapshot(a.snapshot, b.snapshot) && nearlyEqual(a.layoutInlineSize, b.layoutInlineSize, MORPH.geometryEpsilon) && sameReservedInlineSize && sameFlowInlineSize && nearlyEqual(a.rootOrigin.left, b.rootOrigin.left, MORPH.geometryEpsilon) && nearlyEqual(a.rootOrigin.top, b.rootOrigin.top, MORPH.geometryEpsilon);
|
|
3071
|
+
}
|
|
3072
|
+
function selectMorphLayoutHint(session) {
|
|
3073
|
+
if (session.animating && session.target !== null) {
|
|
3074
|
+
return session.target;
|
|
3075
|
+
}
|
|
3076
|
+
return session.committed;
|
|
3077
|
+
}
|
|
3078
|
+
function decideMorphSessionUpdate({
|
|
3079
|
+
committed,
|
|
3080
|
+
target,
|
|
3081
|
+
animating,
|
|
3082
|
+
nextMeasurement,
|
|
3083
|
+
fontsReady
|
|
3084
|
+
}) {
|
|
3085
|
+
let source = committed;
|
|
3086
|
+
if (animating && target !== null) {
|
|
3087
|
+
source = target;
|
|
3088
|
+
}
|
|
3089
|
+
if (source === null) {
|
|
3090
|
+
return {
|
|
3091
|
+
kind: "commit-static",
|
|
3092
|
+
measurement: nextMeasurement
|
|
3093
|
+
};
|
|
3094
|
+
}
|
|
3095
|
+
if (!fontsReady) {
|
|
3096
|
+
return {
|
|
3097
|
+
kind: "commit-static",
|
|
3098
|
+
measurement: nextMeasurement
|
|
3099
|
+
};
|
|
3100
|
+
}
|
|
3101
|
+
if (animating && target !== null) {
|
|
3102
|
+
if (nextMeasurement.snapshot.renderText === target.snapshot.renderText) {
|
|
3103
|
+
return {
|
|
3104
|
+
kind: "freeze-animating-target",
|
|
3105
|
+
target
|
|
3106
|
+
};
|
|
3107
|
+
}
|
|
3108
|
+
}
|
|
3109
|
+
if (committed !== null) {
|
|
3110
|
+
if (committed.snapshot.renderText === nextMeasurement.snapshot.renderText) {
|
|
3111
|
+
if (sameMeasurement(committed, nextMeasurement)) {
|
|
3112
|
+
return {
|
|
3113
|
+
kind: "commit-static",
|
|
3114
|
+
measurement: committed
|
|
3115
|
+
};
|
|
3116
|
+
}
|
|
3117
|
+
return {
|
|
3118
|
+
kind: "commit-static",
|
|
3119
|
+
measurement: nextMeasurement
|
|
3120
|
+
};
|
|
3121
|
+
}
|
|
3122
|
+
}
|
|
3123
|
+
return {
|
|
3124
|
+
kind: "start-morph",
|
|
3125
|
+
source,
|
|
3126
|
+
target: nextMeasurement
|
|
3127
|
+
};
|
|
3128
|
+
}
|
|
3129
|
+
function pinMeasurementToCurrentOrigin(measurement, origin) {
|
|
3130
|
+
if (nearlyEqual(measurement.rootOrigin.left, origin.left, MORPH.geometryEpsilon) && nearlyEqual(measurement.rootOrigin.top, origin.top, MORPH.geometryEpsilon)) {
|
|
3131
|
+
return measurement;
|
|
3132
|
+
}
|
|
3133
|
+
return {
|
|
3134
|
+
snapshot: measurement.snapshot,
|
|
3135
|
+
layoutInlineSize: measurement.layoutInlineSize,
|
|
3136
|
+
reservedInlineSize: measurement.reservedInlineSize,
|
|
3137
|
+
flowInlineSize: measurement.flowInlineSize,
|
|
3138
|
+
rootOrigin: origin
|
|
3139
|
+
};
|
|
3140
|
+
}
|
|
3141
|
+
function createStaticState(measurement) {
|
|
3142
|
+
return {
|
|
3143
|
+
stage: "idle",
|
|
3144
|
+
measurement,
|
|
3145
|
+
plan: null
|
|
2854
3146
|
};
|
|
2855
3147
|
}
|
|
2856
|
-
function
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
if (
|
|
3148
|
+
function areFontsReady() {
|
|
3149
|
+
return document.fonts.status === "loaded";
|
|
3150
|
+
}
|
|
3151
|
+
function cancelTimeline(timeline) {
|
|
3152
|
+
if (timeline.prepareFrame !== null) {
|
|
3153
|
+
cancelAnimationFrame(timeline.prepareFrame);
|
|
3154
|
+
timeline.prepareFrame = null;
|
|
3155
|
+
}
|
|
3156
|
+
if (timeline.animateFrame !== null) {
|
|
3157
|
+
cancelAnimationFrame(timeline.animateFrame);
|
|
3158
|
+
timeline.animateFrame = null;
|
|
3159
|
+
}
|
|
3160
|
+
if (timeline.finalizeTimer !== null) {
|
|
3161
|
+
window.clearTimeout(timeline.finalizeTimer);
|
|
3162
|
+
timeline.finalizeTimer = null;
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
function resetMorph(session, timeline, setState) {
|
|
3166
|
+
cancelTimeline(timeline);
|
|
3167
|
+
session.committed = null;
|
|
3168
|
+
session.target = null;
|
|
3169
|
+
session.animating = false;
|
|
3170
|
+
setState(EMPTY_STATE);
|
|
3171
|
+
}
|
|
3172
|
+
function commitStaticMeasurement(session, measurement, setState) {
|
|
3173
|
+
if (!session.animating && session.target === null && session.committed !== null && sameMeasurement(session.committed, measurement)) {
|
|
2861
3174
|
return;
|
|
2862
3175
|
}
|
|
2863
|
-
|
|
2864
|
-
|
|
3176
|
+
session.committed = measurement;
|
|
3177
|
+
session.target = null;
|
|
3178
|
+
session.animating = false;
|
|
3179
|
+
setState((current) => {
|
|
3180
|
+
if (current.stage === "idle" && current.plan === null && current.measurement !== null && sameMeasurement(current.measurement, measurement)) {
|
|
3181
|
+
return current;
|
|
3182
|
+
}
|
|
3183
|
+
return createStaticState(measurement);
|
|
3184
|
+
});
|
|
3185
|
+
}
|
|
3186
|
+
function applyMorphSessionDecision({
|
|
3187
|
+
decision,
|
|
3188
|
+
session,
|
|
3189
|
+
timeline,
|
|
3190
|
+
setState
|
|
3191
|
+
}) {
|
|
3192
|
+
if (decision.kind === "freeze-animating-target") {
|
|
3193
|
+
return decision.target;
|
|
2865
3194
|
}
|
|
2866
|
-
|
|
2867
|
-
|
|
3195
|
+
cancelTimeline(timeline);
|
|
3196
|
+
if (decision.kind === "commit-static") {
|
|
3197
|
+
commitStaticMeasurement(session, decision.measurement, setState);
|
|
3198
|
+
return decision.measurement;
|
|
3199
|
+
}
|
|
3200
|
+
startMorph({
|
|
3201
|
+
source: decision.source,
|
|
3202
|
+
target: decision.target,
|
|
3203
|
+
session,
|
|
3204
|
+
timeline,
|
|
3205
|
+
setState
|
|
3206
|
+
});
|
|
3207
|
+
return decision.target;
|
|
3208
|
+
}
|
|
3209
|
+
function reconcileMorphSessionUpdate({
|
|
3210
|
+
session,
|
|
3211
|
+
timeline,
|
|
3212
|
+
nextMeasurement,
|
|
3213
|
+
fontsReady,
|
|
3214
|
+
setState
|
|
3215
|
+
}) {
|
|
3216
|
+
const decision = decideMorphSessionUpdate({
|
|
3217
|
+
committed: session.committed,
|
|
3218
|
+
target: session.target,
|
|
3219
|
+
animating: session.animating,
|
|
3220
|
+
nextMeasurement,
|
|
3221
|
+
fontsReady
|
|
3222
|
+
});
|
|
3223
|
+
return applyMorphSessionDecision({
|
|
3224
|
+
decision,
|
|
3225
|
+
session,
|
|
3226
|
+
timeline,
|
|
3227
|
+
setState
|
|
3228
|
+
});
|
|
3229
|
+
}
|
|
3230
|
+
function finalizeMorphTransition({
|
|
3231
|
+
session,
|
|
3232
|
+
timeline,
|
|
3233
|
+
measurement,
|
|
3234
|
+
setState
|
|
3235
|
+
}) {
|
|
3236
|
+
cancelTimeline(timeline);
|
|
3237
|
+
commitStaticMeasurement(session, session.target ?? measurement, setState);
|
|
3238
|
+
}
|
|
3239
|
+
function resolvePreparedMeasurementOrigin(measurement, origin) {
|
|
3240
|
+
return pinMeasurementToCurrentOrigin(measurement, origin);
|
|
3241
|
+
}
|
|
3242
|
+
function resolvePreparedPlanVisualBridge(plan, origin) {
|
|
3243
|
+
const offsetX = plan.sourceRootOrigin.left - origin.left;
|
|
3244
|
+
const offsetY = plan.sourceRootOrigin.top - origin.top;
|
|
3245
|
+
if (nearlyEqual(plan.visualBridge.offsetX, offsetX, MORPH.geometryEpsilon) && nearlyEqual(plan.visualBridge.offsetY, offsetY, MORPH.geometryEpsilon)) {
|
|
3246
|
+
return plan;
|
|
2868
3247
|
}
|
|
3248
|
+
return {
|
|
3249
|
+
...plan,
|
|
3250
|
+
visualBridge: {
|
|
3251
|
+
offsetX,
|
|
3252
|
+
offsetY
|
|
3253
|
+
}
|
|
3254
|
+
};
|
|
3255
|
+
}
|
|
3256
|
+
function startMorph({
|
|
3257
|
+
source,
|
|
3258
|
+
target,
|
|
3259
|
+
session,
|
|
3260
|
+
timeline,
|
|
3261
|
+
setState
|
|
3262
|
+
}) {
|
|
3263
|
+
const plan = buildMorphPlan(source, target, ZERO_BRIDGE);
|
|
3264
|
+
session.target = target;
|
|
3265
|
+
session.animating = true;
|
|
3266
|
+
setState({
|
|
3267
|
+
stage: "prepare",
|
|
3268
|
+
measurement: target,
|
|
3269
|
+
plan
|
|
3270
|
+
});
|
|
2869
3271
|
}
|
|
3272
|
+
|
|
3273
|
+
// torph/src/core/layout-observer.ts
|
|
3274
|
+
import { useLayoutEffect, useRef, useState } from "react";
|
|
3275
|
+
var activeMorphMeasurementConsumers = 0;
|
|
3276
|
+
var detachMorphMeasurementInvalidationListeners = null;
|
|
3277
|
+
var morphMeasurementInvalidationSubscribers = new Set;
|
|
3278
|
+
var FONT_METRIC_TRANSITION_PROPERTIES = new Set([
|
|
3279
|
+
"font",
|
|
3280
|
+
"font-family",
|
|
3281
|
+
"font-size",
|
|
3282
|
+
"font-stretch",
|
|
3283
|
+
"font-style",
|
|
3284
|
+
"font-weight",
|
|
3285
|
+
"font-variation-settings",
|
|
3286
|
+
"letter-spacing",
|
|
3287
|
+
"line-height",
|
|
3288
|
+
"text-transform",
|
|
3289
|
+
"word-spacing"
|
|
3290
|
+
]);
|
|
2870
3291
|
function parsePx(value) {
|
|
2871
3292
|
const parsed = Number.parseFloat(value);
|
|
2872
3293
|
if (Number.isFinite(parsed)) {
|
|
@@ -2908,6 +3329,18 @@ function readContentWidth(node, styles) {
|
|
|
2908
3329
|
const borderRight = parsePx(styles.borderRightWidth) ?? 0;
|
|
2909
3330
|
return Math.max(0, rectWidth - paddingLeft - paddingRight - borderLeft - borderRight);
|
|
2910
3331
|
}
|
|
3332
|
+
function isFontMetricTransitionProperty(propertyName) {
|
|
3333
|
+
return FONT_METRIC_TRANSITION_PROPERTIES.has(propertyName);
|
|
3334
|
+
}
|
|
3335
|
+
function doesTransitionTargetAffectNode(node, target) {
|
|
3336
|
+
if (target === node) {
|
|
3337
|
+
return true;
|
|
3338
|
+
}
|
|
3339
|
+
if (typeof target !== "object" || target === null || !("contains" in target) || typeof target.contains !== "function") {
|
|
3340
|
+
return false;
|
|
3341
|
+
}
|
|
3342
|
+
return target.contains(node);
|
|
3343
|
+
}
|
|
2911
3344
|
function readLayoutContext(node, width) {
|
|
2912
3345
|
const styles = getComputedStyle(node);
|
|
2913
3346
|
const parentDisplay = (node.parentElement && getComputedStyle(node.parentElement).display) ?? "block";
|
|
@@ -2933,41 +3366,16 @@ function sameLayoutContext(a, b) {
|
|
|
2933
3366
|
}
|
|
2934
3367
|
return a.display === b.display && a.direction === b.direction && a.font === b.font && a.fontFeatureSettings === b.fontFeatureSettings && a.fontVariationSettings === b.fontVariationSettings && Math.abs(a.letterSpacingPx - b.letterSpacingPx) < MORPH.geometryEpsilon && Math.abs(a.lineHeightPx - b.lineHeightPx) < MORPH.geometryEpsilon && a.parentDisplay === b.parentDisplay && a.textTransform === b.textTransform && a.whiteSpace === b.whiteSpace && Math.abs(a.width - b.width) < MORPH.geometryEpsilon && Math.abs(a.wordSpacingPx - b.wordSpacingPx) < MORPH.geometryEpsilon;
|
|
2935
3368
|
}
|
|
2936
|
-
function
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
function clearMorphMeasurementCaches() {
|
|
2940
|
-
morphSegmentCache.clear();
|
|
2941
|
-
clearPretextMorphTrustCache();
|
|
2942
|
-
clearPretextMorphCaches();
|
|
2943
|
-
}
|
|
2944
|
-
function bumpMorphMeasurementEpoch() {
|
|
2945
|
-
morphMeasurementEpoch += 1;
|
|
2946
|
-
}
|
|
2947
|
-
function getMorphMeasurementEpoch() {
|
|
2948
|
-
return morphMeasurementEpoch;
|
|
2949
|
-
}
|
|
2950
|
-
function isSingleLineSnapshot(snapshot) {
|
|
2951
|
-
if (snapshot.graphemes.length <= 1) {
|
|
2952
|
-
return true;
|
|
3369
|
+
function notifyMorphMeasurementInvalidationSubscribers() {
|
|
3370
|
+
for (const subscriber of morphMeasurementInvalidationSubscribers) {
|
|
3371
|
+
subscriber();
|
|
2953
3372
|
}
|
|
2954
|
-
const firstTop = snapshot.graphemes[0].top;
|
|
2955
|
-
return snapshot.graphemes.every((grapheme) => nearlyEqual(grapheme.top, firstTop, MORPH.lineGroupingEpsilon));
|
|
2956
3373
|
}
|
|
2957
|
-
function
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
let currentTop = snapshot.graphemes[0].top;
|
|
2963
|
-
for (let index = 1;index < snapshot.graphemes.length; index += 1) {
|
|
2964
|
-
const top = snapshot.graphemes[index].top;
|
|
2965
|
-
if (!nearlyEqual(top, currentTop, MORPH.lineGroupingEpsilon)) {
|
|
2966
|
-
currentTop = top;
|
|
2967
|
-
lineCount += 1;
|
|
2968
|
-
}
|
|
2969
|
-
}
|
|
2970
|
-
return lineCount;
|
|
3374
|
+
function subscribeMorphMeasurementInvalidation(subscriber) {
|
|
3375
|
+
morphMeasurementInvalidationSubscribers.add(subscriber);
|
|
3376
|
+
return () => {
|
|
3377
|
+
morphMeasurementInvalidationSubscribers.delete(subscriber);
|
|
3378
|
+
};
|
|
2971
3379
|
}
|
|
2972
3380
|
function acquireMorphMeasurementInvalidationListeners() {
|
|
2973
3381
|
activeMorphMeasurementConsumers += 1;
|
|
@@ -2975,6 +3383,7 @@ function acquireMorphMeasurementInvalidationListeners() {
|
|
|
2975
3383
|
const handleFontChange = () => {
|
|
2976
3384
|
clearMorphMeasurementCaches();
|
|
2977
3385
|
bumpMorphMeasurementEpoch();
|
|
3386
|
+
notifyMorphMeasurementInvalidationSubscribers();
|
|
2978
3387
|
};
|
|
2979
3388
|
document.fonts.ready.then(handleFontChange);
|
|
2980
3389
|
if (typeof document.fonts.addEventListener === "function") {
|
|
@@ -2997,6 +3406,7 @@ function releaseMorphMeasurementInvalidationListeners() {
|
|
|
2997
3406
|
function useObservedLayoutContext(deps) {
|
|
2998
3407
|
const ref = useRef(null);
|
|
2999
3408
|
const [layoutContext, setLayoutContext] = useState(null);
|
|
3409
|
+
const syncLayoutContextRef = useRef(null);
|
|
3000
3410
|
useLayoutEffect(() => {
|
|
3001
3411
|
const node = ref.current;
|
|
3002
3412
|
if (node === null) {
|
|
@@ -3025,9 +3435,88 @@ function useObservedLayoutContext(deps) {
|
|
|
3025
3435
|
const next = readLayoutContext(node, width);
|
|
3026
3436
|
commitLayoutContext(next, refreshMeasurements);
|
|
3027
3437
|
};
|
|
3438
|
+
syncLayoutContextRef.current = syncLayoutContext;
|
|
3028
3439
|
const initialLayoutContext = readLayoutContext(node);
|
|
3029
3440
|
const shouldObserveWrappingWidth = initialLayoutContext.whiteSpace !== "nowrap" && !supportsIntrinsicWidthLock(initialLayoutContext.display, initialLayoutContext.parentDisplay);
|
|
3030
3441
|
commitLayoutContext(initialLayoutContext, true);
|
|
3442
|
+
const unsubscribeInvalidation = subscribeMorphMeasurementInvalidation(() => {
|
|
3443
|
+
syncLayoutContext({
|
|
3444
|
+
refreshMeasurements: true
|
|
3445
|
+
});
|
|
3446
|
+
});
|
|
3447
|
+
const activeFontMetricTransitions = new Map;
|
|
3448
|
+
const ownerDocument = node.ownerDocument;
|
|
3449
|
+
const ownerWindow = ownerDocument.defaultView ?? window;
|
|
3450
|
+
let fontMetricTransitionFrame = null;
|
|
3451
|
+
const stopFontMetricTransitionPolling = () => {
|
|
3452
|
+
if (fontMetricTransitionFrame === null) {
|
|
3453
|
+
return;
|
|
3454
|
+
}
|
|
3455
|
+
ownerWindow.cancelAnimationFrame(fontMetricTransitionFrame);
|
|
3456
|
+
fontMetricTransitionFrame = null;
|
|
3457
|
+
};
|
|
3458
|
+
const pollFontMetricTransition = () => {
|
|
3459
|
+
syncLayoutContext({
|
|
3460
|
+
refreshMeasurements: true
|
|
3461
|
+
});
|
|
3462
|
+
fontMetricTransitionFrame = ownerWindow.requestAnimationFrame(pollFontMetricTransition);
|
|
3463
|
+
};
|
|
3464
|
+
const startFontMetricTransitionPolling = () => {
|
|
3465
|
+
if (fontMetricTransitionFrame !== null) {
|
|
3466
|
+
return;
|
|
3467
|
+
}
|
|
3468
|
+
syncLayoutContext({
|
|
3469
|
+
refreshMeasurements: true
|
|
3470
|
+
});
|
|
3471
|
+
fontMetricTransitionFrame = ownerWindow.requestAnimationFrame(pollFontMetricTransition);
|
|
3472
|
+
};
|
|
3473
|
+
const handleFontMetricTransitionStart = (event) => {
|
|
3474
|
+
if (!isFontMetricTransitionProperty(event.propertyName)) {
|
|
3475
|
+
return;
|
|
3476
|
+
}
|
|
3477
|
+
if (!doesTransitionTargetAffectNode(node, event.target)) {
|
|
3478
|
+
return;
|
|
3479
|
+
}
|
|
3480
|
+
const transitionTarget = event.target;
|
|
3481
|
+
if (transitionTarget === null) {
|
|
3482
|
+
return;
|
|
3483
|
+
}
|
|
3484
|
+
let activeProperties = activeFontMetricTransitions.get(transitionTarget);
|
|
3485
|
+
if (activeProperties === undefined) {
|
|
3486
|
+
activeProperties = new Set;
|
|
3487
|
+
activeFontMetricTransitions.set(transitionTarget, activeProperties);
|
|
3488
|
+
}
|
|
3489
|
+
activeProperties.add(`${event.propertyName}\x00${event.pseudoElement}`);
|
|
3490
|
+
startFontMetricTransitionPolling();
|
|
3491
|
+
};
|
|
3492
|
+
const handleFontMetricTransitionStop = (event) => {
|
|
3493
|
+
if (!isFontMetricTransitionProperty(event.propertyName)) {
|
|
3494
|
+
return;
|
|
3495
|
+
}
|
|
3496
|
+
if (!doesTransitionTargetAffectNode(node, event.target)) {
|
|
3497
|
+
return;
|
|
3498
|
+
}
|
|
3499
|
+
const transitionTarget = event.target;
|
|
3500
|
+
if (transitionTarget === null) {
|
|
3501
|
+
return;
|
|
3502
|
+
}
|
|
3503
|
+
const activeProperties = activeFontMetricTransitions.get(transitionTarget);
|
|
3504
|
+
if (activeProperties === undefined) {
|
|
3505
|
+
return;
|
|
3506
|
+
}
|
|
3507
|
+
activeProperties.delete(`${event.propertyName}\x00${event.pseudoElement}`);
|
|
3508
|
+
if (activeProperties.size > 0) {
|
|
3509
|
+
return;
|
|
3510
|
+
}
|
|
3511
|
+
activeFontMetricTransitions.delete(transitionTarget);
|
|
3512
|
+
if (activeFontMetricTransitions.size > 0) {
|
|
3513
|
+
return;
|
|
3514
|
+
}
|
|
3515
|
+
stopFontMetricTransitionPolling();
|
|
3516
|
+
syncLayoutContext({
|
|
3517
|
+
refreshMeasurements: true
|
|
3518
|
+
});
|
|
3519
|
+
};
|
|
3031
3520
|
let resizeObserver = null;
|
|
3032
3521
|
if (shouldObserveWrappingWidth) {
|
|
3033
3522
|
resizeObserver = new ResizeObserver(([entry]) => {
|
|
@@ -3037,27 +3526,40 @@ function useObservedLayoutContext(deps) {
|
|
|
3037
3526
|
});
|
|
3038
3527
|
}
|
|
3039
3528
|
resizeObserver?.observe(node);
|
|
3529
|
+
ownerDocument.addEventListener("transitionrun", handleFontMetricTransitionStart, true);
|
|
3530
|
+
ownerDocument.addEventListener("transitionstart", handleFontMetricTransitionStart, true);
|
|
3531
|
+
ownerDocument.addEventListener("transitionend", handleFontMetricTransitionStop, true);
|
|
3532
|
+
ownerDocument.addEventListener("transitioncancel", handleFontMetricTransitionStop, true);
|
|
3040
3533
|
acquireMorphMeasurementInvalidationListeners();
|
|
3041
3534
|
return () => {
|
|
3042
3535
|
disposed = true;
|
|
3536
|
+
syncLayoutContextRef.current = null;
|
|
3537
|
+
unsubscribeInvalidation();
|
|
3043
3538
|
resizeObserver?.disconnect();
|
|
3539
|
+
stopFontMetricTransitionPolling();
|
|
3540
|
+
activeFontMetricTransitions.clear();
|
|
3541
|
+
ownerDocument.removeEventListener("transitionrun", handleFontMetricTransitionStart, true);
|
|
3542
|
+
ownerDocument.removeEventListener("transitionstart", handleFontMetricTransitionStart, true);
|
|
3543
|
+
ownerDocument.removeEventListener("transitionend", handleFontMetricTransitionStop, true);
|
|
3544
|
+
ownerDocument.removeEventListener("transitioncancel", handleFontMetricTransitionStop, true);
|
|
3044
3545
|
releaseMorphMeasurementInvalidationListeners();
|
|
3045
3546
|
};
|
|
3046
3547
|
}, deps);
|
|
3047
3548
|
return { ref, layoutContext };
|
|
3048
3549
|
}
|
|
3049
|
-
|
|
3050
|
-
|
|
3051
|
-
|
|
3550
|
+
|
|
3551
|
+
// torph/src/core/dom-measurement.ts
|
|
3552
|
+
var domMeasurementService = null;
|
|
3553
|
+
function readFirstTextNode(node) {
|
|
3554
|
+
if (node === null) {
|
|
3555
|
+
return null;
|
|
3052
3556
|
}
|
|
3053
|
-
const
|
|
3054
|
-
|
|
3055
|
-
|
|
3557
|
+
for (const childNode of node.childNodes) {
|
|
3558
|
+
if (childNode.nodeType === Node.TEXT_NODE) {
|
|
3559
|
+
return childNode;
|
|
3560
|
+
}
|
|
3056
3561
|
}
|
|
3057
|
-
|
|
3058
|
-
granularity: "grapheme"
|
|
3059
|
-
});
|
|
3060
|
-
return graphemeSegmenter;
|
|
3562
|
+
return null;
|
|
3061
3563
|
}
|
|
3062
3564
|
function getDomMeasurementService() {
|
|
3063
3565
|
if (domMeasurementService !== null) {
|
|
@@ -3129,51 +3631,6 @@ function applyMeasurementHostStyle({
|
|
|
3129
3631
|
host.style.width = "max-content";
|
|
3130
3632
|
}
|
|
3131
3633
|
}
|
|
3132
|
-
function segmentTorphText(text) {
|
|
3133
|
-
const segments = [];
|
|
3134
|
-
let ordinal = 0;
|
|
3135
|
-
for (const segment of getSegmenter().segment(text)) {
|
|
3136
|
-
segments.push({
|
|
3137
|
-
glyph: segment.segment,
|
|
3138
|
-
key: `${segment.segment}:${ordinal}`
|
|
3139
|
-
});
|
|
3140
|
-
ordinal += 1;
|
|
3141
|
-
}
|
|
3142
|
-
return segments;
|
|
3143
|
-
}
|
|
3144
|
-
function readCachedMorphSegments(text) {
|
|
3145
|
-
const cached = morphSegmentCache.get(text);
|
|
3146
|
-
if (cached !== undefined) {
|
|
3147
|
-
morphSegmentCache.delete(text);
|
|
3148
|
-
morphSegmentCache.set(text, cached);
|
|
3149
|
-
return cached;
|
|
3150
|
-
}
|
|
3151
|
-
const segments = segmentTorphText(text);
|
|
3152
|
-
morphSegmentCache.set(text, segments);
|
|
3153
|
-
if (morphSegmentCache.size > MORPH_SEGMENT_CACHE_LIMIT) {
|
|
3154
|
-
const oldest = morphSegmentCache.keys().next();
|
|
3155
|
-
if (!oldest.done) {
|
|
3156
|
-
morphSegmentCache.delete(oldest.value);
|
|
3157
|
-
}
|
|
3158
|
-
}
|
|
3159
|
-
return segments;
|
|
3160
|
-
}
|
|
3161
|
-
function getDomMeasurementRequestKey(text, renderText, layoutContext, useContentInlineSize) {
|
|
3162
|
-
let inlineSizeMode = "container";
|
|
3163
|
-
if (useContentInlineSize) {
|
|
3164
|
-
inlineSizeMode = "content";
|
|
3165
|
-
}
|
|
3166
|
-
return `dom\x00${inlineSizeMode}\x00${text}\x00${renderText}\x00${layoutContext.measurementVersion}\x00${getMorphMeasurementEpoch()}`;
|
|
3167
|
-
}
|
|
3168
|
-
function needsMeasurementLayer(measurementBackend, renderText) {
|
|
3169
|
-
if (measurementBackend === "pretext") {
|
|
3170
|
-
return false;
|
|
3171
|
-
}
|
|
3172
|
-
return renderText.length > 0;
|
|
3173
|
-
}
|
|
3174
|
-
function canCacheMeasurementLayerSnapshot(measurementBackend) {
|
|
3175
|
-
return measurementBackend === "dom";
|
|
3176
|
-
}
|
|
3177
3634
|
function readCachedMorphSnapshot(cache, cacheKey) {
|
|
3178
3635
|
const cached = cache.get(cacheKey);
|
|
3179
3636
|
if (cached === undefined) {
|
|
@@ -3186,7 +3643,7 @@ function readCachedMorphSnapshot(cache, cacheKey) {
|
|
|
3186
3643
|
function rememberCachedMorphSnapshot(cache, cacheKey, snapshot) {
|
|
3187
3644
|
cache.delete(cacheKey);
|
|
3188
3645
|
cache.set(cacheKey, snapshot);
|
|
3189
|
-
if (cache.size >
|
|
3646
|
+
if (cache.size > 8) {
|
|
3190
3647
|
const oldest = cache.keys().next();
|
|
3191
3648
|
if (!oldest.done) {
|
|
3192
3649
|
cache.delete(oldest.value);
|
|
@@ -3267,65 +3724,27 @@ function measureMorphSnapshotWithDomService({
|
|
|
3267
3724
|
useContentInlineSize
|
|
3268
3725
|
}) {
|
|
3269
3726
|
if (renderText.length === 0) {
|
|
3270
|
-
return {
|
|
3271
|
-
text,
|
|
3272
|
-
renderText,
|
|
3273
|
-
width: 0,
|
|
3274
|
-
height: 0,
|
|
3275
|
-
graphemes: []
|
|
3276
|
-
};
|
|
3277
|
-
}
|
|
3278
|
-
const service = getDomMeasurementService();
|
|
3279
|
-
applyMeasurementHostStyle({
|
|
3280
|
-
host: service.host,
|
|
3281
|
-
root,
|
|
3282
|
-
layoutContext,
|
|
3283
|
-
useContentInlineSize
|
|
3284
|
-
});
|
|
3285
|
-
service.host.textContent = renderText;
|
|
3286
|
-
return measureMorphSnapshotFromLayer(text, renderText, segments, service.host);
|
|
3287
|
-
}
|
|
3288
|
-
function readRootOrigin(node) {
|
|
3289
|
-
const rect = node.getBoundingClientRect();
|
|
3290
|
-
return { left: rect.left, top: rect.top };
|
|
3291
|
-
}
|
|
3292
|
-
function readFlowInlineSize(node) {
|
|
3293
|
-
if (node === null) {
|
|
3294
|
-
return null;
|
|
3295
|
-
}
|
|
3296
|
-
return node.getBoundingClientRect().width;
|
|
3297
|
-
}
|
|
3298
|
-
function readFlowLineCount(node) {
|
|
3299
|
-
if (node === null) {
|
|
3300
|
-
return null;
|
|
3301
|
-
}
|
|
3302
|
-
const rects = Array.from(node.getClientRects());
|
|
3303
|
-
if (rects.length === 0) {
|
|
3304
|
-
if ((node.textContent ?? "").length === 0) {
|
|
3305
|
-
return 0;
|
|
3306
|
-
}
|
|
3307
|
-
return 1;
|
|
3308
|
-
}
|
|
3309
|
-
let lineCount = 0;
|
|
3310
|
-
let currentTop = null;
|
|
3311
|
-
for (const rect of rects) {
|
|
3312
|
-
if (currentTop === null || !nearlyEqual(rect.top, currentTop, MORPH.lineGroupingEpsilon)) {
|
|
3313
|
-
currentTop = rect.top;
|
|
3314
|
-
lineCount += 1;
|
|
3315
|
-
}
|
|
3316
|
-
}
|
|
3317
|
-
return lineCount;
|
|
3318
|
-
}
|
|
3319
|
-
function readFirstTextNode(node) {
|
|
3320
|
-
if (node === null) {
|
|
3321
|
-
return null;
|
|
3322
|
-
}
|
|
3323
|
-
for (const childNode of node.childNodes) {
|
|
3324
|
-
if (childNode.nodeType === Node.TEXT_NODE) {
|
|
3325
|
-
return childNode;
|
|
3326
|
-
}
|
|
3727
|
+
return {
|
|
3728
|
+
text,
|
|
3729
|
+
renderText,
|
|
3730
|
+
width: 0,
|
|
3731
|
+
height: 0,
|
|
3732
|
+
graphemes: []
|
|
3733
|
+
};
|
|
3327
3734
|
}
|
|
3328
|
-
|
|
3735
|
+
const service = getDomMeasurementService();
|
|
3736
|
+
applyMeasurementHostStyle({
|
|
3737
|
+
host: service.host,
|
|
3738
|
+
root,
|
|
3739
|
+
layoutContext,
|
|
3740
|
+
useContentInlineSize
|
|
3741
|
+
});
|
|
3742
|
+
service.host.textContent = renderText;
|
|
3743
|
+
return measureMorphSnapshotFromLayer(text, renderText, segments, service.host);
|
|
3744
|
+
}
|
|
3745
|
+
function readRootOrigin(node) {
|
|
3746
|
+
const rect = node.getBoundingClientRect();
|
|
3747
|
+
return { left: rect.left, top: rect.top };
|
|
3329
3748
|
}
|
|
3330
3749
|
function measureLiveFlowSnapshot(root, flowTextNode) {
|
|
3331
3750
|
const textNode = readFirstTextNode(flowTextNode);
|
|
@@ -3458,141 +3877,6 @@ function measureOverlayBoxSnapshot(root, overlayRoot, role) {
|
|
|
3458
3877
|
graphemes
|
|
3459
3878
|
};
|
|
3460
3879
|
}
|
|
3461
|
-
function getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize) {
|
|
3462
|
-
const backend = getPretextMorphMeasurementBackend(text, layoutContext);
|
|
3463
|
-
if (backend !== "probe") {
|
|
3464
|
-
return backend;
|
|
3465
|
-
}
|
|
3466
|
-
const signature = getPretextMorphTrustSignature({
|
|
3467
|
-
renderText,
|
|
3468
|
-
layoutContext,
|
|
3469
|
-
useContentInlineSize
|
|
3470
|
-
});
|
|
3471
|
-
if (signature === null) {
|
|
3472
|
-
return "dom";
|
|
3473
|
-
}
|
|
3474
|
-
const trusted = pretextMorphTrustCache.get(signature);
|
|
3475
|
-
if (trusted === undefined) {
|
|
3476
|
-
return "probe";
|
|
3477
|
-
}
|
|
3478
|
-
if (trusted) {
|
|
3479
|
-
return "pretext";
|
|
3480
|
-
}
|
|
3481
|
-
return "dom";
|
|
3482
|
-
}
|
|
3483
|
-
function resolveContentWidthLockInlineSize(layoutHint) {
|
|
3484
|
-
if (layoutHint.flowInlineSize !== null) {
|
|
3485
|
-
return layoutHint.flowInlineSize;
|
|
3486
|
-
}
|
|
3487
|
-
return layoutHint.snapshot.width;
|
|
3488
|
-
}
|
|
3489
|
-
function shouldMeasureUsingContentInlineSize(layoutContext, layoutHint) {
|
|
3490
|
-
if (supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay)) {
|
|
3491
|
-
return true;
|
|
3492
|
-
}
|
|
3493
|
-
if (layoutContext.whiteSpace === "nowrap") {
|
|
3494
|
-
return true;
|
|
3495
|
-
}
|
|
3496
|
-
if (layoutHint === null || !isSingleLineSnapshot(layoutHint.snapshot)) {
|
|
3497
|
-
return false;
|
|
3498
|
-
}
|
|
3499
|
-
return nearlyEqual(layoutHint.layoutInlineSize, resolveContentWidthLockInlineSize(layoutHint), MORPH.contentWidthLockEpsilon);
|
|
3500
|
-
}
|
|
3501
|
-
function shouldHealIdleMeasurementFromFlow(measurement, flowLineCount) {
|
|
3502
|
-
if (flowLineCount !== 1) {
|
|
3503
|
-
return false;
|
|
3504
|
-
}
|
|
3505
|
-
return countSnapshotLines(measurement.snapshot) > 1;
|
|
3506
|
-
}
|
|
3507
|
-
function refineMeasurementWithLiveGeometry(measurement, liveGeometry) {
|
|
3508
|
-
const sameFlowInlineSize = measurement.flowInlineSize === null && liveGeometry.flowInlineSize === null || measurement.flowInlineSize !== null && liveGeometry.flowInlineSize !== null && nearlyEqual(measurement.flowInlineSize, liveGeometry.flowInlineSize);
|
|
3509
|
-
if (sameFlowInlineSize && nearlyEqual(measurement.rootOrigin.left, liveGeometry.rootOrigin.left) && nearlyEqual(measurement.rootOrigin.top, liveGeometry.rootOrigin.top)) {
|
|
3510
|
-
return measurement;
|
|
3511
|
-
}
|
|
3512
|
-
return {
|
|
3513
|
-
snapshot: measurement.snapshot,
|
|
3514
|
-
layoutInlineSize: measurement.layoutInlineSize,
|
|
3515
|
-
reservedInlineSize: measurement.reservedInlineSize,
|
|
3516
|
-
flowInlineSize: liveGeometry.flowInlineSize,
|
|
3517
|
-
rootOrigin: liveGeometry.rootOrigin
|
|
3518
|
-
};
|
|
3519
|
-
}
|
|
3520
|
-
function refineMeasurementFromLiveNodes(measurement, root, flowTextNode) {
|
|
3521
|
-
if (root === null) {
|
|
3522
|
-
return measurement;
|
|
3523
|
-
}
|
|
3524
|
-
return refineMeasurementWithLiveGeometry(measurement, {
|
|
3525
|
-
flowInlineSize: readFlowInlineSize(flowTextNode),
|
|
3526
|
-
rootOrigin: readRootOrigin(root)
|
|
3527
|
-
});
|
|
3528
|
-
}
|
|
3529
|
-
function createMorphMeasurementRequest({
|
|
3530
|
-
text,
|
|
3531
|
-
layoutContext,
|
|
3532
|
-
layoutHint,
|
|
3533
|
-
forceContentInlineSize = false
|
|
3534
|
-
}) {
|
|
3535
|
-
if (layoutContext === null) {
|
|
3536
|
-
return null;
|
|
3537
|
-
}
|
|
3538
|
-
const renderText = getPretextMorphRenderedText(text, layoutContext);
|
|
3539
|
-
let useContentInlineSize = shouldMeasureUsingContentInlineSize(layoutContext, layoutHint);
|
|
3540
|
-
if (forceContentInlineSize) {
|
|
3541
|
-
useContentInlineSize = true;
|
|
3542
|
-
}
|
|
3543
|
-
const measurementBackend = getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize);
|
|
3544
|
-
let segments = readCachedMorphSegments(renderText);
|
|
3545
|
-
if (measurementBackend === "pretext") {
|
|
3546
|
-
segments = EMPTY_SEGMENTS;
|
|
3547
|
-
}
|
|
3548
|
-
let domMeasurementKey = null;
|
|
3549
|
-
if (needsMeasurementLayer(measurementBackend, renderText)) {
|
|
3550
|
-
domMeasurementKey = getDomMeasurementRequestKey(text, renderText, layoutContext, useContentInlineSize);
|
|
3551
|
-
}
|
|
3552
|
-
return {
|
|
3553
|
-
text,
|
|
3554
|
-
renderText,
|
|
3555
|
-
segments,
|
|
3556
|
-
measurementBackend,
|
|
3557
|
-
useContentInlineSize,
|
|
3558
|
-
domMeasurementKey
|
|
3559
|
-
};
|
|
3560
|
-
}
|
|
3561
|
-
function rememberPretextMeasurementTrust({
|
|
3562
|
-
renderText,
|
|
3563
|
-
layoutContext,
|
|
3564
|
-
useContentInlineSize,
|
|
3565
|
-
trusted
|
|
3566
|
-
}) {
|
|
3567
|
-
const signature = getPretextMorphTrustSignature({
|
|
3568
|
-
renderText,
|
|
3569
|
-
layoutContext,
|
|
3570
|
-
useContentInlineSize
|
|
3571
|
-
});
|
|
3572
|
-
if (signature === null) {
|
|
3573
|
-
return;
|
|
3574
|
-
}
|
|
3575
|
-
pretextMorphTrustCache.set(signature, trusted);
|
|
3576
|
-
}
|
|
3577
|
-
function areSnapshotsEquivalentForPretextTrust(left, right) {
|
|
3578
|
-
if (left.renderText !== right.renderText || left.graphemes.length !== right.graphemes.length) {
|
|
3579
|
-
return false;
|
|
3580
|
-
}
|
|
3581
|
-
if (Math.abs(left.width - right.width) > MORPH.geometryEpsilon || Math.abs(left.height - right.height) > MORPH.geometryEpsilon) {
|
|
3582
|
-
return false;
|
|
3583
|
-
}
|
|
3584
|
-
for (let index = 0;index < left.graphemes.length; index += 1) {
|
|
3585
|
-
const from = left.graphemes[index];
|
|
3586
|
-
const to = right.graphemes[index];
|
|
3587
|
-
if (from.glyph !== to.glyph) {
|
|
3588
|
-
return false;
|
|
3589
|
-
}
|
|
3590
|
-
if (Math.abs(from.left - to.left) > MORPH.geometryEpsilon || Math.abs(from.top - to.top) > MORPH.geometryEpsilon || Math.abs(from.width - to.width) > MORPH.geometryEpsilon || Math.abs(from.height - to.height) > MORPH.geometryEpsilon) {
|
|
3591
|
-
return false;
|
|
3592
|
-
}
|
|
3593
|
-
}
|
|
3594
|
-
return true;
|
|
3595
|
-
}
|
|
3596
3880
|
function measureFromNodes({
|
|
3597
3881
|
root,
|
|
3598
3882
|
layoutContext,
|
|
@@ -3612,7 +3896,7 @@ function measureFromNodes({
|
|
|
3612
3896
|
width: Number.MAX_SAFE_INTEGER / 4
|
|
3613
3897
|
};
|
|
3614
3898
|
}
|
|
3615
|
-
const snapshot = snapshotOverride ?? (() => {
|
|
3899
|
+
const snapshot = assertSingleLineSnapshot(snapshotOverride ?? (() => {
|
|
3616
3900
|
let pretextSnapshot = null;
|
|
3617
3901
|
if (measurementBackend !== "dom") {
|
|
3618
3902
|
pretextSnapshot = measureMorphSnapshotWithPretext(text, measurementLayoutContext);
|
|
@@ -3649,294 +3933,378 @@ function measureFromNodes({
|
|
|
3649
3933
|
if (resolvedSnapshot === null) {
|
|
3650
3934
|
throw new Error("Torph failed to resolve a measurement snapshot.");
|
|
3651
3935
|
}
|
|
3652
|
-
return resolvedSnapshot;
|
|
3653
|
-
})();
|
|
3654
|
-
let layoutInlineSize = layoutContext.width;
|
|
3655
|
-
if (useContentInlineSize) {
|
|
3656
|
-
layoutInlineSize = snapshot.width;
|
|
3936
|
+
return resolvedSnapshot;
|
|
3937
|
+
})());
|
|
3938
|
+
let layoutInlineSize = layoutContext.width;
|
|
3939
|
+
if (useContentInlineSize) {
|
|
3940
|
+
layoutInlineSize = snapshot.width;
|
|
3941
|
+
}
|
|
3942
|
+
let reservedInlineSize = null;
|
|
3943
|
+
if (supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay)) {
|
|
3944
|
+
reservedInlineSize = snapshot.width;
|
|
3945
|
+
}
|
|
3946
|
+
let flowInlineSize = null;
|
|
3947
|
+
if (useContentInlineSize) {
|
|
3948
|
+
flowInlineSize = snapshot.width;
|
|
3949
|
+
}
|
|
3950
|
+
return {
|
|
3951
|
+
snapshot,
|
|
3952
|
+
layoutInlineSize,
|
|
3953
|
+
reservedInlineSize,
|
|
3954
|
+
flowInlineSize,
|
|
3955
|
+
rootOrigin: readRootOrigin(root)
|
|
3956
|
+
};
|
|
3957
|
+
}
|
|
3958
|
+
|
|
3959
|
+
// torph/src/debug/trace.ts
|
|
3960
|
+
var TORPH_TRACE_MAX_BYTES = 4 * 1024 * 1024;
|
|
3961
|
+
var TORPH_TRACE_MAX_LINES = 4000;
|
|
3962
|
+
var TORPH_TRACE_SCHEMA_VERSION = 7;
|
|
3963
|
+
var DEFAULT_TORPH_DEBUG_CONFIG = {
|
|
3964
|
+
capture: false,
|
|
3965
|
+
console: false
|
|
3966
|
+
};
|
|
3967
|
+
var torphDebugInstanceOrdinal = 0;
|
|
3968
|
+
function nextTorphDebugInstanceId() {
|
|
3969
|
+
torphDebugInstanceOrdinal += 1;
|
|
3970
|
+
return torphDebugInstanceOrdinal;
|
|
3971
|
+
}
|
|
3972
|
+
function readTorphDebugConfig() {
|
|
3973
|
+
const scope = globalThis;
|
|
3974
|
+
return scope.__TORPH_DEBUG__ ?? DEFAULT_TORPH_DEBUG_CONFIG;
|
|
3975
|
+
}
|
|
3976
|
+
function shouldCaptureTorphTrace(config) {
|
|
3977
|
+
if (config === null) {
|
|
3978
|
+
return false;
|
|
3979
|
+
}
|
|
3980
|
+
if (typeof config === "boolean") {
|
|
3981
|
+
return config;
|
|
3982
|
+
}
|
|
3983
|
+
if (config.capture === true) {
|
|
3984
|
+
return true;
|
|
3985
|
+
}
|
|
3986
|
+
return false;
|
|
3987
|
+
}
|
|
3988
|
+
function isTorphDebugEnabled(config) {
|
|
3989
|
+
if (config === null) {
|
|
3990
|
+
return false;
|
|
3991
|
+
}
|
|
3992
|
+
if (typeof config === "boolean") {
|
|
3993
|
+
return config;
|
|
3994
|
+
}
|
|
3995
|
+
if (config.console !== undefined) {
|
|
3996
|
+
return config.console;
|
|
3997
|
+
}
|
|
3998
|
+
if (config.enabled === true) {
|
|
3999
|
+
return true;
|
|
4000
|
+
}
|
|
4001
|
+
return false;
|
|
4002
|
+
}
|
|
4003
|
+
function shouldRunTorphInstrumentation(config) {
|
|
4004
|
+
if (shouldCaptureTorphTrace(config)) {
|
|
4005
|
+
return true;
|
|
4006
|
+
}
|
|
4007
|
+
return isTorphDebugEnabled(config);
|
|
4008
|
+
}
|
|
4009
|
+
function getTorphTraceStore() {
|
|
4010
|
+
const scope = globalThis;
|
|
4011
|
+
let store = scope.__TORPH_TRACE_STORE__;
|
|
4012
|
+
if (store !== undefined) {
|
|
4013
|
+
return store;
|
|
4014
|
+
}
|
|
4015
|
+
store = {
|
|
4016
|
+
lines: [],
|
|
4017
|
+
nextSeq: 1,
|
|
4018
|
+
totalBytes: 0
|
|
4019
|
+
};
|
|
4020
|
+
scope.__TORPH_TRACE_STORE__ = store;
|
|
4021
|
+
return store;
|
|
4022
|
+
}
|
|
4023
|
+
function getTorphTraceText() {
|
|
4024
|
+
return getTorphTraceStore().lines.join("");
|
|
4025
|
+
}
|
|
4026
|
+
function clearTorphTrace() {
|
|
4027
|
+
const store = getTorphTraceStore();
|
|
4028
|
+
store.lines = [];
|
|
4029
|
+
store.nextSeq = 1;
|
|
4030
|
+
store.totalBytes = 0;
|
|
4031
|
+
}
|
|
4032
|
+
function downloadTorphTrace(filename) {
|
|
4033
|
+
if (typeof document === "undefined") {
|
|
4034
|
+
return null;
|
|
4035
|
+
}
|
|
4036
|
+
const text = getTorphTraceText();
|
|
4037
|
+
const blob = new Blob([text], { type: "application/x-ndjson;charset=utf-8" });
|
|
4038
|
+
const href = URL.createObjectURL(blob);
|
|
4039
|
+
const anchor = document.createElement("a");
|
|
4040
|
+
let resolvedFilename = filename;
|
|
4041
|
+
if (resolvedFilename === undefined) {
|
|
4042
|
+
resolvedFilename = `torph-trace-${new Date().toISOString().replaceAll(":", "-")}.jsonl`;
|
|
4043
|
+
}
|
|
4044
|
+
anchor.href = href;
|
|
4045
|
+
anchor.download = resolvedFilename;
|
|
4046
|
+
anchor.click();
|
|
4047
|
+
window.setTimeout(() => {
|
|
4048
|
+
URL.revokeObjectURL(href);
|
|
4049
|
+
}, 0);
|
|
4050
|
+
return resolvedFilename;
|
|
4051
|
+
}
|
|
4052
|
+
function ensureTorphTraceApi() {
|
|
4053
|
+
const scope = globalThis;
|
|
4054
|
+
if (scope.__TORPH_TRACE__ !== undefined) {
|
|
4055
|
+
return scope.__TORPH_TRACE__;
|
|
4056
|
+
}
|
|
4057
|
+
const api = {
|
|
4058
|
+
clear: clearTorphTrace,
|
|
4059
|
+
count: () => getTorphTraceStore().lines.length,
|
|
4060
|
+
download: downloadTorphTrace,
|
|
4061
|
+
text: getTorphTraceText
|
|
4062
|
+
};
|
|
4063
|
+
scope.__TORPH_TRACE__ = api;
|
|
4064
|
+
return api;
|
|
4065
|
+
}
|
|
4066
|
+
function appendTorphTrace(instanceId, event, payload) {
|
|
4067
|
+
ensureTorphTraceApi();
|
|
4068
|
+
const store = getTorphTraceStore();
|
|
4069
|
+
const entry = {
|
|
4070
|
+
instanceId,
|
|
4071
|
+
event,
|
|
4072
|
+
payload,
|
|
4073
|
+
seq: store.nextSeq,
|
|
4074
|
+
time: new Date().toISOString()
|
|
4075
|
+
};
|
|
4076
|
+
store.nextSeq += 1;
|
|
4077
|
+
const line = `${JSON.stringify(entry)}
|
|
4078
|
+
`;
|
|
4079
|
+
store.lines.push(line);
|
|
4080
|
+
store.totalBytes += line.length;
|
|
4081
|
+
while (store.lines.length > TORPH_TRACE_MAX_LINES || store.totalBytes > TORPH_TRACE_MAX_BYTES) {
|
|
4082
|
+
const removed = store.lines.shift();
|
|
4083
|
+
if (removed === undefined) {
|
|
4084
|
+
break;
|
|
4085
|
+
}
|
|
4086
|
+
store.totalBytes = Math.max(0, store.totalBytes - removed.length);
|
|
3657
4087
|
}
|
|
3658
|
-
|
|
3659
|
-
|
|
3660
|
-
|
|
4088
|
+
}
|
|
4089
|
+
function roundDebugValue(value) {
|
|
4090
|
+
if (value === null || value === undefined) {
|
|
4091
|
+
return value;
|
|
3661
4092
|
}
|
|
3662
|
-
return
|
|
3663
|
-
snapshot,
|
|
3664
|
-
layoutInlineSize,
|
|
3665
|
-
reservedInlineSize,
|
|
3666
|
-
flowInlineSize: null,
|
|
3667
|
-
rootOrigin: readRootOrigin(root)
|
|
3668
|
-
};
|
|
4093
|
+
return Math.round(value * 1e4) / 1e4;
|
|
3669
4094
|
}
|
|
3670
|
-
function
|
|
3671
|
-
if (
|
|
3672
|
-
return
|
|
4095
|
+
function summarizeDebugSnapshot(snapshot) {
|
|
4096
|
+
if (snapshot === null) {
|
|
4097
|
+
return null;
|
|
3673
4098
|
}
|
|
3674
4099
|
return {
|
|
3675
|
-
|
|
3676
|
-
|
|
3677
|
-
|
|
3678
|
-
|
|
3679
|
-
|
|
4100
|
+
text: snapshot.text,
|
|
4101
|
+
renderText: snapshot.renderText,
|
|
4102
|
+
width: roundDebugValue(snapshot.width),
|
|
4103
|
+
height: roundDebugValue(snapshot.height),
|
|
4104
|
+
graphemes: snapshot.graphemes.length
|
|
3680
4105
|
};
|
|
3681
4106
|
}
|
|
3682
|
-
function
|
|
3683
|
-
|
|
3684
|
-
|
|
3685
|
-
const bucket = buckets.get(grapheme.glyph);
|
|
3686
|
-
if (bucket) {
|
|
3687
|
-
bucket.push(grapheme);
|
|
3688
|
-
} else {
|
|
3689
|
-
buckets.set(grapheme.glyph, [grapheme]);
|
|
3690
|
-
}
|
|
4107
|
+
function summarizeDebugGlyphs(snapshot) {
|
|
4108
|
+
if (snapshot === null) {
|
|
4109
|
+
return null;
|
|
3691
4110
|
}
|
|
3692
|
-
return
|
|
4111
|
+
return snapshot.graphemes.map((grapheme, index) => ({
|
|
4112
|
+
index,
|
|
4113
|
+
glyph: grapheme.glyph,
|
|
4114
|
+
key: grapheme.key,
|
|
4115
|
+
left: roundDebugValue(grapheme.left),
|
|
4116
|
+
top: roundDebugValue(grapheme.top),
|
|
4117
|
+
width: roundDebugValue(grapheme.width),
|
|
4118
|
+
height: roundDebugValue(grapheme.height)
|
|
4119
|
+
}));
|
|
3693
4120
|
}
|
|
3694
|
-
function
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
const pairings = [];
|
|
3698
|
-
for (const [glyph, previousItems] of previousBuckets) {
|
|
3699
|
-
const nextItems = nextBuckets.get(glyph) ?? [];
|
|
3700
|
-
const shared = Math.min(previousItems.length, nextItems.length);
|
|
3701
|
-
for (let index = 0;index < shared; index += 1) {
|
|
3702
|
-
pairings.push({
|
|
3703
|
-
kind: "move",
|
|
3704
|
-
from: previousItems[index],
|
|
3705
|
-
to: nextItems[index]
|
|
3706
|
-
});
|
|
3707
|
-
}
|
|
3708
|
-
for (let index = shared;index < previousItems.length; index += 1) {
|
|
3709
|
-
pairings.push({
|
|
3710
|
-
kind: "exit",
|
|
3711
|
-
from: previousItems[index]
|
|
3712
|
-
});
|
|
3713
|
-
}
|
|
3714
|
-
}
|
|
3715
|
-
for (const [glyph, nextItems] of nextBuckets) {
|
|
3716
|
-
const previousItems = previousBuckets.get(glyph) ?? [];
|
|
3717
|
-
const shared = Math.min(previousItems.length, nextItems.length);
|
|
3718
|
-
for (let index = shared;index < nextItems.length; index += 1) {
|
|
3719
|
-
pairings.push({
|
|
3720
|
-
kind: "enter",
|
|
3721
|
-
to: nextItems[index]
|
|
3722
|
-
});
|
|
3723
|
-
}
|
|
4121
|
+
function summarizeDebugMeasurement(measurement) {
|
|
4122
|
+
if (measurement === null) {
|
|
4123
|
+
return null;
|
|
3724
4124
|
}
|
|
3725
|
-
return pairings;
|
|
3726
|
-
}
|
|
3727
|
-
function resolveMorphFrameBounds(previous, next) {
|
|
3728
4125
|
return {
|
|
3729
|
-
|
|
3730
|
-
|
|
4126
|
+
layoutInlineSize: roundDebugValue(measurement.layoutInlineSize),
|
|
4127
|
+
reservedInlineSize: roundDebugValue(measurement.reservedInlineSize),
|
|
4128
|
+
flowInlineSize: roundDebugValue(measurement.flowInlineSize),
|
|
4129
|
+
rootOrigin: {
|
|
4130
|
+
left: roundDebugValue(measurement.rootOrigin.left),
|
|
4131
|
+
top: roundDebugValue(measurement.rootOrigin.top)
|
|
4132
|
+
},
|
|
4133
|
+
snapshot: summarizeDebugSnapshot(measurement.snapshot)
|
|
3731
4134
|
};
|
|
3732
4135
|
}
|
|
3733
|
-
function
|
|
4136
|
+
function summarizeDebugLayoutContext(layoutContext) {
|
|
4137
|
+
if (layoutContext === null) {
|
|
4138
|
+
return null;
|
|
4139
|
+
}
|
|
3734
4140
|
return {
|
|
3735
|
-
|
|
3736
|
-
|
|
4141
|
+
display: layoutContext.display,
|
|
4142
|
+
parentDisplay: layoutContext.parentDisplay,
|
|
4143
|
+
whiteSpace: layoutContext.whiteSpace,
|
|
4144
|
+
width: roundDebugValue(layoutContext.width),
|
|
4145
|
+
measurementVersion: layoutContext.measurementVersion
|
|
3737
4146
|
};
|
|
3738
4147
|
}
|
|
3739
|
-
function
|
|
3740
|
-
|
|
3741
|
-
|
|
3742
|
-
const exitItems = [];
|
|
3743
|
-
for (const pairing of pairings) {
|
|
3744
|
-
if (pairing.kind === "move") {
|
|
3745
|
-
movesByDestinationKey.set(pairing.to.key, pairing);
|
|
3746
|
-
continue;
|
|
3747
|
-
}
|
|
3748
|
-
if (pairing.kind === "exit") {
|
|
3749
|
-
exitItems.push(pairing.from);
|
|
3750
|
-
}
|
|
4148
|
+
function summarizeDebugRect(rect) {
|
|
4149
|
+
if (rect === null) {
|
|
4150
|
+
return null;
|
|
3751
4151
|
}
|
|
3752
|
-
const frame = resolveMorphFrameBounds(previous.snapshot, next.snapshot);
|
|
3753
4152
|
return {
|
|
3754
|
-
|
|
3755
|
-
|
|
3756
|
-
|
|
3757
|
-
|
|
3758
|
-
sourceRenderText: previous.snapshot.renderText,
|
|
3759
|
-
targetRenderText: next.snapshot.renderText,
|
|
3760
|
-
visualBridge,
|
|
3761
|
-
liveItems: next.snapshot.graphemes.map((grapheme) => {
|
|
3762
|
-
const move = movesByDestinationKey.get(grapheme.key);
|
|
3763
|
-
if (move) {
|
|
3764
|
-
return {
|
|
3765
|
-
...grapheme,
|
|
3766
|
-
kind: "move",
|
|
3767
|
-
fromLeft: move.from.left,
|
|
3768
|
-
fromTop: move.from.top
|
|
3769
|
-
};
|
|
3770
|
-
}
|
|
3771
|
-
return {
|
|
3772
|
-
...grapheme,
|
|
3773
|
-
kind: "enter",
|
|
3774
|
-
fromLeft: null,
|
|
3775
|
-
fromTop: null
|
|
3776
|
-
};
|
|
3777
|
-
}),
|
|
3778
|
-
exitItems
|
|
4153
|
+
left: roundDebugValue(rect.left),
|
|
4154
|
+
top: roundDebugValue(rect.top),
|
|
4155
|
+
width: roundDebugValue(rect.width),
|
|
4156
|
+
height: roundDebugValue(rect.height)
|
|
3779
4157
|
};
|
|
3780
4158
|
}
|
|
3781
|
-
function
|
|
3782
|
-
|
|
3783
|
-
|
|
3784
|
-
|
|
3785
|
-
if (a === b) {
|
|
3786
|
-
return true;
|
|
3787
|
-
}
|
|
3788
|
-
if (a.text !== b.text || a.renderText !== b.renderText || a.graphemes.length !== b.graphemes.length) {
|
|
3789
|
-
return false;
|
|
4159
|
+
function collectDebugAnchorIndices(length) {
|
|
4160
|
+
const indices = new Set;
|
|
4161
|
+
if (length <= 0) {
|
|
4162
|
+
return [];
|
|
3790
4163
|
}
|
|
3791
|
-
|
|
3792
|
-
|
|
4164
|
+
indices.add(0);
|
|
4165
|
+
if (length > 1) {
|
|
4166
|
+
indices.add(1);
|
|
4167
|
+
indices.add(length - 2);
|
|
3793
4168
|
}
|
|
3794
|
-
|
|
3795
|
-
|
|
3796
|
-
const right = b.graphemes[index];
|
|
3797
|
-
if (left.glyph !== right.glyph || left.key !== right.key) {
|
|
3798
|
-
return false;
|
|
3799
|
-
}
|
|
3800
|
-
if (!nearlyEqual(left.left, right.left) || !nearlyEqual(left.top, right.top) || !nearlyEqual(left.width, right.width) || !nearlyEqual(left.height, right.height)) {
|
|
3801
|
-
return false;
|
|
3802
|
-
}
|
|
4169
|
+
if (length > 2) {
|
|
4170
|
+
indices.add(Math.floor((length - 1) / 2));
|
|
3803
4171
|
}
|
|
3804
|
-
|
|
4172
|
+
indices.add(length - 1);
|
|
4173
|
+
return Array.from(indices).sort((left, right) => left - right);
|
|
3805
4174
|
}
|
|
3806
|
-
function
|
|
3807
|
-
if (
|
|
3808
|
-
return
|
|
4175
|
+
function summarizeDebugViewportAnchors(snapshot, rootRect) {
|
|
4176
|
+
if (snapshot === null || rootRect === null) {
|
|
4177
|
+
return null;
|
|
3809
4178
|
}
|
|
3810
|
-
|
|
3811
|
-
|
|
3812
|
-
|
|
3813
|
-
|
|
3814
|
-
|
|
4179
|
+
const anchors = [];
|
|
4180
|
+
const anchorIndices = collectDebugAnchorIndices(snapshot.graphemes.length);
|
|
4181
|
+
for (const index of anchorIndices) {
|
|
4182
|
+
const grapheme = snapshot.graphemes[index];
|
|
4183
|
+
if (grapheme === undefined) {
|
|
4184
|
+
continue;
|
|
4185
|
+
}
|
|
4186
|
+
anchors.push({
|
|
4187
|
+
index,
|
|
4188
|
+
glyph: grapheme.glyph,
|
|
4189
|
+
left: roundDebugValue(rootRect.left + grapheme.left),
|
|
4190
|
+
top: roundDebugValue(rootRect.top + grapheme.top),
|
|
4191
|
+
width: roundDebugValue(grapheme.width),
|
|
4192
|
+
height: roundDebugValue(grapheme.height)
|
|
4193
|
+
});
|
|
3815
4194
|
}
|
|
3816
|
-
return
|
|
3817
|
-
snapshot: activeTarget.snapshot,
|
|
3818
|
-
layoutInlineSize: measurement.layoutInlineSize,
|
|
3819
|
-
reservedInlineSize: measurement.reservedInlineSize,
|
|
3820
|
-
flowInlineSize: activeTarget.flowInlineSize,
|
|
3821
|
-
rootOrigin: measurement.rootOrigin
|
|
3822
|
-
};
|
|
4195
|
+
return anchors;
|
|
3823
4196
|
}
|
|
3824
|
-
function
|
|
3825
|
-
if (
|
|
3826
|
-
return
|
|
4197
|
+
function summarizeDebugRootOriginDrift(measurement, rootRect) {
|
|
4198
|
+
if (measurement === null || rootRect === null) {
|
|
4199
|
+
return null;
|
|
3827
4200
|
}
|
|
3828
|
-
return measurement;
|
|
3829
|
-
}
|
|
3830
|
-
function createStaticState(measurement) {
|
|
3831
4201
|
return {
|
|
3832
|
-
|
|
3833
|
-
measurement,
|
|
3834
|
-
|
|
4202
|
+
expectedLeft: roundDebugValue(measurement.rootOrigin.left),
|
|
4203
|
+
expectedTop: roundDebugValue(measurement.rootOrigin.top),
|
|
4204
|
+
actualLeft: roundDebugValue(rootRect.left),
|
|
4205
|
+
actualTop: roundDebugValue(rootRect.top),
|
|
4206
|
+
deltaLeft: roundDebugValue(rootRect.left - measurement.rootOrigin.left),
|
|
4207
|
+
deltaTop: roundDebugValue(rootRect.top - measurement.rootOrigin.top)
|
|
3835
4208
|
};
|
|
3836
4209
|
}
|
|
3837
|
-
function
|
|
3838
|
-
return
|
|
3839
|
-
|
|
3840
|
-
|
|
3841
|
-
|
|
3842
|
-
|
|
3843
|
-
|
|
3844
|
-
|
|
3845
|
-
|
|
3846
|
-
|
|
3847
|
-
|
|
3848
|
-
|
|
3849
|
-
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
|
|
3853
|
-
|
|
3854
|
-
|
|
3855
|
-
|
|
3856
|
-
|
|
3857
|
-
session.target = null;
|
|
3858
|
-
session.animating = false;
|
|
3859
|
-
setState(EMPTY_STATE);
|
|
4210
|
+
function summarizeSnapshotDrift(drift) {
|
|
4211
|
+
return {
|
|
4212
|
+
comparedGlyphs: drift.comparedGlyphs,
|
|
4213
|
+
expectedGlyphs: drift.expectedGlyphs,
|
|
4214
|
+
actualGlyphs: drift.actualGlyphs,
|
|
4215
|
+
snapshotWidthDelta: roundDebugValue(drift.snapshotWidthDelta),
|
|
4216
|
+
snapshotHeightDelta: roundDebugValue(drift.snapshotHeightDelta),
|
|
4217
|
+
maxAbsLeftDelta: roundDebugValue(drift.maxAbsLeftDelta),
|
|
4218
|
+
maxAbsTopDelta: roundDebugValue(drift.maxAbsTopDelta),
|
|
4219
|
+
maxAbsWidthDelta: roundDebugValue(drift.maxAbsWidthDelta),
|
|
4220
|
+
maxAbsHeightDelta: roundDebugValue(drift.maxAbsHeightDelta),
|
|
4221
|
+
mismatches: drift.mismatches.map((mismatch) => ({
|
|
4222
|
+
index: mismatch.index,
|
|
4223
|
+
glyph: mismatch.glyph,
|
|
4224
|
+
leftDelta: roundDebugValue(mismatch.leftDelta),
|
|
4225
|
+
topDelta: roundDebugValue(mismatch.topDelta),
|
|
4226
|
+
widthDelta: roundDebugValue(mismatch.widthDelta),
|
|
4227
|
+
heightDelta: roundDebugValue(mismatch.heightDelta)
|
|
4228
|
+
}))
|
|
4229
|
+
};
|
|
3860
4230
|
}
|
|
3861
|
-
function
|
|
3862
|
-
|
|
4231
|
+
function logTorphDebug(instanceId, event, payload) {
|
|
4232
|
+
const config = readTorphDebugConfig();
|
|
4233
|
+
const captureTrace = shouldCaptureTorphTrace(config);
|
|
4234
|
+
const logToConsole = isTorphDebugEnabled(config);
|
|
4235
|
+
if (!captureTrace && !logToConsole) {
|
|
3863
4236
|
return;
|
|
3864
4237
|
}
|
|
3865
|
-
|
|
3866
|
-
|
|
3867
|
-
|
|
3868
|
-
|
|
3869
|
-
|
|
3870
|
-
|
|
3871
|
-
}
|
|
3872
|
-
return createStaticState(measurement);
|
|
3873
|
-
});
|
|
3874
|
-
}
|
|
3875
|
-
function scheduleMorphTimeline({
|
|
3876
|
-
session,
|
|
3877
|
-
timeline,
|
|
3878
|
-
finalizeMeasurement,
|
|
3879
|
-
measurement,
|
|
3880
|
-
plan,
|
|
3881
|
-
setState
|
|
3882
|
-
}) {
|
|
3883
|
-
timeline.prepareFrame = requestAnimationFrame(() => {
|
|
3884
|
-
timeline.prepareFrame = null;
|
|
3885
|
-
setState((current) => {
|
|
3886
|
-
if (current.measurement !== measurement || current.plan !== plan) {
|
|
3887
|
-
return current;
|
|
3888
|
-
}
|
|
3889
|
-
return {
|
|
3890
|
-
stage: "animate",
|
|
3891
|
-
measurement,
|
|
3892
|
-
plan
|
|
3893
|
-
};
|
|
3894
|
-
});
|
|
3895
|
-
timeline.animateFrame = requestAnimationFrame(() => {
|
|
3896
|
-
timeline.animateFrame = null;
|
|
3897
|
-
timeline.finalizeTimer = window.setTimeout(() => {
|
|
3898
|
-
timeline.finalizeTimer = null;
|
|
3899
|
-
commitStaticMeasurement(session, finalizeMeasurement(session.target ?? measurement), setState);
|
|
3900
|
-
}, MORPH.durationMs);
|
|
3901
|
-
});
|
|
3902
|
-
});
|
|
4238
|
+
if (captureTrace) {
|
|
4239
|
+
appendTorphTrace(instanceId, event, payload);
|
|
4240
|
+
}
|
|
4241
|
+
if (logToConsole) {
|
|
4242
|
+
console.log(`[Torph#${instanceId}] ${event}`, payload);
|
|
4243
|
+
}
|
|
3903
4244
|
}
|
|
3904
|
-
|
|
3905
|
-
|
|
3906
|
-
|
|
3907
|
-
|
|
3908
|
-
|
|
3909
|
-
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
3913
|
-
|
|
4245
|
+
|
|
4246
|
+
// torph/src/components/Torph.tsx
|
|
4247
|
+
import { jsxDEV } from "react/jsx-dev-runtime";
|
|
4248
|
+
var SCREEN_READER_ONLY_STYLE = {
|
|
4249
|
+
position: "absolute",
|
|
4250
|
+
width: "1px",
|
|
4251
|
+
height: "1px",
|
|
4252
|
+
margin: "-1px",
|
|
4253
|
+
padding: 0,
|
|
4254
|
+
border: 0,
|
|
4255
|
+
clip: "rect(0 0 0 0)",
|
|
4256
|
+
clipPath: "inset(50%)",
|
|
4257
|
+
overflow: "hidden",
|
|
4258
|
+
whiteSpace: "nowrap"
|
|
4259
|
+
};
|
|
4260
|
+
var FALLBACK_TEXT_STYLE = {
|
|
4261
|
+
display: "block",
|
|
4262
|
+
gridArea: "1 / 1"
|
|
4263
|
+
};
|
|
4264
|
+
var SHARED_GLYPH_TYPOGRAPHY_STYLE = {
|
|
4265
|
+
font: "inherit",
|
|
4266
|
+
fontKerning: "inherit",
|
|
4267
|
+
fontFeatureSettings: "inherit",
|
|
4268
|
+
fontOpticalSizing: "inherit",
|
|
4269
|
+
fontStretch: "inherit",
|
|
4270
|
+
fontStyle: "inherit",
|
|
4271
|
+
fontVariant: "inherit",
|
|
4272
|
+
fontVariantNumeric: "inherit",
|
|
4273
|
+
fontVariationSettings: "inherit",
|
|
4274
|
+
fontWeight: "inherit",
|
|
4275
|
+
letterSpacing: "inherit",
|
|
4276
|
+
textTransform: "inherit",
|
|
4277
|
+
wordSpacing: "inherit",
|
|
4278
|
+
direction: "inherit"
|
|
4279
|
+
};
|
|
4280
|
+
var ABSOLUTE_GLYPH_STYLE = {
|
|
4281
|
+
position: "absolute",
|
|
4282
|
+
display: "block",
|
|
4283
|
+
overflow: "hidden",
|
|
4284
|
+
transformOrigin: "left top"
|
|
4285
|
+
};
|
|
4286
|
+
var CONTEXT_SLICE_TEXT_STYLE = {
|
|
4287
|
+
...SHARED_GLYPH_TYPOGRAPHY_STYLE,
|
|
4288
|
+
position: "absolute",
|
|
4289
|
+
display: "block",
|
|
4290
|
+
minWidth: 0,
|
|
4291
|
+
whiteSpace: "inherit"
|
|
4292
|
+
};
|
|
4293
|
+
var debugDomNodeIds = new WeakMap;
|
|
4294
|
+
var debugDomNodeOrdinal = 0;
|
|
4295
|
+
function getDebugDomNodeId(node) {
|
|
4296
|
+
if (node === null) {
|
|
4297
|
+
return null;
|
|
3914
4298
|
}
|
|
3915
|
-
|
|
3916
|
-
|
|
3917
|
-
return;
|
|
4299
|
+
const existing = debugDomNodeIds.get(node);
|
|
4300
|
+
if (existing !== undefined) {
|
|
4301
|
+
return existing;
|
|
3918
4302
|
}
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
session.target = nextMeasurement;
|
|
3923
|
-
session.animating = true;
|
|
3924
|
-
setState({
|
|
3925
|
-
stage: "prepare",
|
|
3926
|
-
measurement: nextMeasurement,
|
|
3927
|
-
plan
|
|
3928
|
-
});
|
|
3929
|
-
scheduleMorphTimeline({
|
|
3930
|
-
session,
|
|
3931
|
-
timeline,
|
|
3932
|
-
finalizeMeasurement,
|
|
3933
|
-
measurement: nextMeasurement,
|
|
3934
|
-
plan,
|
|
3935
|
-
setState
|
|
3936
|
-
});
|
|
4303
|
+
debugDomNodeOrdinal += 1;
|
|
4304
|
+
debugDomNodeIds.set(node, debugDomNodeOrdinal);
|
|
4305
|
+
return debugDomNodeOrdinal;
|
|
3937
4306
|
}
|
|
3938
4307
|
function reconcileMorphChange({
|
|
3939
|
-
finalizeMeasurement,
|
|
3940
4308
|
root,
|
|
3941
4309
|
measurementLayer,
|
|
3942
4310
|
measurementBackend,
|
|
@@ -3956,10 +4324,7 @@ function reconcileMorphChange({
|
|
|
3956
4324
|
if (measurementBackend === null) {
|
|
3957
4325
|
throw new Error("Torph measurement backend is missing.");
|
|
3958
4326
|
}
|
|
3959
|
-
|
|
3960
|
-
if (session.animating && session.target !== null) {
|
|
3961
|
-
layoutHint = session.target;
|
|
3962
|
-
}
|
|
4327
|
+
const layoutHint = selectMorphLayoutHint(session);
|
|
3963
4328
|
const nextMeasurement = measureFromNodes({
|
|
3964
4329
|
root,
|
|
3965
4330
|
layoutContext,
|
|
@@ -3971,73 +4336,13 @@ function reconcileMorphChange({
|
|
|
3971
4336
|
renderText,
|
|
3972
4337
|
segments
|
|
3973
4338
|
});
|
|
3974
|
-
|
|
3975
|
-
if (nextMeasurement.snapshot.renderText === session.target.snapshot.renderText) {
|
|
3976
|
-
session.target = refreshAnimatingTarget(session.target, nextMeasurement);
|
|
3977
|
-
return nextMeasurement;
|
|
3978
|
-
}
|
|
3979
|
-
}
|
|
3980
|
-
cancelTimeline(timeline);
|
|
3981
|
-
if (session.committed === null) {
|
|
3982
|
-
commitStaticMeasurement(session, nextMeasurement, setState);
|
|
3983
|
-
return nextMeasurement;
|
|
3984
|
-
}
|
|
3985
|
-
if (!areFontsReady()) {
|
|
3986
|
-
commitStaticMeasurement(session, nextMeasurement, setState);
|
|
3987
|
-
return nextMeasurement;
|
|
3988
|
-
}
|
|
3989
|
-
if (session.committed.snapshot.renderText === nextMeasurement.snapshot.renderText) {
|
|
3990
|
-
commitStaticMeasurement(session, reuseCommittedMeasurement(session.committed, nextMeasurement), setState);
|
|
3991
|
-
return nextMeasurement;
|
|
3992
|
-
}
|
|
3993
|
-
startMorph({
|
|
3994
|
-
finalizeMeasurement,
|
|
3995
|
-
nextMeasurement,
|
|
4339
|
+
return reconcileMorphSessionUpdate({
|
|
3996
4340
|
session,
|
|
3997
4341
|
timeline,
|
|
4342
|
+
nextMeasurement,
|
|
4343
|
+
fontsReady: areFontsReady(),
|
|
3998
4344
|
setState
|
|
3999
4345
|
});
|
|
4000
|
-
return nextMeasurement;
|
|
4001
|
-
}
|
|
4002
|
-
function syncCommittedRootOriginWhenIdle({
|
|
4003
|
-
root,
|
|
4004
|
-
flowTextRef,
|
|
4005
|
-
layoutContext,
|
|
4006
|
-
state,
|
|
4007
|
-
session
|
|
4008
|
-
}) {
|
|
4009
|
-
if (root === null || layoutContext === null) {
|
|
4010
|
-
return;
|
|
4011
|
-
}
|
|
4012
|
-
if (state.stage !== "idle" || state.measurement === null) {
|
|
4013
|
-
return;
|
|
4014
|
-
}
|
|
4015
|
-
const nextRootOrigin = readRootOrigin(root);
|
|
4016
|
-
const nextFlowInlineSize = readFlowInlineSize(flowTextRef.current);
|
|
4017
|
-
const committedMeasurement = state.measurement;
|
|
4018
|
-
if (nearlyEqual(committedMeasurement.rootOrigin.left, nextRootOrigin.left) && nearlyEqual(committedMeasurement.rootOrigin.top, nextRootOrigin.top) && (committedMeasurement.flowInlineSize === null && nextFlowInlineSize === null || committedMeasurement.flowInlineSize !== null && nextFlowInlineSize !== null && nearlyEqual(committedMeasurement.flowInlineSize, nextFlowInlineSize))) {
|
|
4019
|
-
session.committed = committedMeasurement;
|
|
4020
|
-
return;
|
|
4021
|
-
}
|
|
4022
|
-
session.committed = {
|
|
4023
|
-
snapshot: committedMeasurement.snapshot,
|
|
4024
|
-
layoutInlineSize: committedMeasurement.layoutInlineSize,
|
|
4025
|
-
reservedInlineSize: committedMeasurement.reservedInlineSize,
|
|
4026
|
-
flowInlineSize: nextFlowInlineSize,
|
|
4027
|
-
rootOrigin: nextRootOrigin
|
|
4028
|
-
};
|
|
4029
|
-
}
|
|
4030
|
-
function getFadeDuration(fraction) {
|
|
4031
|
-
return Math.min(MORPH.durationMs * fraction, MORPH.maxFadeMs);
|
|
4032
|
-
}
|
|
4033
|
-
function getLiveTransform(item, stage, visualBridge) {
|
|
4034
|
-
if (stage !== "prepare") {
|
|
4035
|
-
return "translate(0px, 0px)";
|
|
4036
|
-
}
|
|
4037
|
-
if (item.kind === "move") {
|
|
4038
|
-
return `translate(${(item.fromLeft ?? item.left) - item.left + visualBridge.offsetX}px, ${(item.fromTop ?? item.top) - item.top + visualBridge.offsetY}px)`;
|
|
4039
|
-
}
|
|
4040
|
-
return `translate(${visualBridge.offsetX}px, ${visualBridge.offsetY}px)`;
|
|
4041
4346
|
}
|
|
4042
4347
|
function getLiveOpacity(item, stage) {
|
|
4043
4348
|
if (stage === "prepare" && item.kind === "enter") {
|
|
@@ -4045,96 +4350,14 @@ function getLiveOpacity(item, stage) {
|
|
|
4045
4350
|
}
|
|
4046
4351
|
return 1;
|
|
4047
4352
|
}
|
|
4048
|
-
function getLiveTransition(item, stage) {
|
|
4049
|
-
if (stage !== "animate") {
|
|
4050
|
-
return;
|
|
4051
|
-
}
|
|
4052
|
-
if (item.kind === "enter") {
|
|
4053
|
-
return `opacity ${getFadeDuration(0.5)}ms linear ${getFadeDuration(0.25)}ms`;
|
|
4054
|
-
}
|
|
4055
|
-
return `transform ${MORPH.durationMs}ms ${MORPH.ease}, opacity ${getFadeDuration(0.25)}ms linear`;
|
|
4056
|
-
}
|
|
4057
4353
|
function getExitOpacity(stage) {
|
|
4058
4354
|
if (stage === "animate") {
|
|
4059
4355
|
return 0;
|
|
4060
4356
|
}
|
|
4061
4357
|
return 1;
|
|
4062
4358
|
}
|
|
4063
|
-
function
|
|
4064
|
-
|
|
4065
|
-
}
|
|
4066
|
-
function getExitTransition(stage) {
|
|
4067
|
-
if (stage !== "animate") {
|
|
4068
|
-
return;
|
|
4069
|
-
}
|
|
4070
|
-
return `transform ${MORPH.durationMs}ms ${MORPH.ease}, opacity ${getFadeDuration(0.25)}ms linear`;
|
|
4071
|
-
}
|
|
4072
|
-
function supportsIntrinsicWidthLock(display, parentDisplay) {
|
|
4073
|
-
const parentNeedsReservation = parentDisplay === "flex" || parentDisplay === "inline-flex" || parentDisplay === "grid" || parentDisplay === "inline-grid";
|
|
4074
|
-
return display === "inline" || display === "inline-block" || display === "inline-flex" || display === "inline-grid" || parentNeedsReservation;
|
|
4075
|
-
}
|
|
4076
|
-
function getRootDisplay(layoutContext) {
|
|
4077
|
-
if (layoutContext === null) {
|
|
4078
|
-
return "grid";
|
|
4079
|
-
}
|
|
4080
|
-
if (supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay)) {
|
|
4081
|
-
return "inline-grid";
|
|
4082
|
-
}
|
|
4083
|
-
return "grid";
|
|
4084
|
-
}
|
|
4085
|
-
function getRootStyle(stage, plan, measurement, layoutContext) {
|
|
4086
|
-
let width = measurement?.reservedInlineSize ?? undefined;
|
|
4087
|
-
if (plan !== null) {
|
|
4088
|
-
width = plan.layoutInlineSizeTo;
|
|
4089
|
-
if (stage === "prepare") {
|
|
4090
|
-
width = plan.layoutInlineSizeFrom;
|
|
4091
|
-
}
|
|
4092
|
-
}
|
|
4093
|
-
let height;
|
|
4094
|
-
if (plan !== null) {
|
|
4095
|
-
height = plan.frameHeight;
|
|
4096
|
-
}
|
|
4097
|
-
const shouldTransitionWidth = stage === "animate" && plan !== null && !nearlyEqual(plan.layoutInlineSizeFrom, plan.layoutInlineSizeTo);
|
|
4098
|
-
const style = {
|
|
4099
|
-
position: "relative",
|
|
4100
|
-
display: getRootDisplay(layoutContext)
|
|
4101
|
-
};
|
|
4102
|
-
if (width !== undefined) {
|
|
4103
|
-
style.width = width;
|
|
4104
|
-
}
|
|
4105
|
-
if (height !== undefined) {
|
|
4106
|
-
style.height = height;
|
|
4107
|
-
}
|
|
4108
|
-
if (shouldTransitionWidth) {
|
|
4109
|
-
style.transition = `width ${MORPH.durationMs}ms ${MORPH.ease}`;
|
|
4110
|
-
}
|
|
4111
|
-
return style;
|
|
4112
|
-
}
|
|
4113
|
-
function getMeasurementLayerStyle(layoutContext, useContentInlineSize = false) {
|
|
4114
|
-
const intrinsicWidthLock = layoutContext !== null && (useContentInlineSize || supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay));
|
|
4115
|
-
if (!intrinsicWidthLock) {
|
|
4116
|
-
return MEASUREMENT_LAYER_STYLE;
|
|
4117
|
-
}
|
|
4118
|
-
return {
|
|
4119
|
-
...MEASUREMENT_LAYER_STYLE,
|
|
4120
|
-
right: "auto",
|
|
4121
|
-
width: "max-content"
|
|
4122
|
-
};
|
|
4123
|
-
}
|
|
4124
|
-
function resolveFlowText(committedMeasurement, stateMeasurement, text) {
|
|
4125
|
-
return stateMeasurement?.snapshot.text ?? committedMeasurement?.snapshot.text ?? text;
|
|
4126
|
-
}
|
|
4127
|
-
function getOverlayStyle(plan) {
|
|
4128
|
-
return {
|
|
4129
|
-
...OVERLAY_STYLE,
|
|
4130
|
-
right: "auto",
|
|
4131
|
-
bottom: "auto",
|
|
4132
|
-
width: plan.frameWidth,
|
|
4133
|
-
height: plan.frameHeight
|
|
4134
|
-
};
|
|
4135
|
-
}
|
|
4136
|
-
function getFallbackTextStyle(shouldRenderOverlay) {
|
|
4137
|
-
if (!shouldRenderOverlay) {
|
|
4359
|
+
function getFallbackTextStyle(shouldHideFlowText) {
|
|
4360
|
+
if (!shouldHideFlowText) {
|
|
4138
4361
|
return FALLBACK_TEXT_STYLE;
|
|
4139
4362
|
}
|
|
4140
4363
|
return {
|
|
@@ -4167,18 +4390,136 @@ function getExitGlyphStyle(item, stage, visualBridge) {
|
|
|
4167
4390
|
transition: getExitTransition(stage)
|
|
4168
4391
|
};
|
|
4169
4392
|
}
|
|
4170
|
-
function getContextSliceStyle(layoutInlineSize, item) {
|
|
4393
|
+
function getContextSliceStyle(layoutInlineSize, item, whiteSpace) {
|
|
4394
|
+
return {
|
|
4395
|
+
...CONTEXT_SLICE_TEXT_STYLE,
|
|
4396
|
+
left: -item.left,
|
|
4397
|
+
top: -item.top,
|
|
4398
|
+
width: layoutInlineSize,
|
|
4399
|
+
whiteSpace
|
|
4400
|
+
};
|
|
4401
|
+
}
|
|
4402
|
+
function summarizePreciseRect(rect) {
|
|
4403
|
+
if (rect === null) {
|
|
4404
|
+
return null;
|
|
4405
|
+
}
|
|
4406
|
+
return {
|
|
4407
|
+
left: roundDebugValue(rect.left),
|
|
4408
|
+
top: roundDebugValue(rect.top),
|
|
4409
|
+
width: roundDebugValue(rect.width),
|
|
4410
|
+
height: roundDebugValue(rect.height)
|
|
4411
|
+
};
|
|
4412
|
+
}
|
|
4413
|
+
function summarizePreciseGlyphs(snapshot, rootRect) {
|
|
4414
|
+
if (snapshot === null) {
|
|
4415
|
+
return null;
|
|
4416
|
+
}
|
|
4417
|
+
return snapshot.graphemes.map((grapheme, index) => ({
|
|
4418
|
+
index,
|
|
4419
|
+
glyph: grapheme.glyph,
|
|
4420
|
+
key: grapheme.key,
|
|
4421
|
+
left: roundDebugValue(grapheme.left),
|
|
4422
|
+
top: roundDebugValue(grapheme.top),
|
|
4423
|
+
width: roundDebugValue(grapheme.width),
|
|
4424
|
+
height: roundDebugValue(grapheme.height),
|
|
4425
|
+
viewportLeft: rootRect === null ? null : roundDebugValue(rootRect.left + grapheme.left),
|
|
4426
|
+
viewportTop: rootRect === null ? null : roundDebugValue(rootRect.top + grapheme.top)
|
|
4427
|
+
}));
|
|
4428
|
+
}
|
|
4429
|
+
function summarizeLiveNodeStyles(overlayNode) {
|
|
4430
|
+
if (overlayNode === null) {
|
|
4431
|
+
return null;
|
|
4432
|
+
}
|
|
4433
|
+
return Array.from(overlayNode.querySelectorAll("[data-morph-role='live']")).map((node, index) => {
|
|
4434
|
+
const styles = getComputedStyle(node);
|
|
4435
|
+
const sliceNode = node.firstElementChild;
|
|
4436
|
+
let sliceStyles = null;
|
|
4437
|
+
let sliceRect = null;
|
|
4438
|
+
if (sliceNode instanceof HTMLElement) {
|
|
4439
|
+
sliceStyles = getComputedStyle(sliceNode);
|
|
4440
|
+
sliceRect = sliceNode.getBoundingClientRect();
|
|
4441
|
+
}
|
|
4442
|
+
let nodeRect = null;
|
|
4443
|
+
nodeRect = node.getBoundingClientRect();
|
|
4444
|
+
let sliceScrollWidth = null;
|
|
4445
|
+
let sliceClientWidth = null;
|
|
4446
|
+
let sliceOffsetWidth = null;
|
|
4447
|
+
if (sliceNode instanceof HTMLElement) {
|
|
4448
|
+
sliceScrollWidth = sliceNode.scrollWidth;
|
|
4449
|
+
sliceClientWidth = sliceNode.clientWidth;
|
|
4450
|
+
sliceOffsetWidth = sliceNode.offsetWidth;
|
|
4451
|
+
}
|
|
4452
|
+
return {
|
|
4453
|
+
index,
|
|
4454
|
+
nodeId: getDebugDomNodeId(node),
|
|
4455
|
+
key: node.dataset.morphKey ?? null,
|
|
4456
|
+
glyph: node.dataset.morphGlyph ?? null,
|
|
4457
|
+
kind: node.dataset.morphKind ?? null,
|
|
4458
|
+
transform: styles.transform,
|
|
4459
|
+
inlineTransform: node.style.transform,
|
|
4460
|
+
opacity: styles.opacity,
|
|
4461
|
+
transitionProperty: styles.transitionProperty,
|
|
4462
|
+
transitionDuration: styles.transitionDuration,
|
|
4463
|
+
transitionTimingFunction: styles.transitionTimingFunction,
|
|
4464
|
+
nodeRect: summarizePreciseRect(nodeRect),
|
|
4465
|
+
sliceNodeId: getDebugDomNodeId(sliceNode),
|
|
4466
|
+
sliceInlineLeft: node.firstElementChild instanceof HTMLElement ? node.firstElementChild.style.left : null,
|
|
4467
|
+
sliceInlineTop: node.firstElementChild instanceof HTMLElement ? node.firstElementChild.style.top : null,
|
|
4468
|
+
sliceInlineWidth: node.firstElementChild instanceof HTMLElement ? node.firstElementChild.style.width : null,
|
|
4469
|
+
sliceLeft: sliceStyles?.left ?? null,
|
|
4470
|
+
sliceTop: sliceStyles?.top ?? null,
|
|
4471
|
+
sliceWidth: sliceStyles?.width ?? null,
|
|
4472
|
+
sliceWhiteSpace: sliceStyles?.whiteSpace ?? null,
|
|
4473
|
+
sliceText: sliceNode instanceof HTMLElement ? sliceNode.textContent : null,
|
|
4474
|
+
sliceRect: summarizePreciseRect(sliceRect),
|
|
4475
|
+
sliceScrollWidth: roundDebugValue(sliceScrollWidth),
|
|
4476
|
+
sliceClientWidth: roundDebugValue(sliceClientWidth),
|
|
4477
|
+
sliceOffsetWidth: roundDebugValue(sliceOffsetWidth)
|
|
4478
|
+
};
|
|
4479
|
+
});
|
|
4480
|
+
}
|
|
4481
|
+
function summarizeRootRuntimeStyles(root) {
|
|
4482
|
+
if (root === null) {
|
|
4483
|
+
return null;
|
|
4484
|
+
}
|
|
4485
|
+
const styles = getComputedStyle(root);
|
|
4486
|
+
const parent = root.parentElement;
|
|
4487
|
+
let parentStyles = null;
|
|
4488
|
+
let parentRect = null;
|
|
4489
|
+
if (parent instanceof HTMLElement) {
|
|
4490
|
+
parentStyles = getComputedStyle(parent);
|
|
4491
|
+
parentRect = parent.getBoundingClientRect();
|
|
4492
|
+
}
|
|
4493
|
+
let parentSummary = null;
|
|
4494
|
+
if (parent !== null) {
|
|
4495
|
+
parentSummary = {
|
|
4496
|
+
display: parentStyles?.display ?? null,
|
|
4497
|
+
justifyContent: parentStyles?.justifyContent ?? null,
|
|
4498
|
+
alignItems: parentStyles?.alignItems ?? null,
|
|
4499
|
+
placeItems: parentStyles?.placeItems ?? null,
|
|
4500
|
+
textAlign: parentStyles?.textAlign ?? null,
|
|
4501
|
+
rect: summarizePreciseRect(parentRect)
|
|
4502
|
+
};
|
|
4503
|
+
}
|
|
4171
4504
|
return {
|
|
4172
|
-
|
|
4173
|
-
|
|
4174
|
-
|
|
4175
|
-
|
|
4505
|
+
inlineWidth: root.style.width || null,
|
|
4506
|
+
computedWidth: styles.width,
|
|
4507
|
+
inlineTransition: root.style.transition || null,
|
|
4508
|
+
computedTransitionProperty: styles.transitionProperty,
|
|
4509
|
+
computedTransitionDuration: styles.transitionDuration,
|
|
4510
|
+
computedTransform: styles.transform,
|
|
4511
|
+
offsetWidth: roundDebugValue(root.offsetWidth),
|
|
4512
|
+
clientWidth: roundDebugValue(root.clientWidth),
|
|
4513
|
+
scrollWidth: roundDebugValue(root.scrollWidth),
|
|
4514
|
+
parent: parentSummary
|
|
4176
4515
|
};
|
|
4177
4516
|
}
|
|
4178
4517
|
function MorphOverlay({
|
|
4179
4518
|
overlayRef,
|
|
4180
4519
|
stage,
|
|
4181
|
-
plan
|
|
4520
|
+
plan,
|
|
4521
|
+
sourceSliceWhiteSpace,
|
|
4522
|
+
targetSliceWhiteSpace
|
|
4182
4523
|
}) {
|
|
4183
4524
|
let exitItems = [];
|
|
4184
4525
|
if (stage !== "idle") {
|
|
@@ -4187,7 +4528,7 @@ function MorphOverlay({
|
|
|
4187
4528
|
return /* @__PURE__ */ jsxDEV("div", {
|
|
4188
4529
|
ref: overlayRef,
|
|
4189
4530
|
"aria-hidden": "true",
|
|
4190
|
-
style: getOverlayStyle(plan),
|
|
4531
|
+
style: getOverlayStyle(stage, plan),
|
|
4191
4532
|
children: [
|
|
4192
4533
|
exitItems.map((item) => /* @__PURE__ */ jsxDEV("span", {
|
|
4193
4534
|
"data-morph-role": "exit",
|
|
@@ -4195,7 +4536,8 @@ function MorphOverlay({
|
|
|
4195
4536
|
"data-morph-glyph": item.glyph,
|
|
4196
4537
|
style: getExitGlyphStyle(item, stage, plan.visualBridge),
|
|
4197
4538
|
children: /* @__PURE__ */ jsxDEV("span", {
|
|
4198
|
-
|
|
4539
|
+
"data-morph-slice": "context",
|
|
4540
|
+
style: getContextSliceStyle(plan.layoutInlineSizeFrom, item, sourceSliceWhiteSpace),
|
|
4199
4541
|
children: plan.sourceRenderText
|
|
4200
4542
|
}, undefined, false, undefined, this)
|
|
4201
4543
|
}, `exit-${item.key}`, false, undefined, this)),
|
|
@@ -4203,9 +4545,11 @@ function MorphOverlay({
|
|
|
4203
4545
|
"data-morph-role": "live",
|
|
4204
4546
|
"data-morph-key": item.key,
|
|
4205
4547
|
"data-morph-glyph": item.glyph,
|
|
4548
|
+
"data-morph-kind": item.kind,
|
|
4206
4549
|
style: getLiveGlyphStyle(item, stage, plan.visualBridge),
|
|
4207
4550
|
children: /* @__PURE__ */ jsxDEV("span", {
|
|
4208
|
-
|
|
4551
|
+
"data-morph-slice": "context",
|
|
4552
|
+
style: getContextSliceStyle(plan.layoutInlineSizeTo, item, targetSliceWhiteSpace),
|
|
4209
4553
|
children: plan.targetRenderText
|
|
4210
4554
|
}, undefined, false, undefined, this)
|
|
4211
4555
|
}, item.key, false, undefined, this))
|
|
@@ -4225,54 +4569,92 @@ function MeasurementLayer({
|
|
|
4225
4569
|
children: text
|
|
4226
4570
|
}, undefined, false, undefined, this);
|
|
4227
4571
|
}
|
|
4572
|
+
function isMorphOverlayTransformFinalizeEvent(event, hasMoveTransitions) {
|
|
4573
|
+
if (!hasMoveTransitions) {
|
|
4574
|
+
return false;
|
|
4575
|
+
}
|
|
4576
|
+
const target = event.target;
|
|
4577
|
+
if (!(target instanceof HTMLElement)) {
|
|
4578
|
+
return false;
|
|
4579
|
+
}
|
|
4580
|
+
if (target.dataset.morphRole !== "live") {
|
|
4581
|
+
return false;
|
|
4582
|
+
}
|
|
4583
|
+
return event.propertyName === "transform";
|
|
4584
|
+
}
|
|
4585
|
+
function resolveMorphFinalizeSignal(event, hasMoveTransitions) {
|
|
4586
|
+
if (isMorphOverlayTransformFinalizeEvent(event, hasMoveTransitions)) {
|
|
4587
|
+
return "live-transform";
|
|
4588
|
+
}
|
|
4589
|
+
return null;
|
|
4590
|
+
}
|
|
4228
4591
|
function useMorphTransition(text, className) {
|
|
4229
|
-
const
|
|
4230
|
-
const
|
|
4231
|
-
|
|
4232
|
-
|
|
4233
|
-
const
|
|
4234
|
-
const
|
|
4235
|
-
const
|
|
4236
|
-
const
|
|
4237
|
-
const
|
|
4238
|
-
const
|
|
4239
|
-
const
|
|
4240
|
-
const
|
|
4592
|
+
const [state, setState] = useState2(EMPTY_STATE);
|
|
4593
|
+
const { ref, layoutContext } = useObservedLayoutContext([
|
|
4594
|
+
className
|
|
4595
|
+
]);
|
|
4596
|
+
const debugInstanceIdRef = useRef2(null);
|
|
4597
|
+
const debugRenderOrdinalRef = useRef2(0);
|
|
4598
|
+
const flowTextRef = useRef2(null);
|
|
4599
|
+
const measurementLayerRef = useRef2(null);
|
|
4600
|
+
const completedDomMeasurementKeyRef = useRef2(null);
|
|
4601
|
+
const domMeasurementSnapshotCacheRef = useRef2(new Map);
|
|
4602
|
+
const sessionRef = useRef2({ ...EMPTY_SESSION });
|
|
4603
|
+
const timelineRef = useRef2({ ...EMPTY_TIMELINE });
|
|
4604
|
+
const debugDriftSignatureRef = useRef2(null);
|
|
4605
|
+
const [domMeasurementRequestKey, setDomMeasurementRequestKey] = useState2(null);
|
|
4606
|
+
debugRenderOrdinalRef.current += 1;
|
|
4607
|
+
const debugRenderOrdinal = debugRenderOrdinalRef.current;
|
|
4241
4608
|
if (debugInstanceIdRef.current === null) {
|
|
4242
4609
|
debugInstanceIdRef.current = nextTorphDebugInstanceId();
|
|
4243
4610
|
}
|
|
4244
|
-
|
|
4245
|
-
if (sessionRef.current.animating) {
|
|
4246
|
-
measurementHint = sessionRef.current.target ?? sessionRef.current.committed;
|
|
4247
|
-
}
|
|
4248
|
-
const forceContentInlineSize = forceContentMeasurementText === text;
|
|
4611
|
+
const measurementHint = selectMorphLayoutHint(sessionRef.current);
|
|
4249
4612
|
const measurementRequest = useMemo(() => createMorphMeasurementRequest({
|
|
4250
4613
|
text,
|
|
4251
4614
|
layoutContext,
|
|
4252
|
-
layoutHint: measurementHint
|
|
4253
|
-
|
|
4254
|
-
}), [text, layoutContext, measurementHint, forceContentInlineSize]);
|
|
4615
|
+
layoutHint: measurementHint
|
|
4616
|
+
}), [text, layoutContext, measurementHint]);
|
|
4255
4617
|
const renderText = measurementRequest?.renderText ?? text;
|
|
4256
4618
|
const useContentInlineSize = measurementRequest?.useContentInlineSize ?? false;
|
|
4257
4619
|
const measurementBackend = measurementRequest?.measurementBackend ?? null;
|
|
4258
4620
|
const segments = measurementRequest?.segments ?? EMPTY_SEGMENTS;
|
|
4259
4621
|
const domMeasurementKey = measurementRequest?.domMeasurementKey ?? null;
|
|
4260
|
-
|
|
4622
|
+
const logTransitionTrace = (event, payload = {}) => {
|
|
4261
4623
|
const config = readTorphDebugConfig();
|
|
4262
|
-
if (!
|
|
4624
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
4263
4625
|
return;
|
|
4264
4626
|
}
|
|
4627
|
+
logTorphDebug(debugInstanceIdRef.current, event, {
|
|
4628
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
4629
|
+
renderOrdinal: debugRenderOrdinal,
|
|
4630
|
+
text,
|
|
4631
|
+
renderText,
|
|
4632
|
+
stateStage: state.stage,
|
|
4633
|
+
committed: summarizeDebugMeasurement(sessionRef.current.committed),
|
|
4634
|
+
stateMeasurement: summarizeDebugMeasurement(state.measurement),
|
|
4635
|
+
layoutContext: summarizeDebugLayoutContext(layoutContext),
|
|
4636
|
+
measurementBackend,
|
|
4637
|
+
useContentInlineSize,
|
|
4638
|
+
domMeasurementKey,
|
|
4639
|
+
domMeasurementRequestKey,
|
|
4640
|
+
completedDomMeasurementKey: completedDomMeasurementKeyRef.current,
|
|
4641
|
+
...payload
|
|
4642
|
+
});
|
|
4643
|
+
};
|
|
4644
|
+
useLayoutEffect2(() => {
|
|
4265
4645
|
ensureTorphTraceApi();
|
|
4266
4646
|
}, []);
|
|
4267
|
-
|
|
4268
|
-
const finalizeMeasurement = (measurement) => refineMeasurementFromLiveNodes(measurement, ref.current, flowTextRef.current);
|
|
4647
|
+
useLayoutEffect2(() => {
|
|
4269
4648
|
if (ref.current === null || layoutContext === null) {
|
|
4270
4649
|
completedDomMeasurementKeyRef.current = null;
|
|
4271
4650
|
if (domMeasurementRequestKey !== null) {
|
|
4651
|
+
logTransitionTrace("effect:dom-measurement-request-update", {
|
|
4652
|
+
reason: "clear-missing-root-or-layout",
|
|
4653
|
+
nextDomMeasurementRequestKey: null
|
|
4654
|
+
});
|
|
4272
4655
|
setDomMeasurementRequestKey(null);
|
|
4273
4656
|
}
|
|
4274
4657
|
reconcileMorphChange({
|
|
4275
|
-
finalizeMeasurement,
|
|
4276
4658
|
root: ref.current,
|
|
4277
4659
|
measurementLayer: measurementLayerRef.current,
|
|
4278
4660
|
measurementBackend,
|
|
@@ -4295,10 +4677,14 @@ function useMorphTransition(text, className) {
|
|
|
4295
4677
|
if (cachedSnapshot !== null) {
|
|
4296
4678
|
completedDomMeasurementKeyRef.current = domMeasurementKey;
|
|
4297
4679
|
if (domMeasurementRequestKey !== null) {
|
|
4680
|
+
logTransitionTrace("effect:dom-measurement-request-update", {
|
|
4681
|
+
reason: "clear-after-cache-hit",
|
|
4682
|
+
nextDomMeasurementRequestKey: null,
|
|
4683
|
+
snapshotSource: "cache"
|
|
4684
|
+
});
|
|
4298
4685
|
setDomMeasurementRequestKey(null);
|
|
4299
4686
|
}
|
|
4300
4687
|
reconcileMorphChange({
|
|
4301
|
-
finalizeMeasurement,
|
|
4302
4688
|
root: ref.current,
|
|
4303
4689
|
measurementLayer: null,
|
|
4304
4690
|
measurementBackend,
|
|
@@ -4315,14 +4701,20 @@ function useMorphTransition(text, className) {
|
|
|
4315
4701
|
}
|
|
4316
4702
|
if (completedDomMeasurementKeyRef.current !== domMeasurementKey) {
|
|
4317
4703
|
if (domMeasurementRequestKey !== domMeasurementKey) {
|
|
4704
|
+
logTransitionTrace("effect:dom-measurement-request-update", {
|
|
4705
|
+
reason: "request-measurement-layer",
|
|
4706
|
+
nextDomMeasurementRequestKey: domMeasurementKey
|
|
4707
|
+
});
|
|
4318
4708
|
setDomMeasurementRequestKey(domMeasurementKey);
|
|
4319
4709
|
return;
|
|
4320
4710
|
}
|
|
4321
4711
|
if (measurementLayerRef.current === null) {
|
|
4712
|
+
logTransitionTrace("effect:dom-measurement-await-layer", {
|
|
4713
|
+
reason: "measurement-layer-not-mounted"
|
|
4714
|
+
});
|
|
4322
4715
|
return;
|
|
4323
4716
|
}
|
|
4324
4717
|
const nextMeasurement2 = reconcileMorphChange({
|
|
4325
|
-
finalizeMeasurement,
|
|
4326
4718
|
root: ref.current,
|
|
4327
4719
|
measurementLayer: measurementLayerRef.current,
|
|
4328
4720
|
measurementBackend,
|
|
@@ -4342,21 +4734,33 @@ function useMorphTransition(text, className) {
|
|
|
4342
4734
|
}
|
|
4343
4735
|
completedDomMeasurementKeyRef.current = domMeasurementKey;
|
|
4344
4736
|
if (domMeasurementRequestKey !== null) {
|
|
4737
|
+
logTransitionTrace("effect:dom-measurement-request-update", {
|
|
4738
|
+
reason: "clear-after-live-measurement",
|
|
4739
|
+
nextDomMeasurementRequestKey: null,
|
|
4740
|
+
snapshotSource: "layer"
|
|
4741
|
+
});
|
|
4345
4742
|
setDomMeasurementRequestKey(null);
|
|
4346
4743
|
}
|
|
4347
4744
|
return;
|
|
4348
4745
|
}
|
|
4349
4746
|
if (domMeasurementRequestKey !== null) {
|
|
4747
|
+
logTransitionTrace("effect:dom-measurement-request-update", {
|
|
4748
|
+
reason: "clear-completed-measurement",
|
|
4749
|
+
nextDomMeasurementRequestKey: null
|
|
4750
|
+
});
|
|
4350
4751
|
setDomMeasurementRequestKey(null);
|
|
4351
4752
|
}
|
|
4352
4753
|
return;
|
|
4353
4754
|
}
|
|
4354
4755
|
completedDomMeasurementKeyRef.current = null;
|
|
4355
4756
|
if (domMeasurementRequestKey !== null) {
|
|
4757
|
+
logTransitionTrace("effect:dom-measurement-request-update", {
|
|
4758
|
+
reason: "clear-no-dom-measurement-needed",
|
|
4759
|
+
nextDomMeasurementRequestKey: null
|
|
4760
|
+
});
|
|
4356
4761
|
setDomMeasurementRequestKey(null);
|
|
4357
4762
|
}
|
|
4358
4763
|
const nextMeasurement = reconcileMorphChange({
|
|
4359
|
-
finalizeMeasurement,
|
|
4360
4764
|
root: ref.current,
|
|
4361
4765
|
measurementLayer: measurementLayerRef.current,
|
|
4362
4766
|
measurementBackend,
|
|
@@ -4379,36 +4783,7 @@ function useMorphTransition(text, className) {
|
|
|
4379
4783
|
domMeasurementKey,
|
|
4380
4784
|
domMeasurementRequestKey
|
|
4381
4785
|
]);
|
|
4382
|
-
|
|
4383
|
-
syncCommittedRootOriginWhenIdle({
|
|
4384
|
-
root: ref.current,
|
|
4385
|
-
flowTextRef,
|
|
4386
|
-
layoutContext,
|
|
4387
|
-
state,
|
|
4388
|
-
session: sessionRef.current
|
|
4389
|
-
});
|
|
4390
|
-
}, [layoutContext, state]);
|
|
4391
|
-
useLayoutEffect(() => {
|
|
4392
|
-
if (forceContentMeasurementText !== null && forceContentMeasurementText !== text) {
|
|
4393
|
-
setForceContentMeasurementText(null);
|
|
4394
|
-
return;
|
|
4395
|
-
}
|
|
4396
|
-
if (state.stage !== "idle" || state.measurement === null) {
|
|
4397
|
-
return;
|
|
4398
|
-
}
|
|
4399
|
-
const flowLineCount = readFlowLineCount(flowTextRef.current);
|
|
4400
|
-
const shouldHeal = shouldHealIdleMeasurementFromFlow(state.measurement, flowLineCount);
|
|
4401
|
-
if (shouldHeal) {
|
|
4402
|
-
if (forceContentMeasurementText !== text) {
|
|
4403
|
-
setForceContentMeasurementText(text);
|
|
4404
|
-
}
|
|
4405
|
-
return;
|
|
4406
|
-
}
|
|
4407
|
-
if (forceContentMeasurementText === text) {
|
|
4408
|
-
setForceContentMeasurementText(null);
|
|
4409
|
-
}
|
|
4410
|
-
}, [forceContentMeasurementText, state, text]);
|
|
4411
|
-
useLayoutEffect(() => {
|
|
4786
|
+
useLayoutEffect2(() => {
|
|
4412
4787
|
const config = readTorphDebugConfig();
|
|
4413
4788
|
if (!shouldRunTorphInstrumentation(config)) {
|
|
4414
4789
|
debugDriftSignatureRef.current = null;
|
|
@@ -4451,55 +4826,171 @@ function useMorphTransition(text, className) {
|
|
|
4451
4826
|
drift: summarizeSnapshotDrift(drift)
|
|
4452
4827
|
});
|
|
4453
4828
|
}, [state, text]);
|
|
4454
|
-
|
|
4829
|
+
useLayoutEffect2(() => {
|
|
4455
4830
|
return () => {
|
|
4456
4831
|
cancelTimeline(timelineRef.current);
|
|
4457
4832
|
};
|
|
4458
4833
|
}, []);
|
|
4834
|
+
useLayoutEffect2(() => {
|
|
4835
|
+
if (state.stage !== "prepare" || state.measurement === null || state.plan === null) {
|
|
4836
|
+
return;
|
|
4837
|
+
}
|
|
4838
|
+
const root = ref.current;
|
|
4839
|
+
if (root === null) {
|
|
4840
|
+
return;
|
|
4841
|
+
}
|
|
4842
|
+
const nextOrigin = readRootOrigin(root);
|
|
4843
|
+
const nextMeasurement = resolvePreparedMeasurementOrigin(state.measurement, nextOrigin);
|
|
4844
|
+
const nextPlan = resolvePreparedPlanVisualBridge(state.plan, nextOrigin);
|
|
4845
|
+
if (nextMeasurement !== state.measurement || nextPlan !== state.plan) {
|
|
4846
|
+
sessionRef.current.target = nextMeasurement;
|
|
4847
|
+
logTransitionTrace("effect:prepare-refine", {
|
|
4848
|
+
preparedOrigin: {
|
|
4849
|
+
left: roundDebugValue(nextOrigin.left),
|
|
4850
|
+
top: roundDebugValue(nextOrigin.top)
|
|
4851
|
+
},
|
|
4852
|
+
refinedMeasurement: summarizeDebugMeasurement(nextMeasurement),
|
|
4853
|
+
refinedVisualBridge: {
|
|
4854
|
+
offsetX: roundDebugValue(nextPlan.visualBridge.offsetX),
|
|
4855
|
+
offsetY: roundDebugValue(nextPlan.visualBridge.offsetY)
|
|
4856
|
+
}
|
|
4857
|
+
});
|
|
4858
|
+
setState((current) => {
|
|
4859
|
+
if (current.stage !== "prepare" || current.measurement === null || current.plan === null) {
|
|
4860
|
+
return current;
|
|
4861
|
+
}
|
|
4862
|
+
if (current.measurement === nextMeasurement && current.plan === nextPlan) {
|
|
4863
|
+
return current;
|
|
4864
|
+
}
|
|
4865
|
+
return {
|
|
4866
|
+
stage: "prepare",
|
|
4867
|
+
measurement: nextMeasurement,
|
|
4868
|
+
plan: nextPlan
|
|
4869
|
+
};
|
|
4870
|
+
});
|
|
4871
|
+
return;
|
|
4872
|
+
}
|
|
4873
|
+
timelineRef.current.prepareFrame = requestAnimationFrame(() => {
|
|
4874
|
+
timelineRef.current.prepareFrame = null;
|
|
4875
|
+
timelineRef.current.animateFrame = requestAnimationFrame(() => {
|
|
4876
|
+
timelineRef.current.animateFrame = null;
|
|
4877
|
+
logTransitionTrace("effect:prepare-animate", {
|
|
4878
|
+
preparedOrigin: {
|
|
4879
|
+
left: roundDebugValue(nextOrigin.left),
|
|
4880
|
+
top: roundDebugValue(nextOrigin.top)
|
|
4881
|
+
},
|
|
4882
|
+
visualBridge: {
|
|
4883
|
+
offsetX: roundDebugValue(nextPlan.visualBridge.offsetX),
|
|
4884
|
+
offsetY: roundDebugValue(nextPlan.visualBridge.offsetY)
|
|
4885
|
+
}
|
|
4886
|
+
});
|
|
4887
|
+
setState((current) => {
|
|
4888
|
+
if (current.stage !== "prepare" || current.measurement === null || current.plan === null) {
|
|
4889
|
+
return current;
|
|
4890
|
+
}
|
|
4891
|
+
return {
|
|
4892
|
+
stage: "animate",
|
|
4893
|
+
measurement: current.measurement,
|
|
4894
|
+
plan: current.plan
|
|
4895
|
+
};
|
|
4896
|
+
});
|
|
4897
|
+
});
|
|
4898
|
+
});
|
|
4899
|
+
return () => {
|
|
4900
|
+
if (timelineRef.current.prepareFrame !== null) {
|
|
4901
|
+
cancelAnimationFrame(timelineRef.current.prepareFrame);
|
|
4902
|
+
timelineRef.current.prepareFrame = null;
|
|
4903
|
+
}
|
|
4904
|
+
if (timelineRef.current.animateFrame !== null) {
|
|
4905
|
+
cancelAnimationFrame(timelineRef.current.animateFrame);
|
|
4906
|
+
timelineRef.current.animateFrame = null;
|
|
4907
|
+
}
|
|
4908
|
+
};
|
|
4909
|
+
}, [state.measurement, state.plan, state.stage]);
|
|
4910
|
+
const finalizeMorphTransition2 = (measurement, reason) => {
|
|
4911
|
+
logTransitionTrace("effect:finalize-trigger", {
|
|
4912
|
+
reason,
|
|
4913
|
+
measurement: summarizeDebugMeasurement(measurement)
|
|
4914
|
+
});
|
|
4915
|
+
finalizeMorphTransition({
|
|
4916
|
+
session: sessionRef.current,
|
|
4917
|
+
timeline: timelineRef.current,
|
|
4918
|
+
measurement,
|
|
4919
|
+
setState
|
|
4920
|
+
});
|
|
4921
|
+
};
|
|
4459
4922
|
return {
|
|
4460
4923
|
debugInstanceId: debugInstanceIdRef.current,
|
|
4924
|
+
debugRenderOrdinal,
|
|
4461
4925
|
committedMeasurement: sessionRef.current.committed,
|
|
4462
4926
|
domMeasurementRequestKey,
|
|
4463
4927
|
flowTextRef,
|
|
4464
4928
|
ref,
|
|
4465
4929
|
measurementLayerRef,
|
|
4930
|
+
measurementBackend,
|
|
4931
|
+
domMeasurementKey,
|
|
4466
4932
|
renderText,
|
|
4467
4933
|
segments,
|
|
4468
4934
|
layoutContext,
|
|
4469
4935
|
state,
|
|
4470
|
-
useContentInlineSize
|
|
4936
|
+
useContentInlineSize,
|
|
4937
|
+
finalizeMorphTransition: finalizeMorphTransition2,
|
|
4938
|
+
timelineRef
|
|
4471
4939
|
};
|
|
4472
4940
|
}
|
|
4473
4941
|
function ActiveTorph({
|
|
4474
4942
|
text,
|
|
4475
4943
|
className
|
|
4476
4944
|
}) {
|
|
4477
|
-
const
|
|
4478
|
-
const
|
|
4479
|
-
const
|
|
4480
|
-
const
|
|
4481
|
-
const
|
|
4482
|
-
const
|
|
4483
|
-
const
|
|
4484
|
-
const
|
|
4945
|
+
const debugRenderOrdinalRef = useRef2(0);
|
|
4946
|
+
const overlayRef = useRef2(null);
|
|
4947
|
+
const debugFinalizeSignatureRef = useRef2(null);
|
|
4948
|
+
const debugFrameHandleRef = useRef2(null);
|
|
4949
|
+
const debugFrameOrdinalRef = useRef2(0);
|
|
4950
|
+
const debugAnimateTailFramesRef = useRef2([]);
|
|
4951
|
+
const debugIdlePostFrameHandleRef = useRef2(null);
|
|
4952
|
+
const debugIdlePostFrameOrdinalRef = useRef2(0);
|
|
4953
|
+
const debugIdlePostFrameTokenRef = useRef2(0);
|
|
4954
|
+
const debugPendingIdlePostFramesRef = useRef2(false);
|
|
4955
|
+
const debugPreviousStageRef = useRef2(null);
|
|
4956
|
+
debugRenderOrdinalRef.current += 1;
|
|
4957
|
+
const debugRenderOrdinal = debugRenderOrdinalRef.current;
|
|
4485
4958
|
const {
|
|
4486
4959
|
debugInstanceId,
|
|
4960
|
+
debugRenderOrdinal: hookRenderOrdinal,
|
|
4487
4961
|
committedMeasurement,
|
|
4488
4962
|
domMeasurementRequestKey,
|
|
4963
|
+
domMeasurementKey,
|
|
4489
4964
|
flowTextRef,
|
|
4490
4965
|
ref,
|
|
4491
4966
|
measurementLayerRef,
|
|
4967
|
+
measurementBackend,
|
|
4492
4968
|
renderText,
|
|
4493
4969
|
segments,
|
|
4494
4970
|
layoutContext,
|
|
4495
4971
|
state,
|
|
4496
|
-
useContentInlineSize
|
|
4972
|
+
useContentInlineSize,
|
|
4973
|
+
finalizeMorphTransition: finalizeMorphTransition2,
|
|
4974
|
+
timelineRef
|
|
4497
4975
|
} = useMorphTransition(text, className);
|
|
4498
4976
|
const plan = state.plan;
|
|
4499
|
-
|
|
4977
|
+
let visibleGlyphPlan = plan;
|
|
4978
|
+
if (state.stage === "idle" && state.measurement !== null) {
|
|
4979
|
+
visibleGlyphPlan = createSteadyGlyphPlan(state.measurement);
|
|
4980
|
+
}
|
|
4981
|
+
let sourceSliceWhiteSpace = "inherit";
|
|
4982
|
+
if (committedMeasurement !== null) {
|
|
4983
|
+
sourceSliceWhiteSpace = resolveGlyphSliceWhiteSpace(committedMeasurement.snapshot);
|
|
4984
|
+
}
|
|
4985
|
+
let targetSliceWhiteSpace = "inherit";
|
|
4986
|
+
if (state.measurement !== null) {
|
|
4987
|
+
targetSliceWhiteSpace = resolveGlyphSliceWhiteSpace(state.measurement.snapshot);
|
|
4988
|
+
}
|
|
4989
|
+
const shouldRenderGlyphLayer2 = shouldRenderGlyphLayer(state.stage, visibleGlyphPlan, state.measurement);
|
|
4990
|
+
const shouldHideFlowText = shouldRenderGlyphLayer2;
|
|
4500
4991
|
const shouldRenderMeasurementLayer = domMeasurementRequestKey !== null;
|
|
4501
4992
|
const flowText = resolveFlowText(committedMeasurement, state.measurement, text);
|
|
4502
|
-
|
|
4993
|
+
useLayoutEffect2(() => {
|
|
4503
4994
|
const config = readTorphDebugConfig();
|
|
4504
4995
|
if (!shouldRunTorphInstrumentation(config)) {
|
|
4505
4996
|
return;
|
|
@@ -4507,11 +4998,264 @@ function ActiveTorph({
|
|
|
4507
4998
|
logTorphDebug(debugInstanceId, "effect:trace-meta", {
|
|
4508
4999
|
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
4509
5000
|
includesIdlePostFrame: true,
|
|
5001
|
+
includesIdlePostFrameLifecycle: true,
|
|
4510
5002
|
includesViewportAnchors: true,
|
|
4511
|
-
includesRootOriginRefine: true
|
|
5003
|
+
includesRootOriginRefine: true,
|
|
5004
|
+
includesFullGlyphLayouts: true,
|
|
5005
|
+
includesIdleVisibleGlyphLayer: true,
|
|
5006
|
+
includesPreciseGlyphGeometry: true,
|
|
5007
|
+
includesAnimateTailFrames: true,
|
|
5008
|
+
includesLiveNodeStyles: true
|
|
4512
5009
|
});
|
|
4513
5010
|
}, [debugInstanceId]);
|
|
4514
|
-
|
|
5011
|
+
useLayoutEffect2(() => {
|
|
5012
|
+
const config = readTorphDebugConfig();
|
|
5013
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
5014
|
+
debugFinalizeSignatureRef.current = null;
|
|
5015
|
+
return;
|
|
5016
|
+
}
|
|
5017
|
+
if (state.stage !== "animate" || state.measurement === null || plan === null) {
|
|
5018
|
+
debugFinalizeSignatureRef.current = null;
|
|
5019
|
+
}
|
|
5020
|
+
}, [plan, state.measurement, state.stage]);
|
|
5021
|
+
const logAnimateFinalizeSnapshot = (measurement, activePlan, reason, barrier, signal, event) => {
|
|
5022
|
+
const config = readTorphDebugConfig();
|
|
5023
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
5024
|
+
return;
|
|
5025
|
+
}
|
|
5026
|
+
const root = ref.current;
|
|
5027
|
+
const overlayNode = overlayRef.current;
|
|
5028
|
+
const flowNode = flowTextRef.current;
|
|
5029
|
+
if (root === null || overlayNode === null || flowNode === null) {
|
|
5030
|
+
return;
|
|
5031
|
+
}
|
|
5032
|
+
const overlayLiveSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "live");
|
|
5033
|
+
const overlayExitSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "exit");
|
|
5034
|
+
const flowSnapshot = measureLiveFlowSnapshot(root, flowNode);
|
|
5035
|
+
if (overlayLiveSnapshot === null || flowSnapshot === null) {
|
|
5036
|
+
return;
|
|
5037
|
+
}
|
|
5038
|
+
const overlayLiveDrift = measureSnapshotDrift(measurement.snapshot, overlayLiveSnapshot);
|
|
5039
|
+
const flowDrift = measureSnapshotDrift(measurement.snapshot, flowSnapshot);
|
|
5040
|
+
const rootRect = root.getBoundingClientRect();
|
|
5041
|
+
const flowRect = flowNode.getBoundingClientRect();
|
|
5042
|
+
const overlayRect = overlayNode.getBoundingClientRect();
|
|
5043
|
+
const signature = JSON.stringify({
|
|
5044
|
+
text,
|
|
5045
|
+
renderText: measurement.snapshot.renderText,
|
|
5046
|
+
reason,
|
|
5047
|
+
signal,
|
|
5048
|
+
barrier: summarizeMorphFinalizeBarrier(barrier),
|
|
5049
|
+
overlayLiveDrift: summarizeSnapshotDrift(overlayLiveDrift),
|
|
5050
|
+
flowDrift: summarizeSnapshotDrift(flowDrift),
|
|
5051
|
+
overlayWidth: roundDebugValue(overlayRect.width),
|
|
5052
|
+
rootWidth: roundDebugValue(rootRect.width)
|
|
5053
|
+
});
|
|
5054
|
+
if (debugFinalizeSignatureRef.current === signature) {
|
|
5055
|
+
return;
|
|
5056
|
+
}
|
|
5057
|
+
debugFinalizeSignatureRef.current = signature;
|
|
5058
|
+
let morphRole = null;
|
|
5059
|
+
let morphKey = null;
|
|
5060
|
+
let morphGlyph = null;
|
|
5061
|
+
const target = event?.target;
|
|
5062
|
+
if (target instanceof HTMLElement) {
|
|
5063
|
+
morphRole = target.dataset.morphRole ?? null;
|
|
5064
|
+
morphKey = target.dataset.morphKey ?? null;
|
|
5065
|
+
morphGlyph = target.dataset.morphGlyph ?? null;
|
|
5066
|
+
}
|
|
5067
|
+
logTorphDebug(debugInstanceId, "effect:animate-finalize-snapshot", {
|
|
5068
|
+
text,
|
|
5069
|
+
reason,
|
|
5070
|
+
propertyName: event?.propertyName ?? null,
|
|
5071
|
+
finalizeSignal: signal,
|
|
5072
|
+
morphRole,
|
|
5073
|
+
morphKey,
|
|
5074
|
+
morphGlyph,
|
|
5075
|
+
barrier: summarizeMorphFinalizeBarrier(barrier),
|
|
5076
|
+
target: {
|
|
5077
|
+
layoutInlineSize: roundDebugValue(measurement.layoutInlineSize),
|
|
5078
|
+
reservedInlineSize: roundDebugValue(measurement.reservedInlineSize),
|
|
5079
|
+
flowInlineSize: roundDebugValue(measurement.flowInlineSize),
|
|
5080
|
+
rootOrigin: {
|
|
5081
|
+
left: roundDebugValue(measurement.rootOrigin.left),
|
|
5082
|
+
top: roundDebugValue(measurement.rootOrigin.top)
|
|
5083
|
+
},
|
|
5084
|
+
snapshot: summarizeDebugSnapshot(measurement.snapshot)
|
|
5085
|
+
},
|
|
5086
|
+
plan: {
|
|
5087
|
+
frameWidth: roundDebugValue(activePlan.frameWidth),
|
|
5088
|
+
frameHeight: roundDebugValue(activePlan.frameHeight),
|
|
5089
|
+
layoutInlineSizeFrom: roundDebugValue(activePlan.layoutInlineSizeFrom),
|
|
5090
|
+
layoutInlineSizeTo: roundDebugValue(activePlan.layoutInlineSizeTo),
|
|
5091
|
+
sourceRenderText: activePlan.sourceRenderText,
|
|
5092
|
+
targetRenderText: activePlan.targetRenderText
|
|
5093
|
+
},
|
|
5094
|
+
overlayLive: summarizeDebugSnapshot(overlayLiveSnapshot),
|
|
5095
|
+
overlayLiveGlyphs: summarizeDebugGlyphs(overlayLiveSnapshot),
|
|
5096
|
+
overlayLiveGlyphsPrecise: summarizePreciseGlyphs(overlayLiveSnapshot, rootRect),
|
|
5097
|
+
overlayLiveDrift: summarizeSnapshotDrift(overlayLiveDrift),
|
|
5098
|
+
overlayExit: summarizeDebugSnapshot(overlayExitSnapshot),
|
|
5099
|
+
overlayExitGlyphs: summarizeDebugGlyphs(overlayExitSnapshot),
|
|
5100
|
+
flow: summarizeDebugSnapshot(flowSnapshot),
|
|
5101
|
+
flowGlyphs: summarizeDebugGlyphs(flowSnapshot),
|
|
5102
|
+
flowGlyphsPrecise: summarizePreciseGlyphs(flowSnapshot, rootRect),
|
|
5103
|
+
flowDrift: summarizeSnapshotDrift(flowDrift),
|
|
5104
|
+
rootOriginDrift: summarizeDebugRootOriginDrift(measurement, rootRect),
|
|
5105
|
+
overlayLiveViewportAnchors: summarizeDebugViewportAnchors(overlayLiveSnapshot, rootRect),
|
|
5106
|
+
overlayExitViewportAnchors: summarizeDebugViewportAnchors(overlayExitSnapshot, rootRect),
|
|
5107
|
+
flowViewportAnchors: summarizeDebugViewportAnchors(flowSnapshot, rootRect),
|
|
5108
|
+
rootBox: {
|
|
5109
|
+
width: roundDebugValue(rootRect.width),
|
|
5110
|
+
height: roundDebugValue(rootRect.height)
|
|
5111
|
+
},
|
|
5112
|
+
overlayBox: {
|
|
5113
|
+
width: roundDebugValue(overlayRect.width),
|
|
5114
|
+
height: roundDebugValue(overlayRect.height)
|
|
5115
|
+
},
|
|
5116
|
+
flowBox: {
|
|
5117
|
+
width: roundDebugValue(flowRect.width),
|
|
5118
|
+
height: roundDebugValue(flowRect.height)
|
|
5119
|
+
},
|
|
5120
|
+
rootBoxPrecise: summarizePreciseRect(rootRect),
|
|
5121
|
+
overlayBoxPrecise: summarizePreciseRect(overlayRect),
|
|
5122
|
+
flowBoxPrecise: summarizePreciseRect(flowRect),
|
|
5123
|
+
rootRuntimeStyles: summarizeRootRuntimeStyles(root),
|
|
5124
|
+
overlayLiveNodeStyles: summarizeLiveNodeStyles(overlayNode),
|
|
5125
|
+
animateTailFrames: debugAnimateTailFramesRef.current
|
|
5126
|
+
});
|
|
5127
|
+
debugAnimateTailFramesRef.current = [];
|
|
5128
|
+
};
|
|
5129
|
+
useLayoutEffect2(() => {
|
|
5130
|
+
if (state.stage !== "animate" || state.measurement === null || plan === null) {
|
|
5131
|
+
return;
|
|
5132
|
+
}
|
|
5133
|
+
const root = ref.current;
|
|
5134
|
+
if (root === null) {
|
|
5135
|
+
return;
|
|
5136
|
+
}
|
|
5137
|
+
const measurement = state.measurement;
|
|
5138
|
+
const hasMoveTransitions = plan.liveItems.some((item) => item.kind === "move");
|
|
5139
|
+
let barrier = createMorphFinalizeBarrier(hasMoveTransitions);
|
|
5140
|
+
let finalizeScheduled = false;
|
|
5141
|
+
let finalizeCommitted = false;
|
|
5142
|
+
let finalizeFrame = null;
|
|
5143
|
+
const armedAt = performance.now();
|
|
5144
|
+
const finalizeNow = (reason, signal, barrierState, event) => {
|
|
5145
|
+
if (finalizeCommitted) {
|
|
5146
|
+
return;
|
|
5147
|
+
}
|
|
5148
|
+
finalizeCommitted = true;
|
|
5149
|
+
const target = event?.target;
|
|
5150
|
+
let morphRole = null;
|
|
5151
|
+
let morphKey = null;
|
|
5152
|
+
let morphGlyph = null;
|
|
5153
|
+
if (target instanceof HTMLElement) {
|
|
5154
|
+
morphRole = target.dataset.morphRole ?? null;
|
|
5155
|
+
morphKey = target.dataset.morphKey ?? null;
|
|
5156
|
+
morphGlyph = target.dataset.morphGlyph ?? null;
|
|
5157
|
+
}
|
|
5158
|
+
logAnimateFinalizeSnapshot(measurement, plan, reason, barrierState, signal, event);
|
|
5159
|
+
finalizeMorphTransition2(measurement, reason);
|
|
5160
|
+
const config = readTorphDebugConfig();
|
|
5161
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
5162
|
+
return;
|
|
5163
|
+
}
|
|
5164
|
+
logTorphDebug(debugInstanceId, "effect:finalize-authority", {
|
|
5165
|
+
text,
|
|
5166
|
+
reason,
|
|
5167
|
+
propertyName: event?.propertyName ?? null,
|
|
5168
|
+
morphRole,
|
|
5169
|
+
morphKey,
|
|
5170
|
+
morphGlyph,
|
|
5171
|
+
elapsedMs: roundDebugValue(performance.now() - armedAt),
|
|
5172
|
+
hasMoveTransitions,
|
|
5173
|
+
finalizeSignal: signal,
|
|
5174
|
+
barrier: summarizeMorphFinalizeBarrier(barrierState),
|
|
5175
|
+
measurement: summarizeDebugMeasurement(measurement)
|
|
5176
|
+
});
|
|
5177
|
+
};
|
|
5178
|
+
const scheduleFinalize = (reason, signal, barrierState, event) => {
|
|
5179
|
+
if (finalizeCommitted || finalizeScheduled) {
|
|
5180
|
+
return;
|
|
5181
|
+
}
|
|
5182
|
+
finalizeScheduled = true;
|
|
5183
|
+
if (timelineRef.current.finalizeTimer !== null) {
|
|
5184
|
+
window.clearTimeout(timelineRef.current.finalizeTimer);
|
|
5185
|
+
timelineRef.current.finalizeTimer = null;
|
|
5186
|
+
}
|
|
5187
|
+
logTorphDebug(debugInstanceId, "effect:finalize-raf-schedule", {
|
|
5188
|
+
text,
|
|
5189
|
+
reason,
|
|
5190
|
+
propertyName: event?.propertyName ?? null,
|
|
5191
|
+
finalizeSignal: signal,
|
|
5192
|
+
elapsedMs: roundDebugValue(performance.now() - armedAt),
|
|
5193
|
+
barrier: summarizeMorphFinalizeBarrier(barrierState)
|
|
5194
|
+
});
|
|
5195
|
+
finalizeFrame = requestAnimationFrame(() => {
|
|
5196
|
+
finalizeFrame = null;
|
|
5197
|
+
finalizeNow(reason, signal, barrierState, event);
|
|
5198
|
+
});
|
|
5199
|
+
};
|
|
5200
|
+
const onTransitionEnd = (event) => {
|
|
5201
|
+
const signal = resolveMorphFinalizeSignal(event, hasMoveTransitions);
|
|
5202
|
+
if (signal === null) {
|
|
5203
|
+
return;
|
|
5204
|
+
}
|
|
5205
|
+
barrier = recordMorphFinalizeSignal(barrier, signal);
|
|
5206
|
+
const target = event.target;
|
|
5207
|
+
let morphRole = null;
|
|
5208
|
+
let morphKey = null;
|
|
5209
|
+
let morphGlyph = null;
|
|
5210
|
+
if (target instanceof HTMLElement) {
|
|
5211
|
+
morphRole = target.dataset.morphRole ?? null;
|
|
5212
|
+
morphKey = target.dataset.morphKey ?? null;
|
|
5213
|
+
morphGlyph = target.dataset.morphGlyph ?? null;
|
|
5214
|
+
}
|
|
5215
|
+
logTorphDebug(debugInstanceId, "effect:finalize-barrier-progress", {
|
|
5216
|
+
text,
|
|
5217
|
+
propertyName: event.propertyName,
|
|
5218
|
+
signal,
|
|
5219
|
+
morphRole,
|
|
5220
|
+
morphKey,
|
|
5221
|
+
morphGlyph,
|
|
5222
|
+
elapsedMs: roundDebugValue(performance.now() - armedAt),
|
|
5223
|
+
barrier: summarizeMorphFinalizeBarrier(barrier)
|
|
5224
|
+
});
|
|
5225
|
+
if (!isMorphFinalizeBarrierSatisfied(barrier)) {
|
|
5226
|
+
return;
|
|
5227
|
+
}
|
|
5228
|
+
scheduleFinalize("transitionend", signal, barrier, event);
|
|
5229
|
+
};
|
|
5230
|
+
root.addEventListener("transitionend", onTransitionEnd);
|
|
5231
|
+
if (timelineRef.current.finalizeTimer !== null) {
|
|
5232
|
+
window.clearTimeout(timelineRef.current.finalizeTimer);
|
|
5233
|
+
}
|
|
5234
|
+
timelineRef.current.finalizeTimer = window.setTimeout(() => {
|
|
5235
|
+
timelineRef.current.finalizeTimer = null;
|
|
5236
|
+
scheduleFinalize("watchdog-timeout", null, barrier);
|
|
5237
|
+
}, MORPH.durationMs + 32);
|
|
5238
|
+
return () => {
|
|
5239
|
+
root.removeEventListener("transitionend", onTransitionEnd);
|
|
5240
|
+
if (finalizeFrame !== null) {
|
|
5241
|
+
cancelAnimationFrame(finalizeFrame);
|
|
5242
|
+
finalizeFrame = null;
|
|
5243
|
+
}
|
|
5244
|
+
if (timelineRef.current.finalizeTimer !== null) {
|
|
5245
|
+
window.clearTimeout(timelineRef.current.finalizeTimer);
|
|
5246
|
+
timelineRef.current.finalizeTimer = null;
|
|
5247
|
+
}
|
|
5248
|
+
};
|
|
5249
|
+
}, [
|
|
5250
|
+
debugInstanceId,
|
|
5251
|
+
finalizeMorphTransition2,
|
|
5252
|
+
plan,
|
|
5253
|
+
state.measurement,
|
|
5254
|
+
state.stage,
|
|
5255
|
+
text,
|
|
5256
|
+
timelineRef
|
|
5257
|
+
]);
|
|
5258
|
+
useLayoutEffect2(() => {
|
|
4515
5259
|
const config = readTorphDebugConfig();
|
|
4516
5260
|
if (!shouldRunTorphInstrumentation(config)) {
|
|
4517
5261
|
debugPendingIdlePostFramesRef.current = false;
|
|
@@ -4522,25 +5266,34 @@ function ActiveTorph({
|
|
|
4522
5266
|
if (previousStage !== state.stage) {
|
|
4523
5267
|
if (state.stage === "idle") {
|
|
4524
5268
|
debugPendingIdlePostFramesRef.current = true;
|
|
5269
|
+
debugIdlePostFrameTokenRef.current += 1;
|
|
5270
|
+
} else {
|
|
5271
|
+
debugPendingIdlePostFramesRef.current = false;
|
|
4525
5272
|
}
|
|
4526
5273
|
logTorphDebug(debugInstanceId, "effect:stage-transition", {
|
|
5274
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5275
|
+
renderOrdinal: debugRenderOrdinal,
|
|
4527
5276
|
text,
|
|
4528
5277
|
fromStage: previousStage,
|
|
4529
5278
|
toStage: state.stage,
|
|
4530
5279
|
committed: summarizeDebugMeasurement(committedMeasurement),
|
|
4531
5280
|
stateMeasurement: summarizeDebugMeasurement(state.measurement),
|
|
4532
|
-
flowText
|
|
5281
|
+
flowText,
|
|
5282
|
+
domMeasurementRequestKey,
|
|
5283
|
+
domMeasurementKey,
|
|
5284
|
+
measurementBackend
|
|
4533
5285
|
});
|
|
4534
5286
|
debugPreviousStageRef.current = state.stage;
|
|
4535
5287
|
}
|
|
4536
5288
|
}, [committedMeasurement, debugInstanceId, flowText, state, text]);
|
|
4537
|
-
|
|
5289
|
+
useLayoutEffect2(() => {
|
|
4538
5290
|
const config = readTorphDebugConfig();
|
|
4539
5291
|
if (!shouldRunTorphInstrumentation(config)) {
|
|
4540
5292
|
if (debugFrameHandleRef.current !== null) {
|
|
4541
5293
|
cancelAnimationFrame(debugFrameHandleRef.current);
|
|
4542
5294
|
debugFrameHandleRef.current = null;
|
|
4543
5295
|
}
|
|
5296
|
+
debugAnimateTailFramesRef.current = [];
|
|
4544
5297
|
return;
|
|
4545
5298
|
}
|
|
4546
5299
|
if (state.stage === "idle" || state.measurement === null) {
|
|
@@ -4549,6 +5302,7 @@ function ActiveTorph({
|
|
|
4549
5302
|
debugFrameHandleRef.current = null;
|
|
4550
5303
|
}
|
|
4551
5304
|
debugFrameOrdinalRef.current = 0;
|
|
5305
|
+
debugAnimateTailFramesRef.current = [];
|
|
4552
5306
|
return;
|
|
4553
5307
|
}
|
|
4554
5308
|
debugFrameOrdinalRef.current = 0;
|
|
@@ -4593,6 +5347,19 @@ function ActiveTorph({
|
|
|
4593
5347
|
if (flowSnapshot !== null) {
|
|
4594
5348
|
flowDrift = summarizeSnapshotDrift(measureSnapshotDrift(measurement.snapshot, flowSnapshot));
|
|
4595
5349
|
}
|
|
5350
|
+
debugAnimateTailFramesRef.current.push({
|
|
5351
|
+
frame: debugFrameOrdinalRef.current,
|
|
5352
|
+
stateStage: state.stage,
|
|
5353
|
+
rootBoxPrecise: summarizePreciseRect(rootRect),
|
|
5354
|
+
overlayBoxPrecise: summarizePreciseRect(overlayRect),
|
|
5355
|
+
flowBoxPrecise: summarizePreciseRect(flowRect),
|
|
5356
|
+
overlayLiveGlyphsPrecise: summarizePreciseGlyphs(overlayLiveSnapshot, rootRect),
|
|
5357
|
+
flowGlyphsPrecise: summarizePreciseGlyphs(flowSnapshot, rootRect),
|
|
5358
|
+
overlayLiveNodeStyles: summarizeLiveNodeStyles(overlayNode)
|
|
5359
|
+
});
|
|
5360
|
+
if (debugAnimateTailFramesRef.current.length > 8) {
|
|
5361
|
+
debugAnimateTailFramesRef.current.shift();
|
|
5362
|
+
}
|
|
4596
5363
|
let planSummary = null;
|
|
4597
5364
|
if (plan !== null) {
|
|
4598
5365
|
planSummary = {
|
|
@@ -4624,13 +5391,17 @@ function ActiveTorph({
|
|
|
4624
5391
|
flowBox: summarizeDebugRect(flowRect),
|
|
4625
5392
|
rootOriginDrift: summarizeDebugRootOriginDrift(measurement, rootRect),
|
|
4626
5393
|
overlayLive: summarizeDebugSnapshot(overlayLiveSnapshot),
|
|
5394
|
+
overlayLiveGlyphs: summarizeDebugGlyphs(overlayLiveSnapshot),
|
|
4627
5395
|
overlayLiveViewportAnchors: summarizeDebugViewportAnchors(overlayLiveSnapshot, rootRect),
|
|
4628
5396
|
overlayLiveDrift,
|
|
4629
5397
|
overlayExit: summarizeDebugSnapshot(overlayExitSnapshot),
|
|
5398
|
+
overlayExitGlyphs: summarizeDebugGlyphs(overlayExitSnapshot),
|
|
4630
5399
|
overlayExitViewportAnchors: summarizeDebugViewportAnchors(overlayExitSnapshot, rootRect),
|
|
4631
5400
|
flow: summarizeDebugSnapshot(flowSnapshot),
|
|
5401
|
+
flowGlyphs: summarizeDebugGlyphs(flowSnapshot),
|
|
4632
5402
|
flowViewportAnchors: summarizeDebugViewportAnchors(flowSnapshot, rootRect),
|
|
4633
|
-
flowDrift
|
|
5403
|
+
flowDrift,
|
|
5404
|
+
rootRuntimeStyles: summarizeRootRuntimeStyles(root)
|
|
4634
5405
|
});
|
|
4635
5406
|
debugFrameOrdinalRef.current += 1;
|
|
4636
5407
|
debugFrameHandleRef.current = requestAnimationFrame(captureFrame);
|
|
@@ -4644,11 +5415,22 @@ function ActiveTorph({
|
|
|
4644
5415
|
}
|
|
4645
5416
|
};
|
|
4646
5417
|
}, [committedMeasurement, debugInstanceId, flowText, plan, ref, state, text]);
|
|
4647
|
-
|
|
5418
|
+
useLayoutEffect2(() => {
|
|
4648
5419
|
const config = readTorphDebugConfig();
|
|
4649
5420
|
if (!shouldRunTorphInstrumentation(config)) {
|
|
4650
5421
|
debugPendingIdlePostFramesRef.current = false;
|
|
4651
5422
|
if (debugIdlePostFrameHandleRef.current !== null) {
|
|
5423
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame-cleanup", {
|
|
5424
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5425
|
+
reason: "instrumentation-disabled",
|
|
5426
|
+
renderOrdinal: debugRenderOrdinal,
|
|
5427
|
+
hookRenderOrdinal,
|
|
5428
|
+
token: debugIdlePostFrameTokenRef.current,
|
|
5429
|
+
handle: debugIdlePostFrameHandleRef.current,
|
|
5430
|
+
domMeasurementRequestKey,
|
|
5431
|
+
domMeasurementKey,
|
|
5432
|
+
measurementBackend
|
|
5433
|
+
});
|
|
4652
5434
|
cancelAnimationFrame(debugIdlePostFrameHandleRef.current);
|
|
4653
5435
|
debugIdlePostFrameHandleRef.current = null;
|
|
4654
5436
|
}
|
|
@@ -4660,28 +5442,93 @@ function ActiveTorph({
|
|
|
4660
5442
|
if (state.stage !== "idle" || state.measurement === null) {
|
|
4661
5443
|
return;
|
|
4662
5444
|
}
|
|
4663
|
-
debugPendingIdlePostFramesRef.current = false;
|
|
4664
5445
|
debugIdlePostFrameOrdinalRef.current = 0;
|
|
5446
|
+
const token = debugIdlePostFrameTokenRef.current;
|
|
5447
|
+
const scheduledRenderOrdinal = debugRenderOrdinal;
|
|
5448
|
+
const scheduledHookRenderOrdinal = hookRenderOrdinal;
|
|
4665
5449
|
const measurement = state.measurement;
|
|
4666
5450
|
let remainingFrames = 3;
|
|
4667
5451
|
let cancelled = false;
|
|
5452
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame-arm", {
|
|
5453
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5454
|
+
renderOrdinal: scheduledRenderOrdinal,
|
|
5455
|
+
hookRenderOrdinal: scheduledHookRenderOrdinal,
|
|
5456
|
+
token,
|
|
5457
|
+
text,
|
|
5458
|
+
stateStage: state.stage,
|
|
5459
|
+
flowText,
|
|
5460
|
+
committed: summarizeDebugMeasurement(committedMeasurement),
|
|
5461
|
+
stateMeasurement: summarizeDebugMeasurement(measurement),
|
|
5462
|
+
domMeasurementRequestKey,
|
|
5463
|
+
domMeasurementKey,
|
|
5464
|
+
measurementBackend
|
|
5465
|
+
});
|
|
4668
5466
|
const captureIdlePostFrame = () => {
|
|
4669
5467
|
if (cancelled) {
|
|
4670
5468
|
return;
|
|
4671
5469
|
}
|
|
5470
|
+
if (debugPendingIdlePostFramesRef.current) {
|
|
5471
|
+
debugPendingIdlePostFramesRef.current = false;
|
|
5472
|
+
}
|
|
5473
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame-fire", {
|
|
5474
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5475
|
+
renderOrdinal: debugRenderOrdinalRef.current,
|
|
5476
|
+
hookRenderOrdinal,
|
|
5477
|
+
scheduledRenderOrdinal,
|
|
5478
|
+
scheduledHookRenderOrdinal,
|
|
5479
|
+
token,
|
|
5480
|
+
frame: debugIdlePostFrameOrdinalRef.current,
|
|
5481
|
+
remainingFrames,
|
|
5482
|
+
text,
|
|
5483
|
+
stateStage: state.stage,
|
|
5484
|
+
flowText
|
|
5485
|
+
});
|
|
4672
5486
|
const root = ref.current;
|
|
4673
5487
|
const flowNode = flowTextRef.current;
|
|
4674
|
-
|
|
5488
|
+
const overlayNode = overlayRef.current;
|
|
5489
|
+
if (root === null || flowNode === null || overlayNode === null) {
|
|
5490
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame-skip", {
|
|
5491
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5492
|
+
renderOrdinal: debugRenderOrdinalRef.current,
|
|
5493
|
+
hookRenderOrdinal,
|
|
5494
|
+
scheduledRenderOrdinal,
|
|
5495
|
+
scheduledHookRenderOrdinal,
|
|
5496
|
+
token,
|
|
5497
|
+
text,
|
|
5498
|
+
stateStage: state.stage,
|
|
5499
|
+
frame: debugIdlePostFrameOrdinalRef.current,
|
|
5500
|
+
hasRoot: root !== null,
|
|
5501
|
+
hasFlowNode: flowNode !== null,
|
|
5502
|
+
hasOverlayNode: overlayNode !== null,
|
|
5503
|
+
flowText,
|
|
5504
|
+
committed: summarizeDebugMeasurement(committedMeasurement),
|
|
5505
|
+
stateMeasurement: summarizeDebugMeasurement(measurement)
|
|
5506
|
+
});
|
|
4675
5507
|
return;
|
|
4676
5508
|
}
|
|
4677
5509
|
const rootRect = root.getBoundingClientRect();
|
|
4678
5510
|
const flowRect = flowNode.getBoundingClientRect();
|
|
5511
|
+
const overlayRect = overlayNode.getBoundingClientRect();
|
|
4679
5512
|
const flowSnapshot = measureLiveFlowSnapshot(root, flowNode);
|
|
5513
|
+
let visibleSnapshot = null;
|
|
5514
|
+
if (overlayNode !== null) {
|
|
5515
|
+
visibleSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "live");
|
|
5516
|
+
}
|
|
4680
5517
|
let flowDrift = null;
|
|
4681
5518
|
if (flowSnapshot !== null) {
|
|
4682
5519
|
flowDrift = summarizeSnapshotDrift(measureSnapshotDrift(measurement.snapshot, flowSnapshot));
|
|
4683
5520
|
}
|
|
5521
|
+
let visibleDrift = null;
|
|
5522
|
+
if (visibleSnapshot !== null) {
|
|
5523
|
+
visibleDrift = summarizeSnapshotDrift(measureSnapshotDrift(measurement.snapshot, visibleSnapshot));
|
|
5524
|
+
}
|
|
4684
5525
|
logTorphDebug(debugInstanceId, "effect:idle-post-frame", {
|
|
5526
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5527
|
+
renderOrdinal: debugRenderOrdinalRef.current,
|
|
5528
|
+
hookRenderOrdinal,
|
|
5529
|
+
scheduledRenderOrdinal,
|
|
5530
|
+
scheduledHookRenderOrdinal,
|
|
5531
|
+
token,
|
|
4685
5532
|
text,
|
|
4686
5533
|
frame: debugIdlePostFrameOrdinalRef.current,
|
|
4687
5534
|
stateStage: state.stage,
|
|
@@ -4690,11 +5537,24 @@ function ActiveTorph({
|
|
|
4690
5537
|
committed: summarizeDebugMeasurement(committedMeasurement),
|
|
4691
5538
|
stateMeasurement: summarizeDebugMeasurement(measurement),
|
|
4692
5539
|
rootBox: summarizeDebugRect(rootRect),
|
|
5540
|
+
rootBoxPrecise: summarizePreciseRect(rootRect),
|
|
5541
|
+
overlayBox: summarizeDebugRect(overlayRect),
|
|
5542
|
+
overlayBoxPrecise: summarizePreciseRect(overlayRect),
|
|
4693
5543
|
flowBox: summarizeDebugRect(flowRect),
|
|
5544
|
+
flowBoxPrecise: summarizePreciseRect(flowRect),
|
|
5545
|
+
rootRuntimeStyles: summarizeRootRuntimeStyles(root),
|
|
4694
5546
|
rootOriginDrift: summarizeDebugRootOriginDrift(measurement, rootRect),
|
|
4695
5547
|
flow: summarizeDebugSnapshot(flowSnapshot),
|
|
5548
|
+
flowGlyphs: summarizeDebugGlyphs(flowSnapshot),
|
|
5549
|
+
flowGlyphsPrecise: summarizePreciseGlyphs(flowSnapshot, rootRect),
|
|
4696
5550
|
flowViewportAnchors: summarizeDebugViewportAnchors(flowSnapshot, rootRect),
|
|
4697
|
-
flowDrift
|
|
5551
|
+
flowDrift,
|
|
5552
|
+
visible: summarizeDebugSnapshot(visibleSnapshot),
|
|
5553
|
+
visibleGlyphs: summarizeDebugGlyphs(visibleSnapshot),
|
|
5554
|
+
visibleGlyphsPrecise: summarizePreciseGlyphs(visibleSnapshot, rootRect),
|
|
5555
|
+
visibleViewportAnchors: summarizeDebugViewportAnchors(visibleSnapshot, rootRect),
|
|
5556
|
+
visibleDrift,
|
|
5557
|
+
visibleLiveNodeStyles: summarizeLiveNodeStyles(overlayNode)
|
|
4698
5558
|
});
|
|
4699
5559
|
debugIdlePostFrameOrdinalRef.current += 1;
|
|
4700
5560
|
remainingFrames -= 1;
|
|
@@ -4703,121 +5563,77 @@ function ActiveTorph({
|
|
|
4703
5563
|
return;
|
|
4704
5564
|
}
|
|
4705
5565
|
debugIdlePostFrameHandleRef.current = requestAnimationFrame(captureIdlePostFrame);
|
|
5566
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame-reschedule", {
|
|
5567
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5568
|
+
renderOrdinal: debugRenderOrdinalRef.current,
|
|
5569
|
+
hookRenderOrdinal,
|
|
5570
|
+
scheduledRenderOrdinal,
|
|
5571
|
+
scheduledHookRenderOrdinal,
|
|
5572
|
+
token,
|
|
5573
|
+
handle: debugIdlePostFrameHandleRef.current,
|
|
5574
|
+
nextFrame: debugIdlePostFrameOrdinalRef.current,
|
|
5575
|
+
remainingFrames,
|
|
5576
|
+
text,
|
|
5577
|
+
stateStage: state.stage,
|
|
5578
|
+
flowText
|
|
5579
|
+
});
|
|
4706
5580
|
};
|
|
4707
5581
|
debugIdlePostFrameHandleRef.current = requestAnimationFrame(captureIdlePostFrame);
|
|
5582
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame-schedule", {
|
|
5583
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5584
|
+
renderOrdinal: scheduledRenderOrdinal,
|
|
5585
|
+
hookRenderOrdinal: scheduledHookRenderOrdinal,
|
|
5586
|
+
token,
|
|
5587
|
+
handle: debugIdlePostFrameHandleRef.current,
|
|
5588
|
+
remainingFrames,
|
|
5589
|
+
text,
|
|
5590
|
+
stateStage: state.stage,
|
|
5591
|
+
flowText,
|
|
5592
|
+
domMeasurementRequestKey,
|
|
5593
|
+
domMeasurementKey,
|
|
5594
|
+
measurementBackend
|
|
5595
|
+
});
|
|
4708
5596
|
return () => {
|
|
4709
5597
|
cancelled = true;
|
|
4710
5598
|
if (debugIdlePostFrameHandleRef.current !== null) {
|
|
5599
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame-cleanup", {
|
|
5600
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5601
|
+
reason: "effect-rerun-or-unmount",
|
|
5602
|
+
renderOrdinal: debugRenderOrdinalRef.current,
|
|
5603
|
+
hookRenderOrdinal,
|
|
5604
|
+
scheduledRenderOrdinal,
|
|
5605
|
+
scheduledHookRenderOrdinal,
|
|
5606
|
+
token,
|
|
5607
|
+
handle: debugIdlePostFrameHandleRef.current,
|
|
5608
|
+
completedFrames: debugIdlePostFrameOrdinalRef.current,
|
|
5609
|
+
remainingFrames,
|
|
5610
|
+
text,
|
|
5611
|
+
stateStage: state.stage,
|
|
5612
|
+
flowText,
|
|
5613
|
+
domMeasurementRequestKey,
|
|
5614
|
+
domMeasurementKey,
|
|
5615
|
+
measurementBackend
|
|
5616
|
+
});
|
|
4711
5617
|
cancelAnimationFrame(debugIdlePostFrameHandleRef.current);
|
|
4712
5618
|
debugIdlePostFrameHandleRef.current = null;
|
|
4713
5619
|
}
|
|
4714
5620
|
};
|
|
4715
5621
|
}, [committedMeasurement, debugInstanceId, flowText, ref, state, text]);
|
|
4716
|
-
|
|
5622
|
+
useLayoutEffect2(() => {
|
|
4717
5623
|
return () => {
|
|
4718
5624
|
if (debugIdlePostFrameHandleRef.current !== null) {
|
|
5625
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame-cleanup", {
|
|
5626
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
5627
|
+
reason: "component-unmount",
|
|
5628
|
+
renderOrdinal: debugRenderOrdinalRef.current,
|
|
5629
|
+
token: debugIdlePostFrameTokenRef.current,
|
|
5630
|
+
handle: debugIdlePostFrameHandleRef.current
|
|
5631
|
+
});
|
|
4719
5632
|
cancelAnimationFrame(debugIdlePostFrameHandleRef.current);
|
|
4720
5633
|
debugIdlePostFrameHandleRef.current = null;
|
|
4721
5634
|
}
|
|
4722
5635
|
};
|
|
4723
5636
|
}, []);
|
|
4724
|
-
useLayoutEffect(() => {
|
|
4725
|
-
const config = readTorphDebugConfig();
|
|
4726
|
-
if (!shouldRunTorphInstrumentation(config)) {
|
|
4727
|
-
debugFinalizeSignatureRef.current = null;
|
|
4728
|
-
return;
|
|
4729
|
-
}
|
|
4730
|
-
if (state.stage !== "animate" || state.measurement === null || plan === null) {
|
|
4731
|
-
debugFinalizeSignatureRef.current = null;
|
|
4732
|
-
return;
|
|
4733
|
-
}
|
|
4734
|
-
const root = ref.current;
|
|
4735
|
-
const overlayNode = overlayRef.current;
|
|
4736
|
-
const flowNode = flowTextRef.current;
|
|
4737
|
-
if (root === null || overlayNode === null || flowNode === null) {
|
|
4738
|
-
debugFinalizeSignatureRef.current = null;
|
|
4739
|
-
return;
|
|
4740
|
-
}
|
|
4741
|
-
const measurement = state.measurement;
|
|
4742
|
-
let handled = false;
|
|
4743
|
-
const capture = (event) => {
|
|
4744
|
-
if (handled) {
|
|
4745
|
-
return;
|
|
4746
|
-
}
|
|
4747
|
-
if (event.propertyName !== "transform") {
|
|
4748
|
-
return;
|
|
4749
|
-
}
|
|
4750
|
-
const target = event.target;
|
|
4751
|
-
if (!(target instanceof HTMLElement)) {
|
|
4752
|
-
return;
|
|
4753
|
-
}
|
|
4754
|
-
if (target.dataset.morphRole !== "live") {
|
|
4755
|
-
return;
|
|
4756
|
-
}
|
|
4757
|
-
handled = true;
|
|
4758
|
-
const overlayLiveSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "live");
|
|
4759
|
-
const overlayExitSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "exit");
|
|
4760
|
-
const flowSnapshot = measureLiveFlowSnapshot(root, flowNode);
|
|
4761
|
-
if (overlayLiveSnapshot === null || flowSnapshot === null) {
|
|
4762
|
-
return;
|
|
4763
|
-
}
|
|
4764
|
-
const overlayLiveDrift = measureSnapshotDrift(measurement.snapshot, overlayLiveSnapshot);
|
|
4765
|
-
const flowDrift = measureSnapshotDrift(measurement.snapshot, flowSnapshot);
|
|
4766
|
-
const rootRect = root.getBoundingClientRect();
|
|
4767
|
-
const flowRect = flowNode.getBoundingClientRect();
|
|
4768
|
-
const overlayRect = overlayNode.getBoundingClientRect();
|
|
4769
|
-
const signature = JSON.stringify({
|
|
4770
|
-
text,
|
|
4771
|
-
renderText: measurement.snapshot.renderText,
|
|
4772
|
-
overlayLiveDrift: summarizeSnapshotDrift(overlayLiveDrift),
|
|
4773
|
-
flowDrift: summarizeSnapshotDrift(flowDrift),
|
|
4774
|
-
overlayWidth: roundDebugValue(overlayRect.width),
|
|
4775
|
-
rootWidth: roundDebugValue(rootRect.width)
|
|
4776
|
-
});
|
|
4777
|
-
if (debugFinalizeSignatureRef.current === signature) {
|
|
4778
|
-
return;
|
|
4779
|
-
}
|
|
4780
|
-
debugFinalizeSignatureRef.current = signature;
|
|
4781
|
-
logTorphDebug(debugInstanceId, "effect:animate-finalize-snapshot", {
|
|
4782
|
-
text,
|
|
4783
|
-
target: {
|
|
4784
|
-
layoutInlineSize: roundDebugValue(measurement.layoutInlineSize),
|
|
4785
|
-
reservedInlineSize: roundDebugValue(measurement.reservedInlineSize),
|
|
4786
|
-
flowInlineSize: roundDebugValue(measurement.flowInlineSize),
|
|
4787
|
-
rootOrigin: {
|
|
4788
|
-
left: roundDebugValue(measurement.rootOrigin.left),
|
|
4789
|
-
top: roundDebugValue(measurement.rootOrigin.top)
|
|
4790
|
-
},
|
|
4791
|
-
snapshot: summarizeDebugSnapshot(measurement.snapshot)
|
|
4792
|
-
},
|
|
4793
|
-
overlayLive: summarizeDebugSnapshot(overlayLiveSnapshot),
|
|
4794
|
-
overlayLiveDrift: summarizeSnapshotDrift(overlayLiveDrift),
|
|
4795
|
-
overlayExit: summarizeDebugSnapshot(overlayExitSnapshot),
|
|
4796
|
-
flow: summarizeDebugSnapshot(flowSnapshot),
|
|
4797
|
-
flowDrift: summarizeSnapshotDrift(flowDrift),
|
|
4798
|
-
rootOriginDrift: summarizeDebugRootOriginDrift(measurement, rootRect),
|
|
4799
|
-
overlayLiveViewportAnchors: summarizeDebugViewportAnchors(overlayLiveSnapshot, rootRect),
|
|
4800
|
-
overlayExitViewportAnchors: summarizeDebugViewportAnchors(overlayExitSnapshot, rootRect),
|
|
4801
|
-
flowViewportAnchors: summarizeDebugViewportAnchors(flowSnapshot, rootRect),
|
|
4802
|
-
rootBox: {
|
|
4803
|
-
width: roundDebugValue(rootRect.width),
|
|
4804
|
-
height: roundDebugValue(rootRect.height)
|
|
4805
|
-
},
|
|
4806
|
-
overlayBox: {
|
|
4807
|
-
width: roundDebugValue(overlayRect.width),
|
|
4808
|
-
height: roundDebugValue(overlayRect.height)
|
|
4809
|
-
},
|
|
4810
|
-
flowBox: {
|
|
4811
|
-
width: roundDebugValue(flowRect.width),
|
|
4812
|
-
height: roundDebugValue(flowRect.height)
|
|
4813
|
-
}
|
|
4814
|
-
});
|
|
4815
|
-
};
|
|
4816
|
-
overlayNode.addEventListener("transitionend", capture);
|
|
4817
|
-
return () => {
|
|
4818
|
-
overlayNode.removeEventListener("transitionend", capture);
|
|
4819
|
-
};
|
|
4820
|
-
}, [debugInstanceId, plan, ref, state, text]);
|
|
4821
5637
|
let measurementLayer = null;
|
|
4822
5638
|
if (shouldRenderMeasurementLayer) {
|
|
4823
5639
|
measurementLayer = /* @__PURE__ */ jsxDEV(MeasurementLayer, {
|
|
@@ -4828,11 +5644,13 @@ function ActiveTorph({
|
|
|
4828
5644
|
}, undefined, false, undefined, this);
|
|
4829
5645
|
}
|
|
4830
5646
|
let overlay = null;
|
|
4831
|
-
if (
|
|
5647
|
+
if (shouldRenderGlyphLayer2 && visibleGlyphPlan !== null) {
|
|
4832
5648
|
overlay = /* @__PURE__ */ jsxDEV(MorphOverlay, {
|
|
4833
5649
|
overlayRef,
|
|
4834
5650
|
stage: state.stage,
|
|
4835
|
-
plan
|
|
5651
|
+
plan: visibleGlyphPlan,
|
|
5652
|
+
sourceSliceWhiteSpace,
|
|
5653
|
+
targetSliceWhiteSpace
|
|
4836
5654
|
}, undefined, false, undefined, this);
|
|
4837
5655
|
}
|
|
4838
5656
|
return /* @__PURE__ */ jsxDEV("div", {
|
|
@@ -4846,7 +5664,7 @@ function ActiveTorph({
|
|
|
4846
5664
|
}, undefined, false, undefined, this),
|
|
4847
5665
|
/* @__PURE__ */ jsxDEV("span", {
|
|
4848
5666
|
"aria-hidden": "true",
|
|
4849
|
-
style: getFallbackTextStyle(
|
|
5667
|
+
style: getFallbackTextStyle(shouldHideFlowText),
|
|
4850
5668
|
children: /* @__PURE__ */ jsxDEV("span", {
|
|
4851
5669
|
ref: flowTextRef,
|
|
4852
5670
|
children: flowText
|
|
@@ -4867,23 +5685,5 @@ function Torph({
|
|
|
4867
5685
|
}, undefined, false, undefined, this);
|
|
4868
5686
|
}
|
|
4869
5687
|
export {
|
|
4870
|
-
supportsIntrinsicWidthLock,
|
|
4871
|
-
shouldHealIdleMeasurementFromFlow,
|
|
4872
|
-
resolveMorphFrameBounds,
|
|
4873
|
-
resolveFlowText,
|
|
4874
|
-
resolveContentWidthLockInlineSize,
|
|
4875
|
-
refineMeasurementWithLiveGeometry,
|
|
4876
|
-
pairMorphCharacters,
|
|
4877
|
-
needsMeasurementLayer,
|
|
4878
|
-
measureMorphSnapshotFromLayer,
|
|
4879
|
-
getRootStyle,
|
|
4880
|
-
getRootDisplay,
|
|
4881
|
-
getMeasurementLayerStyle,
|
|
4882
|
-
getLiveTransition,
|
|
4883
|
-
getLiveTransform,
|
|
4884
|
-
getExitTransition,
|
|
4885
|
-
getExitTransform,
|
|
4886
|
-
buildMorphVisualBridge,
|
|
4887
|
-
buildMorphPlan,
|
|
4888
5688
|
Torph
|
|
4889
5689
|
};
|