@usssa/component-library 1.0.0-alpha.10 → 1.0.0-alpha.100

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.
Files changed (53) hide show
  1. package/README.md +5 -2
  2. package/package.json +19 -4
  3. package/src/assets/files.png +0 -0
  4. package/src/assets/logo.svg +19 -0
  5. package/src/assets/no-result.png +0 -0
  6. package/src/assets/quasar-logo-vertical.svg +15 -0
  7. package/src/components/core/UAvatar.vue +39 -6
  8. package/src/components/core/UAvatarGroup.vue +15 -14
  9. package/src/components/core/UBannerStd.vue +51 -22
  10. package/src/components/core/UBreadCrumbs.vue +67 -0
  11. package/src/components/core/UBtnIcon.vue +24 -14
  12. package/src/components/core/UBtnStd.vue +35 -31
  13. package/src/components/core/UBtnToggle.vue +68 -0
  14. package/src/components/core/UCheckboxStd.vue +25 -8
  15. package/src/components/core/UChip.vue +30 -4
  16. package/src/components/core/UDialogStd.vue +244 -0
  17. package/src/components/core/UDrawer.vue +235 -0
  18. package/src/components/core/UInnerLoader.vue +58 -0
  19. package/src/components/core/UInputAddressLookup.vue +470 -0
  20. package/src/components/core/UInputPhoneStd.vue +299 -0
  21. package/src/components/core/UInputTextStd.vue +114 -85
  22. package/src/components/core/UInputTypeaheadAdvanceSearch.vue +59 -0
  23. package/src/components/core/UMenuButtonStd.vue +274 -0
  24. package/src/components/core/UMenuDropdown.vue +72 -0
  25. package/src/components/core/UMenuDropdownAdvancedSearch.vue +301 -0
  26. package/src/components/core/UMenuItem.vue +134 -0
  27. package/src/components/core/UMenuSearch.vue +752 -0
  28. package/src/components/core/UMultiSelectStd.vue +63 -57
  29. package/src/components/core/UPagination.vue +104 -0
  30. package/src/components/core/URadioBtn.vue +116 -0
  31. package/src/components/core/URadioStd.vue +7 -3
  32. package/src/components/core/USelectStd.vue +74 -59
  33. package/src/components/core/UTabBtnStd.vue +82 -59
  34. package/src/components/core/UTable/UTable.vue +93 -0
  35. package/src/components/core/UTable/UTd.vue +63 -0
  36. package/src/components/core/UTable/UTh.vue +48 -0
  37. package/src/components/core/UTable/UTr.vue +20 -0
  38. package/src/components/core/UTableStd.vue +1003 -0
  39. package/src/components/core/UTabsStd.vue +17 -5
  40. package/src/components/core/UToggleStd.vue +30 -20
  41. package/src/components/core/UToolbar.vue +94 -0
  42. package/src/components/core/UTooltip.vue +25 -4
  43. package/src/components/core/UUploader.vue +497 -0
  44. package/src/components/index.js +57 -6
  45. package/src/composables/useNotify.js +79 -0
  46. package/src/composables/useOverlayLoader.js +23 -0
  47. package/src/css/app.sass +159 -0
  48. package/src/css/colors.sass +101 -0
  49. package/src/css/media.sass +1 -0
  50. package/src/css/quasar.variables.sass +121 -0
  51. package/src/css/typography.sass +0 -0
  52. package/src/css/vars/colors.variables.sass +126 -0
  53. package/src/utils/data.ts +146 -0
