You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

usePopper.js 4.1 KiB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114
  1. import _extends from "@babel/runtime/helpers/esm/extends";
  2. import PopperJS from 'popper.js';
  3. import { useCallback, useEffect, useRef, useState } from 'react';
  4. var initialPopperStyles = {
  5. position: 'absolute',
  6. top: '0',
  7. left: '0',
  8. opacity: '0',
  9. pointerEvents: 'none'
  10. };
  11. var initialArrowStyles = {};
  12. /**
  13. * Position an element relative some reference element using Popper.js
  14. *
  15. * @param {HTMLElement} referenceElement The element
  16. * @param {HTMLElement} popperElement
  17. * @param {Object} options
  18. * @param {Object} options.modifiers Popper.js modifiers
  19. * @param {Boolean} options.enabled toggle the popper functionality on/off
  20. * @param {String} options.placement The popper element placement relative to the reference element
  21. * @param {Boolean} options.positionFixed use fixed positioning
  22. * @param {Boolean} options.eventsEnabled have Popper listen on window resize events to reposition the element
  23. */
  24. export default function usePopper(referenceElement, popperElement, _temp) {
  25. var _ref = _temp === void 0 ? {} : _temp,
  26. _ref$enabled = _ref.enabled,
  27. enabled = _ref$enabled === void 0 ? true : _ref$enabled,
  28. _ref$placement = _ref.placement,
  29. placement = _ref$placement === void 0 ? 'bottom' : _ref$placement,
  30. _ref$positionFixed = _ref.positionFixed,
  31. positionFixed = _ref$positionFixed === void 0 ? false : _ref$positionFixed,
  32. _ref$eventsEnabled = _ref.eventsEnabled,
  33. eventsEnabled = _ref$eventsEnabled === void 0 ? true : _ref$eventsEnabled,
  34. _ref$modifiers = _ref.modifiers,
  35. modifiers = _ref$modifiers === void 0 ? {} : _ref$modifiers;
  36. var popperInstanceRef = useRef();
  37. var hasArrow = !!(modifiers.arrow && modifiers.arrow.element);
  38. var scheduleUpdate = useCallback(function () {
  39. if (popperInstanceRef.current) {
  40. popperInstanceRef.current.scheduleUpdate();
  41. }
  42. }, []);
  43. var _useState = useState({
  44. placement: placement,
  45. scheduleUpdate: scheduleUpdate,
  46. outOfBoundaries: false,
  47. styles: initialPopperStyles,
  48. arrowStyles: initialArrowStyles
  49. }),
  50. state = _useState[0],
  51. setState = _useState[1]; // A placement difference in state means popper determined a new placement
  52. // apart from the props value. By the time the popper element is rendered with
  53. // the new position Popper has already measured it, if the place change triggers
  54. // a size change it will result in a misaligned popper. So we schedule an update to be sure.
  55. useEffect(function () {
  56. scheduleUpdate();
  57. }, [state.placement, scheduleUpdate]);
  58. /** Toggle Events */
  59. useEffect(function () {
  60. if (popperInstanceRef.current) {
  61. // eslint-disable-next-line no-unused-expressions
  62. eventsEnabled ? popperInstanceRef.current.enableEventListeners() : popperInstanceRef.current.disableEventListeners();
  63. }
  64. }, [eventsEnabled]);
  65. useEffect(function () {
  66. if (!enabled || referenceElement == null || popperElement == null) {
  67. return undefined;
  68. }
  69. var arrow = modifiers.arrow && _extends({}, modifiers.arrow, {
  70. element: modifiers.arrow.element
  71. });
  72. popperInstanceRef.current = new PopperJS(referenceElement, popperElement, {
  73. placement: placement,
  74. positionFixed: positionFixed,
  75. modifiers: _extends({}, modifiers, {
  76. arrow: arrow,
  77. applyStyle: {
  78. enabled: false
  79. },
  80. updateStateModifier: {
  81. enabled: true,
  82. order: 900,
  83. fn: function fn(data) {
  84. setState({
  85. scheduleUpdate: scheduleUpdate,
  86. styles: _extends({
  87. position: data.offsets.popper.position
  88. }, data.styles),
  89. arrowStyles: data.arrowStyles,
  90. outOfBoundaries: data.hide,
  91. placement: data.placement
  92. });
  93. }
  94. }
  95. })
  96. });
  97. return function () {
  98. if (popperInstanceRef.current !== null) {
  99. popperInstanceRef.current.destroy();
  100. popperInstanceRef.current = null;
  101. }
  102. }; // intentionally NOT re-running on new modifiers
  103. // eslint-disable-next-line react-hooks/exhaustive-deps
  104. }, [enabled, placement, positionFixed, referenceElement, popperElement, hasArrow]);
  105. return state;
  106. }