@skbkontur/ui-kit
Version:
231 lines • 10.6 kB
JavaScript
"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