"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module Picker
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.ListPicker = exports.ListPickerBase = exports.getListPanel = exports.ExpandableSection = exports.ListPickerItem = exports.ListItemType = void 0;
require("./ListPicker.scss");
const classnames_1 = require("classnames");
const React = require("react");
const components_react_1 = require("@itwin/components-react");
const core_react_1 = require("@itwin/core-react");
const appui_layout_react_1 = require("@itwin/appui-layout-react");
const useFrameworkVersion_1 = require("../hooks/useFrameworkVersion");
const DragInteraction_1 = require("../toolbar/DragInteraction");
const UiFramework_1 = require("../UiFramework");
const InternalFrontstageManager_1 = require("../frontstage/InternalFrontstageManager");
// eslint-disable-next-line @typescript-eslint/naming-convention, deprecation/deprecation
const ContainedGroup = (0, core_react_1.withOnOutsideClick)((0, appui_layout_react_1.withContainIn)(appui_layout_react_1.Group), undefined, false);
/** Enum for the list picker item type
 * @beta
 */
var ListItemType;
(function (ListItemType) {
    ListItemType[ListItemType["Item"] = 0] = "Item";
    ListItemType[ListItemType["Separator"] = 1] = "Separator";
    ListItemType[ListItemType["Container"] = 2] = "Container";
})(ListItemType = exports.ListItemType || (exports.ListItemType = {}));
let lastOpenedPicker; // eslint-disable-line deprecation/deprecation
/** List Picker Item React component
 * @beta
 */
class ListPickerItem extends React.PureComponent {
    /** Renders ListPickerItem */
    render() {
        const itemClassName = (0, classnames_1.default)("ListPicker-item", this.props.isActive && "is-active", this.props.isFocused && "is-focused", this.props.className);
        // TODO - if cut off, show a title
        const title = (this.props.label && this.props.label.length > 25) ? this.props.label : undefined;
        return (
        // eslint-disable-next-line jsx-a11y/click-events-have-key-events
        React.createElement("div", { className: itemClassName, onClick: this.props.onClick, role: "button", tabIndex: -1 },
            React.createElement("div", { className: "label", title: title }, this.props.label)));
    }
}
exports.ListPickerItem = ListPickerItem;
/** Expandable Section React component used by [[ListPickerBase]]
 * @beta
 */
