@usssa/component-library 1.0.0-alpha.203 → 1.0.0-alpha.204
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/README.md +1 -1
- package/package.json +1 -1
- package/src/components/core/UAccordionSelect.vue +237 -0
- package/src/components/index.js +2 -1
package/README.md
CHANGED
package/package.json
CHANGED
|
@@ -0,0 +1,237 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { nextTick, ref, watch } from 'vue'
|
|
3
|
+
import UTooltip from './UTooltip.vue'
|
|
4
|
+
|
|
5
|
+
const emit = defineEmits(['onItemClick'])
|
|
6
|
+
|
|
7
|
+
const props = defineProps({
|
|
8
|
+
data: { type: Array, default: () => [] },
|
|
9
|
+
dataTestId: {
|
|
10
|
+
type: String,
|
|
11
|
+
default: 'accordion-select',
|
|
12
|
+
},
|
|
13
|
+
multiple: { type: Boolean, default: false },
|
|
14
|
+
title: { type: String, default: 'Select Division' },
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
const activeLineStyles = ref({})
|
|
18
|
+
const selectedRows = ref({})
|
|
19
|
+
const showTooltipFor = ref({})
|
|
20
|
+
|
|
21
|
+
//Tooltip handling
|
|
22
|
+
const checkEllipsis = (sectionIndex, rowIndex, el) => {
|
|
23
|
+
if (!el) return
|
|
24
|
+
setTimeout(() => {
|
|
25
|
+
const isEllipsed = el.scrollWidth > el.clientWidth
|
|
26
|
+
if (!showTooltipFor.value[sectionIndex]) {
|
|
27
|
+
showTooltipFor.value[sectionIndex] = {}
|
|
28
|
+
}
|
|
29
|
+
showTooltipFor.value[sectionIndex][rowIndex] = isEllipsed
|
|
30
|
+
}, 50)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
//Selection handling
|
|
34
|
+
const isSelected = (sectionIndex, rowIndex) =>
|
|
35
|
+
selectedRows.value[sectionIndex]?.includes(rowIndex)
|
|
36
|
+
|
|
37
|
+
const selectItem = (sectionIndex, rowIndex, item) => {
|
|
38
|
+
if (item.disabled) return
|
|
39
|
+
|
|
40
|
+
let isSelected = false
|
|
41
|
+
if (props.multiple) {
|
|
42
|
+
if (!selectedRows.value[sectionIndex]) {
|
|
43
|
+
selectedRows.value[sectionIndex] = []
|
|
44
|
+
}
|
|
45
|
+
const idx = selectedRows.value[sectionIndex].indexOf(rowIndex)
|
|
46
|
+
if (idx > -1) {
|
|
47
|
+
selectedRows.value[sectionIndex].splice(idx, 1)
|
|
48
|
+
isSelected = false
|
|
49
|
+
} else {
|
|
50
|
+
selectedRows.value[sectionIndex].push(rowIndex)
|
|
51
|
+
isSelected = true
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
selectedRows.value[sectionIndex].sort((a, b) => a - b)
|
|
55
|
+
updateActiveLine(sectionIndex)
|
|
56
|
+
} else {
|
|
57
|
+
const alreadySelected =
|
|
58
|
+
selectedRows.value[sectionIndex]?.[0] === rowIndex &&
|
|
59
|
+
Object.keys(selectedRows.value).length === 1
|
|
60
|
+
|
|
61
|
+
if (alreadySelected) {
|
|
62
|
+
selectedRows.value = {}
|
|
63
|
+
activeLineStyles.value = {}
|
|
64
|
+
isSelected = false
|
|
65
|
+
} else {
|
|
66
|
+
selectedRows.value = { [sectionIndex]: [rowIndex] }
|
|
67
|
+
activeLineStyles.value = {}
|
|
68
|
+
updateActiveLine(sectionIndex)
|
|
69
|
+
isSelected = true
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
emit('onItemClick', { sectionIndex, item, selected: isSelected })
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
//Active line handling
|
|
77
|
+
const updateActiveLine = (sectionIndex) => {
|
|
78
|
+
nextTick(() => {
|
|
79
|
+
const container = document.querySelector(`[data-section="${sectionIndex}"]`)
|
|
80
|
+
const allRows = [...(container?.querySelectorAll('.row-item') || [])]
|
|
81
|
+
|
|
82
|
+
const selectedIndexes = selectedRows.value[sectionIndex] || []
|
|
83
|
+
const groups = []
|
|
84
|
+
let currentGroup = []
|
|
85
|
+
|
|
86
|
+
selectedIndexes.forEach((idx, i) => {
|
|
87
|
+
if (i === 0 || idx === selectedIndexes[i - 1] + 1) {
|
|
88
|
+
currentGroup.push(idx)
|
|
89
|
+
} else {
|
|
90
|
+
groups.push(currentGroup)
|
|
91
|
+
currentGroup = [idx]
|
|
92
|
+
}
|
|
93
|
+
})
|
|
94
|
+
if (currentGroup.length) groups.push(currentGroup)
|
|
95
|
+
|
|
96
|
+
activeLineStyles.value[sectionIndex] = groups.map((group) => {
|
|
97
|
+
const firstEl = allRows[group[0]]
|
|
98
|
+
const lastEl = allRows[group[group.length - 1]]
|
|
99
|
+
const top = firstEl.offsetTop
|
|
100
|
+
const height = lastEl.offsetTop + lastEl.offsetHeight - top
|
|
101
|
+
return { top: `${top}px`, height: `${height}px` }
|
|
102
|
+
})
|
|
103
|
+
})
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
//Reset when switching to single select
|
|
107
|
+
watch(
|
|
108
|
+
() => props.multiple,
|
|
109
|
+
(value) => {
|
|
110
|
+
if (!value) {
|
|
111
|
+
selectedRows.value = {}
|
|
112
|
+
activeLineStyles.value = {}
|
|
113
|
+
showTooltipFor.value = {}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
</script>
|
|
118
|
+
|
|
119
|
+
<template>
|
|
120
|
+
<div class="u-accordion-select" :dataTestId="dataTestId">
|
|
121
|
+
<div class="q-pa-xs">
|
|
122
|
+
<span class="text-heading-xxs text-dark" tabindex="0">{{ title }}</span>
|
|
123
|
+
</div>
|
|
124
|
+
|
|
125
|
+
<q-expansion-item
|
|
126
|
+
v-bind="$attrs"
|
|
127
|
+
v-for="(item, sectionIndex) in data"
|
|
128
|
+
header-class="q-px-xxs accordion-header text-caption-md"
|
|
129
|
+
:caption="item.caption"
|
|
130
|
+
dataTestId="division-item"
|
|
131
|
+
:disable="item.disabled"
|
|
132
|
+
:key="sectionIndex"
|
|
133
|
+
:label="item.title"
|
|
134
|
+
switch-toggle-side
|
|
135
|
+
>
|
|
136
|
+
<div class="content-with-line q-mx-sm" :data-section="sectionIndex">
|
|
137
|
+
<template
|
|
138
|
+
v-for="styleObj in activeLineStyles[sectionIndex] || []"
|
|
139
|
+
:key="styleObj.index"
|
|
140
|
+
>
|
|
141
|
+
<div class="active-line" :style="styleObj" />
|
|
142
|
+
</template>
|
|
143
|
+
|
|
144
|
+
<div
|
|
145
|
+
v-for="(row, rowIndex) in item?.children"
|
|
146
|
+
:class="[
|
|
147
|
+
'row-item q-py-xs',
|
|
148
|
+
row.disabled ? 'disabled' : '',
|
|
149
|
+
isSelected(sectionIndex, rowIndex) ? 'active' : '',
|
|
150
|
+
]"
|
|
151
|
+
dataTestId="division-child"
|
|
152
|
+
:key="rowIndex"
|
|
153
|
+
role="option"
|
|
154
|
+
:tabindex="row.disabled ? -1 : 0"
|
|
155
|
+
@click="selectItem(sectionIndex, rowIndex, row)"
|
|
156
|
+
@keydown.enter.prevent="selectItem(sectionIndex, rowIndex, row)"
|
|
157
|
+
>
|
|
158
|
+
<span
|
|
159
|
+
class="text-body-sm row-text ellipsis"
|
|
160
|
+
dataTestId="child-item"
|
|
161
|
+
:ref="(el) => checkEllipsis(sectionIndex, rowIndex, el)"
|
|
162
|
+
>
|
|
163
|
+
{{ row.title }}
|
|
164
|
+
<UTooltip
|
|
165
|
+
v-if="showTooltipFor[sectionIndex]?.[rowIndex] && row?.title"
|
|
166
|
+
:description="row?.title"
|
|
167
|
+
/>
|
|
168
|
+
</span>
|
|
169
|
+
</div>
|
|
170
|
+
</div>
|
|
171
|
+
</q-expansion-item>
|
|
172
|
+
</div>
|
|
173
|
+
</template>
|
|
174
|
+
|
|
175
|
+
<style lang="sass">
|
|
176
|
+
.u-accordion-select
|
|
177
|
+
border: 1.5px solid $neutral-4
|
|
178
|
+
border-radius: $xs
|
|
179
|
+
padding: $xxs
|
|
180
|
+
|
|
181
|
+
.accordion-header
|
|
182
|
+
.q-item__section--avatar
|
|
183
|
+
min-width: 0px
|
|
184
|
+
.q-item__section--side
|
|
185
|
+
padding-right: $xxs
|
|
186
|
+
border-radius: $xxs
|
|
187
|
+
.q-item__label
|
|
188
|
+
word-break: break-word
|
|
189
|
+
|
|
190
|
+
.q-expansion-item__toggle-icon
|
|
191
|
+
font-size: $ba
|
|
192
|
+
.q-expansion-item--expanded .q-expansion-item__toggle-icon
|
|
193
|
+
line-height: 4.5
|
|
194
|
+
|
|
195
|
+
.content-with-line
|
|
196
|
+
position: relative
|
|
197
|
+
padding-left: $sm
|
|
198
|
+
|
|
199
|
+
&::before
|
|
200
|
+
content: ''
|
|
201
|
+
position: absolute
|
|
202
|
+
top: 0
|
|
203
|
+
bottom: 2px
|
|
204
|
+
left: 0
|
|
205
|
+
width: 2px
|
|
206
|
+
background-color: $neutral-4
|
|
207
|
+
|
|
208
|
+
.active-line
|
|
209
|
+
position: absolute
|
|
210
|
+
left: 0
|
|
211
|
+
width: 2px
|
|
212
|
+
background-color: $primary
|
|
213
|
+
z-index: 1
|
|
214
|
+
border-radius: $xs
|
|
215
|
+
|
|
216
|
+
.row-text
|
|
217
|
+
flex: 1 1 auto
|
|
218
|
+
word-wrap: break-word
|
|
219
|
+
min-width: 0px
|
|
220
|
+
overflow: hidden
|
|
221
|
+
white-space: nowrap
|
|
222
|
+
text-overflow: ellipsis
|
|
223
|
+
|
|
224
|
+
.row-item
|
|
225
|
+
border: 0px
|
|
226
|
+
cursor: pointer
|
|
227
|
+
position: relative
|
|
228
|
+
display: flex
|
|
229
|
+
align-items: center
|
|
230
|
+
&:hover:not(.disabled)
|
|
231
|
+
.row-text
|
|
232
|
+
color: $primary
|
|
233
|
+
.row-item.disabled
|
|
234
|
+
opacity: 0.5
|
|
235
|
+
cursor: not-allowed
|
|
236
|
+
pointer-events: none
|
|
237
|
+
</style>
|
package/src/components/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import UAccordionSelect from './core/UAccordionSelect.vue'
|
|
2
2
|
import UAvatar from './core/UAvatar.vue'
|
|
3
3
|
import UAvatarGroup from './core/UAvatarGroup.vue'
|
|
4
4
|
import UBadgeStd from './core/UBadgeStd.vue'
|
|
@@ -46,6 +46,7 @@ import { useOverlayLoader } from '../composables/useOverlayLoader.js'
|
|
|
46
46
|
import { useScreenType } from '../composables/useScreenType.js'
|
|
47
47
|
|
|
48
48
|
export {
|
|
49
|
+
UAccordionSelect,
|
|
49
50
|
UAvatar,
|
|
50
51
|
UAvatarGroup,
|
|
51
52
|
UBadgeStd,
|