@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 CHANGED
@@ -1,4 +1,4 @@
1
- # Component Library v1.0.0-alpha.203
1
+ # Component Library v1.0.0-alpha.204
2
2
 
3
3
  **This library provides custom UI components for USSSA applications**
4
4
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@usssa/component-library",
3
- "version": "1.0.0-alpha.203",
3
+ "version": "1.0.0-alpha.204",
4
4
  "description": "A Quasar component library project",
5
5
  "productName": "Quasar component library App",
6
6
  "author": "Engineering Team <engineering@usssa.com>",
@@ -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>
@@ -1,4 +1,4 @@
1
- // import BtnStd from "./BtnStd.vue";
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,