"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.SelectOptionsList = exports.Select = exports.isDataOptionGroups = exports.isDataOptions = exports.Option = void 0;
const tslib_1 = require("tslib");
const classnames_1 = tslib_1.__importDefault(require("classnames"));
const react_1 = tslib_1.__importStar(require("react"));
require("./style.less");
const icon_1 = require("../icon");
const Option = (_a) => {
    var { value, children, disabled, onClick, className } = _a, otherProps = tslib_1.__rest(_a, ["value", "children", "disabled", "onClick", "className"]);
    return (react_1.default.createElement("span", Object.assign({}, otherProps, { className: (0, classnames_1.default)(className, { 'kt-option-disabled': disabled }), onClick: () => onClick && !disabled && onClick(value) }), children));
};
exports.Option = Option;
function noop(...args) { }
function getValueWithProps(element, key) {
    if (key) {
        return element.props[key];
    }
    return element.props.value;
}
function flatChildren(children, warpper) {
    let flatted = [];
    if (Array.isArray(children)) {
        flatted = react_1.default.Children.toArray(children).map(warpper);
    }
    else {
        flatted = [warpper(children)];
    }
    return flatted;
}
/**
 * @deprecated
 * 从react node 上获取 props 来比较有点反模式，不符合数据和视图解耦的思想
 */
