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]]);
});