class ExpandableSection extends React.PureComponent {
    /** Creates an ExpandableSection */
    constructor(props) {
        super(props);
        this._onClick = () => {
            this.setState((prevState) => ({ expanded: !prevState.expanded }));
        };
        this.state = { expanded: !!this.props.expanded };
    }
    /** Renders ExpandableSection */
    render() {
        const className = (0, classnames_1.default)("nz-toolbar-item-expandable-group-group", this.props.className);
        const icon = this.state.expanded ? React.createElement("i", { className: "icon icon-chevron-down" }) : React.createElement("i", { className: "icon icon-chevron-right" });
        return (React.createElement(appui_layout_react_1.Panel, { className: className, style: this.props.style, key: this.props.title },
            " ",
            React.createElement("div", { onClick: this._onClick, className: this.state.expanded ? "ListPickerInnerContainer-header-expanded" : "ListPickerInnerContainer-header", role: "button", tabIndex: -1, "aria-expanded": this.state.expanded },
                React.createElement("div", { className: "ListPickerInnerContainer-header-content" },
                    React.createElement("div", { className: "ListPickerInnerContainer-expander" }, icon),
                    React.createElement("div", { className: "ListPickerInnerContainer-title" }, this.props.title))),
            this.state.expanded ?
                React.createElement(appui_layout_react_1.GroupColumn, null,
                    " ",
                    this.props.children) : React.createElement("div", null)));
    }
}
exports.ExpandableSection = ExpandableSection;
/** @beta */
function getListPanel(props) {
    const expandSingleSection = () => {
        const populatedContainers = props.items.filter((item) => {
            return (item.type === ListItemType.Container && item.children.length !== 0);
        });
        return populatedContainers.length === 1;
    };
    const listItemToElement = (item, itemIndex) => {
        switch (item.type) {
            case ListItemType.Item:
                return (React.createElement(ListPickerItem, { ...props, key: itemIndex.toString(), label: item.name, isActive: item.enabled, onClick: 
                    // istanbul ignore next
                    () => { props.setEnabled(item, !item.enabled); } }));
            case ListItemType.Separator:
                return (React.createElement("div", { key: itemIndex.toString(), className: "ListPicker-separator" }));
            case ListItemType.Container:
                if (item.children.length !== 0) {
                    return (React.createElement(ExpandableSection, { key: itemIndex.toString(), title: item.name, className: "ListPickerInnerContainer", expanded: expandSingleSection() },
                        React.createElement(appui_layout_react_1.GroupColumn, null,
                            " ",
                            item.children.map(listItemToElement))));
                }
                else {
                    return (React.createElement("div", { key: itemIndex.toString() }));
                }
            // istanbul ignore next
            default:
                return (React.createElement("div", { key: itemIndex.toString() }));
        }
    };
    return (React.createElement(ContainedGroup, { className: "ListPickerContainer", columns: React.createElement(appui_layout_react_1.GroupColumn, { className: "ListPicker-column" },
            " ",
            props.items.map(listItemToElement)), containFn: appui_layout_react_1.containHorizontally, title: props.title, header: props.searchBox && props.onSearchValueChange &&
            React.createElement(core_react_1.SearchBox, { className: "ListPickerSearchBox", onValueChanged: props.onSearchValueChange }) }));
}
exports.getListPanel = getListPanel;
/**
 * List picker base class.
 * Used to provide an expandable list of items to enable/disable items.
 * @deprecated in 3.5. Used in UI1.0 only.
 * @beta
 */
