winbox-ui-next
Version:
We Design Vue 2.0: A Vue.js 3 UI Library
154 lines (153 loc) • 5.11 kB
JavaScript
import { defineComponent, ref, computed, createVNode, mergeProps } from "vue";
import NP from "number-precision";
import IconStarFill from "../icon/icon-star-fill/index.js";
import IconFaceMehFill from "../icon/icon-face-meh-fill/index.js";
import IconFaceSmileFill from "../icon/icon-face-smile-fill/index.js";
import IconFaceFrownFill from "../icon/icon-face-frown-fill/index.js";
import { getPrefixCls } from "../_utils/global-config.js";
var _Rate = defineComponent({
name: "Rate",
props: {
count: {
type: Number,
default: 5
},
modelValue: {
type: Number,
default: void 0
},
defaultValue: {
type: Number,
default: 0
},
allowHalf: {
type: Boolean,
default: false
},
clearable: {
type: Boolean,
default: false
},
grading: {
type: Boolean,
default: false
},
readonly: {
type: Boolean,
default: false
},
disabled: {
type: Boolean,
default: false
},
onChange: {
type: [Function, Array]
},
onHoverChange: {
type: [Function, Array]
}
},
emits: [
"update:modelValue",
"change",
"hoverChange"
],
setup(props, {
emit,
slots
}) {
const prefixCls = getPrefixCls("rate");
const _value = ref(props.defaultValue);
const animation = ref(false);
const hoverIndex = ref(0);
const computedValue = computed(() => {
var _a;
return (_a = props.modelValue) != null ? _a : _value.value;
});
const disabled = computed(() => props.disabled || props.readonly);
const resetHoverIndex = () => {
if (hoverIndex.value) {
hoverIndex.value = 0;
emit("hoverChange", 0);
}
};
const handleMouseEnter = (index, isHalf) => {
const newHoverIndex = isHalf && props.allowHalf ? index + 0.5 : index + 1;
if (newHoverIndex !== hoverIndex.value) {
hoverIndex.value = newHoverIndex;
emit("hoverChange", newHoverIndex);
}
};
const handleClick = (index, isHalf) => {
const newValue = isHalf && props.allowHalf ? index + 0.5 : index + 1;
animation.value = true;
if (newValue !== computedValue.value) {
_value.value = newValue;
emit("update:modelValue", newValue);
emit("change", newValue);
} else if (props.clearable) {
_value.value = 0;
emit("update:modelValue", 0);
emit("change", 0);
}
};
const handleAnimationEnd = (index) => {
if (animation.value && index + 1 >= computedValue.value - 1) {
animation.value = false;
}
};
const renderGradingCharacter = (index, displayIndex) => {
if (index > displayIndex) {
return createVNode(IconFaceMehFill, null, null);
}
if (displayIndex <= 2) {
return createVNode(IconFaceFrownFill, null, null);
}
if (displayIndex <= 3) {
return createVNode(IconFaceMehFill, null, null);
}
return createVNode(IconFaceSmileFill, null, null);
};
const renderCharacter = (index) => {
var _a, _b;
const fixedValue = props.allowHalf ? NP.times(NP.round(NP.divide(computedValue.value, 0.5), 0), 0.5) : Math.round(computedValue.value);
const displayIndex = hoverIndex.value || fixedValue;
const displayCharacter = props.grading ? renderGradingCharacter(index, displayIndex) : (_b = (_a = slots.character) == null ? void 0 : _a.call(slots, index)) != null ? _b : createVNode(IconStarFill, null, null);
const leftProps = disabled.value ? {} : {
onMouseenter: () => handleMouseEnter(index, true),
onClick: () => handleClick(index, true)
};
const rightProps = disabled.value ? {} : {
onMouseenter: () => handleMouseEnter(index, false),
onClick: () => handleClick(index, false)
};
const style = animation.value ? {
animationDelay: `${50 * index}ms`
} : {};
const cls2 = [`${prefixCls}-character`, {
[`${prefixCls}-character-half`]: props.allowHalf && index + 0.5 === displayIndex,
[`${prefixCls}-character-full`]: index + 1 <= displayIndex,
[`${prefixCls}-character-scale`]: animation.value && index + 1 < computedValue.value
}];
return createVNode("div", {
"class": cls2,
"style": style,
"onAnimationend": () => handleAnimationEnd(index)
}, [createVNode("div", mergeProps({
"class": `${prefixCls}-character-left`
}, leftProps), [displayCharacter]), createVNode("div", mergeProps({
"class": `${prefixCls}-character-right`
}, rightProps), [displayCharacter])]);
};
const indexArray = computed(() => [...Array(props.grading ? 5 : props.count)]);
const cls = computed(() => [prefixCls, {
[`${prefixCls}-readonly`]: props.readonly,
[`${prefixCls}-disabled`]: props.disabled
}]);
return () => createVNode("div", {
"class": cls.value,
"onMouseleave": resetHoverIndex
}, [indexArray.value.map((_, index) => renderCharacter(index))]);
}
});
export { _Rate as default };