@fluentui/react
Version:
Reusable React components for building web experiences.
308 lines • 19.3 kB
JavaScript
define(["require", "exports", "tslib", "react", "../../Button", "../../Layer", "../../Overlay", "../../Popup", "../../Utilities", "../FocusTrapZone/index", "./Panel.types", "@fluentui/react-window-provider", "../../utilities/dom"], function (require, exports, tslib_1, React, Button_1, Layer_1, Overlay_1, Popup_1, Utilities_1, index_1, Panel_types_1, react_window_provider_1, dom_1) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PanelBase = void 0;
var getClassNames = (0, Utilities_1.classNamesFunction)();
var COMPONENT_NAME = 'Panel';
var PanelVisibilityState;
(function (PanelVisibilityState) {
PanelVisibilityState[PanelVisibilityState["closed"] = 0] = "closed";
PanelVisibilityState[PanelVisibilityState["animatingOpen"] = 1] = "animatingOpen";
PanelVisibilityState[PanelVisibilityState["open"] = 2] = "open";
PanelVisibilityState[PanelVisibilityState["animatingClosed"] = 3] = "animatingClosed";
})(PanelVisibilityState || (PanelVisibilityState = {}));
var PanelBase = /** @class */ (function (_super) {
tslib_1.__extends(PanelBase, _super);
function PanelBase(props) {
var _this = _super.call(this, props) || this;
_this._panel = React.createRef();
_this._animationCallback = null;
_this._hasCustomNavigation = !!(_this.props.onRenderNavigation || _this.props.onRenderNavigationContent);
_this.dismiss = function (ev) {
if (_this.props.onDismiss && _this.isActive) {
_this.props.onDismiss(ev);
}
if (!ev || (ev && !ev.defaultPrevented)) {
_this.close();
}
};
// Allow the user to scroll within the panel but not on the body
_this._allowScrollOnPanel = function (elt) {
var _a;
_this._resizeObserver = _this._createResizeObserver(function (entries) {
if (entries.length > 0 && entries[0].target === elt) {
_this._updateFooterPosition();
}
});
if (elt) {
(_a = _this._resizeObserver) === null || _a === void 0 ? void 0 : _a.observe(elt);
if (_this._allowTouchBodyScroll) {
(0, Utilities_1.allowOverscrollOnElement)(elt, _this._events);
}
else {
(0, Utilities_1.allowScrollOnElement)(elt, _this._events);
}
}
else {
_this._events.off(_this._scrollableContent);
}
_this._scrollableContent = elt;
};
_this._onRenderNavigation = function (props) {
if (!_this.props.onRenderNavigationContent && !_this.props.onRenderNavigation && !_this.props.hasCloseButton) {
return null;
}
var _a = _this.props.onRenderNavigationContent, onRenderNavigationContent = _a === void 0 ? _this._onRenderNavigationContent : _a;
return (React.createElement("div", { className: _this._classNames.navigation }, onRenderNavigationContent(props, _this._onRenderNavigationContent)));
};
_this._onRenderNavigationContent = function (props) {
var _a;
var closeButtonAriaLabel = props.closeButtonAriaLabel, hasCloseButton = props.hasCloseButton, _b = props.onRenderHeader, onRenderHeader = _b === void 0 ? _this._onRenderHeader : _b;
if (hasCloseButton) {
var iconButtonStyles = (_a = _this._classNames.subComponentStyles) === null || _a === void 0 ? void 0 : _a.closeButton();
return (React.createElement(React.Fragment, null,
!_this._hasCustomNavigation && onRenderHeader(_this.props, _this._onRenderHeader, _this._headerTextId),
React.createElement(Button_1.IconButton, { styles: iconButtonStyles, className: _this._classNames.closeButton, onClick: _this._onPanelClick, ariaLabel: closeButtonAriaLabel, title: closeButtonAriaLabel, "data-is-visible": true, iconProps: { iconName: 'Cancel' } })));
}
return null;
};
_this._onRenderHeader = function (props, defaultRender, headerTextId) {
var headerText = props.headerText, _a = props.headerTextProps, headerTextProps = _a === void 0 ? {} : _a;
if (headerText) {
return (React.createElement("div", { className: _this._classNames.header },
React.createElement("div", tslib_1.__assign({ id: headerTextId, role: "heading", "aria-level": 1 }, headerTextProps, { className: (0, Utilities_1.css)(_this._classNames.headerText, headerTextProps.className) }), headerText)));
}
return null;
};
_this._onRenderBody = function (props) {
return React.createElement("div", { className: _this._classNames.content }, props.children);
};
_this._onRenderFooter = function (props) {
var _a = _this.props.onRenderFooterContent, onRenderFooterContent = _a === void 0 ? null : _a;
if (onRenderFooterContent) {
return (React.createElement("div", { className: _this._classNames.footer },
React.createElement("div", { className: _this._classNames.footerInner }, onRenderFooterContent())));
}
return null;
};
_this._animateTo = function (newVisibilityState) {
if (newVisibilityState === PanelVisibilityState.open && _this.props.onOpen) {
_this.props.onOpen();
}
_this._animationCallback = _this._async.setTimeout(function () {
_this.setState({ visibility: newVisibilityState });
_this._onTransitionComplete(newVisibilityState);
}, 200);
};
_this._clearExistingAnimationTimer = function () {
if (_this._animationCallback !== null) {
_this._async.clearTimeout(_this._animationCallback);
}
};
_this._onPanelClick = function (ev) {
_this.dismiss(ev);
};
_this._onTransitionComplete = function (newVisibilityState) {
_this._updateFooterPosition();
if (newVisibilityState === PanelVisibilityState.open && _this.props.onOpened) {
_this.props.onOpened();
}
if (newVisibilityState === PanelVisibilityState.closed && _this.props.onDismissed) {
_this.props.onDismissed();
}
};
var _a = _this.props.allowTouchBodyScroll, allowTouchBodyScroll = _a === void 0 ? false : _a;
_this._allowTouchBodyScroll = allowTouchBodyScroll;
(0, Utilities_1.initializeComponentRef)(_this);
(0, Utilities_1.warnDeprecations)(COMPONENT_NAME, props, {
ignoreExternalFocusing: 'focusTrapZoneProps',
forceFocusInsideTrap: 'focusTrapZoneProps',
firstFocusableSelector: 'focusTrapZoneProps',
});
_this.state = {
isFooterSticky: false,
// intentionally ignore props so animation takes place during componentDidMount
visibility: PanelVisibilityState.closed,
id: (0, Utilities_1.getId)('Panel'),
};
return _this;
}
PanelBase.getDerivedStateFromProps = function (nextProps, prevState) {
if (nextProps.isOpen === undefined) {
return null; // no state update
}
if (nextProps.isOpen &&
(prevState.visibility === PanelVisibilityState.closed ||
prevState.visibility === PanelVisibilityState.animatingClosed)) {
return { visibility: PanelVisibilityState.animatingOpen };
}
if (!nextProps.isOpen &&
(prevState.visibility === PanelVisibilityState.open ||
prevState.visibility === PanelVisibilityState.animatingOpen)) {
return { visibility: PanelVisibilityState.animatingClosed };
}
return null;
};
PanelBase.prototype.componentDidMount = function () {
this._async = new Utilities_1.Async(this);
this._events = new Utilities_1.EventGroup(this);
var win = (0, dom_1.getWindowEx)(this.context);
var doc = (0, dom_1.getDocumentEx)(this.context);
this._events.on(win, 'resize', this._updateFooterPosition);
if (this._shouldListenForOuterClick(this.props)) {
this._events.on(doc === null || doc === void 0 ? void 0 : doc.body, 'mousedown', this._dismissOnOuterClick, true);
}
if (this.props.isOpen) {
this.setState({ visibility: PanelVisibilityState.animatingOpen });
}
};
PanelBase.prototype.componentDidUpdate = function (previousProps, previousState) {
var shouldListenOnOuterClick = this._shouldListenForOuterClick(this.props);
var previousShouldListenOnOuterClick = this._shouldListenForOuterClick(previousProps);
if (this.state.visibility !== previousState.visibility) {
this._clearExistingAnimationTimer();
if (this.state.visibility === PanelVisibilityState.animatingOpen) {
this._animateTo(PanelVisibilityState.open);
}
else if (this.state.visibility === PanelVisibilityState.animatingClosed) {
this._animateTo(PanelVisibilityState.closed);
}
}
var doc = (0, dom_1.getDocumentEx)(this.context);
if (shouldListenOnOuterClick && !previousShouldListenOnOuterClick) {
this._events.on(doc === null || doc === void 0 ? void 0 : doc.body, 'mousedown', this._dismissOnOuterClick, true);
}
else if (!shouldListenOnOuterClick && previousShouldListenOnOuterClick) {
this._events.off(doc === null || doc === void 0 ? void 0 : doc.body, 'mousedown', this._dismissOnOuterClick, true);
}
};
PanelBase.prototype.componentWillUnmount = function () {
var _a;
this._async.dispose();
this._events.dispose();
(_a = this._resizeObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
};
PanelBase.prototype.render = function () {
var _a = this.props, _b = _a.className, className = _b === void 0 ? '' : _b, elementToFocusOnDismiss = _a.elementToFocusOnDismiss,
/* eslint-disable @typescript-eslint/no-deprecated */
firstFocusableSelector = _a.firstFocusableSelector, focusTrapZoneProps = _a.focusTrapZoneProps, forceFocusInsideTrap = _a.forceFocusInsideTrap, hasCloseButton = _a.hasCloseButton, headerText = _a.headerText, _c = _a.headerClassName, headerClassName = _c === void 0 ? '' : _c, ignoreExternalFocusing = _a.ignoreExternalFocusing, isBlocking = _a.isBlocking, isFooterAtBottom = _a.isFooterAtBottom, isLightDismiss = _a.isLightDismiss, isHiddenOnDismiss = _a.isHiddenOnDismiss, layerProps = _a.layerProps, overlayProps = _a.overlayProps, popupProps = _a.popupProps, type = _a.type, styles = _a.styles, theme = _a.theme, customWidth = _a.customWidth, _d = _a.onLightDismissClick, onLightDismissClick = _d === void 0 ? this._onPanelClick : _d, _e = _a.onRenderNavigation, onRenderNavigation = _e === void 0 ? this._onRenderNavigation : _e, _f = _a.onRenderHeader, onRenderHeader = _f === void 0 ? this._onRenderHeader : _f, _g = _a.onRenderBody, onRenderBody = _g === void 0 ? this._onRenderBody : _g, _h = _a.onRenderFooter, onRenderFooter = _h === void 0 ? this._onRenderFooter : _h;
var _j = this.state, isFooterSticky = _j.isFooterSticky, visibility = _j.visibility, id = _j.id;
var isLeft = type === Panel_types_1.PanelType.smallFixedNear || type === Panel_types_1.PanelType.customNear ? true : false;
var isRTL = (0, Utilities_1.getRTL)(theme);
var isOnRightSide = isRTL ? isLeft : !isLeft;
var customWidthStyles = type === Panel_types_1.PanelType.custom || type === Panel_types_1.PanelType.customNear ? { width: customWidth } : {};
var nativeProps = (0, Utilities_1.getNativeProps)(this.props, Utilities_1.divProperties);
var isOpen = this.isActive;
var isAnimating = visibility === PanelVisibilityState.animatingClosed || visibility === PanelVisibilityState.animatingOpen;
this._headerTextId = headerText && id + '-headerText';
if (!isOpen && !isAnimating && !isHiddenOnDismiss) {
return null;
}
this._classNames = getClassNames(styles, {
theme: theme,
className: className,
focusTrapZoneClassName: focusTrapZoneProps ? focusTrapZoneProps.className : undefined,
hasCloseButton: hasCloseButton,
headerClassName: headerClassName,
isAnimating: isAnimating,
isFooterSticky: isFooterSticky,
isFooterAtBottom: isFooterAtBottom,
isOnRightSide: isOnRightSide,
isOpen: isOpen,
isHiddenOnDismiss: isHiddenOnDismiss,
type: type,
hasCustomNavigation: this._hasCustomNavigation,
});
var _k = this, _classNames = _k._classNames, _allowTouchBodyScroll = _k._allowTouchBodyScroll;
var overlay;
if (isBlocking && isOpen) {
overlay = (React.createElement(Overlay_1.Overlay, tslib_1.__assign({ className: _classNames.overlay, isDarkThemed: false, onClick: isLightDismiss ? onLightDismissClick : undefined, allowTouchBodyScroll: _allowTouchBodyScroll }, overlayProps)));
}
return (React.createElement(Layer_1.Layer, tslib_1.__assign({}, layerProps),
React.createElement(Popup_1.Popup, tslib_1.__assign({ role: "dialog", "aria-modal": isBlocking ? 'true' : undefined, ariaLabelledBy: this._headerTextId ? this._headerTextId : undefined, onDismiss: this.dismiss, className: _classNames.hiddenPanel, enableAriaHiddenSiblings: isOpen ? true : false }, popupProps),
React.createElement("div", tslib_1.__assign({ "aria-hidden": !isOpen && isAnimating }, nativeProps, { ref: this._panel, className: _classNames.root }),
overlay,
React.createElement(index_1.FocusTrapZone, tslib_1.__assign({ ignoreExternalFocusing: ignoreExternalFocusing, forceFocusInsideTrap: !isBlocking || (isHiddenOnDismiss && !isOpen) ? false : forceFocusInsideTrap, firstFocusableSelector: firstFocusableSelector, isClickableOutsideFocusTrap: true }, focusTrapZoneProps, { className: _classNames.main, style: customWidthStyles, elementToFocusOnDismiss: elementToFocusOnDismiss }),
React.createElement("div", { className: _classNames.contentInner },
React.createElement("div", { ref: this._allowScrollOnPanel, className: _classNames.scrollableContent, "data-is-scrollable": true },
React.createElement("div", { className: _classNames.commands, "data-is-visible": true }, onRenderNavigation(this.props, this._onRenderNavigation)),
(this._hasCustomNavigation || !hasCloseButton) &&
onRenderHeader(this.props, this._onRenderHeader, this._headerTextId),
onRenderBody(this.props, this._onRenderBody),
onRenderFooter(this.props, this._onRenderFooter))))))));
};
PanelBase.prototype.open = function () {
if (this.props.isOpen !== undefined) {
return;
}
if (this.isActive) {
return;
}
this.setState({ visibility: PanelVisibilityState.animatingOpen });
};
PanelBase.prototype.close = function () {
if (this.props.isOpen !== undefined) {
return;
}
if (!this.isActive) {
return;
}
this.setState({ visibility: PanelVisibilityState.animatingClosed });
};
Object.defineProperty(PanelBase.prototype, "isActive", {
/** isActive is true when panel is open or opening. */
get: function () {
return (this.state.visibility === PanelVisibilityState.open ||
this.state.visibility === PanelVisibilityState.animatingOpen);
},
enumerable: false,
configurable: true
});
PanelBase.prototype._createResizeObserver = function (callback) {
var _a;
var doc = (0, dom_1.getDocumentEx)(this.context);
var resizeObserver = null;
if ((_a = doc === null || doc === void 0 ? void 0 : doc.defaultView) === null || _a === void 0 ? void 0 : _a.ResizeObserver) {
resizeObserver = new doc.defaultView.ResizeObserver(callback);
}
return resizeObserver;
};
PanelBase.prototype._shouldListenForOuterClick = function (props) {
return !!props.isBlocking && !!props.isOpen;
};
PanelBase.prototype._updateFooterPosition = function () {
var scrollableContent = this._scrollableContent;
if (scrollableContent) {
var height = scrollableContent.clientHeight;
var innerHeight_1 = scrollableContent.scrollHeight;
this.setState({
isFooterSticky: height < innerHeight_1 ? true : false,
});
}
};
PanelBase.prototype._dismissOnOuterClick = function (ev) {
var panel = this._panel.current;
if (this.isActive && panel && !ev.defaultPrevented) {
if (!(0, Utilities_1.elementContains)(panel, ev.target)) {
if (this.props.onOuterClick) {
this.props.onOuterClick(ev);
}
else {
this.dismiss(ev);
}
}
}
};
PanelBase.defaultProps = {
isHiddenOnDismiss: false,
isOpen: undefined,
isBlocking: true,
hasCloseButton: true,
type: Panel_types_1.PanelType.smallFixedFar,
};
PanelBase.contextType = react_window_provider_1.WindowContext;
return PanelBase;
}(React.Component));
exports.PanelBase = PanelBase;
});
//# sourceMappingURL=Panel.base.js.map