useAlign.js 21 KB

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