UNPKG

4.26 kBJavaScriptView Raw
1import { useCallback, useMemo, useRef } from 'react';
2import hasClass from 'dom-helpers/hasClass';
3import { useBootstrapPrefix } from './ThemeProvider';
4
5function getMargins(element) {
6 var styles = window.getComputedStyle(element);
7 var top = parseFloat(styles.marginTop) || 0;
8 var right = parseFloat(styles.marginRight) || 0;
9 var bottom = parseFloat(styles.marginBottom) || 0;
10 var left = parseFloat(styles.marginLeft) || 0;
11 return {
12 top: top,
13 right: right,
14 bottom: bottom,
15 left: left
16 };
17}
18
19export default function usePopperMarginModifiers() {
20 var overlayRef = useRef(null);
21 var margins = useRef(null);
22 var arrowMargins = useRef(null);
23 var popoverClass = useBootstrapPrefix(undefined, 'popover');
24 var dropdownMenuClass = useBootstrapPrefix(undefined, 'dropdown-menu');
25 var callback = useCallback(function (overlay) {
26 if (!overlay || !(hasClass(overlay, popoverClass) || hasClass(overlay, dropdownMenuClass))) return;
27 margins.current = getMargins(overlay);
28 overlay.style.margin = '0';
29 overlayRef.current = overlay;
30 }, [popoverClass, dropdownMenuClass]);
31 var offset = useMemo(function () {
32 return {
33 name: 'offset',
34 options: {
35 offset: function offset(_ref) {
36 var placement = _ref.placement;
37 if (!margins.current) return [0, 0];
38 var _margins$current = margins.current,
39 top = _margins$current.top,
40 left = _margins$current.left,
41 bottom = _margins$current.bottom,
42 right = _margins$current.right;
43
44 switch (placement.split('-')[0]) {
45 case 'top':
46 return [0, bottom];
47
48 case 'left':
49 return [0, right];
50
51 case 'bottom':
52 return [0, top];
53
54 case 'right':
55 return [0, left];
56
57 default:
58 return [0, 0];
59 }
60 }
61 }
62 };
63 }, [margins]);
64 var arrow = useMemo(function () {
65 return {
66 name: 'arrow',
67 options: {
68 padding: function padding() {
69 // The options here are used for Popper 2.8.4 and up.
70 // For earlier version, padding is handled in popoverArrowMargins below.
71 if (!arrowMargins.current) {
72 return 0;
73 }
74
75 var _arrowMargins$current = arrowMargins.current,
76 top = _arrowMargins$current.top,
77 right = _arrowMargins$current.right;
78 var padding = top || right;
79 return {
80 top: padding,
81 left: padding,
82 right: padding,
83 bottom: padding
84 };
85 }
86 }
87 };
88 }, [arrowMargins]); // Converts popover arrow margin to arrow modifier padding
89
90 var popoverArrowMargins = useMemo(function () {
91 return {
92 name: 'popoverArrowMargins',
93 enabled: true,
94 phase: 'main',
95 fn: function fn() {
96 return undefined;
97 },
98 requiresIfExists: ['arrow'],
99 effect: function effect(_ref2) {
100 var state = _ref2.state;
101
102 if (!overlayRef.current || !state.elements.arrow || !hasClass(overlayRef.current, popoverClass)) {
103 return undefined;
104 }
105
106 if (state.modifiersData['arrow#persistent']) {
107 // @popperjs/core <= 2.8.3 uses arrow#persistent to pass padding to arrow modifier.
108 var _getMargins = getMargins(state.elements.arrow),
109 top = _getMargins.top,
110 right = _getMargins.right;
111
112 var padding = top || right;
113 state.modifiersData['arrow#persistent'].padding = {
114 top: padding,
115 left: padding,
116 right: padding,
117 bottom: padding
118 };
119 } else {
120 // @popperjs/core >= 2.8.4 gets the padding from the arrow modifier options,
121 // so we'll get the margins here, and let the arrow modifier above pass
122 // it to popper.
123 arrowMargins.current = getMargins(state.elements.arrow);
124 }
125
126 state.elements.arrow.style.margin = '0';
127 return function () {
128 if (state.elements.arrow) state.elements.arrow.style.margin = '';
129 };
130 }
131 };
132 }, [popoverClass]);
133 return [callback, [offset, arrow, popoverArrowMargins]];
134}
\No newline at end of file