computeStyles.js 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. import { top, left, right, bottom, end } from "../enums.js";
  2. import getOffsetParent from "../dom-utils/getOffsetParent.js";
  3. import getWindow from "../dom-utils/getWindow.js";
  4. import getDocumentElement from "../dom-utils/getDocumentElement.js";
  5. import getComputedStyle from "../dom-utils/getComputedStyle.js";
  6. import getBasePlacement from "../utils/getBasePlacement.js";
  7. import getVariation from "../utils/getVariation.js";
  8. import { round } from "../utils/math.js"; // eslint-disable-next-line import/no-unused-modules
  9. var unsetSides = {
  10. top: 'auto',
  11. right: 'auto',
  12. bottom: 'auto',
  13. left: 'auto'
  14. }; // Round the offsets to the nearest suitable subpixel based on the DPR.
  15. // Zooming can change the DPR, but it seems to report a value that will
  16. // cleanly divide the values into the appropriate subpixels.
  17. function roundOffsetsByDPR(_ref) {
  18. var x = _ref.x,
  19. y = _ref.y;
  20. var win = window;
  21. var dpr = win.devicePixelRatio || 1;
  22. return {
  23. x: round(x * dpr) / dpr || 0,
  24. y: round(y * dpr) / dpr || 0
  25. };
  26. }
  27. export function mapToStyles(_ref2) {
  28. var _Object$assign2;
  29. var popper = _ref2.popper,
  30. popperRect = _ref2.popperRect,
  31. placement = _ref2.placement,
  32. variation = _ref2.variation,
  33. offsets = _ref2.offsets,
  34. position = _ref2.position,
  35. gpuAcceleration = _ref2.gpuAcceleration,
  36. adaptive = _ref2.adaptive,
  37. roundOffsets = _ref2.roundOffsets,
  38. isFixed = _ref2.isFixed;
  39. var _offsets$x = offsets.x,
  40. x = _offsets$x === void 0 ? 0 : _offsets$x,
  41. _offsets$y = offsets.y,
  42. y = _offsets$y === void 0 ? 0 : _offsets$y;
  43. var _ref3 = typeof roundOffsets === 'function' ? roundOffsets({
  44. x: x,
  45. y: y
  46. }) : {
  47. x: x,
  48. y: y
  49. };
  50. x = _ref3.x;
  51. y = _ref3.y;
  52. var hasX = offsets.hasOwnProperty('x');
  53. var hasY = offsets.hasOwnProperty('y');
  54. var sideX = left;
  55. var sideY = top;
  56. var win = window;
  57. if (adaptive) {
  58. var offsetParent = getOffsetParent(popper);
  59. var heightProp = 'clientHeight';
  60. var widthProp = 'clientWidth';
  61. if (offsetParent === getWindow(popper)) {
  62. offsetParent = getDocumentElement(popper);
  63. if (getComputedStyle(offsetParent).position !== 'static' && position === 'absolute') {
  64. heightProp = 'scrollHeight';
  65. widthProp = 'scrollWidth';
  66. }
  67. } // $FlowFixMe[incompatible-cast]: force type refinement, we compare offsetParent with window above, but Flow doesn't detect it
  68. offsetParent = offsetParent;
  69. if (placement === top || (placement === left || placement === right) && variation === end) {
  70. sideY = bottom;
  71. var offsetY = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.height : // $FlowFixMe[prop-missing]
  72. offsetParent[heightProp];
  73. y -= offsetY - popperRect.height;
  74. y *= gpuAcceleration ? 1 : -1;
  75. }
  76. if (placement === left || (placement === top || placement === bottom) && variation === end) {
  77. sideX = right;
  78. var offsetX = isFixed && offsetParent === win && win.visualViewport ? win.visualViewport.width : // $FlowFixMe[prop-missing]
  79. offsetParent[widthProp];
  80. x -= offsetX - popperRect.width;
  81. x *= gpuAcceleration ? 1 : -1;
  82. }
  83. }
  84. var commonStyles = Object.assign({
  85. position: position
  86. }, adaptive && unsetSides);
  87. var _ref4 = roundOffsets === true ? roundOffsetsByDPR({
  88. x: x,
  89. y: y
  90. }) : {
  91. x: x,
  92. y: y
  93. };
  94. x = _ref4.x;
  95. y = _ref4.y;
  96. if (gpuAcceleration) {
  97. var _Object$assign;
  98. return Object.assign({}, commonStyles, (_Object$assign = {}, _Object$assign[sideY] = hasY ? '0' : '', _Object$assign[sideX] = hasX ? '0' : '', _Object$assign.transform = (win.devicePixelRatio || 1) <= 1 ? "translate(" + x + "px, " + y + "px)" : "translate3d(" + x + "px, " + y + "px, 0)", _Object$assign));
  99. }
  100. return Object.assign({}, commonStyles, (_Object$assign2 = {}, _Object$assign2[sideY] = hasY ? y + "px" : '', _Object$assign2[sideX] = hasX ? x + "px" : '', _Object$assign2.transform = '', _Object$assign2));
  101. }
  102. function computeStyles(_ref5) {
  103. var state = _ref5.state,
  104. options = _ref5.options;
  105. var _options$gpuAccelerat = options.gpuAcceleration,
  106. gpuAcceleration = _options$gpuAccelerat === void 0 ? true : _options$gpuAccelerat,
  107. _options$adaptive = options.adaptive,
  108. adaptive = _options$adaptive === void 0 ? true : _options$adaptive,
  109. _options$roundOffsets = options.roundOffsets,
  110. roundOffsets = _options$roundOffsets === void 0 ? true : _options$roundOffsets;
  111. if (process.env.NODE_ENV !== "production") {
  112. var transitionProperty = getComputedStyle(state.elements.popper).transitionProperty || '';
  113. if (adaptive && ['transform', 'top', 'right', 'bottom', 'left'].some(function (property) {
  114. return transitionProperty.indexOf(property) >= 0;
  115. })) {
  116. console.warn(['Popper: Detected CSS transitions on at least one of the following', 'CSS properties: "transform", "top", "right", "bottom", "left".', '\n\n', 'Disable the "computeStyles" modifier\'s `adaptive` option to allow', 'for smooth transitions, or remove these properties from the CSS', 'transition declaration on the popper element if only transitioning', 'opacity or background-color for example.', '\n\n', 'We recommend using the popper element as a wrapper around an inner', 'element that can have any CSS property transitioned for animations.'].join(' '));
  117. }
  118. }
  119. var commonStyles = {
  120. placement: getBasePlacement(state.placement),
  121. variation: getVariation(state.placement),
  122. popper: state.elements.popper,
  123. popperRect: state.rects.popper,
  124. gpuAcceleration: gpuAcceleration,
  125. isFixed: state.options.strategy === 'fixed'
  126. };
  127. if (state.modifiersData.popperOffsets != null) {
  128. state.styles.popper = Object.assign({}, state.styles.popper, mapToStyles(Object.assign({}, commonStyles, {
  129. offsets: state.modifiersData.popperOffsets,
  130. position: state.options.strategy,
  131. adaptive: adaptive,
  132. roundOffsets: roundOffsets
  133. })));
  134. }
  135. if (state.modifiersData.arrow != null) {
  136. state.styles.arrow = Object.assign({}, state.styles.arrow, mapToStyles(Object.assign({}, commonStyles, {
  137. offsets: state.modifiersData.arrow,
  138. position: 'absolute',
  139. adaptive: false,
  140. roundOffsets: roundOffsets
  141. })));
  142. }
  143. state.attributes.popper = Object.assign({}, state.attributes.popper, {
  144. 'data-popper-placement': state.placement
  145. });
  146. } // eslint-disable-next-line import/no-unused-modules
  147. export default {
  148. name: 'computeStyles',
  149. enabled: true,
  150. phase: 'beforeWrite',
  151. fn: computeStyles,
  152. data: {}
  153. };