ef56bd107a5daebcc91cb9a881289c8a60ceedaddfab3f7b5a6544c34864f6a12f2b11f88dc7080dec1cf792e5ac76a7ac2de4e2c5460c2a6e216f4cb7524e 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  1. import { defineComponent, inject, ref, computed, markRaw, watch, openBlock, createElementBlock, unref, normalizeClass, normalizeStyle, Fragment, renderList, createVNode, withCtx, withDirectives, createBlock, resolveDynamicComponent, vShow, toDisplayString, createCommentVNode } from 'vue';
  2. import { clamp } from 'lodash-unified';
  3. import { ElIcon } from '../../icon/index.mjs';
  4. import { rateProps, rateEmits } from './rate.mjs';
  5. import _export_sfc from '../../../_virtual/plugin-vue_export-helper.mjs';
  6. import { formContextKey, formItemContextKey } from '../../form/src/constants.mjs';
  7. import { useFormSize } from '../../form/src/hooks/use-form-common-props.mjs';
  8. import { useNamespace } from '../../../hooks/use-namespace/index.mjs';
  9. import { useFormItemInputId } from '../../form/src/hooks/use-form-item.mjs';
  10. import { isArray, isObject, isString } from '@vue/shared';
  11. import { UPDATE_MODEL_EVENT, CHANGE_EVENT } from '../../../constants/event.mjs';
  12. import { EVENT_CODE } from '../../../constants/aria.mjs';
  13. const __default__ = defineComponent({
  14. name: "ElRate"
  15. });
  16. const _sfc_main = /* @__PURE__ */ defineComponent({
  17. ...__default__,
  18. props: rateProps,
  19. emits: rateEmits,
  20. setup(__props, { expose, emit }) {
  21. const props = __props;
  22. function getValueFromMap(value, map) {
  23. const isExcludedObject = (val) => isObject(val);
  24. const matchedKeys = Object.keys(map).map((key) => +key).filter((key) => {
  25. const val = map[key];
  26. const excluded = isExcludedObject(val) ? val.excluded : false;
  27. return excluded ? value < key : value <= key;
  28. }).sort((a, b) => a - b);
  29. const matchedValue = map[matchedKeys[0]];
  30. return isExcludedObject(matchedValue) && matchedValue.value || matchedValue;
  31. }
  32. const formContext = inject(formContextKey, void 0);
  33. const formItemContext = inject(formItemContextKey, void 0);
  34. const rateSize = useFormSize();
  35. const ns = useNamespace("rate");
  36. const { inputId, isLabeledByFormItem } = useFormItemInputId(props, {
  37. formItemContext
  38. });
  39. const currentValue = ref(props.modelValue);
  40. const hoverIndex = ref(-1);
  41. const pointerAtLeftHalf = ref(true);
  42. const iconRefs = ref([]);
  43. const iconClientWidths = computed(() => iconRefs.value.map((icon) => icon.$el.clientWidth));
  44. const rateClasses = computed(() => [ns.b(), ns.m(rateSize.value)]);
  45. const rateDisabled = computed(() => props.disabled || (formContext == null ? void 0 : formContext.disabled));
  46. const rateStyles = computed(() => {
  47. return ns.cssVarBlock({
  48. "void-color": props.voidColor,
  49. "disabled-void-color": props.disabledVoidColor,
  50. "fill-color": activeColor.value
  51. });
  52. });
  53. const text = computed(() => {
  54. let result = "";
  55. if (props.showScore) {
  56. result = props.scoreTemplate.replace(/\{\s*value\s*\}/, rateDisabled.value ? `${props.modelValue}` : `${currentValue.value}`);
  57. } else if (props.showText) {
  58. result = props.texts[Math.ceil(currentValue.value) - 1];
  59. }
  60. return result;
  61. });
  62. const valueDecimal = computed(() => props.modelValue * 100 - Math.floor(props.modelValue) * 100);
  63. const colorMap = computed(() => isArray(props.colors) ? {
  64. [props.lowThreshold]: props.colors[0],
  65. [props.highThreshold]: { value: props.colors[1], excluded: true },
  66. [props.max]: props.colors[2]
  67. } : props.colors);
  68. const activeColor = computed(() => {
  69. const color = getValueFromMap(currentValue.value, colorMap.value);
  70. return isObject(color) ? "" : color;
  71. });
  72. const decimalStyle = computed(() => {
  73. let width = "";
  74. if (rateDisabled.value) {
  75. width = `${valueDecimal.value}%`;
  76. } else if (props.allowHalf) {
  77. width = "50%";
  78. }
  79. return {
  80. color: activeColor.value,
  81. width
  82. };
  83. });
  84. const componentMap = computed(() => {
  85. let icons = isArray(props.icons) ? [...props.icons] : { ...props.icons };
  86. icons = markRaw(icons);
  87. return isArray(icons) ? {
  88. [props.lowThreshold]: icons[0],
  89. [props.highThreshold]: {
  90. value: icons[1],
  91. excluded: true
  92. },
  93. [props.max]: icons[2]
  94. } : icons;
  95. });
  96. const decimalIconComponent = computed(() => getValueFromMap(props.modelValue, componentMap.value));
  97. const voidComponent = computed(() => rateDisabled.value ? isString(props.disabledVoidIcon) ? props.disabledVoidIcon : markRaw(props.disabledVoidIcon) : isString(props.voidIcon) ? props.voidIcon : markRaw(props.voidIcon));
  98. const activeComponent = computed(() => getValueFromMap(currentValue.value, componentMap.value));
  99. function showDecimalIcon(item) {
  100. const showWhenDisabled = rateDisabled.value && valueDecimal.value > 0 && item - 1 < props.modelValue && item > props.modelValue;
  101. const showWhenAllowHalf = props.allowHalf && pointerAtLeftHalf.value && item - 0.5 <= currentValue.value && item > currentValue.value;
  102. return showWhenDisabled || showWhenAllowHalf;
  103. }
  104. function emitValue(value) {
  105. if (props.clearable && value === props.modelValue) {
  106. value = 0;
  107. }
  108. emit(UPDATE_MODEL_EVENT, value);
  109. if (props.modelValue !== value) {
  110. emit(CHANGE_EVENT, value);
  111. }
  112. }
  113. function selectValue(value) {
  114. if (rateDisabled.value) {
  115. return;
  116. }
  117. if (props.allowHalf && pointerAtLeftHalf.value) {
  118. emitValue(currentValue.value);
  119. } else {
  120. emitValue(value);
  121. }
  122. }
  123. function handleKey(e) {
  124. if (rateDisabled.value) {
  125. return;
  126. }
  127. const code = e.code;
  128. const step = props.allowHalf ? 0.5 : 1;
  129. let _currentValue = currentValue.value;
  130. if (code === EVENT_CODE.up || code === EVENT_CODE.right) {
  131. _currentValue += step;
  132. } else if (code === EVENT_CODE.left || code === EVENT_CODE.down) {
  133. _currentValue -= step;
  134. }
  135. _currentValue = clamp(_currentValue, 0, props.max);
  136. if (_currentValue === currentValue.value) {
  137. return;
  138. }
  139. e.stopPropagation();
  140. e.preventDefault();
  141. emit(UPDATE_MODEL_EVENT, _currentValue);
  142. emit(CHANGE_EVENT, _currentValue);
  143. return _currentValue;
  144. }
  145. function setCurrentValue(value, event) {
  146. if (rateDisabled.value) {
  147. return;
  148. }
  149. if (props.allowHalf && event) {
  150. pointerAtLeftHalf.value = event.offsetX * 2 <= iconClientWidths.value[value - 1];
  151. currentValue.value = pointerAtLeftHalf.value ? value - 0.5 : value;
  152. } else {
  153. currentValue.value = value;
  154. }
  155. hoverIndex.value = value;
  156. }
  157. function resetCurrentValue() {
  158. if (rateDisabled.value) {
  159. return;
  160. }
  161. if (props.allowHalf) {
  162. pointerAtLeftHalf.value = props.modelValue !== Math.floor(props.modelValue);
  163. }
  164. currentValue.value = props.modelValue;
  165. hoverIndex.value = -1;
  166. }
  167. watch(() => props.modelValue, (val) => {
  168. currentValue.value = val;
  169. pointerAtLeftHalf.value = props.modelValue !== Math.floor(props.modelValue);
  170. });
  171. if (!props.modelValue) {
  172. emit(UPDATE_MODEL_EVENT, 0);
  173. }
  174. expose({
  175. setCurrentValue,
  176. resetCurrentValue
  177. });
  178. return (_ctx, _cache) => {
  179. var _a;
  180. return openBlock(), createElementBlock("div", {
  181. id: unref(inputId),
  182. class: normalizeClass([unref(rateClasses), unref(ns).is("disabled", unref(rateDisabled))]),
  183. role: "slider",
  184. "aria-label": !unref(isLabeledByFormItem) ? _ctx.ariaLabel || "rating" : void 0,
  185. "aria-labelledby": unref(isLabeledByFormItem) ? (_a = unref(formItemContext)) == null ? void 0 : _a.labelId : void 0,
  186. "aria-valuenow": currentValue.value,
  187. "aria-valuetext": unref(text) || void 0,
  188. "aria-valuemin": "0",
  189. "aria-valuemax": _ctx.max,
  190. tabindex: "0",
  191. style: normalizeStyle(unref(rateStyles)),
  192. onKeydown: handleKey
  193. }, [
  194. (openBlock(true), createElementBlock(Fragment, null, renderList(_ctx.max, (item, key) => {
  195. return openBlock(), createElementBlock("span", {
  196. key,
  197. class: normalizeClass(unref(ns).e("item")),
  198. onMousemove: ($event) => setCurrentValue(item, $event),
  199. onMouseleave: resetCurrentValue,
  200. onClick: ($event) => selectValue(item)
  201. }, [
  202. createVNode(unref(ElIcon), {
  203. ref_for: true,
  204. ref_key: "iconRefs",
  205. ref: iconRefs,
  206. class: normalizeClass([
  207. unref(ns).e("icon"),
  208. { hover: hoverIndex.value === item },
  209. unref(ns).is("active", item <= currentValue.value),
  210. unref(ns).is("focus-visible", item === Math.ceil(currentValue.value || 1))
  211. ])
  212. }, {
  213. default: withCtx(() => [
  214. withDirectives((openBlock(), createBlock(resolveDynamicComponent(unref(activeComponent)), null, null, 512)), [
  215. [vShow, !showDecimalIcon(item) && item <= currentValue.value]
  216. ]),
  217. withDirectives((openBlock(), createBlock(resolveDynamicComponent(unref(voidComponent)), null, null, 512)), [
  218. [vShow, !showDecimalIcon(item) && item > currentValue.value]
  219. ]),
  220. withDirectives((openBlock(), createBlock(resolveDynamicComponent(unref(voidComponent)), {
  221. class: normalizeClass([unref(ns).em("decimal", "box")])
  222. }, null, 8, ["class"])), [
  223. [vShow, showDecimalIcon(item)]
  224. ]),
  225. withDirectives(createVNode(unref(ElIcon), {
  226. style: normalizeStyle(unref(decimalStyle)),
  227. class: normalizeClass([unref(ns).e("icon"), unref(ns).e("decimal")])
  228. }, {
  229. default: withCtx(() => [
  230. (openBlock(), createBlock(resolveDynamicComponent(unref(decimalIconComponent))))
  231. ]),
  232. _: 2
  233. }, 1032, ["style", "class"]), [
  234. [vShow, showDecimalIcon(item)]
  235. ])
  236. ]),
  237. _: 2
  238. }, 1032, ["class"])
  239. ], 42, ["onMousemove", "onClick"]);
  240. }), 128)),
  241. _ctx.showText || _ctx.showScore ? (openBlock(), createElementBlock("span", {
  242. key: 0,
  243. class: normalizeClass(unref(ns).e("text")),
  244. style: normalizeStyle({ color: _ctx.textColor })
  245. }, toDisplayString(unref(text)), 7)) : createCommentVNode("v-if", true)
  246. ], 46, ["id", "aria-label", "aria-labelledby", "aria-valuenow", "aria-valuetext", "aria-valuemax"]);
  247. };
  248. }
  249. });
  250. var Rate = /* @__PURE__ */ _export_sfc(_sfc_main, [["__file", "rate.vue"]]);
  251. export { Rate as default };
  252. //# sourceMappingURL=rate2.mjs.map