Permalink
Browse files

Refactor and apply wave click animation to more components

now support Button, Tag, Radio.Button and switch
  • Loading branch information...
afc163 committed Aug 11, 2018
1 parent d8fd521 commit 9cf6ae601010acbf665d575d34c0cc0918e604e7
@@ -0,0 +1,101 @@
import * as React from 'react';
import { findDOMNode } from 'react-dom';
import TransitionEvents from 'css-animation/lib/Event';
export default class Wave extends React.Component<{insertExtraNode?: boolean}> {
private instance?: {
cancel: () => void;
};
private styleForPesudo: HTMLStyleElement | null;
isNotGrey(color: string) {
const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\.\d]*)?\)/);
console.log(match);
if (match && match[1] && match[2] && match[3]) {
return !(match[1] === match[2] && match[2] === match[3]);
}
return true;
}
onClick = (node: HTMLElement) => {
this.removeExtraStyleNode();
const { insertExtraNode } = this.props;
const extraNode = document.createElement('div');
extraNode.className = 'ant-click-animating-node';
const attributeName = insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
node.removeAttribute(attributeName);
node.setAttribute(attributeName, 'true');
// 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');
// Not white or transparnt or grey
if (waveColor &&
waveColor !== '#ffffff' &&
waveColor !== 'rgb(255, 255, 255)' &&
this.isNotGrey(waveColor) &&
!/rgba\(\d*, \d*, \d*, 0\)/.test(waveColor) && // any transparent rgba color
waveColor !== 'transparent') {
extraNode.style.borderColor = waveColor;
this.styleForPesudo = document.createElement('style');
this.styleForPesudo.innerHTML =
`[ant-click-animating-without-extra-node]:after { border-color: ${waveColor}; }`;
document.body.appendChild(this.styleForPesudo);
}
if (insertExtraNode) {
node.appendChild(extraNode);
}
const transitionEnd = () => {
node.removeAttribute(attributeName);
this.removeExtraStyleNode();
if (insertExtraNode) {
node.removeChild(extraNode);
}
TransitionEvents.removeEndEventListener(node, transitionEnd);
};
TransitionEvents.addEndEventListener(node, transitionEnd);
}
bindAnimationEvent = (node: HTMLElement) => {
if (node.getAttribute('disabled') ||
node.className.indexOf('disabled') >= 0) {
return;
}
const onClick = (e: MouseEvent) => {
// Fix radio button click twice
if ((e.target as HTMLElement).tagName === 'INPUT') {
return;
}
setTimeout(() => this.onClick(node), 0);
};
node.addEventListener('click', onClick, true);
return {
cancel: () => {
node.removeEventListener('click', onClick, true);
},
};
}
removeExtraStyleNode() {
if (this.styleForPesudo && document.body.contains(this.styleForPesudo)) {
document.body.removeChild(this.styleForPesudo);
this.styleForPesudo = null;
}
}
componentDidMount() {
this.instance = this.bindAnimationEvent(findDOMNode(this) as HTMLElement);
}
componentWillUnmount() {
if (this.instance) {
this.instance.cancel();
}
}
render() {
return this.props.children;
}
}
@@ -2,7 +2,7 @@ import * as React from 'react';
import { findDOMNode } from 'react-dom';
import * as PropTypes from 'prop-types';
import classNames from 'classnames';
import clickAnimation from './clickAnimation';
import Wave from '../_util/wave';
import Icon from '../icon';
import Group from './button-group';
@@ -87,10 +87,7 @@ export default class Button extends React.Component<ButtonProps, any> {
block: PropTypes.bool,
};
delayTimeout: number;
clickAnimation: {
cancel: () => void;
};
private delayTimeout: number;
constructor(props: ButtonProps) {
super(props);
@@ -102,7 +99,6 @@ export default class Button extends React.Component<ButtonProps, any> {
componentDidMount() {
this.fixTwoCNChar();
this.clickAnimation = clickAnimation(findDOMNode(this) as HTMLElement);
}
componentWillReceiveProps(nextProps: ButtonProps) {
@@ -128,9 +124,6 @@ export default class Button extends React.Component<ButtonProps, any> {
if (this.delayTimeout) {
clearTimeout(this.delayTimeout);
}
if (this.clickAnimation) {
this.clickAnimation.cancel();
}
}
fixTwoCNChar() {
@@ -213,14 +206,16 @@ export default class Button extends React.Component<ButtonProps, any> {
const { htmlType, ...otherProps } = rest;
return (
<button
{...otherProps}
type={htmlType || 'button'}
className={classes}
onClick={this.handleClick}
>
{iconNode}{kids}
</button>
<Wave>
<button
{...otherProps}
type={htmlType || 'button'}
className={classes}
onClick={this.handleClick}
>
{iconNode}{kids}
</button>
</Wave>
);
}
}

This file was deleted.

Oops, something went wrong.
@@ -8,7 +8,6 @@
@btn-ghost-color: @text-color;
@btn-ghost-bg: transparent;
@btn-ghost-border: @border-color-base;
@btn-animation-width: 6px;
// Button styles
// -----------------------------
@@ -132,10 +131,6 @@
margin-left: 8px;
}
&-danger[ant-click-animating]:after {
border-color: @btn-danger-color;
}
&-background-ghost {
background: transparent !important;
border-color: #fff;
@@ -164,17 +159,6 @@
}
}
@keyframes buttonEffect {
to {
opacity: 0;
top: -@btn-animation-width;
left: -@btn-animation-width;
bottom: -@btn-animation-width;
right: -@btn-animation-width;
border-width: @btn-animation-width;
}
}
a.@{btn-prefix-cls} {
line-height: @btn-height-base - 2px;
&-lg {
@@ -184,17 +168,3 @@ a.@{btn-prefix-cls} {
line-height: @btn-height-sm - 2px;
}
}
[ant-click-animating]:after {
content: '';
position: absolute;
top: -1px;
left: -1px;
bottom: -1px;
right: -1px;
border-radius: inherit;
border: 0 solid @primary-color;
opacity: 0.4;
animation: buttonEffect .4s cubic-bezier(.25, .8, .25, 1);
display: block;
}
@@ -3,6 +3,7 @@ import * as PropTypes from 'prop-types';
import { AbstractCheckboxProps } from '../checkbox/Checkbox';
import Radio from './radio';
import { RadioChangeEvent } from './interface';
import Wave from '../_util/wave';
export type RadioButtonProps = AbstractCheckboxProps<RadioChangeEvent>;
@@ -24,7 +25,9 @@ export default class RadioButton extends React.Component<RadioButtonProps, any>
}
return (
<Radio {...radioProps} />
<Wave>
<Radio {...radioProps} />
</Wave>
);
}
}
@@ -3,3 +3,34 @@
transform: rotate(360deg);
}
}
[ant-click-animating],
[ant-click-animating-without-extra-node] {
position: relative;
}
[ant-click-animating-without-extra-node]:after,
.ant-click-animating-node {
content: '';
position: absolute;
top: -1px;
left: -1px;
bottom: -1px;
right: -1px;
border-radius: inherit;
border: 0 solid @primary-color;
opacity: 0.4;
animation: waveEffect .4s cubic-bezier(.25, .8, .25, 1);
display: block;
}
@keyframes waveEffect {
to {
opacity: 0;
top: -@wave-animation-width;
left: -@wave-animation-width;
bottom: -@wave-animation-width;
right: -@wave-animation-width;
border-width: @wave-animation-width;
}
}
@@ -486,4 +486,8 @@
// ---
@message-notice-content-padding: 10px 16px;
// Motion
// ---
@wave-animation-width: 6px;
@import "./default.deperated.less";
@@ -3,6 +3,7 @@ import * as PropTypes from 'prop-types';
import RcSwitch from 'rc-switch';
import classNames from 'classnames';
import omit from 'omit.js';
import Wave from '../_util/wave';
export interface SwitchProps {
prefixCls?: string;
@@ -51,11 +52,13 @@ export default class Switch extends React.Component<SwitchProps, {}> {
[`${prefixCls}-loading`]: loading,
});
return (
<RcSwitch
{...omit(this.props, ['loading'])}
className={classes}
ref={this.saveSwitch}
/>
<Wave insertExtraNode>
<RcSwitch
{...omit(this.props, ['loading'])}
className={classes}
ref={this.saveSwitch}
/>
</Wave>
);
}
}
@@ -23,6 +23,12 @@ export default class CheckableTag extends React.Component<CheckableTagProps> {
}, className);
delete (restProps as any).onChange; // TypeScript cannot check delete now.
return <div {...restProps as any} className={cls} onClick={this.handleClick} />;
return (
<div
{...restProps as any}
className={cls}
onClick={this.handleClick}
/>
);
}
}
@@ -6,6 +6,7 @@ import omit from 'omit.js';
import { polyfill } from 'react-lifecycles-compat';
import Icon from '../icon';
import CheckableTag from './CheckableTag';
import Wave from '../_util/wave';
export { CheckableTagProps } from './CheckableTag';
@@ -148,7 +149,9 @@ class Tag extends React.Component<TagProps, TagState> {
transitionAppear
onEnd={this.animationEnd}
>
{tag}
<Wave>
{tag}
</Wave>
</Animate>
);
}

0 comments on commit 9cf6ae6

Please sign in to comment.