diff --git a/packages/rate/index.js b/packages/rate/index.js deleted file mode 100644 index b46c0eb26..000000000 --- a/packages/rate/index.js +++ /dev/null @@ -1,94 +0,0 @@ -/* eslint-disable prefer-spread */ -import { use } from '../utils'; -import Icon from '../icon'; - -const [sfc, bem] = use('rate'); - -export default sfc({ - props: { - value: Number, - readonly: Boolean, - disabled: Boolean, - size: { - type: Number, - default: 20 - }, - icon: { - type: String, - default: 'star' - }, - voidIcon: { - type: String, - default: 'star-o' - }, - color: { - type: String, - default: '#ffd21e' - }, - voidColor: { - type: String, - default: '#c7c7c7' - }, - disabledColor: { - type: String, - default: '#bdbdbd' - }, - count: { - type: Number, - default: 5 - } - }, - - computed: { - list() { - return Array.apply(null, { length: this.count }).map((value, index) => index < this.value); - } - }, - - methods: { - onSelect(index) { - if (!this.disabled && !this.readonly) { - this.$emit('input', index + 1); - this.$emit('change', index + 1); - } - }, - - onTouchMove(event) { - if (!document.elementFromPoint) { - return; - } - - event.preventDefault(); - const { clientX, clientY } = event.touches[0]; - const target = document.elementFromPoint(clientX, clientY); - if (target && target.dataset) { - const { index } = target.dataset; - - /* istanbul ignore else */ - if (index) { - this.onSelect(+index); - } - } - } - }, - - render(h) { - return ( -
- {this.list.map((full, index) => ( - { - this.onSelect(index); - }} - /> - ))} -
- ); - } -}); diff --git a/packages/rate/index.tsx b/packages/rate/index.tsx new file mode 100644 index 000000000..eec10630d --- /dev/null +++ b/packages/rate/index.tsx @@ -0,0 +1,125 @@ +/* eslint-disable prefer-spread */ +import { use } from '../utils'; +import { emit, inherit } from '../utils/functional'; +import Icon from '../icon'; + +// Types +import { CreateElement, RenderContext } from 'vue/types'; +import { DefaultSlots } from '../utils/use/sfc'; + +const [sfc, bem] = use('rate'); + +export type RateProps = { + size: number; + icon: string; + count: number; + color: string; + value: number; + voidIcon: string; + voidColor: string; + readonly?: boolean; + disabled?: boolean; + disabledColor: string; +}; + +export type RateEvents = { + input(index: number): void; + change(index: number): void; +} + +function Rate( + h: CreateElement, + props: RateProps, + slots: DefaultSlots, + ctx: RenderContext +) { + const list = []; + for (let i = 0; i < props.count; i++) { + list.push(i < props.value); + } + + const onSelect = (index: number) => { + if (!props.disabled && !props.readonly) { + emit(ctx, 'input', index + 1); + emit(ctx, 'change', index + 1); + } + }; + + const onTouchMove = (event: TouchEvent) => { + if (!document.elementFromPoint) { + return; + } + + event.preventDefault(); + const { clientX, clientY } = event.touches[0]; + const target = document.elementFromPoint(clientX, clientY) as HTMLElement; + if (target && target.dataset) { + const { index } = target.dataset; + + /* istanbul ignore else */ + if (index) { + onSelect(+index); + } + } + }; + + return ( +
+ {list.map((full, index) => ( + { + onSelect(index); + }} + /> + ))} +
+ ); +} + +Rate.props = { + value: Number, + readonly: Boolean, + disabled: Boolean, + size: { + type: Number, + default: 20 + }, + icon: { + type: String, + default: 'star' + }, + voidIcon: { + type: String, + default: 'star-o' + }, + color: { + type: String, + default: '#ffd21e' + }, + voidColor: { + type: String, + default: '#c7c7c7' + }, + disabledColor: { + type: String, + default: '#bdbdbd' + }, + count: { + type: Number, + default: 5 + } +}; + +export default sfc(Rate); diff --git a/packages/rate/test/index.spec.js b/packages/rate/test/index.spec.js index 47751cd23..33aff6b57 100644 --- a/packages/rate/test/index.spec.js +++ b/packages/rate/test/index.spec.js @@ -2,24 +2,55 @@ import Rate from '..'; import { mount, triggerDrag } from '../../../test/utils'; test('change event', () => { + const onInput = jest.fn(); + const onChange = jest.fn(); + const wrapper = mount(Rate, { - propsData: { - disabled: true + context: { + on: { + input: onInput, + change: onChange + } } }); const item4 = wrapper.findAll('.van-rate__item').at(3); item4.trigger('click'); - expect(wrapper.emitted('change')).toBeFalsy(); + expect(onInput.mock.calls[0][0]).toEqual(4); + expect(onChange.mock.calls[0][0]).toEqual(4); +}); + +test('disabled', () => { + const onInput = jest.fn(); + const onChange = jest.fn(); + + const wrapper = mount(Rate, { + propsData: { + disabled: true + }, + context: { + on: { + input: onInput, + change: onChange + } + } + }); + const item4 = wrapper.findAll('.van-rate__item').at(3); - wrapper.vm.disabled = false; item4.trigger('click'); - expect(wrapper.emitted('input')[0][0]).toEqual(4); - expect(wrapper.emitted('change')[0][0]).toEqual(4); + expect(onInput.mock.calls.length).toEqual(0); + expect(onChange.mock.calls.length).toEqual(0); }); test('touchmove', () => { - const wrapper = mount(Rate); + const onChange = jest.fn(); + const wrapper = mount(Rate, { + context: { + on: { + change: onChange + } + } + }); triggerDrag(wrapper, 100, 0); const icons = wrapper.findAll('.van-icon'); @@ -29,6 +60,7 @@ test('touchmove', () => { return icons.at(index).element; } }; + triggerDrag(wrapper, 100, 0); - expect(wrapper.emitted('change')).toEqual([[2], [3], [4]]); + expect(onChange.mock.calls).toEqual([[2], [3], [4]]); });