useTarget.js 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
  2. import useEvent from "rc-util/es/hooks/useEvent";
  3. import useLayoutEffect from "rc-util/es/hooks/useLayoutEffect";
  4. import { useMemo, useState } from 'react';
  5. import { isInViewPort } from "../util";
  6. function isValidNumber(val) {
  7. return typeof val === 'number' && !Number.isNaN(val);
  8. }
  9. export default function useTarget(target, open, gap, scrollIntoViewOptions) {
  10. // ========================= Target =========================
  11. // We trade `undefined` as not get target by function yet.
  12. // `null` as empty target.
  13. var _useState = useState(undefined),
  14. _useState2 = _slicedToArray(_useState, 2),
  15. targetElement = _useState2[0],
  16. setTargetElement = _useState2[1];
  17. useLayoutEffect(function () {
  18. var nextElement = typeof target === 'function' ? target() : target;
  19. setTargetElement(nextElement || null);
  20. });
  21. // ========================= Align ==========================
  22. var _useState3 = useState(null),
  23. _useState4 = _slicedToArray(_useState3, 2),
  24. posInfo = _useState4[0],
  25. setPosInfo = _useState4[1];
  26. var updatePos = useEvent(function () {
  27. if (targetElement) {
  28. // Exist target element. We should scroll and get target position
  29. if (!isInViewPort(targetElement) && open) {
  30. targetElement.scrollIntoView(scrollIntoViewOptions);
  31. }
  32. var _targetElement$getBou = targetElement.getBoundingClientRect(),
  33. left = _targetElement$getBou.left,
  34. top = _targetElement$getBou.top,
  35. width = _targetElement$getBou.width,
  36. height = _targetElement$getBou.height;
  37. var nextPosInfo = {
  38. left: left,
  39. top: top,
  40. width: width,
  41. height: height,
  42. radius: 0
  43. };
  44. setPosInfo(function (origin) {
  45. if (JSON.stringify(origin) !== JSON.stringify(nextPosInfo)) {
  46. return nextPosInfo;
  47. }
  48. return origin;
  49. });
  50. } else {
  51. // Not exist target which means we just show in center
  52. setPosInfo(null);
  53. }
  54. });
  55. var getGapOffset = function getGapOffset(index) {
  56. var _ref;
  57. return (_ref = Array.isArray(gap === null || gap === void 0 ? void 0 : gap.offset) ? gap === null || gap === void 0 ? void 0 : gap.offset[index] : gap === null || gap === void 0 ? void 0 : gap.offset) !== null && _ref !== void 0 ? _ref : 6;
  58. };
  59. useLayoutEffect(function () {
  60. updatePos();
  61. // update when window resize
  62. window.addEventListener('resize', updatePos);
  63. return function () {
  64. window.removeEventListener('resize', updatePos);
  65. };
  66. }, [targetElement, open, updatePos]);
  67. // ======================== PosInfo =========================
  68. var mergedPosInfo = useMemo(function () {
  69. if (!posInfo) {
  70. return posInfo;
  71. }
  72. var gapOffsetX = getGapOffset(0);
  73. var gapOffsetY = getGapOffset(1);
  74. var gapRadius = isValidNumber(gap === null || gap === void 0 ? void 0 : gap.radius) ? gap === null || gap === void 0 ? void 0 : gap.radius : 2;
  75. return {
  76. left: posInfo.left - gapOffsetX,
  77. top: posInfo.top - gapOffsetY,
  78. width: posInfo.width + gapOffsetX * 2,
  79. height: posInfo.height + gapOffsetY * 2,
  80. radius: gapRadius
  81. };
  82. }, [posInfo, gap]);
  83. return [mergedPosInfo, targetElement];
  84. }