@usssa/component-library 1.0.0-alpha.202 → 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.202
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.202",
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>
@@ -0,0 +1,287 @@
1
+ <script setup>
2
+ import { ref } from "vue";
3
+ import { UAvatar, UExpansionStd, UTableStd, useScreenType } from "src/components";
4
+
5
+ const emit = defineEmits(["onCustomSort", "onLoadMore"]);
6
+
7
+ const columns = defineModel("columns", {
8
+ default: () => [],
9
+ type: Array,
10
+ });
11
+ const expansionMinHeight = defineModel("expansionMinHeight", {
12
+ default: 14,
13
+ type: Number,
14
+ });
15
+ const filteredRows = defineModel("filteredRows", { default: [], type: Array });
16
+ const grid = defineModel("grid", {
17
+ default: false,
18
+ type: Boolean,
19
+ });
20
+ const infiniteScroll = defineModel("infiniteScroll", {
21
+ default: false,
22
+ type: Boolean,
23
+ });
24
+ const infiniteScrollProperty = defineModel("infiniteScrollProperty", {
25
+ default: () => {
26
+ return {
27
+ color: "primary",
28
+ height: "55rem",
29
+ image: "",
30
+ loading: false,
31
+ loadingMessage: "Loading data",
32
+ noMoreData: false,
33
+ noMoreDataText: "No more data",
34
+ padding: true,
35
+ size: "1rem",
36
+ type: "default",
37
+ };
38
+ },
39
+ type: Object,
40
+ });
41
+ const loading = defineModel("table-loading", {
42
+ default: () => {},
43
+ type: Boolean,
44
+ });
45
+ const moreActionDialogData = defineModel("moreActionDialogData", {
46
+ type: Object,
47
+ default: null,
48
+ });
49
+ const pagination = defineModel("pagination", {
50
+ default: { page: 1, rowsPerPage: 5 },
51
+ type: Object,
52
+ });
53
+ const rows = defineModel("rows", {
54
+ default: () => [],
55
+ type: Array,
56
+ });
57
+ const rowCardHeight = defineModel("gridCardHeight", {
58
+ default: 25,
59
+ type: Number,
60
+ });
61
+ const selectedRows = defineModel("selectedRows", {
62
+ default: () => [],
63
+ type: Array,
64
+ });
65
+ const separator = defineModel("separator", {
66
+ default: "horizontal",
67
+ type: String,
68
+ });
69
+ const showPagination = defineModel("showPagination", {
70
+ default: false,
71
+ type: Boolean,
72
+ });
73
+ const stickyHeader = defineModel("stickyHeader", {
74
+ default: false,
75
+ type: Boolean,
76
+ });
77
+ const tableRowHover = defineModel("tableRowHover", {
78
+ default: false,
79
+ type: Boolean,
80
+ });
81
+ const tableTitle = defineModel("tableTitle", {
82
+ default: "",
83
+ type: String,
84
+ });
85
+
86
+ const props = defineProps({
87
+ caption: {
88
+ type: String,
89
+ default: "",
90
+ },
91
+ collapsedAriaLabel: {
92
+ type: String,
93
+ default: "Collapsed",
94
+ },
95
+ dataTestId: {
96
+ type: String,
97
+ default: "expansion-table-std",
98
+ },
99
+ disabled: {
100
+ type: Boolean,
101
+ default: false,
102
+ },
103
+ enableGridOn: {
104
+ type: Array,
105
+ default: () => ["tablet", "mobile"],
106
+ },
107
+ enableIconToggle: {
108
+ type: Boolean,
109
+ default: false,
110
+ },
111
+ enableSelection: {
112
+ type: Boolean,
113
+ default: false,
114
+ },
115
+ expandAriaLabel: {
116
+ type: String,
117
+ default: "Expand",
118
+ },
119
+ expansionIconClass: {
120
+ type: String,
121
+ default: "fa-kit fa-caret-down",
122
+ },
123
+ expansionIconColor: {
124
+ type: String,
125
+ default: "description",
126
+ },
127
+ expansionIconSize: {
128
+ type: String,
129
+ default: "1rem", // accept px , rem and (xs|sm|md|lg|xl)
130
+ },
131
+ label: {
132
+ type: String,
133
+ default: "",
134
+ },
135
+ option: {
136
+ default: null,
137
+ type: Object,
138
+ },
139
+ showAvatar: {
140
+ type: Boolean,
141
+ default: false,
142
+ },
143
+ tableCustomClass: {
144
+ type: String,
145
+ default: "",
146
+ },
147
+ toggleIconLeft: {
148
+ type: Boolean,
149
+ default: false,
150
+ },
151
+ viewMoreLabel: {
152
+ type: String,
153
+ default: "View Options",
154
+ },
155
+ });
156
+
157
+ const $screen = useScreenType();
158
+
159
+ const bordered = ref(false);
160
+ const expansion = ref(false);
161
+ const flat = ref(true);
162
+ const isCustomSort = ref(false);
163
+ const multiSelection = ref(false);
164
+ const verticalMoreActions = ref(true);
165
+ const virtualScroll = ref(false);
166
+ </script>
167
+
168
+ <template>
169
+ <UExpansionStd
170
+ :class="`u-expansion-table ${!$screen.isMobile ? 'desktop-tablet-mode' : ''}`"
171
+ :caption="caption"
172
+ :collapsed-aria-label="collapsedAriaLabel"
173
+ :dataTestId="dataTestId"
174
+ :disabled="disabled"
175
+ :enable-icon-toggle="enableIconToggle"
176
+ :enable-selection="enableSelection"
177
+ :expand-aria-label="expandAriaLabel"
178
+ :expansion-icon="expansionIconClass"
179
+ :expansion-icon-color="expansionIconColor"
180
+ :label="label"
181
+ :row-card-height="expansionMinHeight"
182
+ :toggle-icon-left="toggleIconLeft"
183
+ >
184
+ <template v-if="showAvatar" #avatar>
185
+ <UAvatar name="UExpansion" :round="true" size="lg" />
186
+ </template>
187
+ <template #body>
188
+ <UTableStd
189
+ v-model:columns="columns"
190
+ v-model:grid="grid"
191
+ v-model:pagination="pagination"
192
+ v-model:loading="loading"
193
+ v-model:selected-rows="selectedRows"
194
+ v-model:rows="rows"
195
+ :customClass="tableCustomClass"
196
+ :bordered="bordered"
197
+ :enable-grid-on="enableGridOn"
198
+ :expansion="expansion"
199
+ :flat="flat"
200
+ :infiniteScroll="infiniteScroll"
201
+ :infiniteScrollProperty="infiniteScrollProperty"
202
+ :isCustomSort="isCustomSort"
203
+ :more-action-dialog-data="moreActionDialogData"
204
+ :multiSelection="multiSelection"
205
+ :row-card-height="rowCardHeight"
206
+ :separator="separator"
207
+ :showPagination="showPagination"
208
+ :stickyHeader="stickyHeader"
209
+ :tableRowHover="tableRowHover"
210
+ :title="tableTitle"
211
+ :vertical-more-actions="verticalMoreActions"
212
+ :viewMoreLabel="viewMoreLabel"
213
+ :virtualScroll="virtualScroll"
214
+ @onCustomSort="
215
+ (key, sortOrder, type) => $emit('onCustomSort', key, sortOrder, type)
216
+ "
217
+ @onLoadMore="(payload) => $emit('onLoadMore', payload)"
218
+ />
219
+ </template>
220
+ </UExpansionStd>
221
+ </template>
222
+
223
+ <style lang="sass">
224
+ .u-expansion-table
225
+ background: $neutral-2 !important
226
+ .u-expansion-label > :first-child
227
+ margin-bottom: $xxs !important
228
+
229
+ table tbody tr:last-child
230
+ .u-td-std
231
+ border-bottom: none !important
232
+
233
+ .u-expansion .q-expansion-item__content > :first-child
234
+ padding: 0px !important
235
+
236
+ .u-expansion .q-expansion-item__content
237
+ padding: 0px !important
238
+
239
+ .desktop-tablet-mode .q-expansion-item__content
240
+ padding: $xxs !important
241
+
242
+ .q-table__grid-content
243
+ .expansion-table-card
244
+ padding: 0px !important
245
+ .q-card
246
+ border-radius: inherit !important
247
+ border: none !important
248
+ box-shadow: none
249
+ .q-list
250
+ padding: $ba $ba 0px $ba !important
251
+ column-gap: $xs !important
252
+ row-gap: $ba !important
253
+ .q-item
254
+ .long-text-content
255
+ width: 8.2rem !important
256
+ .q-item.q-item-type:first-child
257
+ grid-column: auto !important
258
+ padding-top: 0 !important
259
+ padding-bottom: 0 !important
260
+ .q-item__section--main
261
+ display: inline !important
262
+ .q-item__label.q-item__label--caption span
263
+ font-weight: normal !important
264
+ line-height: normal !important
265
+ width: 100%
266
+ .q-item.q-item-type:last-child
267
+ padding-top: 0 !important
268
+ margin-bottom: 0 !important
269
+ .u-expansion-body
270
+ display: flex
271
+ .expansion-table-card-action
272
+ display: flex
273
+ justify-content: space-between
274
+ align-items: center
275
+ gap: $xs
276
+ width: 100%
277
+ padding: $xs 0px
278
+
279
+ .expansion-table-card-separator
280
+ width: 100%
281
+ padding: $xs $ba
282
+ background-color: white
283
+
284
+ .expansion-table-card:last-of-type
285
+ .q-card .q-list
286
+ padding-bottom: $xs !important
287
+ </style>