floating-ui.utils.dom.umd.js 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
  3. typeof define === 'function' && define.amd ? define(['exports'], factory) :
  4. (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.FloatingUIUtilsDOM = {}));
  5. })(this, (function (exports) { 'use strict';
  6. function hasWindow() {
  7. return typeof window !== 'undefined';
  8. }
  9. function getNodeName(node) {
  10. if (isNode(node)) {
  11. return (node.nodeName || '').toLowerCase();
  12. }
  13. // Mocked nodes in testing environments may not be instances of Node. By
  14. // returning `#document` an infinite loop won't occur.
  15. // https://github.com/floating-ui/floating-ui/issues/2317
  16. return '#document';
  17. }
  18. function getWindow(node) {
  19. var _node$ownerDocument;
  20. return (node == null || (_node$ownerDocument = node.ownerDocument) == null ? void 0 : _node$ownerDocument.defaultView) || window;
  21. }
  22. function getDocumentElement(node) {
  23. var _ref;
  24. return (_ref = (isNode(node) ? node.ownerDocument : node.document) || window.document) == null ? void 0 : _ref.documentElement;
  25. }
  26. function isNode(value) {
  27. if (!hasWindow()) {
  28. return false;
  29. }
  30. return value instanceof Node || value instanceof getWindow(value).Node;
  31. }
  32. function isElement(value) {
  33. if (!hasWindow()) {
  34. return false;
  35. }
  36. return value instanceof Element || value instanceof getWindow(value).Element;
  37. }
  38. function isHTMLElement(value) {
  39. if (!hasWindow()) {
  40. return false;
  41. }
  42. return value instanceof HTMLElement || value instanceof getWindow(value).HTMLElement;
  43. }
  44. function isShadowRoot(value) {
  45. if (!hasWindow() || typeof ShadowRoot === 'undefined') {
  46. return false;
  47. }
  48. return value instanceof ShadowRoot || value instanceof getWindow(value).ShadowRoot;
  49. }
  50. function isOverflowElement(element) {
  51. const {
  52. overflow,
  53. overflowX,
  54. overflowY,
  55. display
  56. } = getComputedStyle(element);
  57. return /auto|scroll|overlay|hidden|clip/.test(overflow + overflowY + overflowX) && display !== 'inline' && display !== 'contents';
  58. }
  59. function isTableElement(element) {
  60. return /^(table|td|th)$/.test(getNodeName(element));
  61. }
  62. function isTopLayer(element) {
  63. try {
  64. if (element.matches(':popover-open')) {
  65. return true;
  66. }
  67. } catch (_e) {
  68. // no-op
  69. }
  70. try {
  71. return element.matches(':modal');
  72. } catch (_e) {
  73. return false;
  74. }
  75. }
  76. const willChangeRe = /transform|translate|scale|rotate|perspective|filter/;
  77. const containRe = /paint|layout|strict|content/;
  78. const isNotNone = value => !!value && value !== 'none';
  79. let isWebKitValue;
  80. function isContainingBlock(elementOrCss) {
  81. const css = isElement(elementOrCss) ? getComputedStyle(elementOrCss) : elementOrCss;
  82. // https://developer.mozilla.org/en-US/docs/Web/CSS/Containing_block#identifying_the_containing_block
  83. // https://drafts.csswg.org/css-transforms-2/#individual-transforms
  84. return isNotNone(css.transform) || isNotNone(css.translate) || isNotNone(css.scale) || isNotNone(css.rotate) || isNotNone(css.perspective) || !isWebKit() && (isNotNone(css.backdropFilter) || isNotNone(css.filter)) || willChangeRe.test(css.willChange || '') || containRe.test(css.contain || '');
  85. }
  86. function getContainingBlock(element) {
  87. let currentNode = getParentNode(element);
  88. while (isHTMLElement(currentNode) && !isLastTraversableNode(currentNode)) {
  89. if (isContainingBlock(currentNode)) {
  90. return currentNode;
  91. } else if (isTopLayer(currentNode)) {
  92. return null;
  93. }
  94. currentNode = getParentNode(currentNode);
  95. }
  96. return null;
  97. }
  98. function isWebKit() {
  99. if (isWebKitValue == null) {
  100. isWebKitValue = typeof CSS !== 'undefined' && CSS.supports && CSS.supports('-webkit-backdrop-filter', 'none');
  101. }
  102. return isWebKitValue;
  103. }
  104. function isLastTraversableNode(node) {
  105. return /^(html|body|#document)$/.test(getNodeName(node));
  106. }
  107. function getComputedStyle(element) {
  108. return getWindow(element).getComputedStyle(element);
  109. }
  110. function getNodeScroll(element) {
  111. if (isElement(element)) {
  112. return {
  113. scrollLeft: element.scrollLeft,
  114. scrollTop: element.scrollTop
  115. };
  116. }
  117. return {
  118. scrollLeft: element.scrollX,
  119. scrollTop: element.scrollY
  120. };
  121. }
  122. function getParentNode(node) {
  123. if (getNodeName(node) === 'html') {
  124. return node;
  125. }
  126. const result =
  127. // Step into the shadow DOM of the parent of a slotted node.
  128. node.assignedSlot ||
  129. // DOM Element detected.
  130. node.parentNode ||
  131. // ShadowRoot detected.
  132. isShadowRoot(node) && node.host ||
  133. // Fallback.
  134. getDocumentElement(node);
  135. return isShadowRoot(result) ? result.host : result;
  136. }
  137. function getNearestOverflowAncestor(node) {
  138. const parentNode = getParentNode(node);
  139. if (isLastTraversableNode(parentNode)) {
  140. return node.ownerDocument ? node.ownerDocument.body : node.body;
  141. }
  142. if (isHTMLElement(parentNode) && isOverflowElement(parentNode)) {
  143. return parentNode;
  144. }
  145. return getNearestOverflowAncestor(parentNode);
  146. }
  147. function getOverflowAncestors(node, list, traverseIframes) {
  148. var _node$ownerDocument2;
  149. if (list === void 0) {
  150. list = [];
  151. }
  152. if (traverseIframes === void 0) {
  153. traverseIframes = true;
  154. }
  155. const scrollableAncestor = getNearestOverflowAncestor(node);
  156. const isBody = scrollableAncestor === ((_node$ownerDocument2 = node.ownerDocument) == null ? void 0 : _node$ownerDocument2.body);
  157. const win = getWindow(scrollableAncestor);
  158. if (isBody) {
  159. const frameElement = getFrameElement(win);
  160. return list.concat(win, win.visualViewport || [], isOverflowElement(scrollableAncestor) ? scrollableAncestor : [], frameElement && traverseIframes ? getOverflowAncestors(frameElement) : []);
  161. } else {
  162. return list.concat(scrollableAncestor, getOverflowAncestors(scrollableAncestor, [], traverseIframes));
  163. }
  164. }
  165. function getFrameElement(win) {
  166. return win.parent && Object.getPrototypeOf(win.parent) ? win.frameElement : null;
  167. }
  168. exports.getComputedStyle = getComputedStyle;
  169. exports.getContainingBlock = getContainingBlock;
  170. exports.getDocumentElement = getDocumentElement;
  171. exports.getFrameElement = getFrameElement;
  172. exports.getNearestOverflowAncestor = getNearestOverflowAncestor;
  173. exports.getNodeName = getNodeName;
  174. exports.getNodeScroll = getNodeScroll;
  175. exports.getOverflowAncestors = getOverflowAncestors;
  176. exports.getParentNode = getParentNode;
  177. exports.getWindow = getWindow;
  178. exports.isContainingBlock = isContainingBlock;
  179. exports.isElement = isElement;
  180. exports.isHTMLElement = isHTMLElement;
  181. exports.isLastTraversableNode = isLastTraversableNode;
  182. exports.isNode = isNode;
  183. exports.isOverflowElement = isOverflowElement;
  184. exports.isShadowRoot = isShadowRoot;
  185. exports.isTableElement = isTableElement;
  186. exports.isTopLayer = isTopLayer;
  187. exports.isWebKit = isWebKit;
  188. }));