@elliemae/ds-floating-context 3.57.6 → 3.57.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -34,78 +34,61 @@ module.exports = __toCommonJS(computePosition_exports);
34
34
  var React = __toESM(require("react"));
35
35
  var import_getExpandedFallbackPlacements = require("./getExpandedFallbackPlacements.js");
36
36
  var import_getArrowOffset = require("./getArrowOffset.js");
37
- var import_getOppositePlacement = __toESM(require("./getOppositePlacement.js"));
38
37
  var import_detectOverflow = require("./detectOverflow.js");
39
- const findFixedParent = (el) => {
40
- let element = el;
41
- while (element && element !== document.body) {
42
- const style = getComputedStyle(element);
43
- if (style.position === "fixed" || style.position === "absolute") {
44
- return element;
45
- }
46
- element = element.parentElement;
47
- }
48
- return null;
49
- };
50
- const adjustForFixedParent = (child) => {
51
- const fixedParent = findFixedParent(child);
52
- if (fixedParent) {
53
- const rect = fixedParent.getBoundingClientRect();
54
- return { top: rect.top, left: rect.left };
55
- }
56
- return {
57
- top: 0,
58
- left: 0
59
- };
60
- };
38
+ var import_floatingPositioning = require("./floatingPositioning.js");
61
39
  const computePosition = (props) => {
62
40
  const { reference, floating, placement, placementOrderPreference, customOffset, withoutPortal } = props;
63
- const scrollBarY = window.innerHeight - document.documentElement.clientHeight;
64
- const parentOffsets = withoutPortal ? adjustForFixedParent(reference) : {
65
- top: 0,
66
- left: 0
67
- };
41
+ const parentOffsets = withoutPortal ? (0, import_floatingPositioning.adjustForFixedParent)(reference) : { top: 0, left: 0 };
68
42
  const referenceRect = reference.getBoundingClientRect();
69
43
  const floatingRect = floating.getBoundingClientRect();
70
- const variationPlacement = placement.split("-")[1];
71
44
  const fallbackPlacements = placementOrderPreference || (0, import_getExpandedFallbackPlacements.getExpandedFallbackPlacements)(placement);
72
- const coords = {};
45
+ const placements = (0, import_floatingPositioning.expandWithVariations)(
46
+ [placement].concat(fallbackPlacements)
47
+ );
48
+ const clippingParent = withoutPortal ? (0, import_floatingPositioning.getClippingParent)(reference) : null;
49
+ const clippingRect = clippingParent ? clippingParent.getBoundingClientRect() : (0, import_floatingPositioning.getViewportRect)();
73
50
  let isVertical = false;
74
- const placements = [placement].concat(fallbackPlacements);
75
- let finalPlacement = "";
51
+ let bestPlacement = placement;
52
+ let bestOverflows = null;
53
+ let bestScore = { total: Number.POSITIVE_INFINITY, maxSide: Number.POSITIVE_INFINITY };
54
+ let bestIsVertical = false;
76
55
  for (let i = 0; i < placements.length; i += 1) {
77
56
  const currentPlacement = placements[i];
78
- const currentBasePlacement = currentPlacement.split("-")[0];
79
- isVertical = ["top", "bottom"].indexOf(currentBasePlacement) >= 0;
80
- const overflows = (0, import_detectOverflow.detectOverflow)(referenceRect, floatingRect, currentPlacement, customOffset);
81
- const checks = [];
82
- const isStartVariation = variationPlacement === "start";
83
- let mainVariationSide = isVertical ? isStartVariation ? "right" : "left" : isStartVariation ? "bottom" : "top";
84
- const len = isVertical ? "width" : "height";
85
- if (referenceRect[len] > floatingRect[len]) {
86
- mainVariationSide = (0, import_getOppositePlacement.default)(mainVariationSide);
87
- }
88
- const altVariationSide = (0, import_getOppositePlacement.default)(mainVariationSide);
89
- checks.push(overflows[currentBasePlacement] <= 0);
90
- checks.push(overflows[mainVariationSide] <= 0, overflows[altVariationSide] <= 0);
91
- if (checks.every((check) => {
92
- return check;
93
- })) {
94
- coords.top = -overflows.top + window.scrollY - parentOffsets.top + scrollBarY;
95
- coords.left = -overflows.left + window.scrollX - parentOffsets.left;
96
- finalPlacement = currentPlacement;
57
+ const base = currentPlacement.split("-")[0];
58
+ const currentIsVertical = base === "top" || base === "bottom";
59
+ const overflows2 = (0, import_detectOverflow.detectOverflow)(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);
60
+ if ((0, import_floatingPositioning.fits)(overflows2)) {
61
+ bestPlacement = currentPlacement;
62
+ bestOverflows = overflows2;
63
+ bestIsVertical = currentIsVertical;
97
64
  break;
98
65
  }
66
+ const score = (0, import_floatingPositioning.getOverflowScore)(overflows2);
67
+ const isBetter = score.maxSide < bestScore.maxSide || score.maxSide === bestScore.maxSide && score.total < bestScore.total;
68
+ if (isBetter) {
69
+ bestPlacement = currentPlacement;
70
+ bestOverflows = overflows2;
71
+ bestScore = score;
72
+ bestIsVertical = currentIsVertical;
73
+ }
99
74
  }
100
- if (!finalPlacement) {
101
- finalPlacement = placement;
102
- const overflows = (0, import_detectOverflow.detectOverflow)(referenceRect, floatingRect, placement, customOffset);
103
- coords.top = -overflows.top + window.scrollY - parentOffsets.top;
104
- coords.left = -overflows.left + window.scrollX - parentOffsets.left;
75
+ const finalPlacement = bestPlacement;
76
+ isVertical = bestIsVertical;
77
+ const overflows = bestOverflows ?? (0, import_detectOverflow.detectOverflow)(referenceRect, floatingRect, finalPlacement, customOffset, clippingRect);
78
+ let x = -overflows.left - parentOffsets.left;
79
+ let y = -overflows.top - parentOffsets.top;
80
+ if (!withoutPortal) {
81
+ x += window.scrollX;
82
+ y += window.scrollY;
83
+ } else {
84
+ const op = (0, import_floatingPositioning.getOffsetParentData)(floating);
85
+ x = x - op.left + op.scrollLeft;
86
+ y = y - op.top + op.scrollTop;
105
87
  }
88
+ ({ x, y } = (0, import_floatingPositioning.applyShift)(x, y, overflows));
106
89
  return {
107
90
  coordsStyle: {
108
- transform: `translate3d(${Math.round(coords.left ?? 0)}px, ${Math.round(coords.top ?? 0)}px, 0)`,
91
+ transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
109
92
  top: 0,
110
93
  left: 0
111
94
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/utils/computePosition.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable no-nested-ternary */\n/* eslint-disable complexity */\n/* eslint-disable max-statements */\n/* eslint-disable @typescript-eslint/no-use-before-define */\n/* eslint-disable max-params */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable arrow-body-style */\nimport type { DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport { getExpandedFallbackPlacements } from './getExpandedFallbackPlacements.js';\nimport { getArrowOffset } from './getArrowOffset.js';\nimport getOppositePlacement from './getOppositePlacement.js';\nimport { detectOverflow } from './detectOverflow.js';\n\ninterface ComputePositionProps {\n reference: Element;\n floating: HTMLElement;\n placement: DSHookFloatingContextT.PopperPlacementsT;\n placementOrderPreference?: DSHookFloatingContextT.PopperPlacementsT[];\n customOffset: [number, number];\n withoutPortal: boolean;\n}\n\nconst findFixedParent = (el: Element | null) => {\n let element = el;\n while (element && element !== document.body) {\n const style = getComputedStyle(element);\n if (style.position === 'fixed' || style.position === 'absolute') {\n return element;\n }\n element = element.parentElement;\n }\n return null;\n};\n\nconst adjustForFixedParent = (child: Element) => {\n const fixedParent = findFixedParent(child);\n if (fixedParent) {\n const rect = fixedParent.getBoundingClientRect();\n return { top: rect.top, left: rect.left };\n }\n return {\n top: 0,\n left: 0,\n };\n};\n\nexport const computePosition = (props: ComputePositionProps) => {\n const { reference, floating, placement, placementOrderPreference, customOffset, withoutPortal } = props;\n\n const scrollBarY = window.innerHeight - document.documentElement.clientHeight;\n\n const parentOffsets = withoutPortal\n ? adjustForFixedParent(reference)\n : {\n top: 0,\n left: 0,\n };\n const referenceRect = reference.getBoundingClientRect();\n const floatingRect = floating.getBoundingClientRect();\n\n const variationPlacement = placement.split('-')[1];\n const fallbackPlacements = placementOrderPreference || getExpandedFallbackPlacements(placement);\n\n const coords: { top?: number; left?: number; bottom?: number; right?: number } = {};\n\n let isVertical = false;\n const placements = [placement].concat(fallbackPlacements as DSHookFloatingContextT.PopperPlacementsT[]);\n let finalPlacement = '';\n\n for (let i = 0; i < placements.length; i += 1) {\n const currentPlacement = placements[i];\n\n const currentBasePlacement = currentPlacement.split('-')[0] as keyof typeof coords;\n isVertical = ['top', 'bottom'].indexOf(currentBasePlacement) >= 0;\n\n const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset);\n\n const checks: boolean[] = [];\n\n const isStartVariation = variationPlacement === 'start';\n\n let mainVariationSide: keyof typeof coords = isVertical\n ? isStartVariation\n ? 'right'\n : 'left'\n : isStartVariation\n ? 'bottom'\n : 'top';\n\n const len = isVertical ? 'width' : 'height';\n\n if (referenceRect[len] > floatingRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide) as keyof typeof coords;\n }\n\n const altVariationSide = getOppositePlacement(mainVariationSide) as keyof typeof coords;\n\n checks.push(overflows[currentBasePlacement] <= 0);\n checks.push(overflows[mainVariationSide] <= 0, overflows[altVariationSide] <= 0);\n if (\n checks.every((check) => {\n return check;\n })\n ) {\n coords.top = -overflows.top + window.scrollY - parentOffsets.top + scrollBarY;\n coords.left = -overflows.left + window.scrollX - parentOffsets.left;\n finalPlacement = currentPlacement;\n\n break;\n }\n }\n\n if (!finalPlacement) {\n // if we don't find a placement that fits, we use the original one\n finalPlacement = placement;\n const overflows = detectOverflow(referenceRect, floatingRect, placement, customOffset);\n coords.top = -overflows.top + window.scrollY - parentOffsets.top;\n coords.left = -overflows.left + window.scrollX - parentOffsets.left;\n }\n\n return {\n coordsStyle: {\n transform: `translate3d(${Math.round(coords.left ?? 0)}px, ${Math.round(coords.top ?? 0)}px, 0)`,\n top: 0,\n left: 0,\n },\n finalPlacement,\n coordsArrow: getArrowOffset(finalPlacement, isVertical),\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": "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",
6
- "names": ["getOppositePlacement"]
4
+ "sourcesContent": ["/* eslint-disable max-lines */\n/* eslint-disable no-nested-ternary */\n/* eslint-disable complexity */\n/* eslint-disable max-statements */\n/* eslint-disable @typescript-eslint/no-use-before-define */\n/* eslint-disable max-params */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable arrow-body-style */\nimport type { DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport { getExpandedFallbackPlacements } from './getExpandedFallbackPlacements.js';\nimport { getArrowOffset } from './getArrowOffset.js';\nimport { detectOverflow } from './detectOverflow.js';\nimport {\n applyShift,\n adjustForFixedParent,\n expandWithVariations,\n fits,\n getClippingParent,\n getOverflowScore,\n getOffsetParentData,\n getViewportRect,\n type RectLike,\n type OverflowOffsets,\n} from './floatingPositioning.js';\n\ninterface ComputePositionProps {\n reference: Element;\n floating: HTMLElement;\n placement: DSHookFloatingContextT.PopperPlacementsT;\n placementOrderPreference?: DSHookFloatingContextT.PopperPlacementsT[];\n customOffset: [number, number];\n withoutPortal: boolean;\n}\n\nexport const computePosition = (props: ComputePositionProps) => {\n const { reference, floating, placement, placementOrderPreference, customOffset, withoutPortal } = props;\n\n // When WITHOUT portal: only apply fixed-parent offsets (absolute parents scroll and must NOT be treated as fixed)\n const parentOffsets = withoutPortal ? adjustForFixedParent(reference) : { top: 0, left: 0 };\n\n const referenceRect = reference.getBoundingClientRect();\n const floatingRect = floating.getBoundingClientRect();\n\n const fallbackPlacements = placementOrderPreference || getExpandedFallbackPlacements(placement);\n\n const placements = expandWithVariations(\n [placement].concat(fallbackPlacements as DSHookFloatingContextT.PopperPlacementsT[]),\n );\n\n // Boundary selection:\n // - Portal => viewport (inset by body padding for Storybook)\n // - No portal => nearest clipping/scroll container (fallback viewport rect)\n const clippingParent = withoutPortal ? getClippingParent(reference) : null;\n const clippingRect: RectLike = clippingParent ? clippingParent.getBoundingClientRect() : getViewportRect();\n\n let isVertical = false;\n\n // Best-fit selection:\n // 1) choose first placement that fully fits\n // 2) otherwise choose placement with smallest max overflow, tie-break by total overflow\n let bestPlacement = placement;\n let bestOverflows: OverflowOffsets | null = null;\n let bestScore = { total: Number.POSITIVE_INFINITY, maxSide: Number.POSITIVE_INFINITY };\n let bestIsVertical = false;\n\n for (let i = 0; i < placements.length; i += 1) {\n const currentPlacement = placements[i];\n const base = currentPlacement.split('-')[0];\n const currentIsVertical = base === 'top' || base === 'bottom';\n\n const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);\n\n if (fits(overflows)) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\n bestIsVertical = currentIsVertical;\n break;\n }\n\n const score = getOverflowScore(overflows);\n\n const isBetter =\n score.maxSide < bestScore.maxSide || (score.maxSide === bestScore.maxSide && score.total < bestScore.total);\n\n if (isBetter) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\n bestScore = score;\n bestIsVertical = currentIsVertical;\n }\n }\n\n const finalPlacement = bestPlacement;\n isVertical = bestIsVertical;\n\n const overflows =\n bestOverflows ?? detectOverflow(referenceRect, floatingRect, finalPlacement, customOffset, clippingRect);\n\n // Convert overflow -> coordinates.\n // detectOverflow uses viewport/clipping-rect coordinates.\n //\n // - If tooltip is rendered IN A PORTAL (withoutPortal === false) and is positioned with `position: absolute`,\n // convert viewport coords to page coords by adding window.scrollX/Y.\n //\n // - If tooltip is rendered WITHOUT portal, convert viewport coords to offsetParent coords\n // (subtract offsetParent rect, add its scroll).\n let x = -overflows.left - parentOffsets.left;\n let y = -overflows.top - parentOffsets.top;\n\n if (!withoutPortal) {\n x += window.scrollX;\n y += window.scrollY;\n } else {\n const op = getOffsetParentData(floating);\n x = x - op.left + op.scrollLeft;\n y = y - op.top + op.scrollTop;\n }\n\n // Always shift back inside boundary\n ({ x, y } = applyShift(x, y, overflows));\n\n return {\n coordsStyle: {\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n top: 0,\n left: 0,\n },\n finalPlacement,\n coordsArrow: getArrowOffset(finalPlacement, isVertical),\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADSvB,2CAA8C;AAC9C,4BAA+B;AAC/B,4BAA+B;AAC/B,iCAWO;AAWA,MAAM,kBAAkB,CAAC,UAAgC;AAC9D,QAAM,EAAE,WAAW,UAAU,WAAW,0BAA0B,cAAc,cAAc,IAAI;AAGlG,QAAM,gBAAgB,oBAAgB,iDAAqB,SAAS,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE;AAE1F,QAAM,gBAAgB,UAAU,sBAAsB;AACtD,QAAM,eAAe,SAAS,sBAAsB;AAEpD,QAAM,qBAAqB,gCAA4B,oEAA8B,SAAS;AAE9F,QAAM,iBAAa;AAAA,IACjB,CAAC,SAAS,EAAE,OAAO,kBAAgE;AAAA,EACrF;AAKA,QAAM,iBAAiB,oBAAgB,8CAAkB,SAAS,IAAI;AACtE,QAAM,eAAyB,iBAAiB,eAAe,sBAAsB,QAAI,4CAAgB;AAEzG,MAAI,aAAa;AAKjB,MAAI,gBAAgB;AACpB,MAAI,gBAAwC;AAC5C,MAAI,YAAY,EAAE,OAAO,OAAO,mBAAmB,SAAS,OAAO,kBAAkB;AACrF,MAAI,iBAAiB;AAErB,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,UAAM,mBAAmB,WAAW,CAAC;AACrC,UAAM,OAAO,iBAAiB,MAAM,GAAG,EAAE,CAAC;AAC1C,UAAM,oBAAoB,SAAS,SAAS,SAAS;AAErD,UAAMA,iBAAY,sCAAe,eAAe,cAAc,kBAAkB,cAAc,YAAY;AAE1G,YAAI,iCAAKA,UAAS,GAAG;AACnB,sBAAgB;AAChB,sBAAgBA;AAChB,uBAAiB;AACjB;AAAA,IACF;AAEA,UAAM,YAAQ,6CAAiBA,UAAS;AAExC,UAAM,WACJ,MAAM,UAAU,UAAU,WAAY,MAAM,YAAY,UAAU,WAAW,MAAM,QAAQ,UAAU;AAEvG,QAAI,UAAU;AACZ,sBAAgB;AAChB,sBAAgBA;AAChB,kBAAY;AACZ,uBAAiB;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,iBAAiB;AACvB,eAAa;AAEb,QAAM,YACJ,qBAAiB,sCAAe,eAAe,cAAc,gBAAgB,cAAc,YAAY;AAUzG,MAAI,IAAI,CAAC,UAAU,OAAO,cAAc;AACxC,MAAI,IAAI,CAAC,UAAU,MAAM,cAAc;AAEvC,MAAI,CAAC,eAAe;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd,OAAO;AACL,UAAM,SAAK,gDAAoB,QAAQ;AACvC,QAAI,IAAI,GAAG,OAAO,GAAG;AACrB,QAAI,IAAI,GAAG,MAAM,GAAG;AAAA,EACtB;AAGA,GAAC,EAAE,GAAG,EAAE,QAAI,uCAAW,GAAG,GAAG,SAAS;AAEtC,SAAO;AAAA,IACL,aAAa;AAAA,MACX,WAAW,eAAe,KAAK,MAAM,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,MAC3D,KAAK;AAAA,MACL,MAAM;AAAA,IACR;AAAA,IACA;AAAA,IACA,iBAAa,sCAAe,gBAAgB,UAAU;AAAA,EACxD;AACF;",
6
+ "names": ["overflows"]
7
7
  }
@@ -51,28 +51,27 @@ function domRectToObject(rect) {
51
51
  }
52
52
  };
53
53
  }
54
- const detectOverflow = (referenceRect, floatingRect, placement, customOffset) => {
54
+ const detectOverflow = (referenceRect, floatingRect, placement, customOffset, clippingClientRect) => {
55
55
  const basePlacement = placement.split("-")[0];
56
56
  const isVertical = ["top", "bottom"].indexOf(basePlacement) >= 0;
57
- const scrollBarX = window.innerWidth - document.documentElement.clientWidth;
58
- const scrollBarY = window.innerHeight - document.documentElement.clientHeight;
59
- const clippingClientRect = {
57
+ const clipping = clippingClientRect ?? {
60
58
  top: 0,
61
59
  left: 0,
62
- right: document.documentElement.clientWidth + scrollBarX,
63
- bottom: document.documentElement.clientHeight + scrollBarY
60
+ right: window.innerWidth,
61
+ bottom: window.innerHeight
64
62
  };
65
63
  const popperOffsets = (0, import_computeOffsets.default)(placement, referenceRect, floatingRect);
66
64
  const popperClientRect = rectToClientRect({ ...domRectToObject(floatingRect), ...popperOffsets });
67
65
  const overflowOffsets = {
68
- top: clippingClientRect.top - popperClientRect.top + paddingObject.top,
69
- bottom: popperClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
70
- left: clippingClientRect.left - popperClientRect.left + paddingObject.left,
71
- right: popperClientRect.right - clippingClientRect.right + paddingObject.right
66
+ top: clipping.top - popperClientRect.top + paddingObject.top,
67
+ bottom: popperClientRect.bottom - clipping.bottom + paddingObject.bottom,
68
+ left: clipping.left - popperClientRect.left + paddingObject.left,
69
+ right: popperClientRect.right - clipping.right + paddingObject.right
72
70
  };
73
71
  const offset = {
74
72
  x: basePlacement === "left" ? -(customOffset?.[0] ?? 12) : customOffset?.[0] ?? 12,
75
- y: basePlacement === "top" ? -(customOffset?.[1] ?? -12) : customOffset?.[1] ?? 12
73
+ // FIX: default must be 12, not -12 (otherwise 'top' flips)
74
+ y: basePlacement === "top" ? -(customOffset?.[1] ?? 12) : customOffset?.[1] ?? 12
76
75
  };
77
76
  if (!isVertical) {
78
77
  const temp = offset.x;
@@ -80,8 +79,8 @@ const detectOverflow = (referenceRect, floatingRect, placement, customOffset) =>
80
79
  offset.y = temp;
81
80
  }
82
81
  Object.keys(overflowOffsets).forEach((key) => {
83
- const multiply = ["right", "bottom"].indexOf(key) >= 0 ? 1 : -1;
84
- const axis = ["top", "bottom"].indexOf(key) >= 0 ? "y" : "x";
82
+ const multiply = key === "right" || key === "bottom" ? 1 : -1;
83
+ const axis = key === "top" || key === "bottom" ? "y" : "x";
85
84
  overflowOffsets[key] += offset[axis] * multiply;
86
85
  });
87
86
  return overflowOffsets;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/utils/detectOverflow.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable no-nested-ternary */\n/* eslint-disable max-params */\nimport { type DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport computeOffsets from './computeOffsets.js';\n\nconst paddingObject = { top: 0, right: 0, bottom: 0, left: 0 };\n\nfunction rectToClientRect(rect: DOMRect) {\n return { ...rect, left: rect.x, top: rect.y, right: rect.x + rect.width, bottom: rect.y + rect.height };\n}\n\nfunction domRectToObject(rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n top: number;\n right: number;\n bottom: number;\n left: number;\n}): DOMRect {\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left,\n toJSON: () => {},\n };\n}\n\nexport const detectOverflow = (\n referenceRect: DOMRect,\n floatingRect: DOMRect,\n placement: DSHookFloatingContextT.PopperPlacementsT,\n customOffset: [number, number],\n) => {\n const basePlacement = placement.split('-')[0];\n const isVertical = ['top', 'bottom'].indexOf(basePlacement) >= 0;\n\n const scrollBarX = window.innerWidth - document.documentElement.clientWidth;\n const scrollBarY = window.innerHeight - document.documentElement.clientHeight;\n\n const clippingClientRect = {\n top: 0,\n left: 0,\n right: document.documentElement.clientWidth + scrollBarX,\n bottom: document.documentElement.clientHeight + scrollBarY,\n };\n\n const popperOffsets = computeOffsets(placement, referenceRect, floatingRect);\n const popperClientRect = rectToClientRect({ ...domRectToObject(floatingRect), ...popperOffsets });\n\n const overflowOffsets = {\n top: clippingClientRect.top - popperClientRect.top + paddingObject.top,\n bottom: popperClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - popperClientRect.left + paddingObject.left,\n right: popperClientRect.right - clippingClientRect.right + paddingObject.right,\n };\n\n const offset = {\n x: basePlacement === 'left' ? -(customOffset?.[0] ?? 12) : (customOffset?.[0] ?? 12),\n y: basePlacement === 'top' ? -(customOffset?.[1] ?? -12) : (customOffset?.[1] ?? 12),\n };\n\n // if vertical switch x for y and vice versa\n if (!isVertical) {\n const temp = offset.x;\n offset.x = offset.y * (basePlacement === 'right' ? 1 : -1);\n offset.y = temp;\n }\n\n Object.keys(overflowOffsets).forEach((key) => {\n const multiply = ['right', 'bottom'].indexOf(key) >= 0 ? 1 : -1;\n const axis = ['top', 'bottom'].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key as keyof typeof overflowOffsets] += offset[axis] * multiply;\n });\n return overflowOffsets;\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,4BAA2B;AAE3B,MAAM,gBAAgB,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE;AAE7D,SAAS,iBAAiB,MAAe;AACvC,SAAO,EAAE,GAAG,MAAM,MAAM,KAAK,GAAG,KAAK,KAAK,GAAG,OAAO,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO;AACxG;AAEA,SAAS,gBAAgB,MASb;AACV,SAAO;AAAA,IACL,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,QAAQ,MAAM;AAAA,IAAC;AAAA,EACjB;AACF;AAEO,MAAM,iBAAiB,CAC5B,eACA,cACA,WACA,iBACG;AACH,QAAM,gBAAgB,UAAU,MAAM,GAAG,EAAE,CAAC;AAC5C,QAAM,aAAa,CAAC,OAAO,QAAQ,EAAE,QAAQ,aAAa,KAAK;AAE/D,QAAM,aAAa,OAAO,aAAa,SAAS,gBAAgB;AAChE,QAAM,aAAa,OAAO,cAAc,SAAS,gBAAgB;AAEjE,QAAM,qBAAqB;AAAA,IACzB,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS,gBAAgB,cAAc;AAAA,IAC9C,QAAQ,SAAS,gBAAgB,eAAe;AAAA,EAClD;AAEA,QAAM,oBAAgB,sBAAAA,SAAe,WAAW,eAAe,YAAY;AAC3E,QAAM,mBAAmB,iBAAiB,EAAE,GAAG,gBAAgB,YAAY,GAAG,GAAG,cAAc,CAAC;AAEhG,QAAM,kBAAkB;AAAA,IACtB,KAAK,mBAAmB,MAAM,iBAAiB,MAAM,cAAc;AAAA,IACnE,QAAQ,iBAAiB,SAAS,mBAAmB,SAAS,cAAc;AAAA,IAC5E,MAAM,mBAAmB,OAAO,iBAAiB,OAAO,cAAc;AAAA,IACtE,OAAO,iBAAiB,QAAQ,mBAAmB,QAAQ,cAAc;AAAA,EAC3E;AAEA,QAAM,SAAS;AAAA,IACb,GAAG,kBAAkB,SAAS,EAAE,eAAe,CAAC,KAAK,MAAO,eAAe,CAAC,KAAK;AAAA,IACjF,GAAG,kBAAkB,QAAQ,EAAE,eAAe,CAAC,KAAK,OAAQ,eAAe,CAAC,KAAK;AAAA,EACnF;AAGA,MAAI,CAAC,YAAY;AACf,UAAM,OAAO,OAAO;AACpB,WAAO,IAAI,OAAO,KAAK,kBAAkB,UAAU,IAAI;AACvD,WAAO,IAAI;AAAA,EACb;AAEA,SAAO,KAAK,eAAe,EAAE,QAAQ,CAAC,QAAQ;AAC5C,UAAM,WAAW,CAAC,SAAS,QAAQ,EAAE,QAAQ,GAAG,KAAK,IAAI,IAAI;AAC7D,UAAM,OAAO,CAAC,OAAO,QAAQ,EAAE,QAAQ,GAAG,KAAK,IAAI,MAAM;AACzD,oBAAgB,GAAmC,KAAK,OAAO,IAAI,IAAI;AAAA,EACzE,CAAC;AACD,SAAO;AACT;",
4
+ "sourcesContent": ["/* eslint-disable no-nested-ternary */\n/* eslint-disable max-params */\nimport { type DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport computeOffsets from './computeOffsets.js';\n\nconst paddingObject = { top: 0, right: 0, bottom: 0, left: 0 };\n\ntype RectLike = { top: number; left: number; right: number; bottom: number };\n\nfunction rectToClientRect(rect: DOMRect) {\n return { ...rect, left: rect.x, top: rect.y, right: rect.x + rect.width, bottom: rect.y + rect.height };\n}\n\nfunction domRectToObject(rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n top: number;\n right: number;\n bottom: number;\n left: number;\n}): DOMRect {\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left,\n toJSON: () => {},\n };\n}\n\nexport const detectOverflow = (\n referenceRect: DOMRect,\n floatingRect: DOMRect,\n placement: DSHookFloatingContextT.PopperPlacementsT,\n customOffset: [number, number],\n clippingClientRect?: RectLike,\n) => {\n const basePlacement = placement.split('-')[0];\n const isVertical = ['top', 'bottom'].indexOf(basePlacement) >= 0;\n\n const clipping: RectLike = clippingClientRect ?? {\n top: 0,\n left: 0,\n right: window.innerWidth,\n bottom: window.innerHeight,\n };\n\n const popperOffsets = computeOffsets(placement, referenceRect, floatingRect);\n const popperClientRect = rectToClientRect({ ...domRectToObject(floatingRect), ...popperOffsets });\n\n const overflowOffsets = {\n top: clipping.top - popperClientRect.top + paddingObject.top,\n bottom: popperClientRect.bottom - clipping.bottom + paddingObject.bottom,\n left: clipping.left - popperClientRect.left + paddingObject.left,\n right: popperClientRect.right - clipping.right + paddingObject.right,\n };\n\n const offset = {\n x: basePlacement === 'left' ? -(customOffset?.[0] ?? 12) : (customOffset?.[0] ?? 12),\n // FIX: default must be 12, not -12 (otherwise 'top' flips)\n y: basePlacement === 'top' ? -(customOffset?.[1] ?? 12) : (customOffset?.[1] ?? 12),\n };\n\n // if NOT vertical, switch x for y and vice versa\n if (!isVertical) {\n const temp = offset.x;\n offset.x = offset.y * (basePlacement === 'right' ? 1 : -1);\n offset.y = temp;\n }\n\n (Object.keys(overflowOffsets) as Array<keyof typeof overflowOffsets>).forEach((key) => {\n const multiply = key === 'right' || key === 'bottom' ? 1 : -1;\n const axis = key === 'top' || key === 'bottom' ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n\n return overflowOffsets;\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,4BAA2B;AAE3B,MAAM,gBAAgB,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE;AAI7D,SAAS,iBAAiB,MAAe;AACvC,SAAO,EAAE,GAAG,MAAM,MAAM,KAAK,GAAG,KAAK,KAAK,GAAG,OAAO,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO;AACxG;AAEA,SAAS,gBAAgB,MASb;AACV,SAAO;AAAA,IACL,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,QAAQ,MAAM;AAAA,IAAC;AAAA,EACjB;AACF;AAEO,MAAM,iBAAiB,CAC5B,eACA,cACA,WACA,cACA,uBACG;AACH,QAAM,gBAAgB,UAAU,MAAM,GAAG,EAAE,CAAC;AAC5C,QAAM,aAAa,CAAC,OAAO,QAAQ,EAAE,QAAQ,aAAa,KAAK;AAE/D,QAAM,WAAqB,sBAAsB;AAAA,IAC/C,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO;AAAA,EACjB;AAEA,QAAM,oBAAgB,sBAAAA,SAAe,WAAW,eAAe,YAAY;AAC3E,QAAM,mBAAmB,iBAAiB,EAAE,GAAG,gBAAgB,YAAY,GAAG,GAAG,cAAc,CAAC;AAEhG,QAAM,kBAAkB;AAAA,IACtB,KAAK,SAAS,MAAM,iBAAiB,MAAM,cAAc;AAAA,IACzD,QAAQ,iBAAiB,SAAS,SAAS,SAAS,cAAc;AAAA,IAClE,MAAM,SAAS,OAAO,iBAAiB,OAAO,cAAc;AAAA,IAC5D,OAAO,iBAAiB,QAAQ,SAAS,QAAQ,cAAc;AAAA,EACjE;AAEA,QAAM,SAAS;AAAA,IACb,GAAG,kBAAkB,SAAS,EAAE,eAAe,CAAC,KAAK,MAAO,eAAe,CAAC,KAAK;AAAA;AAAA,IAEjF,GAAG,kBAAkB,QAAQ,EAAE,eAAe,CAAC,KAAK,MAAO,eAAe,CAAC,KAAK;AAAA,EAClF;AAGA,MAAI,CAAC,YAAY;AACf,UAAM,OAAO,OAAO;AACpB,WAAO,IAAI,OAAO,KAAK,kBAAkB,UAAU,IAAI;AACvD,WAAO,IAAI;AAAA,EACb;AAEA,EAAC,OAAO,KAAK,eAAe,EAA0C,QAAQ,CAAC,QAAQ;AACrF,UAAM,WAAW,QAAQ,WAAW,QAAQ,WAAW,IAAI;AAC3D,UAAM,OAAO,QAAQ,SAAS,QAAQ,WAAW,MAAM;AACvD,oBAAgB,GAAG,KAAK,OAAO,IAAI,IAAI;AAAA,EACzC,CAAC;AAED,SAAO;AACT;",
6
6
  "names": ["computeOffsets"]
7
7
  }
@@ -0,0 +1,131 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __export = (target, all) => {
9
+ for (var name in all)
10
+ __defProp(target, name, { get: all[name], enumerable: true });
11
+ };
12
+ var __copyProps = (to, from, except, desc) => {
13
+ if (from && typeof from === "object" || typeof from === "function") {
14
+ for (let key of __getOwnPropNames(from))
15
+ if (!__hasOwnProp.call(to, key) && key !== except)
16
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
+ }
18
+ return to;
19
+ };
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var floatingPositioning_exports = {};
30
+ __export(floatingPositioning_exports, {
31
+ adjustForFixedParent: () => adjustForFixedParent,
32
+ applyShift: () => applyShift,
33
+ expandWithVariations: () => expandWithVariations,
34
+ fits: () => fits,
35
+ getClippingParent: () => getClippingParent,
36
+ getOffsetParentData: () => getOffsetParentData,
37
+ getOverflowScore: () => getOverflowScore,
38
+ getViewportRect: () => getViewportRect
39
+ });
40
+ module.exports = __toCommonJS(floatingPositioning_exports);
41
+ var React = __toESM(require("react"));
42
+ const findFixedParent = (el) => {
43
+ let element = el;
44
+ while (element && element !== document.body) {
45
+ const style = getComputedStyle(element);
46
+ if (style.position === "fixed") {
47
+ return element;
48
+ }
49
+ element = element.parentElement;
50
+ }
51
+ return null;
52
+ };
53
+ const adjustForFixedParent = (child) => {
54
+ const fixedParent = findFixedParent(child);
55
+ if (fixedParent) {
56
+ const rect = fixedParent.getBoundingClientRect();
57
+ return { top: rect.top, left: rect.left };
58
+ }
59
+ return { top: 0, left: 0 };
60
+ };
61
+ const getClippingParent = (el) => {
62
+ let node = el?.parentElement ?? null;
63
+ while (node && node !== document.body) {
64
+ const style = getComputedStyle(node);
65
+ const overflowX = style.overflowX || style.overflow;
66
+ const overflowY = style.overflowY || style.overflow;
67
+ const clipsX = /(auto|scroll|hidden|clip)/.test(overflowX);
68
+ const clipsY = /(auto|scroll|hidden|clip)/.test(overflowY);
69
+ if (clipsX || clipsY) return node;
70
+ node = node.parentElement;
71
+ }
72
+ return null;
73
+ };
74
+ const getViewportRect = () => ({
75
+ top: 0,
76
+ left: 0,
77
+ right: window.innerWidth,
78
+ bottom: window.innerHeight
79
+ });
80
+ const applyShift = (x, y, overflow) => {
81
+ let nextX = x;
82
+ let nextY = y;
83
+ if (overflow.left > 0) nextX += overflow.left;
84
+ if (overflow.right > 0) nextX -= overflow.right;
85
+ if (overflow.top > 0) nextY += overflow.top;
86
+ if (overflow.bottom > 0) nextY -= overflow.bottom;
87
+ return { x: nextX, y: nextY };
88
+ };
89
+ const fits = (o) => o.top <= 0 && o.bottom <= 0 && o.left <= 0 && o.right <= 0;
90
+ const getOverflowScore = (o) => {
91
+ const top = Math.max(0, o.top);
92
+ const bottom = Math.max(0, o.bottom);
93
+ const left = Math.max(0, o.left);
94
+ const right = Math.max(0, o.right);
95
+ const total = top + bottom + left + right;
96
+ const maxSide = Math.max(top, bottom, left, right);
97
+ return { total, maxSide };
98
+ };
99
+ const expandWithVariations = (pls) => {
100
+ const out = [];
101
+ const seen = /* @__PURE__ */ new Set();
102
+ const add = (p) => {
103
+ if (!seen.has(p)) {
104
+ seen.add(p);
105
+ out.push(p);
106
+ }
107
+ };
108
+ pls.forEach((p) => {
109
+ add(p);
110
+ const [base, variation] = p.split("-");
111
+ if (!variation) {
112
+ add(`${base}-start`);
113
+ add(`${base}-end`);
114
+ }
115
+ });
116
+ return out;
117
+ };
118
+ const getOffsetParentData = (floating) => {
119
+ const op = floating.offsetParent;
120
+ if (!op) {
121
+ return { left: 0, top: 0, scrollLeft: 0, scrollTop: 0 };
122
+ }
123
+ const opRect = op.getBoundingClientRect();
124
+ return {
125
+ left: opRect.left,
126
+ top: opRect.top,
127
+ scrollLeft: op.scrollLeft ?? 0,
128
+ scrollTop: op.scrollTop ?? 0
129
+ };
130
+ };
131
+ //# sourceMappingURL=floatingPositioning.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../src/utils/floatingPositioning.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
4
+ "sourcesContent": ["import type { DSHookFloatingContextT } from '../react-desc-prop-types.js';\n\ntype RectLike = { top: number; left: number; right: number; bottom: number };\ntype OverflowOffsets = { top: number; bottom: number; left: number; right: number };\n\nconst findFixedParent = (el: Element | null) => {\n let element = el;\n while (element && element !== document.body) {\n const style = getComputedStyle(element);\n // IMPORTANT: only treat FIXED as special. Absolute parents are common and scroll,\n // and using their rect as an offset breaks positioning on scroll.\n if (style.position === 'fixed') {\n return element;\n }\n element = element.parentElement;\n }\n return null;\n};\n\nconst adjustForFixedParent = (child: Element) => {\n const fixedParent = findFixedParent(child);\n if (fixedParent) {\n const rect = fixedParent.getBoundingClientRect();\n return { top: rect.top, left: rect.left };\n }\n return { top: 0, left: 0 };\n};\n\n/**\n * Finds nearest ancestor that can CLIP the floating element.\n * This is typically the correct boundary when rendering without portal.\n */\nconst getClippingParent = (el: Element | null): Element | null => {\n let node = el?.parentElement ?? null;\n\n while (node && node !== document.body) {\n const style = getComputedStyle(node);\n\n const overflowX = style.overflowX || style.overflow;\n const overflowY = style.overflowY || style.overflow;\n\n const clipsX = /(auto|scroll|hidden|clip)/.test(overflowX);\n const clipsY = /(auto|scroll|hidden|clip)/.test(overflowY);\n\n if (clipsX || clipsY) return node;\n\n node = node.parentElement;\n }\n\n return null;\n};\n\nconst getViewportRect = (): RectLike => ({\n top: 0,\n left: 0,\n right: window.innerWidth,\n bottom: window.innerHeight,\n});\n\n/**\n * Shift behavior: if any overflow side is positive, push the popper back inside.\n * Similar to Floating UI \"shift\" middleware.\n */\nconst applyShift = (x: number, y: number, overflow: OverflowOffsets) => {\n let nextX = x;\n let nextY = y;\n\n if (overflow.left > 0) nextX += overflow.left;\n if (overflow.right > 0) nextX -= overflow.right;\n\n if (overflow.top > 0) nextY += overflow.top;\n if (overflow.bottom > 0) nextY -= overflow.bottom;\n\n return { x: nextX, y: nextY };\n};\n\nconst fits = (o: OverflowOffsets) => o.top <= 0 && o.bottom <= 0 && o.left <= 0 && o.right <= 0;\n\nconst getOverflowScore = (o: OverflowOffsets) => {\n const top = Math.max(0, o.top);\n const bottom = Math.max(0, o.bottom);\n const left = Math.max(0, o.left);\n const right = Math.max(0, o.right);\n\n const total = top + bottom + left + right;\n const maxSide = Math.max(top, bottom, left, right);\n\n return { total, maxSide };\n};\n\n/**\n * Ensure we actually TRY variations (start/end) for each base placement.\n * Fixes cases where only e.g. \"bottom-end\" fits but would never be tried.\n */\nconst expandWithVariations = (pls: DSHookFloatingContextT.PopperPlacementsT[]) => {\n const out: DSHookFloatingContextT.PopperPlacementsT[] = [];\n const seen = new Set<string>();\n\n const add = (p: string) => {\n if (!seen.has(p)) {\n seen.add(p);\n out.push(p as DSHookFloatingContextT.PopperPlacementsT);\n }\n };\n\n pls.forEach((p) => {\n add(p);\n\n const [base, variation] = p.split('-');\n if (!variation) {\n add(`${base}-start`);\n add(`${base}-end`);\n }\n });\n\n return out;\n};\n\n/**\n * When rendering WITHOUT portal, the floating element is positioned relative to its offsetParent.\n * But referenceRect/floatingRect are in viewport coordinates, so we must convert x/y from viewport\n * space into the offsetParent's coordinate space (including its scroll offsets).\n */\nconst getOffsetParentData = (floating: HTMLElement) => {\n const op = floating.offsetParent as HTMLElement | null;\n\n // If there's no offsetParent (rare), assume viewport.\n if (!op) {\n return { left: 0, top: 0, scrollLeft: 0, scrollTop: 0 };\n }\n\n const opRect = op.getBoundingClientRect();\n\n return {\n left: opRect.left,\n top: opRect.top,\n scrollLeft: op.scrollLeft ?? 0,\n scrollTop: op.scrollTop ?? 0,\n };\n};\n\nexport {\n applyShift,\n adjustForFixedParent,\n expandWithVariations,\n fits,\n getClippingParent,\n getOverflowScore,\n getOffsetParentData,\n getViewportRect,\n type RectLike,\n type OverflowOffsets,\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -1,78 +1,70 @@
1
1
  import * as React from "react";
2
2
  import { getExpandedFallbackPlacements } from "./getExpandedFallbackPlacements.js";
3
3
  import { getArrowOffset } from "./getArrowOffset.js";
4
- import getOppositePlacement from "./getOppositePlacement.js";
5
4
  import { detectOverflow } from "./detectOverflow.js";
6
- const findFixedParent = (el) => {
7
- let element = el;
8
- while (element && element !== document.body) {
9
- const style = getComputedStyle(element);
10
- if (style.position === "fixed" || style.position === "absolute") {
11
- return element;
12
- }
13
- element = element.parentElement;
14
- }
15
- return null;
16
- };
17
- const adjustForFixedParent = (child) => {
18
- const fixedParent = findFixedParent(child);
19
- if (fixedParent) {
20
- const rect = fixedParent.getBoundingClientRect();
21
- return { top: rect.top, left: rect.left };
22
- }
23
- return {
24
- top: 0,
25
- left: 0
26
- };
27
- };
5
+ import {
6
+ applyShift,
7
+ adjustForFixedParent,
8
+ expandWithVariations,
9
+ fits,
10
+ getClippingParent,
11
+ getOverflowScore,
12
+ getOffsetParentData,
13
+ getViewportRect
14
+ } from "./floatingPositioning.js";
28
15
  const computePosition = (props) => {
29
16
  const { reference, floating, placement, placementOrderPreference, customOffset, withoutPortal } = props;
30
- const scrollBarY = window.innerHeight - document.documentElement.clientHeight;
31
- const parentOffsets = withoutPortal ? adjustForFixedParent(reference) : {
32
- top: 0,
33
- left: 0
34
- };
17
+ const parentOffsets = withoutPortal ? adjustForFixedParent(reference) : { top: 0, left: 0 };
35
18
  const referenceRect = reference.getBoundingClientRect();
36
19
  const floatingRect = floating.getBoundingClientRect();
37
- const variationPlacement = placement.split("-")[1];
38
20
  const fallbackPlacements = placementOrderPreference || getExpandedFallbackPlacements(placement);
39
- const coords = {};
21
+ const placements = expandWithVariations(
22
+ [placement].concat(fallbackPlacements)
23
+ );
24
+ const clippingParent = withoutPortal ? getClippingParent(reference) : null;
25
+ const clippingRect = clippingParent ? clippingParent.getBoundingClientRect() : getViewportRect();
40
26
  let isVertical = false;
41
- const placements = [placement].concat(fallbackPlacements);
42
- let finalPlacement = "";
27
+ let bestPlacement = placement;
28
+ let bestOverflows = null;
29
+ let bestScore = { total: Number.POSITIVE_INFINITY, maxSide: Number.POSITIVE_INFINITY };
30
+ let bestIsVertical = false;
43
31
  for (let i = 0; i < placements.length; i += 1) {
44
32
  const currentPlacement = placements[i];
45
- const currentBasePlacement = currentPlacement.split("-")[0];
46
- isVertical = ["top", "bottom"].indexOf(currentBasePlacement) >= 0;
47
- const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset);
48
- const checks = [];
49
- const isStartVariation = variationPlacement === "start";
50
- let mainVariationSide = isVertical ? isStartVariation ? "right" : "left" : isStartVariation ? "bottom" : "top";
51
- const len = isVertical ? "width" : "height";
52
- if (referenceRect[len] > floatingRect[len]) {
53
- mainVariationSide = getOppositePlacement(mainVariationSide);
54
- }
55
- const altVariationSide = getOppositePlacement(mainVariationSide);
56
- checks.push(overflows[currentBasePlacement] <= 0);
57
- checks.push(overflows[mainVariationSide] <= 0, overflows[altVariationSide] <= 0);
58
- if (checks.every((check) => {
59
- return check;
60
- })) {
61
- coords.top = -overflows.top + window.scrollY - parentOffsets.top + scrollBarY;
62
- coords.left = -overflows.left + window.scrollX - parentOffsets.left;
63
- finalPlacement = currentPlacement;
33
+ const base = currentPlacement.split("-")[0];
34
+ const currentIsVertical = base === "top" || base === "bottom";
35
+ const overflows2 = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);
36
+ if (fits(overflows2)) {
37
+ bestPlacement = currentPlacement;
38
+ bestOverflows = overflows2;
39
+ bestIsVertical = currentIsVertical;
64
40
  break;
65
41
  }
42
+ const score = getOverflowScore(overflows2);
43
+ const isBetter = score.maxSide < bestScore.maxSide || score.maxSide === bestScore.maxSide && score.total < bestScore.total;
44
+ if (isBetter) {
45
+ bestPlacement = currentPlacement;
46
+ bestOverflows = overflows2;
47
+ bestScore = score;
48
+ bestIsVertical = currentIsVertical;
49
+ }
66
50
  }
67
- if (!finalPlacement) {
68
- finalPlacement = placement;
69
- const overflows = detectOverflow(referenceRect, floatingRect, placement, customOffset);
70
- coords.top = -overflows.top + window.scrollY - parentOffsets.top;
71
- coords.left = -overflows.left + window.scrollX - parentOffsets.left;
51
+ const finalPlacement = bestPlacement;
52
+ isVertical = bestIsVertical;
53
+ const overflows = bestOverflows ?? detectOverflow(referenceRect, floatingRect, finalPlacement, customOffset, clippingRect);
54
+ let x = -overflows.left - parentOffsets.left;
55
+ let y = -overflows.top - parentOffsets.top;
56
+ if (!withoutPortal) {
57
+ x += window.scrollX;
58
+ y += window.scrollY;
59
+ } else {
60
+ const op = getOffsetParentData(floating);
61
+ x = x - op.left + op.scrollLeft;
62
+ y = y - op.top + op.scrollTop;
72
63
  }
64
+ ({ x, y } = applyShift(x, y, overflows));
73
65
  return {
74
66
  coordsStyle: {
75
- transform: `translate3d(${Math.round(coords.left ?? 0)}px, ${Math.round(coords.top ?? 0)}px, 0)`,
67
+ transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
76
68
  top: 0,
77
69
  left: 0
78
70
  },
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/utils/computePosition.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable no-nested-ternary */\n/* eslint-disable complexity */\n/* eslint-disable max-statements */\n/* eslint-disable @typescript-eslint/no-use-before-define */\n/* eslint-disable max-params */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable arrow-body-style */\nimport type { DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport { getExpandedFallbackPlacements } from './getExpandedFallbackPlacements.js';\nimport { getArrowOffset } from './getArrowOffset.js';\nimport getOppositePlacement from './getOppositePlacement.js';\nimport { detectOverflow } from './detectOverflow.js';\n\ninterface ComputePositionProps {\n reference: Element;\n floating: HTMLElement;\n placement: DSHookFloatingContextT.PopperPlacementsT;\n placementOrderPreference?: DSHookFloatingContextT.PopperPlacementsT[];\n customOffset: [number, number];\n withoutPortal: boolean;\n}\n\nconst findFixedParent = (el: Element | null) => {\n let element = el;\n while (element && element !== document.body) {\n const style = getComputedStyle(element);\n if (style.position === 'fixed' || style.position === 'absolute') {\n return element;\n }\n element = element.parentElement;\n }\n return null;\n};\n\nconst adjustForFixedParent = (child: Element) => {\n const fixedParent = findFixedParent(child);\n if (fixedParent) {\n const rect = fixedParent.getBoundingClientRect();\n return { top: rect.top, left: rect.left };\n }\n return {\n top: 0,\n left: 0,\n };\n};\n\nexport const computePosition = (props: ComputePositionProps) => {\n const { reference, floating, placement, placementOrderPreference, customOffset, withoutPortal } = props;\n\n const scrollBarY = window.innerHeight - document.documentElement.clientHeight;\n\n const parentOffsets = withoutPortal\n ? adjustForFixedParent(reference)\n : {\n top: 0,\n left: 0,\n };\n const referenceRect = reference.getBoundingClientRect();\n const floatingRect = floating.getBoundingClientRect();\n\n const variationPlacement = placement.split('-')[1];\n const fallbackPlacements = placementOrderPreference || getExpandedFallbackPlacements(placement);\n\n const coords: { top?: number; left?: number; bottom?: number; right?: number } = {};\n\n let isVertical = false;\n const placements = [placement].concat(fallbackPlacements as DSHookFloatingContextT.PopperPlacementsT[]);\n let finalPlacement = '';\n\n for (let i = 0; i < placements.length; i += 1) {\n const currentPlacement = placements[i];\n\n const currentBasePlacement = currentPlacement.split('-')[0] as keyof typeof coords;\n isVertical = ['top', 'bottom'].indexOf(currentBasePlacement) >= 0;\n\n const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset);\n\n const checks: boolean[] = [];\n\n const isStartVariation = variationPlacement === 'start';\n\n let mainVariationSide: keyof typeof coords = isVertical\n ? isStartVariation\n ? 'right'\n : 'left'\n : isStartVariation\n ? 'bottom'\n : 'top';\n\n const len = isVertical ? 'width' : 'height';\n\n if (referenceRect[len] > floatingRect[len]) {\n mainVariationSide = getOppositePlacement(mainVariationSide) as keyof typeof coords;\n }\n\n const altVariationSide = getOppositePlacement(mainVariationSide) as keyof typeof coords;\n\n checks.push(overflows[currentBasePlacement] <= 0);\n checks.push(overflows[mainVariationSide] <= 0, overflows[altVariationSide] <= 0);\n if (\n checks.every((check) => {\n return check;\n })\n ) {\n coords.top = -overflows.top + window.scrollY - parentOffsets.top + scrollBarY;\n coords.left = -overflows.left + window.scrollX - parentOffsets.left;\n finalPlacement = currentPlacement;\n\n break;\n }\n }\n\n if (!finalPlacement) {\n // if we don't find a placement that fits, we use the original one\n finalPlacement = placement;\n const overflows = detectOverflow(referenceRect, floatingRect, placement, customOffset);\n coords.top = -overflows.top + window.scrollY - parentOffsets.top;\n coords.left = -overflows.left + window.scrollX - parentOffsets.left;\n }\n\n return {\n coordsStyle: {\n transform: `translate3d(${Math.round(coords.left ?? 0)}px, ${Math.round(coords.top ?? 0)}px, 0)`,\n top: 0,\n left: 0,\n },\n finalPlacement,\n coordsArrow: getArrowOffset(finalPlacement, isVertical),\n };\n};\n"],
5
- "mappings": "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",
6
- "names": []
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-lines */\n/* eslint-disable no-nested-ternary */\n/* eslint-disable complexity */\n/* eslint-disable max-statements */\n/* eslint-disable @typescript-eslint/no-use-before-define */\n/* eslint-disable max-params */\n/* eslint-disable @typescript-eslint/no-unsafe-assignment */\n/* eslint-disable arrow-body-style */\nimport type { DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport { getExpandedFallbackPlacements } from './getExpandedFallbackPlacements.js';\nimport { getArrowOffset } from './getArrowOffset.js';\nimport { detectOverflow } from './detectOverflow.js';\nimport {\n applyShift,\n adjustForFixedParent,\n expandWithVariations,\n fits,\n getClippingParent,\n getOverflowScore,\n getOffsetParentData,\n getViewportRect,\n type RectLike,\n type OverflowOffsets,\n} from './floatingPositioning.js';\n\ninterface ComputePositionProps {\n reference: Element;\n floating: HTMLElement;\n placement: DSHookFloatingContextT.PopperPlacementsT;\n placementOrderPreference?: DSHookFloatingContextT.PopperPlacementsT[];\n customOffset: [number, number];\n withoutPortal: boolean;\n}\n\nexport const computePosition = (props: ComputePositionProps) => {\n const { reference, floating, placement, placementOrderPreference, customOffset, withoutPortal } = props;\n\n // When WITHOUT portal: only apply fixed-parent offsets (absolute parents scroll and must NOT be treated as fixed)\n const parentOffsets = withoutPortal ? adjustForFixedParent(reference) : { top: 0, left: 0 };\n\n const referenceRect = reference.getBoundingClientRect();\n const floatingRect = floating.getBoundingClientRect();\n\n const fallbackPlacements = placementOrderPreference || getExpandedFallbackPlacements(placement);\n\n const placements = expandWithVariations(\n [placement].concat(fallbackPlacements as DSHookFloatingContextT.PopperPlacementsT[]),\n );\n\n // Boundary selection:\n // - Portal => viewport (inset by body padding for Storybook)\n // - No portal => nearest clipping/scroll container (fallback viewport rect)\n const clippingParent = withoutPortal ? getClippingParent(reference) : null;\n const clippingRect: RectLike = clippingParent ? clippingParent.getBoundingClientRect() : getViewportRect();\n\n let isVertical = false;\n\n // Best-fit selection:\n // 1) choose first placement that fully fits\n // 2) otherwise choose placement with smallest max overflow, tie-break by total overflow\n let bestPlacement = placement;\n let bestOverflows: OverflowOffsets | null = null;\n let bestScore = { total: Number.POSITIVE_INFINITY, maxSide: Number.POSITIVE_INFINITY };\n let bestIsVertical = false;\n\n for (let i = 0; i < placements.length; i += 1) {\n const currentPlacement = placements[i];\n const base = currentPlacement.split('-')[0];\n const currentIsVertical = base === 'top' || base === 'bottom';\n\n const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);\n\n if (fits(overflows)) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\n bestIsVertical = currentIsVertical;\n break;\n }\n\n const score = getOverflowScore(overflows);\n\n const isBetter =\n score.maxSide < bestScore.maxSide || (score.maxSide === bestScore.maxSide && score.total < bestScore.total);\n\n if (isBetter) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\n bestScore = score;\n bestIsVertical = currentIsVertical;\n }\n }\n\n const finalPlacement = bestPlacement;\n isVertical = bestIsVertical;\n\n const overflows =\n bestOverflows ?? detectOverflow(referenceRect, floatingRect, finalPlacement, customOffset, clippingRect);\n\n // Convert overflow -> coordinates.\n // detectOverflow uses viewport/clipping-rect coordinates.\n //\n // - If tooltip is rendered IN A PORTAL (withoutPortal === false) and is positioned with `position: absolute`,\n // convert viewport coords to page coords by adding window.scrollX/Y.\n //\n // - If tooltip is rendered WITHOUT portal, convert viewport coords to offsetParent coords\n // (subtract offsetParent rect, add its scroll).\n let x = -overflows.left - parentOffsets.left;\n let y = -overflows.top - parentOffsets.top;\n\n if (!withoutPortal) {\n x += window.scrollX;\n y += window.scrollY;\n } else {\n const op = getOffsetParentData(floating);\n x = x - op.left + op.scrollLeft;\n y = y - op.top + op.scrollTop;\n }\n\n // Always shift back inside boundary\n ({ x, y } = applyShift(x, y, overflows));\n\n return {\n coordsStyle: {\n transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,\n top: 0,\n left: 0,\n },\n finalPlacement,\n coordsArrow: getArrowOffset(finalPlacement, isVertical),\n };\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACSvB,SAAS,qCAAqC;AAC9C,SAAS,sBAAsB;AAC/B,SAAS,sBAAsB;AAC/B;AAAA,EACE;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAGK;AAWA,MAAM,kBAAkB,CAAC,UAAgC;AAC9D,QAAM,EAAE,WAAW,UAAU,WAAW,0BAA0B,cAAc,cAAc,IAAI;AAGlG,QAAM,gBAAgB,gBAAgB,qBAAqB,SAAS,IAAI,EAAE,KAAK,GAAG,MAAM,EAAE;AAE1F,QAAM,gBAAgB,UAAU,sBAAsB;AACtD,QAAM,eAAe,SAAS,sBAAsB;AAEpD,QAAM,qBAAqB,4BAA4B,8BAA8B,SAAS;AAE9F,QAAM,aAAa;AAAA,IACjB,CAAC,SAAS,EAAE,OAAO,kBAAgE;AAAA,EACrF;AAKA,QAAM,iBAAiB,gBAAgB,kBAAkB,SAAS,IAAI;AACtE,QAAM,eAAyB,iBAAiB,eAAe,sBAAsB,IAAI,gBAAgB;AAEzG,MAAI,aAAa;AAKjB,MAAI,gBAAgB;AACpB,MAAI,gBAAwC;AAC5C,MAAI,YAAY,EAAE,OAAO,OAAO,mBAAmB,SAAS,OAAO,kBAAkB;AACrF,MAAI,iBAAiB;AAErB,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,UAAM,mBAAmB,WAAW,CAAC;AACrC,UAAM,OAAO,iBAAiB,MAAM,GAAG,EAAE,CAAC;AAC1C,UAAM,oBAAoB,SAAS,SAAS,SAAS;AAErD,UAAMA,aAAY,eAAe,eAAe,cAAc,kBAAkB,cAAc,YAAY;AAE1G,QAAI,KAAKA,UAAS,GAAG;AACnB,sBAAgB;AAChB,sBAAgBA;AAChB,uBAAiB;AACjB;AAAA,IACF;AAEA,UAAM,QAAQ,iBAAiBA,UAAS;AAExC,UAAM,WACJ,MAAM,UAAU,UAAU,WAAY,MAAM,YAAY,UAAU,WAAW,MAAM,QAAQ,UAAU;AAEvG,QAAI,UAAU;AACZ,sBAAgB;AAChB,sBAAgBA;AAChB,kBAAY;AACZ,uBAAiB;AAAA,IACnB;AAAA,EACF;AAEA,QAAM,iBAAiB;AACvB,eAAa;AAEb,QAAM,YACJ,iBAAiB,eAAe,eAAe,cAAc,gBAAgB,cAAc,YAAY;AAUzG,MAAI,IAAI,CAAC,UAAU,OAAO,cAAc;AACxC,MAAI,IAAI,CAAC,UAAU,MAAM,cAAc;AAEvC,MAAI,CAAC,eAAe;AAClB,SAAK,OAAO;AACZ,SAAK,OAAO;AAAA,EACd,OAAO;AACL,UAAM,KAAK,oBAAoB,QAAQ;AACvC,QAAI,IAAI,GAAG,OAAO,GAAG;AACrB,QAAI,IAAI,GAAG,MAAM,GAAG;AAAA,EACtB;AAGA,GAAC,EAAE,GAAG,EAAE,IAAI,WAAW,GAAG,GAAG,SAAS;AAEtC,SAAO;AAAA,IACL,aAAa;AAAA,MACX,WAAW,eAAe,KAAK,MAAM,CAAC,CAAC,OAAO,KAAK,MAAM,CAAC,CAAC;AAAA,MAC3D,KAAK;AAAA,MACL,MAAM;AAAA,IACR;AAAA,IACA;AAAA,IACA,aAAa,eAAe,gBAAgB,UAAU;AAAA,EACxD;AACF;",
6
+ "names": ["overflows"]
7
7
  }
@@ -18,28 +18,27 @@ function domRectToObject(rect) {
18
18
  }
19
19
  };
20
20
  }
21
- const detectOverflow = (referenceRect, floatingRect, placement, customOffset) => {
21
+ const detectOverflow = (referenceRect, floatingRect, placement, customOffset, clippingClientRect) => {
22
22
  const basePlacement = placement.split("-")[0];
23
23
  const isVertical = ["top", "bottom"].indexOf(basePlacement) >= 0;
24
- const scrollBarX = window.innerWidth - document.documentElement.clientWidth;
25
- const scrollBarY = window.innerHeight - document.documentElement.clientHeight;
26
- const clippingClientRect = {
24
+ const clipping = clippingClientRect ?? {
27
25
  top: 0,
28
26
  left: 0,
29
- right: document.documentElement.clientWidth + scrollBarX,
30
- bottom: document.documentElement.clientHeight + scrollBarY
27
+ right: window.innerWidth,
28
+ bottom: window.innerHeight
31
29
  };
32
30
  const popperOffsets = computeOffsets(placement, referenceRect, floatingRect);
33
31
  const popperClientRect = rectToClientRect({ ...domRectToObject(floatingRect), ...popperOffsets });
34
32
  const overflowOffsets = {
35
- top: clippingClientRect.top - popperClientRect.top + paddingObject.top,
36
- bottom: popperClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,
37
- left: clippingClientRect.left - popperClientRect.left + paddingObject.left,
38
- right: popperClientRect.right - clippingClientRect.right + paddingObject.right
33
+ top: clipping.top - popperClientRect.top + paddingObject.top,
34
+ bottom: popperClientRect.bottom - clipping.bottom + paddingObject.bottom,
35
+ left: clipping.left - popperClientRect.left + paddingObject.left,
36
+ right: popperClientRect.right - clipping.right + paddingObject.right
39
37
  };
40
38
  const offset = {
41
39
  x: basePlacement === "left" ? -(customOffset?.[0] ?? 12) : customOffset?.[0] ?? 12,
42
- y: basePlacement === "top" ? -(customOffset?.[1] ?? -12) : customOffset?.[1] ?? 12
40
+ // FIX: default must be 12, not -12 (otherwise 'top' flips)
41
+ y: basePlacement === "top" ? -(customOffset?.[1] ?? 12) : customOffset?.[1] ?? 12
43
42
  };
44
43
  if (!isVertical) {
45
44
  const temp = offset.x;
@@ -47,8 +46,8 @@ const detectOverflow = (referenceRect, floatingRect, placement, customOffset) =>
47
46
  offset.y = temp;
48
47
  }
49
48
  Object.keys(overflowOffsets).forEach((key) => {
50
- const multiply = ["right", "bottom"].indexOf(key) >= 0 ? 1 : -1;
51
- const axis = ["top", "bottom"].indexOf(key) >= 0 ? "y" : "x";
49
+ const multiply = key === "right" || key === "bottom" ? 1 : -1;
50
+ const axis = key === "top" || key === "bottom" ? "y" : "x";
52
51
  overflowOffsets[key] += offset[axis] * multiply;
53
52
  });
54
53
  return overflowOffsets;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/utils/detectOverflow.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable no-nested-ternary */\n/* eslint-disable max-params */\nimport { type DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport computeOffsets from './computeOffsets.js';\n\nconst paddingObject = { top: 0, right: 0, bottom: 0, left: 0 };\n\nfunction rectToClientRect(rect: DOMRect) {\n return { ...rect, left: rect.x, top: rect.y, right: rect.x + rect.width, bottom: rect.y + rect.height };\n}\n\nfunction domRectToObject(rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n top: number;\n right: number;\n bottom: number;\n left: number;\n}): DOMRect {\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left,\n toJSON: () => {},\n };\n}\n\nexport const detectOverflow = (\n referenceRect: DOMRect,\n floatingRect: DOMRect,\n placement: DSHookFloatingContextT.PopperPlacementsT,\n customOffset: [number, number],\n) => {\n const basePlacement = placement.split('-')[0];\n const isVertical = ['top', 'bottom'].indexOf(basePlacement) >= 0;\n\n const scrollBarX = window.innerWidth - document.documentElement.clientWidth;\n const scrollBarY = window.innerHeight - document.documentElement.clientHeight;\n\n const clippingClientRect = {\n top: 0,\n left: 0,\n right: document.documentElement.clientWidth + scrollBarX,\n bottom: document.documentElement.clientHeight + scrollBarY,\n };\n\n const popperOffsets = computeOffsets(placement, referenceRect, floatingRect);\n const popperClientRect = rectToClientRect({ ...domRectToObject(floatingRect), ...popperOffsets });\n\n const overflowOffsets = {\n top: clippingClientRect.top - popperClientRect.top + paddingObject.top,\n bottom: popperClientRect.bottom - clippingClientRect.bottom + paddingObject.bottom,\n left: clippingClientRect.left - popperClientRect.left + paddingObject.left,\n right: popperClientRect.right - clippingClientRect.right + paddingObject.right,\n };\n\n const offset = {\n x: basePlacement === 'left' ? -(customOffset?.[0] ?? 12) : (customOffset?.[0] ?? 12),\n y: basePlacement === 'top' ? -(customOffset?.[1] ?? -12) : (customOffset?.[1] ?? 12),\n };\n\n // if vertical switch x for y and vice versa\n if (!isVertical) {\n const temp = offset.x;\n offset.x = offset.y * (basePlacement === 'right' ? 1 : -1);\n offset.y = temp;\n }\n\n Object.keys(overflowOffsets).forEach((key) => {\n const multiply = ['right', 'bottom'].indexOf(key) >= 0 ? 1 : -1;\n const axis = ['top', 'bottom'].indexOf(key) >= 0 ? 'y' : 'x';\n overflowOffsets[key as keyof typeof overflowOffsets] += offset[axis] * multiply;\n });\n return overflowOffsets;\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACGvB,OAAO,oBAAoB;AAE3B,MAAM,gBAAgB,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE;AAE7D,SAAS,iBAAiB,MAAe;AACvC,SAAO,EAAE,GAAG,MAAM,MAAM,KAAK,GAAG,KAAK,KAAK,GAAG,OAAO,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO;AACxG;AAEA,SAAS,gBAAgB,MASb;AACV,SAAO;AAAA,IACL,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,QAAQ,MAAM;AAAA,IAAC;AAAA,EACjB;AACF;AAEO,MAAM,iBAAiB,CAC5B,eACA,cACA,WACA,iBACG;AACH,QAAM,gBAAgB,UAAU,MAAM,GAAG,EAAE,CAAC;AAC5C,QAAM,aAAa,CAAC,OAAO,QAAQ,EAAE,QAAQ,aAAa,KAAK;AAE/D,QAAM,aAAa,OAAO,aAAa,SAAS,gBAAgB;AAChE,QAAM,aAAa,OAAO,cAAc,SAAS,gBAAgB;AAEjE,QAAM,qBAAqB;AAAA,IACzB,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO,SAAS,gBAAgB,cAAc;AAAA,IAC9C,QAAQ,SAAS,gBAAgB,eAAe;AAAA,EAClD;AAEA,QAAM,gBAAgB,eAAe,WAAW,eAAe,YAAY;AAC3E,QAAM,mBAAmB,iBAAiB,EAAE,GAAG,gBAAgB,YAAY,GAAG,GAAG,cAAc,CAAC;AAEhG,QAAM,kBAAkB;AAAA,IACtB,KAAK,mBAAmB,MAAM,iBAAiB,MAAM,cAAc;AAAA,IACnE,QAAQ,iBAAiB,SAAS,mBAAmB,SAAS,cAAc;AAAA,IAC5E,MAAM,mBAAmB,OAAO,iBAAiB,OAAO,cAAc;AAAA,IACtE,OAAO,iBAAiB,QAAQ,mBAAmB,QAAQ,cAAc;AAAA,EAC3E;AAEA,QAAM,SAAS;AAAA,IACb,GAAG,kBAAkB,SAAS,EAAE,eAAe,CAAC,KAAK,MAAO,eAAe,CAAC,KAAK;AAAA,IACjF,GAAG,kBAAkB,QAAQ,EAAE,eAAe,CAAC,KAAK,OAAQ,eAAe,CAAC,KAAK;AAAA,EACnF;AAGA,MAAI,CAAC,YAAY;AACf,UAAM,OAAO,OAAO;AACpB,WAAO,IAAI,OAAO,KAAK,kBAAkB,UAAU,IAAI;AACvD,WAAO,IAAI;AAAA,EACb;AAEA,SAAO,KAAK,eAAe,EAAE,QAAQ,CAAC,QAAQ;AAC5C,UAAM,WAAW,CAAC,SAAS,QAAQ,EAAE,QAAQ,GAAG,KAAK,IAAI,IAAI;AAC7D,UAAM,OAAO,CAAC,OAAO,QAAQ,EAAE,QAAQ,GAAG,KAAK,IAAI,MAAM;AACzD,oBAAgB,GAAmC,KAAK,OAAO,IAAI,IAAI;AAAA,EACzE,CAAC;AACD,SAAO;AACT;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable no-nested-ternary */\n/* eslint-disable max-params */\nimport { type DSHookFloatingContextT } from '../react-desc-prop-types.js';\nimport computeOffsets from './computeOffsets.js';\n\nconst paddingObject = { top: 0, right: 0, bottom: 0, left: 0 };\n\ntype RectLike = { top: number; left: number; right: number; bottom: number };\n\nfunction rectToClientRect(rect: DOMRect) {\n return { ...rect, left: rect.x, top: rect.y, right: rect.x + rect.width, bottom: rect.y + rect.height };\n}\n\nfunction domRectToObject(rect: {\n x: number;\n y: number;\n width: number;\n height: number;\n top: number;\n right: number;\n bottom: number;\n left: number;\n}): DOMRect {\n return {\n x: rect.x,\n y: rect.y,\n width: rect.width,\n height: rect.height,\n top: rect.top,\n right: rect.right,\n bottom: rect.bottom,\n left: rect.left,\n toJSON: () => {},\n };\n}\n\nexport const detectOverflow = (\n referenceRect: DOMRect,\n floatingRect: DOMRect,\n placement: DSHookFloatingContextT.PopperPlacementsT,\n customOffset: [number, number],\n clippingClientRect?: RectLike,\n) => {\n const basePlacement = placement.split('-')[0];\n const isVertical = ['top', 'bottom'].indexOf(basePlacement) >= 0;\n\n const clipping: RectLike = clippingClientRect ?? {\n top: 0,\n left: 0,\n right: window.innerWidth,\n bottom: window.innerHeight,\n };\n\n const popperOffsets = computeOffsets(placement, referenceRect, floatingRect);\n const popperClientRect = rectToClientRect({ ...domRectToObject(floatingRect), ...popperOffsets });\n\n const overflowOffsets = {\n top: clipping.top - popperClientRect.top + paddingObject.top,\n bottom: popperClientRect.bottom - clipping.bottom + paddingObject.bottom,\n left: clipping.left - popperClientRect.left + paddingObject.left,\n right: popperClientRect.right - clipping.right + paddingObject.right,\n };\n\n const offset = {\n x: basePlacement === 'left' ? -(customOffset?.[0] ?? 12) : (customOffset?.[0] ?? 12),\n // FIX: default must be 12, not -12 (otherwise 'top' flips)\n y: basePlacement === 'top' ? -(customOffset?.[1] ?? 12) : (customOffset?.[1] ?? 12),\n };\n\n // if NOT vertical, switch x for y and vice versa\n if (!isVertical) {\n const temp = offset.x;\n offset.x = offset.y * (basePlacement === 'right' ? 1 : -1);\n offset.y = temp;\n }\n\n (Object.keys(overflowOffsets) as Array<keyof typeof overflowOffsets>).forEach((key) => {\n const multiply = key === 'right' || key === 'bottom' ? 1 : -1;\n const axis = key === 'top' || key === 'bottom' ? 'y' : 'x';\n overflowOffsets[key] += offset[axis] * multiply;\n });\n\n return overflowOffsets;\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACGvB,OAAO,oBAAoB;AAE3B,MAAM,gBAAgB,EAAE,KAAK,GAAG,OAAO,GAAG,QAAQ,GAAG,MAAM,EAAE;AAI7D,SAAS,iBAAiB,MAAe;AACvC,SAAO,EAAE,GAAG,MAAM,MAAM,KAAK,GAAG,KAAK,KAAK,GAAG,OAAO,KAAK,IAAI,KAAK,OAAO,QAAQ,KAAK,IAAI,KAAK,OAAO;AACxG;AAEA,SAAS,gBAAgB,MASb;AACV,SAAO;AAAA,IACL,GAAG,KAAK;AAAA,IACR,GAAG,KAAK;AAAA,IACR,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,KAAK,KAAK;AAAA,IACV,OAAO,KAAK;AAAA,IACZ,QAAQ,KAAK;AAAA,IACb,MAAM,KAAK;AAAA,IACX,QAAQ,MAAM;AAAA,IAAC;AAAA,EACjB;AACF;AAEO,MAAM,iBAAiB,CAC5B,eACA,cACA,WACA,cACA,uBACG;AACH,QAAM,gBAAgB,UAAU,MAAM,GAAG,EAAE,CAAC;AAC5C,QAAM,aAAa,CAAC,OAAO,QAAQ,EAAE,QAAQ,aAAa,KAAK;AAE/D,QAAM,WAAqB,sBAAsB;AAAA,IAC/C,KAAK;AAAA,IACL,MAAM;AAAA,IACN,OAAO,OAAO;AAAA,IACd,QAAQ,OAAO;AAAA,EACjB;AAEA,QAAM,gBAAgB,eAAe,WAAW,eAAe,YAAY;AAC3E,QAAM,mBAAmB,iBAAiB,EAAE,GAAG,gBAAgB,YAAY,GAAG,GAAG,cAAc,CAAC;AAEhG,QAAM,kBAAkB;AAAA,IACtB,KAAK,SAAS,MAAM,iBAAiB,MAAM,cAAc;AAAA,IACzD,QAAQ,iBAAiB,SAAS,SAAS,SAAS,cAAc;AAAA,IAClE,MAAM,SAAS,OAAO,iBAAiB,OAAO,cAAc;AAAA,IAC5D,OAAO,iBAAiB,QAAQ,SAAS,QAAQ,cAAc;AAAA,EACjE;AAEA,QAAM,SAAS;AAAA,IACb,GAAG,kBAAkB,SAAS,EAAE,eAAe,CAAC,KAAK,MAAO,eAAe,CAAC,KAAK;AAAA;AAAA,IAEjF,GAAG,kBAAkB,QAAQ,EAAE,eAAe,CAAC,KAAK,MAAO,eAAe,CAAC,KAAK;AAAA,EAClF;AAGA,MAAI,CAAC,YAAY;AACf,UAAM,OAAO,OAAO;AACpB,WAAO,IAAI,OAAO,KAAK,kBAAkB,UAAU,IAAI;AACvD,WAAO,IAAI;AAAA,EACb;AAEA,EAAC,OAAO,KAAK,eAAe,EAA0C,QAAQ,CAAC,QAAQ;AACrF,UAAM,WAAW,QAAQ,WAAW,QAAQ,WAAW,IAAI;AAC3D,UAAM,OAAO,QAAQ,SAAS,QAAQ,WAAW,MAAM;AACvD,oBAAgB,GAAG,KAAK,OAAO,IAAI,IAAI;AAAA,EACzC,CAAC;AAED,SAAO;AACT;",
6
6
  "names": []
7
7
  }
@@ -0,0 +1,101 @@
1
+ import * as React from "react";
2
+ const findFixedParent = (el) => {
3
+ let element = el;
4
+ while (element && element !== document.body) {
5
+ const style = getComputedStyle(element);
6
+ if (style.position === "fixed") {
7
+ return element;
8
+ }
9
+ element = element.parentElement;
10
+ }
11
+ return null;
12
+ };
13
+ const adjustForFixedParent = (child) => {
14
+ const fixedParent = findFixedParent(child);
15
+ if (fixedParent) {
16
+ const rect = fixedParent.getBoundingClientRect();
17
+ return { top: rect.top, left: rect.left };
18
+ }
19
+ return { top: 0, left: 0 };
20
+ };
21
+ const getClippingParent = (el) => {
22
+ let node = el?.parentElement ?? null;
23
+ while (node && node !== document.body) {
24
+ const style = getComputedStyle(node);
25
+ const overflowX = style.overflowX || style.overflow;
26
+ const overflowY = style.overflowY || style.overflow;
27
+ const clipsX = /(auto|scroll|hidden|clip)/.test(overflowX);
28
+ const clipsY = /(auto|scroll|hidden|clip)/.test(overflowY);
29
+ if (clipsX || clipsY) return node;
30
+ node = node.parentElement;
31
+ }
32
+ return null;
33
+ };
34
+ const getViewportRect = () => ({
35
+ top: 0,
36
+ left: 0,
37
+ right: window.innerWidth,
38
+ bottom: window.innerHeight
39
+ });
40
+ const applyShift = (x, y, overflow) => {
41
+ let nextX = x;
42
+ let nextY = y;
43
+ if (overflow.left > 0) nextX += overflow.left;
44
+ if (overflow.right > 0) nextX -= overflow.right;
45
+ if (overflow.top > 0) nextY += overflow.top;
46
+ if (overflow.bottom > 0) nextY -= overflow.bottom;
47
+ return { x: nextX, y: nextY };
48
+ };
49
+ const fits = (o) => o.top <= 0 && o.bottom <= 0 && o.left <= 0 && o.right <= 0;
50
+ const getOverflowScore = (o) => {
51
+ const top = Math.max(0, o.top);
52
+ const bottom = Math.max(0, o.bottom);
53
+ const left = Math.max(0, o.left);
54
+ const right = Math.max(0, o.right);
55
+ const total = top + bottom + left + right;
56
+ const maxSide = Math.max(top, bottom, left, right);
57
+ return { total, maxSide };
58
+ };
59
+ const expandWithVariations = (pls) => {
60
+ const out = [];
61
+ const seen = /* @__PURE__ */ new Set();
62
+ const add = (p) => {
63
+ if (!seen.has(p)) {
64
+ seen.add(p);
65
+ out.push(p);
66
+ }
67
+ };
68
+ pls.forEach((p) => {
69
+ add(p);
70
+ const [base, variation] = p.split("-");
71
+ if (!variation) {
72
+ add(`${base}-start`);
73
+ add(`${base}-end`);
74
+ }
75
+ });
76
+ return out;
77
+ };
78
+ const getOffsetParentData = (floating) => {
79
+ const op = floating.offsetParent;
80
+ if (!op) {
81
+ return { left: 0, top: 0, scrollLeft: 0, scrollTop: 0 };
82
+ }
83
+ const opRect = op.getBoundingClientRect();
84
+ return {
85
+ left: opRect.left,
86
+ top: opRect.top,
87
+ scrollLeft: op.scrollLeft ?? 0,
88
+ scrollTop: op.scrollTop ?? 0
89
+ };
90
+ };
91
+ export {
92
+ adjustForFixedParent,
93
+ applyShift,
94
+ expandWithVariations,
95
+ fits,
96
+ getClippingParent,
97
+ getOffsetParentData,
98
+ getOverflowScore,
99
+ getViewportRect
100
+ };
101
+ //# sourceMappingURL=floatingPositioning.js.map
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/utils/floatingPositioning.ts"],
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "import type { DSHookFloatingContextT } from '../react-desc-prop-types.js';\n\ntype RectLike = { top: number; left: number; right: number; bottom: number };\ntype OverflowOffsets = { top: number; bottom: number; left: number; right: number };\n\nconst findFixedParent = (el: Element | null) => {\n let element = el;\n while (element && element !== document.body) {\n const style = getComputedStyle(element);\n // IMPORTANT: only treat FIXED as special. Absolute parents are common and scroll,\n // and using their rect as an offset breaks positioning on scroll.\n if (style.position === 'fixed') {\n return element;\n }\n element = element.parentElement;\n }\n return null;\n};\n\nconst adjustForFixedParent = (child: Element) => {\n const fixedParent = findFixedParent(child);\n if (fixedParent) {\n const rect = fixedParent.getBoundingClientRect();\n return { top: rect.top, left: rect.left };\n }\n return { top: 0, left: 0 };\n};\n\n/**\n * Finds nearest ancestor that can CLIP the floating element.\n * This is typically the correct boundary when rendering without portal.\n */\nconst getClippingParent = (el: Element | null): Element | null => {\n let node = el?.parentElement ?? null;\n\n while (node && node !== document.body) {\n const style = getComputedStyle(node);\n\n const overflowX = style.overflowX || style.overflow;\n const overflowY = style.overflowY || style.overflow;\n\n const clipsX = /(auto|scroll|hidden|clip)/.test(overflowX);\n const clipsY = /(auto|scroll|hidden|clip)/.test(overflowY);\n\n if (clipsX || clipsY) return node;\n\n node = node.parentElement;\n }\n\n return null;\n};\n\nconst getViewportRect = (): RectLike => ({\n top: 0,\n left: 0,\n right: window.innerWidth,\n bottom: window.innerHeight,\n});\n\n/**\n * Shift behavior: if any overflow side is positive, push the popper back inside.\n * Similar to Floating UI \"shift\" middleware.\n */\nconst applyShift = (x: number, y: number, overflow: OverflowOffsets) => {\n let nextX = x;\n let nextY = y;\n\n if (overflow.left > 0) nextX += overflow.left;\n if (overflow.right > 0) nextX -= overflow.right;\n\n if (overflow.top > 0) nextY += overflow.top;\n if (overflow.bottom > 0) nextY -= overflow.bottom;\n\n return { x: nextX, y: nextY };\n};\n\nconst fits = (o: OverflowOffsets) => o.top <= 0 && o.bottom <= 0 && o.left <= 0 && o.right <= 0;\n\nconst getOverflowScore = (o: OverflowOffsets) => {\n const top = Math.max(0, o.top);\n const bottom = Math.max(0, o.bottom);\n const left = Math.max(0, o.left);\n const right = Math.max(0, o.right);\n\n const total = top + bottom + left + right;\n const maxSide = Math.max(top, bottom, left, right);\n\n return { total, maxSide };\n};\n\n/**\n * Ensure we actually TRY variations (start/end) for each base placement.\n * Fixes cases where only e.g. \"bottom-end\" fits but would never be tried.\n */\nconst expandWithVariations = (pls: DSHookFloatingContextT.PopperPlacementsT[]) => {\n const out: DSHookFloatingContextT.PopperPlacementsT[] = [];\n const seen = new Set<string>();\n\n const add = (p: string) => {\n if (!seen.has(p)) {\n seen.add(p);\n out.push(p as DSHookFloatingContextT.PopperPlacementsT);\n }\n };\n\n pls.forEach((p) => {\n add(p);\n\n const [base, variation] = p.split('-');\n if (!variation) {\n add(`${base}-start`);\n add(`${base}-end`);\n }\n });\n\n return out;\n};\n\n/**\n * When rendering WITHOUT portal, the floating element is positioned relative to its offsetParent.\n * But referenceRect/floatingRect are in viewport coordinates, so we must convert x/y from viewport\n * space into the offsetParent's coordinate space (including its scroll offsets).\n */\nconst getOffsetParentData = (floating: HTMLElement) => {\n const op = floating.offsetParent as HTMLElement | null;\n\n // If there's no offsetParent (rare), assume viewport.\n if (!op) {\n return { left: 0, top: 0, scrollLeft: 0, scrollTop: 0 };\n }\n\n const opRect = op.getBoundingClientRect();\n\n return {\n left: opRect.left,\n top: opRect.top,\n scrollLeft: op.scrollLeft ?? 0,\n scrollTop: op.scrollTop ?? 0,\n };\n};\n\nexport {\n applyShift,\n adjustForFixedParent,\n expandWithVariations,\n fits,\n getClippingParent,\n getOverflowScore,\n getOffsetParentData,\n getViewportRect,\n type RectLike,\n type OverflowOffsets,\n};\n"],
5
+ "mappings": "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",
6
+ "names": []
7
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -13,7 +13,7 @@ export declare const computePosition: (props: ComputePositionProps) => {
13
13
  top: number;
14
14
  left: number;
15
15
  };
16
- finalPlacement: string;
16
+ finalPlacement: DSHookFloatingContextT.PopperPlacementsT;
17
17
  coordsArrow: {
18
18
  left: string;
19
19
  top?: undefined;
@@ -1,7 +1,14 @@
1
1
  import { type DSHookFloatingContextT } from '../react-desc-prop-types.js';
2
- export declare const detectOverflow: (referenceRect: DOMRect, floatingRect: DOMRect, placement: DSHookFloatingContextT.PopperPlacementsT, customOffset: [number, number]) => {
2
+ type RectLike = {
3
+ top: number;
4
+ left: number;
5
+ right: number;
6
+ bottom: number;
7
+ };
8
+ export declare const detectOverflow: (referenceRect: DOMRect, floatingRect: DOMRect, placement: DSHookFloatingContextT.PopperPlacementsT, customOffset: [number, number], clippingClientRect?: RectLike) => {
3
9
  top: number;
4
10
  bottom: number;
5
11
  left: number;
6
12
  right: number;
7
13
  };
14
+ export {};
@@ -0,0 +1,53 @@
1
+ import type { DSHookFloatingContextT } from '../react-desc-prop-types.js';
2
+ type RectLike = {
3
+ top: number;
4
+ left: number;
5
+ right: number;
6
+ bottom: number;
7
+ };
8
+ type OverflowOffsets = {
9
+ top: number;
10
+ bottom: number;
11
+ left: number;
12
+ right: number;
13
+ };
14
+ declare const adjustForFixedParent: (child: Element) => {
15
+ top: number;
16
+ left: number;
17
+ };
18
+ /**
19
+ * Finds nearest ancestor that can CLIP the floating element.
20
+ * This is typically the correct boundary when rendering without portal.
21
+ */
22
+ declare const getClippingParent: (el: Element | null) => Element | null;
23
+ declare const getViewportRect: () => RectLike;
24
+ /**
25
+ * Shift behavior: if any overflow side is positive, push the popper back inside.
26
+ * Similar to Floating UI "shift" middleware.
27
+ */
28
+ declare const applyShift: (x: number, y: number, overflow: OverflowOffsets) => {
29
+ x: number;
30
+ y: number;
31
+ };
32
+ declare const fits: (o: OverflowOffsets) => boolean;
33
+ declare const getOverflowScore: (o: OverflowOffsets) => {
34
+ total: number;
35
+ maxSide: number;
36
+ };
37
+ /**
38
+ * Ensure we actually TRY variations (start/end) for each base placement.
39
+ * Fixes cases where only e.g. "bottom-end" fits but would never be tried.
40
+ */
41
+ declare const expandWithVariations: (pls: DSHookFloatingContextT.PopperPlacementsT[]) => DSHookFloatingContextT.PopperPlacementsT[];
42
+ /**
43
+ * When rendering WITHOUT portal, the floating element is positioned relative to its offsetParent.
44
+ * But referenceRect/floatingRect are in viewport coordinates, so we must convert x/y from viewport
45
+ * space into the offsetParent's coordinate space (including its scroll offsets).
46
+ */
47
+ declare const getOffsetParentData: (floating: HTMLElement) => {
48
+ left: number;
49
+ top: number;
50
+ scrollLeft: number;
51
+ scrollTop: number;
52
+ };
53
+ export { applyShift, adjustForFixedParent, expandWithVariations, fits, getClippingParent, getOverflowScore, getOffsetParentData, getViewportRect, type RectLike, type OverflowOffsets, };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elliemae/ds-floating-context",
3
- "version": "3.57.6",
3
+ "version": "3.57.7",
4
4
  "license": "MIT",
5
5
  "description": "ICE MT - Dimsum - Popper Hook",
6
6
  "files": [
@@ -36,15 +36,15 @@
36
36
  "indent": 4
37
37
  },
38
38
  "dependencies": {
39
- "@elliemae/ds-hooks-headless-tooltip": "3.57.6",
40
- "@elliemae/ds-props-helpers": "3.57.6",
41
- "@elliemae/ds-system": "3.57.6",
42
- "@elliemae/ds-typescript-helpers": "3.57.6"
39
+ "@elliemae/ds-hooks-headless-tooltip": "3.57.7",
40
+ "@elliemae/ds-props-helpers": "3.57.7",
41
+ "@elliemae/ds-system": "3.57.7",
42
+ "@elliemae/ds-typescript-helpers": "3.57.7"
43
43
  },
44
44
  "devDependencies": {
45
45
  "@elliemae/pui-cli": "9.0.0-next.65",
46
46
  "jest": "~29.7.0",
47
- "@elliemae/ds-monorepo-devops": "3.57.6"
47
+ "@elliemae/ds-monorepo-devops": "3.57.7"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "lodash-es": "^4.17.21",