class ListPickerBase extends React.PureComponent {
    /** Creates a ListPickerBase */
    constructor(props) {
        super(props);
        this._isMounted = false;
        this._closeOnPanelOpened = true;
        this._ref = React.createRef();
        /** Minimizes the expandable component. */
        this.minimize = () => {
            // istanbul ignore else
            if (this._isMounted)
                this.setState({
                    expanded: false,
                });
        };
        /** Checks if ExpandableItem is expanded. */
        this.isExpanded = () => {
            return this.state.expanded;
        };
        this._handleOnOutsideClick = (e) => {
            if (!this._ref.current || !(e.target instanceof Node) || this._ref.current.contains(e.target))
                return;
            this.minimize();
            this.props.onExpanded && this.props.onExpanded(false);
        };
        this._handleToolPanelOpenedEvent = () => {
            if (!this._closeOnPanelOpened)
                return;
            this.minimize();
        };
        this._handleClick = () => {
            // istanbul ignore next
            if (!this._isMounted)
                return;
            this.setState((prevState) => {
                const expanded = !prevState.expanded;
                return {
                    expanded,
                };
            }, () => {
                const expanded = this.state.expanded;
                if (expanded) {
                    // Minimize any other list picker that has been opened
                    // This is to mimic Bimium's behavior where pickers only close when other pickers are opened
                    if (lastOpenedPicker && lastOpenedPicker !== this && lastOpenedPicker.isExpanded())
                        lastOpenedPicker.minimize();
                    lastOpenedPicker = this;
                    this._closeOnPanelOpened = false;
                    expanded && InternalFrontstageManager_1.InternalFrontstageManager.onToolPanelOpenedEvent.emit();
                    this._closeOnPanelOpened = true;
                }
                this.props.onExpanded && this.props.onExpanded(expanded);
            });
        };
        this.state = {
            expanded: false,
        };
    }
    /** @internal */
    componentDidMount() {
        this._isMounted = true;
        InternalFrontstageManager_1.InternalFrontstageManager.onToolPanelOpenedEvent.addListener(this._handleToolPanelOpenedEvent);
    }
    /** @internal */
    componentWillUnmount() {
        this._isMounted = false;
        InternalFrontstageManager_1.InternalFrontstageManager.onToolPanelOpenedEvent.addListener(this._handleToolPanelOpenedEvent);
    }
    /** Renders ListPickerBase */
    render() {
        const icon = this.props.iconSpec ? /* istanbul ignore next */ (typeof this.props.iconSpec === "string" ?
            /* istanbul ignore next */ React.createElement(core_react_1.Icon, { iconSpec: this.props.iconSpec }) : React.createElement("i", { className: "icon uifw-item-svg-icon" }, this.props.iconSpec)) :
            React.createElement("i", { className: "icon icon-list" });
        return (React.createElement(DragInteraction_1.ToolbarDragInteractionContext.Consumer, null, (isEnabled) => {
            return (React.createElement(appui_layout_react_1.ExpandableItem // eslint-disable-line deprecation/deprecation
            , { ...this.props, hideIndicator: isEnabled, panel: this.getExpandedContent() },
                React.createElement("div", { ref: this._ref },
                    React.createElement(appui_layout_react_1.Item // eslint-disable-line deprecation/deprecation
                    , { icon: icon, onClick: this._handleClick, onSizeKnown: this.props.onSizeKnown, title: this.props.title }))));
        }));
    }
    /** Returns the list with the items */
    getExpandedContent() {
        if (!this.state.expanded)
            return undefined;
        const expandSingleSection = () => {
            const populatedContainers = this.props.items.filter((item) => {
                return (item.type === ListItemType.Container && item.children.length !== 0);
            });
            return populatedContainers.length === 1;
        };
        const listItemToElement = (item, itemIndex) => {
            switch (item.type) {
                case ListItemType.Item:
                    return (React.createElement(ListPickerItem, { ...this.props, key: itemIndex.toString(), label: item.name, isActive: item.enabled, onClick: () => { this.props.setEnabled(item, !item.enabled); } }));
                case ListItemType.Separator:
                    return (React.createElement("div", { key: itemIndex.toString(), className: "ListPicker-separator" }));
                case ListItemType.Container:
                    if (item.children.length !== 0) {
                        return (React.createElement(ExpandableSection, { key: itemIndex.toString(), title: item.name, className: "ListPickerInnerContainer", expanded: expandSingleSection() },
                            React.createElement(appui_layout_react_1.GroupColumn, null,
                                " ",
                                item.children.map(listItemToElement))));
                    }
                    else {
                        return (React.createElement("div", { key: itemIndex.toString() }));
                    }
                default:
                    return (React.createElement("div", { key: itemIndex.toString() }));
            }
        };
        return (React.createElement(ContainedGroup, { className: "ListPickerContainer", columns: React.createElement(appui_layout_react_1.GroupColumn, { className: "ListPicker-column" },
                " ",
                this.props.items.map(listItemToElement)), containFn: appui_layout_react_1.containHorizontally, onOutsideClick: this._handleOnOutsideClick, title: this.props.title }));
    }
}
exports.ListPickerBase = ListPickerBase;
/**
 * List picker toolbar popup item.
 * Used to provide an expandable list of items to enable/disable items.
 * @beta
 */
function ListPickerPopupItem(props) {
    const icon = props.iconSpec ? ( /* istanbul ignore next */typeof props.iconSpec === "string" ? React.createElement(core_react_1.Icon, { iconSpec: props.iconSpec }) :
        React.createElement("i", { className: "icon uifw-item-svg-icon" }, props.iconSpec)) : React.createElement(core_react_1.Icon, { iconSpec: "icon-list" });
    return (React.createElement(DragInteraction_1.ToolbarDragInteractionContext.Consumer, null, (isEnabled) => {
        return React.createElement(components_react_1.PopupItem, { hideIndicator: isEnabled, icon: icon, title: props.title, panel: getListPanel(props) });
    }));
}
/**
 * List Picker that lets the user pick from a list of items to enable/disable
 * It also provides options to enable all, disable all and invert selection
 * @beta
 */
