import { __assign, __rest } from "tslib";
import React, { useCallback, useContext, useEffect, useRef, useState } from 'react';
import classNames from 'classnames';
import { ConfigContext } from '../config-provider/config-context';
import { getPrefixCls } from '../_utils/general';
import { getRect, getScroll, getNodeHeight } from '../_utils/dom';
var Sticky = function (props) {
    var offsetTop = props.offsetTop, offsetBottom = props.offsetBottom, _a = props.container, container = _a === void 0 ? function () { return window; } : _a, onChange = props.onChange, className = props.className, style = props.style, children = props.children, customisedCls = props.prefixCls, otherProps = __rest(props, ["offsetTop", "offsetBottom", "container", "onChange", "className", "style", "children", "prefixCls"]);
    var configContext = useContext(ConfigContext);
    var prefixCls = getPrefixCls('sticky', configContext.prefixCls, customisedCls);
    var cls = classNames(prefixCls, className);
    var placeholderRef = useRef(null);
    var stickyRef = useRef(null);
    var _b = useState({}), stickyStyle = _b[0], setStickyStyle = _b[1];
    var _c = useState({}), placeholderStyle = _c[0], setPlaceholderStyle = _c[1];
    var _d = useState(container()), stickyContainer = _d[0], setStickyContainer = _d[1];
    var getStickyMode = function () {
        var mode = {
            top: false,
            bottom: false,
            offset: 0,
        };
        if (typeof offsetTop !== 'number' && typeof offsetBottom !== 'number') {
            mode.top = true;
        }
        else if (typeof offsetTop === 'number') {
            mode.top = true;
            mode.bottom = false;
            mode.offset = offsetTop || 0;
        }
        else if (typeof offsetBottom === 'number') {
            mode.bottom = true;
            mode.top = false;
            mode.offset = offsetBottom || 0;
        }
        return mode;
    };
    var stickyMode = useState(getStickyMode())[0];
    var getOffset = useCallback(function (placeholderNode, stickyContainer) {
        var rect = placeholderNode.getBoundingClientRect();
        var containerRect = getRect(stickyContainer);
        var containerScrollTop = getScroll(stickyContainer, true);
        var containerScrollLeft = getScroll(stickyContainer, false);
        return {
            top: rect.top - containerRect.top + containerScrollTop,
            left: rect.left - containerRect.left + containerScrollLeft,
            width: rect.width,
            height: rect.height,
        };
    }, []);
    var updateStickyStyle = useCallback(function (stickyStyle, stuck) {
        if (stuck === void 0) { stuck = false; }
        setStickyStyle(__assign({}, stickyStyle));
        if (stuck) {
            onChange && onChange(true);
        }
        else if (!stickyStyle) {
            onChange && onChange(false);
        }
    }, [onChange]);
    var updatePlaceholderStyle = function (placeholderStyle) {
        setPlaceholderStyle(__assign({}, placeholderStyle));
    };
    var updateNodePosition = useCallback(function () {
        var placeholderNode = placeholderRef.current;
        var stickyNode = stickyRef.current;
        if (!placeholderNode || !stickyContainer || !stickyNode) {
            return;
        }
        var containerScrollTop = getScroll(stickyContainer, true);
        var placeholderOffset = getOffset(placeholderNode, stickyContainer);
        var containerHeight = getNodeHeight(stickyContainer);
        var placeholderHeight = placeholderNode.offsetHeight;
        var containerRect = getRect(stickyContainer);
        var stickyHeight = stickyNode.offsetHeight;
        var stickyStyle = {
            width: placeholderOffset.width,
        };
        var placeholderStyle = {
            width: placeholderOffset.width,
            height: stickyHeight,
        };
        if (stickyMode.top && containerScrollTop > placeholderOffset.top - stickyMode.offset) {
            stickyStyle.position = 'fixed';
            stickyStyle.top = stickyMode.offset + containerRect.top;
            updateStickyStyle(stickyStyle, true);
            updatePlaceholderStyle(placeholderStyle);
        }
        else if (stickyMode.bottom &&
            containerScrollTop <
                placeholderOffset.top + placeholderHeight + stickyMode.offset - containerHeight) {
            stickyStyle.height = placeholderHeight;
            stickyStyle.position = 'fixed';
            stickyStyle.bottom = stickyMode.offset;
            updateStickyStyle(stickyStyle, true);
            updatePlaceholderStyle(placeholderStyle);
        }
        else {
            updateStickyStyle({});
            updatePlaceholderStyle({});
        }
    }, [stickyContainer, updateStickyStyle, stickyMode, getOffset]);
    useEffect(function () {
        var stickyContainer = container();
        if (!stickyContainer) {
            return;
        }
        setStickyContainer(stickyContainer);
        stickyContainer.addEventListener('scroll', updateNodePosition);
        stickyContainer.addEventListener('resize', updateNodePosition);
        return function () {
            stickyContainer.removeEventListener('scroll', updateNodePosition);
            stickyContainer.removeEventListener('resize', updateNodePosition);
        };
    }, [updateNodePosition, container]);
    useEffect(function () {
        updateNodePosition();
    }, [updateNodePosition]);
    return (React.createElement("div", { ref: placeholderRef, style: placeholderStyle },
        React.createElement("div", __assign({}, otherProps, { className: cls, ref: stickyRef, style: __assign(__assign({}, stickyStyle), style) }), children)));
};
Sticky.displayName = 'Sticky';
export default Sticky;
//# sourceMappingURL=index.js.map