@elliemae/ds-floating-context 3.57.7 → 3.57.9

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.
@@ -47,20 +47,15 @@ const computePosition = (props) => {
47
47
  );
48
48
  const clippingParent = withoutPortal ? (0, import_floatingPositioning.getClippingParent)(reference) : null;
49
49
  const clippingRect = clippingParent ? clippingParent.getBoundingClientRect() : (0, import_floatingPositioning.getViewportRect)();
50
- let isVertical = false;
51
50
  let bestPlacement = placement;
52
51
  let bestOverflows = null;
53
52
  let bestScore = { total: Number.POSITIVE_INFINITY, maxSide: Number.POSITIVE_INFINITY };
54
- let bestIsVertical = false;
55
53
  for (let i = 0; i < placements.length; i += 1) {
56
54
  const currentPlacement = placements[i];
57
- const base = currentPlacement.split("-")[0];
58
- const currentIsVertical = base === "top" || base === "bottom";
59
55
  const overflows2 = (0, import_detectOverflow.detectOverflow)(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);
60
56
  if ((0, import_floatingPositioning.fits)(overflows2)) {
61
57
  bestPlacement = currentPlacement;
62
58
  bestOverflows = overflows2;
63
- bestIsVertical = currentIsVertical;
64
59
  break;
65
60
  }
66
61
  const score = (0, import_floatingPositioning.getOverflowScore)(overflows2);
@@ -69,11 +64,9 @@ const computePosition = (props) => {
69
64
  bestPlacement = currentPlacement;
70
65
  bestOverflows = overflows2;
71
66
  bestScore = score;
72
- bestIsVertical = currentIsVertical;
73
67
  }
74
68
  }
75
69
  const finalPlacement = bestPlacement;
76
- isVertical = bestIsVertical;
77
70
  const overflows = bestOverflows ?? (0, import_detectOverflow.detectOverflow)(referenceRect, floatingRect, finalPlacement, customOffset, clippingRect);
78
71
  let x = -overflows.left - parentOffsets.left;
79
72
  let y = -overflows.top - parentOffsets.top;
@@ -86,6 +79,17 @@ const computePosition = (props) => {
86
79
  y = y - op.top + op.scrollTop;
87
80
  }
88
81
  ({ x, y } = (0, import_floatingPositioning.applyShift)(x, y, overflows));
82
+ const coordsArrow = (0, import_getArrowOffset.getArrowOffsetDynamic)({
83
+ placement: finalPlacement,
84
+ referenceRect,
85
+ floatingRect,
86
+ x,
87
+ y,
88
+ withoutPortal,
89
+ parentOffsets,
90
+ floatingEl: floating,
91
+ arrowPadding: 12
92
+ });
89
93
  return {
90
94
  coordsStyle: {
91
95
  transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
@@ -93,7 +97,7 @@ const computePosition = (props) => {
93
97
  left: 0
94
98
  },
95
99
  finalPlacement,
96
- coordsArrow: (0, import_getArrowOffset.getArrowOffset)(finalPlacement, isVertical)
100
+ coordsArrow
97
101
  };
98
102
  };
99
103
  //# sourceMappingURL=computePosition.js.map
@@ -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 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;",
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 { getArrowOffsetDynamic } 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 // 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\n for (let i = 0; i < placements.length; i += 1) {\n const currentPlacement = placements[i];\n\n const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);\n\n if (fits(overflows)) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\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 }\n }\n\n const finalPlacement = bestPlacement;\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 const coordsArrow = getArrowOffsetDynamic({\n placement: finalPlacement,\n referenceRect,\n floatingRect,\n x,\n y,\n withoutPortal,\n parentOffsets,\n floatingEl: floating,\n arrowPadding: 12,\n });\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,\n };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADSvB,2CAA8C;AAC9C,4BAAsC;AACtC,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;AAKzG,MAAI,gBAAgB;AACpB,MAAI,gBAAwC;AAC5C,MAAI,YAAY,EAAE,OAAO,OAAO,mBAAmB,SAAS,OAAO,kBAAkB;AAErF,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,UAAM,mBAAmB,WAAW,CAAC;AAErC,UAAMA,iBAAY,sCAAe,eAAe,cAAc,kBAAkB,cAAc,YAAY;AAE1G,YAAI,iCAAKA,UAAS,GAAG;AACnB,sBAAgB;AAChB,sBAAgBA;AAChB;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;AAAA,IACd;AAAA,EACF;AAEA,QAAM,iBAAiB;AAEvB,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,QAAM,kBAAc,6CAAsB;AAAA,IACxC,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB,CAAC;AAED,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,EACF;AACF;",
6
6
  "names": ["overflows"]
