UNPKG

10.2 kBJavaScriptView Raw
1// Copyright (c) Jupyter Development Team.
2// Distributed under the terms of the Modified BSD License.
3/**
4 * The class name added to all hover boxes.
5 */
6const HOVERBOX_CLASS = 'jp-HoverBox';
7/**
8 * The z-index used to hide hovering node that is scrolled out of view.
9 */
10const OUTOFVIEW_Z_INDEX = '-1000';
11/**
12 * A namespace for `HoverBox` members.
13 */
14export var HoverBox;
15(function (HoverBox) {
16 /**
17 * Set the visible dimensions of a hovering box anchored to an editor cursor.
18 *
19 * @param options - The hover box geometry calculation options.
20 */
21 function setGeometry(options) {
22 const { anchor, host, node, privilege, outOfViewDisplay } = options;
23 const hostRect = host.getBoundingClientRect();
24 // Add hover box class if it does not exist.
25 if (!node.classList.contains(HOVERBOX_CLASS)) {
26 node.classList.add(HOVERBOX_CLASS);
27 }
28 // Start with the node displayed as if it was in view.
29 if (node.style.visibility) {
30 node.style.visibility = '';
31 }
32 if (node.style.zIndex === '') {
33 node.style.zIndex = '';
34 }
35 // Clear any previously set max-height.
36 node.style.maxHeight = '';
37 // Clear any programmatically set margin-top.
38 node.style.marginTop = '';
39 const style = options.style || window.getComputedStyle(node);
40 const spaceAbove = anchor.top - hostRect.top;
41 const spaceBelow = hostRect.bottom - anchor.bottom;
42 const marginTop = parseInt(style.marginTop, 10) || 0;
43 const marginLeft = parseInt(style.marginLeft, 10) || 0;
44 const minHeight = parseInt(style.minHeight, 10) || options.minHeight;
45 let maxHeight = parseInt(style.maxHeight, 10) || options.maxHeight;
46 // Determine whether to render above or below; check privilege.
47 const renderBelow = privilege === 'forceAbove'
48 ? false
49 : privilege === 'forceBelow'
50 ? true
51 : privilege === 'above'
52 ? spaceAbove < maxHeight && spaceAbove < spaceBelow
53 : spaceBelow >= maxHeight || spaceBelow >= spaceAbove;
54 if (renderBelow) {
55 maxHeight = Math.min(spaceBelow - marginTop, maxHeight);
56 }
57 else {
58 maxHeight = Math.min(spaceAbove, maxHeight);
59 // If the box renders above the text, its top margin is irrelevant.
60 node.style.marginTop = '0px';
61 }
62 node.style.maxHeight = `${maxHeight}px`;
63 // Make sure the box ought to be visible.
64 const withinBounds = maxHeight > minHeight &&
65 (spaceBelow >= minHeight || spaceAbove >= minHeight);
66 if (!withinBounds) {
67 node.style.zIndex = OUTOFVIEW_Z_INDEX;
68 node.style.visibility = 'hidden';
69 return;
70 }
71 if (options.size) {
72 node.style.width = `${options.size.width}px`;
73 node.style.height = `${options.size.height}px`;
74 node.style.contain = 'strict';
75 }
76 else {
77 node.style.contain = '';
78 node.style.width = 'auto';
79 node.style.height = '';
80 }
81 // Position the box vertically.
82 const initialHeight = options.size
83 ? options.size.height
84 : node.getBoundingClientRect().height;
85 const offsetAbove = (options.offset &&
86 options.offset.vertical &&
87 options.offset.vertical.above) ||
88 0;
89 const offsetBelow = (options.offset &&
90 options.offset.vertical &&
91 options.offset.vertical.below) ||
92 0;
93 let top = renderBelow
94 ? hostRect.bottom - spaceBelow + offsetBelow
95 : hostRect.top + spaceAbove - initialHeight + offsetAbove;
96 node.style.top = `${Math.floor(top)}px`;
97 // Position the box horizontally.
98 const offsetHorizontal = (options.offset && options.offset.horizontal) || 0;
99 let left = anchor.left + offsetHorizontal;
100 node.style.left = `${Math.ceil(left)}px`;
101 let rect = node.getBoundingClientRect();
102 // Move left to fit in the window.
103 const right = rect.right;
104 if (right > window.innerWidth) {
105 left -= right - window.innerWidth;
106 node.style.left = `${Math.ceil(left)}px`;
107 }
108 // Move right to fit in the window
109 if (left < offsetHorizontal - marginLeft) {
110 left = offsetHorizontal - marginLeft;
111 node.style.left = `${Math.ceil(left)}px`;
112 }
113 // Hide the hover box before querying the DOM for the anchor coordinates.
114 // Using z-index set directly for performance.
115 node.style.zIndex = '-1000';
116 const bottom = rect.bottom;
117 const includesLeftTop = host.contains(document.elementFromPoint(left, top));
118 const includesRightTop = host.contains(document.elementFromPoint(right, top));
119 const includesRightBottom = host.contains(document.elementFromPoint(right, bottom));
120 const includesLeftBottom = host.contains(document.elementFromPoint(left, bottom));
121 node.style.zIndex = '';
122 const topEdgeInside = includesLeftTop || includesRightTop;
123 const bottomEdgeInside = includesLeftBottom || includesRightBottom;
124 const leftEdgeInside = includesLeftTop || includesLeftBottom;
125 const rightEdgeInside = includesRightBottom || includesRightTop;
126 const height = bottom - top;
127 const width = right - left;
128 const overTheTop = top < hostRect.top;
129 const belowTheBottom = bottom > hostRect.bottom;
130 const beforeTheLeft = left + marginLeft < hostRect.left;
131 const afterTheRight = right > hostRect.right;
132 let hide = false;
133 let leftChanged = false;
134 let topChanged = false;
135 if (overTheTop) {
136 switch ((outOfViewDisplay === null || outOfViewDisplay === void 0 ? void 0 : outOfViewDisplay.top) || 'hidden-inside') {
137 case 'hidden-inside':
138 if (!topEdgeInside) {
139 hide = true;
140 }
141 break;
142 case 'hidden-outside':
143 if (!bottomEdgeInside) {
144 hide = true;
145 }
146 break;
147 case 'stick-inside':
148 if (hostRect.top > top) {
149 top = hostRect.top;
150 topChanged = true;
151 }
152 break;
153 case 'stick-outside':
154 if (hostRect.top > bottom) {
155 top = hostRect.top - height;
156 topChanged = true;
157 }
158 break;
159 }
160 }
161 if (belowTheBottom) {
162 switch ((outOfViewDisplay === null || outOfViewDisplay === void 0 ? void 0 : outOfViewDisplay.bottom) || 'hidden-outside') {
163 case 'hidden-inside':
164 if (!bottomEdgeInside) {
165 hide = true;
166 }
167 break;
168 case 'hidden-outside':
169 if (!topEdgeInside) {
170 hide = true;
171 }
172 break;
173 case 'stick-inside':
174 if (hostRect.bottom < bottom) {
175 top = hostRect.bottom - height;
176 topChanged = true;
177 }
178 break;
179 case 'stick-outside':
180 if (hostRect.bottom < top) {
181 top = hostRect.bottom;
182 topChanged = true;
183 }
184 break;
185 }
186 }
187 if (beforeTheLeft) {
188 switch ((outOfViewDisplay === null || outOfViewDisplay === void 0 ? void 0 : outOfViewDisplay.left) || 'hidden-inside') {
189 case 'hidden-inside':
190 if (!leftEdgeInside) {
191 hide = true;
192 }
193 break;
194 case 'hidden-outside':
195 if (!rightEdgeInside) {
196 hide = true;
197 }
198 break;
199 case 'stick-inside':
200 if (hostRect.left > left + marginLeft) {
201 left = hostRect.left - marginLeft;
202 leftChanged = true;
203 }
204 break;
205 case 'stick-outside':
206 if (hostRect.left > right) {
207 left = hostRect.left - marginLeft - width;
208 leftChanged = true;
209 }
210 break;
211 }
212 }
213 if (afterTheRight) {
214 switch ((outOfViewDisplay === null || outOfViewDisplay === void 0 ? void 0 : outOfViewDisplay.right) || 'hidden-outside') {
215 case 'hidden-inside':
216 if (!rightEdgeInside) {
217 hide = true;
218 }
219 break;
220 case 'hidden-outside':
221 if (!leftEdgeInside) {
222 hide = true;
223 }
224 break;
225 case 'stick-inside':
226 if (hostRect.right < right) {
227 left = hostRect.right - width;
228 leftChanged = true;
229 }
230 break;
231 case 'stick-outside':
232 if (hostRect.right < left) {
233 left = hostRect.right;
234 leftChanged = true;
235 }
236 break;
237 }
238 }
239 if (hide) {
240 node.style.zIndex = OUTOFVIEW_Z_INDEX;
241 node.style.visibility = 'hidden';
242 }
243 if (leftChanged) {
244 node.style.left = `${Math.ceil(left)}px`;
245 }
246 if (topChanged) {
247 node.style.top = `${Math.ceil(top)}px`;
248 }
249 }
250 HoverBox.setGeometry = setGeometry;
251})(HoverBox || (HoverBox = {}));
252//# sourceMappingURL=hoverbox.js.map
\No newline at end of file