feat: radio && rate && spin
parent
16409c6ed1
commit
1af8349504
|
@ -2,6 +2,7 @@ import classNames from 'classnames';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import Radio from './Radio';
|
import Radio from './Radio';
|
||||||
import { getOptionProps, filterEmpty, hasProp } from '../_util/props-util';
|
import { getOptionProps, filterEmpty, hasProp } from '../_util/props-util';
|
||||||
|
import { ConfigConsumerProps } from '../config-provider';
|
||||||
function noop() {}
|
function noop() {}
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
|
@ -11,7 +12,6 @@ export default {
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
prefixCls: {
|
prefixCls: {
|
||||||
default: 'ant-radio',
|
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
defaultValue: PropTypes.any,
|
defaultValue: PropTypes.any,
|
||||||
|
@ -41,6 +41,9 @@ export default {
|
||||||
radioGroupContext: this,
|
radioGroupContext: this,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
inject: {
|
||||||
|
configProvider: { default: () => ({}) },
|
||||||
|
},
|
||||||
computed: {
|
computed: {
|
||||||
radioOptions() {
|
radioOptions() {
|
||||||
const { disabled } = this;
|
const { disabled } = this;
|
||||||
|
@ -79,7 +82,10 @@ export default {
|
||||||
render() {
|
render() {
|
||||||
const { mouseenter = noop, mouseleave = noop } = this.$listeners;
|
const { mouseenter = noop, mouseleave = noop } = this.$listeners;
|
||||||
const props = getOptionProps(this);
|
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 groupPrefixCls = `${prefixCls}-group`;
|
||||||
const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, {
|
const classString = classNames(groupPrefixCls, `${groupPrefixCls}-${buttonStyle}`, {
|
||||||
[`${groupPrefixCls}-${props.size}`]: props.size,
|
[`${groupPrefixCls}-${props.size}`]: props.size,
|
||||||
|
|
|
@ -2,6 +2,7 @@ import PropTypes from '../_util/vue-types';
|
||||||
import VcCheckbox from '../vc-checkbox';
|
import VcCheckbox from '../vc-checkbox';
|
||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import { getOptionProps, getAttrs } from '../_util/props-util';
|
import { getOptionProps, getAttrs } from '../_util/props-util';
|
||||||
|
import { ConfigConsumerProps } from '../config-provider';
|
||||||
|
|
||||||
function noop() {}
|
function noop() {}
|
||||||
|
|
||||||
|
@ -12,7 +13,6 @@ export default {
|
||||||
},
|
},
|
||||||
props: {
|
props: {
|
||||||
prefixCls: {
|
prefixCls: {
|
||||||
default: 'ant-radio',
|
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
defaultChecked: Boolean,
|
defaultChecked: Boolean,
|
||||||
|
@ -27,6 +27,7 @@ export default {
|
||||||
},
|
},
|
||||||
inject: {
|
inject: {
|
||||||
radioGroupContext: { default: undefined },
|
radioGroupContext: { default: undefined },
|
||||||
|
configProvider: { default: () => ({}) },
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleChange(event) {
|
handleChange(event) {
|
||||||
|
@ -47,7 +48,10 @@ export default {
|
||||||
const props = getOptionProps(this);
|
const props = getOptionProps(this);
|
||||||
const children = $slots.default;
|
const children = $slots.default;
|
||||||
const { mouseenter = noop, mouseleave = noop, ...restListeners } = $listeners;
|
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 = {
|
const radioProps = {
|
||||||
props: { ...restProps, prefixCls },
|
props: { ...restProps, prefixCls },
|
||||||
on: restListeners,
|
on: restListeners,
|
||||||
|
|
|
@ -1,21 +1,28 @@
|
||||||
import Radio from './Radio';
|
import Radio from './Radio';
|
||||||
import { getOptionProps } from '../_util/props-util';
|
import { getOptionProps } from '../_util/props-util';
|
||||||
|
import { ConfigConsumerProps } from '../config-provider';
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: 'ARadioButton',
|
name: 'ARadioButton',
|
||||||
props: {
|
props: {
|
||||||
...Radio.props,
|
...Radio.props,
|
||||||
prefixCls: {
|
prefixCls: {
|
||||||
default: 'ant-radio-button',
|
|
||||||
type: String,
|
type: String,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
inject: {
|
inject: {
|
||||||
radioGroupContext: { default: undefined },
|
radioGroupContext: { default: undefined },
|
||||||
|
configProvider: { default: () => ({}) },
|
||||||
},
|
},
|
||||||
render() {
|
render() {
|
||||||
const props = getOptionProps(this);
|
const {prefixCls: customizePrefixCls, ...otherProps} = getOptionProps(this);
|
||||||
const radioProps = { props, on: { ...this.$listeners } };
|
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
|
||||||
|
const prefixCls = getPrefixCls('radio-button', customizePrefixCls);
|
||||||
|
|
||||||
|
const radioProps = { props: {
|
||||||
|
...otherProps,
|
||||||
|
prefixCls,
|
||||||
|
}, on: { ...this.$listeners } };
|
||||||
if (this.radioGroupContext) {
|
if (this.radioGroupContext) {
|
||||||
radioProps.on.change = this.radioGroupContext.onRadioChange;
|
radioProps.on.change = this.radioGroupContext.onRadioChange;
|
||||||
radioProps.props.checked = props.value === this.radioGroupContext.stateValue;
|
radioProps.props.checked = props.value === this.radioGroupContext.stateValue;
|
||||||
|
|
|
@ -11,8 +11,8 @@ Add copywriting in rate components.
|
||||||
```html
|
```html
|
||||||
<template>
|
<template>
|
||||||
<span>
|
<span>
|
||||||
<a-rate v-model='value'/>
|
<a-rate :tooltips="desc" v-model='value'/>
|
||||||
<span class="ant-rate-text">{{value}} stars</span>
|
<span class="ant-rate-text">{{desc[value - 1]}}</span>
|
||||||
</span>
|
</span>
|
||||||
</template>
|
</template>
|
||||||
<script>
|
<script>
|
||||||
|
@ -20,6 +20,7 @@ export default {
|
||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
value: 3,
|
value: 3,
|
||||||
|
desc: ['terrible', 'bad', 'normal', 'good', 'wonderful']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
| count | star count | number | 5 |
|
| count | star count | number | 5 |
|
||||||
| defaultValue | default value | number | 0 |
|
| defaultValue | default value | number | 0 |
|
||||||
| disabled | read only, unable to interact | boolean | false |
|
| disabled | read only, unable to interact | boolean | false |
|
||||||
|
| tooltips | Customize tooltip by each character | string\[] | - |
|
||||||
| value(v-model) | current value | number | - |
|
| value(v-model) | current value | number | - |
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,11 @@
|
||||||
|
|
||||||
|
import omit from 'omit.js';
|
||||||
import PropTypes from '../_util/vue-types';
|
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 VcRate from '../vc-rate';
|
||||||
import Icon from '../icon';
|
import Icon from '../icon';
|
||||||
|
import Tooltip from '../tooltip';
|
||||||
|
|
||||||
export const RateProps = {
|
export const RateProps = {
|
||||||
prefixCls: PropTypes.string,
|
prefixCls: PropTypes.string,
|
||||||
|
@ -10,6 +14,7 @@ export const RateProps = {
|
||||||
defaultValue: PropTypes.value,
|
defaultValue: PropTypes.value,
|
||||||
allowHalf: PropTypes.bool,
|
allowHalf: PropTypes.bool,
|
||||||
allowClear: PropTypes.bool,
|
allowClear: PropTypes.bool,
|
||||||
|
tooltips: PropTypes.arrayOf(PropTypes.string),
|
||||||
disabled: PropTypes.bool,
|
disabled: PropTypes.bool,
|
||||||
character: PropTypes.any,
|
character: PropTypes.any,
|
||||||
autoFocus: PropTypes.bool,
|
autoFocus: PropTypes.bool,
|
||||||
|
@ -21,9 +26,10 @@ const Rate = {
|
||||||
prop: 'value',
|
prop: 'value',
|
||||||
event: 'change',
|
event: 'change',
|
||||||
},
|
},
|
||||||
props: initDefaultProps(RateProps, {
|
props: RateProps,
|
||||||
prefixCls: 'ant-rate',
|
inject: {
|
||||||
}),
|
configProvider: { default: () => ({}) },
|
||||||
|
},
|
||||||
methods: {
|
methods: {
|
||||||
focus() {
|
focus() {
|
||||||
this.$refs.refRate.focus();
|
this.$refs.refRate.focus();
|
||||||
|
@ -31,15 +37,31 @@ const Rate = {
|
||||||
blur() {
|
blur() {
|
||||||
this.$refs.refRate.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() {
|
render() {
|
||||||
|
const { prefixCls: customizePrefixCls, ...restProps } = getOptionProps(this);
|
||||||
|
const getPrefixCls = this.configProvider.getPrefixCls || ConfigConsumerProps.getPrefixCls;
|
||||||
|
const prefixCls = getPrefixCls('rate', customizePrefixCls);
|
||||||
|
|
||||||
const character = getComponentFromProp(this, 'character') || (
|
const character = getComponentFromProp(this, 'character') || (
|
||||||
<Icon type="star" theme="filled" />
|
<Icon type="star" theme="filled" />
|
||||||
);
|
);
|
||||||
const rateProps = {
|
const rateProps = {
|
||||||
props: {
|
props: {
|
||||||
character,
|
character,
|
||||||
...getOptionProps(this),
|
characterRender: this.characterRender,
|
||||||
|
prefixCls,
|
||||||
|
...omit(restProps, ['tooltips']),
|
||||||
},
|
},
|
||||||
on: this.$listeners,
|
on: this.$listeners,
|
||||||
ref: 'refRate',
|
ref: 'refRate',
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
| count | star 总数 | number | 5 |
|
| count | star 总数 | number | 5 |
|
||||||
| defaultValue | 默认值 | number | 0 |
|
| defaultValue | 默认值 | number | 0 |
|
||||||
| disabled | 只读,无法进行交互 | boolean | false |
|
| disabled | 只读,无法进行交互 | boolean | false |
|
||||||
|
| tooltips | 自定义每项的提示信息 | string\[] | - |
|
||||||
| value(v-model) | 当前数,受控值 | number | - |
|
| value(v-model) | 当前数,受控值 | number | - |
|
||||||
|
|
||||||
### 事件
|
### 事件
|
||||||
|
|
|
@ -1,3 +1,4 @@
|
||||||
|
import debounce from 'lodash/debounce';
|
||||||
import PropTypes from '../_util/vue-types';
|
import PropTypes from '../_util/vue-types';
|
||||||
import BaseMixin from '../_util/BaseMixin';
|
import BaseMixin from '../_util/BaseMixin';
|
||||||
import {
|
import {
|
||||||
|
@ -7,6 +8,7 @@ import {
|
||||||
getComponentFromProp,
|
getComponentFromProp,
|
||||||
} from '../_util/props-util';
|
} from '../_util/props-util';
|
||||||
import { cloneElement } from '../_util/vnode';
|
import { cloneElement } from '../_util/vnode';
|
||||||
|
import { ConfigConsumerProps } from '../config-provider';
|
||||||
|
|
||||||
export const SpinSize = PropTypes.oneOf(['small', 'default', 'large']);
|
export const SpinSize = PropTypes.oneOf(['small', 'default', 'large']);
|
||||||
|
|
||||||
|
@ -40,56 +42,43 @@ export default {
|
||||||
name: 'ASpin',
|
name: 'ASpin',
|
||||||
mixins: [BaseMixin],
|
mixins: [BaseMixin],
|
||||||
props: initDefaultProps(SpinProps(), {
|
props: initDefaultProps(SpinProps(), {
|
||||||
prefixCls: 'ant-spin',
|
|
||||||
size: 'default',
|
size: 'default',
|
||||||
spinning: true,
|
spinning: true,
|
||||||
wrapperClassName: '',
|
wrapperClassName: '',
|
||||||
}),
|
}),
|
||||||
|
inject: {
|
||||||
|
configProvider: { default: () => ({}) },
|
||||||
|
},
|
||||||
data() {
|
data() {
|
||||||
const { spinning, delay } = this;
|
const { spinning, delay } = this;
|
||||||
this.debounceTimeout = null;
|
this.originalUpdateSpinning = this.updateSpinning;
|
||||||
this.delayTimeout = null;
|
this.debouncifyUpdateSpinning(this.$props);
|
||||||
return {
|
return {
|
||||||
sSpinning: spinning && !shouldDelay(spinning, delay),
|
sSpinning: spinning && !shouldDelay(spinning, delay),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
mounted() {
|
||||||
|
this.updateSpinning();
|
||||||
|
},
|
||||||
updated() {
|
updated() {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
const { delay, spinning, sSpinning } = this;
|
this.debouncifyUpdateSpinning();
|
||||||
if (sSpinning === spinning) {
|
this.updateSpinning();
|
||||||
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 });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
beforeDestroy() {
|
beforeDestroy() {
|
||||||
if (this.debounceTimeout) {
|
if (this.updateSpinning && this.updateSpinning.cancel) {
|
||||||
clearTimeout(this.debounceTimeout);
|
this.updateSpinning.cancel();
|
||||||
}
|
|
||||||
if (this.delayTimeout) {
|
|
||||||
clearTimeout(this.delayTimeout);
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
delayUpdateSpinning() {
|
debouncifyUpdateSpinning(props) {
|
||||||
|
const { delay } = props || this.$props;
|
||||||
|
if(delay) {
|
||||||
|
this.updateSpinning = debounce(this.originalUpdateSpinning, delay);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
updateSpinning() {
|
||||||
const { spinning, sSpinning } = this;
|
const { spinning, sSpinning } = this;
|
||||||
if (sSpinning !== spinning) {
|
if (sSpinning !== spinning) {
|
||||||
this.setState({ sSpinning: spinning });
|
this.setState({ sSpinning: spinning });
|
||||||
|
@ -101,9 +90,8 @@ export default {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
renderIndicator(h, props) {
|
renderIndicator(h, prefixCls) {
|
||||||
// const h = this.$createElement
|
// const h = this.$createElement
|
||||||
const { prefixCls } = props;
|
|
||||||
const dotClassName = `${prefixCls}-dot`;
|
const dotClassName = `${prefixCls}-dot`;
|
||||||
let indicator = getComponentFromProp(this, 'indicator');
|
let indicator = getComponentFromProp(this, 'indicator');
|
||||||
if (Array.isArray(indicator)) {
|
if (Array.isArray(indicator)) {
|
||||||
|
@ -129,7 +117,10 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
render(h) {
|
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 { sSpinning } = this;
|
||||||
const spinClassName = {
|
const spinClassName = {
|
||||||
[prefixCls]: true,
|
[prefixCls]: true,
|
||||||
|
@ -141,7 +132,7 @@ export default {
|
||||||
|
|
||||||
const spinElement = (
|
const spinElement = (
|
||||||
<div {...restProps} class={spinClassName}>
|
<div {...restProps} class={spinClassName}>
|
||||||
{this.renderIndicator(h, this.$props)}
|
{this.renderIndicator(h, prefixCls)}
|
||||||
{tip ? <div class={`${prefixCls}-text`}>{tip}</div> : null}
|
{tip ? <div class={`${prefixCls}-text`}>{tip}</div> : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -32,25 +32,6 @@ describe('Spin', () => {
|
||||||
expect(wrapper.html()).toMatchSnapshot();
|
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 () => {
|
it('should be controlled by spinning', async () => {
|
||||||
const props = {
|
const props = {
|
||||||
propsData: {
|
propsData: {
|
||||||
|
|
Loading…
Reference in New Issue