floating-ui.core.umd.js 36 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157
  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.FloatingUICore = {}));
  5. })(this, (function (exports) { 'use strict';
  6. function getSide(placement) {
  7. return placement.split('-')[0];
  8. }
  9. function getAlignment(placement) {
  10. return placement.split('-')[1];
  11. }
  12. function getMainAxisFromPlacement(placement) {
  13. return ['top', 'bottom'].includes(getSide(placement)) ? 'x' : 'y';
  14. }
  15. function getLengthFromAxis(axis) {
  16. return axis === 'y' ? 'height' : 'width';
  17. }
  18. function computeCoordsFromPlacement(_ref, placement, rtl) {
  19. let {
  20. reference,
  21. floating
  22. } = _ref;
  23. const commonX = reference.x + reference.width / 2 - floating.width / 2;
  24. const commonY = reference.y + reference.height / 2 - floating.height / 2;
  25. const mainAxis = getMainAxisFromPlacement(placement);
  26. const length = getLengthFromAxis(mainAxis);
  27. const commonAlign = reference[length] / 2 - floating[length] / 2;
  28. const side = getSide(placement);
  29. const isVertical = mainAxis === 'x';
  30. let coords;
  31. switch (side) {
  32. case 'top':
  33. coords = {
  34. x: commonX,
  35. y: reference.y - floating.height
  36. };
  37. break;
  38. case 'bottom':
  39. coords = {
  40. x: commonX,
  41. y: reference.y + reference.height
  42. };
  43. break;
  44. case 'right':
  45. coords = {
  46. x: reference.x + reference.width,
  47. y: commonY
  48. };
  49. break;
  50. case 'left':
  51. coords = {
  52. x: reference.x - floating.width,
  53. y: commonY
  54. };
  55. break;
  56. default:
  57. coords = {
  58. x: reference.x,
  59. y: reference.y
  60. };
  61. }
  62. switch (getAlignment(placement)) {
  63. case 'start':
  64. coords[mainAxis] -= commonAlign * (rtl && isVertical ? -1 : 1);
  65. break;
  66. case 'end':
  67. coords[mainAxis] += commonAlign * (rtl && isVertical ? -1 : 1);
  68. break;
  69. }
  70. return coords;
  71. }
  72. /**
  73. * Computes the `x` and `y` coordinates that will place the floating element
  74. * next to a reference element when it is given a certain positioning strategy.
  75. *
  76. * This export does not have any `platform` interface logic. You will need to
  77. * write one for the platform you are using Floating UI with.
  78. */
  79. const computePosition = async (reference, floating, config) => {
  80. const {
  81. placement = 'bottom',
  82. strategy = 'absolute',
  83. middleware = [],
  84. platform
  85. } = config;
  86. const validMiddleware = middleware.filter(Boolean);
  87. const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(floating));
  88. {
  89. if (platform == null) {
  90. console.error(['Floating UI: `platform` property was not passed to config. If you', 'want to use Floating UI on the web, install @floating-ui/dom', 'instead of the /core package. Otherwise, you can create your own', '`platform`: https://floating-ui.com/docs/platform'].join(' '));
  91. }
  92. if (validMiddleware.filter(_ref => {
  93. let {
  94. name
  95. } = _ref;
  96. return name === 'autoPlacement' || name === 'flip';
  97. }).length > 1) {
  98. throw new Error(['Floating UI: duplicate `flip` and/or `autoPlacement` middleware', 'detected. This will lead to an infinite loop. Ensure only one of', 'either has been passed to the `middleware` array.'].join(' '));
  99. }
  100. if (!reference || !floating) {
  101. console.error(['Floating UI: The reference and/or floating element was not defined', 'when `computePosition()` was called. Ensure that both elements have', 'been created and can be measured.'].join(' '));
  102. }
  103. }
  104. let rects = await platform.getElementRects({
  105. reference,
  106. floating,
  107. strategy
  108. });
  109. let {
  110. x,
  111. y
  112. } = computeCoordsFromPlacement(rects, placement, rtl);
  113. let statefulPlacement = placement;
  114. let middlewareData = {};
  115. let resetCount = 0;
  116. for (let i = 0; i < validMiddleware.length; i++) {
  117. const {
  118. name,
  119. fn
  120. } = validMiddleware[i];
  121. const {
  122. x: nextX,
  123. y: nextY,
  124. data,
  125. reset
  126. } = await fn({
  127. x,
  128. y,
  129. initialPlacement: placement,
  130. placement: statefulPlacement,
  131. strategy,
  132. middlewareData,
  133. rects,
  134. platform,
  135. elements: {
  136. reference,
  137. floating
  138. }
  139. });
  140. x = nextX != null ? nextX : x;
  141. y = nextY != null ? nextY : y;
  142. middlewareData = { ...middlewareData,
  143. [name]: { ...middlewareData[name],
  144. ...data
  145. }
  146. };
  147. {
  148. if (resetCount > 50) {
  149. console.warn(['Floating UI: The middleware lifecycle appears to be running in an', 'infinite loop. This is usually caused by a `reset` continually', 'being returned without a break condition.'].join(' '));
  150. }
  151. }
  152. if (reset && resetCount <= 50) {
  153. resetCount++;
  154. if (typeof reset === 'object') {
  155. if (reset.placement) {
  156. statefulPlacement = reset.placement;
  157. }
  158. if (reset.rects) {
  159. rects = reset.rects === true ? await platform.getElementRects({
  160. reference,
  161. floating,
  162. strategy
  163. }) : reset.rects;
  164. }
  165. ({
  166. x,
  167. y
  168. } = computeCoordsFromPlacement(rects, statefulPlacement, rtl));
  169. }
  170. i = -1;
  171. continue;
  172. }
  173. }
  174. return {
  175. x,
  176. y,
  177. placement: statefulPlacement,
  178. strategy,
  179. middlewareData
  180. };
  181. };
  182. function expandPaddingObject(padding) {
  183. return {
  184. top: 0,
  185. right: 0,
  186. bottom: 0,
  187. left: 0,
  188. ...padding
  189. };
  190. }
  191. function getSideObjectFromPadding(padding) {
  192. return typeof padding !== 'number' ? expandPaddingObject(padding) : {
  193. top: padding,
  194. right: padding,
  195. bottom: padding,
  196. left: padding
  197. };
  198. }
  199. function rectToClientRect(rect) {
  200. return { ...rect,
  201. top: rect.y,
  202. left: rect.x,
  203. right: rect.x + rect.width,
  204. bottom: rect.y + rect.height
  205. };
  206. }
  207. /**
  208. * Resolves with an object of overflow side offsets that determine how much the
  209. * element is overflowing a given clipping boundary.
  210. * - positive = overflowing the boundary by that number of pixels
  211. * - negative = how many pixels left before it will overflow
  212. * - 0 = lies flush with the boundary
  213. * @see https://floating-ui.com/docs/detectOverflow
  214. */
  215. async function detectOverflow(middlewareArguments, options) {
  216. var _await$platform$isEle;
  217. if (options === void 0) {
  218. options = {};
  219. }
  220. const {
  221. x,
  222. y,
  223. platform,
  224. rects,
  225. elements,
  226. strategy
  227. } = middlewareArguments;
  228. const {
  229. boundary = 'clippingAncestors',
  230. rootBoundary = 'viewport',
  231. elementContext = 'floating',
  232. altBoundary = false,
  233. padding = 0
  234. } = options;
  235. const paddingObject = getSideObjectFromPadding(padding);
  236. const altContext = elementContext === 'floating' ? 'reference' : 'floating';
  237. const element = elements[altBoundary ? altContext : elementContext];
  238. const clippingClientRect = rectToClientRect(await platform.getClippingRect({
  239. element: ((_await$platform$isEle = await (platform.isElement == null ? void 0 : platform.isElement(element))) != null ? _await$platform$isEle : true) ? element : element.contextElement || (await (platform.getDocumentElement == null ? void 0 : platform.getDocumentElement(elements.floating))),
  240. boundary,
  241. rootBoundary,
  242. strategy
  243. }));
  244. const rect = elementContext === 'floating' ? { ...rects.floating,
  245. x,
  246. y
  247. } : rects.reference;
  248. const offsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating));
  249. const offsetScale = (await (platform.isElement == null ? void 0 : platform.isElement(offsetParent))) ? (await (platform.getScale == null ? void 0 : platform.getScale(offsetParent))) || {
  250. x: 1,
  251. y: 1
  252. } : {
  253. x: 1,
  254. y: 1
  255. };
  256. const elementClientRect = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
  257. rect,
  258. offsetParent,
  259. strategy
  260. }) : rect);
  261. return {
  262. top: (clippingClientRect.top - elementClientRect.top + paddingObject.top) / offsetScale.y,
  263. bottom: (elementClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom) / offsetScale.y,
  264. left: (clippingClientRect.left - elementClientRect.left + paddingObject.left) / offsetScale.x,
  265. right: (elementClientRect.right - clippingClientRect.right + paddingObject.right) / offsetScale.x
  266. };
  267. }
  268. const min = Math.min;
  269. const max = Math.max;
  270. function within(min$1, value, max$1) {
  271. return max(min$1, min(value, max$1));
  272. }
  273. /**
  274. * Positions an inner element of the floating element such that it is centered
  275. * to the reference element.
  276. * @see https://floating-ui.com/docs/arrow
  277. */
  278. const arrow = options => ({
  279. name: 'arrow',
  280. options,
  281. async fn(middlewareArguments) {
  282. // Since `element` is required, we don't Partial<> the type
  283. const {
  284. element,
  285. padding = 0
  286. } = options != null ? options : {};
  287. const {
  288. x,
  289. y,
  290. placement,
  291. rects,
  292. platform
  293. } = middlewareArguments;
  294. if (element == null) {
  295. {
  296. console.warn('Floating UI: No `element` was passed to the `arrow` middleware.');
  297. }
  298. return {};
  299. }
  300. const paddingObject = getSideObjectFromPadding(padding);
  301. const coords = {
  302. x,
  303. y
  304. };
  305. const axis = getMainAxisFromPlacement(placement);
  306. const alignment = getAlignment(placement);
  307. const length = getLengthFromAxis(axis);
  308. const arrowDimensions = await platform.getDimensions(element);
  309. const minProp = axis === 'y' ? 'top' : 'left';
  310. const maxProp = axis === 'y' ? 'bottom' : 'right';
  311. const endDiff = rects.reference[length] + rects.reference[axis] - coords[axis] - rects.floating[length];
  312. const startDiff = coords[axis] - rects.reference[axis];
  313. const arrowOffsetParent = await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(element));
  314. let clientSize = arrowOffsetParent ? axis === 'y' ? arrowOffsetParent.clientHeight || 0 : arrowOffsetParent.clientWidth || 0 : 0;
  315. if (clientSize === 0) {
  316. clientSize = rects.floating[length];
  317. }
  318. const centerToReference = endDiff / 2 - startDiff / 2; // Make sure the arrow doesn't overflow the floating element if the center
  319. // point is outside the floating element's bounds
  320. const min = paddingObject[minProp];
  321. const max = clientSize - arrowDimensions[length] - paddingObject[maxProp];
  322. const center = clientSize / 2 - arrowDimensions[length] / 2 + centerToReference;
  323. const offset = within(min, center, max); // Make sure that arrow points at the reference
  324. const alignmentPadding = alignment === 'start' ? paddingObject[minProp] : paddingObject[maxProp];
  325. const shouldAddOffset = alignmentPadding > 0 && center !== offset && rects.reference[length] <= rects.floating[length];
  326. const alignmentOffset = shouldAddOffset ? center < min ? min - center : max - center : 0;
  327. return {
  328. [axis]: coords[axis] - alignmentOffset,
  329. data: {
  330. [axis]: offset,
  331. centerOffset: center - offset
  332. }
  333. };
  334. }
  335. });
  336. const hash$1 = {
  337. left: 'right',
  338. right: 'left',
  339. bottom: 'top',
  340. top: 'bottom'
  341. };
  342. function getOppositePlacement(placement) {
  343. return placement.replace(/left|right|bottom|top/g, matched => hash$1[matched]);
  344. }
  345. function getAlignmentSides(placement, rects, rtl) {
  346. if (rtl === void 0) {
  347. rtl = false;
  348. }
  349. const alignment = getAlignment(placement);
  350. const mainAxis = getMainAxisFromPlacement(placement);
  351. const length = getLengthFromAxis(mainAxis);
  352. let mainAlignmentSide = mainAxis === 'x' ? alignment === (rtl ? 'end' : 'start') ? 'right' : 'left' : alignment === 'start' ? 'bottom' : 'top';
  353. if (rects.reference[length] > rects.floating[length]) {
  354. mainAlignmentSide = getOppositePlacement(mainAlignmentSide);
  355. }
  356. return {
  357. main: mainAlignmentSide,
  358. cross: getOppositePlacement(mainAlignmentSide)
  359. };
  360. }
  361. const hash = {
  362. start: 'end',
  363. end: 'start'
  364. };
  365. function getOppositeAlignmentPlacement(placement) {
  366. return placement.replace(/start|end/g, matched => hash[matched]);
  367. }
  368. const sides = ['top', 'right', 'bottom', 'left'];
  369. const allPlacements = /*#__PURE__*/sides.reduce((acc, side) => acc.concat(side, side + "-start", side + "-end"), []);
  370. function getPlacementList(alignment, autoAlignment, allowedPlacements) {
  371. const allowedPlacementsSortedByAlignment = alignment ? [...allowedPlacements.filter(placement => getAlignment(placement) === alignment), ...allowedPlacements.filter(placement => getAlignment(placement) !== alignment)] : allowedPlacements.filter(placement => getSide(placement) === placement);
  372. return allowedPlacementsSortedByAlignment.filter(placement => {
  373. if (alignment) {
  374. return getAlignment(placement) === alignment || (autoAlignment ? getOppositeAlignmentPlacement(placement) !== placement : false);
  375. }
  376. return true;
  377. });
  378. }
  379. /**
  380. * Automatically chooses the `placement` which has the most space available.
  381. * @see https://floating-ui.com/docs/autoPlacement
  382. */
  383. const autoPlacement = function (options) {
  384. if (options === void 0) {
  385. options = {};
  386. }
  387. return {
  388. name: 'autoPlacement',
  389. options,
  390. async fn(middlewareArguments) {
  391. var _middlewareData$autoP, _middlewareData$autoP2, _middlewareData$autoP3, _middlewareData$autoP4, _placementsSortedByLe;
  392. const {
  393. x,
  394. y,
  395. rects,
  396. middlewareData,
  397. placement,
  398. platform,
  399. elements
  400. } = middlewareArguments;
  401. const {
  402. alignment = null,
  403. allowedPlacements = allPlacements,
  404. autoAlignment = true,
  405. ...detectOverflowOptions
  406. } = options;
  407. const placements = getPlacementList(alignment, autoAlignment, allowedPlacements);
  408. const overflow = await detectOverflow(middlewareArguments, detectOverflowOptions);
  409. const currentIndex = (_middlewareData$autoP = (_middlewareData$autoP2 = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP2.index) != null ? _middlewareData$autoP : 0;
  410. const currentPlacement = placements[currentIndex];
  411. if (currentPlacement == null) {
  412. return {};
  413. }
  414. const {
  415. main,
  416. cross
  417. } = getAlignmentSides(currentPlacement, rects, await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating))); // Make `computeCoords` start from the right place
  418. if (placement !== currentPlacement) {
  419. return {
  420. x,
  421. y,
  422. reset: {
  423. placement: placements[0]
  424. }
  425. };
  426. }
  427. const currentOverflows = [overflow[getSide(currentPlacement)], overflow[main], overflow[cross]];
  428. const allOverflows = [...((_middlewareData$autoP3 = (_middlewareData$autoP4 = middlewareData.autoPlacement) == null ? void 0 : _middlewareData$autoP4.overflows) != null ? _middlewareData$autoP3 : []), {
  429. placement: currentPlacement,
  430. overflows: currentOverflows
  431. }];
  432. const nextPlacement = placements[currentIndex + 1]; // There are more placements to check
  433. if (nextPlacement) {
  434. return {
  435. data: {
  436. index: currentIndex + 1,
  437. overflows: allOverflows
  438. },
  439. reset: {
  440. placement: nextPlacement
  441. }
  442. };
  443. }
  444. const placementsSortedByLeastOverflow = allOverflows.slice().sort((a, b) => a.overflows[0] - b.overflows[0]);
  445. const placementThatFitsOnAllSides = (_placementsSortedByLe = placementsSortedByLeastOverflow.find(_ref => {
  446. let {
  447. overflows
  448. } = _ref;
  449. return overflows.every(overflow => overflow <= 0);
  450. })) == null ? void 0 : _placementsSortedByLe.placement;
  451. const resetPlacement = placementThatFitsOnAllSides != null ? placementThatFitsOnAllSides : placementsSortedByLeastOverflow[0].placement;
  452. if (resetPlacement !== placement) {
  453. return {
  454. data: {
  455. index: currentIndex + 1,
  456. overflows: allOverflows
  457. },
  458. reset: {
  459. placement: resetPlacement
  460. }
  461. };
  462. }
  463. return {};
  464. }
  465. };
  466. };
  467. function getExpandedPlacements(placement) {
  468. const oppositePlacement = getOppositePlacement(placement);
  469. return [getOppositeAlignmentPlacement(placement), oppositePlacement, getOppositeAlignmentPlacement(oppositePlacement)];
  470. }
  471. /**
  472. * Changes the placement of the floating element to one that will fit if the
  473. * initially specified `placement` does not.
  474. * @see https://floating-ui.com/docs/flip
  475. */
  476. const flip = function (options) {
  477. if (options === void 0) {
  478. options = {};
  479. }
  480. return {
  481. name: 'flip',
  482. options,
  483. async fn(middlewareArguments) {
  484. var _middlewareData$flip;
  485. const {
  486. placement,
  487. middlewareData,
  488. rects,
  489. initialPlacement,
  490. platform,
  491. elements
  492. } = middlewareArguments;
  493. const {
  494. mainAxis: checkMainAxis = true,
  495. crossAxis: checkCrossAxis = true,
  496. fallbackPlacements: specifiedFallbackPlacements,
  497. fallbackStrategy = 'bestFit',
  498. flipAlignment = true,
  499. ...detectOverflowOptions
  500. } = options;
  501. const side = getSide(placement);
  502. const isBasePlacement = side === initialPlacement;
  503. const fallbackPlacements = specifiedFallbackPlacements || (isBasePlacement || !flipAlignment ? [getOppositePlacement(initialPlacement)] : getExpandedPlacements(initialPlacement));
  504. const placements = [initialPlacement, ...fallbackPlacements];
  505. const overflow = await detectOverflow(middlewareArguments, detectOverflowOptions);
  506. const overflows = [];
  507. let overflowsData = ((_middlewareData$flip = middlewareData.flip) == null ? void 0 : _middlewareData$flip.overflows) || [];
  508. if (checkMainAxis) {
  509. overflows.push(overflow[side]);
  510. }
  511. if (checkCrossAxis) {
  512. const {
  513. main,
  514. cross
  515. } = getAlignmentSides(placement, rects, await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating)));
  516. overflows.push(overflow[main], overflow[cross]);
  517. }
  518. overflowsData = [...overflowsData, {
  519. placement,
  520. overflows
  521. }]; // One or more sides is overflowing
  522. if (!overflows.every(side => side <= 0)) {
  523. var _middlewareData$flip$, _middlewareData$flip2;
  524. const nextIndex = ((_middlewareData$flip$ = (_middlewareData$flip2 = middlewareData.flip) == null ? void 0 : _middlewareData$flip2.index) != null ? _middlewareData$flip$ : 0) + 1;
  525. const nextPlacement = placements[nextIndex];
  526. if (nextPlacement) {
  527. // Try next placement and re-run the lifecycle
  528. return {
  529. data: {
  530. index: nextIndex,
  531. overflows: overflowsData
  532. },
  533. reset: {
  534. placement: nextPlacement
  535. }
  536. };
  537. }
  538. let resetPlacement = 'bottom';
  539. switch (fallbackStrategy) {
  540. case 'bestFit':
  541. {
  542. var _overflowsData$map$so;
  543. const placement = (_overflowsData$map$so = overflowsData.map(d => [d, d.overflows.filter(overflow => overflow > 0).reduce((acc, overflow) => acc + overflow, 0)]).sort((a, b) => a[1] - b[1])[0]) == null ? void 0 : _overflowsData$map$so[0].placement;
  544. if (placement) {
  545. resetPlacement = placement;
  546. }
  547. break;
  548. }
  549. case 'initialPlacement':
  550. resetPlacement = initialPlacement;
  551. break;
  552. }
  553. if (placement !== resetPlacement) {
  554. return {
  555. reset: {
  556. placement: resetPlacement
  557. }
  558. };
  559. }
  560. }
  561. return {};
  562. }
  563. };
  564. };
  565. function getSideOffsets(overflow, rect) {
  566. return {
  567. top: overflow.top - rect.height,
  568. right: overflow.right - rect.width,
  569. bottom: overflow.bottom - rect.height,
  570. left: overflow.left - rect.width
  571. };
  572. }
  573. function isAnySideFullyClipped(overflow) {
  574. return sides.some(side => overflow[side] >= 0);
  575. }
  576. /**
  577. * Provides data to hide the floating element in applicable situations, such as
  578. * when it is not in the same clipping context as the reference element.
  579. * @see https://floating-ui.com/docs/hide
  580. */
  581. const hide = function (_temp) {
  582. let {
  583. strategy = 'referenceHidden',
  584. ...detectOverflowOptions
  585. } = _temp === void 0 ? {} : _temp;
  586. return {
  587. name: 'hide',
  588. async fn(middlewareArguments) {
  589. const {
  590. rects
  591. } = middlewareArguments;
  592. switch (strategy) {
  593. case 'referenceHidden':
  594. {
  595. const overflow = await detectOverflow(middlewareArguments, { ...detectOverflowOptions,
  596. elementContext: 'reference'
  597. });
  598. const offsets = getSideOffsets(overflow, rects.reference);
  599. return {
  600. data: {
  601. referenceHiddenOffsets: offsets,
  602. referenceHidden: isAnySideFullyClipped(offsets)
  603. }
  604. };
  605. }
  606. case 'escaped':
  607. {
  608. const overflow = await detectOverflow(middlewareArguments, { ...detectOverflowOptions,
  609. altBoundary: true
  610. });
  611. const offsets = getSideOffsets(overflow, rects.floating);
  612. return {
  613. data: {
  614. escapedOffsets: offsets,
  615. escaped: isAnySideFullyClipped(offsets)
  616. }
  617. };
  618. }
  619. default:
  620. {
  621. return {};
  622. }
  623. }
  624. }
  625. };
  626. };
  627. async function convertValueToCoords(middlewareArguments, value) {
  628. const {
  629. placement,
  630. platform,
  631. elements
  632. } = middlewareArguments;
  633. const rtl = await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating));
  634. const side = getSide(placement);
  635. const alignment = getAlignment(placement);
  636. const isVertical = getMainAxisFromPlacement(placement) === 'x';
  637. const mainAxisMulti = ['left', 'top'].includes(side) ? -1 : 1;
  638. const crossAxisMulti = rtl && isVertical ? -1 : 1;
  639. const rawValue = typeof value === 'function' ? value(middlewareArguments) : value; // eslint-disable-next-line prefer-const
  640. let {
  641. mainAxis,
  642. crossAxis,
  643. alignmentAxis
  644. } = typeof rawValue === 'number' ? {
  645. mainAxis: rawValue,
  646. crossAxis: 0,
  647. alignmentAxis: null
  648. } : {
  649. mainAxis: 0,
  650. crossAxis: 0,
  651. alignmentAxis: null,
  652. ...rawValue
  653. };
  654. if (alignment && typeof alignmentAxis === 'number') {
  655. crossAxis = alignment === 'end' ? alignmentAxis * -1 : alignmentAxis;
  656. }
  657. return isVertical ? {
  658. x: crossAxis * crossAxisMulti,
  659. y: mainAxis * mainAxisMulti
  660. } : {
  661. x: mainAxis * mainAxisMulti,
  662. y: crossAxis * crossAxisMulti
  663. };
  664. }
  665. /**
  666. * Displaces the floating element from its reference element.
  667. * @see https://floating-ui.com/docs/offset
  668. */
  669. const offset = function (value) {
  670. if (value === void 0) {
  671. value = 0;
  672. }
  673. return {
  674. name: 'offset',
  675. options: value,
  676. async fn(middlewareArguments) {
  677. const {
  678. x,
  679. y
  680. } = middlewareArguments;
  681. const diffCoords = await convertValueToCoords(middlewareArguments, value);
  682. return {
  683. x: x + diffCoords.x,
  684. y: y + diffCoords.y,
  685. data: diffCoords
  686. };
  687. }
  688. };
  689. };
  690. function getCrossAxis(axis) {
  691. return axis === 'x' ? 'y' : 'x';
  692. }
  693. /**
  694. * Shifts the floating element in order to keep it in view when it will overflow
  695. * a clipping boundary.
  696. * @see https://floating-ui.com/docs/shift
  697. */
  698. const shift = function (options) {
  699. if (options === void 0) {
  700. options = {};
  701. }
  702. return {
  703. name: 'shift',
  704. options,
  705. async fn(middlewareArguments) {
  706. const {
  707. x,
  708. y,
  709. placement
  710. } = middlewareArguments;
  711. const {
  712. mainAxis: checkMainAxis = true,
  713. crossAxis: checkCrossAxis = false,
  714. limiter = {
  715. fn: _ref => {
  716. let {
  717. x,
  718. y
  719. } = _ref;
  720. return {
  721. x,
  722. y
  723. };
  724. }
  725. },
  726. ...detectOverflowOptions
  727. } = options;
  728. const coords = {
  729. x,
  730. y
  731. };
  732. const overflow = await detectOverflow(middlewareArguments, detectOverflowOptions);
  733. const mainAxis = getMainAxisFromPlacement(getSide(placement));
  734. const crossAxis = getCrossAxis(mainAxis);
  735. let mainAxisCoord = coords[mainAxis];
  736. let crossAxisCoord = coords[crossAxis];
  737. if (checkMainAxis) {
  738. const minSide = mainAxis === 'y' ? 'top' : 'left';
  739. const maxSide = mainAxis === 'y' ? 'bottom' : 'right';
  740. const min = mainAxisCoord + overflow[minSide];
  741. const max = mainAxisCoord - overflow[maxSide];
  742. mainAxisCoord = within(min, mainAxisCoord, max);
  743. }
  744. if (checkCrossAxis) {
  745. const minSide = crossAxis === 'y' ? 'top' : 'left';
  746. const maxSide = crossAxis === 'y' ? 'bottom' : 'right';
  747. const min = crossAxisCoord + overflow[minSide];
  748. const max = crossAxisCoord - overflow[maxSide];
  749. crossAxisCoord = within(min, crossAxisCoord, max);
  750. }
  751. const limitedCoords = limiter.fn({ ...middlewareArguments,
  752. [mainAxis]: mainAxisCoord,
  753. [crossAxis]: crossAxisCoord
  754. });
  755. return { ...limitedCoords,
  756. data: {
  757. x: limitedCoords.x - x,
  758. y: limitedCoords.y - y
  759. }
  760. };
  761. }
  762. };
  763. };
  764. /**
  765. * Built-in `limiter` that will stop `shift()` at a certain point.
  766. */
  767. const limitShift = function (options) {
  768. if (options === void 0) {
  769. options = {};
  770. }
  771. return {
  772. options,
  773. fn(middlewareArguments) {
  774. const {
  775. x,
  776. y,
  777. placement,
  778. rects,
  779. middlewareData
  780. } = middlewareArguments;
  781. const {
  782. offset = 0,
  783. mainAxis: checkMainAxis = true,
  784. crossAxis: checkCrossAxis = true
  785. } = options;
  786. const coords = {
  787. x,
  788. y
  789. };
  790. const mainAxis = getMainAxisFromPlacement(placement);
  791. const crossAxis = getCrossAxis(mainAxis);
  792. let mainAxisCoord = coords[mainAxis];
  793. let crossAxisCoord = coords[crossAxis];
  794. const rawOffset = typeof offset === 'function' ? offset(middlewareArguments) : offset;
  795. const computedOffset = typeof rawOffset === 'number' ? {
  796. mainAxis: rawOffset,
  797. crossAxis: 0
  798. } : {
  799. mainAxis: 0,
  800. crossAxis: 0,
  801. ...rawOffset
  802. };
  803. if (checkMainAxis) {
  804. const len = mainAxis === 'y' ? 'height' : 'width';
  805. const limitMin = rects.reference[mainAxis] - rects.floating[len] + computedOffset.mainAxis;
  806. const limitMax = rects.reference[mainAxis] + rects.reference[len] - computedOffset.mainAxis;
  807. if (mainAxisCoord < limitMin) {
  808. mainAxisCoord = limitMin;
  809. } else if (mainAxisCoord > limitMax) {
  810. mainAxisCoord = limitMax;
  811. }
  812. }
  813. if (checkCrossAxis) {
  814. var _middlewareData$offse, _middlewareData$offse2, _middlewareData$offse3, _middlewareData$offse4;
  815. const len = mainAxis === 'y' ? 'width' : 'height';
  816. const isOriginSide = ['top', 'left'].includes(getSide(placement));
  817. const limitMin = rects.reference[crossAxis] - rects.floating[len] + (isOriginSide ? (_middlewareData$offse = (_middlewareData$offse2 = middlewareData.offset) == null ? void 0 : _middlewareData$offse2[crossAxis]) != null ? _middlewareData$offse : 0 : 0) + (isOriginSide ? 0 : computedOffset.crossAxis);
  818. const limitMax = rects.reference[crossAxis] + rects.reference[len] + (isOriginSide ? 0 : (_middlewareData$offse3 = (_middlewareData$offse4 = middlewareData.offset) == null ? void 0 : _middlewareData$offse4[crossAxis]) != null ? _middlewareData$offse3 : 0) - (isOriginSide ? computedOffset.crossAxis : 0);
  819. if (crossAxisCoord < limitMin) {
  820. crossAxisCoord = limitMin;
  821. } else if (crossAxisCoord > limitMax) {
  822. crossAxisCoord = limitMax;
  823. }
  824. }
  825. return {
  826. [mainAxis]: mainAxisCoord,
  827. [crossAxis]: crossAxisCoord
  828. };
  829. }
  830. };
  831. };
  832. /**
  833. * Provides data to change the size of the floating element. For instance,
  834. * prevent it from overflowing its clipping boundary or match the width of the
  835. * reference element.
  836. * @see https://floating-ui.com/docs/size
  837. */
  838. const size = function (options) {
  839. if (options === void 0) {
  840. options = {};
  841. }
  842. return {
  843. name: 'size',
  844. options,
  845. async fn(middlewareArguments) {
  846. const {
  847. placement,
  848. rects,
  849. platform,
  850. elements
  851. } = middlewareArguments;
  852. const {
  853. apply = () => {},
  854. ...detectOverflowOptions
  855. } = options;
  856. const overflow = await detectOverflow(middlewareArguments, detectOverflowOptions);
  857. const side = getSide(placement);
  858. const alignment = getAlignment(placement);
  859. let heightSide;
  860. let widthSide;
  861. if (side === 'top' || side === 'bottom') {
  862. heightSide = side;
  863. widthSide = alignment === ((await (platform.isRTL == null ? void 0 : platform.isRTL(elements.floating))) ? 'start' : 'end') ? 'left' : 'right';
  864. } else {
  865. widthSide = side;
  866. heightSide = alignment === 'end' ? 'top' : 'bottom';
  867. }
  868. const xMin = max(overflow.left, 0);
  869. const xMax = max(overflow.right, 0);
  870. const yMin = max(overflow.top, 0);
  871. const yMax = max(overflow.bottom, 0);
  872. const dimensions = {
  873. availableHeight: rects.floating.height - (['left', 'right'].includes(placement) ? 2 * (yMin !== 0 || yMax !== 0 ? yMin + yMax : max(overflow.top, overflow.bottom)) : overflow[heightSide]),
  874. availableWidth: rects.floating.width - (['top', 'bottom'].includes(placement) ? 2 * (xMin !== 0 || xMax !== 0 ? xMin + xMax : max(overflow.left, overflow.right)) : overflow[widthSide])
  875. };
  876. await apply({ ...middlewareArguments,
  877. ...dimensions
  878. });
  879. const nextDimensions = await platform.getDimensions(elements.floating);
  880. if (rects.floating.width !== nextDimensions.width || rects.floating.height !== nextDimensions.height) {
  881. return {
  882. reset: {
  883. rects: true
  884. }
  885. };
  886. }
  887. return {};
  888. }
  889. };
  890. };
  891. /**
  892. * Provides improved positioning for inline reference elements that can span
  893. * over multiple lines, such as hyperlinks or range selections.
  894. * @see https://floating-ui.com/docs/inline
  895. */
  896. const inline = function (options) {
  897. if (options === void 0) {
  898. options = {};
  899. }
  900. return {
  901. name: 'inline',
  902. options,
  903. async fn(middlewareArguments) {
  904. var _await$platform$getCl;
  905. const {
  906. placement,
  907. elements,
  908. rects,
  909. platform,
  910. strategy
  911. } = middlewareArguments; // A MouseEvent's client{X,Y} coords can be up to 2 pixels off a
  912. // ClientRect's bounds, despite the event listener being triggered. A
  913. // padding of 2 seems to handle this issue.
  914. const {
  915. padding = 2,
  916. x,
  917. y
  918. } = options;
  919. const fallback = rectToClientRect(platform.convertOffsetParentRelativeRectToViewportRelativeRect ? await platform.convertOffsetParentRelativeRectToViewportRelativeRect({
  920. rect: rects.reference,
  921. offsetParent: await (platform.getOffsetParent == null ? void 0 : platform.getOffsetParent(elements.floating)),
  922. strategy
  923. }) : rects.reference);
  924. const clientRects = (_await$platform$getCl = await (platform.getClientRects == null ? void 0 : platform.getClientRects(elements.reference))) != null ? _await$platform$getCl : [];
  925. const paddingObject = getSideObjectFromPadding(padding);
  926. function getBoundingClientRect() {
  927. // There are two rects and they are disjoined
  928. if (clientRects.length === 2 && clientRects[0].left > clientRects[1].right && x != null && y != null) {
  929. var _clientRects$find;
  930. // Find the first rect in which the point is fully inside
  931. return (_clientRects$find = clientRects.find(rect => x > rect.left - paddingObject.left && x < rect.right + paddingObject.right && y > rect.top - paddingObject.top && y < rect.bottom + paddingObject.bottom)) != null ? _clientRects$find : fallback;
  932. } // There are 2 or more connected rects
  933. if (clientRects.length >= 2) {
  934. if (getMainAxisFromPlacement(placement) === 'x') {
  935. const firstRect = clientRects[0];
  936. const lastRect = clientRects[clientRects.length - 1];
  937. const isTop = getSide(placement) === 'top';
  938. const top = firstRect.top;
  939. const bottom = lastRect.bottom;
  940. const left = isTop ? firstRect.left : lastRect.left;
  941. const right = isTop ? firstRect.right : lastRect.right;
  942. const width = right - left;
  943. const height = bottom - top;
  944. return {
  945. top,
  946. bottom,
  947. left,
  948. right,
  949. width,
  950. height,
  951. x: left,
  952. y: top
  953. };
  954. }
  955. const isLeftSide = getSide(placement) === 'left';
  956. const maxRight = max(...clientRects.map(rect => rect.right));
  957. const minLeft = min(...clientRects.map(rect => rect.left));
  958. const measureRects = clientRects.filter(rect => isLeftSide ? rect.left === minLeft : rect.right === maxRight);
  959. const top = measureRects[0].top;
  960. const bottom = measureRects[measureRects.length - 1].bottom;
  961. const left = minLeft;
  962. const right = maxRight;
  963. const width = right - left;
  964. const height = bottom - top;
  965. return {
  966. top,
  967. bottom,
  968. left,
  969. right,
  970. width,
  971. height,
  972. x: left,
  973. y: top
  974. };
  975. }
  976. return fallback;
  977. }
  978. const resetRects = await platform.getElementRects({
  979. reference: {
  980. getBoundingClientRect
  981. },
  982. floating: elements.floating,
  983. strategy
  984. });
  985. if (rects.reference.x !== resetRects.reference.x || rects.reference.y !== resetRects.reference.y || rects.reference.width !== resetRects.reference.width || rects.reference.height !== resetRects.reference.height) {
  986. return {
  987. reset: {
  988. rects: resetRects
  989. }
  990. };
  991. }
  992. return {};
  993. }
  994. };
  995. };
  996. exports.arrow = arrow;
  997. exports.autoPlacement = autoPlacement;
  998. exports.computePosition = computePosition;
  999. exports.detectOverflow = detectOverflow;
  1000. exports.flip = flip;
  1001. exports.hide = hide;
  1002. exports.inline = inline;
  1003. exports.limitShift = limitShift;
  1004. exports.offset = offset;
  1005. exports.rectToClientRect = rectToClientRect;
  1006. exports.shift = shift;
  1007. exports.size = size;
  1008. Object.defineProperty(exports, '__esModule', { value: true });
  1009. }));