@atlaskit/renderer
Version:
Renderer component
89 lines (83 loc) • 3.33 kB
JavaScript
import { useRef, useCallback } from 'react';
/**
* Hook that provides functionality to wait for layout stability before performing an action.
* Uses ResizeObserver to detect when a container has stopped resizing (e.g., images finished loading).
*/
export var useStableScroll = function useStableScroll() {
var options = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
var _options$stabilityWai = options.stabilityWaitTime,
stabilityWaitTime = _options$stabilityWai === void 0 ? 200 : _options$stabilityWai,
_options$maxStability = options.maxStabilityWaitTime,
maxStabilityWaitTime = _options$maxStability === void 0 ? 10000 : _options$maxStability;
var stabilityTimeoutRef = useRef(null);
var resizeObserverRef = useRef(null);
var lastStableTimeRef = useRef(0);
var onStableCallbackRef = useRef(null);
var cleanup = useCallback(function () {
if (stabilityTimeoutRef.current) {
clearTimeout(stabilityTimeoutRef.current);
stabilityTimeoutRef.current = null;
}
if (resizeObserverRef.current) {
resizeObserverRef.current.disconnect();
resizeObserverRef.current = null;
}
onStableCallbackRef.current = null;
lastStableTimeRef.current = 0;
}, []);
var scheduleStabilityCheck = useCallback(function () {
// Clear any existing stability timeout.
if (stabilityTimeoutRef.current) {
clearTimeout(stabilityTimeoutRef.current);
stabilityTimeoutRef.current = null;
}
// Check if we've exceeded the maximum stability wait time.
var now = Date.now();
if (lastStableTimeRef.current === 0) {
lastStableTimeRef.current = now;
} else if (now - lastStableTimeRef.current > maxStabilityWaitTime) {
// We've waited too long for stability, call the callback now.
if (onStableCallbackRef.current) {
onStableCallbackRef.current();
cleanup();
}
return;
}
// Set a timeout to call the callback after the stability wait time.
stabilityTimeoutRef.current = setTimeout(function () {
if (onStableCallbackRef.current) {
onStableCallbackRef.current();
cleanup();
}
}, stabilityWaitTime);
}, [stabilityWaitTime, maxStabilityWaitTime, cleanup]);
var waitForStability = useCallback(function (container, onStable) {
// Clean up any existing observer
cleanup();
// Store the callback
onStableCallbackRef.current = onStable;
// Check if ResizeObserver is available
if (typeof ResizeObserver === 'undefined') {
// Fallback: just call the callback after the stability wait time
stabilityTimeoutRef.current = setTimeout(function () {
if (onStableCallbackRef.current) {
onStableCallbackRef.current();
cleanup();
}
}, stabilityWaitTime);
return;
}
// Create a ResizeObserver to monitor the container for size changes.
resizeObserverRef.current = new ResizeObserver(function () {
// Container size changed, reset stability timer.
scheduleStabilityCheck();
});
resizeObserverRef.current.observe(container);
// Start the initial stability check
scheduleStabilityCheck();
}, [stabilityWaitTime, scheduleStabilityCheck, cleanup]);
return {
waitForStability: waitForStability,
cleanup: cleanup
};
};