"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.UIDropdown = exports.UIDropdownMenuItemType = void 0;
const react_1 = __importDefault(require("react"));
const react_2 = require("@fluentui/react");
Object.defineProperty(exports, "UIDropdownMenuItemType", { enumerable: true, get: function () { return react_2.DropdownMenuItemType; } });
const UIIcon_1 = require("../UIIcon");
const ValidationMessage_1 = require("../../helper/ValidationMessage");
const UILabel_1 = require("../UILabel");
const utils_1 = require("./utils");
const UICallout_1 = require("../UICallout");
const types_1 = require("../types");
require("./UIDropdown.scss");
const ERROR_BORDER_COLOR = 'var(--vscode-inputValidation-errorBorder)';
/**
 * UIDropdown component
 * based on https://developer.microsoft.com/en-us/fluentui#/controls/web/dropdown
 *
 * @exports
 * @class UIDropdown
 * @extends {React.Component<UIDropdownProps, UIDropdownState>}
 */
class UIDropdown extends react_1.default.Component {
    /**
     * Initializes component properties.
     *
     * @param {UIDropdownProps} props
     */
    constructor(props) {
        super(props);
        this.dropdownDomRef = react_1.default.createRef();
        this.menuDomRef = react_1.default.createRef();
        this.calloutCollisionTransform = new UICallout_1.CalloutCollisionTransform(this.dropdownDomRef, this.menuDomRef);
        this.onRenderCaretDown = () => {
            return react_1.default.createElement(UIIcon_1.UIIcon, { iconName: "ArrowDown", style: { height: '100%' } });
        };
        this.onRenderTitle = (items) => {
            if (this.props.multiSelect && this.props.onHandleRenderTitle) {
                return this.props.onHandleRenderTitle(items);
            }
            else {
                const { multiSelectDelimiter = ', ' } = this.props;
                if (items) {
                    const title = items.map((i) => i.text).join(multiSelectDelimiter);
                    return react_1.default.createElement(react_1.default.Fragment, null, title);
                }
                else {
                    return react_1.default.createElement(react_1.default.Fragment, null, this.props.title);
                }
            }
        };
        this.onClick = ( /* event: React.FormEvent<HTMLDivElement>, option?: IDropdownOption, index?: number */) => {
            this.setState((prevState) => ({ isOpen: !prevState.isOpen }), () => {
                if (this.props.multiSelect && this.props.onHandleOpen) {
                    if (this.state.isOpen) {
                        this.setState((prevState) => ({ isOpen: !prevState.isOpen }));
                        this.props.onHandleOpen();
                    }
                }
            });
        };
        this.onChange = (event, option, index) => {
            if (this.props.multiSelect && this.props.onHandleChange) {
                if (option && index) {
                    this.props.onHandleChange(option, index);
                }
            }
        };
        /**
         * Method stops event propagation.
         *
         * @param {React.MouseEvent<HTMLDivElement>} event Mouse event.
         */
        this.stopEventPropagation = (event) => {
            event.stopPropagation();
        };
        /**
         * Method used as workaround to separate focus and hover.
         * Default behaviour of fluent ui is that focus follows hover, but we need separe them.
         *
         * @param {IDropdownOption} [props] Dropdown props.
         * @param {(props?: IDropdownOption) => JSX.Element | null} [defaultRender] Default option renderer.
         * @returns {JSX.Element | null} Returns dropdown option element.
         */
        this._onRenderOption = (props, defaultRender) => {
            return (react_1.default.createElement(react_1.default.Fragment, null,
                defaultRender?.(props),
                props?.itemType !== react_2.DropdownMenuItemType.Header && (react_1.default.createElement("div", { onMouseEnter: this.stopEventPropagation.bind(this), onMouseLeave: this.stopEventPropagation.bind(this), onMouseMove: this.stopEventPropagation.bind(this), className: "ts-dropdown-item-blocker" }))));
        };
        /**
         * Render dropdown menu option.
         *
         * @param {IDropdownOption} [props] Dropdown props.
         * @param {(props?: IDropdownOption) => JSX.Element | null} [defaultRender] Default option renderer.
         * @returns {JSX.Element | null} Returns dropdown option element.
         */
        this.onRenderOption = (props, defaultRender) => {
            if (this.props.onRenderOption) {
                return this.props.onRenderOption(props, this._onRenderOption.bind(this, props, defaultRender));
            }
            return this._onRenderOption(props, defaultRender);
        };
        /**
         * Method called on combobox item render.
         * We should pass query to it and avoid rendering if it is hidden.
         *
         * @param {IComboBoxOption} props Combobox item props.
         * @param {Function} defaultRender Combobox item default renderer.
         * @returns {JSX.Element | null} Element to render.
         */
        this._onRenderItem = (props, defaultRender) => {
            if (defaultRender && props) {
                if (props.title === undefined) {
                    // Apply title by default if property not provided
                    // In older fluent-ui versions it was applied by default, but behavior changed in version '8.66.2'
                    props.title = props.text;
                }
                return defaultRender(props);
            }
            return null;
        };
        /**
         * Render dropdown menu item.
         *
         * @param {IComboBoxOption} props Combobox item props.
         * @param {Function} defaultRender Combobox item default renderer.
         * @returns {JSX.Element | null} Element to render.
         */
        this.onRenderItem = (props, defaultRender) => {
            if (this.props.onRenderItem) {
                return this.props.onRenderItem(props, this._onRenderItem.bind(this, props, defaultRender));
            }
            return this._onRenderItem(props, defaultRender);
        };
        this.state = {
            options: [],
            isOpen: false
        };
    }
    /**
     * Method returns styles for callout to support property 'useDropdownAsMenuMinWidth'.
     * States:
     * 1. Min width of callout is equals to width of droipdown input box;
     * 2. Max width equals to windows size minus 10px;
     * 3. Width is auto - it allows to make callout wider if menu option size exceeds size of dropdown input(min-width).
     *
     * @param {ICalloutContentStyleProps} calloutStyleProps Current callout styles.
     * @returns {Partial<ICalloutContentStyles>} Styles for callout.
     */
    getCalloutStylesForUseAsMinWidth(calloutStyleProps) {
        return {
            root: {
                minWidth: calloutStyleProps.calloutWidth,
                width: 'auto',
                maxWidth: 'calc(100% - 10px)'
            }
        };
    }
    /**
     * Method returns class names string depending on props and component state.
     *
     * @param {InputValidationMessageInfo} messageInfo Error/warning message if applied
     * @returns {string} Class names of root dropdown element.
     */
    getClassNames(messageInfo) {
        const { className, readOnly, disabled } = this.props;
        const errorSuffix = messageInfo.message ? ValidationMessage_1.MESSAGE_TYPES_CLASSNAME_MAP.get(messageInfo.type) : undefined;
        let classNames = `ts-SelectBox${messageInfo.message ? ' ts-SelectBox--' + errorSuffix : ''}`;
        // Readonly
        if (readOnly && !disabled) {
            classNames += ' ts-SelectBox--readonly';
        }
        // Disabled
        if (disabled) {
            classNames += ' ts-SelectBox--disabled';
        }
        // Custom external classes
        if (className) {
            classNames += ` ${className}`;
        }
        // Empty value
        if ((0, utils_1.isDropdownEmpty)(this.props)) {
            classNames += ' ts-SelectBox--empty';
        }
        return classNames;
    }
    /**
     * Method returns additional component properties for accessibility.
     *
     * @returns {AccessibilityProps} Additional properties.
     */
    getAccessibilityProps() {
        const { readOnly, disabled } = this.props;
        const additionalProps = {};
        if (readOnly && !disabled) {
            // Make dropdown focusable
            additionalProps.tabIndex = 0;
            additionalProps['data-is-focusable'] = true;
            // Adjust aria attributes for readonly
            additionalProps['aria-disabled'] = undefined;
            additionalProps['aria-readonly'] = true;
        }
        else if (disabled) {
            additionalProps.tabIndex = 0;
            additionalProps['data-is-focusable'] = true;
        }
        return additionalProps;
    }
    /**
     * @returns {JSX.Element}
     */
    render() {
        const messageInfo = (0, ValidationMessage_1.getMessageInfo)(this.props);
        const additionalProps = this.getAccessibilityProps();
        const dropdownStyles = () => ({
            ...{
                label: {
                    ...UILabel_1.labelGlobalStyle,
                    ...(this.props.disabled && {
                        opacity: '0.4'
                    }),
                    ...(this.props.required && {
                        selectors: {
                            '::after': {
                                content: types_1.REQUIRED_LABEL_INDICATOR,
                                color: ERROR_BORDER_COLOR,
                                paddingRight: 12
                            }
                        }
                    })
                },
                errorMessage: [messageInfo.style],
                callout: {
                    boxShadow: 'var(--ui-box-shadow-small)'
                }
            }
        });
        return (react_1.default.createElement(react_2.Dropdown, { ref: this.dropdownDomRef, onRenderCaretDown: this.onRenderCaretDown, onClick: this.onClick, onChange: this.onChange, onRenderTitle: this.onRenderTitle, 
            // Use default responsiveMode as xxxLarge, which does not enter mobile mode.
            responsiveMode: react_2.ResponsiveMode.xxxLarge, disabled: this.props.readOnly, ...additionalProps, ...this.props, calloutProps: {
                calloutMaxHeight: 200,
                styles: this.props.useDropdownAsMenuMinWidth ? this.getCalloutStylesForUseAsMinWidth : undefined,
                className: 'ts-Callout ts-Callout-Dropdown',
                popupProps: {
                    ref: this.menuDomRef
                },
                ...this.props.calloutProps,
                ...(0, utils_1.getCalloutCollisionTransformationPropsForDropdown)(this, this.calloutCollisionTransform)
            }, onRenderOption: this.onRenderOption.bind(this), onRenderItem: this.onRenderItem.bind(this), styles: dropdownStyles, className: this.getClassNames(messageInfo), errorMessage: messageInfo.message }));
    }
}
exports.UIDropdown = UIDropdown;
//# sourceMappingURL=UIDropdown.js.map