@farm-investimentos/front-mfe-components 15.10.1 → 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.
@@ -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
- <slot />
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
- * Tooltip color
48
+ /**
49
+ * Control visibility with v-model
31
50
  */
32
- color: {
33
- type: String as PropType<
34
- | 'primary'
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
- * Control visibility
51
- * v-model bind
56
+ * Fluid width (grows based on content)
52
57
  */
53
- value: {
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 parentBoundingClientRect = parent.value.getBoundingClientRect();
80
- const activatorBoundingClientRect = activator.value.getBoundingClientRect();
81
- const popupBoundingClientRect = popup.value.getBoundingClientRect();
166
+ const { left, top } = calculatePosition();
82
167
 
83
- styles.left =
84
- parentBoundingClientRect.left +
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
  });