function getLabelWithChildrenProps(value, children, equals = (v1, v2) => v1 === v2) {
    const nodes = react_1.default.Children.toArray(children).filter((v) => react_1.default.isValidElement(v));
    const currentOption = nodes.find((node) => {
        var _a;
        if (node.props) {
            if (equals((_a = node.props) === null || _a === void 0 ? void 0 : _a.value, value)) {
                return node;
            }
        }
        return null;
    });
    return currentOption === null || currentOption === void 0 ? void 0 : currentOption.props;
}
function isDataOptions(options) {
    if (!options) {
        return false;
    }
    if (options.length === 0) {
        return true;
    }
    return isDataOption(options[0]);
}
exports.isDataOptions = isDataOptions;
function isDataOptionGroups(options) {
    if (!options) {
        return false;
    }
    if (options.length === 0) {
        return true;
    }
    return isDataOptionGroup(options[0]);
}
exports.isDataOptionGroups = isDataOptionGroups;
function isDataOption(option) {
    return option.value !== undefined;
}
function isDataOptionGroup(option) {
    return option.groupName !== undefined && isDataOptions(option.options);
}
function defaultOptionRenderer(v) {
    return (react_1.default.createElement(react_1.default.Fragment, null,
        v.data.iconClass ? react_1.default.createElement("div", { className: (0, classnames_1.default)(v.data.iconClass, 'kt-select-option-icon') }) : undefined,
        v.data.label));
}
function defaultGroupTitleRenderer({ group, index }) {
    return (react_1.default.createElement("div", { key: 'header_' + index, className: 'kt-select-group-header' },
        group.iconClass ? react_1.default.createElement("div", { className: (0, classnames_1.default)(group.iconClass, 'kt-select-option-icon') }) : undefined,
        react_1.default.createElement("div", null, group.groupName)));
}
function defaultFilterOption(input, option) {
    let strToSearch = option.label;
    if (strToSearch === undefined) {
        try {
            strToSearch = option.value.toString();
        }
        catch (e) {
            strToSearch = undefined;
        }
    }
    if (typeof strToSearch === 'string') {
        return strToSearch.indexOf(input) !== -1;
    }
    return false;
}
function Select({ disabled, options, size = 'default', children, value, onChange, onMouseEnter, optionLabelProp, style, optionStyle, className, maxHeight, equals = (v1, v2) => v1 === v2, optionRenderer = defaultOptionRenderer, groupTitleRenderer, footerComponent, headerComponent, showSearch = false, filterOption = defaultFilterOption, searchPlaceholder = '', emptyComponent, selectedRenderer, onBeforeShowOptions, allowOptionsOverflow, dropdownRenderType = 'fixed', description, notMatchWarning, }) {
    const [open, setOpen] = (0, react_1.useState)(false);
    const [searchInput, setSearchInput] = (0, react_1.useState)('');
    const selectRef = react_1.default.useRef(null);
    const overlayRef = react_1.default.useRef(null);
    const toggleOpen = (0, react_1.useCallback)((e) => {
        e.preventDefault();
        e.stopPropagation();
        const target = !open;
        if (target) {
            if (onBeforeShowOptions && onBeforeShowOptions()) {
                return;
            }
        }
        setOpen(target);
    }, [open, onBeforeShowOptions, onBeforeShowOptions]);
    const getSelectedValue = (0, react_1.useCallback)(() => {
        var _a, _b, _c, _d, _e, _f, _g, _h, _j;
        if (options && isDataOptions(options)) {
            for (const option of options) {
                if (equals(value, option.value)) {
                    return {
                        iconClass: option.iconClass,
                        label: option.label,
                        value: option.value,
                    };
                }
            }
            return {
                iconClass: (_a = options[0]) === null || _a === void 0 ? void 0 : _a.iconClass,
                label: (_b = options[0]) === null || _b === void 0 ? void 0 : _b.label,
                value: (_c = options[0]) === null || _c === void 0 ? void 0 : _c.value,
            };
        }
        else if (options && isDataOptionGroups(options)) {
            for (const group of options) {
                for (const option of group.options) {
                    if (equals(value, option.value)) {
                        return {
                            iconClass: option.iconClass,
                            label: option.label,
                            value: option.value,
                        };
                    }
                }
            }
            return {
                iconClass: (_e = (_d = options[0]) === null || _d === void 0 ? void 0 : _d.options[0]) === null || _e === void 0 ? void 0 : _e.iconClass,
                label: (_g = (_f = options[0]) === null || _f === void 0 ? void 0 : _f.options[0]) === null || _g === void 0 ? void 0 : _g.label,
                value: (_j = (_h = options[0]) === null || _h === void 0 ? void 0 : _h.options[0]) === null || _j === void 0 ? void 0 : _j.value,
            };
        }
        else {
            const nodeOption = children && getLabelWithChildrenProps(value, children);
            if (nodeOption) {
                return {
                    label: nodeOption.label || nodeOption.value,
                    value: nodeOption.value,
                };
            }
        }
        // 如果当前 value 和任何一个 option 都不匹配，返回当前 value
        return {
            label: value,
            value: value,
            notMatch: true,
        };
    }, [options, value, children]);
    const selected = getSelectedValue();
    const optionsContainerClasses = (0, classnames_1.default)('kt-select-options', {
        ['kt-select-options-visible']: open,
        [`kt-select-options-${size}`]: size,
    });
    const showWarning = notMatchWarning && selected.notMatch;
    const selectClasses = (0, classnames_1.default)('kt-select-value', {
        ['kt-select-warning']: showWarning,
        ['kt-select-disabled']: disabled,
        ['kt-select-value-active']: open,
        [`kt-select-value-${size}`]: size,
    });
    function Wrapper(node, index) {
        var _a;
        if (!node) {
            return null;
        }
        if (typeof node === 'string' || typeof node === 'number') {
            node = (react_1.default.createElement(exports.Option, { value: node, label: String(node), key: `${node}_${index}` }, node));
        }
        const element = node;
        const disabled = ((_a = element.props) === null || _a === void 0 ? void 0 : _a.disabled) || false;
        return (react_1.default.createElement("div", { key: `${element.props.value}_${index}`, className: (0, classnames_1.default)({
                ['kt-select-option-select']: value === element.props.value,
            }), onMouseEnter: () => onMouseEnter === null || onMouseEnter === void 0 ? void 0 : onMouseEnter(element.props.value, index), onClick: disabled
                ? noop
                : () => {
                    setOpen(false);
                    if (onChange) {
                        onChange(getValueWithProps(node, optionLabelProp));
                    }
                } }, node));
    }
    (0, react_1.useEffect)(() => {
        if (!open && searchInput) {
            setSearchInput('');
        }
    }, []);
    (0, react_1.useEffect)(() => {
        if (selectRef.current && overlayRef.current) {
            const boxRect = selectRef.current.getBoundingClientRect();
            if (allowOptionsOverflow) {
                overlayRef.current.style.minWidth = `${boxRect.width}px`;
                // 防止戳出屏幕
                overlayRef.current.style.maxWidth = `${window.innerWidth - boxRect.left - 4}px`;
            }
            else {
                overlayRef.current.style.width = `${boxRect.width}px`;
            }
            // 防止戳出下方屏幕
            const toBottom = window.innerHeight - boxRect.bottom - 50;
            if (toBottom < overlayRef.current.clientHeight) {
                // 下方距离小于浮层高度，设置向上弹出选择框
                overlayRef.current.style.bottom = selectRef.current.clientHeight + 4 + 'px';
            }
            else {
                // 下方距离大于浮层高度，设置最大高度为下方距离
                overlayRef.current.style.maxHeight = `${toBottom}px`;
            }
            overlayRef.current.style.position = dropdownRenderType === 'fixed' ? 'fixed' : 'absolute';
        }
        if (open) {
            const listener = () => {
                setOpen(false);
            };
            document.addEventListener('click', listener);
            return () => {
                document.removeEventListener('click', listener);
            };
        }
    }, [open]);
    // 根据搜索输入过滤 options
    if (searchInput) {
        if (options && isDataOptions(options)) {
            options = options.filter((o) => filterOption(searchInput, o));
        }
        else if (options && isDataOptionGroups(options)) {
            const result = [];
            for (const group of options) {
                const filteredGroup = {
                    iconClass: group.iconClass,
                    groupName: group.groupName,
                    options: group.options.filter((o) => filterOption(searchInput, o, group)),
                };
                if (filteredGroup.options.length > 0) {
                    // 不显示空的group
                    result.push(filteredGroup);
                }
            }
            options = result;
        }
    }
    const renderSelected = () => {
        const CustomSC = selectedRenderer;
        return (react_1.default.createElement(react_1.default.Fragment, null,
            CustomSC ? (react_1.default.createElement(CustomSC, { data: selected })) : (react_1.default.createElement(react_1.default.Fragment, null,
                selected.iconClass ? react_1.default.createElement("div", { className: (0, classnames_1.default)(selected.iconClass, 'kt-select-option-icon') }) : undefined,
                react_1.default.createElement("span", { className: 'kt-select-option' }, selected.label))),
            react_1.default.createElement(icon_1.Icon, { iconClass: (0, classnames_1.default)((0, icon_1.getIcon)('down'), 'kt-select-value-default-icon') })));
    };
    const renderSearch = () => (react_1.default.createElement("input", { className: (0, classnames_1.default)('kt-select-search'), onChange: (e) => {
            setSearchInput(e.target.value);
        }, value: searchInput, autoFocus: true, placeholder: searchPlaceholder || '' }));
    return (react_1.default.createElement("div", { className: (0, classnames_1.default)('kt-select-container', className), ref: selectRef },
        react_1.default.createElement("div", { className: selectClasses, onClick: toggleOpen, style: style }, showSearch && open ? renderSearch() : renderSelected()),
        showWarning && react_1.default.createElement("div", { className: 'kt-select-warning-text' }, notMatchWarning),
        open &&
            (isDataOptions(options) || isDataOptionGroups(options) ? (react_1.default.createElement(exports.SelectOptionsList, { optionRenderer: optionRenderer, options: options, equals: equals, optionStyle: optionStyle, currentValue: value, size: size, onSelect: (value) => {
                    if (onChange) {
                        onChange(value);
                    }
                    setOpen(false);
                }, groupTitleRenderer: groupTitleRenderer, className: optionsContainerClasses, style: { maxHeight: `${maxHeight}px` }, ref: overlayRef, footerComponent: footerComponent, headerComponent: headerComponent, emptyComponent: emptyComponent })) : (
            // FIXME: to be deprecated
            // 下面这种使用 children 的方式不够标准化，待废弃
            react_1.default.createElement("div", { className: optionsContainerClasses, style: { maxHeight: `${maxHeight}px` }, ref: overlayRef },
                options && options.map((v, i) => Wrapper(v, i)),
                children && flatChildren(children, Wrapper),
                description && react_1.default.createElement(Description, { text: description }),
                react_1.default.createElement("div", { className: 'kt-select-overlay', onClick: toggleOpen }))))));
}
exports.Select = Select;
function Description({ text }) {
    return (react_1.default.createElement(react_1.default.Fragment, null,
        react_1.default.createElement("div", { className: 'kt-option-divider' }),
        react_1.default.createElement("div", { className: 'kt-option-description' }, text)));
}
exports.SelectOptionsList = react_1.default.forwardRef((props, ref) => {
    const { options, optionRenderer: OPC = defaultOptionRenderer, equals = (v1, v2) => v1 === v2, onSelect, currentValue, optionStyle, size, className, style, groupTitleRenderer: GT = defaultGroupTitleRenderer, renderCheck, headerComponent: HC, footerComponent: FC, emptyComponent: EC, } = props;
    const optionsContainerClasses = (0, classnames_1.default)('kt-select-options', {
        [`kt-select-options-${size}`]: true,
    }, className);
    function renderWithGroup(groups) {
        return groups.map((group, index) => {
            const header = react_1.default.createElement(GT, { group: group, index: index });
            return (react_1.default.createElement(react_1.default.Fragment, { key: 'group_' + index },
                header,
                renderWithoutGroup(group.options)));
        });
    }
    function renderWithoutGroup(options) {
        return (options &&
            options.map((v, index) => {
                const isCurrent = equals(currentValue, v.value);
                return (react_1.default.createElement(exports.Option, { value: index, key: index, className: (0, classnames_1.default)({
                        ['kt-select-option-select']: isCurrent,
                        ['kt-select-option-default']: true,
                        ['kt-option-with-check']: renderCheck,
                    }), onClick: () => onSelect(v.value), style: optionStyle },
                    renderCheck && equals(currentValue, v.value) ? (react_1.default.createElement("div", { className: 'kt-option-check' },
                        react_1.default.createElement(icon_1.Icon, { icon: 'check' }))) : undefined,
                    react_1.default.createElement(OPC, { data: v, isCurrent: isCurrent })));
            }));
    }
    let isEmpty;
    if (isDataOptionGroups(options)) {
        isEmpty = options.filter((group) => group.options.length > 0).length === 0;
    }
    else {
        isEmpty = options.length === 0;
    }
    return (react_1.default.createElement("div", { className: optionsContainerClasses, style: style, ref: ref, onClick: (event) => {
            event.stopPropagation();
        } },
        HC ? react_1.default.createElement(HC, null) : null,
        isEmpty && EC ? (react_1.default.createElement(EC, null)) : ((isDataOptionGroups(options) ? renderWithGroup(options) : renderWithoutGroup(options)) || (EC && react_1.default.createElement(EC, null))),
        FC ? react_1.default.createElement(FC, null) : null));
});
//# sourceMappingURL=index.js.map