@farm-investimentos/front-mfe-components 15.10.2 → 15.11.0
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 +436 -451
- 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 +436 -451
- 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.scss +95 -13
- package/src/components/Tooltip/Tooltip.stories.js +163 -58
- package/src/components/Tooltip/Tooltip.vue +126 -38
package/package.json
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
@import '../../configurations/theme-colors';
|
|
2
1
|
@import '../../configurations/variables';
|
|
3
2
|
|
|
3
|
+
$arrow-size: 6px;
|
|
4
|
+
$tooltip-color: #333333;
|
|
5
|
+
$arrow-margin: 12px;
|
|
6
|
+
|
|
4
7
|
.farm-tooltip {
|
|
5
8
|
display: inline-block;
|
|
6
9
|
position: relative;
|
|
@@ -11,31 +14,110 @@
|
|
|
11
14
|
}
|
|
12
15
|
|
|
13
16
|
.farm-tooltip__popup {
|
|
14
|
-
background-color:
|
|
15
|
-
@each $color in $theme-colors-list {
|
|
16
|
-
&.farm-tooltip--#{$color} {
|
|
17
|
-
background-color: rgba(themeColor($color), 0.95);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
.farm-tooltip__popup {
|
|
17
|
+
background-color: $tooltip-color;
|
|
23
18
|
visibility: hidden;
|
|
24
19
|
opacity: 0;
|
|
25
20
|
transition: visibility 0.3s linear, opacity 0.3s linear;
|
|
26
21
|
position: absolute;
|
|
27
22
|
width: 160px;
|
|
28
|
-
|
|
29
|
-
color: white;
|
|
23
|
+
color: #f5f5f5;
|
|
30
24
|
border-radius: 5px;
|
|
31
25
|
font-family: 'Manrope', sans-serif !important;
|
|
32
26
|
font-size: 12px;
|
|
33
27
|
font-weight: 500px;
|
|
34
|
-
padding:
|
|
28
|
+
padding: 16px;
|
|
35
29
|
display: block;
|
|
30
|
+
z-index: 9999;
|
|
31
|
+
|
|
32
|
+
&--fluid {
|
|
33
|
+
width: auto;
|
|
34
|
+
min-width: 160px;
|
|
35
|
+
max-width: 300px;
|
|
36
|
+
}
|
|
36
37
|
|
|
37
38
|
&--visible {
|
|
38
39
|
opacity: 1;
|
|
39
40
|
visibility: visible;
|
|
40
41
|
}
|
|
42
|
+
|
|
43
|
+
.farm-tooltip__header {
|
|
44
|
+
display: flex;
|
|
45
|
+
justify-content: space-between;
|
|
46
|
+
align-items: center;
|
|
47
|
+
margin-bottom: 8px;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
.farm-tooltip__title {
|
|
51
|
+
font-weight: 600;
|
|
52
|
+
font-size: 13px;
|
|
53
|
+
margin-right: 16px;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
.farm-tooltip__content {
|
|
57
|
+
font-weight: 500;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
.farm-tooltip__arrow {
|
|
61
|
+
position: absolute;
|
|
62
|
+
width: 0;
|
|
63
|
+
height: 0;
|
|
64
|
+
border-style: solid;
|
|
65
|
+
z-index: 10000;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
// Top positions - arrow at bottom
|
|
69
|
+
&--top-center .farm-tooltip__arrow,
|
|
70
|
+
&--top-left .farm-tooltip__arrow,
|
|
71
|
+
&--top-right .farm-tooltip__arrow {
|
|
72
|
+
border-width: $arrow-size $arrow-size 0 $arrow-size;
|
|
73
|
+
border-color: $tooltip-color transparent transparent transparent;
|
|
74
|
+
bottom: -$arrow-size;
|
|
75
|
+
z-index: 99999;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
// Bottom positions - arrow at top
|
|
79
|
+
&--bottom-center .farm-tooltip__arrow,
|
|
80
|
+
&--bottom-left .farm-tooltip__arrow,
|
|
81
|
+
&--bottom-right .farm-tooltip__arrow {
|
|
82
|
+
border-width: 0 $arrow-size $arrow-size $arrow-size;
|
|
83
|
+
border-color: transparent transparent $tooltip-color transparent;
|
|
84
|
+
top: -$arrow-size;
|
|
85
|
+
z-index: 99999;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Left alignment - arrow at left
|
|
89
|
+
&--top-left .farm-tooltip__arrow,
|
|
90
|
+
&--bottom-left .farm-tooltip__arrow {
|
|
91
|
+
left: $arrow-margin;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Right alignment - arrow at right
|
|
95
|
+
&--top-right .farm-tooltip__arrow,
|
|
96
|
+
&--bottom-right .farm-tooltip__arrow {
|
|
97
|
+
right: $arrow-margin;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// Center alignment - arrow at center
|
|
101
|
+
&--top-center .farm-tooltip__arrow,
|
|
102
|
+
&--bottom-center .farm-tooltip__arrow {
|
|
103
|
+
left: 50%;
|
|
104
|
+
transform: translateX(-50%);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.farm-tooltip__close {
|
|
108
|
+
position: relative;
|
|
109
|
+
width: 16px;
|
|
110
|
+
height: 16px;
|
|
111
|
+
line-height: 16px;
|
|
112
|
+
text-align: center;
|
|
113
|
+
cursor: pointer;
|
|
114
|
+
font-size: 16px;
|
|
115
|
+
color: #f5f5f5;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
&:not(.farm-tooltip__popup--has-title) .farm-tooltip__close {
|
|
119
|
+
position: absolute;
|
|
120
|
+
top: 8px;
|
|
121
|
+
right: 8px;
|
|
122
|
+
}
|
|
41
123
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { withDesign } from 'storybook-addon-designs';
|
|
2
2
|
import Tooltip from '.';
|
|
3
|
-
import baseThemeColors from '../../configurations/_theme-colors-base.scss';
|
|
4
|
-
const colors = Object.keys(baseThemeColors);
|
|
5
3
|
|
|
6
4
|
export default {
|
|
7
5
|
title: 'Interactions/Tooltip',
|
|
@@ -13,6 +11,16 @@ export default {
|
|
|
13
11
|
component: `Tooltip<br />
|
|
14
12
|
selector: <em>farm-tooltip</em><br />
|
|
15
13
|
<span style="color: var(--farm-primary-base);">ready for use</span>
|
|
14
|
+
<br /><br />
|
|
15
|
+
<h3>Important notes:</h3>
|
|
16
|
+
<ul>
|
|
17
|
+
<li><strong>Do not add margin to the activator element</strong> - This can confuse the tooltip display watcher and prevent the arrow from being positioned correctly</li>
|
|
18
|
+
<li>Prefer to add margin to the parent element or sibling elements of the tooltip</li>
|
|
19
|
+
<li>Arrow positioning is calculated based on the activator element position</li>
|
|
20
|
+
<li>The close button (X) is automatically displayed only in tooltips controlled by v-model</li>
|
|
21
|
+
<li>The arrow is only displayed when a position is explicitly defined (position property). If no position is defined, the tooltip will not have an arrow</li>
|
|
22
|
+
<li>You can add a title to the tooltip using the "title" slot. When used in a controlled tooltip, the close button will be aligned with the title</li>
|
|
23
|
+
</ul>
|
|
16
24
|
`,
|
|
17
25
|
},
|
|
18
26
|
},
|
|
@@ -25,76 +33,173 @@ export default {
|
|
|
25
33
|
};
|
|
26
34
|
|
|
27
35
|
export const Tooltips = () => ({
|
|
28
|
-
data() {
|
|
29
|
-
return {
|
|
30
|
-
colors,
|
|
31
|
-
};
|
|
32
|
-
},
|
|
33
36
|
template: `<div style="padding-left: 80px; padding-top: 80px;">
|
|
34
|
-
<
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
</template>
|
|
46
|
-
</farm-tooltip>
|
|
37
|
+
<span style="display: flex; align-items: center;">
|
|
38
|
+
Hover over the icon
|
|
39
|
+
<farm-tooltip>
|
|
40
|
+
<span>
|
|
41
|
+
This is a simple tooltip
|
|
42
|
+
</span>
|
|
43
|
+
<template v-slot:activator>
|
|
44
|
+
<farm-icon size="sm" color="gray" style="margin-left: 8px; cursor: help;">help-circle</farm-icon>
|
|
45
|
+
</template>
|
|
46
|
+
</farm-tooltip>
|
|
47
|
+
</span>
|
|
47
48
|
</div>`,
|
|
48
49
|
});
|
|
49
50
|
|
|
50
|
-
export const
|
|
51
|
+
export const InsideCard = () => ({
|
|
51
52
|
template: `<div style="padding-left: 80px; padding-top: 80px;">
|
|
52
|
-
<farm-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
53
|
+
<farm-card style="padding: 32px">
|
|
54
|
+
<span style="display: flex; align-items: center;">
|
|
55
|
+
<span style="margin-right: 8px;">Important information</span>
|
|
56
|
+
<farm-tooltip>
|
|
57
|
+
this is the tooltip!
|
|
58
|
+
<template v-slot:activator>
|
|
59
|
+
<farm-icon size="sm" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
60
|
+
</template>
|
|
61
|
+
</farm-tooltip>
|
|
62
|
+
</span>
|
|
63
|
+
</farm-card>
|
|
60
64
|
</div>`,
|
|
61
65
|
});
|
|
62
66
|
|
|
63
|
-
export const
|
|
64
|
-
data() {
|
|
65
|
-
return {
|
|
66
|
-
show: false,
|
|
67
|
-
};
|
|
68
|
-
},
|
|
67
|
+
export const FluidTooltip = () => ({
|
|
69
68
|
template: `<div style="padding-left: 80px; padding-top: 80px;">
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<template v-slot:activator="{ on, attrs }">
|
|
81
|
-
<farm-btn @click="show = !show">
|
|
82
|
-
toggle me
|
|
83
|
-
</farm-btn>
|
|
84
|
-
</template>
|
|
85
|
-
</farm-tooltip>
|
|
69
|
+
<span style="display: flex; align-items: center;">
|
|
70
|
+
<span style="margin-right: 8px;">Fluid width tooltip</span>
|
|
71
|
+
<farm-tooltip fluid>
|
|
72
|
+
This is a fluid tooltip that will grow based on its content.
|
|
73
|
+
It contains a longer text to demonstrate how it expands horizontally.
|
|
74
|
+
<template v-slot:activator>
|
|
75
|
+
<farm-icon size="sm" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
76
|
+
</template>
|
|
77
|
+
</farm-tooltip>
|
|
78
|
+
</span>
|
|
86
79
|
</div>`,
|
|
87
80
|
});
|
|
88
81
|
|
|
89
|
-
export const
|
|
82
|
+
export const TooltipPositions = () => ({
|
|
83
|
+
template: `<div style="padding: 100px; display: flex; flex-direction: column; align-items: center; gap: 50px;">
|
|
84
|
+
<div style="display: flex; gap: 30px; margin-bottom: 50px;">
|
|
85
|
+
<div style="display: flex; flex-direction: column; align-items: center;">
|
|
86
|
+
<p style="margin-bottom: 10px;">Top Left</p>
|
|
87
|
+
<farm-tooltip position="top-left">
|
|
88
|
+
Top-Left Position
|
|
89
|
+
<template v-slot:activator>
|
|
90
|
+
<farm-icon size="md" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
91
|
+
</template>
|
|
92
|
+
</farm-tooltip>
|
|
93
|
+
</div>
|
|
94
|
+
|
|
95
|
+
<div style="display: flex; flex-direction: column; align-items: center;">
|
|
96
|
+
<p style="margin-bottom: 10px;">Top Center</p>
|
|
97
|
+
<farm-tooltip position="top-center">
|
|
98
|
+
Top-Center Position (Default)
|
|
99
|
+
<template v-slot:activator>
|
|
100
|
+
<farm-icon size="md" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
101
|
+
</template>
|
|
102
|
+
</farm-tooltip>
|
|
103
|
+
</div>
|
|
104
|
+
|
|
105
|
+
<div style="display: flex; flex-direction: column; align-items: center;">
|
|
106
|
+
<p style="margin-bottom: 10px;">Top Right</p>
|
|
107
|
+
<farm-tooltip position="top-right">
|
|
108
|
+
Top-Right Position
|
|
109
|
+
<template v-slot:activator>
|
|
110
|
+
<farm-icon size="md" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
111
|
+
</template>
|
|
112
|
+
</farm-tooltip>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
|
|
116
|
+
<div style="display: flex; gap: 30px;">
|
|
117
|
+
<div style="display: flex; flex-direction: column; align-items: center;">
|
|
118
|
+
<p style="margin-bottom: 10px;">Bottom Left</p>
|
|
119
|
+
<farm-tooltip position="bottom-left">
|
|
120
|
+
Bottom-Left Position
|
|
121
|
+
<template v-slot:activator>
|
|
122
|
+
<farm-icon size="md" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
123
|
+
</template>
|
|
124
|
+
</farm-tooltip>
|
|
125
|
+
</div>
|
|
126
|
+
|
|
127
|
+
<div style="display: flex; flex-direction: column; align-items: center;">
|
|
128
|
+
<p style="margin-bottom: 10px;">Bottom Center</p>
|
|
129
|
+
<farm-tooltip position="bottom-center">
|
|
130
|
+
Bottom-Center Position
|
|
131
|
+
<template v-slot:activator>
|
|
132
|
+
<farm-icon size="md" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
133
|
+
</template>
|
|
134
|
+
</farm-tooltip>
|
|
135
|
+
</div>
|
|
136
|
+
|
|
137
|
+
<div style="display: flex; flex-direction: column; align-items: center;">
|
|
138
|
+
<p style="margin-bottom: 10px;">Bottom Right</p>
|
|
139
|
+
<farm-tooltip position="bottom-right">
|
|
140
|
+
Bottom-Right Position
|
|
141
|
+
<template v-slot:activator>
|
|
142
|
+
<farm-icon size="md" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
143
|
+
</template>
|
|
144
|
+
</farm-tooltip>
|
|
145
|
+
</div>
|
|
146
|
+
</div>
|
|
147
|
+
</div>`,
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
export const FluidWithPosition = () => ({
|
|
151
|
+
template: `<div style="padding: 200px;">
|
|
152
|
+
<span style="display: flex; align-items: center;">
|
|
153
|
+
<span style="margin-right: 8px;">Fluid tooltip with position</span>
|
|
154
|
+
<farm-tooltip fluid position="bottom-left">
|
|
155
|
+
This is a fluid tooltip with Bottom-Left position.
|
|
156
|
+
Notice how it grows based on content and has the arrow in the correct position.
|
|
157
|
+
<template v-slot:activator>
|
|
158
|
+
<farm-icon size="md" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
159
|
+
</template>
|
|
160
|
+
</farm-tooltip>
|
|
161
|
+
</span>
|
|
162
|
+
</div>`,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
export const TooltipWithTitle = () => ({
|
|
90
166
|
template: `<div style="padding-left: 80px; padding-top: 80px;">
|
|
91
|
-
|
|
92
|
-
<
|
|
93
|
-
|
|
94
|
-
<template v-slot:
|
|
95
|
-
<farm-
|
|
167
|
+
<span style="display: flex; align-items: center;">
|
|
168
|
+
<span style="margin-right: 8px;">Tooltip with title</span>
|
|
169
|
+
<farm-tooltip fluid position="top-left">
|
|
170
|
+
<template v-slot:title>
|
|
171
|
+
<farm-icon size="sm" color="white">alert</farm-icon>
|
|
172
|
+
<span class="ml-10">Important Information</span>
|
|
173
|
+
</template>
|
|
174
|
+
This tooltip has a title that appears at the top.
|
|
175
|
+
<template v-slot:activator>
|
|
176
|
+
<farm-icon size="md" color="gray" style="cursor: help;">help-circle</farm-icon>
|
|
96
177
|
</template>
|
|
97
178
|
</farm-tooltip>
|
|
98
|
-
</
|
|
179
|
+
</span>
|
|
180
|
+
</div>`,
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
export const ControlledTooltipWithTitle = () => ({
|
|
184
|
+
data() {
|
|
185
|
+
return {
|
|
186
|
+
showTooltip: false,
|
|
187
|
+
};
|
|
188
|
+
},
|
|
189
|
+
template: `<div style="padding: 80px;">
|
|
190
|
+
<span style="display: flex; align-items: center;">
|
|
191
|
+
<span style="margin-right: 8px;">Click to open:</span>
|
|
192
|
+
<farm-tooltip fluid v-model="showTooltip" position="top-right">
|
|
193
|
+
<template v-slot:title>
|
|
194
|
+
Tooltip Title
|
|
195
|
+
</template>
|
|
196
|
+
This is a controlled tooltip with title.
|
|
197
|
+
<br><br>
|
|
198
|
+
Notice how the close button is aligned with the title.
|
|
199
|
+
<template v-slot:activator>
|
|
200
|
+
<farm-icon @click="showTooltip = !showTooltip" size="md" color="blue" style="cursor: pointer;">help-circle</farm-icon>
|
|
201
|
+
</template>
|
|
202
|
+
</farm-tooltip>
|
|
203
|
+
</span>
|
|
99
204
|
</div>`,
|
|
100
205
|
});
|
|
@@ -8,54 +8,76 @@
|
|
|
8
8
|
ref="popup"
|
|
9
9
|
:class="{
|
|
10
10
|
'farm-tooltip__popup': true,
|
|
11
|
-
['farm-tooltip--' + color]: true,
|
|
12
11
|
'farm-tooltip__popup--visible':
|
|
13
12
|
(!externalControl && showOver) || (externalControl && toggleComponent),
|
|
13
|
+
'farm-tooltip__popup--fluid': fluid,
|
|
14
|
+
[`farm-tooltip__popup--${position}`]: position,
|
|
15
|
+
'farm-tooltip__popup--has-title': hasTitle,
|
|
14
16
|
}"
|
|
15
17
|
:style="styles"
|
|
16
18
|
@mouseout="onOut"
|
|
17
19
|
>
|
|
18
|
-
<
|
|
20
|
+
<div v-if="hasTitle" class="farm-tooltip__header">
|
|
21
|
+
<div class="farm-tooltip__title">
|
|
22
|
+
<slot name="title"></slot>
|
|
23
|
+
</div>
|
|
24
|
+
<span v-if="externalControl" class="farm-tooltip__close" @click="onClose">×</span>
|
|
25
|
+
</div>
|
|
26
|
+
<div class="farm-tooltip__content">
|
|
27
|
+
<slot />
|
|
28
|
+
</div>
|
|
29
|
+
<span v-if="hasPosition" class="farm-tooltip__arrow"></span>
|
|
19
30
|
</span>
|
|
20
31
|
</span>
|
|
21
32
|
</template>
|
|
22
33
|
<script lang="ts">
|
|
23
|
-
import { PropType, ref, computed, reactive, onBeforeUnmount, defineComponent } from 'vue';
|
|
34
|
+
import { PropType, ref, computed, reactive, onBeforeUnmount, defineComponent, useSlots } from 'vue';
|
|
24
35
|
import { calculateMainZindex } from '../../helpers';
|
|
25
36
|
|
|
37
|
+
export type TooltipPosition =
|
|
38
|
+
| 'top-left'
|
|
39
|
+
| 'top-center'
|
|
40
|
+
| 'top-right'
|
|
41
|
+
| 'bottom-left'
|
|
42
|
+
| 'bottom-center'
|
|
43
|
+
| 'bottom-right';
|
|
44
|
+
|
|
26
45
|
export default defineComponent({
|
|
27
46
|
name: 'farm-tooltip',
|
|
28
47
|
props: {
|
|
29
|
-
|
|
30
|
-
*
|
|
48
|
+
/**
|
|
49
|
+
* Control visibility with v-model
|
|
31
50
|
*/
|
|
32
|
-
|
|
33
|
-
type:
|
|
34
|
-
|
|
35
|
-
| 'secondary'
|
|
36
|
-
| 'secondary-green'
|
|
37
|
-
| 'secondary-golden'
|
|
38
|
-
| 'neutral'
|
|
39
|
-
| 'info'
|
|
40
|
-
| 'success'
|
|
41
|
-
| 'error'
|
|
42
|
-
| 'warning'
|
|
43
|
-
| 'extra-1'
|
|
44
|
-
| 'extra-2'
|
|
45
|
-
| 'gray'
|
|
46
|
-
>,
|
|
47
|
-
default: 'gray',
|
|
51
|
+
value: {
|
|
52
|
+
type: Boolean,
|
|
53
|
+
default: undefined,
|
|
48
54
|
},
|
|
49
55
|
/**
|
|
50
|
-
*
|
|
51
|
-
* v-model bind
|
|
56
|
+
* Fluid width (grows based on content)
|
|
52
57
|
*/
|
|
53
|
-
|
|
58
|
+
fluid: {
|
|
54
59
|
type: Boolean,
|
|
60
|
+
default: false,
|
|
61
|
+
},
|
|
62
|
+
/**
|
|
63
|
+
* Position of the tooltip relative to the activator
|
|
64
|
+
*/
|
|
65
|
+
position: {
|
|
66
|
+
type: String as PropType<TooltipPosition>,
|
|
55
67
|
default: undefined,
|
|
68
|
+
validator: (value: string) => {
|
|
69
|
+
return [
|
|
70
|
+
'top-left',
|
|
71
|
+
'top-center',
|
|
72
|
+
'top-right',
|
|
73
|
+
'bottom-left',
|
|
74
|
+
'bottom-center',
|
|
75
|
+
'bottom-right',
|
|
76
|
+
].includes(value);
|
|
77
|
+
},
|
|
56
78
|
},
|
|
57
79
|
},
|
|
58
|
-
setup(props) {
|
|
80
|
+
setup(props, { emit }) {
|
|
59
81
|
const parent = ref(null);
|
|
60
82
|
const popup = ref(null);
|
|
61
83
|
const activator = ref(null);
|
|
@@ -65,40 +87,103 @@ export default defineComponent({
|
|
|
65
87
|
top: '0',
|
|
66
88
|
zIndex: 1,
|
|
67
89
|
});
|
|
90
|
+
const slots = useSlots();
|
|
68
91
|
|
|
69
92
|
const toggleComponent = computed(() => props.value);
|
|
70
93
|
const externalControl = computed(() => props.value !== undefined);
|
|
94
|
+
const hasPosition = computed(() => !!props.position);
|
|
95
|
+
const hasTitle = computed(() => !!slots.title);
|
|
71
96
|
|
|
72
97
|
let hasBeenBoostrapped = false;
|
|
73
98
|
|
|
99
|
+
const calculatePosition = () => {
|
|
100
|
+
const parentBoundingClientRect = parent.value.getBoundingClientRect();
|
|
101
|
+
const activatorBoundingClientRect = activator.value.getBoundingClientRect();
|
|
102
|
+
const popupBoundingClientRect = popup.value.getBoundingClientRect();
|
|
103
|
+
|
|
104
|
+
const activatorWidth = activatorBoundingClientRect.width;
|
|
105
|
+
const activatorHeight = activatorBoundingClientRect.height;
|
|
106
|
+
const popupWidth = popupBoundingClientRect.width;
|
|
107
|
+
const popupHeight = popupBoundingClientRect.height;
|
|
108
|
+
|
|
109
|
+
let left = 0;
|
|
110
|
+
let top = 0;
|
|
111
|
+
|
|
112
|
+
if (!props.position) {
|
|
113
|
+
left =
|
|
114
|
+
parentBoundingClientRect.left +
|
|
115
|
+
window.scrollX +
|
|
116
|
+
activatorWidth / 2 -
|
|
117
|
+
popupWidth / 2;
|
|
118
|
+
|
|
119
|
+
top = parentBoundingClientRect.top + window.scrollY - popupHeight - 8;
|
|
120
|
+
} else {
|
|
121
|
+
const [verticalPosition, horizontalAlignment] = props.position.split('-');
|
|
122
|
+
|
|
123
|
+
switch (horizontalAlignment) {
|
|
124
|
+
case 'left':
|
|
125
|
+
left = parentBoundingClientRect.left + window.scrollX - 8;
|
|
126
|
+
break;
|
|
127
|
+
case 'right':
|
|
128
|
+
left =
|
|
129
|
+
parentBoundingClientRect.left +
|
|
130
|
+
window.scrollX +
|
|
131
|
+
activatorWidth -
|
|
132
|
+
popupWidth +
|
|
133
|
+
8;
|
|
134
|
+
break;
|
|
135
|
+
case 'center':
|
|
136
|
+
default:
|
|
137
|
+
left =
|
|
138
|
+
parentBoundingClientRect.left +
|
|
139
|
+
window.scrollX +
|
|
140
|
+
activatorWidth / 2 -
|
|
141
|
+
popupWidth / 2;
|
|
142
|
+
break;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (verticalPosition === 'top') {
|
|
146
|
+
top = parentBoundingClientRect.top + window.scrollY - popupHeight - 8;
|
|
147
|
+
} else {
|
|
148
|
+
top = parentBoundingClientRect.top + window.scrollY + activatorHeight + 8;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
if (left < window.scrollX) {
|
|
153
|
+
left = window.scrollX + 5;
|
|
154
|
+
} else if (left + popupWidth > window.innerWidth + window.scrollX) {
|
|
155
|
+
left = window.innerWidth + window.scrollX - popupWidth - 5;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
return { left, top };
|
|
159
|
+
};
|
|
160
|
+
|
|
74
161
|
const onOver = () => {
|
|
75
162
|
showOver.value = true;
|
|
76
163
|
|
|
77
164
|
if (!hasBeenBoostrapped) {
|
|
78
165
|
document.querySelector('body').appendChild(popup.value);
|
|
79
|
-
const
|
|
80
|
-
const activatorBoundingClientRect = activator.value.getBoundingClientRect();
|
|
81
|
-
const popupBoundingClientRect = popup.value.getBoundingClientRect();
|
|
166
|
+
const { left, top } = calculatePosition();
|
|
82
167
|
|
|
83
|
-
styles.left =
|
|
84
|
-
|
|
85
|
-
window.scrollX -
|
|
86
|
-
(80 - activatorBoundingClientRect.width / 2) +
|
|
87
|
-
'px';
|
|
88
|
-
styles.top =
|
|
89
|
-
parentBoundingClientRect.top +
|
|
90
|
-
window.scrollY -
|
|
91
|
-
(popupBoundingClientRect.height + 8) +
|
|
92
|
-
'px';
|
|
168
|
+
styles.left = `${left}px`;
|
|
169
|
+
styles.top = `${top}px`;
|
|
93
170
|
styles.zIndex = calculateMainZindex();
|
|
94
171
|
|
|
95
172
|
hasBeenBoostrapped = true;
|
|
96
173
|
}
|
|
97
174
|
};
|
|
175
|
+
|
|
98
176
|
const onOut = (event: MouseEvent) => {
|
|
99
177
|
showOver.value = parent.value.contains(event.relatedTarget);
|
|
100
178
|
};
|
|
101
179
|
|
|
180
|
+
const onClose = () => {
|
|
181
|
+
showOver.value = false;
|
|
182
|
+
if (externalControl.value) {
|
|
183
|
+
emit('input', false);
|
|
184
|
+
}
|
|
185
|
+
};
|
|
186
|
+
|
|
102
187
|
onBeforeUnmount(() => {
|
|
103
188
|
if (hasBeenBoostrapped) {
|
|
104
189
|
document.querySelector('body').removeChild(popup.value);
|
|
@@ -112,9 +197,12 @@ export default defineComponent({
|
|
|
112
197
|
showOver,
|
|
113
198
|
toggleComponent,
|
|
114
199
|
externalControl,
|
|
200
|
+
hasPosition,
|
|
201
|
+
hasTitle,
|
|
115
202
|
styles,
|
|
116
203
|
onOver,
|
|
117
204
|
onOut,
|
|
205
|
+
onClose,
|
|
118
206
|
};
|
|
119
207
|
},
|
|
120
208
|
});
|