chore: update util

pull/1790/head
tangjinzhou 2020-02-07 16:26:47 +08:00
parent 37c6293ede
commit 92dcc1b90d
13 changed files with 237 additions and 87 deletions

View File

@ -1,5 +1,5 @@
module.exports = {
dev: {
componentName: 'tree', // dev components
componentName: 'affix', // dev components
},
};

View File

@ -0,0 +1,13 @@
import { easeInOutCubic } from '../easings';
describe('Test easings', () => {
it('easeInOutCubic return value', () => {
const nums = [];
// eslint-disable-next-line no-plusplus
for (let index = 0; index < 5; index++) {
nums.push(easeInOutCubic(index, 1, 5, 4));
}
expect(nums).toEqual([1, 1.25, 3, 4.75, 5]);
});
});

View File

@ -0,0 +1,56 @@
import scrollTo from '../scrollTo';
describe('Test ScrollTo function', () => {
let dateNowMock;
beforeAll(() => {
jest.useFakeTimers();
});
afterAll(() => {
jest.useRealTimers();
});
beforeEach(() => {
dateNowMock = jest
.spyOn(Date, 'now')
.mockImplementationOnce(() => 0)
.mockImplementationOnce(() => 1000);
});
afterEach(() => {
dateNowMock.mockRestore();
});
it('test scrollTo', async () => {
const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => {
window.scrollY = y;
window.pageYOffset = y;
});
scrollTo(1000);
jest.runAllTimers();
expect(window.pageYOffset).toBe(1000);
scrollToSpy.mockRestore();
});
it('test callback - option', async () => {
const cbMock = jest.fn();
scrollTo(1000, {
callback: cbMock,
});
jest.runAllTimers();
expect(cbMock).toHaveBeenCalledTimes(1);
});
it('test getContainer - option', async () => {
const div = document.createElement('div');
scrollTo(1000, {
getContainer: () => div,
});
jest.runAllTimers();
expect(div.scrollTop).toBe(1000);
});
});

View File

@ -0,0 +1,17 @@
import { tuple } from './type';
export const PresetColorTypes = tuple(
'pink',
'red',
'yellow',
'orange',
'cyan',
'green',
'blue',
'purple',
'geekblue',
'magenta',
'volcano',
'gold',
'lime',
);

View File

@ -0,0 +1,8 @@
export function easeInOutCubic(t, b, c, d) {
const cc = c - b;
t /= d / 2;
if (t < 1) {
return (cc / 2) * t * t * t + b;
}
return (cc / 2) * ((t -= 2) * t * t + 2) + b;
}

View File

