@reshaped/utilities 3.9.1-canary.2 → 3.9.1-canary.3
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/flyout/Flyout.js +9 -7
- package/dist/flyout/constants.d.ts +1 -1
- package/dist/flyout/constants.js +1 -1
- package/dist/flyout/utilities/applyPosition.js +45 -25
- package/dist/flyout/utilities/calculateLayoutAdjustment.d.ts +19 -0
- package/dist/flyout/utilities/calculateLayoutAdjustment.js +73 -0
- package/dist/flyout/utilities/calculatePosition.d.ts +7 -20
- package/dist/flyout/utilities/calculatePosition.js +11 -87
- package/dist/flyout/utilities/isFullyVisible.d.ts +2 -4
- package/dist/flyout/utilities/isFullyVisible.js +11 -14
- package/dist/flyout/utilities/tests/calculateLayoutAdjustment.test.d.ts +1 -0
- package/dist/flyout/utilities/tests/calculateLayoutAdjustment.test.js +384 -0
- package/dist/flyout/utilities/tests/calculatePosition.test.js +243 -292
- package/dist/flyout/utilities/tests/findClosestFixedContainer.test.js +1 -1
- package/dist/flyout/utilities/tests/isFullyVisible.test.js +27 -51
- package/package.json +1 -1
package/dist/flyout/Flyout.js
CHANGED
|
@@ -9,10 +9,9 @@ class Flyout {
|
|
|
9
9
|
constructor(options) {
|
|
10
10
|
this.#options = options;
|
|
11
11
|
}
|
|
12
|
-
#update = (
|
|
12
|
+
#update = () => {
|
|
13
13
|
const result = applyPosition({
|
|
14
14
|
...this.#options,
|
|
15
|
-
fallbackPositions: options?.fallback === false ? [] : this.#options.fallbackPositions,
|
|
16
15
|
lastUsedPosition: this.#lastUsedPosition,
|
|
17
16
|
});
|
|
18
17
|
this.#lastUsedPosition = result.position;
|
|
@@ -23,11 +22,14 @@ class Flyout {
|
|
|
23
22
|
if (!trigger)
|
|
24
23
|
return;
|
|
25
24
|
const container = findClosestScrollableContainer({ el: trigger });
|
|
26
|
-
|
|
27
|
-
return;
|
|
25
|
+
const root = container || window;
|
|
28
26
|
const handleScroll = rafThrottle(() => {
|
|
29
27
|
if (!this.#active)
|
|
30
28
|
return;
|
|
29
|
+
if (!container) {
|
|
30
|
+
this.#update();
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
31
33
|
const triggerBounds = trigger.getBoundingClientRect();
|
|
32
34
|
const containerBounds = container.getBoundingClientRect();
|
|
33
35
|
if (triggerBounds.top < containerBounds.top ||
|
|
@@ -37,11 +39,11 @@ class Flyout {
|
|
|
37
39
|
onClose();
|
|
38
40
|
}
|
|
39
41
|
else {
|
|
40
|
-
this.#update(
|
|
42
|
+
this.#update();
|
|
41
43
|
}
|
|
42
44
|
});
|
|
43
|
-
|
|
44
|
-
this.#handlerCleanupMap.scroll = () =>
|
|
45
|
+
root.addEventListener("scroll", handleScroll, { passive: true });
|
|
46
|
+
this.#handlerCleanupMap.scroll = () => root.removeEventListener("scroll", handleScroll);
|
|
45
47
|
};
|
|
46
48
|
#addRTLHandler = () => {
|
|
47
49
|
const observer = new MutationObserver(() => {
|
package/dist/flyout/constants.js
CHANGED
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import getShadowRoot from "../../dom/getShadowRoot.js";
|
|
2
2
|
import isRTL from "../../i18n/isRTL.js";
|
|
3
|
-
import {
|
|
3
|
+
import { VIEWPORT_OFFSET, RESET_STYLES } from "../constants.js";
|
|
4
|
+
import calculateLayoutAdjustment from "./calculateLayoutAdjustment.js";
|
|
4
5
|
import calculatePosition from "./calculatePosition.js";
|
|
5
|
-
import findClosestFixedContainer from "./findClosestFixedContainer.js";
|
|
6
6
|
import getPositionFallbacks from "./getPositionFallbacks.js";
|
|
7
7
|
import getRectFromCoordinates from "./getRectFromCoordinates.js";
|
|
8
8
|
import isFullyVisible from "./isFullyVisible.js";
|
|
9
9
|
const applyPosition = (args) => {
|
|
10
|
-
const { trigger, content, triggerCoordinates, container
|
|
10
|
+
const { trigger, content, triggerCoordinates, container, contentShift = 0, contentGap = 0, position, fallbackPositions, fallbackAdjustLayout, fallbackMinHeight, width, lastUsedPosition, } = args;
|
|
11
11
|
const rtl = isRTL();
|
|
12
12
|
const contentClone = content.cloneNode(true);
|
|
13
13
|
const triggerBounds = triggerCoordinates || trigger?.getBoundingClientRect();
|
|
14
|
+
const containerBounds = container?.getBoundingClientRect() ?? {
|
|
15
|
+
width: window.innerWidth,
|
|
16
|
+
height: window.innerHeight,
|
|
17
|
+
left: 0,
|
|
18
|
+
top: 0,
|
|
19
|
+
};
|
|
14
20
|
contentClone.style.cssText = "";
|
|
15
21
|
if (!triggerBounds)
|
|
16
22
|
throw new Error("Trigger bounds are required");
|
|
@@ -24,15 +30,9 @@ const applyPosition = (args) => {
|
|
|
24
30
|
// Insert inside shadow root if possible to make sure styles are applied correctly
|
|
25
31
|
const root = (trigger && getShadowRoot(trigger)) ?? document.body;
|
|
26
32
|
root.appendChild(contentClone);
|
|
27
|
-
const closestFixedContainer = !passedContainer && trigger ? findClosestFixedContainer({ el: trigger }) : undefined;
|
|
28
|
-
const container = passedContainer ||
|
|
29
|
-
// Render inside fixed position container automatically to keep their position synced on scroll
|
|
30
|
-
closestFixedContainer ||
|
|
31
|
-
document.body;
|
|
32
|
-
const renderContainerBounds = container.getBoundingClientRect();
|
|
33
33
|
const testPosition = (position, options) => {
|
|
34
34
|
if (options?.width === "100%") {
|
|
35
|
-
contentClone.style.width = `calc(100% - ${
|
|
35
|
+
contentClone.style.width = `calc(100% - ${VIEWPORT_OFFSET * 2}px)`;
|
|
36
36
|
}
|
|
37
37
|
else if (options?.width === "trigger") {
|
|
38
38
|
contentClone.style.width = `${resolvedTriggerBounds.width}px`;
|
|
@@ -43,32 +43,37 @@ const applyPosition = (args) => {
|
|
|
43
43
|
else {
|
|
44
44
|
contentClone.style.width = "";
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
const flyoutBounds = contentClone.getBoundingClientRect();
|
|
47
|
+
const result = calculatePosition({
|
|
47
48
|
triggerBounds: resolvedTriggerBounds,
|
|
48
|
-
flyoutBounds
|
|
49
|
-
containerBounds: renderContainerBounds,
|
|
49
|
+
flyoutBounds,
|
|
50
50
|
position,
|
|
51
51
|
contentGap,
|
|
52
52
|
contentShift,
|
|
53
53
|
rtl,
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
});
|
|
55
|
+
const adjustedResult = calculateLayoutAdjustment({
|
|
56
|
+
...result,
|
|
57
57
|
fallbackAdjustLayout,
|
|
58
58
|
fallbackMinHeight,
|
|
59
|
+
width,
|
|
60
|
+
flyoutBounds,
|
|
61
|
+
containerBounds,
|
|
62
|
+
triggerBounds: resolvedTriggerBounds,
|
|
59
63
|
});
|
|
64
|
+
return adjustedResult;
|
|
60
65
|
};
|
|
61
66
|
const testVisibility = (calculated) => {
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
+
const flyoutBounds = {
|
|
68
|
+
// Flyout is rendered in body with position absolute, so bounds need to include the page scroll
|
|
69
|
+
left: calculated.styles.left,
|
|
70
|
+
top: calculated.styles.top,
|
|
71
|
+
height: calculated.styles.height ?? Math.ceil(contentClone.clientHeight),
|
|
72
|
+
width: calculated.styles.width ?? Math.ceil(contentClone.clientWidth),
|
|
67
73
|
};
|
|
68
74
|
return isFullyVisible({
|
|
69
|
-
flyoutBounds
|
|
70
|
-
|
|
71
|
-
renderContainerBounds,
|
|
75
|
+
flyoutBounds,
|
|
76
|
+
containerBounds,
|
|
72
77
|
});
|
|
73
78
|
};
|
|
74
79
|
let calculated = null;
|
|
@@ -95,7 +100,22 @@ const applyPosition = (args) => {
|
|
|
95
100
|
if (!calculated)
|
|
96
101
|
calculated = testPosition(lastUsedPosition ?? position);
|
|
97
102
|
root.removeChild(contentClone);
|
|
98
|
-
|
|
103
|
+
const { styles } = calculated;
|
|
104
|
+
const translateX = (styles.right !== null ? -styles.right : styles.left) + window.scrollX;
|
|
105
|
+
const translateY = (styles.bottom !== null ? -styles.bottom : styles.top) + window.scrollY;
|
|
106
|
+
const resolvedStyles = {
|
|
107
|
+
left: styles.right === null ? "0px" : undefined,
|
|
108
|
+
right: styles.right === null ? undefined : "0px",
|
|
109
|
+
top: styles.bottom === null ? "0px" : undefined,
|
|
110
|
+
bottom: styles.bottom === null ? undefined : "0px",
|
|
111
|
+
height: styles.height !== null ? `${styles.height}px` : undefined,
|
|
112
|
+
width: styles.width !== null ? `${styles.width}px` : (width ?? undefined),
|
|
113
|
+
transform: `translate(${translateX}px, ${translateY}px)`,
|
|
114
|
+
};
|
|
115
|
+
content.style.cssText = "";
|
|
116
|
+
Object.entries(resolvedStyles).forEach(([key, value]) => {
|
|
117
|
+
if (!value)
|
|
118
|
+
return;
|
|
99
119
|
content.style.setProperty(key, value);
|
|
100
120
|
});
|
|
101
121
|
return { position: calculated.position };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import type { CalculatePositionResult } from "./calculatePosition";
|
|
2
|
+
import type { Options } from "../types";
|
|
3
|
+
type CalculateLayoutAdjustmentArgs = CalculatePositionResult & Pick<Options, "fallbackAdjustLayout" | "fallbackMinHeight" | "width"> & {
|
|
4
|
+
flyoutBounds: DOMRect;
|
|
5
|
+
triggerBounds: DOMRect;
|
|
6
|
+
containerBounds: Pick<DOMRect, "left" | "top" | "width" | "height">;
|
|
7
|
+
};
|
|
8
|
+
declare const calculateLayoutAdjustment: (args: CalculateLayoutAdjustmentArgs) => {
|
|
9
|
+
position: import("../types").Position;
|
|
10
|
+
styles: {
|
|
11
|
+
left: number;
|
|
12
|
+
right: number | null;
|
|
13
|
+
top: number;
|
|
14
|
+
bottom: number | null;
|
|
15
|
+
height: number | null;
|
|
16
|
+
width: number | null;
|
|
17
|
+
};
|
|
18
|
+
};
|
|
19
|
+
export default calculateLayoutAdjustment;
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { VIEWPORT_OFFSET } from "../constants.js";
|
|
2
|
+
const calculateLayoutAdjustment = (args) => {
|
|
3
|
+
const { position, styles, fallbackAdjustLayout, fallbackMinHeight, width: passedWidth, flyoutBounds, containerBounds, triggerBounds, } = args;
|
|
4
|
+
const { width: flyoutWidth, height: flyoutHeight } = flyoutBounds;
|
|
5
|
+
const { width: containerWidth, height: containerHeight, top: containerTop, left: containerLeft, } = containerBounds;
|
|
6
|
+
const isHorizontalPosition = !!position.match(/^(start|end)/);
|
|
7
|
+
let top = styles.top;
|
|
8
|
+
let left = styles.left;
|
|
9
|
+
let bottom = styles.bottom;
|
|
10
|
+
let right = styles.right;
|
|
11
|
+
let height = null;
|
|
12
|
+
let width = null;
|
|
13
|
+
if (fallbackAdjustLayout) {
|
|
14
|
+
const getOverflow = () => {
|
|
15
|
+
return {
|
|
16
|
+
top: containerTop + VIEWPORT_OFFSET - top,
|
|
17
|
+
bottom: top + flyoutHeight + VIEWPORT_OFFSET - containerTop - containerHeight,
|
|
18
|
+
left: containerLeft + VIEWPORT_OFFSET - left,
|
|
19
|
+
right: left + flyoutWidth + VIEWPORT_OFFSET - containerLeft - containerWidth,
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
const overflow = getOverflow();
|
|
23
|
+
if (isHorizontalPosition) {
|
|
24
|
+
if (overflow.top > 0) {
|
|
25
|
+
top = containerTop + VIEWPORT_OFFSET;
|
|
26
|
+
if (bottom !== null)
|
|
27
|
+
bottom = bottom - overflow.top;
|
|
28
|
+
}
|
|
29
|
+
else if (overflow.bottom > 0) {
|
|
30
|
+
top = top - overflow.bottom;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
if (overflow.left > 0) {
|
|
35
|
+
left = VIEWPORT_OFFSET + containerLeft;
|
|
36
|
+
if (right !== null)
|
|
37
|
+
right = right - overflow.left;
|
|
38
|
+
}
|
|
39
|
+
else if (overflow.right > 0) {
|
|
40
|
+
left = left - overflow.right;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const updatedOverflow = getOverflow();
|
|
44
|
+
if (updatedOverflow.top > 0) {
|
|
45
|
+
height = Math.max(parseInt(fallbackMinHeight ?? "0"), flyoutHeight - updatedOverflow.top);
|
|
46
|
+
top = top + (flyoutHeight - height);
|
|
47
|
+
}
|
|
48
|
+
else if (updatedOverflow.bottom > 0) {
|
|
49
|
+
height = Math.max(parseInt(fallbackMinHeight ?? "0"), flyoutHeight - updatedOverflow.bottom);
|
|
50
|
+
if (bottom !== null)
|
|
51
|
+
bottom = bottom + (flyoutHeight - height);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (passedWidth === "100%") {
|
|
55
|
+
left = VIEWPORT_OFFSET;
|
|
56
|
+
width = window.innerWidth - VIEWPORT_OFFSET * 2;
|
|
57
|
+
}
|
|
58
|
+
else if (passedWidth === "trigger") {
|
|
59
|
+
width = triggerBounds.width;
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
position,
|
|
63
|
+
styles: {
|
|
64
|
+
left,
|
|
65
|
+
right,
|
|
66
|
+
top,
|
|
67
|
+
bottom,
|
|
68
|
+
height,
|
|
69
|
+
width,
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
};
|
|
73
|
+
export default calculateLayoutAdjustment;
|
|
@@ -1,33 +1,20 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
type
|
|
1
|
+
import type { Position } from "../types";
|
|
2
|
+
type CalculatePositionArgs = {
|
|
3
3
|
triggerBounds: DOMRect;
|
|
4
4
|
flyoutBounds: DOMRect;
|
|
5
|
-
containerBounds: DOMRect;
|
|
6
|
-
passedContainer?: HTMLElement | null;
|
|
7
5
|
position: Position;
|
|
8
6
|
rtl: boolean;
|
|
9
|
-
width?: Width;
|
|
10
7
|
contentGap: number;
|
|
11
8
|
contentShift: number;
|
|
12
|
-
fallbackAdjustLayout?: boolean;
|
|
13
|
-
fallbackMinHeight?: string;
|
|
14
9
|
};
|
|
15
|
-
|
|
10
|
+
export type CalculatePositionResult = {
|
|
16
11
|
position: Position;
|
|
17
12
|
styles: {
|
|
18
|
-
left: string | null;
|
|
19
|
-
right: string | null;
|
|
20
|
-
top: string | null;
|
|
21
|
-
bottom: string | null;
|
|
22
|
-
transform: string;
|
|
23
|
-
height: string | null;
|
|
24
|
-
width: string | null;
|
|
25
|
-
};
|
|
26
|
-
boundaries: {
|
|
27
|
-
left: number;
|
|
28
13
|
top: number;
|
|
29
|
-
|
|
30
|
-
|
|
14
|
+
left: number;
|
|
15
|
+
bottom: number | null;
|
|
16
|
+
right: number | null;
|
|
31
17
|
};
|
|
32
18
|
};
|
|
19
|
+
declare const calculatePosition: (args: CalculatePositionArgs) => CalculatePositionResult;
|
|
33
20
|
export default calculatePosition;
|
|
@@ -1,36 +1,19 @@
|
|
|
1
|
-
import { CONTAINER_OFFSET } from "../constants.js";
|
|
2
1
|
import centerBySize from "./centerBySize.js";
|
|
3
2
|
import getRTLPosition from "./getRTLPosition.js";
|
|
4
3
|
const calculatePosition = (args) => {
|
|
5
|
-
const { triggerBounds, flyoutBounds,
|
|
4
|
+
const { triggerBounds, flyoutBounds, position: passedPosition, rtl, contentGap = 0, contentShift = 0, } = args;
|
|
6
5
|
const position = rtl ? getRTLPosition(passedPosition) : passedPosition;
|
|
7
|
-
const isHorizontalPosition = !!position.match(/^(start|end)/);
|
|
8
6
|
let left = 0;
|
|
9
7
|
let top = 0;
|
|
10
8
|
let bottom = null;
|
|
11
9
|
let right = null;
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
const containerX = passedContainer?.scrollLeft;
|
|
20
|
-
const containerY = passedContainer?.scrollTop;
|
|
21
|
-
const scrollX = containerX ?? window.scrollX;
|
|
22
|
-
const scrollY = containerY ?? window.scrollY;
|
|
23
|
-
const renderContainerHeight = passedContainer?.clientHeight ?? window.innerHeight;
|
|
24
|
-
const renderContainerWidth = passedContainer?.clientWidth ?? window.innerWidth;
|
|
25
|
-
// When rendering in the body, bottom bounds will be larrger than the viewport so we calculate it manually
|
|
26
|
-
const containerBoundsBottom = passedContainer
|
|
27
|
-
? containerBounds.bottom
|
|
28
|
-
: window.innerHeight - scrollY;
|
|
29
|
-
// When inside a container, adjut position based on the container scroll since flyout is rendered outside the scroll area
|
|
30
|
-
const relativeLeft = triggerBounds.left - containerBounds.left + (containerX || 0);
|
|
31
|
-
const relativeRight = containerBounds.right - triggerBounds.right - (containerX || 0);
|
|
32
|
-
const relativeTop = triggerBounds.top - containerBounds.top - (containerY || 0);
|
|
33
|
-
const relativeBottom = containerBoundsBottom - triggerBounds.bottom - (containerY || 0);
|
|
10
|
+
const { width: flyoutWidth, height: flyoutHeight } = flyoutBounds;
|
|
11
|
+
const { width: triggerWidth, height: triggerHeight, left: triggerLeft, top: triggerTop, right: triggerRight, bottom: triggerBottom, } = triggerBounds;
|
|
12
|
+
// Convert rect values to css position values
|
|
13
|
+
const relativeLeft = triggerLeft;
|
|
14
|
+
const relativeRight = window.innerWidth - triggerRight;
|
|
15
|
+
const relativeTop = triggerTop;
|
|
16
|
+
const relativeBottom = window.innerHeight - triggerBottom;
|
|
34
17
|
switch (position) {
|
|
35
18
|
case "start":
|
|
36
19
|
case "start-top":
|
|
@@ -87,72 +70,13 @@ const calculatePosition = (args) => {
|
|
|
87
70
|
default:
|
|
88
71
|
break;
|
|
89
72
|
}
|
|
90
|
-
if (fallbackAdjustLayout) {
|
|
91
|
-
const getOverflow = () => {
|
|
92
|
-
return {
|
|
93
|
-
top: -top + scrollY + CONTAINER_OFFSET,
|
|
94
|
-
bottom: top + flyoutHeight + CONTAINER_OFFSET - scrollY - renderContainerHeight,
|
|
95
|
-
left: -left + scrollX + CONTAINER_OFFSET,
|
|
96
|
-
right: left + flyoutWidth + CONTAINER_OFFSET - scrollX - renderContainerWidth,
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
const overflow = getOverflow();
|
|
100
|
-
if (isHorizontalPosition) {
|
|
101
|
-
if (overflow.top > 0) {
|
|
102
|
-
top = CONTAINER_OFFSET + scrollY;
|
|
103
|
-
if (bottom !== null)
|
|
104
|
-
bottom = bottom - overflow.top;
|
|
105
|
-
}
|
|
106
|
-
else if (overflow.bottom > 0) {
|
|
107
|
-
top = top - overflow.bottom;
|
|
108
|
-
}
|
|
109
|
-
}
|
|
110
|
-
else {
|
|
111
|
-
if (overflow.left > 0) {
|
|
112
|
-
left = CONTAINER_OFFSET + scrollX;
|
|
113
|
-
if (right !== null)
|
|
114
|
-
right = right - overflow.left;
|
|
115
|
-
}
|
|
116
|
-
else if (overflow.right > 0) {
|
|
117
|
-
left = left - overflow.right;
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
const updatedOverflow = getOverflow();
|
|
121
|
-
if (updatedOverflow.top > 0) {
|
|
122
|
-
height = Math.max(parseInt(fallbackMinHeight ?? "0"), flyoutHeight - updatedOverflow.top);
|
|
123
|
-
top = top + (flyoutHeight - height);
|
|
124
|
-
}
|
|
125
|
-
else if (updatedOverflow.bottom > 0) {
|
|
126
|
-
height = Math.max(parseInt(fallbackMinHeight ?? "0"), flyoutHeight - updatedOverflow.bottom);
|
|
127
|
-
if (bottom !== null)
|
|
128
|
-
bottom = bottom + (flyoutHeight - height);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (passedWidth === "100%") {
|
|
132
|
-
left = CONTAINER_OFFSET;
|
|
133
|
-
width = window.innerWidth - CONTAINER_OFFSET * 2;
|
|
134
|
-
}
|
|
135
|
-
else if (passedWidth === "trigger") {
|
|
136
|
-
width = triggerBounds.width;
|
|
137
|
-
}
|
|
138
|
-
const translateX = right !== null ? -right : left;
|
|
139
|
-
const translateY = bottom !== null ? -bottom : top;
|
|
140
73
|
return {
|
|
141
74
|
position,
|
|
142
75
|
styles: {
|
|
143
|
-
left: right === null ? "0px" : null,
|
|
144
|
-
right: right === null ? null : "0px",
|
|
145
|
-
top: bottom === null ? "0px" : null,
|
|
146
|
-
bottom: bottom === null ? null : "0px",
|
|
147
|
-
transform: `translate(${translateX}px, ${translateY}px)`,
|
|
148
|
-
height: height !== null ? `${height}px` : null,
|
|
149
|
-
width: width !== null ? `${width}px` : (passedWidth ?? null),
|
|
150
|
-
},
|
|
151
|
-
boundaries: {
|
|
152
|
-
left,
|
|
153
76
|
top,
|
|
154
|
-
|
|
155
|
-
|
|
77
|
+
left,
|
|
78
|
+
bottom,
|
|
79
|
+
right,
|
|
156
80
|
},
|
|
157
81
|
};
|
|
158
82
|
};
|
|
@@ -2,12 +2,10 @@ type Bounds = Pick<DOMRect, "left" | "top" | "width" | "height">;
|
|
|
2
2
|
/**
|
|
3
3
|
* Check if element visually fits within its render container
|
|
4
4
|
* @param flyoutBounds - Bounds of the flyout content
|
|
5
|
-
* @param
|
|
6
|
-
* @param renderContainerBounds - Bounds of the container where flyout content is rendered
|
|
5
|
+
* @param containerBounds - Bounds of the container where the flyout content should visually fit
|
|
7
6
|
*/
|
|
8
7
|
declare const isFullyVisible: (args: {
|
|
9
8
|
flyoutBounds: Bounds;
|
|
10
|
-
|
|
11
|
-
renderContainerBounds: Bounds;
|
|
9
|
+
containerBounds: Bounds;
|
|
12
10
|
}) => boolean;
|
|
13
11
|
export default isFullyVisible;
|
|
@@ -1,26 +1,23 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { VIEWPORT_OFFSET } from "../constants.js";
|
|
2
2
|
/**
|
|
3
3
|
* Check if element visually fits within its render container
|
|
4
4
|
* @param flyoutBounds - Bounds of the flyout content
|
|
5
|
-
* @param
|
|
6
|
-
* @param renderContainerBounds - Bounds of the container where flyout content is rendered
|
|
5
|
+
* @param containerBounds - Bounds of the container where the flyout content should visually fit
|
|
7
6
|
*/
|
|
8
7
|
const isFullyVisible = (args) => {
|
|
9
|
-
const { flyoutBounds,
|
|
10
|
-
const flyoutLeft =
|
|
11
|
-
const flyoutTop =
|
|
12
|
-
const containerLeft =
|
|
13
|
-
const containerTop =
|
|
14
|
-
if (flyoutLeft < containerLeft +
|
|
8
|
+
const { flyoutBounds, containerBounds } = args;
|
|
9
|
+
const flyoutLeft = flyoutBounds.left;
|
|
10
|
+
const flyoutTop = flyoutBounds.top;
|
|
11
|
+
const containerLeft = containerBounds.left;
|
|
12
|
+
const containerTop = containerBounds.top;
|
|
13
|
+
if (flyoutLeft < containerLeft + VIEWPORT_OFFSET)
|
|
15
14
|
return false;
|
|
16
|
-
if (flyoutTop < containerTop +
|
|
15
|
+
if (flyoutTop < containerTop + VIEWPORT_OFFSET)
|
|
17
16
|
return false;
|
|
18
|
-
if (flyoutLeft + flyoutBounds.width >
|
|
19
|
-
containerLeft + visualContainerBounds.width - CONTAINER_OFFSET) {
|
|
17
|
+
if (flyoutLeft + flyoutBounds.width > containerLeft + containerBounds.width - VIEWPORT_OFFSET) {
|
|
20
18
|
return false;
|
|
21
19
|
}
|
|
22
|
-
if (flyoutTop + flyoutBounds.height >
|
|
23
|
-
containerTop + visualContainerBounds.height - CONTAINER_OFFSET) {
|
|
20
|
+
if (flyoutTop + flyoutBounds.height > containerTop + containerBounds.height - VIEWPORT_OFFSET) {
|
|
24
21
|
return false;
|
|
25
22
|
}
|
|
26
23
|
return true;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|