UNPKG

office-ui-fabric-react

Version:

Reusable React components for building experiences for Office 365.

108 lines 5.25 kB
import * as tslib_1 from "tslib"; import * as React from 'react'; import { BaseComponent, divProperties, doesElementContainFocus, getDocument, getNativeProps, createRef } from '../../Utilities'; /** * This adds accessibility to Dialog and Panel controls */ var Popup = /** @class */ (function (_super) { tslib_1.__extends(Popup, _super); function Popup(props) { var _this = _super.call(this, props) || this; _this._root = createRef(); _this._onKeyDown = function (ev) { switch (ev.which) { case 27 /* escape */: if (_this.props.onDismiss) { _this.props.onDismiss(ev); ev.preventDefault(); ev.stopPropagation(); } break; } }; _this.state = { needsVerticalScrollBar: false }; return _this; } Popup.prototype.componentWillMount = function () { this._originalFocusedElement = getDocument().activeElement; }; Popup.prototype.componentDidMount = function () { if (!this._root.current) { return; } this._events.on(this._root.current, 'focus', this._onFocus, true); this._events.on(this._root.current, 'blur', this._onBlur, true); if (doesElementContainFocus(this._root.current)) { this._containsFocus = true; } this._updateScrollBarAsync(); }; Popup.prototype.componentDidUpdate = function () { this._updateScrollBarAsync(); }; Popup.prototype.componentWillUnmount = function () { if (this.props.shouldRestoreFocus && this._originalFocusedElement && this._containsFocus && this._originalFocusedElement !== window) { // This slight delay is required so that we can unwind the stack, let react try to mess with focus, and then // apply the correct focus. Without the setTimeout, we end up focusing the correct thing, and then React wants // to reset the focus back to the thing it thinks should have been focused. if (this._originalFocusedElement) { this._originalFocusedElement.focus(); } } }; Popup.prototype.render = function () { var _a = this.props, role = _a.role, className = _a.className, ariaLabel = _a.ariaLabel, ariaLabelledBy = _a.ariaLabelledBy, ariaDescribedBy = _a.ariaDescribedBy, style = _a.style; return (React.createElement("div", tslib_1.__assign({ ref: this._root }, getNativeProps(this.props, divProperties), { className: className, role: role, "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, "aria-describedby": ariaDescribedBy, onKeyDown: this._onKeyDown, style: tslib_1.__assign({ overflowY: this.state.needsVerticalScrollBar ? 'scroll' : undefined }, style) }), this.props.children)); }; Popup.prototype._updateScrollBarAsync = function () { var _this = this; this._async.requestAnimationFrame(function () { _this._getScrollBar(); }); }; Popup.prototype._getScrollBar = function () { // If overflowY is overriden, don't waste time calculating whether the scrollbar is necessary. if (this.props.style && this.props.style.overflowY) { return; } var needsVerticalScrollBar = false; if (this._root && this._root.current && this._root.current.firstElementChild) { // ClientHeight returns the client height of an element rounded to an // integer. On some browsers at different zoom levels this rounding // can generate different results for the root container and child even // though they are the same height. This causes us to show a scroll bar // when not needed. Ideally we would use BoundingClientRect().height // instead however seems that the API is 90% slower than using ClientHeight. // Therefore instead we will calculate the difference between heights and // allow for a 1px difference to still be considered ok and not show the // scroll bar. var rootHeight = this._root.current.clientHeight; var firstChildHeight = this._root.current.firstElementChild.clientHeight; if (rootHeight > 0 && firstChildHeight > rootHeight) { needsVerticalScrollBar = firstChildHeight - rootHeight > 1; } } if (this.state.needsVerticalScrollBar !== needsVerticalScrollBar) { this.setState({ needsVerticalScrollBar: needsVerticalScrollBar }); } }; Popup.prototype._onFocus = function () { this._containsFocus = true; }; Popup.prototype._onBlur = function (ev) { if (this._root.value && this._root.value.contains(ev.relatedTarget)) { this._containsFocus = false; } }; Popup.defaultProps = { shouldRestoreFocus: true }; return Popup; }(BaseComponent)); export { Popup }; //# sourceMappingURL=Popup.js.map