UNPKG

@skbkontur/ui-kit

Version:

231 lines 10.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var React = tslib_1.__importStar(require("react")); var react_dom_1 = require("react-dom"); var react_transition_group_1 = require("react-transition-group"); var RenderContainer_1 = tslib_1.__importDefault(require("../RenderContainer")); var RenderLayer_1 = tslib_1.__importDefault(require("../RenderLayer")); var LayoutEvents_1 = tslib_1.__importDefault(require("../../../lib/LayoutEvents")); var PopupHelper_1 = tslib_1.__importDefault(require("./PopupHelper")); var PopupPin_1 = tslib_1.__importDefault(require("./PopupPin")); var PopupView_1 = require("./PopupView"); var Popup = /** @class */ (function (_super) { tslib_1.__extends(Popup, _super); function Popup() { var _this = _super !== null && _super.apply(this, arguments) || this; _this.state = { location: null }; _this.layoutEventsToken = null; _this.lastPopupElement = null; _this.refPopupElement = function (element) { if (element) { _this.lastPopupElement = element && react_dom_1.findDOMNode(element); } }; _this.handleClickOutside = function () { _this.requestClose(); }; _this.handleFocusOutside = function () { _this.requestClose(); }; _this.handleLayoutEvent = function () { if (_this.state.location) { _this.updateLocation(); } }; _this.requestClose = function () { if (_this.props.onCloseRequest) { _this.props.onCloseRequest(); } }; return _this; } Popup.prototype.componentDidMount = function () { this.updateLocation(); this.layoutEventsToken = LayoutEvents_1.default.addListener(this.handleLayoutEvent); }; Popup.prototype.componentDidUpdate = function () { /** * For react < 16 version ReactDOM.unstable_renderSubtreeIntoContainer is * used. It causes refs callbacks to call after componentDidUpdate. * * Delaying _updateLocation to ensure that ref is set */ this.delayUpdateLocation(); }; Popup.prototype.componentWillUnmount = function () { if (this.layoutEventsToken) { this.layoutEventsToken.remove(); } }; Popup.prototype.render = function () { var location = this.state.location || this.getDummyLocation(); return (React.createElement(RenderLayer_1.default, { onClickOutside: this.handleClickOutside, onFocusOutside: this.handleFocusOutside, /** * If onCloseRequest is not specified _handleClickOutside and _handleFocusOutside * are doing nothing. So there is no need in RenderLayer at all. */ active: this.props.onCloseRequest && this.props.opened }, React.createElement(RenderContainer_1.default, null, this.renderContent(location)))); }; Popup.prototype.renderContent = function (location) { var _this = this; if (!this.props.opened) { return null; } var children = typeof this.props.children === 'function' ? this.props.children() : this.props.children; if (children == null) { return null; } var direction = PopupHelper_1.default.getPositionObject(location.position).direction; return (React.createElement(react_transition_group_1.Transition, { timeout: { enter: 0, exit: 200 }, appear: true, in: true }, function (state) { return (React.createElement(PopupView_1.PopupStyledView, { key: _this.state.location ? 'real' : 'dummy', delta: 1000, innerRef: _this.refPopupElement, hasShadow: _this.props.hasShadow, style: { top: location.coordinates.top, left: location.coordinates.left, backgroundColor: _this.props.backgroundColor }, onMouseEnter: _this.props.onMouseEnter, onMouseLeave: _this.props.onMouseLeave, direction: direction, transitionState: state }, children, _this.renderPin(location.position))); })); }; Popup.prototype.renderPin = function (position) { var _a = this.props, pinSize = _a.pinSize, pinOffset = _a.pinOffset, hasShadow = _a.hasShadow, backgroundColor = _a.backgroundColor; return (this.props.hasPin && (React.createElement(PopupPin_1.default, { popupElement: this.lastPopupElement, popupPosition: position, size: pinSize, offset: pinOffset, borderWidth: hasShadow ? 1 : 0, backgroundColor: backgroundColor, borderColor: "transparent" }))); }; Popup.prototype.delayUpdateLocation = function () { var _this = this; window.requestAnimationFrame(function () { return _this.updateLocation(); }); }; Popup.prototype.updateLocation = function () { if (!this.props.opened) { if (this.state.location) { this.setState({ location: null }); } return; } var popupElement = this.lastPopupElement; if (!popupElement) { return; } var location = this.getLocation(popupElement); if (!this.locationEquals(this.state.location, location)) { this.setState({ location: location }); } }; Popup.prototype.locationEquals = function (x, y) { if (x === y) { return true; } if (x === null || y === null) { return false; } return (x.coordinates.left === y.coordinates.left && x.coordinates.top === y.coordinates.top && x.position === y.position); }; Popup.prototype.getDummyLocation = function () { return { coordinates: { top: -9999, left: -9999 }, position: 'top left' }; }; Popup.prototype.getLocation = function (popupElement) { var _a = this.props, anchorElement = _a.anchorElement, positions = _a.positions, margin = _a.margin, popupOffset = _a.popupOffset; if (!anchorElement) { throw new Error('Anchor element is not defined'); } var anchorRect = PopupHelper_1.default.getElementAbsoluteRect(anchorElement); var popupRect = PopupHelper_1.default.getElementAbsoluteRect(popupElement); for (var _i = 0, positions_1 = positions; _i < positions_1.length; _i++) { var position = positions_1[_i]; var positionObject = PopupHelper_1.default.getPositionObject(position); var coordinates = this.getCoordinates(anchorRect, popupRect, positionObject, margin, popupOffset + this.getPinnedPopupOffset(anchorRect, positionObject)); if (PopupHelper_1.default.isAbsoluteRectFullyVisible({ top: coordinates.top, left: coordinates.left, height: popupRect.height, width: popupRect.width })) { return { coordinates: coordinates, position: position }; } } var positionObjectFirst = PopupHelper_1.default.getPositionObject(positions[0]); var coordinatesFirst = this.getCoordinates(anchorRect, popupRect, positionObjectFirst, margin, popupOffset + this.getPinnedPopupOffset(anchorRect, positionObjectFirst)); return { coordinates: coordinatesFirst, position: positions[0] }; }; Popup.prototype.getPinnedPopupOffset = function (anchorRect, positionObject) { if (!this.props.hasPin || /center|middle/.test(positionObject.align)) { return 0; } var anchorSize = /top|bottom/.test(positionObject.direction) ? anchorRect.width : anchorRect.height; var _a = this.props, pinOffset = _a.pinOffset, pinSize = _a.pinSize; return Math.max(0, pinOffset + pinSize - anchorSize / 2); }; Popup.prototype.getCoordinates = function (anchorRect, popupRect, positionObject, margin, popupOffset) { switch (positionObject.direction) { case 'top': return { top: anchorRect.top - popupRect.height - margin, left: this.getHorizontalPosition(anchorRect, popupRect, positionObject.align, popupOffset) }; case 'bottom': return { top: anchorRect.top + anchorRect.height + margin, left: this.getHorizontalPosition(anchorRect, popupRect, positionObject.align, popupOffset) }; case 'left': return { top: this.getVerticalPosition(anchorRect, popupRect, positionObject.align, popupOffset), left: anchorRect.left - popupRect.width - margin }; case 'right': return { top: this.getVerticalPosition(anchorRect, popupRect, positionObject.align, popupOffset), left: anchorRect.left + anchorRect.width + margin }; default: throw new Error("Unxpected direction '" + positionObject.direction + "'"); } }; Popup.prototype.getHorizontalPosition = function (anchorRect, popupRect, align, popupOffset) { switch (align) { case 'left': return anchorRect.left - popupOffset; case 'center': return anchorRect.left - (popupRect.width - anchorRect.width) / 2; case 'right': return anchorRect.left - (popupRect.width - anchorRect.width) + popupOffset; default: throw new Error("Unxpected align '" + align + "'"); } }; Popup.prototype.getVerticalPosition = function (anchorRect, popupRect, align, popupOffset) { switch (align) { case 'top': return anchorRect.top - popupOffset; case 'middle': return anchorRect.top - (popupRect.height - anchorRect.height) / 2; case 'bottom': return anchorRect.top - (popupRect.height - anchorRect.height) + popupOffset; default: throw new Error("Unxpected align '" + align + "'"); } }; Popup.defaultProps = { margin: 10, popupOffset: 0, pinSize: 8, pinOffset: 16, hasPin: false, hasShadow: false, backgroundColor: '#fff' }; return Popup; }(React.Component)); exports.default = Popup; //# sourceMappingURL=Popup.js.map