fix: button wave not work
							parent
							
								
									7d1418d9f4
								
							
						
					
					
						commit
						dcc3bb10cb
					
				| 
						 | 
				
			
			@ -1,178 +0,0 @@
 | 
			
		|||
import { nextTick, defineComponent, getCurrentInstance, onMounted, onBeforeUnmount } from 'vue';
 | 
			
		||||
import TransitionEvents from './css-animation/Event';
 | 
			
		||||
import raf from './raf';
 | 
			
		||||
import { findDOMNode } from './props-util';
 | 
			
		||||
import useConfigInject from '../config-provider/hooks/useConfigInject';
 | 
			
		||||
let styleForPesudo: HTMLStyleElement;
 | 
			
		||||
 | 
			
		||||
// Where el is the DOM element you'd like to test for visibility
 | 
			
		||||
function isHidden(element: HTMLElement) {
 | 
			
		||||
  if (process.env.NODE_ENV === 'test') {
 | 
			
		||||
    return false;
 | 
			
		||||
  }
 | 
			
		||||
  return !element || element.offsetParent === null;
 | 
			
		||||
}
 | 
			
		||||
function isNotGrey(color: string) {
 | 
			
		||||
  // eslint-disable-next-line no-useless-escape
 | 
			
		||||
  const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\.\d]*)?\)/);
 | 
			
		||||
  if (match && match[1] && match[2] && match[3]) {
 | 
			
		||||
    return !(match[1] === match[2] && match[2] === match[3]);
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  compatConfig: { MODE: 3 },
 | 
			
		||||
  name: 'Wave',
 | 
			
		||||
  props: {
 | 
			
		||||
    insertExtraNode: Boolean,
 | 
			
		||||
    disabled: Boolean,
 | 
			
		||||
  },
 | 
			
		||||
  setup(props, { slots, expose }) {
 | 
			
		||||
    const instance = getCurrentInstance();
 | 
			
		||||
    const { csp, prefixCls } = useConfigInject('', props);
 | 
			
		||||
    expose({
 | 
			
		||||
      csp,
 | 
			
		||||
    });
 | 
			
		||||
    let eventIns = null;
 | 
			
		||||
    let clickWaveTimeoutId = null;
 | 
			
		||||
    let animationStartId = null;
 | 
			
		||||
    let animationStart = false;
 | 
			
		||||
    let extraNode = null;
 | 
			
		||||
    let isUnmounted = false;
 | 
			
		||||
    const onTransitionStart = e => {
 | 
			
		||||
      if (isUnmounted) return;
 | 
			
		||||
 | 
			
		||||
      const node = findDOMNode(instance);
 | 
			
		||||
      if (!e || e.target !== node) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (!animationStart) {
 | 
			
		||||
        resetEffect(node);
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    const onTransitionEnd = (e: any) => {
 | 
			
		||||
      if (!e || e.animationName !== 'fadeEffect') {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      resetEffect(e.target);
 | 
			
		||||
    };
 | 
			
		||||
    const getAttributeName = () => {
 | 
			
		||||
      const { insertExtraNode } = props;
 | 
			
		||||
      return insertExtraNode
 | 
			
		||||
        ? `${prefixCls.value}-click-animating`
 | 
			
		||||
        : `${prefixCls.value}-click-animating-without-extra-node`;
 | 
			
		||||
    };
 | 
			
		||||
    const onClick = (node: HTMLElement, waveColor: string) => {
 | 
			
		||||
      const { insertExtraNode, disabled } = props;
 | 
			
		||||
      if (disabled || !node || isHidden(node) || node.className.indexOf('-leave') >= 0) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      extraNode = document.createElement('div');
 | 
			
		||||
      extraNode.className = `${prefixCls.value}-click-animating-node`;
 | 
			
		||||
      const attributeName = getAttributeName();
 | 
			
		||||
      node.removeAttribute(attributeName);
 | 
			
		||||
      node.setAttribute(attributeName, 'true');
 | 
			
		||||
      // Not white or transparent or grey
 | 
			
		||||
      styleForPesudo = styleForPesudo || document.createElement('style');
 | 
			
		||||
      if (
 | 
			
		||||
        waveColor &&
 | 
			
		||||
        waveColor !== '#ffffff' &&
 | 
			
		||||
        waveColor !== 'rgb(255, 255, 255)' &&
 | 
			
		||||
        isNotGrey(waveColor) &&
 | 
			
		||||
        !/rgba\(\d*, \d*, \d*, 0\)/.test(waveColor) && // any transparent rgba color
 | 
			
		||||
        waveColor !== 'transparent'
 | 
			
		||||
      ) {
 | 
			
		||||
        // Add nonce if CSP exist
 | 
			
		||||
        if (csp.value?.nonce) {
 | 
			
		||||
          styleForPesudo.nonce = csp.value.nonce;
 | 
			
		||||
        }
 | 
			
		||||
        extraNode.style.borderColor = waveColor;
 | 
			
		||||
        styleForPesudo.innerHTML = `
 | 
			
		||||
        [${prefixCls.value}-click-animating-without-extra-node='true']::after, .${prefixCls.value}-click-animating-node {
 | 
			
		||||
          --antd-wave-shadow-color: ${waveColor};
 | 
			
		||||
        }`;
 | 
			
		||||
        if (!document.body.contains(styleForPesudo)) {
 | 
			
		||||
          document.body.appendChild(styleForPesudo);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
      if (insertExtraNode) {
 | 
			
		||||
        node.appendChild(extraNode);
 | 
			
		||||
      }
 | 
			
		||||
      TransitionEvents.addStartEventListener(node, onTransitionStart);
 | 
			
		||||
      TransitionEvents.addEndEventListener(node, onTransitionEnd);
 | 
			
		||||
    };
 | 
			
		||||
    const resetEffect = (node: HTMLElement) => {
 | 
			
		||||
      if (!node || node === extraNode || !(node instanceof Element)) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const { insertExtraNode } = props;
 | 
			
		||||
      const attributeName = getAttributeName();
 | 
			
		||||
      node.setAttribute(attributeName, 'false'); // edge has bug on `removeAttribute` #14466
 | 
			
		||||
      if (styleForPesudo) {
 | 
			
		||||
        styleForPesudo.innerHTML = '';
 | 
			
		||||
      }
 | 
			
		||||
      if (insertExtraNode && extraNode && node.contains(extraNode)) {
 | 
			
		||||
        node.removeChild(extraNode);
 | 
			
		||||
      }
 | 
			
		||||
      TransitionEvents.removeStartEventListener(node, onTransitionStart);
 | 
			
		||||
      TransitionEvents.removeEndEventListener(node, onTransitionEnd);
 | 
			
		||||
    };
 | 
			
		||||
    const bindAnimationEvent = (node: HTMLElement) => {
 | 
			
		||||
      if (
 | 
			
		||||
        !node ||
 | 
			
		||||
        !node.getAttribute ||
 | 
			
		||||
        node.getAttribute('disabled') ||
 | 
			
		||||
        node.className.indexOf('disabled') >= 0
 | 
			
		||||
      ) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      const newClick = (e: MouseEvent) => {
 | 
			
		||||
        // Fix radio button click twice
 | 
			
		||||
        if ((e.target as any).tagName === 'INPUT' || isHidden(e.target as HTMLElement)) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        resetEffect(node);
 | 
			
		||||
        // Get wave color from target
 | 
			
		||||
        const waveColor =
 | 
			
		||||
          getComputedStyle(node).getPropertyValue('border-top-color') || // Firefox Compatible
 | 
			
		||||
          getComputedStyle(node).getPropertyValue('border-color') ||
 | 
			
		||||
          getComputedStyle(node).getPropertyValue('background-color');
 | 
			
		||||
        clickWaveTimeoutId = setTimeout(() => onClick(node, waveColor), 0);
 | 
			
		||||
        raf.cancel(animationStartId);
 | 
			
		||||
        animationStart = true;
 | 
			
		||||
 | 
			
		||||
        // Render to trigger transition event cost 3 frames. Let's delay 10 frames to reset this.
 | 
			
		||||
        animationStartId = raf(() => {
 | 
			
		||||
          animationStart = false;
 | 
			
		||||
        }, 10);
 | 
			
		||||
      };
 | 
			
		||||
      node.addEventListener('click', newClick, true);
 | 
			
		||||
      return {
 | 
			
		||||
        cancel: () => {
 | 
			
		||||
          node.removeEventListener('click', newClick, true);
 | 
			
		||||
        },
 | 
			
		||||
      };
 | 
			
		||||
    };
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      nextTick(() => {
 | 
			
		||||
        const node = findDOMNode(instance);
 | 
			
		||||
        if (node.nodeType !== 1) {
 | 
			
		||||
          return;
 | 
			
		||||
        }
 | 
			
		||||
        eventIns = bindAnimationEvent(node);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    onBeforeUnmount(() => {
 | 
			
		||||
      if (eventIns) {
 | 
			
		||||
        eventIns.cancel();
 | 
			
		||||
      }
 | 
			
		||||
      clearTimeout(clickWaveTimeoutId);
 | 
			
		||||
      isUnmounted = true;
 | 
			
		||||
    });
 | 
			
		||||
    return () => {
 | 
			
		||||
      return slots.default?.()[0];
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,164 @@
 | 
			
		|||
import type { CSSProperties } from 'vue';
 | 
			
		||||
import { onBeforeUnmount, onMounted, Transition, render, defineComponent, ref } from 'vue';
 | 
			
		||||
import useState from '../hooks/useState';
 | 
			
		||||
import { objectType } from '../type';
 | 
			
		||||
import { getTargetWaveColor } from './util';
 | 
			
		||||
import wrapperRaf from '../raf';
 | 
			
		||||
function validateNum(value: number) {
 | 
			
		||||
  return Number.isNaN(value) ? 0 : value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface WaveEffectProps {
 | 
			
		||||
  className: string;
 | 
			
		||||
  target: HTMLElement;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
const WaveEffect = defineComponent({
 | 
			
		||||
  props: {
 | 
			
		||||
    target: objectType<HTMLElement>(),
 | 
			
		||||
    className: String,
 | 
			
		||||
  },
 | 
			
		||||
  setup(props) {
 | 
			
		||||
    const divRef = ref<HTMLDivElement | null>(null);
 | 
			
		||||
 | 
			
		||||
    const [color, setWaveColor] = useState<string | null>(null);
 | 
			
		||||
    const [borderRadius, setBorderRadius] = useState<number[]>([]);
 | 
			
		||||
    const [left, setLeft] = useState(0);
 | 
			
		||||
    const [top, setTop] = useState(0);
 | 
			
		||||
    const [width, setWidth] = useState(0);
 | 
			
		||||
    const [height, setHeight] = useState(0);
 | 
			
		||||
    const [enabled, setEnabled] = useState(false);
 | 
			
		||||
 | 
			
		||||
    function syncPos() {
 | 
			
		||||
      const { target } = props;
 | 
			
		||||
      const nodeStyle = getComputedStyle(target);
 | 
			
		||||
 | 
			
		||||
      // Get wave color from target
 | 
			
		||||
      setWaveColor(getTargetWaveColor(target));
 | 
			
		||||
 | 
			
		||||
      const isStatic = nodeStyle.position === 'static';
 | 
			
		||||
 | 
			
		||||
      // Rect
 | 
			
		||||
      const { borderLeftWidth, borderTopWidth } = nodeStyle;
 | 
			
		||||
      setLeft(isStatic ? target.offsetLeft : validateNum(-parseFloat(borderLeftWidth)));
 | 
			
		||||
      setTop(isStatic ? target.offsetTop : validateNum(-parseFloat(borderTopWidth)));
 | 
			
		||||
      setWidth(target.offsetWidth);
 | 
			
		||||
      setHeight(target.offsetHeight);
 | 
			
		||||
 | 
			
		||||
      // Get border radius
 | 
			
		||||
      const {
 | 
			
		||||
        borderTopLeftRadius,
 | 
			
		||||
        borderTopRightRadius,
 | 
			
		||||
        borderBottomLeftRadius,
 | 
			
		||||
        borderBottomRightRadius,
 | 
			
		||||
      } = nodeStyle;
 | 
			
		||||
 | 
			
		||||
      setBorderRadius(
 | 
			
		||||
        [
 | 
			
		||||
          borderTopLeftRadius,
 | 
			
		||||
          borderTopRightRadius,
 | 
			
		||||
          borderBottomRightRadius,
 | 
			
		||||
          borderBottomLeftRadius,
 | 
			
		||||
        ].map(radius => validateNum(parseFloat(radius))),
 | 
			
		||||
      );
 | 
			
		||||
    }
 | 
			
		||||
    // Add resize observer to follow size
 | 
			
		||||
    let resizeObserver: ResizeObserver;
 | 
			
		||||
    let rafId: number;
 | 
			
		||||
    let timeoutId: any;
 | 
			
		||||
    const clear = () => {
 | 
			
		||||
      clearTimeout(timeoutId);
 | 
			
		||||
      wrapperRaf.cancel(rafId);
 | 
			
		||||
      resizeObserver?.disconnect();
 | 
			
		||||
    };
 | 
			
		||||
    const removeDom = () => {
 | 
			
		||||
      const holder = divRef.value?.parentElement;
 | 
			
		||||
      if (holder) {
 | 
			
		||||
        render(null, holder);
 | 
			
		||||
        if (holder.parentElement) {
 | 
			
		||||
          holder.parentElement.removeChild(holder);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      clear();
 | 
			
		||||
      timeoutId = setTimeout(() => {
 | 
			
		||||
        removeDom();
 | 
			
		||||
      }, 5000);
 | 
			
		||||
      const { target } = props;
 | 
			
		||||
      if (target) {
 | 
			
		||||
        // We need delay to check position here
 | 
			
		||||
        // since UI may change after click
 | 
			
		||||
        rafId = wrapperRaf(() => {
 | 
			
		||||
          syncPos();
 | 
			
		||||
 | 
			
		||||
          setEnabled(true);
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        if (typeof ResizeObserver !== 'undefined') {
 | 
			
		||||
          resizeObserver = new ResizeObserver(syncPos);
 | 
			
		||||
 | 
			
		||||
          resizeObserver.observe(target);
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
    onBeforeUnmount(() => {
 | 
			
		||||
      clear();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    const onTransitionend = (e: TransitionEvent) => {
 | 
			
		||||
      if (e.propertyName === 'opacity') {
 | 
			
		||||
        removeDom();
 | 
			
		||||
      }
 | 
			
		||||
    };
 | 
			
		||||
    return () => {
 | 
			
		||||
      if (!enabled.value) {
 | 
			
		||||
        return null;
 | 
			
		||||
      }
 | 
			
		||||
      const waveStyle = {
 | 
			
		||||
        left: `${left.value}px`,
 | 
			
		||||
        top: `${top.value}px`,
 | 
			
		||||
        width: `${width.value}px`,
 | 
			
		||||
        height: `${height.value}px`,
 | 
			
		||||
        borderRadius: borderRadius.value.map(radius => `${radius}px`).join(' '),
 | 
			
		||||
      } as CSSProperties & {
 | 
			
		||||
        [name: string]: number | string;
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      if (color) {
 | 
			
		||||
        waveStyle['--wave-color'] = color.value as string;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      return (
 | 
			
		||||
        <Transition
 | 
			
		||||
          appear
 | 
			
		||||
          name="wave-motion"
 | 
			
		||||
          appearFromClass="wave-motion-appear"
 | 
			
		||||
          appearActiveClass="wave-motion-appear"
 | 
			
		||||
          appearToClass="wave-motion-appear wave-motion-appear-active"
 | 
			
		||||
        >
 | 
			
		||||
          <div
 | 
			
		||||
            ref={divRef}
 | 
			
		||||
            class={props.className}
 | 
			
		||||
            style={waveStyle}
 | 
			
		||||
            onTransitionend={onTransitionend}
 | 
			
		||||
          />
 | 
			
		||||
        </Transition>
 | 
			
		||||
      );
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function showWaveEffect(node: HTMLElement, className: string) {
 | 
			
		||||
  // Create holder
 | 
			
		||||
  const holder = document.createElement('div');
 | 
			
		||||
  holder.style.position = 'absolute';
 | 
			
		||||
  holder.style.left = `0px`;
 | 
			
		||||
  holder.style.top = `0px`;
 | 
			
		||||
  node?.insertBefore(holder, node?.firstChild);
 | 
			
		||||
 | 
			
		||||
  render(<WaveEffect target={node} className={className} />, holder);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default showWaveEffect;
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,96 @@
 | 
			
		|||
import {
 | 
			
		||||
  computed,
 | 
			
		||||
  defineComponent,
 | 
			
		||||
  getCurrentInstance,
 | 
			
		||||
  nextTick,
 | 
			
		||||
  onBeforeUnmount,
 | 
			
		||||
  onMounted,
 | 
			
		||||
  watch,
 | 
			
		||||
} from 'vue';
 | 
			
		||||
import useConfigInject from '../../config-provider/hooks/useConfigInject';
 | 
			
		||||
import isVisible from '../../vc-util/Dom/isVisible';
 | 
			
		||||
import classNames from '../classNames';
 | 
			
		||||
import { findDOMNode } from '../props-util';
 | 
			
		||||
import useStyle from './style';
 | 
			
		||||
import useWave from './useWave';
 | 
			
		||||
 | 
			
		||||
export interface WaveProps {
 | 
			
		||||
  disabled?: boolean;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default defineComponent({
 | 
			
		||||
  compatConfig: { MODE: 3 },
 | 
			
		||||
  name: 'Wave',
 | 
			
		||||
  props: {
 | 
			
		||||
    disabled: Boolean,
 | 
			
		||||
  },
 | 
			
		||||
  setup(props, { slots }) {
 | 
			
		||||
    const instance = getCurrentInstance();
 | 
			
		||||
    const { prefixCls } = useConfigInject('wave', props);
 | 
			
		||||
 | 
			
		||||
    // ============================== Style ===============================
 | 
			
		||||
    const [, hashId] = useStyle(prefixCls);
 | 
			
		||||
 | 
			
		||||
    // =============================== Wave ===============================
 | 
			
		||||
    const showWave = useWave(
 | 
			
		||||
      instance,
 | 
			
		||||
      computed(() => classNames(prefixCls.value, hashId.value)),
 | 
			
		||||
    );
 | 
			
		||||
    let onClick: (e: MouseEvent) => void;
 | 
			
		||||
    const clear = () => {
 | 
			
		||||
      const node = findDOMNode(instance);
 | 
			
		||||
      node.removeEventListener('click', onClick, true);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    onMounted(() => {
 | 
			
		||||
      watch(
 | 
			
		||||
        () => props.disabled,
 | 
			
		||||
        () => {
 | 
			
		||||
          clear();
 | 
			
		||||
          nextTick(() => {
 | 
			
		||||
            const node = findDOMNode(instance);
 | 
			
		||||
 | 
			
		||||
            if (!node || node.nodeType !== 1 || props.disabled) {
 | 
			
		||||
              return;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // Click handler
 | 
			
		||||
            const onClick = (e: MouseEvent) => {
 | 
			
		||||
              // Fix radio button click twice
 | 
			
		||||
              if (
 | 
			
		||||
                (e.target as HTMLElement).tagName === 'INPUT' ||
 | 
			
		||||
                !isVisible(e.target as HTMLElement) ||
 | 
			
		||||
                // No need wave
 | 
			
		||||
                !node.getAttribute ||
 | 
			
		||||
                node.getAttribute('disabled') ||
 | 
			
		||||
                (node as HTMLInputElement).disabled ||
 | 
			
		||||
                node.className.includes('disabled') ||
 | 
			
		||||
                node.className.includes('-leave')
 | 
			
		||||
              ) {
 | 
			
		||||
                return;
 | 
			
		||||
              }
 | 
			
		||||
 | 
			
		||||
              showWave();
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            // Bind events
 | 
			
		||||
            node.addEventListener('click', onClick, true);
 | 
			
		||||
          });
 | 
			
		||||
        },
 | 
			
		||||
        {
 | 
			
		||||
          immediate: true,
 | 
			
		||||
          flush: 'post',
 | 
			
		||||
        },
 | 
			
		||||
      );
 | 
			
		||||
    });
 | 
			
		||||
    onBeforeUnmount(() => {
 | 
			
		||||
      clear();
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    return () => {
 | 
			
		||||
      // ============================== Render ==============================
 | 
			
		||||
      const children = slots.default?.()[0];
 | 
			
		||||
      return children;
 | 
			
		||||
    };
 | 
			
		||||
  },
 | 
			
		||||
});
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,38 @@
 | 
			
		|||
import { genComponentStyleHook } from '../../theme/internal';
 | 
			
		||||
import type { FullToken, GenerateStyle } from '../../theme/internal';
 | 
			
		||||
 | 
			
		||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
 | 
			
		||||
export interface ComponentToken {}
 | 
			
		||||
 | 
			
		||||
export type WaveToken = FullToken<'Wave'>;
 | 
			
		||||
 | 
			
		||||
const genWaveStyle: GenerateStyle<WaveToken> = token => {
 | 
			
		||||
  const { componentCls, colorPrimary } = token;
 | 
			
		||||
  return {
 | 
			
		||||
    [componentCls]: {
 | 
			
		||||
      position: 'absolute',
 | 
			
		||||
      background: 'transparent',
 | 
			
		||||
      pointerEvents: 'none',
 | 
			
		||||
      boxSizing: 'border-box',
 | 
			
		||||
      color: `var(--wave-color, ${colorPrimary})`,
 | 
			
		||||
 | 
			
		||||
      boxShadow: `0 0 0 0 currentcolor`,
 | 
			
		||||
      opacity: 0.2,
 | 
			
		||||
 | 
			
		||||
      // =================== Motion ===================
 | 
			
		||||
      '&.wave-motion-appear': {
 | 
			
		||||
        transition: [
 | 
			
		||||
          `box-shadow 0.4s ${token.motionEaseOutCirc}`,
 | 
			
		||||
          `opacity 2s ${token.motionEaseOutCirc}`,
 | 
			
		||||
        ].join(','),
 | 
			
		||||
 | 
			
		||||
        '&-active': {
 | 
			
		||||
          boxShadow: `0 0 0 6px currentcolor`,
 | 
			
		||||
          opacity: 0,
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
export default genComponentStyleHook('Wave', token => [genWaveStyle(token)]);
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,16 @@
 | 
			
		|||
import type { ComponentInternalInstance, Ref } from 'vue';
 | 
			
		||||
import { findDOMNode } from '../props-util';
 | 
			
		||||
import showWaveEffect from './WaveEffect';
 | 
			
		||||
 | 
			
		||||
export default function useWave(
 | 
			
		||||
  instance: ComponentInternalInstance | null,
 | 
			
		||||
  className: Ref<string>,
 | 
			
		||||
): VoidFunction {
 | 
			
		||||
  function showWave() {
 | 
			
		||||
    const node = findDOMNode(instance);
 | 
			
		||||
 | 
			
		||||
    showWaveEffect(node, className.value);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  return showWave;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,35 @@
 | 
			
		|||
export function isNotGrey(color: string) {
 | 
			
		||||
  // eslint-disable-next-line no-useless-escape
 | 
			
		||||
  const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\d.]*)?\)/);
 | 
			
		||||
  if (match && match[1] && match[2] && match[3]) {
 | 
			
		||||
    return !(match[1] === match[2] && match[2] === match[3]);
 | 
			
		||||
  }
 | 
			
		||||
  return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function isValidWaveColor(color: string) {
 | 
			
		||||
  return (
 | 
			
		||||
    color &&
 | 
			
		||||
    color !== '#fff' &&
 | 
			
		||||
    color !== '#ffffff' &&
 | 
			
		||||
    color !== 'rgb(255, 255, 255)' &&
 | 
			
		||||
    color !== 'rgba(255, 255, 255, 1)' &&
 | 
			
		||||
    isNotGrey(color) &&
 | 
			
		||||
    !/rgba\((?:\d*, ){3}0\)/.test(color) && // any transparent rgba color
 | 
			
		||||
    color !== 'transparent'
 | 
			
		||||
  );
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export function getTargetWaveColor(node: HTMLElement) {
 | 
			
		||||
  const { borderTopColor, borderColor, backgroundColor } = getComputedStyle(node);
 | 
			
		||||
  if (isValidWaveColor(borderTopColor)) {
 | 
			
		||||
    return borderTopColor;
 | 
			
		||||
  }
 | 
			
		||||
  if (isValidWaveColor(borderColor)) {
 | 
			
		||||
    return borderColor;
 | 
			
		||||
  }
 | 
			
		||||
  if (isValidWaveColor(backgroundColor)) {
 | 
			
		||||
    return backgroundColor;
 | 
			
		||||
  }
 | 
			
		||||
  return null;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			@ -154,7 +154,7 @@ const Switch = defineComponent({
 | 
			
		|||
 | 
			
		||||
    return () =>
 | 
			
		||||
      wrapSSR(
 | 
			
		||||
        <Wave insertExtraNode>
 | 
			
		||||
        <Wave>
 | 
			
		||||
          <button
 | 
			
		||||
            {...omit(props, [
 | 
			
		||||
              'prefixCls',
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -48,7 +48,7 @@ import type { ComponentToken as UploadComponentToken } from '../../upload/style'
 | 
			
		|||
// import type { ComponentToken as TourComponentToken } from '../../tour/style';
 | 
			
		||||
import type { ComponentToken as QRCodeComponentToken } from '../../qrcode/style';
 | 
			
		||||
// import type { ComponentToken as AppComponentToken } from '../../app/style';
 | 
			
		||||
// import type { ComponentToken as WaveToken } from '../../_util/wave/style';
 | 
			
		||||
import type { ComponentToken as WaveToken } from '../../_util/wave/style';
 | 
			
		||||
 | 
			
		||||
export interface ComponentTokenMap {
 | 
			
		||||
  Affix?: {};
 | 
			
		||||
| 
						 | 
				
			
			@ -117,5 +117,5 @@ export interface ComponentTokenMap {
 | 
			
		|||
  //   App?: AppComponentToken;
 | 
			
		||||
 | 
			
		||||
  //   /** @private Internal TS definition. Do not use. */
 | 
			
		||||
  //   Wave?: WaveToken;
 | 
			
		||||
  Wave?: WaveToken;
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue