pgo-ui 1.0.38 → 1.0.39

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": "pgo-ui",
3
- "version": "1.0.38",
3
+ "version": "1.0.39",
4
4
  "description": "A Vue 3 component library with PGO design system",
5
5
  "private": false,
6
6
  "type": "module",
@@ -48,7 +48,7 @@
48
48
 
49
49
  <!-- Iframe PDF viewer -->
50
50
  <iframe
51
- v-if="validatedSrc && open && !error"
51
+ v-if="src && open && !error"
52
52
  ref="iframeRef"
53
53
  :src="iframeSrc"
54
54
  class="w-full h-full border-0"
@@ -85,80 +85,19 @@ const props = defineProps({
85
85
 
86
86
  const emit = defineEmits(['update:modelValue', 'loaded', 'error', 'close'])
87
87
 
88
- const open = ref(props.modelValue)
89
- const iframeRef = ref(null)
90
- const loading = ref(true)
91
- const error = ref(null)
92
- const validatedSrc = ref('')
93
-
94
- const DOCUMENT_TYPES = [
95
- 'application/pdf',
96
- 'image/png', 'image/jpeg', 'image/gif', 'image/webp', 'image/svg+xml',
97
- 'text/plain',
98
- ]
88
+ const open = ref(props.modelValue)
89
+ const iframeRef = ref(null)
90
+ const loading = ref(true)
91
+ const error = ref(null)
99
92
 
100
93
  // Build iframe src — hide native toolbar so only our custom buttons are used
101
94
  const iframeSrc = computed(() => {
102
- if (!validatedSrc.value) return ''
95
+ if (!props.src) return ''
103
96
  const params = ['toolbar=0', 'navpanes=0']
104
97
  if (props.initialPage > 1) params.push(`page=${props.initialPage}`)
105
- return `${validatedSrc.value}#${params.join('&')}`
98
+ return `${props.src}#${params.join('&')}`
106
99
  })
107
100
 
108
- // ─── Validate source URL ──────────────────────────────────────────────────────
109
-
110
- function isValidUrl(str) {
111
- if (/^https?:\/\//i.test(str)) return true
112
- if (str.startsWith('/')) return true
113
- try { return Boolean(new URL(str)) } catch { return false }
114
- }
115
-
116
- async function validateSrc(url) {
117
- if (!url) {
118
- error.value = 'No document source provided'
119
- loading.value = false
120
- return
121
- }
122
-
123
- if (!isValidUrl(url)) {
124
- error.value = 'Invalid document URL'
125
- loading.value = false
126
- emit('error', error.value)
127
- return
128
- }
129
-
130
- loading.value = true
131
- error.value = null
132
- validatedSrc.value = ''
133
-
134
- try {
135
- const res = await fetch(url, { method: 'HEAD' })
136
-
137
- if (!res.ok) {
138
- error.value = res.status === 404
139
- ? 'Document not found'
140
- : `Failed to load document (${res.status})`
141
- loading.value = false
142
- emit('error', error.value)
143
- return
144
- }
145
-
146
- const contentType = (res.headers.get('content-type') || '').split(';')[0].trim().toLowerCase()
147
- if (contentType && !DOCUMENT_TYPES.some(t => contentType.startsWith(t))) {
148
- error.value = `Unsupported file type: ${contentType}`
149
- loading.value = false
150
- emit('error', error.value)
151
- return
152
- }
153
-
154
- validatedSrc.value = url
155
- } catch {
156
- error.value = 'Unable to reach the document. Please check the URL or your connection.'
157
- loading.value = false
158
- emit('error', error.value)
159
- }
160
- }
161
-
162
101
  // ─── Sync modelValue ──────────────────────────────────────────────────────────
163
102
 
164
103
  watch(() => props.modelValue, (val) => { open.value = val })
@@ -166,11 +105,11 @@ watch(() => props.modelValue, (val) => { open.value = val })
166
105
  watch(open, (val) => {
167
106
  emit('update:modelValue', val)
168
107
  if (val) {
169
- validateSrc(props.src)
108
+ loading.value = true
109
+ error.value = null
170
110
  } else {
171
- loading.value = false
172
- error.value = null
173
- validatedSrc.value = ''
111
+ loading.value = false
112
+ error.value = null
174
113
  }
175
114
  })
176
115
 
@@ -222,8 +161,9 @@ function printPdf() {
222
161
  }
223
162
  }
224
163
 
225
- watch(() => props.src, (url) => {
226
- if (open.value) validateSrc(url)
164
+ watch(() => props.src, () => {
165
+ loading.value = true
166
+ error.value = null
227
167
  })
228
168
 
229
169
  defineExpose({ printPdf, downloadPdf })
@@ -16,10 +16,10 @@
16
16
 
17
17
  <Teleport to="body">
18
18
  <div
19
- v-show="isOpen"
19
+ v-show="isOpen && hasPositioned"
20
20
  :id="tooltipId"
21
21
  ref="tooltipRef"
22
- class="vts-position-absolute vts-bg-surface-elevated vts-text vts-border vts-rounded-sm vts-elevation-2 vts-pt-2 vts-pb-2 vts-pl-3 vts-pr-3 vts-max-w-280"
22
+ class="vts-bg-surface-elevated vts-text vts-border vts-rounded-sm vts-elevation-2 vts-pt-2 vts-pb-2 vts-pl-3 vts-pr-3 vts-max-w-280 tooltip-container"
23
23
  role="tooltip"
24
24
  :class="[placementClass]"
25
25
  :style="tooltipStyles"
@@ -109,25 +109,23 @@
109
109
  const activator = activatorRef.value
110
110
  const tooltip = tooltipRef.value
111
111
  if (!activator || !tooltip) return
112
- // Ensure the tooltip can be measured on first render
112
+
113
+ // Measure tooltip off-screen first
113
114
  if (!hasPositioned.value) {
114
115
  tooltipStyles.value = {
115
- position: 'absolute',
116
+ position: 'fixed',
116
117
  top: '-9999px',
117
118
  left: '-9999px',
118
119
  visibility: 'hidden',
119
- zIndex: 'var(--vts-z-tooltip, 1000)'
120
+ zIndex: 'var(--vts-z-tooltip, 1000)',
121
+ pointerEvents: 'none'
120
122
  }
121
- // Force a reflow so getBoundingClientRect has correct size
122
123
  void tooltip.offsetHeight
123
124
  }
124
125
 
125
126
  const rect = activator.getBoundingClientRect()
126
127
  const tooltipRect = tooltip.getBoundingClientRect()
127
128
 
128
- const scrollX = window.scrollX || window.pageXOffset
129
- const scrollY = window.scrollY || window.pageYOffset
130
-
131
129
  let top = 0
132
130
  let left = 0
133
131
 
@@ -135,50 +133,71 @@
135
133
  const offsetY = props.offset?.y ?? 0
136
134
  const gap = props.arrow ? 8 : 0
137
135
 
136
+ // Position relative to viewport (fixed positioning)
138
137
  switch (normalizedPlacement.value) {
139
138
  case 'top':
140
- top = rect.top + scrollY - tooltipRect.height - gap - offsetY
141
- left = rect.left + scrollX + rect.width / 2 - tooltipRect.width / 2 + offsetX
139
+ top = rect.top - tooltipRect.height - gap - offsetY
140
+ left = rect.left + rect.width / 2 - tooltipRect.width / 2 + offsetX
142
141
  break
143
142
  case 'bottom':
144
- top = rect.bottom + scrollY + gap + offsetY
145
- left = rect.left + scrollX + rect.width / 2 - tooltipRect.width / 2 + offsetX
143
+ top = rect.bottom + gap + offsetY
144
+ left = rect.left + rect.width / 2 - tooltipRect.width / 2 + offsetX
146
145
  break
147
146
  case 'left':
148
- top = rect.top + scrollY + rect.height / 2 - tooltipRect.height / 2 + offsetY
149
- left = rect.left + scrollX - tooltipRect.width - gap - offsetX
147
+ top = rect.top + rect.height / 2 - tooltipRect.height / 2 + offsetY
148
+ left = rect.left - tooltipRect.width - gap - offsetX
150
149
  break
151
150
  case 'right':
152
- top = rect.top + scrollY + rect.height / 2 - tooltipRect.height / 2 + offsetY
153
- left = rect.right + scrollX + gap + offsetX
151
+ top = rect.top + rect.height / 2 - tooltipRect.height / 2 + offsetY
152
+ left = rect.right + gap + offsetX
154
153
  break
155
154
  }
156
155
 
156
+ // Clamp to viewport so the tooltip never causes scrollbars
157
+ const viewW = document.documentElement.clientWidth
158
+ const viewH = document.documentElement.clientHeight
159
+ const pad = 8
160
+
161
+ left = Math.max(pad, Math.min(left, viewW - tooltipRect.width - pad))
162
+ top = Math.max(pad, Math.min(top, viewH - tooltipRect.height - pad))
163
+
157
164
  tooltipStyles.value = {
158
- position: 'absolute',
165
+ position: 'fixed',
159
166
  top: `${top}px`,
160
167
  left: `${left}px`,
161
168
  zIndex: 'var(--vts-z-tooltip, 1000)',
162
- visibility: ''
169
+ visibility: '',
170
+ pointerEvents: 'auto'
163
171
  }
164
172
 
165
- // Arrow positioning
173
+ // Arrow positioning — offset arrow to point at the activator center
166
174
  if (props.arrow) {
167
175
  const size = 8
168
176
  const common = { width: `${size}px`, height: `${size}px` }
177
+ const actCenterX = rect.left + rect.width / 2
178
+ const actCenterY = rect.top + rect.height / 2
179
+ const arrowMinEdge = 12
169
180
  switch (normalizedPlacement.value) {
170
- case 'top':
171
- arrowStyles.value = { ...common, bottom: `-4px`, left: '50%', transform: 'translateX(-50%) rotate(45deg)' }
181
+ case 'top': {
182
+ const ax = Math.max(arrowMinEdge, Math.min(actCenterX - left, tooltipRect.width - arrowMinEdge))
183
+ arrowStyles.value = { ...common, bottom: `-4px`, left: `${ax}px`, transform: 'translateX(-50%) rotate(45deg)' }
172
184
  break
173
- case 'bottom':
174
- arrowStyles.value = { ...common, top: `-4px`, left: '50%', transform: 'translateX(-50%) rotate(45deg)' }
185
+ }
186
+ case 'bottom': {
187
+ const ax = Math.max(arrowMinEdge, Math.min(actCenterX - left, tooltipRect.width - arrowMinEdge))
188
+ arrowStyles.value = { ...common, top: `-4px`, left: `${ax}px`, transform: 'translateX(-50%) rotate(45deg)' }
175
189
  break
176
- case 'left':
177
- arrowStyles.value = { ...common, right: `-4px`, top: '50%', transform: 'translateY(-50%) rotate(45deg)' }
190
+ }
191
+ case 'left': {
192
+ const ay = Math.max(arrowMinEdge, Math.min(actCenterY - top, tooltipRect.height - arrowMinEdge))
193
+ arrowStyles.value = { ...common, right: `-4px`, top: `${ay}px`, transform: 'translateY(-50%) rotate(45deg)' }
178
194
  break
179
- case 'right':
180
- arrowStyles.value = { ...common, left: `-4px`, top: '50%', transform: 'translateY(-50%) rotate(45deg)' }
195
+ }
196
+ case 'right': {
197
+ const ay = Math.max(arrowMinEdge, Math.min(actCenterY - top, tooltipRect.height - arrowMinEdge))
198
+ arrowStyles.value = { ...common, left: `-4px`, top: `${ay}px`, transform: 'translateY(-50%) rotate(45deg)' }
181
199
  break
200
+ }
182
201
  }
183
202
  }
184
203
 
@@ -278,4 +297,9 @@
278
297
  </script>
279
298
 
280
299
  <style scoped>
300
+ .tooltip-container {
301
+ position: fixed;
302
+ pointer-events: none;
303
+ max-width: calc(100vw - 16px);
304
+ }
281
305
  </style>
@@ -0,0 +1,281 @@
1
+ <template>
2
+ <div
3
+ ref="activatorRef"
4
+ class="vts-d-inline-block"
5
+ @mouseenter="onMouseEnter"
6
+ @mouseleave="onMouseLeave"
7
+ @focusin="onFocusIn"
8
+ @focusout="onFocusOut"
9
+ @click="onClick"
10
+ :aria-describedby="tooltipId"
11
+ :aria-expanded="isOpen"
12
+ :aria-disabled="disabled ? 'true' : 'false'"
13
+ >
14
+ <slot name="activator" :props="activatorSlotProps"></slot>
15
+ </div>
16
+
17
+ <Teleport to="body">
18
+ <div
19
+ v-show="isOpen"
20
+ :id="tooltipId"
21
+ ref="tooltipRef"
22
+ class="vts-position-absolute vts-bg-surface-elevated vts-text vts-border vts-rounded-sm vts-elevation-2 vts-pt-2 vts-pb-2 vts-pl-3 vts-pr-3 vts-max-w-280"
23
+ role="tooltip"
24
+ :class="[placementClass]"
25
+ :style="tooltipStyles"
26
+ @keydown.esc.stop.prevent="close"
27
+ >
28
+ <div v-if="arrow" class="vts-position-absolute vts-bg-surface-elevated vts-border-t vts-border-s vts-border-color" :class="[placementClass]" :style="arrowStyles"></div>
29
+ <div class="vts-text-body-2">
30
+ <slot />
31
+ </div>
32
+ </div>
33
+ </Teleport>
34
+ </template>
35
+
36
+ <script setup lang="ts">
37
+ import { ref, computed, watch, onMounted, onBeforeUnmount, nextTick } from 'vue'
38
+ import { globalRtl } from '../../pgo-components/lib/core/rtl/rtl'
39
+
40
+ // Props
41
+ interface Offset {
42
+ x?: number
43
+ y?: number
44
+ }
45
+
46
+ type Trigger = 'hover' | 'focus' | 'click' | 'manual'
47
+
48
+ type PlacementBase = 'top' | 'bottom' | 'left' | 'right'
49
+
50
+
51
+ const props = defineProps({
52
+ modelValue: { type: Boolean, default: undefined }, // controlled mode
53
+ openOnHover: { type: Boolean, default: true },
54
+ openOnFocus: { type: Boolean, default: true },
55
+ openOnClick: { type: Boolean, default: false },
56
+ disabled: { type: Boolean, default: false },
57
+ placement: { type: String as () => PlacementBase, default: 'top' },
58
+ offset: { type: Object as () => Offset, default: () => ({ x: 0, y: 0 }) },
59
+ arrow: { type: Boolean, default: true },
60
+ showDelay: { type: Number, default: 80 },
61
+ hideDelay: { type: Number, default: 80 },
62
+ teleport: { type: String, default: 'body' }
63
+ })
64
+
65
+ const emit = defineEmits(['update:modelValue', 'open', 'close'])
66
+
67
+ // State
68
+ const isControlled = computed(() => props.modelValue !== undefined)
69
+ const internalOpen = ref(false)
70
+ const isOpen = computed({
71
+ get: () => (isControlled.value ? !!props.modelValue : internalOpen.value),
72
+ set: (val: boolean) => {
73
+ if (props.disabled) return
74
+ if (isControlled.value) emit('update:modelValue', val)
75
+ else internalOpen.value = val
76
+ }
77
+ })
78
+
79
+ // Elements
80
+ const activatorRef = ref<HTMLElement | null>(null)
81
+ const tooltipRef = ref<HTMLElement | null>(null)
82
+
83
+ // IDs
84
+ const tooltipId = `tooltip-${Math.random().toString(36).slice(2, 10)}`
85
+
86
+ // RTL
87
+ const isRtl = computed(() => globalRtl.value)
88
+
89
+ // Placement with RTL adjustment for left/right
90
+ const normalizedPlacement = computed<PlacementBase>(() => {
91
+ if (!isRtl.value) return props.placement
92
+ if (props.placement === 'left') return 'right'
93
+ if (props.placement === 'right') return 'left'
94
+ return props.placement
95
+ })
96
+
97
+ const placementClass = computed(() => `placement-${normalizedPlacement.value}`)
98
+
99
+ // Positioning
100
+ const tooltipStyles = ref<Record<string, string>>({})
101
+ const arrowStyles = ref<Record<string, string>>({})
102
+ const hasPositioned = ref(false)
103
+
104
+ // Track how tooltip was opened to coordinate closing behavior
105
+ type TriggerSource = 'hover' | 'focus' | 'click' | 'manual' | null
106
+ const lastTrigger = ref<TriggerSource>(null)
107
+
108
+ function computePosition() {
109
+ const activator = activatorRef.value
110
+ const tooltip = tooltipRef.value
111
+ if (!activator || !tooltip) return
112
+ // Ensure the tooltip can be measured on first render
113
+ if (!hasPositioned.value) {
114
+ tooltipStyles.value = {
115
+ position: 'absolute',
116
+ top: '-9999px',
117
+ left: '-9999px',
118
+ visibility: 'hidden',
119
+ zIndex: 'var(--vts-z-tooltip, 1000)'
120
+ }
121
+ // Force a reflow so getBoundingClientRect has correct size
122
+ void tooltip.offsetHeight
123
+ }
124
+
125
+ const rect = activator.getBoundingClientRect()
126
+ const tooltipRect = tooltip.getBoundingClientRect()
127
+
128
+ const scrollX = window.scrollX || window.pageXOffset
129
+ const scrollY = window.scrollY || window.pageYOffset
130
+
131
+ let top = 0
132
+ let left = 0
133
+
134
+ const offsetX = props.offset?.x ?? 0
135
+ const offsetY = props.offset?.y ?? 0
136
+ const gap = props.arrow ? 8 : 0
137
+
138
+ switch (normalizedPlacement.value) {
139
+ case 'top':
140
+ top = rect.top + scrollY - tooltipRect.height - gap - offsetY
141
+ left = rect.left + scrollX + rect.width / 2 - tooltipRect.width / 2 + offsetX
142
+ break
143
+ case 'bottom':
144
+ top = rect.bottom + scrollY + gap + offsetY
145
+ left = rect.left + scrollX + rect.width / 2 - tooltipRect.width / 2 + offsetX
146
+ break
147
+ case 'left':
148
+ top = rect.top + scrollY + rect.height / 2 - tooltipRect.height / 2 + offsetY
149
+ left = rect.left + scrollX - tooltipRect.width - gap - offsetX
150
+ break
151
+ case 'right':
152
+ top = rect.top + scrollY + rect.height / 2 - tooltipRect.height / 2 + offsetY
153
+ left = rect.right + scrollX + gap + offsetX
154
+ break
155
+ }
156
+
157
+ tooltipStyles.value = {
158
+ position: 'absolute',
159
+ top: `${top}px`,
160
+ left: `${left}px`,
161
+ zIndex: 'var(--vts-z-tooltip, 1000)',
162
+ visibility: ''
163
+ }
164
+
165
+ // Arrow positioning
166
+ if (props.arrow) {
167
+ const size = 8
168
+ const common = { width: `${size}px`, height: `${size}px` }
169
+ switch (normalizedPlacement.value) {
170
+ case 'top':
171
+ arrowStyles.value = { ...common, bottom: `-4px`, left: '50%', transform: 'translateX(-50%) rotate(45deg)' }
172
+ break
173
+ case 'bottom':
174
+ arrowStyles.value = { ...common, top: `-4px`, left: '50%', transform: 'translateX(-50%) rotate(45deg)' }
175
+ break
176
+ case 'left':
177
+ arrowStyles.value = { ...common, right: `-4px`, top: '50%', transform: 'translateY(-50%) rotate(45deg)' }
178
+ break
179
+ case 'right':
180
+ arrowStyles.value = { ...common, left: `-4px`, top: '50%', transform: 'translateY(-50%) rotate(45deg)' }
181
+ break
182
+ }
183
+ }
184
+
185
+ hasPositioned.value = true
186
+ }
187
+
188
+ // Open/close with delays
189
+ let showTimer: number | null = null
190
+ let hideTimer: number | null = null
191
+
192
+ function clearTimers() {
193
+ if (showTimer) {
194
+ window.clearTimeout(showTimer)
195
+ showTimer = null
196
+ }
197
+ if (hideTimer) {
198
+ window.clearTimeout(hideTimer)
199
+ hideTimer = null
200
+ }
201
+ }
202
+
203
+ function open(source: TriggerSource = null) {
204
+ if (props.disabled) return
205
+ clearTimers()
206
+ showTimer = window.setTimeout(async () => {
207
+ lastTrigger.value = source
208
+ isOpen.value = true
209
+ await nextTick()
210
+ computePosition()
211
+ emit('open')
212
+ }, props.showDelay)
213
+ }
214
+
215
+ function close() {
216
+ clearTimers()
217
+ hideTimer = window.setTimeout(() => {
218
+ isOpen.value = false
219
+ lastTrigger.value = null
220
+ hasPositioned.value = false
221
+ emit('close')
222
+ }, props.hideDelay)
223
+ }
224
+
225
+ // Triggers
226
+ const activatorSlotProps = computed(() => ({
227
+ open: (src?: TriggerSource) => open(src ?? 'manual'),
228
+ close,
229
+ isOpen: isOpen.value
230
+ }))
231
+
232
+ function onMouseEnter() {
233
+ if (props.openOnHover) open('hover')
234
+ }
235
+ function onMouseLeave() {
236
+ if (props.openOnHover) close()
237
+ }
238
+ function onFocusIn() {
239
+ if (props.openOnFocus) open('focus')
240
+ }
241
+ function onFocusOut() {
242
+ // Avoid immediate close on click-first interaction when openOnClick is enabled
243
+ if (props.openOnFocus && lastTrigger.value === 'focus') close()
244
+ }
245
+ function onClick() {
246
+ if (!props.openOnClick) return
247
+ if (isOpen.value) close()
248
+ else open('click')
249
+ }
250
+
251
+ // Outside click & escape
252
+ function onDocumentClick(e: MouseEvent) {
253
+ if (!isOpen.value) return
254
+ const target = e.target as Node
255
+ if (tooltipRef.value && tooltipRef.value.contains(target)) return
256
+ if (activatorRef.value && activatorRef.value.contains(target)) return
257
+ close()
258
+ }
259
+
260
+ function onDocumentKeydown(e: KeyboardEvent) {
261
+ if (e.key === 'Escape') close()
262
+ }
263
+
264
+ onMounted(() => {
265
+ computePosition()
266
+ document.addEventListener('click', onDocumentClick, { passive: true })
267
+ document.addEventListener('keydown', onDocumentKeydown)
268
+ })
269
+
270
+ onBeforeUnmount(() => {
271
+ document.removeEventListener('click', onDocumentClick)
272
+ document.removeEventListener('keydown', onDocumentKeydown)
273
+ })
274
+
275
+ watch(isOpen, val => {
276
+ if (val) nextTick(computePosition)
277
+ })
278
+ </script>
279
+
280
+ <style scoped>
281
+ </style>
@@ -20,6 +20,7 @@
20
20
  type="hidden"
21
21
  />
22
22
  <!-- Render grouped fields -->
23
+
23
24
  <!-- -->
24
25
  <template v-if="form.groups">
25
26
  <template v-for="(group, id) in form.groups" :key="id">
@@ -123,7 +124,7 @@
123
124
  import { ref, computed, watch, defineAsyncComponent, inject, reactive, onMounted, nextTick } from 'vue'
124
125
  import Form from './Form.vue';
125
126
  import Modal from '../Modal.vue'
126
- import { Banner } from '../index'
127
+ import { Banner, LabelField } from '../index'
127
128
  import { gridColsMap, columnSpansMap, useLanguageSelected, initializeFunctions } from '@/pgo-components/lib/componentConfig';
128
129
 
129
130
  const rules = inject('validationRules')
@@ -522,6 +523,10 @@
522
523
  map['file'] = defineAsyncComponent(() => import('../inputs/FileUpload.vue'))
523
524
  map['filefield'] = defineAsyncComponent(() => import('../inputs/FileUpload.vue'))
524
525
  }
526
+ if (usedTypes.has('label') || usedTypes.has('labelfield')) {
527
+ map['label'] = defineAsyncComponent(() => import('../inputs/LabelField.vue'))
528
+ map['labelfield'] = defineAsyncComponent(() => import('../inputs/LabelField.vue'))
529
+ }
525
530
 
526
531
  return map
527
532
  })
@@ -22,6 +22,7 @@ import FileUpload from './inputs/FileUpload.vue'
22
22
  import FilterSection from './filters/FilterSection.vue'
23
23
  import Footer from './Footer.vue'
24
24
  import Form from './forms/Form.vue'
25
+ import LabelField from './inputs/LabelField.vue'
25
26
  import LayoutContainer from './LayoutContainer.vue'
26
27
  import Main from './Main.vue'
27
28
  import Modal from './Modal.vue'
@@ -70,6 +71,7 @@ export { Button, Card, HeroIcon,
70
71
  FilterSection,
71
72
  Footer,
72
73
  Form,
74
+ LabelField,
73
75
  LayoutContainer,
74
76
  Main,
75
77
  Modal,
@@ -2,10 +2,10 @@
2
2
  <div :class="['flex items-start gap-2', width, margin]">
3
3
  <!-- Label -->
4
4
  <span
5
- v-if="computedLabel"
5
+ v-if="label"
6
6
  :class="['text-sm font-medium shrink-0', labelClass]"
7
7
  >
8
- {{ computedLabel }}:
8
+ {{ useLanguageSelected(label, computedLang) }}:
9
9
  </span>
10
10
 
11
11
  <!-- Value -->
@@ -21,8 +21,8 @@ import { useLanguageSelected } from '../../../pgo-components/lib/componentConfig
21
21
 
22
22
  const props = defineProps({
23
23
  label: { type: [String, Object], default: '' },
24
- labelEn: { type: String, default: '' },
25
- labelDv: { type: String, default: '' },
24
+ // labelEn: { type: String, default: '' },
25
+ // labelDv: { type: String, default: '' },
26
26
  value: { type: [String, Number, Boolean, Object, Array], default: '' },
27
27
  placeholder: { type: String, default: '-' },
28
28
  width: { type: String, default: 'w-full' },
@@ -35,14 +35,15 @@ const props = defineProps({
35
35
 
36
36
  const cardDir = inject('parentDir', '')
37
37
  const cardLang = inject('parentLang', '')
38
+ const { language } = inject('i18n')
38
39
 
39
- const computedLang = computed(() => props.lang || cardLang)
40
+ const computedLang = computed(() => props.lang || cardLang || language.value || 'dv')
40
41
 
41
42
  const { selectedLabel } = useLanguageSelected(
42
43
  computed(() => ({
43
44
  label: props.label,
44
- labelEn: props.labelEn,
45
- labelDv: props.labelDv,
45
+ // labelEn: props.labelEn,
46
+ // labelDv: props.labelDv,
46
47
  })),
47
48
  computedLang
48
49
  )