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
|
||||
});
|
||||
|
||||
// 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');
|
||||
document.addEventListener('keydown', handleTutorialKey);
|
||||
showTutorialStep(0);
|
||||
@@ -276,19 +284,25 @@ function _positionSpotlight(target, overlay, step, index, isFixed) {
|
||||
|
||||
if (tooltip) {
|
||||
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. */
|
||||
function _waitForScrollEnd(scrollTarget) {
|
||||
/** Wait for scroll to settle (position stops changing). */
|
||||
function _waitForScrollEnd() {
|
||||
return new Promise(resolve => {
|
||||
let timer = setTimeout(resolve, 500); // fallback
|
||||
const onEnd = () => {
|
||||
clearTimeout(timer);
|
||||
scrollTarget.removeEventListener('scrollend', onEnd);
|
||||
resolve();
|
||||
};
|
||||
scrollTarget.addEventListener('scrollend', onEnd, { once: true });
|
||||
let lastY = window.scrollY;
|
||||
let stableFrames = 0;
|
||||
const fallback = setTimeout(resolve, 300);
|
||||
function check() {
|
||||
const y = window.scrollY;
|
||||
if (y === lastY) stableFrames++;
|
||||
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;
|
||||
|
||||
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' });
|
||||
_waitForScrollEnd(isFixed ? document.scrollingElement || document.documentElement : activeTutorial.container).then(() => {
|
||||
_waitForScrollEnd().then(() => {
|
||||
if (activeTutorial && activeTutorial.step === index) {
|
||||
_positionSpotlight(target, overlay, step, index, isFixed);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user