@@ -0,0 +1,1003 @@
1
+ <script setup>
2
+ import { computed, ref } from 'vue'
3
+ import UAvatar from './UAvatar.vue'
4
+ import UBtnIcon from './UBtnIcon.vue'
5
+ import UBtnStd from './UBtnStd.vue'
6
+ import UCheckboxStd from './UCheckboxStd.vue'
7
+ import UChip from './UChip.vue'
8
+ import UMenuDropdown from './UMenuDropdown.vue'
9
+ import UPagination from './UPagination.vue'
10
+ import UTable from './UTable/UTable.vue'
11
+ import UTd from './UTable/UTd.vue'
12
+ import UTh from './UTable/UTh.vue'
13
+ import UTr from './UTable/UTr.vue'
14
+ import UTooltip from './UTooltip.vue'
15
+
16
+ const emit = defineEmits(['onCustomSort'])
17
+ const columns = defineModel('columns', {
18
+ default: () => [],
19
+ type: Array,
20
+ })
21
+ const loading = defineModel('loading', {
22
+ default: () => {},
23
+ type: Boolean,
24
+ })
25
+ const moreActionDialogData = defineModel('moreActionDialogData', {
26
+ type: Object,
27
+ default: null,
28
+ })
29
+ const pagination = defineModel('pagination', {
30
+ default: { page: 1, rowsPerPage: 15 },
31
+ type: Object,
32
+ })
33
+ const rows = defineModel('rows', {
34
+ default: () => [],
35
+ type: Array,
36
+ })
37
+ const selectedRows = defineModel('selectedRows', {
38
+ default: () => [],
39
+ type: Array,
40
+ })
41
+
42
+ const props = defineProps({
43
+ bordered: {
44
+ type: Boolean,
45
+ default: false,
46
+ },
47
+ customClass: {
48
+ type: String,
49
+ default: '',
50
+ },
51
+ flat: {
52
+ type: Boolean,
53
+ default: false,
54
+ },
55
+ grid: {
56
+ type: Boolean,
57
+ default: false,
58
+ },
59
+ isCustomSort: {
60
+ type: Boolean,
61
+ default: false,
62
+ },
63
+ multiSelection: {
64
+ type: Boolean,
65
+ default: false,
66
+ },
67
+ separator: {
68
+ type: String,
69
+ default: 'horizontal',
70
+ },
71
+ showPagination: {
72
+ type: Boolean,
73
+ default: true,
74
+ },
75
+ stickyHeader: {
76
+ type: Boolean,
77
+ default: false,
78
+ },
79
+ tableRowHover: {
80
+ type: Boolean,
81
+ default: false,
82
+ },
83
+ title: {
84
+ type: String,
85
+ default: '',
86
+ },
87
+ verticalMoreActions: {
88
+ type: Boolean,
89
+ default: false,
90
+ },
91
+ virtualScroll: {
92
+ type: Boolean,
93
+ default: false,
94
+ },
95
+ })
96
+
97
+ const customLoading = ref(false)
98
+ const rowsPerPageOptions = ref([
99
+ { label: '5 / per page', value: 5 },
100
+ { label: '10 / per page', value: 10 },
101
+ { label: '15 / per page', value: 15 },
102
+ { label: '20 / per page', value: 20 },
103
+ { label: '25 / per page', value: 25 },
104
+ ])
105
+ const tableDataChip = ref(true) // this is required to show chip
106
+ const tailClass = ref(null)
107
+
108
+ // if virtual scroll is enbaled then adding large rows per page to view in virtual scroll
109
+ const getRowsPerPageOptions = computed(() => {
110
+ if (props.virtualScroll) {
111
+ return [
112
+ ...rowsPerPageOptions.value,
113
+ { label: '100 / per page', value: 100 },
114
+ { label: '500 / per page', value: 500 },
115
+ { label: '1000 / per page', value: 1000 },
116
+ ]
117
+ } else {
118
+ return rowsPerPageOptions.value
119
+ }
120
+ })
121
+
122
+ // chekcing the menu position after show
123
+ const checkMenuPosition = (id) => {
124
+ const menuElement = document.getElementById(`actionPopupRef-${id}`) // Access the menu by ID
125
+ const buttonElement = document.getElementById(`actionPopupRefBtn-${id}`) // Access the button element
126
+
127
+ if (menuElement && buttonElement) {
128
+ const menuRect = menuElement.getBoundingClientRect() // Menu position
129
+ const buttonRect = buttonElement.getBoundingClientRect() // Button position
130
+
131
+ // Determine if the menu opens above or below
132
+ if (menuRect.top < buttonRect.top) {
133
+ tailClass.value = 'tail-bottom' // Menu opens below, tail at the bottom
134
+ } else {
135
+ tailClass.value = 'tail-top' // Menu opens above, tail at the top
136
+ }
137
+ }
138
+ }
139
+
140
+ // sorting funtion to handle text and number type of data
141
+ const dataSort = (data, key, order, type) => {
142
+ if (type === 'text') {
143
+ return data.sort((a, b) =>
144
+ order === 'asc'
145
+ ? a[key].localeCompare(b[key])
146
+ : b[key].localeCompare(a[key])
147
+ )
148
+ } else {
149
+ return data.sort((a, b) =>
150
+ order === 'asc' ? a[key] - b[key] : b[key] - a[key]
151
+ )
152
+ }
153
+ }
154
+
155
+ //getting the chip color accroding to value of chip from row
156
+ const getChipColor = (data, value) => {
157
+ const foundObject = data.find((chip) => chip.value === value)
158
+ if (foundObject) {
159
+ return foundObject['color']
160
+ } else {
161
+ return 'neutral-3'
162
+ }
163
+ }
164
+
165
+ //getting the sorted icon according the order
166
+ const getSortingIcon = (col) => {
167
+ if (col) {
168
+ if (col.sortOrder === 'asc') {
169
+ return 'fa-kit fa-ascending'
170
+ } else {
171
+ return 'fa-kit fa-descending'
172
+ }
173
+ }
174
+ }
175
+
176
+ const handleActionColClick = (e) => {
177
+ e.preventDefault()
178
+ e.stopPropagation()
179
+ }
180
+
181
+ const handleMenuEventStop = (e) => {
182
+ e.preventDefault()
183
+ e.stopPropagation()
184
+ }
185
+
186
+ //if user want to add custom sort on data
187
+ const handleCustomSort = (key, sortOrder, type) => {
188
+ emit('onCustomSort', key, sortOrder, type)
189
+ }
190
+
191
+ // handling the large selection data in chunks
192
+ const handleSelectAllData = () => {
193
+ customLoading.value = true
194
+ return new Promise((resolve, reject) => {
195
+ let index = 0
196
+ function processChunk() {
197
+ if (index >= rows.value.length) {
198
+ resolve(200)
199
+ return
200
+ }
201
+ const chunk = props.rows.slice(index, index + 25)
202
+ chunk.forEach((element) => {
203
+ if (
204
+ selectedRows.value.findIndex((item) => item._id === element._id) ===
205
+ -1
206
+ ) {
207
+ selectedRows.value.push(element)
208
+ }
209
+ })
210
+ index += 25
211
+ setTimeout(processChunk, 10)
212
+ }
213
+ try {
214
+ processChunk()
215
+ } catch {
216
+ reject('error')
217
+ }
218
+ })
219
+ }
220
+
221
+ //it is sorting the data according to type like text or number type of data
222
+ const handleSort = (key, sortOrder, type) => {
223
+ rows.value = dataSort(rows.value, key, sortOrder, type)
224
+ columns.value.forEach((col) => {
225
+ if (key === col.field) {
226
+ col.sortOrder = sortOrder === 'asc' ? 'desc' : 'asc'
227
+ }
228
+ })
229
+ }
230
+
231
+ //adding a new row to selectedRows
232
+ const handleToSelectRow = (row) => {
233
+ if (row) {
234
+ const index = selectedRows.value.findIndex((item) => item._id === row._id)
235
+ if (index === -1) {
236
+ selectedRows.value.push(row)
237
+ } else {
238
+ selectedRows.value.splice(index, 1)
239
+ }
240
+ }
241
+ }
242
+
243
+ // it is giving the selected row and setting the new selection
244
+ const isRowSelected = (row) => {
245
+ if (row) {
246
+ const index = selectedRows.value.findIndex((item) => item._id === row._id)
247
+ return computed({
248
+ get: () => {
249
+ return index === -1 ? false : true
250
+ },
251
+ set: () => {
252
+ if (index === -1) {
253
+ selectedRows.value.push(row)
254
+ } else {
255
+ selectedRows.value.splice(index, 1)
256
+ }
257
+ },
258
+ })
259
+ } else {
260
+ return computed({
261
+ get: () => {
262
+ let dataLength = props.rows.length
263
+ return selectedRows.value.length === dataLength
264
+ ? true
265
+ : selectedRows.value.length === 0
266
+ ? false
267
+ : null
268
+ },
269
+ set: (value) => {
270
+ if (value !== null) {
271
+ selectedRows.value.splice(0, selectedRows.value.length)
272
+ } else {
273
+ handleSelectAllData().then((res) => {
274
+ if (res === 200) {
275
+ customLoading.value = false
276
+ }
277
+ })
278
+ }
279
+ },
280
+ })
281
+ }
282
+ }
283
+
284
+ // handle to change the page, and if virtual scroll is enabled and user scrolled to bottom it will take user to the top
285
+ const onPageChange = (value) => {
286
+ pagination.value.page = value
287
+ }
288
+
289
+ //adding a new row to selectedRows
290
+ const onRowClick = (event, row) => {
291
+ if (props.multiSelection) {
292
+ event.stopPropagation()
293
+ handleToSelectRow(row)
294
+ }
295
+ }
296
+
297
+ //handle to change the rows per page
298
+ const onRowPerPageChange = (value) => {
299
+ pagination.value.rowsPerPage = value
300
+ }
301
+ </script>
302
+
303
+ <template>
304
+ <UTable
305
+ v-model:columns="columns"
306
+ v-model:pagination="pagination"
307
+ v-model:rows="rows"
308
+ :class="customClass"
309
+ :bordered="bordered"
310
+ :flat="flat"
311
+ :grid="grid"
312
+ :loading="loading"
313
+ :separator="separator"
314
+ :showPagination="showPagination"
315
+ :stickyHeader="stickyHeader"
316
+ :title="title"
317
+ :virtualScroll="virtualScroll"
318
+ >
319
+ <!-- custom header slot to add customized header -->
320
+ <template v-slot:header="props">
321
+ <UTr :props="props" :tableRowHover="tableRowHover">
322
+ <UTh
323
+ v-if="multiSelection"
324
+ :separator="separator"
325
+ style="width: 3% !important"
326
+ :tableHeaderAutoWidth="false"
327
+ tableHeadAlignment="left"
328
+ >
329
+ <UCheckboxStd
330
+ v-model="isRowSelected(null).value"
331
+ id="u-checkbox-table-header"
332
+ :indeterminate="true"
333
+ name="Table Header"
334
+ />
335
+ </UTh>
336
+ <template v-for="(col, key) in props.cols">
337
+ <UTh
338
+ v-if="typeof col.show === 'undefined' || col.show"
339
+ :class="`${col.sortable ? 'cursor-pointer' : ''} ${
340
+ col.headerClasses
341
+ }`"
342
+ :key="key"
343
+ :separator="separator"
344
+ :style="col.headerStyle"
345
+ :tableHeaderAutoWidth="col.autoWidth"
346
+ :tableHeadAlignment="col.field === 'action' ? col.align : col.align"
347
+ @click="
348
+ col.sortable
349
+ ? isCustomSort
350
+ ? handleCustomSort(col.field, col.sortOrder, col.type)
351
+ : handleSort(col.field, col.sortOrder, col.type)
352
+ : null
353
+ "
354
+ >
355
+ <span
356
+ :class="`${col.field === 'action' ? 'hidden-header-label' : ''}`"
357
+ >
358
+ {{ col.field === 'action' ? 'Action' : col.label }}
359
+ </span>
360
+
361
+ <span v-if="col.sortable && col.field !== 'action'">
362
+ <UBtnIcon
363
+ :class="`more-action-icon cursor-pointer`"
364
+ :iconClass="`${getSortingIcon(col)}`"
365
+ :aria-label="`Sort ${col.label}`"
366
+ ref="btn-icon"
367
+ size="sm"
368
+ />
369
+ </span>
370
+ </UTh>
371
+ </template>
372
+ </UTr>
373
+ </template>
374
+ <!-- custom body slots to add customized cell data -->
375
+ <template v-slot:body="props">
376
+ <UTr
377
+ :class="`${isRowSelected(props.row).value ? 'selected-data-row' : ''}`"
378
+ :props="props"
379
+ :tableRowHover="tableRowHover"
380
+ @click="onRowClick($event, props.row)"
381
+ >
382
+ <UTd
383
+ v-if="multiSelection"
384
+ :index="-1"
385
+ :separator="separator"
386
+ tableDataAlignment="left"
387
+ :tableHeaderAutoWidth="false"
388
+ >
389
+ <UCheckboxStd
390
+ v-model="isRowSelected(props.row).value"
391
+ :id="`u-checkbox-${props.row._id}`"
392
+ :name="props.row._id"
393
+ />
394
+ </UTd>
395
+
396
+ <template v-for="(col, index) in props.cols" :key="index">
397
+ <!-- to show the cell data without the action cell -->
398
+ <UTd
399
+ v-if="
400
+ col.field !== 'action' &&
401
+ (typeof col.show === 'undefined' || col.show)
402
+ "
403
+ :class="col.classes"
404
+ :col="col"
405
+ :index="index"
406
+ :row="props.row"
407
+ :separator="separator"
408
+ :style="col.style"
409
+ :tableDataAlignment="col.align"
410
+ :tableDataAutoWidth="col.autoWidth"
411
+ >
412
+ <!-- to show the chips with different variant -->
413
+ <template v-if="col.chipValues && col.chipValues.length > 0">
414
+ <UChip
415
+ v-model="tableDataChip"
416
+ class="u-table-chip"
417
+ avatarLabel=""
418
+ :anchor="col.anchor"
419
+ :chipLabel="props.row[col.field].toString()"
420
+ :dense="col.denseChip"
421
+ :is-show-tooltip="col.showChipTooltip"
422
+ :offset="col.offset"
423
+ :removable="false"
424
+ :type="getChipColor(col.chipValues, props.row[col.field])"
425
+ />
426
+ </template>
427
+ <!-- to show the avatar of user image with name and other details -->
428
+ <template v-else-if="col.avatarKey">
429
+ <div class="flex justify-start items-center">
430
+ <div
431
+ v-if="
432
+ props.row[col.avatarKey] &&
433
+ typeof props.row[col.avatarKey] === 'object'
434
+ "
435
+ class="table-data-avatar"
436
+ >
437
+ <UAvatar
438
+ v-if="props.row[col.avatarKey]?.type === 'initials'"
439
+ :name="`${props.row[col.avatarKey]?.value}`"
440
+ size="md"
441
+ />
442
+ <UAvatar
443
+ v-else-if="props.row[col.avatarKey]?.type === 'image'"
444
+ :image="`${props.row[col.avatarKey]?.value}`"
445
+ :name="
446
+ props.row[col.avatarKey]?.name ??
447
+ props.row[col.avatarKey]?.value
448
+ "
449
+ size="md"
450
+ />
451
+ </div>
452
+ <div v-else class="table-data-avatar">
453
+ <UAvatar
454
+ :image="`${props.row[col.avatarKey]}`"
455
+ :name="`${props.row[col.avatarKey]}`"
456
+ size="md"
457
+ />
458
+ </div>
459
+ <div class="td-grid-content">
460
+ <div>{{ props.row[col.field] }}</div>
461
+ <div v-if="col.captionKey" class="td-caption text-body-xs">
462
+ {{ props.row[col.captionKey] }}
463
+ </div>
464
+ </div>
465
+ </div>
466
+ </template>
467
+ <!-- to show other cell data -->
468
+ <template v-else>
469
+ <div class="td-grid-content">
470
+ <div v-if="col.type !== 'icon'">
471
+ {{ props.row[col.field] }}
472
+ </div>
473
+ <div v-else-if="col.type === 'icon'">
474
+ <template v-if="props.row[col.field]">
475
+ <q-icon
476
+ :class="props.row[col.field]"
477
+ :aria-label="props.row.ariaLabel"
478
+ :alt="props.row.ariaLabel"
479
+ :color="props?.row?.iconColor ?? 'primary'"
480
+ size="1.5rem"
481
+ />
482
+ </template>
483
+ </div>
484
+ <div
485
+ v-if="col.captionKey && col.type !== 'icon'"
486
+ class="td-caption text-body-xs"
487
+ >
488
+ {{ props.row[col.captionKey] }}
489
+ </div>
490
+ </div>
491
+ </template>
492
+ </UTd>
493
+ <!-- to the action cell, it can have single and multiple -->
494
+
495
+ <UTd
496
+ v-else-if="typeof col.show === 'undefined' || col.show"
497
+ :class="col.classes"
498
+ :index="index"
499
+ :separator="separator"
500
+ :style="col.style"
501
+ style="width: 3%"
502
+ :tableDataAlignment="col.align"
503
+ :tableDataAutoWidth="false"
504
+ @click="handleActionColClick"
505
+ >
506
+ <template v-if="col.actions && col.actions.length === 1">
507
+ <template v-for="(action, key) in col.actions" :key="key">
508
+ <UBtnStd
509
+ v-if="
510
+ typeof action.hide === 'function'
511
+ ? !action.hide(props.row)
512
+ : true
513
+ "
514
+ :color="
515
+ typeof action.color === 'function'
516
+ ? action.color(props.row)
517
+ : action.color
518
+ "
519
+ :disable="
520
+ typeof action.disable === 'function' &&
521
+ action.disable(props.row)
522
+ "
523
+ :flat="
524
+ typeof action.flat === 'function'
525
+ ? action.flat(props.row)
526
+ : action.flat
527
+ "
528
+ :key="key"
529
+ :label="
530
+ typeof action.label === 'function'
531
+ ? action.label(props.row)
532
+ : action.label
533
+ "
534
+ :leftIcon="
535
+ typeof action.icon === 'function'
536
+ ? action.icon(props.row)
537
+ : action.icon
538
+ "
539
+ :outline="
540
+ typeof action.outline === 'function'
541
+ ? action.outline(props.row)
542
+ : action.outline
543
+ "
544
+ :size="action.size"
545
+ @onClick="action.handler(props.row)"
546
+ >
547
+ <template #tooltip>
548
+ <UTooltip
549
+ v-if="
550
+ typeof action.tooltip === 'function'
551
+ ? action.tooltip(props.row)
552
+ : action.tooltip
553
+ "
554
+ :anchor="action.anchor"
555
+ :description="
556
+ typeof action.tooltip === 'function'
557
+ ? action.tooltip(props.row)
558
+ : action.tooltip
559
+ "
560
+ :offset="action.offset ? action.offset : [10, 40]"
561
+ :self="action.anchor"
562
+ />
563
+ </template>
564
+ </UBtnStd>
565
+ </template>
566
+ </template>
567
+ <!-- to show the actions list if the actions are multiple -->
568
+ <template v-else>
569
+ <q-menu
570
+ v-if="
571
+ moreActionDialogData &&
572
+ moreActionDialogData.showDialog[props.row.id]
573
+ "
574
+ v-model="moreActionDialogData.showDialog[props.row.id]"
575
+ :class="`more-action-popup q-px-ba q-py-ba`"
576
+ anchor="top left"
577
+ :cover="false"
578
+ :fit="true"
579
+ :id="`actionPopupRef-${props.row.id}`"
580
+ :offset="[85, 0]"
581
+ role="list"
582
+ self="bottom middle"
583
+ transition-show="scale"
584
+ transition-hide="scale"
585
+ @show="checkMenuPosition(props.row.id)"
586
+ >
587
+ <div :class="tailClass"></div>
588
+ <q-card class="more-action-popup-wrapper">
589
+ <q-card-section>
590
+ <div class="content-wrapper text-center">
591
+ <div class="q-pb-ba flex justify-center items-center">
592
+ <div
593
+ :class="`remove-icon-wrapper ${
594
+ moreActionDialogData.row.iconColor === 'accent'
595
+ ? 'icon-bg-accent'
596
+ : 'icon-bg-primary'
597
+ }`"
598
+ >
599
+ <q-icon
600
+ :class="`${moreActionDialogData.row.icon} ${
601
+ moreActionDialogData.row.iconColor === 'accent'
602
+ ? 'icon-text-accent'
603
+ : 'icon-text-primary'
604
+ }`"
605
+ alt="confirmation icon"
606
+ aria-label="confirmation icon"
607
+ size="1.5rem"
608
+ />
609
+ </div>
610
+ </div>
611
+
612
+ <div
613
+ class="text-heading-xxs primary-content-text q-pb-xxs"
614
+ >
615
+ {{ moreActionDialogData.row.title }}
616
+ </div>
617
+ <div
618
+ v-if="moreActionDialogData.row.description"
619
+ class="text-body-sm secondary-content-text q-pb-xs"
620
+ >
621
+ {{ moreActionDialogData.row.description }}
622
+ </div>
623
+ </div>
624
+ <!-- <p class="hidden-scope-value">{{ scope.value }}</p> -->
625
+ </q-card-section>
626
+
627
+ <q-card-actions align="right">
628
+ <UBtnStd
629
+ v-if="moreActionDialogData.secondaryAction"
630
+ :color="moreActionDialogData.secondaryAction.color"
631
+ :disable="moreActionDialogData.secondaryAction.disable"
632
+ :flat="moreActionDialogData.secondaryAction.flat"
633
+ :label="moreActionDialogData.secondaryAction.label"
634
+ :loading="moreActionDialogData.secondaryAction.loading"
635
+ :outline="moreActionDialogData.secondaryAction.outline"
636
+ :size="moreActionDialogData.secondaryAction.size"
637
+ @on-click="
638
+ moreActionDialogData.secondaryAction.handler(props.row)
639
+ "
640
+ />
641
+ <UBtnStd
642
+ v-if="moreActionDialogData.primaryAction"
643
+ class="confirm-primary-action"
644
+ :color="moreActionDialogData.primaryAction.color"
645
+ :disable="moreActionDialogData.primaryAction.disable"
646
+ :flat="moreActionDialogData.primaryAction.flat"
647
+ :label="moreActionDialogData.primaryAction.label"
648
+ :loading="moreActionDialogData.primaryAction.loading"
649
+ :outline="moreActionDialogData.primaryAction.outline"
650
+ :size="moreActionDialogData.primaryAction.size"
651
+ @on-click="
652
+ moreActionDialogData.primaryAction.handler(props.row)
653
+ "
654
+ />
655
+ </q-card-actions>
656
+ </q-card>
657
+ </q-menu>
658
+
659
+ <UBtnIcon
660
+ :class="`action-icon cursor-pointer`"
661
+ iconClass="fa-kit fa-ellipsis-vertical"
662
+ ariaLabel="More action"
663
+ :id="`actionPopupRefBtn-${props.row.id}`"
664
+ :key="index"
665
+ ref="btn-icon"
666
+ @click.stop="handleMenuEventStop"
667
+ >
668
+ <template #menu>
669
+ <q-menu v-if="!verticalMoreActions" auto-close role="list">
670
+ <div
671
+ :class="`${
672
+ verticalMoreActions ? 'vertical' : 'horizontal'
673
+ }-more-action-wrapper more-action-common`"
674
+ >
675
+ <template v-for="(action, key) in col.actions" :key="key">
676
+ <UBtnIcon
677
+ v-if="
678
+ typeof action.hide === 'function'
679
+ ? !action.hide(props.row)
680
+ : true && !verticalMoreActions
681
+ "
682
+ :class="`more-action-icon cursor-pointer table-more-action`"
683
+ :iconClass="
684
+ typeof action.icon === 'function'
685
+ ? action.icon(props.row)
686
+ : action.icon
687
+ "
688
+ :anchor="action.anchor"
689
+ :ariaLabel="
690
+ typeof action.label === 'function'
691
+ ? action.label(props.row)
692
+ : action.label
693
+ "
694
+ :disable="
695
+ typeof action.disable === 'function' &&
696
+ action.disable(props.row)
697
+ "
698
+ :id="`more-action-${key}`"
699
+ :offset="action.offset ? action.offset : [10, 40]"
700
+ ref="btn-icon"
701
+ :self="action.self"
702
+ :size="action.size"
703
+ :tooltip="
704
+ typeof action.tooltip === 'function'
705
+ ? action.tooltip(props.row)
706
+ : action.tooltip
707
+ "
708
+ @click.stop="handleMenuEventStop"
709
+ @onClick="action.handler(props.row)"
710
+ />
711
+ </template>
712
+ </div>
713
+ </q-menu>
714
+
715
+ <q-menu v-else auto-close role="list">
716
+ <UMenuDropdown
717
+ v-if="verticalMoreActions"
718
+ :data="
719
+ col.actions.map((action) => {
720
+ return {
721
+ destructive: action.destructive,
722
+ disable:
723
+ typeof action.disable === 'function' &&
724
+ action.disable(props.row),
725
+ hide: !(typeof action.hide === 'function'
726
+ ? !action.hide(props.row)
727
+ : true),
728
+ label:
729
+ typeof action.label === 'function'
730
+ ? action.label(props.row)
731
+ : action.label,
732
+ leftIcon:
733
+ typeof action.icon === 'function'
734
+ ? action.icon(props.row)
735
+ : action.icon,
736
+ handler: function () {
737
+ return action.handler(props.row)
738
+ },
739
+ }
740
+ })
741
+ "
742
+ />
743
+ </q-menu>
744
+ </template>
745
+ </UBtnIcon>
746
+ </template>
747
+ </UTd>
748
+ </template>
749
+ </UTr>
750
+ </template>
751
+ <!-- slot to show if there is no data in rows -->
752
+ <template v-slot:no-data>
753
+ <div class="full-width row flex-center text-accent q-gutter-sm">
754
+ <span> No Data Found </span>
755
+ </div>
756
+ </template>
757
+ <!-- to add the custom loading state -->
758
+ <!-- <template v-slot:loading>
759
+ <q-inner-loading v-if="customLoading" showing color="primary" />
760
+ </template> -->
761
+ </UTable>
762
+ <!-- customized pagination with the vitual scroll functionality and rows per page selection -->
763
+ <div
764
+ v-if="showPagination"
765
+ class="row justify-end items-center pagination-wrapper"
766
+ >
767
+ <UPagination
768
+ v-if="rows.length >= 6"
769
+ v-model="pagination.page"
770
+ :maxPageLink="
771
+ Number(Math.ceil(rows.length / pagination.rowsPerPage > 10 ? 6 : 3))
772
+ "
773
+ :maxPages="Number(Math.ceil(rows.length / pagination.rowsPerPage))"
774
+ :perPageOptions="getRowsPerPageOptions"
775
+ :rowPerPage="pagination.rowsPerPage"
776
+ @onPageChange="onPageChange"
777
+ @onRowChange="onRowPerPageChange"
778
+ />
779
+ </div>
780
+ <q-inner-loading :showing="customLoading" class="custom-table-loader" />
781
+ </template>
782
+
783
+ <style lang="sass">
784
+ .action-icon
785
+ &:hover
786
+ background: $blue-1
787
+
788
+ .q-icon
789
+ height: $md !important
790
+ width: $md !important
791
+ color: $neutral-9 !important
792
+ font-size: $ba !important
793
+ &:hover
794
+ color: $primary !important
795
+
796
+ .table-data-avatar
797
+ padding: $xs
798
+ padding-left: 0px
799
+
800
+ .td-caption
801
+ color: $description
802
+
803
+ .more-action-common
804
+ min-width: 3.125rem
805
+ padding: $xs
806
+ min-height: $xl
807
+ gap: $xs
808
+ border-bottom: 1.5px solid $neutral-4
809
+ background: $surface-bg-1
810
+ box-shadow: 0px 0px 4px 0px rgba(16, 17, 20, 0.08)
811
+
812
+ .vertical-more-action-wrapper
813
+ display: grid
814
+ place-items: flex-start
815
+ place-content: center
816
+ padding: $xxs
817
+ gap: $xxs
818
+
819
+ .horizontal-more-action-wrapper
820
+ display: flex
821
+ align-items: center
822
+ justify-content: start
823
+
824
+ .vertical-single-action
825
+ width: 100%
826
+ gap: $xs
827
+ padding: 0 $xs
828
+ height: $lg
829
+
830
+ .q-item__section--main
831
+ color: $neutral-9
832
+ white-space: nowrap
833
+
834
+ .q-item__section--avatar
835
+ min-width: 0px
836
+
837
+ .q-item__section--side
838
+ padding-right: 0
839
+
840
+ .q-icon
841
+ color: $neutral-9
842
+ font-size: $ba
843
+
844
+ .more-action-icon
845
+ .q-icon
846
+ color: $neutral-9 !important
847
+ font-size: $ba !important
848
+
849
+ .selected-data-row
850
+ background: #F7F7F7
851
+
852
+ .rows-per-page-dropdown
853
+ margin-right: 0.5rem
854
+
855
+ .u-table
856
+ height: auto
857
+
858
+ .q-table__progress
859
+ .q-linear-progress
860
+ color: $primary !important
861
+ height: 0.145rem
862
+
863
+ .force-auto-height-table
864
+ height: auto !important
865
+
866
+ .u-virtualscroll-table
867
+ height: 50rem
868
+
869
+ .u-virtualscroll-grid-table
870
+ max-height: 50rem
871
+ overflow: auto
872
+
873
+ .u-sticky-table-header
874
+ .q-table__top,
875
+ .q-table__bottom,
876
+ thead tr:first-child th
877
+ background-color: #FFFFFF
878
+
879
+ thead tr th
880
+ position: sticky
881
+ z-index: 1
882
+
883
+ thead tr:first-child th
884
+ top: 0
885
+
886
+ &.q-table--loading thead tr:last-child th
887
+ top: 3rem
888
+
889
+ tbody
890
+ scroll-margin-top: 3rem
891
+
892
+ .u-sorting-btn
893
+ padding: 0
894
+ min-height: auto
895
+ .block
896
+ display: none !important
897
+
898
+ .q-focus-helper
899
+ background: none !important
900
+
901
+ .u-sorting-btn:before
902
+ box-shadow: none !important
903
+
904
+ .u-table-chip
905
+ .q-icon
906
+ display: none
907
+
908
+ .no-border-bottom-cell
909
+ border-bottom: none !important
910
+
911
+ .pagination-wrapper
912
+ margin-top: $ba
913
+
914
+ .custom-table-loader
915
+ .q-spinner
916
+ color: $primary
917
+
918
+ .td-grid-content
919
+ text-wrap: balance
920
+ word-break: break-all
921
+
922
+ .hidden-header-label
923
+ visibility: hidden
924
+
925
+ .more-action-popup
926
+ border-radius: $border-radius-sm
927
+ background: $neutral-1
928
+ box-shadow: 0rem 0rem 0.75rem 0rem rgba(16, 17, 20, 0.16)
929
+ max-width: 18.375rem !important
930
+ width: 100%
931
+ position: relative
932
+ overflow: visible
933
+
934
+ .more-action-popup-wrapper
935
+ box-shadow: none
936
+ max-width: 18.375rem !important
937
+ width: 100%
938
+ .hidden-scope-value
939
+ display: none
940
+ .q-card__section
941
+ padding: 0
942
+ .q-card__actions
943
+ flex-wrap: nowrap
944
+ padding: $ba 0 0 0
945
+ .q-btn
946
+ width: 50%
947
+
948
+ .content-wrapper
949
+ display: grid
950
+ place-content: center
951
+ place-items: center
952
+
953
+ .secondary-content-text
954
+ color: $description
955
+
956
+ .primary-content-text
957
+ color: $dark
958
+
959
+ .remove-icon-wrapper
960
+ border-radius: 7.75rem
961
+ padding: $sm
962
+ width: 3.125rem
963
+ height: 3.125rem
964
+ .q-icon
965
+ color: $accent
966
+
967
+ .confirm-primary-action
968
+ margin-left: $ba !important
969
+
970
+ .icon-bg-accent
971
+ background-color: $red-1
972
+
973
+ .icon-bg-primary
974
+ background-color: $blue-1
975
+
976
+ .icon-text-accent
977
+ color: $accent
978
+
979
+ .icon-text-primary
980
+ color: $primary !important
981
+
982
+ .tail-top
983
+ width: 1.25rem
984
+ height: 1.25rem
985
+ transform: rotate(45deg)
986
+ position: absolute
987
+ right: 1.304rem
988
+ top: -0.604rem
989
+ border-top-left-radius: $border-radius-xs
990
+ background: $neutral-1
991
+ box-shadow: -3px -2px 5px -3px rgba(0, 0, 0, 0.2)
992
+
993
+ .tail-bottom
994
+ width: 1.25rem
995
+ height: 1.25rem
996
+ transform: rotate(45deg)
997
+ position: absolute
998
+ right: 1.304rem
999
+ bottom: -0.604rem
1000
+ border-bottom-right-radius: $border-radius-xs
1001
+ background: $neutral-1
1002
+ box-shadow: 3px 4px 5px -3px rgba(0, 0, 0, 0.2)
1003
+ </style>