define(["require", "exports", "tslib", "react", "../../Utilities", "./SwatchColorPicker.Props", "../../ContextualMenu", "../../utilities/color/colors", "../../utilities/grid/Grid", "../../Button", "../../Callout", "../../FocusZone", "./SwatchColorPicker.scss"], function (require, exports, tslib_1, React, Utilities_1, SwatchColorPicker_Props_1, ContextualMenu_1, colors_1, Grid_1, Button_1, Callout_1, FocusZone_1, stylesImport) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var styles = stylesImport;
    var SwatchColorPickerOption = function (props) {
        var item = props.item, id = props.id, posInSet = props.posInSet, setSize = props.setSize, className = props.className, role = props.role, selectedIndex = props.selectedIndex, disabled = props.disabled, cellShape = props.cellShape, onClick = props.onClick, onHover = props.onHover, onFocus = props.onFocus;
        return (React.createElement(Button_1.CommandButton, tslib_1.__assign({}, item.menuItemButtonProps, { id: id + '-item' + item.index, "data-index": item.index, "data-is-focusable": true, "aria-posinset": posInSet && posInSet, "aria-setsize": setSize && setSize, disabled: disabled, className: Utilities_1.css(className, (_a = {},
                _a['is-selected ' + styles.cellIsSelected] = (selectedIndex && selectedIndex === item.index),
                _a['is-disabled ' + styles.disabled] = disabled,
                _a)), onClick: _onClick, onMouseEnter: _onMouseEnter, onMouseLeave: _onMouseLeave, onFocus: _onFocus, role: role, "aria-selected": selectedIndex && (selectedIndex === item.index).toString(), ariaLabel: item.label && item.label, title: item.label && item.label }), _onRenderOption()));
        function _onClick() {
            if (onClick && !disabled) {
                onClick(item);
            }
        }
        function _onMouseEnter() {
            if (onHover && !disabled) {
                onHover(item.id, item.color);
            }
        }
        function _onMouseLeave() {
            if (onHover && !disabled) {
                onHover();
            }
        }
        function _onFocus() {
            if (onFocus && !disabled) {
                onFocus(item.id, item.color);
            }
        }
        /**
         * Render the core of an cell or menu item
         * @returns {JSX.Element} - Element representing the core of the item
         */
        function _onRenderOption() {
            // Menu items just need their label text
            if (item.type !== SwatchColorPicker_Props_1.SwatchColorPickerItemType.Cell) {
                return React.createElement("span", { className: styles.menuItem }, item.label);
            }
            // Build an SVG for the cell with the given shape and color properties
            return (React.createElement("svg", { className: Utilities_1.css(styles.svg, cellShape, cellShape === 'circle' ? styles.circle : ''), viewBox: '0 0 20 20', fill: colors_1.getColorFromString(item.color).str }, cellShape === 'circle' ?
                React.createElement("circle", { cx: '50%', cy: '50%', r: '50%' }) :
                React.createElement("rect", { width: '100%', height: '100%' })));
        }
        var _a;
    };
    var SwatchColorPicker = (function (_super) {
        tslib_1.__extends(SwatchColorPicker, _super);
        function SwatchColorPicker(props) {
            var _this = _super.call(this, props) || this;
            _this._id = props.id || Utilities_1.getId('swatchColorPicker');
            var selectedIndex;
            if (props.selectedId) {
                selectedIndex = _this._getSelectedIndex(props.swatchColorPickerItems, props.selectedId);
            }
            _this.state = {
                selectedIndex: selectedIndex,
                expanded: false
            };
            return _this;
        }
        SwatchColorPicker.prototype.componentWillReceiveProps = function (newProps) {
            var newSelectedIndex;
            if (newProps.selectedId) {
                newSelectedIndex = this._getSelectedIndex(newProps.swatchColorPickerItems, newProps.selectedId);
            }
            if (newSelectedIndex !== undefined &&
                newSelectedIndex !== this.state.selectedIndex) {
                this.setState({
                    selectedIndex: newSelectedIndex
                });
            }
        };
        SwatchColorPicker.prototype.render = function () {
            var expanded = this.state.expanded;
            var _a = this.props, menuButtonProps = _a.menuButtonProps, disabled = _a.disabled, swatchColorPickerItems = _a.swatchColorPickerItems, columnCount = _a.columnCount;
            // If we got button props, put the swatch color picker behind a button, otherwise
            // render all of the items
            var colorToSet = this._getSelectedColorToSet();
            var renderElement = menuButtonProps !== undefined ?
                React.createElement(SwatchColorPickerMenuButton, tslib_1.__assign({}, this.props, { color: colorToSet, onClick: this._onButtonClick, expanded: !!this.state.expanded, onRenderContainer: this._onRenderContainer, menuIconProps: menuButtonProps.menuIconProps ?
                        menuButtonProps.menuIconProps :
                        { iconName: 'chevronDown' } })) :
                React.createElement(SwatchColorPickerBody, tslib_1.__assign({}, this.props, { onRenderItems: this._onRenderItems }));
            return (React.createElement("div", { ref: this._resolveRef('_buttonWrapper'), className: Utilities_1.css('ms-swatchColorPickerWrapper', styles.wrapper) }, renderElement));
        };
        /**
         * Get the selected item's index
         * @param items - The items to search
         * @param selectedId - The selected item's id to find
         * @returns {number} - The index of the selected item's id, -1 if there was no match
         */
        SwatchColorPicker.prototype._getSelectedIndex = function (items, selectedId) {
            var selectedIndex = Utilities_1.findIndex(items, (function (item) { return (item.id === selectedId); }));
            return selectedIndex >= 0 ? selectedIndex : undefined;
        };
        /**
         * Gets the color for the selected index
         * @returns {string} - The color for the selected index,
         *   or undefined if: we are not updating the button icon with color,
         *   there is not a valid selected index, or if we do not have a valid color
         */
        SwatchColorPicker.prototype._getSelectedColorToSet = function () {
            var selectedIndex = this.state.selectedIndex;
            var _a = this.props, swatchColorPickerItems = _a.swatchColorPickerItems, setSelectedColorForIcon = _a.setSelectedColorForIcon;
            // Do we need to update the button with the selected
            // item's color? If so, attempt to grab the color
            if (setSelectedColorForIcon && selectedIndex !== undefined) {
                var swatchColorPickerItem = swatchColorPickerItems[selectedIndex];
                if (swatchColorPickerItem.type === SwatchColorPicker_Props_1.SwatchColorPickerItemType.Cell) {
                    return swatchColorPickerItem.color;
                }
            }
            return undefined;
        };
        /**
         * Render all the items
         * @param items - The swatch color picker items
         * @returns {JSX.Element[]} - An array of all the items in the swatch color picker
         */
        SwatchColorPicker.prototype._onRenderItems = function (items) {
            // This holds all of the element for the items
            var elements = [];
            // The number of cells that were processed in the previous iteration of loop.
            // This will be used to increase the index to the item after the last processed
            // item
            var numOfItemsInChunk = -1;
            // If we have cell items and we are in a menu, get all the
            // first executable items per chunk. Note, in this
            // context each menuItem is in its own "chunk", only grouped
            // cells are processed as a chunk. This helps with being able
            // to determine the correct aria-posinset and aria-setsize values
            var firstExecutableItemsPerChunk = (this.props.menuButtonProps ?
                this._getFirstExecutableItemsPerChunk() : undefined);
            // Did we find any executable items? (e.g. should be calculate the set information)
            var shouldGetSetInfo = (firstExecutableItemsPerChunk && firstExecutableItemsPerChunk.length > 0);
            var setSize = shouldGetSetInfo ? firstExecutableItemsPerChunk.length : undefined;
            // If any menuItem has an icon, all menu items need to be positined correctly so they align
            var shouldAccountForIcon = (firstExecutableItemsPerChunk && Utilities_1.findIndex(firstExecutableItemsPerChunk, function (executableItem) { return (executableItem.type === SwatchColorPicker_Props_1.SwatchColorPickerItemType.MenuItem && executableItem.menuItemButtonProps); }));
            // Loop across the items processing them depending on their item type
            var index = 0;
            while (index < items.length) {
                var item = items[index];
                var posInSet = shouldGetSetInfo ? this._getPositionInSet(firstExecutableItemsPerChunk, item.id) : undefined;
                switch (item.type) {
                    case SwatchColorPicker_Props_1.SwatchColorPickerItemType.Divider:
                        elements.push(this._renderSeparator(item));
                        break;
                    case SwatchColorPicker_Props_1.SwatchColorPickerItemType.Header:
                        elements.push(this._renderHeader(item));
                        break;
                    case SwatchColorPicker_Props_1.SwatchColorPickerItemType.Cell:
                        // build all the cells in the chunk this cell
                        // exists within (this will process all of the
                        // consecutive cells until the next non-cell type
                        // is incountered (or if we reach the end of the items))
                        var chunkItems = this._getNextChunkOfCellItems(items.slice(index));
                        // Update the number of items in chunk
                        numOfItemsInChunk = chunkItems.length > 0 ? chunkItems.length : -1;
                        // Add the result to the array
                        elements.push(this._renderNextChunkOfCellItems(chunkItems, posInSet, setSize));
                        break;
                    default:
                        // Does at least one of the menu items have an icon?
                        if (shouldAccountForIcon) {
                            // Make sure the width styling is the same by applying a consistent className
                            if (item.menuItemButtonProps) {
                                item.menuItemButtonProps = tslib_1.__assign({}, item.menuItemButtonProps, { iconProps: tslib_1.__assign({}, item.menuItemButtonProps.iconProps, { className: styles.icon }) });
                            }
                            else {
                                // This menu item didn't have an icon so add a "spacer" icon to make the text
                                // content align. This aligns with how ContextualMenu achieves this alignmet
                                item.menuItemButtonProps = tslib_1.__assign({}, item.menuItemButtonProps, { iconProps: { iconName: 'customIcon', className: styles.icon } });
                            }
                        }
                        elements.push(this._renderOption(item, posInSet, setSize));
                }
                // Increase the index by the number of items in the just processed chunk,
                // otherwise just increment the index
                index += numOfItemsInChunk > 0 ? numOfItemsInChunk : 1;
                numOfItemsInChunk = -1;
            }
            return elements;
        };
        /**
         * Renders the next consecutive chunk of cells
         * @param items - The items to process
         * @param posInSet - Optional, the position in the set for this chunk
         * @param setSize - Optional, the size of the total set
         * @returns {JSX.Element} - The grid that represents the chunk
         */
        SwatchColorPicker.prototype._renderNextChunkOfCellItems = function (items, posInSet, setSize) {
            return (React.createElement(Grid_1.Grid, { key: this._id + items[0].id + '-grid', items: items, columnCount: this.props.columnCount, onRenderItem: this._renderOption, positionInSet: posInSet, setSize: setSize }));
        };
        /**
         * Get the position in set for the given id
         * @param firstExecutableItemsPerChunk - The list of fist executable items per chunk
         * @param itemId - The id of item to find the index of
         * @returns {number} - The position in the set
         */
        SwatchColorPicker.prototype._getPositionInSet = function (firstExecutableItemsPerChunk, itemId) {
            // Find the index of the given id in the list of first executable items per chunk
            var index = Utilities_1.findIndex(firstExecutableItemsPerChunk, function (executableItem) { return (executableItem.id === itemId); });
            return index < 0 ? undefined : index + 1;
        };
        /**
         * Gets the next chunk of consecutive cells starting a index zero.
         * Note, index zero should be of type cell
         * @param items - The list of items to process where index zero is the start of the chunk
         * @returns {ISwatchColorPickerItemProps[]} - the array of consecutive cells starting at index zero
         *   (and continuing to the first non-cell type or the end of the items)
         */
        SwatchColorPicker.prototype._getNextChunkOfCellItems = function (items) {
            var nextIndextAfterChunk = Utilities_1.findIndex(items, (function (item) { return item.type !== SwatchColorPicker_Props_1.SwatchColorPickerItemType.Cell; }));
            // If we didn't find a non-cell item, we need to handle everything that is left
            if (nextIndextAfterChunk < 0) {
                return items;
            }
            // If we get here we found our chunk boundry
            return items.slice(0 /* start */, nextIndextAfterChunk);
        };
        /**
         * Get only the executable items (cells and menuItems)
         * @returns {ISwatchColorPickerItemProps[]} - an array of the executable items
         */
        SwatchColorPicker.prototype._getFirstExecutableItemsPerChunk = function () {
            // Make sure every item has an index, then filter
            // the results so that you only get the executable items,
            // finally filter those items down to just the items that are
            // either the start of a chunk or an menu item
            return (this.props.swatchColorPickerItems.map(function (item, index) { return tslib_1.__assign({}, item, { index: index }); })
                .filter(function (item) { return (item.type === SwatchColorPicker_Props_1.SwatchColorPickerItemType.Cell || item.type === SwatchColorPicker_Props_1.SwatchColorPickerItemType.MenuItem); })
                .filter(function (item, filteredIndex, items) {
                return (filteredIndex === 0 ||
                    item.type === SwatchColorPicker_Props_1.SwatchColorPickerItemType.MenuItem ||
                    (item.index - items[filteredIndex - 1].index !== 1));
            }));
        };
        /**
         * Render the separator
         * @param item - The divider item to get the data to render from
         * @returns {JSX.Element} - Element that represents the separator
         */
        SwatchColorPicker.prototype._renderSeparator = function (item) {
            return this._renderHeaderOrDivider(item, 'separator', styles.divider);
        };
        /**
         * Render the header
         * @param item - The header item to get the data to render from
         * @returns {JSX.Element} - Element that represents the header
         */
        SwatchColorPicker.prototype._renderHeader = function (item) {
            return this._renderHeaderOrDivider(item, 'heading', styles.header);
        };
        /**
         * Handle the rendering of the header/divider
         * @param item - The item to get the data to render from
         * @param role - The role of the element
         * @param className - the className to use
         * @returns {JSX.Element} - Element that represents the header
         */
        SwatchColorPicker.prototype._renderHeaderOrDivider = function (item, role, className) {
            return React.createElement("div", { role: role, key: item.id, className: className }, item.label && item.label);
        };
        /**
         * Render a cell or menu item
         * @param item - The item to render
         * @param posInSet - Optional, the position in the set of the item
         * @param setSize - Optional, the total set size this item is in
         * @returns {JSX.Element} - Element representing the item
         */
        SwatchColorPicker.prototype._renderOption = function (item, posInSet, setSize) {
            var id = this._id;
            var isCell = item.type === SwatchColorPicker_Props_1.SwatchColorPickerItemType.Cell;
            var optionProps;
            if (isCell) {
                optionProps = {
                    className: styles.cell,
                    onClick: this._onCellClick,
                    onHover: this.props.onCellHovered,
                    onFocus: this.props.onCellFocused,
                    role: 'gridcell',
                    selectedIndex: this.state.selectedIndex
                };
            }
            else {
                optionProps = {
                    posInSet: posInSet && posInSet,
                    setSize: setSize && setSize,
                    className: styles.item,
                    onClick: this._onMenuItemClick,
                    onFocus: this._clearFocusColorOnMenuItem,
                    role: this.props.menuButtonProps ? 'menuitem' : 'button'
                };
            }
            return (React.createElement(SwatchColorPickerOption, tslib_1.__assign({ item: item, id: this._id, key: id + item.id, disabled: this.props.disabled || item.disabled, cellShape: this.props.cellShape }, optionProps)));
        };
        /**
         * Handle the click on a cell
         * @param item - The cell that the click was fired against
         */
        SwatchColorPicker.prototype._onCellClick = function (item) {
            if (this.props.disabled || item.disabled) {
                return;
            }
            var index = item.index;
            // If we have a valid index and it is not already
            // selected, select it
            if (index >= 0 && index !== this.state.selectedIndex) {
                if (this.props.onColorChanged) {
                    this.props.onColorChanged(item.id, item.color);
                }
                this.setState({
                    selectedIndex: index,
                    expanded: false
                });
            }
            else if (index === this.state.selectedIndex) {
                // The index that got the click was already selected,
                // clear the selection
                this._clearColors([this.props.onColorChanged, this.props.onCellHovered, this.props.onCellFocused]);
                this.setState({
                    selectedIndex: undefined,
                    expanded: false
                });
            }
        };
        /**
         * Handle the click on a menu item
         * @param item - The menu item that the click was fired against
         */
        SwatchColorPicker.prototype._onMenuItemClick = function (item) {
            if (this.props.disabled || item.disabled) {
                return;
            }
            if (this.props.onMenuItemClick) {
                this.props.onMenuItemClick(item);
            }
            // Make sure to clear any hover/focus colors
            this._clearColors([this.props.onCellHovered, this.props.onCellFocused]);
            this.setState({
                expanded: false
            });
        };
        /**
         * Clear the colors by calling the given callbacks
         * @param callbacks - The callbacks to handle the clear operation
         */
        SwatchColorPicker.prototype._clearColors = function (callbacks) {
            callbacks.forEach(function (callback) {
                if (callback) {
                    callback();
                }
            });
        };
        /**
         * Clear the focus color
         * @param id - The id of the item
         * @param color - The color for the item
         */
        SwatchColorPicker.prototype._clearFocusColorOnMenuItem = function (id, color) {
            this._clearColors([this.props.onCellFocused]);
        };
        /**
         * onClick Handler for the button
         */
        SwatchColorPicker.prototype._onButtonClick = function () {
            if (this.props.disabled) {
                return;
            }
            if (this.state.expanded) {
                this._onDismiss();
            }
            this.setState({
                expanded: this.props.disabled ? false : !this.state.expanded
            });
        };
        /**
         * Render the menu (callout) for when the swatch color picker
         * is behind a button and is expanded
         */
        SwatchColorPicker.prototype._onRenderContainer = function () {
            return (React.createElement(Callout_1.Callout, { isBeakVisible: false, gapSpace: 0, doNotLayer: false, role: 'menu', directionalHint: ContextualMenu_1.DirectionalHint.bottomLeftEdge, className: Utilities_1.css('ms-swatchColorPickerMenu', styles.swatchColorPickerContainer), targetElement: this._buttonWrapper, onDismiss: this._onDismiss, setInitialFocus: true },
                React.createElement(SwatchColorPickerBody, tslib_1.__assign({}, this.props, { onRenderItems: this._onRenderItems }))));
        };
        /**
         * Handle dismissing the menu
         */
        SwatchColorPicker.prototype._onDismiss = function () {
            this._clearColors([this.props.onCellHovered, this.props.onCellFocused]);
            this.setState({
                expanded: false
            });
        };
        return SwatchColorPicker;
    }(Utilities_1.BaseComponent));
    SwatchColorPicker.defaultProps = {
        cellShape: 'circle',
        updateButtonIconWithColor: false,
        disabled: false
    };
    tslib_1.__decorate([
        Utilities_1.autobind
    ], SwatchColorPicker.prototype, "_onRenderItems", null);
    tslib_1.__decorate([
        Utilities_1.autobind
    ], SwatchColorPicker.prototype, "_renderOption", null);
    tslib_1.__decorate([
        Utilities_1.autobind
    ], SwatchColorPicker.prototype, "_onCellClick", null);
    tslib_1.__decorate([
        Utilities_1.autobind
    ], SwatchColorPicker.prototype, "_onMenuItemClick", null);
    tslib_1.__decorate([
        Utilities_1.autobind
    ], SwatchColorPicker.prototype, "_clearFocusColorOnMenuItem", null);
    tslib_1.__decorate([
        Utilities_1.autobind
    ], SwatchColorPicker.prototype, "_onButtonClick", null);
    tslib_1.__decorate([
        Utilities_1.autobind
    ], SwatchColorPicker.prototype, "_onRenderContainer", null);
    tslib_1.__decorate([
        Utilities_1.autobind
    ], SwatchColorPicker.prototype, "_onDismiss", null);
    exports.SwatchColorPicker = SwatchColorPicker;
    var SwatchColorPickerMenuButton = (function (_super) {
        tslib_1.__extends(SwatchColorPickerMenuButton, _super);
        function SwatchColorPickerMenuButton() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        SwatchColorPickerMenuButton.prototype.render = function () {
            var _a = this.props, color = _a.color, expanded = _a.expanded, disabled = _a.disabled, onClick = _a.onClick, onRenderContainer = _a.onRenderContainer, menuIconProps = _a.menuIconProps, menuButtonProps = _a.menuButtonProps;
            return (React.createElement("div", null,
                React.createElement(Button_1.DefaultButton, tslib_1.__assign({}, menuButtonProps, { style: { color: color && color }, className: Utilities_1.css('ms-swatchColorPickerButton', {
                        'is-expanded': expanded
                    }), onClick: onClick, "aria-haspopup": true, "aria-expanded": !disabled && expanded, disabled: disabled, menuIconProps: menuIconProps ?
                        menuIconProps :
                        { iconName: 'chevronDown' } })),
                (!disabled && expanded) &&
                    onRenderContainer()));
        };
        return SwatchColorPickerMenuButton;
    }(Utilities_1.BaseComponent));
    SwatchColorPickerMenuButton.defaultProps = {
        expanded: false,
        disabled: false
    };
    var SwatchColorPickerBody = (function (_super) {
        tslib_1.__extends(SwatchColorPickerBody, _super);
        function SwatchColorPickerBody() {
            return _super !== null && _super.apply(this, arguments) || this;
        }
        SwatchColorPickerBody.prototype.render = function () {
            var _a = this.props, swatchColorPickerItems = _a.swatchColorPickerItems, columnCount = _a.columnCount, onRenderItems = _a.onRenderItems;
            return (React.createElement(FocusZone_1.FocusZone, { isCircularNavigation: true, className: Utilities_1.css('ms-swatchColorPickerBodyContainer', styles.swatchColorPickerContainer) }, onRenderItems(swatchColorPickerItems.map(function (item, index) { return tslib_1.__assign({}, item, { index: index }); }))));
        };
        return SwatchColorPickerBody;
    }(Utilities_1.BaseComponent));
});

//# sourceMappingURL=SwatchColorPicker.js.map
