{"version":3,"file":"rate.mjs","sources":["../../../../../../packages/components/rate/src/rate.vue"],"sourcesContent":["<template>\r\n  <div\r\n    :class=\"rateKls\"\r\n    role=\"slider\"\r\n    :aria-valuenow=\"currentValue\"\r\n    aria-valuemin=\"0\"\r\n    :aria-valuemax=\"max\"\r\n    tabindex=\"0\"\r\n\r\n  >\r\n    <span\r\n      v-for=\"(item, key) in max\"\r\n      :key=\"key\"\r\n      :class=\"[ns.e('item'), ns.is('disabled', rateDisabled as boolean), ns.is('allowHalf', allowHalf as boolean)]\"\r\n      :style=\"{ cursor: rateDisabled ? 'auto' : 'pointer' }\"\r\n      @mousemove=\"setCurrentValue(item, $event)\"\r\n      @mouseleave=\"resetCurrentValue\"\r\n      @click=\"selectValue(item)\"\r\n    >\r\n      <sg-icon\r\n        :class=\"[ns.e('icon'), { hover: hoverIndex === item}]\"\r\n        :style=\"getIconStyle(item)\"\r\n      >\r\n        <component :is=\"iconComponents[item - 1]\" />\r\n        <sg-icon\r\n          v-if=\"showDecimalIcon(item)\"\r\n          :style=\"decimalStyle\"\r\n          :class=\"[ns.e('icon'), ns.e('decimal')]\"\r\n        >\r\n          <component :is=\"decimalIconComponent\" />\r\n        </sg-icon>\r\n      </sg-icon>\r\n    </span>\r\n  </div>\r\n</template>\r\n<script lang=\"ts\">\r\nimport { defineComponent, computed, ref, watch } from 'vue'\r\nimport { isObject, isArray } from '@vue/shared'\r\nimport { hasClass } from '@sgui-plus/utils/dom'\r\n\r\nimport { UPDATE_MODEL_EVENT } from '@sgui-plus/utils/constants'\r\nimport { SgIcon } from '@sgui-plus/components/icon'\r\nimport { StarOn, StarOff } from '@sgui-plus/icons-vue'\r\nimport { useNamespace, useSize } from '@sgui-plus/hooks'\r\nimport { rateProps, rateEmits } from './rate'\r\n\r\nfunction getValueFromMap<T>(\r\n  value: number,\r\n  map: Record<string, T | { excluded?: boolean; value: T }>\r\n) {\r\n  const isExcludedObject = (\r\n    val: unknown\r\n  ): val is { excluded?: boolean } & Record<any, unknown> => isObject(val)\r\n\r\n  const matchedKeys = Object.keys(map)\r\n    .map((key) => +key)\r\n    .filter((key) => {\r\n      const val = map[key]\r\n      const excluded = isExcludedObject(val) ? val.excluded : false\r\n      return excluded ? value < key : value <= key\r\n    })\r\n    .sort((a, b) => a - b)\r\n  const matchedValue = map[matchedKeys[0]]\r\n  return (isExcludedObject(matchedValue) && matchedValue.value) || matchedValue\r\n}\r\n\r\nexport default defineComponent({\r\n  name: 'SgRate',\r\n  components: {\r\n    SgIcon,\r\n    StarOn,\r\n    StarOff,\r\n  },\r\n  props: rateProps,\r\n  emits: rateEmits,\r\n\r\n  setup(props, { emit }) {\r\n    const rateSize = useSize()\r\n    const ns = useNamespace('rate')\r\n\r\n    const currentValue = ref(props.modelValue)\r\n    const hoverIndex = ref(-1)\r\n    const pointerAtLeftHalf = ref(true)\r\n\r\n    const rateKls = computed(() => [ns.b(), ns.m(rateSize.value)])\r\n\r\n    const rateDisabled = computed(() => props.disabled)\r\n    const valueDecimal = computed(\r\n      () => props.modelValue * 100 - Math.floor(props.modelValue) * 100\r\n    )\r\n    const colorMap = computed(() =>\r\n      isArray(props.colors)\r\n        ? {\r\n            [props.lowThreshold]: props.colors[0],\r\n            [props.highThreshold]: { value: props.colors[1], excluded: true },\r\n            [props.max]: props.colors[2],\r\n          }\r\n        : props.colors\r\n    )\r\n    const activeColor = computed(() =>\r\n      getValueFromMap(currentValue.value, colorMap.value)\r\n    )\r\n    const decimalStyle = computed(() => {\r\n      let width = ''\r\n      if (rateDisabled.value) {\r\n        width = `${valueDecimal.value}%`\r\n      } else if (props.allowHalf) {\r\n        width = '50%'\r\n      }\r\n      return {\r\n        color: activeColor.value,\r\n        width,\r\n      }\r\n    })\r\n    const componentMap = computed(() =>\r\n      isArray(props.icons)\r\n        ? {\r\n            [props.lowThreshold]: props.icons[0],\r\n            [props.highThreshold]: {\r\n              value: props.icons[1],\r\n              excluded: true,\r\n            },\r\n            [props.max]: props.icons[2],\r\n          }\r\n        : props.icons\r\n    )\r\n    const decimalIconComponent = computed(() =>\r\n      getValueFromMap(props.modelValue, componentMap.value)\r\n    )\r\n    const voidComponent = computed(() =>\r\n      rateDisabled.value ? 'StarOn' : 'StarOff'\r\n    )\r\n    const activeComponent = computed(() =>\r\n      getValueFromMap(currentValue.value, componentMap.value)\r\n    )\r\n    const iconComponents = computed(() => {\r\n      const result = Array(props.max)\r\n      const threshold = currentValue.value\r\n      result.fill(activeComponent.value, 0, threshold)\r\n      result.fill(voidComponent.value, threshold, props.max)\r\n      return result\r\n    })\r\n    function showDecimalIcon(item: number) {\r\n      const showWhenDisabled =\r\n        rateDisabled.value &&\r\n        valueDecimal.value > 0 &&\r\n        item - 1 < props.modelValue &&\r\n        item > props.modelValue\r\n      const showWhenAllowHalf =\r\n        props.allowHalf &&\r\n        pointerAtLeftHalf.value &&\r\n        item - 0.5 <= currentValue.value &&\r\n        item > currentValue.value\r\n      return showWhenDisabled || showWhenAllowHalf\r\n    }\r\n\r\n    function getIconStyle(item: number) {\r\n      const voidColor = rateDisabled.value\r\n        ? 'var(--sg-rate-disable-void-color)'\r\n        : 'var(--sg-rate-void-color)'\r\n      return {\r\n        color: item <= currentValue.value ? activeColor.value : voidColor,\r\n      }\r\n    }\r\n\r\n    function selectValue(value: number) {\r\n      if (rateDisabled.value) {\r\n        return\r\n      }\r\n      if (props.allowHalf && pointerAtLeftHalf.value) {\r\n        emit(UPDATE_MODEL_EVENT, currentValue.value)\r\n        if (props.modelValue !== currentValue.value) {\r\n          emit('onChange', currentValue.value)\r\n        }\r\n      } else {\r\n        emit(UPDATE_MODEL_EVENT, value)\r\n        if (props.modelValue !== value) {\r\n          emit('onChange', value)\r\n        }\r\n      }\r\n    }\r\n\r\n   \r\n\r\n    function setCurrentValue(value: number, event: MouseEvent) {\r\n      if (rateDisabled.value) {\r\n        return\r\n      }\r\n      if (props.allowHalf) {\r\n        // TODO: use cache via computed https://github.com/element-plus/element-plus/pull/5456#discussion_r786472092\r\n        let target = event.target as HTMLElement\r\n        if (hasClass(target, ns.e('item'))) {\r\n          target = target.querySelector(`.${ns.e('icon')}`)!\r\n        }\r\n        if (target.clientWidth === 0 || hasClass(target, ns.e('decimal'))) {\r\n          target = target.parentNode as HTMLElement\r\n        }\r\n        pointerAtLeftHalf.value = event.offsetX * 2 <= target.clientWidth\r\n        currentValue.value = pointerAtLeftHalf.value ? value - 0.5 : value\r\n      } else {\r\n        currentValue.value = value\r\n      }\r\n      hoverIndex.value = value\r\n    }\r\n\r\n    function resetCurrentValue() {\r\n      if (rateDisabled.value) {\r\n        return\r\n      }\r\n      if (props.allowHalf) {\r\n        pointerAtLeftHalf.value =\r\n          props.modelValue !== Math.floor(props.modelValue)\r\n      }\r\n      currentValue.value = props.modelValue\r\n      hoverIndex.value = -1\r\n    }\r\n\r\n    watch(\r\n      () => props.modelValue,\r\n      (val) => {\r\n        currentValue.value = val\r\n        pointerAtLeftHalf.value =\r\n          props.modelValue !== Math.floor(props.modelValue)\r\n      }\r\n    )\r\n\r\n    if (!props.modelValue) {\r\n      emit(UPDATE_MODEL_EVENT, 0)\r\n    }\r\n\r\n    return {\r\n      ns,\r\n      hoverIndex,\r\n      currentValue,\r\n      rateDisabled,\r\n      decimalStyle,\r\n      decimalIconComponent,\r\n      iconComponents,\r\n      rateKls,\r\n\r\n      showDecimalIcon,\r\n      getIconStyle,\r\n      selectValue,\r\n      setCurrentValue,\r\n      resetCurrentValue,\r\n    }\r\n  },\r\n})\r\n</script>\r\n"],"names":["_resolveComponent","_openBlock","_createElementBlock","_Fragment","_renderList","_normalizeClass","_normalizeStyle","_withCtx","_createBlock","_resolveDynamicComponent"],"mappings":";;;;;;;6BACEA,gBAgCM,CAAA,SAAA,CAAA,CAAA;SA9BCC,SAAQ,EAAA,EAAAC,kBAAA,CAAA,KAAA,EAAA;AAAA,IACZ,sBAAe,IAAY,CAAA,OAAA,CAAA;AAAA,IAC5B,IAAA,EAAA,QAAA;AAAA,IACC,eAAe,EAAA,IAAA,CAAA,YAAA;AAAA,IAChB,eAAY,EAAA,GAAA;AAAA,IAAA,eAAA,EAAA,IAAA,CAAA,GAAA;;;AAKD,KAAAD,SAAA,CAAA,IAAA,CAAA,EAAAC,kBAAA,CAAAC,QAAA,EAAA,IAAA,EAAAC,UAAA,CAAA,IAAA,CAAA,GAAA,EAAA,CAAA,IAAA,EAAA,GAAA,KAAA;AACH,MAAA,OAAAH,SAAA,EAAA,EAAAC,kBAAA,CAAO,MAAU,EAAA;AAAA,QACtB,GAAA;AAAA,QACA,KAAS,EAAAG,cAAA,CAAA,CAAE,IAAgB,CAAA,EAAA,CAAA,CAAA,CAAA,MAAA,CAAA,EAAA,IAAA,CAAA,EAAA,CAAM,EAAM,CAAA,UAAA,EAAA,IAAA,CAAA,YAAA,CAAA,EAAA,IAAA,CAAA,EAAA,CAAA,EAAA,CAAA,WAAA,EAAA,IAAA,CAAA,SAAA,CAAA,CAAA,CAAA;AAAA,QACvC,sBAAU,EAAE,MAAA,EAAA,IAAA,CAAA,YAAA,GAAA,MAAA,GAAA,SAAA,EAAA,CAAA;AAAA,QACZ,WAAA,EAAK,YAAE,IAAgB,CAAA,eAAA,CAAA,IAAA,EAAA,MAAA,CAAA;AAAA,QAAA,YAAA,EAAA,MAAA,CAAA,CAAA,CAAA,KAAA,MAAA,CAAA,CAAA,CAAA,GAAA,CAAA,GAAA,IAAA,KAAA,IAAA,CAAA,iBAAA,IAAA,IAAA,CAAA,iBAAA,CAAA,GAAA,IAAA,CAAA,CAAA;QAExB,OAYU,EAAA,CAAA,MAAA,KAAA,IAAA,CAAA,WAAA,CAAA,IAAA,CAAA;AAAA,OAAA,EAAA;oBAVF,kBAAE,EAAA;AAAA,UAAA,KAAA,EAAAA,cAAA,CAAA,CAAA,IAAA,CAAA,EAAA,CAAA,CAAA,CAAA,MAAA,CAAA,EAAA,EAAA,KAAA,EAAA,IAAA,CAAA,UAAA,KAAA,IAAA,EAAA,CAAA,CAAA;AAEoC,UAAA,KAAA,EAAAC,cAAA,CAAA,IAAA,CAAA,YAAA,CAAA,IAAA,CAAA,CAAA;AAAA,SAAA,EAAA;mBAEpCC,OAAgB,CAAA,MAAA;AAAA,aAAAN,SAAA,EAAA,EAAAO,WAAA,CADxBC,uBAMU,CAAA,IAAA,CAAA,cAAA,CAAA,IAAA,GAAA,CAAA,CAAA,CAAA,CAAA;AAAA,YAAA,IAAA,CAAA,eAAA,CAAA,IAAA,CAAA,IAAAR,SAAA,gBAJA,kBAAY,EAAA;AAAA,cACnB,GAAK,EAAA,CAAA;AAAA,cAAA,KAAA,EAAAK,cAAA,CAAA,IAAA,CAAA,YAAA,CAAA;AAEkC,cAAA,KAAA,EAAAD,cAAA,CAAA,CAAA,IAAA,CAAA,EAAA,CAAA,CAAA,CAAA,MAAA,CAAA,EAAA,IAAA,CAAA,EAAA,CAAA,CAAA,CAAA,SAAA,CAAA,CAAA,CAAA;AAAA,aAAA,EAAA;;;;;;;;;;;;;;;;;"}