Fix tutorial tooltip flash at 0,0 and slow step transitions
- Hide tooltip/ring with visibility:hidden until first step is positioned - Hide tooltip between steps when scrolling to prevent stale position flash - Replace scrollend event (poor browser support, 500ms fallback) with requestAnimationFrame polling that resolves in ~50ms when scroll settles Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -104,6 +104,14 @@ export function startTutorial(config) {
|
|||||||
onClose: config.onClose || null
|
onClose: config.onClose || null
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Hide tooltip and ring until first step positions them (prevents flash at 0,0)
|
||||||
|
const tooltip = overlay.querySelector('.tutorial-tooltip');
|
||||||
|
const ring = overlay.querySelector('.tutorial-ring');
|
||||||
|
const backdrop = overlay.querySelector('.tutorial-backdrop');
|
||||||
|
if (tooltip) tooltip.style.visibility = 'hidden';
|
||||||
|
if (ring) ring.style.visibility = 'hidden';
|
||||||
|
if (backdrop) backdrop.style.clipPath = 'none';
|
||||||
|
|
||||||
overlay.classList.add('active');
|
overlay.classList.add('active');
|
||||||
document.addEventListener('keydown', handleTutorialKey);
|
document.addEventListener('keydown', handleTutorialKey);
|
||||||
showTutorialStep(0);
|
showTutorialStep(0);
|
||||||
@@ -276,19 +284,25 @@ function _positionSpotlight(target, overlay, step, index, isFixed) {
|
|||||||
|
|
||||||
if (tooltip) {
|
if (tooltip) {
|
||||||
positionTutorialTooltip(tooltip, x, y, w, h, step.position, isFixed);
|
positionTutorialTooltip(tooltip, x, y, w, h, step.position, isFixed);
|
||||||
|
tooltip.style.visibility = '';
|
||||||
}
|
}
|
||||||
|
if (ring) ring.style.visibility = '';
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Wait for smooth scroll to finish, then resolve. */
|
/** Wait for scroll to settle (position stops changing). */
|
||||||
function _waitForScrollEnd(scrollTarget) {
|
function _waitForScrollEnd() {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
let timer = setTimeout(resolve, 500); // fallback
|
let lastY = window.scrollY;
|
||||||
const onEnd = () => {
|
let stableFrames = 0;
|
||||||
clearTimeout(timer);
|
const fallback = setTimeout(resolve, 300);
|
||||||
scrollTarget.removeEventListener('scrollend', onEnd);
|
function check() {
|
||||||
resolve();
|
const y = window.scrollY;
|
||||||
};
|
if (y === lastY) stableFrames++;
|
||||||
scrollTarget.addEventListener('scrollend', onEnd, { once: true });
|
else { stableFrames = 0; lastY = y; }
|
||||||
|
if (stableFrames >= 3) { clearTimeout(fallback); resolve(); }
|
||||||
|
else requestAnimationFrame(check);
|
||||||
|
}
|
||||||
|
requestAnimationFrame(check);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,8 +335,11 @@ function showTutorialStep(index, direction = 1) {
|
|||||||
const needsScroll = preRect.bottom > window.innerHeight || preRect.top < headerH;
|
const needsScroll = preRect.bottom > window.innerHeight || preRect.top < headerH;
|
||||||
|
|
||||||
if (needsScroll) {
|
if (needsScroll) {
|
||||||
|
// Hide tooltip while scrolling to prevent stale position flash
|
||||||
|
const tt = overlay.querySelector('.tutorial-tooltip');
|
||||||
|
if (tt) tt.style.visibility = 'hidden';
|
||||||
target.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
target.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
||||||
_waitForScrollEnd(isFixed ? document.scrollingElement || document.documentElement : activeTutorial.container).then(() => {
|
_waitForScrollEnd().then(() => {
|
||||||
if (activeTutorial && activeTutorial.step === index) {
|
if (activeTutorial && activeTutorial.step === index) {
|
||||||
_positionSpotlight(target, overlay, step, index, isFixed);
|
_positionSpotlight(target, overlay, step, index, isFixed);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user