feat: radio && rate && spin

pull/666/head
wangxueliang 6 years ago
parent 16409c6ed1
commit 1af8349504

@ -2,6 +2,7 @@ import classNames from 'classnames';
import PropTypes from '../_util/vue-types';
import Radio from './Radio';
import { getOptionProps, filterEmpty, hasProp } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
function noop() {}
export default {
@ -11,7 +12,6 @@ export default {
},
props: {
prefixCls: {
default: 'ant-radio',
type: String,
},
defaultValue: PropTypes.any,
@ -41,6 +41,9 @@ export default {
radioGroupContext: this,
};
},
inject: {
configProvider: { default: () => ({}) },
},
computed: {
radioOptions() {
const { disabled } = this;
@ -79,7 +82,10 @@ export default {
render() {
const { mouseenter = noop, mouseleave = noop } = this.$listeners;
const props = getOptionProps(this);
const { prefixCls, options, buttonStyle } = props;
const { prefixCls: customizePrefixCls, options, buttonStyle } = props;
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const groupPrefixCls = `${prefixCls}-group`;
const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, {
[`${groupPrefixCls}-${props.size}`]: props.size,

@ -2,6 +2,7 @@ import PropTypes from '../_util/vue-types';
import VcCheckbox from '../vc-checkbox';
import classNames from 'classnames';
import { getOptionProps, getAttrs } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
function noop() {}
@ -12,7 +13,6 @@ export default {
},
props: {
prefixCls: {
default: 'ant-radio',
type: String,
},
defaultChecked: Boolean,
@ -27,6 +27,7 @@ export default {
},
inject: {
radioGroupContext: { default: undefined },
configProvider: { default: () => ({}) },
},
methods: {
handleChange(event) {
@ -47,7 +48,10 @@ export default {
const props = getOptionProps(this);
const children = $slots.default;
const { mouseenter = noop, mouseleave = noop, ...restListeners } = $listeners;
const { prefixCls, ...restProps } = props;
const { prefixCls: customizePrefixCls, ...restProps } = props;
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('radio', customizePrefixCls);
const radioProps = {
props: { ...restProps, prefixCls },
on: restListeners,

@ -1,21 +1,28 @@
import Radio from './Radio';
import { getOptionProps } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
export default {
name: 'ARadioButton',
props: {
...Radio.props,
prefixCls: {
default: 'ant-radio-button',
type: String,
},
},
inject: {
radioGroupContext: { default: undefined },
configProvider: { default: () => ({}) },
},
render() {
const props = getOptionProps(this);
const radioProps = { props, on: { ...this.$listeners } };
const {prefixCls: customizePrefixCls, ...otherProps} = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('radio-button', customizePrefixCls);
const radioProps = { props: {
...otherProps,
prefixCls,
}, on: { ...this.$listeners } };
if (this.radioGroupContext) {
radioProps.on.change = this.radioGroupContext.onRadioChange;
radioProps.props.checked = props.value === this.radioGroupContext.stateValue;

@ -11,8 +11,8 @@ Add copywriting in rate components.
```html
<template>
<span>
<a-rate v-model='value'/>
<span class="ant-rate-text">{{value}} stars</span>
<a-rate :tooltips="desc" v-model='value'/>
<span class="ant-rate-text">{{desc[value - 1]}}</span>
</span>
</template>
<script>
@ -20,6 +20,7 @@ export default {
data() {
return {
value: 3,
desc: ['terrible', 'bad', 'normal', 'good', 'wonderful']
}
},
}

@ -9,6 +9,7 @@
| count | star count | number | 5 |
| defaultValue | default value | number | 0 |
| disabled | read only, unable to interact | boolean | false |
| tooltips | Customize tooltip by each character | string\[] | - |
| value(v-model) | current value | number | - |

@ -1,7 +1,11 @@
import omit from 'omit.js';
import PropTypes from '../_util/vue-types';
import { initDefaultProps, getOptionProps, getComponentFromProp } from '../_util/props-util';
import { getOptionProps, getComponentFromProp } from '../_util/props-util';
import { ConfigConsumerProps } from '../config-provider';
import VcRate from '../vc-rate';
import Icon from '../icon';
import Tooltip from '../tooltip';
export const RateProps = {
prefixCls: PropTypes.string,
@ -10,6 +14,7 @@ export const RateProps = {
defaultValue: PropTypes.value,
allowHalf: PropTypes.bool,
allowClear: PropTypes.bool,
tooltips: PropTypes.arrayOf(PropTypes.string),
disabled: PropTypes.bool,
character: PropTypes.any,
autoFocus: PropTypes.bool,
@ -21,9 +26,10 @@ const Rate = {
prop: 'value',
event: 'change',
},
props: initDefaultProps(RateProps, {
prefixCls: 'ant-rate',
}),
props: RateProps,
inject: {
configProvider: { default: () => ({}) },
},
methods: {
focus() {
this.$refs.refRate.focus();
@ -31,15 +37,31 @@ const Rate = {
blur() {
this.$refs.refRate.blur();
},
characterRender(node, { index }) {
const { tooltips } = this.$props;
if (!tooltips) return node;
const tooltipsProps = {
props: {
title: tooltips[index],
},
};
return <Tooltip {...tooltipsProps}>{node}</Tooltip>;
},
},
render() {
const { prefixCls: customizePrefixCls, ...restProps } = getOptionProps(this);
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('rate', customizePrefixCls);
const character = getComponentFromProp(this, 'character') || (
<Icon type="star" theme="filled" />
);
const rateProps = {
props: {
character,
...getOptionProps(this),
characterRender: this.characterRender,
prefixCls,
...omit(restProps, ['tooltips']),
},
on: this.$listeners,
ref: 'refRate',

@ -9,6 +9,7 @@
| count | star 总数 | number | 5 |
| defaultValue | 默认值 | number | 0 |
| disabled | 只读,无法进行交互 | boolean | false |
| tooltips | 自定义每项的提示信息 | string\[] | - |
| value(v-model) | 当前数,受控值 | number | - |
### 事件

@ -1,3 +1,4 @@
import debounce from 'lodash/debounce';
import PropTypes from '../_util/vue-types';
import BaseMixin from '../_util/BaseMixin';
import {
@ -7,6 +8,7 @@ import {
getComponentFromProp,
} from '../_util/props-util';
import { cloneElement } from '../_util/vnode';
import { ConfigConsumerProps } from '../config-provider';
export const SpinSize = PropTypes.oneOf(['small', 'default', 'large']);
@ -40,56 +42,43 @@ export default {
name: 'ASpin',
mixins: [BaseMixin],
props: initDefaultProps(SpinProps(), {
prefixCls: 'ant-spin',
size: 'default',
spinning: true,
wrapperClassName: '',
}),
inject: {
configProvider: { default: () => ({}) },
},
data() {
const { spinning, delay } = this;
this.debounceTimeout = null;
this.delayTimeout = null;
this.originalUpdateSpinning = this.updateSpinning;
this.debouncifyUpdateSpinning(this.$props);
return {
sSpinning: spinning && !shouldDelay(spinning, delay),
};
},
mounted() {
this.updateSpinning();
},
updated() {
this.$nextTick(() => {
const { delay, spinning, sSpinning } = this;
if (sSpinning === spinning) {
return;
}
if (this.debounceTimeout) {
clearTimeout(this.debounceTimeout);
}
if (sSpinning && !spinning) {
this.debounceTimeout = window.setTimeout(() => this.setState({ sSpinning: spinning }), 200);
if (this.delayTimeout) {
clearTimeout(this.delayTimeout);
}
} else {
if (shouldDelay(spinning, delay)) {
if (this.delayTimeout) {
clearTimeout(this.delayTimeout);
}
this.delayTimeout = window.setTimeout(this.delayUpdateSpinning, delay);
} else {
this.setState({ sSpinning: spinning });
}
}
this.debouncifyUpdateSpinning();
this.updateSpinning();
});
},
beforeDestroy() {
if (this.debounceTimeout) {
clearTimeout(this.debounceTimeout);
}
if (this.delayTimeout) {
clearTimeout(this.delayTimeout);
if (this.updateSpinning && this.updateSpinning.cancel) {
this.updateSpinning.cancel();
}
},
methods: {
delayUpdateSpinning() {
debouncifyUpdateSpinning(props) {
const { delay } = props || this.$props;
if(delay) {
this.updateSpinning = debounce(this.originalUpdateSpinning, delay);
}
},
updateSpinning() {
const { spinning, sSpinning } = this;
if (sSpinning !== spinning) {
this.setState({ sSpinning: spinning });
@ -101,9 +90,8 @@ export default {
}
return null;
},
renderIndicator(h, props) {
renderIndicator(h, prefixCls) {
// const h = this.$createElement
const { prefixCls } = props;
const dotClassName = `${prefixCls}-dot`;
let indicator = getComponentFromProp(this, 'indicator');
if (Array.isArray(indicator)) {
@ -129,7 +117,10 @@ export default {
},
},
render(h) {
const { size, prefixCls, tip, wrapperClassName, ...restProps } = this.$props;
const { size, prefixCls: customizePrefixCls, tip, wrapperClassName, ...restProps } = this.$props;
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
const prefixCls = getPrefixCls('spin', customizePrefixCls);
const { sSpinning } = this;
const spinClassName = {
[prefixCls]: true,
@ -141,7 +132,7 @@ export default {
const spinElement = (
<div {...restProps} class={spinClassName}>
{this.renderIndicator(h, this.$props)}
{this.renderIndicator(h, prefixCls)}
{tip ? <div class={`${prefixCls}-text`}>{tip}</div> : null}
</div>
);

@ -32,25 +32,6 @@ describe('Spin', () => {
expect(wrapper.html()).toMatchSnapshot();
});
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 be controlled by spinning', async () => {
const props = {
propsData: {

Loading…
Cancel
Save