"use strict";

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

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 _clsx() {
  const data = _interopRequireDefault(require("clsx"));

  _clsx = function () {
    return data;
  };

  return data;
}

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

var _FloatingBallContext = _interopRequireDefault(require("./FloatingBallContext"));

var _useClickAway = _interopRequireDefault(require("../hooks/use-click-away"));

var _FloatingBallItem = _interopRequireDefault(require("./FloatingBallItem"));

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

var _throttle = require("../utils/throttle");

var _useFloatingTouch = _interopRequireDefault(require("./useFloatingTouch"));

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

var _raf = require("../utils/raf");

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; }

const TOUCH_DURATION = 0;
const TRANSITION_DURATION = 300;
const DEFAULT_ADSORB = {
  indent: 0.5,
  distance: 0
};
const FloatingBall = (0, _react().forwardRef)((props, ref) => {
  var _a, _b, _c, _d;

  const {
    prefixCls,
    createNamespace
  } = (0, _react().useContext)(_ConfigProviderContext.default);
  const [bem] = createNamespace('floating-ball', prefixCls);

  const timer = _react().default.useRef(null);

  const [position, setPosition] = (0, _react().useState)('bottom right');

  const [container, setContainer] = _react().default.useState();

  const touch = (0, _useFloatingTouch.default)({
    target: container,
    offset: props.offset
  });
  const [active, updateActive] = (0, _useMergedState.default)({
    value: (_a = props.menu) === null || _a === void 0 ? void 0 : _a.active,
    defaultValue: (_b = props.menu) === null || _b === void 0 ? void 0 : _b.defaultActive
  });
  const [state, updateState] = (0, _hooks.useSetState)({
    indenting: false,
    duration: TOUCH_DURATION
  }); // 是否处于滚动缩进中

  const isIndenting = state.indenting; // 是否可拖动

  const isDraggable = event => props.draggable && event.touches.length === 1 && container && !props.disabled; // 吸附属性


  const adsorb = _react().default.useMemo(() => {
    if (typeof props.adsorb === 'boolean') {
      if (!props.adsorb) return false;
      return DEFAULT_ADSORB;
    }

    return Object.assign(Object.assign({}, DEFAULT_ADSORB), props.adsorb);
  }, [props.adsorb]);

  const validMenus = _react().default.useMemo(() => {
    var _a, _b;

    return (props === null || props === void 0 ? void 0 : props.menu.items) && Array.isArray((_a = props.menu) === null || _a === void 0 ? void 0 : _a.items) ? (_b = props.menu) === null || _b === void 0 ? void 0 : _b.items.filter(Boolean).filter((_, i) => i < 5) : [];
  }, [(_c = props.menu) === null || _c === void 0 ? void 0 : _c.items]); // 处理菜单


  const renderMenus = _react().default.useCallback(() => {
    var _a, _b;

    if (!validMenus.length) return null;
    const [position1, position2] = position.split(' ');
    return (0, _jsxRuntime().jsx)("div", Object.assign({
      className: (0, _clsx().default)(bem('menu', {
        [(_a = props.menu) === null || _a === void 0 ? void 0 : _a.direction]: !!((_b = props.menu) === null || _b === void 0 ? void 0 : _b.direction),
        [position1]: !!position1,
        [position2]: !!position2
      }), `list-${Math.max(validMenus.length, 5)}`)
    }, {
      children: validMenus.map((cld, i) => (0, _jsxRuntime().jsx)(_FloatingBallItem.default, {
        children: cld
      }, i))
    })); // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [position, (_d = props.menu) === null || _d === void 0 ? void 0 : _d.direction, validMenus]); // 更新 menu 的位置


  const checkMenuPosition = () => {
    if (container) {
      const {
        rect: {
          left,
          top,
          width,
          height
        }
      } = getSideWithRect();
      const windowW = window.innerWidth;
      const windowH = window.innerHeight;

      if (left + width / 2 < windowW / 2) {
        position.indexOf('right') >= 0 && setPosition(state => state.replace('right', 'left'));
      } else if (position.indexOf('left') >= 0) {
        setPosition(state => state.replace('left', 'right'));
      }

      if (top + height / 2 < windowH / 2) {
        position.indexOf('bottom') >= 0 && setPosition(state => state.replace('bottom', 'top'));
      } else if (position.indexOf('top') >= 0) {
        setPosition(state => state.replace('top', 'bottom'));
      }
    }
  };

  const innerChange = value => {
    var _a, _b;

    updateActive(value);
    (_b = (_a = props.menu) === null || _a === void 0 ? void 0 : _a.onChange) === null || _b === void 0 ? void 0 : _b.call(_a, value);
  }; // 悬浮球点击事件


  const handleBaseClick = () => {
    // 是否禁用
    if (props.disabled || !validMenus.length) return;
    innerChange(!active);
  }; // 获取容器在屏幕的哪一侧


  const getSideWithRect = () => {
    const rect = container.getBoundingClientRect();
    const side = rect.left + rect.width / 2 > window.innerWidth / 2 ? 'right' : 'left';
    return {
      rect,
      side
    };
  }; // 近边吸附


  const checkPosition = () => {
    const {
      side,
      rect
    } = getSideWithRect();

    if (adsorb) {
      const {
        distance
      } = adsorb;
      const isRightSide = side === 'right';
      const x = isRightSide ? -distance : -(window.innerWidth - rect.width) + +distance;
      updateState({
        duration: TRANSITION_DURATION
      });
      touch.update({
        deltaX: x
      });
    }
  };

  const onTouchStart = event => {
    if (!isDraggable(event) || isIndenting) return;
    updateState({
      duration: TOUCH_DURATION
    });
    touch.start(event);
  };

  const onTouchMove = event => {
    if (!isDraggable(event) || isIndenting) return;
    touch.move(event);

    if (typeof event.cancelable !== 'boolean' || event.cancelable) {
      event.preventDefault();
    }

    if (active) innerChange(false);
  };

  const onTouchEnd = () => {
    if (isIndenting) return;
    checkPosition();
    checkMenuPosition();
  };

  (0, _hooks.useIsomorphicLayoutEffect)(() => {
    if (!active || !touch.ready) return;
    checkMenuPosition();
  }, [touch.ready]);
  (0, _hooks.useEventListener)('touchmove', onTouchMove, {
    target: container,
    depends: [container, touch.deltaX, touch.deltaY, props.disabled, props.draggable]
  }); // 点击除悬浮球之外的地方自动收回悬浮球

  (0, _useClickAway.default)(container, () => {
    innerChange(false);
  }); // 实例方法

  (0, _react().useImperativeHandle)(ref, () => ({
    open: () => {
      if (!validMenus.length) return; // viod click away mix

      (0, _raf.raf)(() => innerChange(true));
    },
    close: () => {
      if (!validMenus.length) return; // viod click away mix

      (0, _raf.raf)(() => innerChange(false));
    }
  })); // 滚动时缩进

  (0, _hooks.useIsomorphicLayoutEffect)(() => {
    if (props.disabled || !adsorb || !touch.ready) return;

    const onScroll = () => {
      const {
        side,
        rect
      } = getSideWithRect();
      const {
        indent,
        distance
      } = adsorb;
      const isRightSide = side === 'right';
      const indentPx = rect.width * (isRightSide ? +indent : 1 - +indent);
      const offsetX = isRightSide ? +indentPx : -(window.innerWidth - indentPx);
      updateState({
        indenting: true,
        duration: TRANSITION_DURATION
      });
      innerChange(false);
      touch.update({
        deltaX: offsetX
      });
      if (timer.current) clearTimeout(timer.current);
      timer.current = setTimeout(() => {
        const x = isRightSide ? -distance : -(window.innerWidth - rect.width) + +distance;
        updateState({
          indenting: false
        });
        touch.update({
          deltaX: x
        });
      }, 600);
    };

    const handle = (0, _throttle.throttle)(() => (0, _raf.raf)(onScroll), 300);
    window.addEventListener('scroll', handle);
    return () => window.removeEventListener('scroll', handle); // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [touch.ready, container, adsorb, props.disabled]);

  const indentClassName = _react().default.useMemo(() => {
    if (!adsorb) return '';
    if (state.indenting) return adsorb.indentClassName;
    return '';
  }, [adsorb, state.indenting]);

  const trackStyle = _react().default.useMemo(() => Object.assign(Object.assign({}, props.style), {
    transitionDuration: `${state.duration}ms`,
    transform: `translate3d(${touch.deltaX}px,${touch.deltaY}px, 0)`
  }), [props.style, state.duration, touch.deltaX, touch.deltaY]);

  return (0, _jsxRuntime().jsx)(_FloatingBallContext.default.Provider, Object.assign({
    value: {
      close: () => {
        var _a, _b;

        const closeable = (_b = (_a = props.menu) === null || _a === void 0 ? void 0 : _a.itemClickClose) !== null && _b !== void 0 ? _b : true;
        if (closeable) innerChange(false);
      }
    }
  }, {
    children: (0, _jsxRuntime().jsxs)("div", Object.assign({
      className: (0, _clsx().default)(props.className, indentClassName, bem({
        active
      })),
      style: trackStyle,
      ref: setContainer,
      onTouchStart: onTouchStart,
      onTouchEnd: onTouchEnd,
      onTouchCancel: onTouchEnd
    }, {
      children: [renderMenus(), (0, _jsxRuntime().jsx)("div", Object.assign({
        className: (0, _clsx().default)(bem('base', {
          [props.disabledClassName]: props.disabled
        })),
        onClick: handleBaseClick
      }, {
        children: typeof props.children === 'function' ? props.children({
          active,
          indenting: state.indenting
        }) : props.children
      }))]
    }))
  }));
});
FloatingBall.defaultProps = {
  adsorb: DEFAULT_ADSORB,
  draggable: true,
  menu: {},
  offset: {
    right: 0,
    bottom: '30vh'
  }
};
var _default = FloatingBall;
exports.default = _default;