@eturnity/eturnity_reusable_components 7.51.13 → 7.51.15

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eturnity/eturnity_reusable_components",
3
- "version": "7.51.13",
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>
@@ -93,13 +93,14 @@
93
93
  </ComponentItem>
94
94
  <ArrowContainer class="arrow-container" :is-disabled="disabled">
95
95
  <ArrowWrapper :show-archived="showArchived">
96
- <InfoText
97
- v-if="showArchived"
98
- icon-color="red"
99
- :text="
100
- $gettext(`Component has been archived and shouldn't be used`)
101
- "
102
- />
96
+ <InfoWrapper v-if="showArchived">
97
+ <InfoText
98
+ icon-color="red"
99
+ :text="
100
+ $gettext(`Component has been archived and shouldn't be used`)
101
+ "
102
+ />
103
+ </InfoWrapper>
103
104
  <ArrowDown
104
105
  v-if="!isOpen"
105
106
  class="arrow-dropdown"
@@ -434,6 +435,13 @@
434
435
  align-items: center;
435
436
  `
436
437
 
438
+ const InfoWrapper = styled.div`
439
+ display: flex;
440
+ align-items: center;
441
+ justify-content: center;
442
+ padding-left: 8px;
443
+ `
444
+
437
445
  export default {
438
446
  name: 'TableDropdown',
439
447
  components: {
@@ -464,6 +472,7 @@
464
472
  NestedContainer,
465
473
  Icon,
466
474
  InfoText,
475
+ InfoWrapper,
467
476
  },
468
477
  props: {
469
478
  colSpan: {