useAlign.js 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540
  1. "use strict";
  2. var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
  3. var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
  4. Object.defineProperty(exports, "__esModule", {
  5. value: true
  6. });
  7. exports.default = useAlign;
  8. var _objectSpread2 = _interopRequireDefault(require("@babel/runtime/helpers/objectSpread2"));
  9. var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
  10. var _findDOMNode = require("rc-util/lib/Dom/findDOMNode");
  11. var _isVisible = _interopRequireDefault(require("rc-util/lib/Dom/isVisible"));
  12. var _useEvent = _interopRequireDefault(require("rc-util/lib/hooks/useEvent"));
  13. var _useLayoutEffect = _interopRequireDefault(require("rc-util/lib/hooks/useLayoutEffect"));
  14. var React = _interopRequireWildcard(require("react"));
  15. var _util = require("../util");
  16. function getUnitOffset(size) {
  17. var offset = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0;
  18. var offsetStr = "".concat(offset);
  19. var cells = offsetStr.match(/^(.*)\%$/);
  20. if (cells) {
  21. return size * (parseFloat(cells[1]) / 100);
  22. }
  23. return parseFloat(offsetStr);
  24. }
  25. function getNumberOffset(rect, offset) {
  26. var _ref = offset || [],
  27. _ref2 = (0, _slicedToArray2.default)(_ref, 2),
  28. offsetX = _ref2[0],
  29. offsetY = _ref2[1];
  30. return [getUnitOffset(rect.width, offsetX), getUnitOffset(rect.height, offsetY)];
  31. }
  32. function splitPoints() {
  33. var points = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : '';
  34. return [points[0], points[1]];
  35. }
  36. function getAlignPoint(rect, points) {
  37. var topBottom = points[0];
  38. var leftRight = points[1];
  39. var x;
  40. var y;
  41. // Top & Bottom
  42. if (topBottom === 't') {
  43. y = rect.y;
  44. } else if (topBottom === 'b') {
  45. y = rect.y + rect.height;
  46. } else {
  47. y = rect.y + rect.height / 2;
  48. }
  49. // Left & Right
  50. if (leftRight === 'l') {
  51. x = rect.x;
  52. } else if (leftRight === 'r') {
  53. x = rect.x + rect.width;
  54. } else {
  55. x = rect.x + rect.width / 2;
  56. }
  57. return {
  58. x: x,
  59. y: y
  60. };
  61. }
  62. function reversePoints(points, index) {
  63. var reverseMap = {
  64. t: 'b',
  65. b: 't',
  66. l: 'r',
  67. r: 'l'
  68. };
  69. return points.map(function (point, i) {
  70. if (i === index) {
  71. return reverseMap[point] || 'c';
  72. }
  73. return point;
  74. }).join('');
  75. }
  76. function useAlign(open, popupEle, target, placement, builtinPlacements, popupAlign, onPopupAlign) {
  77. var _React$useState = React.useState({
  78. ready: false,
  79. offsetX: 0,
  80. offsetY: 0,
  81. offsetR: 0,
  82. offsetB: 0,
  83. arrowX: 0,
  84. arrowY: 0,
  85. scaleX: 1,
  86. scaleY: 1,
  87. align: builtinPlacements[placement] || {}
  88. }),
  89. _React$useState2 = (0, _slicedToArray2.default)(_React$useState, 2),
  90. offsetInfo = _React$useState2[0],
  91. setOffsetInfo = _React$useState2[1];
  92. var alignCountRef = React.useRef(0);
  93. var scrollerList = React.useMemo(function () {
  94. if (!popupEle) {
  95. return [];
  96. }
  97. return (0, _util.collectScroller)(popupEle);
  98. }, [popupEle]);
  99. // ========================= Flip ==========================
  100. // We will memo flip info.
  101. // If size change to make flip, it will memo the flip info and use it in next align.
  102. var prevFlipRef = React.useRef({});
  103. var resetFlipCache = function resetFlipCache() {
  104. prevFlipRef.current = {};
  105. };
  106. if (!open) {
  107. resetFlipCache();
  108. }
  109. // ========================= Align =========================
  110. var onAlign = (0, _useEvent.default)(function () {
  111. if (popupEle && target && open) {
  112. var _popupElement$parentE, _popupRect$x, _popupRect$y, _popupElement$parentE2;
  113. var popupElement = popupEle;
  114. var doc = popupElement.ownerDocument;
  115. var win = (0, _util.getWin)(popupElement);
  116. var _win$getComputedStyle = win.getComputedStyle(popupElement),
  117. popupPosition = _win$getComputedStyle.position;
  118. var originLeft = popupElement.style.left;
  119. var originTop = popupElement.style.top;
  120. var originRight = popupElement.style.right;
  121. var originBottom = popupElement.style.bottom;
  122. var originOverflow = popupElement.style.overflow;
  123. // Placement
  124. var placementInfo = (0, _objectSpread2.default)((0, _objectSpread2.default)({}, builtinPlacements[placement]), popupAlign);
  125. // placeholder element
  126. var placeholderElement = doc.createElement('div');
  127. (_popupElement$parentE = popupElement.parentElement) === null || _popupElement$parentE === void 0 || _popupElement$parentE.appendChild(placeholderElement);
  128. placeholderElement.style.left = "".concat(popupElement.offsetLeft, "px");
  129. placeholderElement.style.top = "".concat(popupElement.offsetTop, "px");
  130. placeholderElement.style.position = popupPosition;
  131. placeholderElement.style.height = "".concat(popupElement.offsetHeight, "px");
  132. placeholderElement.style.width = "".concat(popupElement.offsetWidth, "px");
  133. // Reset first
  134. popupElement.style.left = '0';
  135. popupElement.style.top = '0';
  136. popupElement.style.right = 'auto';
  137. popupElement.style.bottom = 'auto';
  138. popupElement.style.overflow = 'hidden';
  139. // Calculate align style, we should consider `transform` case
  140. var targetRect;
  141. if (Array.isArray(target)) {
  142. targetRect = {
  143. x: target[0],
  144. y: target[1],
  145. width: 0,
  146. height: 0
  147. };
  148. } else {
  149. var _rect$x, _rect$y;
  150. var rect = target.getBoundingClientRect();
  151. rect.x = (_rect$x = rect.x) !== null && _rect$x !== void 0 ? _rect$x : rect.left;
  152. rect.y = (_rect$y = rect.y) !== null && _rect$y !== void 0 ? _rect$y : rect.top;
  153. targetRect = {
  154. x: rect.x,
  155. y: rect.y,
  156. width: rect.width,
  157. height: rect.height
  158. };
  159. }
  160. var popupRect = popupElement.getBoundingClientRect();
  161. var _win$getComputedStyle2 = win.getComputedStyle(popupElement),
  162. height = _win$getComputedStyle2.height,
  163. width = _win$getComputedStyle2.width;
  164. popupRect.x = (_popupRect$x = popupRect.x) !== null && _popupRect$x !== void 0 ? _popupRect$x : popupRect.left;
  165. popupRect.y = (_popupRect$y = popupRect.y) !== null && _popupRect$y !== void 0 ? _popupRect$y : popupRect.top;
  166. var _doc$documentElement = doc.documentElement,
  167. clientWidth = _doc$documentElement.clientWidth,
  168. clientHeight = _doc$documentElement.clientHeight,
  169. scrollWidth = _doc$documentElement.scrollWidth,
  170. scrollHeight = _doc$documentElement.scrollHeight,
  171. scrollTop = _doc$documentElement.scrollTop,
  172. scrollLeft = _doc$documentElement.scrollLeft;
  173. var popupHeight = popupRect.height;
  174. var popupWidth = popupRect.width;
  175. var targetHeight = targetRect.height;
  176. var targetWidth = targetRect.width;
  177. // Get bounding of visible area
  178. var visibleRegion = {
  179. left: 0,
  180. top: 0,
  181. right: clientWidth,
  182. bottom: clientHeight
  183. };
  184. var scrollRegion = {
  185. left: -scrollLeft,
  186. top: -scrollTop,
  187. right: scrollWidth - scrollLeft,
  188. bottom: scrollHeight - scrollTop
  189. };
  190. var htmlRegion = placementInfo.htmlRegion;
  191. var VISIBLE = 'visible';
  192. var VISIBLE_FIRST = 'visibleFirst';
  193. if (htmlRegion !== 'scroll' && htmlRegion !== VISIBLE_FIRST) {
  194. htmlRegion = VISIBLE;
  195. }
  196. var isVisibleFirst = htmlRegion === VISIBLE_FIRST;
  197. var scrollRegionArea = (0, _util.getVisibleArea)(scrollRegion, scrollerList);
  198. var visibleRegionArea = (0, _util.getVisibleArea)(visibleRegion, scrollerList);
  199. var visibleArea = htmlRegion === VISIBLE ? visibleRegionArea : scrollRegionArea;
  200. // When set to `visibleFirst`,
  201. // the check `adjust` logic will use `visibleRegion` for check first.
  202. var adjustCheckVisibleArea = isVisibleFirst ? visibleRegionArea : visibleArea;
  203. // Record right & bottom align data
  204. popupElement.style.left = 'auto';
  205. popupElement.style.top = 'auto';
  206. popupElement.style.right = '0';
  207. popupElement.style.bottom = '0';
  208. var popupMirrorRect = popupElement.getBoundingClientRect();
  209. // Reset back
  210. popupElement.style.left = originLeft;
  211. popupElement.style.top = originTop;
  212. popupElement.style.right = originRight;
  213. popupElement.style.bottom = originBottom;
  214. popupElement.style.overflow = originOverflow;
  215. (_popupElement$parentE2 = popupElement.parentElement) === null || _popupElement$parentE2 === void 0 || _popupElement$parentE2.removeChild(placeholderElement);
  216. // Calculate scale
  217. var _scaleX = (0, _util.toNum)(Math.round(popupWidth / parseFloat(width) * 1000) / 1000);
  218. var _scaleY = (0, _util.toNum)(Math.round(popupHeight / parseFloat(height) * 1000) / 1000);
  219. // No need to align since it's not visible in view
  220. if (_scaleX === 0 || _scaleY === 0 || (0, _findDOMNode.isDOM)(target) && !(0, _isVisible.default)(target)) {
  221. return;
  222. }
  223. // Offset
  224. var offset = placementInfo.offset,
  225. targetOffset = placementInfo.targetOffset;
  226. var _getNumberOffset = getNumberOffset(popupRect, offset),
  227. _getNumberOffset2 = (0, _slicedToArray2.default)(_getNumberOffset, 2),
  228. popupOffsetX = _getNumberOffset2[0],
  229. popupOffsetY = _getNumberOffset2[1];
  230. var _getNumberOffset3 = getNumberOffset(targetRect, targetOffset),
  231. _getNumberOffset4 = (0, _slicedToArray2.default)(_getNumberOffset3, 2),
  232. targetOffsetX = _getNumberOffset4[0],
  233. targetOffsetY = _getNumberOffset4[1];
  234. targetRect.x -= targetOffsetX;
  235. targetRect.y -= targetOffsetY;
  236. // Points
  237. var _ref3 = placementInfo.points || [],
  238. _ref4 = (0, _slicedToArray2.default)(_ref3, 2),
  239. popupPoint = _ref4[0],
  240. targetPoint = _ref4[1];
  241. var targetPoints = splitPoints(targetPoint);
  242. var popupPoints = splitPoints(popupPoint);
  243. var targetAlignPoint = getAlignPoint(targetRect, targetPoints);
  244. var popupAlignPoint = getAlignPoint(popupRect, popupPoints);
  245. // Real align info may not same as origin one
  246. var nextAlignInfo = (0, _objectSpread2.default)({}, placementInfo);
  247. // Next Offset
  248. var nextOffsetX = targetAlignPoint.x - popupAlignPoint.x + popupOffsetX;
  249. var nextOffsetY = targetAlignPoint.y - popupAlignPoint.y + popupOffsetY;
  250. // ============== Intersection ===============
  251. // Get area by position. Used for check if flip area is better
  252. function getIntersectionVisibleArea(offsetX, offsetY) {
  253. var area = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : visibleArea;
  254. var l = popupRect.x + offsetX;
  255. var t = popupRect.y + offsetY;
  256. var r = l + popupWidth;
  257. var b = t + popupHeight;
  258. var visibleL = Math.max(l, area.left);
  259. var visibleT = Math.max(t, area.top);
  260. var visibleR = Math.min(r, area.right);
  261. var visibleB = Math.min(b, area.bottom);
  262. return Math.max(0, (visibleR - visibleL) * (visibleB - visibleT));
  263. }
  264. var originIntersectionVisibleArea = getIntersectionVisibleArea(nextOffsetX, nextOffsetY);
  265. // As `visibleFirst`, we prepare this for check
  266. var originIntersectionRecommendArea = getIntersectionVisibleArea(nextOffsetX, nextOffsetY, visibleRegionArea);
  267. // ========================== Overflow ===========================
  268. var targetAlignPointTL = getAlignPoint(targetRect, ['t', 'l']);
  269. var popupAlignPointTL = getAlignPoint(popupRect, ['t', 'l']);
  270. var targetAlignPointBR = getAlignPoint(targetRect, ['b', 'r']);
  271. var popupAlignPointBR = getAlignPoint(popupRect, ['b', 'r']);
  272. var overflow = placementInfo.overflow || {};
  273. var adjustX = overflow.adjustX,
  274. adjustY = overflow.adjustY,
  275. shiftX = overflow.shiftX,
  276. shiftY = overflow.shiftY;
  277. var supportAdjust = function supportAdjust(val) {
  278. if (typeof val === 'boolean') {
  279. return val;
  280. }
  281. return val >= 0;
  282. };
  283. // Prepare position
  284. var nextPopupY;
  285. var nextPopupBottom;
  286. var nextPopupX;
  287. var nextPopupRight;
  288. function syncNextPopupPosition() {
  289. nextPopupY = popupRect.y + nextOffsetY;
  290. nextPopupBottom = nextPopupY + popupHeight;
  291. nextPopupX = popupRect.x + nextOffsetX;
  292. nextPopupRight = nextPopupX + popupWidth;
  293. }
  294. syncNextPopupPosition();
  295. // >>>>>>>>>> Top & Bottom
  296. var needAdjustY = supportAdjust(adjustY);
  297. var sameTB = popupPoints[0] === targetPoints[0];
  298. // Bottom to Top
  299. if (needAdjustY && popupPoints[0] === 't' && (nextPopupBottom > adjustCheckVisibleArea.bottom || prevFlipRef.current.bt)) {
  300. var tmpNextOffsetY = nextOffsetY;
  301. if (sameTB) {
  302. tmpNextOffsetY -= popupHeight - targetHeight;
  303. } else {
  304. tmpNextOffsetY = targetAlignPointTL.y - popupAlignPointBR.y - popupOffsetY;
  305. }
  306. var newVisibleArea = getIntersectionVisibleArea(nextOffsetX, tmpNextOffsetY);
  307. var newVisibleRecommendArea = getIntersectionVisibleArea(nextOffsetX, tmpNextOffsetY, visibleRegionArea);
  308. if (
  309. // Of course use larger one
  310. newVisibleArea > originIntersectionVisibleArea || newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst ||
  311. // Choose recommend one
  312. newVisibleRecommendArea >= originIntersectionRecommendArea)) {
  313. prevFlipRef.current.bt = true;
  314. nextOffsetY = tmpNextOffsetY;
  315. popupOffsetY = -popupOffsetY;
  316. nextAlignInfo.points = [reversePoints(popupPoints, 0), reversePoints(targetPoints, 0)];
  317. } else {
  318. prevFlipRef.current.bt = false;
  319. }
  320. }
  321. // Top to Bottom
  322. if (needAdjustY && popupPoints[0] === 'b' && (nextPopupY < adjustCheckVisibleArea.top || prevFlipRef.current.tb)) {
  323. var _tmpNextOffsetY = nextOffsetY;
  324. if (sameTB) {
  325. _tmpNextOffsetY += popupHeight - targetHeight;
  326. } else {
  327. _tmpNextOffsetY = targetAlignPointBR.y - popupAlignPointTL.y - popupOffsetY;
  328. }
  329. var _newVisibleArea = getIntersectionVisibleArea(nextOffsetX, _tmpNextOffsetY);
  330. var _newVisibleRecommendArea = getIntersectionVisibleArea(nextOffsetX, _tmpNextOffsetY, visibleRegionArea);
  331. if (
  332. // Of course use larger one
  333. _newVisibleArea > originIntersectionVisibleArea || _newVisibleArea === originIntersectionVisibleArea && (!isVisibleFirst ||
  334. // Choose recommend one
  335. _newVisibleRecommendArea >= originIntersectionRecommendArea)) {
  336. prevFlipRef.current.tb = true;
  337. nextOffsetY = _tmpNextOffsetY;
  338. popupOffsetY = -popupOffsetY;
  339. nextAlignInfo.points = [reversePoints(popupPoints, 0), reversePoints(targetPoints, 0)];
  340. } else {
  341. prevFlipRef.current.tb = false;
  342. }
  343. }
  344. // >>>>>>>>>> Left & Right
  345. var needAdjustX = supportAdjust(adjustX);
  346. // >>>>> Flip
  347. var sameLR = popupPoints[1] === targetPoints[1];
  348. // Right to Left
  349. if (needAdjustX && popupPoints[1] === 'l' && (nextPopupRight > adjustCheckVisibleArea.right || prevFlipRef.current.rl)) {
  350. var tmpNextOffsetX = nextOffsetX;
  351. if (sameLR) {
  352. tmpNextOffsetX -= popupWidth - targetWidth;
  353. } else {
  354. tmpNextOffsetX = targetAlignPointTL.x - popupAlignPointBR.x - popupOffsetX;
  355. }
  356. var _newVisibleArea2 = getIntersectionVisibleArea(tmpNextOffsetX, nextOffsetY);
  357. var _newVisibleRecommendArea2 = getIntersectionVisibleArea(tmpNextOffsetX, nextOffsetY, visibleRegionArea);
  358. if (
  359. // Of course use larger one
  360. _newVisibleArea2 > originIntersectionVisibleArea || _newVisibleArea2 === originIntersectionVisibleArea && (!isVisibleFirst ||
  361. // Choose recommend one
  362. _newVisibleRecommendArea2 >= originIntersectionRecommendArea)) {
  363. prevFlipRef.current.rl = true;
  364. nextOffsetX = tmpNextOffsetX;
  365. popupOffsetX = -popupOffsetX;
  366. nextAlignInfo.points = [reversePoints(popupPoints, 1), reversePoints(targetPoints, 1)];
  367. } else {
  368. prevFlipRef.current.rl = false;
  369. }
  370. }
  371. // Left to Right
  372. if (needAdjustX && popupPoints[1] === 'r' && (nextPopupX < adjustCheckVisibleArea.left || prevFlipRef.current.lr)) {
  373. var _tmpNextOffsetX = nextOffsetX;
  374. if (sameLR) {
  375. _tmpNextOffsetX += popupWidth - targetWidth;
  376. } else {
  377. _tmpNextOffsetX = targetAlignPointBR.x - popupAlignPointTL.x - popupOffsetX;
  378. }
  379. var _newVisibleArea3 = getIntersectionVisibleArea(_tmpNextOffsetX, nextOffsetY);
  380. var _newVisibleRecommendArea3 = getIntersectionVisibleArea(_tmpNextOffsetX, nextOffsetY, visibleRegionArea);
  381. if (
  382. // Of course use larger one
  383. _newVisibleArea3 > originIntersectionVisibleArea || _newVisibleArea3 === originIntersectionVisibleArea && (!isVisibleFirst ||
  384. // Choose recommend one
  385. _newVisibleRecommendArea3 >= originIntersectionRecommendArea)) {
  386. prevFlipRef.current.lr = true;
  387. nextOffsetX = _tmpNextOffsetX;
  388. popupOffsetX = -popupOffsetX;
  389. nextAlignInfo.points = [reversePoints(popupPoints, 1), reversePoints(targetPoints, 1)];
  390. } else {
  391. prevFlipRef.current.lr = false;
  392. }
  393. }
  394. // ============================ Shift ============================
  395. syncNextPopupPosition();
  396. var numShiftX = shiftX === true ? 0 : shiftX;
  397. if (typeof numShiftX === 'number') {
  398. // Left
  399. if (nextPopupX < visibleRegionArea.left) {
  400. nextOffsetX -= nextPopupX - visibleRegionArea.left - popupOffsetX;
  401. if (targetRect.x + targetWidth < visibleRegionArea.left + numShiftX) {
  402. nextOffsetX += targetRect.x - visibleRegionArea.left + targetWidth - numShiftX;
  403. }
  404. }
  405. // Right
  406. if (nextPopupRight > visibleRegionArea.right) {
  407. nextOffsetX -= nextPopupRight - visibleRegionArea.right - popupOffsetX;
  408. if (targetRect.x > visibleRegionArea.right - numShiftX) {
  409. nextOffsetX += targetRect.x - visibleRegionArea.right + numShiftX;
  410. }
  411. }
  412. }
  413. var numShiftY = shiftY === true ? 0 : shiftY;
  414. if (typeof numShiftY === 'number') {
  415. // Top
  416. if (nextPopupY < visibleRegionArea.top) {
  417. nextOffsetY -= nextPopupY - visibleRegionArea.top - popupOffsetY;
  418. // When target if far away from visible area
  419. // Stop shift
  420. if (targetRect.y + targetHeight < visibleRegionArea.top + numShiftY) {
  421. nextOffsetY += targetRect.y - visibleRegionArea.top + targetHeight - numShiftY;
  422. }
  423. }
  424. // Bottom
  425. if (nextPopupBottom > visibleRegionArea.bottom) {
  426. nextOffsetY -= nextPopupBottom - visibleRegionArea.bottom - popupOffsetY;
  427. if (targetRect.y > visibleRegionArea.bottom - numShiftY) {
  428. nextOffsetY += targetRect.y - visibleRegionArea.bottom + numShiftY;
  429. }
  430. }
  431. }
  432. // ============================ Arrow ============================
  433. // Arrow center align
  434. var popupLeft = popupRect.x + nextOffsetX;
  435. var popupRight = popupLeft + popupWidth;
  436. var popupTop = popupRect.y + nextOffsetY;
  437. var popupBottom = popupTop + popupHeight;
  438. var targetLeft = targetRect.x;
  439. var targetRight = targetLeft + targetWidth;
  440. var targetTop = targetRect.y;
  441. var targetBottom = targetTop + targetHeight;
  442. var maxLeft = Math.max(popupLeft, targetLeft);
  443. var minRight = Math.min(popupRight, targetRight);
  444. var xCenter = (maxLeft + minRight) / 2;
  445. var nextArrowX = xCenter - popupLeft;
  446. var maxTop = Math.max(popupTop, targetTop);
  447. var minBottom = Math.min(popupBottom, targetBottom);
  448. var yCenter = (maxTop + minBottom) / 2;
  449. var nextArrowY = yCenter - popupTop;
  450. onPopupAlign === null || onPopupAlign === void 0 || onPopupAlign(popupEle, nextAlignInfo);
  451. // Additional calculate right & bottom position
  452. var offsetX4Right = popupMirrorRect.right - popupRect.x - (nextOffsetX + popupRect.width);
  453. var offsetY4Bottom = popupMirrorRect.bottom - popupRect.y - (nextOffsetY + popupRect.height);
  454. if (_scaleX === 1) {
  455. nextOffsetX = Math.round(nextOffsetX);
  456. offsetX4Right = Math.round(offsetX4Right);
  457. }
  458. if (_scaleY === 1) {
  459. nextOffsetY = Math.round(nextOffsetY);
  460. offsetY4Bottom = Math.round(offsetY4Bottom);
  461. }
  462. var nextOffsetInfo = {
  463. ready: true,
  464. offsetX: nextOffsetX / _scaleX,
  465. offsetY: nextOffsetY / _scaleY,
  466. offsetR: offsetX4Right / _scaleX,
  467. offsetB: offsetY4Bottom / _scaleY,
  468. arrowX: nextArrowX / _scaleX,
  469. arrowY: nextArrowY / _scaleY,
  470. scaleX: _scaleX,
  471. scaleY: _scaleY,
  472. align: nextAlignInfo
  473. };
  474. setOffsetInfo(nextOffsetInfo);
  475. }
  476. });
  477. var triggerAlign = function triggerAlign() {
  478. alignCountRef.current += 1;
  479. var id = alignCountRef.current;
  480. // Merge all align requirement into one frame
  481. Promise.resolve().then(function () {
  482. if (alignCountRef.current === id) {
  483. onAlign();
  484. }
  485. });
  486. };
  487. // Reset ready status when placement & open changed
  488. var resetReady = function resetReady() {
  489. setOffsetInfo(function (ori) {
  490. return (0, _objectSpread2.default)((0, _objectSpread2.default)({}, ori), {}, {
  491. ready: false
  492. });
  493. });
  494. };
  495. (0, _useLayoutEffect.default)(resetReady, [placement]);
  496. (0, _useLayoutEffect.default)(function () {
  497. if (!open) {
  498. resetReady();
  499. }
  500. }, [open]);
  501. return [offsetInfo.ready, offsetInfo.offsetX, offsetInfo.offsetY, offsetInfo.offsetR, offsetInfo.offsetB, offsetInfo.arrowX, offsetInfo.arrowY, offsetInfo.scaleX, offsetInfo.scaleY, offsetInfo.align, triggerAlign];
  502. }