use-visual-state.mjs 3.8 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import { useContext } from 'react';
  2. import { isAnimationControls } from '../../animation/utils/is-animation-controls.mjs';
  3. import { MotionContext } from '../../context/MotionContext/index.mjs';
  4. import { PresenceContext } from '../../context/PresenceContext.mjs';
  5. import { isControllingVariants, isVariantNode } from '../../render/utils/is-controlling-variants.mjs';
  6. import { resolveVariantFromProps } from '../../render/utils/resolve-variants.mjs';
  7. import { useConstant } from '../../utils/use-constant.mjs';
  8. import { resolveMotionValue } from '../../value/utils/resolve-motion-value.mjs';
  9. function makeState({ scrapeMotionValuesFromProps, createRenderState, onUpdate, }, props, context, presenceContext) {
  10. const state = {
  11. latestValues: makeLatestValues(props, context, presenceContext, scrapeMotionValuesFromProps),
  12. renderState: createRenderState(),
  13. };
  14. if (onUpdate) {
  15. /**
  16. * onMount works without the VisualElement because it could be
  17. * called before the VisualElement payload has been hydrated.
  18. * (e.g. if someone is using m components <m.circle />)
  19. */
  20. state.onMount = (instance) => onUpdate({ props, current: instance, ...state });
  21. state.onUpdate = (visualElement) => onUpdate(visualElement);
  22. }
  23. return state;
  24. }
  25. const makeUseVisualState = (config) => (props, isStatic) => {
  26. const context = useContext(MotionContext);
  27. const presenceContext = useContext(PresenceContext);
  28. const make = () => makeState(config, props, context, presenceContext);
  29. return isStatic ? make() : useConstant(make);
  30. };
  31. function makeLatestValues(props, context, presenceContext, scrapeMotionValues) {
  32. const values = {};
  33. const motionValues = scrapeMotionValues(props, {});
  34. for (const key in motionValues) {
  35. values[key] = resolveMotionValue(motionValues[key]);
  36. }
  37. let { initial, animate } = props;
  38. const isControllingVariants$1 = isControllingVariants(props);
  39. const isVariantNode$1 = isVariantNode(props);
  40. if (context &&
  41. isVariantNode$1 &&
  42. !isControllingVariants$1 &&
  43. props.inherit !== false) {
  44. if (initial === undefined)
  45. initial = context.initial;
  46. if (animate === undefined)
  47. animate = context.animate;
  48. }
  49. let isInitialAnimationBlocked = presenceContext
  50. ? presenceContext.initial === false
  51. : false;
  52. isInitialAnimationBlocked = isInitialAnimationBlocked || initial === false;
  53. const variantToSet = isInitialAnimationBlocked ? animate : initial;
  54. if (variantToSet &&
  55. typeof variantToSet !== "boolean" &&
  56. !isAnimationControls(variantToSet)) {
  57. const list = Array.isArray(variantToSet) ? variantToSet : [variantToSet];
  58. for (let i = 0; i < list.length; i++) {
  59. const resolved = resolveVariantFromProps(props, list[i]);
  60. if (resolved) {
  61. const { transitionEnd, transition, ...target } = resolved;
  62. for (const key in target) {
  63. let valueTarget = target[key];
  64. if (Array.isArray(valueTarget)) {
  65. /**
  66. * Take final keyframe if the initial animation is blocked because
  67. * we want to initialise at the end of that blocked animation.
  68. */
  69. const index = isInitialAnimationBlocked
  70. ? valueTarget.length - 1
  71. : 0;
  72. valueTarget = valueTarget[index];
  73. }
  74. if (valueTarget !== null) {
  75. values[key] = valueTarget;
  76. }
  77. }
  78. for (const key in transitionEnd) {
  79. values[key] = transitionEnd[key];
  80. }
  81. }
  82. }
  83. }
  84. return values;
  85. }
  86. export { makeUseVisualState };