mini.js 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. 'use strict';
  2. Object.defineProperty(exports, '__esModule', { value: true });
  3. var react = require('react');
  4. var motionDom = require('motion-dom');
  5. var motionUtils = require('motion-utils');
  6. /**
  7. * Creates a constant value over the lifecycle of a component.
  8. *
  9. * Even if `useMemo` is provided an empty array as its final argument, it doesn't offer
  10. * a guarantee that it won't re-run for performance reasons later on. By using `useConstant`
  11. * you can ensure that initialisers don't execute twice or more.
  12. */
  13. function useConstant(init) {
  14. const ref = react.useRef(null);
  15. if (ref.current === null) {
  16. ref.current = init();
  17. }
  18. return ref.current;
  19. }
  20. function useUnmountEffect(callback) {
  21. return react.useEffect(() => () => callback(), []);
  22. }
  23. function animateElements(elementOrSelector, keyframes, options, scope) {
  24. const elements = motionDom.resolveElements(elementOrSelector, scope);
  25. const numElements = elements.length;
  26. motionUtils.invariant(Boolean(numElements), "No valid element provided.");
  27. const animations = [];
  28. for (let i = 0; i < numElements; i++) {
  29. const element = elements[i];
  30. const elementTransition = { ...options };
  31. /**
  32. * Resolve stagger function if provided.
  33. */
  34. if (typeof elementTransition.delay === "function") {
  35. elementTransition.delay = elementTransition.delay(i, numElements);
  36. }
  37. for (const valueName in keyframes) {
  38. const valueKeyframes = keyframes[valueName];
  39. const valueOptions = {
  40. ...motionDom.getValueTransition(elementTransition, valueName),
  41. };
  42. valueOptions.duration && (valueOptions.duration = motionUtils.secondsToMilliseconds(valueOptions.duration));
  43. valueOptions.delay && (valueOptions.delay = motionUtils.secondsToMilliseconds(valueOptions.delay));
  44. animations.push(new motionDom.NativeAnimation({
  45. element,
  46. name: valueName,
  47. keyframes: valueKeyframes,
  48. transition: valueOptions,
  49. allowFlatten: !elementTransition.type && !elementTransition.ease,
  50. }));
  51. }
  52. }
  53. return animations;
  54. }
  55. const createScopedWaapiAnimate = (scope) => {
  56. function scopedAnimate(elementOrSelector, keyframes, options) {
  57. return new motionDom.GroupAnimationWithThen(animateElements(elementOrSelector, keyframes, options, scope));
  58. }
  59. return scopedAnimate;
  60. };
  61. function useAnimateMini() {
  62. const scope = useConstant(() => ({
  63. current: null, // Will be hydrated by React
  64. animations: [],
  65. }));
  66. const animate = useConstant(() => createScopedWaapiAnimate(scope));
  67. useUnmountEffect(() => {
  68. scope.animations.forEach((animation) => animation.stop());
  69. });
  70. return [scope, animate];
  71. }
  72. exports.useAnimate = useAnimateMini;