@@ -34,6 +34,7 @@ const CHECKOUT_DOUBLE_ZOOM_RANGE = Object.freeze({
3434 min : 2.35 ,
3535 max : 3.15 ,
3636} ) ;
37+ const TRANSFORM_SIGNATURE_STEP_PX = 0.5 ;
3738
3839function parseScoreText ( text ) {
3940 const match = String ( text || "" ) . match ( / - ? \d + / ) ;
@@ -165,6 +166,19 @@ export function getBestVisibleScoreFromDom(documentRef, windowRef) {
165166 return candidates [ 0 ] . value ;
166167}
167168
169+ function quantizeForSignature ( value , step = TRANSFORM_SIGNATURE_STEP_PX ) {
170+ if ( ! Number . isFinite ( value ) ) {
171+ return 0 ;
172+ }
173+
174+ const numericStep = Number ( step ) ;
175+ if ( ! Number . isFinite ( numericStep ) || numericStep <= 0 ) {
176+ return value ;
177+ }
178+
179+ return Math . round ( value / numericStep ) * numericStep ;
180+ }
181+
168182function parseSegmentWithFallback ( segmentName , x01Rules ) {
169183 if ( x01Rules && typeof x01Rules . parseSegment === "function" ) {
170184 const parsed = x01Rules . parseSegment ( segmentName ) ;
@@ -931,18 +945,22 @@ export function buildZoomTransform(options = {}) {
931945 }
932946
933947 const transform = `translate(${ tx . toFixed ( 2 ) } px, ${ ty . toFixed ( 2 ) } px) scale(${ zoomLevel . toFixed ( 4 ) } )` ;
934- const signature = [
935- baseTransform || "none" ,
936- tx . toFixed ( 2 ) ,
937- ty . toFixed ( 2 ) ,
938- zoomLevel . toFixed ( 4 ) ,
948+ const intentSignature = [
939949 String ( segmentPoint . parsedSegment ?. normalized || intent . segment || "" ) ,
940950 String ( intent . reason || "" ) ,
951+ zoomLevel . toFixed ( 4 ) ,
952+ ] . join ( "|" ) ;
953+ const signature = [
954+ baseTransform || "none" ,
955+ quantizeForSignature ( tx ) . toFixed ( 2 ) ,
956+ quantizeForSignature ( ty ) . toFixed ( 2 ) ,
957+ intentSignature ,
941958 ] . join ( "|" ) ;
942959
943960 return {
944961 transform,
945962 baseTransform,
963+ intentSignature,
946964 signature,
947965 anchor,
948966 tx,
@@ -1271,6 +1289,7 @@ export function applyZoom(
12711289 restoreTargetStyle ( state , state . zoomedElement ) ;
12721290 state . zoomedElement = null ;
12731291 state . lastAppliedSignature = "" ;
1292+ state . lastAppliedIntentSignature = "" ;
12741293 }
12751294 if ( state . zoomHost && state . zoomHost !== hostNode ) {
12761295 restoreHostStyle ( state , state . zoomHost ) ;
@@ -1299,30 +1318,47 @@ export function applyZoom(
12991318 }
13001319 if ( hostNode ?. classList ) {
13011320 cacheHostStyle ( state , hostNode ) ;
1302- hostNode . classList . add ( ZOOM_HOST_CLASS ) ;
1303- setStyleWithPriority ( hostNode . style , "overflow" , "hidden" , "important" ) ;
1304- setStyleWithPriority ( hostNode . style , "overflow-x" , "hidden" , "important" ) ;
1305- setStyleWithPriority ( hostNode . style , "overflow-y" , "hidden" , "important" ) ;
1321+ if ( ! hostNode . classList . contains ( ZOOM_HOST_CLASS ) ) {
1322+ hostNode . classList . add ( ZOOM_HOST_CLASS ) ;
1323+ }
1324+ if ( getStyleValue ( hostNode . style , "overflow" ) !== "hidden" ) {
1325+ setStyleWithPriority ( hostNode . style , "overflow" , "hidden" , "important" ) ;
1326+ }
1327+ if ( getStyleValue ( hostNode . style , "overflow-x" ) !== "hidden" ) {
1328+ setStyleWithPriority ( hostNode . style , "overflow-x" , "hidden" , "important" ) ;
1329+ }
1330+ if ( getStyleValue ( hostNode . style , "overflow-y" ) !== "hidden" ) {
1331+ setStyleWithPriority ( hostNode . style , "overflow-y" , "hidden" , "important" ) ;
1332+ }
13061333 }
13071334 applyGifOverlayContainment ( state , targetNode , hostNode || targetNode ) ;
13081335
13091336 const composedTransform = zoomData . baseTransform
13101337 ? `${ zoomData . baseTransform } ${ zoomData . transform } `
13111338 : zoomData . transform ;
1339+ const isSameVisualIntent =
1340+ state . zoomedElement === targetNode &&
1341+ state . zoomHost === ( hostNode || null ) &&
1342+ state . lastAppliedIntentSignature === zoomData . intentSignature ;
13121343 if ( state . zoomedElement === targetNode && state . lastAppliedSignature === zoomData . signature ) {
13131344 state . zoomHost = hostNode || null ;
13141345 return zoomData ;
13151346 }
13161347
1317- targetNode . classList . add ( ZOOM_CLASS ) ;
1348+ if ( ! targetNode . classList . contains ( ZOOM_CLASS ) ) {
1349+ targetNode . classList . add ( ZOOM_CLASS ) ;
1350+ }
13181351 targetNode . style . transformOrigin = "0 0" ;
13191352 targetNode . style . willChange = "transform" ;
1320- targetNode . style . transition = `transform ${ speedConfig . zoomInMs } ms ${ speedConfig . easingIn } ` ;
1353+ targetNode . style . transition = isSameVisualIntent
1354+ ? "none"
1355+ : `transform ${ speedConfig . zoomInMs } ms ${ speedConfig . easingIn } ` ;
13211356 targetNode . style . transform = composedTransform ;
13221357
13231358 state . zoomedElement = targetNode ;
13241359 state . zoomHost = hostNode || null ;
13251360 state . lastAppliedSignature = zoomData . signature ;
1361+ state . lastAppliedIntentSignature = zoomData . intentSignature ;
13261362 return zoomData ;
13271363}
13281364
@@ -1343,6 +1379,7 @@ export function resetZoom(speedConfig, state, immediate = false) {
13431379 state . zoomHost = null ;
13441380 state . hostStyleSnapshot = null ;
13451381 state . lastAppliedSignature = "" ;
1382+ state . lastAppliedIntentSignature = "" ;
13461383 return ;
13471384 }
13481385
@@ -1358,6 +1395,7 @@ export function resetZoom(speedConfig, state, immediate = false) {
13581395 state . targetStyleSnapshot = null ;
13591396 state . hostStyleSnapshot = null ;
13601397 state . lastAppliedSignature = "" ;
1398+ state . lastAppliedIntentSignature = "" ;
13611399 return ;
13621400 }
13631401
@@ -1384,5 +1422,6 @@ export function resetZoom(speedConfig, state, immediate = false) {
13841422 }
13851423
13861424 state . lastAppliedSignature = "" ;
1425+ state . lastAppliedIntentSignature = "" ;
13871426 } , releaseDelay ) ;
13881427}
0 commit comments