@farm-investimentos/front-mfe-components 15.14.8 → 15.14.9
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/front-mfe-components.common.js +214 -121
- package/dist/front-mfe-components.common.js.map +1 -1
- package/dist/front-mfe-components.css +1 -1
- package/dist/front-mfe-components.umd.js +214 -121
- package/dist/front-mfe-components.umd.js.map +1 -1
- package/dist/front-mfe-components.umd.min.js +1 -1
- package/dist/front-mfe-components.umd.min.js.map +1 -1
- package/package.json +1 -1
- package/src/components/Tooltip/Tooltip.vue +89 -14
- package/src/components/Tooltip/utils/tooltip.utils.ts +31 -17
package/package.json
CHANGED
|
@@ -3,14 +3,13 @@
|
|
|
3
3
|
<div
|
|
4
4
|
ref="activatorRef"
|
|
5
5
|
class="tooltip-activator"
|
|
6
|
-
@
|
|
7
|
-
@
|
|
8
|
-
@mouseleave="hide"
|
|
6
|
+
@mouseenter="onActivatorEnter"
|
|
7
|
+
@mouseleave="onActivatorLeave"
|
|
9
8
|
>
|
|
10
9
|
<slot name="activator" />
|
|
11
10
|
</div>
|
|
12
11
|
|
|
13
|
-
<div v-if="isVisible" ref="tooltipRef" :class="tooltipClasses" :style="tooltipStyles">
|
|
12
|
+
<div v-if="isVisible" ref="tooltipRef" :class="tooltipClasses" :style="tooltipStyles" @mouseenter="onTooltipEnter" @mouseleave="onTooltipLeave">
|
|
14
13
|
<div v-if="hasTitle || showCloseButton" class="tooltip-header">
|
|
15
14
|
<div v-if="hasTitle" class="tooltip-title">
|
|
16
15
|
<slot name="title" />
|
|
@@ -96,6 +95,10 @@ export default defineComponent({
|
|
|
96
95
|
type: String,
|
|
97
96
|
default: undefined,
|
|
98
97
|
},
|
|
98
|
+
anchorTo: {
|
|
99
|
+
type: String as PropType<'auto' | 'viewport' | 'modal'>,
|
|
100
|
+
default: 'auto',
|
|
101
|
+
},
|
|
99
102
|
hideOnScroll: {
|
|
100
103
|
type: Boolean,
|
|
101
104
|
default: true,
|
|
@@ -106,6 +109,8 @@ export default defineComponent({
|
|
|
106
109
|
const containerRef = ref<HTMLElement | null>(null);
|
|
107
110
|
const activatorRef = ref<HTMLElement | null>(null);
|
|
108
111
|
const tooltipRef = ref<HTMLElement | null>(null);
|
|
112
|
+
const anchorElRef = ref<HTMLElement | null>(null);
|
|
113
|
+
const anchoredToModal = ref(false);
|
|
109
114
|
const scrollableElementsRef = ref<Element[] | null>(null);
|
|
110
115
|
|
|
111
116
|
const Z_INDEX_OFFSET = 1000;
|
|
@@ -161,6 +166,12 @@ export default defineComponent({
|
|
|
161
166
|
return props.placement;
|
|
162
167
|
});
|
|
163
168
|
|
|
169
|
+
// Placement realmente utilizado (pode sofrer flip em runtime)
|
|
170
|
+
const currentPlacement = ref(normalizedPlacement.value);
|
|
171
|
+
watch(normalizedPlacement, (val) => {
|
|
172
|
+
currentPlacement.value = val;
|
|
173
|
+
});
|
|
174
|
+
|
|
164
175
|
const normalizedMaxWidth = computed(() => {
|
|
165
176
|
if (props.fluid) {
|
|
166
177
|
return '300px';
|
|
@@ -174,12 +185,12 @@ export default defineComponent({
|
|
|
174
185
|
[`tooltip-popup--${props.variant}`]: true,
|
|
175
186
|
[`tooltip-popup--${props.size}`]: true,
|
|
176
187
|
'tooltip-popup--has-title': hasTitle.value,
|
|
177
|
-
[`tooltip-popup--${
|
|
188
|
+
[`tooltip-popup--${currentPlacement.value}`]: true,
|
|
178
189
|
}));
|
|
179
190
|
|
|
180
191
|
const tooltipStyles = computed(() => {
|
|
181
192
|
const styles: Record<string, string> = {
|
|
182
|
-
position: 'fixed',
|
|
193
|
+
position: anchoredToModal.value ? 'absolute' : 'fixed',
|
|
183
194
|
zIndex: String(getTooltipZIndex()),
|
|
184
195
|
};
|
|
185
196
|
|
|
@@ -195,7 +206,7 @@ export default defineComponent({
|
|
|
195
206
|
});
|
|
196
207
|
|
|
197
208
|
const arrowStyles = computed(() => {
|
|
198
|
-
const [verticalPos, horizontalAlign] =
|
|
209
|
+
const [verticalPos, horizontalAlign] = currentPlacement.value.split('-');
|
|
199
210
|
|
|
200
211
|
const styles: Record<string, string> = {
|
|
201
212
|
position: 'absolute',
|
|
@@ -235,14 +246,29 @@ export default defineComponent({
|
|
|
235
246
|
|
|
236
247
|
nextTick(() => {
|
|
237
248
|
if (tooltipRef.value && activatorRef.value) {
|
|
238
|
-
|
|
249
|
+
// Resolver onde ancorar o tooltip
|
|
250
|
+
let anchorEl: HTMLElement | null = null;
|
|
251
|
+
if (props.anchorTo === 'viewport') {
|
|
252
|
+
anchorEl = document.body;
|
|
253
|
+
} else if (props.anchorTo === 'modal' || props.anchorTo === 'auto') {
|
|
254
|
+
const modalEl = activatorRef.value.closest('.farm-modal') as HTMLElement | null;
|
|
255
|
+
anchorEl = modalEl || document.body;
|
|
256
|
+
}
|
|
257
|
+
|
|
258
|
+
anchorElRef.value = anchorEl;
|
|
259
|
+
anchoredToModal.value = !!anchorEl && anchorEl !== document.body;
|
|
260
|
+
if (anchoredToModal.value && anchorElRef.value && tooltipRef.value) {
|
|
261
|
+
anchorElRef.value.appendChild(tooltipRef.value);
|
|
262
|
+
} else {
|
|
263
|
+
moveToBody(tooltipRef.value);
|
|
264
|
+
}
|
|
239
265
|
updatePosition();
|
|
240
266
|
addScrollListener();
|
|
241
267
|
}
|
|
242
268
|
});
|
|
243
269
|
};
|
|
244
270
|
|
|
245
|
-
|
|
271
|
+
const hide = () => {
|
|
246
272
|
if (props.disabled || isControlled.value) return;
|
|
247
273
|
|
|
248
274
|
isVisible.value = false;
|
|
@@ -250,6 +276,38 @@ export default defineComponent({
|
|
|
250
276
|
removeScrollListener();
|
|
251
277
|
};
|
|
252
278
|
|
|
279
|
+
// Hover management to avoid flicker when moving from activator to tooltip
|
|
280
|
+
let hoverInside = false;
|
|
281
|
+
let hideTimeout: number | null = null;
|
|
282
|
+
|
|
283
|
+
const clearHideTimeout = () => {
|
|
284
|
+
if (hideTimeout) {
|
|
285
|
+
window.clearTimeout(hideTimeout);
|
|
286
|
+
hideTimeout = null;
|
|
287
|
+
}
|
|
288
|
+
};
|
|
289
|
+
|
|
290
|
+
const onActivatorEnter = () => {
|
|
291
|
+
clearHideTimeout();
|
|
292
|
+
show();
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const onActivatorLeave = () => {
|
|
296
|
+
hideTimeout = window.setTimeout(() => {
|
|
297
|
+
if (!hoverInside) hide();
|
|
298
|
+
}, (Array.isArray(props.delay) ? (props.delay[1] || 50) : 50) as number);
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const onTooltipEnter = () => {
|
|
302
|
+
hoverInside = true;
|
|
303
|
+
clearHideTimeout();
|
|
304
|
+
};
|
|
305
|
+
|
|
306
|
+
const onTooltipLeave = () => {
|
|
307
|
+
hoverInside = false;
|
|
308
|
+
hide();
|
|
309
|
+
};
|
|
310
|
+
|
|
253
311
|
const close = () => {
|
|
254
312
|
if (isControlled.value) {
|
|
255
313
|
emit('input', false);
|
|
@@ -278,12 +336,25 @@ export default defineComponent({
|
|
|
278
336
|
const position = calculateTooltipPosition(
|
|
279
337
|
activatorRect,
|
|
280
338
|
tooltipRect,
|
|
281
|
-
|
|
339
|
+
currentPlacement.value,
|
|
282
340
|
props.offset
|
|
283
341
|
);
|
|
284
342
|
|
|
285
|
-
|
|
286
|
-
|
|
343
|
+
// Atualiza placement efetivo (com flip) para setinha/classes
|
|
344
|
+
currentPlacement.value = position.placementUsed as TooltipPlacement;
|
|
345
|
+
|
|
346
|
+
if (anchoredToModal.value && anchorElRef.value) {
|
|
347
|
+
const containerRect = anchorElRef.value.getBoundingClientRect();
|
|
348
|
+
const scrollLeft = anchorElRef.value.scrollLeft || 0;
|
|
349
|
+
const scrollTop = anchorElRef.value.scrollTop || 0;
|
|
350
|
+
const left = position.left - containerRect.left + scrollLeft;
|
|
351
|
+
const top = position.top - containerRect.top + scrollTop;
|
|
352
|
+
tooltipRef.value.style.left = `${left}px`;
|
|
353
|
+
tooltipRef.value.style.top = `${top}px`;
|
|
354
|
+
} else {
|
|
355
|
+
tooltipRef.value.style.left = `${position.left}px`;
|
|
356
|
+
tooltipRef.value.style.top = `${position.top}px`;
|
|
357
|
+
}
|
|
287
358
|
};
|
|
288
359
|
|
|
289
360
|
const getScrollableElements = () => {
|
|
@@ -372,8 +443,12 @@ export default defineComponent({
|
|
|
372
443
|
tooltipClasses,
|
|
373
444
|
tooltipStyles,
|
|
374
445
|
arrowStyles,
|
|
375
|
-
|
|
376
|
-
|
|
446
|
+
show,
|
|
447
|
+
hide,
|
|
448
|
+
onActivatorEnter,
|
|
449
|
+
onActivatorLeave,
|
|
450
|
+
onTooltipEnter,
|
|
451
|
+
onTooltipLeave,
|
|
377
452
|
close,
|
|
378
453
|
};
|
|
379
454
|
},
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export interface TooltipPosition {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
left: number;
|
|
3
|
+
top: number;
|
|
4
|
+
placementUsed: string; // ex.: 'top-left', 'bottom-center'
|
|
4
5
|
}
|
|
5
6
|
|
|
6
7
|
export interface TooltipRect {
|
|
@@ -20,16 +21,19 @@ export function calculateTooltipPosition(
|
|
|
20
21
|
placement: string,
|
|
21
22
|
offset: number = 8
|
|
22
23
|
): TooltipPosition {
|
|
23
|
-
|
|
24
|
+
const parts = placement.split('-');
|
|
25
|
+
let verticalPos = parts[0];
|
|
26
|
+
const horizontalAlign = parts[1];
|
|
24
27
|
|
|
25
28
|
let left = 0;
|
|
26
29
|
let top = 0;
|
|
27
30
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
31
|
+
const computeTop = (vert: string) =>
|
|
32
|
+
vert === 'top'
|
|
33
|
+
? activatorRect.top - tooltipRect.height - offset
|
|
34
|
+
: activatorRect.bottom + offset;
|
|
35
|
+
|
|
36
|
+
top = computeTop(verticalPos);
|
|
33
37
|
|
|
34
38
|
switch (horizontalAlign) {
|
|
35
39
|
case 'left':
|
|
@@ -45,16 +49,26 @@ export function calculateTooltipPosition(
|
|
|
45
49
|
break;
|
|
46
50
|
}
|
|
47
51
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
52
|
+
// Flip vertical if not enough space
|
|
53
|
+
const tooHigh = top < offset;
|
|
54
|
+
const tooLow = top + tooltipRect.height > window.innerHeight - offset;
|
|
55
|
+
if ((verticalPos === 'top' && tooHigh) || (verticalPos === 'bottom' && tooLow)) {
|
|
56
|
+
verticalPos = verticalPos === 'top' ? 'bottom' : 'top';
|
|
57
|
+
top = computeTop(verticalPos);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Clamp within viewport horizontally and vertically
|
|
61
|
+
if (left < offset) left = offset;
|
|
62
|
+
if (left + tooltipRect.width > window.innerWidth - offset) {
|
|
63
|
+
left = window.innerWidth - tooltipRect.width - offset;
|
|
64
|
+
}
|
|
65
|
+
if (top < offset) top = offset;
|
|
66
|
+
if (top + tooltipRect.height > window.innerHeight - offset) {
|
|
67
|
+
top = window.innerHeight - tooltipRect.height - offset;
|
|
68
|
+
}
|
|
56
69
|
|
|
57
|
-
|
|
70
|
+
const placementUsed = `${verticalPos}-${horizontalAlign || 'center'}`;
|
|
71
|
+
return { left, top, placementUsed };
|
|
58
72
|
}
|
|
59
73
|
|
|
60
74
|
export function moveToBody(element: HTMLElement): void {
|