7
7
  }
@@ -28,14 +28,46 @@ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__ge
28
28
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
29
  var getArrowOffset_exports = {};
30
30
  __export(getArrowOffset_exports, {
31
- getArrowOffset: () => getArrowOffset
31
+ getArrowOffsetDynamic: () => getArrowOffsetDynamic
32
32
  });
33
33
  module.exports = __toCommonJS(getArrowOffset_exports);
34
34
  var React = __toESM(require("react"));
35
- const getArrowOffset = (placement, isVertical) => {
35
+ const clamp = (v, min, max) => Math.min(max, Math.max(min, v));
36
+ const getArrowOffsetDynamic = ({
37
+ placement,
38
+ referenceRect,
39
+ floatingRect,
40
+ x,
41
+ y,
42
+ withoutPortal,
43
+ parentOffsets,
44
+ floatingEl,
45
+ arrowPadding = 12
46
+ }) => {
47
+ const base = placement.split("-")[0];
48
+ const isVertical = base === "top" || base === "bottom";
49
+ const refCenterViewportX = referenceRect.left + referenceRect.width / 2;
50
+ const refCenterViewportY = referenceRect.top + referenceRect.height / 2;
51
+ let refCenterX;
52
+ let refCenterY;
53
+ if (!withoutPortal) {
54
+ refCenterX = refCenterViewportX + window.scrollX;
55
+ refCenterY = refCenterViewportY + window.scrollY;
56
+ } else {
57
+ const op = floatingEl.offsetParent;
58
+ const opRect = op?.getBoundingClientRect();
59
+ const opLeft = opRect?.left ?? 0;
60
+ const opTop = opRect?.top ?? 0;
61
+ const opScrollLeft = op?.scrollLeft ?? 0;
62
+ const opScrollTop = op?.scrollTop ?? 0;
63
+ refCenterX = refCenterViewportX - parentOffsets.left - opLeft + opScrollLeft;
64
+ refCenterY = refCenterViewportY - parentOffsets.top - opTop + opScrollTop;
65
+ }
36
66
  if (isVertical) {
37
- return { left: placement.endsWith("end") ? "95%" : placement.endsWith("start") ? "5%" : "50%" };
67
+ const leftPx = clamp(refCenterX - x, arrowPadding, floatingRect.width - arrowPadding);
68
+ return { left: `${leftPx}px` };
38
69
  }
39
- return { top: placement.endsWith("start") ? "75%" : placement.endsWith("end") ? "25%" : "50%" };
70
+ const topPx = clamp(refCenterY - y, arrowPadding, floatingRect.height - arrowPadding);
71
+ return { top: `${topPx}px` };
40
72
  };
41
73
  //# sourceMappingURL=getArrowOffset.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/utils/getArrowOffset.ts", "../../../../../../scripts/build/transpile/react-shim.js"],
4
- "sourcesContent": ["/* eslint-disable no-nested-ternary */\nexport const getArrowOffset = (placement: string, isVertical: boolean) => {\n if (isVertical) {\n return { left: placement.endsWith('end') ? '95%' : placement.endsWith('start') ? '5%' : '50%' };\n }\n return { top: placement.endsWith('start') ? '75%' : placement.endsWith('end') ? '25%' : '50%' };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADChB,MAAM,iBAAiB,CAAC,WAAmB,eAAwB;AACxE,MAAI,YAAY;AACd,WAAO,EAAE,MAAM,UAAU,SAAS,KAAK,IAAI,QAAQ,UAAU,SAAS,OAAO,IAAI,OAAO,MAAM;AAAA,EAChG;AACA,SAAO,EAAE,KAAK,UAAU,SAAS,OAAO,IAAI,QAAQ,UAAU,SAAS,KAAK,IAAI,QAAQ,MAAM;AAChG;",
4
+ "sourcesContent": ["/* eslint-disable max-statements */\ntype ArrowOffset = { left?: string; top?: string };\n\nconst clamp = (v: number, min: number, max: number) => Math.min(max, Math.max(min, v));\n\nexport const getArrowOffsetDynamic = ({\n placement,\n referenceRect,\n floatingRect,\n x,\n y,\n withoutPortal,\n parentOffsets,\n floatingEl,\n arrowPadding = 12,\n}: {\n placement: string;\n referenceRect: DOMRect;\n floatingRect: DOMRect;\n x: number;\n y: number;\n withoutPortal: boolean;\n parentOffsets: { top: number; left: number };\n floatingEl: HTMLElement;\n arrowPadding?: number;\n}): ArrowOffset => {\n const base = placement.split('-')[0];\n const isVertical = base === 'top' || base === 'bottom';\n\n const refCenterViewportX = referenceRect.left + referenceRect.width / 2;\n const refCenterViewportY = referenceRect.top + referenceRect.height / 2;\n\n let refCenterX: number;\n let refCenterY: number;\n\n if (!withoutPortal) {\n refCenterX = refCenterViewportX + window.scrollX;\n refCenterY = refCenterViewportY + window.scrollY;\n } else {\n const op = floatingEl.offsetParent as HTMLElement | null;\n const opRect = op?.getBoundingClientRect();\n const opLeft = opRect?.left ?? 0;\n const opTop = opRect?.top ?? 0;\n const opScrollLeft = op?.scrollLeft ?? 0;\n const opScrollTop = op?.scrollTop ?? 0;\n\n refCenterX = refCenterViewportX - parentOffsets.left - opLeft + opScrollLeft;\n refCenterY = refCenterViewportY - parentOffsets.top - opTop + opScrollTop;\n }\n\n if (isVertical) {\n const leftPx = clamp(refCenterX - x, arrowPadding, floatingRect.width - arrowPadding);\n return { left: `${leftPx}px` };\n }\n\n const topPx = clamp(refCenterY - y, arrowPadding, floatingRect.height - arrowPadding);\n return { top: `${topPx}px` };\n};\n", "import * as React from 'react';\nexport { React };\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADGvB,MAAM,QAAQ,CAAC,GAAW,KAAa,QAAgB,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC;AAE9E,MAAM,wBAAwB,CAAC;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,MAUmB;AACjB,QAAM,OAAO,UAAU,MAAM,GAAG,EAAE,CAAC;AACnC,QAAM,aAAa,SAAS,SAAS,SAAS;AAE9C,QAAM,qBAAqB,cAAc,OAAO,cAAc,QAAQ;AACtE,QAAM,qBAAqB,cAAc,MAAM,cAAc,SAAS;AAEtE,MAAI;AACJ,MAAI;AAEJ,MAAI,CAAC,eAAe;AAClB,iBAAa,qBAAqB,OAAO;AACzC,iBAAa,qBAAqB,OAAO;AAAA,EAC3C,OAAO;AACL,UAAM,KAAK,WAAW;AACtB,UAAM,SAAS,IAAI,sBAAsB;AACzC,UAAM,SAAS,QAAQ,QAAQ;AAC/B,UAAM,QAAQ,QAAQ,OAAO;AAC7B,UAAM,eAAe,IAAI,cAAc;AACvC,UAAM,cAAc,IAAI,aAAa;AAErC,iBAAa,qBAAqB,cAAc,OAAO,SAAS;AAChE,iBAAa,qBAAqB,cAAc,MAAM,QAAQ;AAAA,EAChE;AAEA,MAAI,YAAY;AACd,UAAM,SAAS,MAAM,aAAa,GAAG,cAAc,aAAa,QAAQ,YAAY;AACpF,WAAO,EAAE,MAAM,GAAG,MAAM,KAAK;AAAA,EAC/B;AAEA,QAAM,QAAQ,MAAM,aAAa,GAAG,cAAc,aAAa,SAAS,YAAY;AACpF,SAAO,EAAE,KAAK,GAAG,KAAK,KAAK;AAC7B;",
6
6
  "names": []
7
7
  }
@@ -1,6 +1,6 @@
1
1
  import * as React from "react";
2
2
  import { getExpandedFallbackPlacements } from "./getExpandedFallbackPlacements.js";
3
- import { getArrowOffset } from "./getArrowOffset.js";
3
+ import { getArrowOffsetDynamic } from "./getArrowOffset.js";
4
4
  import { detectOverflow } from "./detectOverflow.js";
5
5
  import {
6
6
  applyShift,
@@ -23,20 +23,15 @@ const computePosition = (props) => {
23
23
  );
24
24
  const clippingParent = withoutPortal ? getClippingParent(reference) : null;
25
25
  const clippingRect = clippingParent ? clippingParent.getBoundingClientRect() : getViewportRect();
26
- let isVertical = false;
27
26
  let bestPlacement = placement;
28
27
  let bestOverflows = null;
29
28
  let bestScore = { total: Number.POSITIVE_INFINITY, maxSide: Number.POSITIVE_INFINITY };
30
- let bestIsVertical = false;
31
29
  for (let i = 0; i < placements.length; i += 1) {
32
30
  const currentPlacement = placements[i];
33
- const base = currentPlacement.split("-")[0];
34
- const currentIsVertical = base === "top" || base === "bottom";
35
31
  const overflows2 = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);
36
32
  if (fits(overflows2)) {
37
33
  bestPlacement = currentPlacement;
38
34
  bestOverflows = overflows2;
39
- bestIsVertical = currentIsVertical;
40
35
  break;
41
36
  }
42
37
  const score = getOverflowScore(overflows2);
@@ -45,11 +40,9 @@ const computePosition = (props) => {
45
40
  bestPlacement = currentPlacement;
46
41
  bestOverflows = overflows2;
47
42
  bestScore = score;
48
- bestIsVertical = currentIsVertical;
49
43
  }
50
44
  }
51
45
  const finalPlacement = bestPlacement;
52
- isVertical = bestIsVertical;
53
46
  const overflows = bestOverflows ?? detectOverflow(referenceRect, floatingRect, finalPlacement, customOffset, clippingRect);
54
47
  let x = -overflows.left - parentOffsets.left;
55
48
  let y = -overflows.top - parentOffsets.top;
@@ -62,6 +55,17 @@ const computePosition = (props) => {
62
55
  y = y - op.top + op.scrollTop;
63
56
  }
64
57
  ({ x, y } = applyShift(x, y, overflows));
58
+ const coordsArrow = getArrowOffsetDynamic({
59
+ placement: finalPlacement,
60
+ referenceRect,
61
+ floatingRect,
62
+ x,
63
+ y,
64
+ withoutPortal,
65
+ parentOffsets,
66
+ floatingEl: floating,
67
+ arrowPadding: 12
68
+ });
65
69
  return {
66
70
  coordsStyle: {
67
71
  transform: `translate3d(${Math.round(x)}px, ${Math.round(y)}px, 0)`,
@@ -69,7 +73,7 @@ const computePosition = (props) => {
69
73
  left: 0
70
74
  },
71
75
  finalPlacement,
72
- coordsArrow: getArrowOffset(finalPlacement, isVertical)
76
+ coordsArrow
73
77
  };
74
78
  };
75
79
  export {
@@ -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 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;",
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 { getArrowOffsetDynamic } 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 // 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\n for (let i = 0; i < placements.length; i += 1) {\n const currentPlacement = placements[i];\n\n const overflows = detectOverflow(referenceRect, floatingRect, currentPlacement, customOffset, clippingRect);\n\n if (fits(overflows)) {\n bestPlacement = currentPlacement;\n bestOverflows = overflows;\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 }\n }\n\n const finalPlacement = bestPlacement;\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 const coordsArrow = getArrowOffsetDynamic({\n placement: finalPlacement,\n referenceRect,\n floatingRect,\n x,\n y,\n withoutPortal,\n parentOffsets,\n floatingEl: floating,\n arrowPadding: 12,\n });\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,\n };\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACSvB,SAAS,qCAAqC;AAC9C,SAAS,6BAA6B;AACtC,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;AAKzG,MAAI,gBAAgB;AACpB,MAAI,gBAAwC;AAC5C,MAAI,YAAY,EAAE,OAAO,OAAO,mBAAmB,SAAS,OAAO,kBAAkB;AAErF,WAAS,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK,GAAG;AAC7C,UAAM,mBAAmB,WAAW,CAAC;AAErC,UAAMA,aAAY,eAAe,eAAe,cAAc,kBAAkB,cAAc,YAAY;AAE1G,QAAI,KAAKA,UAAS,GAAG;AACnB,sBAAgB;AAChB,sBAAgBA;AAChB;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;AAAA,IACd;AAAA,EACF;AAEA,QAAM,iBAAiB;AAEvB,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,QAAM,cAAc,sBAAsB;AAAA,IACxC,WAAW;AAAA,IACX;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,YAAY;AAAA,IACZ,cAAc;AAAA,EAChB,CAAC;AAED,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,EACF;AACF;",
6
6
  "names": ["overflows"]
7
7
  }
@@ -1,11 +1,43 @@
1
1
  import * as React from "react";
2
- const getArrowOffset = (placement, isVertical) => {
2
+ const clamp = (v, min, max) => Math.min(max, Math.max(min, v));
3
+ const getArrowOffsetDynamic = ({
4
+ placement,
5
+ referenceRect,
6
+ floatingRect,
7
+ x,
8
+ y,
9
+ withoutPortal,
10
+ parentOffsets,
11
+ floatingEl,
12
+ arrowPadding = 12
13
+ }) => {
14
+ const base = placement.split("-")[0];
15
+ const isVertical = base === "top" || base === "bottom";
16
+ const refCenterViewportX = referenceRect.left + referenceRect.width / 2;
17
+ const refCenterViewportY = referenceRect.top + referenceRect.height / 2;
18
+ let refCenterX;
19
+ let refCenterY;
20
+ if (!withoutPortal) {
21
+ refCenterX = refCenterViewportX + window.scrollX;
22
+ refCenterY = refCenterViewportY + window.scrollY;
23
+ } else {
24
+ const op = floatingEl.offsetParent;
25
+ const opRect = op?.getBoundingClientRect();
26
+ const opLeft = opRect?.left ?? 0;
27
+ const opTop = opRect?.top ?? 0;
28
+ const opScrollLeft = op?.scrollLeft ?? 0;
29
+ const opScrollTop = op?.scrollTop ?? 0;
30
+ refCenterX = refCenterViewportX - parentOffsets.left - opLeft + opScrollLeft;
31
+ refCenterY = refCenterViewportY - parentOffsets.top - opTop + opScrollTop;
32
+ }
3
33
  if (isVertical) {
4
- return { left: placement.endsWith("end") ? "95%" : placement.endsWith("start") ? "5%" : "50%" };
34
+ const leftPx = clamp(refCenterX - x, arrowPadding, floatingRect.width - arrowPadding);
35
+ return { left: `${leftPx}px` };
5
36
  }
6
- return { top: placement.endsWith("start") ? "75%" : placement.endsWith("end") ? "25%" : "50%" };
37
+ const topPx = clamp(refCenterY - y, arrowPadding, floatingRect.height - arrowPadding);
38
+ return { top: `${topPx}px` };
7
39
  };
8
40
  export {
9
- getArrowOffset
41
+ getArrowOffsetDynamic
10
42
  };
11
43
  //# sourceMappingURL=getArrowOffset.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../scripts/build/transpile/react-shim.js", "../../../src/utils/getArrowOffset.ts"],
4
- "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable no-nested-ternary */\nexport const getArrowOffset = (placement: string, isVertical: boolean) => {\n if (isVertical) {\n return { left: placement.endsWith('end') ? '95%' : placement.endsWith('start') ? '5%' : '50%' };\n }\n return { top: placement.endsWith('start') ? '75%' : placement.endsWith('end') ? '25%' : '50%' };\n};\n"],
5
- "mappings": "AAAA,YAAY,WAAW;ACChB,MAAM,iBAAiB,CAAC,WAAmB,eAAwB;AACxE,MAAI,YAAY;AACd,WAAO,EAAE,MAAM,UAAU,SAAS,KAAK,IAAI,QAAQ,UAAU,SAAS,OAAO,IAAI,OAAO,MAAM;AAAA,EAChG;AACA,SAAO,EAAE,KAAK,UAAU,SAAS,OAAO,IAAI,QAAQ,UAAU,SAAS,KAAK,IAAI,QAAQ,MAAM;AAChG;",
4
+ "sourcesContent": ["import * as React from 'react';\nexport { React };\n", "/* eslint-disable max-statements */\ntype ArrowOffset = { left?: string; top?: string };\n\nconst clamp = (v: number, min: number, max: number) => Math.min(max, Math.max(min, v));\n\nexport const getArrowOffsetDynamic = ({\n placement,\n referenceRect,\n floatingRect,\n x,\n y,\n withoutPortal,\n parentOffsets,\n floatingEl,\n arrowPadding = 12,\n}: {\n placement: string;\n referenceRect: DOMRect;\n floatingRect: DOMRect;\n x: number;\n y: number;\n withoutPortal: boolean;\n parentOffsets: { top: number; left: number };\n floatingEl: HTMLElement;\n arrowPadding?: number;\n}): ArrowOffset => {\n const base = placement.split('-')[0];\n const isVertical = base === 'top' || base === 'bottom';\n\n const refCenterViewportX = referenceRect.left + referenceRect.width / 2;\n const refCenterViewportY = referenceRect.top + referenceRect.height / 2;\n\n let refCenterX: number;\n let refCenterY: number;\n\n if (!withoutPortal) {\n refCenterX = refCenterViewportX + window.scrollX;\n refCenterY = refCenterViewportY + window.scrollY;\n } else {\n const op = floatingEl.offsetParent as HTMLElement | null;\n const opRect = op?.getBoundingClientRect();\n const opLeft = opRect?.left ?? 0;\n const opTop = opRect?.top ?? 0;\n const opScrollLeft = op?.scrollLeft ?? 0;\n const opScrollTop = op?.scrollTop ?? 0;\n\n refCenterX = refCenterViewportX - parentOffsets.left - opLeft + opScrollLeft;\n refCenterY = refCenterViewportY - parentOffsets.top - opTop + opScrollTop;\n }\n\n if (isVertical) {\n const leftPx = clamp(refCenterX - x, arrowPadding, floatingRect.width - arrowPadding);\n return { left: `${leftPx}px` };\n }\n\n const topPx = clamp(refCenterY - y, arrowPadding, floatingRect.height - arrowPadding);\n return { top: `${topPx}px` };\n};\n"],
5
+ "mappings": "AAAA,YAAY,WAAW;ACGvB,MAAM,QAAQ,CAAC,GAAW,KAAa,QAAgB,KAAK,IAAI,KAAK,KAAK,IAAI,KAAK,CAAC,CAAC;AAE9E,MAAM,wBAAwB,CAAC;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA,eAAe;AACjB,MAUmB;AACjB,QAAM,OAAO,UAAU,MAAM,GAAG,EAAE,CAAC;AACnC,QAAM,aAAa,SAAS,SAAS,SAAS;AAE9C,QAAM,qBAAqB,cAAc,OAAO,cAAc,QAAQ;AACtE,QAAM,qBAAqB,cAAc,MAAM,cAAc,SAAS;AAEtE,MAAI;AACJ,MAAI;AAEJ,MAAI,CAAC,eAAe;AAClB,iBAAa,qBAAqB,OAAO;AACzC,iBAAa,qBAAqB,OAAO;AAAA,EAC3C,OAAO;AACL,UAAM,KAAK,WAAW;AACtB,UAAM,SAAS,IAAI,sBAAsB;AACzC,UAAM,SAAS,QAAQ,QAAQ;AAC/B,UAAM,QAAQ,QAAQ,OAAO;AAC7B,UAAM,eAAe,IAAI,cAAc;AACvC,UAAM,cAAc,IAAI,aAAa;AAErC,iBAAa,qBAAqB,cAAc,OAAO,SAAS;AAChE,iBAAa,qBAAqB,cAAc,MAAM,QAAQ;AAAA,EAChE;AAEA,MAAI,YAAY;AACd,UAAM,SAAS,MAAM,aAAa,GAAG,cAAc,aAAa,QAAQ,YAAY;AACpF,WAAO,EAAE,MAAM,GAAG,MAAM,KAAK;AAAA,EAC/B;AAEA,QAAM,QAAQ,MAAM,aAAa,GAAG,cAAc,aAAa,SAAS,YAAY;AACpF,SAAO,EAAE,KAAK,GAAG,KAAK,KAAK;AAC7B;",
6
6
  "names": []
7
7
  }
@@ -15,11 +15,8 @@ export declare const computePosition: (props: ComputePositionProps) => {
15
15
  };
16
16
  finalPlacement: DSHookFloatingContextT.PopperPlacementsT;
17
17
  coordsArrow: {
18
- left: string;
19
- top?: undefined;
20
- } | {
21
- top: string;
22
- left?: undefined;
18
+ left?: string;
19
+ top?: string;
23
20
  };
24
21
  };
