visual-element-target.mjs 3.0 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273
  1. import { getValueTransition, frame } from 'motion-dom';
  2. import { positionalKeys } from '../../render/html/utils/keys-position.mjs';
  3. import { setTarget } from '../../render/utils/setters.mjs';
  4. import { addValueToWillChange } from '../../value/use-will-change/add-will-change.mjs';
  5. import { getOptimisedAppearId } from '../optimized-appear/get-appear-id.mjs';
  6. import { animateMotionValue } from './motion-value.mjs';
  7. /**
  8. * Decide whether we should block this animation. Previously, we achieved this
  9. * just by checking whether the key was listed in protectedKeys, but this
  10. * posed problems if an animation was triggered by afterChildren and protectedKeys
  11. * had been set to true in the meantime.
  12. */
  13. function shouldBlockAnimation({ protectedKeys, needsAnimating }, key) {
  14. const shouldBlock = protectedKeys.hasOwnProperty(key) && needsAnimating[key] !== true;
  15. needsAnimating[key] = false;
  16. return shouldBlock;
  17. }
  18. function animateTarget(visualElement, targetAndTransition, { delay = 0, transitionOverride, type } = {}) {
  19. let { transition = visualElement.getDefaultTransition(), transitionEnd, ...target } = targetAndTransition;
  20. if (transitionOverride)
  21. transition = transitionOverride;
  22. const animations = [];
  23. const animationTypeState = type &&
  24. visualElement.animationState &&
  25. visualElement.animationState.getState()[type];
  26. for (const key in target) {
  27. const value = visualElement.getValue(key, visualElement.latestValues[key] ?? null);
  28. const valueTarget = target[key];
  29. if (valueTarget === undefined ||
  30. (animationTypeState &&
  31. shouldBlockAnimation(animationTypeState, key))) {
  32. continue;
  33. }
  34. const valueTransition = {
  35. delay,
  36. ...getValueTransition(transition || {}, key),
  37. };
  38. /**
  39. * If this is the first time a value is being animated, check
  40. * to see if we're handling off from an existing animation.
  41. */
  42. let isHandoff = false;
  43. if (window.MotionHandoffAnimation) {
  44. const appearId = getOptimisedAppearId(visualElement);
  45. if (appearId) {
  46. const startTime = window.MotionHandoffAnimation(appearId, key, frame);
  47. if (startTime !== null) {
  48. valueTransition.startTime = startTime;
  49. isHandoff = true;
  50. }
  51. }
  52. }
  53. addValueToWillChange(visualElement, key);
  54. value.start(animateMotionValue(key, value, valueTarget, visualElement.shouldReduceMotion && positionalKeys.has(key)
  55. ? { type: false }
  56. : valueTransition, visualElement, isHandoff));
  57. const animation = value.animation;
  58. if (animation) {
  59. animations.push(animation);
  60. }
  61. }
  62. if (transitionEnd) {
  63. Promise.all(animations).then(() => {
  64. frame.update(() => {
  65. transitionEnd && setTarget(visualElement, transitionEnd);
  66. });
  67. });
  68. }
  69. return animations;
  70. }
  71. export { animateTarget };