-
-
Notifications
You must be signed in to change notification settings - Fork 533
/
Copy pathcompute-positions.ts
93 lines (80 loc) · 2.68 KB
/
compute-positions.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
import { computePosition, offset, shift, arrow, flip } from '@floating-ui/dom'
import type { IComputePositions } from './compute-positions-types'
export const computeTooltipPosition = async ({
elementReference = null,
tooltipReference = null,
tooltipArrowReference = null,
place = 'top',
offset: offsetValue = 10,
strategy = 'absolute',
middlewares = [
offset(Number(offsetValue)),
flip({
fallbackAxisSideDirection: 'start',
}),
shift({ padding: 5 }),
],
border,
}: IComputePositions) => {
if (!elementReference) {
// elementReference can be null or undefined and we will not compute the position
// eslint-disable-next-line no-console
// console.error('The reference element for tooltip was not defined: ', elementReference)
return { tooltipStyles: {}, tooltipArrowStyles: {}, place }
}
if (tooltipReference === null) {
return { tooltipStyles: {}, tooltipArrowStyles: {}, place }
}
const middleware = middlewares
if (tooltipArrowReference) {
middleware.push(arrow({ element: tooltipArrowReference as HTMLElement, padding: 5 }))
return computePosition(elementReference as HTMLElement, tooltipReference as HTMLElement, {
placement: place,
strategy,
middleware,
}).then(({ x, y, placement, middlewareData }) => {
const styles = { left: `${x}px`, top: `${y}px`, border }
const { x: arrowX, y: arrowY } = middlewareData.arrow ?? { x: 0, y: 0 }
const staticSide =
{
top: 'bottom',
right: 'left',
bottom: 'top',
left: 'right',
}[placement.split('-')[0]] ?? 'bottom'
const borderSide = border && {
borderBottom: border,
borderRight: border,
}
let borderWidth = 0
if (border) {
const match = `${border}`.match(/(\d+)px/)
if (match?.[1]) {
borderWidth = Number(match[1])
} else {
/**
* this means `border` was set without `width`, or non-px value
*/
borderWidth = 1
}
}
const arrowStyle = {
left: arrowX != null ? `${arrowX}px` : '',
top: arrowY != null ? `${arrowY}px` : '',
right: '',
bottom: '',
...borderSide,
[staticSide]: `-${4 + borderWidth}px`,
}
return { tooltipStyles: styles, tooltipArrowStyles: arrowStyle, place: placement }
})
}
return computePosition(elementReference as HTMLElement, tooltipReference as HTMLElement, {
placement: 'bottom',
strategy,
middleware,
}).then(({ x, y, placement }) => {
const styles = { left: `${x}px`, top: `${y}px` }
return { tooltipStyles: styles, tooltipArrowStyles: {}, place: placement }
})
}