25
22
  export {};
@@ -1,7 +1,19 @@
1
- export declare const getArrowOffset: (placement: string, isVertical: boolean) => {
2
- left: string;
3
- top?: undefined;
4
- } | {
5
- top: string;
6
- left?: undefined;
1
+ type ArrowOffset = {
2
+ left?: string;
3
+ top?: string;
7
4
  };
5
+ export declare const getArrowOffsetDynamic: ({ placement, referenceRect, floatingRect, x, y, withoutPortal, parentOffsets, floatingEl, arrowPadding, }: {
6
+ placement: string;
7
+ referenceRect: DOMRect;
8
+ floatingRect: DOMRect;
9
+ x: number;
10
+ y: number;
11
+ withoutPortal: boolean;
12
+ parentOffsets: {
13
+ top: number;
14
+ left: number;
15
+ };
16
+ floatingEl: HTMLElement;
17
+ arrowPadding?: number;
18
+ }) => ArrowOffset;
19
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@elliemae/ds-floating-context",
3
- "version": "3.57.7",
3
+ "version": "3.57.9",
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.7",
40
- "@elliemae/ds-props-helpers": "3.57.7",
41
- "@elliemae/ds-system": "3.57.7",
42
- "@elliemae/ds-typescript-helpers": "3.57.7"
39
+ "@elliemae/ds-hooks-headless-tooltip": "3.57.9",
40
+ "@elliemae/ds-typescript-helpers": "3.57.9",
41
+ "@elliemae/ds-props-helpers": "3.57.9",
42
+ "@elliemae/ds-system": "3.57.9"
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.7"
47
+ "@elliemae/ds-monorepo-devops": "3.57.9"
48
48
  },
49
49
  "peerDependencies": {
50
50
  "lodash-es": "^4.17.21",