@imaginario27/air-ui-ds 1.1.2 → 1.1.4
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/components/alerts/Alert.vue +1 -1
- package/components/buttons/CopyButton.vue +1 -1
- package/components/dropdowns/DropdownMenu.vue +262 -65
- package/components/dropdowns/DropdownSelect.vue +3 -2
- package/components/dropdowns/DropdownSelectItem.vue +1 -1
- package/components/empty-states/EmptyState.vue +3 -3
- package/components/icons/Icon.vue +36 -12
- package/components/lists/List.vue +2 -2
- package/components/lists/ListItem.vue +10 -10
- package/components/rating/RatingItem.vue +3 -3
- package/package.json +1 -1
|
@@ -138,7 +138,7 @@ const iconColorClass = computed(() => {
|
|
|
138
138
|
[AlertType.WARNING]: '!text-icon-warning-on-bg',
|
|
139
139
|
[AlertType.DANGER]: '!text-icon-danger',
|
|
140
140
|
[AlertType.SUCCESS]: '!text-icon-success',
|
|
141
|
-
[AlertType.INFO]: 'text-icon-info',
|
|
141
|
+
[AlertType.INFO]: '!text-icon-info',
|
|
142
142
|
}
|
|
143
143
|
return variant[props.type as AlertType] || '!text-icon-warning-on-bg'
|
|
144
144
|
})
|
|
@@ -114,7 +114,7 @@ const handleCopy = useThrottleFn(
|
|
|
114
114
|
const success = await copyToClipboard(props.textToCopy)
|
|
115
115
|
|
|
116
116
|
if (success) {
|
|
117
|
-
currentCopyButtonIcon.value = 'mdi:check
|
|
117
|
+
currentCopyButtonIcon.value = 'mdi:check'
|
|
118
118
|
currentCopyButtonText.value = props.copySuccessText
|
|
119
119
|
|
|
120
120
|
if (
|
|
@@ -1,67 +1,131 @@
|
|
|
1
|
+
|
|
1
2
|
<template>
|
|
2
|
-
<div
|
|
3
|
-
ref="dropdownContainer"
|
|
3
|
+
<div
|
|
4
|
+
ref="dropdownContainer"
|
|
4
5
|
data-test="dropdown-container"
|
|
5
6
|
:class="[isRelative && 'relative']"
|
|
6
7
|
>
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
'py-1',
|
|
13
|
-
'rounded',
|
|
14
|
-
hasShadow && 'shadow-lg',
|
|
15
|
-
'w-full',
|
|
16
|
-
'flex flex-col',
|
|
17
|
-
'z-50',
|
|
18
|
-
hasBorder && 'border border-border-default',
|
|
19
|
-
positionClass ? positionClass : dropdownPositionClass,
|
|
20
|
-
dropdownClass,
|
|
21
|
-
]"
|
|
22
|
-
:style="!positionClass && positionOffsetStyle"
|
|
8
|
+
<!-- Activator Wrapper -->
|
|
9
|
+
<div
|
|
10
|
+
ref="activatorWrapper"
|
|
11
|
+
class="dropdown-activator"
|
|
12
|
+
@click="onActivatorClick"
|
|
23
13
|
>
|
|
24
|
-
<slot
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
:onClose="toggle"
|
|
14
|
+
<slot
|
|
15
|
+
name="activator"
|
|
16
|
+
:isOpen="isOpen"
|
|
28
17
|
/>
|
|
29
|
-
<template v-else-if="items?.length && !$slots['items']">
|
|
30
|
-
<DropdownMenuItem
|
|
31
|
-
v-for="(item, index) in items" :key="index"
|
|
32
|
-
:actionType="item.actionType"
|
|
33
|
-
:text="item.text"
|
|
34
|
-
:icon="item.icon"
|
|
35
|
-
:size="item.size"
|
|
36
|
-
:type="item.type"
|
|
37
|
-
:userDisplayName="item.userDisplayName"
|
|
38
|
-
:userProfileImg="item.userProfileImg"
|
|
39
|
-
:imgUrl="item.imgUrl"
|
|
40
|
-
:alt="item.alt"
|
|
41
|
-
:helpText="item.helpText"
|
|
42
|
-
:to="item.to"
|
|
43
|
-
:isExternal="item.isExternal"
|
|
44
|
-
:exportData="item.exportData"
|
|
45
|
-
:exportFields="item.exportFields"
|
|
46
|
-
:exportType="item.exportType"
|
|
47
|
-
:exportFileName="item.exportFileName"
|
|
48
|
-
:hasSeparator="item.hasSeparator"
|
|
49
|
-
@click="handleClick(item.callback)"
|
|
50
|
-
/>
|
|
51
|
-
</template>
|
|
52
18
|
</div>
|
|
53
|
-
|
|
54
|
-
<
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
19
|
+
|
|
20
|
+
<template v-if="shouldTeleport">
|
|
21
|
+
<!-- Teleported Dropdown Menu -->
|
|
22
|
+
<teleport to="body">
|
|
23
|
+
<div
|
|
24
|
+
v-if="isOpen"
|
|
25
|
+
ref="dropdown"
|
|
26
|
+
v-bind="$attrs"
|
|
27
|
+
:class="[
|
|
28
|
+
'bg-background-surface',
|
|
29
|
+
'py-1',
|
|
30
|
+
'rounded',
|
|
31
|
+
hasShadow && 'shadow-lg',
|
|
32
|
+
'flex flex-col',
|
|
33
|
+
'z-50',
|
|
34
|
+
hasBorder && 'border border-border-default',
|
|
35
|
+
dropdownClass,
|
|
36
|
+
]"
|
|
37
|
+
:style="computedTeleportStyle"
|
|
38
|
+
>
|
|
39
|
+
<slot
|
|
40
|
+
v-if="$slots.items"
|
|
41
|
+
name="items"
|
|
42
|
+
:onClose="close"
|
|
43
|
+
/>
|
|
44
|
+
<template v-else-if="items?.length">
|
|
45
|
+
<DropdownMenuItem
|
|
46
|
+
v-for="(item, index) in items"
|
|
47
|
+
:key="index"
|
|
48
|
+
:actionType="item.actionType"
|
|
49
|
+
:text="item.text"
|
|
50
|
+
:icon="item.icon"
|
|
51
|
+
:size="item.size"
|
|
52
|
+
:type="item.type"
|
|
53
|
+
:userDisplayName="item.userDisplayName"
|
|
54
|
+
:userProfileImg="item.userProfileImg"
|
|
55
|
+
:imgUrl="item.imgUrl"
|
|
56
|
+
:alt="item.alt"
|
|
57
|
+
:helpText="item.helpText"
|
|
58
|
+
:to="item.to"
|
|
59
|
+
:isExternal="item.isExternal"
|
|
60
|
+
:exportData="item.exportData"
|
|
61
|
+
:exportFields="item.exportFields"
|
|
62
|
+
:exportType="item.exportType"
|
|
63
|
+
:exportFileName="item.exportFileName"
|
|
64
|
+
:hasSeparator="item.hasSeparator"
|
|
65
|
+
@click="handleClick(item.callback)"
|
|
66
|
+
/>
|
|
67
|
+
</template>
|
|
68
|
+
</div>
|
|
69
|
+
</teleport>
|
|
70
|
+
</template>
|
|
71
|
+
<template v-else>
|
|
72
|
+
<div
|
|
73
|
+
v-if="isOpen"
|
|
74
|
+
ref="dropdown"
|
|
75
|
+
v-bind="$attrs"
|
|
76
|
+
:class="[
|
|
77
|
+
'bg-background-surface',
|
|
78
|
+
'py-1',
|
|
79
|
+
'rounded',
|
|
80
|
+
hasShadow && 'shadow-lg',
|
|
81
|
+
'w-full',
|
|
82
|
+
'flex flex-col',
|
|
83
|
+
'z-50',
|
|
84
|
+
hasBorder && 'border border-border-default',
|
|
85
|
+
positionClass ? positionClass : dropdownPositionClass,
|
|
86
|
+
dropdownClass,
|
|
87
|
+
]"
|
|
88
|
+
:style="!positionClass && positionOffsetStyle"
|
|
89
|
+
>
|
|
90
|
+
<slot
|
|
91
|
+
v-if="$slots['items']"
|
|
92
|
+
name="items"
|
|
93
|
+
:onClose="toggle"
|
|
94
|
+
/>
|
|
95
|
+
<template v-else-if="items?.length && !$slots['items']">
|
|
96
|
+
<DropdownMenuItem
|
|
97
|
+
v-for="(item, index) in items" :key="index"
|
|
98
|
+
:actionType="item.actionType"
|
|
99
|
+
:text="item.text"
|
|
100
|
+
:icon="item.icon"
|
|
101
|
+
:size="item.size"
|
|
102
|
+
:type="item.type"
|
|
103
|
+
:userDisplayName="item.userDisplayName"
|
|
104
|
+
:userProfileImg="item.userProfileImg"
|
|
105
|
+
:imgUrl="item.imgUrl"
|
|
106
|
+
:alt="item.alt"
|
|
107
|
+
:helpText="item.helpText"
|
|
108
|
+
:to="item.to"
|
|
109
|
+
:isExternal="item.isExternal"
|
|
110
|
+
:exportData="item.exportData"
|
|
111
|
+
:exportFields="item.exportFields"
|
|
112
|
+
:exportType="item.exportType"
|
|
113
|
+
:exportFileName="item.exportFileName"
|
|
114
|
+
:hasSeparator="item.hasSeparator"
|
|
115
|
+
@click="handleClick(item.callback)"
|
|
116
|
+
/>
|
|
117
|
+
</template>
|
|
118
|
+
</div>
|
|
119
|
+
</template>
|
|
59
120
|
</div>
|
|
60
121
|
</template>
|
|
122
|
+
|
|
61
123
|
<script setup lang="ts">
|
|
62
|
-
//
|
|
124
|
+
// Imports
|
|
125
|
+
import type { CSSProperties } from 'vue'
|
|
126
|
+
|
|
63
127
|
defineOptions({
|
|
64
|
-
inheritAttrs: false,
|
|
128
|
+
inheritAttrs: false,
|
|
65
129
|
})
|
|
66
130
|
|
|
67
131
|
// Props
|
|
@@ -94,27 +158,149 @@ const props = defineProps({
|
|
|
94
158
|
type: Boolean as PropType<boolean>,
|
|
95
159
|
default: true,
|
|
96
160
|
},
|
|
161
|
+
shouldTeleport: {
|
|
162
|
+
type: Boolean as PropType<boolean>,
|
|
163
|
+
default: true,
|
|
164
|
+
},
|
|
97
165
|
})
|
|
98
166
|
|
|
99
|
-
//
|
|
100
|
-
const
|
|
167
|
+
// Refs
|
|
168
|
+
const activatorWrapper = ref<HTMLElement | null>(null)
|
|
169
|
+
const dropdown = ref<HTMLElement | null>(null)
|
|
170
|
+
const isOpen = ref(false)
|
|
101
171
|
|
|
102
|
-
//
|
|
103
|
-
const
|
|
172
|
+
// States
|
|
173
|
+
const isPositioned = ref(false)
|
|
174
|
+
const activatorRect = ref<DOMRect | null>(null)
|
|
175
|
+
const dropdownRect = ref<DOMRect | null>(null)
|
|
104
176
|
|
|
105
|
-
|
|
177
|
+
// Methods
|
|
178
|
+
const close = () => {
|
|
106
179
|
isOpen.value = false
|
|
107
|
-
|
|
180
|
+
isPositioned.value = false
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
const open = () => {
|
|
184
|
+
isOpen.value = true
|
|
185
|
+
isPositioned.value = false
|
|
186
|
+
|
|
187
|
+
nextTick(() => {
|
|
188
|
+
requestAnimationFrame(() => {
|
|
189
|
+
updateRects()
|
|
190
|
+
isPositioned.value = true
|
|
191
|
+
})
|
|
192
|
+
})
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const toggle = () => {
|
|
196
|
+
if (isOpen.value) {
|
|
197
|
+
close()
|
|
198
|
+
} else {
|
|
199
|
+
open()
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const getActivatorElement = () => {
|
|
204
|
+
return activatorWrapper.value
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const onActivatorClick = (event: MouseEvent) => {
|
|
208
|
+
if (!activatorWrapper.value) return
|
|
209
|
+
|
|
210
|
+
if (activatorWrapper.value.contains(event.target as Node)) {
|
|
211
|
+
toggle()
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const updateRects = () => {
|
|
216
|
+
const activatorEl = getActivatorElement()
|
|
217
|
+
if (!activatorEl || !dropdown.value) return
|
|
218
|
+
|
|
219
|
+
activatorRect.value = activatorEl.getBoundingClientRect()
|
|
220
|
+
dropdownRect.value = dropdown.value.getBoundingClientRect()
|
|
221
|
+
}
|
|
108
222
|
|
|
109
|
-
// Handlers
|
|
110
223
|
const handleClick = (callback?: () => void) => {
|
|
111
|
-
if(callback)
|
|
112
|
-
|
|
224
|
+
if (callback) callback()
|
|
225
|
+
close()
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const handleClickOutside = (event: MouseEvent) => {
|
|
229
|
+
const dropdownEl = dropdown.value
|
|
230
|
+
const activatorEl = activatorWrapper.value
|
|
231
|
+
|
|
232
|
+
if (!dropdownEl || !activatorEl) return
|
|
233
|
+
|
|
234
|
+
const target = event.target as Node
|
|
235
|
+
|
|
236
|
+
if (
|
|
237
|
+
!dropdownEl.contains(target) &&
|
|
238
|
+
!activatorEl.contains(target)
|
|
239
|
+
) {
|
|
240
|
+
close()
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
const handleScrollOutside = (event: Event) => {
|
|
245
|
+
const dropdownEl = dropdown.value
|
|
246
|
+
const activatorEl = activatorWrapper.value
|
|
247
|
+
|
|
248
|
+
if (!dropdownEl || !activatorEl) return
|
|
249
|
+
|
|
250
|
+
const target = event.target as Node
|
|
251
|
+
|
|
252
|
+
// If scroll happened on an element not containing the dropdown or activator
|
|
253
|
+
if (
|
|
254
|
+
!dropdownEl.contains(target) &&
|
|
255
|
+
!activatorEl.contains(target)
|
|
256
|
+
) {
|
|
257
|
+
close()
|
|
113
258
|
}
|
|
114
|
-
toggle()
|
|
115
259
|
}
|
|
116
260
|
|
|
117
|
-
|
|
261
|
+
const computedTeleportStyle = computed<CSSProperties>(() => {
|
|
262
|
+
if (!isPositioned.value || !activatorRect.value || !dropdownRect.value) {
|
|
263
|
+
return {
|
|
264
|
+
position: 'absolute',
|
|
265
|
+
top: '0px',
|
|
266
|
+
left: '0px',
|
|
267
|
+
visibility: 'hidden',
|
|
268
|
+
zIndex: '50',
|
|
269
|
+
width: '0px',
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
const a = activatorRect.value
|
|
274
|
+
const d = dropdownRect.value
|
|
275
|
+
const x = Number(props.positionXOffset) || 0
|
|
276
|
+
const y = Number(props.positionYOffset) || 0
|
|
277
|
+
|
|
278
|
+
const [primary, secondary] = props.position.toLowerCase().split('-')
|
|
279
|
+
|
|
280
|
+
let top = 0
|
|
281
|
+
let left = 0
|
|
282
|
+
|
|
283
|
+
if (primary === 'bottom') top = a.bottom + y
|
|
284
|
+
if (primary === 'top') top = a.top - d.height - y
|
|
285
|
+
if (primary === 'left') left = a.left - d.width - x
|
|
286
|
+
if (primary === 'right') left = a.right + x
|
|
287
|
+
|
|
288
|
+
if (secondary === 'left') left = a.left
|
|
289
|
+
if (secondary === 'right') left = a.right - d.width
|
|
290
|
+
if (secondary === 'top') top = a.top
|
|
291
|
+
if (secondary === 'bottom') top = a.bottom - d.height
|
|
292
|
+
|
|
293
|
+
return {
|
|
294
|
+
position: 'absolute',
|
|
295
|
+
top: `${top + window.scrollY}px`,
|
|
296
|
+
left: `${left + window.scrollX}px`,
|
|
297
|
+
width: `${a.width}px`,
|
|
298
|
+
visibility: 'visible',
|
|
299
|
+
zIndex: '50',
|
|
300
|
+
}
|
|
301
|
+
})
|
|
302
|
+
|
|
303
|
+
// Styles for non-teleported dropdown
|
|
118
304
|
const dropdownPositionClass = computed(() => {
|
|
119
305
|
const variant = {
|
|
120
306
|
[DropdownPosition.LEFT_TOP]: 'absolute right-full top-0',
|
|
@@ -204,4 +390,15 @@ const positionOffsetStyle = computed(() => {
|
|
|
204
390
|
return style
|
|
205
391
|
})
|
|
206
392
|
|
|
207
|
-
|
|
393
|
+
onMounted(() => {
|
|
394
|
+
document.addEventListener('click', handleClickOutside)
|
|
395
|
+
window.addEventListener('resize', close)
|
|
396
|
+
document.addEventListener('scroll', handleScrollOutside, true)
|
|
397
|
+
})
|
|
398
|
+
|
|
399
|
+
onBeforeUnmount(() => {
|
|
400
|
+
document.removeEventListener('click', handleClickOutside)
|
|
401
|
+
window.removeEventListener('resize', close)
|
|
402
|
+
document.removeEventListener('scroll', handleScrollOutside, true)
|
|
403
|
+
})
|
|
404
|
+
</script>
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
<!-- Dropdown Menu -->
|
|
4
4
|
<DropdownMenu
|
|
5
5
|
ref="dropdownContainer"
|
|
6
|
+
:shouldTeleport="false"
|
|
6
7
|
:positionClass="`absolute ${dropdownPositionClass}`"
|
|
7
8
|
dropdownClass="max-w-full z-10"
|
|
8
9
|
:class="[
|
|
@@ -12,7 +13,7 @@
|
|
|
12
13
|
'border-border-default',
|
|
13
14
|
]"
|
|
14
15
|
>
|
|
15
|
-
<template #activator="{
|
|
16
|
+
<template #activator="{ isOpen }">
|
|
16
17
|
<!-- Select Box -->
|
|
17
18
|
<div
|
|
18
19
|
:class="[
|
|
@@ -29,7 +30,7 @@
|
|
|
29
30
|
disabled ? 'text-text-neutral-disabled' : 'text-text-default',
|
|
30
31
|
sizeClass,
|
|
31
32
|
]"
|
|
32
|
-
@click="!disabled
|
|
33
|
+
@click="!disabled"
|
|
33
34
|
>
|
|
34
35
|
<div v-if="multiple">
|
|
35
36
|
<template v-if="Array.isArray(selected) && selected.length">
|
|
@@ -123,10 +123,10 @@ const orientationClass = computed(() => {
|
|
|
123
123
|
|
|
124
124
|
const iconSizeClass = computed(() => {
|
|
125
125
|
const iconSize = {
|
|
126
|
-
[Orientation.VERTICAL]: '
|
|
127
|
-
[Orientation.HORIZONTAL]: '
|
|
126
|
+
[Orientation.VERTICAL]: 'w-[40px] h-[40px] min-w-[40px] min-h-[40px]',
|
|
127
|
+
[Orientation.HORIZONTAL]: 'w-[32px] h-[32px] min-w-[32px] min-h-[32px]',
|
|
128
128
|
}
|
|
129
|
-
return iconSize[props.orientation as Orientation] || '
|
|
129
|
+
return iconSize[props.orientation as Orientation] || 'w-[32px] h-[32px] min-w-[32px] min-h-[32px]'
|
|
130
130
|
})
|
|
131
131
|
|
|
132
132
|
const containerClasses = computed(() => {
|
|
@@ -3,13 +3,10 @@
|
|
|
3
3
|
:name
|
|
4
4
|
:mode
|
|
5
5
|
:customize="svgCustomize"
|
|
6
|
-
:class="
|
|
7
|
-
iconSizeClass,
|
|
8
|
-
iconColorClass,
|
|
9
|
-
...normalizedIconClass,
|
|
10
|
-
]"
|
|
6
|
+
:class="finalIconClasses"
|
|
11
7
|
/>
|
|
12
8
|
</template>
|
|
9
|
+
|
|
13
10
|
<script setup lang="ts">
|
|
14
11
|
// Props
|
|
15
12
|
const props = defineProps({
|
|
@@ -24,23 +21,36 @@ const props = defineProps({
|
|
|
24
21
|
},
|
|
25
22
|
size: {
|
|
26
23
|
type: String as PropType<IconSize>,
|
|
27
|
-
default: IconSize.MD,
|
|
24
|
+
default: IconSize.MD,
|
|
28
25
|
validator: (value: IconSize) => Object.values(IconSize).includes(value),
|
|
29
26
|
},
|
|
30
27
|
color: String as PropType<ColorAccent>,
|
|
31
|
-
svgCustomize: Function as PropType<CollectionCustomizeCallback>,
|
|
32
|
-
iconClass: [String, Array] as PropType<string | string[]>,
|
|
28
|
+
svgCustomize: Function as PropType<CollectionCustomizeCallback>,
|
|
29
|
+
iconClass: [String, Array] as PropType<string | string[]>,
|
|
33
30
|
})
|
|
34
31
|
|
|
35
|
-
//
|
|
32
|
+
// Normalize iconClass into array
|
|
36
33
|
const normalizedIconClass = computed(() => {
|
|
37
34
|
return Array.isArray(props.iconClass)
|
|
38
35
|
? props.iconClass
|
|
39
36
|
: props.iconClass?.split(' ').filter(Boolean) || []
|
|
40
37
|
})
|
|
41
38
|
|
|
42
|
-
//
|
|
39
|
+
// Detect overrides
|
|
40
|
+
const hasTextClass = computed(() =>
|
|
41
|
+
normalizedIconClass.value.some(cls => cls.startsWith('text-'))
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const hasSizeClass = computed(() =>
|
|
45
|
+
normalizedIconClass.value.some(cls =>
|
|
46
|
+
/^(w-|h-|min-w-|min-h-)/.test(cls)
|
|
47
|
+
)
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
// Size classes (skipped if overridden)
|
|
43
51
|
const iconSizeClass = computed(() => {
|
|
52
|
+
if (hasSizeClass.value) return null
|
|
53
|
+
|
|
44
54
|
const variants = {
|
|
45
55
|
[IconSize.XS]: 'w-[12px] h-[12px] min-w-[12px] min-h-[12px]',
|
|
46
56
|
[IconSize.SM]: 'w-[16px] h-[16px] min-w-[16px] min-h-[16px]',
|
|
@@ -50,10 +60,13 @@ const iconSizeClass = computed(() => {
|
|
|
50
60
|
[IconSize.XXL]: 'w-[40px] h-[40px] min-w-[40px] min-h-[40px]',
|
|
51
61
|
}
|
|
52
62
|
|
|
53
|
-
return variants[props.size as IconSize] ||
|
|
63
|
+
return variants[props.size as IconSize] || variants[IconSize.MD]
|
|
54
64
|
})
|
|
55
65
|
|
|
66
|
+
// Color classes (skipped if overridden)
|
|
56
67
|
const iconColorClass = computed(() => {
|
|
68
|
+
if (hasTextClass.value) return null
|
|
69
|
+
|
|
57
70
|
if (!props.color) return 'text-inherit'
|
|
58
71
|
|
|
59
72
|
const variants = {
|
|
@@ -68,4 +81,15 @@ const iconColorClass = computed(() => {
|
|
|
68
81
|
|
|
69
82
|
return variants[props.color] || 'text-inherit'
|
|
70
83
|
})
|
|
71
|
-
|
|
84
|
+
|
|
85
|
+
// Final class list (deduplicated)
|
|
86
|
+
const finalIconClasses = computed(() => {
|
|
87
|
+
const classes = [
|
|
88
|
+
iconSizeClass.value,
|
|
89
|
+
iconColorClass.value,
|
|
90
|
+
...normalizedIconClass.value,
|
|
91
|
+
].filter(Boolean)
|
|
92
|
+
|
|
93
|
+
return [...new Set(classes)]
|
|
94
|
+
})
|
|
95
|
+
</script>
|
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
<template v-if="items.length && !$slots.default">
|
|
10
10
|
<ListItem
|
|
11
11
|
v-for="(item, index) in items" :key="index"
|
|
12
|
-
:
|
|
13
|
-
:
|
|
12
|
+
:markerIcon="listItemIcon"
|
|
13
|
+
:markerIconClass="listItemIconClass"
|
|
14
14
|
:size="listItemSize"
|
|
15
15
|
:spaced="spaced"
|
|
16
16
|
>
|
|
@@ -6,9 +6,9 @@
|
|
|
6
6
|
]"
|
|
7
7
|
>
|
|
8
8
|
<Icon
|
|
9
|
-
v-if="
|
|
10
|
-
:name="
|
|
11
|
-
:
|
|
9
|
+
v-if="markerIcon"
|
|
10
|
+
:name="markerIcon"
|
|
11
|
+
:iconClass="[markerIconClass, markerIconSizeClass]"
|
|
12
12
|
/>
|
|
13
13
|
<span :class="[contentSizeClass, 'w-full']">
|
|
14
14
|
<slot />
|
|
@@ -18,8 +18,8 @@
|
|
|
18
18
|
<script setup lang="ts">
|
|
19
19
|
// Props
|
|
20
20
|
const props = defineProps({
|
|
21
|
-
|
|
22
|
-
|
|
21
|
+
markerIcon: String as PropType<string>,
|
|
22
|
+
markerIconClass: {
|
|
23
23
|
type: String as PropType<string>,
|
|
24
24
|
default: 'text-icon-secondary-brand-default'
|
|
25
25
|
},
|
|
@@ -35,13 +35,13 @@ const props = defineProps({
|
|
|
35
35
|
})
|
|
36
36
|
|
|
37
37
|
// Computed
|
|
38
|
-
const
|
|
38
|
+
const markerIconSizeClass = computed(() => {
|
|
39
39
|
const sizeVariant = {
|
|
40
|
-
[ListItemSize.XS]: 'w-[16px] h-[16px] min-w-[16px] min-h-[16px]',
|
|
41
|
-
[ListItemSize.SM]: 'w-[20px] h-[20px] min-w-[20px] min-h-[20px]',
|
|
42
|
-
[ListItemSize.MD]: 'w-[24px] h-[24px] min-w-[24px] min-h-[24px]',
|
|
40
|
+
[ListItemSize.XS]: '!w-[16px] h-[16px] !min-w-[16px] !min-h-[16px]',
|
|
41
|
+
[ListItemSize.SM]: '!w-[20px] h-[20px] !min-w-[20px] !min-h-[20px]',
|
|
42
|
+
[ListItemSize.MD]: '!w-[24px] h-[24px] !min-w-[24px] !min-h-[24px]',
|
|
43
43
|
}
|
|
44
|
-
return sizeVariant[props.size as ListItemSize] || 'w-[20px] h-[20px] min-w-[20px] min-h-[20px]'
|
|
44
|
+
return sizeVariant[props.size as ListItemSize] || '!w-[20px] !h-[20px] !min-w-[20px] !min-h-[20px]'
|
|
45
45
|
})
|
|
46
46
|
|
|
47
47
|
const contentSizeClass = computed(() => {
|
|
@@ -45,9 +45,9 @@ const iconSizeClass = computed(() => {
|
|
|
45
45
|
|
|
46
46
|
const colorClass = computed(() => {
|
|
47
47
|
const colorVariants = {
|
|
48
|
-
[RatingItemColor.GOLD]: 'text-icon-rating',
|
|
49
|
-
[RatingItemColor.PRIMARY_BRAND]: 'text-icon-primary-brand-rating',
|
|
48
|
+
[RatingItemColor.GOLD]: '!text-icon-rating',
|
|
49
|
+
[RatingItemColor.PRIMARY_BRAND]: '!text-icon-primary-brand-rating',
|
|
50
50
|
}
|
|
51
|
-
return colorVariants[props.color as RatingItemColor] || 'text-icon-rating'
|
|
51
|
+
return colorVariants[props.color as RatingItemColor] || '!text-icon-rating'
|
|
52
52
|
})
|
|
53
53
|
</script>
|