class ListPicker extends React.Component {
    /** Creates a ListPicker */
    constructor(props) {
        super(props);
        // Handle enabling/disabling the items
        // This will call the this.props.setEnabled function to provide the parent with a chance to process it
        this._setEnabled = (item, enabled) => {
            if (this.isSpecialItem(item)) {
                switch (item.key) {
                    case ListPicker.Key_All: {
                        // istanbul ignore else
                        if (this.props.enableAllFunc)
                            this.props.enableAllFunc();
                        return;
                    }
                    case ListPicker.Key_None: {
                        // istanbul ignore else
                        if (this.props.disableAllFunc)
                            this.props.disableAllFunc();
                        return;
                    }
                    case ListPicker.Key_Invert: {
                        // istanbul ignore else
                        if (this.props.invertFunc)
                            this.props.invertFunc();
                        return;
                    }
                }
            }
            // Call on parent to do processing of the item
            this.props.setEnabled(item, enabled);
        };
    }
    static get Key_All() { return -3; }
    static get Key_None() { return -2; }
    static get Key_Invert() { return -1; }
    static get Key_Separator() { return -4; }
    // Creates an array of items containing the separator and special requests (all, none, invert)
    createItems(items) {
        const newItems = [];
        // Create special buttons (All/None/Invert)
        if (this.props.enableAllFunc) {
            let allEnabled = true;
            items.map((item) => { allEnabled = allEnabled && item.enabled; });
            newItems.push({ key: ListPicker.Key_All, name: UiFramework_1.UiFramework.translate("pickerButtons.all"), enabled: allEnabled, type: ListItemType.Item });
        }
        if (this.props.disableAllFunc) {
            let allDisabled = false;
            items.map((item) => { allDisabled = allDisabled || item.enabled; });
            newItems.push({ key: ListPicker.Key_None, name: UiFramework_1.UiFramework.translate("pickerButtons.none"), enabled: !allDisabled, type: ListItemType.Item });
        }
        if (this.props.invertFunc) {
            newItems.push({ key: ListPicker.Key_Invert, name: UiFramework_1.UiFramework.translate("pickerButtons.invert"), enabled: false, type: ListItemType.Item });
        }
        if (this.props.enableAllFunc || this.props.disableAllFunc || this.props.invertFunc) {
            newItems.push({ key: ListPicker.Key_Separator, name: UiFramework_1.UiFramework.translate("pickerButtons.separator"), enabled: false, type: ListItemType.Separator });
        }
        // Push items
        items.map((item) => { newItems.push(item); });
        return newItems;
    }
    /**
     * Checks if item is a special item.
     * @param item Item to check
     */
    isSpecialItem(item) {
        return item.key === ListPicker.Key_All || item.key === ListPicker.Key_Invert || item.key === ListPicker.Key_None || item.type !== ListItemType.Item || item.key === ListPicker.Key_Separator;
    }
    /** Renders ListPicker */
    render() {
        return (React.createElement(useFrameworkVersion_1.FrameworkVersionSwitch, { v1: React.createElement(ListPickerBase // eslint-disable-line deprecation/deprecation
            , { ...this.props, title: this.props.title, setEnabled: this._setEnabled, onExpanded: this.props.onExpanded, items: this.createItems(this.props.items), iconSpec: this.props.iconSpec }), v2: React.createElement(ListPickerPopupItem, { ...this.props, title: this.props.title, setEnabled: this._setEnabled, onExpanded: this.props.onExpanded, items: this.createItems(this.props.items), iconSpec: this.props.iconSpec }) }));
    }
}
exports.ListPicker = ListPicker;
//# sourceMappingURL=ListPicker.js.map