202 lines
7.7 KiB
JavaScript
202 lines
7.7 KiB
JavaScript
'use client';
|
|
"use strict";
|
|
Object.defineProperty(exports, "__esModule", {
|
|
value: true
|
|
});
|
|
function _export(target, all) {
|
|
for(var name in all)Object.defineProperty(target, name, {
|
|
enumerable: true,
|
|
get: all[name]
|
|
});
|
|
}
|
|
_export(exports, {
|
|
DEFAULT_ANIMATION_OPTIONS: function() {
|
|
return DEFAULT_ANIMATION_OPTIONS;
|
|
},
|
|
useAnimateAtoms: function() {
|
|
return useAnimateAtoms;
|
|
}
|
|
});
|
|
const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard");
|
|
const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react"));
|
|
const _isAnimationRunning = require("../utils/isAnimationRunning");
|
|
const DEFAULT_ANIMATION_OPTIONS = {
|
|
fill: 'forwards'
|
|
};
|
|
// A motion atom's default reduced motion is a simple 1 ms duration.
|
|
// But an atom can define a custom reduced motion, overriding keyframes and/or params like duration, easing, iterations, etc.
|
|
const DEFAULT_REDUCED_MOTION_ATOM = {
|
|
duration: 1
|
|
};
|
|
/**
|
|
* Creates an animation handle that controls multiple animations.
|
|
* Is used to avoid leaking "element" references from the hook.
|
|
*
|
|
* @param animations
|
|
*/ function createHandle(animations) {
|
|
return {
|
|
set playbackRate (rate){
|
|
animations.forEach((animation)=>{
|
|
animation.playbackRate = rate;
|
|
});
|
|
},
|
|
setMotionEndCallbacks (onfinish, oncancel) {
|
|
// Heads up!
|
|
// This could use "Animation:finished", but it's causing a memory leak in Chromium.
|
|
// See: https://issues.chromium.org/u/2/issues/383016426
|
|
const promises = animations.map((animation)=>{
|
|
return new Promise((resolve, reject)=>{
|
|
animation.onfinish = ()=>resolve();
|
|
animation.oncancel = ()=>reject();
|
|
});
|
|
});
|
|
Promise.all(promises).then(()=>{
|
|
onfinish();
|
|
}).catch(()=>{
|
|
oncancel();
|
|
});
|
|
},
|
|
isRunning () {
|
|
return animations.some((animation)=>(0, _isAnimationRunning.isAnimationRunning)(animation));
|
|
},
|
|
dispose: ()=>{
|
|
animations.length = 0;
|
|
},
|
|
cancel: ()=>{
|
|
animations.forEach((animation)=>{
|
|
animation.cancel();
|
|
});
|
|
},
|
|
pause: ()=>{
|
|
animations.forEach((animation)=>{
|
|
animation.pause();
|
|
});
|
|
},
|
|
play: ()=>{
|
|
animations.forEach((animation)=>{
|
|
animation.play();
|
|
});
|
|
},
|
|
finish: ()=>{
|
|
animations.forEach((animation)=>{
|
|
animation.finish();
|
|
});
|
|
},
|
|
reverse: ()=>{
|
|
// Heads up!
|
|
//
|
|
// This is used for the interruptible motion. If the animation is running, we need to reverse it.
|
|
//
|
|
// TODO: what do with animations that have "delay"?
|
|
// TODO: what do with animations that have different "durations"?
|
|
animations.forEach((animation)=>{
|
|
animation.reverse();
|
|
});
|
|
}
|
|
};
|
|
}
|
|
function useAnimateAtomsInSupportedEnvironment() {
|
|
var _window_Animation;
|
|
// eslint-disable-next-line @nx/workspace-no-restricted-globals
|
|
const SUPPORTS_PERSIST = typeof window !== 'undefined' && typeof ((_window_Animation = window.Animation) === null || _window_Animation === void 0 ? void 0 : _window_Animation.prototype.persist) === 'function';
|
|
return _react.useCallback((element, value, options)=>{
|
|
const atoms = Array.isArray(value) ? value : [
|
|
value
|
|
];
|
|
const { isReducedMotion } = options;
|
|
const animations = atoms.map((motion)=>{
|
|
// Grab the custom reduced motion definition if it exists, or fall back to the default reduced motion.
|
|
const { keyframes: motionKeyframes, reducedMotion = DEFAULT_REDUCED_MOTION_ATOM, ...params } = motion;
|
|
// Grab the reduced motion keyframes if they exist, or fall back to the regular keyframes.
|
|
const { keyframes: reducedMotionKeyframes = motionKeyframes, ...reducedMotionParams } = reducedMotion;
|
|
const animationKeyframes = isReducedMotion ? reducedMotionKeyframes : motionKeyframes;
|
|
const animationParams = {
|
|
...DEFAULT_ANIMATION_OPTIONS,
|
|
...params,
|
|
// Use reduced motion overrides (e.g. duration, easing) when reduced motion is enabled
|
|
...isReducedMotion && reducedMotionParams
|
|
};
|
|
try {
|
|
// Firefox can throw an error when calling `element.animate()`.
|
|
// See: https://github.com/microsoft/fluentui/issues/33902
|
|
const animation = element.animate(animationKeyframes, animationParams);
|
|
if (SUPPORTS_PERSIST) {
|
|
// Chromium browsers can return null when calling `element.animate()`.
|
|
// See: https://github.com/microsoft/fluentui/issues/33902
|
|
animation === null || animation === void 0 ? void 0 : animation.persist();
|
|
} else {
|
|
const resultKeyframe = animationKeyframes[animationKeyframes.length - 1];
|
|
var _element_style;
|
|
Object.assign((_element_style = element.style) !== null && _element_style !== void 0 ? _element_style : {}, resultKeyframe);
|
|
}
|
|
return animation;
|
|
} catch (e) {
|
|
return null;
|
|
}
|
|
}).filter((animation)=>!!animation);
|
|
return createHandle(animations);
|
|
}, [
|
|
SUPPORTS_PERSIST
|
|
]);
|
|
}
|
|
/**
|
|
* In test environments, this hook is used to delay the execution of a callback until the next render. This is necessary
|
|
* to ensure that the callback is not executed synchronously, which would cause the test to fail.
|
|
*
|
|
* @see https://github.com/microsoft/fluentui/issues/31701
|
|
*/ function useAnimateAtomsInTestEnvironment() {
|
|
const [count, setCount] = _react.useState(0);
|
|
const callbackRef = _react.useRef(undefined);
|
|
const realAnimateAtoms = useAnimateAtomsInSupportedEnvironment();
|
|
_react.useEffect(()=>{
|
|
if (count > 0) {
|
|
var _callbackRef_current;
|
|
(_callbackRef_current = callbackRef.current) === null || _callbackRef_current === void 0 ? void 0 : _callbackRef_current.call(callbackRef);
|
|
}
|
|
}, [
|
|
count
|
|
]);
|
|
return _react.useCallback((element, value, options)=>{
|
|
const ELEMENT_SUPPORTS_WEB_ANIMATIONS = typeof element.animate === 'function';
|
|
// Heads up!
|
|
// If the environment supports Web Animations API, we can use the native implementation.
|
|
if (ELEMENT_SUPPORTS_WEB_ANIMATIONS) {
|
|
return realAnimateAtoms(element, value, options);
|
|
}
|
|
return {
|
|
setMotionEndCallbacks (onfinish) {
|
|
callbackRef.current = onfinish;
|
|
setCount((v)=>v + 1);
|
|
},
|
|
set playbackRate (rate){
|
|
/* no-op */ },
|
|
isRunning () {
|
|
return false;
|
|
},
|
|
dispose () {
|
|
/* no-op */ },
|
|
cancel () {
|
|
/* no-op */ },
|
|
pause () {
|
|
/* no-op */ },
|
|
play () {
|
|
/* no-op */ },
|
|
finish () {
|
|
/* no-op */ },
|
|
reverse () {
|
|
/* no-op */ }
|
|
};
|
|
}, [
|
|
realAnimateAtoms
|
|
]);
|
|
}
|
|
function useAnimateAtoms() {
|
|
'use no memo';
|
|
if (process.env.NODE_ENV === 'test') {
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
return useAnimateAtomsInTestEnvironment();
|
|
}
|
|
// eslint-disable-next-line react-hooks/rules-of-hooks
|
|
return useAnimateAtomsInSupportedEnvironment();
|
|
}
|