"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.masonryProps = exports.default = void 0;
var _vue = require("vue");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
require("../grid");
var _MasonryItem = _interopRequireDefault(require("./MasonryItem"));
var _responsiveObserve = require("../_util/responsiveObserve");
var _useConfigInject = _interopRequireDefault(require("../config-provider/hooks/useConfigInject"));
var _useBreakpoint = _interopRequireDefault(require("../_util/hooks/useBreakpoint"));
var _useGutter = _interopRequireDefault(require("./hooks/useGutter"));
var _useDelay = _interopRequireDefault(require("./hooks/useDelay"));
var _usePositions = _interopRequireDefault(require("./hooks/usePositions"));
var _useRefs = _interopRequireDefault(require("./hooks/useRefs"));
var _isEqual = _interopRequireDefault(require("../vc-util/isEqual"));
var _vcResizeObserver = _interopRequireDefault(require("../vc-resize-observer"));
var _transition = require("../_util/transition");
var _style = _interopRequireDefault(require("./style"));
const masonryProps = () => ({
  prefixCls: String,
  className: String,
  rootClassName: String,
  style: Object,
  gutter: {
    type: [Number, Object, Array],
    default: undefined
  },
  items: Array,
  itemRender: Function,
  /** Number of columns in the masonry grid layout */
  columns: {
    type: [Number, Object],
    default: undefined
  },
  /** Trigger when item layout order changed */
  onLayoutChange: Function,
  fresh: Boolean
});
exports.masonryProps = masonryProps;
const Masonry = (0, _vue.defineComponent)({
  name: 'AMasonry',
  props: masonryProps(),
  slots: Object,
  setup(props, {
    slots
  }) {
    const {
      prefixCls,
      direction
    } = (0, _useConfigInject.default)('masonry', props);
    const containerRef = (0, _vue.ref)();
    const {
      getRef,
      setRef
    } = (0, _useRefs.default)();
    const [wrapSSR, hashId] = (0, _style.default)(prefixCls);
    // ======================= Item =======================
    const mergedItems = (0, _vue.ref)([]);
    (0, _vue.watchEffect)(() => {
      mergedItems.value = props.items;
    });
    // ==================== Breakpoint ====================
    const screens = (0, _useBreakpoint.default)();
    const gutters = (0, _useGutter.default)((0, _vue.toRef)(props, 'gutter'), screens);
    // ====================== Layout ======================
    const columnCount = (0, _vue.computed)(() => {
      var _a;
      const {
        columns
      } = props;
      if (!columns) {
        return 3;
      }
      if (typeof columns === 'number') {
        return columns;
      }
      const matchingBreakpoint = _responsiveObserve.responsiveArray.find(breakpoint => screens.value[breakpoint] && columns[breakpoint] !== undefined);
      if (matchingBreakpoint) {
        return columns[matchingBreakpoint];
      }
      return (_a = columns === null || columns === void 0 ? void 0 : columns.xs) !== null && _a !== void 0 ? _a : 1;
    });
    // ================== Items Position ==================
    const itemHeights = (0, _vue.ref)();
    const collectItemSize = (0, _useDelay.default)(() => {
      const nextItemsHeight = mergedItems.value.map((item, index) => {
        var _a;
        const itemKey = (_a = item.key) !== null && _a !== void 0 ? _a : index;
        const itemEle = getRef(itemKey);
        const rect = itemEle === null || itemEle === void 0 ? void 0 : itemEle.getBoundingClientRect();
        return [itemKey, rect ? rect.height : 0, item.column];
      });
      itemHeights.value = (0, _isEqual.default)(itemHeights.value, nextItemsHeight) ? itemHeights.value : nextItemsHeight;
    });
    const verticalGutter = (0, _vue.computed)(() => {
      const [horizontalGutter = 0, verticalGutter = horizontalGutter] = gutters.value;
      return verticalGutter;
    });
    const horizontalGutter = (0, _vue.computed)(() => {
      const [horizontalGutter = 0] = gutters.value;
      return horizontalGutter;
    });
    const positions = (0, _usePositions.default)(itemHeights, columnCount, verticalGutter);
    const itemWithPositions = (0, _vue.computed)(() => mergedItems.value.map((item, index) => {
      var _a;
      const key = (_a = item.key) !== null && _a !== void 0 ? _a : index;
      return {
        item,
        itemIndex: index,
        itemKey: key,
        key,
        position: positions.value[0].get(key)
      };
    }));
    (0, _vue.watch)([mergedItems, columnCount], () => {
      collectItemSize();
    }, {
      immediate: true
    });
    const itemColumns = (0, _vue.ref)();
    function handleImgLoadOrError(e) {
      const img = e.target;
      // tips: only trigger once
      img.removeEventListener('load', handleImgLoadOrError);
      img.removeEventListener('error', handleImgLoadOrError);
      collectItemSize();
    }
    (0, _vue.onMounted)(() => {
      const images = containerRef.value.querySelectorAll('img');
      images.forEach(img => {
        img.addEventListener('load', handleImgLoadOrError);
        img.addEventListener('error', handleImgLoadOrError);
      });
    });
    (0, _vue.watch)(() => itemWithPositions.value, nextItemWithPositions => {
      if (props.onLayoutChange && nextItemWithPositions.every(({
        position
      }) => position)) {
        const nextItemColumns = nextItemWithPositions.map(({
          item,
          position
        }) => [item, position.column]);
        itemColumns.value = (0, _isEqual.default)(itemColumns.value, nextItemColumns) ? itemColumns.value : nextItemColumns;
      }
    }, {
      flush: 'post',
      immediate: true
    });
    (0, _vue.watch)(() => itemColumns.value, nextItemColumns => {
      const {
        onLayoutChange,
        items
      } = props;
      if (onLayoutChange && items && items.length === nextItemColumns.length) {
        onLayoutChange(nextItemColumns.map(([item, column]) => (0, _extends2.default)((0, _extends2.default)({}, item), {
          column
        })));
      }
    }, {
      flush: 'post',
      immediate: true
    });
    // ====================== Render ======================
    const transitionProps = (0, _transition.getTransitionGroupProps)(`${prefixCls.value}-item-fade`);
    return () => {
      const {
        rootClassName,
        className,
        itemRender = slots.itemRender,
        style = {}
      } = props;
      return wrapSSR((0, _vue.createVNode)(_vcResizeObserver.default, {
        "onResize": collectItemSize
      }, {
        default: () => [(0, _vue.createVNode)("div", {
          "ref": containerRef,
          "class": [prefixCls.value, rootClassName, className, hashId.value, {
            [`${prefixCls.value}-rtl`]: direction.value === 'rtl'
          }],
          "style": (0, _extends2.default)({
            height: `${positions.value[1]}px`
          }, style)
        }, [(0, _vue.createVNode)(_vue.TransitionGroup, transitionProps, {
          default: () => [itemWithPositions.value.map(({
            position,
            itemIndex,
            key,
            item
          }) => {
            const {
              column: columnIndex = 0,
              top
            } = position || {};
            const itemStyle = {
              '--item-width': `calc((100% + ${horizontalGutter.value}px) / ${columnCount.value})`,
              insetInlineStart: `calc(var(--item-width) * ${columnIndex})`,
              width: `calc(var(--item-width) - ${horizontalGutter.value}px)`,
              top: `${top}px`,
              position: 'absolute'
            };
            return (0, _vue.createVNode)(_MasonryItem.default, {
              "prefixCls": prefixCls.value,
              "key": key,
              "item": item,
              "style": itemStyle,
              "ref": el => setRef(item.key, el === null || el === void 0 ? void 0 : el.itemRef),
              "index": itemIndex,
              "itemRender": itemRender,
              "column": columnIndex,
              "onResize": props.fresh ? collectItemSize : null
            }, null);
          })]
        })])]
      }));
    };
  }
});
var _default = exports.default = Masonry;