dialog-transition.mjs 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. import { createVNode as _createVNode, mergeProps as _mergeProps, resolveDirective as _resolveDirective } from "vue";
  2. // Utilities
  3. import { Transition } from 'vue';
  4. import { acceleratedEasing, animate, deceleratedEasing, genericComponent, nullifyTransforms, propsFactory, standardEasing } from "../../util/index.mjs";
  5. import { getTargetBox } from "../../util/box.mjs"; // Types
  6. export const makeVDialogTransitionProps = propsFactory({
  7. target: [Object, Array]
  8. }, 'v-dialog-transition');
  9. export const VDialogTransition = genericComponent()({
  10. name: 'VDialogTransition',
  11. props: makeVDialogTransitionProps(),
  12. setup(props, _ref) {
  13. let {
  14. slots
  15. } = _ref;
  16. const functions = {
  17. onBeforeEnter(el) {
  18. el.style.pointerEvents = 'none';
  19. el.style.visibility = 'hidden';
  20. },
  21. async onEnter(el, done) {
  22. await new Promise(resolve => requestAnimationFrame(resolve));
  23. await new Promise(resolve => requestAnimationFrame(resolve));
  24. el.style.visibility = '';
  25. const {
  26. x,
  27. y,
  28. sx,
  29. sy,
  30. speed
  31. } = getDimensions(props.target, el);
  32. const animation = animate(el, [{
  33. transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
  34. opacity: 0
  35. }, {}], {
  36. duration: 225 * speed,
  37. easing: deceleratedEasing
  38. });
  39. getChildren(el)?.forEach(el => {
  40. animate(el, [{
  41. opacity: 0
  42. }, {
  43. opacity: 0,
  44. offset: 0.33
  45. }, {}], {
  46. duration: 225 * 2 * speed,
  47. easing: standardEasing
  48. });
  49. });
  50. animation.finished.then(() => done());
  51. },
  52. onAfterEnter(el) {
  53. el.style.removeProperty('pointer-events');
  54. },
  55. onBeforeLeave(el) {
  56. el.style.pointerEvents = 'none';
  57. },
  58. async onLeave(el, done) {
  59. await new Promise(resolve => requestAnimationFrame(resolve));
  60. const {
  61. x,
  62. y,
  63. sx,
  64. sy,
  65. speed
  66. } = getDimensions(props.target, el);
  67. const animation = animate(el, [{}, {
  68. transform: `translate(${x}px, ${y}px) scale(${sx}, ${sy})`,
  69. opacity: 0
  70. }], {
  71. duration: 125 * speed,
  72. easing: acceleratedEasing
  73. });
  74. animation.finished.then(() => done());
  75. getChildren(el)?.forEach(el => {
  76. animate(el, [{}, {
  77. opacity: 0,
  78. offset: 0.2
  79. }, {
  80. opacity: 0
  81. }], {
  82. duration: 125 * 2 * speed,
  83. easing: standardEasing
  84. });
  85. });
  86. },
  87. onAfterLeave(el) {
  88. el.style.removeProperty('pointer-events');
  89. }
  90. };
  91. return () => {
  92. return props.target ? _createVNode(Transition, _mergeProps({
  93. "name": "dialog-transition"
  94. }, functions, {
  95. "css": false
  96. }), slots) : _createVNode(Transition, {
  97. "name": "dialog-transition"
  98. }, slots);
  99. };
  100. }
  101. });
  102. /** Animatable children (card, sheet, list) */
  103. function getChildren(el) {
  104. const els = el.querySelector(':scope > .v-card, :scope > .v-sheet, :scope > .v-list')?.children;
  105. return els && [...els];
  106. }
  107. function getDimensions(target, el) {
  108. const targetBox = getTargetBox(target);
  109. const elBox = nullifyTransforms(el);
  110. const [originX, originY] = getComputedStyle(el).transformOrigin.split(' ').map(v => parseFloat(v));
  111. const [anchorSide, anchorOffset] = getComputedStyle(el).getPropertyValue('--v-overlay-anchor-origin').split(' ');
  112. let offsetX = targetBox.left + targetBox.width / 2;
  113. if (anchorSide === 'left' || anchorOffset === 'left') {
  114. offsetX -= targetBox.width / 2;
  115. } else if (anchorSide === 'right' || anchorOffset === 'right') {
  116. offsetX += targetBox.width / 2;
  117. }
  118. let offsetY = targetBox.top + targetBox.height / 2;
  119. if (anchorSide === 'top' || anchorOffset === 'top') {
  120. offsetY -= targetBox.height / 2;
  121. } else if (anchorSide === 'bottom' || anchorOffset === 'bottom') {
  122. offsetY += targetBox.height / 2;
  123. }
  124. const tsx = targetBox.width / elBox.width;
  125. const tsy = targetBox.height / elBox.height;
  126. const maxs = Math.max(1, tsx, tsy);
  127. const sx = tsx / maxs || 0;
  128. const sy = tsy / maxs || 0;
  129. // Animate elements larger than 12% of the screen area up to 1.5x slower
  130. const asa = elBox.width * elBox.height / (window.innerWidth * window.innerHeight);
  131. const speed = asa > 0.12 ? Math.min(1.5, (asa - 0.12) * 10 + 1) : 1;
  132. return {
  133. x: offsetX - (originX + elBox.left),
  134. y: offsetY - (originY + elBox.top),
  135. sx,
  136. sy,
  137. speed
  138. };
  139. }
  140. //# sourceMappingURL=dialog-transition.mjs.map