WaveEffect.js 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. "use strict";
  2. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
  3. Object.defineProperty(exports, "__esModule", {
  4. value: true
  5. });
  6. exports.default = void 0;
  7. var _vue = require("vue");
  8. var _useState = _interopRequireDefault(require("../hooks/useState"));
  9. var _type = require("../type");
  10. var _util = require("./util");
  11. var _raf = _interopRequireDefault(require("../raf"));
  12. function validateNum(value) {
  13. return Number.isNaN(value) ? 0 : value;
  14. }
  15. const WaveEffect = (0, _vue.defineComponent)({
  16. props: {
  17. target: (0, _type.objectType)(),
  18. className: String
  19. },
  20. setup(props) {
  21. const divRef = (0, _vue.shallowRef)(null);
  22. const [color, setWaveColor] = (0, _useState.default)(null);
  23. const [borderRadius, setBorderRadius] = (0, _useState.default)([]);
  24. const [left, setLeft] = (0, _useState.default)(0);
  25. const [top, setTop] = (0, _useState.default)(0);
  26. const [width, setWidth] = (0, _useState.default)(0);
  27. const [height, setHeight] = (0, _useState.default)(0);
  28. const [enabled, setEnabled] = (0, _useState.default)(false);
  29. function syncPos() {
  30. const {
  31. target
  32. } = props;
  33. const nodeStyle = getComputedStyle(target);
  34. // Get wave color from target
  35. setWaveColor((0, _util.getTargetWaveColor)(target));
  36. const isStatic = nodeStyle.position === 'static';
  37. // Rect
  38. const {
  39. borderLeftWidth,
  40. borderTopWidth
  41. } = nodeStyle;
  42. setLeft(isStatic ? target.offsetLeft : validateNum(-parseFloat(borderLeftWidth)));
  43. setTop(isStatic ? target.offsetTop : validateNum(-parseFloat(borderTopWidth)));
  44. setWidth(target.offsetWidth);
  45. setHeight(target.offsetHeight);
  46. // Get border radius
  47. const {
  48. borderTopLeftRadius,
  49. borderTopRightRadius,
  50. borderBottomLeftRadius,
  51. borderBottomRightRadius
  52. } = nodeStyle;
  53. setBorderRadius([borderTopLeftRadius, borderTopRightRadius, borderBottomRightRadius, borderBottomLeftRadius].map(radius => validateNum(parseFloat(radius))));
  54. }
  55. // Add resize observer to follow size
  56. let resizeObserver;
  57. let rafId;
  58. let timeoutId;
  59. const clear = () => {
  60. clearTimeout(timeoutId);
  61. _raf.default.cancel(rafId);
  62. resizeObserver === null || resizeObserver === void 0 ? void 0 : resizeObserver.disconnect();
  63. };
  64. const removeDom = () => {
  65. var _a;
  66. const holder = (_a = divRef.value) === null || _a === void 0 ? void 0 : _a.parentElement;
  67. if (holder) {
  68. (0, _vue.render)(null, holder);
  69. if (holder.parentElement) {
  70. holder.parentElement.removeChild(holder);
  71. }
  72. }
  73. };
  74. (0, _vue.onMounted)(() => {
  75. clear();
  76. timeoutId = setTimeout(() => {
  77. removeDom();
  78. }, 5000);
  79. const {
  80. target
  81. } = props;
  82. if (target) {
  83. // We need delay to check position here
  84. // since UI may change after click
  85. rafId = (0, _raf.default)(() => {
  86. syncPos();
  87. setEnabled(true);
  88. });
  89. if (typeof ResizeObserver !== 'undefined') {
  90. resizeObserver = new ResizeObserver(syncPos);
  91. resizeObserver.observe(target);
  92. }
  93. }
  94. });
  95. (0, _vue.onBeforeUnmount)(() => {
  96. clear();
  97. });
  98. const onTransitionend = e => {
  99. if (e.propertyName === 'opacity') {
  100. removeDom();
  101. }
  102. };
  103. return () => {
  104. if (!enabled.value) {
  105. return null;
  106. }
  107. const waveStyle = {
  108. left: `${left.value}px`,
  109. top: `${top.value}px`,
  110. width: `${width.value}px`,
  111. height: `${height.value}px`,
  112. borderRadius: borderRadius.value.map(radius => `${radius}px`).join(' ')
  113. };
  114. if (color) {
  115. waveStyle['--wave-color'] = color.value;
  116. }
  117. return (0, _vue.createVNode)(_vue.Transition, {
  118. "appear": true,
  119. "name": "wave-motion",
  120. "appearFromClass": "wave-motion-appear",
  121. "appearActiveClass": "wave-motion-appear",
  122. "appearToClass": "wave-motion-appear wave-motion-appear-active"
  123. }, {
  124. default: () => [(0, _vue.createVNode)("div", {
  125. "ref": divRef,
  126. "class": props.className,
  127. "style": waveStyle,
  128. "onTransitionend": onTransitionend
  129. }, null)]
  130. });
  131. };
  132. }
  133. });
  134. function showWaveEffect(node, className) {
  135. // Create holder
  136. const holder = document.createElement('div');
  137. holder.style.position = 'absolute';
  138. holder.style.left = `0px`;
  139. holder.style.top = `0px`;
  140. node === null || node === void 0 ? void 0 : node.insertBefore(holder, node === null || node === void 0 ? void 0 : node.firstChild);
  141. (0, _vue.render)((0, _vue.createVNode)(WaveEffect, {
  142. "target": node,
  143. "className": className
  144. }, null), holder);
  145. }
  146. var _default = exports.default = showWaveEffect;