baseui
Version:
A React Component library implementing the Base design language
270 lines (267 loc) • 10.5 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var React = _interopRequireWildcard(require("react"));
var _reactFocusLock = _interopRequireDefault(require("react-focus-lock"));
var _locale = require("../locale");
var _overrides = require("../helpers/overrides");
var _layer = require("../layer");
var _constants = require("./constants");
var _styledComponents = require("./styled-components");
var _closeIcon = require("./close-icon");
var _focusVisible = require("../utils/focusVisible");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
function _getRequireWildcardCache(e) { if ("function" != typeof WeakMap) return null; var r = new WeakMap(), t = new WeakMap(); return (_getRequireWildcardCache = function (e) { return e ? t : r; })(e); }
function _interopRequireWildcard(e, r) { if (!r && e && e.__esModule) return e; if (null === e || "object" != typeof e && "function" != typeof e) return { default: e }; var t = _getRequireWildcardCache(r); if (t && t.has(e)) return t.get(e); var n = { __proto__: null }, a = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var u in e) if ("default" !== u && Object.prototype.hasOwnProperty.call(e, u)) { var i = a ? Object.getOwnPropertyDescriptor(e, u) : null; i && (i.get || i.set) ? Object.defineProperty(n, u, i) : n[u] = e[u]; } return n.default = e, t && t.set(e, n), n; }
function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
function _defineProperty(obj, key, value) { key = _toPropertyKey(key); if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : String(i); }
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*
Copyright (c) Uber Technologies, Inc.
This source code is licensed under the MIT license found in the
LICENSE file in the root directory of this source tree.
*/ /* global document */
class Drawer extends React.Component {
constructor(...args) {
super(...args);
_defineProperty(this, "animateOutTimer", void 0);
_defineProperty(this, "animateStartTimer", void 0);
_defineProperty(this, "lastFocus", null);
_defineProperty(this, "lastMountNodeOverflowStyle", null);
_defineProperty(this, "_refs", {});
_defineProperty(this, "state", {
isVisible: false,
mounted: false,
isFocusVisible: false
});
_defineProperty(this, "handleFocus", event => {
if ((0, _focusVisible.isFocusVisible)(event)) {
this.setState({
isFocusVisible: true
});
}
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_defineProperty(this, "handleBlur", event => {
if (this.state.isFocusVisible !== false) {
this.setState({
isFocusVisible: false
});
}
});
_defineProperty(this, "onEscape", () => {
if (!this.props.closeable) {
return;
}
this.triggerClose(_constants.CLOSE_SOURCE.escape);
});
_defineProperty(this, "onBackdropClick", event => {
if (this.props.onBackdropClick) {
this.props.onBackdropClick(event);
}
if (!this.props.closeable) {
return;
}
this.triggerClose(_constants.CLOSE_SOURCE.backdrop);
});
_defineProperty(this, "onCloseClick", () => {
this.triggerClose(_constants.CLOSE_SOURCE.closeButton);
});
_defineProperty(this, "animateOutComplete", () => {
this.setState({
isVisible: false
});
});
}
componentDidMount() {
this.setState({
mounted: true
});
}
componentWillUnmount() {
this.resetMountNodeScroll();
this.clearTimers();
}
componentDidUpdate(prevProps, prevState) {
const {
isOpen
} = this.props;
if (
// If isOpen is changing *or* we just mounted and drawer should be open
isOpen !== prevProps.isOpen || isOpen && this.state.mounted && !prevState.mounted) {
if (isOpen) {
this.didOpen();
} else {
this.didClose();
}
}
}
disableMountNodeScroll() {
if (this.props.showBackdrop) {
const mountNode = this.getMountNode();
this.lastMountNodeOverflowStyle = mountNode.style.overflow || '';
mountNode.style.overflow = 'hidden';
}
}
resetMountNodeScroll() {
if (this.props.showBackdrop) {
const mountNode = this.getMountNode();
const lastStyle = this.lastMountNodeOverflowStyle;
if (mountNode && lastStyle !== null) {
mountNode.style.overflow = lastStyle || '';
this.lastMountNodeOverflowStyle = null;
}
}
}
getMountNode() {
const {
mountNode
} = this.props;
if (mountNode) {
return mountNode;
}
// Flow thinks body could be null (cast through any)
// eslint-disable-next-line @typescript-eslint/no-explicit-any
return document.body;
}
clearTimers() {
if (this.animateOutTimer) {
clearTimeout(this.animateOutTimer);
}
if (this.animateStartTimer) {
cancelAnimationFrame(this.animateStartTimer);
}
}
didOpen() {
// Sometimes scroll starts past zero, possibly due to animation
// Reset scroll to 0 (other libraries do this as well)
const rootRef = this.getRef('Root').current;
if (rootRef) {
rootRef.scrollTop = 0;
}
// Clear any existing timers (like previous animateOutTimer)
this.clearTimers();
this.disableMountNodeScroll();
this.animateStartTimer = requestAnimationFrame(() => {
this.setState({
isVisible: true
});
});
}
didClose() {
this.resetMountNodeScroll();
this.animateOutTimer = setTimeout(this.animateOutComplete, 500);
}
triggerClose(source) {
// If there's no source, it just means the isOpen prop changed. No need to call onClose.
if (this.props.onClose && source) {
this.props.onClose({
closeSource: source
});
}
}
getSharedProps() {
const {
animate,
isOpen,
size,
closeable,
anchor,
showBackdrop
} = this.props;
return {
$animating: animate,
$isVisible: this.state.isVisible,
$isOpen: !!isOpen,
$size: size,
$closeable: !!closeable,
$anchor: anchor,
$isFocusVisible: this.state.isFocusVisible,
$showBackdrop: showBackdrop
};
}
getChildren() {
const {
children
} = this.props;
return typeof children === 'function' ? children() : children;
}
getRef(component) {
if (!this._refs[component]) {
this._refs[component] = /*#__PURE__*/React.createRef();
}
return this._refs[component];
}
renderDrawer(renderedContent) {
const {
overrides = {},
closeable,
autoFocus
} = this.props;
const {
Root: RootOverride,
DrawerContainer: DrawerContainerOverride,
DrawerBody: DrawerBodyOverride,
Backdrop: BackdropOverride,
Close: CloseOverride
} = overrides;
const [Root, rootProps] = (0, _overrides.getOverrides)(RootOverride, _styledComponents.StyledRoot);
const [Backdrop, backdropProps] = (0, _overrides.getOverrides)(BackdropOverride, _styledComponents.StyledBackdrop);
const [DrawerContainer, drawerContainerProps] = (0, _overrides.getOverrides)(DrawerContainerOverride, _styledComponents.StyledDrawerContainer);
const [DrawerBody, drawerBodyProps] = (0, _overrides.getOverrides)(DrawerBodyOverride, _styledComponents.StyledDrawerBody);
const [Close, closeProps] = (0, _overrides.getOverrides)(CloseOverride, _styledComponents.StyledClose);
const sharedProps = this.getSharedProps();
return /*#__PURE__*/React.createElement(_locale.LocaleContext.Consumer, null, locale => {
return /*#__PURE__*/React.createElement(_reactFocusLock.default
// Allow focus to escape when UI is within an iframe
, {
crossFrame: false,
returnFocus: true,
autoFocus: autoFocus,
noFocusGuards: true
}, /*#__PURE__*/React.createElement(Root, _extends({
"data-baseweb": "drawer",
ref: this.getRef('Root')
}, sharedProps, rootProps), /*#__PURE__*/React.createElement(Backdrop, _extends({
onClick: this.onBackdropClick
}, sharedProps, backdropProps)), /*#__PURE__*/React.createElement(DrawerContainer, _extends({}, sharedProps, drawerContainerProps), /*#__PURE__*/React.createElement(DrawerBody, _extends({}, sharedProps, drawerBodyProps), renderedContent), closeable ? /*#__PURE__*/React.createElement(Close, _extends({
"aria-label": locale.drawer.close,
onClick: this.onCloseClick
}, sharedProps, closeProps, {
onFocus: (0, _focusVisible.forkFocus)(closeProps, this.handleFocus),
onBlur: (0, _focusVisible.forkBlur)(closeProps, this.handleBlur)
}), /*#__PURE__*/React.createElement(_closeIcon.CloseIcon, {
title: locale.drawer.close
})) : null)));
});
}
render() {
const mountedAndOpen = this.state.mounted && (this.props.isOpen || this.state.isVisible);
const renderedContent = mountedAndOpen || this.props.renderAll ? this.getChildren() : null;
if (renderedContent) {
if (mountedAndOpen) {
return /*#__PURE__*/React.createElement(_layer.Layer, {
onEscape: this.onEscape,
mountNode: this.props.mountNode
}, this.renderDrawer(renderedContent));
} else {
return /*#__PURE__*/React.createElement(_styledComponents.Hidden, null, renderedContent);
}
}
return null;
}
}
_defineProperty(Drawer, "defaultProps", {
animate: true,
closeable: true,
isOpen: false,
overrides: {},
size: _constants.SIZE.default,
anchor: _constants.ANCHOR.right,
showBackdrop: true,
autoFocus: true,
renderAll: false
});
var _default = exports.default = Drawer;