UNPKG

@alifd/next

Version:

A configurable component library for web built on React.

174 lines (173 loc) 6.89 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var tslib_1 = require("tslib"); var react_1 = require("react"); var react_dom_1 = require("react-dom"); var prop_types_1 = tslib_1.__importDefault(require("prop-types")); var resize_observer_polyfill_1 = tslib_1.__importDefault(require("resize-observer-polyfill")); var util_1 = require("../util"); var position_1 = tslib_1.__importDefault(require("./utils/position")); var find_node_1 = tslib_1.__importDefault(require("./utils/find-node")); var log_1 = require("../util/log"); var noop = util_1.func.noop, bindCtx = util_1.func.bindCtx; var getStyle = util_1.dom.getStyle; var place = position_1.default.place; // Follow react NESTED_UPDATE_LIMIT = 50 var MAX_UPDATE_COUNT = 50; var Position = /** @class */ (function (_super) { tslib_1.__extends(Position, _super); function Position(props) { var _this = _super.call(this, props) || this; _this.updateCount = 0; _this.observe = function () { var contentNode = _this.getContentNode(); contentNode && _this.resizeObserver.observe(contentNode); }; _this.unobserve = function () { _this.resizeObserver.disconnect(); }; _this.shouldIgnorePosition = function () { var node = _this.getContentNode(); if (typeof window === 'undefined') { return true; } if (!node) { return true; } // 从文档中移除 if (!node.parentNode) { return true; } // 元素隐藏 var _a = getComputedStyle(node), position = _a.position, display = _a.display, visibility = _a.visibility; if (!node.offsetParent && position !== 'fixed') { return true; } // Firefox offsetParent 会返回 body,这里兼容处理 if (display === 'none' || visibility === 'hidden') { return true; } // 兜底处理,同步进程里连续更新多次,强制中断 _this.updateCount++; Promise.resolve().then(function () { _this.updateCount = 0; }); if (_this.updateCount > MAX_UPDATE_COUNT - 10) { (0, log_1.warning)('Over maximum times to adjust position at one task, it is recommended to use v2.'); return true; } return false; }; bindCtx(_this, ['handleResize']); _this.resizeObserver = new resize_observer_polyfill_1.default(_this.handleResize); return _this; } Position.prototype.componentDidMount = function () { this.setPosition(); if (this.props.needListenResize) { if (typeof window !== 'undefined') { util_1.events.on(window, 'resize', this.handleResize); } this.observe(); } }; Position.prototype.componentDidUpdate = function (prevProps) { var props = this.props; if (('align' in props && props.align !== prevProps.align) || props.shouldUpdatePosition) { this.shouldUpdatePosition = true; } if (this.shouldUpdatePosition) { clearTimeout(this.resizeTimeout); this.setPosition(); this.shouldUpdatePosition = false; } }; Position.prototype.componentWillUnmount = function () { if (this.props.needListenResize) { util_1.events.off(window, 'resize', this.handleResize); this.unobserve(); } clearTimeout(this.resizeTimeout); }; Position.prototype.setPosition = function () { var _a = this.props, align = _a.align, offset = _a.offset, beforePosition = _a.beforePosition, onPosition = _a.onPosition, needAdjust = _a.needAdjust, container = _a.container, rtl = _a.rtl, pinFollowBaseElementWhenFixed = _a.pinFollowBaseElementWhenFixed, autoFit = _a.autoFit; if (this.shouldIgnorePosition()) { return; } beforePosition(); var contentNode = this.getContentNode(); var targetNode = this.getTargetNode(); if (contentNode && targetNode) { var resultAlign = place({ pinElement: contentNode, baseElement: targetNode, pinFollowBaseElementWhenFixed: pinFollowBaseElementWhenFixed, align: align, offset: offset, autoFit: autoFit, container: container, needAdjust: needAdjust, isRtl: rtl, }); var top_1 = getStyle(contentNode, 'top'); var left = getStyle(contentNode, 'left'); onPosition({ align: resultAlign.split(' '), top: top_1, left: left, }, contentNode); } }; Position.prototype.getContentNode = function () { try { return (0, react_dom_1.findDOMNode)(this); } catch (err) { return null; } }; Position.prototype.getTargetNode = function () { var target = this.props.target; return target === position_1.default.VIEWPORT ? position_1.default.VIEWPORT : (0, find_node_1.default)(target, this.props); }; Position.prototype.handleResize = function () { var _this = this; clearTimeout(this.resizeTimeout); this.resizeTimeout = window.setTimeout(function () { _this.setPosition(); }, 200); }; Position.prototype.render = function () { return react_1.Children.only(this.props.children); }; Position.displayName = 'Position'; Position.VIEWPORT = position_1.default.VIEWPORT; Position.propTypes = { children: prop_types_1.default.node, target: prop_types_1.default.any, container: prop_types_1.default.any, align: prop_types_1.default.oneOfType([prop_types_1.default.string, prop_types_1.default.bool]), offset: prop_types_1.default.array, beforePosition: prop_types_1.default.func, onPosition: prop_types_1.default.func, needAdjust: prop_types_1.default.bool, autoFit: prop_types_1.default.bool, needListenResize: prop_types_1.default.bool, shouldUpdatePosition: prop_types_1.default.bool, rtl: prop_types_1.default.bool, pinFollowBaseElementWhenFixed: prop_types_1.default.bool, }; Position.defaultProps = { align: 'tl bl', offset: [0, 0], beforePosition: noop, onPosition: noop, needAdjust: true, autoFit: false, needListenResize: true, shouldUpdatePosition: false, rtl: false, }; return Position; }(react_1.Component)); exports.default = Position;