"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.Affix = void 0;
const React = __importStar(require("react"));
const react_dom_1 = require("react-dom");
var AFFIX_STATE;
(function (AFFIX_STATE) {
    AFFIX_STATE["TOP"] = "TOP";
    AFFIX_STATE["AFFIXED"] = "AFFIXED";
    AFFIX_STATE["BOTTOM"] = "BOTTOM";
})(AFFIX_STATE || (AFFIX_STATE = {}));
// const TOP = "TOP", AFFIXED = "AFFIXED", BOTTOM = "BOTTOM";
class Affix extends React.Component {
    constructor(props) {
        super(props);
        this.containerRef = React.createRef();
        this.wrapperRef = React.createRef();
        this.positionerRef = React.createRef();
        this.getState = (props) => {
            var _a;
            const { topOffset = 0, bottomOffset = 0, containerRef } = props;
            const container = (0, react_dom_1.findDOMNode)((containerRef || this.containerRef).current);
            const wrapperElem = (0, react_dom_1.findDOMNode)(this.wrapperRef.current);
            if (!container || !document.body.contains(container) || !wrapperElem) {
                return {};
            }
            const containerTop = container.getBoundingClientRect().top;
            const containerHeight = container.offsetHeight;
            const containerVisibleHeight = containerHeight + containerTop;
            const wrapperHeight = wrapperElem.offsetHeight;
            const wrapperScrollHeight = wrapperElem.scrollHeight;
            const scrolled = this.containerRef.current.getBoundingClientRect().top < topOffset;
            const viewportHeight = Math.max(document.documentElement.clientHeight, window.innerHeight || 0);
            const bottomDist = viewportHeight - container.getBoundingClientRect().top - containerHeight;
            const bottomInvisibleHeight = Math.min(bottomDist, 0);
            let affixState = AFFIX_STATE.TOP;
            if (scrolled && containerVisibleHeight < wrapperScrollHeight + topOffset)
                affixState = AFFIX_STATE.BOTTOM;
            else if (scrolled)
                affixState = AFFIX_STATE.AFFIXED;
            const width = wrapperElem ? wrapperElem.offsetWidth : undefined;
            const top = topOffset;
            const affixHeight = affixState === AFFIX_STATE.BOTTOM
                ? Math.max(containerVisibleHeight
                    - topOffset
                    + Math.min(bottomInvisibleHeight, 0)
                    - (bottomDist < bottomOffset ? Math.min(bottomOffset - bottomDist, bottomOffset) : 0), 0)
                : undefined;
            const wrapperCutHeight = wrapperHeight - (affixHeight || 0);
            let change = undefined;
            if (affixState === AFFIX_STATE.BOTTOM) {
                if (!this.state) {
                    change = wrapperCutHeight;
                }
                else {
                    if (this.state.affixState === AFFIX_STATE.BOTTOM) {
                        const lastChange = (_a = this.state.change) !== null && _a !== void 0 ? _a : 0;
                        const changeNow = wrapperCutHeight;
                        change = lastChange + changeNow;
                    }
                    else {
                        change = wrapperCutHeight;
                    }
                }
            }
            const fixerHeight = affixState === AFFIX_STATE.AFFIXED
                ? wrapperHeight - (affixHeight || 0)
                : affixState === AFFIX_STATE.BOTTOM
                    ? (affixHeight !== null && affixHeight !== void 0 ? affixHeight : 0) + (change !== null && change !== void 0 ? change : 0)
                    : 0;
            return { affixState, width, top, affixHeight, fixerHeight, change };
        };
        this._onScroll = () => {
            this.setState(this.getState(this.props));
        };
        this.onScroll = () => {
            requestAnimationFrame(this._onScroll);
        };
        this._onResize = () => {
            const positioner = (0, react_dom_1.findDOMNode)(this.positionerRef.current);
            const width = positioner.getBoundingClientRect().width;
            const nextState = { width };
            const currentState = this.getState(this.props);
            if (currentState.affixState !== AFFIX_STATE.TOP) {
                nextState.top = currentState.top;
            }
            this.setState(nextState);
        };
        this.onResize = () => {
            requestAnimationFrame(this._onResize);
        };
        this.state = this.getState(props);
    }
    componentDidMount() {
        window.addEventListener("scroll", this.onScroll);
        window.addEventListener("resize", this.onResize);
    }
    componentWillUnmount() {
        window.removeEventListener("scroll", this.onScroll);
        window.removeEventListener("resize", this.onResize);
    }
    componentDidUpdate(prevProps, prevState) {
        if (!this.props.onAffixChange || !prevState || !this.state) {
            return;
        }
        if (prevState.affixState !== AFFIX_STATE.AFFIXED && this.state.affixState === AFFIX_STATE.AFFIXED) {
            this.props.onAffixChange(true);
        }
        else if (prevState.affixState === AFFIX_STATE.AFFIXED && this.state.affixState !== AFFIX_STATE.AFFIXED) {
            this.props.onAffixChange(false);
        }
    }
    render() {
        const { children, style: containerStyle } = this.props;
        const { top, width, affixState, affixHeight, fixerHeight } = this.state || {};
        const style = {};
        const fixerStyle = { position: "relative", zIndex: -1, height: fixerHeight };
        style.position = "relative";
        if (affixState === AFFIX_STATE.BOTTOM || affixState === AFFIX_STATE.AFFIXED) {
            style.position = "fixed";
            style.width = width;
            style.top = top;
            style.zIndex = 1000;
            style.height = affixHeight;
            if (affixState === AFFIX_STATE.BOTTOM) {
                style.overflow = "hidden";
            }
        }
        return (React.createElement("div", { style: containerStyle, ref: this.containerRef },
            React.createElement("div", { ref: this.positionerRef }),
            React.createElement("div", { ref: this.wrapperRef, style: style, className: this.props.className }, children),
            React.createElement("div", { style: fixerStyle })));
    }
}
exports.Affix = Affix;
