"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;

function _tslib() {
  const data = require("tslib");

  _tslib = function () {
    return data;
  };

  return data;
}

function _jsxRuntime() {
  const data = require("react/jsx-runtime");

  _jsxRuntime = function () {
    return data;
  };

  return data;
}

function _react() {
  const data = _interopRequireWildcard(require("react"));

  _react = function () {
    return data;
  };

  return data;
}

function _icons() {
  const data = require("@react-vant/icons");

  _icons = function () {
    return data;
  };

  return data;
}

function _clsx() {
  const data = _interopRequireDefault(require("clsx"));

  _clsx = function () {
    return data;
  };

  return data;
}

var _utils = require("../utils");

var _useRefs = _interopRequireDefault(require("../hooks/use-refs"));

var _useMergedState = _interopRequireDefault(require("../hooks/use-merged-state"));

var _ConfigProviderContext = _interopRequireDefault(require("../config-provider/ConfigProviderContext"));

var _useEventListener = _interopRequireDefault(require("../hooks/use-event-listener"));

var _hooks = require("../hooks");

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }

function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }

/* eslint-disable no-nested-ternary */
function getRateStatus(value, index, allowHalf, readonly) {
  if (value >= index) {
    return {
      status: 'full',
      value: 1
    };
  }

  if (value + 0.5 >= index && allowHalf && !readonly) {
    return {
      status: 'half',
      value: 0.5
    };
  }

  if (value + 1 >= index && allowHalf && readonly) {
    const cardinal = Math.pow(10, 10);
    return {
      status: 'half',
      value: Math.round((value - index + 1) * cardinal) / cardinal
    };
  }

  return {
    status: 'void',
    value: 0
  };
}

const Rate = _a => {
  var {
    count,
    touchable,
    onChange
  } = _a,
      props = (0, _tslib().__rest)(_a, ["count", "touchable", "onChange"]);
  const {
    prefixCls,
    createNamespace
  } = (0, _react().useContext)(_ConfigProviderContext.default);
  const [bem] = createNamespace('rate', prefixCls);
  const [value, setValue] = (0, _useMergedState.default)({
    value: props.value,
    defaultValue: props.defaultValue
  });
  const root = (0, _react().useRef)(null);
  const touch = (0, _hooks.useTouch)();
  const [itemRefs, setItemRefs] = (0, _useRefs.default)();

  const untouchable = () => props.readonly || props.disabled || !touchable;

  const list = (0, _react().useMemo)(() => Array(count).fill('').map((_, i) => getRateStatus(value, i + 1, props.allowHalf, props.readonly)), [count, value, props.allowHalf, props.readonly]);
  const ranges = (0, _react().useRef)();

  const updateRanges = () => {
    const rects = itemRefs.map(item => item.getBoundingClientRect());
    ranges.current = [];
    rects.forEach((rect, index) => {
      if (props.allowHalf) {
        ranges.current.push({
          score: index + 0.5,
          left: rect.left
        }, {
          score: index + 1,
          left: rect.left + rect.width / 2
        });
      } else {
        ranges.current.push({
          score: index + 1,
          left: rect.left
        });
      }
    });
  };

  const getScoreByPosition = x => {
    // eslint-disable-next-line no-plusplus
    for (let i = ranges.current.length - 1; i > 0; i--) {
      if (x > ranges.current[i].left) {
        return ranges.current[i].score;
      }
    }

    return props.allowHalf ? 0.5 : 1;
  };

  const select = index => {
    if (!props.disabled && !props.readonly && index !== value) {
      setValue(index);
      onChange === null || onChange === void 0 ? void 0 : onChange(index);
    }
  };

  const onTouchStart = event => {
    if (untouchable()) {
      return;
    }

    touch.start(event.nativeEvent);
    updateRanges();
  };

  const onTouchMove = event => {
    if (untouchable()) {
      return;
    }

    touch.move(event);

    if (touch.isHorizontal()) {
      const {
        clientX
      } = event.touches[0];
      (0, _utils.preventDefault)(event);
      select(getScoreByPosition(clientX));
    }
  };

  const renderStar = (item, index) => {
    const {
      icon,
      size,
      color,
      gutter,
      voidIcon,
      disabled,
      voidColor,
      allowHalf,
      disabledColor
    } = props;
    const score = index + 1;
    const isFull = item.status === 'full';
    const isVoid = item.status === 'void';
    const renderHalf = allowHalf && item.value > 0 && item.value < 1;
    let style;

    if (gutter && score !== +count) {
      style = {
        paddingRight: (0, _utils.addUnit)(gutter)
      };
    }

    const onClickItem = event => {
      updateRanges();
      select(allowHalf ? getScoreByPosition(event.clientX) : score);
    };

    return (0, _jsxRuntime().jsxs)("div", Object.assign({
      ref: setItemRefs(index),
      role: "radio",
      style: style,
      className: (0, _clsx().default)(bem('item')),
      tabIndex: 0,
      "aria-setsize": parseInt(count === null || count === void 0 ? void 0 : count.toString(), 10),
      "aria-posinset": score,
      "aria-checked": !isVoid,
      onClick: onClickItem
    }, {
      children: [_react().default.cloneElement(isFull ? icon : voidIcon, {
        className: (0, _clsx().default)(bem('icon', {
          disabled,
          full: isFull
        })),
        style: {
          color: disabled ? disabledColor : isFull ? color : voidColor,
          fontSize: size
        }
      }), renderHalf && (0, _jsxRuntime().jsx)("div", Object.assign({
        className: (0, _clsx().default)(bem('icon', ['half'])),
        style: {
          width: `${item.value}em`
        }
      }, {
        children: _react().default.cloneElement(isVoid ? voidIcon : icon, {
          className: (0, _clsx().default)(bem('icon', [{
            disabled,
            full: !isVoid
          }])),
          style: {
            color: disabled ? disabledColor : isVoid ? voidColor : color,
            fontSize: size
          }
        })
      }))]
    }), index);
  };

  (0, _useEventListener.default)('touchmove', onTouchMove, {
    target: root.current,
    depends: [touch.deltaY.current]
  });
  return (0, _jsxRuntime().jsx)("div", Object.assign({
    ref: root,
    role: "radiogroup",
    className: (0, _clsx().default)(bem({
      readonly: props.readonly,
      disabled: props.disabled
    })),
    tabIndex: 0,
    onTouchStart: onTouchStart
  }, {
    children: list.map(renderStar)
  }));
};

Rate.defaultProps = {
  size: 20,
  count: 5,
  gutter: 4,
  icon: (0, _jsxRuntime().jsx)(_icons().Star, {}),
  voidIcon: (0, _jsxRuntime().jsx)(_icons().StarO, {}),
  touchable: true
};
var _default = Rate;
exports.default = _default;