@grahlnn/comps 0.1.7 → 0.1.8
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 +952 -110
- package/dist/torph/src/components/Torph.d.ts +10 -0
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2600,20 +2600,273 @@ var SHARED_GLYPH_TYPOGRAPHY_STYLE = {
|
|
|
2600
2600
|
wordSpacing: "inherit",
|
|
2601
2601
|
direction: "inherit"
|
|
2602
2602
|
};
|
|
2603
|
-
var MEASUREMENT_GLYPH_STYLE = {
|
|
2604
|
-
...SHARED_GLYPH_TYPOGRAPHY_STYLE,
|
|
2605
|
-
display: "inline"
|
|
2606
|
-
};
|
|
2607
2603
|
var ABSOLUTE_GLYPH_STYLE = {
|
|
2604
|
+
position: "absolute",
|
|
2605
|
+
display: "block",
|
|
2606
|
+
overflow: "hidden",
|
|
2607
|
+
transformOrigin: "left top"
|
|
2608
|
+
};
|
|
2609
|
+
var CONTEXT_SLICE_TEXT_STYLE = {
|
|
2608
2610
|
...SHARED_GLYPH_TYPOGRAPHY_STYLE,
|
|
2609
2611
|
position: "absolute",
|
|
2610
2612
|
display: "block",
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
whiteSpace: "pre"
|
|
2613
|
+
minWidth: 0,
|
|
2614
|
+
whiteSpace: "inherit"
|
|
2614
2615
|
};
|
|
2615
2616
|
var graphemeSegmenter = null;
|
|
2616
2617
|
var domMeasurementService = null;
|
|
2618
|
+
var torphDebugInstanceOrdinal = 0;
|
|
2619
|
+
var TORPH_TRACE_MAX_BYTES = 4 * 1024 * 1024;
|
|
2620
|
+
var TORPH_TRACE_MAX_LINES = 4000;
|
|
2621
|
+
var TORPH_TRACE_SCHEMA_VERSION = 2;
|
|
2622
|
+
function nextTorphDebugInstanceId() {
|
|
2623
|
+
torphDebugInstanceOrdinal += 1;
|
|
2624
|
+
return torphDebugInstanceOrdinal;
|
|
2625
|
+
}
|
|
2626
|
+
function readTorphDebugConfig() {
|
|
2627
|
+
const scope = globalThis;
|
|
2628
|
+
return scope.__TORPH_DEBUG__ ?? null;
|
|
2629
|
+
}
|
|
2630
|
+
function shouldCaptureTorphTrace(config) {
|
|
2631
|
+
if (config === null) {
|
|
2632
|
+
return true;
|
|
2633
|
+
}
|
|
2634
|
+
if (typeof config === "boolean") {
|
|
2635
|
+
return config;
|
|
2636
|
+
}
|
|
2637
|
+
if (config.capture === false) {
|
|
2638
|
+
return false;
|
|
2639
|
+
}
|
|
2640
|
+
return true;
|
|
2641
|
+
}
|
|
2642
|
+
function isTorphDebugEnabled(config) {
|
|
2643
|
+
if (config === null) {
|
|
2644
|
+
return false;
|
|
2645
|
+
}
|
|
2646
|
+
if (typeof config === "boolean") {
|
|
2647
|
+
return config;
|
|
2648
|
+
}
|
|
2649
|
+
if (config.console !== undefined) {
|
|
2650
|
+
return config.console;
|
|
2651
|
+
}
|
|
2652
|
+
return config.enabled !== false;
|
|
2653
|
+
}
|
|
2654
|
+
function shouldRunTorphInstrumentation(config) {
|
|
2655
|
+
if (shouldCaptureTorphTrace(config)) {
|
|
2656
|
+
return true;
|
|
2657
|
+
}
|
|
2658
|
+
return isTorphDebugEnabled(config);
|
|
2659
|
+
}
|
|
2660
|
+
function getTorphTraceStore() {
|
|
2661
|
+
const scope = globalThis;
|
|
2662
|
+
let store = scope.__TORPH_TRACE_STORE__;
|
|
2663
|
+
if (store !== undefined) {
|
|
2664
|
+
return store;
|
|
2665
|
+
}
|
|
2666
|
+
store = {
|
|
2667
|
+
lines: [],
|
|
2668
|
+
nextSeq: 1,
|
|
2669
|
+
totalBytes: 0
|
|
2670
|
+
};
|
|
2671
|
+
scope.__TORPH_TRACE_STORE__ = store;
|
|
2672
|
+
return store;
|
|
2673
|
+
}
|
|
2674
|
+
function getTorphTraceText() {
|
|
2675
|
+
return getTorphTraceStore().lines.join("");
|
|
2676
|
+
}
|
|
2677
|
+
function clearTorphTrace() {
|
|
2678
|
+
const store = getTorphTraceStore();
|
|
2679
|
+
store.lines = [];
|
|
2680
|
+
store.nextSeq = 1;
|
|
2681
|
+
store.totalBytes = 0;
|
|
2682
|
+
}
|
|
2683
|
+
function downloadTorphTrace(filename) {
|
|
2684
|
+
if (typeof document === "undefined") {
|
|
2685
|
+
return null;
|
|
2686
|
+
}
|
|
2687
|
+
const text = getTorphTraceText();
|
|
2688
|
+
const blob = new Blob([text], { type: "application/x-ndjson;charset=utf-8" });
|
|
2689
|
+
const href = URL.createObjectURL(blob);
|
|
2690
|
+
const anchor = document.createElement("a");
|
|
2691
|
+
let resolvedFilename = filename;
|
|
2692
|
+
if (resolvedFilename === undefined) {
|
|
2693
|
+
resolvedFilename = `torph-trace-${new Date().toISOString().replaceAll(":", "-")}.jsonl`;
|
|
2694
|
+
}
|
|
2695
|
+
anchor.href = href;
|
|
2696
|
+
anchor.download = resolvedFilename;
|
|
2697
|
+
anchor.click();
|
|
2698
|
+
window.setTimeout(() => {
|
|
2699
|
+
URL.revokeObjectURL(href);
|
|
2700
|
+
}, 0);
|
|
2701
|
+
return resolvedFilename;
|
|
2702
|
+
}
|
|
2703
|
+
function ensureTorphTraceApi() {
|
|
2704
|
+
const scope = globalThis;
|
|
2705
|
+
if (scope.__TORPH_TRACE__ !== undefined) {
|
|
2706
|
+
return scope.__TORPH_TRACE__;
|
|
2707
|
+
}
|
|
2708
|
+
const api = {
|
|
2709
|
+
clear: clearTorphTrace,
|
|
2710
|
+
count: () => getTorphTraceStore().lines.length,
|
|
2711
|
+
download: downloadTorphTrace,
|
|
2712
|
+
text: getTorphTraceText
|
|
2713
|
+
};
|
|
2714
|
+
scope.__TORPH_TRACE__ = api;
|
|
2715
|
+
return api;
|
|
2716
|
+
}
|
|
2717
|
+
function appendTorphTrace(instanceId, event, payload) {
|
|
2718
|
+
ensureTorphTraceApi();
|
|
2719
|
+
const store = getTorphTraceStore();
|
|
2720
|
+
const entry = {
|
|
2721
|
+
instanceId,
|
|
2722
|
+
event,
|
|
2723
|
+
payload,
|
|
2724
|
+
seq: store.nextSeq,
|
|
2725
|
+
time: new Date().toISOString()
|
|
2726
|
+
};
|
|
2727
|
+
store.nextSeq += 1;
|
|
2728
|
+
const line = `${JSON.stringify(entry)}
|
|
2729
|
+
`;
|
|
2730
|
+
store.lines.push(line);
|
|
2731
|
+
store.totalBytes += line.length;
|
|
2732
|
+
while (store.lines.length > TORPH_TRACE_MAX_LINES || store.totalBytes > TORPH_TRACE_MAX_BYTES) {
|
|
2733
|
+
const removed = store.lines.shift();
|
|
2734
|
+
if (removed === undefined) {
|
|
2735
|
+
break;
|
|
2736
|
+
}
|
|
2737
|
+
store.totalBytes = Math.max(0, store.totalBytes - removed.length);
|
|
2738
|
+
}
|
|
2739
|
+
}
|
|
2740
|
+
function roundDebugValue(value) {
|
|
2741
|
+
if (value === null || value === undefined) {
|
|
2742
|
+
return value;
|
|
2743
|
+
}
|
|
2744
|
+
return Math.round(value * 100) / 100;
|
|
2745
|
+
}
|
|
2746
|
+
function summarizeDebugSnapshot(snapshot) {
|
|
2747
|
+
if (snapshot === null) {
|
|
2748
|
+
return null;
|
|
2749
|
+
}
|
|
2750
|
+
return {
|
|
2751
|
+
text: snapshot.text,
|
|
2752
|
+
renderText: snapshot.renderText,
|
|
2753
|
+
width: roundDebugValue(snapshot.width),
|
|
2754
|
+
height: roundDebugValue(snapshot.height),
|
|
2755
|
+
graphemes: snapshot.graphemes.length
|
|
2756
|
+
};
|
|
2757
|
+
}
|
|
2758
|
+
function summarizeDebugMeasurement(measurement) {
|
|
2759
|
+
if (measurement === null) {
|
|
2760
|
+
return null;
|
|
2761
|
+
}
|
|
2762
|
+
return {
|
|
2763
|
+
layoutInlineSize: roundDebugValue(measurement.layoutInlineSize),
|
|
2764
|
+
reservedInlineSize: roundDebugValue(measurement.reservedInlineSize),
|
|
2765
|
+
flowInlineSize: roundDebugValue(measurement.flowInlineSize),
|
|
2766
|
+
rootOrigin: {
|
|
2767
|
+
left: roundDebugValue(measurement.rootOrigin.left),
|
|
2768
|
+
top: roundDebugValue(measurement.rootOrigin.top)
|
|
2769
|
+
},
|
|
2770
|
+
snapshot: summarizeDebugSnapshot(measurement.snapshot)
|
|
2771
|
+
};
|
|
2772
|
+
}
|
|
2773
|
+
function summarizeDebugRect(rect) {
|
|
2774
|
+
if (rect === null) {
|
|
2775
|
+
return null;
|
|
2776
|
+
}
|
|
2777
|
+
return {
|
|
2778
|
+
left: roundDebugValue(rect.left),
|
|
2779
|
+
top: roundDebugValue(rect.top),
|
|
2780
|
+
width: roundDebugValue(rect.width),
|
|
2781
|
+
height: roundDebugValue(rect.height)
|
|
2782
|
+
};
|
|
2783
|
+
}
|
|
2784
|
+
function collectDebugAnchorIndices(length) {
|
|
2785
|
+
const indices = new Set;
|
|
2786
|
+
if (length <= 0) {
|
|
2787
|
+
return [];
|
|
2788
|
+
}
|
|
2789
|
+
indices.add(0);
|
|
2790
|
+
if (length > 1) {
|
|
2791
|
+
indices.add(1);
|
|
2792
|
+
indices.add(length - 2);
|
|
2793
|
+
}
|
|
2794
|
+
if (length > 2) {
|
|
2795
|
+
indices.add(Math.floor((length - 1) / 2));
|
|
2796
|
+
}
|
|
2797
|
+
indices.add(length - 1);
|
|
2798
|
+
return Array.from(indices).sort((left, right) => left - right);
|
|
2799
|
+
}
|
|
2800
|
+
function summarizeDebugViewportAnchors(snapshot, rootRect) {
|
|
2801
|
+
if (snapshot === null || rootRect === null) {
|
|
2802
|
+
return null;
|
|
2803
|
+
}
|
|
2804
|
+
const anchors = [];
|
|
2805
|
+
const anchorIndices = collectDebugAnchorIndices(snapshot.graphemes.length);
|
|
2806
|
+
for (const index of anchorIndices) {
|
|
2807
|
+
const grapheme = snapshot.graphemes[index];
|
|
2808
|
+
if (grapheme === undefined) {
|
|
2809
|
+
continue;
|
|
2810
|
+
}
|
|
2811
|
+
anchors.push({
|
|
2812
|
+
index,
|
|
2813
|
+
glyph: grapheme.glyph,
|
|
2814
|
+
left: roundDebugValue(rootRect.left + grapheme.left),
|
|
2815
|
+
top: roundDebugValue(rootRect.top + grapheme.top),
|
|
2816
|
+
width: roundDebugValue(grapheme.width),
|
|
2817
|
+
height: roundDebugValue(grapheme.height)
|
|
2818
|
+
});
|
|
2819
|
+
}
|
|
2820
|
+
return anchors;
|
|
2821
|
+
}
|
|
2822
|
+
function summarizeDebugRootOriginDrift(measurement, rootRect) {
|
|
2823
|
+
if (measurement === null || rootRect === null) {
|
|
2824
|
+
return null;
|
|
2825
|
+
}
|
|
2826
|
+
return {
|
|
2827
|
+
expectedLeft: roundDebugValue(measurement.rootOrigin.left),
|
|
2828
|
+
expectedTop: roundDebugValue(measurement.rootOrigin.top),
|
|
2829
|
+
actualLeft: roundDebugValue(rootRect.left),
|
|
2830
|
+
actualTop: roundDebugValue(rootRect.top),
|
|
2831
|
+
deltaLeft: roundDebugValue(rootRect.left - measurement.rootOrigin.left),
|
|
2832
|
+
deltaTop: roundDebugValue(rootRect.top - measurement.rootOrigin.top)
|
|
2833
|
+
};
|
|
2834
|
+
}
|
|
2835
|
+
function summarizeSnapshotDrift(drift) {
|
|
2836
|
+
return {
|
|
2837
|
+
comparedGlyphs: drift.comparedGlyphs,
|
|
2838
|
+
expectedGlyphs: drift.expectedGlyphs,
|
|
2839
|
+
actualGlyphs: drift.actualGlyphs,
|
|
2840
|
+
snapshotWidthDelta: roundDebugValue(drift.snapshotWidthDelta),
|
|
2841
|
+
snapshotHeightDelta: roundDebugValue(drift.snapshotHeightDelta),
|
|
2842
|
+
maxAbsLeftDelta: roundDebugValue(drift.maxAbsLeftDelta),
|
|
2843
|
+
maxAbsTopDelta: roundDebugValue(drift.maxAbsTopDelta),
|
|
2844
|
+
maxAbsWidthDelta: roundDebugValue(drift.maxAbsWidthDelta),
|
|
2845
|
+
maxAbsHeightDelta: roundDebugValue(drift.maxAbsHeightDelta),
|
|
2846
|
+
mismatches: drift.mismatches.map((mismatch) => ({
|
|
2847
|
+
index: mismatch.index,
|
|
2848
|
+
glyph: mismatch.glyph,
|
|
2849
|
+
leftDelta: roundDebugValue(mismatch.leftDelta),
|
|
2850
|
+
topDelta: roundDebugValue(mismatch.topDelta),
|
|
2851
|
+
widthDelta: roundDebugValue(mismatch.widthDelta),
|
|
2852
|
+
heightDelta: roundDebugValue(mismatch.heightDelta)
|
|
2853
|
+
}))
|
|
2854
|
+
};
|
|
2855
|
+
}
|
|
2856
|
+
function logTorphDebug(instanceId, event, payload) {
|
|
2857
|
+
const config = readTorphDebugConfig();
|
|
2858
|
+
const captureTrace = shouldCaptureTorphTrace(config);
|
|
2859
|
+
const logToConsole = isTorphDebugEnabled(config);
|
|
2860
|
+
if (!captureTrace && !logToConsole) {
|
|
2861
|
+
return;
|
|
2862
|
+
}
|
|
2863
|
+
if (captureTrace) {
|
|
2864
|
+
appendTorphTrace(instanceId, event, payload);
|
|
2865
|
+
}
|
|
2866
|
+
if (logToConsole) {
|
|
2867
|
+
console.log(`[Torph#${instanceId}] ${event}`, payload);
|
|
2868
|
+
}
|
|
2869
|
+
}
|
|
2617
2870
|
function parsePx(value) {
|
|
2618
2871
|
const parsed = Number.parseFloat(value);
|
|
2619
2872
|
if (Number.isFinite(parsed)) {
|
|
@@ -2701,6 +2954,21 @@ function isSingleLineSnapshot(snapshot) {
|
|
|
2701
2954
|
const firstTop = snapshot.graphemes[0].top;
|
|
2702
2955
|
return snapshot.graphemes.every((grapheme) => nearlyEqual(grapheme.top, firstTop, MORPH.lineGroupingEpsilon));
|
|
2703
2956
|
}
|
|
2957
|
+
function countSnapshotLines(snapshot) {
|
|
2958
|
+
if (snapshot.graphemes.length === 0) {
|
|
2959
|
+
return 0;
|
|
2960
|
+
}
|
|
2961
|
+
let lineCount = 1;
|
|
2962
|
+
let currentTop = snapshot.graphemes[0].top;
|
|
2963
|
+
for (let index = 1;index < snapshot.graphemes.length; index += 1) {
|
|
2964
|
+
const top = snapshot.graphemes[index].top;
|
|
2965
|
+
if (!nearlyEqual(top, currentTop, MORPH.lineGroupingEpsilon)) {
|
|
2966
|
+
currentTop = top;
|
|
2967
|
+
lineCount += 1;
|
|
2968
|
+
}
|
|
2969
|
+
}
|
|
2970
|
+
return lineCount;
|
|
2971
|
+
}
|
|
2704
2972
|
function acquireMorphMeasurementInvalidationListeners() {
|
|
2705
2973
|
activeMorphMeasurementConsumers += 1;
|
|
2706
2974
|
if (detachMorphMeasurementInvalidationListeners === null) {
|
|
@@ -2791,25 +3059,6 @@ function getSegmenter() {
|
|
|
2791
3059
|
});
|
|
2792
3060
|
return graphemeSegmenter;
|
|
2793
3061
|
}
|
|
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;
|
|
2812
|
-
}
|
|
2813
3062
|
function getDomMeasurementService() {
|
|
2814
3063
|
if (domMeasurementService !== null) {
|
|
2815
3064
|
return domMeasurementService;
|
|
@@ -2831,25 +3080,10 @@ function getDomMeasurementService() {
|
|
|
2831
3080
|
document.body.appendChild(root);
|
|
2832
3081
|
domMeasurementService = {
|
|
2833
3082
|
root,
|
|
2834
|
-
host
|
|
2835
|
-
glyphNodes: []
|
|
3083
|
+
host
|
|
2836
3084
|
};
|
|
2837
3085
|
return domMeasurementService;
|
|
2838
3086
|
}
|
|
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
3087
|
function applyMeasurementHostStyle({
|
|
2854
3088
|
host,
|
|
2855
3089
|
root,
|
|
@@ -2959,51 +3193,38 @@ function rememberCachedMorphSnapshot(cache, cacheKey, snapshot) {
|
|
|
2959
3193
|
}
|
|
2960
3194
|
}
|
|
2961
3195
|
}
|
|
2962
|
-
function assertMeasurementLayer(layer
|
|
3196
|
+
function assertMeasurementLayer(layer) {
|
|
2963
3197
|
if (layer === null) {
|
|
2964
3198
|
throw new Error("Torph measurement layer is missing.");
|
|
2965
3199
|
}
|
|
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
3200
|
return layer;
|
|
2970
3201
|
}
|
|
2971
3202
|
function readMeasuredGlyphLayouts(layer, layerRect, segments) {
|
|
2972
3203
|
const measuredGlyphs = [];
|
|
2973
|
-
const
|
|
3204
|
+
const textNode = readFirstTextNode(layer);
|
|
3205
|
+
if (textNode === null) {
|
|
3206
|
+
throw new Error("Torph measurement layer text node is missing.");
|
|
3207
|
+
}
|
|
3208
|
+
const range = document.createRange();
|
|
3209
|
+
let offset = 0;
|
|
2974
3210
|
for (let index = 0;index < segments.length; index += 1) {
|
|
2975
3211
|
const segment = segments[index];
|
|
2976
|
-
const
|
|
2977
|
-
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
const rect = child.getBoundingClientRect();
|
|
3212
|
+
const nextOffset = offset + segment.glyph.length;
|
|
3213
|
+
range.setStart(textNode, offset);
|
|
3214
|
+
range.setEnd(textNode, nextOffset);
|
|
3215
|
+
const rect = range.getBoundingClientRect();
|
|
2981
3216
|
measuredGlyphs.push({
|
|
2982
3217
|
glyph: segment.glyph,
|
|
2983
3218
|
key: segment.key,
|
|
2984
3219
|
left: rect.left - layerRect.left,
|
|
2985
|
-
top:
|
|
2986
|
-
width: rect.width
|
|
3220
|
+
top: rect.top - layerRect.top,
|
|
3221
|
+
width: rect.width,
|
|
3222
|
+
height: rect.height
|
|
2987
3223
|
});
|
|
3224
|
+
offset = nextOffset;
|
|
2988
3225
|
}
|
|
2989
3226
|
return measuredGlyphs;
|
|
2990
3227
|
}
|
|
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
3228
|
function measureMorphSnapshotFromLayer(text, renderText, segments, layer) {
|
|
3008
3229
|
if (renderText.length === 0) {
|
|
3009
3230
|
return {
|
|
@@ -3014,28 +3235,19 @@ function measureMorphSnapshotFromLayer(text, renderText, segments, layer) {
|
|
|
3014
3235
|
graphemes: []
|
|
3015
3236
|
};
|
|
3016
3237
|
}
|
|
3017
|
-
const measurementLayer = assertMeasurementLayer(layer
|
|
3238
|
+
const measurementLayer = assertMeasurementLayer(layer);
|
|
3018
3239
|
const layerRect = measurementLayer.getBoundingClientRect();
|
|
3019
3240
|
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
3241
|
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
|
-
}
|
|
3242
|
+
const graphemes = measuredGlyphs.map((glyph) => {
|
|
3031
3243
|
width = Math.max(width, glyph.left + glyph.width);
|
|
3032
3244
|
return {
|
|
3033
3245
|
glyph: glyph.glyph,
|
|
3034
3246
|
key: glyph.key,
|
|
3035
3247
|
left: glyph.left,
|
|
3036
|
-
top:
|
|
3248
|
+
top: glyph.top,
|
|
3037
3249
|
width: glyph.width,
|
|
3038
|
-
height:
|
|
3250
|
+
height: glyph.height
|
|
3039
3251
|
};
|
|
3040
3252
|
});
|
|
3041
3253
|
return {
|
|
@@ -3070,7 +3282,7 @@ function measureMorphSnapshotWithDomService({
|
|
|
3070
3282
|
layoutContext,
|
|
3071
3283
|
useContentInlineSize
|
|
3072
3284
|
});
|
|
3073
|
-
|
|
3285
|
+
service.host.textContent = renderText;
|
|
3074
3286
|
return measureMorphSnapshotFromLayer(text, renderText, segments, service.host);
|
|
3075
3287
|
}
|
|
3076
3288
|
function readRootOrigin(node) {
|
|
@@ -3083,6 +3295,169 @@ function readFlowInlineSize(node) {
|
|
|
3083
3295
|
}
|
|
3084
3296
|
return node.getBoundingClientRect().width;
|
|
3085
3297
|
}
|
|
3298
|
+
function readFlowLineCount(node) {
|
|
3299
|
+
if (node === null) {
|
|
3300
|
+
return null;
|
|
3301
|
+
}
|
|
3302
|
+
const rects = Array.from(node.getClientRects());
|
|
3303
|
+
if (rects.length === 0) {
|
|
3304
|
+
if ((node.textContent ?? "").length === 0) {
|
|
3305
|
+
return 0;
|
|
3306
|
+
}
|
|
3307
|
+
return 1;
|
|
3308
|
+
}
|
|
3309
|
+
let lineCount = 0;
|
|
3310
|
+
let currentTop = null;
|
|
3311
|
+
for (const rect of rects) {
|
|
3312
|
+
if (currentTop === null || !nearlyEqual(rect.top, currentTop, MORPH.lineGroupingEpsilon)) {
|
|
3313
|
+
currentTop = rect.top;
|
|
3314
|
+
lineCount += 1;
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
return lineCount;
|
|
3318
|
+
}
|
|
3319
|
+
function readFirstTextNode(node) {
|
|
3320
|
+
if (node === null) {
|
|
3321
|
+
return null;
|
|
3322
|
+
}
|
|
3323
|
+
for (const childNode of node.childNodes) {
|
|
3324
|
+
if (childNode.nodeType === Node.TEXT_NODE) {
|
|
3325
|
+
return childNode;
|
|
3326
|
+
}
|
|
3327
|
+
}
|
|
3328
|
+
return null;
|
|
3329
|
+
}
|
|
3330
|
+
function measureLiveFlowSnapshot(root, flowTextNode) {
|
|
3331
|
+
const textNode = readFirstTextNode(flowTextNode);
|
|
3332
|
+
if (textNode === null) {
|
|
3333
|
+
return null;
|
|
3334
|
+
}
|
|
3335
|
+
const text = textNode.data;
|
|
3336
|
+
const renderText = text;
|
|
3337
|
+
if (renderText.length === 0) {
|
|
3338
|
+
return {
|
|
3339
|
+
text,
|
|
3340
|
+
renderText,
|
|
3341
|
+
width: 0,
|
|
3342
|
+
height: 0,
|
|
3343
|
+
graphemes: []
|
|
3344
|
+
};
|
|
3345
|
+
}
|
|
3346
|
+
const rootRect = root.getBoundingClientRect();
|
|
3347
|
+
const range = document.createRange();
|
|
3348
|
+
const graphemes = [];
|
|
3349
|
+
let width = 0;
|
|
3350
|
+
let height = 0;
|
|
3351
|
+
let offset = 0;
|
|
3352
|
+
const segments = readCachedMorphSegments(renderText);
|
|
3353
|
+
for (const segment of segments) {
|
|
3354
|
+
const nextOffset = offset + segment.glyph.length;
|
|
3355
|
+
range.setStart(textNode, offset);
|
|
3356
|
+
range.setEnd(textNode, nextOffset);
|
|
3357
|
+
const rect = range.getBoundingClientRect();
|
|
3358
|
+
graphemes.push({
|
|
3359
|
+
glyph: segment.glyph,
|
|
3360
|
+
key: segment.key,
|
|
3361
|
+
left: rect.left - rootRect.left,
|
|
3362
|
+
top: rect.top - rootRect.top,
|
|
3363
|
+
width: rect.width,
|
|
3364
|
+
height: rect.height
|
|
3365
|
+
});
|
|
3366
|
+
width = Math.max(width, rect.right - rootRect.left);
|
|
3367
|
+
height = Math.max(height, rect.bottom - rootRect.top);
|
|
3368
|
+
offset = nextOffset;
|
|
3369
|
+
}
|
|
3370
|
+
return {
|
|
3371
|
+
text,
|
|
3372
|
+
renderText,
|
|
3373
|
+
width,
|
|
3374
|
+
height,
|
|
3375
|
+
graphemes
|
|
3376
|
+
};
|
|
3377
|
+
}
|
|
3378
|
+
function measureSnapshotDrift(expected, actual) {
|
|
3379
|
+
const comparedGlyphs = Math.min(expected.graphemes.length, actual.graphemes.length);
|
|
3380
|
+
const mismatches = [];
|
|
3381
|
+
let maxAbsLeftDelta = 0;
|
|
3382
|
+
let maxAbsTopDelta = 0;
|
|
3383
|
+
let maxAbsWidthDelta = 0;
|
|
3384
|
+
let maxAbsHeightDelta = 0;
|
|
3385
|
+
for (let index = 0;index < comparedGlyphs; index += 1) {
|
|
3386
|
+
const expectedGlyph = expected.graphemes[index];
|
|
3387
|
+
const actualGlyph = actual.graphemes[index];
|
|
3388
|
+
const leftDelta = actualGlyph.left - expectedGlyph.left;
|
|
3389
|
+
const topDelta = actualGlyph.top - expectedGlyph.top;
|
|
3390
|
+
const widthDelta = actualGlyph.width - expectedGlyph.width;
|
|
3391
|
+
const heightDelta = actualGlyph.height - expectedGlyph.height;
|
|
3392
|
+
maxAbsLeftDelta = Math.max(maxAbsLeftDelta, Math.abs(leftDelta));
|
|
3393
|
+
maxAbsTopDelta = Math.max(maxAbsTopDelta, Math.abs(topDelta));
|
|
3394
|
+
maxAbsWidthDelta = Math.max(maxAbsWidthDelta, Math.abs(widthDelta));
|
|
3395
|
+
maxAbsHeightDelta = Math.max(maxAbsHeightDelta, Math.abs(heightDelta));
|
|
3396
|
+
if (mismatches.length < 8 && (Math.abs(leftDelta) > MORPH.geometryEpsilon || Math.abs(topDelta) > MORPH.geometryEpsilon || Math.abs(widthDelta) > MORPH.geometryEpsilon || Math.abs(heightDelta) > MORPH.geometryEpsilon)) {
|
|
3397
|
+
mismatches.push({
|
|
3398
|
+
index,
|
|
3399
|
+
glyph: expectedGlyph.glyph,
|
|
3400
|
+
leftDelta,
|
|
3401
|
+
topDelta,
|
|
3402
|
+
widthDelta,
|
|
3403
|
+
heightDelta
|
|
3404
|
+
});
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
return {
|
|
3408
|
+
comparedGlyphs,
|
|
3409
|
+
expectedGlyphs: expected.graphemes.length,
|
|
3410
|
+
actualGlyphs: actual.graphemes.length,
|
|
3411
|
+
maxAbsLeftDelta,
|
|
3412
|
+
maxAbsTopDelta,
|
|
3413
|
+
maxAbsWidthDelta,
|
|
3414
|
+
maxAbsHeightDelta,
|
|
3415
|
+
snapshotWidthDelta: actual.width - expected.width,
|
|
3416
|
+
snapshotHeightDelta: actual.height - expected.height,
|
|
3417
|
+
mismatches
|
|
3418
|
+
};
|
|
3419
|
+
}
|
|
3420
|
+
function measureOverlayBoxSnapshot(root, overlayRoot, role) {
|
|
3421
|
+
const nodes = overlayRoot.querySelectorAll(`[data-morph-role='${role}']`);
|
|
3422
|
+
if (nodes.length === 0) {
|
|
3423
|
+
return null;
|
|
3424
|
+
}
|
|
3425
|
+
const rootRect = root.getBoundingClientRect();
|
|
3426
|
+
const graphemes = [];
|
|
3427
|
+
let width = 0;
|
|
3428
|
+
let height = 0;
|
|
3429
|
+
let renderText = "";
|
|
3430
|
+
for (const node of nodes) {
|
|
3431
|
+
const key = node.dataset.morphKey;
|
|
3432
|
+
const glyph = node.dataset.morphGlyph;
|
|
3433
|
+
if (key === undefined || glyph === undefined) {
|
|
3434
|
+
return null;
|
|
3435
|
+
}
|
|
3436
|
+
const rect = node.getBoundingClientRect();
|
|
3437
|
+
const left = rect.left - rootRect.left;
|
|
3438
|
+
const top = rect.top - rootRect.top;
|
|
3439
|
+
const boxWidth = rect.width;
|
|
3440
|
+
const boxHeight = rect.height;
|
|
3441
|
+
graphemes.push({
|
|
3442
|
+
glyph,
|
|
3443
|
+
key,
|
|
3444
|
+
left,
|
|
3445
|
+
top,
|
|
3446
|
+
width: boxWidth,
|
|
3447
|
+
height: boxHeight
|
|
3448
|
+
});
|
|
3449
|
+
renderText += glyph;
|
|
3450
|
+
width = Math.max(width, left + boxWidth);
|
|
3451
|
+
height = Math.max(height, top + boxHeight);
|
|
3452
|
+
}
|
|
3453
|
+
return {
|
|
3454
|
+
text: renderText,
|
|
3455
|
+
renderText,
|
|
3456
|
+
width,
|
|
3457
|
+
height,
|
|
3458
|
+
graphemes
|
|
3459
|
+
};
|
|
3460
|
+
}
|
|
3086
3461
|
function getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize) {
|
|
3087
3462
|
const backend = getPretextMorphMeasurementBackend(text, layoutContext);
|
|
3088
3463
|
if (backend !== "probe") {
|
|
@@ -3123,16 +3498,48 @@ function shouldMeasureUsingContentInlineSize(layoutContext, layoutHint) {
|
|
|
3123
3498
|
}
|
|
3124
3499
|
return nearlyEqual(layoutHint.layoutInlineSize, resolveContentWidthLockInlineSize(layoutHint), MORPH.contentWidthLockEpsilon);
|
|
3125
3500
|
}
|
|
3501
|
+
function shouldHealIdleMeasurementFromFlow(measurement, flowLineCount) {
|
|
3502
|
+
if (flowLineCount !== 1) {
|
|
3503
|
+
return false;
|
|
3504
|
+
}
|
|
3505
|
+
return countSnapshotLines(measurement.snapshot) > 1;
|
|
3506
|
+
}
|
|
3507
|
+
function refineMeasurementWithLiveGeometry(measurement, liveGeometry) {
|
|
3508
|
+
const sameFlowInlineSize = measurement.flowInlineSize === null && liveGeometry.flowInlineSize === null || measurement.flowInlineSize !== null && liveGeometry.flowInlineSize !== null && nearlyEqual(measurement.flowInlineSize, liveGeometry.flowInlineSize);
|
|
3509
|
+
if (sameFlowInlineSize && nearlyEqual(measurement.rootOrigin.left, liveGeometry.rootOrigin.left) && nearlyEqual(measurement.rootOrigin.top, liveGeometry.rootOrigin.top)) {
|
|
3510
|
+
return measurement;
|
|
3511
|
+
}
|
|
3512
|
+
return {
|
|
3513
|
+
snapshot: measurement.snapshot,
|
|
3514
|
+
layoutInlineSize: measurement.layoutInlineSize,
|
|
3515
|
+
reservedInlineSize: measurement.reservedInlineSize,
|
|
3516
|
+
flowInlineSize: liveGeometry.flowInlineSize,
|
|
3517
|
+
rootOrigin: liveGeometry.rootOrigin
|
|
3518
|
+
};
|
|
3519
|
+
}
|
|
3520
|
+
function refineMeasurementFromLiveNodes(measurement, root, flowTextNode) {
|
|
3521
|
+
if (root === null) {
|
|
3522
|
+
return measurement;
|
|
3523
|
+
}
|
|
3524
|
+
return refineMeasurementWithLiveGeometry(measurement, {
|
|
3525
|
+
flowInlineSize: readFlowInlineSize(flowTextNode),
|
|
3526
|
+
rootOrigin: readRootOrigin(root)
|
|
3527
|
+
});
|
|
3528
|
+
}
|
|
3126
3529
|
function createMorphMeasurementRequest({
|
|
3127
3530
|
text,
|
|
3128
3531
|
layoutContext,
|
|
3129
|
-
layoutHint
|
|
3532
|
+
layoutHint,
|
|
3533
|
+
forceContentInlineSize = false
|
|
3130
3534
|
}) {
|
|
3131
3535
|
if (layoutContext === null) {
|
|
3132
3536
|
return null;
|
|
3133
3537
|
}
|
|
3134
3538
|
const renderText = getPretextMorphRenderedText(text, layoutContext);
|
|
3135
|
-
|
|
3539
|
+
let useContentInlineSize = shouldMeasureUsingContentInlineSize(layoutContext, layoutHint);
|
|
3540
|
+
if (forceContentInlineSize) {
|
|
3541
|
+
useContentInlineSize = true;
|
|
3542
|
+
}
|
|
3136
3543
|
const measurementBackend = getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize);
|
|
3137
3544
|
let segments = readCachedMorphSegments(renderText);
|
|
3138
3545
|
if (measurementBackend === "pretext") {
|
|
@@ -3348,6 +3755,8 @@ function buildMorphPlan(previous, next, visualBridge = ZERO_BRIDGE) {
|
|
|
3348
3755
|
frameHeight: frame.height,
|
|
3349
3756
|
layoutInlineSizeFrom: previous.layoutInlineSize,
|
|
3350
3757
|
layoutInlineSizeTo: next.layoutInlineSize,
|
|
3758
|
+
sourceRenderText: previous.snapshot.renderText,
|
|
3759
|
+
targetRenderText: next.snapshot.renderText,
|
|
3351
3760
|
visualBridge,
|
|
3352
3761
|
liveItems: next.snapshot.graphemes.map((grapheme) => {
|
|
3353
3762
|
const move = movesByDestinationKey.get(grapheme.key);
|
|
@@ -3466,6 +3875,7 @@ function commitStaticMeasurement(session, measurement, setState) {
|
|
|
3466
3875
|
function scheduleMorphTimeline({
|
|
3467
3876
|
session,
|
|
3468
3877
|
timeline,
|
|
3878
|
+
finalizeMeasurement,
|
|
3469
3879
|
measurement,
|
|
3470
3880
|
plan,
|
|
3471
3881
|
setState
|
|
@@ -3486,12 +3896,13 @@ function scheduleMorphTimeline({
|
|
|
3486
3896
|
timeline.animateFrame = null;
|
|
3487
3897
|
timeline.finalizeTimer = window.setTimeout(() => {
|
|
3488
3898
|
timeline.finalizeTimer = null;
|
|
3489
|
-
commitStaticMeasurement(session, session.target ?? measurement, setState);
|
|
3899
|
+
commitStaticMeasurement(session, finalizeMeasurement(session.target ?? measurement), setState);
|
|
3490
3900
|
}, MORPH.durationMs);
|
|
3491
3901
|
});
|
|
3492
3902
|
});
|
|
3493
3903
|
}
|
|
3494
3904
|
function startMorph({
|
|
3905
|
+
finalizeMeasurement,
|
|
3495
3906
|
nextMeasurement,
|
|
3496
3907
|
session,
|
|
3497
3908
|
timeline,
|
|
@@ -3518,12 +3929,14 @@ function startMorph({
|
|
|
3518
3929
|
scheduleMorphTimeline({
|
|
3519
3930
|
session,
|
|
3520
3931
|
timeline,
|
|
3932
|
+
finalizeMeasurement,
|
|
3521
3933
|
measurement: nextMeasurement,
|
|
3522
3934
|
plan,
|
|
3523
3935
|
setState
|
|
3524
3936
|
});
|
|
3525
3937
|
}
|
|
3526
3938
|
function reconcileMorphChange({
|
|
3939
|
+
finalizeMeasurement,
|
|
3527
3940
|
root,
|
|
3528
3941
|
measurementLayer,
|
|
3529
3942
|
measurementBackend,
|
|
@@ -3578,6 +3991,7 @@ function reconcileMorphChange({
|
|
|
3578
3991
|
return nextMeasurement;
|
|
3579
3992
|
}
|
|
3580
3993
|
startMorph({
|
|
3994
|
+
finalizeMeasurement,
|
|
3581
3995
|
nextMeasurement,
|
|
3582
3996
|
session,
|
|
3583
3997
|
timeline,
|
|
@@ -3708,7 +4122,7 @@ function getMeasurementLayerStyle(layoutContext, useContentInlineSize = false) {
|
|
|
3708
4122
|
};
|
|
3709
4123
|
}
|
|
3710
4124
|
function resolveFlowText(committedMeasurement, stateMeasurement, text) {
|
|
3711
|
-
return
|
|
4125
|
+
return stateMeasurement?.snapshot.text ?? committedMeasurement?.snapshot.text ?? text;
|
|
3712
4126
|
}
|
|
3713
4127
|
function getOverlayStyle(plan) {
|
|
3714
4128
|
return {
|
|
@@ -3736,7 +4150,6 @@ function getLiveGlyphStyle(item, stage, visualBridge) {
|
|
|
3736
4150
|
top: item.top,
|
|
3737
4151
|
width: item.width,
|
|
3738
4152
|
height: item.height,
|
|
3739
|
-
lineHeight: `${item.height}px`,
|
|
3740
4153
|
opacity: getLiveOpacity(item, stage),
|
|
3741
4154
|
transform: getLiveTransform(item, stage, visualBridge),
|
|
3742
4155
|
transition: getLiveTransition(item, stage)
|
|
@@ -3749,28 +4162,52 @@ function getExitGlyphStyle(item, stage, visualBridge) {
|
|
|
3749
4162
|
top: item.top,
|
|
3750
4163
|
width: item.width,
|
|
3751
4164
|
height: item.height,
|
|
3752
|
-
lineHeight: `${item.height}px`,
|
|
3753
4165
|
opacity: getExitOpacity(stage),
|
|
3754
4166
|
transform: getExitTransform(visualBridge),
|
|
3755
4167
|
transition: getExitTransition(stage)
|
|
3756
4168
|
};
|
|
3757
4169
|
}
|
|
3758
|
-
function
|
|
4170
|
+
function getContextSliceStyle(layoutInlineSize, item) {
|
|
4171
|
+
return {
|
|
4172
|
+
...CONTEXT_SLICE_TEXT_STYLE,
|
|
4173
|
+
left: -item.left,
|
|
4174
|
+
top: -item.top,
|
|
4175
|
+
width: layoutInlineSize
|
|
4176
|
+
};
|
|
4177
|
+
}
|
|
4178
|
+
function MorphOverlay({
|
|
4179
|
+
overlayRef,
|
|
4180
|
+
stage,
|
|
4181
|
+
plan
|
|
4182
|
+
}) {
|
|
3759
4183
|
let exitItems = [];
|
|
3760
4184
|
if (stage !== "idle") {
|
|
3761
4185
|
exitItems = plan.exitItems;
|
|
3762
4186
|
}
|
|
3763
4187
|
return /* @__PURE__ */ jsxDEV("div", {
|
|
4188
|
+
ref: overlayRef,
|
|
3764
4189
|
"aria-hidden": "true",
|
|
3765
4190
|
style: getOverlayStyle(plan),
|
|
3766
4191
|
children: [
|
|
3767
4192
|
exitItems.map((item) => /* @__PURE__ */ jsxDEV("span", {
|
|
4193
|
+
"data-morph-role": "exit",
|
|
4194
|
+
"data-morph-key": item.key,
|
|
4195
|
+
"data-morph-glyph": item.glyph,
|
|
3768
4196
|
style: getExitGlyphStyle(item, stage, plan.visualBridge),
|
|
3769
|
-
children:
|
|
4197
|
+
children: /* @__PURE__ */ jsxDEV("span", {
|
|
4198
|
+
style: getContextSliceStyle(plan.layoutInlineSizeFrom, item),
|
|
4199
|
+
children: plan.sourceRenderText
|
|
4200
|
+
}, undefined, false, undefined, this)
|
|
3770
4201
|
}, `exit-${item.key}`, false, undefined, this)),
|
|
3771
4202
|
plan.liveItems.map((item) => /* @__PURE__ */ jsxDEV("span", {
|
|
4203
|
+
"data-morph-role": "live",
|
|
4204
|
+
"data-morph-key": item.key,
|
|
4205
|
+
"data-morph-glyph": item.glyph,
|
|
3772
4206
|
style: getLiveGlyphStyle(item, stage, plan.visualBridge),
|
|
3773
|
-
children:
|
|
4207
|
+
children: /* @__PURE__ */ jsxDEV("span", {
|
|
4208
|
+
style: getContextSliceStyle(plan.layoutInlineSizeTo, item),
|
|
4209
|
+
children: plan.targetRenderText
|
|
4210
|
+
}, undefined, false, undefined, this)
|
|
3774
4211
|
}, item.key, false, undefined, this))
|
|
3775
4212
|
]
|
|
3776
4213
|
}, undefined, true, undefined, this);
|
|
@@ -3779,55 +4216,63 @@ function MeasurementLayer({
|
|
|
3779
4216
|
layerRef,
|
|
3780
4217
|
layoutContext,
|
|
3781
4218
|
text,
|
|
3782
|
-
segments,
|
|
3783
4219
|
useContentInlineSize
|
|
3784
4220
|
}) {
|
|
3785
|
-
let glyphs = segments;
|
|
3786
|
-
if (text.length === 0) {
|
|
3787
|
-
glyphs = EMPTY_SEGMENTS;
|
|
3788
|
-
}
|
|
3789
4221
|
return /* @__PURE__ */ jsxDEV("span", {
|
|
3790
4222
|
ref: layerRef,
|
|
3791
4223
|
"aria-hidden": "true",
|
|
3792
4224
|
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))
|
|
4225
|
+
children: text
|
|
3798
4226
|
}, undefined, false, undefined, this);
|
|
3799
4227
|
}
|
|
3800
4228
|
function useMorphTransition(text, className) {
|
|
3801
4229
|
const { ref, layoutContext } = useObservedLayoutContext([className]);
|
|
4230
|
+
const debugInstanceIdRef = useRef(null);
|
|
3802
4231
|
const flowTextRef = useRef(null);
|
|
3803
4232
|
const measurementLayerRef = useRef(null);
|
|
3804
4233
|
const completedDomMeasurementKeyRef = useRef(null);
|
|
3805
4234
|
const domMeasurementSnapshotCacheRef = useRef(new Map);
|
|
3806
4235
|
const sessionRef = useRef({ ...EMPTY_SESSION });
|
|
3807
4236
|
const timelineRef = useRef({ ...EMPTY_TIMELINE });
|
|
4237
|
+
const debugDriftSignatureRef = useRef(null);
|
|
3808
4238
|
const [domMeasurementRequestKey, setDomMeasurementRequestKey] = useState(null);
|
|
4239
|
+
const [forceContentMeasurementText, setForceContentMeasurementText] = useState(null);
|
|
3809
4240
|
const [state, setState] = useState(EMPTY_STATE);
|
|
4241
|
+
if (debugInstanceIdRef.current === null) {
|
|
4242
|
+
debugInstanceIdRef.current = nextTorphDebugInstanceId();
|
|
4243
|
+
}
|
|
3810
4244
|
let measurementHint = sessionRef.current.committed;
|
|
3811
4245
|
if (sessionRef.current.animating) {
|
|
3812
4246
|
measurementHint = sessionRef.current.target ?? sessionRef.current.committed;
|
|
3813
4247
|
}
|
|
4248
|
+
const forceContentInlineSize = forceContentMeasurementText === text;
|
|
3814
4249
|
const measurementRequest = useMemo(() => createMorphMeasurementRequest({
|
|
3815
4250
|
text,
|
|
3816
4251
|
layoutContext,
|
|
3817
|
-
layoutHint: measurementHint
|
|
3818
|
-
|
|
4252
|
+
layoutHint: measurementHint,
|
|
4253
|
+
forceContentInlineSize
|
|
4254
|
+
}), [text, layoutContext, measurementHint, forceContentInlineSize]);
|
|
3819
4255
|
const renderText = measurementRequest?.renderText ?? text;
|
|
3820
4256
|
const useContentInlineSize = measurementRequest?.useContentInlineSize ?? false;
|
|
3821
4257
|
const measurementBackend = measurementRequest?.measurementBackend ?? null;
|
|
3822
4258
|
const segments = measurementRequest?.segments ?? EMPTY_SEGMENTS;
|
|
3823
4259
|
const domMeasurementKey = measurementRequest?.domMeasurementKey ?? null;
|
|
3824
4260
|
useLayoutEffect(() => {
|
|
4261
|
+
const config = readTorphDebugConfig();
|
|
4262
|
+
if (!shouldCaptureTorphTrace(config)) {
|
|
4263
|
+
return;
|
|
4264
|
+
}
|
|
4265
|
+
ensureTorphTraceApi();
|
|
4266
|
+
}, []);
|
|
4267
|
+
useLayoutEffect(() => {
|
|
4268
|
+
const finalizeMeasurement = (measurement) => refineMeasurementFromLiveNodes(measurement, ref.current, flowTextRef.current);
|
|
3825
4269
|
if (ref.current === null || layoutContext === null) {
|
|
3826
4270
|
completedDomMeasurementKeyRef.current = null;
|
|
3827
4271
|
if (domMeasurementRequestKey !== null) {
|
|
3828
4272
|
setDomMeasurementRequestKey(null);
|
|
3829
4273
|
}
|
|
3830
4274
|
reconcileMorphChange({
|
|
4275
|
+
finalizeMeasurement,
|
|
3831
4276
|
root: ref.current,
|
|
3832
4277
|
measurementLayer: measurementLayerRef.current,
|
|
3833
4278
|
measurementBackend,
|
|
@@ -3853,6 +4298,7 @@ function useMorphTransition(text, className) {
|
|
|
3853
4298
|
setDomMeasurementRequestKey(null);
|
|
3854
4299
|
}
|
|
3855
4300
|
reconcileMorphChange({
|
|
4301
|
+
finalizeMeasurement,
|
|
3856
4302
|
root: ref.current,
|
|
3857
4303
|
measurementLayer: null,
|
|
3858
4304
|
measurementBackend,
|
|
@@ -3875,7 +4321,8 @@ function useMorphTransition(text, className) {
|
|
|
3875
4321
|
if (measurementLayerRef.current === null) {
|
|
3876
4322
|
return;
|
|
3877
4323
|
}
|
|
3878
|
-
const
|
|
4324
|
+
const nextMeasurement2 = reconcileMorphChange({
|
|
4325
|
+
finalizeMeasurement,
|
|
3879
4326
|
root: ref.current,
|
|
3880
4327
|
measurementLayer: measurementLayerRef.current,
|
|
3881
4328
|
measurementBackend,
|
|
@@ -3888,9 +4335,9 @@ function useMorphTransition(text, className) {
|
|
|
3888
4335
|
timeline: timelineRef.current,
|
|
3889
4336
|
setState
|
|
3890
4337
|
});
|
|
3891
|
-
if (
|
|
4338
|
+
if (nextMeasurement2 !== null) {
|
|
3892
4339
|
if (canCacheMeasurementLayerSnapshot(measurementBackend)) {
|
|
3893
|
-
rememberCachedMorphSnapshot(domMeasurementSnapshotCacheRef.current, domMeasurementKey,
|
|
4340
|
+
rememberCachedMorphSnapshot(domMeasurementSnapshotCacheRef.current, domMeasurementKey, nextMeasurement2.snapshot);
|
|
3894
4341
|
}
|
|
3895
4342
|
}
|
|
3896
4343
|
completedDomMeasurementKeyRef.current = domMeasurementKey;
|
|
@@ -3908,7 +4355,8 @@ function useMorphTransition(text, className) {
|
|
|
3908
4355
|
if (domMeasurementRequestKey !== null) {
|
|
3909
4356
|
setDomMeasurementRequestKey(null);
|
|
3910
4357
|
}
|
|
3911
|
-
reconcileMorphChange({
|
|
4358
|
+
const nextMeasurement = reconcileMorphChange({
|
|
4359
|
+
finalizeMeasurement,
|
|
3912
4360
|
root: ref.current,
|
|
3913
4361
|
measurementLayer: measurementLayerRef.current,
|
|
3914
4362
|
measurementBackend,
|
|
@@ -3940,12 +4388,76 @@ function useMorphTransition(text, className) {
|
|
|
3940
4388
|
session: sessionRef.current
|
|
3941
4389
|
});
|
|
3942
4390
|
}, [layoutContext, state]);
|
|
4391
|
+
useLayoutEffect(() => {
|
|
4392
|
+
if (forceContentMeasurementText !== null && forceContentMeasurementText !== text) {
|
|
4393
|
+
setForceContentMeasurementText(null);
|
|
4394
|
+
return;
|
|
4395
|
+
}
|
|
4396
|
+
if (state.stage !== "idle" || state.measurement === null) {
|
|
4397
|
+
return;
|
|
4398
|
+
}
|
|
4399
|
+
const flowLineCount = readFlowLineCount(flowTextRef.current);
|
|
4400
|
+
const shouldHeal = shouldHealIdleMeasurementFromFlow(state.measurement, flowLineCount);
|
|
4401
|
+
if (shouldHeal) {
|
|
4402
|
+
if (forceContentMeasurementText !== text) {
|
|
4403
|
+
setForceContentMeasurementText(text);
|
|
4404
|
+
}
|
|
4405
|
+
return;
|
|
4406
|
+
}
|
|
4407
|
+
if (forceContentMeasurementText === text) {
|
|
4408
|
+
setForceContentMeasurementText(null);
|
|
4409
|
+
}
|
|
4410
|
+
}, [forceContentMeasurementText, state, text]);
|
|
4411
|
+
useLayoutEffect(() => {
|
|
4412
|
+
const config = readTorphDebugConfig();
|
|
4413
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
4414
|
+
debugDriftSignatureRef.current = null;
|
|
4415
|
+
return;
|
|
4416
|
+
}
|
|
4417
|
+
if (state.stage !== "idle" || state.measurement === null) {
|
|
4418
|
+
debugDriftSignatureRef.current = null;
|
|
4419
|
+
return;
|
|
4420
|
+
}
|
|
4421
|
+
const root = ref.current;
|
|
4422
|
+
const flowTextNode = flowTextRef.current;
|
|
4423
|
+
if (root === null || flowTextNode === null) {
|
|
4424
|
+
debugDriftSignatureRef.current = null;
|
|
4425
|
+
return;
|
|
4426
|
+
}
|
|
4427
|
+
const liveSnapshot = measureLiveFlowSnapshot(root, flowTextNode);
|
|
4428
|
+
if (liveSnapshot === null) {
|
|
4429
|
+
debugDriftSignatureRef.current = null;
|
|
4430
|
+
return;
|
|
4431
|
+
}
|
|
4432
|
+
const drift = measureSnapshotDrift(state.measurement.snapshot, liveSnapshot);
|
|
4433
|
+
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;
|
|
4434
|
+
if (!hasDrift) {
|
|
4435
|
+
debugDriftSignatureRef.current = null;
|
|
4436
|
+
return;
|
|
4437
|
+
}
|
|
4438
|
+
const signature = JSON.stringify({
|
|
4439
|
+
text,
|
|
4440
|
+
renderText: state.measurement.snapshot.renderText,
|
|
4441
|
+
drift: summarizeSnapshotDrift(drift)
|
|
4442
|
+
});
|
|
4443
|
+
if (debugDriftSignatureRef.current === signature) {
|
|
4444
|
+
return;
|
|
4445
|
+
}
|
|
4446
|
+
debugDriftSignatureRef.current = signature;
|
|
4447
|
+
logTorphDebug(debugInstanceIdRef.current, "effect:idle-flow-drift", {
|
|
4448
|
+
text,
|
|
4449
|
+
expected: summarizeDebugSnapshot(state.measurement.snapshot),
|
|
4450
|
+
actual: summarizeDebugSnapshot(liveSnapshot),
|
|
4451
|
+
drift: summarizeSnapshotDrift(drift)
|
|
4452
|
+
});
|
|
4453
|
+
}, [state, text]);
|
|
3943
4454
|
useLayoutEffect(() => {
|
|
3944
4455
|
return () => {
|
|
3945
4456
|
cancelTimeline(timelineRef.current);
|
|
3946
4457
|
};
|
|
3947
4458
|
}, []);
|
|
3948
4459
|
return {
|
|
4460
|
+
debugInstanceId: debugInstanceIdRef.current,
|
|
3949
4461
|
committedMeasurement: sessionRef.current.committed,
|
|
3950
4462
|
domMeasurementRequestKey,
|
|
3951
4463
|
flowTextRef,
|
|
@@ -3962,7 +4474,16 @@ function ActiveTorph({
|
|
|
3962
4474
|
text,
|
|
3963
4475
|
className
|
|
3964
4476
|
}) {
|
|
4477
|
+
const overlayRef = useRef(null);
|
|
4478
|
+
const debugFinalizeSignatureRef = useRef(null);
|
|
4479
|
+
const debugFrameHandleRef = useRef(null);
|
|
4480
|
+
const debugFrameOrdinalRef = useRef(0);
|
|
4481
|
+
const debugIdlePostFrameHandleRef = useRef(null);
|
|
4482
|
+
const debugIdlePostFrameOrdinalRef = useRef(0);
|
|
4483
|
+
const debugPendingIdlePostFramesRef = useRef(false);
|
|
4484
|
+
const debugPreviousStageRef = useRef(null);
|
|
3965
4485
|
const {
|
|
4486
|
+
debugInstanceId,
|
|
3966
4487
|
committedMeasurement,
|
|
3967
4488
|
domMeasurementRequestKey,
|
|
3968
4489
|
flowTextRef,
|
|
@@ -3978,19 +4499,338 @@ function ActiveTorph({
|
|
|
3978
4499
|
const shouldRenderOverlay = state.stage !== "idle" && plan !== null;
|
|
3979
4500
|
const shouldRenderMeasurementLayer = domMeasurementRequestKey !== null;
|
|
3980
4501
|
const flowText = resolveFlowText(committedMeasurement, state.measurement, text);
|
|
4502
|
+
useLayoutEffect(() => {
|
|
4503
|
+
const config = readTorphDebugConfig();
|
|
4504
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
4505
|
+
return;
|
|
4506
|
+
}
|
|
4507
|
+
logTorphDebug(debugInstanceId, "effect:trace-meta", {
|
|
4508
|
+
traceSchemaVersion: TORPH_TRACE_SCHEMA_VERSION,
|
|
4509
|
+
includesIdlePostFrame: true,
|
|
4510
|
+
includesViewportAnchors: true,
|
|
4511
|
+
includesRootOriginRefine: true
|
|
4512
|
+
});
|
|
4513
|
+
}, [debugInstanceId]);
|
|
4514
|
+
useLayoutEffect(() => {
|
|
4515
|
+
const config = readTorphDebugConfig();
|
|
4516
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
4517
|
+
debugPendingIdlePostFramesRef.current = false;
|
|
4518
|
+
debugPreviousStageRef.current = state.stage;
|
|
4519
|
+
return;
|
|
4520
|
+
}
|
|
4521
|
+
const previousStage = debugPreviousStageRef.current;
|
|
4522
|
+
if (previousStage !== state.stage) {
|
|
4523
|
+
if (state.stage === "idle") {
|
|
4524
|
+
debugPendingIdlePostFramesRef.current = true;
|
|
4525
|
+
}
|
|
4526
|
+
logTorphDebug(debugInstanceId, "effect:stage-transition", {
|
|
4527
|
+
text,
|
|
4528
|
+
fromStage: previousStage,
|
|
4529
|
+
toStage: state.stage,
|
|
4530
|
+
committed: summarizeDebugMeasurement(committedMeasurement),
|
|
4531
|
+
stateMeasurement: summarizeDebugMeasurement(state.measurement),
|
|
4532
|
+
flowText
|
|
4533
|
+
});
|
|
4534
|
+
debugPreviousStageRef.current = state.stage;
|
|
4535
|
+
}
|
|
4536
|
+
}, [committedMeasurement, debugInstanceId, flowText, state, text]);
|
|
4537
|
+
useLayoutEffect(() => {
|
|
4538
|
+
const config = readTorphDebugConfig();
|
|
4539
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
4540
|
+
if (debugFrameHandleRef.current !== null) {
|
|
4541
|
+
cancelAnimationFrame(debugFrameHandleRef.current);
|
|
4542
|
+
debugFrameHandleRef.current = null;
|
|
4543
|
+
}
|
|
4544
|
+
return;
|
|
4545
|
+
}
|
|
4546
|
+
if (state.stage === "idle" || state.measurement === null) {
|
|
4547
|
+
if (debugFrameHandleRef.current !== null) {
|
|
4548
|
+
cancelAnimationFrame(debugFrameHandleRef.current);
|
|
4549
|
+
debugFrameHandleRef.current = null;
|
|
4550
|
+
}
|
|
4551
|
+
debugFrameOrdinalRef.current = 0;
|
|
4552
|
+
return;
|
|
4553
|
+
}
|
|
4554
|
+
debugFrameOrdinalRef.current = 0;
|
|
4555
|
+
const measurement = state.measurement;
|
|
4556
|
+
let cancelled = false;
|
|
4557
|
+
const captureFrame = () => {
|
|
4558
|
+
if (cancelled) {
|
|
4559
|
+
return;
|
|
4560
|
+
}
|
|
4561
|
+
const root = ref.current;
|
|
4562
|
+
const flowNode = flowTextRef.current;
|
|
4563
|
+
const overlayNode = overlayRef.current;
|
|
4564
|
+
let rootRect = null;
|
|
4565
|
+
if (root !== null) {
|
|
4566
|
+
rootRect = root.getBoundingClientRect();
|
|
4567
|
+
}
|
|
4568
|
+
let flowRect = null;
|
|
4569
|
+
if (flowNode !== null) {
|
|
4570
|
+
flowRect = flowNode.getBoundingClientRect();
|
|
4571
|
+
}
|
|
4572
|
+
let overlayRect = null;
|
|
4573
|
+
if (overlayNode !== null) {
|
|
4574
|
+
overlayRect = overlayNode.getBoundingClientRect();
|
|
4575
|
+
}
|
|
4576
|
+
let overlayLiveSnapshot = null;
|
|
4577
|
+
if (root !== null && overlayNode !== null) {
|
|
4578
|
+
overlayLiveSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "live");
|
|
4579
|
+
}
|
|
4580
|
+
let overlayExitSnapshot = null;
|
|
4581
|
+
if (root !== null && overlayNode !== null) {
|
|
4582
|
+
overlayExitSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "exit");
|
|
4583
|
+
}
|
|
4584
|
+
let flowSnapshot = null;
|
|
4585
|
+
if (root !== null && flowNode !== null) {
|
|
4586
|
+
flowSnapshot = measureLiveFlowSnapshot(root, flowNode);
|
|
4587
|
+
}
|
|
4588
|
+
let overlayLiveDrift = null;
|
|
4589
|
+
if (overlayLiveSnapshot !== null) {
|
|
4590
|
+
overlayLiveDrift = summarizeSnapshotDrift(measureSnapshotDrift(measurement.snapshot, overlayLiveSnapshot));
|
|
4591
|
+
}
|
|
4592
|
+
let flowDrift = null;
|
|
4593
|
+
if (flowSnapshot !== null) {
|
|
4594
|
+
flowDrift = summarizeSnapshotDrift(measureSnapshotDrift(measurement.snapshot, flowSnapshot));
|
|
4595
|
+
}
|
|
4596
|
+
let planSummary = null;
|
|
4597
|
+
if (plan !== null) {
|
|
4598
|
+
planSummary = {
|
|
4599
|
+
frameWidth: roundDebugValue(plan.frameWidth),
|
|
4600
|
+
frameHeight: roundDebugValue(plan.frameHeight),
|
|
4601
|
+
layoutInlineSizeFrom: roundDebugValue(plan.layoutInlineSizeFrom),
|
|
4602
|
+
layoutInlineSizeTo: roundDebugValue(plan.layoutInlineSizeTo),
|
|
4603
|
+
sourceRenderText: plan.sourceRenderText,
|
|
4604
|
+
targetRenderText: plan.targetRenderText,
|
|
4605
|
+
visualBridge: {
|
|
4606
|
+
offsetX: roundDebugValue(plan.visualBridge.offsetX),
|
|
4607
|
+
offsetY: roundDebugValue(plan.visualBridge.offsetY)
|
|
4608
|
+
},
|
|
4609
|
+
liveItems: plan.liveItems.length,
|
|
4610
|
+
exitItems: plan.exitItems.length
|
|
4611
|
+
};
|
|
4612
|
+
}
|
|
4613
|
+
logTorphDebug(debugInstanceId, "effect:frame-snapshot", {
|
|
4614
|
+
text,
|
|
4615
|
+
frame: debugFrameOrdinalRef.current,
|
|
4616
|
+
stateStage: state.stage,
|
|
4617
|
+
propText: text,
|
|
4618
|
+
flowText,
|
|
4619
|
+
committed: summarizeDebugMeasurement(committedMeasurement),
|
|
4620
|
+
stateMeasurement: summarizeDebugMeasurement(measurement),
|
|
4621
|
+
plan: planSummary,
|
|
4622
|
+
rootBox: summarizeDebugRect(rootRect),
|
|
4623
|
+
overlayBox: summarizeDebugRect(overlayRect),
|
|
4624
|
+
flowBox: summarizeDebugRect(flowRect),
|
|
4625
|
+
rootOriginDrift: summarizeDebugRootOriginDrift(measurement, rootRect),
|
|
4626
|
+
overlayLive: summarizeDebugSnapshot(overlayLiveSnapshot),
|
|
4627
|
+
overlayLiveViewportAnchors: summarizeDebugViewportAnchors(overlayLiveSnapshot, rootRect),
|
|
4628
|
+
overlayLiveDrift,
|
|
4629
|
+
overlayExit: summarizeDebugSnapshot(overlayExitSnapshot),
|
|
4630
|
+
overlayExitViewportAnchors: summarizeDebugViewportAnchors(overlayExitSnapshot, rootRect),
|
|
4631
|
+
flow: summarizeDebugSnapshot(flowSnapshot),
|
|
4632
|
+
flowViewportAnchors: summarizeDebugViewportAnchors(flowSnapshot, rootRect),
|
|
4633
|
+
flowDrift
|
|
4634
|
+
});
|
|
4635
|
+
debugFrameOrdinalRef.current += 1;
|
|
4636
|
+
debugFrameHandleRef.current = requestAnimationFrame(captureFrame);
|
|
4637
|
+
};
|
|
4638
|
+
debugFrameHandleRef.current = requestAnimationFrame(captureFrame);
|
|
4639
|
+
return () => {
|
|
4640
|
+
cancelled = true;
|
|
4641
|
+
if (debugFrameHandleRef.current !== null) {
|
|
4642
|
+
cancelAnimationFrame(debugFrameHandleRef.current);
|
|
4643
|
+
debugFrameHandleRef.current = null;
|
|
4644
|
+
}
|
|
4645
|
+
};
|
|
4646
|
+
}, [committedMeasurement, debugInstanceId, flowText, plan, ref, state, text]);
|
|
4647
|
+
useLayoutEffect(() => {
|
|
4648
|
+
const config = readTorphDebugConfig();
|
|
4649
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
4650
|
+
debugPendingIdlePostFramesRef.current = false;
|
|
4651
|
+
if (debugIdlePostFrameHandleRef.current !== null) {
|
|
4652
|
+
cancelAnimationFrame(debugIdlePostFrameHandleRef.current);
|
|
4653
|
+
debugIdlePostFrameHandleRef.current = null;
|
|
4654
|
+
}
|
|
4655
|
+
return;
|
|
4656
|
+
}
|
|
4657
|
+
if (!debugPendingIdlePostFramesRef.current) {
|
|
4658
|
+
return;
|
|
4659
|
+
}
|
|
4660
|
+
if (state.stage !== "idle" || state.measurement === null) {
|
|
4661
|
+
return;
|
|
4662
|
+
}
|
|
4663
|
+
debugPendingIdlePostFramesRef.current = false;
|
|
4664
|
+
debugIdlePostFrameOrdinalRef.current = 0;
|
|
4665
|
+
const measurement = state.measurement;
|
|
4666
|
+
let remainingFrames = 3;
|
|
4667
|
+
let cancelled = false;
|
|
4668
|
+
const captureIdlePostFrame = () => {
|
|
4669
|
+
if (cancelled) {
|
|
4670
|
+
return;
|
|
4671
|
+
}
|
|
4672
|
+
const root = ref.current;
|
|
4673
|
+
const flowNode = flowTextRef.current;
|
|
4674
|
+
if (root === null || flowNode === null) {
|
|
4675
|
+
return;
|
|
4676
|
+
}
|
|
4677
|
+
const rootRect = root.getBoundingClientRect();
|
|
4678
|
+
const flowRect = flowNode.getBoundingClientRect();
|
|
4679
|
+
const flowSnapshot = measureLiveFlowSnapshot(root, flowNode);
|
|
4680
|
+
let flowDrift = null;
|
|
4681
|
+
if (flowSnapshot !== null) {
|
|
4682
|
+
flowDrift = summarizeSnapshotDrift(measureSnapshotDrift(measurement.snapshot, flowSnapshot));
|
|
4683
|
+
}
|
|
4684
|
+
logTorphDebug(debugInstanceId, "effect:idle-post-frame", {
|
|
4685
|
+
text,
|
|
4686
|
+
frame: debugIdlePostFrameOrdinalRef.current,
|
|
4687
|
+
stateStage: state.stage,
|
|
4688
|
+
propText: text,
|
|
4689
|
+
flowText,
|
|
4690
|
+
committed: summarizeDebugMeasurement(committedMeasurement),
|
|
4691
|
+
stateMeasurement: summarizeDebugMeasurement(measurement),
|
|
4692
|
+
rootBox: summarizeDebugRect(rootRect),
|
|
4693
|
+
flowBox: summarizeDebugRect(flowRect),
|
|
4694
|
+
rootOriginDrift: summarizeDebugRootOriginDrift(measurement, rootRect),
|
|
4695
|
+
flow: summarizeDebugSnapshot(flowSnapshot),
|
|
4696
|
+
flowViewportAnchors: summarizeDebugViewportAnchors(flowSnapshot, rootRect),
|
|
4697
|
+
flowDrift
|
|
4698
|
+
});
|
|
4699
|
+
debugIdlePostFrameOrdinalRef.current += 1;
|
|
4700
|
+
remainingFrames -= 1;
|
|
4701
|
+
if (remainingFrames <= 0) {
|
|
4702
|
+
debugIdlePostFrameHandleRef.current = null;
|
|
4703
|
+
return;
|
|
4704
|
+
}
|
|
4705
|
+
debugIdlePostFrameHandleRef.current = requestAnimationFrame(captureIdlePostFrame);
|
|
4706
|
+
};
|
|
4707
|
+
debugIdlePostFrameHandleRef.current = requestAnimationFrame(captureIdlePostFrame);
|
|
4708
|
+
return () => {
|
|
4709
|
+
cancelled = true;
|
|
4710
|
+
if (debugIdlePostFrameHandleRef.current !== null) {
|
|
4711
|
+
cancelAnimationFrame(debugIdlePostFrameHandleRef.current);
|
|
4712
|
+
debugIdlePostFrameHandleRef.current = null;
|
|
4713
|
+
}
|
|
4714
|
+
};
|
|
4715
|
+
}, [committedMeasurement, debugInstanceId, flowText, ref, state, text]);
|
|
4716
|
+
useLayoutEffect(() => {
|
|
4717
|
+
return () => {
|
|
4718
|
+
if (debugIdlePostFrameHandleRef.current !== null) {
|
|
4719
|
+
cancelAnimationFrame(debugIdlePostFrameHandleRef.current);
|
|
4720
|
+
debugIdlePostFrameHandleRef.current = null;
|
|
4721
|
+
}
|
|
4722
|
+
};
|
|
4723
|
+
}, []);
|
|
4724
|
+
useLayoutEffect(() => {
|
|
4725
|
+
const config = readTorphDebugConfig();
|
|
4726
|
+
if (!shouldRunTorphInstrumentation(config)) {
|
|
4727
|
+
debugFinalizeSignatureRef.current = null;
|
|
4728
|
+
return;
|
|
4729
|
+
}
|
|
4730
|
+
if (state.stage !== "animate" || state.measurement === null || plan === null) {
|
|
4731
|
+
debugFinalizeSignatureRef.current = null;
|
|
4732
|
+
return;
|
|
4733
|
+
}
|
|
4734
|
+
const root = ref.current;
|
|
4735
|
+
const overlayNode = overlayRef.current;
|
|
4736
|
+
const flowNode = flowTextRef.current;
|
|
4737
|
+
if (root === null || overlayNode === null || flowNode === null) {
|
|
4738
|
+
debugFinalizeSignatureRef.current = null;
|
|
4739
|
+
return;
|
|
4740
|
+
}
|
|
4741
|
+
const measurement = state.measurement;
|
|
4742
|
+
let handled = false;
|
|
4743
|
+
const capture = (event) => {
|
|
4744
|
+
if (handled) {
|
|
4745
|
+
return;
|
|
4746
|
+
}
|
|
4747
|
+
if (event.propertyName !== "transform") {
|
|
4748
|
+
return;
|
|
4749
|
+
}
|
|
4750
|
+
const target = event.target;
|
|
4751
|
+
if (!(target instanceof HTMLElement)) {
|
|
4752
|
+
return;
|
|
4753
|
+
}
|
|
4754
|
+
if (target.dataset.morphRole !== "live") {
|
|
4755
|
+
return;
|
|
4756
|
+
}
|
|
4757
|
+
handled = true;
|
|
4758
|
+
const overlayLiveSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "live");
|
|
4759
|
+
const overlayExitSnapshot = measureOverlayBoxSnapshot(root, overlayNode, "exit");
|
|
4760
|
+
const flowSnapshot = measureLiveFlowSnapshot(root, flowNode);
|
|
4761
|
+
if (overlayLiveSnapshot === null || flowSnapshot === null) {
|
|
4762
|
+
return;
|
|
4763
|
+
}
|
|
4764
|
+
const overlayLiveDrift = measureSnapshotDrift(measurement.snapshot, overlayLiveSnapshot);
|
|
4765
|
+
const flowDrift = measureSnapshotDrift(measurement.snapshot, flowSnapshot);
|
|
4766
|
+
const rootRect = root.getBoundingClientRect();
|
|
4767
|
+
const flowRect = flowNode.getBoundingClientRect();
|
|
4768
|
+
const overlayRect = overlayNode.getBoundingClientRect();
|
|
4769
|
+
const signature = JSON.stringify({
|
|
4770
|
+
text,
|
|
4771
|
+
renderText: measurement.snapshot.renderText,
|
|
4772
|
+
overlayLiveDrift: summarizeSnapshotDrift(overlayLiveDrift),
|
|
4773
|
+
flowDrift: summarizeSnapshotDrift(flowDrift),
|
|
4774
|
+
overlayWidth: roundDebugValue(overlayRect.width),
|
|
4775
|
+
rootWidth: roundDebugValue(rootRect.width)
|
|
4776
|
+
});
|
|
4777
|
+
if (debugFinalizeSignatureRef.current === signature) {
|
|
4778
|
+
return;
|
|
4779
|
+
}
|
|
4780
|
+
debugFinalizeSignatureRef.current = signature;
|
|
4781
|
+
logTorphDebug(debugInstanceId, "effect:animate-finalize-snapshot", {
|
|
4782
|
+
text,
|
|
4783
|
+
target: {
|
|
4784
|
+
layoutInlineSize: roundDebugValue(measurement.layoutInlineSize),
|
|
4785
|
+
reservedInlineSize: roundDebugValue(measurement.reservedInlineSize),
|
|
4786
|
+
flowInlineSize: roundDebugValue(measurement.flowInlineSize),
|
|
4787
|
+
rootOrigin: {
|
|
4788
|
+
left: roundDebugValue(measurement.rootOrigin.left),
|
|
4789
|
+
top: roundDebugValue(measurement.rootOrigin.top)
|
|
4790
|
+
},
|
|
4791
|
+
snapshot: summarizeDebugSnapshot(measurement.snapshot)
|
|
4792
|
+
},
|
|
4793
|
+
overlayLive: summarizeDebugSnapshot(overlayLiveSnapshot),
|
|
4794
|
+
overlayLiveDrift: summarizeSnapshotDrift(overlayLiveDrift),
|
|
4795
|
+
overlayExit: summarizeDebugSnapshot(overlayExitSnapshot),
|
|
4796
|
+
flow: summarizeDebugSnapshot(flowSnapshot),
|
|
4797
|
+
flowDrift: summarizeSnapshotDrift(flowDrift),
|
|
4798
|
+
rootOriginDrift: summarizeDebugRootOriginDrift(measurement, rootRect),
|
|
4799
|
+
overlayLiveViewportAnchors: summarizeDebugViewportAnchors(overlayLiveSnapshot, rootRect),
|
|
4800
|
+
overlayExitViewportAnchors: summarizeDebugViewportAnchors(overlayExitSnapshot, rootRect),
|
|
4801
|
+
flowViewportAnchors: summarizeDebugViewportAnchors(flowSnapshot, rootRect),
|
|
4802
|
+
rootBox: {
|
|
4803
|
+
width: roundDebugValue(rootRect.width),
|
|
4804
|
+
height: roundDebugValue(rootRect.height)
|
|
4805
|
+
},
|
|
4806
|
+
overlayBox: {
|
|
4807
|
+
width: roundDebugValue(overlayRect.width),
|
|
4808
|
+
height: roundDebugValue(overlayRect.height)
|
|
4809
|
+
},
|
|
4810
|
+
flowBox: {
|
|
4811
|
+
width: roundDebugValue(flowRect.width),
|
|
4812
|
+
height: roundDebugValue(flowRect.height)
|
|
4813
|
+
}
|
|
4814
|
+
});
|
|
4815
|
+
};
|
|
4816
|
+
overlayNode.addEventListener("transitionend", capture);
|
|
4817
|
+
return () => {
|
|
4818
|
+
overlayNode.removeEventListener("transitionend", capture);
|
|
4819
|
+
};
|
|
4820
|
+
}, [debugInstanceId, plan, ref, state, text]);
|
|
3981
4821
|
let measurementLayer = null;
|
|
3982
4822
|
if (shouldRenderMeasurementLayer) {
|
|
3983
4823
|
measurementLayer = /* @__PURE__ */ jsxDEV(MeasurementLayer, {
|
|
3984
4824
|
layerRef: measurementLayerRef,
|
|
3985
4825
|
layoutContext,
|
|
3986
4826
|
text: renderText,
|
|
3987
|
-
segments,
|
|
3988
4827
|
useContentInlineSize
|
|
3989
4828
|
}, undefined, false, undefined, this);
|
|
3990
4829
|
}
|
|
3991
4830
|
let overlay = null;
|
|
3992
4831
|
if (shouldRenderOverlay) {
|
|
3993
4832
|
overlay = /* @__PURE__ */ jsxDEV(MorphOverlay, {
|
|
4833
|
+
overlayRef,
|
|
3994
4834
|
stage: state.stage,
|
|
3995
4835
|
plan
|
|
3996
4836
|
}, undefined, false, undefined, this);
|
|
@@ -4028,9 +4868,11 @@ function Torph({
|
|
|
4028
4868
|
}
|
|
4029
4869
|
export {
|
|
4030
4870
|
supportsIntrinsicWidthLock,
|
|
4871
|
+
shouldHealIdleMeasurementFromFlow,
|
|
4031
4872
|
resolveMorphFrameBounds,
|
|
4032
4873
|
resolveFlowText,
|
|
4033
4874
|
resolveContentWidthLockInlineSize,
|
|
4875
|
+
refineMeasurementWithLiveGeometry,
|
|
4034
4876
|
pairMorphCharacters,
|
|
4035
4877
|
needsMeasurementLayer,
|
|
4036
4878
|
measureMorphSnapshotFromLayer,
|
|
@@ -40,6 +40,8 @@ export type MorphRenderPlan = {
|
|
|
40
40
|
frameHeight: number;
|
|
41
41
|
layoutInlineSizeFrom: number;
|
|
42
42
|
layoutInlineSizeTo: number;
|
|
43
|
+
sourceRenderText: string;
|
|
44
|
+
targetRenderText: string;
|
|
43
45
|
visualBridge: MorphVisualBridge;
|
|
44
46
|
liveItems: MorphLiveItem[];
|
|
45
47
|
exitItems: MorphCharacterLayout[];
|
|
@@ -81,6 +83,14 @@ type GlyphPairing = GlyphMove | GlyphEnter | GlyphExit;
|
|
|
81
83
|
export declare function needsMeasurementLayer(measurementBackend: PretextMorphMeasurementBackend, renderText: string): boolean;
|
|
82
84
|
export declare function measureMorphSnapshotFromLayer(text: string, renderText: string, segments: readonly MorphSegment[], layer: HTMLElement | null): MorphSnapshot;
|
|
83
85
|
export declare function resolveContentWidthLockInlineSize(layoutHint: MorphMeasurement): number;
|
|
86
|
+
export declare function shouldHealIdleMeasurementFromFlow(measurement: MorphMeasurement, flowLineCount: number | null): boolean;
|
|
87
|
+
export declare function refineMeasurementWithLiveGeometry(measurement: MorphMeasurement, liveGeometry: {
|
|
88
|
+
flowInlineSize: number | null;
|
|
89
|
+
rootOrigin: {
|
|
90
|
+
left: number;
|
|
91
|
+
top: number;
|
|
92
|
+
};
|
|
93
|
+
}): MorphMeasurement;
|
|
84
94
|
export declare function pairMorphCharacters(previous: MorphCharacterLayout[], next: MorphCharacterLayout[]): GlyphPairing[];
|
|
85
95
|
export declare function resolveMorphFrameBounds(previous: MorphSnapshot, next: MorphSnapshot): {
|
|
86
96
|
width: number;
|