Skip to content

Commit a49952b

Browse files
authored
Properly clean up gesture Animations (#35559)
Follow up to #35337. During a gesture, we always cancel the original animation and create a new one that we control. That's the one we need to add to the set that needs to be cancelled. Otherwise future gestures hang. An unfortunate consequence is that any custom ones that you start e.g. with #35556 or through other means aren't automatically cleaned up (in fact there's not even a clean up callback yet). This can lead these to freeze the whole UI afterwards. It would be really good to get this fixed in browsers instead so we can revert #35337.
1 parent 4bcf67e commit a49952b

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

‎packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,7 @@ function animateGesture(
23722372
targetElement: Element,
23732373
pseudoElement: string,
23742374
timeline: GestureTimeline,
2375+
viewTransitionAnimations: Array<Animation>,
23752376
customTimelineCleanup: Array<()=>void>,
23762377
rangeStart: number,
23772378
rangeEnd: number,
@@ -2464,7 +2465,7 @@ function animateGesture(
24642465
if(timelineinstanceofAnimationTimeline){
24652466
// Native Timeline
24662467
// $FlowFixMe[incompatible-call]
2467-
targetElement.animate(keyframes,{
2468+
constanimation=targetElement.animate(keyframes,{
24682469
pseudoElement: pseudoElement,
24692470
// Set the timeline to the current gesture timeline to drive the updates.
24702471
timeline: timeline,
@@ -2482,6 +2483,7 @@ function animateGesture(
24822483
rangeStart: (reverse ? rangeEnd : rangeStart)+'%',
24832484
rangeEnd: (reverse ? rangeStart : rangeEnd)+'%',
24842485
});
2486+
viewTransitionAnimations.push(animation);
24852487
}else{
24862488
// Custom Timeline
24872489
// $FlowFixMe[incompatible-call]
@@ -2554,8 +2556,10 @@ export function startGestureTransition(
25542556
// $FlowFixMe
25552557
constpseudoElement: ?string=effect.pseudoElement;
25562558
if(pseudoElement==null){
2557-
}elseif(pseudoElement.startsWith('::view-transition')){
2558-
viewTransitionAnimations.push(animations[i]);
2559+
}elseif(
2560+
pseudoElement.startsWith('::view-transition')&&
2561+
effect.target===documentElement
2562+
){
25592563
consttiming=effect.getTiming();
25602564
constduration=
25612565
// $FlowFixMe[prop-missing]
@@ -2648,6 +2652,7 @@ export function startGestureTransition(
26482652
effect.target,
26492653
pseudoElement,
26502654
timeline,
2655+
viewTransitionAnimations,
26512656
customTimelineCleanup,
26522657
adjustedRangeStart,
26532658
adjustedRangeEnd,
@@ -2675,6 +2680,7 @@ export function startGestureTransition(
26752680
effect.target,
26762681
pseudoElementName,
26772682
timeline,
2683+
viewTransitionAnimations,
26782684
customTimelineCleanup,
26792685
rangeStart,
26802686
rangeEnd,
@@ -2696,6 +2702,7 @@ export function startGestureTransition(
26962702
duration: 1,
26972703
});
26982704
blockingAnim.pause();
2705+
viewTransitionAnimations.push(blockingAnim);
26992706
animateCallback();
27002707
};
27012708
// In Chrome, "new" animations are not ready in the ready callback. We have to wait

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Add copy buttons to all
 blocks
(function() {
function addCopyButtons() {
document.querySelectorAll('pre code').forEach(function(codeBlock) {
if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;
codeBlock.parentElement.setAttribute('data-copy-added', 'true');
var btn = document.createElement('button');
btn.textContent = 'Copy';
btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';
btn.onmouseover = function() { this.style.opacity = '1'; };
btn.onmouseout = function() { this.style.opacity = '0.7'; };
btn.onclick = function() {
navigator.clipboard.writeText(codeBlock.textContent).then(function() {
btn.textContent = 'Copied!';
setTimeout(function() { btn.textContent = 'Copy'; }, 1500);
});
};
codeBlock.parentElement.style.position = 'relative';
codeBlock.parentElement.appendChild(btn);
});
}
addCopyButtons();
// Re-run on dynamic content
var observer = new MutationObserver(addCopyButtons);
observer.observe(document.body, { childList: true, subtree: true });
})();
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Properly clean up gesture Animations (#35559) · react/react@a49952b · GitHub
Skip to content

Commit a49952b

Browse files
authored
Properly clean up gesture Animations (#35559)
Follow up to #35337. During a gesture, we always cancel the original animation and create a new one that we control. That's the one we need to add to the set that needs to be cancelled. Otherwise future gestures hang. An unfortunate consequence is that any custom ones that you start e.g. with #35556 or through other means aren't automatically cleaned up (in fact there's not even a clean up callback yet). This can lead these to freeze the whole UI afterwards. It would be really good to get this fixed in browsers instead so we can revert #35337.
1 parent 4bcf67e commit a49952b

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

‎packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,7 @@ function animateGesture(
23722372
targetElement: Element,
23732373
pseudoElement: string,
23742374
timeline: GestureTimeline,
2375+
viewTransitionAnimations: Array<Animation>,
23752376
customTimelineCleanup: Array<()=>void>,
23762377
rangeStart: number,
23772378
rangeEnd: number,
@@ -2464,7 +2465,7 @@ function animateGesture(
24642465
if(timelineinstanceofAnimationTimeline){
24652466
// Native Timeline
24662467
// $FlowFixMe[incompatible-call]
2467-
targetElement.animate(keyframes,{
2468+
constanimation=targetElement.animate(keyframes,{
24682469
pseudoElement: pseudoElement,
24692470
// Set the timeline to the current gesture timeline to drive the updates.
24702471
timeline: timeline,
@@ -2482,6 +2483,7 @@ function animateGesture(
24822483
rangeStart: (reverse ? rangeEnd : rangeStart)+'%',
24832484
rangeEnd: (reverse ? rangeStart : rangeEnd)+'%',
24842485
});
2486+
viewTransitionAnimations.push(animation);
24852487
}else{
24862488
// Custom Timeline
24872489
// $FlowFixMe[incompatible-call]
@@ -2554,8 +2556,10 @@ export function startGestureTransition(
25542556
// $FlowFixMe
25552557
constpseudoElement: ?string=effect.pseudoElement;
25562558
if(pseudoElement==null){
2557-
}elseif(pseudoElement.startsWith('::view-transition')){
2558-
viewTransitionAnimations.push(animations[i]);
2559+
}elseif(
2560+
pseudoElement.startsWith('::view-transition')&&
2561+
effect.target===documentElement
2562+
){
25592563
consttiming=effect.getTiming();
25602564
constduration=
25612565
// $FlowFixMe[prop-missing]
@@ -2648,6 +2652,7 @@ export function startGestureTransition(
26482652
effect.target,
26492653
pseudoElement,
26502654
timeline,
2655+
viewTransitionAnimations,
26512656
customTimelineCleanup,
26522657
adjustedRangeStart,
26532658
adjustedRangeEnd,
@@ -2675,6 +2680,7 @@ export function startGestureTransition(
26752680
effect.target,
26762681
pseudoElementName,
26772682
timeline,
2683+
viewTransitionAnimations,
26782684
customTimelineCleanup,
26792685
rangeStart,
26802686
rangeEnd,
@@ -2696,6 +2702,7 @@ export function startGestureTransition(
26962702
duration: 1,
26972703
});
26982704
blockingAnim.pause();
2705+
viewTransitionAnimations.push(blockingAnim);
26992706
animateCallback();
27002707
};
27012708
// In Chrome, "new" animations are not ready in the ready callback. We have to wait

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Force GitHub README to respect dark mode (function() { var style = document.createElement('style'); style.textContent = ' .markdown-body { color-scheme: dark light; } .markdown-body pre { background: #161b22 !important; } .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; } .markdown-body table th, .markdown-body table td { border-color: #30363d !important; } .markdown-body img { background: #0d1117; } .markdown-body blockquote { border-left-color: #8b949e; } .markdown-body hr { border-color: #30363d; } '; document.head.appendChild(style); })(); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Properly clean up gesture Animations (#35559) · react/react@a49952b · GitHub
Skip to content

Commit a49952b

Browse files
authored
Properly clean up gesture Animations (#35559)
Follow up to #35337. During a gesture, we always cancel the original animation and create a new one that we control. That's the one we need to add to the set that needs to be cancelled. Otherwise future gestures hang. An unfortunate consequence is that any custom ones that you start e.g. with #35556 or through other means aren't automatically cleaned up (in fact there's not even a clean up callback yet). This can lead these to freeze the whole UI afterwards. It would be really good to get this fixed in browsers instead so we can revert #35337.
1 parent 4bcf67e commit a49952b

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

‎packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,7 @@ function animateGesture(
23722372
targetElement: Element,
23732373
pseudoElement: string,
23742374
timeline: GestureTimeline,
2375+
viewTransitionAnimations: Array<Animation>,
23752376
customTimelineCleanup: Array<()=>void>,
23762377
rangeStart: number,
23772378
rangeEnd: number,
@@ -2464,7 +2465,7 @@ function animateGesture(
24642465
if(timelineinstanceofAnimationTimeline){
24652466
// Native Timeline
24662467
// $FlowFixMe[incompatible-call]
2467-
targetElement.animate(keyframes,{
2468+
constanimation=targetElement.animate(keyframes,{
24682469
pseudoElement: pseudoElement,
24692470
// Set the timeline to the current gesture timeline to drive the updates.
24702471
timeline: timeline,
@@ -2482,6 +2483,7 @@ function animateGesture(
24822483
rangeStart: (reverse ? rangeEnd : rangeStart)+'%',
24832484
rangeEnd: (reverse ? rangeStart : rangeEnd)+'%',
24842485
});
2486+
viewTransitionAnimations.push(animation);
24852487
}else{
24862488
// Custom Timeline
24872489
// $FlowFixMe[incompatible-call]
@@ -2554,8 +2556,10 @@ export function startGestureTransition(
25542556
// $FlowFixMe
25552557
constpseudoElement: ?string=effect.pseudoElement;
25562558
if(pseudoElement==null){
2557-
}elseif(pseudoElement.startsWith('::view-transition')){
2558-
viewTransitionAnimations.push(animations[i]);
2559+
}elseif(
2560+
pseudoElement.startsWith('::view-transition')&&
2561+
effect.target===documentElement
2562+
){
25592563
consttiming=effect.getTiming();
25602564
constduration=
25612565
// $FlowFixMe[prop-missing]
@@ -2648,6 +2652,7 @@ export function startGestureTransition(
26482652
effect.target,
26492653
pseudoElement,
26502654
timeline,
2655+
viewTransitionAnimations,
26512656
customTimelineCleanup,
26522657
adjustedRangeStart,
26532658
adjustedRangeEnd,
@@ -2675,6 +2680,7 @@ export function startGestureTransition(
26752680
effect.target,
26762681
pseudoElementName,
26772682
timeline,
2683+
viewTransitionAnimations,
26782684
customTimelineCleanup,
26792685
rangeStart,
26802686
rangeEnd,
@@ -2696,6 +2702,7 @@ export function startGestureTransition(
26962702
duration: 1,
26972703
});
26982704
blockingAnim.pause();
2705+
viewTransitionAnimations.push(blockingAnim);
26992706
animateCallback();
27002707
};
27012708
// In Chrome, "new" animations are not ready in the ready callback. We have to wait

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Highlight search terms from Google/DuckDuckGo/Bing referrer (function() { var ref = document.referrer; var terms = []; if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) { var url = new URL(ref); var q = url.searchParams.get('q') || url.searchParams.get('p'); if (q) { terms = q.split(/\s+/).filter(function(t) { return t.length > 2; }); } } if (terms.length === 0) return; var style = document.createElement('style'); style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }'; document.head.appendChild(style); function highlight(node) { if (node.nodeType === 3) { // text node var text = node.textContent; var found = false; terms.forEach(function(term) { var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\]\\]/g, '\\') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Properly clean up gesture Animations (#35559) · react/react@a49952b · GitHub
Skip to content

Commit a49952b

Browse files
authored
Properly clean up gesture Animations (#35559)
Follow up to #35337. During a gesture, we always cancel the original animation and create a new one that we control. That's the one we need to add to the set that needs to be cancelled. Otherwise future gestures hang. An unfortunate consequence is that any custom ones that you start e.g. with #35556 or through other means aren't automatically cleaned up (in fact there's not even a clean up callback yet). This can lead these to freeze the whole UI afterwards. It would be really good to get this fixed in browsers instead so we can revert #35337.
1 parent 4bcf67e commit a49952b

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

‎packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,7 @@ function animateGesture(
23722372
targetElement: Element,
23732373
pseudoElement: string,
23742374
timeline: GestureTimeline,
2375+
viewTransitionAnimations: Array<Animation>,
23752376
customTimelineCleanup: Array<()=>void>,
23762377
rangeStart: number,
23772378
rangeEnd: number,
@@ -2464,7 +2465,7 @@ function animateGesture(
24642465
if(timelineinstanceofAnimationTimeline){
24652466
// Native Timeline
24662467
// $FlowFixMe[incompatible-call]
2467-
targetElement.animate(keyframes,{
2468+
constanimation=targetElement.animate(keyframes,{
24682469
pseudoElement: pseudoElement,
24692470
// Set the timeline to the current gesture timeline to drive the updates.
24702471
timeline: timeline,
@@ -2482,6 +2483,7 @@ function animateGesture(
24822483
rangeStart: (reverse ? rangeEnd : rangeStart)+'%',
24832484
rangeEnd: (reverse ? rangeStart : rangeEnd)+'%',
24842485
});
2486+
viewTransitionAnimations.push(animation);
24852487
}else{
24862488
// Custom Timeline
24872489
// $FlowFixMe[incompatible-call]
@@ -2554,8 +2556,10 @@ export function startGestureTransition(
25542556
// $FlowFixMe
25552557
constpseudoElement: ?string=effect.pseudoElement;
25562558
if(pseudoElement==null){
2557-
}elseif(pseudoElement.startsWith('::view-transition')){
2558-
viewTransitionAnimations.push(animations[i]);
2559+
}elseif(
2560+
pseudoElement.startsWith('::view-transition')&&
2561+
effect.target===documentElement
2562+
){
25592563
consttiming=effect.getTiming();
25602564
constduration=
25612565
// $FlowFixMe[prop-missing]
@@ -2648,6 +2652,7 @@ export function startGestureTransition(
26482652
effect.target,
26492653
pseudoElement,
26502654
timeline,
2655+
viewTransitionAnimations,
26512656
customTimelineCleanup,
26522657
adjustedRangeStart,
26532658
adjustedRangeEnd,
@@ -2675,6 +2680,7 @@ export function startGestureTransition(
26752680
effect.target,
26762681
pseudoElementName,
26772682
timeline,
2683+
viewTransitionAnimations,
26782684
customTimelineCleanup,
26792685
rangeStart,
26802686
rangeEnd,
@@ -2696,6 +2702,7 @@ export function startGestureTransition(
26962702
duration: 1,
26972703
});
26982704
blockingAnim.pause();
2705+
viewTransitionAnimations.push(blockingAnim);
26992706
animateCallback();
27002707
};
27012708
// In Chrome, "new" animations are not ready in the ready callback. We have to wait

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ' Properly clean up gesture Animations (#35559) · react/react@a49952b · GitHub
Skip to content

Commit a49952b

Browse files
authored
Properly clean up gesture Animations (#35559)
Follow up to #35337. During a gesture, we always cancel the original animation and create a new one that we control. That's the one we need to add to the set that needs to be cancelled. Otherwise future gestures hang. An unfortunate consequence is that any custom ones that you start e.g. with #35556 or through other means aren't automatically cleaned up (in fact there's not even a clean up callback yet). This can lead these to freeze the whole UI afterwards. It would be really good to get this fixed in browsers instead so we can revert #35337.
1 parent 4bcf67e commit a49952b

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

‎packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,7 @@ function animateGesture(
23722372
targetElement: Element,
23732373
pseudoElement: string,
23742374
timeline: GestureTimeline,
2375+
viewTransitionAnimations: Array<Animation>,
23752376
customTimelineCleanup: Array<()=>void>,
23762377
rangeStart: number,
23772378
rangeEnd: number,
@@ -2464,7 +2465,7 @@ function animateGesture(
24642465
if(timelineinstanceofAnimationTimeline){
24652466
// Native Timeline
24662467
// $FlowFixMe[incompatible-call]
2467-
targetElement.animate(keyframes,{
2468+
constanimation=targetElement.animate(keyframes,{
24682469
pseudoElement: pseudoElement,
24692470
// Set the timeline to the current gesture timeline to drive the updates.
24702471
timeline: timeline,
@@ -2482,6 +2483,7 @@ function animateGesture(
24822483
rangeStart: (reverse ? rangeEnd : rangeStart)+'%',
24832484
rangeEnd: (reverse ? rangeStart : rangeEnd)+'%',
24842485
});
2486+
viewTransitionAnimations.push(animation);
24852487
}else{
24862488
// Custom Timeline
24872489
// $FlowFixMe[incompatible-call]
@@ -2554,8 +2556,10 @@ export function startGestureTransition(
25542556
// $FlowFixMe
25552557
constpseudoElement: ?string=effect.pseudoElement;
25562558
if(pseudoElement==null){
2557-
}elseif(pseudoElement.startsWith('::view-transition')){
2558-
viewTransitionAnimations.push(animations[i]);
2559+
}elseif(
2560+
pseudoElement.startsWith('::view-transition')&&
2561+
effect.target===documentElement
2562+
){
25592563
consttiming=effect.getTiming();
25602564
constduration=
25612565
// $FlowFixMe[prop-missing]
@@ -2648,6 +2652,7 @@ export function startGestureTransition(
26482652
effect.target,
26492653
pseudoElement,
26502654
timeline,
2655+
viewTransitionAnimations,
26512656
customTimelineCleanup,
26522657
adjustedRangeStart,
26532658
adjustedRangeEnd,
@@ -2675,6 +2680,7 @@ export function startGestureTransition(
26752680
effect.target,
26762681
pseudoElementName,
26772682
timeline,
2683+
viewTransitionAnimations,
26782684
customTimelineCleanup,
26792685
rangeStart,
26802686
rangeEnd,
@@ -2696,6 +2702,7 @@ export function startGestureTransition(
26962702
duration: 1,
26972703
});
26982704
blockingAnim.pause();
2705+
viewTransitionAnimations.push(blockingAnim);
26992706
animateCallback();
27002707
};
27012708
// In Chrome, "new" animations are not ready in the ready callback. We have to wait

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Properly clean up gesture Animations (#35559) · react/react@a49952b · GitHub
Skip to content

Commit a49952b

Browse files
authored
Properly clean up gesture Animations (#35559)
Follow up to #35337. During a gesture, we always cancel the original animation and create a new one that we control. That's the one we need to add to the set that needs to be cancelled. Otherwise future gestures hang. An unfortunate consequence is that any custom ones that you start e.g. with #35556 or through other means aren't automatically cleaned up (in fact there's not even a clean up callback yet). This can lead these to freeze the whole UI afterwards. It would be really good to get this fixed in browsers instead so we can revert #35337.
1 parent 4bcf67e commit a49952b

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

‎packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,7 @@ function animateGesture(
23722372
targetElement: Element,
23732373
pseudoElement: string,
23742374
timeline: GestureTimeline,
2375+
viewTransitionAnimations: Array<Animation>,
23752376
customTimelineCleanup: Array<()=>void>,
23762377
rangeStart: number,
23772378
rangeEnd: number,
@@ -2464,7 +2465,7 @@ function animateGesture(
24642465
if(timelineinstanceofAnimationTimeline){
24652466
// Native Timeline
24662467
// $FlowFixMe[incompatible-call]
2467-
targetElement.animate(keyframes,{
2468+
constanimation=targetElement.animate(keyframes,{
24682469
pseudoElement: pseudoElement,
24692470
// Set the timeline to the current gesture timeline to drive the updates.
24702471
timeline: timeline,
@@ -2482,6 +2483,7 @@ function animateGesture(
24822483
rangeStart: (reverse ? rangeEnd : rangeStart)+'%',
24832484
rangeEnd: (reverse ? rangeStart : rangeEnd)+'%',
24842485
});
2486+
viewTransitionAnimations.push(animation);
24852487
}else{
24862488
// Custom Timeline
24872489
// $FlowFixMe[incompatible-call]
@@ -2554,8 +2556,10 @@ export function startGestureTransition(
25542556
// $FlowFixMe
25552557
constpseudoElement: ?string=effect.pseudoElement;
25562558
if(pseudoElement==null){
2557-
}elseif(pseudoElement.startsWith('::view-transition')){
2558-
viewTransitionAnimations.push(animations[i]);
2559+
}elseif(
2560+
pseudoElement.startsWith('::view-transition')&&
2561+
effect.target===documentElement
2562+
){
25592563
consttiming=effect.getTiming();
25602564
constduration=
25612565
// $FlowFixMe[prop-missing]
@@ -2648,6 +2652,7 @@ export function startGestureTransition(
26482652
effect.target,
26492653
pseudoElement,
26502654
timeline,
2655+
viewTransitionAnimations,
26512656
customTimelineCleanup,
26522657
adjustedRangeStart,
26532658
adjustedRangeEnd,
@@ -2675,6 +2680,7 @@ export function startGestureTransition(
26752680
effect.target,
26762681
pseudoElementName,
26772682
timeline,
2683+
viewTransitionAnimations,
26782684
customTimelineCleanup,
26792685
rangeStart,
26802686
rangeEnd,
@@ -2696,6 +2702,7 @@ export function startGestureTransition(
26962702
duration: 1,
26972703
});
26982704
blockingAnim.pause();
2705+
viewTransitionAnimations.push(blockingAnim);
26992706
animateCallback();
27002707
};
27012708
// In Chrome, "new" animations are not ready in the ready callback. We have to wait

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ' Properly clean up gesture Animations (#35559) · react/react@a49952b · GitHub
Skip to content

Commit a49952b

Browse files
authored
Properly clean up gesture Animations (#35559)
Follow up to #35337. During a gesture, we always cancel the original animation and create a new one that we control. That's the one we need to add to the set that needs to be cancelled. Otherwise future gestures hang. An unfortunate consequence is that any custom ones that you start e.g. with #35556 or through other means aren't automatically cleaned up (in fact there's not even a clean up callback yet). This can lead these to freeze the whole UI afterwards. It would be really good to get this fixed in browsers instead so we can revert #35337.
1 parent 4bcf67e commit a49952b

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

‎packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,7 @@ function animateGesture(
23722372
targetElement: Element,
23732373
pseudoElement: string,
23742374
timeline: GestureTimeline,
2375+
viewTransitionAnimations: Array<Animation>,
23752376
customTimelineCleanup: Array<()=>void>,
23762377
rangeStart: number,
23772378
rangeEnd: number,
@@ -2464,7 +2465,7 @@ function animateGesture(
24642465
if(timelineinstanceofAnimationTimeline){
24652466
// Native Timeline
24662467
// $FlowFixMe[incompatible-call]
2467-
targetElement.animate(keyframes,{
2468+
constanimation=targetElement.animate(keyframes,{
24682469
pseudoElement: pseudoElement,
24692470
// Set the timeline to the current gesture timeline to drive the updates.
24702471
timeline: timeline,
@@ -2482,6 +2483,7 @@ function animateGesture(
24822483
rangeStart: (reverse ? rangeEnd : rangeStart)+'%',
24832484
rangeEnd: (reverse ? rangeStart : rangeEnd)+'%',
24842485
});
2486+
viewTransitionAnimations.push(animation);
24852487
}else{
24862488
// Custom Timeline
24872489
// $FlowFixMe[incompatible-call]
@@ -2554,8 +2556,10 @@ export function startGestureTransition(
25542556
// $FlowFixMe
25552557
constpseudoElement: ?string=effect.pseudoElement;
25562558
if(pseudoElement==null){
2557-
}elseif(pseudoElement.startsWith('::view-transition')){
2558-
viewTransitionAnimations.push(animations[i]);
2559+
}elseif(
2560+
pseudoElement.startsWith('::view-transition')&&
2561+
effect.target===documentElement
2562+
){
25592563
consttiming=effect.getTiming();
25602564
constduration=
25612565
// $FlowFixMe[prop-missing]
@@ -2648,6 +2652,7 @@ export function startGestureTransition(
26482652
effect.target,
26492653
pseudoElement,
26502654
timeline,
2655+
viewTransitionAnimations,
26512656
customTimelineCleanup,
26522657
adjustedRangeStart,
26532658
adjustedRangeEnd,
@@ -2675,6 +2680,7 @@ export function startGestureTransition(
26752680
effect.target,
26762681
pseudoElementName,
26772682
timeline,
2683+
viewTransitionAnimations,
26782684
customTimelineCleanup,
26792685
rangeStart,
26802686
rangeEnd,
@@ -2696,6 +2702,7 @@ export function startGestureTransition(
26962702
duration: 1,
26972703
});
26982704
blockingAnim.pause();
2705+
viewTransitionAnimations.push(blockingAnim);
26992706
animateCallback();
27002707
};
27012708
// In Chrome, "new" animations are not ready in the ready callback. We have to wait

0 commit comments

Comments
 (0)
, 'i'); if (__m === '*' || __re.test(location.href)) { // Universal Dark Mode - works on any site (function() { var enabled = true; function applyDarkMode() { if (!enabled) return; // Create style element if it doesn't exist var style = document.getElementById('universal-dark-mode-style'); if (!style) { style = document.createElement('style'); style.id = 'universal-dark-mode-style'; document.head.appendChild(style); } // Dark mode CSS - inverts colors but preserves images/video style.textContent = ' /* Invert everything except media */ html { filter: invert(1) hue-rotate(180deg) !important; background: #1a1a2e !important; } /* Restore images, videos, iframes, canvas */ img, video, iframe, canvas, svg, picture, [style*="background-image"] { filter: invert(1) hue-rotate(180deg) !important; } /* Preserve specific elements that should not be inverted */ .no-dark-mode, .no-dark-mode *, [data-theme="light"], [data-theme="light"], .ace_editor, .ace_editor *, .CodeMirror, .CodeMirror *, .monaco-editor, .monaco-editor *, .markdown-body pre, .markdown-body pre *, .highlight, .highlight *, pre code, pre code * { filter: none !important; } /* Fix common UI elements */ .modal, .popup, .dropdown-menu, .tooltip, .popover { filter: invert(1) hue-rotate(180deg) !important; background: #2d2d44 !important; border-color: #444 !important; } /* Scrollbars */ ::-webkit-scrollbar { background: #1a1a2e !important; } ::-webkit-scrollbar-thumb { background: #444 !important; } ::-webkit-scrollbar-thumb:hover { background: #555 !important; } /* Selection */ ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; } ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; } '; } function removeDarkMode() { var style = document.getElementById('universal-dark-mode-style'); if (style) style.remove(); } // Toggle with Alt+Shift+D document.addEventListener('keydown', function(e) { if (e.altKey && e.shiftKey && e.key === 'D') { e.preventDefault(); enabled = !enabled; if (enabled) { applyDarkMode(); console.log('[Universal Dark Mode] Enabled'); } else { removeDarkMode(); console.log('[Universal Dark Mode] Disabled'); } } }); // Apply on load applyDarkMode(); // Re-apply on dynamic content var observer = new MutationObserver(function(mutations) { if (enabled && !document.getElementById('universal-dark-mode-style')) { applyDarkMode(); } }); observer.observe(document.head, { childList: true }); console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle'); })(); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })(); Properly clean up gesture Animations (#35559) · react/react@a49952b · GitHub
Skip to content

Commit a49952b

Browse files
authored
Properly clean up gesture Animations (#35559)
Follow up to #35337. During a gesture, we always cancel the original animation and create a new one that we control. That's the one we need to add to the set that needs to be cancelled. Otherwise future gestures hang. An unfortunate consequence is that any custom ones that you start e.g. with #35556 or through other means aren't automatically cleaned up (in fact there's not even a clean up callback yet). This can lead these to freeze the whole UI afterwards. It would be really good to get this fixed in browsers instead so we can revert #35337.
1 parent 4bcf67e commit a49952b

1 file changed

Lines changed: 10 additions & 3 deletions

File tree

‎packages/react-dom-bindings/src/client/ReactFiberConfigDOM.js‎

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2372,6 +2372,7 @@ function animateGesture(
23722372
targetElement: Element,
23732373
pseudoElement: string,
23742374
timeline: GestureTimeline,
2375+
viewTransitionAnimations: Array<Animation>,
23752376
customTimelineCleanup: Array<()=>void>,
23762377
rangeStart: number,
23772378
rangeEnd: number,
@@ -2464,7 +2465,7 @@ function animateGesture(
24642465
if(timelineinstanceofAnimationTimeline){
24652466
// Native Timeline
24662467
// $FlowFixMe[incompatible-call]
2467-
targetElement.animate(keyframes,{
2468+
constanimation=targetElement.animate(keyframes,{
24682469
pseudoElement: pseudoElement,
24692470
// Set the timeline to the current gesture timeline to drive the updates.
24702471
timeline: timeline,
@@ -2482,6 +2483,7 @@ function animateGesture(
24822483
rangeStart: (reverse ? rangeEnd : rangeStart)+'%',
24832484
rangeEnd: (reverse ? rangeStart : rangeEnd)+'%',
24842485
});
2486+
viewTransitionAnimations.push(animation);
24852487
}else{
24862488
// Custom Timeline
24872489
// $FlowFixMe[incompatible-call]
@@ -2554,8 +2556,10 @@ export function startGestureTransition(
25542556
// $FlowFixMe
25552557
constpseudoElement: ?string=effect.pseudoElement;
25562558
if(pseudoElement==null){
2557-
}elseif(pseudoElement.startsWith('::view-transition')){
2558-
viewTransitionAnimations.push(animations[i]);
2559+
}elseif(
2560+
pseudoElement.startsWith('::view-transition')&&
2561+
effect.target===documentElement
2562+
){
25592563
consttiming=effect.getTiming();
25602564
constduration=
25612565
// $FlowFixMe[prop-missing]
@@ -2648,6 +2652,7 @@ export function startGestureTransition(
26482652
effect.target,
26492653
pseudoElement,
26502654
timeline,
2655+
viewTransitionAnimations,
26512656
customTimelineCleanup,
26522657
adjustedRangeStart,
26532658
adjustedRangeEnd,
@@ -2675,6 +2680,7 @@ export function startGestureTransition(
26752680
effect.target,
26762681
pseudoElementName,
26772682
timeline,
2683+
viewTransitionAnimations,
26782684
customTimelineCleanup,
26792685
rangeStart,
26802686
rangeEnd,
@@ -2696,6 +2702,7 @@ export function startGestureTransition(
26962702
duration: 1,
26972703
});
26982704
blockingAnim.pause();
2705+
viewTransitionAnimations.push(blockingAnim);
26992706
animateCallback();
27002707
};
27012708
// In Chrome, "new" animations are not ready in the ready callback. We have to wait

0 commit comments

Comments
 (0)