{"version":3,"file":"rate.vue.mjs","sources":["../../../../../packages/components/rate/src/rate.vue"],"sourcesContent":["<template>\n  <div\n    :class=\"rateKls\"\n    role=\"slider\"\n    :aria-valuenow=\"currentValue\"\n    :aria-valuetext=\"text\"\n    aria-valuemin=\"0\"\n    :aria-valuemax=\"max\"\n    tabindex=\"0\"\n    @keydown=\"handleKey\"\n  >\n    <span\n      v-for=\"(item, key) in max\"\n      :key=\"key\"\n      :class=\"ns.e('item')\"\n      :style=\"{ cursor: rateDisabled ? 'auto' : 'pointer' }\"\n      @mousemove=\"setCurrentValue(item, $event)\"\n      @mouseleave=\"resetCurrentValue\"\n      @click=\"selectValue(item)\"\n    >\n      <el-icon\n        :class=\"[ns.e('icon'), { hover: hoverIndex === item }]\"\n        :style=\"getIconStyle(item)\"\n      >\n        <component\n          :is=\"iconComponents[item - 1]\"\n          v-if=\"!showDecimalIcon(item)\"\n        />\n        <el-icon\n          v-if=\"showDecimalIcon(item)\"\n          :style=\"decimalStyle\"\n          :class=\"[ns.e('icon'), ns.e('decimal')]\"\n        >\n          <component :is=\"decimalIconComponent\" />\n        </el-icon>\n      </el-icon>\n    </span>\n    <span\n      v-if=\"showText || showScore\"\n      :class=\"ns.e('text')\"\n      :style=\"{ color: textColor }\"\n    >\n      {{ text }}\n    </span>\n  </div>\n</template>\n<script lang=\"ts\">\nimport { defineComponent, inject, computed, ref, watch } from 'vue'\nimport { isObject, isArray } from '@vue/shared'\nimport { formKey } from '@element-ultra/tokens'\nimport { hasClass } from '@element-ultra/utils'\nimport { EVENT_CODE, UPDATE_MODEL_EVENT } from '@element-ultra/shared'\nimport { ElIcon } from '@element-ultra/components/icon'\nimport { StarFilled, Star } from 'icon-ultra'\nimport { useFormItem, useNamespace, useSize } from '@element-ultra/hooks'\nimport { rateProps, rateEmits } from './rate'\nimport type { FormContext } from '@element-ultra/tokens'\n\nfunction getValueFromMap<T>(\n  value: number,\n  map: Record<string, T | { excluded?: boolean; value: T }>\n) {\n  const isExcludedObject = (\n    val: unknown\n  ): val is { excluded?: boolean } & Record<any, unknown> => isObject(val)\n\n  const matchedKeys = Object.keys(map)\n    .map(key => +key)\n    .filter(key => {\n      const val = map[key]\n      const excluded = isExcludedObject(val) ? val.excluded : false\n      return excluded ? value < key : value <= key\n    })\n    .sort((a, b) => a - b)\n  const matchedValue = map[matchedKeys[0]]\n  return (isExcludedObject(matchedValue) && matchedValue.value) || matchedValue\n}\n\nexport default defineComponent({\n  name: 'ElRate',\n  components: {\n    ElIcon,\n    StarFilled,\n    Star\n  },\n  props: rateProps,\n  emits: rateEmits,\n\n  setup(props, { emit }) {\n    const rateSize = useSize({ props })\n    const ns = useNamespace('rate')\n    const { form } = useFormItem()\n\n    const currentValue = ref(props.modelValue)\n    const hoverIndex = ref(-1)\n    const pointerAtLeftHalf = ref(true)\n\n    const rateKls = computed(() => [ns.b(), ns.m(rateSize.value)])\n\n    const rateDisabled = computed(() => props.disabled || form?.props.disabled)\n    const text = computed(() => {\n      let result = ''\n      if (props.showScore) {\n        result = props.scoreTemplate.replace(\n          /\\{\\s*value\\s*\\}/,\n          rateDisabled.value ? `${props.modelValue}` : `${currentValue.value}`\n        )\n      } else if (props.showText) {\n        result = props.texts[Math.ceil(currentValue.value) - 1]\n      }\n      return result\n    })\n    const valueDecimal = computed(\n      () => props.modelValue * 100 - Math.floor(props.modelValue) * 100\n    )\n    const colorMap = computed(() =>\n      isArray(props.colors)\n        ? {\n            [props.lowThreshold]: props.colors[0],\n            [props.highThreshold]: { value: props.colors[1], excluded: true },\n            [props.max]: props.colors[2]\n          }\n        : props.colors\n    )\n    const activeColor = computed(() =>\n      getValueFromMap(currentValue.value, colorMap.value)\n    )\n    const decimalStyle = computed(() => {\n      let width = ''\n      if (rateDisabled.value) {\n        width = `${valueDecimal.value}%`\n      } else if (props.allowHalf) {\n        width = '50%'\n      }\n      return {\n        color: activeColor.value,\n        width\n      }\n    })\n    const componentMap = computed(() =>\n      isArray(props.icons)\n        ? {\n            [props.lowThreshold]: props.icons[0],\n            [props.highThreshold]: {\n              value: props.icons[1],\n              excluded: true\n            },\n            [props.max]: props.icons[2]\n          }\n        : props.icons\n    )\n    const decimalIconComponent = computed(() =>\n      getValueFromMap(props.modelValue, componentMap.value)\n    )\n    const voidComponent = computed(() =>\n      rateDisabled.value ? props.disabledvoidIcon : props.voidIcon\n    )\n    const activeComponent = computed(() =>\n      getValueFromMap(currentValue.value, componentMap.value)\n    )\n    const iconComponents = computed(() => {\n      const result = Array(props.max)\n      const threshold = currentValue.value\n      result.fill(activeComponent.value, 0, threshold)\n      result.fill(voidComponent.value, threshold, props.max)\n      return result\n    })\n\n    function showDecimalIcon(item: number) {\n      const showWhenDisabled =\n        rateDisabled.value &&\n        valueDecimal.value > 0 &&\n        item - 1 < props.modelValue &&\n        item > props.modelValue\n      const showWhenAllowHalf =\n        props.allowHalf &&\n        pointerAtLeftHalf.value &&\n        item - 0.5 <= currentValue.value &&\n        item > currentValue.value\n      return showWhenDisabled || showWhenAllowHalf\n    }\n\n    function getIconStyle(item: number) {\n      const voidColor = rateDisabled.value\n        ? props.disabledVoidColor\n        : props.voidColor\n      return {\n        color: item <= currentValue.value ? activeColor.value : voidColor\n      }\n    }\n\n    function selectValue(value: number) {\n      if (rateDisabled.value) {\n        return\n      }\n      if (props.allowHalf && pointerAtLeftHalf.value) {\n        emit(UPDATE_MODEL_EVENT, currentValue.value)\n        if (props.modelValue !== currentValue.value) {\n          emit('change', currentValue.value)\n        }\n      } else {\n        emit(UPDATE_MODEL_EVENT, value)\n        if (props.modelValue !== value) {\n          emit('change', value)\n        }\n      }\n    }\n\n    function handleKey(e: KeyboardEvent) {\n      if (rateDisabled.value) {\n        return\n      }\n      let _currentValue = currentValue.value\n      const code = e.code\n      if (code === EVENT_CODE.up || code === EVENT_CODE.right) {\n        if (props.allowHalf) {\n          _currentValue += 0.5\n        } else {\n          _currentValue += 1\n        }\n        e.stopPropagation()\n        e.preventDefault()\n      } else if (code === EVENT_CODE.left || code === EVENT_CODE.down) {\n        if (props.allowHalf) {\n          _currentValue -= 0.5\n        } else {\n          _currentValue -= 1\n        }\n        e.stopPropagation()\n        e.preventDefault()\n      }\n      _currentValue = _currentValue < 0 ? 0 : _currentValue\n      _currentValue = _currentValue > props.max ? props.max : _currentValue\n      emit(UPDATE_MODEL_EVENT, _currentValue)\n      emit('change', _currentValue)\n      return _currentValue\n    }\n\n    function setCurrentValue(value: number, event: MouseEvent) {\n      if (rateDisabled.value) {\n        return\n      }\n      if (props.allowHalf) {\n        // TODO: use cache via computed https://github.com/element-plus/element-plus/pull/5456#discussion_r786472092\n        let target = event.target as HTMLElement\n        if (hasClass(target, ns.e('item'))) {\n          target = target.querySelector(`.${ns.e('icon')}`)!\n        }\n        if (target.clientWidth === 0 || hasClass(target, ns.e('decimal'))) {\n          target = target.parentNode as HTMLElement\n        }\n        pointerAtLeftHalf.value = event.offsetX * 2 <= target.clientWidth\n        currentValue.value = pointerAtLeftHalf.value ? value - 0.5 : value\n      } else {\n        currentValue.value = value\n      }\n      hoverIndex.value = value\n    }\n\n    function resetCurrentValue() {\n      if (rateDisabled.value) {\n        return\n      }\n      if (props.allowHalf) {\n        pointerAtLeftHalf.value =\n          props.modelValue !== Math.floor(props.modelValue)\n      }\n      currentValue.value = props.modelValue\n      hoverIndex.value = -1\n    }\n\n    watch(\n      () => props.modelValue,\n      val => {\n        currentValue.value = val\n        pointerAtLeftHalf.value =\n          props.modelValue !== Math.floor(props.modelValue)\n      }\n    )\n\n    if (!props.modelValue) {\n      emit(UPDATE_MODEL_EVENT, 0)\n    }\n\n    return {\n      ns,\n      hoverIndex,\n      currentValue,\n      rateDisabled,\n      text,\n      decimalStyle,\n      decimalIconComponent,\n      iconComponents,\n      rateKls,\n\n      showDecimalIcon,\n      getIconStyle,\n      selectValue,\n      handleKey,\n      setCurrentValue,\n      resetCurrentValue\n    }\n  }\n})\n</script>\n"],"names":["_resolveComponent","_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeClass","_normalizeStyle","_withCtx","_createBlock","_resolveDynamicComponent"],"mappings":"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"}