"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UISplitter = exports.UISplitterLayoutType = exports.UISplitterType = void 0;
const react_1 = __importDefault(require("react"));
require("./UISplitter.scss");
const Icons_1 = require("../Icons");
const UIIcon_1 = require("../UIIcon");
var UISplitterType;
(function (UISplitterType) {
    UISplitterType["Resize"] = "resize";
    UISplitterType["Toggle"] = "toggle";
})(UISplitterType || (exports.UISplitterType = UISplitterType = {}));
var UISplitterLayoutType;
(function (UISplitterLayoutType) {
    UISplitterLayoutType["Standard"] = "standard";
    UISplitterLayoutType["Compact"] = "compact";
})(UISplitterLayoutType || (exports.UISplitterLayoutType = UISplitterLayoutType = {}));
/**
 *
 */
class UISplitter extends react_1.default.Component {
    /**
     *
     * @param props
     */
    constructor(props) {
        super(props);
        this.mousedownPosition = {
            x: 0,
            y: 0
        };
        this.size = 14;
        this.compactSize = 8;
        this.rootRef = react_1.default.createRef();
        this.stopMousemoveResize = this.stopMousemoveResize.bind(this);
        this.doMousemoveResize = this.doMousemoveResize.bind(this);
        // Splitter overlay DOM for block dom during resize
        this.splitterOverlay = document.createElement('div');
        this.splitterOverlay.setAttribute('class', `splitter__overlay ${props.vertical ? 'splitter__overlay--vertical' : 'splitter__overlay--horizontal'}`);
    }
    /**
     * Method called on mousedown over splitter.
     * Method would start resize session.
     *
     * @param {React.MouseEvent} event Mouse.
     */
    startSplitterMove(event) {
        this.mousedownPosition.x = event.clientX;
        this.mousedownPosition.y = event.clientY;
        // Update DOM
        this.updateSplitterEvents(true);
        // Stop event bubbling
        event.stopPropagation();
    }
    /**
     * Method called when resize session is in progress and user moves mouse.
     *
     * @param {React.MouseEvent} event Mouse event.
     */
    doMousemoveResize(event) {
        const propertyName = this.props.vertical ? 'clientY' : 'clientX';
        const coordinateNameName = this.props.vertical ? 'y' : 'x';
        const newPosition = event[propertyName] - this.mousedownPosition[coordinateNameName];
        this.doResize(newPosition);
    }
    /**
     * Method which receives new delta position of splitter and updates DOM with calling callback.
     *
     * @param {number} deltaPosition Delta position of splitter.
     */
    doResize(deltaPosition) {
        const cssPropertyName = this.props.vertical ? 'top' : 'left';
        if (this.animationFrame) {
            window.cancelAnimationFrame(this.animationFrame);
        }
        this.animationFrame = window.requestAnimationFrame(() => {
            // Call callback
            if (this.props.onResize(deltaPosition)) {
                // Update resizer DOM
                const dom = this.rootRef.current;
                if (dom) {
                    dom.style[cssPropertyName] = `${deltaPosition - this.size / 2}px`;
                }
            }
        });
    }
    /**
     * Method called on mouseup or mouseleave events.
     * Method would end resize session.
     */
    stopMousemoveResize() {
        this.updateSplitterEvents(false);
    }
    /**
     * Method to update splitter DOM and events depending on if resize started or ended.
     *
     * @param {boolean} start Resize is started or ended.
     */
    updateSplitterEvents(start) {
        if (start) {
            document.body.addEventListener('mouseup', this.stopMousemoveResize);
            document.body.addEventListener('mouseleave', this.stopMousemoveResize);
            document.body.addEventListener('mousemove', this.doMousemoveResize);
            document.body.appendChild(this.splitterOverlay);
        }
        else {
            document.body.removeEventListener('mouseup', this.stopMousemoveResize);
            document.body.removeEventListener('mouseleave', this.stopMousemoveResize);
            document.body.removeEventListener('mousemove', this.doMousemoveResize);
            this.splitterOverlay.remove();
        }
        if (start && this.props.onResizeStart) {
            this.props.onResizeStart();
        }
        else if (!start && this.props.onResizeEnd) {
            this.props.onResizeEnd();
        }
    }
    /**
     * Method called when clicked over splitter and splitter type is 'Toggle'.
     */
    toggleSplitter() {
        if (this.props.onToggle) {
            this.props.onToggle();
        }
    }
    /**
     * Gets icon.
     *
     * @param type
     * @param splitterLayoutType
     * @returns {string}
     */
    getIcon(type, splitterLayoutType = UISplitterLayoutType.Standard) {
        if (type === UISplitterType.Toggle) {
            return Icons_1.UiIcons.ArrowLeft;
        }
        else if (splitterLayoutType === UISplitterLayoutType.Compact) {
            return Icons_1.UiIcons.Grabber;
        }
        else {
            return Icons_1.UiIcons.VerticalGrip;
        }
    }
    /**
     * Method called when keydown events fired while splitter is focused.
     * Method enables support for resize using keyboard.
     *
     * @param {React.KeyboardEvent<HTMLDivElement>} event KeyDown event.
     */
    onKeyDown(event) {
        if (this.props.type === UISplitterType.Resize) {
            const stepSize = 10;
            let deltaPosition = 0;
            if (['ArrowLeft', 'ArrowUp'].includes(event.key)) {
                deltaPosition = -stepSize;
            }
            else if (['ArrowRight', 'ArrowDown'].includes(event.key)) {
                deltaPosition = stepSize;
            }
            if (deltaPosition === 0) {
                // There no resize with keyboard
                return;
            }
            // Do full resize cycle - start, move and end
            if (this.props.onResizeStart) {
                this.props.onResizeStart();
            }
            this.doResize(deltaPosition);
            if (this.props.onResizeEnd) {
                this.props.onResizeEnd();
            }
        }
        else if (this.props.type === UISplitterType.Toggle && event.key === 'Enter') {
            this.toggleSplitter();
        }
    }
    /**
     * Method returns class names string depending on props and component state.
     *
     * @returns {number} Minimal size of section.
     */
    getClassNames() {
        const { type, vertical, hidden, splitterLayoutType } = this.props;
        let classNames = `splitter splitter--${type}`;
        // vertical or horizontal
        classNames += ` ${vertical ? 'splitter--vertical' : 'splitter--horizontal'}`;
        if (hidden && type === UISplitterType.Resize) {
            classNames += ' splitter--hidden';
        }
        classNames += ` ${splitterLayoutType === UISplitterLayoutType.Standard ? 'splitter--standard' : 'splitter--compact'}`;
        return classNames;
    }
    /**
     * @returns {React.ReactElement}
     */
    render() {
        const { type, vertical, hidden, title, splitterLayoutType } = this.props;
        const tabIndex = this.props.splitterTabIndex ?? 0;
        const size = splitterLayoutType === UISplitterLayoutType.Standard ? this.size : this.compactSize;
        const splitterOffset = type === UISplitterType.Toggle ? -size : -size / 2;
        const role = type === UISplitterType.Toggle ? 'button' : 'separator';
        const orientation = vertical ? 'horizontal' : 'vertical';
        let ariaPressed;
        if (type === UISplitterType.Toggle) {
            ariaPressed = !hidden;
        }
        return (react_1.default.createElement("div", { ref: this.rootRef, role: role, "aria-orientation": orientation, "aria-pressed": ariaPressed, title: title, tabIndex: tabIndex, onKeyDown: this.onKeyDown.bind(this), style: {
                ...(vertical && { height: size, top: splitterOffset }),
                ...(!vertical && { width: size, left: splitterOffset })
            }, onMouseDown: type === UISplitterType.Resize
                ? (event) => this.startSplitterMove(event)
                : undefined, onClick: type === UISplitterType.Toggle ? () => this.toggleSplitter() : undefined, className: this.getClassNames() },
            react_1.default.createElement("div", { className: "splitter__grip" },
                react_1.default.createElement(UIIcon_1.UIIcon, { iconName: this.getIcon(type, splitterLayoutType) }))));
    }
}
exports.UISplitter = UISplitter;
//# sourceMappingURL=UISplitter.js.map