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