mirror of
https://gitee.com/ant-design-vue/ant-design-vue.git
synced 2024-12-02 03:58:05 +08:00
cr pxxx to sxxx and tree
This commit is contained in:
parent
4ce99b91e1
commit
c015c8d34c
@ -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 {
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { Circle as VCCircle } from '../vc-progress';
|
||||
import { validProgress } from './utils';
|
||||
import { ProgressProps } from './progress';
|
||||
|
||||
const statusColorMap = {
|
||||
normal: '#108ee9',
|
||||
|
@ -1,5 +1,4 @@
|
||||
import { validProgress } from './utils';
|
||||
import { ProgressProps } from './progress';
|
||||
|
||||
const Line = {
|
||||
functional: true,
|
||||
|
@ -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}
|
||||
|
@ -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 {
|
||||
|
@ -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 },
|
||||
|
@ -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 (
|
||||
<RadioGroup ref="radioGroup" {...groupProps} onChange={onChangeRadioGroup}>
|
||||
<Radio value="A" onChange={onChange}>
|
||||
A
|
||||
</Radio>
|
||||
<Radio value="B" onChange={onChange}>
|
||||
B
|
||||
</Radio>
|
||||
<Radio value="C" onChange={onChange}>
|
||||
C
|
||||
</Radio>
|
||||
</RadioGroup>
|
||||
);
|
||||
},
|
||||
},
|
||||
{ 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(<RadioGroup options={options} onChange={onChange} />);
|
||||
|
||||
// wrapper.find('input').trigger('change');
|
||||
// expect(onChange).toHaveBeenCalledTimes(1);
|
||||
// });
|
||||
|
||||
// it('won\'t fire change events when value not changes', async () => {
|
||||
// const onChange = jest.fn()
|
||||
|
||||
|
@ -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();
|
||||
});
|
||||
|
@ -40,12 +40,7 @@ const Rate = {
|
||||
characterRender(node, { index }) {
|
||||
const { tooltips } = this.$props;
|
||||
if (!tooltips) return node;
|
||||
const tooltipsProps = {
|
||||
props: {
|
||||
title: tooltips[index],
|
||||
},
|
||||
};
|
||||
return <Tooltip {...tooltipsProps}>{node}</Tooltip>;
|
||||
return <Tooltip title={tooltips[index]}>{node}</Tooltip>;
|
||||
},
|
||||
},
|
||||
render() {
|
||||
|
@ -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'),
|
||||
|
@ -1,5 +1,4 @@
|
||||
import PropTypes from '../_util/vue-types';
|
||||
import { initDefaultProps } from '../_util/props-util';
|
||||
|
||||
const skeletonTitleProps = {
|
||||
prefixCls: PropTypes.string,
|
||||
|
@ -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 (
|
||||
<div>
|
||||
<md cn={md.cn} us={md.us}/>
|
||||
<br/>
|
||||
<Basic/>
|
||||
<md cn={md.cn} us={md.us} />
|
||||
<br />
|
||||
<Basic />
|
||||
<br />
|
||||
<Complex />
|
||||
<br />
|
||||
@ -52,12 +48,12 @@ export default {
|
||||
<Children />
|
||||
<br />
|
||||
<List />
|
||||
<br/>
|
||||
<br />
|
||||
<api>
|
||||
<template slot='cn'>
|
||||
<CN/>
|
||||
<template slot="cn">
|
||||
<CN />
|
||||
</template>
|
||||
<US/>
|
||||
<US />
|
||||
</api>
|
||||
</div>
|
||||
);
|
||||
|
@ -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 |
|
||||
|
@ -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,
|
||||
|
@ -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 |
|
||||
|
@ -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() {
|
||||
|
69
components/spin/__tests__/delay.test.js
Normal file
69
components/spin/__tests__/delay.test.js
Normal file
@ -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();
|
||||
});
|
||||
});
|
@ -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 (
|
||||
<Statistic
|
||||
key={this.uniKey}
|
||||
ref="statistic"
|
||||
{...{
|
||||
props: {
|
||||
...this.$props,
|
||||
valueRender: this.valueRenderHtml,
|
||||
formatter: this.formatCountdown,
|
||||
},
|
||||
on: this.$listeners,
|
||||
}}
|
||||
/>
|
||||
);
|
||||
|
@ -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);
|
||||
|
@ -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 = (
|
||||
<StatisticNumber {...{ props: this.$props }} value={value} formatter={formatter} />
|
||||
<StatisticNumber {...{ props: { ...this.$props, prefixCls, value, formatter } }} />
|
||||
);
|
||||
if (valueRender) {
|
||||
valueNode = valueRender(valueNode);
|
||||
|
@ -0,0 +1,8 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Statistic support negetive number 1`] = `
|
||||
<div class="ant-statistic">
|
||||
<div class="ant-statistic-title">Account Balance (CNY)</div>
|
||||
<div class="ant-statistic-content"><span class="ant-statistic-content-value"><span class="ant-statistic-content-value-int">-112,893</span><span class="ant-statistic-content-value-decimal">.12</span></span></div>
|
||||
</div>
|
||||
`;
|
107
components/statistic/__tests__/index.test.js
Normal file
107
components/statistic/__tests__/index.test.js
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
});
|
@ -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 |
|
||||
|
@ -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);
|
||||
};
|
||||
|
@ -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事件
|
||||
| 事件名称 | 说明 | 回调参数 |
|
||||
|
@ -141,7 +141,6 @@ export default {
|
||||
const switcherOriginCls = getClass(switcherIcon[0]);
|
||||
return cloneElement(switcherIcon, {
|
||||
class: {
|
||||
...switcherOriginCls,
|
||||
[switcherCls]: true,
|
||||
},
|
||||
});
|
||||
|
@ -16,7 +16,7 @@ You can customize icons for different nodes.
|
||||
defaultExpandAll
|
||||
:defaultSelectedKeys="['0-0-0']"
|
||||
>
|
||||
<a-icon type="down" slot="switcherIcon" />
|
||||
<a-icon type="down" slot="switcherIcon" class="test" />
|
||||
<a-icon slot="smile" type="smile-o" />
|
||||
<a-icon slot="meh" type="smile-o" />
|
||||
<template slot="custom" slot-scope="{selected}">
|
||||
|
@ -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
|
||||
|
@ -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 |
|
||||
|
||||
|
||||
|
2
types/rate.d.ts
vendored
2
types/rate.d.ts
vendored
@ -60,6 +60,8 @@ export declare class Rate extends AntdComponent {
|
||||
*/
|
||||
value: number;
|
||||
|
||||
tooltips: Array<string>;
|
||||
|
||||
/**
|
||||
* remove focus
|
||||
*/
|
||||
|
34
types/statistic/statistic-countdown.d.ts
vendored
Normal file
34
types/statistic/statistic-countdown.d.ts
vendored
Normal file
@ -0,0 +1,34 @@
|
||||
// Project: https://github.com/vueComponent/ant-design-vue
|
||||
// Definitions by: akki-jat <https://github.com/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;
|
||||
}
|
@ -2,10 +2,12 @@
|
||||
// Definitions by: akki-jat <https://github.com/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 '.'
|
Loading…
Reference in New Issue
Block a user