@eturnity/eturnity_reusable_components 7.51.14 → 7.51.15

Sign up to get free protection for your applications and to get access to all the features.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "7.51.14",
3
+ "version": "7.51.15",
4
4
  "files": [
5
5
  "dist",
6
6
  "src"
@@ -17,7 +17,12 @@
17
17
  </div>
18
18
  <Teleport v-if="isVisible" to="body">
19
19
  <TextWrapper :style="wrapperStyle">
20
- <TextOverlay ref="infoBox" :image="image" :style="boxStyle">
20
+ <TextOverlay
21
+ ref="infoBox"
22
+ :image="image"
23
+ :style="boxStyle"
24
+ :width="infoBoxWidth"
25
+ >
21
26
  <OverlayImage
22
27
  v-if="image"
23
28
  ref="infoImage"
@@ -63,7 +68,7 @@
63
68
  word-wrap: break-word;
64
69
  overflow-wrap: break-word;
65
70
  white-space: normal;
66
- width: 100%; // Ensure the TextOverlay takes full width of its parent
71
+ width: ${(props) => (props.width ? `${props.width}px` : '100%')};
67
72
  box-shadow: ${(props) =>
68
73
  props.image ? '0 2px 10px rgba(0, 0, 0, 0.1)' : 'none'};
69
74
 
@@ -81,11 +86,9 @@
81
86
  position: absolute;
82
87
  width: 0;
83
88
  height: 0;
84
- border-left: 8px solid transparent;
85
- border-right: 8px solid transparent;
86
- border-top: 8px solid
87
- ${(props) =>
88
- props.image ? props.theme.colors.white : props.theme.colors.black};
89
+ border: 8px solid transparent;
90
+ border-top-color: ${(props) =>
91
+ props.image ? props.theme.colors.white : props.theme.colors.black};
89
92
  filter: ${(props) =>
90
93
  props.image ? 'drop-shadow(0 2px 2px rgba(0, 0, 0, 0.1))' : 'none'};
91
94
  `
@@ -184,57 +187,127 @@
184
187
  }))
185
188
 
186
189
  const calculatePosition = (width) => {
187
- if (!icon.value) return {}
190
+ if (!icon.value || !width) return {}
188
191
 
189
192
  const iconRect = icon.value.getBoundingClientRect()
190
193
  const windowHeight = window.innerHeight
191
194
  const windowWidth = window.innerWidth
192
195
 
193
- let top = iconRect.bottom + 10
194
- let left = iconRect.left
195
-
196
- // Adjust left based on the infoBoxWidth
197
- if (left + width > windowWidth) {
198
- left = windowWidth - width - 10
199
- }
200
-
201
- // Ensure there's enough space below or place above if not
202
- const isAbove = top + infoBoxHeight.value > windowHeight
203
- if (isAbove) {
204
- top = iconRect.top - infoBoxHeight.value - 10
205
- }
206
-
207
- // Calculate arrow position
208
- let arrowLeft = iconRect.left - left + iconRect.width / 2 - 8
209
-
210
- // Adjust arrow position if it's too close to the edges
211
- const edgeThreshold = 2 // pixels from the edge to start adjusting
212
- if (arrowLeft < edgeThreshold) {
213
- arrowLeft = edgeThreshold
214
- } else if (arrowLeft > width - 16 - edgeThreshold) {
215
- arrowLeft = width - 16 - edgeThreshold
196
+ // Calculate available space in all directions
197
+ const spaceBelow = windowHeight - iconRect.bottom - 10
198
+ const spaceAbove = iconRect.top - 10
199
+ const spaceRight = windowWidth - iconRect.right - 10
200
+ const spaceLeft = iconRect.left - 10
201
+
202
+ // Determine the best position based on available space
203
+ const positions = [
204
+ { position: 'bottom', space: spaceBelow },
205
+ { position: 'top', space: spaceAbove },
206
+ { position: 'right', space: spaceRight },
207
+ { position: 'left', space: spaceLeft },
208
+ ].sort((a, b) => b.space - a.space)
209
+
210
+ const bestPosition = positions[0].position
211
+
212
+ let top, left, arrowPosition
213
+
214
+ switch (bestPosition) {
215
+ case 'bottom':
216
+ top = Math.round(iconRect.bottom + 10)
217
+ left = Math.round(Math.min(iconRect.left, windowWidth - width - 10))
218
+ arrowPosition = {
219
+ left: `${Math.round(
220
+ Math.min(
221
+ Math.max(iconRect.left - left + iconRect.width / 2 - 8, 2),
222
+ width - 18
223
+ )
224
+ )}px`,
225
+ top: '-7px',
226
+ bottom: 'auto',
227
+ transform: 'rotate(180deg)',
228
+ }
229
+ break
230
+
231
+ case 'top':
232
+ top = Math.round(iconRect.top - infoBoxHeight.value - 10)
233
+ left = Math.round(Math.min(iconRect.left, windowWidth - width - 10))
234
+ arrowPosition = {
235
+ left: `${Math.round(
236
+ Math.min(
237
+ Math.max(iconRect.left - left + iconRect.width / 2 - 8, 2),
238
+ width - 18
239
+ )
240
+ )}px`,
241
+ top: 'auto',
242
+ bottom: '-7px',
243
+ transform: 'none',
244
+ }
245
+ break
246
+
247
+ case 'right':
248
+ top = Math.round(
249
+ Math.max(
250
+ Math.min(
251
+ iconRect.top - (infoBoxHeight.value - iconRect.height) / 2,
252
+ windowHeight - infoBoxHeight.value - 10
253
+ ),
254
+ 10
255
+ )
256
+ )
257
+ left = Math.round(iconRect.right + 10)
258
+ arrowPosition = {
259
+ left: '-7px',
260
+ top: `${Math.round(
261
+ Math.min(
262
+ Math.max(iconRect.top - top + iconRect.height / 2 - 8, 2),
263
+ infoBoxHeight.value - 18
264
+ )
265
+ )}px`,
266
+ bottom: 'auto',
267
+ transform: 'rotate(90deg)',
268
+ }
269
+ break
270
+
271
+ case 'left':
272
+ top = Math.round(
273
+ Math.max(
274
+ Math.min(
275
+ iconRect.top - (infoBoxHeight.value - iconRect.height) / 2,
276
+ windowHeight - infoBoxHeight.value - 10
277
+ ),
278
+ 10
279
+ )
280
+ )
281
+ left = Math.round(iconRect.left - width - 10)
282
+ arrowPosition = {
283
+ left: 'auto',
284
+ right: '-7px',
285
+ top: `${Math.round(
286
+ Math.min(
287
+ Math.max(iconRect.top - top + iconRect.height / 2 - 8, 2),
288
+ infoBoxHeight.value - 18
289
+ )
290
+ )}px`,
291
+ bottom: 'auto',
292
+ transform: 'rotate(-90deg)',
293
+ }
294
+ break
216
295
  }
217
296
 
218
- const arrowTop = isAbove ? 'auto' : '-7px'
219
- const arrowBottom = isAbove ? '-7px' : 'auto'
220
-
221
- arrowStyle.value = {
222
- left: `${arrowLeft}px`,
223
- top: arrowTop,
224
- bottom: arrowBottom,
225
- transform: isAbove ? 'none' : 'rotate(180deg)',
226
- }
297
+ // Set arrow styles
298
+ arrowStyle.value = arrowPosition
227
299
 
300
+ // Set wrapper styles
228
301
  wrapperStyle.value = {
229
302
  position: 'fixed',
230
303
  top: `${top}px`,
231
304
  left: `${left}px`,
232
305
  transform: 'none',
233
- width: `${width}px`, // Set a fixed width for the wrapper
306
+ width: `${width}px`,
234
307
  }
235
308
 
236
309
  return {
237
- width: '100%', // Always use 100% width for the TextOverlay
310
+ width: '100%',
238
311
  maxWidth: props.maxWidth,
239
312
  overflowY: 'auto',
240
313
  backgroundColor: props.image
@@ -245,12 +318,15 @@
245
318
 
246
319
  const showInfo = async () => {
247
320
  isVisible.value = true
321
+ // Wait for two render cycles to ensure content is stable
248
322
  await nextTick()
249
- updatePosition()
323
+ await nextTick()
324
+ await updatePosition()
250
325
  }
251
326
 
252
327
  const hideInfo = () => {
253
328
  isVisible.value = false
329
+ infoBoxWidth.value = 0 // Reset width when hiding
254
330
  }
255
331
 
256
332
  const toggleInfo = () => {
@@ -278,25 +354,55 @@
278
354
  }
279
355
 
280
356
  const updatePosition = async () => {
281
- if (infoBox.value && textContent.value) {
282
- await nextTick()
283
-
284
- if (isIconInView()) {
285
- const contentWidth = textContent.value.offsetWidth
286
- infoBoxWidth.value = Math.min(
287
- Math.max(contentWidth, 200), // Set a minimum width of 200px
288
- parseInt(props.maxWidth, 10)
289
- )
290
- infoBoxHeight.value = infoBox.value.$el.offsetHeight
291
- boxStyle.value = calculatePosition(infoBoxWidth.value)
357
+ console.log('updatePosition')
358
+ if (!infoBox.value || !textContent.value) return
292
359
 
293
- // Now make it visible if it should be
294
- if (isVisible.value) {
295
- infoBox.value.$el.style.visibility = 'visible'
296
- }
297
- } else if (isVisible.value) {
298
- hideInfo()
299
- }
360
+ // First make the content visible but hidden to get accurate measurements
361
+ if (infoBox.value.$el) {
362
+ infoBox.value.$el.style.visibility = 'hidden'
363
+ infoBox.value.$el.style.display = 'block'
364
+ }
365
+
366
+ await nextTick()
367
+
368
+ if (!isIconInView()) {
369
+ if (isVisible.value) hideInfo()
370
+ return
371
+ }
372
+
373
+ // Create a temporary clone to measure true width
374
+ const clone = textContent.value.cloneNode(true)
375
+ clone.style.position = 'absolute'
376
+ clone.style.visibility = 'hidden'
377
+ clone.style.width = 'auto'
378
+ clone.style.maxWidth = 'none'
379
+ clone.style.whiteSpace = 'nowrap' // Prevent text wrapping during measurement
380
+ document.body.appendChild(clone)
381
+
382
+ // Get fresh content width from clone
383
+ const contentWidth = clone.offsetWidth
384
+ document.body.removeChild(clone)
385
+
386
+ // Calculate new width
387
+ const calculatedWidth = Math.min(
388
+ Math.max(contentWidth, 200),
389
+ parseInt(props.maxWidth, 10)
390
+ )
391
+
392
+ // Set new dimensions
393
+ infoBoxWidth.value = calculatedWidth
394
+
395
+ // Wait for width to be applied
396
+ await nextTick()
397
+
398
+ infoBoxHeight.value = infoBox.value.$el.offsetHeight
399
+
400
+ // Calculate and apply position
401
+ boxStyle.value = calculatePosition(calculatedWidth)
402
+
403
+ // Make visible after position is set
404
+ if (isVisible.value && infoBox.value.$el) {
405
+ infoBox.value.$el.style.visibility = 'visible'
300
406
  }
301
407
  }
302
408
 
@@ -9,8 +9,7 @@
9
9
  <InfoText
10
10
  v-if="infoTextMessage"
11
11
  :align-arrow="infoTextAlign"
12
- border-color="#ccc"
13
- :size="fontSize ? fontSize : '16px'"
12
+ :size="fontSize ? fontSize : '14px'"
14
13
  :text="infoTextMessage"
15
14
  />
16
15
  </LabelWrapper>