@grahlnn/comps 0.1.6 → 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 +982 -114
- package/dist/torph/src/components/Torph.d.ts +12 -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,13 +3282,182 @@ 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) {
|
|
3077
3289
|
const rect = node.getBoundingClientRect();
|
|
3078
3290
|
return { left: rect.left, top: rect.top };
|
|
3079
3291
|
}
|
|
3292
|
+
function readFlowInlineSize(node) {
|
|
3293
|
+
if (node === null) {
|
|
3294
|
+
return null;
|
|
3295
|
+
}
|
|
3296
|
+
return node.getBoundingClientRect().width;
|
|
3297
|
+
}
|
|
3298
|
+
function readFlowLineCount(node) {
|
|
3299
|
+
if (node === null) {
|
|
3300
|
+
return null;
|
|
3301
|
+
}
|
|
3302
|
+
const rects = Array.from(node.getClientRects());
|
|
3303
|
+
if (rects.length === 0) {
|
|
3304
|
+
if ((node.textContent ?? "").length === 0) {
|
|
3305
|
+
return 0;
|
|
3306
|
+
}
|
|
3307
|
+
return 1;
|
|
3308
|
+
}
|
|
3309
|
+
let lineCount = 0;
|
|
3310
|
+
let currentTop = null;
|
|
3311
|
+
for (const rect of rects) {
|
|
3312
|
+
if (currentTop === null || !nearlyEqual(rect.top, currentTop, MORPH.lineGroupingEpsilon)) {
|
|
3313
|
+
currentTop = rect.top;
|
|
3314
|
+
lineCount += 1;
|
|
3315
|
+
}
|
|
3316
|
+
}
|
|
3317
|
+
return lineCount;
|
|
3318
|
+
}
|
|
3319
|
+
function readFirstTextNode(node) {
|
|
3320
|
+
if (node === null) {
|
|
3321
|
+
return null;
|
|
3322
|
+
}
|
|
3323
|
+
for (const childNode of node.childNodes) {
|
|
3324
|
+
if (childNode.nodeType === Node.TEXT_NODE) {
|
|
3325
|
+
return childNode;
|
|
3326
|
+
}
|
|
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
|
+
}
|
|
3080
3461
|
function getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize) {
|
|
3081
3462
|
const backend = getPretextMorphMeasurementBackend(text, layoutContext);
|
|
3082
3463
|
if (backend !== "probe") {
|
|
@@ -3099,6 +3480,12 @@ function getTrustedPretextMeasurementBackend(text, renderText, layoutContext, us
|
|
|
3099
3480
|
}
|
|
3100
3481
|
return "dom";
|
|
3101
3482
|
}
|
|
3483
|
+
function resolveContentWidthLockInlineSize(layoutHint) {
|
|
3484
|
+
if (layoutHint.flowInlineSize !== null) {
|
|
3485
|
+
return layoutHint.flowInlineSize;
|
|
3486
|
+
}
|
|
3487
|
+
return layoutHint.snapshot.width;
|
|
3488
|
+
}
|
|
3102
3489
|
function shouldMeasureUsingContentInlineSize(layoutContext, layoutHint) {
|
|
3103
3490
|
if (supportsIntrinsicWidthLock(layoutContext.display, layoutContext.parentDisplay)) {
|
|
3104
3491
|
return true;
|
|
@@ -3109,18 +3496,50 @@ function shouldMeasureUsingContentInlineSize(layoutContext, layoutHint) {
|
|
|
3109
3496
|
if (layoutHint === null || !isSingleLineSnapshot(layoutHint.snapshot)) {
|
|
3110
3497
|
return false;
|
|
3111
3498
|
}
|
|
3112
|
-
return nearlyEqual(layoutHint.layoutInlineSize, layoutHint
|
|
3499
|
+
return nearlyEqual(layoutHint.layoutInlineSize, resolveContentWidthLockInlineSize(layoutHint), MORPH.contentWidthLockEpsilon);
|
|
3500
|
+
}
|
|
3501
|
+
function shouldHealIdleMeasurementFromFlow(measurement, flowLineCount) {
|
|
3502
|
+
if (flowLineCount !== 1) {
|
|
3503
|
+
return false;
|
|
3504
|
+
}
|
|
3505
|
+
return countSnapshotLines(measurement.snapshot) > 1;
|
|
3506
|
+
}
|
|
3507
|
+
function refineMeasurementWithLiveGeometry(measurement, liveGeometry) {
|
|
3508
|
+
const sameFlowInlineSize = measurement.flowInlineSize === null && liveGeometry.flowInlineSize === null || measurement.flowInlineSize !== null && liveGeometry.flowInlineSize !== null && nearlyEqual(measurement.flowInlineSize, liveGeometry.flowInlineSize);
|
|
3509
|
+
if (sameFlowInlineSize && nearlyEqual(measurement.rootOrigin.left, liveGeometry.rootOrigin.left) && nearlyEqual(measurement.rootOrigin.top, liveGeometry.rootOrigin.top)) {
|
|
3510
|
+
return measurement;
|
|
3511
|
+
}
|
|
3512
|
+
return {
|
|
3513
|
+
snapshot: measurement.snapshot,
|
|
3514
|
+
layoutInlineSize: measurement.layoutInlineSize,
|
|
3515
|
+
reservedInlineSize: measurement.reservedInlineSize,
|
|
3516
|
+
flowInlineSize: liveGeometry.flowInlineSize,
|
|
3517
|
+
rootOrigin: liveGeometry.rootOrigin
|
|
3518
|
+
};
|
|
3519
|
+
}
|
|
3520
|
+
function refineMeasurementFromLiveNodes(measurement, root, flowTextNode) {
|
|
3521
|
+
if (root === null) {
|
|
3522
|
+
return measurement;
|
|
3523
|
+
}
|
|
3524
|
+
return refineMeasurementWithLiveGeometry(measurement, {
|
|
3525
|
+
flowInlineSize: readFlowInlineSize(flowTextNode),
|
|
3526
|
+
rootOrigin: readRootOrigin(root)
|
|
3527
|
+
});
|
|
3113
3528
|
}
|
|
3114
3529
|
function createMorphMeasurementRequest({
|
|
3115
3530
|
text,
|
|
3116
3531
|
layoutContext,
|
|
3117
|
-
layoutHint
|
|
3532
|
+
layoutHint,
|
|
3533
|
+
forceContentInlineSize = false
|
|
3118
3534
|
}) {
|
|
3119
3535
|
if (layoutContext === null) {
|
|
3120
3536
|
return null;
|
|
3121
3537
|
}
|
|
3122
3538
|
const renderText = getPretextMorphRenderedText(text, layoutContext);
|
|
3123
|
-
|
|
3539
|
+
let useContentInlineSize = shouldMeasureUsingContentInlineSize(layoutContext, layoutHint);
|
|
3540
|
+
if (forceContentInlineSize) {
|
|
3541
|
+
useContentInlineSize = true;
|
|
3542
|
+
}
|
|
3124
3543
|
const measurementBackend = getTrustedPretextMeasurementBackend(text, renderText, layoutContext, useContentInlineSize);
|
|
3125
3544
|
let segments = readCachedMorphSegments(renderText);
|
|
3126
3545
|
if (measurementBackend === "pretext") {
|
|
@@ -3244,6 +3663,7 @@ function measureFromNodes({
|
|
|
3244
3663
|
snapshot,
|
|
3245
3664
|
layoutInlineSize,
|
|
3246
3665
|
reservedInlineSize,
|
|
3666
|
+
flowInlineSize: null,
|
|
3247
3667
|
rootOrigin: readRootOrigin(root)
|
|
3248
3668
|
};
|
|
3249
3669
|
}
|
|
@@ -3255,6 +3675,7 @@ function pinMeasurementToCurrentOrigin(measurement, origin) {
|
|
|
3255
3675
|
snapshot: measurement.snapshot,
|
|
3256
3676
|
layoutInlineSize: measurement.layoutInlineSize,
|
|
3257
3677
|
reservedInlineSize: measurement.reservedInlineSize,
|
|
3678
|
+
flowInlineSize: measurement.flowInlineSize,
|
|
3258
3679
|
rootOrigin: origin
|
|
3259
3680
|
};
|
|
3260
3681
|
}
|
|
@@ -3334,6 +3755,8 @@ function buildMorphPlan(previous, next, visualBridge = ZERO_BRIDGE) {
|
|
|
3334
3755
|
frameHeight: frame.height,
|
|
3335
3756
|
layoutInlineSizeFrom: previous.layoutInlineSize,
|
|
3336
3757
|
layoutInlineSizeTo: next.layoutInlineSize,
|
|
3758
|
+
sourceRenderText: previous.snapshot.renderText,
|
|
3759
|
+
targetRenderText: next.snapshot.renderText,
|
|
3337
3760
|
visualBridge,
|
|
3338
3761
|
liveItems: next.snapshot.graphemes.map((grapheme) => {
|
|
3339
3762
|
const move = movesByDestinationKey.get(grapheme.key);
|
|
@@ -3384,7 +3807,7 @@ function sameMeasurement(a, b) {
|
|
|
3384
3807
|
if (a === b) {
|
|
3385
3808
|
return true;
|
|
3386
3809
|
}
|
|
3387
|
-
return sameSnapshot(a.snapshot, b.snapshot) && nearlyEqual(a.layoutInlineSize, b.layoutInlineSize) && (a.reservedInlineSize === null && b.reservedInlineSize === null || a.reservedInlineSize !== null && b.reservedInlineSize !== null && nearlyEqual(a.reservedInlineSize, b.reservedInlineSize)) && nearlyEqual(a.rootOrigin.left, b.rootOrigin.left) && nearlyEqual(a.rootOrigin.top, b.rootOrigin.top);
|
|
3810
|
+
return sameSnapshot(a.snapshot, b.snapshot) && nearlyEqual(a.layoutInlineSize, b.layoutInlineSize) && (a.reservedInlineSize === null && b.reservedInlineSize === null || a.reservedInlineSize !== null && b.reservedInlineSize !== null && nearlyEqual(a.reservedInlineSize, b.reservedInlineSize)) && (a.flowInlineSize === null && b.flowInlineSize === null || a.flowInlineSize !== null && b.flowInlineSize !== null && nearlyEqual(a.flowInlineSize, b.flowInlineSize)) && nearlyEqual(a.rootOrigin.left, b.rootOrigin.left) && nearlyEqual(a.rootOrigin.top, b.rootOrigin.top);
|
|
3388
3811
|
}
|
|
3389
3812
|
function refreshAnimatingTarget(activeTarget, measurement) {
|
|
3390
3813
|
if (sameMeasurement(activeTarget, measurement)) {
|
|
@@ -3394,6 +3817,7 @@ function refreshAnimatingTarget(activeTarget, measurement) {
|
|
|
3394
3817
|
snapshot: activeTarget.snapshot,
|
|
3395
3818
|
layoutInlineSize: measurement.layoutInlineSize,
|
|
3396
3819
|
reservedInlineSize: measurement.reservedInlineSize,
|
|
3820
|
+
flowInlineSize: activeTarget.flowInlineSize,
|
|
3397
3821
|
rootOrigin: measurement.rootOrigin
|
|
3398
3822
|
};
|
|
3399
3823
|
}
|
|
@@ -3451,6 +3875,7 @@ function commitStaticMeasurement(session, measurement, setState) {
|
|
|
3451
3875
|
function scheduleMorphTimeline({
|
|
3452
3876
|
session,
|
|
3453
3877
|
timeline,
|
|
3878
|
+
finalizeMeasurement,
|
|
3454
3879
|
measurement,
|
|
3455
3880
|
plan,
|
|
3456
3881
|
setState
|
|
@@ -3471,12 +3896,13 @@ function scheduleMorphTimeline({
|
|
|
3471
3896
|
timeline.animateFrame = null;
|
|
3472
3897
|
timeline.finalizeTimer = window.setTimeout(() => {
|
|
3473
3898
|
timeline.finalizeTimer = null;
|
|
3474
|
-
commitStaticMeasurement(session, session.target ?? measurement, setState);
|
|
3899
|
+
commitStaticMeasurement(session, finalizeMeasurement(session.target ?? measurement), setState);
|
|
3475
3900
|
}, MORPH.durationMs);
|
|
3476
3901
|
});
|
|
3477
3902
|
});
|
|
3478
3903
|
}
|
|
3479
3904
|
function startMorph({
|
|
3905
|
+
finalizeMeasurement,
|
|
3480
3906
|
nextMeasurement,
|
|
3481
3907
|
session,
|
|
3482
3908
|
timeline,
|
|
@@ -3503,12 +3929,14 @@ function startMorph({
|
|
|
3503
3929
|
scheduleMorphTimeline({
|
|
3504
3930
|
session,
|
|
3505
3931
|
timeline,
|
|
3932
|
+
finalizeMeasurement,
|
|
3506
3933
|
measurement: nextMeasurement,
|
|
3507
3934
|
plan,
|
|
3508
3935
|
setState
|
|
3509
3936
|
});
|
|
3510
3937
|
}
|
|
3511
3938
|
function reconcileMorphChange({
|
|
3939
|
+
finalizeMeasurement,
|
|
3512
3940
|
root,
|
|
3513
3941
|
measurementLayer,
|
|
3514
3942
|
measurementBackend,
|
|
@@ -3563,6 +3991,7 @@ function reconcileMorphChange({
|
|
|
3563
3991
|
return nextMeasurement;
|
|
3564
3992
|
}
|
|
3565
3993
|
startMorph({
|
|
3994
|
+
finalizeMeasurement,
|
|
3566
3995
|
nextMeasurement,
|
|
3567
3996
|
session,
|
|
3568
3997
|
timeline,
|
|
@@ -3572,6 +4001,7 @@ function reconcileMorphChange({
|
|
|
3572
4001
|
}
|
|
3573
4002
|
function syncCommittedRootOriginWhenIdle({
|
|
3574
4003
|
root,
|
|
4004
|
+
flowTextRef,
|
|
3575
4005
|
layoutContext,
|
|
3576
4006
|
state,
|
|
3577
4007
|
session
|
|
@@ -3583,8 +4013,9 @@ function syncCommittedRootOriginWhenIdle({
|
|
|
3583
4013
|
return;
|
|
3584
4014
|
}
|
|
3585
4015
|
const nextRootOrigin = readRootOrigin(root);
|
|
4016
|
+
const nextFlowInlineSize = readFlowInlineSize(flowTextRef.current);
|
|
3586
4017
|
const committedMeasurement = state.measurement;
|
|
3587
|
-
if (nearlyEqual(committedMeasurement.rootOrigin.left, nextRootOrigin.left) && nearlyEqual(committedMeasurement.rootOrigin.top, nextRootOrigin.top)) {
|
|
4018
|
+
if (nearlyEqual(committedMeasurement.rootOrigin.left, nextRootOrigin.left) && nearlyEqual(committedMeasurement.rootOrigin.top, nextRootOrigin.top) && (committedMeasurement.flowInlineSize === null && nextFlowInlineSize === null || committedMeasurement.flowInlineSize !== null && nextFlowInlineSize !== null && nearlyEqual(committedMeasurement.flowInlineSize, nextFlowInlineSize))) {
|
|
3588
4019
|
session.committed = committedMeasurement;
|
|
3589
4020
|
return;
|
|
3590
4021
|
}
|
|
@@ -3592,6 +4023,7 @@ function syncCommittedRootOriginWhenIdle({
|
|
|
3592
4023
|
snapshot: committedMeasurement.snapshot,
|
|
3593
4024
|
layoutInlineSize: committedMeasurement.layoutInlineSize,
|
|
3594
4025
|
reservedInlineSize: committedMeasurement.reservedInlineSize,
|
|
4026
|
+
flowInlineSize: nextFlowInlineSize,
|
|
3595
4027
|
rootOrigin: nextRootOrigin
|
|
3596
4028
|
};
|
|
3597
4029
|
}
|
|
@@ -3690,7 +4122,7 @@ function getMeasurementLayerStyle(layoutContext, useContentInlineSize = false) {
|
|
|
3690
4122
|
};
|
|
3691
4123
|
}
|
|
3692
4124
|
function resolveFlowText(committedMeasurement, stateMeasurement, text) {
|
|
3693
|
-
return
|
|
4125
|
+
return stateMeasurement?.snapshot.text ?? committedMeasurement?.snapshot.text ?? text;
|
|
3694
4126
|
}
|
|
3695
4127
|
function getOverlayStyle(plan) {
|
|
3696
4128
|
return {
|
|
@@ -3718,7 +4150,6 @@ function getLiveGlyphStyle(item, stage, visualBridge) {
|
|
|
3718
4150
|
top: item.top,
|
|
3719
4151
|
width: item.width,
|
|
3720
4152
|
height: item.height,
|
|
3721
|
-
lineHeight: `${item.height}px`,
|
|
3722
4153
|
opacity: getLiveOpacity(item, stage),
|
|
3723
4154
|
transform: getLiveTransform(item, stage, visualBridge),
|
|
3724
4155
|
transition: getLiveTransition(item, stage)
|
|
@@ -3731,28 +4162,52 @@ function getExitGlyphStyle(item, stage, visualBridge) {
|
|
|
3731
4162
|
top: item.top,
|
|
3732
4163
|
width: item.width,
|
|
3733
4164
|
height: item.height,
|
|
3734
|
-
lineHeight: `${item.height}px`,
|
|
3735
4165
|
opacity: getExitOpacity(stage),
|
|
3736
4166
|
transform: getExitTransform(visualBridge),
|
|
3737
4167
|
transition: getExitTransition(stage)
|
|
3738
4168
|
};
|
|
3739
4169
|
}
|
|
3740
|
-
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
|
+
}) {
|
|
3741
4183
|
let exitItems = [];
|
|
3742
4184
|
if (stage !== "idle") {
|
|
3743
4185
|
exitItems = plan.exitItems;
|
|
3744
4186
|
}
|
|
3745
4187
|
return /* @__PURE__ */ jsxDEV("div", {
|
|
4188
|
+
ref: overlayRef,
|
|
3746
4189
|
"aria-hidden": "true",
|
|
3747
4190
|
style: getOverlayStyle(plan),
|
|
3748
4191
|
children: [
|
|
3749
4192
|
exitItems.map((item) => /* @__PURE__ */ jsxDEV("span", {
|
|
4193
|
+
"data-morph-role": "exit",
|
|
4194
|
+
"data-morph-key": item.key,
|
|
4195
|
+
"data-morph-glyph": item.glyph,
|
|
3750
4196
|
style: getExitGlyphStyle(item, stage, plan.visualBridge),
|
|
3751
|
-
children:
|
|
4197
|
+
children: /* @__PURE__ */ jsxDEV("span", {
|
|
4198
|
+
style: getContextSliceStyle(plan.layoutInlineSizeFrom, item),
|
|
4199
|
+
children: plan.sourceRenderText
|
|
4200
|
+
}, undefined, false, undefined, this)
|
|
3752
4201
|
}, `exit-${item.key}`, false, undefined, this)),
|
|
3753
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,
|
|
3754
4206
|
style: getLiveGlyphStyle(item, stage, plan.visualBridge),
|
|
3755
|
-
children:
|
|
4207
|
+
children: /* @__PURE__ */ jsxDEV("span", {
|
|
4208
|
+
style: getContextSliceStyle(plan.layoutInlineSizeTo, item),
|
|
4209
|
+
children: plan.targetRenderText
|
|
4210
|
+
}, undefined, false, undefined, this)
|
|
3756
4211
|
}, item.key, false, undefined, this))
|
|
3757
4212
|
]
|
|
3758
4213
|
}, undefined, true, undefined, this);
|
|
@@ -3761,54 +4216,63 @@ function MeasurementLayer({
|
|
|
3761
4216
|
layerRef,
|
|
3762
4217
|
layoutContext,
|
|
3763
4218
|
text,
|
|
3764
|
-
segments,
|
|
3765
4219
|
useContentInlineSize
|
|
3766
4220
|
}) {
|
|
3767
|
-
let glyphs = segments;
|
|
3768
|
-
if (text.length === 0) {
|
|
3769
|
-
glyphs = EMPTY_SEGMENTS;
|
|
3770
|
-
}
|
|
3771
4221
|
return /* @__PURE__ */ jsxDEV("span", {
|
|
3772
4222
|
ref: layerRef,
|
|
3773
4223
|
"aria-hidden": "true",
|
|
3774
4224
|
style: getMeasurementLayerStyle(layoutContext, useContentInlineSize),
|
|
3775
|
-
children:
|
|
3776
|
-
"data-morph-key": segment.key,
|
|
3777
|
-
style: MEASUREMENT_GLYPH_STYLE,
|
|
3778
|
-
children: segment.glyph
|
|
3779
|
-
}, segment.key, false, undefined, this))
|
|
4225
|
+
children: text
|
|
3780
4226
|
}, undefined, false, undefined, this);
|
|
3781
4227
|
}
|
|
3782
4228
|
function useMorphTransition(text, className) {
|
|
3783
4229
|
const { ref, layoutContext } = useObservedLayoutContext([className]);
|
|
4230
|
+
const debugInstanceIdRef = useRef(null);
|
|
4231
|
+
const flowTextRef = useRef(null);
|
|
3784
4232
|
const measurementLayerRef = useRef(null);
|
|
3785
4233
|
const completedDomMeasurementKeyRef = useRef(null);
|
|
3786
4234
|
const domMeasurementSnapshotCacheRef = useRef(new Map);
|
|
3787
4235
|
const sessionRef = useRef({ ...EMPTY_SESSION });
|
|
3788
4236
|
const timelineRef = useRef({ ...EMPTY_TIMELINE });
|
|
4237
|
+
const debugDriftSignatureRef = useRef(null);
|
|
3789
4238
|
const [domMeasurementRequestKey, setDomMeasurementRequestKey] = useState(null);
|
|
4239
|
+
const [forceContentMeasurementText, setForceContentMeasurementText] = useState(null);
|
|
3790
4240
|
const [state, setState] = useState(EMPTY_STATE);
|
|
4241
|
+
if (debugInstanceIdRef.current === null) {
|
|
4242
|
+
debugInstanceIdRef.current = nextTorphDebugInstanceId();
|
|
4243
|
+
}
|
|
3791
4244
|
let measurementHint = sessionRef.current.committed;
|
|
3792
4245
|
if (sessionRef.current.animating) {
|
|
3793
4246
|
measurementHint = sessionRef.current.target ?? sessionRef.current.committed;
|
|
3794
4247
|
}
|
|
4248
|
+
const forceContentInlineSize = forceContentMeasurementText === text;
|
|
3795
4249
|
const measurementRequest = useMemo(() => createMorphMeasurementRequest({
|
|
3796
4250
|
text,
|
|
3797
4251
|
layoutContext,
|
|
3798
|
-
layoutHint: measurementHint
|
|
3799
|
-
|
|
4252
|
+
layoutHint: measurementHint,
|
|
4253
|
+
forceContentInlineSize
|
|
4254
|
+
}), [text, layoutContext, measurementHint, forceContentInlineSize]);
|
|
3800
4255
|
const renderText = measurementRequest?.renderText ?? text;
|
|
3801
4256
|
const useContentInlineSize = measurementRequest?.useContentInlineSize ?? false;
|
|
3802
4257
|
const measurementBackend = measurementRequest?.measurementBackend ?? null;
|
|
3803
4258
|
const segments = measurementRequest?.segments ?? EMPTY_SEGMENTS;
|
|
3804
4259
|
const domMeasurementKey = measurementRequest?.domMeasurementKey ?? null;
|
|
3805
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);
|
|
3806
4269
|
if (ref.current === null || layoutContext === null) {
|
|
3807
4270
|
completedDomMeasurementKeyRef.current = null;
|
|
3808
4271
|
if (domMeasurementRequestKey !== null) {
|
|
3809
4272
|
setDomMeasurementRequestKey(null);
|
|
3810
4273
|
}
|
|
3811
4274
|
reconcileMorphChange({
|
|
4275
|
+
finalizeMeasurement,
|
|
3812
4276
|
root: ref.current,
|
|
3813
4277
|
measurementLayer: measurementLayerRef.current,
|
|
3814
4278
|
measurementBackend,
|
|
@@ -3834,6 +4298,7 @@ function useMorphTransition(text, className) {
|
|
|
3834
4298
|
setDomMeasurementRequestKey(null);
|
|
3835
4299
|
}
|
|
3836
4300
|
reconcileMorphChange({
|
|
4301
|
+
finalizeMeasurement,
|
|
3837
4302
|
root: ref.current,
|
|
3838
4303
|
measurementLayer: null,
|
|
3839
4304
|
measurementBackend,
|
|
@@ -3856,7 +4321,8 @@ function useMorphTransition(text, className) {
|
|
|
3856
4321
|
if (measurementLayerRef.current === null) {
|
|
3857
4322
|
return;
|
|
3858
4323
|
}
|
|
3859
|
-
const
|
|
4324
|
+
const nextMeasurement2 = reconcileMorphChange({
|
|
4325
|
+
finalizeMeasurement,
|
|
3860
4326
|
root: ref.current,
|
|
3861
4327
|
measurementLayer: measurementLayerRef.current,
|
|
3862
4328
|
measurementBackend,
|
|
@@ -3869,9 +4335,9 @@ function useMorphTransition(text, className) {
|
|
|
3869
4335
|
timeline: timelineRef.current,
|
|
3870
4336
|
setState
|
|
3871
4337
|
});
|
|
3872
|
-
if (
|
|
4338
|
+
if (nextMeasurement2 !== null) {
|
|
3873
4339
|
if (canCacheMeasurementLayerSnapshot(measurementBackend)) {
|
|
3874
|
-
rememberCachedMorphSnapshot(domMeasurementSnapshotCacheRef.current, domMeasurementKey,
|
|
4340
|
+
rememberCachedMorphSnapshot(domMeasurementSnapshotCacheRef.current, domMeasurementKey, nextMeasurement2.snapshot);
|
|
3875
4341
|
}
|
|
3876
4342
|
}
|
|
3877
4343
|
completedDomMeasurementKeyRef.current = domMeasurementKey;
|
|
@@ -3889,7 +4355,8 @@ function useMorphTransition(text, className) {
|
|
|
3889
4355
|
if (domMeasurementRequestKey !== null) {
|
|
3890
4356
|
setDomMeasurementRequestKey(null);
|
|
3891
4357
|
}
|
|
3892
|
-
reconcileMorphChange({
|
|
4358
|
+
const nextMeasurement = reconcileMorphChange({
|
|
4359
|
+
finalizeMeasurement,
|
|
3893
4360
|
root: ref.current,
|
|
3894
4361
|
measurementLayer: measurementLayerRef.current,
|
|
3895
4362
|
measurementBackend,
|
|
@@ -3915,19 +4382,85 @@ function useMorphTransition(text, className) {
|
|
|
3915
4382
|
useLayoutEffect(() => {
|
|
3916
4383
|
syncCommittedRootOriginWhenIdle({
|
|
3917
4384
|
root: ref.current,
|
|
4385
|
+
flowTextRef,
|
|
3918
4386
|
layoutContext,
|
|
3919
4387
|
state,
|
|
3920
4388
|
session: sessionRef.current
|
|
3921
4389
|
});
|
|
3922
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]);
|
|
3923
4454
|
useLayoutEffect(() => {
|
|
3924
4455
|
return () => {
|
|
3925
4456
|
cancelTimeline(timelineRef.current);
|
|
3926
4457
|
};
|
|
3927
4458
|
}, []);
|
|
3928
4459
|
return {
|
|
4460
|
+
debugInstanceId: debugInstanceIdRef.current,
|
|
3929
4461
|
committedMeasurement: sessionRef.current.committed,
|
|
3930
4462
|
domMeasurementRequestKey,
|
|
4463
|
+
flowTextRef,
|
|
3931
4464
|
ref,
|
|
3932
4465
|
measurementLayerRef,
|
|
3933
4466
|
renderText,
|
|
@@ -3941,9 +4474,19 @@ function ActiveTorph({
|
|
|
3941
4474
|
text,
|
|
3942
4475
|
className
|
|
3943
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);
|
|
3944
4485
|
const {
|
|
4486
|
+
debugInstanceId,
|
|
3945
4487
|
committedMeasurement,
|
|
3946
4488
|
domMeasurementRequestKey,
|
|
4489
|
+
flowTextRef,
|
|
3947
4490
|
ref,
|
|
3948
4491
|
measurementLayerRef,
|
|
3949
4492
|
renderText,
|
|
@@ -3956,19 +4499,338 @@ function ActiveTorph({
|
|
|
3956
4499
|
const shouldRenderOverlay = state.stage !== "idle" && plan !== null;
|
|
3957
4500
|
const shouldRenderMeasurementLayer = domMeasurementRequestKey !== null;
|
|
3958
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]);
|
|
3959
4821
|
let measurementLayer = null;
|
|
3960
4822
|
if (shouldRenderMeasurementLayer) {
|
|
3961
4823
|
measurementLayer = /* @__PURE__ */ jsxDEV(MeasurementLayer, {
|
|
3962
4824
|
layerRef: measurementLayerRef,
|
|
3963
4825
|
layoutContext,
|
|
3964
4826
|
text: renderText,
|
|
3965
|
-
segments,
|
|
3966
4827
|
useContentInlineSize
|
|
3967
4828
|
}, undefined, false, undefined, this);
|
|
3968
4829
|
}
|
|
3969
4830
|
let overlay = null;
|
|
3970
4831
|
if (shouldRenderOverlay) {
|
|
3971
4832
|
overlay = /* @__PURE__ */ jsxDEV(MorphOverlay, {
|
|
4833
|
+
overlayRef,
|
|
3972
4834
|
stage: state.stage,
|
|
3973
4835
|
plan
|
|
3974
4836
|
}, undefined, false, undefined, this);
|
|
@@ -3985,7 +4847,10 @@ function ActiveTorph({
|
|
|
3985
4847
|
/* @__PURE__ */ jsxDEV("span", {
|
|
3986
4848
|
"aria-hidden": "true",
|
|
3987
4849
|
style: getFallbackTextStyle(shouldRenderOverlay),
|
|
3988
|
-
children:
|
|
4850
|
+
children: /* @__PURE__ */ jsxDEV("span", {
|
|
4851
|
+
ref: flowTextRef,
|
|
4852
|
+
children: flowText
|
|
4853
|
+
}, undefined, false, undefined, this)
|
|
3989
4854
|
}, undefined, false, undefined, this),
|
|
3990
4855
|
measurementLayer,
|
|
3991
4856
|
overlay
|
|
@@ -4003,8 +4868,11 @@ function Torph({
|
|
|
4003
4868
|
}
|
|
4004
4869
|
export {
|
|
4005
4870
|
supportsIntrinsicWidthLock,
|
|
4871
|
+
shouldHealIdleMeasurementFromFlow,
|
|
4006
4872
|
resolveMorphFrameBounds,
|
|
4007
4873
|
resolveFlowText,
|
|
4874
|
+
resolveContentWidthLockInlineSize,
|
|
4875
|
+
refineMeasurementWithLiveGeometry,
|
|
4008
4876
|
pairMorphCharacters,
|
|
4009
4877
|
needsMeasurementLayer,
|
|
4010
4878
|
measureMorphSnapshotFromLayer,
|