UNPKG

7.81 kBJavaScriptView Raw
1var __defProp = Object.defineProperty;
2var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3var __getOwnPropNames = Object.getOwnPropertyNames;
4var __hasOwnProp = Object.prototype.hasOwnProperty;
5var __export = (target, all) => {
6 for (var name2 in all)
7 __defProp(target, name2, { get: all[name2], enumerable: true });
8};
9var __copyProps = (to, from, except, desc) => {
10 if (from && typeof from === "object" || typeof from === "function") {
11 for (let key of __getOwnPropNames(from))
12 if (!__hasOwnProp.call(to, key) && key !== except)
13 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14 }
15 return to;
16};
17var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18var stdin_exports = {};
19__export(stdin_exports, {
20 default: () => stdin_default,
21 rateProps: () => rateProps
22});
23module.exports = __toCommonJS(stdin_exports);
24var import_vue = require("vue");
25var import_utils = require("../utils");
26var import_use = require("@vant/use");
27var import_use_refs = require("../composables/use-refs");
28var import_use_touch = require("../composables/use-touch");
29var import_icon = require("../icon");
30const [name, bem] = (0, import_utils.createNamespace)("rate");
31function getRateStatus(value, index, allowHalf, readonly) {
32 if (value >= index) {
33 return {
34 status: "full",
35 value: 1
36 };
37 }
38 if (value + 0.5 >= index && allowHalf && !readonly) {
39 return {
40 status: "half",
41 value: 0.5
42 };
43 }
44 if (value + 1 >= index && allowHalf && readonly) {
45 const cardinal = 10 ** 10;
46 return {
47 status: "half",
48 value: Math.round((value - index + 1) * cardinal) / cardinal
49 };
50 }
51 return {
52 status: "void",
53 value: 0
54 };
55}
56const rateProps = {
57 size: import_utils.numericProp,
58 icon: (0, import_utils.makeStringProp)("star"),
59 color: String,
60 count: (0, import_utils.makeNumericProp)(5),
61 gutter: import_utils.numericProp,
62 clearable: Boolean,
63 readonly: Boolean,
64 disabled: Boolean,
65 voidIcon: (0, import_utils.makeStringProp)("star-o"),
66 allowHalf: Boolean,
67 voidColor: String,
68 touchable: import_utils.truthProp,
69 iconPrefix: String,
70 modelValue: (0, import_utils.makeNumberProp)(0),
71 disabledColor: String
72};
73var stdin_default = (0, import_vue.defineComponent)({
74 name,
75 props: rateProps,
76 emits: ["change", "update:modelValue"],
77 setup(props, {
78 emit
79 }) {
80 const touch = (0, import_use_touch.useTouch)();
81 const [itemRefs, setItemRefs] = (0, import_use_refs.useRefs)();
82 const groupRef = (0, import_vue.ref)();
83 const unselectable = (0, import_vue.computed)(() => props.readonly || props.disabled);
84 const untouchable = (0, import_vue.computed)(() => unselectable.value || !props.touchable);
85 const list = (0, import_vue.computed)(() => Array(+props.count).fill("").map((_, i) => getRateStatus(props.modelValue, i + 1, props.allowHalf, props.readonly)));
86 let ranges;
87 let groupRefRect;
88 let minRectTop = Number.MAX_SAFE_INTEGER;
89 let maxRectTop = Number.MIN_SAFE_INTEGER;
90 const updateRanges = () => {
91 groupRefRect = (0, import_use.useRect)(groupRef);
92 const rects = itemRefs.value.map(import_use.useRect);
93 ranges = [];
94 rects.forEach((rect, index) => {
95 minRectTop = Math.min(rect.top, minRectTop);
96 maxRectTop = Math.max(rect.top, maxRectTop);
97 if (props.allowHalf) {
98 ranges.push({
99 score: index + 0.5,
100 left: rect.left,
101 top: rect.top,
102 height: rect.height
103 }, {
104 score: index + 1,
105 left: rect.left + rect.width / 2,
106 top: rect.top,
107 height: rect.height
108 });
109 } else {
110 ranges.push({
111 score: index + 1,
112 left: rect.left,
113 top: rect.top,
114 height: rect.height
115 });
116 }
117 });
118 };
119 const getScoreByPosition = (x, y) => {
120 for (let i = ranges.length - 1; i > 0; i--) {
121 if (y >= groupRefRect.top && y <= groupRefRect.bottom) {
122 if (x > ranges[i].left && y >= ranges[i].top && y <= ranges[i].top + ranges[i].height) {
123 return ranges[i].score;
124 }
125 } else {
126 const curTop = y < groupRefRect.top ? minRectTop : maxRectTop;
127 if (x > ranges[i].left && ranges[i].top === curTop) {
128 return ranges[i].score;
129 }
130 }
131 }
132 return props.allowHalf ? 0.5 : 1;
133 };
134 const select = (value) => {
135 if (unselectable.value || value === props.modelValue) return;
136 emit("update:modelValue", value);
137 emit("change", value);
138 };
139 const onTouchStart = (event) => {
140 if (untouchable.value) {
141 return;
142 }
143 touch.start(event);
144 updateRanges();
145 };
146 const onTouchMove = (event) => {
147 if (untouchable.value) {
148 return;
149 }
150 touch.move(event);
151 if (touch.isHorizontal() && !touch.isTap.value) {
152 const {
153 clientX,
154 clientY
155 } = event.touches[0];
156 (0, import_utils.preventDefault)(event);
157 select(getScoreByPosition(clientX, clientY));
158 }
159 };
160 const renderStar = (item, index) => {
161 const {
162 icon,
163 size,
164 color,
165 count,
166 gutter,
167 voidIcon,
168 disabled,
169 voidColor,
170 allowHalf,
171 iconPrefix,
172 disabledColor
173 } = props;
174 const score = index + 1;
175 const isFull = item.status === "full";
176 const isVoid = item.status === "void";
177 const renderHalf = allowHalf && item.value > 0 && item.value < 1;
178 let style;
179 if (gutter && score !== +count) {
180 style = {
181 paddingRight: (0, import_utils.addUnit)(gutter)
182 };
183 }
184 const onClickItem = (event) => {
185 updateRanges();
186 let value = allowHalf ? getScoreByPosition(event.clientX, event.clientY) : score;
187 if (props.clearable && touch.isTap.value && value === props.modelValue) {
188 value = 0;
189 }
190 select(value);
191 };
192 return (0, import_vue.createVNode)("div", {
193 "key": index,
194 "ref": setItemRefs(index),
195 "role": "radio",
196 "style": style,
197 "class": bem("item"),
198 "tabindex": disabled ? void 0 : 0,
199 "aria-setsize": count,
200 "aria-posinset": score,
201 "aria-checked": !isVoid,
202 "onClick": onClickItem
203 }, [(0, import_vue.createVNode)(import_icon.Icon, {
204 "size": size,
205 "name": isFull ? icon : voidIcon,
206 "class": bem("icon", {
207 disabled,
208 full: isFull
209 }),
210 "color": disabled ? disabledColor : isFull ? color : voidColor,
211 "classPrefix": iconPrefix
212 }, null), renderHalf && (0, import_vue.createVNode)(import_icon.Icon, {
213 "size": size,
214 "style": {
215 width: item.value + "em"
216 },
217 "name": isVoid ? voidIcon : icon,
218 "class": bem("icon", ["half", {
219 disabled,
220 full: !isVoid
221 }]),
222 "color": disabled ? disabledColor : isVoid ? voidColor : color,
223 "classPrefix": iconPrefix
224 }, null)]);
225 };
226 (0, import_use.useCustomFieldValue)(() => props.modelValue);
227 (0, import_use.useEventListener)("touchmove", onTouchMove, {
228 target: groupRef
229 });
230 return () => (0, import_vue.createVNode)("div", {
231 "ref": groupRef,
232 "role": "radiogroup",
233 "class": bem({
234 readonly: props.readonly,
235 disabled: props.disabled
236 }),
237 "tabindex": props.disabled ? void 0 : 0,
238 "aria-disabled": props.disabled,
239 "aria-readonly": props.readonly,
240 "onTouchstartPassive": onTouchStart
241 }, [list.value.map(renderStar)]);
242 }
243});