UNPKG

office-ui-fabric-react

Version:

Reusable React components for building experiences for Office 365.

327 lines • 17.5 kB
import * as tslib_1 from "tslib"; import * as React from 'react'; import { BaseComponent, anchorProperties, assign, autobind, buttonProperties, getId, getNativeProps } from '../../Utilities'; import { Icon } from '../../Icon'; import { ContextualMenu } from '../../ContextualMenu'; import { getBaseButtonClassNames } from './BaseButton.classNames'; import { getClassNames as getBaseSplitButtonClassNames } from './SplitButton/SplitButton.classNames'; var BaseButton = /** @class */ (function (_super) { tslib_1.__extends(BaseButton, _super); function BaseButton(props, rootClassName) { var _this = _super.call(this, props) || this; _this._warnConditionallyRequiredProps(['menuProps', 'onClick'], 'split', _this.props.split); _this._warnDeprecations({ rootProps: undefined }); _this._labelId = getId(); _this._descriptionId = getId(); _this._ariaDescriptionId = getId(); _this.state = { menuProps: null }; return _this; } Object.defineProperty(BaseButton.prototype, "_isSplitButton", { get: function () { return (!!this.props.menuProps && !!this.props.onClick) && this.props.split === true; }, enumerable: true, configurable: true }); Object.defineProperty(BaseButton.prototype, "_isExpanded", { get: function () { return !!this.state.menuProps; }, enumerable: true, configurable: true }); BaseButton.prototype.render = function () { var _a = this.props, ariaDescription = _a.ariaDescription, ariaLabel = _a.ariaLabel, ariaHidden = _a.ariaHidden, className = _a.className, description = _a.description, disabled = _a.disabled, primaryDisabled = _a.primaryDisabled, href = _a.href, iconProps = _a.iconProps, menuIconProps = _a.menuIconProps, styles = _a.styles, text = _a.text, checked = _a.checked, variantClassName = _a.variantClassName, theme = _a.theme, getClassNames = _a.getClassNames; var menuProps = this.state.menuProps; // Button is disabled if the whole button (in case of splitbutton is disabled) or if the primary action is disabled var isPrimaryButtonDisabled = (disabled || primaryDisabled); this._classNames = getClassNames ? getClassNames(theme, className, variantClassName, iconProps && iconProps.className, menuIconProps && menuIconProps.className, isPrimaryButtonDisabled, checked, !!this.state.menuProps, this.props.split) : getBaseButtonClassNames(styles, className, variantClassName, iconProps && iconProps.className, menuIconProps && menuIconProps.className, isPrimaryButtonDisabled, checked, !!this.state.menuProps, this.props.split); var _b = this, _ariaDescriptionId = _b._ariaDescriptionId, _labelId = _b._labelId, _descriptionId = _b._descriptionId; // Anchor tag cannot be disabled hence in disabled state rendering // anchor button as normal button var renderAsAnchor = !isPrimaryButtonDisabled && !!href; var tag = renderAsAnchor ? 'a' : 'button'; var nativeProps = getNativeProps(assign(renderAsAnchor ? {} : { type: 'button' }, this.props.rootProps, this.props), renderAsAnchor ? anchorProperties : buttonProperties, [ 'disabled' // let disabled buttons be focused and styled as disabled. ]); // Check for ariaDescription, description or aria-describedby in the native props to determine source of aria-describedby // otherwise default to null. var ariaDescribedBy; if (ariaDescription) { ariaDescribedBy = _ariaDescriptionId; } else if (description) { ariaDescribedBy = _descriptionId; } else if (nativeProps['aria-describedby']) { ariaDescribedBy = nativeProps['aria-describedby']; } else { ariaDescribedBy = null; } // If an explicit ariaLabel is given, use that as the label and we're done. // If an explicit aria-labelledby is given, use that and we're done. // If any kind of description is given (which will end up as an aria-describedby attribute), // set the labelledby element. Otherwise, the button is labeled implicitly by the descendent // text on the button (if it exists). Never set both aria-label and aria-labelledby. var ariaLabelledBy = null; if (!ariaLabel) { if (nativeProps['aria-labelledby']) { ariaLabelledBy = nativeProps['aria-labelledby']; } else if (ariaDescribedBy) { ariaLabelledBy = text ? _labelId : null; } } var buttonProps = assign(nativeProps, { className: this._classNames.root, ref: this._resolveRef('_buttonElement'), 'disabled': isPrimaryButtonDisabled, 'aria-label': ariaLabel, 'aria-labelledby': ariaLabelledBy, 'aria-describedby': ariaDescribedBy, 'data-is-focusable': (this.props['data-is-focusable'] === false || disabled) ? false : true, 'aria-pressed': checked }); if (ariaHidden) { buttonProps['aria-hidden'] = true; } if (this._isSplitButton) { return (this._onRenderSplitButtonContent(tag, buttonProps)); } else if (this.props.menuProps) { assign(buttonProps, { 'onKeyDown': this._onMenuKeyDown, 'onClick': this._onMenuClick, 'aria-expanded': this._isExpanded, 'aria-owns': this.state.menuProps ? this._labelId + '-menu' : null, 'aria-haspopup': true }); } return this._onRenderContent(tag, buttonProps); }; BaseButton.prototype.componentDidUpdate = function (prevProps, prevState) { // If Button's menu was closed, run onAfterMenuDismiss if (this.props.onAfterMenuDismiss && prevState.menuProps && !this.state.menuProps) { this.props.onAfterMenuDismiss(); } }; BaseButton.prototype.focus = function () { if (this._buttonElement) { this._buttonElement.focus(); } }; BaseButton.prototype.dismissMenu = function () { this.setState({ menuProps: null }); }; BaseButton.prototype._onRenderContent = function (tag, buttonProps) { var props = this.props; var Tag = tag; var menuIconProps = props.menuIconProps, menuProps = props.menuProps, _a = props.onRenderIcon, onRenderIcon = _a === void 0 ? this._onRenderIcon : _a, _b = props.onRenderAriaDescription, onRenderAriaDescription = _b === void 0 ? this._onRenderAriaDescription : _b, _c = props.onRenderChildren, onRenderChildren = _c === void 0 ? this._onRenderChildren : _c, _d = props.onRenderMenu, onRenderMenu = _d === void 0 ? this._onRenderMenu : _d, _e = props.onRenderMenuIcon, onRenderMenuIcon = _e === void 0 ? this._onRenderMenuIcon : _e; var Content = (React.createElement(Tag, tslib_1.__assign({}, buttonProps), React.createElement("div", { className: this._classNames.flexContainer }, onRenderIcon(props, this._onRenderIcon), this._onRenderTextContents(), onRenderAriaDescription(props, this._onRenderAriaDescription), onRenderChildren(props, this._onRenderChildren), !this._isSplitButton && (menuProps || menuIconProps || this.props.onRenderMenuIcon) && onRenderMenuIcon(this.props, this._onRenderMenuIcon), this.state.menuProps && !this.state.menuProps.doNotLayer && onRenderMenu(menuProps, this._onRenderMenu)))); if (menuProps && menuProps.doNotLayer) { return (React.createElement("div", { style: { display: 'inline-block' } }, Content, this.state.menuProps && onRenderMenu(menuProps, this._onRenderMenu))); } return Content; }; BaseButton.prototype._onRenderIcon = function (buttonProps, defaultRender) { var iconProps = this.props.iconProps; if (iconProps) { return (React.createElement(Icon, tslib_1.__assign({}, iconProps, { className: this._classNames.icon }))); } return null; }; BaseButton.prototype._onRenderTextContents = function () { var _a = this.props, text = _a.text, children = _a.children, description = _a.description, _b = _a.onRenderText, onRenderText = _b === void 0 ? this._onRenderText : _b, _c = _a.onRenderDescription, onRenderDescription = _c === void 0 ? this._onRenderDescription : _c; if (text || typeof (children) === 'string' || description) { return (React.createElement("div", { className: this._classNames.textContainer }, onRenderText(this.props, this._onRenderText), onRenderDescription(this.props, this._onRenderDescription))); } return ([ onRenderText(this.props, this._onRenderText), onRenderDescription(this.props, this._onRenderDescription) ]); }; BaseButton.prototype._onRenderText = function () { var text = this.props.text; var children = this.props.children; // For backwards compat, we should continue to take in the text content from children. if (text === undefined && typeof (children) === 'string') { text = children; } if (text) { return (React.createElement("div", { key: this._labelId, className: this._classNames.label, id: this._labelId }, text)); } return null; }; BaseButton.prototype._onRenderChildren = function () { var children = this.props.children; // If children is just a string, either it or the text will be rendered via onRenderLabel // If children is another component, it will be rendered after text if (typeof (children) === 'string') { return null; } return children; }; BaseButton.prototype._onRenderDescription = function (props) { var description = this.props.description; // ms-Button-description is only shown when the button type is compound. // In other cases it will not be displayed. return description ? (React.createElement("div", { key: this._descriptionId, className: this._classNames.description, id: this._descriptionId }, description)) : (null); }; BaseButton.prototype._onRenderAriaDescription = function () { var ariaDescription = this.props.ariaDescription; // If ariaDescription is given, descriptionId will be assigned to ariaDescriptionSpan, // otherwise it will be assigned to descriptionSpan. return ariaDescription ? (React.createElement("span", { className: this._classNames.screenReaderText, id: this._ariaDescriptionId }, ariaDescription)) : (null); }; BaseButton.prototype._onRenderMenuIcon = function (props) { var menuIconProps = this.props.menuIconProps; return (React.createElement(Icon, tslib_1.__assign({ iconName: 'ChevronDown' }, menuIconProps, { className: this._classNames.menuIcon }))); }; BaseButton.prototype._onRenderMenu = function (menuProps) { var _a = menuProps.onDismiss, onDismiss = _a === void 0 ? this._dismissMenu : _a; return (React.createElement(ContextualMenu, tslib_1.__assign({ id: this._labelId + '-menu', directionalHint: 4 /* bottomLeftEdge */ }, menuProps, { className: 'ms-BaseButton-menuhost ' + menuProps.className, target: this._isSplitButton ? this._splitButtonContainer : this._buttonElement, labelElementId: this._labelId, onDismiss: onDismiss }))); }; BaseButton.prototype._dismissMenu = function () { this.setState({ menuProps: null }); }; BaseButton.prototype._onToggleMenu = function () { var menuProps = this.props.menuProps; var currentMenuProps = this.state.menuProps; this.setState({ menuProps: currentMenuProps ? null : menuProps }); }; BaseButton.prototype._onRenderSplitButtonContent = function (tag, buttonProps) { var _a = this.props, _b = _a.styles, styles = _b === void 0 ? {} : _b, disabled = _a.disabled, checked = _a.checked, getSplitButtonClassNames = _a.getSplitButtonClassNames, onClick = _a.onClick, primaryDisabled = _a.primaryDisabled; var classNames = getSplitButtonClassNames ? getSplitButtonClassNames(!!disabled, !!this.state.menuProps, !!checked) : styles && getBaseSplitButtonClassNames(styles, !!disabled, !!this.state.menuProps, !!checked); buttonProps = tslib_1.__assign({}, buttonProps, { onClick: undefined }); return (React.createElement("div", { role: 'button', "aria-labelledby": buttonProps.ariaLabel, "aria-disabled": disabled, "aria-haspopup": true, "aria-expanded": this._isExpanded, "aria-pressed": this.props.checked, "aria-describedby": buttonProps.ariaDescription, className: classNames && classNames.splitButtonContainer, onKeyDown: this._onMenuKeyDown, ref: this._resolveRef('_splitButtonContainer'), "data-is-focusable": true, onClick: !disabled && !primaryDisabled ? onClick : undefined }, React.createElement("span", { style: { 'display': 'flex' } }, this._onRenderContent(tag, buttonProps), this._onRenderSplitButtonMenuButton(classNames), this._onRenderSplitButtonDivider(classNames)))); }; BaseButton.prototype._onRenderSplitButtonDivider = function (classNames) { if (classNames && classNames.divider) { return React.createElement("span", { className: classNames.divider }); } return null; }; BaseButton.prototype._onRenderSplitButtonMenuButton = function (classNames) { var menuIconProps = this.props.menuIconProps; var splitButtonAriaLabel = this.props.splitButtonAriaLabel; if (menuIconProps === undefined) { menuIconProps = { iconName: 'ChevronDown' }; } var splitButtonProps = { 'styles': classNames, 'checked': this.props.checked, 'disabled': this.props.disabled, 'onClick': this._onMenuClick, 'menuProps': undefined, 'iconProps': menuIconProps, 'ariaLabel': splitButtonAriaLabel, 'aria-haspopup': true, 'aria-expanded': this._isExpanded }; return React.createElement(BaseButton, tslib_1.__assign({}, splitButtonProps, { onMouseDown: this._onMouseDown })); }; BaseButton.prototype._onMouseDown = function (ev) { if (this.props.onMouseDown) { this.props.onMouseDown(ev); } ev.preventDefault(); }; BaseButton.prototype._onMenuKeyDown = function (ev) { if (this.props.onKeyDown) { this.props.onKeyDown(ev); } var onMenuClick = this.props.onMenuClick; if (onMenuClick) { onMenuClick(ev, this); } if (!ev.defaultPrevented && this.props.menuTriggerKeyCode !== null && ev.which === (this.props.menuTriggerKeyCode === undefined ? 40 /* down */ : this.props.menuTriggerKeyCode)) { this._onToggleMenu(); ev.preventDefault(); ev.stopPropagation(); } }; BaseButton.prototype._onMenuClick = function (ev) { var onMenuClick = this.props.onMenuClick; if (onMenuClick) { onMenuClick(ev, this); } if (!ev.defaultPrevented) { this._onToggleMenu(); ev.preventDefault(); ev.stopPropagation(); } }; BaseButton.defaultProps = { baseClassName: 'ms-Button', classNames: {}, styles: {}, split: false, }; tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onRenderIcon", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onRenderTextContents", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onRenderText", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onRenderChildren", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onRenderDescription", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onRenderAriaDescription", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onRenderMenuIcon", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onRenderMenu", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_dismissMenu", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onToggleMenu", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onMouseDown", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onMenuKeyDown", null); tslib_1.__decorate([ autobind ], BaseButton.prototype, "_onMenuClick", null); return BaseButton; }(BaseComponent)); export { BaseButton }; //# sourceMappingURL=BaseButton.js.map