office-ui-fabric-react
Version:
Reusable React components for building experiences for Office 365.
327 lines • 17.5 kB
JavaScript
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