visual-element-variant.mjs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465
  1. import { resolveVariant } from '../../render/utils/resolve-dynamic-variants.mjs';
  2. import { animateTarget } from './visual-element-target.mjs';
  3. function animateVariant(visualElement, variant, options = {}) {
  4. const resolved = resolveVariant(visualElement, variant, options.type === "exit"
  5. ? visualElement.presenceContext?.custom
  6. : undefined);
  7. let { transition = visualElement.getDefaultTransition() || {} } = resolved || {};
  8. if (options.transitionOverride) {
  9. transition = options.transitionOverride;
  10. }
  11. /**
  12. * If we have a variant, create a callback that runs it as an animation.
  13. * Otherwise, we resolve a Promise immediately for a composable no-op.
  14. */
  15. const getAnimation = resolved
  16. ? () => Promise.all(animateTarget(visualElement, resolved, options))
  17. : () => Promise.resolve();
  18. /**
  19. * If we have children, create a callback that runs all their animations.
  20. * Otherwise, we resolve a Promise immediately for a composable no-op.
  21. */
  22. const getChildAnimations = visualElement.variantChildren && visualElement.variantChildren.size
  23. ? (forwardDelay = 0) => {
  24. const { delayChildren = 0, staggerChildren, staggerDirection, } = transition;
  25. return animateChildren(visualElement, variant, delayChildren + forwardDelay, staggerChildren, staggerDirection, options);
  26. }
  27. : () => Promise.resolve();
  28. /**
  29. * If the transition explicitly defines a "when" option, we need to resolve either
  30. * this animation or all children animations before playing the other.
  31. */
  32. const { when } = transition;
  33. if (when) {
  34. const [first, last] = when === "beforeChildren"
  35. ? [getAnimation, getChildAnimations]
  36. : [getChildAnimations, getAnimation];
  37. return first().then(() => last());
  38. }
  39. else {
  40. return Promise.all([getAnimation(), getChildAnimations(options.delay)]);
  41. }
  42. }
  43. function animateChildren(visualElement, variant, delayChildren = 0, staggerChildren = 0, staggerDirection = 1, options) {
  44. const animations = [];
  45. const maxStaggerDuration = (visualElement.variantChildren.size - 1) * staggerChildren;
  46. const generateStaggerDuration = staggerDirection === 1
  47. ? (i = 0) => i * staggerChildren
  48. : (i = 0) => maxStaggerDuration - i * staggerChildren;
  49. Array.from(visualElement.variantChildren)
  50. .sort(sortByTreeOrder)
  51. .forEach((child, i) => {
  52. child.notify("AnimationStart", variant);
  53. animations.push(animateVariant(child, variant, {
  54. ...options,
  55. delay: delayChildren + generateStaggerDuration(i),
  56. }).then(() => child.notify("AnimationComplete", variant)));
  57. });
  58. return Promise.all(animations);
  59. }
  60. function sortByTreeOrder(a, b) {
  61. return a.sortNodePosition(b);
  62. }
  63. export { animateVariant, sortByTreeOrder };