Skip to content

Commit d442db0

Browse files
committed
refactor: wave
1 parent 7657157 commit d442db0

File tree

3 files changed

+95
-92
lines changed

3 files changed

+95
-92
lines changed

components/_util/hooks/useConfigInject.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { RequiredMark } from '../../form/Form';
22
import type { ComputedRef, UnwrapRef } from 'vue';
33
import { computed, inject } from 'vue';
4-
import type { ConfigProviderProps, Direction, SizeType } from '../../config-provider';
4+
import type { ConfigProviderProps, CSPConfig, Direction, SizeType } from '../../config-provider';
55
import { defaultConfigProvider } from '../../config-provider';
66
import type { VueNode } from '../type';
77

@@ -27,6 +27,7 @@ export default (
2727
getPopupContainer: ComputedRef<ConfigProviderProps['getPopupContainer']>;
2828
getPrefixCls: ConfigProviderProps['getPrefixCls'];
2929
autocomplete: ComputedRef<string>;
30+
csp: ComputedRef<CSPConfig>;
3031
} => {
3132
const configProvider = inject<UnwrapRef<ConfigProviderProps>>(
3233
'configProvider',
@@ -52,6 +53,7 @@ export default (
5253
);
5354
const size = computed(() => props.size || configProvider.componentSize);
5455
const autocomplete = computed(() => props.autocomplete || configProvider.input?.autocomplete);
56+
const csp = computed(() => configProvider.csp);
5557
return {
5658
configProvider,
5759
prefixCls,
@@ -69,5 +71,6 @@ export default (
6971
rootPrefixCls,
7072
getPrefixCls: configProvider.getPrefixCls,
7173
autocomplete,
74+
csp,
7275
};
7376
};
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,18 @@
1-
import { nextTick, inject, defineComponent } from 'vue';
1+
import { nextTick, defineComponent, getCurrentInstance, onMounted, onBeforeUnmount } from 'vue';
22
import TransitionEvents from './css-animation/Event';
33
import raf from './raf';
4-
import { defaultConfigProvider } from '../config-provider';
54
import { findDOMNode } from './props-util';
6-
let styleForPesudo;
5+
import useConfigInject from './hooks/useConfigInject';
6+
let styleForPesudo: HTMLStyleElement;
77

88
// Where el is the DOM element you'd like to test for visibility
9-
function isHidden(element) {
9+
function isHidden(element: HTMLElement) {
1010
if (process.env.NODE_ENV === 'test') {
1111
return false;
1212
}
1313
return !element || element.offsetParent === null;
1414
}
15-
function isNotGrey(color) {
15+
function isNotGrey(color: string) {
1616
// eslint-disable-next-line no-useless-escape
1717
const match = (color || '').match(/rgba?\((\d*), (\d*), (\d*)(, [\.\d]*)?\)/);
1818
if (match && match[1] && match[2] && match[3]) {
@@ -22,40 +22,51 @@ function isNotGrey(color) {
2222
}
2323
export default defineComponent({
2424
name: 'Wave',
25-
props: ['insertExtraNode'],
26-
setup() {
27-
const configProvider = inject('configProvider', defaultConfigProvider);
28-
return {
29-
configProvider,
30-
};
25+
props: {
26+
insertExtraNode: Boolean,
3127
},
32-
mounted() {
33-
nextTick(() => {
34-
const node = findDOMNode(this);
35-
if (node.nodeType !== 1) {
28+
setup(props, { slots, expose }) {
29+
const instance = getCurrentInstance();
30+
const { csp } = useConfigInject('', props);
31+
expose({
32+
csp,
33+
});
34+
let eventIns = null;
35+
let clickWaveTimeoutId = null;
36+
let animationStartId = null;
37+
let animationStart = false;
38+
let extraNode = null;
39+
let isUnmounted = false;
40+
const onTransitionStart = e => {
41+
if (isUnmounted) return;
42+
43+
const node = findDOMNode(instance);
44+
if (!e || e.target !== node) {
3645
return;
3746
}
38-
this.instance = this.bindAnimationEvent(node);
39-
});
40-
},
41-
beforeUnmount() {
42-
if (this.instance) {
43-
this.instance.cancel();
44-
}
45-
if (this.clickWaveTimeoutId) {
46-
clearTimeout(this.clickWaveTimeoutId);
47-
}
48-
},
49-
methods: {
50-
onClick(node, waveColor) {
47+
48+
if (!animationStart) {
49+
resetEffect(node);
50+
}
51+
};
52+
const onTransitionEnd = (e: any) => {
53+
if (!e || e.animationName !== 'fadeEffect') {
54+
return;
55+
}
56+
resetEffect(e.target);
57+
};
58+
const getAttributeName = () => {
59+
const { insertExtraNode } = props;
60+
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
61+
};
62+
const onClick = (node: HTMLElement, waveColor: string) => {
5163
if (!node || isHidden(node) || node.className.indexOf('-leave') >= 0) {
5264
return;
5365
}
54-
const { insertExtraNode } = this.$props;
55-
this.extraNode = document.createElement('div');
56-
const extraNode = this.extraNode;
66+
const { insertExtraNode } = props;
67+
extraNode = document.createElement('div');
5768
extraNode.className = 'ant-click-animating-node';
58-
const attributeName = this.getAttributeName();
69+
const attributeName = getAttributeName();
5970
node.removeAttribute(attributeName);
6071
node.setAttribute(attributeName, 'true');
6172
// Not white or transparent or grey
@@ -69,8 +80,8 @@ export default defineComponent({
6980
waveColor !== 'transparent'
7081
) {
7182
// Add nonce if CSP exist
72-
if (this.csp && this.csp.nonce) {
73-
styleForPesudo.nonce = this.csp.nonce;
83+
if (csp.value?.nonce) {
84+
styleForPesudo.nonce = csp.value.nonce;
7485
}
7586
extraNode.style.borderColor = waveColor;
7687
styleForPesudo.innerHTML = `
@@ -84,32 +95,26 @@ export default defineComponent({
8495
if (insertExtraNode) {
8596
node.appendChild(extraNode);
8697
}
87-
TransitionEvents.addStartEventListener(node, this.onTransitionStart);
88-
TransitionEvents.addEndEventListener(node, this.onTransitionEnd);
89-
},
90-
onTransitionStart(e) {
91-
if (this._.isUnmounted) return;
92-
93-
const node = findDOMNode(this);
94-
if (!e || e.target !== node) {
98+
TransitionEvents.addStartEventListener(node, onTransitionStart);
99+
TransitionEvents.addEndEventListener(node, onTransitionEnd);
100+
};
101+
const resetEffect = (node: HTMLElement) => {
102+
if (!node || node === extraNode || !(node instanceof Element)) {
95103
return;
96104
}
97-
98-
if (!this.animationStart) {
99-
this.resetEffect(node);
105+
const { insertExtraNode } = props;
106+
const attributeName = getAttributeName();
107+
node.setAttribute(attributeName, 'false'); // edge has bug on `removeAttribute` #14466
108+
if (styleForPesudo) {
109+
styleForPesudo.innerHTML = '';
100110
}
101-
},
102-
onTransitionEnd(e) {
103-
if (!e || e.animationName !== 'fadeEffect') {
104-
return;
111+
if (insertExtraNode && extraNode && node.contains(extraNode)) {
112+
node.removeChild(extraNode);
105113
}
106-
this.resetEffect(e.target);
107-
},
108-
getAttributeName() {
109-
const { insertExtraNode } = this.$props;
110-
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
111-
},
112-
bindAnimationEvent(node) {
114+
TransitionEvents.removeStartEventListener(node, onTransitionStart);
115+
TransitionEvents.removeEndEventListener(node, onTransitionEnd);
116+
};
117+
const bindAnimationEvent = (node: HTMLElement) => {
113118
if (
114119
!node ||
115120
!node.getAttribute ||
@@ -118,57 +123,51 @@ export default defineComponent({
118123
) {
119124
return;
120125
}
121-
const onClick = e => {
126+
const newClick = (e: MouseEvent) => {
122127
// Fix radio button click twice
123-
if (e.target.tagName === 'INPUT' || isHidden(e.target)) {
128+
if ((e.target as any).tagName === 'INPUT' || isHidden(e.target as HTMLElement)) {
124129
return;
125130
}
126-
this.resetEffect(node);
131+
resetEffect(node);
127132
// Get wave color from target
128133
const waveColor =
129134
getComputedStyle(node).getPropertyValue('border-top-color') || // Firefox Compatible
130135
getComputedStyle(node).getPropertyValue('border-color') ||
131136
getComputedStyle(node).getPropertyValue('background-color');
132-
this.clickWaveTimeoutId = setTimeout(() => this.onClick(node, waveColor), 0);
133-
raf.cancel(this.animationStartId);
134-
this.animationStart = true;
137+
clickWaveTimeoutId = setTimeout(() => onClick(node, waveColor), 0);
138+
raf.cancel(animationStartId);
139+
animationStart = true;
135140

136141
// Render to trigger transition event cost 3 frames. Let's delay 10 frames to reset this.
137-
this.animationStartId = raf(() => {
138-
this.animationStart = false;
142+
animationStartId = raf(() => {
143+
animationStart = false;
139144
}, 10);
140145
};
141-
node.addEventListener('click', onClick, true);
146+
node.addEventListener('click', newClick, true);
142147
return {
143148
cancel: () => {
144-
node.removeEventListener('click', onClick, true);
149+
node.removeEventListener('click', newClick, true);
145150
},
146151
};
147-
},
148-
149-
resetEffect(node) {
150-
if (!node || node === this.extraNode || !(node instanceof Element)) {
151-
return;
152-
}
153-
const { insertExtraNode } = this.$props;
154-
const attributeName = this.getAttributeName();
155-
node.setAttribute(attributeName, 'false'); // edge has bug on `removeAttribute` #14466
156-
if (styleForPesudo) {
157-
styleForPesudo.innerHTML = '';
158-
}
159-
if (insertExtraNode && this.extraNode && node.contains(this.extraNode)) {
160-
node.removeChild(this.extraNode);
152+
};
153+
onMounted(() => {
154+
nextTick(() => {
155+
const node = findDOMNode(instance);
156+
if (node.nodeType !== 1) {
157+
return;
158+
}
159+
eventIns = bindAnimationEvent(node);
160+
});
161+
});
162+
onBeforeUnmount(() => {
163+
if (eventIns) {
164+
eventIns.cancel();
161165
}
162-
TransitionEvents.removeStartEventListener(node, this.onTransitionStart);
163-
TransitionEvents.removeEndEventListener(node, this.onTransitionEnd);
164-
},
165-
},
166-
167-
render() {
168-
const csp = this.configProvider.csp;
169-
if (csp) {
170-
this.csp = csp;
171-
}
172-
return this.$slots.default?.()[0];
166+
clearTimeout(clickWaveTimeoutId);
167+
isUnmounted = true;
168+
});
169+
return () => {
170+
return slots.default?.()[0];
171+
};
173172
},
174173
});

components/config-provider/index.tsx

+1
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ export const configProviderProps = {
161161
},
162162
csp: {
163163
type: Object as PropType<CSPConfig>,
164+
default: undefined as CSPConfig,
164165
},
165166
input: {
166167
type: Object as PropType<{ autocomplete: string }>,

0 commit comments

Comments
 (0)