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.

141 lines
6.4 KiB

2 months ago
  1. import { top, left, right, bottom, start } from "../enums.js";
  2. import getBasePlacement from "../utils/getBasePlacement.js";
  3. import getMainAxisFromPlacement from "../utils/getMainAxisFromPlacement.js";
  4. import getAltAxis from "../utils/getAltAxis.js";
  5. import { within, withinMaxClamp } from "../utils/within.js";
  6. import getLayoutRect from "../dom-utils/getLayoutRect.js";
  7. import getOffsetParent from "../dom-utils/getOffsetParent.js";
  8. import detectOverflow from "../utils/detectOverflow.js";
  9. import getVariation from "../utils/getVariation.js";
  10. import getFreshSideObject from "../utils/getFreshSideObject.js";
  11. import { min as mathMin, max as mathMax } from "../utils/math.js";
  12. function preventOverflow(_ref) {
  13. var state = _ref.state,
  14. options = _ref.options,
  15. name = _ref.name;
  16. var _options$mainAxis = options.mainAxis,
  17. checkMainAxis = _options$mainAxis === void 0 ? true : _options$mainAxis,
  18. _options$altAxis = options.altAxis,
  19. checkAltAxis = _options$altAxis === void 0 ? false : _options$altAxis,
  20. boundary = options.boundary,
  21. rootBoundary = options.rootBoundary,
  22. altBoundary = options.altBoundary,
  23. padding = options.padding,
  24. _options$tether = options.tether,
  25. tether = _options$tether === void 0 ? true : _options$tether,
  26. _options$tetherOffset = options.tetherOffset,
  27. tetherOffset = _options$tetherOffset === void 0 ? 0 : _options$tetherOffset;
  28. var overflow = detectOverflow(state, {
  29. boundary: boundary,
  30. rootBoundary: rootBoundary,
  31. padding: padding,
  32. altBoundary: altBoundary
  33. });
  34. var basePlacement = getBasePlacement(state.placement);
  35. var variation = getVariation(state.placement);
  36. var isBasePlacement = !variation;
  37. var mainAxis = getMainAxisFromPlacement(basePlacement);
  38. var altAxis = getAltAxis(mainAxis);
  39. var popperOffsets = state.modifiersData.popperOffsets;
  40. var referenceRect = state.rects.reference;
  41. var popperRect = state.rects.popper;
  42. var tetherOffsetValue = typeof tetherOffset === 'function' ? tetherOffset(Object.assign({}, state.rects, {
  43. placement: state.placement
  44. })) : tetherOffset;
  45. var normalizedTetherOffsetValue = typeof tetherOffsetValue === 'number' ? {
  46. mainAxis: tetherOffsetValue,
  47. altAxis: tetherOffsetValue
  48. } : Object.assign({
  49. mainAxis: 0,
  50. altAxis: 0
  51. }, tetherOffsetValue);
  52. var offsetModifierState = state.modifiersData.offset ? state.modifiersData.offset[state.placement] : null;
  53. var data = {
  54. x: 0,
  55. y: 0
  56. };
  57. if (!popperOffsets) {
  58. return;
  59. }
  60. if (checkMainAxis) {
  61. var _offsetModifierState$;
  62. var mainSide = mainAxis === 'y' ? top : left;
  63. var altSide = mainAxis === 'y' ? bottom : right;
  64. var len = mainAxis === 'y' ? 'height' : 'width';
  65. var offset = popperOffsets[mainAxis];
  66. var min = offset + overflow[mainSide];
  67. var max = offset - overflow[altSide];
  68. var additive = tether ? -popperRect[len] / 2 : 0;
  69. var minLen = variation === start ? referenceRect[len] : popperRect[len];
  70. var maxLen = variation === start ? -popperRect[len] : -referenceRect[len]; // We need to include the arrow in the calculation so the arrow doesn't go
  71. // outside the reference bounds
  72. var arrowElement = state.elements.arrow;
  73. var arrowRect = tether && arrowElement ? getLayoutRect(arrowElement) : {
  74. width: 0,
  75. height: 0
  76. };
  77. var arrowPaddingObject = state.modifiersData['arrow#persistent'] ? state.modifiersData['arrow#persistent'].padding : getFreshSideObject();
  78. var arrowPaddingMin = arrowPaddingObject[mainSide];
  79. var arrowPaddingMax = arrowPaddingObject[altSide]; // If the reference length is smaller than the arrow length, we don't want
  80. // to include its full size in the calculation. If the reference is small
  81. // and near the edge of a boundary, the popper can overflow even if the
  82. // reference is not overflowing as well (e.g. virtual elements with no
  83. // width or height)
  84. var arrowLen = within(0, referenceRect[len], arrowRect[len]);
  85. var minOffset = isBasePlacement ? referenceRect[len] / 2 - additive - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis : minLen - arrowLen - arrowPaddingMin - normalizedTetherOffsetValue.mainAxis;
  86. var maxOffset = isBasePlacement ? -referenceRect[len] / 2 + additive + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis : maxLen + arrowLen + arrowPaddingMax + normalizedTetherOffsetValue.mainAxis;
  87. var arrowOffsetParent = state.elements.arrow && getOffsetParent(state.elements.arrow);
  88. var clientOffset = arrowOffsetParent ? mainAxis === 'y' ? arrowOffsetParent.clientTop || 0 : arrowOffsetParent.clientLeft || 0 : 0;
  89. var offsetModifierValue = (_offsetModifierState$ = offsetModifierState == null ? void 0 : offsetModifierState[mainAxis]) != null ? _offsetModifierState$ : 0;
  90. var tetherMin = offset + minOffset - offsetModifierValue - clientOffset;
  91. var tetherMax = offset + maxOffset - offsetModifierValue;
  92. var preventedOffset = within(tether ? mathMin(min, tetherMin) : min, offset, tether ? mathMax(max, tetherMax) : max);
  93. popperOffsets[mainAxis] = preventedOffset;
  94. data[mainAxis] = preventedOffset - offset;
  95. }
  96. if (checkAltAxis) {
  97. var _offsetModifierState$2;
  98. var _mainSide = mainAxis === 'x' ? top : left;
  99. var _altSide = mainAxis === 'x' ? bottom : right;
  100. var _offset = popperOffsets[altAxis];
  101. var _len = altAxis === 'y' ? 'height' : 'width';
  102. var _min = _offset + overflow[_mainSide];
  103. var _max = _offset - overflow[_altSide];
  104. var isOriginSide = [top, left].indexOf(basePlacement) !== -1;
  105. var _offsetModifierValue = (_offsetModifierState$2 = offsetModifierState == null ? void 0 : offsetModifierState[altAxis]) != null ? _offsetModifierState$2 : 0;
  106. var _tetherMin = isOriginSide ? _min : _offset - referenceRect[_len] - popperRect[_len] - _offsetModifierValue + normalizedTetherOffsetValue.altAxis;
  107. var _tetherMax = isOriginSide ? _offset + referenceRect[_len] + popperRect[_len] - _offsetModifierValue - normalizedTetherOffsetValue.altAxis : _max;
  108. var _preventedOffset = tether && isOriginSide ? withinMaxClamp(_tetherMin, _offset, _tetherMax) : within(tether ? _tetherMin : _min, _offset, tether ? _tetherMax : _max);
  109. popperOffsets[altAxis] = _preventedOffset;
  110. data[altAxis] = _preventedOffset - _offset;
  111. }
  112. state.modifiersData[name] = data;
  113. } // eslint-disable-next-line import/no-unused-modules
  114. export default {
  115. name: 'preventOverflow',
  116. enabled: true,
  117. phase: 'main',
  118. fn: preventOverflow,
  119. requiresIfExists: ['offset']
  120. };