-
-
Notifications
You must be signed in to change notification settings - Fork 303
/
utils.ts
126 lines (114 loc) · 3.32 KB
/
utils.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
import {
getViewportBounds,
getViewportSize,
unitToNumber,
Maybe,
HorizontalPosition,
VerticalPosition,
} from "@react-md/utils";
import { RenderConditionalPortalProps } from "@react-md/portal";
import {
TooltipPosition,
DeterminePositionConfig,
TooltipSpacingConfig,
} from "./types.d";
export function getSpacing({
spacing,
denseSpacing,
dense,
}: TooltipSpacingConfig) {
return `${dense ? denseSpacing : spacing}`;
}
export function determineBestPosition(
container: Maybe<HTMLElement>,
config: DeterminePositionConfig
): TooltipPosition {
const { id, position, vwMargin, vhMargin } = config;
if (position !== "auto") {
return position;
} else if (!container) {
return "below";
}
const rect = container.getBoundingClientRect();
if (rect.top > getViewportBounds("height", vhMargin)) {
return "above";
}
let { left, right } = rect;
const tooltip = document.getElementById(id);
if (tooltip) {
const { offsetWidth } = tooltip;
const spacing = unitToNumber(getSpacing(config));
const vw = getViewportSize("width");
if (
left + offsetWidth + spacing > vw &&
right - offsetWidth - spacing < 0
) {
return "below";
}
const halvedWidth = (tooltip as HTMLSpanElement).offsetWidth / 2;
left -= halvedWidth;
right += halvedWidth;
}
if (left < getViewportBounds("width", vwMargin)) {
return "right";
} else if (right > getViewportBounds("width", vwMargin, false)) {
return "left";
}
return "below";
}
export function validateContainerPosition(
container: Maybe<HTMLElement>,
config: RenderConditionalPortalProps
) {
if (process.env.NODE_ENV === "production" || !container) {
return;
}
const { portal, portalInto, portalIntoId } = config;
if (portal || portalInto || portalIntoId) {
// don't need to check for position relative when portaling since
// it's fixed in the page anyways
return;
}
// when in dev mode, make sure that the container element has a relative position
// so that the tooltip will appear "fixed" to the container element. This will have]
// to be updated when I implement tooltip portal support
const { position } = window.getComputedStyle(container);
if (position !== "relative") {
console.error(
"A tooltip's container must have `position: relative` as a style for a tooltip to " +
`appear but its position is: \`${position}\`. An inline style has been applied, ` +
"but your container must be updated before going into production as this " +
"functionality will be removed"
);
console.error(new Error().stack);
container.style.position = "relative";
}
}
export function createPositionOptions(
position: TooltipPosition,
spacing: string
) {
let horizontalSpacing: string = "";
let verticalSpacing: string = "";
let horizontalPosition: HorizontalPosition = "center";
let verticalPosition: VerticalPosition = "center";
switch (position) {
case "left":
horizontalPosition = position;
horizontalSpacing = spacing;
break;
case "right":
horizontalPosition = position;
horizontalSpacing = spacing;
break;
default:
verticalPosition = position;
verticalSpacing = spacing;
}
return {
horizontalPosition,
horizontalSpacing,
verticalPosition,
verticalSpacing,
};
}