@ -6,7 +6,7 @@ function animate(node, show, done) {
let height;
let requestAnimationFrameId;
let appearRequestAnimationFrameId;
return cssAnimation(node, 'ant-motion-collapse', {
return cssAnimation(node, 'ant-motion-collapse-legacy', {
start() {
if (appearRequestAnimationFrameId) {
raf.cancel(appearRequestAnimationFrameId);

View File

@ -13,18 +13,20 @@ export default function wrapperRaf(callback, delayFrames = 1) {
if (restFrames <= 0) {
callback();
delete ids[id];
delete ids[myId];
} else {
ids[id] = raf(internalCallback);
ids[myId] = raf(internalCallback);
}
}
ids[id] = raf(internalCallback);
ids[myId] = raf(internalCallback);
return myId;
}
wrapperRaf.cancel = function(pid) {
if (pid === undefined) return;
raf.cancel(ids[pid]);
delete ids[pid];
};
wrapperRaf.ids = ids; // export this for test usage

View File

@ -0,0 +1,37 @@
import raf from 'raf';
import getScroll from './getScroll';
import { easeInOutCubic } from './easings';
// interface ScrollToOptions {
// /** Scroll container, default as window */
// getContainer?: () => HTMLElement | Window;
// /** Scroll end callback */
// callback?: () => any;
// /** Animation duration, default as 450 */
// duration?: number;
// }
export default function scrollTo(y, options = {}) {
const { getContainer = () => window, callback, duration = 450 } = options;
const container = getContainer();
const scrollTop = getScroll(container, true);
const startTime = Date.now();
const frameFunc = () => {
const timestamp = Date.now();
const time = timestamp - startTime;
const nextScrollTop = easeInOutCubic(time > duration ? duration : time, scrollTop, y, duration);
if (container === window) {
window.scrollTo(window.pageXOffset, nextScrollTop);
} else {
container.scrollTop = nextScrollTop;
}
if (time < duration) {
raf(frameFunc);
} else if (typeof callback === 'function') {
callback();
}
};
raf(frameFunc);
}

View File

@ -1,4 +1,4 @@
function isStyleSupport(styleName) {
const isStyleSupport = styleName => {
if (typeof window !== 'undefined' && window.document && window.document.documentElement) {
const styleNameList = Array.isArray(styleName) ? styleName : [styleName];
const { documentElement } = window.document;
@ -6,7 +6,7 @@ function isStyleSupport(styleName) {
return styleNameList.some(name => name in documentElement.style);
}
return false;
}
};
export const isFlexSupported = isStyleSupport(['flex', 'webkitFlex', 'Flex', 'msFlex']);

4
components/_util/type.js Normal file
View File

@ -0,0 +1,4 @@
// https://stackoverflow.com/questions/46176165/ways-to-get-string-literal-type-of-array-values-without-enum-overhead
export const tuple = (...args) => args;
export const tupleNum = (...args) => args;

View File

@ -1,38 +1,7 @@
/* eslint-disable no-console */
let warned = {};
import warning, { resetWarned } from '../vc-util/warning';
export function warning(valid, message) {
// Support uglify
if (process.env.NODE_ENV !== 'production' && !valid && console !== undefined) {
console.error(`Warning: ${message}`);
}
}
export { resetWarned };
export function note(valid, message) {
// Support uglify
if (process.env.NODE_ENV !== 'production' && !valid && console !== undefined) {
console.warn(`Note: ${message}`);
}
}
export function resetWarned() {
warned = {};
}
export function call(method, valid, message) {
if (!valid && !warned[message]) {
method(false, message);
warned[message] = true;
}
}
export function warningOnce(valid, message) {
call(warning, valid, message);
}
export function noteOnce(valid, message) {
call(note, valid, message);
}
export default warningOnce;
/* eslint-enable */
export default (valid, component, message) => {
warning(valid, `[antdv: ${component}] ${message}`);
};

View File

@ -1,5 +1,6 @@
import TransitionEvents from './css-animation/Event';
import raf from '../_util/raf';
import raf from './raf';
import { ConfigConsumerProps } from '../config-provider';
let styleForPesudo;
// Where el is the DOM element you'd like to test for visibility
@ -9,7 +10,14 @@ function isHidden(element) {
}
return !element || element.offsetParent === null;
}
function isNotGrey(color) {
// 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 {
name: 'Wave',
props: ['insertExtraNode'],
@ -22,7 +30,9 @@ export default {
this.instance = this.bindAnimationEvent(node);
});
},
inject: {
configProvider: { default: () => ConfigConsumerProps },
},
beforeDestroy() {
if (this.instance) {
this.instance.cancel();
@ -33,19 +43,10 @@ export default {
this.destroy = true;
},
methods: {
isNotGrey(color) {
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;
},
onClick(node, waveColor) {
if (!node || isHidden(node) || node.className.indexOf('-leave') >= 0) {
return;
}
this.removeExtraStyleNode();
const { insertExtraNode } = this.$props;
this.extraNode = document.createElement('div');
const extraNode = this.extraNode;
@ -59,13 +60,19 @@ export default {
waveColor &&
waveColor !== '#ffffff' &&
waveColor !== 'rgb(255, 255, 255)' &&
this.isNotGrey(waveColor) &&
isNotGrey(waveColor) &&
!/rgba\(\d*, \d*, \d*, 0\)/.test(waveColor) && // any transparent rgba color
waveColor !== 'transparent'
) {
// Add nonce if CSP exist
if (this.csp && this.csp.nonce) {
styleForPesudo.nonce = this.csp.nonce;
}
extraNode.style.borderColor = waveColor;
styleForPesudo.innerHTML = `[ant-click-animating-without-extra-node]:after { border-color: ${waveColor}; }`;
styleForPesudo.innerHTML = `
[ant-click-animating-without-extra-node='true']::after, .ant-click-animating-node {
--antd-wave-shadow-color: ${waveColor};
}`;
if (!document.body.contains(styleForPesudo)) {
document.body.appendChild(styleForPesudo);
}
@ -76,7 +83,28 @@ export default {
TransitionEvents.addStartEventListener(node, this.onTransitionStart);
TransitionEvents.addEndEventListener(node, this.onTransitionEnd);
},
onTransitionStart(e) {
if (this.destroy) return;
const node = this.$el;
if (!e || e.target !== node) {
return;
}
if (!this.animationStart) {
this.resetEffect(node);
}
},
onTransitionEnd(e) {
if (!e || e.animationName !== 'fadeEffect') {
return;
}
this.resetEffect(e.target);
},
getAttributeName() {
const { insertExtraNode } = this.$props;
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
},
bindAnimationEvent(node) {
if (
!node ||
@ -113,10 +141,6 @@ export default {
},
};
},
getAttributeName() {
const { insertExtraNode } = this.$props;
return insertExtraNode ? 'ant-click-animating' : 'ant-click-animating-without-extra-node';
},
resetEffect(node) {
if (!node || node === this.extraNode || !(node instanceof Element)) {
@ -124,40 +148,22 @@ export default {
}
const { insertExtraNode } = this.$props;
const attributeName = this.getAttributeName();
node.removeAttribute(attributeName);
this.removeExtraStyleNode();
node.setAttribute(attributeName, 'false'); // edge has bug on `removeAttribute` #14466
if (styleForPesudo) {
styleForPesudo.innerHTML = '';
}
if (insertExtraNode && this.extraNode && node.contains(this.extraNode)) {
node.removeChild(this.extraNode);
}
TransitionEvents.removeStartEventListener(node, this.onTransitionStart);
TransitionEvents.removeEndEventListener(node, this.onTransitionEnd);
},
onTransitionStart(e) {
if (this.destroy) return;
const node = this.$el;
if (!e || e.target !== node) {
return;
}
if (!this.animationStart) {
this.resetEffect(node);
}
},
onTransitionEnd(e) {
if (!e || e.animationName !== 'fadeEffect') {
return;
}
this.resetEffect(e.target);
},
removeExtraStyleNode() {
if (styleForPesudo) {
styleForPesudo.innerHTML = '';
}
},
},
render() {
if (this.configProvider.csp) {
this.csp = csp;
}
return this.$slots.default && this.$slots.default[0];
},
};

View File

@ -0,0 +1,38 @@
/* eslint-disable no-console */
let warned = {};
export function warning(valid, message) {
// Support uglify
if (process.env.NODE_ENV !== 'production' && !valid && console !== undefined) {
console.error(`Warning: ${message}`);
}
}
export function note(valid, message) {
// Support uglify
if (process.env.NODE_ENV !== 'production' && !valid && console !== undefined) {
console.warn(`Note: ${message}`);
}
}
export function resetWarned() {
warned = {};
}
export function call(method, valid, message) {
if (!valid && !warned[message]) {
method(false, message);
warned[message] = true;
}
}
export function warningOnce(valid, message) {
call(warning, valid, message);
}
export function noteOnce(valid, message) {
call(note, valid, message);
}
export default warningOnce;
/* eslint-enable */