use-start-view-transition
Version:
A set of hooks to use `document.startViewTransition` upon state/value changes
60 lines (59 loc) • 2.28 kB
JavaScript
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
let react = require("react");
//#region src/index.ts
const startViewTransition = async (fn) => {
if (typeof window === "undefined" || !("startViewTransition" in document)) {
fn();
return;
}
try {
return document.startViewTransition(fn).ready.catch((error) => {
if (error instanceof Error && (error.name === "AbortError" || error.name === "InvalidStateError")) return;
throw error;
});
} catch (error) {
if (error instanceof Error && (error.name === "AbortError" || error.name === "InvalidStateError")) {
fn();
return;
}
throw error;
}
};
const useStartViewTransitionWrap = ([value, _setState], options = {}) => {
const optionsRef = (0, react.useRef)(options);
const isTransitionReadyRef = (0, react.useRef)(false);
optionsRef.current = options;
(0, react.useEffect)(() => {
const frameId = window.requestAnimationFrame(() => {
isTransitionReadyRef.current = true;
});
return () => {
window.cancelAnimationFrame(frameId);
};
}, []);
return [value, (0, react.useCallback)(async (v) => {
const { skipTransition } = optionsRef.current;
const skipFn = typeof skipTransition === "function" ? skipTransition : (v) => skipTransition;
if (isTransitionReadyRef.current && !skipFn(value)) return startViewTransition(() => _setState(v));
_setState(v);
}, [_setState, value])];
};
const useStartViewTransitionValue = (_value, options = {}) => {
const valueRef = (0, react.useRef)(_value);
const [value, setValue] = useStartViewTransitionWrap((0, react.useState)(_value), options);
const { skipTransition } = options;
const shouldSkip = (typeof skipTransition === "function" ? skipTransition : (v) => skipTransition)(_value);
if (_value !== valueRef.current) {
valueRef.current = _value;
setValue(_value);
}
return shouldSkip ? _value : value;
};
const useStartViewTransitionState = (state, options = {}) => {
return useStartViewTransitionWrap((0, react.useState)(state), options);
};
//#endregion
exports.startViewTransition = startViewTransition;
exports.useStartViewTransitionState = useStartViewTransitionState;
exports.useStartViewTransitionValue = useStartViewTransitionValue;
exports.useStartViewTransitionWrap = useStartViewTransitionWrap;