"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.gridInjectionKey = void 0;
const vue_1 = require("vue");
const vooks_1 = require("vooks");
const vueuc_1 = require("vueuc");
const seemly_1 = require("seemly");
const config_1 = require("../../config-provider/src/config");
const _mixins_1 = require("../../_mixins");
const _utils_1 = require("../../_utils");
const GridItem_1 = require("./GridItem");
const defaultCols = 24;
const gridProps = {
    responsive: {
        type: [String, Boolean],
        default: 'self'
    },
    cols: {
        type: [Number, String],
        default: defaultCols
    },
    itemResponsive: Boolean,
    collapsed: Boolean,
    // may create grid rows < collapsedRows since a item may take all the row
    collapsedRows: {
        type: Number,
        default: 1
    },
    itemStyle: [Object, String],
    xGap: {
        type: [Number, String],
        default: 0
    },
    yGap: {
        type: [Number, String],
        default: 0
    }
};
exports.gridInjectionKey = Symbol('grid');
exports.default = (0, vue_1.defineComponent)({
    name: 'Grid',
    inheritAttrs: false,
    props: gridProps,
    setup(props) {
        const { mergedClsPrefixRef, NConfigProvider } = (0, _mixins_1.useConfig)(props);
        const numRegex = /^\d+$/;
        const widthRef = (0, vue_1.ref)(undefined);
        const breakpointsRef = (0, vooks_1.useBreakpoints)((NConfigProvider === null || NConfigProvider === void 0 ? void 0 : NConfigProvider.mergedBreakpointsRef.value) || config_1.defaultBreakpoints);
        const isResponsiveRef = (0, vooks_1.useMemo)(() => {
            if (props.itemResponsive)
                return true;
            if (!numRegex.test(props.cols.toString()))
                return true;
            if (!numRegex.test(props.xGap.toString()))
                return true;
            if (!numRegex.test(props.yGap.toString()))
                return true;
            return false;
        });
        const responsiveQueryRef = (0, vue_1.computed)(() => {
            if (!isResponsiveRef.value)
                return undefined;
            return props.responsive === 'self' ? widthRef.value : breakpointsRef.value;
        });
        const responsiveColsRef = (0, vooks_1.useMemo)(() => {
            var _a;
            return ((_a = Number((0, seemly_1.parseResponsivePropValue)(props.cols.toString(), responsiveQueryRef.value))) !== null && _a !== void 0 ? _a : defaultCols);
        });
        const responsiveXGapRef = (0, vooks_1.useMemo)(() => (0, seemly_1.parseResponsivePropValue)(props.xGap.toString(), responsiveQueryRef.value));
        const responsiveYGapRef = (0, vooks_1.useMemo)(() => (0, seemly_1.parseResponsivePropValue)(props.yGap.toString(), responsiveQueryRef.value));
        const handleResize = (entry) => {
            widthRef.value = entry.contentRect.width;
        };
        const handleResizeRaf = (entry) => {
            (0, seemly_1.beforeNextFrameOnce)(handleResize, entry);
        };
        const overflowRef = (0, vue_1.ref)(false);
        const handleResizeRef = (0, vue_1.computed)(() => {
            if (props.responsive === 'self') {
                return handleResizeRaf;
            }
            return undefined;
        });
        (0, vue_1.provide)(exports.gridInjectionKey, {
            itemStyleRef: (0, vue_1.toRef)(props, 'itemStyle'),
            xGapRef: responsiveXGapRef,
            overflowRef
        });
        return {
            mergedClsPrefix: mergedClsPrefixRef,
            style: (0, vue_1.computed)(() => {
                return {
                    width: '100%',
                    display: 'grid',
                    gridTemplateColumns: `repeat(${responsiveColsRef.value}, minmax(0, 1fr))`,
                    columnGap: (0, seemly_1.pxfy)(responsiveXGapRef.value),
                    rowGap: (0, seemly_1.pxfy)(responsiveYGapRef.value)
                };
            }),
            isResponsive: isResponsiveRef,
            responsiveQuery: responsiveQueryRef,
            responsiveCols: responsiveColsRef,
            handleResize: handleResizeRef,
            overflow: overflowRef
        };
    },
    render() {
        const renderContent = () => {
            var _a, _b, _c, _d, _e, _f;
            this.overflow = false;
            // render will be called twice when mounted, I can't figure out why
            // 2 jobs will be pushed into job queues with same id, and then be flushed
            const rawChildren = (0, _utils_1.flatten)((0, _utils_1.getSlot)(this));
            const childrenAndRawSpan = [];
            const { collapsed, collapsedRows, responsiveCols, responsiveQuery } = this;
            rawChildren.forEach((child) => {
                var _a, _b, _c;
                if (((_a = child === null || child === void 0 ? void 0 : child.type) === null || _a === void 0 ? void 0 : _a.__GRID_ITEM__) !== true)
                    return;
                const clonedChild = (0, vue_1.cloneVNode)(child);
                const rawChildSpan = Number((_c = (0, seemly_1.parseResponsivePropValue)((_b = clonedChild.props) === null || _b === void 0 ? void 0 : _b.span, responsiveQuery)) !== null && _c !== void 0 ? _c : GridItem_1.defaultSpan);
                if (rawChildSpan === 0)
                    return;
                childrenAndRawSpan.push({
                    child: clonedChild,
                    rawChildSpan
                });
            });
            let suffixSpan = 0;
            const maybeSuffixNode = (_a = childrenAndRawSpan[childrenAndRawSpan.length - 1]) === null || _a === void 0 ? void 0 : _a.child;
            if (maybeSuffixNode === null || maybeSuffixNode === void 0 ? void 0 : maybeSuffixNode.props) {
                const suffixPropValue = (_b = maybeSuffixNode.props) === null || _b === void 0 ? void 0 : _b.suffix;
                if (suffixPropValue !== undefined && suffixPropValue !== false) {
                    suffixSpan = (_d = (_c = maybeSuffixNode.props) === null || _c === void 0 ? void 0 : _c.span) !== null && _d !== void 0 ? _d : GridItem_1.defaultSpan;
                    maybeSuffixNode.props.privateColStart =
                        responsiveCols + 1 - suffixSpan;
                    maybeSuffixNode.props.privateShow = true;
                }
            }
            let spanCounter = 0;
            let done = false;
            for (const { child, rawChildSpan } of childrenAndRawSpan) {
                if (done) {
                    this.overflow = true;
                }
                if (!done) {
                    const childOffset = Number((_f = (0, seemly_1.parseResponsivePropValue)((_e = child.props) === null || _e === void 0 ? void 0 : _e.offset, responsiveQuery)) !== null && _f !== void 0 ? _f : 0);
                    const childSpan = Math.min(rawChildSpan + childOffset, responsiveCols) || 1;
                    if (!child.props) {
                        child.props = {
                            privateSpan: childSpan,
                            privateOffset: childOffset
                        };
                    }
                    else {
                        child.props.privateSpan = childSpan;
                        child.props.privateOffset = childOffset;
                    }
                    if (collapsed) {
                        const remainder = spanCounter % responsiveCols;
                        if (childSpan + remainder > responsiveCols) {
                            spanCounter += responsiveCols - remainder;
                        }
                        if (childSpan + spanCounter + suffixSpan >
                            collapsedRows * responsiveCols) {
                            done = true;
                        }
                        else {
                            spanCounter += childSpan;
                        }
                    }
                }
                if (done) {
                    if (child.props) {
                        if (child.props.privateShow !== true) {
                            child.props.privateShow = false;
                        }
                    }
                    else {
                        child.props = {
                            privateShow: false
                        };
                    }
                }
            }
            return (0, vue_1.h)('div', (0, vue_1.mergeProps)({
                class: `${this.mergedClsPrefix}-grid`,
                style: this.style
            }, this.$attrs), childrenAndRawSpan.map(({ child }) => child));
        };
        return this.isResponsive && this.responsive === 'self' ? ((0, vue_1.h)(vueuc_1.VResizeObserver, { onResize: this.handleResize }, {
            default: renderContent
        })) : (renderContent());
    }
});
