diff --git a/components/_util/props-util.js b/components/_util/props-util.js
index 3872ccb86..9c95d149a 100644
--- a/components/_util/props-util.js
+++ b/components/_util/props-util.js
@@ -133,6 +133,7 @@ const getComponentFromProp = (instance, prop, options = instance, execute = true
const componentOptions = instance.componentOptions || {};
(componentOptions.children || []).forEach(child => {
if (child.data && child.data.slot === prop) {
+ delete child.data.slot;
if (child.tag === 'template') {
slotsProp.push(child.children);
} else {
diff --git a/components/progress/circle.jsx b/components/progress/circle.jsx
index 89db450ee..581bffe9f 100644
--- a/components/progress/circle.jsx
+++ b/components/progress/circle.jsx
@@ -1,6 +1,5 @@
import { Circle as VCCircle } from '../vc-progress';
import { validProgress } from './utils';
-import { ProgressProps } from './progress';
const statusColorMap = {
normal: '#108ee9',
diff --git a/components/progress/line.jsx b/components/progress/line.jsx
index 6d80d0f5f..bd5d0bd7c 100644
--- a/components/progress/line.jsx
+++ b/components/progress/line.jsx
@@ -1,5 +1,4 @@
import { validProgress } from './utils';
-import { ProgressProps } from './progress';
const Line = {
functional: true,
diff --git a/components/radio/Group.jsx b/components/radio/Group.jsx
index 68faee769..371dbc40f 100644
--- a/components/radio/Group.jsx
+++ b/components/radio/Group.jsx
@@ -11,9 +11,7 @@ export default {
prop: 'value',
},
props: {
- prefixCls: {
- type: String,
- },
+ prefixCls: PropTypes.string,
defaultValue: PropTypes.any,
value: PropTypes.any,
size: {
@@ -103,7 +101,6 @@ export default {
prefixCls={prefixCls}
disabled={props.disabled}
value={option}
- onChange={this.onRadioChange}
checked={this.stateValue === option}
>
{option}
@@ -116,7 +113,6 @@ export default {
prefixCls={prefixCls}
disabled={option.disabled || props.disabled}
value={option.value}
- onChange={this.onRadioChange}
checked={this.stateValue === option.value}
>
{option.label}
diff --git a/components/radio/Radio.jsx b/components/radio/Radio.jsx
index d229c483a..b8d8e838c 100644
--- a/components/radio/Radio.jsx
+++ b/components/radio/Radio.jsx
@@ -12,9 +12,7 @@ export default {
prop: 'checked',
},
props: {
- prefixCls: {
- type: String,
- },
+ prefixCls: PropTypes.string,
defaultChecked: Boolean,
checked: { type: Boolean, default: undefined },
disabled: Boolean,
@@ -41,6 +39,12 @@ export default {
blur() {
this.$refs.vcCheckbox.blur();
},
+ onChange(e) {
+ this.$emit('change', e);
+ if (this.radioGroupContext && this.radioGroupContext.onRadioChange) {
+ this.radioGroupContext.onRadioChange(e);
+ }
+ },
},
render() {
@@ -60,7 +64,7 @@ export default {
if (radioGroup) {
radioProps.props.name = radioGroup.name;
- radioProps.on.change = radioGroup.onRadioChange;
+ radioProps.on.change = this.onChange;
radioProps.props.checked = props.value === radioGroup.stateValue;
radioProps.props.disabled = props.disabled || radioGroup.disabled;
} else {
diff --git a/components/radio/RadioButton.jsx b/components/radio/RadioButton.jsx
index fefa0ce8d..2b4599a1a 100644
--- a/components/radio/RadioButton.jsx
+++ b/components/radio/RadioButton.jsx
@@ -1,4 +1,5 @@
import Radio from './Radio';
+import PropTypes from '../_util/vue-types';
import { getOptionProps } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
@@ -6,9 +7,6 @@ export default {
name: 'ARadioButton',
props: {
...Radio.props,
- prefixCls: {
- type: String,
- },
},
inject: {
radioGroupContext: { default: undefined },
diff --git a/components/radio/__tests__/group.test.js b/components/radio/__tests__/group.test.js
index 9cb4039a0..add89c5e5 100644
--- a/components/radio/__tests__/group.test.js
+++ b/components/radio/__tests__/group.test.js
@@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
import { asyncExpect } from '@/tests/utils';
import Radio from '../Radio';
import RadioGroup from '../Group';
+import RadioButton from '../radioButton';
describe('Radio', () => {
function createRadioGroup(props, listeners = {}) {
@@ -50,10 +51,16 @@ describe('Radio', () => {
},
});
- wrapper.trigger('mouseenter');
+ wrapper
+ .findAll('div')
+ .at(0)
+ .trigger('mouseenter');
expect(onMouseEnter).toHaveBeenCalled();
- wrapper.trigger('mouseleave');
+ wrapper
+ .findAll('div')
+ .at(0)
+ .trigger('mouseleave');
expect(onMouseLeave).toHaveBeenCalled();
});
@@ -89,6 +96,80 @@ describe('Radio', () => {
});
});
+ it('both of radio and radioGroup will trigger onchange event when they exists', async () => {
+ const onChange = jest.fn();
+ const onChangeRadioGroup = jest.fn();
+
+ const wrapper = mount(
+ {
+ props: ['value'],
+ render() {
+ const groupProps = {};
+ if (this.value !== undefined) {
+ groupProps.value = this.value;
+ }
+ return (
+
+
+ A
+
+
+ B
+
+
+ C
+
+
+ );
+ },
+ },
+ { sync: false },
+ );
+ const radios = wrapper.findAll('input');
+
+ // uncontrolled component
+ wrapper.vm.$refs.radioGroup.stateValue = 'B';
+ radios.at(0).trigger('change');
+ expect(onChange.mock.calls.length).toBe(1);
+ expect(onChangeRadioGroup.mock.calls.length).toBe(1);
+
+ // controlled component
+ wrapper.setProps({ value: 'A' });
+ radios.at(1).trigger('change');
+ expect(onChange.mock.calls.length).toBe(2);
+ });
+
+ it('Trigger onChange when both of radioButton and radioGroup exists', () => {
+ const onChange = jest.fn();
+ const props = {};
+ const wrapper = mount(
+ createRadioGroup(props, {
+ change: onChange,
+ }),
+ { sync: false },
+ );
+ const radios = wrapper.findAll('input');
+
+ // uncontrolled component
+ wrapper.vm.$refs.radioGroup.stateValue = 'B';
+ radios.at(0).trigger('change');
+ expect(onChange.mock.calls.length).toBe(1);
+
+ // controlled component
+ wrapper.setProps({ value: 'A' });
+ radios.at(1).trigger('change');
+ expect(onChange.mock.calls.length).toBe(2);
+ });
+
+ // it('should only trigger once when in group with options', () => {
+ // const onChange = jest.fn();
+ // const options = [{ label: 'Bamboo', value: 'Bamboo' }];
+ // const wrapper = mount();
+
+ // wrapper.find('input').trigger('change');
+ // expect(onChange).toHaveBeenCalledTimes(1);
+ // });
+
// it('won\'t fire change events when value not changes', async () => {
// const onChange = jest.fn()
diff --git a/components/radio/__tests__/radio.test.js b/components/radio/__tests__/radio.test.js
index 09739fd6f..7141c3072 100644
--- a/components/radio/__tests__/radio.test.js
+++ b/components/radio/__tests__/radio.test.js
@@ -28,12 +28,12 @@ describe('Radio', () => {
{ sync: false },
);
await asyncExpect(() => {
- wrapper.trigger('mouseenter');
+ wrapper.find('label').trigger('mouseenter');
});
await asyncExpect(() => {
expect(onMouseEnter).toHaveBeenCalled();
});
- wrapper.trigger('mouseleave');
+ wrapper.find('label').trigger('mouseleave');
await asyncExpect(() => {
expect(onMouseLeave).toHaveBeenCalled();
});
diff --git a/components/rate/index.jsx b/components/rate/index.jsx
index 60c1b070f..006acf993 100644
--- a/components/rate/index.jsx
+++ b/components/rate/index.jsx
@@ -40,12 +40,7 @@ const Rate = {
characterRender(node, { index }) {
const { tooltips } = this.$props;
if (!tooltips) return node;
- const tooltipsProps = {
- props: {
- title: tooltips[index],
- },
- };
- return {node};
+ return {node};
},
},
render() {
diff --git a/components/select/index.jsx b/components/select/index.jsx
index 36ed1013f..c5c687737 100644
--- a/components/select/index.jsx
+++ b/components/select/index.jsx
@@ -1,4 +1,4 @@
-import warning from 'warning';
+import warning from '../_util/warning';
import omit from 'omit.js';
import PropTypes from '../_util/vue-types';
import { Select as VcSelect, Option, OptGroup } from '../vc-select';
@@ -96,7 +96,6 @@ const Select = {
name: 'ASelect',
props: {
...SelectProps,
- prefixCls: PropTypes.string,
showSearch: PropTypes.bool.def(false),
transitionName: PropTypes.string.def('slide-up'),
choiceTransitionName: PropTypes.string.def('zoom'),
diff --git a/components/skeleton/Title.jsx b/components/skeleton/Title.jsx
index 2bc922a44..2ffc7911d 100644
--- a/components/skeleton/Title.jsx
+++ b/components/skeleton/Title.jsx
@@ -1,5 +1,4 @@
import PropTypes from '../_util/vue-types';
-import { initDefaultProps } from '../_util/props-util';
const skeletonTitleProps = {
prefixCls: PropTypes.string,
diff --git a/components/skeleton/demo/index.vue b/components/skeleton/demo/index.vue
index cc37b9e16..65c6d185f 100644
--- a/components/skeleton/demo/index.vue
+++ b/components/skeleton/demo/index.vue
@@ -16,8 +16,6 @@ const md = {
- 网络较慢,需要长时间等待加载处理的情况下。
- 图文信息内容较多的列表/卡片中。
- - 只适合用在第一次加载数据的场景。
- - 可以被 Spin 完全代替,但是在可用的场景下可以比 Spin 提供更好的视觉效果和用户体验。
## 代码演示`,
us: `# Skeleton
@@ -27,8 +25,6 @@ const md = {
- When resource needs long time to load, like low network speed.
- The component contains much information. Such as List or Card.
- - Only works when loading data at first time.
- - Could be replaced by Spin in all situation, but provide better user experience then spin if it works.
## Examples
`,
};
@@ -38,12 +34,12 @@ export default {
type: 'Feedback',
title: 'Skeleton',
cols: 1,
- render () {
+ render() {
return (
-
-
-
+
+
+
@@ -52,12 +48,12 @@ export default {
-
+
-
-
+
+
-
+
);
diff --git a/components/slider/index.en-US.md b/components/slider/index.en-US.md
index a91e60aa5..8ec5ce03b 100644
--- a/components/slider/index.en-US.md
+++ b/components/slider/index.en-US.md
@@ -3,11 +3,11 @@
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| autoFocus | get focus when component mounted | boolean | false |
-| defaultValue | The default value of slider. When `range` is `false`, use `number`, otherwise, use `[number, number]` | number\|number\[] | 0 or [0, 0] |
+| defaultValue | The default value of slider. When `range` is `false`, use `number`, otherwise, use `[number, number]` | number\|number\[] | 0 or \[0, 0] |
| disabled | If true, the slider will not be interactable. | boolean | false |
| dots | Whether the thumb can drag over tick only. | boolean | false |
| included | Make effect when `marks` not null,`true` means containment and `false` means coordinative | boolean | true |
-| marks | Tick mark of Slider, type of key must be `number`, and must in closed interval [min, max] ,each mark can declare its own style. | object | { number: string\|VNode } or { number: { style: object, label: string\|VNode } } or { number: () => VNode } |
+| marks | Tick mark of Slider, type of key must be `number`, and must in closed interval \[min, max], each mark can declare its own style. | object | { number: string\|VNode } or { number: { style: object, label: string\|VNode } } or { number: () => VNode } |
| max | The maximum value the slider can slide to | number | 100 |
| min | The minimum value the slider can slide to. | number | 0 |
| range | dual thumb mode | boolean | false |
diff --git a/components/slider/index.jsx b/components/slider/index.jsx
index 8c56e9aeb..fcbafa16d 100644
--- a/components/slider/index.jsx
+++ b/components/slider/index.jsx
@@ -6,6 +6,7 @@ import VcRange from '../vc-slider/src/Range';
import VcHandle from '../vc-slider/src/Handle';
import Tooltip from '../tooltip';
import Base from '../base';
+import { ConfigConsumerProps } from '../config-provider';
// export interface SliderMarks {
// [key]: React.ReactNode | {
@@ -43,10 +44,11 @@ const Slider = {
event: 'change',
},
mixins: [BaseMixin],
+ inject: {
+ configProvider: { default: () => ConfigConsumerProps },
+ },
props: {
...SliderProps(),
- prefixCls: PropTypes.string.def('ant-slider'),
- tooltipPrefixCls: PropTypes.string.def('ant-tooltip'),
tipFormatter: PropTypes.oneOfType([PropTypes.func, PropTypes.object]).def(value =>
value.toString(),
),
@@ -65,8 +67,8 @@ const Slider = {
},
}));
},
- handleWithTooltip({ value, dragging, index, directives, on, ...restProps }) {
- const { tooltipPrefixCls, tipFormatter, tooltipVisible } = this.$props;
+ handleWithTooltip(tooltipPrefixCls, { value, dragging, index, directives, on, ...restProps }) {
+ const { tipFormatter, tooltipVisible } = this.$props;
const { visibles } = this;
const isTipFormatter = tipFormatter ? visibles[index] || dragging : false;
const visible = tooltipVisible || (tooltipVisible === undefined && isTipFormatter);
@@ -106,12 +108,22 @@ const Slider = {
},
},
render() {
- const { range, ...restProps } = getOptionProps(this);
+ const {
+ range,
+ prefixCls: customizePrefixCls,
+ tooltipPrefixCls: customizeTooltipPrefixCls,
+ ...restProps
+ } = getOptionProps(this);
+ const getPrefixCls = this.configProvider.getPrefixCls;
+ const prefixCls = getPrefixCls('skeleton', customizePrefixCls);
+ const tooltipPrefixCls = getPrefixCls('skeleton', customizeTooltipPrefixCls);
if (range) {
const vcRangeProps = {
props: {
...restProps,
- handle: this.handleWithTooltip,
+ prefixCls,
+ tooltipPrefixCls,
+ handle: info => this.handleWithTooltip(tooltipPrefixCls, info),
},
ref: 'sliderRef',
on: this.$listeners,
@@ -121,7 +133,9 @@ const Slider = {
const vcSliderProps = {
props: {
...restProps,
- handle: this.handleWithTooltip,
+ prefixCls,
+ tooltipPrefixCls,
+ handle: info => this.handleWithTooltip(tooltipPrefixCls, info),
},
ref: 'sliderRef',
on: this.$listeners,
diff --git a/components/slider/index.zh-CN.md b/components/slider/index.zh-CN.md
index 44a69b026..b53878afa 100644
--- a/components/slider/index.zh-CN.md
+++ b/components/slider/index.zh-CN.md
@@ -3,11 +3,11 @@
| 参数 | 说明 | 类型 | 默认值 |
| --- | --- | --- | --- |
| autoFocus | 自动获取焦点 | boolean | false |
-| defaultValue | 设置初始取值。当 `range` 为 `false` 时,使用 `number`,否则用 `[number, number]` | number\|number\[] | 0 or [0, 0] |
+| defaultValue | 设置初始取值。当 `range` 为 `false` 时,使用 `number`,否则用 `[number, number]` | number\|number\[] | 0 or \[0, 0] |
| disabled | 值为 `true` 时,滑块为禁用状态 | boolean | false |
| dots | 是否只能拖拽到刻度上 | boolean | false |
| included | `marks` 不为空对象时有效,值为 true 时表示值为包含关系,false 表示并列 | boolean | true |
-| marks | 刻度标记,key 的类型必须为 `number` 且取值在闭区间 [min, max] 内,每个标签可以单独设置样式 | object | { number: string\|VNode } or { number: { style: object, label: string\|VNode } } or { number: () => VNode } |
+| marks | 刻度标记,key 的类型必须为 `number` 且取值在闭区间 \[min, max] 内,每个标签可以单独设置样式 | object | { number: string\|VNode } or { number: { style: object, label: string\|VNode } } or { number: () => VNode } |
| max | 最大值 | number | 100 |
| min | 最小值 | number | 0 |
| range | 双滑块模式 | boolean | false |
diff --git a/components/spin/Spin.jsx b/components/spin/Spin.jsx
index ee0cebd53..c4f095d70 100644
--- a/components/spin/Spin.jsx
+++ b/components/spin/Spin.jsx
@@ -51,10 +51,11 @@ export default {
},
data() {
const { spinning, delay } = this;
+ const shouldBeDelayed = shouldDelay(spinning, delay);
this.originalUpdateSpinning = this.updateSpinning;
this.debouncifyUpdateSpinning(this.$props);
return {
- sSpinning: spinning && !shouldDelay(spinning, delay),
+ sSpinning: spinning && !shouldBeDelayed,
};
},
mounted() {
diff --git a/components/spin/__tests__/delay.test.js b/components/spin/__tests__/delay.test.js
new file mode 100644
index 000000000..b838df87b
--- /dev/null
+++ b/components/spin/__tests__/delay.test.js
@@ -0,0 +1,69 @@
+import { mount } from '@vue/test-utils';
+import { asyncExpect } from '@/tests/utils';
+import Spin from '..';
+
+describe('delay spinning', () => {
+ it("should render with delay when it's mounted with spinning=true and delay", async () => {
+ const props = {
+ propsData: {
+ delay: 500,
+ spinning: true,
+ },
+ sync: false,
+ };
+ const wrapper = mount(Spin, props);
+ await asyncExpect(() => {
+ expect(
+ wrapper
+ .find('.ant-spin')
+ .classes()
+ .includes('ant-spin-spinning'),
+ ).toEqual(false);
+ });
+ });
+
+ it('should render when delay is init set', async () => {
+ const props = {
+ propsData: {
+ delay: 100,
+ spinning: true,
+ },
+ sync: false,
+ };
+ const wrapper = mount(Spin, props);
+
+ expect(
+ wrapper
+ .findAll('.ant-spin')
+ .at(0)
+ .classes()
+ .includes('ant-spin-spinning'),
+ ).toEqual(false);
+
+ // use await not jest.runAllTimers()
+ // because of https://github.com/facebook/jest/issues/3465
+ await new Promise(resolve => setTimeout(resolve, 500));
+
+ expect(
+ wrapper
+ .findAll('.ant-spin')
+ .at(0)
+ .classes()
+ .includes('ant-spin-spinning'),
+ ).toEqual(true);
+ });
+
+ it('should cancel debounce function when unmount', async () => {
+ const props = {
+ propsData: {
+ delay: 100,
+ spinning: true,
+ },
+ sync: false,
+ };
+ const wrapper = mount(Spin, props);
+ const spy = jest.spyOn(wrapper.vm.updateSpinning, 'cancel');
+ expect(wrapper.vm.updateSpinning.cancel).toEqual(expect.any(Function));
+ expect(spy).not.toHaveBeenCalled();
+ });
+});
diff --git a/components/statistic/Countdown.jsx b/components/statistic/Countdown.jsx
index 16254980f..97dc20101 100644
--- a/components/statistic/Countdown.jsx
+++ b/components/statistic/Countdown.jsx
@@ -17,24 +17,16 @@ export default {
format: 'HH:mm:ss',
}),
- data() {
- return {
- uniKey: 0,
- };
+ created() {
+ this.countdownId = undefined;
},
- countdownId: undefined,
-
mounted() {
- this.$nextTick(() => {
- this.syncTimer();
- });
+ this.syncTimer();
},
updated() {
- this.$nextTick(() => {
- this.syncTimer();
- });
+ this.syncTimer();
},
beforeDestroy() {
@@ -53,11 +45,9 @@ export default {
},
startTimer() {
- if (this.countdownId) {
- return;
- }
+ if (this.countdownId) return;
this.countdownId = window.setInterval(() => {
- this.uniKey++;
+ this.$refs.statistic.$forceUpdate();
}, REFRESH_INTERVAL);
},
@@ -74,7 +64,7 @@ export default {
}
},
- formatCountdown(value, config) {
+ formatCountdown({ value, config }) {
const { format } = this.$props;
return formatCountdown(value, { ...config, format });
},
@@ -91,13 +81,14 @@ export default {
render() {
return (
);
diff --git a/components/statistic/Number.jsx b/components/statistic/Number.jsx
index f09aa39f9..49a1a1f6f 100644
--- a/components/statistic/Number.jsx
+++ b/components/statistic/Number.jsx
@@ -12,12 +12,11 @@ export default {
groupSeparator = '',
prefixCls,
} = context.props;
-
let valueNode;
if (typeof formatter === 'function') {
// Customize formatter
- valueNode = formatter(value);
+ valueNode = formatter({ value, h });
} else {
// Internal formatter
const val = String(value);
diff --git a/components/statistic/Statistic.jsx b/components/statistic/Statistic.jsx
index 336ec3d03..fee065f27 100644
--- a/components/statistic/Statistic.jsx
+++ b/components/statistic/Statistic.jsx
@@ -8,7 +8,7 @@ export const StatisticProps = {
decimalSeparator: PropTypes.string,
groupSeparator: PropTypes.string,
format: PropTypes.string,
- value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
+ value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.object]),
valueStyle: PropTypes.any,
valueRender: PropTypes.any,
formatter: PropTypes.any,
@@ -21,7 +21,6 @@ export const StatisticProps = {
export default {
name: 'AStatistic',
props: initDefaultProps(StatisticProps, {
- prefixCls: 'ant-statistic',
decimalSeparator: '.',
groupSeparator: ',',
}),
@@ -37,9 +36,9 @@ export default {
const title = getComponentFromProp(this, 'title');
let prefix = getComponentFromProp(this, 'prefix');
let suffix = getComponentFromProp(this, 'suffix');
- const formatter = getComponentFromProp(this, 'formatter');
+ const formatter = getComponentFromProp(this, 'formatter', {}, false);
let valueNode = (
-
+
);
if (valueRender) {
valueNode = valueRender(valueNode);
diff --git a/components/statistic/__tests__/__snapshots__/index.test.js.snap b/components/statistic/__tests__/__snapshots__/index.test.js.snap
new file mode 100644
index 000000000..42bf7e0b2
--- /dev/null
+++ b/components/statistic/__tests__/__snapshots__/index.test.js.snap
@@ -0,0 +1,8 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`Statistic support negetive number 1`] = `
+
+
Account Balance (CNY)
+
-112,893.12
+
+`;
diff --git a/components/statistic/__tests__/index.test.js b/components/statistic/__tests__/index.test.js
new file mode 100644
index 000000000..a6755b9e2
--- /dev/null
+++ b/components/statistic/__tests__/index.test.js
@@ -0,0 +1,107 @@
+import { mount } from '@vue/test-utils';
+import { asyncExpect } from '@/tests/utils';
+import MockDate from 'mockdate';
+import moment from 'moment';
+import Statistic from '..';
+
+describe('Statistic', () => {
+ beforeAll(() => {
+ MockDate.set(moment('2018-11-28 00:00:00'));
+ });
+
+ afterAll(() => {
+ MockDate.reset();
+ });
+
+ it('customize formatter', () => {
+ const formatter = jest.fn(() => 93);
+ const props = {
+ propsData: {
+ value: 1128,
+ formatter,
+ },
+ };
+ const wrapper = mount(Statistic, props);
+ expect(formatter).toBeCalledWith(expect.objectContaining({ value: 1128 }));
+ expect(wrapper.find('.ant-statistic-content-value').text()).toEqual('93');
+ });
+
+ it('groupSeparator', () => {
+ const props = {
+ propsData: {
+ value: 1128,
+ groupSeparator: '__TEST__',
+ },
+ };
+ const wrapper = mount(Statistic, props);
+ expect(wrapper.find('.ant-statistic-content-value').text()).toEqual('1__TEST__128');
+ });
+
+ it('not a number', () => {
+ const props = {
+ propsData: {
+ value: 'bamboo',
+ },
+ };
+ const wrapper = mount(Statistic, props);
+ expect(wrapper.find('.ant-statistic-content-value').text()).toEqual('bamboo');
+ });
+
+ it('support negetive number', () => {
+ const props = {
+ propsData: {
+ title: 'Account Balance (CNY)',
+ value: -112893.12345,
+ precision: 2,
+ },
+ };
+ const wrapper = mount(Statistic, props);
+ expect(wrapper.html()).toMatchSnapshot();
+ });
+
+ describe('Countdown', () => {
+ it('render correctly', () => {
+ const now = moment()
+ .add(2, 'd')
+ .add(11, 'h')
+ .add(28, 'm')
+ .add(9, 's')
+ .add(3, 'ms');
+
+ [
+ ['H:m:s', '59:28:9'],
+ ['HH:mm:ss', '59:28:09'],
+ ['HH:mm:ss:SSS', '59:28:09:003'],
+ ['DD-HH:mm:ss', '02-11:28:09'],
+ ].forEach(([format, value]) => {
+ const props = {
+ propsData: {
+ format,
+ value: now,
+ },
+ };
+ const wrapper = mount(Statistic.Countdown, props);
+ expect(wrapper.find('.ant-statistic-content-value').text()).toEqual(value);
+ });
+ });
+
+ it('time going', async () => {
+ const now = Date.now() + 1000;
+ const props = {
+ propsData: {
+ value: now,
+ },
+ };
+ const wrapper = mount(Statistic.Countdown, props);
+
+ // setInterval should work
+ const instance = wrapper.vm;
+ expect(instance.countdownId).not.toBe(undefined);
+
+ // await delay(50);
+
+ // wrapper.unmount();
+ // expect(instance.countdownId).toBe(undefined);
+ });
+ });
+});
diff --git a/components/statistic/index.en-US.md b/components/statistic/index.en-US.md
index e60bcb350..c47ec8532 100644
--- a/components/statistic/index.en-US.md
+++ b/components/statistic/index.en-US.md
@@ -5,13 +5,14 @@
| Property | Description | Type | Default |
| -------- | ----------- | ---- | ------- |
| decimalSeparator | decimal separator | string | . |
-| formatter | customize value display logic | v-slot \|(h) => VNode | - |
+| formatter | customize value display logic | v-slot \|({h, value}) => VNode | - |
| groupSeparator | group separator | string | , |
| precision | precision of input value | number | - |
| prefix | prefix node of value | string \| v-slot | - |
| suffix | suffix node of value | string \| v-slot | - |
| title | Display title | string \| v-slot | - |
| value | Display value | string \| number | - |
+| valueStyle | Set value css style | style | - |
### Statistic.Countdown
@@ -23,6 +24,7 @@
| suffix | suffix node of value | string \| v-slot | - |
| title | Display title | string \| v-slot | - |
| value | Set target countdown time | number \| moment | - |
+| valueStyle | Set value css style | style | - |
#### Statistic.Countdown Events
| Events Name | Description | Arguments |
diff --git a/components/statistic/index.js b/components/statistic/index.js
index 5a13e5d6a..e464f189f 100644
--- a/components/statistic/index.js
+++ b/components/statistic/index.js
@@ -1,9 +1,11 @@
import Statistic from './Statistic';
import Countdown from './Countdown';
+import Base from '../base';
Statistic.Countdown = Countdown;
/* istanbul ignore next */
Statistic.install = function(Vue) {
+ Vue.use(Base);
Vue.component(Statistic.name, Statistic);
Vue.component(Statistic.Countdown.name, Statistic.Countdown);
};
diff --git a/components/statistic/index.zh-CN.md b/components/statistic/index.zh-CN.md
index 88dde6235..cb28be015 100644
--- a/components/statistic/index.zh-CN.md
+++ b/components/statistic/index.zh-CN.md
@@ -5,13 +5,14 @@
| 参数 | 说明 | 类型 | 默认值 |
| -------- | ----------- | ---- | ------- |
| decimalSeparator | 设置小数点 | string | . |
-| formatter | 自定义数值展示 | v-slot \| (h) => VNode | - |
+| formatter | 自定义数值展示 | v-slot \| ({h, value}) => VNode | - |
| groupSeparator | 设置千分位标识符 | string | , |
| precision | 数值精度 | number | - |
| prefix | 设置数值的前缀 | string \| v-slot | - |
| suffix | 设置数值的后缀 | string \| v-slot | - |
| title | 数值的标题 | string \| v-slot | - |
| value | 数值内容 | string \| number | - |
+| valueStyle | 设置数值的样式 | style | - |
### Statistic.Countdown
@@ -22,6 +23,7 @@
| suffix | 设置数值的后缀 | string \| v-slot | - |
| title | 数值的标题 | string \| v-slot | - |
| value | 数值内容 | number \| moment | - |
+| valueStyle | 设置数值的样式 | style | - |
#### Statistic.Countdown事件
| 事件名称 | 说明 | 回调参数 |
diff --git a/components/tree/Tree.jsx b/components/tree/Tree.jsx
index 136c3d738..8fd7c7ceb 100644
--- a/components/tree/Tree.jsx
+++ b/components/tree/Tree.jsx
@@ -141,7 +141,6 @@ export default {
const switcherOriginCls = getClass(switcherIcon[0]);
return cloneElement(switcherIcon, {
class: {
- ...switcherOriginCls,
[switcherCls]: true,
},
});
diff --git a/components/tree/demo/customized-icon.md b/components/tree/demo/customized-icon.md
index 0bf711e39..2de451364 100644
--- a/components/tree/demo/customized-icon.md
+++ b/components/tree/demo/customized-icon.md
@@ -16,7 +16,7 @@ You can customize icons for different nodes.
defaultExpandAll
:defaultSelectedKeys="['0-0-0']"
>
-
+
diff --git a/components/tree/index.en-US.md b/components/tree/index.en-US.md
index 7fd4bbd16..3c2cebe57 100644
--- a/components/tree/index.en-US.md
+++ b/components/tree/index.en-US.md
@@ -24,7 +24,7 @@
| multiple | Allows selecting multiple treeNodes | boolean | false |
| selectedKeys(.sync) | (Controlled) Specifies the keys of the selected treeNodes | string\[] \| number\[] | - |
| showIcon | Shows the icon before a TreeNode's title. There is no default style; you must set a custom style for it if set to `true` | boolean | false |
-| switcherIcon | customize collapse/expand icon of tree node | slot(vnode) | - |
+| switcherIcon | customize collapse/expand icon of tree node | slot | - |
| showLine | Shows a connecting line | boolean | false |
### Events
diff --git a/components/tree/index.zh-CN.md b/components/tree/index.zh-CN.md
index a492c648e..0122debe9 100644
--- a/components/tree/index.zh-CN.md
+++ b/components/tree/index.zh-CN.md
@@ -24,7 +24,7 @@
| multiple | 支持点选多个节点(节点本身) | boolean | false |
| selectedKeys(.sync) | (受控)设置选中的树节点 | string\[] \| number\[] | - |
| showIcon | 是否展示 TreeNode title 前的图标,没有默认样式,如设置为 true,需要自行定义图标相关样式 | boolean | false |
-| switcherIcon | 自定义树节点的展开/折叠图标 | slot(vnode) | - |
+| switcherIcon | 自定义树节点的展开/折叠图标 | slot | - |
| showLine | 是否展示连接线 | boolean | false |
diff --git a/types/rate.d.ts b/types/rate.d.ts
index 6bdd3ccb4..aa2bbbad6 100644
--- a/types/rate.d.ts
+++ b/types/rate.d.ts
@@ -60,6 +60,8 @@ export declare class Rate extends AntdComponent {
*/
value: number;
+ tooltips: Array;
+
/**
* remove focus
*/
diff --git a/types/statistic/statistic-countdown.d.ts b/types/statistic/statistic-countdown.d.ts
new file mode 100644
index 000000000..499d106b9
--- /dev/null
+++ b/types/statistic/statistic-countdown.d.ts
@@ -0,0 +1,34 @@
+// Project: https://github.com/vueComponent/ant-design-vue
+// Definitions by: akki-jat
+// Definitions: https://github.com/vueComponent/ant-design-vue/types
+
+import { AntdComponent } from '../component';
+import { VNode } from 'vue';
+
+export declare class AStatisticCountdown extends AntdComponent {
+ format: string;
+ /**
+ * prefix node of value
+ * @type string | VNode
+ */
+ prefix: string | VNode;
+
+ /**
+ * suffix node of value
+ * @type string | VNode
+ */
+ suffix: string | VNode;
+
+ /**
+ * Display title
+ * @type string | VNode
+ */
+ title: string | VNode;
+
+ /**
+ * Display value
+ * @type string or number
+ */
+ value: string | number;
+ valueStyle: object;
+}
diff --git a/types/statistic.ts b/types/statistic/statistic.d.ts
similarity index 85%
rename from types/statistic.ts
rename to types/statistic/statistic.d.ts
index d24320de7..4d47592f2 100644
--- a/types/statistic.ts
+++ b/types/statistic/statistic.d.ts
@@ -2,10 +2,12 @@
// Definitions by: akki-jat
// Definitions: https://github.com/vueComponent/ant-design-vue/types
-import { AntdComponent } from './component';
+import { AntdComponent } from '../component';
import { VNode } from 'vue';
+import AStatisticCountdown from './statistic-countdown';
export declare class Statistic extends AntdComponent {
+ static AStatisticCountdown: typeof AStatisticCountdown;
/**
* decimal separator
* @default '.'