office-ui-fabric-react
Version: 
Reusable React components for building experiences for Office 365.
285 lines • 19.3 kB
JavaScript
define(["require", "exports", "tslib", "react", "../../Utilities", "../../FocusZone", "../../ContextualMenu", "../../utilities/contextualMenu/index", "../../Icon", "../../Styling", "../../Tooltip", "./CommandBar.scss", "../../Utilities"], function (require, exports, tslib_1, React, Utilities_1, FocusZone_1, ContextualMenu_1, index_1, Icon_1, Styling_1, Tooltip_1, stylesImport, Utilities_2) {
    "use strict";
    Object.defineProperty(exports, "__esModule", { value: true });
    var styles = stylesImport;
    var OVERFLOW_KEY = 'overflow';
    var OVERFLOW_WIDTH = 41.5;
    var CommandBar = /** @class */ (function (_super) {
        tslib_1.__extends(CommandBar, _super);
        function CommandBar(props) {
            var _this = _super.call(this, props) || this;
            _this._searchSurface = Utilities_2.createRef();
            _this._commandSurface = Utilities_2.createRef();
            _this._commandBarRegion = Utilities_2.createRef();
            _this._farCommandSurface = Utilities_2.createRef();
            _this._focusZone = Utilities_2.createRef();
            _this._overflow = Utilities_2.createRef();
            _this.state = _this._getStateFromProps(props);
            _this._id = Utilities_1.getId('CommandBar');
            return _this;
        }
        CommandBar.prototype.componentDidMount = function () {
            // Asynchronously update command bar layout to eliminate forced synchronous reflow
            this._asyncMeasure();
            this._events.on(window, 'resize', this._updateRenderedItems);
        };
        CommandBar.prototype.componentWillReceiveProps = function (nextProps) {
            this.setState(this._getStateFromProps(nextProps));
            this._commandItemWidths = null;
        };
        CommandBar.prototype.componentDidUpdate = function (prevProps, prevStates) {
            if (!this._commandItemWidths) {
                // Asynchronously update command bar layout to eliminate forced synchronous reflow
                this._asyncMeasure();
            }
        };
        CommandBar.prototype.render = function () {
            var _this = this;
            var _a = this.props, isSearchBoxVisible = _a.isSearchBoxVisible, searchPlaceholderText = _a.searchPlaceholderText, className = _a.className;
            var _b = this.state, renderedItems = _b.renderedItems, contextualMenuProps = _b.contextualMenuProps, expandedMenuItemKey = _b.expandedMenuItemKey, expandedMenuId = _b.expandedMenuId, renderedOverflowItems = _b.renderedOverflowItems, contextualMenuTarget = _b.contextualMenuTarget, renderedFarItems = _b.renderedFarItems;
            var searchBox;
            if (isSearchBoxVisible) {
                searchBox = (React.createElement("div", { className: Utilities_1.css('ms-CommandBarSearch', styles.search), ref: this._searchSurface },
                    React.createElement("input", { className: Utilities_1.css('ms-CommandBarSearch-input', styles.searchInput), type: 'text', placeholder: searchPlaceholderText }),
                    React.createElement("div", { className: Utilities_1.css('ms-CommandBarSearch-iconWrapper ms-CommandBarSearch-iconSearchWrapper', styles.searchIconWrapper, styles.searchIconSearchWrapper) }, React.createElement(Icon_1.Icon, { iconName: 'Search' })),
                    React.createElement("div", { className: Utilities_1.css('ms-CommandBarSearch-iconWrapper ms-CommandBarSearch-iconClearWrapper', Styling_1.FontClassNames.small, styles.searchIconWrapper, styles.searchIconClearWrapper) },
                        React.createElement(Icon_1.Icon, { iconName: 'cancel' }))));
            }
            // Total # of menu items is regular items + far items + 1 for the ellipsis, if necessary
            var setSize = renderedItems.length + renderedFarItems.length + (renderedOverflowItems && renderedOverflowItems.length > 0 ? 1 : 0);
            var posInSet = 1;
            return (React.createElement("div", { className: Utilities_1.css('ms-CommandBar', styles.root, className), ref: this._commandBarRegion },
                searchBox,
                React.createElement(FocusZone_1.FocusZone, { ref: this._focusZone, className: styles.container, direction: FocusZone_1.FocusZoneDirection.horizontal, role: 'menubar' },
                    React.createElement("div", { className: Utilities_1.css('ms-CommandBar-primaryCommands', styles.primaryCommands), ref: this._commandSurface }, renderedItems.map(function (item) { return (_this._renderItemInCommandBar(item, posInSet++, setSize, expandedMenuItemKey)); }).concat((renderedOverflowItems && renderedOverflowItems.length) ? [
                        React.createElement("div", { className: Utilities_1.css('ms-CommandBarItem', styles.item), key: OVERFLOW_KEY, ref: this._overflow },
                            React.createElement("button", { type: 'button', id: this._id + OVERFLOW_KEY, className: Utilities_1.css('ms-CommandBarItem-link', styles.itemLink, (_c = {},
                                    _c['is-expanded ' + styles.itemLinkIsExpanded] = (expandedMenuItemKey === OVERFLOW_KEY),
                                    _c)), onClick: this._onOverflowClick, role: 'menuitem', "aria-expanded": this.state.expandedMenuItemKey === OVERFLOW_KEY, "aria-label": this.props.elipisisAriaLabel || '', "aria-haspopup": true, "aria-setsize": setSize, "aria-posinset": posInSet++, "data-automation-id": 'commandBarOverflow' },
                                React.createElement(Icon_1.Icon, { className: Utilities_1.css('ms-CommandBarItem-overflow', styles.itemOverflow), iconName: 'more' })))
                    ] : [])),
                    React.createElement("div", { className: Utilities_1.css('ms-CommandBar-sideCommands', styles.sideCommands), ref: this._farCommandSurface }, renderedFarItems.map(function (item) { return (_this._renderItemInCommandBar(item, posInSet++, setSize, expandedMenuItemKey, true)); }))),
                (contextualMenuProps) ?
                    (React.createElement(ContextualMenu_1.ContextualMenu, tslib_1.__assign({ className: Utilities_1.css('ms-CommandBar-menuHost'), directionalHint: 7 /* bottomAutoEdge */ }, contextualMenuProps, { target: contextualMenuTarget, labelElementId: expandedMenuId, onDismiss: this._onContextMenuDismiss }))) : (null)));
            var _c;
        };
        CommandBar.prototype.focus = function () {
            var focusZone = this._focusZone.value;
            focusZone && focusZone.focus();
        };
        CommandBar.prototype._renderItemInCommandBar = function (item, posInSet, setSize, expandedMenuItemKey, isFarItem) {
            if (item.onRender) {
                return (React.createElement("div", { className: Utilities_1.css('ms-CommandBarItem', styles.item, item.className), key: item.key, ref: item.key }, item.onRender(item, this._onContextMenuDismiss)));
            }
            var itemKey = item.key || String(posInSet);
            var isLink = item.onClick || index_1.hasSubmenu(item);
            var className = Utilities_1.css(isLink ? ('ms-CommandBarItem-link ' + styles.itemLink) : ('ms-CommandBarItem-text ' + styles.itemText), !item.name && ('ms-CommandBarItem--noName ' + styles.itemLinkIsNoName), (expandedMenuItemKey === item.key) && ('is-expanded ' + styles.itemLinkIsExpanded));
            var hasIcon = !!item.icon || !!item.iconProps;
            var isNameVisible = !!item.name && !item.iconOnly;
            var ariaLabel = item.ariaLabel || (item.iconOnly ? item.name : undefined);
            var command;
            if (isLink) {
                command = (React.createElement("button", tslib_1.__assign({}, Utilities_1.getNativeProps(item, Utilities_1.buttonProperties), { id: this._id + item.key, className: className, onClick: this._onItemClick(item), "data-command-key": itemKey, "aria-haspopup": index_1.hasSubmenu(item), "aria-expanded": index_1.hasSubmenu(item) ? expandedMenuItemKey === item.key : undefined, role: 'menuitem', "aria-label": ariaLabel, "aria-setsize": setSize, "aria-posinset": posInSet }),
                    (hasIcon) ? this._renderIcon(item) : (null),
                    isNameVisible && (React.createElement("span", { className: Utilities_1.css('ms-CommandBarItem-commandText', styles.itemCommandText) }, item.name)),
                    index_1.hasSubmenu(item) ? (React.createElement(Icon_1.Icon, { className: Utilities_1.css('ms-CommandBarItem-chevronDown', styles.itemChevronDown), iconName: 'ChevronDown' })) : (null)));
            }
            else if (item.href) {
                // Allow the disabled property on anchor elements for commandbar
                command = (React.createElement("a", tslib_1.__assign({}, Utilities_1.getNativeProps(item, Utilities_1.anchorProperties.concat(['disabled'])), { id: this._id + item.key, className: className, href: item.disabled ? undefined : item.href, "data-command-key": itemKey, "aria-haspopup": index_1.hasSubmenu(item), role: 'menuitem', "aria-label": ariaLabel, "aria-setsize": setSize, "aria-posinset": posInSet }),
                    (hasIcon) ? this._renderIcon(item) : (null),
                    isNameVisible && (React.createElement("span", { className: Utilities_1.css('ms-CommandBarItem-commandText', styles.itemCommandText) }, item.name))));
            }
            else {
                // Allow the disabled property on div elements for commandbar
                command = (React.createElement("div", tslib_1.__assign({}, Utilities_1.getNativeProps(item, Utilities_1.divProperties.concat(['disabled'])), { id: this._id + item.key, className: className, "data-command-key": itemKey, "aria-haspopup": index_1.hasSubmenu(item), "aria-label": ariaLabel, "aria-setsize": setSize, "aria-posinset": posInSet }),
                    (hasIcon) ? this._renderIcon(item) : (null),
                    (isNameVisible) && (React.createElement("span", { className: Utilities_1.css('ms-CommandBarItem-commandText', styles.itemCommandText), "aria-hidden": 'true', role: 'presentation' }, item.name))));
            }
            if (item.iconOnly && item.name) {
                command = (React.createElement(Tooltip_1.TooltipHost, { content: item.name }, command));
            }
            return (React.createElement("div", { className: Utilities_1.css('ms-CommandBarItem', styles.item, item.className), key: itemKey, ref: itemKey }, command));
        };
        CommandBar.prototype._renderIcon = function (item) {
            // Only present to allow continued use of item.icon which is deprecated.
            var iconProps = item.iconProps ? item.iconProps : {
                iconName: item.icon
            };
            // Use the default icon color for the known icon names
            var iconColorClassName = iconProps.iconName === 'None' ? '' : ('ms-CommandBarItem-iconColor ' + styles.itemIconColor);
            var iconClassName = Utilities_1.css('ms-CommandBarItem-icon', styles.itemIcon, iconColorClassName, iconProps.className);
            return React.createElement(Icon_1.Icon, tslib_1.__assign({}, iconProps, { className: iconClassName }));
        };
        CommandBar.prototype._asyncMeasure = function () {
            var _this = this;
            this._async.requestAnimationFrame(function () {
                _this._updateItemMeasurements();
                _this._updateRenderedItems();
            });
        };
        CommandBar.prototype._updateItemMeasurements = function () {
            // the generated width for overflow is 35 in chrome, 38 in IE, but the actual value is 41.5
            if (this._overflow.value || (this.props.overflowItems && this.props.overflowItems.length)) {
                this._overflowWidth = OVERFLOW_WIDTH;
            }
            else {
                this._overflowWidth = 0;
            }
            if (!this._commandItemWidths) {
                this._commandItemWidths = {};
            }
            for (var i = 0; i < this.props.items.length; i++) {
                var item = this.props.items[i];
                if (!this._commandItemWidths[item.key]) {
                    var el = this.refs[item.key];
                    if (el) {
                        this._commandItemWidths[item.key] = el.getBoundingClientRect().width;
                    }
                }
            }
        };
        CommandBar.prototype._updateRenderedItems = function () {
            var _a = this.props, items = _a.items, overflowItems = _a.overflowItems;
            var commandSurface = this._commandSurface.value;
            var farCommandSurface = this._farCommandSurface.value;
            var commandBarRegion = this._commandBarRegion.value;
            var searchSurface = this._searchSurface.value;
            var renderedItems = items.slice();
            var renderedOverflowItems = overflowItems;
            var consumedWidth = 0;
            var isOverflowVisible = overflowItems && overflowItems.length;
            if (!commandSurface || !commandBarRegion) {
                return;
            }
            var style = window.getComputedStyle(commandSurface);
            var availableWidth = commandBarRegion.clientWidth - parseInt(style.marginLeft, 10) - parseInt(style.marginRight, 10);
            if (searchSurface) {
                availableWidth -= searchSurface.getBoundingClientRect().width;
            }
            if (farCommandSurface) {
                availableWidth -= farCommandSurface.getBoundingClientRect().width;
            }
            if (isOverflowVisible) {
                availableWidth -= this._overflowWidth;
            }
            if (!this._commandItemWidths) {
                this._asyncMeasure();
                return;
            }
            for (var i = 0; i < renderedItems.length; i++) {
                var item = renderedItems[i];
                var itemWidth = this._commandItemWidths[item.key];
                if ((consumedWidth + itemWidth) >= availableWidth) {
                    if (i > 0 && !isOverflowVisible && (availableWidth - consumedWidth) < OVERFLOW_WIDTH) {
                        i--;
                    }
                    renderedOverflowItems = renderedItems.splice(i).concat(overflowItems);
                    break;
                }
                else {
                    consumedWidth += itemWidth;
                }
            }
            var renderedContextualMenuProps = this._getContextualMenuPropsAfterUpdate(renderedItems.concat(this.state.renderedFarItems), renderedOverflowItems);
            this.setState({
                renderedItems: renderedItems,
                renderedOverflowItems: renderedOverflowItems,
                expandedMenuItemKey: renderedContextualMenuProps ? this.state.expandedMenuItemKey : undefined,
                contextualMenuProps: renderedContextualMenuProps,
                contextualMenuTarget: renderedContextualMenuProps ? this.state.contextualMenuTarget : undefined
            });
        };
        CommandBar.prototype._onItemClick = function (item) {
            var _this = this;
            return function (ev) {
                if (item.key === _this.state.expandedMenuItemKey || !index_1.hasSubmenu(item)) {
                    _this._onContextMenuDismiss();
                }
                else {
                    _this.setState({
                        expandedMenuId: ev.currentTarget.id,
                        expandedMenuItemKey: item.key,
                        contextualMenuProps: _this._getContextualMenuPropsFromItem(item),
                        contextualMenuTarget: ev.currentTarget
                    });
                }
                if (item.onClick) {
                    item.onClick(ev, item);
                }
            };
        };
        CommandBar.prototype._onOverflowClick = function (ev) {
            if (this.state.expandedMenuItemKey === OVERFLOW_KEY) {
                this._onContextMenuDismiss();
            }
            else {
                this.setState({
                    expandedMenuId: ev.currentTarget.id,
                    expandedMenuItemKey: OVERFLOW_KEY,
                    contextualMenuProps: { items: this.state.renderedOverflowItems },
                    contextualMenuTarget: ev.currentTarget
                });
            }
        };
        CommandBar.prototype._onContextMenuDismiss = function (ev) {
            var commandSurface = this._commandSurface.value;
            if (!ev || !ev.relatedTarget || commandSurface && !commandSurface.contains(ev.relatedTarget)) {
                var contextualMenuProps = this.state.contextualMenuProps;
                if (contextualMenuProps && contextualMenuProps.onDismiss) {
                    this.state.contextualMenuProps.onDismiss(ev);
                }
                this.setState({
                    expandedMenuItemKey: undefined,
                    contextualMenuProps: undefined,
                    contextualMenuTarget: undefined
                });
            }
            else {
                ev.stopPropagation();
                ev.preventDefault();
            }
        };
        CommandBar.prototype._getStateFromProps = function (nextProps) {
            return {
                renderedItems: nextProps.items || [],
                contextualMenuProps: this._getContextualMenuPropsAfterUpdate(nextProps.items.concat(nextProps.farItems), nextProps.overflowItems),
                renderedFarItems: nextProps.farItems || undefined
            };
        };
        CommandBar.prototype._getContextualMenuPropsAfterUpdate = function (renderedItems, overflowItems) {
            var _this = this;
            if (this.state && this.state.expandedMenuItemKey) {
                if (this.state.expandedMenuItemKey === OVERFLOW_KEY) {
                    // Keep the overflow menu open
                    return { items: overflowItems };
                }
                else {
                    // Find the currently open key in the new props
                    var matchingItem = renderedItems.filter(function (item) { return item.key === _this.state.expandedMenuItemKey; });
                    if (matchingItem.length === 1) {
                        return this._getContextualMenuPropsFromItem(matchingItem[0]);
                    }
                }
            }
            return null;
        };
        CommandBar.prototype._getContextualMenuPropsFromItem = function (item) {
            return item.subMenuProps || (item.items && { items: item.items });
        };
        CommandBar.defaultProps = {
            items: [],
            overflowItems: [],
            farItems: []
        };
        tslib_1.__decorate([
            Utilities_1.autobind
        ], CommandBar.prototype, "_onOverflowClick", null);
        tslib_1.__decorate([
            Utilities_1.autobind
        ], CommandBar.prototype, "_onContextMenuDismiss", null);
        return CommandBar;
    }(Utilities_1.BaseComponent));
    exports.CommandBar = CommandBar;
});
//# sourceMappingURL=CommandBar.js.map