@elliemae/ds-floating-context 3.57.7 → 3.57.8
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.
- package/dist/cjs/utils/computePosition.js +12 -8
- package/dist/cjs/utils/computePosition.js.map +2 -2
- package/dist/cjs/utils/getArrowOffset.js +36 -4
- package/dist/cjs/utils/getArrowOffset.js.map +2 -2
- package/dist/esm/utils/computePosition.js +13 -9
- package/dist/esm/utils/computePosition.js.map +2 -2
- package/dist/esm/utils/getArrowOffset.js +36 -4
- package/dist/esm/utils/getArrowOffset.js.map +2 -2
- package/dist/types/utils/computePosition.d.ts +2 -5
- package/dist/types/utils/getArrowOffset.d.ts +18 -6
- package/package.json +6 -6
|
@@ -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
|
|
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 {
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;ADSvB,2CAA8C;AAC9C,
|
|
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
|
-
|
|
31
|
+
getArrowOffsetDynamic: () => getArrowOffsetDynamic
|
|
32
32
|
});
|
|
33
33
|
module.exports = __toCommonJS(getArrowOffset_exports);
|
|
34
34
|
var React = __toESM(require("react"));
|
|
35
|
-
const
|
|
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
|
-
|
|
67
|
+
const leftPx = clamp(refCenterX - x, arrowPadding, floatingRect.width - arrowPadding);
|
|
68
|
+
return { left: `${leftPx}px` };
|
|
38
69
|
}
|
|
39
|
-
|
|
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
|
|
5
|
-
"mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;ACAA,YAAuB;
|
|
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 {
|
|
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
|
|
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 {
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;ACSvB,SAAS,qCAAqC;AAC9C,SAAS,
|
|
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
|
|
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
|
-
|
|
34
|
+
const leftPx = clamp(refCenterX - x, arrowPadding, floatingRect.width - arrowPadding);
|
|
35
|
+
return { left: `${leftPx}px` };
|
|
5
36
|
}
|
|
6
|
-
|
|
37
|
+
const topPx = clamp(refCenterY - y, arrowPadding, floatingRect.height - arrowPadding);
|
|
38
|
+
return { top: `${topPx}px` };
|
|
7
39
|
};
|
|
8
40
|
export {
|
|
9
|
-
|
|
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
|
|
5
|
-
"mappings": "AAAA,YAAY,WAAW;
|
|
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
|
|
19
|
-
top?:
|
|
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
|
-
|
|
2
|
-
left
|
|
3
|
-
top?:
|
|
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.
|
|
3
|
+
"version": "3.57.8",
|
|
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.
|
|
40
|
-
"@elliemae/ds-
|
|
41
|
-
"@elliemae/ds-
|
|
42
|
-
"@elliemae/ds-typescript-helpers": "3.57.
|
|
39
|
+
"@elliemae/ds-hooks-headless-tooltip": "3.57.8",
|
|
40
|
+
"@elliemae/ds-system": "3.57.8",
|
|
41
|
+
"@elliemae/ds-props-helpers": "3.57.8",
|
|
42
|
+
"@elliemae/ds-typescript-helpers": "3.57.8"
|
|
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.
|
|
47
|
+
"@elliemae/ds-monorepo-devops": "3.57.8"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"lodash-es": "^4.17.21",
|