"use strict";

function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

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

var _vue = _interopRequireWildcard(require("vue"));

var _vueTypes = _interopRequireDefault(require("../_util/vue-types"));

var _classNames2 = _interopRequireDefault(require("../_util/classNames"));

var _omit = _interopRequireDefault(require("omit.js"));

var _vcResizeObserver = _interopRequireDefault(require("../vc-resize-observer"));

var _BaseMixin = _interopRequireDefault(require("../_util/BaseMixin"));

var _throttleByAnimationFrame = _interopRequireDefault(require("../_util/throttleByAnimationFrame"));

var _configProvider = require("../config-provider");

var _warning = _interopRequireDefault(require("../_util/warning"));

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

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

function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function _getRequireWildcardCache() { return cache; }; return cache; }

function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (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; }

function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }

function getDefaultTarget() {
  return typeof window !== 'undefined' ? window : null;
} // Affix


var AffixProps = {
  /**
   * 距离窗口顶部达到指定偏移量后触发
   */
  offsetTop: _vueTypes.default.number,
  offset: _vueTypes.default.number,

  /** 距离窗口底部达到指定偏移量后触发 */
  offsetBottom: _vueTypes.default.number,

  /** 固定状态改变时触发的回调函数 */
  // onChange?: (affixed?: boolean) => void;

  /** 设置 Affix 需要监听其滚动事件的元素，值为一个返回对应 DOM 元素的函数 */
  target: _vueTypes.default.func.def(getDefaultTarget),
  prefixCls: _vueTypes.default.string,
  onChange: _vueTypes.default.func,
  onTestUpdatePosition: _vueTypes.default.func
};
var AffixStatus = {
  None: 'none',
  Prepare: 'Prepare'
};
var Affix = {
  name: 'AAffix',
  props: AffixProps,
  mixins: [_BaseMixin.default],
  setup: function setup() {
    return {
      configProvider: (0, _vue.inject)('configProvider', _configProvider.ConfigConsumerProps)
    };
  },
  data: function data() {
    return {
      affixStyle: undefined,
      placeholderStyle: undefined,
      status: AffixStatus.None,
      lastAffix: false,
      prevTarget: null
    };
  },
  beforeMount: function beforeMount() {
    this.updatePosition = (0, _throttleByAnimationFrame.default)(this.updatePosition);
    this.lazyUpdatePosition = (0, _throttleByAnimationFrame.default)(this.lazyUpdatePosition);
  },
  mounted: function mounted() {
    var _this = this;

    var target = this.target;

    if (target) {
      // [Legacy] Wait for parent component ref has its value.
      // We should use target as directly element instead of function which makes element check hard.
      this.timeout = setTimeout(function () {
        (0, _utils.addObserveTarget)(target(), _this); // Mock Event object.

        _this.updatePosition();
      });
    }
  },
  updated: function updated() {
    this.measure();
  },
  watch: {
    target: function target(val) {
      var newTarget = null;

      if (val) {
        newTarget = val() || null;
      }

      if (this.prevTarget !== newTarget) {
        (0, _utils.removeObserveTarget)(this);

        if (newTarget) {
          (0, _utils.addObserveTarget)(newTarget, this); // Mock Event object.

          this.updatePosition();
        }

        this.prevTarget = newTarget;
      }
    },
    offsetTop: function offsetTop() {
      this.updatePosition();
    },
    offsetBottom: function offsetBottom() {
      this.updatePosition();
    }
  },
  beforeUnmount: function beforeUnmount() {
    clearTimeout(this.timeout);
    (0, _utils.removeObserveTarget)(this);
    this.updatePosition.cancel(); // https://github.com/ant-design/ant-design/issues/22683

    this.lazyUpdatePosition.cancel();
  },
  methods: {
    getOffsetTop: function getOffsetTop() {
      var offset = this.offset,
          offsetBottom = this.offsetBottom;
      var offsetTop = this.offsetTop;

      if (typeof offsetTop === 'undefined') {
        offsetTop = offset;
        (0, _warning.default)(typeof offset === 'undefined', 'Affix', '`offset` is deprecated. Please use `offsetTop` instead.');
      }

      if (offsetBottom === undefined && offsetTop === undefined) {
        offsetTop = 0;
      }

      return offsetTop;
    },
    getOffsetBottom: function getOffsetBottom() {
      return this.offsetBottom;
    },
    // =================== Measure ===================
    measure: function measure() {
      var status = this.status,
          lastAffix = this.lastAffix;
      var target = this.target;

      if (status !== AffixStatus.Prepare || !this.$refs.fixedNode || !this.$refs.placeholderNode || !target) {
        return;
      }

      var offsetTop = this.getOffsetTop();
      var offsetBottom = this.getOffsetBottom();
      var targetNode = target();

      if (!targetNode) {
        return;
      }

      var newState = {
        status: AffixStatus.None
      };
      var targetRect = (0, _utils.getTargetRect)(targetNode);
      var placeholderReact = (0, _utils.getTargetRect)(this.$refs.placeholderNode);
      var fixedTop = (0, _utils.getFixedTop)(placeholderReact, targetRect, offsetTop);
      var fixedBottom = (0, _utils.getFixedBottom)(placeholderReact, targetRect, offsetBottom);

      if (fixedTop !== undefined) {
        newState.affixStyle = {
          position: 'fixed',
          top: fixedTop,
          width: placeholderReact.width + 'px',
          height: placeholderReact.height + 'px'
        };
        newState.placeholderStyle = {
          width: placeholderReact.width + 'px',
          height: placeholderReact.height + 'px'
        };
      } else if (fixedBottom !== undefined) {
        newState.affixStyle = {
          position: 'fixed',
          bottom: fixedBottom,
          width: placeholderReact.width + 'px',
          height: placeholderReact.height + 'px'
        };
        newState.placeholderStyle = {
          width: placeholderReact.width + 'px',
          height: placeholderReact.height + 'px'
        };
      }

      newState.lastAffix = !!newState.affixStyle;

      if (lastAffix !== newState.lastAffix) {
        this.$emit('change', newState.lastAffix);
      }

      this.setState(newState);
    },
    // @ts-ignore TS6133
    prepareMeasure: function prepareMeasure() {
      this.setState({
        status: AffixStatus.Prepare,
        affixStyle: undefined,
        placeholderStyle: undefined
      });
      this.$forceUpdate(); // Test if `updatePosition` called

      if (process.env.NODE_ENV === 'test') {
        this.$emit('testUpdatePosition');
      }
    },
    updatePosition: function updatePosition() {
      this.prepareMeasure();
    },
    lazyUpdatePosition: function lazyUpdatePosition() {
      var target = this.target;
      var affixStyle = this.affixStyle; // Check position change before measure to make Safari smooth

      if (target && affixStyle) {
        var offsetTop = this.getOffsetTop();
        var offsetBottom = this.getOffsetBottom();
        var targetNode = target();

        if (targetNode && this.$refs.placeholderNode) {
          var targetRect = (0, _utils.getTargetRect)(targetNode);
          var placeholderReact = (0, _utils.getTargetRect)(this.$refs.placeholderNode);
          var fixedTop = (0, _utils.getFixedTop)(placeholderReact, targetRect, offsetTop);
          var fixedBottom = (0, _utils.getFixedBottom)(placeholderReact, targetRect, offsetBottom);

          if (fixedTop !== undefined && affixStyle.top === fixedTop || fixedBottom !== undefined && affixStyle.bottom === fixedBottom) {
            return;
          }
        }
      } // Directly call prepare measure since it's already throttled.


      this.prepareMeasure();
    }
  },
  render: function render() {
    var _this2 = this;

    var prefixCls = this.prefixCls,
        affixStyle = this.affixStyle,
        placeholderStyle = this.placeholderStyle,
        $slots = this.$slots,
        $props = this.$props;
    var getPrefixCls = this.configProvider.getPrefixCls;
    var className = (0, _classNames2.default)(_defineProperty({}, getPrefixCls('affix', prefixCls), affixStyle));
    var props = (0, _omit.default)($props, ['prefixCls', 'offsetTop', 'offsetBottom', 'target']);
    return _vue.createVNode(_vcResizeObserver.default, {
      "onResize": function onResize() {
        _this2.updatePosition();
      }
    }, {
      default: function _default() {
        return [_vue.createVNode("div", _vue.mergeProps(props, {
          "style": placeholderStyle,
          "ref": "placeholderNode"
        }), [_vue.createVNode("div", {
          "class": className,
          "ref": "fixedNode",
          "style": affixStyle
        }, [$slots.default && $slots.default()])])];
      }
    });
  }
};
/* istanbul ignore next */

Affix.install = function (app) {
  app.component(Affix.name, Affix);
};

var _default2 = Affix;
exports.default = _default2;